在线时间543 小时
UID1650185
注册时间2017-4-19
NXP金币480
TA的每日心情 | 怒 2021-1-28 20:09 |
---|
签到天数: 317 天 [LV.8]以坛为家I
金牌会员
- 积分
- 8040
- 最后登录
- 2022-5-12
|
这一讲就来说说54114通过总线I2S控制WM8904播放音乐吧,按键可控开启播放,音量调节。。。
先捋下思路吧:
在官方i2s_interrupt的基础上修改验证I2S总线机制和wm8904的工作机理,由于手头上暂时没有外置麦克,就只测试下播放内部存储的正弦波数据吧。
PS:sdk的工程经过了好一番研究修改。。。也是醉了。。。
系统上电后,初始化IIC, WM8904, IIS完成后,开始播放5次正弦波数据,播放完停止。此时按下按键PB2,再次启动播放,LED5翻转,触发播放完成回调函数,然后播放5次停止。。。
还配备了音量可调功能,PB3音量增加,PB4音量减小。。。大概按一次声音加减8%左右,这是是个可设置的,方便测试,步进故意大了点。。。
老规矩先来看下效果。。。。。
复位和PB2开启播放
音量加减调节
声音没办法展示的哦。。。
还有从CN8接入外置麦克,输入声音,从CN7播放的验证就也不做了,因为没有外置麦克呀,效果原理都是一样一样的。。。。。
切入正题。。。。(基础部分)
关于I2S的基本知识就不在从度娘那里粘贴复制了,这个理论也有人发过帖子了,或者百度搜下。
o(╯□╰)oo(╯□╰)oo(╯□╰)oo(╯□╰)oo(╯□╰)oo(╯□╰)o
不过呢I2S的时序还是有必要看下的:
对于系统而言,产生SCK和WS的信号端就是主设备,用MASTER表示
在IIS总线中,任何设备都可以通过提供必需的时钟信号成为系统的主设备置,而从属设备通过外部时钟信号来得到它的内部时钟信号,这就意味着必须重视主设备和数据以及命令选择信号之间的传播延迟,总的延迟主要由两部分组成:
1.外部时钟和从设备的内部时钟之间的延迟
2.内部时钟和数据信号以及命令选择信号之间的延迟
对于数据和命令信号的输入,外部时钟和内部时的延迟不占据主导的地位,它只是延长了有效的建立时间(set-up time)。延迟的主要部分是发送端的传输延迟和设置接收端所需的时间。
///////////////////////////////////////////////////////////
下面来看开发板的引脚配置吧。。。
从原理图可以看出来,真正链接到WM8904的引脚有
WM8904 54114
SDA---------------> SDA1(PIO1_2)---FUNC5
SCL---------------> SCL1(PIO1_1)---FUNC5
MCLK-------------> MCLK(PIO1_17)---FUNC4
BCLK-------------> BCK1(PIO1_12)---FUNC4
WS---------------> WS1(PIO1_14)---FUNC4
TXD--------------> DATAI(PIO1_13)---FUNC4
RXD--------------> DATAO(PIO0_5)---FUNC1
////////////////////////////////////////////////////////
WM8904部分
wm8904是低功耗便携式立体声编解码器,也即是说,编码解码二合一嘛。采用沃尔夫森SilentSwitch™技术减少有机噪声污染, 可以配为单端或者差分输入,有一个立体声麦克接口。
WM8904有一个高度灵活的数字音频接口,支持多种协议,包括I2S、DSP、msb - first的左/右对齐,并且可以在主或从模式操作。在DSP模式中支持PCM操作。
时序图:
wm8904 的配置寄存器非常的多,感觉相当复杂。。。。
重要函数
从板子上面用到的接口以及demo例程可以看到,IIC接口【DA1(PIO1_2)/SCL1(PIO1_1)】主要是用来操作配置wm8904的的寄存器的。IIC引脚配置
- IOCON_PinMuxSet(IOCON, 1, 1, IOCON_MODE_PULLUP | IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
- IOCON_PinMuxSet(IOCON, 1, 2, IOCON_MODE_PULLUP | IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
复制代码
wm8904写寄存器函数
- status_t WM8904_WriteRegister(wm8904_handle_t *handle, uint8_t reg, uint16_t value)
复制代码
wm8904读寄存器函数
- status_t WM8904_ReadRegister(wm8904_handle_t *handle, uint8_t reg, uint16_t *value)
复制代码
wm8904的初始化函数:
- status_t WM8904_Init(wm8904_handle_t *handle, wm8904_config_t *config)
复制代码 主要完成了有关wm8904寄存器的一些配置,通过IIC总线写读写配置。
看手册可以知道WM8904可以支持很多种总线,这里配置的为iis总线,采样率为48khz,位宽16bit。
还有一个调节音量的函数以后可能用得到,可以调节左右声道的音量大小。。。
- WM8904_SetVolume(wm8904_handle_t *handle, uint16_t volumeLeft, uint16_t volumeRight)
复制代码
代码-----------------------
首先需要配置PLL锁相环,并初始化。
- typedef struct _pll_setup
- {
- uint32_t syspllctrl; /*!< PLL control register SYSPLLCTRL */
- uint32_t syspllndec; /*!< PLL NDEC register SYSPLLNDEC */
- uint32_t syspllpdec; /*!< PLL PDEC register SYSPLLPDEC */
- uint32_t syspllssctrl[2]; /*!< PLL SSCTL registers SYSPLLSSCTRL */
- uint32_t pllRate; /*!< Acutal PLL rate */
- uint32_t flags; /*!< PLL setup flags, Or'ed value of PLL_SETUPFLAG_* definitions */
- } pll_setup_t;
复制代码- const pll_setup_t pllSetup = {
- .syspllctrl = SYSCON_SYSPLLCTRL_BANDSEL_MASK | SYSCON_SYSPLLCTRL_SELP(0x1FU) | SYSCON_SYSPLLCTRL_SELI(0x8U),
- .syspllndec = SYSCON_SYSPLLNDEC_NDEC(0x2DU),
- .syspllpdec = SYSCON_SYSPLLPDEC_PDEC(0x42U),
- .syspllssctrl = {SYSCON_SYSPLLSSCTRL0_MDEC(0x34D3U) | SYSCON_SYSPLLSSCTRL0_SEL_EXT_MASK, 0x00000000U},
- .pllRate = 24576000U, /* 16 bits * 2 channels * 48 kHz * 16 */
- .flags = PLL_SETUPFLAG_WAITLOCK};
复制代码- CLOCK_AttachClk(kFRO12M_to_SYS_PLL);
- CLOCK_SetPLLFreq(&pllSetup);
复制代码 然后初始化IIS时钟,并把IIS时钟连接到MCLK,在复位IIC,IIS,使能iis中断。
- /* I2S clocks */
- CLOCK_AttachClk(kSYS_PLL_to_FLEXCOMM6);
- CLOCK_AttachClk(kSYS_PLL_to_FLEXCOMM7);
- /* Attach PLL clock to MCLK for I2S, no divider */
- CLOCK_AttachClk(kSYS_PLL_to_MCLK);
- SYSCON->MCLKDIV = SYSCON_MCLKDIV_DIV(0U);
- SYSCON->MCLKIO = 1U;
- /* reset FLEXCOMM for I2C */
- RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn);
- /* reset FLEXCOMM for I2S */
- RESET_PeripheralReset(kFC6_RST_SHIFT_RSTn);
- RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);
- /* Enable interrupts for I2S */
- EnableIRQ(FLEXCOMM6_IRQn);
- EnableIRQ(FLEXCOMM7_IRQn);
复制代码
然后就是配置外设,iic,wm8904,iis
代码省略。。。。
1.播放正玄波 启动函数static void StartSoundPlayback(void)
然后初始化传输数据的句柄,当发生完成或者发送失败时,调用回调函数i2s_transfer_callback_t callback
- void I2S_TxTransferCreateHandle(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_callback_t callback, void *userData);
复制代码
然后准备发送数据
- status_t I2S_TxTransferNonBlocking(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_t transfer);
复制代码
发送完成后,触发中断进入发送回调函数,循环发送原数据。。。
- static void TxCallback(I2S_Type *base, i2s_handle_t *handle, status_t completionStatus, void *userData)
- {
- /* Enqueue the same original s_Buffer all over again */
- i2s_transfer_t *transfer = (i2s_transfer_t *)userData;
- I2S_TxTransferNonBlocking(base, handle, *transfer);
- }
复制代码 最终效果可以听到一个正玄波声音。。。
2.播放CN8输入的信号 启动函数static void StartDigitalLoopback(void)
初始化发送和接收数据的句柄,并准备接收和发送,通过中断方式触发。
- I2S_TxTransferCreateHandle(DEMO_I2S_TX, &s_TxHandle, TxCallback, (void *)&s_TxTransfer);
- I2S_RxTransferCreateHandle(DEMO_I2S_RX, &s_RxHandle, RxCallback, (void *)&s_RxTransfer);
- I2S_RxTransferNonBlocking(DEMO_I2S_RX, &s_RxHandle, s_RxTransfer);
- I2S_TxTransferNonBlocking(DEMO_I2S_TX, &s_TxHandle, s_TxTransfer);
复制代码
///////////////////////////////////////
功能说明
增加开发板上的 按键PB2,PB3, PB4, LED5的初始化,这里就不说了,,任务二的帖子有手把手教。。。我从前面做的直接拿过来用。。。
程序初始化到这里要说一下,上面是播放内置的正弦波函数音频数据,下面是从CN8输入数据,并播放。
这里就测试验证下正弦波吧。。。初始化启动一次播放后,进入播放完成回调函数
播放5次,停止,此时按下PB2再起启动播放,触发这个回调函数,又是5次播放,,,,后面重复以上2步
这里完成播放测试。。。。
下面是音量调节功能,先定义几个宏。
文档有说,音量的范围应该在0---63之间
- if(2== key_M)
- {
- key_M = 0;
- cnt_volume += VOLUME_STEP;
- if(cnt_volume >=VOLUME_MAX )
- cnt_volume =VOLUME_MAX;
- WM8904_SetVolume(&codecHandle, cnt_volume, cnt_volume);
- PRINTF("PB3增加音量:%d%%,\r\n" , cnt_volume*100/63);
- }
- if(3== key_M)
- {
- key_M = 0;
- if(cnt_volume >=VOLUME_STEP-1)cnt_volume -= VOLUME_STEP;
- if(cnt_volume <=VOLUME_MIN )
- cnt_volume =VOLUME_MIN;
- WM8904_SetVolume(&codecHandle, cnt_volume, cnt_volume);
- PRINTF("PB4减少音量:%d%%,\r\n" , cnt_volume*100/63);
- }
复制代码 到此 测试验证完成该。。。以上亲测ok,小马哥出品,多多支持
PS:话说我CN7接的是音响,为了测试,把声音调到了100%,到现在还是处于耳鸣中。。。。。
呜呜~~~~(>_<)~~~~
亲们多投票多支持下哦
|
|