硬汉嵌入式论坛

 找回密码
 立即注册
查看: 263|回复: 1
收起左侧

[SAI/I2S] STM32 SAI 实现自定义协议的总结和问题

[复制链接]

11

主题

59

回帖

92

积分

初级会员

积分
92
发表于 2025-8-14 09:02:41 | 显示全部楼层 |阅读模式
前言
SAI我也没有完全学会,文中说了一些问题,解决了但是不知道为什么,有知道的和我说一下,谢谢。
SAI的学习总结时序
bit 组成 slot,slot 组成 frame,
slot:8bit-32bit,>= data_size
frame:1-16个slot,<= 256 bit
大的容器可以大于小的容器,不足补0
SCK是bit的时钟,FS是frame的时钟

3453764-20250807110137744-2056533220.png
时钟
下图是STM32H750/743/753参考手册上的图
3453764-20250807092615913-1500806865.png
这里仅考虑主机模式
先看SAI_xCR1寄存器的NOMCK位,是0,(不知道CubeMX哪里控制,知道的说一下)。
FRL(Frame length)是帧长度寄存器的值,FRL+1就是CubeMX里帧长度的值,必须是2的幂。
OSR由下图中的master clock over sampling控制(没试过),默认是enable(1),
MCKDIV由下图中的master clock divider控制,
3453764-20250807095156313-869127452.png
所以,SCK_x = ((RCC_SAI / MCKDIV) / (OSR+1)) / (256/FRL+1)
3453764-20250807100028324-861156444.png
CubeMX注意事项
3453764-20250807101310794-1934221335.png
slot active:激活slot,一定要设置,把需要的slot都打开。
output drive:不知道作用,官方例程上开了
问题
开机后发送的第一帧数据有问题,应该都像60us-80us时的时序一样,可以开机后阻塞式发送1-2帧数据“0”。
3453764-20250807101335612-1440359975.png
[C] 纯文本查看 复制代码
HAL_SAI_Transmit_DMA()
HAL_SAI_Transmit_IT()
HAL_SAI_Transmit()
使用DMA发送的问题:hsai_BlockB的时序会比hsai_BlockA的时序晚一帧,可以开机后阻塞式发送发送1-2帧数据“0”,可以解决(不知道为什么,知道的说一下)。
如果不开启DMA和SAI中断,DMA设置为normal模式DMA只能发送一次,DMA设置为circular模式DMA可以循环发送。DMA设置为normal模式,第二次发送时
[C] 纯文本查看 复制代码
HAL_SAI_Transmit_DMA()
{...
if (hsai->State == HAL_SAI_STATE_READY)
...}
会判断为否,从而导致发送失败(不知道为什么,知道的说一下)。
中断发送没问题。
调试的时候,中断发送和DMA发送函数完成后不能立即暂停或者打断点,需要延时1-2ms,否则DMA发送AB的时序错位,中断发送只发送前边的一部分。
自定义协议
协议设定:
协议中的1位有2个阶段,相当于2个状态,
引脚A输出0b10,同时引脚B输出0b00,数据“1”,协议中的1位;
引脚A输出0b00,同时引脚B输出0b10,数据“0”,协议中的1位;
引脚A输出0b00,同时引脚B输出0b00,数据空,协议中的1位。
协议速率:100KHz,
SAI设置
1位429 = 2stage = 8bit
1slot = 1位 = 2stage = 8bit
1frame = 4slot = 32bit
所以,下图时CubeMX SAI A的设置,SAI B和这个一样,同步的。
3453764-20250807101200457-958709224.png

Data Size: 8bit
slot size: Data Size
frame length: 32bit
number of slot: 4
slot active: all // 激活全部4个slot
audio frequency:user set // 时钟频率自己设置,
// 协议的频率时100khz,1位=8bit,那引脚频率就是800khz,RCC_SAI设置为64MHz,64000k/MCKDIV/2/(256/32)=800k,MCKDIV=5
Master Clock Divider:5
Master Clock No Divider:disabled
发送数据
1位 = 1字节
BlockA 发送 0xF0
BlockB 发送 0x00 // 就是1
BlockA 发送 0x00
BlockB 发送 0xF0 // 就是0


评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
118320
QQ
发表于 2025-8-14 09:16:25 | 显示全部楼层
谢谢楼主分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-9-26 12:01 , Processed in 0.041825 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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