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 件のコメント:
コメントを投稿