OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12085|回复: 12

基于HAL库的I2S配置

[复制链接]

3

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
86
金钱
86
注册时间
2015-8-21
在线时间
11 小时
发表于 2016-9-19 15:12:07 | 显示全部楼层 |阅读模式
本帖最后由 襟铭心缘 于 2016-9-19 15:12 编辑

最近参考原子哥的SAI例子和标准库的例子成功用HAL库配置除了I2S。
下面是代码:
[mw_shl_code=c,true]#include "i2s.h"
#include "delay.h"
I2S_HandleTypeDef I2S_Handle;
DMA_HandleTypeDef I2S_TxDMA_Handle;

//开启I2S2的DMA功能,HAL库没有提供此函数
//因此我们需要自己操作寄存器编写一个
void I2S2_DMA_Enable(void)
{
  u32 tempreg=0;
  tempreg=SPI2->CR2;          //先读出以前的设置                        
        tempreg|=SPI_CR2_TXDMAEN;                                            //使能DMA
        SPI2->CR2=tempreg;                    //写入CR1寄存器中
}
void HAL_I2S_MspInit(I2S_HandleTypeDef *hi2s)
{
  GPIO_InitTypeDef GPIO_Initure;
        __HAL_RCC_SPI2_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        __HAL_RCC_GPIOC_CLK_ENABLE();
        __HAL_RCC_GPIOD_CLK_ENABLE();
        __HAL_RCC_GPIOI_CLK_ENABLE();
        
        GPIO_Initure.Mode=GPIO_MODE_AF_PP;
        GPIO_Initure.Pull=GPIO_PULLUP;
        GPIO_Initure.Speed=GPIO_SPEED_HIGH;
        GPIO_Initure.Pin=GPIO_PIN_12;
        GPIO_Initure.Alternate=GPIO_AF5_SPI2;
        HAL_GPIO_Init(GPIOB,&GPIO_Initure);
        
        GPIO_Initure.Pin=GPIO_PIN_2;
        GPIO_Initure.Alternate=GPIO_AF6_I2S2ext;
        HAL_GPIO_Init(GPIOC,&GPIO_Initure);
        
        GPIO_Initure.Pin=GPIO_PIN_6;
        GPIO_Initure.Alternate=GPIO_AF5_SPI2;
        HAL_GPIO_Init(GPIOC,&GPIO_Initure);
        
        GPIO_Initure.Pin=GPIO_PIN_3;
        GPIO_Initure.Alternate=GPIO_AF5_SPI2;
        HAL_GPIO_Init(GPIOD,&GPIO_Initure);
        
        GPIO_Initure.Pin=GPIO_PIN_3;
        GPIO_Initure.Alternate=GPIO_AF5_SPI2;
        HAL_GPIO_Init(GPIOI,&GPIO_Initure);
        
        
}
//参数I2S_Mode:  @ref SPI_I2S_Mode  I2S_MODE_SLAVE_TX:从机发送;I2S_MODE_SLAVE_RX:从机接收;I2S_MODE_MASTER_TX:主机发送;I2S_MODE_MASTER_RX:主机接收;
//参数I2S_DataFormat: @ref SPI_I2S_Data_Format :数据长度,I2S_DATAFORMAT_16B,16位标准;I2S_DATAFORMAT_16B_EXTENDED,16位扩展(frame=32bit);I2S_DATAFORMAT_24B,24位;I2S_DATAFORMAT_32B,32位.

