DMAでSPIの出力です
送信するデータはconst uint8_t *Buffで与えられます
1回に512バイトをDMAで出力し、出力が終わるまでwhileでループします
エディタからソースコードをコピペしてきたので行番号がついてるのはご容赦ください
173 DMA_InitTypeDef DMA;
174
175 DMA.DMA_PeripheralBaseAddr = (uint32_t)(&SPI1->DR);
176 DMA.DMA_MemoryBaseAddr = (uint32_t)Buff;
177 DMA.DMA_DIR = DMA_DIR_PeripheralDST;
178 DMA.DMA_BufferSize = 512;
179 DMA.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
180 DMA.DMA_MemoryInc = DMA_MemoryInc_Enable;
181 DMA.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
182 DMA.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
183 DMA.DMA_Mode = DMA_Mode_Normal;
184 DMA.DMA_Priority = DMA_Priority_Medium;
185 DMA.DMA_M2M = DMA_M2M_Disable;
186
187 DMA_DeInit(DMA1_Channel3);
188 DMA_Init(DMA1_Channel3, &DMA);
189 DMA_Cmd(DMA1_Channel3, ENABLE);
190 SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
191
192 while (DMA_GetCurrDataCounter(DMA1_Channel3));
193 while (!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
メモリ2メモリとほぼ同じ感じでできます
違いとしては
1. ペリフェラルアドレスを適切に設定する
2. ペリフェラルのインクリメントはdis
3. M2Mもdis
4. DMA_Cmdを実行した後にペリフェラルのDMACmdを実行
5. ウエイトはDMA_GetCurrDataCounterだけではダメ
こんな感じです
まずペリフェラルアドレスについて
STM32F1のSPIはSPI_I2S_SendData関数を使って出力しますが
DMAの場合はレジスタアドレスを指定する必要があります
レジスタはSPIx->DR(DataRegister)です
データレジスタは配列ではないのでインクリメントも無効にしておきます
メモリ間転送ではないのでM2MもDisableにします
あとはDMA_Initの後にDMA_Cmdですが、M2Mと違い自動的に始まるわけではありません
SPI_I2S_DMACmdでDMAのトリガーをかけてやる必要があります
このトリガーにより適切なタイミングでSPIのレジスタにデータが転送されるようになります
また、メモリ間転送の場合、転送終了はGetCurrDataCounterで検出できますが
SPIの場合はちょっと違っていて、転送が終了してもSPIの送信が終了しているとは限りません
そのため、ソフトウェアでCS端子を操作している場合は、SPIの転送が終わらないうちにCSがネゲートされてしまいます
それを防ぐためにSPI_I2S_GetFlagStatusで送信完了フラグを確認する必要があります
SPIでマスタから一方的にデータを送る場合は比較的簡単に実現できますが
Webの情報を見た感じ、SPIの受信は一工夫必要な感じがあるようです
DMAを使ったデータ転送はSDSPIライブラリではなく、SPIライブラリに書いたほうがいろいろ使い回しができて便利だったかもしれません
例えば送信と受信の双方をDMAで行う関数を作っておけばセンサからのデータを読む場合に簡単になります
低レベルのAPIを書き換えると高レベル側全てに影響するため、結構面倒そうですが 試してみる価値はあるかも
STM32F1のDMAは実質的にDMA1の7chしかなく、その7chも様々なペリフェラルが共存しているので、データ転送をDMAだけでやることはほぼ不可能でしょう
例えばSPI1の受信とUSART3の送信 SPI1の送信とUSART3の受信は同じチャネルを使っています
これからの基板設計はGPIOの配置だけではなく、DMAのことも考慮する必要がありそうです
(例えばSDカードはSPI1を使うためUSART3はDMAが使えない のような)
GPIOのリマップのようにDMAのチャネル入れ替えも欲しい機能ですね
もっとも、USARTは送信・受信割り込みを使った送受信バッファを作ってしまったので、DMAを使う必要はあまり感じておらず、その点ではSPI以外にDMAが必要なIOも無いので気にしなくてもいいという気もしますが
0 件のコメント:
コメントを投稿