查看: 1465|回复: 2

[分享] 【i.MX RT1010体验】+SAI(transfer模式)驱动WM8960的录音和播放

[复制链接]
  • TA的每日心情

    2024-2-5 12:06
  • 签到天数: 627 天

    [LV.9]以坛为家II

    94

    主题

    1628

    帖子

    2

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    4429

    热心会员

    最后登录
    2024-2-5
    发表于 2021-5-26 16:29:15 | 显示全部楼层 |阅读模式
    首先感谢az158兄弟的视频例程,及详细的解答。
    之前下载az158的MDK程序,一直编译报错。
    BUG2.png
    后来才知道,MDK AC6的一些新功能需勾选。
    BG3.png
    编译后无误。
    SAI接口,说实话,我之前很少接触音频播放相关,这个接口我还真没用过,之前仅用过I2S。
    就想在NXP MUCXpresso 环境下配置代码,但是之前配置一直不成功。
    一个简单的配置,没道理不成功。后检测发现,在想SDK加载组件时,多加了fsl_codecs_adapter.
    这个是针对多种解码的文件。具体为什么会不行,我未去仔细分析,但总之是可以了。
    对应陌生的外设接口,本能上有种排斥,但是看明白了,也就是那么一回事。
    WM8960通过IIC接口读写其内部寄存器进行配置,SAI接口进行音频数据的发送和接收。
    WM8960框架图:
    SS1.png
    寄存器表:
    SS2.png
    不说废话了,上配置截图(这里配置录音和播放):
    GPIO:
    M1.png
    CLOCK:时钟默认配置,未降低SAI时钟
    D2.png
    SAI配置:
    D3.png
    D4.png
    代码生成:
    SAI的初始化:
    1. /* SAI1 Tx configuration */
    2. sai_transceiver_t SAI1_Tx_config = {
    3.   .masterSlave = kSAI_Master,
    4.   .bitClock = {
    5.     .bclkSrcSwap = false,
    6.     .bclkSource = kSAI_BclkSourceMclkOption2,
    7.     .bclkPolarity = kSAI_PolarityActiveLow,
    8.     .bclkInputDelay = false
    9.   },
    10.   .frameSync = {
    11.     .frameSyncWidth = 16U,
    12.     .frameSyncPolarity = kSAI_PolarityActiveLow,
    13.     .frameSyncEarly = true,
    14.   },
    15.   .syncMode = kSAI_ModeAsync,
    16.   .channelMask = kSAI_Channel0Mask,
    17.   .startChannel = 0U,
    18.   .endChannel = 0U,
    19.   .channelNums = 1U,
    20.   .serialData = {
    21.     .dataMode = kSAI_DataPinStateOutputZero,
    22.     .dataWord0Length = (uint8_t)kSAI_WordWidth16bits,
    23.     .dataWordNLength = (uint8_t)kSAI_WordWidth16bits,
    24.     .dataWordLength = (uint8_t)kSAI_WordWidth16bits,
    25.     .dataOrder = kSAI_DataMSB,
    26.     .dataFirstBitShifted = 16U,
    27.     .dataWordNum = 2U,
    28.     .dataMaskedWord = 0x0U
    29.   },
    30.   .fifo = {
    31.     .fifoWatermark = 16U,
    32.     .fifoPacking = kSAI_FifoPackingDisabled,
    33.     .fifoContinueOneError = false
    34.   }
    35. };
    36. /* SAI1 Rx configuration */
    37. sai_transceiver_t SAI1_Rx_config = {
    38.   .masterSlave = kSAI_Master,
    39.   .bitClock = {
    40.     .bclkSrcSwap = false,
    41.     .bclkSource = kSAI_BclkSourceMclkOption2,
    42.     .bclkPolarity = kSAI_PolarityActiveLow,
    43.     .bclkInputDelay = false
    44.   },
    45.   .frameSync = {
    46.     .frameSyncWidth = 16U,
    47.     .frameSyncPolarity = kSAI_PolarityActiveLow,
    48.     .frameSyncEarly = true,
    49.   },
    50.   .syncMode = kSAI_ModeSync,
    51.   .channelMask = kSAI_Channel0Mask,
    52.   .startChannel = 0U,
    53.   .endChannel = 0U,
    54.   .channelNums = 1U,
    55.   .serialData = {
    56.     .dataMode = kSAI_DataPinStateTriState,
    57.     .dataWord0Length = (uint8_t)kSAI_WordWidth16bits,
    58.     .dataWordNLength = (uint8_t)kSAI_WordWidth16bits,
    59.     .dataWordLength = (uint8_t)kSAI_WordWidth16bits,
    60.     .dataOrder = kSAI_DataMSB,
    61.     .dataFirstBitShifted = 16U,
    62.     .dataWordNum = 2U,
    63.     .dataMaskedWord = 0x0U
    64.   },
    65.   .fifo = {
    66.     .fifoWatermark = 16U,
    67.     .fifoPacking = kSAI_FifoPackingDisabled,
    68.     .fifoContinueOneError = false
    69.   }
    70. };
    71. sai_handle_t SAI1_Tx_handle;
    72. sai_handle_t SAI1_Rx_handle;

    73. static void SAI1_init(void) {
    74.   /* Initialize SAI clock gate */
    75.   SAI_Init(SAI1_PERIPHERAL);
    76.   /* Create the SAI Tx transfer handle */
    77.   SAI_TransferTxCreateHandle(SAI1_PERIPHERAL, &SAI1_Tx_handle, NULL, NULL);
    78.   /* Create the SAI Rx transfer handle */
    79.   SAI_TransferRxCreateHandle(SAI1_PERIPHERAL, &SAI1_Rx_handle, NULL, NULL);
    80.   /* Configures SAI Tx sub-module functionality */
    81.   SAI_TransferTxSetConfig(SAI1_PERIPHERAL, &SAI1_Tx_handle, &SAI1_Tx_config);
    82.   /* Configures SAI Rx sub-module functionality */
    83.   SAI_TransferRxSetConfig(SAI1_PERIPHERAL, &SAI1_Rx_handle, &SAI1_Rx_config);
    84.   /* Set up SAI Tx bitclock rate by calculation of divider. */
    85.   SAI_TxSetBitClockRate(SAI1_PERIPHERAL, SAI1_TX_BCLK_SOURCE_CLOCK_HZ, SAI1_TX_SAMPLE_RATE, SAI1_TX_WORD_WIDTH, SAI1_TX_WORDS_PER_FRAME);
    86.   /* Set up SAI Rx bitclock rate by calculation of divider. */
    87.   SAI_RxSetBitClockRate(SAI1_PERIPHERAL, SAI1_RX_BCLK_SOURCE_CLOCK_HZ, SAI1_RX_SAMPLE_RATE, SAI1_RX_WORD_WIDTH, SAI1_RX_WORDS_PER_FRAME);
    88. }
    复制代码
    除了初始化,主要配置了发送和接收2个事件的句柄(SAI1_Tx_handle,SAI1_Rx_handle)及bit频率(512K)。
    其中未启用中断,未添加发送接收的回调函数。
    下面,我们添加一个板子解码器的配置:
    1. codec_config_t boardCodecConfig = {.codecDevType = kCODEC_WM8960, .codecDevConfig = &wm8960Config};
    复制代码
    这里解码器型号选择WM8960,库中还有其他型号的解码器。
    WM8960解码器的配置:
    1. wm8960_config_t wm8960Config = {
    2.     .i2cConfig = {.codecI2CInstance = <font color="#ff0000">BOARD_CODEC_I2C_INSTANCE</font>, .codecI2CSourceClock = <font color="#ff0000">BOARD_CODEC_I2C_CLOCK_FREQ</font>},
    3.     .route     = kWM8960_RoutePlaybackandRecord,
    4.     .rightInputSource = kWM8960_InputDifferentialMicInput2,
    5.     .playSource       = kWM8960_PlaySourceDAC,
    6.     .slaveAddress     = <font color="#ff0000">WM8960_I2C_ADDR</font>,
    7.     .bus              = kWM8960_BusI2S,
    8.     .format = {.mclk_HZ = 6144000U, .sampleRate =<font color="#ff0000">kWM8960_AudioSampleRate16KHz</font>, .bitWidth = <font color="#ff0000">kWM8960_AudioBitWidth16bit</font>},
    9.     .master_slave = false,
    10. };
    复制代码
    其中I2C的选择,及采样率要与实际配置的硬件一致,不然声音会失真。

    WM8960clock引脚方向:
    1. //定义WM8960的MCLK方向(由RT1010提供)
    2. void BOARD_EnableSaiMclkOutput(bool enable)
    3. {
    4.     if (enable) //clock引脚输出信号
    5.     {
    6.         IOMUXC_GPR->GPR1 |= IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK;
    7.     }
    8.     else        //clock引脚输入信号
    9.     {
    10.         IOMUXC_GPR->GPR1 &= (~IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK);
    11.     }
    12. }
    复制代码
    音频读取:
    1. SAI_TransferReceiveNonBlocking(SAI1_PERIPHERAL, &SAI1_Rx_handle, &xfer)
    复制代码
    音频输出:
    1. SAI_TransferSendNonBlocking(SAI1_PERIPHERAL, &SAI1_Tx_handle, &xfer)
    复制代码
    本次例程,音频接收缓存4K接收满后就发送。
    具体main函数里面初始化及循环:
    1. /* MCLK作为输出 */
    2.         BOARD_EnableSaiMclkOutput(true);
    3.         //初始化WM8960
    4.         if (CODEC_Init(&codecHandle, &boardCodecConfig) != kStatus_Success)
    5.         {
    6.                 assert(false);
    7.         }
    复制代码
    1. while(1) {


    2.                 if(!readflg){
    3.                         xfer.data     = Buffer + rx_index * BUFFER_SIZE;
    4.                         xfer.dataSize = BUFFER_SIZE;
    5.                         if (kStatus_Success == SAI_TransferReceiveNonBlocking(SAI1_PERIPHERAL, &SAI1_Rx_handle, &xfer))
    6.                         {
    7.                                 rx_index++;
    8.                         }
    9.                         if (rx_index == BUFFER_NUMBER)
    10.                         {
    11.                                 rx_index = 0U;
    12.                                 readflg=1;
    13.                         }
    14.                 }

    15.                 if (readflg)
    16.                 {
    17.                         xfer.data     = Buffer + tx_index * BUFFER_SIZE;
    18.                         xfer.dataSize = BUFFER_SIZE;
    19.                         if (kStatus_Success == SAI_TransferSendNonBlocking(SAI1_PERIPHERAL, &SAI1_Tx_handle, &xfer))
    20.                         {
    21.                                 tx_index++;
    22.                         }
    23.                         if (tx_index == BUFFER_NUMBER)
    24.                         {
    25.                                 tx_index = 0U;
    26.                                 readflg=0;
    27.                         }
    28.                 }

    29.     }
    复制代码
    现象,读取mic后,耳机能接收到声音。
    木有喇叭,不好演示,上个图吧:
    TT1.jpg
    好了,SAI目前就先到这!
    MCUXpresso代码: MIMXRT1011_Project_sai.rar (6.19 MB, 下载次数: 14)
    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2022-12-30 08:07
  • 签到天数: 87 天

    [LV.6]常住居民II

    0

    主题

    242

    帖子

    1

    金牌会员

    Rank: 6Rank: 6

    积分
    1097
    最后登录
    2022-12-30
    发表于 2021-5-27 12:02:28 | 显示全部楼层
    准备用这个方案做个外置USB声卡,就是不知道1010支不支持USB高速?
    生命不息,奋斗不止!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2024-2-5 12:06
  • 签到天数: 627 天

    [LV.9]以坛为家II

    94

    主题

    1628

    帖子

    2

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    4429

    热心会员

    最后登录
    2024-2-5
     楼主| 发表于 2021-5-27 19:23:48 来自手机 | 显示全部楼层
    delei 发表于 2021-5-27 12:02
    准备用这个方案做个外置USB声卡,就是不知道1010支不支持USB高速?

    这个倒没注意  不过单独用作USB声卡 有没有浪费资源呐
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-26 08:17 , Processed in 0.116397 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表