测试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();
- }
- }