你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

SAI_B做slave同SAI_A master同步发送音频,测量波形发现B子模块发送数据会乱序且有部分时钟内发送0数据,这是原始设计还是配置问题?

[复制链接]
stoneno1 提问时间:2022-9-19 20:29 / 未解决
测试1 SAI_A做master TX,发送8 slot数据,产生时钟的同时会发送数据出来:

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

可以看到,红框内第一个slot数据为0。在前面有时钟的地方,有几帧都是0数据。不知道这是配置问题还是原始设计如此?
附加代码:
  1. #define  USE_ANALOG_CHIP
  2. #define SAI_AUDIO_IN_SLOT   8
  3. #define SAI_AUDIO_OUT_SLOT  8
  4. #define SAI_AUDIO_SAMPLING_FREQUENCY 48000
  5. #define SAI_AUDIO_IN_BUF_LEN (SAI_AUDIO_SAMPLING_FREQUENCY/1000 * SAI_AUDIO_IN_SLOT * N_MS*2) //16ms data
  6. #define SAI_AUDIO_OUT_BUF_LEN (SAI_AUDIO_SAMPLING_FREQUENCY/1000 * SAI_AUDIO_OUT_SLOT * N_MS*2) //16ms data

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

  16. SAI_HandleTypeDef   SaiHandle_A_RX;
  17. DMA_HandleTypeDef   hSaiDma_A;
  18. SAI_HandleTypeDef   SaiHandle_B_TX;
  19. DMA_HandleTypeDef   hSaiDma_B;
  20. static int16_t SAIBuffer_A[SAI_AUDIO_IN_BUF_LEN] __attribute__((section(".data_DMA")));
  21. static uint16_t SAIBuffer_B[SAI_AUDIO_OUT_BUF_LEN] __attribute__((section(".data_DMA")));
  22. static int16_t SAI_RX_Data_8ms[SAI_AUDIO_IN_BUF_LEN/2];
  23. static int16_t SAI_TX_Data_8ms[SAI_AUDIO_OUT_BUF_LEN/2];

  24. void hxd_SAI_CLK_Config(void) {
  25.     RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;
  26.     /* 16/1*96/125=12.288M */
  27.     RCC_PeriphCLKInitStruct.PLL2.PLL2M = 1;
  28.     RCC_PeriphCLKInitStruct.PLL2.PLL2N = 96;
  29.     RCC_PeriphCLKInitStruct.PLL2.PLL2P = 125;
  30.     RCC_PeriphCLKInitStruct.PLL2.PLL2Q = 1;
  31.     RCC_PeriphCLKInitStruct.PLL2.PLL2R = 1;

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

  34.     RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI3;
  35.     RCC_PeriphCLKInitStruct.Sai23ClockSelection  = RCC_SAI23CLKSOURCE_PLL2;
  36.     if(HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK)
  37.     {
  38.         Error_Handler();
  39.     }
  40. }

  41. void hxd_SAI_A_RX_Init(void)
  42. {
  43.     /* Initialize SAI */
  44.     __HAL_SAI_RESET_HANDLE_STATE(&SaiHandle_A_RX);

  45. #ifndef USE_ANALOG_CHIP
  46.     SaiHandle_A_RX.Instance = SAI1_Block_A;
  47.     SaiHandle_A_RX.Init.AudioMode      = SAI_MODEMASTER_RX;
  48. #else
  49.     SaiHandle_A_RX.Instance = SAI3_Block_A;
  50.     SaiHandle_A_RX.Init.AudioMode      = SAI_MODEMASTER_RX;
  51. #endif
  52.     __HAL_SAI_DISABLE(&SaiHandle_A_RX);

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

  82. /**
  83.   * @brief  Play initialization
  84.   * @param  None
  85.   * @retval None
  86.   */
  87. void hxd_SAI_B_TX_Init(void)
  88. {
  89.     /* Initialize SAI */
  90.     __HAL_SAI_RESET_HANDLE_STATE(&SaiHandle_B_TX);

  91. #ifndef USE_ANALOG_CHIP
  92.     SaiHandle_B_TX.Instance = SAI1_Block_B;
  93. #else
  94.     SaiHandle_B_TX.Instance = SAI3_Block_B;
  95. #endif
  96.     __HAL_SAI_DISABLE(&SaiHandle_B_TX);

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

  127. /**
  128.   * @brief  SAI MSP Init.
  129.   * @param  hsai : pointer to a SAI_HandleTypeDef structure that contains
  130.   *                the configuration information for SAI module.
  131.   * @retval None
  132.   */
  133. void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
  134. {
  135.     GPIO_InitTypeDef  GPIO_Init;

  136. #ifndef USE_ANALOG_CHIP
  137.     __HAL_RCC_SAI1_CLK_ENABLE();
  138. #else
  139.     __HAL_RCC_SAI3_CLK_ENABLE();
  140. #endif

  141.     if (hsai->Instance == SAI1_Block_A || hsai->Instance == SAI3_Block_A) {
  142. #ifndef USE_ANALOG_CHIP
  143.         /* Configure GPIOs used for SAI1_A
  144.         * SAI1_FS_A  -- PE4
  145.         * SAI1_SCK_A -- PE5
  146.         * SAI1_SD_A  -- PE6
  147.         */
  148.         __GPIOE_CLK_ENABLE();
  149.         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  150.         GPIO_Init.Pull      = GPIO_NOPULL;
  151.         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  152.         GPIO_Init.Alternate = GPIO_AF6_SAI1;
  153.         GPIO_Init.Pin       = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6;
  154.         HAL_GPIO_Init(GPIOE, &GPIO_Init);
  155. #else
  156.         /* Configure GPIOs used for SAI3_A
  157.         * SAI3_FS_A  -- PD4
  158.         * SAI3_SCK_A -- PD0
  159.         * SAI3_SD_A  -- PD1
  160.         */
  161.         __GPIOD_CLK_ENABLE();
  162.         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  163.         GPIO_Init.Pull      = GPIO_NOPULL;
  164.         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  165.         GPIO_Init.Alternate = GPIO_AF6_SAI3;
  166.         GPIO_Init.Pin       = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4;
  167.         HAL_GPIO_Init(GPIOD, &GPIO_Init);
  168. #endif

  169.         /* Configure DMA used for SAI1 */
  170.         __HAL_RCC_DMA2_CLK_ENABLE();
  171. #ifndef USE_ANALOG_CHIP
  172.         hSaiDma_A.Init.Request             = DMA_REQUEST_SAI1_A;
  173. #else
  174.         hSaiDma_A.Init.Request             = DMA_REQUEST_SAI3_A;
  175. #endif
  176.         hSaiDma_A.Init.Direction           = DMA_PERIPH_TO_MEMORY;
  177.         hSaiDma_A.Init.PeriphInc           = DMA_PINC_DISABLE;
  178.         hSaiDma_A.Init.MemInc              = DMA_MINC_ENABLE;
  179.         hSaiDma_A.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  180.         hSaiDma_A.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;
  181.         hSaiDma_A.Init.Mode                = DMA_CIRCULAR;
  182.         hSaiDma_A.Init.Priority            = DMA_PRIORITY_HIGH;
  183.         hSaiDma_A.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  184.         hSaiDma_A.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  185.         hSaiDma_A.Init.MemBurst            = DMA_MBURST_SINGLE;
  186.         hSaiDma_A.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  187.         /* Select the DMA instance to be used for the transfer : DMA2_Stream1 */
  188.         hSaiDma_A.Instance                 = DMA2_Stream1;

  189.         __HAL_LINKDMA(hsai, hdmarx, hSaiDma_A);
  190.         /* Deinitialize the Stream for new transfer */
  191.         HAL_DMA_DeInit(&hSaiDma_A);
  192.         /* Configure the DMA Stream */
  193.         if (HAL_OK != HAL_DMA_Init(&hSaiDma_A))
  194.         {
  195.             Error_Handler();
  196.         }
  197.         HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
  198.         HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
  199.     }

  200.     if (hsai->Instance == SAI1_Block_B || hsai->Instance == SAI3_Block_B) {
  201. #ifndef USE_ANALOG_CHIP
  202.         /* Configure GPIOs used for SAI1_B
  203.         * SAI1_SD_B -- PE3
  204.         */
  205.         __GPIOE_CLK_ENABLE();
  206.         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  207.         GPIO_Init.Pull      = GPIO_NOPULL;
  208.         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  209.         GPIO_Init.Alternate = GPIO_AF6_SAI1;
  210.         GPIO_Init.Pin       = GPIO_PIN_3;
  211.         HAL_GPIO_Init(GPIOE, &GPIO_Init);
  212. #else
  213.         /* Configure GPIOs used for SAI3_B
  214.         * SAI3_SD_B -- PD9
  215.         */
  216.         __GPIOD_CLK_ENABLE();
  217.         GPIO_Init.Mode      = GPIO_MODE_AF_PP;
  218.         GPIO_Init.Pull      = GPIO_NOPULL;
  219.         GPIO_Init.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  220.         GPIO_Init.Alternate = GPIO_AF6_SAI3;
  221.         GPIO_Init.Pin       = GPIO_PIN_9;
  222.         HAL_GPIO_Init(GPIOD, &GPIO_Init);
  223. #endif

  224.         /* Configure DMA used for SAI1 */
  225.         __HAL_RCC_DMA2_CLK_ENABLE();
  226. #ifndef USE_ANALOG_CHIP
  227.         hSaiDma_B.Init.Request             = DMA_REQUEST_SAI1_B;
  228. #else
  229.         hSaiDma_B.Init.Request             = DMA_REQUEST_SAI3_B;
  230. #endif
  231.         hSaiDma_B.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  232.         hSaiDma_B.Init.PeriphInc           = DMA_PINC_DISABLE;
  233.         hSaiDma_B.Init.MemInc              = DMA_MINC_ENABLE;
  234.         hSaiDma_B.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  235.         hSaiDma_B.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD;
  236.         hSaiDma_B.Init.Mode                = DMA_CIRCULAR;
  237.         hSaiDma_B.Init.Priority            = DMA_PRIORITY_HIGH;
  238.         hSaiDma_B.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
  239.         hSaiDma_B.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  240.         hSaiDma_B.Init.MemBurst            = DMA_MBURST_SINGLE;
  241.         hSaiDma_B.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  242.         /* Select the DMA instance to be used for the transfer : DMA2_Stream2 */
  243.         hSaiDma_B.Instance                 = DMA2_Stream2;
  244.         /* Associate the DMA handle */
  245.         __HAL_LINKDMA(hsai, hdmatx, hSaiDma_B);

  246.         /* Deinitialize the Stream for new transfer */
  247.         HAL_DMA_DeInit(&hSaiDma_B);
  248.         /* Configure the DMA Stream */
  249.         if (HAL_OK != HAL_DMA_Init(&hSaiDma_B))
  250.         {
  251.             Error_Handler();
  252.         }
  253.         HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
  254.         HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
  255.     }
  256. }

  257. void hxd_SAI_start(void) {
  258.     static int16_t val = 1;
  259.     for (int i = 0; i < SAI_AUDIO_OUT_BUF_LEN / SAI_AUDIO_OUT_SLOT; i++) {
  260.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT]     = 0XFFFF;//val++;
  261.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 1] = 0X3fff;//val++;
  262.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 2] = 0xfff;//val++;
  263.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 3] = 0x3ff;//val++;
  264.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 4] = 0xff;//val++;
  265.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 5] = 0x3f;//val++;
  266.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 6] = 0xf;//val++;
  267.         SAIBuffer_B[i*SAI_AUDIO_OUT_SLOT + 7] = 0x3;//val++;
  268.     }

  269.     if(HAL_OK != HAL_SAI_Transmit(&SaiHandle_B_TX, (uint8_t *)SAIBuffer_B, SAI_AUDIO_OUT_BUF_LEN, 100))
  270.     {
  271.       Error_Handler();
  272.     }

  273.     if(HAL_OK != HAL_SAI_Receive_DMA(&SaiHandle_A_RX, (uint8_t *)SAIBuffer_A, SAI_AUDIO_IN_BUF_LEN))
  274.     {
  275.       Error_Handler();
  276.     }
  277. }
复制代码





SAI_A master TX波形

SAI_A master TX波形

SAI_B slave TX波形

SAI_B slave TX波形
收藏 评论1 发布时间:2022-9-19 20:29

举报

1个回答
stoneno1 回答时间:2022-9-23 10:22:14
SAI1_B作为slave TX发送8个slot 16bit数据,从现象上看产生时钟后有约4帧都没有数据,且第五帧数据的第一个slot也是0数据,后面才是填充到buffer里的0xFFFF

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版