LSI Jiu-Jitsu

電子工作とブラジリアン柔術

STM32で遊ぶ (11) - SPI

f:id:mohran:20200430211437j:plain

I2C接続のOLEDと同様にSPI接続のOLEDも表示させてみました。
OLEDのコントローラーはSH1106になります。

SPI信号は
 SPI1_NSS
 SPI1_SCK
 SPI1_MOSI
の3本を使用しました。

データシートより各信号のピン番号を調べると
 PA4
 PA5
 PA7
に割り当たっています。
https://www.st.com/ja/microcontrollers-microprocessors/stm32f446re.html
f:id:mohran:20200430222804j:plain
f:id:mohran:20200430222922j:plain

また、ボード(NUCLEO-F446RE)上の端子位置はこちらのデータシートより調べます。
https://www.stmcu.jp/design/hwdevelop/nucleo/51836/
f:id:mohran:20200430223245j:plain
f:id:mohran:20200430223259j:plain

OLEDへは送信のみなので、それほど複雑な設定は必要無いのですが、データとクロックエッジの関係は適切に設定する必要がありました。

SH1106のデータシートによると、クロック(SCL)とデータ(SI)の関係はこのように記載されています。
f:id:mohran:20200430224547j:plain

RM0390 - Reference manualによりますとSPI_CR1レジスタの「CPHA」と「CPOL」の組み合わせで4パターンのタイミングを作ることができますので、どちらも「1」を設定することでSH1106向けのタイミングとなります。
f:id:mohran:20200430224733j:plain

また、SCK周波数はSPIが接続されているAPB2が90MHzなのでSPI_CR1レジスタのBRへ0x7を設定することで256分周で約350KHzとしています。

使用したSPL関数は、データ送信のSPI_I2S_SendDataと、ステータスリードのSPI_I2S_GetFlagStatusの2つのみです。

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

ほか、OLEDに対するDCとRESは
 PB4 (DC)
 PB5 (RES)
を使用しました。
※ 後で気が付いたのですが、PB4はデバッガのリセットとしても使用されているのでブレークやステップ実行を行う際はPB6などに変更した方が良いです。

以上の設定で、いつもの馬の表示プログラムで組み上げてみました。


問題なく動きました。

ついでに先日購入した激安USBロジアナで波形を観測してみました。
f:id:mohran:20200430235726j:plain

SCKも約350KHzで想定通りの周波数になっています。
f:id:mohran:20200430235832j:plain

最後に、今までSPI OLEDのリセットは適当な時間でアサートしていましたが、この機会にきちんと調べてみました。
SH1106のデータシートによると、アサート時間10usec以上、デアサート時間2usec以上と記載されています。
f:id:mohran:20200501000249j:plain

プログラムではnopを200回入れて、アサートとデアサート時間を作っています。

GPIOB->ODR &= ~(0x1 << 5); for(int i=0; i<200; i++){ asm("nop"); }
GPIOB->ODR |=  (0x1 << 5); for(int i=0; i<200; i++){ asm("nop"); }

ロジアナで調べると14.5usecあるので問題なさそうです。
f:id:mohran:20200501000921j:plain

[参考記事]