在线时间372 小时
UID3135871
注册时间2016-10-9
NXP金币20
TA的每日心情 | 怒 2024-2-5 12:06 |
---|
签到天数: 627 天 [LV.9]以坛为家II
版主
- 积分
- 4429
- 最后登录
- 2024-2-5
|
首先感谢az158兄弟的视频例程,及详细的解答。
之前下载az158的MDK程序,一直编译报错。
后来才知道,MDK AC6的一些新功能需勾选。
编译后无误。
SAI接口,说实话,我之前很少接触音频播放相关,这个接口我还真没用过,之前仅用过I2S。
就想在NXP MUCXpresso 环境下配置代码,但是之前配置一直不成功。
一个简单的配置,没道理不成功。后检测发现,在想SDK加载组件时,多加了fsl_codecs_adapter.
这个是针对多种解码的文件。具体为什么会不行,我未去仔细分析,但总之是可以了。
对应陌生的外设接口,本能上有种排斥,但是看明白了,也就是那么一回事。
WM8960通过IIC接口读写其内部寄存器进行配置,SAI接口进行音频数据的发送和接收。
WM8960框架图:
寄存器表:
不说废话了,上配置截图(这里配置录音和播放):
GPIO:
CLOCK:时钟默认配置,未降低SAI时钟
SAI配置:
代码生成:
SAI的初始化:
- /* SAI1 Tx configuration */
- sai_transceiver_t SAI1_Tx_config = {
- .masterSlave = kSAI_Master,
- .bitClock = {
- .bclkSrcSwap = false,
- .bclkSource = kSAI_BclkSourceMclkOption2,
- .bclkPolarity = kSAI_PolarityActiveLow,
- .bclkInputDelay = false
- },
- .frameSync = {
- .frameSyncWidth = 16U,
- .frameSyncPolarity = kSAI_PolarityActiveLow,
- .frameSyncEarly = true,
- },
- .syncMode = kSAI_ModeAsync,
- .channelMask = kSAI_Channel0Mask,
- .startChannel = 0U,
- .endChannel = 0U,
- .channelNums = 1U,
- .serialData = {
- .dataMode = kSAI_DataPinStateOutputZero,
- .dataWord0Length = (uint8_t)kSAI_WordWidth16bits,
- .dataWordNLength = (uint8_t)kSAI_WordWidth16bits,
- .dataWordLength = (uint8_t)kSAI_WordWidth16bits,
- .dataOrder = kSAI_DataMSB,
- .dataFirstBitShifted = 16U,
- .dataWordNum = 2U,
- .dataMaskedWord = 0x0U
- },
- .fifo = {
- .fifoWatermark = 16U,
- .fifoPacking = kSAI_FifoPackingDisabled,
- .fifoContinueOneError = false
- }
- };
- /* SAI1 Rx configuration */
- sai_transceiver_t SAI1_Rx_config = {
- .masterSlave = kSAI_Master,
- .bitClock = {
- .bclkSrcSwap = false,
- .bclkSource = kSAI_BclkSourceMclkOption2,
- .bclkPolarity = kSAI_PolarityActiveLow,
- .bclkInputDelay = false
- },
- .frameSync = {
- .frameSyncWidth = 16U,
- .frameSyncPolarity = kSAI_PolarityActiveLow,
- .frameSyncEarly = true,
- },
- .syncMode = kSAI_ModeSync,
- .channelMask = kSAI_Channel0Mask,
- .startChannel = 0U,
- .endChannel = 0U,
- .channelNums = 1U,
- .serialData = {
- .dataMode = kSAI_DataPinStateTriState,
- .dataWord0Length = (uint8_t)kSAI_WordWidth16bits,
- .dataWordNLength = (uint8_t)kSAI_WordWidth16bits,
- .dataWordLength = (uint8_t)kSAI_WordWidth16bits,
- .dataOrder = kSAI_DataMSB,
- .dataFirstBitShifted = 16U,
- .dataWordNum = 2U,
- .dataMaskedWord = 0x0U
- },
- .fifo = {
- .fifoWatermark = 16U,
- .fifoPacking = kSAI_FifoPackingDisabled,
- .fifoContinueOneError = false
- }
- };
- sai_handle_t SAI1_Tx_handle;
- sai_handle_t SAI1_Rx_handle;
- static void SAI1_init(void) {
- /* Initialize SAI clock gate */
- SAI_Init(SAI1_PERIPHERAL);
- /* Create the SAI Tx transfer handle */
- SAI_TransferTxCreateHandle(SAI1_PERIPHERAL, &SAI1_Tx_handle, NULL, NULL);
- /* Create the SAI Rx transfer handle */
- SAI_TransferRxCreateHandle(SAI1_PERIPHERAL, &SAI1_Rx_handle, NULL, NULL);
- /* Configures SAI Tx sub-module functionality */
- SAI_TransferTxSetConfig(SAI1_PERIPHERAL, &SAI1_Tx_handle, &SAI1_Tx_config);
- /* Configures SAI Rx sub-module functionality */
- SAI_TransferRxSetConfig(SAI1_PERIPHERAL, &SAI1_Rx_handle, &SAI1_Rx_config);
- /* Set up SAI Tx bitclock rate by calculation of divider. */
- SAI_TxSetBitClockRate(SAI1_PERIPHERAL, SAI1_TX_BCLK_SOURCE_CLOCK_HZ, SAI1_TX_SAMPLE_RATE, SAI1_TX_WORD_WIDTH, SAI1_TX_WORDS_PER_FRAME);
- /* Set up SAI Rx bitclock rate by calculation of divider. */
- SAI_RxSetBitClockRate(SAI1_PERIPHERAL, SAI1_RX_BCLK_SOURCE_CLOCK_HZ, SAI1_RX_SAMPLE_RATE, SAI1_RX_WORD_WIDTH, SAI1_RX_WORDS_PER_FRAME);
- }
复制代码 除了初始化,主要配置了发送和接收2个事件的句柄(SAI1_Tx_handle,SAI1_Rx_handle)及bit频率(512K)。
其中未启用中断,未添加发送接收的回调函数。
下面,我们添加一个板子解码器的配置:
- codec_config_t boardCodecConfig = {.codecDevType = kCODEC_WM8960, .codecDevConfig = &wm8960Config};
复制代码 这里解码器型号选择WM8960,库中还有其他型号的解码器。
WM8960解码器的配置:
- wm8960_config_t wm8960Config = {
- .i2cConfig = {.codecI2CInstance = <font color="#ff0000">BOARD_CODEC_I2C_INSTANCE</font>, .codecI2CSourceClock = <font color="#ff0000">BOARD_CODEC_I2C_CLOCK_FREQ</font>},
- .route = kWM8960_RoutePlaybackandRecord,
- .rightInputSource = kWM8960_InputDifferentialMicInput2,
- .playSource = kWM8960_PlaySourceDAC,
- .slaveAddress = <font color="#ff0000">WM8960_I2C_ADDR</font>,
- .bus = kWM8960_BusI2S,
- .format = {.mclk_HZ = 6144000U, .sampleRate =<font color="#ff0000">kWM8960_AudioSampleRate16KHz</font>, .bitWidth = <font color="#ff0000">kWM8960_AudioBitWidth16bit</font>},
- .master_slave = false,
- };
复制代码 其中I2C的选择,及采样率要与实际配置的硬件一致,不然声音会失真。
WM8960clock引脚方向:
- //定义WM8960的MCLK方向(由RT1010提供)
- void BOARD_EnableSaiMclkOutput(bool enable)
- {
- if (enable) //clock引脚输出信号
- {
- IOMUXC_GPR->GPR1 |= IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK;
- }
- else //clock引脚输入信号
- {
- IOMUXC_GPR->GPR1 &= (~IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK);
- }
- }
复制代码 音频读取:
- SAI_TransferReceiveNonBlocking(SAI1_PERIPHERAL, &SAI1_Rx_handle, &xfer)
复制代码 音频输出:
- SAI_TransferSendNonBlocking(SAI1_PERIPHERAL, &SAI1_Tx_handle, &xfer)
复制代码 本次例程,音频接收缓存4K接收满后就发送。
具体main函数里面初始化及循环:
- /* MCLK作为输出 */
- BOARD_EnableSaiMclkOutput(true);
- //初始化WM8960
- if (CODEC_Init(&codecHandle, &boardCodecConfig) != kStatus_Success)
- {
- assert(false);
- }
复制代码- while(1) {
- if(!readflg){
- xfer.data = Buffer + rx_index * BUFFER_SIZE;
- xfer.dataSize = BUFFER_SIZE;
- if (kStatus_Success == SAI_TransferReceiveNonBlocking(SAI1_PERIPHERAL, &SAI1_Rx_handle, &xfer))
- {
- rx_index++;
- }
- if (rx_index == BUFFER_NUMBER)
- {
- rx_index = 0U;
- readflg=1;
- }
- }
- if (readflg)
- {
- xfer.data = Buffer + tx_index * BUFFER_SIZE;
- xfer.dataSize = BUFFER_SIZE;
- if (kStatus_Success == SAI_TransferSendNonBlocking(SAI1_PERIPHERAL, &SAI1_Tx_handle, &xfer))
- {
- tx_index++;
- }
- if (tx_index == BUFFER_NUMBER)
- {
- tx_index = 0U;
- readflg=0;
- }
- }
- }
复制代码 现象,读取mic后,耳机能接收到声音。
木有喇叭,不好演示,上个图吧:
好了,SAI目前就先到这!
MCUXpresso代码:
MIMXRT1011_Project_sai.rar
(6.19 MB, 下载次数: 14)
|
|