2014-01-29

落入凡間的天使 - 蘋果日報






















落入凡間的天使 - 蘋果日報 2014年01月29日

http://hk.apple.nextmedia.com/supplement/culture/art/20140129/18608460

劉建中從事室內及雕塑設計二十多年,現在製造結他延續創作精神。

染了一頭金髮的劉建中(Johnny),廿多年前開設計公司,合作的不是長實,就是新鴻基等大型地產發展商,設計旗下的住宅、酒店或主題公園,例如沙田「史諾比開心世界」及馬灣「挪亞方舟」。

從前,每天穿着整齊地出入高級酒店與辦公室,跟客人洽談每單合約價值數百萬元以上的生意,現在每天打扮型格地在工作室調音、打磨結他,售賣每支約數萬元的結他,雖然單價有天淵之別,但兩者同為藝術創作。

在六、七十年代的香港英文歌王 Danny Diaz,及九十年代出道的香港歌手張崇德等,會拿着劉建中製造的結他自彈自唱,由他親手製作的結他更曾出現在無綫電視劇集《天與地》,成為「樂與怒」精神的象徵。

記者:黃碧珊

攝影:林栢鈞

部份相片由受訪者提供

2012年,劉建中與朋友組成一隊樂隊玩五十年代 Rockabilly,一種集合鄉村、藍調、Boogie Woogie 及 Gosbell 風格音樂,貓王正是該音樂風格的代表人物。劉建中的樂隊 Blinks& Studs 是香港寥寥可數的 Rockabilly 組合,身為樂隊主腦與主音的他,每次出場也梳着Rockabilly 的代表髮型「力怎頭」(Regent Hairstyle),由旁邊往後面梳,蠟起額頭前面的頭髮,在香港非主流音樂界無人不識,人人稱他做 Johnny。

劉建中如今在非主流樂界為人認識,以前在設計界也具地位,代表作有兩個新鴻基有份參與的香港主題公園「史諾比開心世界」及「挪亞方舟」,前者場內有逾六十個不同大小的花生漫畫人物公仔,七成是劉建中公司製造,馬灣公園的挪亞方舟有67對造型與實物相同的動物雕塑,其中三分一動物是劉建中包辦。原本是設計公司老闆的劉建中,厭倦了跟隨客人要求創作設計,加上一次不愉快的合作經驗,「計劃是在八個月內完成工程,但設計不停被修改,工程一拖再拖,做了兩年才完成,要支付期間的師傅人工,白白蝕了半層樓。」其後減少接新工作,約五年前轉行做喜歡的樂器買賣生意。

無師自通製結他

初期,只是直接從中國結他廠購買結他售賣,「與做設計工程相比,賣結他所賺的錢很微薄。」發揮廿多年來的創作小宇宙,在結他表面加點裝飾為結他增值,結果反應良好。在中學階段曾與同學仔自組樂隊,懂得自彈自唱的他,為求有更好音色,在網上參考結他製造方法,加上廿多年的設計經驗,對材料特性熟悉,經網絡訂購木頭及結他配件,無師自通地完成了首件自製結他。

他視每支結他為藝術品,實際與裝飾功能共存,「有個喜歡彈結他的朋友,其太太不允許他在家中掛出任何結他,但我做的就可以,因為她覺得靚。」打磨貝母殼成為暗啞彩色點綴結他、粗糙的木紋是人手雕刻而成、看似是金屬片實際是在木片上塗色……正是與一般結他款式不同之處。

作為基督徒的他以大天使的英文名字 ArchAngels 為自家結他品牌命名,不少結他的設計題材與款式名稱,也是來自《聖經》。將一塊約2.5吋厚的桃花心木,以人手一絲一絲地雕刻,經過幾個月才完成粗糙的琴身,塗上深棕顏料,像是帶領以色列人逃離埃及的摩西之摩杖,這款結他叫 Moses(摩西)。

窩釘做星紀念父親

父親經營旅行社,自小每年也會跟隨家人出團,或到外地旅遊四、五次,開設計公司前,在父親的旅行社工作,從來沒有做過打工仔的劉建中說:「我是很貪靚的,以前總是出入高級酒店傾生意,就算到工廠看進度也不會穿着隨便。自製結他不但要刨木,又要接觸揮發性油漆,一點也不型,覺得自己很慘,這並不是我。」不過,在製造結他的過程中,他可以隨心所欲,不論款式、配件及顏色配搭全部自己話事。

前年,他開始動手做一支結他,整好琴身準備塗色,父親突然離世,敬愛父親的劉建中誠懇地說:「前一天還是好端端的,怎料再見他時已經躺在醫院,雖然驅體外貌無變,但已全無生命迹象,看到生命是多麼脆弱。」每次製造這結他時,他也會流淚,為表達心情,塗上接近黑色的深棕色,並在結他面加上窩釘,營造天上繁星的感覺,繁星從光芒萬丈至暗淡消失,就如爸爸已離他而去。去年,劉建中的外父也去世,為紀念這位做人處事溫文爾雅的外父,正製造一個款式相若的結他,半成品正掛在工作室的牆上,將使用彈出來聲音較柔和的尼龍線組合。

請劉建中拿出紀念父親的結他,他竟回答已賣掉,「我也要交租維生!有個畫家朋友看見這結他,覺得很有感覺,還沒有向他說這背後故事,他已經要買下,現在掛在家中,千叮萬囑幾歲大的女兒不要觸摸它。」雖然劉建中將結他照片放到網上供人訂購,但有原則,客人需親身選購,「要適合他彈奏及造型才賣,有些款式還要看他拿上手好不好看才決定會否賣給他。」他說沒有發生過尷尬場面,原因是他不會將認為不適合的結他讓客人選擇,而是希望樂器能發揮最佳表現。

NEW STEAMPUNK約$2.2萬

 以流行於上世紀八十年代的科幻題材 Steampunk 為創作靈感,它着重表現工業革命的早期科技,在藝術與設計方面,齒輪、鐘錶、護眼鏡及鐳射槍等是 Steampunk 的特徵配飾,劉建中以齒輪為這支結他作重心。

 經打磨後的貝母殼變成啞彩色,手觸琴頭仍凹凸有致。

MICHAEl ACOUSTIC 約$2萬

 在《聖經》中 Michael 是天使長,被委派捉背叛上帝的天使──撒旦,劉建中把天使長兄弟之情與誠信之義的內心爭鬥表現在結他的淺啡與深棕的手繪木紋上。劉建中說買這支結他的客人,買前剛巧畫了一幅畫,畫中的結他居然跟 Michael Acoustic 相似。

MOSES ELECTRIC約$1.98萬

 結他的靈感來自《聖經》人物摩西,他是埃及王子,但其後帶領過着奴隸生活的以色列人逃離埃及。花了幾個月雕刻、約2.5吋厚桃花心木的粗糙結他琴身是摩西的摩杖,貼上金箔的護板象徵摩西曾以埃及王子的身份住在宮殿。

KING DAVID 約$1.8萬

 大衞王戰無不勝,在耶路撒冷定都及興建宮殿,名為大衞城。這位強大的君主,晚年看上了部下的妻子,設計讓部下戰死沙場,把她據為己有。劉建中認為大衞王充份反映人性的陰暗面,故將此結他名為「King David」,並希望由教會人士或傳道人擁有,但最後由一名音樂人購買。

ALPHA& OMEGA 約$1.7萬

 由希臘字母的首字(Alpha)與尾字(Omega)組成,是基督教的一個符號象徵,出自《新約聖經》最後一卷《默示錄》。天主和耶穌分別以Alpha和Omega自稱,說明自己既是受造物的開頭,也是一切的終結。劉建中開始製造此結他時,父親離世,帶着悲傷完成它。結他響孔旁的一對羽毛,表示天使在空中飛舞。

 一個木雕結他琴身需花上最少一個月完成。

 這數十平方呎的地方就是結他的製造工場。

 現在劉建中跟朋友組成五十年代 Rockabilly 樂隊,每次出場也梳着「力怎頭」的髮型。

 劉建中有份參與製造馬灣「挪亞方舟」的雕塑公仔。

.END

自由與創業的平衡藝術 - 香港貿發局

Freelancing - 自由與創業的平衡藝術 - 香港貿發局 2014年1月29日

http://www.hktdc.com/info/web/mi/article.htm?LANGUAGE=tc&ARTICLE_ID=1X09W72D&DATASOURCE=hkthkc

主頁 > 香港貿發局周訊 - 香港版 > 本周焦點

現在不少人考慮以自由業務(Freelancing)模式創業,其好處不但有較大的自由度,而且需投放的創業資源相對也較少。但要成功開創自由業務,談何容易?且聽聽由香港貿易發展局中小企服務中心邀請的香港青年創業家聯盟會員,分享其實戰的成功經驗,並剖析自由業務創業路上可能遇到的各種問題。

photo

Clee Design 設計總監李聰穎認為,當業務做大了便需要找別人合作幫忙,物色夥伴最重要是志同道合,與自己想法一致,這是一項挑戰。

photo

香港青年創業家聯盟顧問夏婉冰建議,freelancer 吸客技巧之一是在30秒內,說明自己的強項與對手有何不同,好讓客人即時分別出來。
 
photo

專業認証學院主席夏永超指出,大客戶委託工作前每考慮 freelancer 的質素,故擁有專業認證非常重要。另外,收費愈高,或令人感覺愈專業

photo

思迅市場顧問業務總監廖俊傑表示,很多人羡慕 freelancer 工作自由,沒有人管束,但當面對工作量不足,也有害怕的時候;建議利用淡季或空檔進修新事物,這對日後拓展新領域有幫助。
 
香港青年創業家聯盟顧問夏婉冰表示,「(本港)的傳統僱佣模式已經改變,由過去畢業後多會找一份長工,到現時多了人出來創業;尤其香港租金日益昂貴,以 Freelancing 模式創業變得日趨普及。」實際上,從經營角度看,企業外判不熟悉的工序給專家代勞,不但服務質素有保證,最重要是節省設立部門的開支,也避免辭退不合用員工的麻煩。

自評 Freelance 合適度

不過,專業認證學院主席夏永超指出,創業者需先行評估此模式是否適合自己。例如,自己有甚麼專長、將有哪些客源、從中享受到甚麼等。成功的自由業務工作者(freelancer)多有以下特點:經驗與信譽(高質素及準時交貨);能處理突如其來的風險;能廣交客源,建立口碑;贏得客人的信任;懂得找外援協助自己完成工作等等。

就此,他提出多項參考竅門,例如,freelancer 需為客人建立名片檔案,以紀錄不同客戶的服務需要;又要分析自己的能力,懂得將弱項轉化為強項;與此同時,瞭解對手虛實,並不時評估市場風險對業務的影響等。最後就是設定收費方式(時、日或工作),注意報價與市價的比較等。

自由業務亦需品牌建立

夏永超強調,建立個人品牌形象,是踏上成功的第一步。他建議業者設計個人名片、信箋、網頁及電郵;多參加研討會建立關係網,甚至準備「飲歌」以備應酬客人。另外,要學會在客人面前展現個人強項,尤其是專業形象及能力,這是說服客人交託工作的關鍵。再來,要及早瞭解客人的滿意程度,一來可為不足做補救工作,二來是為建立互信,成為客人「信得過」的顧問。

Clee Design 設計總監李聰穎笑言,她投身 freelancer 純屬機緣巧合。她原是從事平面造型設計,及後認識一位牙醫客人,應要求用軟性方式代為推廣,結果陽光形象效果理想,該牙醫其後再委託她為新店設計紙袋、名片、宣傳影碟等;又轉介同行與她,工作不絕。在該名牙醫鼓勵下,她決定自設公司,自始全身投入 freelancer 行列。

她指 freelancer 除了做好設計本份外,管好公司一盤帳目也很重要;另外,要不斷與客人溝通,聆聽對方實際需要,事前做足調研工作。雖然很多人認為生意做開了,便應轉向大品牌,但李聰穎認為品牌大小不重要,最重要反是能代客人解決問題。當然,若工作量增多後,個人力量應付不來,這時便需要物色夥伴合作,才能維持業務的長遠發展。

