2018年2月26日 星期一

常聽音樂集錦

人的五官中,眼耳鼻舌口,耳為第二項。相對於眼的空間感,耳在人的抽象思維上,扮演著更吃重的角色。音樂的定義和類型這麼多,私自認為,能自己演奏(唱)或現場聽最好。聽CD、廣播或Youtube及串流音樂,稍嫌被動,只是怡情養性,較難表現自我。

以下是平日常聽音樂列出,數量多且都是單曲為主,當然心中知道好音樂是要一系列聽下來才能有深刻感受,不過網路音樂當道,單曲還是比較吃香。

轉換動作是依靠 YOUTUBE轉換成音樂檔。若論到音樂品質,轉換取樣率是192kbps,雖然比不上Spotify提供的320kbp或CD直接燒錄成無損WAV或FLAC,對我這木耳也是足夠。

演奏


節奏強


岸部真明吉他演奏曲,Time Travel,聽著就能想像自己在青海湖邊騎單車的景緻。這是練習連結
youtube : 連結
Local檔名 : (純音樂)Masaaki Kishibe岸部真明-Time Travel時光旅行

把愛找回來電影原聲
youtube : 連結
Local檔名 : Bari Improv - August Rush

Alan Walker的成名洗腦歌,因為女兒的關係幾乎被聽到爛,類似壞掉音樂結構,讓人印象深刻。
youtube : 連結
Local檔名 : Alan Walker - Fade [NCS Release]
這是演唱版本,當個參考 youtube : 連結 Local檔名 : Alan Walker - Fded

火神咒 傳統北管曲牌的重新演繹 收尾融合東西風 (同片CD還有風入松 民俗風又太過了)
youtube : 連結
Local檔名 : 生祥樂隊 - 火神咒

功夫配樂 闖將令
youtube : 連結

情感動人

偏向比較低迴吧
貝多芬大公三重奏,四個樂章,層次豐富且動人。讀海邊的卡夫卡時文中提及,介紹
百萬三重奏1 
Local檔名: Beethoven Piano Trio No 7 Archduke - 1st (Rubinstein Heifetz Feuermann)  強烈復古,各自獨立  11:52
百萬三重奏2 
Local檔名: Beethoven Piano Trio No 7 Archduke - 2nd (Rubinstein Heifetz Feuermann)   06:14
百萬三重奏3 連結
Local檔名: Tercer Movimiento Archiduque 10:31
百萬三重奏4 連結
Local檔名: Beethoven Piano Trio No. 7 Archduke Cuarto Movimiento 06:20
和所有古典樂相同,名曲總有多種版本流傳。有些清晰、動人,有些較早錄製,收音品質濛濛,但聽久仍喜愛這耐聽演奏法。四樂章 : 連結 下載後檔名 IMSLP74472-PMLP19591-beethoven_o97n7  美國SOLISTI : youtube : 連結 Local檔名 : 貝多芬鋼琴三重奏 大公三重奏   都因為太甜被移走。

孟德爾頌的第64號e小調小提琴協奏曲,溫柔激昂兼容。三大小提琴協奏曲之一 美女小提琴家希拉蕊.韓 演奏。
youtube : 連結
Local檔名 : Mendelssohn Violin Concerto E Minor OP.64 (Full Length)  Hilary Hahn  FRSO

貝多芬第五號 諸大明演奏,(還在尋覓piano concerto @2 -3. Moderato 諸大明 簡文斌 NSO 專輯 樂典 04 盧炎)
youtube : 連結
Local檔名 : Daming Zhu Plays Beethoven Piano Concerto No.5 Emperor

拉赫曼尼諾夫,衝突與激情的代表
youtube : 連結
Local檔名 : Rachmaninoff plays Piano Concerto 2

柴可夫斯基 小提琴協奏曲 第一樂章。是電影常客也是比賽名曲
youtube : 連結
Local檔名 : 海飛茲 柴可夫斯基小提琴協奏曲 第一樂章

巴赫的夏康舞曲,「Partita no.2 BWV1004 (1720)」小提琴獨奏


旋律優美

坂本龍一合集,老婆非常讚賞他作品,多年前就看"音樂即自由",耳濡目染也愛上了。這曲算是集錦,前面就很好聽,而24:12開始的christmas鋼琴提琴版,(網路還有宇多田光翻唱吉他Kaori Muraji 村治佳織)。今年有中文字幕記錄片上映,這是影評
youtube : 連結 
Local檔名 : Ryuichi Sakamoto (坂本龍一) _– 1996

君的名子電影配樂,口嚼酒。
youtube : 連結
Local檔名 : 你的名字bgm - 口嚼酒之行 (Your Name Kuchikamizake trip)

haruka nakamura 中村遼 鋼琴   類似內在風景的音樂實在相當吸引我,覺得生命被豐富了
youtube:連結
Local檔名:Live at Arumakan - AMC Vol.9 - haruka nakamura Session
加入提琴 根本 理恵  youtube:連結
Local檔名:Live at Arumakan - AMC Vol.9 - haruka nakamura音楽のある風景 アルマカンver
youtube:連結 LOCAL還沒下載


Zbigniew Preisner 著名作曲家
youtube : 連結
Local檔名 : Zbigniew Preisner - Danse Macabre

Max Richter - On the Nature of Daylight 馬克思.李希特,極簡主義作曲家,哀傷。連結
youtube : 連結

棉花糖人,marshmello。女兒推薦歌單。有個形容很好,他用電音傳達正面力量。這首音樂很好懂,節奏也相當的慢(好像剛醒來的感覺)。充滿了很容易吸收的元素。
youtube : 連結
Local檔名 : Marshmello - Summer (Official Music Video) with Lele Pons

舒伯特 蘭德勒結構 366 是個可當早餐陪襯的好音樂
youtube : 連結
Local檔名 : Schubert - Ländler D.366 - Richter Paris 1961

Mozart 類似牧歌作品,充滿田園風光
youtube : 連結
Local檔名 : Mozart -  Clarinet Concerto In A Major K 622 Adagio

梁祝,小提琴名家吕思清版本。甜死人但就是好聽。
youtbue : 連結
Local檔名 : 梁祝小提琴协奏曲 - 吕思清 (指挥:夏小汤) Butterfly Lovers Violin Concerto - Lü Siqing (conductor Xia Xiaotang)

雲雀高飛,有梁祝東方精神的小提琴協奏曲。
可以想像雲雀在山谷間盤旋高升的畫面,喜愛。還至和女兒提到,未來就以此當成灑骨灰時的背景音樂吧
youtube:  連結 連結
Local檔名: The_Lark_ascending_-_Ralph_Vaughan_Williams

泰伊思冥想曲,少年時期常聽廣播節目(尋夢園)的主題音樂,現今來聽實在太甜。
youtube : 連結
Local檔名 : 泰伊思冥想曲  帕爾曼
另外還有 經典版 youtube : 連結   二胡版本 youtube : 連結  就沒下載了

德布西 月光,抒情音樂代表作
youtube : 連結
Local檔名 : 德布西 月光

here there every where : 這是FRIENDS某集中,菲比結婚橋段,用鋼鼓演奏出here there every where的旋律。雖然這應該屬於搭配影像才適合看的方式,不過FRIENDS伴隨著我成長(裡面 i will be my something blue 更是有趣)
youtube : 連結
Local檔名 : Friends Phoebes Wedding

