2017年11月2日 星期四

LoRa Gateway / Concentrator


總之這是一個真正的LoRa Gateway,在說明之前我先釐清一下部分人的概念。
LoRa的Modulation除了有頻率的差別以外,還有一個很重要的是Spread Factor(SF),
這些參數要完全對上,一個普通的LoRa Transciver(SX127x)才有辦法收的到。

坊間很多人因為無知或是惡意誤導,會拿SX127x的那種Single Channel的IC去宣稱自己是Single Channel Gateway,這種和SX1301的Level完全不同。

真正在架設LoRa網路的所用的方法,是拿一顆(or 以上)專用的IC(SX1301/8)去弄,
SX1301/8內部是一個FPGA,前端有兩個個0.8Mhz的BW的RFFE把Raw IQ送給SX1301/8
然後SX1301/8內部的FPGA有49個LoRa decoder去解在這1.6Mhz裡面的LoRa封包。

而其中最主要的LoRa Channel是 8個Frequency x 7~12 SF 的48ch decoder,這48組可以同時解,也就是說即使Frequency相同,SF不同的狀況下都能解出來,不過這48組的BW被限制在125Khz。另外一組LoRa則隨意設定,還有個FSK的Channel則是為了短距離的通訊(因為速度夠快,而且因為距離近,收訊沒啥問題,速度夠快On The Fly就短,對於發射裝置來說耗電低,對於接收端來說單位時間所能收的客戶也變多)

所以LoRa Gateway請指名SX1301/8

First Try

續之前的LoRa project,我最主要的是需要一個Mult-Channel的Receiver,這計畫的第一版因為失敗,所以後來的7688 receiver才變成四個Channel的Single channel receiver去撐multi-channel。

那時候失敗最主要的原因是因為我沒有辦法把SX1301的FW成功的Load進去,但是SPI Bus的壓力測試是通過的,也就是裡面的那顆FPGA跑不起來所以整個卡半天都弄不好。

這大概是一年前的Project,那時候受限於SX1301這顆晶片並沒有放完整的Datasheet出來,我所參照的電路圖來自Microchip的LoRa Gateway User Guide,裡面有整個Gateway的完整電路圖,第一版的作法是SX1301那邊照抄,SX1255/7的部分因為有Datasheet,所以抄Datasheet。

不過到了今年年中的時候我發現SX1301竟然Release了Datasheet,所以茅起來檢查一下問題在哪,結果對了Pin腳對半天,竟然......
Reset的電位是拉高Reset,而不是常見的拉低Reset,所以不只是我沒有放電阻拉,後續補上的還拉錯方向。
另外一個比較小的問題是耗電量,我的第一版沒想太多就用LDO上,結果PO到Github就被別人發issue說LDO不夠用,一聽才知道,幹,SX1301的1.8V Rail吃掉0.6A....

所以就打算修正再來試一次,由於我那時候剛好在美國交換一兩個月,Pi Zero買了一堆
就做了一張給PI Zero用的版本,由於Layout塞不下,把一組RFFE拿掉,留一個SX1255/7
但是因為另外一邊超空,所以塞GPS模組提供PPS,然後因為我不想要拖一個天線在外面,就拿了一個有內建天線的模組來用。當然啦,也把LDO換成Switching,不過3.3V Rail就直接從RPI上面拿。
Ver2
這版終於跑起來了,整個超爽der,越想越爽就想說那就做一個RPI用的版本吧。

