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的速度






2016年11月26日 星期六

GPS Antenna test


可能有人注意到我在High Altitude Ballooning with LoRa Fourth launch用的探空儀
GPS天線的部份兩個是不一樣的,主要是因為我當時在設計的時候找到一個非常小的GPS天線
原本抓地到訊號,但是一把其他零件裝上去卻又遲遲Lock不住,所以只好換成另外一種7mm的GPS天線.

所以為了測試天線的效能,這次做一次地面的探空儀測試,兩組裝上不同GPS天線,固定在三角架上測試GPS的性能以外,順便也做一次耗電量的測試.


探空儀還是同一個設計,只是GPS模組的部分因為MTK沒有指令可以Query 目前的GPS資料
只能把一些多餘的NEMA關掉,對Atmega328的Interrupt base的UART來說,TDMA的第一格可能會出問題,因為要處裡GPS丟出來的訊號.所以我還是回去用ublox的MAX 7Q.



最終結果如下:

下兩張圖是GPS衛星的天空軌跡,shaded的顏色是衛星經過時的訊號強度,中間的一槓代表板子的擺放,而凸出來的那根是表示板子的正面
7mm晶片型天線

迷你型晶片天線
首先來講一下7mm的那支天線,可以很明顯的看出來因為板子不是為了這支天線所設計的,焊接的時候並不能避免天線的背面的衰減,理想上應該是要一個圓形對稱
迷你型的比較正常,基本上呈現圓對稱,但是訊號弱了大概1~5db,其中在低仰角的部分根本低到0db了
再來講到細節,注意到板子背面其實還有一個小的死角,其中迷你天線的訊號比較沒那麼低
我的猜測是電池座的鐵片干擾到了天線的接收,而由於電路板上面有做迷你天線的反射面,所以對其影響不大.


電池的話則是出現一個很有趣的現象,看起來用迷你的天線比較省電
另外就是因為電池用的是一次性鋰電池,初始電壓達到1.7,不過迅速降到1.4之後平緩的下降
可惜沒有整個過程都跑完,不過總時間達到四小時三十七分鐘

其他問題最大的大概就是氣壓計的初始誤差了,可以看到兩台的溫溼度基本上一致
但是兩個的氣壓差了
大概0.6hPa左右,還滿恐怖的不過還在Datasheet的正負1hpa之內

2016年11月9日 星期三

High Altitude Ballooning with LoRa Fourth launch



這次最主要的是探空儀改版,從上圖很明顯的可以看出來面積再次的下降
壓到了2x5cm(不包含外部感應器),幾乎是兩個AAA電池的大小了

為了縮小面積,最主要的GPS模組換成MAX-7相容的L70-R,氣壓計換成BMP280
另外Atmega328也換成MLF的版本,唯獨16Mhz的Crystal與RFM98沒換
而升壓電路維持同一個晶片,但是電感換成體積更小的了

BMP280真的很小,旁邊有一個0402的電容可以比較

另外也把SHT21+GPS的天線做在同一張板子上,這樣一來就不用另外再接線了,減低重量也簡化組裝,SHT21為了減少主板的影響,所以中間的PCB寬度很窄,一不小心真的會扳斷

而ISP換成1.25mm的插座,原本用接觸點+彈簧針的方式真的是很不方便而且占面積

天線也換成5/8波長的多芯線,比之前的單芯線重量少很多
所以..這次的減重答案就是.....

各位觀眾,七公克,七公克,七公克
雖然加上電池就變十五克,但是比起之前的重量少了快60%

這次還是打算用鋁箔氣球做測試


接收機還是一樣一個全向性與指向性

一樣還是全向性接收機用的是Linkit 7688架的Server,然後指向性天線是用筆電收

所以iPhone和筆記型電腦都可以直接看到接收的狀態

然後這次的飛行最主要的問題就是我的指向性天線沒有對準,所以導致全向性天線接收機的RSSI比指向性天線好非常多,當然也有可能是我的指向性天線已經有點問題了,這可能要在查一下,不過幸好全向性天線的狀況不錯,整個過程都能接收的到訊號,所以基本上資料沒斷

結果如下:

基本上還是一到高度就開始漏氣然後往下掉,最高到四千公尺左右

電壓這次的測量方式改成用內建的Bandgap,應該比較準一點,可以看到從一剛開始的1.47v一路下降到1.34v,但是有趣的是之後的斜率有點改變,而整個曲線也不像是正常的電池放電那種
我可能之後會做一個正常的探空圖,不過多少用這個可以看看端倪
這天基本上沒啥逆溫層,上去下來的溫度也差不多,不過濕度差異頗大,可以看到1000m處
應該是有雲啦,要算一下水氣量

RSSI的話很明顯可以看到這次指向性比全向性還要好,最主要的問題是我指錯方向..
下一版接收軟體應該會把方位角與仰角顯示出來
這張是兩個資料合併的結果,所以RSSI的變化有點大,不過還是可以看出來基本上極限在-96~100附近

最後就是GPS衛星數最大有11顆,以一個晶片型天線來說很不錯了
還有最遠距離13.19km,不過基本上是因為氣球掉下去才結束的