2023年1月26日 星期四

慢跑紀錄:跑在海濱

去年北竿超馬後就陷入了跑步低潮期,在這之前從未經歷類似心情,真的是什麼都不想碰,可能也是因為工作忙碌,沒有練習也沒有跑量。曾經我的內心真的有很不錯的堅持和意志力,也深知跑步只要不維持就會退步的道理,但就是不想跑,甚至覺得今後可能都找不回來。

對於這種心態,都會安慰自己該振奮了,讓自己維持每年一個馬拉松,至少先報名再說。偶然間看到南橫馬拉松"召喚",由關山開始跑至利稻前原路折返(單程30公里,來回60公里),距離和高度提升都沒有超過自己極限。我想只要不追求速度,應該可以試試看吧。

"恢復跑"的路線選擇首重平緩,其次是景緻。海邊天寬地闊總是強烈吸引著我,以下是幾次從八里、新豐、南寮、十七公里海岸線,苗栗白沙屯甚至到苑裡邊跑邊拍,晃晃悠悠的紀錄。

海闊天空

提到海邊,天寬地闊是第一印象,竹苗海濱當然不會讓人失望,更棒的是還有不同景緻。第一種是香山濕地為主的泥質潮間帶,退潮時可見綿長海岸線以及蜿蜒水道向外擴展,寬闊且愜意。

蜿蜒的河流,野水連天碧

相形之下,苗栗的海岸縱深就淺多了,陸岸緊鄰著海濤,幾乎沒有潮間帶。跑在沙灘上,眼前是綿長的礫石帶和沙灘,左側是岸邊沙丘,右邊海平面矗立著數十隻巨大海上風車。東北季風狂吹著,不時有小沙塵吹打在身上。只有偶爾出現的東方環頸鴴能抵擋這強風,仍然急速飛躍著。

後龍北浦海景

在外埔附近,沙灘較開闊處,原有的小石礫被大型卵石取代,這些大石有秩序的堆疊著,仔細看應該是石滬,範圍大的甚至有內、外圈之分。事後查詢這些石滬可追朔自道卡斯族後壟社人所建,有數百年歷史。

風吹拂的沙丘

人工瓜田造型和沙丘如出一轍

好望角以南,海岸縱深短,與山麓丘陵地近在咫尺。原本這些海底沉積經過地殼運動隆起形成台地,再經過各溪流切割而形成高低不連續的丘陵地。最特別的是富含豐富的貝類化石(連結)。

最後一類是河口和河岸景色。河口最大的特色就是河上橋樑建設和河道上捕魚設施。早期交通建設不發達時,河流兩側難以聯繫,隨著西濱公路和國道興建,網路聯繫更為便捷,也促進了經濟發展。

中港溪口

溪口等待捕撈魚苗

路線選擇上,不同區域有不同特性,桃園只能沿著西濱公路,新竹縣市沿著濱海休閒路網,苗栗則是鄉下農路,即使如此,能力許可內都會試著走道海濱跑跑看,軟沙很難前進,高灘處經過太陽曝曬就比較好跑,在最親近海岸處跑著,會有種獨特感受。(瀏覽Google街景,有多段海岸徒步路線)。

水泥化

根據統計,全台灣海岸線自然海岸的占比約為百分之五十五,我跑的新竹市(香山)只有百分之四,苗栗縣則是百分之二十四(連結)。也就是說,站在沙灘向陸地回望時,看到水泥設施的比例,非常非常高(包括消波塊和堤防)。

海岸的水泥化早在過去數十年內即已普遍展開。各級政府為了防止海岸土地流失,或是解決淹水治理,都投入大量經費,進行水岸水泥化。河堤、海堤、消波塊,厚厚一層的水泥,完全沒有毛細孔,完全無法呼吸,只剩下掩蓋、窒息。 水泥帶來的僵固感總讓我感到困惑,整排的消波塊和海堤總讓我想起Bernd & Hilla Becher的作品。(連結)




發電

發電廠,桃園林口發電廠(連結 外觀雄偉,壁畫是原生種百合花),桃園大潭發電廠(連結 跑到這裡實在很累,沒力氣拍照),苗栗通宵發電廠(連結 跑到這裡實在很累,沒力氣拍照)。都是無比壯觀。

陸上風電和離岸風電都快速建設中,也是新竹以南最常見的景致。景光還有詳細介紹(風神壇 連結)。

苗栗外海

竹南公路邊,強風吹襲

太陽能發電,路上發電板少,較奇特是後龍水尾里滯洪池,有一大片水域型太陽能發電系統(連結),也是奇觀。


最有效的太陽能系統,攝於談文

軍事設施

過往海邊的哨所,靠近海岸的大多已經頹圮,其他大多數會在稻田中和居民共存。

海岸線常見的田間碉堡

海巡的一些安檢所,極少數成為觀光休憩站(永安綠色隧道、十七公里賞蟹步道),其餘大多封存。

更大型的軍事設施就是雷達站,路邊經過可見的有崎頂海水浴場旁,以及外埔漁港附近。另外,竹北北方有一大片區域被設定為軍方砲擊區,若是要跑海濱得特別注意(連結)。

墳墓堆之間的外埔雷達站

觀光休閒

許多路線都是被修整的步道

鳳坑沙灣(連結)

望海秋千架

談文登高望遠景點,後有來探訪

其他

小工具連結(由google路線轉成GPX)。

2023年1月25日 星期三