時間機器time machine類似史詩節奏
youtube : 連結

舒曼兒時情景,各段落解說
youtube : 連結
Local檔名 : 舒曼 兒時情景

久石讓音樂不錯,但還是沒有阪本龍一好聽,阪本的東西有宏大的基礎感。動畫音樂因為有故事加持,比較屬於洗腦音樂。
Summer
youtube : 連結
魔法公主
youtube : 連結
youtube : 連結
神隱少女
主題 The Name of Life 白龍找自己名子 連結  演唱
片尾 Always With Me : 連結 演唱 難得的幸福感

花樣年華
youtube : 連結

演唱



偈 民歌時代最具文學味作品
youtube : 連結
Local檔名 : 王海玲【偈】Official Lyric Video

好樂團,這種聲音,只能說是天賦
youtube : 連結
Local檔名 : 好樂團 GoodBand ─《我把我的青春給你》Official Music Video

好樂團,主唱假音飄啊飄,是首關於無助(無奈?)的音樂
youtube : 連結
Local檔名 : 【好樂團 GoodBand】-我們一樣可惜 Demo

忘我的愛

Hello Nico- 接下來如何
youtube : 連結
Local檔名 : Hello Nico- 接下來如何

蘇打綠 當我們一起走過
youtube : 連結

倆忘煙水裡,喜歡很大原因是黃霑的詞,還有天龍八部和少年時期記憶的重疊
youtube : 連結
Local檔名 : 倆忘煙水裡 關正傑關菊英

原著民
Lulimai 細雨灑落群山,出自"歌,飛過群山"第三首。真誠人聲對自然的禮贊與感恩,同時也是治癒靈魂的聲音。youtube介紹
歌詞  Lu qu li ma yi yi na qa ya qa qu yi yi ma lju lja qa yi nu ua yi
1.Di masu yina dimasu qama, qa qusu sa sa qa mi li mi lin
妳是哪個家族的女孩?為何如女神般美麗?
2. Tu sa yi ve yi ge ma tu qu wan ki ni qa va qa re qe nge ran
灑落群山的細雨,是想念妳而流下的眼淚。
youtube : 連結
Local檔名 : LULIMAI

卑南族除草歌,聲音嘹亮轉折優美,渾然天成
youtube : 連結
Local檔名 : 20121013 PuyumaMowing卑南族除草歌

青蛙的眼睛


外語英
All I Wanna Do,原為HEART(紅心)單曲,Halestorm用更猛烈的硬式搖滾翻唱。女主唱甜美外表和渾厚嗓音衝突但又和諧。因為這首歌,可能得選有重低音的喇叭才行啊。
youtube : 連結
Local檔名 : Halestorm - All I Wanna Do (Is Make Love To You)

艾爾頓強,有搖滾樂界的莫扎特之稱,這首歌雅俗共賞,歌詞,尤其是自己越來越懶的為老婆準備小禮物,聽來更是愧疚啊。
youtube : 連結
Local檔名 : Elton John - Your song

Father and Son
youtube : 連結
Local檔名 : Father And Son - Rod Stewart

白日夢冒險王中配樂,隨著時鐘點滴,體會時間流逝
youtube : 連結
雲端備份 : 連結
Local檔名 : José González - Stay Alive

Journey樂團成名曲 很好的情歌,對當時漂泊的樂團下了很好的註解
youtube : 連結
Local檔名 : Faithfully (Official Video)

here there every where : Beatles Paul McCartney小品,憂鬱中帶點輕快。
Local檔名 : Here There and Everywhere (Take 14)
最早是Friends中非比結婚音樂(連結 連結),讓我覺得未來女兒結婚我也可以彈奏歐(連結)
Paul老年版本也很好(連結)
日本女生的東方版本也很喜歡(連結)
年輕人版本也很好(連結)

LOST STAR 抒情電影中獨特假音
youtube : 連結
Local檔名 : Adam Levine - Lost Stars

BEE GEES熱門歌曲,歌曲單純到不太耐聽,純粹因為有年少記憶啊
youtube : 連結
Local檔名 : Bee Gees - You Win Again

小紅莓 cranberries 主唱空靈又沙啞唱聲
youtube : 連結(這個不能下載) 連結
Local檔名 : The Cranberries - Linger (Acoustic Version)

if you leave me now ,Chicago合唱團經典曲,抒情名曲
youtube : 連結
Local檔名 : Chicago - If you leave me now - 1977 (HQ)

O MIO BABBINO CARO我親愛的爸爸
Hayley Westenra youtube : 連結
這首歌有眾多版本 聲樂式 例如荷蘭小女孩Amira Willighagen youtube : 連結  和 Maria Callas 1965 youtube : 連結 都很好,但Hayley版本 更為耐聽
LOCAL 荷蘭達人秀天使女孩:Amira Willighagen:O Mio Babbino Caro (中文字幕)

LOVE OF MY LIFE
QUEEN
連結  這個影片被看2億次了
韓國J.Fla COVER 連結


外語日

解憂雜貨店reborn,女聲,只能說太好聽
youtube : 連結
Local檔案 : 「REBORN」(セリver.)

日本民謠红蜻蜓
youtube : 連結
Local檔名 : 日本童謡-《赤とんぼ》(红蜻蜓)



音樂觀


世上音樂這麼多,哪些是我喜愛的音樂呢?這牽涉到個人音樂觀,像我等庸才,大致不會脫離下面三個條件。
1.旋律好聽
2.洗腦歌,大多都是太普遍化且沒有個人特色,僅是迎合市場需求的作品,可是放久了,就像果凍般凝固在腦中。
3.青少年期記憶,這其中不少作品,以現在標準看來都太甜了,不耐聽,但好歹也是伴隨成長啊。
類型上則是演奏和演唱都很愛,但前者偏愛程度漸增。

廣義來說,音樂是聲音的一種。同樣是聲音,語言和音樂就有很大差別,語言是天生必備的項目,需要學習才能生存。音樂和宗教很像,並不是必備能力,也很難以言語形容。不需要言傳,卻可以有相當大的感染力。在編曲人豐富的創作與想像力之下,我們荒無的生命,總是如同被啟發,深深被吸引。心會平靜。所以有句話說,音樂始於文字衰退之時(where words fail, music speaks),就是這個意思吧。

就因為音樂有如此廣大魔力,即使是最憂鬱嚴肅的人,獨處時,哼上一兩段自己懷想的小旋律,也是種幸福和安慰。所以我相信,情感可說是音樂的最終目的。

另外,這幾年跟著老婆接觸不少現代藝術,也漸漸開始接觸幫助冥思及潔浄心靈,讓自己靈魂超脫的現代音樂,篇幅比較多,另開篇章

2018年2月21日 星期三

[小說集]星塵Stardust

StarDust

作者 尼爾·蓋曼 是說故事高手,尤其魔幻與冒險題材更是他的強項。趁著年假,一口氣看完電影和原著小說,既有大螢幕的緊張刺激,又兼顧文字的雋永趣味,雙重享受,十分過癮。

