2020年5月17日日曜日

STM32でDCCを作る方向で (14) DAC出力のために1

告知です.
コミケ99にて当社のDDC/DACを頒布いたします.
  日付   2021年12月31日(金) 東地区 テ-40b  東5ホール
  サークル名    bangflat
コミケにお越しの際はお立ち寄りいただけますとありがたいです.
商品紹介ページを作りました.

ーーーー
NUCLEO-F207をtargetとしてDCCを作ろうとしている.今回も重箱の隅つつきをおこなう.
なお今回から、USB peripheralはOTG-HSを使う.関数名の末尾が_FSから_HSに変わっていたりするのはそのせい.

前回は、
  1)USB device setupの実装状況
  2)audio stream処理の入り口
まで理解できた.

audio stream処理の入り口とは、bufferに80mSec分のPCM dataが積まれた時点でcallされる関数を特定できた、というような意味である.
    ファイル名:usbd_audio.c        関数名:USBD_AUDIO_DataOut()
この関数の中でAudioCmd()がcallされる.
AudioCmd()の中身は空っぽになっているので自力でDAC出力codeを追加する必要あり.
要はPCM dataをDACへ出力してやればよい.DACへ出力するとは、I2Sへ送るDMAを起動するというような意味である.(諸事情によりDMA targetはI2SでなくてSPI3とする)

ここまでが第13回調査隊報告書のあらましだった.

------
実機で動かしてみた.
AudioCmd()にbuffer→DMA→SPI3へ転送する関数を追加する.
Linuxマシンからaplayで音楽再生してUSBにaudio streamを流しこむ.

audio streamは確かに来ているんだが音が出ない.

数日間う~んと悩んだ.まだ完全解決には達していないがsamle codeの構造が判ってきた.

まず判ったことは、USBD_AUDIO_DataOut()はaudio streamの先頭でしかAudioCmd()をcallしない.先頭以外では黙々とpacketをbufferに積むだけなのだ.日常的にAudioCmd()をcallする者は他にいる. 

色々と調べたら、日常的AudioCmd()業務の担当者はこいつだった.
    ファイル名:usbd_audio.c        関数名:USBD_AUDIO_Sync()
なのだが、実機動作ではこいつが全くcallされないんだよ.こいつをcallする管理者を探さにゃいかんくなった.

管理者はこの人だった.
    ファイル名:usbd_audio_if.c        関数名:TransferComplete_CallBack_xx()
    ファイル名:usbd_audio_if.c        関数名:HalfTransfer_CallBack_xx()
関数名から、buffer→DMA→SPI3転送完了割り込み、転送半分割り込み らしい.
CallBack関数なのだから元を辿ればいずれかの割り込みが源泉であるはずだ.
こいつらがどの割り込みに紐づけされているのかを調べたけれどsample codeの何処にもいない.当然callされもしない.自分でcodeを追加してくれという事情のようだ.

AudioCmd()にはbuffer→DMA→SPI3転送を起動する関数を仕込む.
    ファイル名:stm32f2xx_hal_spi.c      関数名:HAL_SPI_Transmit_DMA()
これのsource codeを見ると転送完了系割り込みを律儀に用意してくれているのである.
    SPI_DMATransmitCplt()          ←転送完了割り込み関数の登録場所
    SPI_DMAHalfTransmitCplt()    ←転送半分割り込み関数の登録場所
有難く使わしてもらいます.

------
buffer→DMA→SPI3転送に、転送完了割り込み、転送半分割り込み をかけてもらうにはどうしたらいいのか? 2つ操作が必要.

1)main.c の中にあるSPI3初期化関数 MX_SPI3_Init() にてCallBack関数を登録する.
/* USER CODE BEGIN SPI3_Init 2 */
HAL_SPI_RegisterCallback( &hspi3, HAL_SPI_TX_COMPLETE_CB_ID,
     TransferComplete_CallBack_HS );
HAL_SPI_RegisterCallback( &hspi3, HAL_SPI_TX_HALF_COMPLETE_CB_ID,
     HalfTransfer_CallBack_HS );
/* USER CODE END SPI3_Init 2 */

2)登録したCallBack関数を有効化する.
USE_HAL_SPI_REGISTER_CALLBACKS=1にする必要がある.
場所はここ.
    ファイル名:stm32f2xx_hal_conf.h      161行目
これを怠ると登録しても無視される.

説明順序があべこべであるが、
3)AudioCmd()にbuffer→DMA→SPI3起動関数を追加する.
static int8_t AUDIO_AudioCmd_HS(...........){
  switch(cmd)  {
    case AUDIO_CMD_START:   初回のみ
     HAL_SPI_Transmit_DMA(&hspi3, pbuf, AUDIO_TOTAL_BUF_SIZE);
    break;
    case AUDIO_CMD_PLAY:    グルグル
     HAL_SPI_Transmit_DMA(&hspi3, pbuf, AUDIO_TOTAL_BUF_SIZE);
   break;
  }
  return (USBD_OK);
}
#DMAモードは、HAL_SPI_Transmit_DMAを複数回callしているので、Normalであり、Circleではないと推測している.    →Circleじゃないとダメみたいよ.CircleであってもDMA複数回callして挙動がおかしくなりはしないっぽい.Normalだと隙間が空いてしまう.

以上の追加によって少なくとも、audio streamが継続的にSPI3へDMAされるようにはなる.まだマトモな音は出ないがね.

かしこ


0 件のコメント:

コメントを投稿