概述
#include "PCM1770.h"
#include "PCM1770_WaveData.h"
uint16_t i2s_audio_freq = I2S_AUDIOSAMPLE_8K;//I2S音频采样率
uint8_t audio_header_index = 0;
uint8_t *audio_file_header = 0;
/* audio codec variables */
wave_file_struct wave_format;
__IO uint32_t audio_file_address;//播放文件首地址
uint32_t audio_data_length; //音频数据长度
uint32_t data_start_addr; //音频数据起始地址
__IO uint32_t audio_data_index; //音频数据索引
uint8_t audio_play_status; //音频播放状态
static uint32_t audio_replay_remain_count; //音频重播保持计数器
static __IO uint32_t audio_replay_count; //音频重播计数器
static __IO uint32_t monovar; //0表示左通道工作,非0表示右通道工作
//void My_I2S1_Init(uint16_t standard, uint16_t mclk_output, uint16_t audio_freq);
//void My_SPI0_Init(void);
void pcm1770_send_ctrl_data(uint8_t reg, uint8_t data);
uint8_t pcm1770_init(uint32_t address);
/*
BCK:I2S_CK是串行时钟信号;
DATA:I2S_SD是串行数据信号;
LRCK:I2S_WS是数据帧控制信号
SCKI:系统时钟,I2S_MCK是主时钟信号,它最大可提供一个256倍于Fs的时钟频率,其中Fs是音频采样率;
MC:SPI0_SCK时钟
MD:SPI0_MOSI数据
MS:SPI选择引脚
PD:复位引脚
AIN:单声模拟信号混频器输入;
HOUTL:左通道耳机放大器模拟信号输出;
HOUTR:右通道耳机放大器模拟信号输出;
*/
/*
I2S接口有4个引脚,分别是I2S_CK,I2S_WS,I2S_SD和I2S_MCK;
I2S_MCK是主时钟信号,它最大可提供一个256倍于Fs的时钟频率,其中Fs是音频采样率;
I2S_CK是串行时钟信号,与SPI_SCK共享引脚;
I2S_WS是数据帧控制信号,与SPI_NSS共享引脚;
I2S_SD是串行数据信号,与SPI_MOSI共享引脚;
I2S工作在主机模式下:
I2S_SD是串行数据信号,发送时变为输出,接收时变为输入;
I2S_CK是串行移位时钟信号,用作输出;
I2S_WS是选择左右通道信号,用作输出;
I2S_MCK是主时钟信号,只能输出;
I2S工作在从机模式下:
I2S_SD是串行数据信号,发送时变为输出,接收时变为输入;
I2S_CK是串行移位时钟信号,用作输入;
I2S_WS是选择左右通道信号,用作输入;
I2S_MCK是主时钟信号,只能输入;
对于所有标准和数据包类型来说,数据的最高有效位总是最先被发送的;
对于所有基于两通道分时复用的标准来说,总是先发送左通道,然后是右通道;
由于发送和接收的数据缓冲区都是16位宽度,且"通道长度必须大于或等于数据长度",所以有四种数据包类型:
1,16位数据打包成16位数据帧格式,访问1次SPI_DATA寄存器,只发bit15~bit0;
2,16位数据打包成32位数据帧格式,访问1次SPI_DATA寄存器,先发bit15~bit0,剩下的16位被硬件填充为16个0;
3,24位数据打包成32位数据帧格式,访问2次SPI_DATA寄存器,先发bit24~bit8,再发bit7~biT0,然后插入8个0;
4,32位数据打包成32位数据帧格式,访问2次SPI_DATA寄存器,先发bit31~bit16,再发bit15~biT0;
*/
//函数功能:初始化I2S1
void My_I2S1_Init(uint16_t standard, uint16_t mclk_output, uint16_t audio_freq)
{
/I2S1配置开始//
rcu_periph_clock_enable(RCU_AF); //使能RCU_AF外设时钟
rcu_periph_clock_enable(RCU_SPI1); //使能RCU_SPI1外设时钟
rcu_periph_clock_enable(RCU_GPIOB);//使能RCU_GPIOB外设时钟
rcu_periph_clock_enable(RCU_GPIOC);//使能RCU_GPIOC外设时钟
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
//I2S1引脚I2S_WS:配置GPIOB12的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
//I2S1引脚I2S_CK:配置GPIOB13的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
//I2S1引脚I2S_SD:配置GPIOB15的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
//I2S1引脚I2S_MCK:配置GPIOC6的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
spi_i2s_deinit(SPI1);//复位SPI1外设;
i2s_init(SPI1, I2S_MODE_MASTERTX, standard, I2S_CKPL_HIGH);//初始化I2S1
//I2S_MODE_MASTERTX:I2S主机发送模式
//standard=I2S_STD_PHILLIPS:I2S标准选择"飞利浦标准":16位数据,左对齐,空余16位为0
//I2S_CKPL_HIGH:I2S空闲时,时钟极性位为高电平
i2s_psc_config(SPI1, audio_freq, I2S_FRAMEFORMAT_DT16B_CH16B, mclk_output);
//设置"I2S音频采样率",帧格式,I2S时钟输出
spi_i2s_interrupt_disable(SPI1, SPI_I2S_INT_TBE);//不使能"SPI发送缓冲区空"产生中断
i2s_enable(SPI1);//I2S1使能
/I2S1配置结束//
nvic_irq_enable(SPI1_IRQn, 0, 1);
//设置SPI1_IRQn的中断优先级,抢占优先级为0,子优先级为1
}
//函数功能:初始化SPI0
void My_SPI0_Init(void)
{
spi_parameter_struct spi_init_struct;
/SPI0配置开始//
rcu_periph_clock_enable(RCU_AF); //使能RCU_AF外设时钟
rcu_periph_clock_enable(RCU_SPI0); //使能RCU_SPI0外设时钟
rcu_periph_clock_enable(RCU_GPIOA); //使能RCU_GPIOA外设时钟
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
//SPI0_SCK:配置GPIOA5的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
//SPI0_MOSI:配置GPIOA7的工作模式为复用功能IO推挽输出,输出速度最大为50MHz
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
//配置GPIOA4的工作模式为通用型IO推挽输出和输出速度最大为50MHz
PCM1770_CS_HIGH(); //不选中PCM1770
spi_i2s_deinit(SPI0);//复位SPI0外设
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; //SPI在全双工通讯中接收/发送数据
spi_init_struct.device_mode = SPI_MASTER; //SPI为主机模式且SWNSS=1
spi_init_struct.nss = SPI_NSS_SOFT; //使用NSS软件模式:NSS电平取决于SWNSS位;
spi_init_struct.frame_size = SPI_FRAMESIZE_16BIT; //SPI使用16位数据帧格式
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
//在SPI为空闲状态时,CLK引脚拉高,且"在第2个时钟跳变沿时开始采集第1位数据"
spi_init_struct.prescale = SPI_PSC_32; //SPI时钟预分频器值为32
spi_init_struct.endian = SPI_ENDIAN_MSB; //先发送最高位
spi_init(SPI0, &spi_init_struct);//使用spi_init_struct结构参数初始化SPI0
spi_enable(SPI0);//使能SPI0
/SPI0配置结束//
}
//函数功能:将data写入"SPI0数据寄存器"
void SPI0_send_data(uint16_t data)
{
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE))
{//等待建立"SPI发送缓冲区空"标志
}
spi_i2s_data_transmit(SPI0, data);//将data写入"SPI0数据寄存器"
}
//函数功能:将data的值写入"PCM1770的寄存器",寄存器地址为reg
//reg为PCM1770寄存器地址,data为待写入的控制数据
void pcm1770_send_ctrl_data(uint8_t reg, uint8_t data)
{
uint16_t reg_data, i;
reg_data = (0x00FF & reg);
reg_data = reg_data << 8;
reg_data = reg_data | data;
PCM1770_CS_LOW();
SPI0_send_data(reg_data);//将reg_data写入"SPI0数据寄存器"
for(i=0; i<0xFFU; i++)
{//MLH >= 20ns
}
PCM1770_CS_HIGH();
}
//函数功能:从audio_file_header[]中连续读取bytes_num个字节数据,按照指定的大小端方式保存到temp中
//读取的字节数量,
//小端模式是指将数据的低位放在内存的低地址上,而数据的高位放在内存的高地址上;
//大端模式是指将数据的低位放在内存的高地址上,而数据的高位放在内存的低地址上;
static uint32_t audio_read_unit(uint8_t bytes_num, endianness_enum bytes_endian)
{
uint32_t i;
uint32_t temp;
uint32_t k;
uint32_t t;
i=0;
temp=0;
if(LITTLE_ENDIAN == bytes_endian)
{//小端模式是指将数据的低位放在内存的低地址上,而数据的高位放在内存的高地址上;
for(i = 0; i < bytes_num; i++)
{
t=audio_file_header[audio_header_index];
t=(uint32_t)(t&0x000000FF);//保证最低8位有效
k=i;k=k*8;t=t<<k;
temp=(uint32_t)(temp|t);
//i=0时,参与"相或"的是t的bit0~bit7,即为audio_file_header[0]
//i=1时,参与"相或"的是t的bit8~bit15,即为audio_file_header[1]
//i=2时,参与"相或"的是t的bit16~bit23,即为audio_file_header[2]
//i=3时,参与"相或"的是t的bit24~bit31,即为audio_file_header[3]
audio_header_index++;//修改audio_file_header[]下标值
}
}
else
{//大端模式是指将数据的低位放在内存的高地址上,而数据的高位放在内存的低地址上;
for(i = bytes_num; i != 0; i--)
{
t=audio_file_header[audio_header_index];
t=(uint32_t)(t&0x000000FF);//保证最低8位有效
k=i-1;k=k*8;t=t<<k;
temp=(uint32_t)(temp|t);
//i=4时,参与"相或"的是t的bit24~bit31,即为audio_file_header[0]
//i=3时,参与"相或"的是t的bit16~bit23,即为audio_file_header[1]
//i=1时,参与"相或"的是t的bit8~bit15,即为audio_file_header[2]
//i=0时,参与"相或"的是t的bit0~bit7,即为audio_file_header[3]
audio_header_index++;//修改audio_file_header[]下标值
}
}
return temp;
}
//audio_file_header_address为播放文件指针
errorcode_enum audio_format_parsing(uint8_t* audio_file_header_address)
{
uint32_t ret_Data;
uint32_t extra_format_bytes = 0;
audio_file_header = audio_file_header_address;//设置"音频文件头指针"
audio_header_index = 0;//设置音频头索引为0,the audio_header_index
///使用大端方式读取"文件头数据"开始
ret_Data=audio_read_unit(4, BIG_ENDIAN);
//从audio_file_header[]中连续读取4个字节数据,按照指定的大端方式保存到ret_Data中
if(ret_Data!=AUDIO_CHUNKID)
{//使用0x52494646表示字符串"RIFF"
return(UNVALID_RIFF_ID);
}
///使用大端方式读取"文件头数据"结束
ret_Data=audio_read_unit(4, LITTLE_ENDIAN);
//audio_header_index初始值为4
//从audio_file_header[]中连续读取4个字节数据,按照指定的小端方式保存到ret_Data中
//read the audio file length
wave_format.riff_chunk_size = ret_Data;//保存音频文件长度
ret_Data=audio_read_unit(4, BIG_ENDIAN);
//audio_header_index初始值为8
//从audio_file_header[]中连续读取4个字节数据,按照指定的大端方式保存到ret_Data中
//read the audio file format, and it must be 'WAVE'
if( ret_Data != AUDIO_FILEFORMAT )
{//使用0x57415645表示字符串'WAVE'
return(UNVALID_WAVE_FORMAT);
}
ret_Data=audio_read_unit(4, BIG_ENDIAN);
//audio_header_index初始值为12
//从audio_file_header[]中连续读取4个字节数据,按照指定的大端方式保存到ret_Data中
//read the format chunk, and it must be 'fmt'
if( ret_Data != AUDIO_FORMATID )
{//使用0x666D7420表示字符串"fmt "
return(UNVALID_FORMATCHUNK_ID);
}
ret_Data=audio_read_unit(4, LITTLE_ENDIAN);
//audio_header_index初始值为16
//从audio_file_header[]中连续读取4个字节数据,按照指定的小端方式保存到ret_Data中
//读取FMT数据长度为0x10
//read the length of the 'fmt' data, and it must be 0x00000010
if( ret_Data != AUDIO_FORMATLEN )
{//使用0x00000010表示"fmt数据的长度"
extra_format_bytes = 1;
}
ret_Data=audio_read_unit(2, LITTLE_ENDIAN);
//audio_header_index初始值为20
//从audio_file_header[]中连续读取2个字节数据,按照指定的小端方式保存到ret_Data中
//read the audio format, and it must be 0x01 (PCM)
wave_format.format_tag = ret_Data;
if( ret_Data != AUDIO_WAVE_FORMAT_PCM)
{//PCM音频数据格式为0x0001
return(UNSUPPORETD_FORMATTAG);
}
ret_Data=audio_read_unit(2, LITTLE_ENDIAN);
//audio_header_index初始值为22
//从audio_file_header[]中连续读取2个字节数据,按照指定的小端方式保存到ret_Data中
//read the number of channels: 0x02->Stereo(立体声) and 0x01->Mono(单声道)
wave_format.num_channels = ret_Data;//立体声为0x0002
//保存通道数量
//wave_format.num_channels=0x02立体声
//wave_format.num_channels=0x01表示单声道
ret_Data=audio_read_unit(4, LITTLE_ENDIAN);
//audio_header_index初始值为24
//从audio_file_header[]中连续读取4个字节数据,按照指定的小端方式保存到ret_Data中
//read the sample rate
wave_format.sample_rate = ret_Data;//音频采样速率:0x001F40=8000
ret_Data=audio_read_unit(4, LITTLE_ENDIAN);
//audio_header_index初始值为28
//从audio_file_header[]中连续读取4个字节数据,按照指定的小端方式保存到ret_Data中
//read the byte rate
wave_format.byte_rate = ret_Data;//字节的速度:0x00007D00
ret_Data=audio_read_unit(2, LITTLE_ENDIAN);
//audio_header_index初始值为32
//从audio_file_header[]中连续读取2个字节数据,按照指定的小端方式保存到ret_Data中
//read the block alignment
wave_format.block_align = ret_Data;//块对齐:0x0004,(是不是16位,右对齐数据)
ret_Data=audio_read_unit(2, LITTLE_ENDIAN);
//audio_header_index初始值为34
//从audio_file_header[]中连续读取2个字节数据,按照指定的小端方式保存到ret_Data中
//read the number of bits per sample
wave_format.bits_per_sample = ret_Data;
if( ret_Data !=AUDIO_BIT_PER_SAMPLE_16 )
{//如果ret_Data不等于0x0010,这里正确
return(UNSUPPORETD_BITS_PER_SAMPLE);
}
//if there are extra format bytes, these bytes will be defined in "Fact Chunk"
if(1 == extra_format_bytes)//由于extra_format_bytes=0,所以该判断语句不执行
{
ret_Data=audio_read_unit(2, LITTLE_ENDIAN);
//audio_header_index初始值为36
//从audio_file_header[]中连续读取2个字节数据,按照指定的小端方式保存到ret_Data中
//read the extra format bytes, and it must be 0x00
if( ret_Data != 0x0000 )
{
return(UNSUPPORETD_EXTRAFORMATBYTES);
}
ret_Data=audio_read_unit(4, BIG_ENDIAN);
//audio_header_index初始值为38
//从audio_file_header[]中连续读取4个字节数据,按照指定的大端方式保存到ret_Data中
//read the fact chunk, and it must be 'fact'
if( ret_Data!= AUDIO_FACTID )
{//使用0x66616374表示字符串"fact"
return(UNVALID_FACTCHUNK_ID);
}
ret_Data=audio_read_unit(4, LITTLE_ENDIAN);
//audio_header_index初始值为42
//从audio_file_header[]中连续读取4个字节数据,按照指定的小端方式保存到ret_Data中
//read fact chunk data size and set the index to start reading after the header end
audio_header_index += ret_Data;
}
ret_Data=audio_read_unit(4, BIG_ENDIAN);
//audio_header_index初始值为36
//从audio_file_header[]中连续读取4个字节数据,按照指定的大端方式保存到ret_Data中
//read the data chunk, and it must be 'data'
if( ret_Data != AUDIO_DATAID )//ret_Data=0x01000200
{//使用0x64617461表示字符串'data'
return(UNVALID_DATACHUNK_ID);
}
ret_Data=audio_read_unit(4, LITTLE_ENDIAN);
//audio_header_index初始值为40
//从audio_file_header[]中连续读取4个字节数据,按照指定的小端方式保存到ret_Data中
//read the size of sample data
wave_format.data_size = ret_Data;//音频数据长度为0x0000DA40=55872
//set first address of the effective audio data
//audio_header_index初始值为44
data_start_addr += audio_header_index;//记录"音频数据起始地址"
return(VALID_WAVE_FILE);
}
//函数功能:音频文件初始化,并设置音频文件长度和音频采样率
//audio file init and set the audio file length and sample_rate
uint8_t audio_init(void)
{
errorcode_enum ret_Data;
ret_Data=audio_format_parsing( (uint8_t*)(audio_file_address) );
if( ret_Data==VALID_WAVE_FILE )
{
i2s_audio_freq = (uint16_t)wave_format.sample_rate;
//采样频率:0x001F40=8000
//I2S_AUDIOSAMPLE_8K=8000
return AUDIO_OK;
}
return AUDIO_FAIL;
}
//函数功能:设置"音频重播计数器"和"音频重播保持计数器"
void pcm1770_replay_config(uint32_t replay_count)
{
audio_replay_count = replay_count; //设置"音频重播计数器"
audio_replay_remain_count = replay_count; //设置"音频重播保持计数器"
}
//函数功能:PCM1770初始化
uint8_t pcm1770_init(uint32_t address)
{
uint8_t ret_Data;
audio_play_status = STOPPED; //音频播放状态为"停止"
audio_replay_count=0; //音频重播计数器
audio_replay_remain_count=0xFFFF;//音频重播保持计数器
audio_file_address=address;//添加播放文件首地址,如AUDIO_FILE_ADDRESS
audio_data_length = countof(PCM1770_WaveData);//音频数据长度
data_start_addr=0; //音频数据起始地址为0
audio_data_index=0;//音频数据索引为0
monovar=0;//0表示左通道工作,非0表示右通道工作
ret_Data=audio_init();
//音频文件初始化,并设置音频文件长度和音频采样率(I2S_AUDIOSAMPLE_8K=8000)
if(ret_Data==AUDIO_OK)
{
My_SPI0_Init();//初始化SPI0
My_I2S1_Init(I2S_STANDARD, I2S_MCLKOUTPUT, i2s_audio_freq);
//初始化I2S1
//I2S标准选择"MSB对齐标准"
//I2S_MCK时钟输出使能
pcm1770_send_ctrl_data(1,0x3F);//左耳机输出没有衰减
pcm1770_send_ctrl_data(2,0x3F);//右耳机输出没有衰减
pcm1770_send_ctrl_data(3,0x01);
//右耳机同相输出,OVER=0 128fS 过取样;16~24位,I2S格式
//pcm1770_send_ctrl_data(0x03, 0x84);//16位,右对齐数据,OVER=1 192fS,256fS,384fS 过取样
pcm1770_send_ctrl_data(4,0x00);
//ZCAT=0正常衰减;PWRD=0,正常运行;
pcm1770_replay_config(1); //设置播放一次
audio_play_status=PLAYING;//设置为"音频播放中"
spi_i2s_interrupt_enable(SPI1, SPI_I2S_INT_TBE);
//使能"I2S1发送缓冲区空"中断"
}
return ret_Data;
}
//函数功能:设置audio_play_status,记录音频播放状态
//play_status=PLAYING,播放中
//play_status=STOPPED,停止
//play_status=PAUSED,暂停
//play_status=PLAYING_MUTE,使用弱音器播放
//play_status=STOPPED_MUTE,停止弱音器播放
//play_status=PAUSED_MUTE,暂停弱音器
uint8_t audio_set_play_status(uint8_t play_status)
{
audio_play_status = play_status;
return audio_play_status;
}
//函数功能:读取audio_play_status,返回"音频播放状态"
//play_status=PLAYING,播放中
//play_status=STOPPED,停止
//play_status=PAUSED,暂停
//play_status=PLAYING_MUTE,使用弱音器播放
//play_status=STOPPED_MUTE,停止弱音器播放
//play_status=PAUSED_MUTE,暂停弱音器
uint8_t audio_get_play_status(void)
{
return audio_play_status;
}
//函数功能:暂停音频播放
uint32_t pcm1770_audio_file_paused()
{
//set playing status as PAUSED or PAUSED_MUTE
if(1 == (audio_play_status >> 2))
{
//audio_play_status=PLAYING_MUTE,使用弱音器播放
//audio_play_status=STOPPED_MUTE,停止弱音器播放
//audio_play_status=PAUSED_MUTE,暂停弱音器
audio_play_status=PAUSED_MUTE;//暂停弱音器
}
else
{
audio_play_status=PAUSED;//暂停
}
spi_i2s_interrupt_disable(SPI1, SPI_I2S_INT_TBE);
return audio_data_index;
}
/I2S1中断服务程序及其子程序//
//函数功能:修改"音频数据索引"
void audio_data_index_inc(uint32_t inc_num)
{
audio_data_index += (uint32_t)inc_num;
//audio_data_index为音频数据索引
//立体声:audio_data_index=audio_data_index+2
//单声道:audio_data_index=audio_data_index+1
if(audio_data_index >= audio_data_length)
{//播放完毕
if(audio_replay_count != 0)
{
audio_replay_remain_count--;
if(audio_replay_remain_count==0)
{//播放任务结束
if(1 == (audio_play_status >> 2))
{//audio_play_status=PLAYING_MUTE,使用弱音器播放
//audio_play_status=STOPPED_MUTE,停止弱音器播放
//audio_play_status=PAUSED_MUTE,暂停弱音器
audio_play_status=STOPPED_MUTE;//停止弱音器播放
}
else
{
audio_play_status=STOPPED;//停止
}
spi_i2s_interrupt_disable(SPI1, SPI_I2S_INT_TBE);
//不使能"I2S1发送缓冲区空"中断
}
}
}
}
//函数功能:从音频文件中读取半字
uint16_t audio_read_half_word(uint32_t address_offset)
{
uint32_t value = 0U;
if((audio_file_address + address_offset ) >= AUDIOFILEADDRESS_END)
{//"播放文件首地址" + "偏移地址" >= "音频文件结束地址"
audio_data_index = 0;
}
//the left channel is to be sent
if(0U == monovar )//左通道工作
{
value = (*(__IO uint16_t *) (audio_file_address + address_offset));
//从音频文件中读取数据
if(AUDIO_CHANNEL_MONO == wave_format.num_channels)//立体声
{
monovar++;
}
return value;
}
else//右通道工作
{//right channel to be sent in mono format
//reset the monovar variable
monovar = 0U;
//return the previous read data in mono format
return value;
}
}
//函数功能:发送音频数据,send audio data
void I2S1_Send_Data_To_PCM1770(void)
{
uint16_t tmpData;
tmpData=audio_read_half_word(audio_data_index + data_start_addr);
//data_start_addr为音频数据起始地址
//audio_data_index为音频数据索引
//从音频文件中读取半字
spi_i2s_data_transmit(SPI1, tmpData);
//将tmpData通过I2S1发送PCM1770
audio_data_index_inc(wave_format.num_channels);
//修改"音频数据索引"
//wave_format.num_channels=0x02立体声
//wave_format.num_channels=0x01表示单声道
}
//函数功能:I2S1中断服务程序
void SPI1_IRQHandler(void)
{
if(SET == spi_i2s_interrupt_flag_get(SPI1, SPI_I2S_INT_TBE))
{//读取"I2S1发送缓冲区空"中断标志"
I2S1_Send_Data_To_PCM1770();//发送音频数据,send audio data
}
}
/*
地址 B15 B14 B13 B12 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0
1 0 IDX6 IDX5 IDX4 IDX3 IDX2 IDX1 IDX0 MUTR MUTL ATL5 ATL4 ATL3 ATL2 ATL1 ATL0
寄存器地址保存在IDX[6:0]中,为0x01
MUTR=0(默认),右衰减器立即增加到先前设定的衰减;MUTR=1,使能右耳机声音减弱,减弱值为ATR[5:0];
MUTL=0(默认),左衰减器立即增加到先前设定的衰减;MUTL=1,使能左耳机声音减弱,减弱值为ATL[5:0];
ATL[5:0] 左耳机输出的数字衰减水平设置
11 1111b 0 dB, 左耳机输出没有衰减(默认)
11 1110b –1 dB
11 1101b –2 dB
: :
00 0010b –61 dB
00 0001b –62 dB
00 0000b 静音
地址 B15 B14 B13 B12 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0
2 0 IDX6 IDX5 IDX4 IDX3 IDX2 IDX1 IDX0 RSV RSV ATR5 ATR4 ATR3 ATR2 ATR1 ATR0
寄存器地址保存在IDX[6:0]中,为0x02
RSV:保留
ATR[5:0] 右耳机输出的数字衰减水平设置
11 1111b 0 dB, 右耳机输出没有衰减(默认)
11 1110b –1 dB
11 1101b –2 dB
: :
00 0010b –61 dB
00 0001b –62 dB
00 0000b 静音
地址 B15 B14 B13 B12 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0
3 0 IDX6 IDX5 IDX4 IDX3 IDX2 IDX1 IDX0 OVER RSV RINV AMIX DEM FMT2 FMT1 FMT0
寄存器地址保存在IDX[6:0]中,为0x03
OVER=0 128fS 过取样;OVER=1 192fS,256fS,384fS 过取样
RINV=0,右耳机同相输出;RINV=1,右耳机反相输出;
AMIX=0,不允许"AIN引脚输入的信号"混合到DAC输出;AMIX=1,允许"AIN引脚输入的信号"混合到DAC输出;
DEM=0,不使能44.1khz滤波器;DEM=1,使能44.1khz滤波器;
FMT[2:0] 音频数据格式选择
000 16~24位,左对齐格式(默认),低电平收到的是左通道数据,高电平选择右通道
001 16~24位,I2S格式,也是左对齐,高电平收到的是左通道数据,低电平选择右通道
010 24位,右对齐数据
011 20位,右对齐数据
100 16位,右对齐数据
101 16~24位,左对齐格式,主模式
110 保留
111 保留
地址 B15 B14 B13 B12 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0
4 0 IDX6 IDX5 IDX4 IDX3 IDX2 IDX1 IDX0 RSV RSV RSV ZCAT RSV RSV RSV PWR
寄存器地址保存在IDX[6:0]中,为0x04
ZCAT=0(默认),正常衰减;ZCAT=1,零交叉衰减;
PWRD=0,正常运行;PWRD=1,省电状态;
*/
#ifndef __PCM1770_H
#define __PCM1770_H
#include "sys.h"
//#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t,bool
#define PCM1770_CS_LOW() gpio_bit_reset(GPIOA, GPIO_PIN_4) //选中PCM1770
#define PCM1770_CS_HIGH() gpio_bit_set(GPIOA, GPIO_PIN_4) //不选中PCM1770
extern const char PCM1770_WaveData[];
#define AUDIOFILEADDRESS (uint32_t)PCM1770_WaveData
#define AUDIOFILEADDRESS_END (uint32_t)(PCM1770_WaveData + (countof( PCM1770_WaveData)))
#define countof(a) (sizeof(a) / sizeof(a[0])) //计算数组a[]的内成员个数
/* correspond to the letters 'RIFF' */
#define AUDIO_CHUNKID 0x52494646 //使用0x52494646表示字符串"RIFF"
/* correspond to the letters 'WAVE' */
#define AUDIO_FILEFORMAT 0x57415645 //使用0x57415645表示字符串"WAVE"
/* correspond to the letters 'fmt' */
#define AUDIO_FORMATID 0x666D7420 //使用0x666D7420表示字符串"fmt "
/* correspond to the letters 'data' */
#define AUDIO_DATAID 0x64617461 //使用0x64617461表示字符串'data'
/* correspond to the letters 'fact' */
#define AUDIO_FACTID 0x66616374 //使用0x66616374表示字符串"fact"
/* correspond to the letters 'length of the fmt data' */
#define AUDIO_FORMATLEN 0x10 //使用0x10表示"fmt数据的长度"
#define AUDIO_WAVE_FORMAT_PCM 0x01 //PCM音频数据格式为0x0001
#define AUDIO_FORMATCHUNKSIZE 0x10
#define AUDIO_CHANNEL_MONO 0x01 //单声道
#define AUDIO_CHANNEL_STEREO 0x02 //立体声
/* play staus structure */
#define PLAYING 0x00 //播放中
#define STOPPED 0x01 //停止
#define PAUSED 0x02 //暂停
#define PLAYING_MUTE 0x04 //使用弱音器播放
#define STOPPED_MUTE 0x05 //停止弱音器播放
#define PAUSED_MUTE 0x06 //暂停弱音器
/* bits per sample */
#define AUDIO_BIT_PER_SAMPLE_8 8
#define AUDIO_BIT_PER_SAMPLE_16 16 //音频为16位
#define AUDIO_OK 1
#define AUDIO_FAIL 0
//音量控制常数,volume control constants
#define MAX_VOL 0x3F
#define DEFAULT_VOL MAX_VOL
//弱音器命令,MUTE commands
#define MUTE_ON 0xFF
#define MUTE_OFF 0x3F
/* I2S configuration parameters */
#define I2S_STANDARD I2S_STD_MSB //I2S标准选择"MSB对齐标准"
#define I2S_MCLKOUTPUT I2S_MCKOUT_ENABLE //I2S_MCK时钟输出使能
typedef enum
{
VALID_WAVE_FILE = 0, /* valid wave file */
UNVALID_RIFF_ID, /* unvalid riff id */
UNVALID_WAVE_FORMAT, /* unvalid wave format */
UNVALID_FORMATCHUNK_ID, /* unvalid format chunk id */
UNSUPPORETD_FORMATTAG, /* unsupporetd format tag */
UNSUPPORETD_NUMBER_OF_CHANNEL, /* unsupporetd number of channel */
UNSUPPORETD_SAMPLE_RATE, /* unsupporetd sample rate */
UNSUPPORETD_BITS_PER_SAMPLE, /* unsupporetd bits per sample */
UNVALID_DATACHUNK_ID, /* unvalid data chunk id */
UNSUPPORETD_EXTRAFORMATBYTES, /* unsupporetd extra format bytes */
UNVALID_FACTCHUNK_ID /* unvalid fact chunk id */
}errorcode_enum;
/* endianness enum */
//小端模式是指将数据的低位放在内存的低地址上,而数据的高位放在内存的高地址上;
//大端模式是指将数据的低位放在内存的高地址上,而数据的高位放在内存的低地址上;
typedef enum
{
LITTLE_ENDIAN,
BIG_ENDIAN
}endianness_enum;
typedef struct
{
uint32_t riff_chunk_size; /* riff chunk size */
uint16_t format_tag; /* format tag */
uint16_t num_channels; /* number of channel */
uint32_t sample_rate; /* audio sample rate */
uint32_t byte_rate; /* byte rate */
uint16_t block_align; /* block align */
uint16_t bits_per_sample; /* bits per sample */
uint32_t data_size; //音频数据长度audio data size
}wave_file_struct;
extern uint8_t pcm1770_init(uint32_t address);
#endif
#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t,bool
#include "delay.h"
//#include "IWDG.h"
//#include "WWDGT.h"
#include "stdio.h" //使能printf(),sprintf()
#include "string.h" //使能strcpy(),strlen(),memset()
#include "LED.h"
#include "PCM1770.h"
const char CPU_Reset_REG[]="rnCPU reset!rn";
int main(void)
{
//NVIC_PRIGROUP_PRE4_SUB0:抢占优先级为4bit(取值为0~15),子优先级为0bit(没有响应优先级)
//NVIC_PRIGROUP_PRE3_SUB1:抢占优先级为3bit(取值为0~7),子优先级为1bit(取值为0~1)
//NVIC_PRIGROUP_PRE2_SUB2:抢占优先级为2bit(取值为0~3),子优先级为2bit(取值为0~3)
//NVIC_PRIGROUP_PRE1_SUB3:抢占优先级为1bit(取值为0~1),子优先级为3bit(取值为0~7)
//NVIC_PRIGROUP_PRE0_SUB4:抢占优先级为0bit(没有抢占优先级),子优先级为3bit(取值为0~15)
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);//设置系统中断优先级"抢占优先级为4bit,子优先级为0bit"
INTX_ENABLE();//开启所有中断
LED2_Init();//初始化LED2端口
LED3_Init();//初始化LED3端口
LED4_Init();//初始化LED4端口
LED5_Init();//初始化LED5端口
delay_init();
pcm1770_init(AUDIOFILEADDRESS);
while(1)
{
}
}
最后
以上就是现代蓝天为你收集整理的PCM1770测试程序的全部内容,希望文章能够帮你解决PCM1770测试程序所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复