2017年5月29日 星期一

STM32 CAN bus

CAN bus長得有點像是I2C,也長得有點像是RS485,但我覺得更合是合體的protocol,我覺得CAN bus是一個非常適合傳嚴謹的protocol,如果有興趣看CAN bus的protocol,應該可以找其他的介紹,應該會比我介紹的完整,這篇主要是介紹我在STM32上遇到的一些困難和記錄。

下圖是一個一般常見的CAN bus 使用方法,MCU接了一顆CAN transceiver,這也是normal mode的CAN bus。

CAN bus有三個測試 mode,用來自我測試程式是否有問題,比較常用的會是loop back, 如果使用normal mode 又沒有接CAN transceiver IC 也沒有接對應的CAN 的話,那麼就會無法通訊,通訊會fail。 原因是因為normal mode 需要有對應的CAN 來做ACK的動作,但如果是loop back就沒有這個問題,所以可以自我測試。


在STM32 cubeMX 產生出來的code,最重要的就是要調整CAN 的頻率,而頻率的調整就是要靠Time Quanta  in bit segment 1 / Time Quanta  in bit segment 2 和  ReSynchronization Jump Width這3個參數來決定,以我們的應用是500Khz,就要調出2000ns,這個很重要,如果頻率調錯了,是無法通訊的。

記得把RX的interrupt 打開,STM32的RX有support 2個FIFO,主要要看初始化如何設定,像我只需要1個FIFO,就只開FIFO0就好。
  if (HAL_CAN_Receive_IT(&hcan1, CAN_FIFO0) != HAL_OK)
  {
    /* Reception Error */
    OEM_Error_Handler(HAL_CAN1_ERROR);
  }
 會有2個FIFO的需求是因為CAN bus 可能會有很多interrupt,怕MCU太忙,可以用2個FIFO來分擔一下MCU的負擔,有點像是ping-pong buffer。

因為CAN bus 可以並接很多device,bus 上可能會非常的busy,如果每個ID都去檢查,這樣會造成MCU的負擔,所以我們只要檢查自己的ID就好,那麼就需做filter的動作,也就是說,只有屬於自己有關係的ID 才要去處理,其他的就都一概不理會,下面是STM32設計的filter架構: CAN 能設的組數很多, 也有分很多種模式, ID MASK 和 ID List, ID MASK 是選擇那些BIT 是否需要FILTER , ID LIST 像是白名單, 就是需要完全符合ID才行。
 
程式上,filterNumber 就是那個filter,BankNumber是指CAN 2由那個filter 開始。
這裡要補充一下,STM32 的dual CAN 並非2個獨立的CAN bus,而是CAN 1和 CAN 2 share 相關的register,主要就是filter的部分,因為是share的,所可以透過firmware 來做分配,但有一點一定要注意,CAN 2不能單獨使用,一定要enable CAN 1 才有辦法使用。
如果使用的是STM32F1 系列,請注意下面這個說明,白話文就是,CAN 和 USB 因為共用RAM,所以同個案子可以用USB和CAN,但是絕對不能同時使用!!!

因為我們需要dual CAN,本來選用STM32F105,但因為我們需要USB 也需要CAN bus,所以後來是選用STM32F412,除了功能更強之外,最意外的收獲就是這顆還非常省電的!



2017年5月27日 星期六

STM32F0 ADC calibration

如果有需要把ADC做準的話,需要先從MCU的SPEC開始K起……
!!!!!!!!!
有沒有這麼複雜?
看起來有喔!

先看一下介紹,如果不需要做很準的情況下,只要把ADC讀出來即可,但如果需要做準的話,除了VDDA需要注意,STM32F0需要注意internal reference voltage, 被放在channel 17的位置上

實際上的VDDA需要透過2個參數來進行校正:Vreferint_cal還有Vrefint_data, Vreferint_cal由MCU的內部ROM讀出,Vrefint_data就由ADC ch17 讀出,如下圖的公式


Vrefint_data的內部ROM值落在這裡,程式可以用(*(uint16_t*)0x1FFFF7BA)的方式取出

可以確認一下 internal reference voltage的情況


實測的結果:看起來還有一個固定的offset 存在

offset 目前是想在ADC上墊個固定offset,再把這個offet拉到一組ADC上,讀到的電壓減去offset,應該就可以消掉這個問題了!
待續……

STM32 Vbus sensing

在比較高階的STM的USB控制上,他有Vbus sensing的功能,他的功能主要是為了做安規上的控制:  假設device 自帶電源(self power),這樣如果一直讓D+ pull high的話,這樣USB connector的D+的地方就會有電,這樣安規會驗不過,所以比較好的做法就是偵測USB Vbus 是否有進來,假設Vbus 有進來的話,再把D+ pull high即可。
在沒有Vbus sensing的做法,就要靠電阻分壓,再利用GPIO 外部中斷來偵測,firmware偵測到Vbus進來後,自行控制D+ pull high的時機:

在有Vbus sensing的MCU上,只要將Vbus 接上PA9 Vbus sensing 的腳位上,並在程式initial 的時後啟動這個功能, 那麼MCU內部的hardware就會自動偵測Vbus 並且決定D+ pull high or not。
在SEPC裡面有說,如果需要開啟Vbus sensing的功能,就需要200uA的基本耗電,在有battery life 上,200uA其實不小。
Vbus 判斷的準位為4.25V


最後hardware上,請記得加裝ESD保護。 

或是選用USBUF,這顆是在Vbus多加一顆zener diode 防止Vbus 突波,功能就是over voltage protection。

假設USB device 是由USB 提供電源(BUS power),那就不需要考慮這個問題了XDDDD