void I2S2_Init(u16 I2S_Mode,u16 I2S_DataFormat)
{
  
        I2S_Handle.Instance=SPI2;
        __HAL_I2S_DISABLE(&I2S_Handle);
        I2S_Handle.Init.Mode=I2S_Mode;
        I2S_Handle.Init.Standard=I2S_STANDARD_PHILIPS;
        I2S_Handle.Init.DataFormat=I2S_DataFormat;
        I2S_Handle.Init.MCLKOutput=I2S_MCLKOUTPUT_ENABLE;        
        I2S_Handle.Init.AudioFreq=I2S_AUDIOFREQ_DEFAULT;
        I2S_Handle.Init.CPOL=I2S_CPOL_LOW;
        I2S_Handle.Init.ClockSource=I2S_CLOCK_PLL;
        if(HAL_I2S_GetState(&I2S_Handle) == HAL_I2S_STATE_RESET)
  {
    HAL_I2S_MspInit(&I2S_Handle);               
  }
        HAL_I2S_Init(&I2S_Handle);
        __HAL_I2S_ENABLE(&I2S_Handle);
        I2S2_DMA_Enable();
        
}

//采样率计算公式:Fs=I2SxCLK/[256*(2*I2SDIV+ODD)]
//I2SxCLK=(HSE/pllm)*PLLI2SN/PLLI2SR
//一般HSE=25Mhz
//pllm:在Sys_Clock_Set设置的时候确定,一般是8
//PLLI2SN:一般是192~432
//PLLI2SR:2~7
//I2SDIV:2~255
//ODD:0/1
//I2S分频系数表@pllm=25,HSE=25Mhz,即vco输入频率为1Mhz
//表格式:采样率/10,PLLI2SN,PLLI2SR,I2SDIV,ODD
const u16 I2S_PSC_TBL[][5]=
{
        {800 ,256,5,12,1},                //8Khz采样率
        {1102,429,4,19,0},                //11.025Khz采样率
        {1600,213,2,13,0},                //16Khz采样率
        {2205,429,4, 9,1},                //22.05Khz采样率
        {3200,213,2, 6,1},                //32Khz采样率
        {4410,271,2, 6,0},                //44.1Khz采样率
        {4800,258,3, 3,1},                //48Khz采样率
        {8820,316,2, 3,1},                //88.2Khz采样率
        {9600,344,2, 3,1},          //96Khz采样率
        {17640,361,2,2,0},          //176.4Khz采样率
        {19200,393,2,2,0},          //192Khz采样率
};  

//设置IIS的采样率(@MCKEN)
//samplerate:采样率,单位:Hz
//返回值:0,设置成功;1,无法设置.
u8 I2S2_SampleRate_Set(u32 samplerate)
{
        u8 i=0;
        u32 tempreg=0;  
        samplerate/=10;//缩小10倍   
        
        for(i=0;i<(sizeof(I2S_PSC_TBL)/10);i++)//看看改采样率是否可以支持
        {
                if(samplerate==I2S_PSC_TBL[0])break;
        }
        __HAL_RCC_PLLI2S_DISABLE();
  if(i==(sizeof(I2S_PSC_TBL)/10))return 1;//搜遍了也找不到
        //设置I2SxCLK的频率(x=2)  设置PLLI2SN PLLI2SR
  RCC->PLLI2SCFGR = ((u32)I2S_PSC_TBL[1] << 6)  | ((u32)I2S_PSC_TBL[2] << 28);
        RCC->CR|=1<<26;                                        //开启I2S时钟
        while((RCC->CR&1<<27)==0);                //等待I2S时钟开启成功.
        tempreg=I2S_PSC_TBL[3]<<0;        //设置I2SDIV
        tempreg|=I2S_PSC_TBL[4]<<8;        //设置ODD位
        tempreg|=1<<9;                                        //使能MCKOE位,输出MCK
        SPI2->I2SPR=tempreg;                        //设置I2SPR寄存器
        return 0;
}
//I2S2 TX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量

