概要

前言:这篇文章主要记录自己学习的过程

最近拿到一块STM32F767IGT6正点原子板子,叫阿波罗开发板,在家无事想着播放一下David的音乐
,自己玩一下,正点实现的挺简单的,效果还行。直到我上手之后我才觉得和吃了屎一样,感觉代码风格比较落后,而且代码耦合性太高了,很难移植到其他芯片的开发板上。最开始去b站搜发现阿波罗F7没讲这一节,后面去他M4视频里面听了一点关于I2S的原理,但是也讲的很差,但是看了一下最新版的视频讲的还挺不错的,什么时候把这清朝的老视频更新一下,让人学的真的是无语。

而且,它把内存分配,mcu屏幕打印,wav解码啥的,全放一起,我单单把代码移植跑通还是容易,但是这个耦合不去,我感觉我学不到东西,就自己开始一步一步去耦合的过程了。

还有就是学F7最难的不是一些代码的实现,而是一些底层的原理,我这里不过多的赘述原理,只求大家看了这篇文章能知道每个东西是干嘛的,就算我这篇博客的成功了。

大体框架

整个系统的框架如下:(注意:SDMMC虽然画在STM32外面,但是它是stm32外设,只是这样方便理解)
我大概概述一下:
SD卡里面存放了我们的音乐文件,与F7的SDMMC外设进行相连,连接在SD卡槽上,为了方便我们操作我们的音频文件,我们把SD卡挂载在FATFS上,这样就相当于用stm32操作以前我们学的C语言里面的文件操作,就可以让我们的操作变的很简单。然后就是我们通过FATFS读取到wav文件之后,将读到的buffer通过DMA双缓冲传输到SAI接口,WM8978意识到SAI有数据来了,它就会将音频数据输出出来,我们的I2C自然就是对WM8978的一些状态进行设置,比如说调节喇叭和耳机的音量啊,配置输出输入模式啊等等,本文只讲WM8978的输出
在这里插入图片描述

硬件配合STM32CUBEMX进行说明

1. SD卡

驱动方式:
SD卡有两种驱动方式:

  • SDIO接口:CLK/CMD/DAT0~3 (本文使用)
  • SPI :CS/CLK/MOSI/MISO(之后有机会再使用)

了解过SPI的就知道,SPI分为软件和硬件两种方式,F7H7系列还有功能更加强大的QSPI,我们这里先不概述了。
在这里插入图片描述

原理图如下:
在这里插入图片描述
这里可以看到SD卡的接口是SDIO而不是SDMMC,这只是写法上的区别,SDMMC可以理解成SDIO的升级版,速度先不提,SDMMC不仅支持SD卡,还支持emmc。本文没有使用SDMMC的DMA,采用直接传输的方式。

SDMMC在stm32cubemx里支持5种模式:
在这里插入图片描述

选项 卡类型 数据线 常见用途
Disable 不用 SDMMC
SD 1 bit SD 卡 DAT0 兼容性最好、最慢
SD 4 bits Wide bus SD 卡 DAT0–DAT3 最常用,速度快
MMC 1 bit MMC / eMMC DAT0 初始化或低速
MMC 4 bits Wide bus MMC / eMMC DAT0–DAT3 中速
MMC 8 bits Wide bus MMC / eMMC DAT0–DAT7 eMMC 专用,高速

我们这里先试用SD 1 bit模式,四位宽总线模式,以及配合DMA我们到后面有机会再说,我旨在先用最简单的方式驱动。注意:SD卡最开始初始化的时候我们最好用1bit模式,直接用4bit模式可能会出问题,因为上电状态下多线可能不同步,容易通信失败,也是CUBEMX没考虑周到的一个点。

SD卡参数配置:
在这里插入图片描述

参数项 当前设置 作用 配置原因
Clock transition on which the bit capture is made Rising transition 时钟上升沿采样数据 SD 协议规定
SDMMC Clock divider bypass Disable 不绕过分频器 需要精确控制 SD 时钟
SDMMC Clock output enable when the bus is idle Disable power save 空闲时不关闭时钟 稳定性优先
SDMMC hardware flow control Disable 关闭硬件流控 SD 卡通常不需要
SDMMCCLK clock divide factor 0 SDMMC 时钟不再分频 进入高速模式