慢跑紀錄:由苗栗大湖跑上雪見

報名了三月初的南橫馬拉松60公里活動(連結),怕開天窗,積極籌備模擬練習跑。檢視新竹附近距離和爬升數據相仿的首推大湖沿苗61號公路經司馬限林道至雪見景區路線。幾年前曾單車騎行此路線(連結),這次換用不同方式上山,也是新體驗。

大湖鎮位於台三線上,屬於封閉型的盆地,雪見風景區位於其東北方30公里處,沿途由西向東遞升。連結村鎮的公路在低海拔時大多沿河修建,河道平坦處遍植草莓。中間高度是竹林和梅花。後段最高則是人造森林。

離開了熱鬧街區後,映入眼簾就是廣大的草莓園。大湖盛產草莓,灌溉水圳滋養的不是常見的稻米,而是大片草莓園。藍天白雲下,一顆顆鮮紅小草莓在錄道中探出頭來,吸引著目光,等待著假期各地遊客蜂擁前來採摘。

雖說是來跑步的,但路邊景致總是不斷吸引我駐足拍照。大湖鄉客家人口佔九成,反映在環境上,處處是勤勞節儉的"古樸"畫面,例如下面這張照片是路旁水圳的搗衣區,非常有歷史感。

充滿歷史感的路邊搗衣區

正在曬著鹹菜的古錐阿婆,去程和阿婆聊天說地,回程時又巧遇她在收,被她塞了好多鹹菜解渴。



鄉間踽踽獨行

縣道旁,充滿幸福感的住家

續行,經小南勢、大南勢到中興,高度漸次上升,兩旁景觀也由草莓園和丘陵,轉變為溪水掩映的山景,路邊住宅不多,有幾間小型農產加工廠。

過了中興,地勢轉變進入山區,住民結構也先前淺山區漢人不同,為泰雅族原住民。行政區也由大湖改為泰安鄉。中興村設有派出所和國小,泰興國小牆邊有著美麗的壁畫。



滿是瘡痍的山豬圖紙

沿著竹林和幾個髮夾彎,抵達西北方司馬限部落,部落在一片竹林中,舊時因颱風整村數百人遷移組合屋中,目前已拆除興建永久屋,預計今年中完成。

泰安鄉為苗栗原住民鄉,這次經過的中興村和梅園村是所轄八村之二,中興村屬於後龍溪流域北五村,梅園村則是大安溪流域南三村之一(連結)。原住民的生活,以桂竹筍、李子、薑和草莓為大宗(連結)。不過,到處可見露營區的招牌,或許露營區收益遠高於農業收入。

司馬限部落

部落中總是能見到教會蹤跡,此處亦然。教堂座落在林道邊,遠遠就會被十字架吸引。

部落附近還可見到1979年建立的教堂(應該被上述新教堂取代),簡樸精緻的房舍,隱身於密林間,建物屋頂三角形與後方山巒形狀相契合,顯的沈穩堅實。

教堂門口有銘石簡單介紹,最後一句是。

盼望神的國度復興在這個教堂

自己是無神論者,對天主教和基督教的神蹟無法接受。但因為,媽媽、妹妹;外公外婆都是基督教徒,自己國高中六年就讀於台中衛道中學是典型天主教學校校內修士(連結)的影響。耳濡目染總會感受到,天主教和基督教強調神愛世人的精神。更明顯的例子是閱讀丁松青神父散文時,他們將人生歲月奉獻給偏鄉的心情,與我日常接觸的世俗生活,著實有明顯不同。

盼望神的國度復興在這個教堂

再繼續,經過金達路那邊Kingtaru,這邊有個路邊休憩棚、露營區(資料提及為部落督拿可家族發起),以及司馬限禱告山。類似禱告山偶爾會出現在山嶺間,印象中蘭嶼、東北角、箭龍陵邊有,這處算是容易到達的。入口就在休憩棚正對面,踩著石梯往上然後真正向上"爬"十幾分鐘竹林路到小山頂,無展望,到是能從縫隙中俯瞰正在施工中的司馬限部落住宅區。資料上提到司馬限部落民國75年開始地層下陷(原址位置不明),不知道何時開始在現址搭設組合屋(參觀過),兩三年前決定在此搭建永久屋,也就是目前的工地(連結)。

再往後一點就是新興村,此村南倚司馬限山,北眺洗水山,兩山之間是經年累月沖刷而出的大湖溪上游。村子腹地廣大,種植李子、薑和草莓。現在正有有由對岸跨越溪流到此的大橋,未來新興村會成為泰安北五村(八卦、錦水、清安、大興、中興)和南三村(梅園、象鼻、士林)的溝通孔道。

從新興村到雪見有北部和南部兩條路線,兩條路線都跑過,南側(梅興聯絡道)開發程度高,有幾個大型農園,棚架為白色,辨識度非常高、露營區,沿途更有竹林遍布,不知為何地形起伏非常大,跑起來很痛苦。北側是司馬限林道,路徑原始,常見到成群獼猴頂上樹枝跳躍,甚至還有不知是藍腹鷴或帝雉的大鳥(中央有全白色羽毛)穿越路徑(速度實在太快)。林道末端還有廢棄林道( 有大湖溪 連結,出口在更高處)。

從地理位置看,林道在背陽面和山坳內側,整體感覺較陰暗,路線平緩尤其全線約十公里都無人煙,屬於好跑的路段。最後一個迴轉在山嶺間移動,翻越山脊後就由背陽的大湖溪流域進入向陽的大安溪流域。與南側梅興聯絡道合併,若有需要可在涼亭稍微休息。