void I2S2_TX_DMA_Init(u8* buf0,u8 *buf1,u16 num)
{
        __HAL_RCC_DMA1_CLK_ENABLE();
        __HAL_LINKDMA(&I2S_Handle,hdmatx,I2S_TxDMA_Handle);
        
        I2S_TxDMA_Handle.Instance=DMA1_Stream4;
        I2S_TxDMA_Handle.Init.Channel=DMA_CHANNEL_0;
        I2S_TxDMA_Handle.Init.Direction=DMA_MEMORY_TO_PERIPH;
        I2S_TxDMA_Handle.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
        I2S_TxDMA_Handle.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_1QUARTERFULL;
        I2S_TxDMA_Handle.Init.MemBurst=DMA_MBURST_SINGLE;
        I2S_TxDMA_Handle.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD;
        I2S_TxDMA_Handle.Init.MemInc=DMA_MINC_ENABLE;
        I2S_TxDMA_Handle.Init.Mode=DMA_CIRCULAR;
        I2S_TxDMA_Handle.Init.PeriphBurst=DMA_PBURST_SINGLE;
        I2S_TxDMA_Handle.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD;
        I2S_TxDMA_Handle.Init.PeriphInc=DMA_PINC_DISABLE;
        I2S_TxDMA_Handle.Init.Priority=DMA_PRIORITY_HIGH;
        HAL_DMA_DeInit(&I2S_TxDMA_Handle);                            //先清除以前的设置
  HAL_DMA_Init(&I2S_TxDMA_Handle);                                    //初始化DMA
        HAL_DMAEx_MultiBufferStart(&I2S_TxDMA_Handle,(u32)buf0,(u32)&SPI2->DR,(u32)buf1,num);//开启双缓冲
  __HAL_DMA_DISABLE(&I2S_TxDMA_Handle);                         //先关闭DMA
        
        __HAL_DMA_ENABLE_IT(&I2S_TxDMA_Handle,DMA_IT_TC);             //开启传输完成中断
  __HAL_DMA_CLEAR_FLAG(&I2S_TxDMA_Handle,DMA_FLAG_TCIF0_4);     //清除DMA传输完成中断标志位
  HAL_NVIC_SetPriority(DMA1_Stream4_IRQn,0,0);                    //DMA中断优先级
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
        
}
//I2S DMA回调函数指针
void (*i2s_tx_callback)(void);        //TX回调函数
//DMA1_Stream4中断服务函数
void DMA1_Stream4_IRQHandler(void)
{
/*        __HAL_DMA_GET_FLAG(xxx)!=RESET时可以正常工作
                __HAL_DMA_GET_FLAG(xxx)==SET时无法正常工作
                库文件stm32f4xx_hal_dma.h中说明了FLAG的状态是SET or RESET
                The state of FLAG (SET or RESET)
                很奇怪!!!        
*/
        if(__HAL_DMA_GET_FLAG(&I2S_TxDMA_Handle,DMA_FLAG_TCIF0_4)!=RESET)////DMA1_Stream4,传输完成标志
        {
                __HAL_DMA_CLEAR_FLAG(&I2S_TxDMA_Handle,DMA_FLAG_TCIF0_4);     //清除DMA传输完成中断标志位
    i2s_tx_callback();        //执行回调函数,读取数据等操作在这里面处理
        }                                                                                            
}  
//I2S开始播放
void I2S_Play_Start(void)
{            
        __HAL_DMA_ENABLE(&I2S_TxDMA_Handle);//开启DMA TX传输,开始播放                 
}
//关闭I2S播放
void I2S_Play_Stop(void)
{   
        __HAL_DMA_DISABLE(&I2S_TxDMA_Handle);//关闭DMA,结束播放                  
}        
        




[/mw_shl_code]

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
8
金钱
8
注册时间
2020-10-11
在线时间
1 小时
发表于 2021-4-27 15:12:47 | 显示全部楼层
在设置采样率那个地方I2S_PSC_TBL[1] 都应该加个【i】,即I2S_PSC_TBL[i][x]
回复 支持 1 反对 0

使用道具 举报

10

主题

73

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
459
金钱
459
注册时间
2016-7-7
在线时间
110 小时
发表于 2016-11-11 08:31:45 | 显示全部楼层
怎么没人顶啊,顶一下,用HAL库配置出I2S
回复 支持 反对

