/*************************************************************************************************************
* 文件名 : stm32f7_sai.h
* 功能 : STM32F7 SAI接口驱动
* 作者 : cp1300@139.com
* 创建时间 : 2020-02-17
* 最后修改时间 : 2020-02-17
* 详细:
*************************************************************************************************************/
#ifndef __STM32F7_SAI_H_
#define __STM32F7_SAI_H_
#include "system.h"
#include "DMA.h"
#define SAI_CH_COUNT 2 //SAI 数量
#if(SAI_CH_COUNT==0)
#error("SAI数量不能为0");
#endif //SAI_CH_COUNT
//SAIx 音频模块模式(必须在 SAIx 音频模块禁止的情况下配置)
typedef enum
{
SAI_BLOCK_MODE_MTXD = 0, //主发送模式
SAI_BLOCK_MODE_MRXD = 1, //主接收模式
SAI_BLOCK_MODE_STXD = 2, //从发送模式
SAI_BLOCK_MODE_SRXD = 3, //从接收模式
}SAI_BLOCK_MODE;
//SAIx 音频协议配置
typedef enum
{
SAI_PROTOCOL_FREE = 0, //自由协议 由协议允许用户使用音频模块这一强大的配置功能来处理特定的音频协议(如 I2S、LSB/MSB 对齐、TDM、PCM/DSP...)。
SAI_PROTOCOL_SPDIF = 1, //SPDIF协议
SAI_PROTOCOL_AC97 = 2, //AC97协议
}SAI_PROTOCOL_TYPE;
//数据大小(采样深度)
typedef enum
{
SAI_DATA_SIZE_8BIT = 2, //8位
SAI_DATA_SIZE_10BIT = 3, //10位
SAI_DATA_SIZE_16BIT = 4, //16位
SAI_DATA_SIZE_20BIT = 5, //20位
SAI_DATA_SIZE_24BIT = 6, //24位
SAI_DATA_SIZE_32BIT = 7, //32位
}SAI_DATA_SIZE;
//同步设置
typedef enum
{
SAI_ASYNC = 0, //异步模式
SAI_SYNC_IN = 1, //音频子模块与另一个内部音频子模块同步。这种情况下,必须将该音频子模块配置为从模式
SAI_SYNC_OUT = 2, //音频子模块与外部 SAI 的嵌入式外设同步。这种情况下,应将音频子模块配置为从模式。
}SAI_SYNC_TYPE;
//FIFO阈值设置
typedef enum
{
SAI_FIFO_THR_NULL = 0, //FIFO空
SAI_FIFO_THR_1_4 = 1, //FIFO 1/4
SAI_FIFO_THR_1_2 = 2, //FIFO 1/2
SAI_FIFO_THR_3_4 = 3, //FIFO 3/4
SAI_FIFO_THR_FULL = 4, //FIFO 满
}SAI_FIFO_THR;
//Slot大小
typedef enum
{
SAI_SLOT_SIZE_DS = 0, //Slot大小由SAI_DATA_SIZE(DataSize)决定
SAI_SLOT_SIZE_16BIT = 1, //16位
SAI_SLOT_SIZE_32BIT = 2, //32位
}SAI_SLOT_SIZE;
//SAI的block配置
typedef struct
{
//基本配置
SAI_BLOCK_MODE BlockMode; //音频模块模式(必须在 SAIx 音频模块禁止的情况下配置)
SAI_PROTOCOL_TYPE BlockProtocol; //音频协议配置
SAI_DATA_SIZE DataSize; //数据大小
SAI_SYNC_TYPE Sync; //同步模式设置
SAI_FIFO_THR FIFO_Thr; //FIFO阈值
bool isLSB; //使能数据的 LSB 位优先,否则MSB优先
bool isFalEdgeSCK; //在 SCK 下降沿更改 SAI 生成的信号,在上升沿采样,否则上升沿
bool isMono; //使能单声道,否则为立体声
bool isStraiOutput; //使能立即输出,否则当 SAIXEN 置 1 时驱动音频模块输出
bool isEnableDMA; //是否使能DMA
//帧配置
u8 FrameLenght; //帧长度(实际长度为FrameLenght+1)
u8 FrameSyncLenght;//帧同步有效电平长度(实际长度为FrameSyncLenght+1)
bool isFSisChannelId;//使能 FS 信号为 SOF 信号 + 通道识别信号,否则FS信号为帧起始信号
bool isFS_HighLevel; //使能 FS 为高电平有效(上升沿),否则为FS 为低电平有效(下降沿)
bool isFS_Front; //使能 在 Slot 0 第一位的前一位上使能 FS;否则在 Slot 0 的第一位上使能 FS。
//Slot配置
SAI_SLOT_SIZE SlotSize; //Slot 大小
u16 SlotEableBit; //Slot 使能,每1bit对应一个Slot,0-15对应1-16 Slot
u8 FistBitOffset; //此位字段中设置的值定义 Slot 中第一个数据传输位的位置。它表示一个偏移值。在发送模式下,此数据字段以外的位将强制清零。在接收模式下,将丢弃额外接收的位。
u8 SlotNumber; //音频帧中的 Slot 数 (实际数量为:SlotNumber + 1)
}SAI_BLOCK_CONFIG;
//常用配置列表
//默认配置1:主发送模式,标准I2S协议,立体声模式
extern const SAI_BLOCK_CONFIG cg_SAI_MTXD_I2S_CONFIG1;
//SAI选择
typedef enum
{
SAI_CH1 = 0, //SAI1
SAI_CH2 = 1, //SAI2
}SAI_CH_TYPE;
//SAI Block选择
typedef enum
{
SAIx_BLOCK_A = 0, //Block A
SAIx_BLOCK_B = 1, //Block B
}SAI_BLOCK_TYPE;
//相关接口
bool SAI_Init(SAI_CH_TYPE ch);//SAI初始化(基本时钟使能,外设复位)
bool SAI_BlockConfig(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block, const SAI_BLOCK_CONFIG *pConfig); //SAI Block配置(会关闭Block,并且不会使能Block)
bool SAI_SetBlockEnable(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block, bool isEnable); //开启或者关闭Block
bool SAI_SetSampleRate(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block,u32 SampleRate); //SAI 设置采样时钟频率(使用的I2S PLL提供时钟,所有SAI共用)
bool SAI_SetEnableDMA(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block,bool isEnable); //SAI使能DMA
u32 SAI_GetBlockDataAddr(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block); //SAI 获取Block 的收发数据地址
void SAI_BlockDataSize(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block, SAI_DATA_SIZE DataBitSize); //SAI Block配置音频数据大小(采样深度)
//SAI DMA相关
void SAI_SetDMAConfig(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block,bool isTxMode, DMA_SIZE_TYPE DataBitSize); //SAI DMA配置
void SAI_SetDMAStartTrans(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block,void *pBuff1, void *pBuff2, u16 DataCount); //SAI DMA 启动传输
void SAI_SetDMAStopTrans(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block); //SAI DMA 停止传输
int SAI_WaitDMATransCompl(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block, u32 TimeOutMs); //SAI DMA 等待传输完成
/*************************************************************************************************************************
* 函数 : __inline void SAI_IO_Init(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block)
* 功能 : SAI IO 初始化(由于IO口复用较多,请根据实际使用进行配置)
* 参数 : ch:SAI选择;block:block选择;
* 返回 : IIC_ERROR
* 依赖 : 底层宏定义
* 作者 : cp1300@139.com
* 时间 : 2020-02-17
* 最后修改时间 : 2020-02-17
* 说明 : SAI1A
MCK_A PE2 AF6
FS_A PE4 AF6
SCK_A PE5 AF6
SD_A PE6 AF6
SD_A PC1 AF6
SD_A PB2 AF6
SD_A PD6 AF6
SAI1B
SD_B PF6 AF6
MCLK_B PF7 AF6
SCK_B PF8 AF6
FS_B PF9 AF6
SD_B PE3 AF6
SAI2A
SD_A PD11 AF10
FS_A PD12 AF10
SCK_A PD13 AF10
MCK_A PE0 AF10
MCK_A PI4 AF10
SCK_A PI5 AF10
SD_A PI6 AF10
FS_A PI7 AF10
SAI2B
MCK_B PE6 AF10
FS_B PC0 AF8
SD_B PA0 AF10
MCK_B PA1 AF10
SCK_B PA2 AF8
SCK_B PH2 AF10
MCK_B PH3 AF10
SD_B PF11 AF10
SD_B PE11 AF10
SCK_B PE12 AF10
FS_B PE13 AF10
MCK_B PE14 AF10
FS_B PA12 AF8
FS_B PG9 AF10
SD_B PG10 AF10
*************************************************************************************************************************/
__inline void SAI_IO_Init(SAI_CH_TYPE ch, SAI_BLOCK_TYPE block)
{
if(ch == SAI_CH1) //SAI1
{
if(block == SAIx_BLOCK_A) //SAI1_A
{
//PE2,PE4,PE5,PE6
SYS_DeviceClockEnable(DEV_GPIOE, TRUE); //IO时钟使能
SYS_GPIOx_Init(GPIOE, BIT2|BIT4|BIT5|BIT6, AF_PP, SPEED_100M); //速度给最大
SYS_GPIOx_SetAF(GPIOE, 2, AF6_SAI1);
SYS_GPIOx_SetAF(GPIOE, 4, AF6_SAI1);
SYS_GPIOx_SetAF(GPIOE, 5, AF6_SAI1);
SYS_GPIOx_SetAF(GPIOE, 6, AF6_SAI1);
}
else //SAI1_B
{
//PF6,PF7,PF8,PF9
SYS_DeviceClockEnable(DEV_GPIOF, TRUE); //IO时钟使能
SYS_GPIOx_Init(GPIOF, BIT6|BIT7|BIT8|BIT9, AF_PP, SPEED_100M); //速度给最大
SYS_GPIOx_SetAF(GPIOF, 6, AF6_SAI1);
SYS_GPIOx_SetAF(GPIOF, 7, AF6_SAI1);
SYS_GPIOx_SetAF(GPIOF, 8, AF6_SAI1);
SYS_GPIOx_SetAF(GPIOF, 9, AF6_SAI1);
}
}
else //SAI2
{
if(block == SAIx_BLOCK_A) //SAI2_A
{
//PI4,PI5,PI6,PI7
SYS_DeviceClockEnable(DEV_GPIOI, TRUE); //IO时钟使能
SYS_GPIOx_Init(GPIOI, BIT4|BIT5|BIT6|BIT7, AF_PP, SPEED_100M); //速度给最大
SYS_GPIOx_SetAF(GPIOI, 4, AF10_SAI2);
SYS_GPIOx_SetAF(GPIOI, 5, AF10_SAI2);
SYS_GPIOx_SetAF(GPIOI, 6, AF10_SAI2);
SYS_GPIOx_SetAF(GPIOI, 7, AF10_SAI2);
}
else //SAI2_B
{
//PE6,PE11,PE12,PE13
SYS_DeviceClockEnable(DEV_GPIOE, TRUE); //IO时钟使能
SYS_GPIOx_Init(GPIOE, BIT6|BIT11|BIT12|BIT13, AF_PP, SPEED_100M); //速度给最大
SYS_GPIOx_SetAF(GPIOE, 6, AF10_SAI2);
SYS_GPIOx_SetAF(GPIOE, 11, AF10_SAI2);
SYS_GPIOx_SetAF(GPIOE, 12, AF10_SAI2);
SYS_GPIOx_SetAF(GPIOE, 13, AF10_SAI2);
}
}
}
#endif //__STM32F7_SAI_H_
|