1 #include "i2s.h" 2 #include "usart.h" 3 ////////////////////////////////////////////////////////////////////////////////// 4 //本程序只供学习使用,未经作者许可,不得用于其它任何用途 5 //ALIENTEK STM32F407开发板 6 //I2S 驱动代码 7 //正点原子@ALIENTEK 8 //技术论坛:www.openedv.com 9 //创建日期:2014/5/24 10 //版本:V1.0 11 //版权所有,盗版必究。 12 //Copyright(C) 广州市星翼电子科技有限公司 2014-2024 13 //All rights reserved 14 ////////////////////////////////////////////////////////////////////////////////// 15 16 17 //I2S2初始化 18 19 //参数I2S_Standard: @ref SPI_I2S_Standard I2S标准, 20 //I2S_Standard_Phillips,飞利浦标准; 21 //I2S_Standard_MSB,MSB对齐标准(右对齐); 22 //I2S_Standard_LSB,LSB对齐标准(左对齐); 23 //I2S_Standard_PCMShort,I2S_Standard_PCMLong:PCM标准 24 //参数I2S_Mode: @ref SPI_I2S_Mode I2S_Mode_SlaveTx:从机发送;I2S_Mode_SlaveRx:从机接收;I2S_Mode_MasterTx:主机发送;I2S_Mode_MasterRx:主机接收; 25 //参数I2S_Clock_Polarity @ref SPI_I2S_Clock_Polarity: I2S_CPOL_Low,时钟低电平有效;I2S_CPOL_High,时钟高电平有效 26 //参数I2S_DataFormat: @ref SPI_I2S_Data_Format :数据长度,I2S_DataFormat_16b,16位标准;I2S_DataFormat_16bextended,16位扩展(frame=32bit);I2S_DataFormat_24b,24位;I2S_DataFormat_32b,32位. 27 void I2S2_Init(u16 I2S_Standard,u16 I2S_Mode,u16 I2S_Clock_Polarity,u16 I2S_DataFormat) 28 { 29 I2S_InitTypeDef I2S_InitStructure; 30 31 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//使能SPI2时钟 32 33 RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE); //复位SPI2 34 RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//结束复位 35 36 I2S_InitStructure.I2S_Mode=I2S_Mode;//IIS模式 37 I2S_InitStructure.I2S_Standard=I2S_Standard;//IIS标准 38 I2S_InitStructure.I2S_DataFormat=I2S_DataFormat;//IIS数据长度 39 I2S_InitStructure.I2S_MCLKOutput=I2S_MCLKOutput_Disable;//主时钟输出禁止 40 I2S_InitStructure.I2S_AudioFreq=I2S_AudioFreq_Default;//IIS频率设置 41 I2S_InitStructure.I2S_CPOL=I2S_Clock_Polarity;//空闲状态时钟电平 42 I2S_Init(SPI2,&I2S_InitStructure);//初始化IIS 43 44 45 SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx,ENABLE);//SPI2 TX DMA请求使能. 46 I2S_Cmd(SPI2,ENABLE);//SPI2 I2S EN使能. 47 } 48 //采样率计算公式:Fs=I2SxCLK/[256*(2*I2SDIV+ODD)] 49 //I2SxCLK=(HSE/pllm)*PLLI2SN/PLLI2SR 50 //一般HSE=8Mhz 51 //pllm:在Sys_Clock_Set设置的时候确定,一般是8 52 //PLLI2SN:一般是192~432 53 //PLLI2SR:2~7 54 //I2SDIV:2~255 55 //ODD:0/1 56 //I2S分频系数表@pllm=8,HSE=8Mhz,即vco输入频率为1Mhz 57 //表格式:采样率/10,PLLI2SN,PLLI2SR,I2SDIV,ODD 58 const u16 I2S_PSC_TBL[][5]= 59 { 60 {800 ,256,5,12,1}, //8Khz采样率 61 {1102,429,4,19,0}, //11.025Khz采样率 62 {1600,213,2,13,0}, //16Khz采样率 63 {2205,429,4, 9,1}, //22.05Khz采样率 64 {3200,213,2, 6,1}, //32Khz采样率 65 {4410,271,2, 6,0}, //44.1Khz采样率 66 {4800,258,3, 3,1}, //48Khz采样率 67 {8820,316,2, 3,1}, //88.2Khz采样率 68 {9600,344,2, 3,1}, //96Khz采样率 69 {17640,361,2,2,0}, //176.4Khz采样率 70 {19200,393,2,2,0}, //192Khz采样率 71 }; 72 //设置IIS的采样率(@MCKEN) 73 //samplerate:采样率,单位:Hz 74 //返回值:0,设置成功;1,无法设置. 75 u8 I2S2_SampleRate_Set(u32 samplerate) 76 { 77 u8 i=0; 78 u32 tempreg=0; 79 samplerate/=10;//缩小10倍 80 81 for(i=0;i<(sizeof(I2S_PSC_TBL)/10);i++)//看看改采样率是否可以支持 82 { 83 if(samplerate==I2S_PSC_TBL[i][0])break; 84 } 85 86 RCC_PLLI2SCmd(DISABLE);//先关闭PLLI2S 87 if(i==(sizeof(I2S_PSC_TBL)/10))return 1;//搜遍了也找不到 88 RCC_PLLI2SConfig((u32)I2S_PSC_TBL[i][1],(u32)I2S_PSC_TBL[i][2]);//设置I2SxCLK的频率(x=2) 设置PLLI2SN PLLI2SR 89 90 RCC->CR|=1<<26; //开启I2S时钟 91 while((RCC->CR&1<<27)==0); //等待I2S时钟开启成功. 92 tempreg=I2S_PSC_TBL[i][3]<<0; //设置I2SDIV 93 tempreg|=I2S_PSC_TBL[i][4]<<8; //设置ODD位 94 tempreg|=1<<9; //使能MCKOE位,输出MCK 95 SPI2->I2SPR=tempreg; //设置I2SPR寄存器 96 return 0; 97 } 98 //I2S2 TX DMA配置 99 //设置为双缓冲模式,并开启DMA传输完成中断 100 //buf0:M0AR地址. 101 //buf1:M1AR地址. 102 //num:每次传输数据量 103 void I2S2_TX_DMA_Init(u8* buf0,u8 *buf1,u16 num) 104 { 105 NVIC_InitTypeDef NVIC_InitStructure; 106 DMA_InitTypeDef DMA_InitStructure; 107 108 109 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 110 111 DMA_DeInit(DMA1_Stream4); 112 while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE){}//等待DMA1_Stream1可配置 113 114 /* 配置 DMA Stream */ 115 116 DMA_InitStructure.DMA_Channel = DMA_Channel_0; //通道0 SPI2_TX通道 117 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR;//外设地址为:(u32)&SPI2->DR 118 DMA_InitStructure.DMA_Memory0BaseAddr = (u32)buf0;//DMA 存储器0地址 119 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式 120 DMA_InitStructure.DMA_BufferSize = num;//数据传输量 121 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式 122 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式 123 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据长度:16位 124 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据长度:16位 125 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式 126 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级 127 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不使用FIFO模式 128 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; 129 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//外设突发单次传输 130 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//存储器突发单次传输 131 DMA_Init(DMA1_Stream4, &DMA_InitStructure);//初始化DMA Stream 132 133 DMA_DoubleBufferModeConfig(DMA1_Stream4,(u32)buf1,DMA_Memory_0);//双缓冲模式配置 134 135 DMA_DoubleBufferModeCmd(DMA1_Stream4,ENABLE);//双缓冲模式开启 136 137 DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,ENABLE);//开启传输完成中断 138 139 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn; 140 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//抢占优先级0 141 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;//子优先级0 142 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道 143 NVIC_Init(&NVIC_InitStructure);//配置 144 145 } 146 //I2S DMA回调函数指针 147 void (*i2s_tx_callback)(void); //TX回调函数 148 //DMA1_Stream4中断服务函数 149 void DMA1_Stream4_IRQHandler(void) 150 { 151 if(DMA_GetITStatus(DMA1_Stream4,DMA_IT_TCIF4)==SET)////DMA1_Stream4,传输完成标志 152 { 153 DMA_ClearITPendingBit(DMA1_Stream4,DMA_IT_TCIF4); 154 i2s_tx_callback(); //执行回调函数,读取数据等操作在这里面处理 155 } 156 } 157 //I2S开始播放 158 void I2S_Play_Start(void) 159 { 160 DMA_Cmd(DMA1_Stream4,ENABLE);//开启DMA TX传输,开始播放 161 } 162 //关闭I2S播放 163 void I2S_Play_Stop(void) 164 { 165 DMA_Cmd(DMA1_Stream4,DISABLE);//关闭DMA,结束播放 166 }