後段道路兩側原生林夾道,視野隨道路方向可眺望氣勢雄偉的雪山西陵,許多轉角更能俯覽壯闊的大安溪溪谷,氣勢雄偉變化萬千。也因此,此為日治時期重要的軍事地點,設置了二本松駐在所(當時駐在所前有兩棵松樹所以稱為二本松),附近丸田砲台是武力鎮壓原住民的歷史遺跡。

只是景色雖美但坡度是變態的陡,每次髮夾彎都是一次痛苦的折磨,第一次挑戰時,因為對路線的未知感,讓我在界碑前五百公尺終於受不了選擇當步兵,到界碑後折返。第二次有了準備,用小步輻之字形慢慢前進,才通過界碑(觀賞雪山西稜線最佳的地點)。

雪見是個被山林包圍的小區域,小小腹地設有展覽中心和休憩露臺,露臺被參天的柳杉與香杉包圍,靜坐其中真能感受安靜沈謚的氛圍。而原本的司馬限林道在此轉了個大彎,由柏油鋪面真正轉為林道,向前跑了幾百公尺就折返,或許之後會再向前到東洗水山、北坑山登山口。(另外補充,此處還能通行到觀霧雷達站)。


2023年1月10日 星期二

筆記:電池

各種電池

碳鋅電池

空載端電壓1.5V。項目有A4 A5 E90。

鹼性電池

鹼性電池是以鋅為陽極、二氧化錳為陰極、氫氧化鉀為電解液構成的電池,空載端電壓1.5V。鹼性電池可以說是碳鋅電池的改良版,它用高濃度、高活性的氫氧化鉀取代碳鋅電池中的氯化銨作為電解液,再加上陽極、陰極材料的改善,使得鹼性電池可以輸出比碳鋅電池更大的電流,在同樣的體積之下也具有較大的容量。(連結)。產品可以分為金頂或是勁量。型號分成。三號、四號、五號、六號。

鹼性:LR44

直徑 11 mm、厚度 5.4 mm。

高電壓電池

應該是疊合了好幾個鹼性電池,例如23A(或是23A),連結,很多放在鐵捲門遙控器。

連結

鋅空氣電池

目前使用在助聽器等等長效裝置上,容量大、放電也大,使用上,使用前要拔掉貼紙。

鋰電池:一次性鋰電池

CR2016/2025/2032,電壓3V,存放電流300mah,自放電也低,缺點是最大放電電流低。CR2032R有R表示最大放電電流高的意思,連結。可到50mA。

鋰電池:可充電鋰電池

鋰離子電池和鋰聚合物電池(LiPO)是不同的東西(連結 連結 連結)。特性是重量輕,自放電低,電流大,和鎳X比較起來,價格也便宜許多,是現在也是未來潮流。探究其原理,和傳統電池以電子的轉移為主不同,鋰電池內部是通過鋰離子在層壯物質的晶體中的出入,發生能量變化發電。在正常充放電情況下,鋰離子的出入一般只引起層間距的變化,而不會引起晶體結構的破壞。所以鋰電池是一種理想的可逆電池。但過放時,將導致負極碳過度釋出鋰離子而使得其片層結構出現塌陷,而對鋰電池的正負極造成永久的損壞,過度充電則將太多的鋰離子硬塞進負極碳結構里去,而使得其中一些鋰離子再也無法釋放出來。而且這過程中,容易產生氣體,導致電池膨脹,也就是平常戲稱的懷孕(大肚子)啦。

鋰電池內部結構

從結構來看,中間電解質又分成兩種,液態就是鋰離子電池,固態就是鋰聚電池,前者3.6V有漏液危險很少人使用了,後者安全且有更大放電能力已經普及。不過,電池廠商為了能在更小空間放入更大量單元,除了增加堆疊的密度外,就是讓中間薄膜變更薄,無形中就增加爆炸危險。

手邊幾種鋰電池,片狀型可用在四軸飛機和小型開發板。


產品上,有兩種包裝,第一種是V3.7,第二種是V4.2,如果兩片疊合在一起,就有下面幾種組合。3.7(1S) 4.2(1S) 7.4(2S) 8.4(2S) 11.1(3S) 12.6(3S) 每多一個S,就是正極多一條線。容量較單純,僅是影響重量和使用時間。一般小四軸大概300mAh,約三分鐘吧,價格約一百至兩百。大一點的,就是上千,時間約十幾分鐘。

C數:電池內部電組,一般應用上是容量乘上C數等於該電池可以提供的"電流數",例如300mAh*35C=0.3(A)*35(C)=10.5A,C數越高,表示內部電組越小,外部可用電流越高,某種程度就是越高越好,價錢當然越貴。但也不是每個人都要開賓士去菜市場買菜吧。一般35C就很好用。插頭,好像有三種吧,T插,JST XH,小白頭。Desire Power 7.4V 460mAh

手邊電池