故事背景是十六或十七世紀的英國鄉間,一座名為WALL的小鎮開始,這裡的農民平日忙於耕種和採集,是恪守基督教義和社會禮法的老實人,我們知道這種封閉性格,日後成為了現代社會的基礎,但當時還在中期,人們對這世界外還存在的魔法世界,並沒有全盤否認,不過這個情形維持不了多久,人類世界邊緣已經建起道石牆,這是一個很重要的分界線,區分著人類這邊的世界跟那邊的世界。WALL小鎮就在這彼此唯一缺口旁,倚靠著九年才出現一次的魔法市集,讓彼此仍然互相知悉。

不像很多小說一開頭就落落長一大段,作者只用逐漸封閉的石牆、以及人類立下的種種規定,隱喻固步自封的心態。所以隨著男主角為了愛而跨了界線,因為追逐著星星而啟動的冒險歷程,也可以說就是我們對魔法世界最後的想像。

雖然那個世界,有與我們相同的峽谷、平原、森林、高山。不過卻四處充滿著自然靈。他們相信大地是從混沌中產生,而山脈是由夸父巨人倒下後生成。天上星星各有靈性,甚至會被打落墜入人世,變成人型。

植物有靈,所以樹木可互相溝通,動物有靈,所以像獨角獸之類通靈神獸也不稀奇。除人外,精靈與女巫遊走各地。甚至人死去的靈魂,也是存在。人類本身,過著農耕漁牧的村莊生活,雖然受到暴風城堡領主的管制,但仍然自由。這個充滿"自然靈"的世界,就是作者建構的世界。雖然沒有提到文化和歷史,給人的印象也有些原始,卻是異常生猛有力。

在這世界中旅行,無疑要經過許多飢餓、艱險、傷害的考驗。男主角從來不是執意要面對,但臨到了頭上,也只能硬著頭皮上了。一次次,靠著自己的努力,和他人協助,從稚嫩青年轉成為勇敢擔當的成年人。到這又變成成長小說。

看著作者對想像中的生物的描述跟覺得不可能出現的東西,真是覺得神奇和不可思議。對年紀已經漸長,常覺得世事平凡無奇的我來說,好的奇幻小說總讓我想著,世上,還有這麼多地方沒看過,那麼多人要認識,還有要看的風景,更不用提陪伴愛我與我愛的人成長。自然就會湧起樂觀活力。

既然兩者都看了,也順便比較原著和電影版本。小說文筆雋永讓人愛不釋手,電影為配合劇情需要,對捕雷海盜船做了很大改動,終段還加入了女巫魔法大戰,雖然稍嫌誇張,卻也讓內容更為緊湊富有娛樂性。尤其推薦片中風景,美麗且讓人神往。

--------------

最後,節錄電影中,女主角對著變成睡鼠男主角的獨白

You know when I said I knew little about love? That wasn't true. I know a lot about love. I've seen it, centuries and centuries of it, and it was the only thing that made watching your world bearable. All those wars. pain, lies, hate... It made me want to turn away and never look down again. But when I see the way that mankind loves... You could search to the furthest reaches of the universe and never find anything more beautiful.

So yes, I know that love is unconditional. But I also know that it can be unpredictable, unexpected, uncontrollable, unbearable and strangely easy to mistake for loathing, and... What I'm trying to say, Tristan is... I think I love you. Is this love, Tristan?

I never imagined I'd know it for myself. My heart... It feels like my chest can barely contain it. Like it's trying to escape because it doesn't belong to me anymore. It belongs to you. And if you wanted it, I'd wish for nothing in exchange - No gifts. No goods. No demonstrations of devotion. Nothing but knowing you loved me too. Just your heart, in exchange for mine.

你知道嗎,當我說不懂愛情的時候,那不是真的.
關於愛情我知道很多,我看到過了,看了幾百年了.
唯一能支撐我繼續,看著人類世界的東西,就是愛.
所有的戰爭,痛苦,謊言,仇恨,這些東西想讓我轉過頭去,不再往下看,
我就是來看人類是如何愛的.
我是說,你可以到遙遠的世界的深處去尋找,卻找不到比愛更美的東西,
所以,是的,我知道愛是無條件的,但我也知道愛是不可預知的,無法預料的,無法控制的,無法忍受的,
奇怪的是,愛很容易被錯認為是憎惡.
Tristan,我想說的是...我認為我愛上你了.
我的身體幾乎不能包容住我的心了,好像它不再屬於我了,而是屬於你.
如果你要的話,我會無償的給伱,不需要禮物,不需要條件,不需要證明,什麽都不需要.
我只要你愛我.只要你的心.換取我的心.

2018年2月8日 星期四

技術筆記 微型影像模組


我的左眼

以往提到影像模組,浮上的印象就是WebCam搭配PC執行OpenCV,提供防盜監視或停車場車牌辨識。這些年,硬體技術進步,設備上除了CMOS影像外,還加入如LIDAR和紅外線雷射,軟體上更有強大CPU和GPU、大量訓練資料庫、日益普及的類神經網路模組幫助。讓自駕車在複雜天候和路況中自動行駛,萬千人海中的人臉辨識也成為可行。可以預見的是,這進程將會越來越快,影響層面也會更廣。

但也因為設備和軟體平台專門化,這領域也將成為大公司才能進入的領域。以價格便宜、體積小、功耗低取勝的微型影像模組,必須更專精於自己領域,才能在像白堊紀時,地表上都是大恐龍橫行狀況下,找到個陰暗角落,努力爭取生存空間。

光源與影像


微型影像模組第一種特色就是,輸入光源和影像數量的多樣化。

紅外LED。Leap Motion。C# SDK HACK。最近類似產品是DepthEye 3D visual TOF Depth Camera。價格200美元(好貴啊)
Provide Pointcloud  and RAW depth data
FOV(D* H*V ) :90 * 75 * 59
2 850nm band infrared LED
TI OPT8320 sensor

紅外邊射型雷射LD,例如自己曾經參考過CSK的鍵盤專案就是利用這種直線性雷射光,用亮點形狀偵測位置和距離。常聽的商業工具是LIDAR。CSK的陳士凱有個陽春版本RoboPeak,後來延伸為恩嵐,算是窮人版本LIDAR。

掃描出來的空間地圖

紅外面射型雷射VCSEL。從KINECT開始,就以此種雷射發射結構式紅外雷射,分析拍攝畫面後,就可以取得各點的距離深度。最近的APPLE FaceID也是運用相同原理。

結構光是上述技術的延伸,除紅外雷射外也可採用DLP技術的3D投影出來,Opto有量產品。原理是將數位光圖形 (digital light pattern) 投射在物件上,再利用相機從已知的位置角度拍攝光圖形,以三角量測的方法取得3D數據。投射的光圖形通常是黑白相間的光條。


程式上,最基本範例可以參考這裡

最後是模擬兩眼立體視覺的方案,這也是我現在公司主力產品。兩張圖片依照相同方式找出特徵點,接著計算這兩組點的偏移位置,就可以建構距離模型。參考 項目 範例 YOUTUBE位置 。中文 介紹1 介紹2 介紹3


辨識能力


MCU能達到的辨識能力。

1)規則式比對,如OptRec(STM32)的OCR辨識。

2)統計式(數學式)比對,如HAAR辨識。這篇文章對OpenCV能達到的程度有完整介紹。OpenMV範例。

Eigenfaces

OpenMV