使用道具 举报

14

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
168
金钱
168
注册时间
2012-11-18
在线时间
16 小时
发表于 2016-11-12 23:58:14 来自手机 | 显示全部楼层
你这个代码没问题吧,我用了声音不太对
回复 支持 反对

使用道具 举报

buddy218 该用户已被删除
发表于 2017-4-6 21:22:58 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

buddy218 该用户已被删除
发表于 2017-4-7 14:18:14 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

36

主题

256

帖子

0

精华

高级会员

Rank: 4

积分
921
金钱
921
注册时间
2016-4-20
在线时间
169 小时
发表于 2017-6-2 11:26:29 | 显示全部楼层
楼主我也用F429的板子按照你的板子进行了配置,但是没有时钟输出出来。按照我的理解,只要把GPIO和I2S配置了主时钟应该可以出来的。不知道楼主主程序初始化的部分是怎么样的。是不是还有其他的配置。
回复 支持 反对

使用道具 举报

259

主题

806

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1887
金钱
1887
注册时间
2012-10-28
在线时间
353 小时
发表于 2017-12-27 09:24:55 | 显示全部楼层
czdspeed 发表于 2017-6-2 11:26
楼主我也用F429的板子按照你的板子进行了配置,但是没有时钟输出出来。按照我的理解,只要把GPIO和I2S配置 ...

你好,请问你的搞定了没有啊 ?
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2021-2-27
在线时间
0 小时
发表于 2021-6-20 23:45:33 | 显示全部楼层
修正版:


#include "i2s.h"
#include "delay.h"

I2S_HandleTypeDef I2S_Handle;
DMA_HandleTypeDef I2S_TxDMA_Handle;   //DMA发送句柄

DMA_HandleTypeDef I2S_RxDMA_Handler;   //DMA接收句柄

//开启I2S2的DMA功能,HAL库没有提供此函数
//因此我们需要自己操作寄存器编写一个
void I2S2_DMA_Enable(void) {
        u32 tempreg = 0;
        tempreg = SPI2->CR2;                        //先读出以前的设置
        tempreg |= SPI_CR2_TXDMAEN;                //使能DMA
        SPI2->CR2 = tempreg;                        //写入CR1寄存器中
}

void HAL_I2S_MspInit(I2S_HandleTypeDef *hi2s) {
        GPIO_InitTypeDef GPIO_Initure;
        __HAL_RCC_SPI2_CLK_ENABLE();

        __HAL_RCC_GPIOA_CLK_ENABLE();               //使能GPIOX时钟
        __HAL_RCC_GPIOC_CLK_ENABLE();               //使能GPIOX时钟

        GPIO_Initure.Mode = GPIO_MODE_AF_PP;
        GPIO_Initure.Pull = GPIO_PULLUP;
        GPIO_Initure.Speed = GPIO_SPEED_HIGH;

        GPIO_Initure.Pin = GPIO_PIN_15;
        GPIO_Initure.Alternate = GPIO_AF5_SPI2;
        HAL_GPIO_Init(GPIOA, &GPIO_Initure);

        GPIO_Initure.Pin = GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_12;
        HAL_GPIO_Init(GPIOC, &GPIO_Initure);

        GPIO_Initure.Pin = GPIO_PIN_11;
        GPIO_Initure.Alternate = GPIO_AF6_I2S2ext;
        HAL_GPIO_Init(GPIOC, &GPIO_Initure);

}
//参数I2S_Mode:  @Ref SPI_I2S_Mode  I2S_MODE_SLAVE_TX:从机发送;I2S_MODE_SLAVE_RX:从机接收;I2S_MODE_MASTER_TX:主机发送;I2S_MODE_MASTER_RX:主机接收;
//参数I2S_DataFormat: @ref SPI_I2S_Data_Format :数据长度,I2S_DATAFORMAT_16B,16位标准;I2S_DATAFORMAT_16B_EXTENDED,16位扩展(frame=32bit);I2S_DATAFORMAT_24B,24位;I2S_DATAFORMAT_32B,32位.