凡事「一腳踢」 積極主動

思迅市場顧問業務總監廖俊傑形容,freelancer 特質是甚麼都要「一腳踢」(簡體字版用:自己包辦)。以他為例,曾當過唱片騎師,故可勝任司儀一職,更兼任市務推廣。所以,他的公司職銜頗多,既是市務顧問、傳媒服務顧問,又是創意總監、業務董事、客戶服務董事等。

他表示,只要自己能力所及,都會主動爭取各類工作,若做不來,便找專家幫手或合作。舉例說,近年流行網上廣告,他坦言不懂設計,但勝在認識很多行內專家。「當 freelancer 最重要是背後有不同專長的人脈,能夠在客人展現最強一面,和及時滿足其要求。這樣,當對方有需要時,第一個便想起你。」

他寄語同業,接工作不要怕「蝕底」,首次交易虧損一點不要緊,視作汲取經驗,有機會展示你的實力;但又須向客人表明,下一次將收回正價,以免讓人太廉價的印象。此外,他建議業者多利用 facebook 等社交網絡,借助客人用後意見或口碑宣傳自己。

個人業務或成立公司 各有所長

究竟自由業務工作者,應以個人身份還是成立公司經營較好,四位講者總結認為看情況而定,freelancer 強調個人特質,優勢是經營成本低及靈活,客人往往跟著 freelancer 走反觀開設公司營運,成本不菲、行政制度亦未必配合到客人的靈活要求,未必每位freelancer都甘願付出,或寧獨享辛苦所得。

各講者亦提到,freelancer 收費標準不要定得過低,以免破壞個人乃至行業形象,若認定自己有價,不妨稍為抬高收費,以便預留對方議價空間。客人不斷討價還價,更應維持高收費,以突顯專業服務的與眾不同。

最後,freelancer 物色合作夥伴,最重要是有口頭承諾。若以項目合作,由於合散也容易,容易處理外援事宜;反之,若與夥伴合組公司,情況就變得複雜,除了考慮對方的能力及想法是否與自己相同,也必須白紙黑字定明合作條款。因此,有建議找互補長短的夥伴、清晰分工,這樣才不容易引起爭議。

- See more at:

http://www.hktdc.com/info/web/mi/article.htm?LANGUAGE=tc&ARTICLE%5fID=1X09W72D&DATASOURCE=hkthkc#sthash.n7jL2YxF.dpuf

.END


2014-01-28

RPi news

UK faces electronics skills gap, warns Raspberry Pi creator 27 January 2014 • By Dave Baxter

http://business-technology.co.uk/2014/01/uk-faces-electronics-skills-gap-warns-raspberry-pi-creator/

The founder of the Raspberry Pi Foundation warns the UK faces “catastrophe” if it fails to innovate in engineering and electronics.

Eben Upton, one of the people behind the Raspberry Pi computer sets which are distributed in schools to interest children in engineering, says Britain can only stay globally competitive through continued innovation.

When asked what would happen if British innovation dried up, he answers: “It would be an economically threatening catastrophe.

“200 years ago we got to the industrial level before anyone else. Before that, everyone was on a level playing field and your economy was propelled by the size of your population.

“We had 60 million people and this grand economy. We have got used to the idea that this is how the world works, but it’s not how the world works.

“Innovation is about trying to keep that ball in the air for another 50 to 100 years.”

Upton believes children should be given an opportunity to experiment with engineering, which he says is lacking in many homes.

“Often in homes where people do have a PC, it’s seen as a high-value item and a thing you don’t want to screw up.

“If the only chance to get mechanical experience was to dismantle your parents’ car, that won’t happen.

“But if it’s like a bike, you can probably put it back together.”

And he says that while the generation of ‘digital natives’ may be interested in technology, this does not equal an aptitude for engineering.

He says: “The term ‘digital native’ implies a level of sophistication. A two-year-old pinching out on a tablet is a digital native, but that doesn’t translate into understanding how anything works.”

He is keen to give children a chance in life both by giving them the opportunity to experiment with computer sets and teaching them skills such as coding.

“We need a focus on coding and algorithmic thinking. If that goes well, a child of age x will be able to talk about simple data structures.

“If we can do this, we are making sure everybody will be a potential enthusiast.”

He also argues children should be given a chance to study engineering at school – something currently not available.

“Engineering has an unusual problem in that it doesn’t get directly studied at school,” he says. “A child will have to do something like physics at school before studying engineering at university.

“It’s a surprisingly significant step to dedicate three years of your life and £20,000 of debt to study something you have never done. That’s a lot to ask of an 18 year old.”

.END

2014-01-27

破港人KICKSTARTER紀錄 80後自創西遊戰棋 網上集資330萬 - 蘋果日報

破港人KICKSTARTER紀錄 80後自創西遊戰棋 網上集資330萬 - 蘋果日報 2014年01月27日

阿瀚除為西遊戰棋上色,也會找小道具如泥沙、枯枝等襯托。

兩名80後青年憑一副以西遊記為主題的戰棋,在國際創業集資網KICKSTARTER上籌集了330多萬港元,成為該網成立13年來,籌得最多資金的港人。該套名為《行者》(Journey: Wrath of demons)的戰棋(Board Game),將於今年7月在全球推出一千多套。

記者:盧勁業

著名的KICKSTARTER網,透過積少成多的方式向全球公眾集資,最多曾為智能手錶Pebble籌得1,026萬美元(約8,000萬港元)。但港人在該網,除了黃偉民(Ray)和何瀚為(阿瀚)的《行者》戰棋外,最多只籌得9.4萬美元(約73萬港元)。

一個figure雕兩星期

30歲的Ray和29歲的阿瀚,在一個雕塑班上認識,一見如故。Ray一直想做自己原創的人形雕塑,阿瀚支持他,於2012年4月開始籌備推出戰棋。「10幾年前開始我已經想雕齊成套《西遊記》角色出嚟!」Ray 說,國際戰棋市場也缺乏東方元素作品,所以戰棋就以西遊記為主題。

他們考慮在KICKSTARTER集資時,心大心細,一來沒有遊戲創作經驗,二來擔心華人身份受歧視。「唔試過,我哋一定會後悔,失敗咗我哋會無咗筆錢同間Studio(工作室),但最多咪重新嚟過。」Ray說。

將《行者》的遊戲圖板鋪出來,可以鋪滿整個房間。受訪者提供圖片

兩人以Marrow Production為名,於KICKSTARTER上共籌得42.5萬美元(約330萬港元)。互聯網
決定去馬後,單是前期投資,便耗掉每人逾20萬元積蓄。Ray從事電影工作的哥哥,為他們拍了一條很有水準的宣傳短片;他們也找了多位外國著名插畫師幫手畫插畫。

Ray負責戰棋的美術設計、角色雕刻,「單係一個figure就最少要雕兩星期,每日雕七至八個鐘」。《行者》有12個角色,合共33隻棋,主角是唐僧和三個徒弟,連孫悟空的毛髮、豬八戒的豬尾……都雕得巨細無遺。

阿瀚則負責為角色上色,做市場推廣、設計遊戲規則等。他鑽研了無數套受歡迎的戰棋玩法,再加入東方奇幻元素。《行者》可供一至五人參加,共有九塊紙板,四位主角須對付路上的各種妖魔鬼怪,取得西經。

在戰棋成形後,集資計劃去年10月啟動,在一個月內,捐款人可隨時加入或撤銷捐款,捐款人可按金額獲贈戰棋或部份模型等。兩人心情跟隨集資銀碼忽上忽落,足足失眠了一個月。
有低潮,也有驚喜。一間意大利博物館捐出2,000美元(約1.5萬港元),要求擁有整套上了色的戰棋作收藏;也有一對美國夫婦主動為他們的說明書免費校對。

料7月發行逾千套

集資到期日,兩人眼光光望着電腦螢幕上跳動的數字,徹夜不眠。Ray說:「都失眠咗成個月,過關一刻只覺肉體好累,但仲好精神。」完結時天已光,兩人走去打了一場籃球,氣來氣喘,躺在球場上動不了,再回家安安樂樂睡覺去。

計劃共獲1,858人支持,籌得42.5萬美元(約330萬港元),即平均每人捐約1,780港元;支持者來自世界各地,北至冰島、南至南非。「嗰一下感覺好滿足,覺得自己創作有人認同,錢仲係其次。」Ray說。

戰棋製作仍在進行中,有數個角色仍未成形,遊戲規則仍在調整,但歐美定單已蜂擁而至,這份原汁原味的香港創意,將在7月面世,每副售價100美元(約780港元),初版暫定發行一千多套。



雕手辦維生 全港少於五人

Ray手上的豬八戒主角棋,單是雕刻就需時最少兩星期。林寶益攝

闖出名堂

「雖然係籌到300萬,但扣番成本除番開,我時薪其實同老麥(麥當勞)差唔多!」Ray為了做自己的創作,有一年半無任何收入。其實他在會考「失敗」後,早已雕出彩虹,成為受歡迎的雕刻師。

Ray長於公屋家庭,求學時期讀書成績一般,但熱愛雕刻,16歲已開始接雕刻工作,會考前基本上都在雕刻、鑽研畫畫,「會考我得8分,但偏偏美術一科係拎A1」,他尷尬地笑。
其後,他一邊做雕塑,一邊修讀電影道具和雕刻等。父母見到他能靠手藝謀生,也沒多過問。

《行者》四隻主角棋是唐僧和三個徒弟。受訪者提供圖片

難搵新人入行

後來定單越接越多,在行內闖出名堂,例如7-11早前供換購的海賊王公仔、遠銷海外的Q版聖鬥士星矢模型、電影《救火英雄》裏謝霆鋒戴的面具,原型都出自他一雙手。

在香港,像他這種以雕刻首辦模型維生的人不夠五個,「其他都係大我20年以上嘅前輩,呢行學嘅時間長,做嘅時間又長,又無得見工,都好難入行」。

他一直希望能物色新人入行,但並不容易。他表示,雕刻要雕得精,要對人體結構、骨骼有理解,又要對各種美術風格有所認識,「一定係努力重要過天份好多!」須靠經驗、專注累積,技巧才慢慢進步。

雕刻不能帶給他大富大貴,「雖然財政上可以再自由啲就更好,但其實𠵱家都已經係做緊自己鍾意做嘅事」,他和拍檔阿翰滿足地笑。

《蘋果》記者

.END

WuYin LPC1114 in box





















WuYin LPC1114 in box

.END

Beagle Bone Black book abstract

Bad to the Bone: Crafting Electronics Systems with BeagleBone and BeagleBone Black Published by Morgan and Claypool  April 2013, 430 pages

Authors Steven F. Barrett, University of Wyoming Jason Kridner, Texas Instruments

Abstract

This comprehensive book provides detailed materials for both novice and experienced programmers using all BeagleBone variants which host a powerful 32-bit, super-scalar TI Sitara ARM Cortex A8 processor. Authored by Steven F. Barrett and Jason Kridner, a seasoned ECE educator along with the founder of Beagleboard.org, respectively, the work may be used in a wide variety of projects from science fair projects to university courses and senior design projects to first prototypes of very complex systems. Beginners may access the power of the "Bone" through the user-friendly Bonescript examples. Seasoned users may take full advantage of the Bone's power using the underlying Linux-based operating system, a host of feature extension boards (Capes) and a wide variety of Linux community open source libraries. The book contains background theory on system operation coupled with many well-documented, illustrative examples. Examples for novice users are centered on motivational, fun robot projects while advanced projects follow the theme of assistive technology and image processing applications.

Key Features:

Provides detailed examples for all BeagleBone variants, including the newest "next generation" BeagleBone Black

BeagleBone is a low cost, open hardware, expandable computer first introduced in November 2011 by BeagleBoard.org

BeagleBone variants, including the original BeagleBone and the new BeagleBone Black, hosts a powerful 32-bit, super-scalar ARM Cortex A8 processor

BeagleBone is small enough to fit in a small mint tin box

"Bone" may be used in a wide variety of projects from middle school science fair projects to university courses and senior design projects to first prototypes of very complex systems