第五个参数比较重要 它是SD卡时钟配置的一个依据,它就是下面文字中的CLKDIV,手册也有说明。

  • SDMMC_CK=SDMMCCLK/(2+CLKDIV)
    在这里插入图片描述

其中的SDMMC_CK就是我们SD卡的CLK线,SDMMCCLK就是SDMMC 外设的输入时钟。在STM32CUBEMX中如下图所示。
在这里插入图片描述
我们设置的CLKDIV=0,所以我们最后得出来SD卡SCL的时钟频率是48/(2+0)Mhz=24Mhz。

2.WM8978(SAI)

WM8978原理图如下:
WM8978原理图
从原理图能清楚的看到SAI接口和IIC接口。
SAI:
SAI(Serial Audio Interface)可以把它理解为 “升级版、超集的 I2S,是 STM32 在中高端型号里提供的一套更灵活、更强的音频串行接口。那什么是I2S呢,I2S 是 Philips 提出的标准音频总线协议。你可以把他理解为SPI或者I2C一样的通信协议,只不过I2S更多应用于音频处理而已。SAI更底层的原理,我就不概述了,我只说一下我的参数为什么这么配置,如果想更深入了解这个协议,可以看下面的这篇文章,讲的很好。

https://www.taterli.com/3120

SAI配置如下图所示:
在这里插入图片描述
在这里插入图片描述
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a00ba5ac6a074055b3ce9f521f1bf002.png

参数 设置 设置原因 其他原因
Mode Master with Master Clock Out STM32 提供 BCLK / LRCLK / MCLK 给 WM8978 SAI1_MCLKA 无时钟,根本不工作
--------------- ---------------------------- ------------------------------------- ---------------
Synchronization Inputs Asynchronous 单独用 SAI A,不依赖 SAI B 同步模式配置复杂,没必要
--------------- ---------------------------- ------------------------------------- ---------------
Protocol Free 用的是“类 I2S”,但需要自己定义 Frame I2S 固定,后面参数会被限制
Audio Mode Master Transmit 播放 WAV,不是录音 设成 Receive 就没声音
Frame Length 64 bits 左声道32bit + 右左声道32bit = 一帧 WAV 是 16bit,但帧允许 padding
Data Size 32 bits 是SAI 寄存器/DMA 最稳配置 16bit WAV → 扩展到 32bit
Slot Size 32 bits 一个声道占一个 slot 多出来的 16bit 填 0
Output Mode Stereo 左右声道,mono是单声道,只会发送一个slot 和 WAV 的双声道一致
Companding Mode No companding WAV 是线性 PCM(原始音频) A-law/u-law 不用(压缩编码)
SD Line Output Mode Driven 主机必须驱动数据线 否则总线悬空 (TRI-state包括高组态)
--------------- ---------------------------- ------------------------------------- ---------------
First Bit MSB First 音频标准 (I2S协议) WM8978 只认 MSB
Frame Sync Definition Channel Identification LRCLK=0/1 区分左右声道 WM8978 默认就是这种
Frame Sync Polarity Active Low 符合 I2S 标准 大多数 Codec 默认
Frame Sync Offset Before First Bit I2S 标准时序 数据在 LRCLK 翻转后 1bit 输出
Frame Sync Active Level Length 32 FS 占一个 slot 长度 一个声道 32bit
------------------------------ ---------------------- ---------------- ---------------------
First Bit Offset 0 数据紧贴 slot 起始 不会移位
Number of Slots 2 左 + 右 标准立体声
Slot 0 Active 左声道
Slot 1 Active 右声道
Slot Active Final Value 0x00000003 bit0+bit1 CubeMX 自动生成
-------------------- ------------ ---------------- -----------
Master Clock Divider Enabled 给 WM8978 提供 MCLK 很多 IC 必须
Audio Frequency 44.1 kHz 和 WAV 完全一致 设错会变调
Clock Strobing Falling Edge 符合 I2S 采样习惯 边沿错会噪声
Real Audio Frequency 41.868 kHz(按道理越解决44.1khz越好) PLL 精度限制(但是这样设置声音也还是会变调,cubmx配置的参数有5%的误差,后面需要我们手动调整) 属于不可接受范围
-------------------- ------------ ---------------- -----------
FIFO Threshold One Quarter Full DMA 触发及时 DMA负载适中
Output Drive Enabled 推动外部 Codec 信号完整性更好,提高PCB驱动能力