然後就做完了,不過不只是把第二個FE加回去而已,大致上第二版還是有幾個問題
第一個就是LoRawan所提供的lib裡面關於GPS校正時間的軟體,由於吃uBlox專用的指令,所以基本上只支援uBlox的GPS模組,所以沒辦法只好改用很兇的MAX-7Q上,懶得改lib。
第二個就是RX增加了Bias的位置與SAW Filter,最主要是因為SX1255/7是直接downconvert,而且IC內部並沒有SAW,又因為取樣的BW只有0.8Mhz,所以在這外面的訊號通通會變雜訊灌進來,所以還是放了Filter在上面,而Bias則是因為SX1255/7並沒有一個放大用的LNA,所以還是得加一個,而為了接線方便,同時考慮到天線頗長,所以設計上是有個小的板子接在天線正後方,負責Filter與Amp,然後透過RF上面放個DC的Bias去供應這張板子的電流。最後的小細節就是在SAW前面還有一個TSV,防ESD打壞SAW。
直接接起來大概長這樣,注意的是中間可以牽一段很長的SMA線沒問題

然後因為RPI的SPI device有兩個CE0/1,所以在背面也留了一個Jumper可以跳
像上面那張就是疊了一個915+一個433的版本。另外天線接頭的部分也為了選擇多樣性,用的是SMA/U.FL複合體,所以要上哪種都OK。最後就是SX1301運作的時候真的溫度不低,所以拿RPI用的散熱銅片貼上去這樣。

當然啦,以上這幾個改進都回到RPI Zero的版本

歷經一年的Project終於完工,我終於能夠用到同時 8-ch frequency x 7~12 SF的正常Gateway惹。



不過目前這版問題還是有的

第一個就是TX效能很差,因為直接從RFFE拉出來,內建有Driver,但是Power不大,
對我目前只需要Multi-Channel的狀況是還好,但是之後應該會需要用到TX,所以勢必是需要加一個PA,不然就是需要把SX1301的PA enable腳位拉出來,這樣我就可以另外接上一個PA然後用enable作為PA的開關。
第二個是Bias的問題,因為我現在只留了一個電感在那邊,所以用U.FL的時候,一旦不小心接到地,Bias會直接短路燒掉,所以我暫時的改法是後面接電阻,但是因為pad是0402,所以焊接的時候電感和電阻成三角形的方式焊接上去。


2017年6月19日 星期一

Linkit 7697 Badge

總之這是一個很奇妙的Project
最剛開始是主管看到那個Wifi Display,碰巧因為主管的主管想要發給工程師一人一片Linkit97的板子, 所以主管要我做一個類似的東西,但是因為成本的關係所以要改用別的螢幕

同時我聽到有人是想要做Badge,上面插Linkit 7688的那種。所以我同時Layout了兩個試試,一個是TFT LCD + Linkit 7697,另外一張是LED矩陣的Badge概念版。那時候Linkit 7697剛開始量產,還沒來的及打通一些奇奇怪怪的零件,所以想當然耳的TFT LCD其實還跑不了,就先把Badge版焊接一版出來看看。俗話說的好,數大便是美。288顆LED燈雖然用手焊接焊的要死要活,但是滿壯觀的,所以之後就變成了Badge版。

設計上就是兩個LED控制器,加起來可以控制288顆Led燈,規劃成18x16
另外還有一個三軸加速度計與亮度計,Input是一組方向鍵與四顆按鈕(ABXY)與兩個側邊按鈕

供電可以透過鋰電池或是電腦,同時接上的話會幫鋰電池充電
模組就和Linkit7697一樣用的是MT7697的模組,只是這是群登做的

這顆LED控制IC真的不錯
貪吃蛇

 俄羅斯方塊

這張板子大概是我第一次硬體完全都是我設計然後量產打件的,其實滿多點我想留在這邊當個紀錄

首先是板子零件選用,台灣的EMS廠商大都需要一個公司等級的供應商,通常小批量的就是Mouser,Digikey...等等的。但是這樣一來就會造成成本大增,因為這些地方小批量的價錢真的都不便宜,動輒好幾倍的價差。由於我之前都是上掏寶採買零件,這造成我非常大的成本估計落差,所以要嘛就是找到一家可以用掏寶的EMS,不然就是在選擇零件的時候,參考Mouser or Digikey等等的。另外就是請務必確認EMS廠商能夠使用掏寶來的零件以及符合時間要求,比方說EMS廠商要進口的時候,過海關會造成拖延。如果對掏寶的零件不熟悉的EMS廠來說,處理進口就會有非常大的延誤,可以的話建議是直接自己買,然後交給EMS廠商當客供料件,省去可能的問題。(P.S 以上的敘述中,我的量大約在1K以下)