3) 類神經網路比對,如Google AIY的TensorFlow架構,連結
使用INTEL的圖像處理晶片 Movidius MA2450,或是 Orange Pi(文章介紹),完整DIY步驟如下。有了 Google 提供的 3 個基於 TensorFlow 的神經網路模型,用 Vision Kit 進行 DIY 的裝置能夠識別上千種常見物品、識別面部表情或探測拍攝到的人、貓和狗。Google 還提供了 Vision Kit 的模型編譯工具,這樣您就可以在工作站或任何雲服務上用 TensorFlow 對模型進行的訓練和再訓練。

Google AIY

類神經網路其他範例,例如movidius。若嘗試以STM32來運作,最有可能是移植計算的部分,讓複雜的Train交給大型電腦運作,資料存入MCU,MCU只負責算分。

1) STM:複雜運算、奇怪的平台機制  這兩個都不太可行

2) TENSORFLOW:google給手機用的、正在尋找範例,或是這裡
最近更是看到一個介紹,Google提供的TensorFlow Lite for Microcontrollers(連結),直接在Cortex M3就能執行TensorFlow啦,就連OpenMV都有可能可以使用(連結),實在太特別。

3) CAFFE移植CAFFE

其他


幾個可能應用例子工廠案例。

2018年2月7日 星期三

技術筆記 MicroPython


印表玩具
   STM32技術

說明


Python是基本程式語言,可直譯,也可編藝執行。而Micro Python就是運行在MCU上的Python 3(github)。MCU上有完整Python詞法分析器,解析器,編譯器。可離線運行,也可透過命令動態互動。非常適合做時間緊迫,運算複雜度高的應用。缺點是,MicroPython本身佔據不少記憶體空間,MCU上記憶體錙銖必較,或許會有排擠效應。

英文說明如下
MicroPython (GRPL-uPython) is a rewrite of the Python 3.4 programming language tailored for STM32 devices. It offers on-chip compiler, virtual machine and runtime to enable the rapid prototyping of applications. Extension modules provide direct access to the peripherals of the STM32 device. Custom components written in C or C++ can easily be integrated.

移植版本


目前MicroPython可運行於類unix系統、PIC16、ARM、esp8266等平台。STM部分,各種型號的支援程度不同。這裡有目前為止支援的MCU列表。詳細說明在這。分列如下:

1)401開發板,CANNON藍芽開發板

2)405,The pyboard reference development board is a small form-factor electronic circuit board based on a STM32F405 running MicroPython on the bare metal. The STM32 peripherals are exposed via a set of Python functions and classes.

3)407開發板

4)429開發板,有方案,沒套件

運作架構


使用Micro Python需要先產生出空的main.c。
類似空的框架中,INIT和PYTHON_C的對應都會被建立好。main函數位於stmhal/main.c  MCU啟動後進入main函數。

在main函數中大概是初始化MCU的時鐘、各種外部IO的setup,然後執行python的垃圾回收器gc_init(), 初始化python對象列表,相當於啟動了python的虛擬機。

後面緊接着啟動了python的REPL,bind到uart,允許使用者通過外部串口來執行python代碼。

f_res = f_stat("main.py", NULL);
// Parse, compile and execute the main script.
pyexec_file("main.py");
// If there's no script ready, just re-exec REPL
while (!usbdbg_script_ready())
{
    // run REPL
    pyexec_friendly_repl();
  牽涉CONSOLE交互作用的部分,從這個連結可以看到
}
if (usbdbg_script_ready())
{
    // parse, compile and execute script
    pyexec_str(usbdbg_get_script());
}

MicroPython安裝與使用


大致了解後,再來看安裝與使用方式。下載並安裝GNU Tools for ARM Embedded Processors。
sudo apt-get install gcc-arm-none-eabi
window系統下載並安裝ST的DfuSe軟件。
下載MicroPython的源碼,micropython-master.zip
展開MicroPython源碼,打開 stmhal\boards\ 目錄


新建一個CANNON目錄,將NUCLEO_F401RE下的文件複製到CANNON目錄下
在Terminal中進入micropython-master\mpy-cross目錄下

輸入編譯:make
進入micropython-master\stmhal目錄下,輸入 make BOARD=CANNON,就可以編譯了。不過這時編譯出的代碼是不能運行的,因為兩個板子的參數不同。

打開 stmhal\boards\CANNON目錄,先修改文件stm32f4xx_hal_conf.h
找到#define HSI_VALUE    ((uint32_t)8000000)
將數字8000000改為16000000,因為小鋼炮使用了16M的外部時鐘
打開文件 mpconfigboard.h
找到#define MICROPY_HW_CLK_PLLM (8)
將數字8改為16
修改#define MICROPY_HW_HAS_SWITCH  (1)
將1改為0,因為小鋼炮上沒有用戶按鍵
修改#define MICROPY_HW_LED1             (pin_A5) // Green LD2 LED on Nucleo
將pin_A5改為pin_B3,因為兩個板子的LED使用不同的GPIO
修改#define MICROPY_HW_LED_ON(pin)      (mp_hal_pin_high(pin))
將 (mp_hal_pin_high(pin))改為 (mp_hal_pin_low(pin)),因為電路驅動電平不同
修改#define MICROPY_HW_LED_OFF(pin)      (mp_hal_pin_low(pin))
將 (mp_hal_pin_low(pin))改為 (mp_hal_pin_high(pin)),因為電路驅動電平不同
添加下面RTC的定義
// The pyboard has a 32kHz crystal for the RTC
#define MICROPY_HW_RTC_USE_LSE      (1)
#define MICROPY_HW_RTC_USE_US       (0)
#define MICROPY_HW_RTC_USE_CALOUT   (1)
添加UART1
#define MICROPY_HW_UART1_TX      (pin_A9)
#define MICROPY_HW_UART1_RX       (pin_10)
修改SPI1的NSS引腳
#define MICROPY_HW_SPI1_NSS      (pin_A4)
打開文件pins.cvs,這裡預定義了GPIO的名稱
修改LED的GPIO為PB3
修改SW的GPIO為PC13

現在可以再次編譯source code。編譯時建議在Linux下編譯,因為速度快很多,在windows下編譯速度很慢,需要等數分鐘。

準備3個短路塊,連接P1,將BOOT0連接到VCC,BOOT1連接到GND。
將開發板用macroUSB線連接到計算機,因為設置了BOOT0/BOOT1,所以上電後會進入DFU模式。在Windows下如果是第一次使用,會提示安裝驅動,驅動程序就在DfuSe軟件的安裝目錄下。使用DfuSe打開編譯後的dfu文件,並下載到開發板。


從開發角度來看,MicroPython因為結合Python和C,IDE部分,KEIL和uVision都找不到可能的編譯方式。似乎得用gcc編譯。

真正使用時,對話型式的開發環境:

1) openmv有提供一個整合環境( QT產生 )  這是個非常有吸引力的方式。

2) 網路上還有uPyCraft ( 通用型 ) 可以對應處理幾種不同的開發板。

使用方式:透過Python語言控制系統


ESP8266有許多範例,OpenMV操作相似。

因為Micropython已經把開發板各個模組都移植完畢,所以可以直接用Python來控制embedded system,根本不需要加入任何C語言與硬體有關語言,可以快速寫出應用系統。

