本文使用cubemx生成尽可能多的代码。
首先在cubemx中
配置SW,用来使能SW调试口,
配置lcd,用来显示,配置GPIO,用来点亮LCD的背光,
配置sdio和fatfs,用来读写sd卡上的FILE,
配置usbd MSC,用来对接PC,并将PC的读写请求转换为对SD卡的读写。
配置SRAM,用来做扩展RAM使用。
配置RTC,
配置USART,用来做串口打印。
然后,我们需要配置GPIO,用来接受KEY的输入。
++++++++++++++++++++++++++++++++++++++++++++
接下来配置WM8978相关的硬件。
需要配置一个I2C,我们这里用GPIO来模拟,所以需要配置相关的GPIO。
PB8对应SCL,PB9对应SDA。设置为上拉且OD输出。
在需要设置为input的时候,再临时切换即可。
需要配置一个I2S,我们这里使用I2S2。
注意,I2S的pin绑定关系,并不是唯一的,所以,我们仍然需要根据我们的板子的实际情况,将对应的pin绑定关系确定下来。选择各外设后,由于外设功能可关联到不同的引脚,自动分配的引脚可能与硬件连接的引脚不一致。此时,可以在需要重新关联的引脚上按住Ctrl键+鼠标左键按下,然后拖拽,会出现支持相同功能的全部复用引脚,将其拖拽到与硬件设计一致的引脚上。
当配置SD信号线为发送端时,SD_Ext自动被配置为接收端;配置SD为接收端时,SD_Ext自动被配置为发送端。
Fs为采样率,得益于Cube驱动库中的良好API实现,可以直接设置采样率,使用者不需要按照下述公式进行I2SDIV和IDD的计算及配置。
在使用STM324的I2S全双工模式时发现HAL库可能存在的一个问题,DMA使能循环模式后I2S发送和接收完成的回调不执行。查找缘由发现是HAL库的stm32f4xx_hal_i2s_ex.c文件中I2SEx_TxRxDMACplt函数在判断到开启了DMA循环模式就不在调用完成回调。
F4的半双工模式,打开stm32f4xx_hal_i2s.c,发送和接收的回调分别是在不一样的函数上实现的。很明显是否开启DMA的循环模式并不影响完成回调的执行,也就是说在半双工模式开启DMA的循环模式是能够正常使用传输完成回调。
++++++++++++++++++++++++++++++++++++++++++++++++
我们首先移植LED,KEY的模块。
接下来开始移植malloc模块。
然后需要移植I2C的模块。
然后需要移植WM8978的控制驱动模块。
++++++++++++++++++++++++++++++++++++++++++++++
接下来开始移植I2S的模块。
先来看看HAL是怎么处理I2S的。
首先是MX_I2S2_Init,它只配置I2S,但是并不使能启动,所以需要在别的位置启动。
如果需要启动I2S,那么需要使用
HAL_I2S_Transmit_DMA函数。
在HAL_I2S_MspInit中,进行硬件初始化,包括GPIO和DMA初始化。
调用HAL_DMA_Init函数对I2S的DMA控制块初始化之后,调用__HAL_LINKDMA,将DMA控制块的句柄和I2S的控制块的TX通道关联起来。
我们移植了I2S2_SampleRate_Set函数,用来动态设置fs采样率。
注意,输入到PLLI2S的clksource,是1MHZ。
我们还需要移植I2S2_SetBitwitdth_Init,这里借鉴了HAL库的写法,只修改了dataformat,
+++++++++++++++++++++++++++++++++++++++++++++++
接下来,我们开始移植wavplay模块。
不开启双缓冲,而是使用单缓冲,但是开启了两个buffer,
在每个中断来临时,说明上一次的DMA已经完成,在callback中打标,在主进程中检查标志,根据标志的不同,选择不同的buffer,再一次启动DMA传输。
我们需要覆盖定义弱函数callback。
extern volatile uint8_t wavtransferend; //i2s锟斤拷锟斤拷锟斤拷杀锟街?
extern volatile uint8_t wavwitchbuf; //i2sbufx指示锟斤拷志
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
wavwitchbuf=(~wavwitchbuf)&0x01;
wavtransferend=1;
}
+++++++++++++++++++++++++++++++++++
修改main,
添加wm8978的初始化。