STM32 I2S DMA TxHalfCplt 回调仅执行一次

问题描述 投票:0回答:1

我正在使用 I2S DMA 使用双缓冲技术播放一些 wav 文件(固定格式和采样率),

不知何故,当传输开始时,TxHalfCplt Callback仅调用一次,然后停止工作。只有 TxCplt 正常工作。这会导致每次回调时只有缓冲区的后半部分被重新填充,而缓冲区的前半部分留下剩余数据并在 DAC 中播放。

如果我使用

printf
和 UART 来调试它,则在执行 TxHalfCplt 回调时将执行 UART 发送。但其他标志则不然。

这很奇怪。该代码在 RTOS-CMSIS V2 中运行,我已将任务的优先级设置为最高。我还缺少什么?

任务中的代码

 uint32_t task_stat = STOP_TASK;
  uint32_t StartAddr = 0x00000; // Sample Siren Audio Track
  uint32_t EndAddr = 0x4FFFF;
  uint32_t currentAddr = 0x00000;
  uint32_t flashOffsetHalfBuffer = (AUDIO_BUFF_SIZE / 2) * sizeof(uint16_t); // 2 bytes per Channel sample, each half buffer is 4096 bytes
  uint32_t flashOffsetFullBuffer = AUDIO_BUFF_SIZE * sizeof(uint16_t); // 2 bytes per Channel sample, each full buffer is 8196 bytes

  /* Infinite loop */
  for(;;)
  {
    if(osMessageQueueGet(test_TaskQueueHandle, &task_stat, NULL, osWaitForever) == osOK){
      // Process the received message
      printf("TEST STARTED\r\n");
      // fill up the buffer (full buffer)
      initAudioData(StartAddr, dacData);
      currentAddr = StartAddr + flashOffsetFullBuffer;
      FLAG_I2S_DATA_READY = 1;
      
      // Start DAC
      HAL_I2S_Transmit_DMA(&hi2s1, (uint16_t *)dacData, DMA_MAX(AUDIO_BUFF_SIZE / 2));

    } else {
      // Handle error
      printf("ERR: TASK HANDLE MSG QT\r\n");
    }
    while (task_stat == RUN_TASK) {

      if( FLAG_I2S_DATA_READY == 0 ){
        if((currentAddr + flashOffsetHalfBuffer) <= EndAddr){
          // Process Audio Data
          if(processAudioData(currentAddr, dacPtr) == STAT_OK){
            // Increment Start Address
            currentAddr += flashOffsetHalfBuffer;
            FLAG_I2S_DATA_READY = 1;
            // Buffer loading debug output
            //if(FLAG_FIRST_HALF_RELOAD == 1){
            //  printf("F\r\n");
            //} else if(FLAG_SECOND_HALF_RELOAD == 1){
            //  printf("S\r\n");
            //}
          }

        } else {
          // Redirect Current Address to Start Address, Hence the Circular Playback
          currentAddr = StartAddr;
          // Process Audio Data
          if(processAudioData(currentAddr, dacPtr) == STAT_OK){
            // Increment Start Address
            currentAddr += flashOffsetHalfBuffer;
            FLAG_I2S_DATA_READY = 1;
            // Buffer loading debug output
            //if(FLAG_FIRST_HALF_RELOAD == 1){
            //  printf("F\r\n");
            //} else if(FLAG_SECOND_HALF_RELOAD == 1){
            //  printf("S\r\n");
            //}
          }
        }
      }

      
      if(osMessageQueueGet(test_TaskQueueHandle, &task_stat, NULL, 1) == osOK){
        // Process the received message
        printf("TASK PAUSE\r\n");
        HAL_I2S_DMAStop(&hi2s1);
        // Purge DAC Buffer?
        currentAddr = 0x00000;
        // Stop Task
        task_stat = STOP_TASK;
      }
      

    }

    osDelay(1);
  }

回调:

void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s){
  dacPtr = &dacData[AUDIO_BUFF_SIZE/2];
  FLAG_I2S_DATA_READY = 0;
  FLAG_FIRST_HALF_RELOAD = 0;
  FLAG_SECOND_HALF_RELOAD = 1;
  /* Callback debug output*/
  //printf("C\r\n");
}

void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s){
  dacPtr = &dacData[0];
  FLAG_I2S_DATA_READY = 0;
  FLAG_FIRST_HALF_RELOAD = 1;
  FLAG_SECOND_HALF_RELOAD = 0;
  /* Callback debug output*/
  //printf("H\r\n");
}

定义:

// DMA Flag
volatile uint8_t FLAG_I2S_DATA_READY = 1;
volatile uint8_t FLAG_FIRST_HALF_RELOAD = 0;
volatile uint8_t FLAG_SECOND_HALF_RELOAD = 0;

// DMA Buffer
uint16_t dacData[AUDIO_BUFF_SIZE];
// Buffer Pointer
static volatile uint16_t *dacPtr = &dacData[0];
arm stm32 freertos cmsis i2s
1个回答
0
投票

看起来这是一个愚蠢的错误。

当我传输 16 位音频数据时,DMA 必须使用半字(16 位)而不是字(32 位)进行配置(即使 I2S 设置为在 32 位帧中传输 16 位数据)。否则中断似乎无法找出中点在哪里。

© www.soinside.com 2019 - 2024. All rights reserved.