//void I2S2_Init(u16 I2S_Mode, u16 I2S_DataFormat) {
void I2S2_Init(u16 I2S_Standard, u16 I2S_Mode, u16 I2S_Clock_Polarity, u16 I2S_DataFormat) {

        I2S_Handle.Instance = SPI2;
        __HAL_I2S_DISABLE(&I2S_Handle);
        I2S_Handle.Init.Mode = I2S_Mode;
        I2S_Handle.Init.Standard = I2S_Standard;
        I2S_Handle.Init.DataFormat = I2S_DataFormat;
        I2S_Handle.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
        I2S_Handle.Init.AudioFreq = I2S_AUDIOFREQ_DEFAULT;
        I2S_Handle.Init.CPOL = I2S_Clock_Polarity;
        I2S_Handle.Init.ClockSource = I2S_CLOCK_PLL;
        if (HAL_I2S_GetState(&I2S_Handle) == HAL_I2S_STATE_RESET) {
                HAL_I2S_MspInit(&I2S_Handle);
        }
        HAL_I2S_Init(&I2S_Handle);
        __HAL_I2S_ENABLE(&I2S_Handle);
        I2S2_DMA_Enable();

}

//采样率计算公式:Fs=I2SxCLK/[256*(2*I2SDIV+ODD)]
//I2SxCLK=(HSE/pllm)*PLLI2SN/PLLI2SR
//一般HSE=25Mhz
//pllm:在Sys_Clock_Set设置的时候确定,一般是8
//PLLI2SN:一般是192~432
//PLLI2SR:2~7
//I2SDIV:2~255
//ODD:0/1
//I2S分频系数表@pllm=25,HSE=25Mhz,即vco输入频率为1Mhz
//表格式:采样率/10,PLLI2SN,PLLI2SR,I2SDIV,ODD
const u16 I2S_PSC_TBL[][5] = {
                { 800, 256, 5, 12, 1 },                //8Khz采样率
                { 1102, 429, 4, 19, 0 },                //11.025Khz采样率
                { 1600, 213, 2, 13, 0 },                //16Khz采样率
                { 2205, 429, 4, 9, 1 },                //22.05Khz采样率
                { 3200, 213, 2, 6, 1 },                //32Khz采样率
                { 4410, 271, 2, 6, 0 },                //44.1Khz采样率
                { 4800, 258, 3, 3, 1 },                //48Khz采样率
                { 8820, 316, 2, 3, 1 },                //88.2Khz采样率
                { 9600, 344, 2, 3, 1 },          //96Khz采样率
                { 17640, 361, 2, 2, 0 },          //176.4Khz采样率
                { 19200, 393, 2, 2, 0 },          //192Khz采样率
                };