打開一個串口終端軟件,如kitty、xshell、超級終端等,設置波特率為115200,就可以開始玩micropython了。
先試試直接控制LED
import pyb
pyb.LED(1).on()
pyb.LED(1).off()

在試試用GPIO控制LED。
from pyb import Pin
led=Pin.cpu.B3
led.init(Pin.OUT_PP)
led.value(1)
led.value(0)

用PWM控制LED的亮度
from pyb import Pin, Timer
         
tm2=Timer(2, freq=100)
led=tm2.channel(2, Timer.PWM, pin=Pin.cpu.B3, pulse_width=100)
led.pulse_width_percent(100)
led.pulse_width_percent(1)

呼吸燈
# main.py -- put your code here!
from pyb import Timer, Pin

tm2=Timer(2, freq=200)
led=tm2.channel(2, Timer.PWM, pin=Pin.cpu.B3)

# LED breathing lamp
ia = 1
da = 1
def fa(t):
    global ia, da
    if (ia==0)or(ia==100):
        da=100-da
    ia=(ia+da)0
    led.pulse_width_percent(ia)

tm1=Timer(1, freq=100, callback=fa)

stm32f4如何使用SD

如何製作開發板,第一步,以C程式製作LIB


OpenMV為範例。

若有需要純軟體,例如opencv或是未來的dither,核心C程式,會以LIB形式編譯完成,將interface轉為python可以呼叫的項目,讓Python mapping使用。

例如face_eye_detection.py 內
face_cascade = image.HaarCascade("frontalface", stages=25)
img = sensor.snapshot()
objects = img.find_features(face_cascade, threshold=0.5, scale=1.5)
for face in objects:
    img.draw_rectangle(face)


對應的可以使用的LIB在src\omv\py\py_image.c

static const mp_map_elem_t globals_dict_table[] = {
    {MP_OBJ_NEW_QSTR(MP_QSTR_HaarCascade), (mp_obj_t)&py_image_load_cascade_obj},
};

而對應的function是
mp_obj_t py_image_load_cascade(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
  cascade_t cascade; //這是opencv的結構了
  // Return micropython cascade object
  py_cascade_obj_t *o = m_new_obj(py_cascade_obj_t);
  o->base.type = &py_cascade_type;
  o->_cobj = cascade;
  return o;
}

如何製作開發板,第二步,針對不同開發板,架構MicroPython與硬體對應關係


畢竟不是每個硬體都已經被PYTHON包含,要如何讓板子上的裝置讓PYTHON可用。以DAC為例。啟動之後單片機底層的操作通過micropython-master\stmhal\hal\f4目錄下的HAL驅動來完成,那幺在串口敲下的命令又是如何調用底層的驅動的呢?

拿簡單的DAC來説,與之相關的文檔為micropython-master\stmhal\下的dac.h, dac.c, dac.x文檔聲明並定義了MicroPython board DAC類的方法與屬性,通過MP_DEFINE_CONST_FUN_OBJ_KW或MP_DEFINE_CONST_FUN_OBJ_x等註冊給MicroPython的內建對象。比如下面的函數:pyb_dac_write()函數調用STM32 的HAL lib實現硬件的操作,通過MP將此函數註冊為pyb_dac_write_obj

/// \method write(value)
/// Direct access to the DAC output (8 bit only at the moment).
STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) {
pyb_dac_obj_t *self = self_in;
if (self->state != DAC_STATE_WRITE_SINGLE) {
DAC_ChannelConfTypeDef config;
config.DAC_Trigger = DAC_TRIGGER_NONE;
config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
self->state = DAC_STATE_WRITE_SINGLE;
}
// DAC output is always 12-bit at the hardware level, and we provide support
// for multiple bit "resolutions" simply by shifting the input value.
HAL_DAC_SetValue(&DAC_Handle, self->dac_channel, DAC_ALIGN_12B_R,
mp_obj_get_int(val) << (12 - self->bits));
HAL_DAC_Start(&DAC_Handle, self->dac_channel);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_write_obj, pyb_dac_write);
最後將所有的方法註冊給MicroPython
STATIC const mp_map_elem_t pyb_dac_locals_dict_table[] = {
// instance methods
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_dac_init_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_dac_write_obj },
#if defined(TIM6)
{ MP_OBJ_NEW_QSTR(MP_QSTR_noise), (mp_obj_t)&pyb_dac_noise_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_triangle), (mp_obj_t)&pyb_dac_triangle_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write_timed), (mp_obj_t)&pyb_dac_write_timed_obj },
#endif
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_NORMAL),      MP_OBJ_NEW_SMALL_INT(DMA_NORMAL) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_CIRCULAR),    MP_OBJ_NEW_SMALL_INT(DMA_CIRCULAR) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_dac_locals_dict, pyb_dac_locals_dict_table);
const mp_obj_type_t pyb_dac_type = {
{ &mp_type_type },
.name = MP_QSTR_DAC,
.make_new = pyb_dac_make_new,
.locals_dict = (mp_obj_t)&pyb_dac_locals_dict,
};
該結構體在dac.h中聲明為外部變量:
extern const mp_obj_type_t pyb_dac_type;
#if MICROPY_HW_ENABLE_DAC
{ MP_OBJ_NEW_QSTR(MP_QSTR_DAC), (mp_obj_t)&pyb_dac_type },
#endif
因此如果想添加內建的對象或方法應該遵循如下的步驟與原則:
1. 創建mp對象:
const mp_obj_type_t pyb_led_type = {
{ &mp_type_type },
.name = MP_QSTR_LED,   ///name
.print = led_obj_print,       ///重載的print方法
.make_new = led_obj_make_new, ///構造函數
.locals_dict = (mp_obj_t)&led_locals_dict, ///該對象所擁有的方法字典
};

2. 創建方法字典led_locals_dict:


3. 實現方法
實現上圖中畫橫線的方法以及第一步中的重載的print方法,構造方法等。
4. 將mp對象pyb_led_type 添加到modpyb.c中的pyb_module_globals_table[]全局python對象表裏:{ MP_OBJ_NEW_QSTR(MP_QSTR_DAC), (mp_obj_t)&pyb_dac_type }

使用PYBOARD的範例。

編譯MicroPython
一般Build方式 連結
Docker 參考連結

2018年2月4日 星期日

技術筆記 OCR


印表玩具

OptRec專案之分析及測試
因為想多了解STM32在影像分析可達到什麼程度,開始在網路上蒐羅確實可行的範例。OptRec就是其中之一。這是位捷克研究生的碩士論文專案,篇名是Optical Recognition and Analysis for Home Metering。專案與OCR有關。區分成兩個階段。第一階段,是STM32和Camera互動範例技術報告。第二階段是完整流程。YouTube範例作者論文

功能很單純,就是透過鏡頭讀取畫面,送入OCR模組分析文字,再將資料顯示螢幕上,並且記錄入SD卡。互動方式使用觸碰螢幕。

GOCR原理


ocr_gocr : 是入口ocr_algorithm
    job_t job1, *job;
    job=OCR_JOB=&job1;
    // Picture buffer allocation
    img_buffer = malloc(crop_width*crop_height);
    img = malloc(crop_width*crop_height);
    grayscale
    // Assign picture to job
    job->src.p.p = img;
    job->src.p.bpp = 1;
    // Main OCR loop
    img2asc(job);   主要準備開始啟動
    印出結果
    // Free memory
    free_textlines(&(job->res.linelist));
    job_free_image(job);
    free(img);

