2017年12月16日 星期六

[STM32] SPI slave mode

之前比較常用的是SPI master的功能,到是第一次使用SPI slave的功能,測試的時後,就把SPI1 當作Master,SPI2當作Slave,cube的設定如下





假設要使用interrupt mode的話,在initialize的時後

hspi2.RxISR = SPI2_RXISR;
hspi2.TxISR = SPI2_TXISR;
hspi2.RxXferSize  = 1;
hspi2.RxXferCount = 1;
__HAL_SPI_ENABLE_IT(&hspi2, (  SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
__HAL_SPI_ENABLE(&hspi2);

最後加入interrupt handler 即可
uint8_t abc;
void SPI1_RXISR(struct __SPI_HandleTypeDef *hspi){
abc = *(__IO uint8_t *)&hspi->Instance->DR;
}


void SPI1_TXISR(struct __SPI_HandleTypeDef *hspi){
*(__IO uint8_t *)&hspi->Instance->DR = 0x12;
}

假設要使用DMA的話,和master的用法一樣:

#define COMM_RX_MESSAGE_SIZE  4
uint8_t spiStatus, bufferRx[COMM_RX_MESSAGE_SIZE], bufferTx[COMM_RX_MESSAGE_SIZE];

同master的用法:
HAL_SPI_TransmitReceive_DMA(&hspi2, bufferTx, bufferRx, COMM_RX_MESSAGE_SIZE);              

// spi complete callback function
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance==SPI2) {
// spi done
}
}

如果要做ping-pong buffer,可以call下面的function
HAL_SPI_TxRxHalfCpltCallback (SPI_HandleTypeDef *hspi)

確認DMA剩餘DATA, return length, 如果DMA是塞4 bytes,  收到4代表沒有資料, 0 代表master撈走了4個bytes。
length = __HAL_DMA_GET_COUNTER(&hdma_spi2_rx);

2017年9月30日 星期六

PIC12F1822 研究

這是一個有趣的案子,我也是第一次遇過這麼小顆的MCU,算是滿特別的際遇。

首先這顆就是顆8PIN的包裝,可以看出為了讓GPIO可以有最大的輸出,連MCLR(RESET)和ICE(ICSPDAT/ICSPCLK)都可以拿來當GPIO使用了!

另外就是這顆MCU滿特別的,有3組TIMER,但3 組TIMER的架構設計都不太一樣,主要是有些除了當TIMER之外,是可以當作PWM輸出使用,但這在F/W 設計確實也是一種複雜的設計,因為無法直接複製,需要量身定製。



這顆也有4 組ADC的功能,前3組都有照著GPIO對搭配(PA0-->AN0,PA1-->AN1,PA2-->AN2)唯獨PA4-->AN3

最後因這顆GPIO有限,又沒有充足的經驗,所以吃了不少苦頭,不過還好最後有順利結案!


2017年7月8日 星期六

[STM32] 如何量測MCU的耗電流(power consumption)?


之前在量測power consumption都是以target board 在做量測,因為這樣就不需要再重複量測一次了,不過像是stm32 的discovery或是nucleo,在板子上都有設計IDD,供量測power consumption使用。
我們來看一下說明,意思就是JP6就是一個可以斷IDD的Jumper,只要從這裡下手就好
我們看一下電路圖,就知道他設計的原理了,JP6就只是一個斷路Jumper
量測的時後只要把jumper 拔掉,裝上一顆電阻即可
這次使用10Ω的電阻

量到的電壓為0.118,由歐姆定律可以算得I=V/R, 所以得知電流為11.8mA。
當然,如果覺得這還是太複雜,可以用USB meter來做量測,只是會比較不準而已。
按住reset,或是用ice 在reset的時候先觀察一下電流,這個電流就是板子基本耗電流。
按了run之後,這個就是最大耗電流,70mA-60mA=10mA,不過因為我這台USB meter的精度只有小數2位,所以電流大概會落在10~20mA,都是有可能的。

STM32的開發板要做電流的量測,相對來說簡單許多。











2017年6月11日 星期日

STM32 CubeMX 4.21.0 改版

這陣子其實STM32 CubeMX 有改版4.21.0
這次的改版比較有感的就是直接把MCU比較重要的SPEC列出來,還有最重要的價錢都列出來了,不過單位是10K pieces,也就是1萬pieces,不過這對接案來說,是一個非常重要的參考指標

以前如果要知道MCU比較重要的information都要上STM32 的網頁product tree查

這次的改板還有把error handler做修正:
以前的版本就直接while(1)卡死在裡面,這次多了file 和 line的參數,之後就可以寫個debug log 直接吐出file和line方便debug。


雖然這次的改版讓開啟的速度又變慢了,但新增的功能有改善也算是一大福音,如果還有功能有改變的話,也可以和我說^^"

2017年6月2日 星期五

STM32F0 ADC calibration - part 2

還記得上一篇在討論ADC如果需要做準的話,需要面對的問題是什麼,後來有做了一些實驗,但感覺還是怪怪的,後來拿掉calibration 反而是好的,就覺得更怪,印象中的ADC還滿準的,怎麼這次這麼不準,後來才發現這次是用STM32CubeMx generate code base,而不知道為什麼,ADC module 竟然沒有開始ADC calibration的功能,翻了一下ADC的3個範例,發現其中一個範例有加這個功能,如下
註:目前使用的版本為:STM32Cube_FW_F0_V1.7.0
有興趣可以參考一下reference 的說明
也有提供example code,其實就是上面那個框起來的副程式。

ADC + no  auto calibration + internal voltage calibration:

ADC +  auto calibration 

ADC + auto calibration + internal voltage calibration


雖然數劇是只開auto calibration 比較好,但和hardware engineer 討論的結果,還是先保留第3個做法,等之後再完整的驗証。

結論:因為不是第一次踩到STM32CubeMX的Bug了,所以之後的功能如果可以還是對一下example code 比較保險……








2017年6月1日 星期四

STM32F072 & STM32F412 flash organization

因為之前比較常用STM32F072,所以覺得flash 應該彈性很高,一個page 2KB,1個sector=2個page, 所以在換在高階的STM32F412就不疑有它,但是在做firmware update的時後,發現有些不應該被動到的data也被清掉了,所以就來檢查一下STM32F412的定義為何。
這一檢查乖乖不得了,STM32F412的彈性好差,分成SECTOR0~3 16KB,SECTOR 4 64KB,剩下來的128KB,還好有早點發現,不然等到之後要合功能又要來大改一次了。 

結論: 在做memory layout的時後,最好還是看一下每顆MCU的flash organization,以免等到設計好發現有衝突又要大改一次。

STM32F0 DAC output buffer

之前我在看DAC的時後,只會在意輸出能力,準度。
還有DAC的register如何access:像是有分8bit/12bit,對齊左邊或是對齊右邊

不過stm32多出了一個output buffer,其實就是一個電壓隨耦器,目的就是希望MCU的DAC不要受外部電路影響

SPEC有說,如果不開output buffer的話,建議負載的阻抗要 > 1.5MΩ(對地) 如果開啟了output buffer的話,那麼阻抗就只只要>5 kΩ(對地)
看吧! 是不是差很多, 有了這個buffer 就可以比較不擔心被干擾了。

但請注意一下,開啟了output buffer 最低電壓請設在0.2v 最高電壓就是Vdda – 0.2V

結論:SPEC還是有需要認真看一下的。

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