//设置IIS的采样率(@MCKEN)
//samplerate:采样率,单位:Hz
//返回值:0,设置成功;1,无法设置.
u8 I2S2_SampleRate_Set(u32 samplerate) {
        u8 i = 0;
        u32 tempreg = 0;
        samplerate /= 10;          //缩小10倍

        for (i = 0; i < (sizeof(I2S_PSC_TBL) / 10); i++)          //看看改采样率是否可以支持
                        {
                if (samplerate == I2S_PSC_TBL[0])
                        break;
        }
        __HAL_RCC_PLLI2S_DISABLE();
        if (i == (sizeof(I2S_PSC_TBL) / 10))
                return 1;          //搜遍了也找不到
        //设置I2SxCLK的频率(x=2)  设置PLLI2SN PLLI2SR
        RCC->PLLI2SCFGR = ((u32) I2S_PSC_TBL[1] << 6) | ((u32) I2S_PSC_TBL[2] << 28);
        RCC->CR |= 1 << 26;                                        //开启I2S时钟
        while ((RCC->CR & 1 << 27) == 0)
                ;                //等待I2S时钟开启成功.
        tempreg = I2S_PSC_TBL[3] << 0;        //设置I2SDIV
        tempreg |= I2S_PSC_TBL[4] << 8;        //设置ODD位
        tempreg |= 1 << 9;                                        //使能MCKOE位,输出MCK
        SPI2->I2SPR = tempreg;                        //设置I2SPR寄存器
        return 0;
}
//I2S2 TX DMA配置
//设置为双缓冲模式,并开启DMA传输完成中断
//buf0:M0AR地址.
//buf1:M1AR地址.
//num:每次传输数据量
void I2S2_TX_DMA_Init(u8* buf0, u8 *buf1, u16 num) {
        __HAL_RCC_DMA1_CLK_ENABLE();        //DMA1时钟使能
        __HAL_LINKDMA(&I2S_Handle, hdmatx, I2S_TxDMA_Handle);

        I2S_TxDMA_Handle.Instance = DMA1_Stream4;
        I2S_TxDMA_Handle.Init.Channel = DMA_CHANNEL_0;  //通道0 SPI2_TX通道
        I2S_TxDMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH;        //存储器到外设模式
        I2S_TxDMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        I2S_TxDMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
        I2S_TxDMA_Handle.Init.MemBurst = DMA_MBURST_SINGLE;
        I2S_TxDMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        I2S_TxDMA_Handle.Init.MemInc = DMA_MINC_ENABLE;
        I2S_TxDMA_Handle.Init.Mode = DMA_CIRCULAR;
        I2S_TxDMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE;
        I2S_TxDMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
        I2S_TxDMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
        I2S_TxDMA_Handle.Init.Priority = DMA_PRIORITY_HIGH;
        HAL_DMA_DeInit(&I2S_TxDMA_Handle);                            //先清除以前的设置
        HAL_DMA_Init(&I2S_TxDMA_Handle);                                    //初始化DMA
        HAL_DMAEx_MultiBufferStart(&I2S_TxDMA_Handle, (u32) buf0, (u32) &SPI2->DR, (u32) buf1, num);                 //开启双缓冲
        __HAL_DMA_DISABLE(&I2S_TxDMA_Handle);                         //先关闭DMA

        __HAL_DMA_ENABLE_IT(&I2S_TxDMA_Handle, DMA_IT_TC);             //开启传输完成中断
        __HAL_DMA_CLEAR_FLAG(&I2S_TxDMA_Handle, DMA_FLAG_TCIF0_4);     //清除DMA传输完成中断标志位
        HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);                    //DMA中断优先级
        HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);

}
//I2S DMA回调函数指针
void (*i2s_tx_callback)(void);        //TX回调函数
//DMA1_Stream4中断服务函数
void DMA1_Stream4_IRQHandler(void) {
        /*        __HAL_DMA_GET_FLAG(xxx)!=RESET时可以正常工作
         __HAL_DMA_GET_FLAG(xxx)==SET时无法正常工作
         库文件stm32f4xx_hal_dma.h中说明了FLAG的状态是SET or RESET
         The state of FLAG (SET or RESET)
         很奇怪!!!
         */
        if (__HAL_DMA_GET_FLAG(&I2S_TxDMA_Handle, DMA_FLAG_TCIF0_4) != RESET)        ////DMA1_Stream4,传输完成标志
                        {
                __HAL_DMA_CLEAR_FLAG(&I2S_TxDMA_Handle, DMA_FLAG_TCIF0_4);     //清除DMA传输完成中断标志位
                i2s_tx_callback();        //执行回调函数,读取数据等操作在这里面处理
        }
}
//I2S开始播放
void I2S_Play_Start(void) {
        __HAL_DMA_ENABLE(&I2S_TxDMA_Handle);        //开启DMA TX传输,开始播放
}
//关闭I2S播放
void I2S_Play_Stop(void) {
        __HAL_DMA_DISABLE(&I2S_TxDMA_Handle);        //关闭DMA,结束播放
}

