2020年9月1日火曜日

STM32でDCC/DDCを作る方向で (50) 設計資料 USB データの流れをcodeで追う2

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

STM32でDCC/DDCを作ろう!            INDEXページへ

情報が間違っていても責任とらないし賠償とかしないです.

audio data flowをcodeで追いたく思います.

投稿48で書いた【endpoint 1の辺り】を具体的に説明します.

前回の動画で語ったとおり、USBD_AUDIO_DataOut()という関数に動作が集約されていますのでその関数を説明します.

↓リングバッファの定義、30720bytes、+4はご愛敬.
uint8_t pbuf32[AUDIO_TOTAL_BUF_SIZE+4];

↓packet毎に125uSec毎にここがcallされます.
USBD_AUDIO_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
  USBD_AUDIO_HandleTypeDef   *haudio;
  uint32_t rcvcnt;
  uint32_t* psrc;
  uint32_t* pdst;
  uint16_t size;
  int i;

  haudio = (USBD_AUDIO_HandleTypeDef *) pdev->pClassData;

↑haudio構造体の中には2つのpacketバッファが入っています.packetの偶奇で交互に使われます.
  uint8_t buffer_packet0[512];
  uint8_t buffer_packet1[512];

↓EP1であるかどうかの確認
  if (epnum == AUDIO_OUT_EP)  {

↓packetが来なければ再生STOPするためのフラグ
  packet_watch=1;  // to detection of stop

↓rcvcntには入ってきたdata bytesが格納されます.ex.384
  rcvcnt = USBD_GetRxCount(pdev, AUDIO_OUT_EP); // bytes in a packet

↓リングバッファのコピー先アドレス
  pdst = (uint32_t*) &pbuf32[haudio->wr_ptr];

↓2つあるpacketバッファのセレクト
  if(haudio->buffer_writing==0)
                 psrc = (uint32_t*) haudio->buffer_packet0;

  else           psrc = (uint32_t*) haudio->buffer_packet1;
  size = rcvcnt/4;

↓packerバッファからリングバッファへのコピー.__REVはLEBE変換.リングバッファのendまで到達したらゼロへ戻す.
  i=0;
  while(i++<size) {
    *pdst++ = __REV(*psrc++);
    if(pdst==&pbuf32[AUDIO_TOTAL_BUF_SIZE]) pdst=pbuf32;
// buf full
  }

↓リングバッファのポインタ更新、およびバッファフル操作.
  haudio->wr_ptr += rcvcnt;
  if(haudio->wr_ptr >= AUDIO_TOTAL_BUF_SIZE) {
  haudio->wr_ptr -= AUDIO_TOTAL_BUF_SIZE;
// buffer full
  }

↓SPI DMAの起動処理.起動条件は再生先頭かつリングバッファ半分のとき.
  if (haudio->wr_ptr >= AUDIO_TOTAL_BUF_SIZE/2) { // buffer half?
  if (audio_cmd == AUDIO_CMD_WAIT0) { // 再生先頭?
  audio_cmd = AUDIO_CMD_START; // PLAY start

↓44.1k/48k XTALのうち使わない方をOFFする操作
  HAL_GPIO_WritePin(FPGA_CKBON_PRT, FPGA_CKBON_BIT, 0);

↓LRCK生成FPGAをリセットする操作
  HAL_GPIO_WritePin(FPGA_RESTART_PRT, FPGA_RESTART_BIT, 1);

↓SPI DMA起動.SPIには再生停止するまで勝手に走ってもらいます.
  HAL_SPI_Transmit_DMA(&hspi1, pbuf32, AUDIO_TOTAL_BUF_SIZE);

↓LRCK生成FPGAを起動する操作
  HAL_GPIO_WritePin(FPGA_RESTART_PRT, FPGA_RESTART_BIT, 0);
  }
}

バッファ操作は以上でおしまいです.

ここから下は、次のpacket受信のためのお膳立てです.EP1を受信待機状態にします.packet偶奇でどっちのpacketバッファをONにするかを切り替えます.
  if(haudio->buffer_writing==0)  {
haudio->buffer_writing = 1;
USBD_LL_PrepareReceive(pdev, AUDIO_OUT_EP, haudio->buffer_packet1, AUDIO_OUT_PACKET);
  }
  else  {
haudio->buffer_writing = 0;
USBD_LL_PrepareReceive(pdev, AUDIO_OUT_EP, haudio->buffer_packet0, AUDIO_OUT_PACKET);
  }


以上でUSBD_AUDIO_DataOut()という関数の仕事はおしまいです.意外と簡単.data flowはこんなものということです.

なお、SPI DMAが起動されて以降はSTM32のcodeはSPIに対してほとんどする事がありません.勝手にserial dataが出ていきます.

ただ、読者の疑問は、サンプリング周波数などの設定はどこでやっているのか?ではないでしょうか.それはdata flowではなく、USB setup関連のカテゴリになります.後日解説します.

かしこ

0 件のコメント:

コメントを投稿