然後就是BOM表了,如上所述,基本上BOM表需要有一個明確的廠商產品序號供EMS採買
但是有些零件例如電阻,電容等等的通用零件,其實可以詢問EMS廠商的庫存,以及合作的廠商,把所需要的電阻值與精度或者是電容值與電容特性給EMS廠商就可以了。

再來還有打件的零件圖,由於打件後,需要檢查打件有無問題,需要一個參照的圖表標示各個位置的電阻值

最後就是生產的時候會需要有測試程式確認每個零件的焊接都正常,這程式我建議是硬體設計完就可以開始寫了,然後硬體焊接測試的時候就可以直接上,省時間。
工廠的測試試算時間的,所以測試時間也是越短越好,也因此測試的手續越簡單越好。

最後的最後就是,因為這個東西電路板就是最後的外觀,整個電路的設計都需要考慮到視覺的效果,比方說零件的對稱性還有排列的整齊度。
如果用的是亮面的PCB Soldermask的話,那連電路的走線都需要考慮一下。

硬體講完了來講軟體
總之就是雜,功能有以下三種

1.貪吃蛇
2.俄羅斯方塊
3.時鐘

貪吃蛇和時鐘是我自己刻的,俄羅斯方塊是移植

底層的Library修改自Adafruit的Library,就是變成兩顆IC這樣,省去我還要再另外包一層。
然後上層接上Adafruit GFX。

整個Code因為功能不少,所以拆成幾個部分:

1.控制,包含LED矩陣與按鈕
2.貪吃蛇
3.時鐘
4.俄羅斯方塊的一堆Code

Code的部分倒是還好,我比較想講的是Dual buffer。

當我要更新一個Frame的時候,如果我直接動到正在顯示的那個記憶體空間,
在Clear frame的時候就會造成LED矩陣會有一瞬間被清空,導致動畫會有閃爍的情形,
還好這顆LED控制器裡面有8個Frame buffer,所以我可以指定寫入下一個Buffer再通知IC說顯示下一個Buffer,而實際上我只用了兩個做Dual buffer。

其他的倒也還好,MT7697裡面硬體功能不少,而Arduino IDE裡面也可以直接叫出Hal來用。
比方說遊戲所需要的隨機號碼產生器,可以看到我是Call MT7697內建的TRNG,而不是Random() + RandomSeeed。

最後的最後就是亮度計會自動校正螢幕的亮度,因為我非常不喜歡太亮的LED,所以在每次Update螢幕的時候都會去抓亮度計的讀數,唯一可惜的是我忘記加上Filter了....


我的資料都放在Github了,可以看看
https://github.com/will127534/Linkit7697_Badge










2017年4月16日 星期日

Low Power WiFi Weather Display


總之這是一種試驗看看WiFi的耗電量究竟可以做到什麼程度,設計上以耗電量作為主要的考量
螢幕用的是Sharp Memory LCD,之前用過的感想覺得效果真的很棒,所以看到秋葉原賣另一個型號就請別人帶回來了,這次用的是2.7" 400x240的版本,不過技術和之前96x96的有差異,這個比較像是以前的TFT LCD,只是增強了反射性,但是耗電量還是相當的低,Datasheet規格是50uW = 5V x 10uA (這個螢幕真需要5V),雖然不像之前的那個拔掉一兩分鐘都還有顯示就是了XD

功能目前是每六個小時去撈中央氣象局的OpenData,抓36小時的天氣預報顯示這樣

核心這次有兩個,分別是WiFi SoC 的 MT7687,與 Power Management 的 MSP430G2553