手邊片狀鋰電池
  1. 最重要是,要有保護電路板
  2. 上左是某個ARDUINO實驗用,3.7V
  3. 上中是奶油蒼蠅用,3.7V,300mAh,可能已經老化要重購
  4. 上右是WHOOP95使用,7.4V,460mAh,一百六。實測只能飛五分鐘以內,若是860mAh,長寬相同,高從原本9mm變成15mm,重從30g變成46g。雖然會影響靈敏度,且容量雖然增加,但需要更高的油門來維持高度,所以飛行時間不會是正比例。目前已到手,有結果再更新。但這追求效率和重量的過程,不免讓我想到智慧型手錶的設計難處。整機中,最重但也最難移除的,往往是電池啊。
  5. 下方是11.1V 1850mAh,應該老化了。約六百
  6. 電池賣家:賣家1,賣家2 (內文提及尺寸標示)。
  7. 最近多半使用18650,電壓約4。價格和容量及安全性成比例。

鋰電池充電設備

鋰電池什麼都好,就是使用和保存上麻煩,甚至到嬌貴程度,充電時不能過充,使用時不能過放,保存時最好是維持在一定程度電壓保存。充電的機制有理論邏輯,下面是具體的實體項目。

若要處理多顆電池,並聯要注意下面內容 as paralleled cells behave like one larger cell. Charge time will be longer, accordingly. Just be sure the cells you are paralleling are of the same make/model/capacity/state of charge/age and don't parallel more than the manufacturer's limit (normally 3 or 4 cells.為安全起見,乖乖的用外部充電器一顆顆慢慢充吧。串聯的方案,晶片(連結),這是三顆18650的教學影片(連結)。

B6

不包含變壓器(B6AC有AC就是內建變壓器)。使用方式可參考(YOUTUBE ,文字說明)。

B6充電器

鋰電池充電可分成兩類,基礎CHARGE和進階BALANCE。CHARGE的程序。接好兩邊電源(接口有防呆,鋰電池端口則是正接正,負接負)。

  1. 設定,按下最左邊BATT TYPE,持續按按鈕直到畫面到達LIPO( 鋰聚電池 )。按下右邊ENTER進入模式,選擇項目為CHARGE,0.1A,2S。確認完畢後。
  2. 充電,因為用非常低的電流充電0.1A,至少要半小時。充電原理是,充電器端用高一點的電壓逐漸充入並且確認電池電壓達到標準,接著再拉高充電電壓。鋰電池宣告為3.7,充飽電壓為4.2。因為是兩顆串聯,目標自動設定為8.4。
  3. 結束,觀察右上方數字,會逐漸增加直到8.4,到達後系統發出巨大提示音,可按最左邊STOP,或直接拔電源)。

BALANCE的機制,串聯平衡充電(連結)。實際充電時操作方式如下。目前WHOOP95電池都是以0.5A 7.4V2S平衡充(記得要把另外的接頭插上)。最左邊選到鋰聚後,最右邊進入設定,中間兩個按鈕選擇到,0.5A 7.4V2S平衡充。再最右邊按鈕長按,選擇START,就會開始充電,充的時候可以按中間兩個確認狀況(分別是目標電壓和各個S電壓)。直到單片充到4.2或總合8.4就會自動降低電流數字,直到發出聲響。提高安培值可以加快速度但不建議,1C就是XX mAh的千分之一,1100mAh的用1.1A是最保險。雖然號稱5C充電,但不需要那麼高數字。

TP4056

這個討論在電子部分有提到,自己桌子上就有好幾個,也有些應用例如18650充電器。

電池特性:放充電

放電介紹完整(連結),解答存在許久的問題。電池的放電是依循某個模式逐漸下降。中間會因為停止使用而逐漸恢復電壓。但到某個程度後,會快速衰退。2032的最大脉冲放电电流为12mA,连续放电电流小于等于4mA。
連結

充電部分,鋰電池充電如下圖(資料來源是Arduino 實現USB Type-C 雙向快速充電行動電源),有起步狀態,穩定電流充電狀況,穩定電流充電狀況。


2023年1月4日 星期三

ATMEL SAM4S