//I2S开始录音
void I2S_Rec_Start(void) {
        __HAL_DMA_ENABLE(&I2S_RxDMA_Handler);  //开启DMA RX传输
}
//关闭I2S录音
void I2S_Rec_Stop(void) {
        __HAL_DMA_DISABLE(&I2S_RxDMA_Handler);  //结束录音
}
回复 支持 反对

使用道具 举报

0

主题

31

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
274
金钱
274
注册时间
2014-3-21
在线时间
85 小时
发表于 2021-8-13 15:00:41 | 显示全部楼层
搞I2S的人太少了,网上HAL的资料太少,想抄都没有。
回复 支持 反对

使用道具 举报

0

主题

31

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
274
金钱
274
注册时间
2014-3-21
在线时间
85 小时
发表于 2021-8-15 16:00:58 | 显示全部楼层
感谢楼上几位大哥,抄好了,有音乐出来了,
回复 支持 反对

使用道具 举报

0

主题

31

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
274
金钱
274
注册时间
2014-3-21
在线时间
85 小时
发表于 2021-8-19 15:03:21 | 显示全部楼层
本帖最后由 HZY//123456 于 2021-8-19 15:13 编辑

     curindex=0;      printf("再次打开目录\r\n");                     //从0开始显示
     res=f_opendir(&wavdir,(const TCHAR*)dirPath);              //打开目录
     while(res==FR_OK)//打开成功
     {   
        //dir_sdi(&wavdir,wavindextbl[curindex]);            //改变当前目录索引      
        res=f_readdir(&wavdir,wavfileinfo);                               //读取目录下的一个文件
        if(res!=FR_OK||wavfileinfo->fname[0]==0){ printf("到末尾了,退出:%d\r\n",res); break; }
        printf("文件名称:%s\r\n",wavfileinfo->fname);                  
        strcpy((char*)pname,(const TCHAR*)dirPath);                 //复制路径(目录)
        strcat((char*)pname,(const char*)"\\");                           //将文件名接在后面 也可以用  /                           
        strcat((char*)pname,(const char*)wavfileinfo->fname);     //将文件名接在后面                                                   
        audio_index_show(curindex+1,totwavnum); //索引                                                         
        key=audio_play_song(pname);                                       //播放这个音频文件                                
        printf("播放完了\r\n");
                                
回复 支持 反对

使用道具 举报

0

主题

31

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
274
金钱
274
注册时间
2014-3-21
在线时间
85 小时
发表于 2021-8-19 15:07:43 | 显示全部楼层
本帖最后由 HZY//123456 于 2021-8-19 15:19 编辑

       //dir_sdi(&wavdir,wavindextbl[curindex]);     //改变当前目录索引       
        改HAL库后上面的这个就用不了了,经常被STM32CubeMX  删除了,这样就播放不了第二首,这个时候要在wavplay.c  文件最后几行加  f_close(audiodev.file);
       不熟悉FATFS的也许要折腾半天。对于只想实现连续播放音乐,不担心播放到非音乐文件的朋友可以先这样玩玩。
                if((audiodev.status&0X01)==0) delay_ms(10);
                else break;                                   
                   }
                }
               audio_stop();  f_close(audiodev.file);//printf("播放完了哦\r\n");
               }else res=0XFF;
            }else res=0XFF;
        }else res=0XFF;
        myfree(SRAMIN,audiodev.tbuf);         // printf("释放内存1");
        myfree(SRAMIN,audiodev.i2sbuf1);    //printf("释放内存2");
        myfree(SRAMIN,audiodev.i2sbuf2);    //printf("释放内存3");
        myfree(SRAMIN,audiodev.file);          //printf("释放内存4");
        return res;
}
        
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 02:45

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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