運作的方式是JOB,可以簡單區分成下面步驟

  scan_boxes( job, pp );
從上往下,分別在X,Y軸方向投影,得到box list


  remove_dust( job ); /* from the &(job->res.boxlist)! */
  detect_barcode( job );  /* mark barcode */
  detect_pictures( job ); /* mark pictures */

所有box的平均寬度為avgwidth,平均高度為avgheight,符合box.width > 4 * avgwidth || height > 4*avgheight條件並且相近大小的box少於4個的box認為是圖像box。

  remove_pictures( job ); /* do this as early as possible, before layout */
  glue_holes_inside_chars( pp ); /* including count subboxes (holes)  */
  detect_rotation_angle( job );
  detect_text_lines( pp, job->cfg.mode ); /* detect and mark job->tmp.ppo */

Line detection is very important for good recognition. For example it is difficult to distinguish between lowercase letter p and uppercase letter P without having a baseline (same total height). The lowercase version of p has a depht (the lower end is below the baseline) and therefore its easy to distinguish from the uppercase version if the baseline is known. The line detection is responsible for finding the baseline of every text line.
Lines of characters are detected by looking for interline spaces. These are characterized by a large number of non-black pixels in a row. Image rotation (skewing) presents a problem, therefore the program first looks only at the left half of the image. When a line is found, the left half of the right side is scanned, because lines are often short. The variation in height gives an indication of the rotation angle. Using this angle, a second run detects lines more accurately. Line detection may fail if there is dust on the image.

  add_line_info( job /* , &(job->res.boxlist) */);
  divide_vert_glued_boxes( pp, job->cfg.mode); /* after add_line_info, before list_sort! */
  remove_melted_serifs( job, pp ); /* make some corrections on pixmap */
  glue_broken_chars( job, pp ); /* 2nd glue */
  remove_rest_of_dust( job );
  list_sort(&(job->res.boxlist), sort_box_func);
  measure_pitch( job );
  char_recognition( pp, job->cfg.mode);

gocr的識別不是機器學習式的學習,沒有training過程,完全靠先驗的規則,因此只能識別英文字符,數字,標點等。識別主要是一個filter鏈路,每個filter決定box是否是該字符,是則略過後續filter。

a,從box外引出一條射線從某個方向(左,右,上,下)某個坐標(x,y)向box內部,第一個交點位置必須符合某個字符的先驗規則;


 b,經過box的一條直線與字符的交點個數必須符合某個字符的先驗規則,算法:計算這樣的點(如從左向右:Pixel(x,y) = white && Pixel(x+1,y) = black ) 的個數


 c,孔洞的個數必須符合某個字符的先驗規則,比如A有一個洞;這一步只是判斷,實際工作在第5步已經完成。


  compare_unknown_with_known_chars( pp, job->cfg.mode);
  try_to_divide_boxes( pp, job->cfg.mode);
參考來源

各檔案列表
output : debug使用
unicode : 只是顯示文字

GOCR移植OptRec


硬體內容
  stm32f429 discovery (相同)
  ov7670 (相同)
  sdcard (具備)
軟體內容
  console tool chain (非keil)
  sdcard : fatfs
  ocr : GOCR v0.50

這功能在尋常桌機加OpenCV看來,實在是一塊小蛋糕。但在嵌入式系統,包含這個多程式碼,且有UI互動界面,實屬難得啊。分析模組如下。

main.c
   宣告許多起始動作
   控制流程
while(1){
     很特別的command dispatch架構
    /* TASK 1 - Home page display/refresh */
    if (Time_elapsed(200, &task_arr[1])){
        if (sys_mode == SYS_INIT) {
                // Display main page
                LCD_ILI9341_Button_DisableAll();
                Display_Home_Page();
                sys_mode = SYS_HOME;
            }
    }
      /* TASK 2 - Buttons/touch service */
     if (Time_elapsed(100, &task_arr[2])){
            // Home page buttons
            // - Manual mode
            if (button_pressed == BUTTON_MANUAL_MODE){
                LCD_ILI9341_Button_DisableAll();
                Camera_Enable();
                sys_mode = SYS_MANUAL_MODE;
            }
            // - Automatic mode
            else if (button_pressed ==  BUTTON_AUTOMATIC_MODE){
                LCD_ILI9341_Button_DisableAll();
                Display_Automatic_Mode_Page();
                sys_mode = SYS_AUTOMATIC_MODE;
            }
            // - Display data logs
            else if (button_pressed == BUTTON_DISPLAY_LOGS){
                LCD_ILI9341_Button_DisableAll();
                Display_Data_Logs_Page();
                sys_mode = SYS_END;
            }
            // - Settings
            else if (button_pressed == BUTTON_SETTNGS_MODE){
                LCD_ILI9341_Button_DisableAll();
                Display_Settings_Page();
                sys_mode = SYS_SETTINGS_MODE;
            }
            ...還有很多... 這種寫法很特別
     }
     /* TASK 3 - Clock display/refresh */
     if (Time_elapsed(1000, &task_arr[3])){
            if (sys_mode == SYS_HOME) {
                Display_Clock();
            }
     }
     /* TASK 4 - Battery voltage display/refresh */
        if (Time_elapsed(2000, &task_arr[4])){
            if (sys_mode == SYS_HOME) {
                Display_Battery();
            }
     }
}
包括一些callback的handler

/* DCMI DMA interrupt */
void DMA2_Stream1_IRQHandler(void){

/* LCD SPI interrupt */
void DMA2_Stream4_IRQHandler(void){

/* Button GPIO interrupt */
void EXTI0_IRQHandler(void) {
 
/* TOUCH GPIO interrupt */
void EXTI15_10_IRQHandler(void) {

其他程式

1)err_handler : 顯示一些文字,並且一直繞while

2)fatfs_control : APP用到的指令
fats_spi : 一開始設定
fat有個目錄有七個相關檔案

3)lcd_fonts : 字型resource
lcd_ili9341 : 畫圖畫線等
lcd_ili9341_button : 畫出按鈕,並且按下去會有相對記錄
lcd_spi : 設定和DMA等等
background : 印出圖片背景固定顏色

4)ov7670_control : camera固定設定

5)rtc_awu_control : RTC_AWU_SetDateTime RTC_AWU_GetUnixTimeStamp
     RTC_AWU_GetDateTime RTC_AWU_SetAlarm

6)system_control : init一堆東西 顯示各個不同畫面
stm32f4xx_it 固定寫法
system_stm32f4xx 固定寫法

7)touch_i2c : touch
touch_stmpe811

記憶體使用


是影像處理很重要的部分。
fmc_sdram : 只有init,真正使用應該是malloc 不過下載項目中沒有sct之類檔案
syscalls
* Modification of system memory management (e.g. malloc etc.).
* Simply moves heap region to external SDRAM.
* Important is to initialize FMC for SDRAM soon as possible.
* Optimized for 32F429IDISCOVERY board.
會換掉 _sbrk
caddr_t _sbrk(int incr) {
    static char *heap_end;
    static char *sdram_start = (char*) SDRAM_MEM_START;
    static char *sdram_end = (char*) SDRAM_LCD_START1;
    重點應該是 static char * 雖然是function內部變數,但
    char *prev_heap_end;
    // Modify system memory management
    if (heap_end == 0) {
        heap_end = sdram_start;
    }
    prev_heap_end = heap_end;
    if (heap_end + incr > sdram_end) {
        return  (caddr_t) -1;
    }
    heap_end += incr;
    return (caddr_t) prev_heap_end;
}

