STM32
直播中

石正厚

7年用户 1136经验值
私信 关注
[问答]

1 SAI_A做master TX发送8 slot数据,为什么会出现0数据的情况?

测试1 SAI_A做master TX,发送8 slot数据,产生时钟的同时会发送数据出来:

测试2  SAI_A做master RX, 发送8 slot数据,SAI_B做slave TX且和A同步,B经过示波器抓取波形如下:

可以看到,红框内第一个slot数据为0。在前面有时钟的地方,有几帧都是0数据。不知道这是配置问题还是原始设计如此?
附加代码:

  • #define  USE_ANALOG_CHIP
  • #define SAI_AUDIO_IN_SLOT   8
  • #define SAI_AUDIO_OUT_SLOT  8
  • #define SAI_AUDIO_SAMPLING_FREQUENCY 48000
  • #define SAI_AUDIO_IN_BUF_LEN (SAI_AUDIO_SAMPLING_FREQUENCY/1000 * SAI_AUDIO_IN_SLOT * N_MS*2) //16ms data
  • #define SAI_AUDIO_OUT_BUF_LEN (SAI_AUDIO_SAMPLING_FREQUENCY/1000 * SAI_AUDIO_OUT_SLOT * N_MS*2) //16ms data

  • /*
  • * SAI1用来和A2B通信,根据连线图其中Block A作为rx,Block B作为tx
  • * SAI3用来和AD1938通信,根据连线图其中Block A作为rx,Block B作为tx
  • * 所以,可以通过用宏分开的方式,同时配置SAI1和SAI3,实现代码的复用
  • *
  • * 上行需要传8路音频数据,目前是初步保持和原始Final_OUT_Buff相同顺序,前4路mic原始数据+后4路纯净数据。
  • *  -其中A2B要求slot宽度为32bit
  • * 下行是回声消除数据,之前只需要2路,文斌建议预留4路~8路供以后算法扩展。
  • */

  • SAI_HandleTypeDef   SaiHandle_A_RX;
  • DMA_HandleTypeDef   hSaiDma_A;
  • SAI_HandleTypeDef   SaiHandle_B_TX;
  • DMA_HandleTypeDef   hSaiDma_B;
  • static int16_t SAIBuffer_A[SAI_AUDIO_IN_BUF_LEN] __attribute__((section(".data_DMA")));
  • static uint16_t SAIBuffer_B[SAI_AUDIO_OUT_BUF_LEN] __attribute__((section(".data_DMA")));
  • static int16_t SAI_RX_Data_8ms[SAI_AUDIO_IN_BUF_LEN/2];
  • static int16_t SAI_TX_Data_8ms[SAI_AUDIO_OUT_BUF_LEN/2];

  • void hxd_SAI_CLK_Config(void) {
  •     RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;
  •     /* 16/1*96/125=12.288M */
  •     RCC_PeriphCLKInitStruct.PLL2.PLL2M = 1;
  •     RCC_PeriphCLKInitStruct.PLL2.PLL2N = 96;
  •     RCC_PeriphCLKInitStruct.PLL2.PLL2P = 125;
  •     RCC_PeriphCLKInitStruct.PLL2.PLL2Q = 1;
  •     RCC_PeriphCLKInitStruct.PLL2.PLL2R = 1;

  •     RCC_PeriphCLKInitStruct.PLL2.PLL2RGE    = RCC_PLL2VCIRANGE_3; // 这里能保证PLL2输出的频率范围是8MHz到16MHz之间,否则12.288M配不上去
  •     RCC_PeriphCLKInitStruct.PLL2.PLL2VCOSEL = 0;

  •     RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI3;
  •     RCC_PeriphCLKInitStruct.Sai23ClockSelection  = RCC_SAI23CLKSOURCE_PLL2;
  •     if(HAL_RCCEx_PeriphCLKConfig( RCC_PeriphCLKInitStruct) != HAL_OK)
  •     {
  •         Error_Handler();
  •     }
  • }

  • void hxd_SAI_A_RX_Init(void)
  • {
  •     /* Initialize SAI */
  •     __HAL_SAI_RESET_HANDLE_STATE( SaiHandle_A_RX);

  • #ifndef USE_ANALOG_CHIP
  •     SaiHandle_A_RX.Instance = SAI1_Block_A;
  •     SaiHandle_A_RX.Init.AudioMode      = SAI_MODEMASTER_RX;
  • #else
  •     SaiHandle_A_RX.Instance = SAI3_Block_A;
  •     SaiHandle_A_RX.Init.AudioMode      = SAI_MODEMASTER_RX;
  • #endif
  •     __HAL_SAI_DISABLE( SaiHandle_A_RX);

  •     SaiHandle_A_RX.Init.Synchro        = SAI_ASYNCHRONOUS;
  •     SaiHandle_A_RX.Init.OutputDrive    = SAI_OUTPUTDRIVE_DISABLE;//SAI_OUTPUTDRIVE_ENABLE;
  •     SaiHandle_A_RX.Init.NoDivider      = SAI_MASTERDIVIDER_DISABLE; // 禁用主时钟
  •     SaiHandle_A_RX.Init.FIFOThreshold  = SAI_FIFOTHRESHOLD_1QF;    // 配置为1/4的FIFO深度
  •     SaiHandle_A_RX.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_48K; //SAI_AUDIO_FREQUENCY_16K;
  •     SaiHandle_A_RX.Init.Protocol       = SAI_FREE_PROTOCOL;        // 配置SAI协议为:自由协议(支持I2S/LSB/MSB/TDM/PCM/DSP等协议)
  •     SaiHandle_A_RX.Init.DataSize       = SAI_DATASIZE_16;          // 采样深度
  •     SaiHandle_A_RX.Init.FirstBit       = SAI_FIRSTBIT_MSB;         // 数据MSB位优先
  •     SaiHandle_A_RX.Init.ClockStrobing  = SAI_CLOCKSTROBING_RISINGEDGE; /* 为了得到相同的上升沿采样,这里TX和RX的值应该是相反的。
  •                                   对RX来说,在SCK下降沿更改SAI生成的信号,而在SCK上升沿对SAI接收的信号进行采样 */
  •     SaiHandle_A_RX.FrameInit.FrameLength       = 32 * 8; // 表示所有slot需要的位时钟总数
  •     SaiHandle_A_RX.FrameInit.ActiveFrameLength = 1;     // 表示长帧同步还是短帧同步,长帧的话,需要配置成slot位宽,短帧则配置成1
  •     SaiHandle_A_RX.FrameInit.FSDefinition      = SAI_FS_STARTFRAME; //SAI_FS_CHANNEL_IDENTIFICATION;
  •     SaiHandle_A_RX.FrameInit.FSPolarity        = SAI_FS_ACTIVE_HIGH; //SAI_FS_ACTIVE_LOW;
  •     SaiHandle_A_RX.FrameInit.FSOffset          = SAI_FS_BEFOREFIRSTBIT; // PHILIPS
  •     SaiHandle_A_RX.SlotInit.FirstBitOffset = 0;
  •     SaiHandle_A_RX.SlotInit.SlotSize       = SAI_SLOTSIZE_32B;
  •     SaiHandle_A_RX.SlotInit.SlotNumber     = 8;
  • //    SaiHandle_A_RX.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1); // 这里8路slot只取前2路数据
  • //    SaiHandle_A_RX.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3);
  •     SaiHandle_A_RX.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 |
  •                                               SAI_SLOTACTIVE_4 | SAI_SLOTACTIVE_5 | SAI_SLOTACTIVE_6 | SAI_SLOTACTIVE_7);
  •     if(HAL_OK != HAL_SAI_Init( SaiHandle_A_RX))
  •     {
  •         Error_Handler();
  •     }
  •     /* Enable SAI to generate clock used by audio driver */
  •     __HAL_SAI_ENABLE( SaiHandle_A_RX);
  • }

  • /**
  •   * @brief  Play initialization
  •   * @param  None
  •   * @retval None
  •   */
  • void hxd_SAI_B_TX_Init(void)
  • {
  •     /* Initialize SAI */
  •     __HAL_SAI_RESET_HANDLE_STATE( SaiHandle_B_TX);

  • #ifndef USE_ANALOG_CHIP
  •     SaiHandle_B_TX.Instance = SAI1_Block_B;
  • #else
  •     SaiHandle_B_TX.Instance = SAI3_Block_B;
  • #endif
  •     __HAL_SAI_DISABLE( SaiHandle_B_TX);

  •     SaiHandle_B_TX.Init.AudioMode      = SAI_MODESLAVE_TX;
  •     SaiHandle_B_TX.Init.Synchro        = SAI_SYNCHRONOUS;
  •     SaiHandle_B_TX.Init.OutputDrive    = SAI_OUTPUTDRIVE_ENABLE;
  •     SaiHandle_B_TX.Init.NoDivider      = SAI_MASTERDIVIDER_DISABLE; // 禁用主时钟
  •     SaiHandle_B_TX.Init.FIFOThreshold  = SAI_FIFOTHRESHOLD_1QF;    // 配置为1/4的FIFO深度
  •     SaiHandle_B_TX.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_48K; //SAI_AUDIO_FREQUENCY_16K;
  •     SaiHandle_B_TX.Init.Protocol       = SAI_FREE_PROTOCOL;        // 配置SAI协议为:自由协议(支持I2S/LSB/MSB/TDM/PCM/DSP等协议)
  •     SaiHandle_B_TX.Init.DataSize       = SAI_DATASIZE_16;          // 采样深度
  •     SaiHandle_B_TX.Init.FirstBit       = SAI_FIRSTBIT_MSB;         // 数据MSB位优先
  •     SaiHandle_B_TX.Init.ClockStrobing  = SAI_CLOCKSTROBING_RISINGEDGE;//SAI_CLOCKSTROBING_FALLINGEDGE;
  •     /* 为了得到相同的上升沿采样,这里TX和RX的值应该是相反的。
  •                                   对TX来说,在SCK下降沿更改SAI生成的信号,而在SCK上升沿对SAI接收的信号进行采样 */
  •     SaiHandle_B_TX.FrameInit.FrameLength       = 32 * 8; // 表示所有slot需要的位时钟总数
  •     SaiHandle_B_TX.FrameInit.ActiveFrameLength = 1;     // 表示长帧同步还是短帧同步,长帧的话,需要配置成slot位宽,短帧则配置成1
  •     SaiHandle_B_TX.FrameInit.FSDefinition      = SAI_FS_STARTFRAME; //SAI_FS_CHANNEL_IDENTIFICATION;
  •     SaiHandle_B_TX.FrameInit.FSPolarity        = SAI_FS_ACTIVE_HIGH; //SAI_FS_ACTIVE_LOW;
  •     SaiHandle_B_TX.FrameInit.FSOffset          = SAI_FS_FIRSTBIT;//SAI_FS_BEFOREFIRSTBIT; // PHILIPS
  •     SaiHandle_B_TX.SlotInit.FirstBitOffset = 0; // 这里暂时先取默认值,后面根据诚迈需要,再改成高16bit有效
  •     SaiHandle_B_TX.SlotInit.SlotSize       = SAI_SLOTSIZE_32B;
  •     SaiHandle_B_TX.SlotInit.SlotNumber     = 8;
  •     SaiHandle_B_TX.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 |
  •                                               SAI_SLOTACTIVE_4 | SAI_SLOTACTIVE_5 | SAI_SLOTACTIVE_6 | SAI_SLOTACTIVE_7);
  • //    SaiHandle_B_TX.SlotInit.SlotActive     = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3);
  •     if(HAL_OK != HAL_SAI_Init( SaiHandle_B_TX))
  •     {
  •         Error_Handler();
  •     }
  •     /* Enable SAI to generate clock used by audio driver */
  •     __HAL_SAI_ENABLE( SaiHandle_B_TX);
  • }

  • /**
  •   * @brief  SAI MSP Init.
  •   * @param  hsai : pointer to a SAI_HandleTypeDef structure that contains
  •   *                the configuration information for SAI module.
  •   * @retval None
  •   */
  • void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
  • {
  •     GPIO_InitTypeDef  GPIO_Init;

  • #ifndef USE_ANALOG_CHIP
  •     __HAL_RCC_SAI1_CLK_ENABLE();
  • #else
  •     __HAL_RCC_SAI3_CLK_ENABLE();
  • #endif

  •     if (hsai->Instance == SAI1_Block_A || hsai->Instance == SAI3_Block_A) {
  • #ifndef USE_ANALOG_CHIP
  •         /* Configure GPIOs used for SAI1_A
  •         * SAI1_FS_A  -- PE4
  •         * SAI1_SCK_A -- PE5
  •         * SAI1_SD_A  -- PE6
  •         */
  •         __GPIOE_CLK_ENABLE();
  •         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  •         GPIO_Init.Pull      = GPIO_NOPULL;
  •         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  •         GPIO_Init.Alternate = GPIO_AF6_SAI1;
  •         GPIO_Init.Pin       = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
  •         HAL_GPIO_Init(GPIOE,  GPIO_Init);
  • #else
  •         /* Configure GPIOs used for SAI3_A
  •         * SAI3_FS_A  -- PD4
  •         * SAI3_SCK_A -- PD0
  •         * SAI3_SD_A  -- PD1
  •         */
  •         __GPIOD_CLK_ENABLE();
  •         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  •         GPIO_Init.Pull      = GPIO_NOPULL;
  •         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  •         GPIO_Init.Alternate = GPIO_AF6_SAI3;
  •         GPIO_Init.Pin       = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4;
  •         HAL_GPIO_Init(GPIOD,  GPIO_Init);
  • #endif

  •         /* Configure DMA used for SAI1 */
  •         __HAL_RCC_DMA2_CLK_ENABLE();
  • #ifndef USE_ANALOG_CHIP
  •         hSaiDma_A.Init.Request             = DMA_REQUEST_SAI1_A;
  • #else
  •         hSaiDma_A.Init.Request             = DMA_REQUEST_SAI3_A;
  • #endif
  •         hSaiDma_A.Init.Direction           = DMA_PERIPH_TO_MEMORY;
  •         hSaiDma_A.Init.PeriphInc           = DMA_PINC_DISABLE;
  •         hSaiDma_A.Init.MemInc              = DMA_MINC_ENABLE;
  •         hSaiDma_A.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  •         hSaiDma_A.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;
  •         hSaiDma_A.Init.Mode                = DMA_CIRCULAR;
  •         hSaiDma_A.Init.Priority            = DMA_PRIORITY_HIGH;
  •         hSaiDma_A.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  •         hSaiDma_A.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  •         hSaiDma_A.Init.MemBurst            = DMA_MBURST_SINGLE;
  •         hSaiDma_A.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  •         /* Select the DMA instance to be used for the transfer : DMA2_Stream1 */
  •         hSaiDma_A.Instance                 = DMA2_Stream1;

  •         __HAL_LINKDMA(hsai, hdmarx, hSaiDma_A);
  •         /* Deinitialize the Stream for new transfer */
  •         HAL_DMA_DeInit( hSaiDma_A);
  •         /* Configure the DMA Stream */
  •         if (HAL_OK != HAL_DMA_Init( hSaiDma_A))
  •         {
  •             Error_Handler();
  •         }
  •         HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
  •         HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
  •     }

  •     if (hsai->Instance == SAI1_Block_B || hsai->Instance == SAI3_Block_B) {
  • #ifndef USE_ANALOG_CHIP
  •         /* Configure GPIOs used for SAI1_B
  •         * SAI1_SD_B -- PE3
  •         */
  •         __GPIOE_CLK_ENABLE();
  •         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  •         GPIO_Init.Pull      = GPIO_NOPULL;
  •         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  •         GPIO_Init.Alternate = GPIO_AF6_SAI1;
  •         GPIO_Init.Pin       = GPIO_PIN_3;
  •         HAL_GPIO_Init(GPIOE,  GPIO_Init);
  • #else
  •         /* Configure GPIOs used for SAI3_B
  •         * SAI3_SD_B -- PD9
  •         */
  •         __GPIOD_CLK_ENABLE();
  •         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  •         GPIO_Init.Pull      = GPIO_NOPULL;
  •         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  •         GPIO_Init.Alternate = GPIO_AF6_SAI3;
  •         GPIO_Init.Pin       = GPIO_PIN_9;
  •         HAL_GPIO_Init(GPIOD,  GPIO_Init);
  • #endif

  •         /* Configure DMA used for SAI1 */
  •         __HAL_RCC_DMA2_CLK_ENABLE();
  • #ifndef USE_ANALOG_CHIP
  •         hSaiDma_B.Init.Request             = DMA_REQUEST_SAI1_B;
  • #else
  •         hSaiDma_B.Init.Request             = DMA_REQUEST_SAI3_B;
  • #endif
  •         hSaiDma_B.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  •         hSaiDma_B.Init.PeriphInc           = DMA_PINC_DISABLE;
  •         hSaiDma_B.Init.MemInc              = DMA_MINC_ENABLE;
  •         hSaiDma_B.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  •         hSaiDma_B.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;
  •         hSaiDma_B.Init.Mode                = DMA_CIRCULAR;
  •         hSaiDma_B.Init.Priority            = DMA_PRIORITY_HIGH;
  •         hSaiDma_B.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  •         hSaiDma_B.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  •         hSaiDma_B.Init.MemBurst            = DMA_MBURST_SINGLE;
  •         hSaiDma_B.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  •         /* Select the DMA instance to be used for the transfer : DMA2_Stream2 */
  •         hSaiDma_B.Instance                 = DMA2_Stream2;
  •         /* Associate the DMA handle */
  •         __HAL_LINKDMA(hsai, hdmatx, hSaiDma_B);

  •         /* Deinitialize the Stream for new transfer */
  •         HAL_DMA_DeInit( hSaiDma_B);
  •         /* Configure the DMA Stream */
  •         if (HAL_OK != HAL_DMA_Init( hSaiDma_B))
  •         {
  •             Error_Handler();
  •         }
  •         HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  •         HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
  •     }
  • }

  • void hxd_SAI_start(void) {
  •     static int16_t val = 1;
  •     for (int i = 0; i < SAI_AUDIO_OUT_BUF_LEN / SAI_AUDIO_OUT_SLOT; i++) {
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT]     = 0XFFFF;//val++;
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 1] = 0X3fff;//val++;
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 2] = 0xfff;//val++;
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 3] = 0x3ff;//val++;
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 4] = 0xff;//val++;
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 5] = 0x3f;//val++;
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 6] = 0xf;//val++;
  •         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 7] = 0x3;//val++;
  •     }

  •     if(HAL_OK != HAL_SAI_Transmit( SaiHandle_B_TX, (uint8_t *)SAIBuffer_B, SAI_AUDIO_OUT_BUF_LEN, 100))
  •     {
  •       Error_Handler();
  •     }

  •     if(HAL_OK != HAL_SAI_Receive_DMA( SaiHandle_A_RX, (uint8_t *)SAIBuffer_A, SAI_AUDIO_IN_BUF_LEN))
  •     {
  •       Error_Handler();
  •     }
  • }






回帖(1)

王莉淳

2024-3-25 16:14:38
SAI1_B作为slave TX发送8个slot 16bit数据,从现象上看产生时钟后有约4帧都没有数据,且第五帧数据的第一个slot也是0数据,后面才是填充到buffer里的0xFFFF
举报

更多回帖

发帖
×
20
完善资料,
赚取积分