首先來講一下MT7687,這顆是聯發科新推出的WiFi SoC, 標準的ARM Cortex - M4, 特色是記憶體有300K,而且有Arduino IDE支援, Prototype很快.
https://docs.labs.mediatek.com/resource/mt7687-mt7697/zh_tw/downloads
另外一個是MSP430G2553,由於Sharp Memory LCD需要一個Low Freq的Clock去翻Vcom的電位,所以單純只用WiFi Soc耗電量我想會有點太大,所以想找一顆小的MCU專門開關MT7687以及生出Memory LCD需要的Clock.最先的目標其實是手邊有一堆的Attiny84/85,但是後來研究了一下才發現這系列的待機耗電量還頗大...想想倒不如拿MSP430來做,發現便宜的G2553待機耗電量(With LPM3)就遠遠超過了Attiny85的能耐,只有1uA,而且可以用32Khz的Clock做timer,就拿MSP430G2553做了


然後是電源供應的設計,由於Memory LCD需要5V的電壓,所以勢必是需要一個5V的Step-up,
又因為這個螢幕超省電的,所以目光集中在低附載的效率與Iq,找到一顆Ti的TPS61099,BGA封裝還滿省空間的,而且從Datasheet看起來,感覺就是為了這目的(Low Power LCD Bais)設計的XDD

而3.3V因為MT7687的電流不小,所以決定還是用一個Buck-Boost增加效率,同樣找Iq與輕載效率高的,找到的是Ti的TPS62740,然後想說乾脆就在Ti找一個鋰電池的充電IC,就挑了個BQ24045

另外,由於PCB需要Cover到Memory LCD作為支撐,所以有一整面的空白覺得太空虛了,所以找了一個NFC Tag作為設定Wifi AP/Passwd用,然後再LCD底下放滿滿的NFC天線


然後就開始寫程式了
首先當然是要先寫個Parser去處理Wifi設定,Wifi 為了方便使用,有些廠商會在AP上面裝上NFC Tag,格式是同一個=>application/vnd.wfa.wsc

稍微查了一下格式長這樣:
Header : 0x10
Data Type: one byte
Data Length:two byte
Data[len]

Data type:
0x26 : Network index
0x45 : SSID
0x03 : authentication type
0x0F : encryption type
0x27 : Password
0x20 : MAC Address

encryption type分為:
0x0001 None
0x0002 WEP Deprecated.
0x0004 TKIP Deprecated. Use only for mixed mode.
0x0008 AES Includes both CCMP and GCMP

Authentication Type分為:
0x0001 Open
0x0002 WPA-Personal deprecated in version 2.0
0x0004 Shared deprecated in version 2.0
0x0008 WPA-Enterprise deprecated in version 2.0
0x0010 WPA2-Enterprise includes both CCMP and GCMP
0x0020 WPA2-Personal includes both CCMP and GCMP

Code 大概是這樣
使用方式是把NFC的資料Array和SSID,Passward與有無加密的Variable address pass進去
阿記得就是SSID,Passward的陣列開大一點,我在寫的時候沒檢查喔O.<
void parsing(uint8_t *data,uint8_t len,uint8_t *SSID,uint8_t*PASSWD,bool* auth){

  for(int i=0;i<len;i++){
    if(data[i]==0x10){  //Headder get
       i = i + 1;
       uint16_t len = (uint16_t)data[i+1]<<8 | (uint16_t)data[i+2];
       uint8_t type = data[i];
       //Serial.print("Type:");Serial.print(type,HEX);Serial.print(" Len:");Serial.println(len);
       if(type == 0x45){  //SSID
           display.println("SSID:");
           for(int k=0;k<len;k++){
             SSID[k] = data[i+3+k];
             //Serial.println(SSID[k]);
             display.write(SSID[k]);
           }
           //display.write((char*)SSID);
           display.println();
           display.refresh();
       }
       if(type == 0x0E){
          continue;
       }
       if(type == 0x27){   //PASSWD
           display.println("Passward GET");
           for(int k=0;k<len;k++){
            PASSWD[k] = data[i+3+k];
            //Serial.println(PASSWD[k]);
            //display.write(PASSWD[k]);
           }
           //display.write((char*)PASSWD);
           //display.println();
           display.refresh();
       }
       if(type == 0x03){
          display.println("Auth:");
          if(data[i+4]==0x01){
            *auth = 0;
            display.println("OPEN");
          }
          else{
            *auth = 1;
            display.println("WPA");
          }
          display.refresh();
       }
       i = i + 2 + len;
    }
  }
}