2018年1月31日 星期三

技術筆記 STM32 memory usage

STM32F100的電路圖,裡面包含著16k的flash memory

印表玩具

   STM32技術

自從使用C#或JAVA後,就不再關心記憶體配置了(這所謂的記憶體,不是pointer和leak的問題)。為了製作印表玩具使用的STM32,遇到許多記憶體操作問題。分別整理如下。

FLASH RAM原理


【動態記憶體(RAM)】與【唯讀記憶體(ROM or Flash)】是截然不同的。彼此關係,包括STACK和HEAP資料如下。



FLASH:
特性是拔電時,資料還存在著。資料也是區塊寫入讀出。
以前PC程式有硬碟可以存放程式,Keil編譯好的程式,就是直接放在這區。這裡面包括程式本體、resource、變數的宣告值等。資料讀出很方便,但是寫入很"麻煩"。
討論變數與flash的關係
1. int i = 100;  後面的100是要寫在 flash 中。程式啟動後會在RAM中設定 i ,然後從flash中拿出100放在一起。是compiler根據整個程式大小、最佳化等,東算西算決定放在這個位置。
2. const int i = 100; compiler就會將這個變數也會放在flash中(而不是RAM)

RAM:
特性是拔電時,資料就消失。資料可以某個位置直接寫入讀出。
這裡區分成三種資料,是程式運作中需要的項目,可以讀也可以寫。
1. global 變數
2. function 中宣告的變數,這會放在stack中
3. new malloc 的變數,這會放在heap中

這篇文章對記憶體使用有很清楚介紹。下面內容大多是從連結取得,當成筆記。

CODE、RO、RW、ZI Data域及堆棧空間
在工程的編譯提示輸出信息中有一個語句"Program Size:Code=xx RO-data=xx RW-data=xx ZI-data=xx",它說明了程序各個域的大小,編譯後,應用程序中所有具有同一性質的數據(包括代碼)被歸到一個域,程序在存儲或運行的時候,不同的域會呈現不同的狀態,這些域的意義如下:

    Code:即代碼域,它指的是編譯器生成的機器指令,這些內容被存儲到ROM區。

    RO-data:Read Only data,即只讀數據域,它指程序中用到的只讀數據,這些數據被存儲在ROM區,因而程序不能修改其內容。例如C語言中const關鍵字定義的變數就是典型的RO-data。

    RW-data:Read Write data,即可讀寫數據域,它指初始化為"非0值"的可讀寫數據,程序剛運行時,這些數據具有非0的初始值,且運行的時候它們會常駐在RAM區,因而應用程序可以修改其內容。例如C語言中使用定義的全局變數,且定義時賦予"非0值"給該變數進行初始化。

    ZI-data:Zero Initialie data,即0初始化數據,它指初始化為"0值"的可讀寫數據域,它與RW-data的區別是程序剛運行時這些數據初始值全都為0,而後續運行過程與RW-data的性質一樣,它們也常駐在RAM區,因而應用程序可以更改其內容。例如C語言中使用定義的全局變數,且定義時賦予"0值"給該變數進行初始化(若定義該變數時沒有賦予初始值,編譯器會把它當ZI-data來對待,初始化為0);

    ZI-data的棧空間(Stack)及堆空間(Heap):在C語言中,函數內部定義的局部變數屬於棧空間,進入函數的時候從向棧空間申請內存給局部變數,退出時釋放局部變數,歸還內存空間。而使用malloc動態分配的變數屬於堆空間。在程序中的棧空間和堆空間都是屬於ZI-data區域的,這些空間都會被初始值化為0值。編譯器給出的ZI-data占用的空間值中包含了堆棧的大小(經實際測試,若程序中完全沒有使用malloc動態申請堆空間,編譯器會優化,不把堆空間計算在內)。這裡提到如何看編譯後的檔案大小

FLASH RAM起動過程


程式起動後的動作如下

以int i = 100;這個例子來說,i是RAM,但是100是FLASH。此時又有一個問題出現了,上面的描述在使用時,100早就已經放在var裡面了,很明顯的,一定有一個東西把100放進去var那個RAM的位置。C-Language程式的進入點是main(),所以在main()之前,一定有一個東西做了很多事,讓C的程式能夠從main()開始順利運行,那個東西,叫做boot loader,換句話說,因為刻意的安排,CPU會先執行boot loader,等所有環境建立完成後,再進入main()。

當CPU通電開始執行時,依照CPU不同種類,一定固定由某個位置開始抓第一行指令開始執行,boot loader的第一行就放在這裡。依據CPU的複雜度,如ARM7,9就有專門的boot loader,可以做出很複雜的功能,例如可以用TFTP載入,單純的如8051的compiler:IAR51,因為事情很固定,它會自動幫你加上已經寫好的boot loader。

RW-data和ZI-data它們僅僅是初始值不一樣而已,為什麼編譯器非要把它們區分開?這就涉及到程序的存儲狀態了,應用程序具有靜止狀態和運行狀態。靜止態的程序被存儲在非易失存儲器中,如STM32的內部FLASH,因而系統掉電後也能正常保存。但是當程序在運行狀態的時候,程序常常需要修改一些暫存數據,由於運行速度的要求,這些數據往往存放在內存中(RAM),掉電後這些數據會丟失。因此,程序在靜止與運行的時候它在存儲器中的表現是不一樣的



圖中的左側是應用程序的存儲狀態,右側是運行狀態,而上方是RAM存儲器區域,下方是ROM存儲器區域。

程序在存儲狀態時,RO節(RO section)及RW節都被保存在ROM區。當程序開始運行時,內核直接從ROM中讀取代碼,並且在執行主體代碼前,會先執行一段加載代碼,它把RW節數據從ROM複製到RAM,並且在RAM加入ZI節,ZI節的數據都被初始化為0。加載完後RAM區準備完畢,正式開始執行主體程序。

編譯生成的RW-data的數據屬於圖中的RW節,ZI-data的數據屬於圖中的ZI節。是否需要掉電保存,這就是把RW-data與ZI-data區別開來的原因,因為在RAM創建數據的時候,默認值為0,但如果有的數據要求初值非0,那就需要使用ROM記錄該初始值,運行時再複製到RAM。

STM32的RO區域不需要加載到SRAM,內核直接從FLASH讀取指令運行。計算機系統的應用程序運行過程很類似,不過計算機系統的程序在存儲狀態時位於硬盤,執行的時候甚至會把上述的RO區域(代碼、只讀數據)加載到內存,加快運行速度,還有虛擬內存管理單元(MMU)輔助加載數據,使得可以運行比物理內存還大的應用程序。而STM32沒有MMU,所以無法支持Linux和Windows系統。

當程序存儲到STM32晶片的內部FLASH時(即ROM區),它占用的空間是Code、RO-data及RW-data的總和,所以如果這些內容比STM32晶片的FLASH空間大,程序就無法被正常保存了。當程序在執行的時候,需要占用內部SRAM空間(即RAM區),占用的空間包括RW-data和ZI-data。應用程序在各個狀態時各區域的組成見表 482。