Novice users may access the power of the Bone through the user-friendly BoneScript environment

Seasoned users may take full advantage of the Bone's power using the underlying Linux-based operating system

A host of feature extension boards (Capes) and a wide variety of Linux community open source libraries are available

The book provides an introduction to this powerful computer and has been designed for a wide variety of users

The book contains background theory on system operation coupled with many well-documented, illustrative examples

Examples for novice users are centered on motivational, fun robot projects

Advanced projects follow the theme of assistive technology and image processing applications

Resources

Examples from the text

.END

2014-01-26

Raspberry Pi or BeagleBone Black - Michael Leonard

How to Choose the Right Platform: Raspberry Pi or BeagleBone Black - Michael Leonard 08/01/2013

http://makezine.com/magazine/how-to-choose-the-right-platform-raspberry-pi-or-beaglebone-black/

There are already many articles out there comparing Arduino, Raspberry Pi, and BeagleBone Black; this is not one of those articles. I believe it is clear that Arduino is in a different league than the Raspberry Pi or BeagleBone Black, and serves an entirely different purpose.

What I was looking for and couldn’t find was a comprehensive article that would summarize all of the pros and cons of the Raspberry Pi and the BeagleBone Black, and what each platform is best suited for. When I couldn’t find that article, I decided to write it myself.

I begin this comparison by giving a short introduction to each platform and then we will take an in-depth look at the two platforms side-by-side to determine which one is best for each category. The categories covered are:

Raw Comparison

Unboxing

Ease of Setup

Total Cost

Connections

Processor Showdown

Graphical Showdown

Audio Showdown

Power Consumption

Expandability

Hardware Accessibility

Community

Let’s get started!

About the Raspberry Pi

Arduino is the true trailblazer in the microcontroller area and the device that started the whole “maker” revolution; the Raspberry Pi on the other hand is an amazing device that really started the microprocessor revolution.

The Raspberry Pi was the first cheap (read: $35) single-board computer easy enough to use for the general public. The project to develop the Pi was born out of a realization that young students were not proficient in the technical details of computing that their older peers had learned out of necessity. Due to their less technical backgrounds these students we not able to perform at the level expected of them.

To attack this issue the Raspberry Pi creators developed the low-cost and relatively high performance miniature computer that would allow a new generation of students to interact with their computers in a way that they had never thought was possible.

If you would like to learn more about the Raspberry Pi, I recommend you to the official “About” page or the “FAQ” page. The story of the Raspberry Pi’s creation is inspiring and is worth a read.

About the BeagleBone Black

The BeagleBone Black is a relative newcomer to the world of easy to use microprocessor breakouts, however, what it missed out on in time-to-market, the BeagleBone Black has more than made up for in capability.

The BeagleBone Black has evolved out of the long lineage of BeagleBoard products into the current version; a small form-factor, very powerful, and extremely expandable product that allows builders, makers, artists, and engineers the ability to create truly innovative projects.

The BeagleBoard family was originally designed to provide a relatively low-cost development platform for hobbyists to try out the powerful new system-on-a-chip (SOC) devices that were essentially capable of performing all the duties of a computer on a single chip.

The original BeagleBoard is currently priced at $125 while its successor, the BeagleBoard-xM, is priced at $145. So even though these systems were very powerful, they were just not at the right price to compel people to buy them in mass quantities.

After the BeagleBoard-xM, the BeagleBoard team created the original BeagleBone. It is essentially a smaller, stripped down version of the BeagleBoard.

While the BeagleBone was a good start, it still wasn’t as capable as it could have been, and at $89 it was still a bit too pricey for the hobbyist market.

In late 2012 the BeagleBoard team finally released the newest version of the BeagleBone, called the BeagleBone Black. I think one look at the picture will tell you why they chose this name.

This version has maintained the same form-factor as the BeagleBone but added quite a bit of useful functions and is generally an all around better device; to top it all off, the BeagleBone Black is priced at a very affordable $45.

If you would like to learn a little bit more about the BeagleBone or BeagleBoard devices, you can visit the official community page or the manufacturer community page. This is the best way to learn the intricate details of these platforms, and will let you more fully evaluate if the BeagleBone Black is right for you.

So Raspberry Pi or BeagleBone Black?

Now that we know a little bit about each device, let’s compare them side-by-side and see which one is best for what you want to do. I will do my best to cover all of the topics that are important and to be unbiased in my conclusions.

If you see something I missed or think I made a stupid call, let me know in the comments! Just remember to be civil.

RAW COMPARISON

To start this comparison I have made a summary table where we can take a look at the raw specifications from each device. This is a good way to get a quick overview of each platform’s capabilities but does not always tell the whole story.

For full disclosure, I am comparing the BeagleBone Black Rev. A5B to the Raspberry Pi Rev. B. The summary table below compares the two boards as they are shipped, but the in depth comparisons below consider the entire ecosystem supporting each board.

Comparing Raspberry Pi and BeagleBone Black
BeagleBone Black Raspberry Pi
Base Price 45 35
Processor 1GHz TI Sitara AM3359 ARM Cortex A8 700 MHz ARM1176JZFS
RAM 512 MB DDR3L @ 400 MHz 512 MB SDRAM @ 400 MHz
Storage 2 GB on-board eMMC, MicroSD SD
Video Connections 1 Micro-HDMI 1 HDMI, 1 Composite
Supported Resolutions 1280×1024 (5:4), 1024×768 (4:3), 1280×720 (16:9), 1440×900 (16:10) all at 16 bit Extensive from 640×350 up to 1920×1200, this includes 1080p
Audio Stereo over HDMI Stereo over HDMI, Stereo from 3.5 mm jack
Operating Systems Angstrom (Default), Ubuntu, Android, ArchLinux, Gentoo, Minix, RISC OS, others… Raspbian (Recommended), Ubuntu, Android, ArchLinux, FreeBSD, Fedora, RISC OS, others…
Power Draw 210-460 mA @ 5V under varying conditions 150-350 mA @ 5V under varying conditions
GPIO Capability 65 Pins 8 Pins
Peripherals 1 USB Host, 1 Mini-USB Client, 1 10/100 Mbps Ethernet 2 USB Hosts, 1 Micro-USB Power, 1 10/100 Mbps Ethernet, RPi camera connector

UNBOXING

These are hobbyist boards and aren’t exactly expected to adhere to the same high standards as a fully commercialized product. With that in mind, I still believe that the packaging and first opening of the boards constitutes an important part of the first impression a buyer will get.

Unboxing the BBB and RPi. Not really though, I had already unboxed them both and used them quite a bit...

When I bought my Raspberry Pi, it was packaged in a plain white cardboard box with no markings or included accessories. I noticed that they have since begun shipping in nicely packaged boxes with professional looking markings, so I won’t hold my experience against the Raspberry Pi.

The BeagleBone Black was given to me for free as a participant in the 2013 TI Intern Design Competition. It was packaged in an equally professional box and included a mini-USB cable and a tiny introduction card.

Winner: Tie

EASE OF SETUP

Setting up the Raspberry Pi is quite frankly a bit laborious. Since the board does not come with an included micro-USB cable to supply power, you must obtain one on your own. Additionally, the Raspberry Pi does not come with a pre-installed operating system or on-board storage. You will need to obtain an SD card to boot the Raspberry Pi. Once you have an SD card you will need to download and install the operating system on the card. After you have taken care of these prerequisites, the Raspberry Pi should be ready for use.

Setting up the BeagleBone Black on the other hand is quite possibly as simple as it gets. Using the included Mini-USB cable, you can attach the BeagleBone Black to your computer to supply power. The BeagleBone Black will boot from the on-board storage without requiring any more work on your end. If you would like to be able to interact with the BeagleBone Black from your computer you may need to install some included drivers, but this is relatively painless.

Winner: BeagleBone Black by a long-shot

TOTAL COST

This is really kind of a subjective category since the requirements are different for everybody. If you already have an SD card, micro-USB cable, HDMI cable, and a keyboard to use with the Raspberry Pi, then there won’t be any extra cost.

For the BeagleBone Black, it is quite possible that you won’t need any extra parts to end up with a usable board. If you want to extend functionality beyond just the basics, it is likely you will need to buy a MicroSD card and a micro-HDMI cable.

In addition, the two USB ports on the Raspberry Pi mean that you may be able to get by without a USB hub. Since the BeagleBone Black only has one USB port, unless you have something like a Logitech Unifying Receiver, you will need a USB hub to use a mouse and keyboard.

In my case, the BeagleBone Black was slightly cheaper overall but since there are so many factors to consider here, I will leave this one up to you.

Winner: Tie

CONNECTIONS

If there is one thing that Business types and Engineers can agree on it’s that everything comes down to the connections you make, and oh boy the BeagleBone Black can make some connections.

With two 46 pin headers, the BeagleBone Black has a total of 92 possible connection points. Some of these connections are reserved, but almost all of them can be reconfigured to be used if needed. Taking a look at the reference manual shows the following (non-exhaustive) list of possibilities:

3 I2C buses

CAN bus

SPI bus

4 timers

5 serial ports

65 GPIO pins

8 PWM outputs

7 analog inputs (1.8V max 12 bit A/D converters)

With such an impressive list of interfaces, the BeagleBone Black is a real powerhouse in this category. I’m not aware of any other platforms at this size and price point that provide so many interface options, a characteristic that is a real blessing for many applications.

Looking at the Raspberry Pi, we have a 26 pin header for making connections with the following possible interfaces:

8 GPIO pins

1 UART interface

1 SPI bus

1 I2C bus

This is a much smaller list but would be perfectly adequate for an I2C, SPI, or UART based project, as well as any project which doesn’t require external interfacing. The Raspberry Pi’s true power is in a different category which we will take a look at soon.

Winner: BeagleBone Black, no contest

PROCESSOR SHOWDOWN

The processor is perhaps the single most important factor in determining how fast your system will perform. The stock configurations give us a 1 GHz processor on the BeagleBone Black and a 700 MHz processor on the Raspberry Pi.

In an effort to put the two on a more level playing field, let’s assume that you have overclocked the Raspberry Pi to perform at the same clock speed as the AM3359.

The next defining feature we want to look at is the processor architecture. The Raspberry Pi uses the slightly older ARMv6 instruction set while the BeagleBone Black uses the ARMv7 instruction set, which is currently the most common architecture among embedded systems.

The newer architecture of the BeagleBone Black lends itself to more than just bragging rights though. One advantage of using the more modern instruction set is that the processor on the BeagleBone Black is more widely supported by software developers. Notably, some operating systems are no longer designed to be run on the ARMv6 instruction set, including Ubuntu which dropped support in late April.

Another advantage the ARMv7 instruction set enjoys over the ARMv6 goes beyond support, and includes actual performance enhancements. While the list of improvements between v6 and v7 is a long one, some of the more impressive improvements like implementing a superscalar architecture, including instructions for SIMD operations, and an improved branch prediction algorithm lead to some pretty amazing performance increases.

Specifically, even when running at the same clock speed, the processor on the BeagleBone Black is nearly TWICE AS FAST as the processor on the Raspberry Pi. (Source 1: ARM A8 runs 2000 MIPS/MHz, Source 2: ARM11 runs 1250 MIPS/MHz)

Winner: BeagleBone Black

GRAPHICAL SHOWDOWN

This is one category in which the Raspberry Pi really shines. With the integrated Videocore graphics processor, the Raspberry Pi is capable of decoding 1080p video streams, rendering OpenGL, and even running Minecraft (sorry it can’t quite handle Crysis). In addition to the impressive graphics processing, the Raspberry Pi also offers a full sized HDMI connector and a composite video output for lower quality connections.

All of this combines to put the BeagleBone Black on the defensive. The BeagleBone Black does have built in graphics support, but is just not quite as powerful and does not support 1080p. To compound the lower graphics processing power, the BeagleBone Black only offers a micro-HDMI video connection for interfacing with your monitor or TV.

While there are add-on capes which increase your connectivity options, there is no substitution for the graphics computation power of the Videocore system on the Raspberry Pi.

Winner: Raspberry Pi by a solid margin