*Frame Length与Slot Size的关系(图片有点点误差别介意):
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7e5c28cacbad43569b6b166174e61134.png
WAV文件的一般信息:
在这里插入图片描述

开启SAI1_A的DMA,采用DMA双缓冲的方式,减少CPU的负担,cubemx配置如下(wav文件是16bit,所以这里DMA选择Half word):
在这里插入图片描述
I2C:
WM8978的I2C我们直接用软件I2C,这里只要简单移植一下驱动就好了,很简单,后面讲代码的时候讲一下。

3.FATFS

在这里插入图片描述

在这里插入图片描述
SD卡挂载FATFS的路径,我的SD卡的文件结构如下:
MUSIC文件夹下有很多子文件夹,他们分别是陶喆对应发的专辑名称,每个子文件夹里面都是wav文件,本来里面全是中文命名的M4A文件,我用python转了一下,把文件夹以及wav文件名都翻译成了英文,把M4a转成了wav文件,方便我们解码使用。

在这里插入图片描述

在这里插入图片描述

4.FMC:MCU+LCD配置

我们这里利用FMC模拟8080时序来配置LCD,LCD驱动依旧用的正点原子的。
注意!!!:F7和H7等高系列M7核,都带有MPU内存保护,配置完FMC之后我们还需要配置MPU!,低系列不需要
原理图如下:
在这里插入图片描述
在这里插入图片描述
这里是什么东西呢,请打开我们STM32F7的中文手册对应的FMC的那节。
其实这每个选项都对应了我们FMC的存储区域,我们是用SRAM(LCD Interface),所以我们需要用到前四个选项,我们选择存储区域1就好了(Bank1),记住这个Bank1的首地址,我们后面会用(0x6000000)。
F7将FMC分成6个Bank区,前四个bank是NOR Flash/PSRAM/SRAM/ROM,后两个Bank是与SDRAM相关的。
在这里插入图片描述
其中每个Bank又分成四个小bank,对应的就是我们的NE1-NE4,我们选择NE1。
在这里插入图片描述

我们这里选择的是LCD Interface,实际上底层代码也是在把这个选项当SRAM使用,但是可能会有人问为什么不直接选SRAM,其实这是cubemx想好了的,它觉得大部分人都会用LCD屏幕,所以从SRAM里面分出一个选项作为LCD Interface,这样也不用开启FMC_AX(0-17)地址线的使用,因为我们只使用A18这个地址线,使能SRAM的话,会开启FMC_A0到FMC_A17的GPIO,当然我们之间选择SRAM也是没问题的,时序以及功能配置都与LCD Interface一样,配置如下图所示:
在这里插入图片描述FMC的配置我们按照原理图上的网络标签去配置就行了。

  • FMC_NE1对应NE1
  • FMC_A18对应A18
  • D0-D15对应16bits
  • 注意:配置完FMC之后,它给的GPIO是CUBEMX默认的,我对应F7正点原子的开发板是NE1需要修改,其他的不用修改,你们配置的时候注意修改就好了。
    在这里插入图片描述

在这里插入图片描述
这里的一些时序的设置我就不赘述了,网上有很多人讲了如何看手册配置,具体可以参照这位博主的文章,已经很详细了:
https://blog.51cto.com/u_13640625/3021879

5.定时器与串口设置

其中定时器我采用的一个基本定时器TIM6,用于按键状态机消抖,至于我们怎么设置它的预分频器值和自动重装载值,我们看看手册上描述TIM6挂载在哪条总线上。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一般按键消抖时间为10ms,我们TIM6总线频率为108Mhz,所以108000000hz/108/10000=100hz,推出时间是10ms。

串口设置也没什么多说的,注意F767板子上的引脚是那两个就行,很有可能不是cubemx默认的引脚。
在这里插入图片描述

在这里插入图片描述

6.代码:

代码太多了,不好讲解,大家自己看吧,我主要讲解一些配置的原理。
https://gitee.com/zhhdfadfadsdsf/stm32-f767-igt6–music-player

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