然後接下來是去撈Opendata......
所以我說那個中央氣象局為啥要用XML啊啊啊啊啊啊啊啊

真心覺得崩潰,所以我就不貼上來了Orz....
有需要再問,我再整理放上來

接下來是要把資料顯示出來,首先就是要顯示中文,然後就崩潰惹
因為再沒有外掛Flash的狀況下,一個中文字型檔案~1Mb是放不進去MCU的
所以我需要做兩件事情,地一個是把我要顯示的中文字列出來,第二件事情是找出一個方法
讓我可以把UTF-8的字找到對應的點陣字的Array index

第一件事情很簡單,拿個Python Script把CWB的Opendata說明檔的每個字抓出來比對就好
第二件事情我用的方式是Hash function,透過事先計算出一個UTF-8->index的Hash Function

我目前用的Graphics library是Adafruit GFX,所以我稍微修改了一下library之後
用Python做出前面的兩件事情之後,生出GFX用的fontfile.
其他的我就丟Github了:https://github.com/will127534/AdafruitGFX-ChineseFont-Addon

最後是MSP430惹,MSP430的工作非常簡單,就是要生出Clock還有關MT7687
MT7687結束的時候,會拉高一個pin,通知MSP430關電源這樣
我有點偷懶的是都寫在timer interrupt裡面,沒有特別開GPIO Interrupt就是了

#include  <msp430g2553.h>

#define Power P3_6

volatile unsigned int MT7687SleepCount = 0;
volatile bool MT7687Sleeped = 0;

void setup(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
     
BCSCTL1 |= DIVA_3; // ACLK/8
BCSCTL3 |= XCAP_3; //12.5pF cap- setting for 32768Hz crystal


        P1DIR = 0xFF;
        P2DIR = 0xFF;
        P3DIR = 0xFF;
     
        P1OUT = 0x00;
        P2OUT = 0x00;
        P3OUT = 0x00;
     
 
        pinMode(P3_7,OUTPUT);
     
        pinMode(Power,OUTPUT);
        digitalWrite(Power,LOW);
        delayMicroseconds(500);
     
        pinMode(P1_4,INPUT);
        pinMode(P1_5,INPUT);


CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 255; // 512 -> 1 sec, 30720 -> 1 min
TACTL = TASSEL_1 + ID_3 + MC_1; // ACLK, /8, upmode

_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interrupt
}
void loop(){
    _BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interrupt

}
// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
digitalWrite(P3_7,!digitalRead(P3_7));

        if(digitalRead(P1_5)==HIGH){
          digitalWrite(Power,HIGH);
          pinMode(P1_4,OUTPUT);
          digitalWrite(P1_4,LOW);
          MT7687SleepCount = 0;
          MT7687Sleeped = 1;
        }
     
        if(sleep){
          MT7687SleepCount ++;
          if(MT7687SleepCount>43200){
            digitalWrite(Power,LOW);
            delayMicroseconds(50000);
            pinMode(P1_4,INPUT);
            MT7687Sleeped = 0;
          }
        }
     
}

每隔半秒就翻轉一次Pin,這樣耗電量<1uA


少數幾個缺點大概列一下