AUDIO SHOWDOWN

This one really isn’t much of a showdown. With the BeagleBone Black allowing you to output audio over micro-HDMI only and the Raspberry Pi supporting audio over HDMI or through a 3.5 mm audio jack, the Raspberry Pi has more capability out of the box.

Looking at the broader perspective, there is an add-on board for the BeagleBone Black which gives adds a 3.5 mm audio out as well as a 3.5 mm audio in and some extra audio processing capability.

Since this is an add-on and not the default configuration, I will still give this category to the Raspberry Pi. If you already have a BeagleBone or are looking for some more capable audio processing then the audio add-on cape may be a good choice.

Winner: Raspberry Pi

POWER CONSUMPTION

It is quite frankly pretty difficult to find any reliable data on this category. The BeagleBone Black reference manual provides a range of current draws so there isn’t any guesswork there.

The Raspberry Pi, on the other hand, has many different user reported measurements that vary so widely I’m not even sure what is reasonable anymore. The reports which seem most reputable show a slightly lower current draw from the Raspberry Pi.

If you have any reliable data for either one of these boards as far as power consumption goes, please let me know in the comments.

Winner: Raspberry Pi by a small margin based on unreliable data

EXPANDABILITY

I have to admit, when I first set out writing this article I expected the BeagleBone Black to handedly dominate this category. Since I have been working on an add-on cape of my own for the BeagleBone Black (the SensorCape), I was already fully aware of the robust add-on ecosystem that existed for the BeagleBone.

What I was not aware of though, was the add-ons for the Raspberry Pi. Just to clarify, “add-ons” do not refer to cases, cables, or other non-functional accessories; what I am interested in are the additional boards that make your BeagleBone or Raspberry Pi more capable.

We’ll take a look at the BeagleBone first. Browsing through the official CircuitCo capes page, the following add-on boards really stand out to me.

Breadboard, prototype, and breakout capes – These three capes allow you to easily test new additions to your BeagleBone

DVI cape – Allows you to connect to a DVI monitor

VGA cape – Allows you to connect to a VGA monitor

HDMI cape – Allows you to connect to an HDMI connection, this was originally developed for the BeagleBone but could be used for the Black if you just really hate micro-HDMI

LCD capes – There are a few versions of LCD capes in the store that can be used to easily add an LCD screen on top of your BeagleBone

Camera cape – Adds a 3.1 MP camera on top of the BBB, also nicely configured to work with the LCD capes so you could make your own handheld camera

Audio cape – Includes two 3.5 mm audio jacks and allows you to configure audio in and out

Motor cape – Adds a TI motor drive that can drive up to 8 DC motors at 500 mA per motor

Battery cape – For when you want to take your project on the go

Of course this list is not exhaustive, so I don’t want to lead anyone to believe that this is all that is available. These are just the capes that stood out to me as being widely useful.

There are many other more specialized capes in production that I chose not to include. These include the BeagleBone ROV cape, featured in the OpenROV project and is used to control an underwater robot that streams live video; or the Ninja cape that was commercialized into Ninja Blocks, an amazing platform allowing you to automate almost anything.

With such capable extensions for the BeagleBone, you may be wondering how the Raspberry Pi could even compete. I know I was. Truth be told, the Raspberry Pi add-ons are pretty scarce, and since there is no central repository for them, it is difficult to find a good list.

The majority of add-ons I have been able to find are simply “breakout” boards or prototyping boards which allow you to easily interface with a breadboard or to solder directly on the board. These types of boards, while useful, are not a killer feature and are not unique to the Raspberry Pi.

Something that is unique would be this add-on from cooking hacks. This board allows you to easily connect Arduino compatible shields and components directly to the the Raspberry Pi.

That may not seem like a big deal at first, but if you recall the beginning of this article I mentioned that Arduino is really in a league of its own. This is in no small part thanks to the incredible amount of add-on “shields” that are available for Arduino. According to the Arduino Shield List, there are just short of 300 shields available for the Arduino and nearly all of these are now compatible with the Raspberry Pi.

Outside of this Arduino compatibility though, the support for add-on boards is still fairly low in the Raspberry Pi environment . Unless the functionality you want to implement is covered by an Arduino shield, you may be out of luck.

Winner: Raspberry Pi by a hair thanks to Arduino add-on compatibility, I am still very optimistic on the future of the BeagleBone in this category though. And really, if you are planning on buying a Raspberry Pi and then using Arduino capes, you should probably just buy an Arduino.

HARDWARE ACCESSIBILITY

This category may not be important to the majority of readers, but I think it is critical to technical users or anyone who may want to produce a minimal version of a project they made with their chosen platform. Both the Raspberry Pi and the BeagleBone Black rely heavily on the open-source community, so let’s see how open they are in return.

The Raspberry Pi is unfortunately based off of a proprietary processor platform which means you cannot view a full datasheet for the processor without going through some significant hoops such as:

Signing a non-disclosure agreement with Broadcom

Providing Broadcom with a business plan

Committing to buy these processors in bulk

It is possible to get more information on the internal structure of the BCM2835 for register access, but as far as I know there is no documentation for the processor pinouts. In contrast, the full datasheet and user guide for the processor on the BeagleBone Black can be accessed at the Texas Instruments product page, and does not have a minimum purchase requirement.

In addition to the proprietary processor, the Raspberry Pi Foundation also entered into an exclusive manufacturing agreement with RS and Farnell, meaning that the board layout must be kept secret for now.

If you are trying to make your own derivative of the Raspberry Pi or need to know how the components are connected together, Eben has provided the schematics for the Rev. B Raspberry Pi. You will still have to commit to buying the Broadcom chip in bulk if you want to make your own, but at least you have a starting point.

The entire documentation, including layout files, schematics, and reference documents, for the BeagleBone Black are hosted at the BeagleBone Black wiki page, and includes everything you could want to make your own BeagleBone.

Winner: BeagleBone Black

COMMUNITY

Despite my best efforts, I can’t seem to find any reliable data on the size of each platform’s respective community. Seeing as how (as of April 2013) the Raspberry Pi has shipped more than one-million units, I think it is safe to assume that the Raspberry Pi has developed a larger following. On top of this the Raspberry Pi gets much better media coverage and overall exposure.

These considerations are all important if you are unfamiliar with Linux systems or electronics in general, as well as if you are planning on undertaking a large project which you may decide you need help with.

A quick Google insights search shows that while the BeagleBone Black has a growing community, the Raspberry Pi still generates about 13 times more web traffic.

Winner: Raspberry Pi by a long-shot

Summary

Now that we have looked at each category in detail, it is a simple matter to draw some conclusions about which circumstances should lead you to choose one board over the other.

WHEN THE BEAGLEBONE BLACK IS THE RIGHT CHOICE

Projects that need to interface with many external sensors – The incredible number of pins on the BeagleBone Black and the many bus options allow you to easily interface with pretty much any device out there.

Anything requiring small form factor but high speed processing – For example this super cool 33 node Raspberry Pi computing cluster would have been much better off using the BeagleBone Black, both from a price and performance standpoint.

Projects that you may wish to commercialize – Since the Raspberry Pi is more of a closed-source environment, it is impossible to make your own minimal versions. The open nature of the BeagleBone would allow you to just take the most important features and directly port that into your own design.

As an embedded system learning platform – The Raspberry Pi has its roots in education, but the fact that the BeagleBone Black works out of the box leads me to believe it is a better solution for learning about embedded systems.

For when you want it to “just work” – The fact that the BeagleBone Black works right out of the box is a huge bonus and allows you to get up and going in a few minutes rather than an hour or more.

WHEN THE RASPBERRY PI IS THE RIGHT CHOICE

Multimedia based projects – With the significantly more powerful graphics processing and larger number of connection options, the Raspberry Pi is a no-brainer for multimedia interfaces.

Community driven ideas – If you have a project that will in some way rely on the community for proper operation, you should choose the very active community of the Raspberry Pi. If you just think you will need support though, the BeagleBone community is very helpful and many Raspberry Pi projects will easily port to the BeagleBone Black.

As a graphical learning platform – Since the BeagleBone Black does not have quite the video capability of the Raspberry Pi, I would recommend the Raspberry Pi for learning about Linux in a graphical environment. Though to be fair you could do the same thing in a Virtual Machine, it just isn’t quite as much fun.

WHEN EITHER ONE WORKS

Internet connected projects – If you want your project to send updates to a server, or maybe even act as a server, then either board should work just fine for you.

You just want to nerd out – Maybe you just want to get your nerd on. That’s okay, in fact it’s even becoming the cool thing to do. If that is your goal then either platform will serve you well.

I hope you found this guide helpful and that you will use it in making your next purchase. If you still can’t decide which one is right for you and you have some money to burn I really recommend just buying both of these systems. Each board has different strengths and they both offer something different. Happy hacking!

If you liked this post then be sure to share it, for more articles like this visit my blog.

Michael Leonard

BY MICHAEL LEONARD

I am currently a Graduate student at the University of Arkansas. I have a strong interest in making things whether that be software, hardware, or something else entirely doesn’t matter to me.

When I’m not working on something I am an avid SCUBA diver, enjoy travel, and love a good round of golf. I am currently pursuing my Private Pilot License and hope to have that completed by December 2013.

If you would like to learn more about me and what I am working on visit my blog linked below.

http://michaelhleonard.com/

.END

2014-01-25

SWD / ISP in a box



























SWD / ISP in a box

.END

手作夢 - 林欣傑

$90租雷射切割 自嵌木唱盤 - 蘋果日報 2014年01月24日

http://hk.apple.nextmedia.com/supplement/tech/art/20140124/18603066

Dimension+ 藝術總監林欣傑(Keith) 雷射切割木唱盤$940

雷射切割木唱盤$940

曾經做過數次與手作有關的專訪,被訪者不約而同地認為,手作全因現實商品選擇不多,無法迎合自己要求;今回被訪者林欣傑亦如是,他以雷射切割或3D打印這些高科技器材輔助,創作出手作味濃的黑膠唱盤。不僅如此,他更開放器材及製作空間,助需要人士達成手作夢

記者:蘇家華 

攝影:楊錦文

除黑膠唱盤播放模組外,其他組件均由專人以人手組裝。

Dimension+ 工作室的裝潢以簡潔木材為主,很難聯想到這裏提供雷射切割機及3D打印機予用家使用。藝術總監林欣傑笑稱:「我們稱自己為『非大量生產版的Muji』,喜歡把木材和皮革應用在作品之上,我們以木為基調,用雷射切割機切割出來的黑膠唱盤,都是以淺木製。」

大抵音響發燒友不會把這個價值$940的黑膠唱盤放於心上,但在他或對喜歡手作製品的人而言,這可能是其中最令人驚艷的產品:「製作唱盤只是一廂情願的想法,我自己本身有聽黑膠唱片,但眼見不少年輕用家皆有碟無盤用,所以製作了這個設計簡單但功能齊全的款式,給樂迷一個另類選擇,也算回應了十年前的自己,回應了初聽黑膠唱碟但缺乏唱盤的年代。」

雖然Dimension+ 對以上所提的器材運用相當熟悉,但整個唱盤中,只有外殼是用上雷射切割,把木材裁成所需尺寸,然後由專門裝嵌唱盤的工匠負責組裝:「3D打印固然可以印出播放組件,但成本太高昂,製作時間極長。我們找來了OEM廠商,特別在擴音模組及音效輸出作細緻微調,並加上RCA端子以便外接喇叭,在音效理想度與製作成本的考慮下,才有此決定。」


 黑膠唱盤可播7吋、10吋及12吋唱片。

 林欣傑曾試製木製唱片,但最後卻不成功。

 加設RCA端子,可另駁喇叭聆聽。

 轉速有33轉、45轉、78轉三種可選。

 製作唱盤最大難度,是木材需另加夾板才能製作彎位。

開放器材半小時手作