電路板V1

  • 開發板 Board 100 ( #39 )
  • MCU board110 (SAM4S8B)
    • ICE為 ATMEL SAM-ICE  ( 排線有圈圈有顏色那端,靠近下方,由上面正視 )
    • PC軟體為IAR Embedded Workbench IDE
    • CODE在IAR完成後,透過ICE送進MCU。
    • RESET MCU
      • 右下方有個RESET按鈕,按下PCB右邊LED燈會有反應。
      • 系統重啟。
    • RESET MCU
      • 拔除電源和ICE連結
      • 連結MCU版面上右下方的CONNECTOR
      • 通電,等待五秒鐘
      • 拔除電源,拔除右下方的CONNECTOR,放在一邊
  • 板上SAFETY MCU (最新被移除)
    • SAFETY MCU會控制MOTOR開關。
    • 如果要跳過SAFETY MCU控制MOTOR開關,下圖跳線方式,是直接將PCB上電源直接拉到MOTOR電源開關,等於設定ON。這種連結法,會持續浪費2mA左右電源。
    • 第二種方式,MAIN MCU JP9(MCU內側),連結到SAFETY MCU JP97(MCU 外側),這種方式不會浪費電源。
    • SAFETY MCU也會控制BUZZLER開關。
    • 直接控制BUZZLER的方式,JPR8-NO(左側),連結到SAFETY MCU JP99(MCU 外側)。
  • 版上BLE MODULE (最新被移除)。

開發板電源(左下方及中間)

  • 左下下方,左邊是AC/DC進入。
  • 左下下方,右邊是JTAG,右邊可以更進一步插入排線時,由上面正視最左邊是黑色, 另一端接USB。顯示DEBUG訊息,這是利用TX/RX,作法是,打開"設定",搜尋"裝置管理員",確認USB的項目是COM2,然後打開一個PUTTY,設定為COM2,38400,SERIAL,進行連線,可在畫面看到數值。
  • 軟體部分要設定Globals/GlobalSettings.h,設定為#define DEBUG_MESSAGE_OUTPUT    1。寫資料的方法是 PrintDebugString("\r\n########## -- Value = x"); PrintDebugU32Hex(value);( 這還有另外一個define )
  • JTAG用REMOTE CONTROL控制系統運作。(目前較少使用)
  • 左下方,下面是外部供電,上面是電池供電( 包括電池盒、一顆鋅空心 )。
    左方,有個SUPERCAP邊緣是要不要使用SUPERCAP( 目前是取消的狀況 )
  • 電源處理:中下DC/DC LDO


    • LDO,也是DC/DC的一種,線性穩壓器。Low Dropout的簡稱,是即使輸入輸出間電位差低,依然可以運作的線性穩壓器。亦稱作低損耗型線性穩壓器和低飽和型線性穩壓器。

INPUT(中下方)

中間下方兩個,分別是BUTTON 1 BUTTON 2
在APP程序中,同時按下,就會驅動模擬注射程序。(同時按下是考慮使用安全)
同時長按 => 聽到長回應,準備開始
同時短按連續三下 => 聽到短回應(三下)
同時短按,當作確認  => 聽到長回應,系統會依照剛剛輸入時間長度運轉馬達

PI SENSOR
板子中間區域有個小型PI SENSOR,PI的連結線有三個
1.輸出:系統電源,要單獨打開
2.輸出:PI光照電源,這是PWM,要設定頻率和開啟PWM
3.讀入:ADC數值

OUTPUT(中上)

BUZZLER
LED

馬達(右方)

步進馬達,如照片般運作。
透過4 PIN,打開白色在上面,四個電極接腳向下。

也可以用PIN拉到其他步進馬達。DC馬達(空心杯也相同),使用2022/12/27版本軟體,拉線方式如圖。

開發板V2

從MCU上面向下看,上方為BUZZER和MOTOR,右上方為TX RX區域。

TX RX PC端的線上面黑色為GND,由GND向下數,倒數第二為黃( 接到右上方的最右邊)  倒數第三為橘( 接到右上方的右邊數來第二個 )
PUTTY 38400 serial COMX。MOTOR最外面,接到馬達負極。
實驗的電池是501218 廠商說80mah 網路上看到65mah
JTAG的連線方式,先拔掉JTAG端,和電源。
測試連結正確性,然後調整電表,轉到檢測連通的部分,然後按最右邊的那個按鈕
正的探針,連結GND,負的探針依序連到每一個(六個)的接觸點,都要聽到聲音才行。
JTAG連結到PC那端,JTAG編號一那個部分,連結到PC端一。
連線順序,JTAG和PCB的對應方式是,以PCB右上方為第一個,對應到的是JTAG的第二個,2 6 1 5 3  4。JTAG最後一個是GND。

開發環境 IAR

IAR是單一軟體架構下,不同MCU就有不同安裝檔案。配合硬體安裝 IAR for ARM 7.10.1(HAPPY)。解開IAR for ARM 7.10.1\IAR_EWARM_710 安裝畫面選擇Install IAR Embedded Workbench 然後就是一路裝下去。抽屜有Dongle但占用USB太麻煩,選擇打開EWARM_7.10_License,依照說明把Selected.package放在C:\ProgramData\IARSystems\LicenseManagement\LicensePackages\ARM\EW\1\     (If the path doesn't exist, create it manually.) 打開MAIN_MCU_20230502  \ MAIN_MCU \ Build_infrastruction \ Firmware

IAR製做空專案可以參考(連結)

執行download and debug,updating build tree,系統會自動檢查專案中各程式碼是否有被更新,若有就compile,最後打包送入MCU。因為很少用debug功能,都是直接GO。後續把ICE拔開,系統重開後也會進入運作程序(這是我要的)。

IAR之外,atmel也有提供開發軟體AtmelStudio(7.0),可自動產生出driver。

GPIO等設定

kerneldriver.c
Kernel_SetCPUPowerUpPinState
    SetCPUPowerSavingPinState (); //configure PortA, PortB, PortC as GPI Pull-Up
        把功能轉換 例如ERASE和另外..
        MATRIX->CCFG_SYSIO |= (CCFG_SYSIO_SYSIO10|CCFG_SYSIO_SYSIO11);
        設定CLK
        PMC->PMC_PCER0 = PMC_PCER0_PID11|PMC_PCER0_PID12|PMC_PCER0_PID13;
        設定pull high
        PIOA->PIO_PPDDR = 0xFFFFFFFFUL;
        PIOB->PIO_PPDDR = 0xFFFFFFFFUL;
        PIOC->PIO_PPDDR = 0xFFFFFFFFUL;
        PIOA->PIO_PUER = 0xFFFFFFFFUL;
        PIOB->PIO_PUER = 0xFFFFFFFFUL;
        PIOC->PIO_PUER = 0xFFFFFFFFUL;
        PIOA->PIO_ODR = 0xFFFFFFFFUL;
        PIOB->PIO_ODR = 0xFFFFFFFFUL;
        PIOC->PIO_ODR = 0xFFFFFFFFUL;
        PIOA->PIO_PER = 0xFFFFFFFFUL;
        PIOB->PIO_PER = 0xFFFFFFFFUL;
        PIOC->PIO_PER = 0xFFFFFFFFUL;
    // Configure pins  整個的對應表放入
    PIO_Configure(PowerUp_Pins, PIO_LISTSIZE(PowerUp_Pins));
    //Enable Pull-down Register  部分拉回LOW
    PIOA->PIO_PPDER = PIO_PA11 | PIO_PA12 | PIO_PA26;
kerneldriver.h

SW設計

下面是LAMINGO為主,搭配後來的WIPOC調整。
APPLICATION_LAYER
    MAINLOOP
        MAINLOOP.C      真正執行的位置在REMOTE CONTROL裡面,這裡就是去執行這個REMOTE CONTROL FUNCTION,而且是啟動後一秒鐘之後才開始,使用YH

DRIVER
    HARDWAREDRIVER
        ADCDRIVER    YH改了很多,但都是配合新的PCB調整,使用原本
        IDSDRIVER  YH改了LED燈部分,為了SYNC,使用YH
        KERNELDRIVER  整個MAPPING,兩個不同PCB這裡差異最大,使用原本
            LED部分,先用WIPOC的概念
            MOTOR部分,搭配MOTOR的啟動,有兩個新項目,SOLOPB也要拉線
GLOBAL
    VERSION    YH改了一點,使用原本
SERVICE_LAYER
    COMMANDINTERPRETER
        CommandExecutor    YH借用,修改部分,使用YH
            BLESleepMode 呼叫了Controller2_Button1Pressed
        Controller2.c    YH沿用原本APP,並且加入新流程,使用YH但要修改
            Controller2_Button1Pressed
                OneFunction4Demo
        Controller2_fkt.h    YH沿用,使用YH
    EEPROM
        二進制不同,不重要
    IDSENGINE
        IDSENGINE.c  YH小修改,使用YH
    KERNEL
        INTERRUPT   YH修改,對應按鈕功能等等,使用原本
    POWERMANAGEMENT
        POWERMANAGER  YH將ifdef等等重新整理,但功能沒特別改變,使用原本
    SYSTEMSTATE
        SYSTEMSTATE  使用YH
    SYSTEMTIME
        RTC_RTT 雖然目前修改沒有實際用處,使用YH
    USERINTERFACE
        ILED_evtdef  使用YH
        ISLD_evtdef  使用YH
        KEYBOARD  使用原本
        LED  使用YH

EVENT DRIVEN

目前本體是event driven但是,實驗實驗是用個大的寫死的function控制全部流程。這部分要繼續修改。

測試機制

因為是event driven,所以理論上是可以方便測試的,但還沒有實際組合起來。可以避開上面的UI,直接用C#寫對應的virtual function測試程式。同時還包括YH提到要修改的LIB等等。

UART原理

UART的程式位置在XXXX,透過TX RX溝通。

UART應用

UART應用有兩組,通訊組UART0:當成Console或是DVT測試(前面提到的測試機制)。程式範例 Source\Service_Layer\CommunicationDrivers\SlimIrDA

藍芽組:UART1。程式範例 Source \Service_Layer \CommunicationDrivers \BLE。配合event driven結構IBLEDriver_evt,實際連結是BLEDriver

  • timer:StartTimerOfSendData StopTimer
  • 主要流程:BLEDriver_ModuleEventHandler
  • IBLEDriverEvent_eBLEModuleConnectRequest BluetoothLE_SendConnectRequest

  while(1)
  {
   if(BluetoothLE_BLEUartTxFrame((uint8_t)BLECMD_CONNECT, (uint8_t*)NULL, (uint8_t)0))
      break;
  }
這個的細部功能是
    放好表頭
    g_mBLEBgHandleData[ 0] = BLE_UART_HEADER;
    g_mBLEBgHandleData[ 1] = BLE_UART_HEADER_XX;
    g_mBLEBgHandleData[ 2] = 3 + nDataLength;
    g_mBLEBgHandleData[ 3] = nCommand;
    拷貝資料
    memcpy(&g_mBLEBgHandleData[ 4], pnData, nDataLength);
    處理checksum
    for(i=0; i<(4 + nDataLength); i++)
    {
      nCheckSum += g_mBLEBgHandleData[i];
    }
    nCheckSum = 0xFFFF - nCheckSum;
    g_mBLEBgHandleData[4 + nDataLength] = (uint8_t)(nCheckSum & 0x00FF);         // BLE-Uart CheckSum
    g_mBLEBgHandleData[5 + nDataLength] = (uint8_t)((nCheckSum >> 8 ) & 0x00FF); // BLE-Uart CheckSum
    塞好結構
    g_mBLEUartStructTx.nTxLength = 6 + nDataLength;
    g_mBLEUartStructTx.pnTxPointer = &g_mBLEBgHandleData[0];
    BluetoothLE_UartTxFrame((uint8_t*)&g_mBLEUartStructTx);

        真正和UART溝通,後面是call back
UARTDriver_SetTransmitCallbackFunction (UartInterface_eUart1, BLE_Callback_TXC);
這邊帶入的是UART1 (BLE) 就回到前面寫的

  • IBLEDriverEvent_eBLEModuleSendDataWithoutACK BluetoothLE_SendData

    if ((mg_nLastRawCmd == RAWCMD_SPEC_bGRECORD) || (mg_nLastRawCmd == RAWCMD_ALL_bGRECORD))
    {
        if (CurrentNumberofBgRecord >= 0)
        {
            mg_TransferDataAfterRawAck = bTRUE;
            IBLEDriver_AllocateBLEModuleTransferRawDataEvent(ModuleId_eBLEDriver, ModuleId_eBLEDriver);
        }
    }

  • IBLEDriverEvent_eBLEModuleReceiveFrameComplete memcpy(&anTempBuf, &anUartBuf, 20); BLE_CommandParser();
  • IBLEDriverEvent_eBLEModuleRawDataParsing StopTimer (); memcpy(&anRawBuf, &anTempBuf, 20); BLE_HostCommandParser();
  • IBLEDriverEvent_eBLEModuleTransferRawData StartTimerOfSendData BLE_TransferDataToHost

BLE_TransferDataToHost
BluetoothLE_SendBLEUart_BgNumberOfResult
  while(1)
  {
  if(BluetoothLE_BgHandleTxFrame((uint8_t)BGCMD_TRANSFER_NUM_BG, (uint8_t*)&nNumberOfResult, (uint8_t)2))
  break;
  }
BluetoothLE_SendBLEUart_BgSpecifiedResult
  while(1)
  {
  if(BluetoothLE_BgHandleTxFrame((uint8_t)BGCMD_TRANSFER_BG_RESULT, pResultData, (uint8_t)8))
  break;
  }

    pData[0] = BG_HANDLE_HEADER;
    pData[1] = nCommand;
    pData[2] = nLength;
    memcpy(&pData[3], pnData, nLength);
    pData[3+nLength] = BG_HANDLE_TAIL;

    BluetoothLE_BLEUartTxFrame((uint8_t)BLECMD_RAWDATA, pData, nLength+4);



  • aaaaaa
  • bbbbb
  • ccccc






實際演練加入I2C

1.從atmelstudio對應位置拿出需要的檔案,放在目前架構中。確認編譯OK
atmel系統中,不叫i2c,叫做Interface for configuration the Two Wire Interface (TWI) peripheral.
位置在MAIN_MCU\Build_infrastruction\Firmware\Lib_Sam4s8b\include。拷貝到應該的目錄,用add files的方式放進去,但才發現,其實原本專案已經有這些。
2.系統連結
可能流程(連結)
從data spec來看
Datasheet\MainProcessor\ATMEL SAM4S(20140527) 文件中

使用的線路


看起來是有兩組TWI,時序資料如下
從範例來看,有兩種版本
原始版本,聽說是atmel studio 6.1版本(以前?)系統配合有的範例目錄,就是上面提到的MAIN_MCU\Build_infrastruction\Firmware\Lib_Sam4s8b\include
A   比較簡單的範例是 連結
  pTwi->TWI_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
  TWI_ConfigureMaster(pTwi, TWI_CLOCK, VARIANT_MCK);

  TWI_StartRead(pTwi, ADDR_B, TOBJ_1, 1);
  lB = readByte();
  hB = readByte();
  TWI_SendSTOPCondition(pTwi);
  pec = readByte();

uint8_t readByte() {
  while (!TWI_ByteReceived(pTwi))
    ;
  return TWI_ReadByte(pTwi);
}
找不到實際使用範例,決定放棄

B  twi之外,目錄還有twid,挑選常用function,TWID_Read  temperature,在github中尋找有兩種資料
像是MAIN的部分   像是運作的部分  很單純,沒有任何init的動作就開始運作( 哪一組則是另外找了範例 TWID_Initialize(&twid, TWI0); )
繼續找了實際用LIS3DSH的範例( 連結  實際產品範例連結 ),感覺搭湊起來還有個樣子
後面程式會用這個方向繼續下去,不是YH提供的方法

C  過程中YH在atmel studio 7.0附屬的檔案中發現有另外一組程式
asf-standalone-archive-3.52.0.113\xdk-asf-3.52.0\sam0\drivers\i2c
我們使用的應該是master( not slave )  not interrupt ( 所以會是polling 也就是i2c_master.c )
現在沒有往這個方向找,這份文件應該就是討論這組內容(連結)

3.加入APP控制.h中的檔案
硬體結構,只要兩條線。第一組部分線路被占用,直接使用第零組。
PA3 JP36 (右邊)   DATA
PA4 JP56 (右邊)   CLK
有設定的方式
這兩行是新加上去的
#define PIN_NA_PA3      {PIO_PA3,  PIOA, ID_PIOA, PIO_PERIPH_A, PIO_PULLUP}
#define PIN_BLE_INT_MCU {PIO_PA4,  PIOA, ID_PIOA, PIO_PERIPH_A, PIO_PULLUP}
流程可能是下面( ARDUINO版本,做法應該類似 )參考範例(連結)
LIS3DSH 範例一   (比較有參考性)

#define LIS3DSH_CTRL_REG3    0x23
#define LIS3DSH_CTRL_REG4    0x20
#define LIS3DSH_CTRL_REG5    0x24
#define LIS3DSH_CTRL_REG6    0x25
#define LIS3DSH_OUT_TEMP      0x0C
#define LIS3DSH_OUT_X_L      0x28
#define LIS3DSH_OUT_X_H      0x29
#define LIS3DSH_OUT_Y_L      0x2A
#define LIS3DSH_OUT_Y_H      0x2B
#define LIS3DSH_OUT_Z_L      0x2C
#define LIS3DSH_OUT_Z_H      0x2D
#define LIS3DSH_FIFO_CTRL_REG 0x2E

/*arduino example lis3dsh
// 0x0F = 0b00001111
// Normal power mode, all axes enabled, 50 Hz ODR
writeReg(LIS3DSH_CTRL_REG4, 0x5F);
// 200 Hz antialias filter, +/- 2g FS range
writeReg(LIS3DSH_CTRL_REG5, 0x80);
// configure FIFO for bypass mode
writeReg(LIS3DSH_FIFO_CTRL_REG, 0);
// disable FIFO, enable register address auto-increment
writeReg(LIS3DSH_CTRL_REG6, 0x10);
*/  
LIS3DH  範例二  (比較沒有參考性)
 5 #include <Wire.h>
 7 #define ADDRESS_LIS3DH 0x19
 8 #define CTRL_REG1 0x20
 9 #define CTRL_REG4 0x23
10 #define CTRL_REG5 0x24
11 #define STATUS_REG 0x27
12 #define OUT_X_L 0x28
13 
14 byte buffer[6];
15 byte statusReg;
16 
17 boolean ready = false;
18 int outX, outY, outZ;
19 int xVal, yVal, zVal;
20 
21 void setup()
22 {
23 Wire.begin();
24 Serial.begin(9600);
25 delay(5); //5 ms boot procedure
26 
27 // reboot memory content, to make a clean start
28 Wire.beginTransmission(ADDRESS_LIS3DH);
29 Wire.write(CTRL_REG5); 
30 Wire.write(0x80);
31 Wire.endTransmission();
32 
33 delay(5);
34 
35 //set ODR = 1 Hz, normal mode, x/y/z axis enabled
36 Wire.beginTransmission(ADDRESS_LIS3DH);
37 Wire.write(CTRL_REG1); 
38 Wire.write(0x17);
39 Wire.endTransmission();
40 
41 //set BDU= 1, scale = +/-2g, high resolution enabled
42 Wire.beginTransmission(ADDRESS_LIS3DH);
43 Wire.write(CTRL_REG4); 
44 Wire.write(0x80);
45 Wire.endTransmission();
46 }
47 
48 void loop()
49 {
50 // read STATUS_REG
51 while(ready == false)
52 {
53 Wire.beginTransmission(ADDRESS_LIS3DH);
54 Wire.write(STATUS_REG); 
55 Wire.endTransmission();
56 Wire.requestFrom(ADDRESS_LIS3DH, 1);
57 if (Wire.available() >= 1)
58 {
59 statusReg = Wire.read();
60 }
61 if (bitRead(statusReg, 3) == 1) //new data available
62 {
63 ready = true;
64 }
65 delay(10);
66 }
67 
68 if (bitRead(statusReg, 7) == 1)
69 {
70 Serial.println("Some data have been overwritten.");
71 }
72 
73 //read the result
74 Wire.beginTransmission(ADDRESS_LIS3DH);
75 Wire.write(OUT_X_L | 0x80); //read multiple bytes
76 Wire.endTransmission();
77 Wire.requestFrom(ADDRESS_LIS3DH, 6);
78 if (Wire.available() >= 6)
79 {
80 for (int i = 0; i < 6; i++)
81 {
82 buffer[i] = Wire.read();
83 }
84 }
85 
86 //calculation
87 outX = (buffer[1] << 8) | buffer[0]; 
88 outY = (buffer[3] << 8) | buffer[2]; 
89 outZ = (buffer[5] << 8) | buffer[4]; 
90 xVal = outX / 16;
91 yVal = outY / 16;
92 zVal = outZ / 16;
93 
94 Serial.print("outX: "); Serial.print(xVal); Serial.print(" ");
95 Serial.print("outY: "); Serial.print(yVal); Serial.print(" ");
96 Serial.print("outZ: "); Serial.println(zVal);

實際演練設定GPIO

要控制五個GPIO,對應表如下
PA27 JP23  ERASE
PA28 JP52  XX28
PA29 JP49  XX29
PA30 JP41
PB13 JP46
程式架構上,原本event driven之外,還有service觀念。
ModuleList.c
{ModuleId_eKeyboard, Keyboard_ModuleSetup, Keyboard_ModuleEventHandler, Keyboard_ModuleSyncEventHandler},
    keyboard.c
    Keyboard_ModuleSetup
        UserKeysInterruptCallback
            UserKeysPinChangeCallback
                Key12PressedCallback
                    Key12HeldCallback
                        TimerCallback4Demo
interrupt,入口是
KernelDriver.h
//PA15,GPI,BUTTON_SW
#define PIN_BUTTON_SW   {PIO_PA15, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP} //Falling Edge, L(0) is pressed.
//PA2,GPI,VIAL_SW (Vial Locker)
#define PIN_VIAL_SW     {PIO_PA2,  PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP} //Falling Edge, L(0) is pressed.
//PA14,GPI,BODY_SW (Body Sensor)
#define PIN_BODY_SW     {PIO_PA14, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP} //Falling Edge, L(0) is pressed.
//PA5,GPO,DUMMY_EN (Dummy Load)

interrupt.c
放入Key_Pins
要先enable
Interrupt_EnableExternalInterruptPortAKeyBoard  注意還有Interrupt_DisableExternalInterruptPortAKeyBoard
    這種結構可以寫成這樣
    PIOA->PIO_AIMER  = PIO_PA15|PIO_PAXX;
PIOA_IrqHandler  這是系統原始設定,會進入的點
    ExecuteInterrupt(InterruptVector_eExternalPortAKeyBoard) ;  從這裡就會進入到上面service