首先就是該隔離的就該隔離,MT7687因為要控制LCD,所以SPI一定要接在一起,但只要MT7687電源關閉,那SPI拉高的CS就會倒灌回去MT7687造成很大的耗電量,我原先以為MT7687的Floating Well就是設計來擋掉這件事情的,但是實測發現很明顯地沒有,所以才多了那一堆銅線Orz

第二個就是沒辦法量電壓,雖然板子上有預留測量Vbat的電阻,但是我沒有斷開分壓電阻的機制,這樣一來會造成漏電.

應該是不會繼續改版了,畢竟這樣穩穩用也沒啥問題
一切都藏得好好der







2017年2月18日 星期六

High Altitude Ballooning with LoRa fifth launch


總之終於來到了第五次的飛行,與之前的不同在於這次終於將分時多工投入測試了
雖然很久以前就開始跑分時多工,但是測試都只放出一個,並沒有真的跑過一次同時一個以上
最主要的問題在於GPS並沒有辦法Lock住,這等等來講.將GPS解決了之後,TDMA跑起來就很順了
上圖可以很明顯地感覺到掃Channel的感覺

同時由於舊的接收機內部真的太亂,組裝有點鬆散,所以決定設計一套新的電路專門做為接收機用
架構圖如下:


硬體上主要是有四個LoRa模組(對不起我的SX1301 Gateway測試頗失敗的,所以還是四個單通道去湊)然後第一組LoRa模組可以用SX1278+RF FE(30db PA)取代,這樣也能讓接收機去打訊號給node,為未來的Project鋪路,然後模組與ATmega328相連之後用UART接上MT7688.
供電的部分則是透過mini USB或者是鋰電池供電,可以同時接也可以只接任意一個,然後MT7688透過Step-down供電,ATmega328+LoRa模組透過LDO供應.
另外附帶USB轉UART,透過SW切MT7688 Serial console or ATmega328.GPS則是外接一個模組.

不過問題大概就是SD卡的WP/CD沒有拉/接地,所以剛開始7688抓不到SD卡


有電路板差很多
MT7688透過Nodejs架的Server基本上差不多,就只是多了幾個通道這樣,不過因為我發現如果我把四組做上去的話,外殼應該是拿不下來了(RF接頭擋到),所以先上兩個

然後就是新版的Node了,以前到現在最大的問題就在於GPS的穩定性,前幾次由於換成了沒有LNA的天線,訊號更弱了,所以測試起來GPS有時有有時無,但是有趣的是,我去掏寶買了兩種GPS模組,一個是MAX-7Q自製版(拿uBlox的IC做),另外一個是L7(MT3333),MT3333的模組看起來就很正常,雖然TTFF也是需要將近80~100s,但是至少穩定的定到位,反而uBlox的就常常定不了
後來熱風槍一拆才發現,MT3333的模組有一個SAW在旁邊,uBlox的沒有,所以這問題大概是由於底下的LoRa模組打訊號打到上面的GPS模組,有SAW的話就能濾掉了.所以新版的就是加了外部的LNA+SAW,讓TTFF壓到了<50s.


另外這次的氣球也改用塑膠氣球,不過因為比較小顆所以一次要弄五六顆才行.
(重量基本上也是在21~25g之間)

由於這次的地面測試比較頻繁一點,正式升空的時候問題不大,訊號都還不錯

接收機的設置是一個全向性一個指向性(~10db),而距離最遠達到72km,然後,是的我又忘記把計算完的仰角與方位角放到網頁上,所以我指的方向有點落差.


軌跡大概是這樣,可以看到氣球衝過邊界層之後風向改變往東,然後又跌回邊界層的兩個又再次轉向西北.

氣球也很爭氣,一路撐到LOS都沒有顯著的洩氣.最遠的那個還在繼續飄

這次測試有一個問題就是通道是切好了,但是不同模組之間如果同時收到封包,很可能造成切到了下一個通道才把上一個通道的資料傳回來,然後就被誤認成下一個通道的資料
看起來需要切通道的時候檢查Buffer,或者是調整一下SPI的速度