工作室雖附設雷射切割機及3D打印機,但後者還在整理當中,暫不公開使用。前來試用器材的用家,暫時以皮革手作、時裝、建築及設計人士居多,他們的共通點是有製作藍圖,但缺乏金錢,林欣傑指:「我們的出發點是提供執行空間,雷射切割的特色,除可以同時切割同一圖案外,還因為切割機在裁切素材時,總會有些微偏差,所以組件被『燒燶』的部份每次都不同,使其變得獨一無二我們以半小時為一節,每次用家可先預約時間切割木材、皮革、亞加力膠片等素材;我們還提供電腦給用家修改用作切割的AI圖像檔案及刻字用的JPG檔案,那麼用家只需支付器材費用$90及材料費$10至$120不等,就可自行切割心水組件,加快製作時間。」

作為設計師的他認為,任何創作都須要經歷「手作」過程,方顯矜貴:「親手製作一件產品,無論是自用或送禮都別具意義,因此,無論是我們推出的產品或是用家使用我們器材製作的產品,我們均要求中有『手製』的概念,例如滑鼠墊和杯墊、即將推出的記憶卡讀卡器,都有個別組件需要用家自行組裝,令用家有更深刻的體驗,令產品有珍而重之的感覺,不局限於膚淺的消費層面。」

直擊雷射切割過程

1. Universal Laser Systems VLS2.30,最大切割範圍為16吋×12吋,素材厚度最多8mm,約值$150,000。

2.用家先把需要切割的圖形製成AI檔案,直線、曲線也可以。

3.把AI檔案複製至VLS2.30專用電腦軟件,調校切割火力等微細設定,有10W、25W及30W可選。

4.切割完成後,用家可打開面蓋把成品拿出,繼續其他製作步驟。

5.除了切割圖形,也可在素材表面刻字,支援JPG圖像檔案。

3D打印尚未普及

Dimension+的3D打印機尚在整理中,暫不公開使用,不過林欣傑仍開放予我們拍攝,他對3D打印機的普及程度有所保留:「3D打印無疑是近年科技界最重要的趨勢,不過我們眼見用家對操作、支援打印檔案等多方面知識,仍然非常缺乏,對3D打印尚停留在獵奇心態的階段。以一般應用而言,用家多用來印製小模型,作面見客戶、解釋設計概念之用。」

對於店舖理念,他這樣說:「整個工作室都是為有夢想、希望實踐概念的用家而設。只要有時間,本身對設計、器材製作有認識,並帶齊所需印製的檔案,就可以開始埋首創作,用頭腦及雙手將構思一一展現。」

場內擺放兩部3D Systems CubeX Duo3D打印機,須以ABS和PLA兩款塑料打印,前者是製作成品所用的物料,後者則是作打印期間的支撐物料;機價約值二萬港元

可打印最大10×10×9吋的製品,越多曲線的圖案,打印時間會越長,圖中鯊魚頭戒指約需印製半小時,重量為0.46g。

把需要打印的圖案以STL或GCO格式儲存,插進機身下方的USB端子,便會自動因應圖案逐層打印。

手作雷射成品

林欣傑認為市面上沒有型格及漂亮的讀卡器,故自己親手製作。這讀卡器支援CF、SD、microSD三種格式,以USB3.0傳送,$220。

滑鼠墊和杯墊用皮革、阿加力膠作混合素材,同樣以雷射切割機製,不過用家還需自行縫線,貫徹手作特色。滑鼠墊$240、杯墊$120。

木殼相機外形精美,但不作發售。

Dimension+ 地址:觀塘駿業里10號業運工業大廈3樓C室

3D打印行程