宣告的變數太大無法編譯


在MDK中,我們建立的工程一般會選擇晶片型號,選擇後就有確定的FLASH及SRAM大小,若代碼超出了晶片的存儲器的極限,編譯器會提示錯誤,這時就需要裁剪程序了,裁剪時可針對超出的區域來優化。

如果宣告變數太大,編譯時就會有錯誤,
.\Targets\STM32F429_Discovery\project.axf: Error: L6406E: No space in execution regions with .ANY selector matching xxx.o(.bss).
.\Targets\STM32F429_Discovery\project.axf: Error: L6407E: Sections of aggregate size 0x98fa8 bytes could not fit into .ANY selector(s).
換成const有幫助,但這樣一來原本能動的程式就無法執行。

HEAP設定方式



能通過編譯,不代表程式運作時不會有問題。在SD CARD的範例中就會發現,malloc記憶體時會有錯誤。在網頁中提到,Dynamic allocation is used when new file should be created. You need at least 512 bytes of free memory in HEAP region for malloc to allocate data, otherwise, f_open function will return FR_NOT_ENOUGH_CORE result.

default Keil uVision project, HEAP memory is by default set to 0x200 Bytes = 512kB which can be quite small for something like strings can be in size. open .s (startup file) inside your project and edit variable “Heap_Size” to a value you want to reserve for HEAP

這個網頁中,提到如何設定HEAP SIZE,Heap_Size可以從200改成800。檔案位置在D:\stmlib\git\trunk\00-STM32F4xx_STANDARD_PERIPHERAL_DRIVERS\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm\startup_stm32f429_439xx.s。

TM範例  STACKOVERFLOW討論

外部SD RAM原理


STM32控制器芯片內部有一定大小的SRAM及FLASH作為內存和程序存儲空間,但當程序較大,內存和程序空間不足時,就需要在STM32芯片的外部擴展存儲器了。

STM32F429 Discovery board has external 64Mbits or 8MBytes SDRAM chip ISSI IS42S16400. It has a FMC (Flexible Memory Control) peripheral to driving external SDRAM with hardware. 

FMC hardware is able to store up to 32bits variables at same time.
STM32F429使用FMC外設來管理擴展的存儲器,FMC是Flexible Memory Controller的縮寫,譯為可變存儲控制器。它可以用於驅動包括SRAM、SDRAM、NOR FLASH以及NAND FLSAH類型的存儲器。STM32F429的FMC外設才支持該功能,且只支持普通的SDRAM,不支持DDR類型的SDRAM。FMC是如何運作,這篇有非常非常非常深刻的說明。

外部SD RAM:簡單操作


包括TM方式和SPORTS方式,容易瞭解但沒有實用性。
TM的範例
透過API呼叫 FMC Flexible Memory Control (只有429之後才有 407沒有 )
包成 宣告 例如 TM_SDRAM_Write8(location, 8bitvalue); 8bitvalue = TM_SDRAM_Read8(location); 可以動態在SDRAM某個位置進行讀取。
SPORTS範例
取用記憶體,還是使用FMC的指令

外部SD RAM:整合入malloc


讀寫SDRAM存儲的內容時,需要使用指針或者__attribute__((at(具體地址)))來指定變數的位置,修改sct文件,讓連結器自動分配全局變數到SDRAM的地址併進行管理,使得利用SDRAM的空間就跟內部SRAM一樣簡單。

摘要內容,連結


人體自動化 字型文章

網路上找到一些連結似乎有更簡單方法。OPTREC似乎也有使用這個技巧。

連結1
連結2
連結3

2018年1月19日 星期五

[小說集]被埋葬的記憶


讀過石黑一雄長日將盡、別讓我走兩部作品後,繼續閱讀其2015年最新作品【被埋葬的記憶】THE BURIED GIANT。相較以往幾部作品,被埋葬的記憶,無論是在故事設定或風格或探討議題上,都與長日將盡、別讓我走有很大不同。

以故事設定來說,以往擅長書寫小範圍空間如深宅大院(長日將盡)或寄宿學校(別讓我走)的石黑一雄。搖身一變,成為奇幻故事作家。出場人物有騎士、僧侶和惡龍。時間地點也從現代跳轉回亞瑟王時代的英國大陸。

當時不列顛人和撒克遜人正結束一場血腥爭戰。不列顛人雖獲得勝利,戰敗的撒克遜人卻誓言要復仇。為了避免戰爭,亞瑟王指派魔法師梅林利用巨龍神奇煙霧的力量,讓雙方人民忘記這曾經發生過的慘事。

預期中,這代人都將在苟且的假象中,過著渾渾噩噩生活,直到這一代人都死去,傷痕都被撫平,事過境遷,新時代來臨,即使沒有巨龍的煙霧,人民也只會將過往這段殺戮視為歷史,成為和諧共存的雙方。不過,故事結局卻是巨龍終究在計劃完成前被斬殺,沒有了煙霧,人們都將清醒。報仇的心若再加上有心政客操弄,將會引發更大的戰爭。

故事發展過程中,每個參與者都不斷被質問,"是否需要屠龍"。這也是在詢問,對於過往的錯誤,是要強悍面對,揪出施暴者給予逞罰並且修正錯誤,還是該放下仇恨,專注向前?書中蓋文爵士和威斯登戰士的決定,象徵了群體面對這抉擇時的心情,而老夫妻則是代表了家庭和個人的決定會影響家庭是否破裂或和諧。

對於國族、社會、個人,面對沉重不堪的過往,何時該記憶,又何時該遺忘,當然沒有標準答案。若是認為,人是健忘的動物,終究會遺忘。那麼以色列和巴基斯坦兩國的紛爭,早就該結束,為何還是衝突不斷?若是認為,傷痛的記憶很難抹滅。但看看鄰國日本,二戰尾聲日本受到美國原子彈轟炸造成二十萬平民的傷亡,如此慘痛的經驗,為何現在卻無人聞問?

所以,石黑一雄這個問題,是會隨著時間、環境、不同的人而有不同答案。這完全反映吳乃德一篇文章中引述的「不要對揭露真相的後果太樂觀,因為『記憶常帶來和解,也同樣地常帶來報復,而希望透過解放的記憶帶來罪行的洗濯和救贖,結果將只是一個幻影。』因此,在受害者的個人層次上,有些例子支持揭露真相的和解效果,有例子則對這樣的期待加以否定。」(連結)

所以,相信人權價值和正義者,就勇敢面對過去的陰暗,去挑戰和修復創傷吧。若是以目前的人的和諧幸福為優先考量者,為了解決目前的問題,過去的負擔可以拋開。

而我從來就是渾渾噩噩且敏感度極低的人,很少受到記憶的困擾,真要選擇也應該會類似蓋文爵士,非常功利的為了可見的明確而選擇遺忘。

若從文學角度看這本書,原本以細膩筆觸刻劃人物心緒轉折見長的石黑一雄,在本書中比較沒有發揮的餘地。討論主題也從反映時代和人性幽微關連,進化為探討記憶與遺忘。若說這就代表了作者近十年來思考的轉變,我個人反而喜愛以往著作的氛圍。