今年較具看頭的3D打印產品有Makerbot Digitizer3D掃描器,只需三分鐘便可擷取最大8×8×8吋的物件數據,以Replicator2打印,售價約$12,025。(查詢:http://www.makerbot.com/)

 美國Shapify.me推出的3D打印服務,可讓用家以Xbox Kinect鏡頭掃描主體,然後上載至網站打印,售價約$457,但只運送北美及歐洲地區。(查詢:https://shapify.me/)

.END

SPI 0,0, SPI 1,0 dual 7 segment LED tested OK





















SPI 0,0, SPI 1,0 dual 7 segment LED tested OK

.END

2014-01-24

Thursday, January 03, 2013 MCP23017 IO Expander - Test 01

























































Thursday, January 03, 2013 MCP23017 IO Expander - Test 01

http://fongelectronics.blogspot.hk/2013/01/mcp23017-io-expander-testing-notes_2.html

Now I am writing a Raspberry Pi Python function to blink the 8 LEDs connected to the IO port GPA0 to GPA7 of the IO Expander MCP23017 at device address 0x22.  

I will be using the register addresses with IOCON.BANK = 0.



I am using the following constants/variables/functions for the register addresses.


# * MCP23017 register addresses *

IO_DIRECTION_REGISTER_A_BANK_0 = IODIRA_B0 = 0x00
IO_DIRECTION_REGISTER_B_BANK_0 = IODIRB_B0 = 0x01

INPUT_POLARITY_REGISTER_A_BANK_0 = IPOLA_B0 = 0x02
INPUT_POLARITY_REGISTER_B_BANK_0 = IPOLB_B0 = 0x03

INTERRUPT_ON_CHANGE_REGISTER_A_BANK_0 = GPINTENA_B0 = 0x04
INTERRUPT_ON_CHANGE_REGISTER_B_BANK_0 = GPINTENB_B0 = 0x05

DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_0 = DEFVALA_B0 = 0x06
DEFAULT_COMPARE_VALUE_REGISTER_B_BANK_0 = DEFVALB_B0 = 0x07

INTERRUPT_CONTROL_REGISTER_A_BANK_0 = INTCONA_B0 = 0x08
INTERRUPT_CONTROL_REGISTER_B_BANK_0 = INTCONB_B0 = 0x09

IO_CONTROL_REGISTER_A_BANK_0 = IOCONA_B0 = 0x0a
IO_CONTROL_REGISTER_B_BANK_0 = IOCONB_B0 = 0x0b

PULL_UP_RESISTOR_CONFIG_REGISTER_A_BANK_0 = GPPUA_B0 = 0x0c
PULL_UP_RESISTOR_CONFIG_REGISTER_B_BANK_0 = GPPUB_B0 = 0x0d

INTERRUPT_FLAG_REGISTER_A_BANK_0 = INTFA_B0 = 0x0e
INTERRUPT_FLAG_REGISTER_B_BANK_0 = INTFB_B0 = 0x0f

INTERRUPT_CAPTURE_REGISTER_A_BANK_0 = INTCAPA_B0 = 0x10
INTERRUPT_CAPTURE_REGISTER_B_BANK_0 = INTCAPB_B0 = 0x11

GPIO_REGISTER_A_BANK_0 = GPIOA_B0 = 0x12
GPIO_REGISTER_B_BANK_0 = GPIOB_B0 = 0x13

OUTPUT_LATCH_REGISTER_A_BANK_0 = OLATA_B0 = 0x14
OUTPUT_LATCH_REGISTER_B_BANK_0 = OLATB_B0 = 0x15

IO_DIRECTION_REGISTER_A_BANK_1 = IODIRA_B1 = 0x00
INPUT_POLARITY_REGISTER_A_BANK_1 = IPOLA_B1 = 0x01
INTERRUPT_ON_CHANGE_REGISTER_A_BANK_1 = GPINTENA_B1 = 0x02
DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_1 = DEFVALA_B1 = 0x03
INTERRUPT_CONTROL_REGISTER_A_BANK_1 = INTCONA_B1 = 0x04
IO_CONTROL_REGISTER_A_BANK_1 = IOCONA_B1 = 0x05
PULL_UP_RESISTOR_CONFIG_REGISTER_A_BANK_1 = GPPUA_B1 = 0x06
INTERRUPT_FLAG_REGISTER_A_BANK_1 = INTFA_B1 = 0x07
INTERRUPT_CAPTURE_REGISTER_A_BANK_1 = INTCAPA_B1 = 0x08
GPIO_REGISTER_A_BANK_1 = GPIOA_B1 = 0x09
OUTPUT_LATCH_REGISTER_A_BANK_1 = OLATA_B1 = 0x0a

IO_DIRECTION_REGISTER_B_BANK_1 = IODIRB_B1 = 0x10
INPUT_POLARITY_REGISTER_B_BANK_1 = IPOLB_B1 = 0x11
INTERRUPT_ON_CHANGE_REGISTER_B_BANK_1 = GPINTENB_B1 = 0x12
DEFAULT_COMPARE_VALUE_REGISTER_B_BANK_1 = DEFVALB_B1 = 0x13
INTERRUPT_CONTROL_REGISTER_B_BANK_1 = INTCONB_B1 = 0x14
IO_CONTROL_REGISTER_B_BANK_1 = IOCONB_B1 = 0x15
PULL_UP_RESISTOR_CONFIG_REGISTER_B_BANK_1 = GPPUB_B1 = 0x16
INTERRUPT_FLAG_REGISTER_B_BANK_1 = INTFB_B1 = 0x17
INTERRUPT_CAPTURE_REGISTER_B_BANK_1 = INTCAPB_B1 = 0x18
GPIO_REGISTER_B_BANK_1 = GPIOB_B1 = 0x19
OUTPUT_LATCH_REGISTER_B_BANK_1 = OLATB_B1 = 0x1a

# * MAP23017 Register bank setting *

def setRegisterAddresses(bank):
    if bank == 0:
        IO_DIRECTION_REGISTER = IO_DIRECTION_REGISTER_A_BANK_0
 OUTPUT_LATCH_REGISTER = OUTPUT_LATCH_REGISTER_A_BANK_0
 GPIO_REGISTER = GPIO_REGISTER_A_BANK_0
 INTERRUPT_ON_CHANGE_REGISTER = INTERRUPT_ON_CHANGE_REGISTER_A_BANK_0
 DEFAULT_COMPARE_VALUE_REGISTER = DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_0
 INTERRUPT_CONTROL_REGISTER = INTERRUPT_CONTROL_REGISTER_A_BANK_0
 IO_CONTROL_REGISTER = IO_CONTROL_REGISTER_A_BANK_0
 INTERRUPT_FLAG_REGISTER = INTERRUPT_FLAG_REGISTER_A_BANK_0
 INTERRUPT_CAPTURE_REGISTER = INTERRUPT_CAPTURE_REGISTER_A_BANK_0 
    else:
        IO_DIRECTION_REGISTER = IO_DIRECTION_REGISTER_A_BANK_1
 OUTPUT_LATCH_REGISTER = OUTPUT_LATCH_REGISTER_A_BANK_1
 GPIO_REGISTER = GPIO_REGISTER_A_BANK_1
 INTERRUPT_ON_CHANGE_REGISTER = INTERRUPT_ON_CHANGE_REGISTER_A_BANK_1
 DEFAULT_COMPARE_VALUE_REGISTER = DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_1
 INTERRUPT_CONTROL_REGISTER = INTERRUPT_CONTROL_REGISTER_A_BANK_1
 IO_CONTROL_REGISTER = IO_CONTROL_REGISTER_A_BANK_1
 INTERRUPT_FLAG_REGISTER = INTERRUPT_FLAG_REGISTER_A_BANK_1
 INTERRUPT_CAPTURE_REGISTER = INTERRUPT_CAPTURE_REGISTER_A_BANK_1 

I am using the following function to blink 8 LEDs


def switchOffAll8LEDs(RegisterBaseAddress): 
    writeIOxPinsAllLow(RegisterBaseAddress)

def switchOnfAll8LEDs(RegisterBaseAddress): 
    writeIOxPinsAllHigh(RegisterBaseAddress)

def blink8LEDs(RegisterBaseAddress, OnTime, OffTime, Count): 
    setIOxPinsAllOutput(RegisterBaseAddress)
    for i in range(Count):
        writeIOxPinsAllHigh(RegisterBaseAddress)
        sleep(OnTime)
        writeIOxPinsAllLow(RegisterBaseAddress)
        sleep(OffTime)

And the following 3 functions blinks the 8 LEDs connected to MCP23017 GPA0 to GPA7 OK


setupGPIO()
startBeep()

blink8LEDs0x22MCP23017()


So far so good.  Next step is to update the project documentation.





.END



# *****************************************************************************
# *** tb18.py ***
# Program  - Test MCP23017 
# Version  - 1.9
# Date     - 2012nov30
# Update   - 2013jan03
# Author   - tlfong01(at)yahoo.cn 
# File     - tb19_2013jan03.py
# Blog     - http://blog.yahoo.com/_ZGD2MIDSBMSKHSUJW23LXRS2EQ/
# Purpose  - test basics of Raspberry Pi GPIO
# Hardware - Raspberry Pi Model B Revsion 2.0 [2012oct/nov/dec]
# Software - Raspbian Wheezy (2012sep15), Python 2.7.3 
#            GPIO 0.4.1a http://pypi.python.org/pypi/RPi.GPIO/0.4.1a
# Wiring   - RPi Board Numbering
#              P1-02 5V, P1-04 5V, P1-06 Gnd
#              P1-01 3V3, P1-03 I2C SDA1, P1-05 I2C SCL1
#              P1-08 UART TxD (MCP23017 Reset)
#              P1-10 UART RxD (MCP23017 INTB)
#              P1-12 RPi GPIO_GEN1 (BCM18) LED (P1-12 > LED > 330R > Gnd)
#              P1-14 Gnd
#              P1-16 GPIO_GEN4 - Buzzer, 3V3 5mA (P1-16 > Buzzer > Gnd) 
#              P1-18 GPIO_GEN5 Button (3V3 > 10K > Contact 1/2 > 330R > Gnd)
#              P1-20 Gnd
#              P1-22 GPIO_GEN6 - MCP23008 INT / MCP23017 INTA              

# *****************************************************************************
# *** Import Python modules ***

import smbus 
import sys
import RPi.GPIO as GPIO
from time import sleep
import select

# *****************************************************************************
# *** Configure RPi GPIO pins ***

# * RPi.GPIO setting *
GPIO.setmode(GPIO.BOARD) # Use RPi GPIO numbering, Not BCM numbering
GPIO.setwarnings(False)  # Disable linux's "pin already in use warning"

# * P1 pins numbering *
RPiGPIOgen1 = 12 # Brown  (P1-12, BCM GPIO 18) LED
RPiGPIOgen4 = 16 # Yellow (P1-16, BCM GPIO 23) Buzzer
RPiGPIOgen5 = 18 # Green  (P1-18, BCM GPIO 24) Button
RPiGPIOgen6 = 22 # Blue   (P1-22, BCM GPIO 25) IOx Interrupt

RPiTxD = 8 # Orange (P1-08) UART TxD
RPiRxD = 10 # Yellow (P1-10) UART RxD

# * IO device pins assignment *
LEDpin = RPiGPIOgen1
BuzzerPin = RPiGPIOgen4 
ButtonPin = RPiGPIOgen5
InterruptPin = RPiGPIOgen6
TxDpin = RPiTxD
RxDpin = RPiRxD

# * IO pins list *
OutputPinList = [LEDpin, BuzzerPin, TxDpin]
InputPinWithNoPullUpList = [ButtonPin, RxDpin]
InputPinWithPullUpList = [InterruptPin]


# *****************************************************************************
# *** Constants ***

# * General - counts, time periods, nibble types *

TWO_TIMES = 2
FOUR_TIMES = 4
EIGHT_TIMES = 8
TEN_TIMES = 10
TWENTY_TIMES = 20
FIFTY_TIMES = 50
ONE_HUNDRED_TIMES = 100
TWO_HUNDRED_TIMES = 200
FOUR_HUNDRED_TIMES = 400

TWENTY_MILLI_SECONDS = 0.02
FIFTY_MILLI_SECONDS = 0.05
TENTH_SECOND = 0.1
QUARTER_SECOND = 0.25
HALF_SECOND = 0.5
ONE_SECOND = 1
ONE_AND_HALF_SECONDS = 1.5
TWO_SECONDS = 2
ON_TIME = TENTH_SECOND
OFF_TIME = QUARTER_SECOND
BUTTON_DEBOUNCING_TIME = QUARTER_SECOND
TEST_TIME = 0.05

LOW_NIBBLE = 0
HIGH_NIBBLE = 1
BOTH_NIBBLE = 2 # full byte of 8 bits

# * Device constants *

# LED and buzzer states
OFF = False
ON = True

# Button states
PRESSED = False
RELEASED = True


# *****************************************************************************
# *** RPi GPIO functions ***

# Reference - Raspberry Pi Python GPIO Version - GPIO 0.4.1a 
# http://pypi.python.org/pypi/RPi.GPIO/0.4.1a

# RPi Model B 5V0 max current draw: 50 mA 
# RPi Model B 3V3 max current draw: 300 mA 
# GPIO maximum current draw per pin: 17mA source, 12mA sink

# * Setup, read, write GPIO pins *
setupOutputPin = lambda oPin: GPIO.setup(oPin, GPIO.OUT) # set GPIO pin as output

setupInputPinWithNoPullUp = lambda iPin: GPIO.setup(iPin, GPIO.IN, pull_up_down=GPIO.PUD_OFF) # set GPIO pin as input, no pull up

setupInputPinWithPullUp = lambda iPin: GPIO.setup(iPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # set GPIO pin as input, with pull up

writeOutputPin = lambda oPin, oValue: GPIO.output(oPin, oValue) # write value to output pin

setupWriteOutputPin = lambda oPin, oValue: (setupOutputPin(oPin), writeOutputPin(oPin, oValue)) # set and write

readInputPin = lambda iPin: GPIO.input(ButtonPin) # read value from input pin

def setupGPIOpins(outputPinList, inputPinWithNoPullUpList, inputPinWithPullUpList): # set up GPIO pins in InputPinList and OutputPinList
    for oPin in outputPinList:
       setupWriteOutputPin(oPin, OFF)
    for iPin in inputPinWithNoPullUpList:
        setupInputPinWithPullUp(iPin)
    for iPin in inputPinWithPullUpList:
        setupInputPinWithPullUp(iPin)

def setupGPIO(): # set up GPIO pins
     setupGPIOpins(OutputPinList, InputPinWithNoPullUpList, InputPinWithPullUpList )

# * pulse and echo functions * 
def pulsePin(oPin, onTime, offTime): # blink LED or beep buzzer
    writeOutputPin(oPin, ON)
    sleep(onTime)
    writeOutputPin(oPin, OFF)    
    sleep(offTime)

def echoPin(iPin, oPin): # echo input pin to output pin, e.g. button to LED or buzzer
    while True:
        if readInputPin(iPin) == RELEASED:
            pass
        else:
            pulsePin(oPin, ON_TIME, OFF_TIME)
            break
        continue

def togglePin(oPin, toggleTime): # toggle pin
    writeOutputPin(oPin, ON)
    sleep(toggleTime)
    writeOutputPin(oPin, OFF)    
    sleep(toggleTime)

# * Test GPIO functions *
def testBuzzer(): # beep 4 times
    setupGPIO()
    for i in range (FOUR_TIMES):
        pulsePin(BuzzerPin, ON_TIME, OFF_TIME)

def testLED(): # blink 8 times
    setupGPIO()
    for i in range (EIGHT_TIMES): 
        pulsePin(LEDpin, ON_TIME, OFF_TIME)

def testButtonEchoBuzzer(): #
    setupGPIO()
    for i in range (TEN_TIMES):
        echoPin(ButtonPin, BuzzerPin)          

def testButtonEchoLED(): #
    setupGPIO()
    for i in range (TEN_TIMES):
        echoPin(ButtonPin, LEDpin)

def testToggleTxDpin():
    while True:
        togglePin(TxDpin, TWO_SECONDS)

# *****************************************************************************
# *** Beep functions ***
def beep(count):
    for i in range(count):
        pulsePin(BuzzerPin, ON_TIME, OFF_TIME)
    
def startBeep():
    beep(TWO_TIMES)
    sleep(1)

def endBeep():
    beep(FOUR_TIMES)

def oneBeep():
    beep(1)

# *****************************************************************************
# *** IO Expander MCP23008 / MCP23017 ***

# * Bash script using i2cTools's i2cset command to toggle GPIO pins *
#!/bin/bash
# i2cset -y 1 0x20 0x00 0x00
# count=0
# while [ $count -lt 10 ];
# do
#  i2cset -y 1 0x20 0x0a 0x00
#  sleep 0.5
#  i2cset -y 1 0x20 0x0a 0xff
#  sleep 0.5
#  let count++
# done

# To run i2c-X commands in user mode: sudo chmod 666 /dev/i2c-X
# sudo chmod 666 /dev/i2c-1

# * Setup SMBus *

I2C_BUS_NUMBER = 1 # P1-03 = SDA1, P1-05 = SCL1
smBus1 = smbus.SMBus(I2C_BUS_NUMBER) # global variable, cannot be set by a function

# * MCP23008 device addresses *

MCP23008_1_REGISTER_BASE_ADDRESS = 0x20
MCP23008_2_REGISTER_BASE_ADDRESS = 0x21

# * MCP23008 register addresses *

IO_DIRECTION_REGISTER = IODIR_REG = 0x00
INTERRUPT_ON_CHANGE_REGISTER = GPINTEN = 0x02
DEFAULT_COMPARE_VALUE_REGISTER = DEFVAL = 0x03
INTERRUPT_CONTROL_REGISTER = INTCON = 0x04
IO_CONTROL_REGISTER = IOCON = 0x05
INTERRUPT_FLAG_REGISTER = INTF = 0x07
INTERRUPT_CAPTURE_REGISTER = INTCAP = 0x08
GPIO_REGISTER = GPIO_REG = 0x09
OUTPUT_LATCH_REGISTER = OLAT_REG = 0x0a

# * MCP23017 device addresses *

MCP23017_1_REGISTER_BASE_ADDRESS = 0x22
MCP23017_2_REGISTER_BASE_ADDRESS = 0x23

# * MCP23017 register addresses *

IO_DIRECTION_REGISTER_A_BANK_0 = IODIRA_B0 = 0x00
IO_DIRECTION_REGISTER_B_BANK_0 = IODIRB_B0 = 0x01

INPUT_POLARITY_REGISTER_A_BANK_0 = IPOLA_B0 = 0x02
INPUT_POLARITY_REGISTER_B_BANK_0 = IPOLB_B0 = 0x03

INTERRUPT_ON_CHANGE_REGISTER_A_BANK_0 = GPINTENA_B0 = 0x04
INTERRUPT_ON_CHANGE_REGISTER_B_BANK_0 = GPINTENB_B0 = 0x05

DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_0 = DEFVALA_B0 = 0x06
DEFAULT_COMPARE_VALUE_REGISTER_B_BANK_0 = DEFVALB_B0 = 0x07

INTERRUPT_CONTROL_REGISTER_A_BANK_0 = INTCONA_B0 = 0x08
INTERRUPT_CONTROL_REGISTER_B_BANK_0 = INTCONB_B0 = 0x09

IO_CONTROL_REGISTER_A_BANK_0 = IOCONA_B0 = 0x0a
IO_CONTROL_REGISTER_B_BANK_0 = IOCONB_B0 = 0x0b

PULL_UP_RESISTOR_CONFIG_REGISTER_A_BANK_0 = GPPUA_B0 = 0x0c
PULL_UP_RESISTOR_CONFIG_REGISTER_B_BANK_0 = GPPUB_B0 = 0x0d

INTERRUPT_FLAG_REGISTER_A_BANK_0 = INTFA_B0 = 0x0e
INTERRUPT_FLAG_REGISTER_B_BANK_0 = INTFB_B0 = 0x0f

INTERRUPT_CAPTURE_REGISTER_A_BANK_0 = INTCAPA_B0 = 0x10
INTERRUPT_CAPTURE_REGISTER_B_BANK_0 = INTCAPB_B0 = 0x11

GPIO_REGISTER_A_BANK_0 = GPIOA_B0 = 0x12
GPIO_REGISTER_B_BANK_0 = GPIOB_B0 = 0x13

OUTPUT_LATCH_REGISTER_A_BANK_0 = OLATA_B0 = 0x14
OUTPUT_LATCH_REGISTER_B_BANK_0 = OLATB_B0 = 0x15

IO_DIRECTION_REGISTER_A_BANK_1 = IODIRA_B1 = 0x00
INPUT_POLARITY_REGISTER_A_BANK_1 = IPOLA_B1 = 0x01
INTERRUPT_ON_CHANGE_REGISTER_A_BANK_1 = GPINTENA_B1 = 0x02
DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_1 = DEFVALA_B1 = 0x03
INTERRUPT_CONTROL_REGISTER_A_BANK_1 = INTCONA_B1 = 0x04
IO_CONTROL_REGISTER_A_BANK_1 = IOCONA_B1 = 0x05
PULL_UP_RESISTOR_CONFIG_REGISTER_A_BANK_1 = GPPUA_B1 = 0x06
INTERRUPT_FLAG_REGISTER_A_BANK_1 = INTFA_B1 = 0x07
INTERRUPT_CAPTURE_REGISTER_A_BANK_1 = INTCAPA_B1 = 0x08
GPIO_REGISTER_A_BANK_1 = GPIOA_B1 = 0x09
OUTPUT_LATCH_REGISTER_A_BANK_1 = OLATA_B1 = 0x0a

IO_DIRECTION_REGISTER_B_BANK_1 = IODIRB_B1 = 0x10
INPUT_POLARITY_REGISTER_B_BANK_1 = IPOLB_B1 = 0x11
INTERRUPT_ON_CHANGE_REGISTER_B_BANK_1 = GPINTENB_B1 = 0x12
DEFAULT_COMPARE_VALUE_REGISTER_B_BANK_1 = DEFVALB_B1 = 0x13
INTERRUPT_CONTROL_REGISTER_B_BANK_1 = INTCONB_B1 = 0x14
IO_CONTROL_REGISTER_B_BANK_1 = IOCONB_B1 = 0x15
PULL_UP_RESISTOR_CONFIG_REGISTER_B_BANK_1 = GPPUB_B1 = 0x16
INTERRUPT_FLAG_REGISTER_B_BANK_1 = INTFB_B1 = 0x17
INTERRUPT_CAPTURE_REGISTER_B_BANK_1 = INTCAPB_B1 = 0x18
GPIO_REGISTER_B_BANK_1 = GPIOB_B1 = 0x19
OUTPUT_LATCH_REGISTER_B_BANK_1 = OLATB_B1 = 0x1a

# * MAP23017 Register bank setting *

def setRegisterAddresses(bank):
    if bank == 0:
        IO_DIRECTION_REGISTER = IO_DIRECTION_REGISTER_A_BANK_0
 OUTPUT_LATCH_REGISTER = OUTPUT_LATCH_REGISTER_A_BANK_0
 GPIO_REGISTER = GPIO_REGISTER_A_BANK_0
 INTERRUPT_ON_CHANGE_REGISTER = INTERRUPT_ON_CHANGE_REGISTER_A_BANK_0
 DEFAULT_COMPARE_VALUE_REGISTER = DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_0
 INTERRUPT_CONTROL_REGISTER = INTERRUPT_CONTROL_REGISTER_A_BANK_0
 IO_CONTROL_REGISTER = IO_CONTROL_REGISTER_A_BANK_0
 INTERRUPT_FLAG_REGISTER = INTERRUPT_FLAG_REGISTER_A_BANK_0
 INTERRUPT_CAPTURE_REGISTER = INTERRUPT_CAPTURE_REGISTER_A_BANK_0 
    else:
        IO_DIRECTION_REGISTER = IO_DIRECTION_REGISTER_A_BANK_1
 OUTPUT_LATCH_REGISTER = OUTPUT_LATCH_REGISTER_A_BANK_1
 GPIO_REGISTER = GPIO_REGISTER_A_BANK_1
 INTERRUPT_ON_CHANGE_REGISTER = INTERRUPT_ON_CHANGE_REGISTER_A_BANK_1
 DEFAULT_COMPARE_VALUE_REGISTER = DEFAULT_COMPARE_VALUE_REGISTER_A_BANK_1
 INTERRUPT_CONTROL_REGISTER = INTERRUPT_CONTROL_REGISTER_A_BANK_1
 IO_CONTROL_REGISTER = IO_CONTROL_REGISTER_A_BANK_1
 INTERRUPT_FLAG_REGISTER = INTERRUPT_FLAG_REGISTER_A_BANK_1
 INTERRUPT_CAPTURE_REGISTER = INTERRUPT_CAPTURE_REGISTER_A_BANK_1 

# * Direction setting *

DIRECTION_BYTE_ALL_OUTPUT = 0x00
DIRECTION_BYTE_LOW_NIBBLE_OUTPUT_HIGH_NIBBLE_INPUT = 0xf0

# * Data pattern *

DATA_BYTE_ALL_ZERO = 0x00
DATA_BYTE_ALL_ONE = 0xff
DATA_BYTE_HIGH_NIBBLE_ONE_LOW_NIBBLE_ZERO = 0xf0
DATA_BYTE_HIGH_NIBBLE_ZERO_LOW_NIBBLE_ONE = 0x0f

# * Interrupt setting *

ENABLE_INTERRUPT_HIGH_NIBBLE = 0xf0
DEFAULT_COMPARE_VALUE_HIGH_NIBBLE = 0xf0
INTERRUPT_CONTROL_COMPARE_DEFAULT_HIGH_NIBBLE = 0xf0
INTERRUPT_PIN_PUSH_PULL_DRIVER_HIGH_ACTIVE = 0b00111010 # 0x3a, no auto add incre, no slew rate
INTERRUPT_PIN_OPEN_DRAIN = 0b00111000 # 0x38, no auto add incre, no slew rate

# * Setup IO direction *

def setIOxPinsAllOutput(registerBaseAddress): # set up all 8 IOx pins as output
    smBus1.write_byte_data(registerBaseAddress, IO_DIRECTION_REGISTER, DIRECTION_BYTE_ALL_OUTPUT)

def setIOxPinsLowNibbleOutputHighNibbleInput(registerBaseAddress): # set low nibble output, high nibble input
    smBus1.write_byte_data(registerBaseAddress, IO_DIRECTION_REGISTER, DIRECTION_BYTE_LOW_NIBBLE_OUTPUT_HIGH_NIBBLE_INPUT)

# * Writing data *

def writeIOxPinsAllLow(registerBaseAddress): # write zeros to all 8 IOx output pins
    smBus1.write_byte_data(registerBaseAddress, OUTPUT_LATCH_REGISTER, DATA_BYTE_ALL_ZERO)

def writeIOxPinsAllHigh(registerBaseAddress): #write ones to all 8 IOx output pins
    smBus1.write_byte_data(registerBaseAddress, OUTPUT_LATCH_REGISTER, DATA_BYTE_ALL_ONE)   

def writeIOxPins(registerBaseAddress, dataHexString): # write 8 bit hex string to IOx output pins
    smBus1.write_byte_data(registerBaseAddress, OUTPUT_LATCH_REGISTER, dataHexString) 

# * Reading data *

def readIOxPinsByte(registerBaseAddress): # read 8 bit hex data from GPIO register (= 8 output pin)
    hexByte = smBus1.read_byte_data(registerBaseAddress, GPIO_REGISTER)
    return hexByte

def readIOxPinsHighNibble(registerBaseAddress): # read high nibble from GPIO resister (= upper nible of output pins)
    hexByte = readIOxPinsByte(registerBaseAddress)
    hexNibble = hexByte >> 4
    return hexNibble

# * Interrupt setting *

def enableInterruptOnChangeHighNibble(registerBaseAddress): # enable high nibble interrupt on change
    smBus1.write_byte_data(registerBaseAddress, INTERRUPT_ON_CHANGE_REGISTER, ENABLE_INTERRUPT_HIGH_NIBBLE) 

def setInterruptOnChangeDefaultHighNibble(registerBaseAddress): # set high nibble default compare values
    smBus1.write_byte_data(registerBaseAddress, DEFAULT_COMPARE_VALUE_REGISTER, DEFAULT_COMPARE_VALUE_HIGH_NIBBLE) 

def setInterruptOnChangeCompareDefaultHighNibble(registerBaseAddress): # enable high nibble compare default
    smBus1.write_byte_data(registerBaseAddress, INTERRUPT_CONTROL_REGISTER, INTERRUPT_CONTROL_COMPARE_DEFAULT_HIGH_NIBBLE)

def setHighNibbleCompareDefault(registerBaseAddress): # set high nibble compare default
    enableInterruptOnChangeHighNibble(registerBaseAddress)
    setInterruptOnChangeDefaultHighNibble(registerBaseAddress)
    setInterruptOnChangeCompareDefaultHighNibble(registerBaseAddress)

def setInterruptPinPushPullHighActive(registerBaseAddress):  # interrupt pin push pull high active, no auto add inc, no slew rate
    smBus1.write_byte_data(registerBaseAddress, IO_CONTROL_REGISTER, INTERRUPT_PIN_PUSH_PULL_DRIVER_HIGH_ACTIVE) 

def setInterruptPinOpenDrain(registerBaseAddress): # interrupt pin open drain, no auto add inc, no slew rate
    smBus1.write_byte_data(registerBaseAddress, IO_CONTROL_REGISTER, INTERRUPT_PIN_OPEN_DRAIN) 


# * Interrupt reading *

def readInterruptFlagPinsHighNibble(registerBaseAddress): # read high nibble interrupt flag register
    hexByte = smBus1.read_byte_data(registerBaseAddress, INTERRUPT_FLAG_REGISTER)    
    hexNibble = hexByte >> 4
    return hexNibble   
    
def readInterruptCapturePinsHighNibble(registerBaseAddress): # read high nibble interrupt capture register
    hexByte = smBus1.read_byte_data(registerBaseAddress, INTERRUPT_CAPTURE_REGISTER)    
    hexNibble = hexByte >> 4
    return hexNibble  

# * Blink LED *

def switchOffAll8LEDs(RegisterBaseAddress): 
    writeIOxPinsAllLow(RegisterBaseAddress)

def switchOnfAll8LEDs(RegisterBaseAddress): 
    writeIOxPinsAllHigh(RegisterBaseAddress)

def blink8LEDs(RegisterBaseAddress, OnTime, OffTime, Count): 
    setIOxPinsAllOutput(RegisterBaseAddress)
    for i in range(Count):
        writeIOxPinsAllHigh(RegisterBaseAddress)
        sleep(OnTime)
        writeIOxPinsAllLow(RegisterBaseAddress)
        sleep(OffTime)

def blink4LEDs(RegisterBaseAddress, OnTime, OffTime, Count): 
    setIOxPinsLowNibbleOutputHighNibbleInput(RegisterBaseAddress)
    for i in range(Count):
        writeIOxPinsAllHigh(RegisterBaseAddress)
        sleep(OnTime)
        writeIOxPinsAllLow(RegisterBaseAddress)
        sleep(OffTime)

# * Testing *

def blink8LEDsMCP230080x20(): 
    blink8LEDs(MCP23008_1_REGISTER_BASE_ADDRESS, HALF_SECOND, ONE_SECOND, FOUR_TIMES) 

def blink4LEDsMCP230080x21(): 
    blink4LEDs(MCP23008_2_REGISTER_BASE_ADDRESS, HALF_SECOND, ONE_SECOND, FOUR_TIMES) 

def blink8LEDs0x22MCP23017(): 
    blink8LEDs(MCP23017_1_REGISTER_BASE_ADDRESS, TWO_SECONDS, TWO_SECONDS, ONE_HUNDRED_TIMES) 

def testInterruptPinFallingEdgeDetection(): 
    GPIO.cleanup() # set all input pins no pull up, disable all interutp detection setting
    setupGPIO()   
    GPIO.set_low_event(InterruptPin) # set up low level detection 

    for i in range(30):
        if GPIO.event_detected(InterruptPin):
     break
        else:
            print "No interrupt detected.", i
            sleep(1)
     continue

    GPIO.set_low_event(InterruptPin, enable = False)  # disable detection
    print "End of test, or interrupt detected"

# *****************************************************************************
# *** Unipolar Stepping Motor 28BYJ48 etc ***

# Unipolar Stepping Motor Switching Sequence 
# 1. Wave sequence = 1 - 3 - 2 - 4 (A-, B-, A+, B+)
# 2. Full step sequence = 13 - 14 - 24 - 23 (A-B-, A-B+, A+B+, A+B-)
# 3. Half step sequence  = 13 - 1 - 14 - 4 - 24 - 2 - 23 - 3 
# 4. One step swing = 1 - 3 - 1 - 3 (A-, B-, A-, B-)
# Winding        A-(1)    A+(2)    B-(3)   B+(4)    COM
# NPM PF35       Black    Yellow   Brown   Orange   Red
# 28BYJ48        Blue     Pink     Yellow  Orange   Red  
# PX245          Black    Green    Blue    Red      Yellow/White

# * Convert decimal pin number to hex *
def convert1PinToHex(p): # convert 1 of 8 high pin to hex
    hexString = 0x01
    for count in range(p-1):
    hexString = hexString << 1
    return hexString 
def convert2PinToHex(p1, p2):  # convert 2 of 8 high pins to hex
    return (convert1PinToHex(p1) | convert1PinToHex(p2))
def convert2PinToHighNibble(p1, p2):  # convert 2 of 8 high pins to high nibble
    lowNibble = convert1PinToHex(p1) | convert1PinToHex(p2)
    highNibble = lowNibble << 4
    return highNibble
def testConvert1PinToHex(): # test convert 1 high pin to hex
    print "*** Testing 1 pin number decimal 0 ~ 7 converted to hexdecimal 0x01 ~ 0x80"
    for d in range(8):
    print hex(convert1PinToHex(d))
def testConvert2PinToHex(p1, p2): # test convert 2 high pins to hex
    print "*** Testing 2 pin numbers decimal 0 ~ 7 converted to hexdecimal"
    print "Pin 1 = ", p1, "Pin 2 = ", p2
    print "Hex = ", hex(convert2PinToHex(p1, p2))
def testConvert2PinToHighNibble(p1, p2): # test convert 2 of 8 high pins to high nibble
    print "*** Testing 2 pin numbers decimal 0 ~ 7 converted to high nibble"
    print "Pin 1 = ", p1, "Pin 2 = ", p2
    print "HighNibble = ", hex(convert2PinToHighNibble(p1, p2))

# * Move unipolar stepping motor *
def writeSequence_13_24(RegisterBaseAddress, NibbleType, StepCount, StepTime): # move motor using 13-24 sequence  
    setIOxPinsAllOutput(RegisterBaseAddress)
    if NibbleType == LOW_NIBBLE:
 hexString1 =  convert2PinToHex(1, 3)
   hexString2 =  convert2PinToHex(2, 4)
    else:
 hexString1 = convert2PinToHighNibble(1, 3)
 hexString2 = convert2PinToHighNibble(2, 4)
    for i in range(StepCount):
        writeIOxPins(RegisterBaseAddress, hexString1)
    sleep(StepTime)
    writeIOxPins(RegisterBaseAddress, hexString2)
        sleep(StepTime)
def writeSequence_13_23_24_14(RegisterBaseAddress, NibbleType, StepCount, StepTime): #move motor using 13-23-24-14 sequence 
    setIOxPinsAllOutput(RegisterBaseAddress)
    if NibbleType == LOW_NIBBLE:
     motorWindingActivationPatternArray = (0x05, 0x06, 0x0a, 0x09)
    else:
 motorWindingActivationPatternArray = (0x50, 0x60, 0xa0, 0x90)
    for i in range(StepCount):
 for pattern in motorWindingActivationPatternArray:
     writeIOxPins(RegisterBaseAddress, pattern)
     sleep(StepTime)
def move2MotorsUsingMCP23008_1(): # move 2 motors one after another 
 oneBeep()
 writeSequence_13_24(MCP23008_1_REGISTER_BASE_ADDRESS, LOW_NIBBLE, TWENTY_TIMES, FIFTY_MILLI_SECONDS)
 oneBeep()
 writeSequence_13_24(MCP23008_1_REGISTER_BASE_ADDRESS, HIGH_NIBBLE, ONE_HUNDRED_TIMES, TWENTY_MILLI_SECONDS)
 oneBeep()
 writeSequence_13_23_24_14(MCP23008_1_REGISTER_BASE_ADDRESS, LOW_NIBBLE, TWENTY_TIMES, FIFTY_MILLI_SECONDS)
 oneBeep()
 writeSequence_13_23_24_14(MCP23008_1_REGISTER_BASE_ADDRESS, HIGH_NIBBLE, ONE_HUNDRED_TIMES, TWENTY_MILLI_SECONDS)
def move1MotorUsingMCP23008_2(RegisterBaseAddress, OnTime, OffTime, BlinkCount, CycleCount, StepTime ): # move motor on MCP23008 #2
    setIOxPinsLowNibbleOutputHighNibbleInput(RegisterBaseAddress)
    oneBeep
    for i in range(BlinkCount):
        writeIOxPinsAllHigh(RegisterBaseAddress)
        sleep(OnTime)
        writeIOxPinsAllLow(RegisterBaseAddress)
        sleep(OffTime)
    oneBeep()
    writeSequence_13_24(RegisterBaseAddress, LOW_NIBBLE, CycleCount, StepTime)


# *****************************************************************************
# *** Keypad *** 

# Keypad scanning procedure version 1.0
# 1. Set 3 column ports GP0, GP1, GP2 as output (GP3 don't care)
# 2. Set 4 row ports GP4, GP5, GP6, GP7 as input
# 3. Write LOW to all row ports
# 4. Wait for interrupt 
# 5. Pressing any key would cause an interrupt
# 6. When interrupt occurs check which row reads LOW
# 7. Write LOW only to column GP0, if row port still LOW, then this column 0
#    has a key pressed, if not, check if column 1, if not column 3.
# 8. Calculate the key using the column and row data.

# Read MCP23008 GP4 ~ GP7
def testReadGP4567(): # read keypad input rows 0~3
    RegisterBaseAddress = MCP23008_2_REGISTER_BASE_ADDRESS
    setIOxPinsLowNibbleOutputHighNibbleInput(RegisterBaseAddress)
    writeIOxPinsAllLow(RegisterBaseAddress)
    nibble = 0xf0
    while True: 
        oneBeep()
        sleep(1)
        nibble = smBus1.read_byte_data(RegisterBaseAddress, GPIO_REGISTER)
 print "GP4 to GP7 = ", hex(nibble)   

## * keypad base address and smBus setting *

keypadRegisterBaseAddress = MCP23008_2_REGISTER_BASE_ADDRESS
keypadSmBus = smBus1

# * Keypad columns numbering *
ColumnOutputPin0 = 0
ColumnOutputPin1 = 1
ColumnOutputPin2 = 2
ColumnOutputPinTuple = ColumnOutputPin0, ColumnOutputPin1, ColumnOutputPin2
# * Keypad row numbering *
RowInputPin0 = 0
RowInputPin1 = 1
RowInputPin2 = 2
RowInputPin3 = 3
RowInputPinTuple = RowInputPin0, RowInputPin1, RowInputPin2, RowInputPin2
# * Keypad matrix numbering *
KeyPadMatrixTuple = ColumnOutputPinTuple, RowInputPinTuple
# * Write keypad column data patterns *
ColumnAllLow = 0b000
Column0Low = 0b110
Column1Low = 0b101
Column2Low = 0b011
ColumnLowTuple = Column0Low, Column1Low, Column2Low

# * Read keypad data patterns *
RowAllHigh = 0b1111
Row0Low = 0b1110
Row1Low = 0b1101
Row2Low = 0b1011
Row3Low = 0b0111
RowLowTuple = Row0Low, Row1Low, Row2Low, Row3Low

# * Set, write, read keypad pins *
def assignKeypadReadWritePins(keypadRegisterBaseAddress):
    setIOxPinsLowNibbleOutputHighNibbleInput(keypadRegisterBaseAddress)

def writeColumnPins(keypadRegisterBaseAddress, columnPattern):    
    hexString = 0xff & columnPattern
    writeIOxPins(keypadRegisterBaseAddress, hexString)

def readRowPins():    
    hexNibble = readIOxPinsHighNibble(keypadRegisterBaseAddress)
    return hexNibble

# * test polling/interrupt keypad *
def scanKeypad(registerBaseAddress):   
    assignKeypadReadWritePins(registerBaseAddress)
    setInterruptPinOpenDrain(registerBaseAddress) # *** interrupt pin open drain !!!
    
    writeColumnPins(registerBaseAddress, ColumnAllLow)

    setHighNibbleCompareDefault(registerBaseAddress) # *** testing interrupt ***

    # Loop until one key pressed
    keyPressed = False
    while True:
        nibble = readRowPins()
        if nibble == Row0Low:
     row = 0
            keyPressed = True  
            print "Row 0 key pressed"
        elif  nibble == Row1Low:
     row = 1
            keyPressed = True 
            print "Row 1 key pressed"
        elif  nibble == Row2Low:
     row = 2
            keyPressed = True 
            print "Row 2 key pressed"      
        elif  nibble == Row3Low:
     row = 3
            keyPressed = True 
            print "Row 3 key pressed"
        else:
     row = 9
            #print "No key or more than one key pressed"                 

        if keyPressed == True:
     # Check which column the key is pressed
      column = 9
     writeColumnPins(registerBaseAddress, Column0Low)
     nibble = readRowPins()     
     if nibble != RowAllHigh:
         column = 0
                print "Column 0 key pressed"
            else:
                writeColumnPins(registerBaseAddress, Column1Low)
                nibble = readRowPins()     
                if nibble != RowAllHigh:
                    column = 1
                    print "Column 1 key pressed"
                else:
                    writeColumnPins(registerBaseAddress, Column2Low)
                    nibble = readRowPins()     
                    if nibble != RowAllHigh:
                        column = 2
                        print "Column 2 key pressed"
                    else:  
                        print "Error"

            # Calculate which key pressed

            keyNumber = (row * 3) + (column + 1) 

            print "Key pressed              = ", '{0:8}'.format(str(keyNumber).zfill(2).rjust(10))

            # *******************************************************************************
     # checking interrupt
            # *******************************************************************************
     # Check which column interrupt 

            interruptFlagNibble = readInterruptFlagPinsHighNibble(registerBaseAddress)
            interruptCaptureNibble = readInterruptCapturePinsHighNibble(registerBaseAddress)

            print "Interrupt flag nibble    = ", '{0:8}'.format((str(bin(interruptFlagNibble)).zfill(4)).rjust(10))
            print "Interrupt capture nibble = ", '{0:8}'.format((str(bin(interruptCaptureNibble)).zfill(4)).rjust(10))

      keyPressed = False
     sleep(1)
        else:
            pass

def testScanKeypad():
    scanKeypad(MCP23008_2_REGISTER_BASE_ADDRESS)

# *****************************************************************************
# * Old test functions *
# testLEDandBuzzer()
# testButton() !!! not working !!!
# blink8LEDsIOx1()
# blink4LEDsIOx2()
# testConvert1PinToHex()
# blink4LEDsIOx2()
# move1MotorUsingMCP23008_2(MCP23008_2_REGISTER_BASE_ADDRESS, HALF_SECOND, 
#                           ONE_SECOND, FOUR_TIMES, TWENTY_TIMES, ONE_SECOND)

# *****************************************************************************

# *** Old test functions ***

#setupGPIO()
#startBeep()
#blink4LEDsIOx2() # OK 2012dec14
#testReadGP4567() # OK 2012dec14
#testScanKeypad()
#endBeep()

# *****************************************************************************

# *** Current test functions ***

#testBuzzer() # beep buzzer 4 times
#testLED() # blink LED 8 tmes
#testButtonEchoBuzzer() # echo buton with buzzer 10 times
#testButtonEchoLED() # echo buton with LED 10 times
#testToggleTxDpin() # toggle TxD pin every 2 seconds

setupGPIO()
startBeep()

blink8LEDs0x22MCP23017()

# *****************************************************************************
# End of Program
# *****************************************************************************

.END