各位大俠,我用STM32F103+VS1003b+M25P64做的音樂播放器,現在遇到瓶頸,苦惱調了幾天沒得結果,郁悶+不甘心啊~~
正弦測試,RAM測試都通過了,但是音樂文件從SPI的FLASH讀出后,經STM32緩沖,發給VS1003B解碼,可是沒有聲音輸出。
小弟是這么做的,將WAV格式的文件保存為.bin文件,然后通過串口將.bin文件發送到FLASH中,再從FLASH讀出,判斷DREQ的高低情況,為低則發送32B數據,為高等待~,這樣做其中有問題么?請問需要先發WAV的幀頭給VS1003么?請問為啥總是沒得音頻輸出啊~~,我正弦測試和RAM測試都過得,感覺問題很簡單,但找不出來了,特向大俠們求幫助!@@小弟先謝過,
int main(void)
{
#ifdef DEBUG
debug();
#endif
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------------------------*/
/* RCC system reset(for debug purpose) */
RCC_DeInit();
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* Flash 2 wait state */
FLASH_SetLatency(FLASH_Latency_2);
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08)
{
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG, ENABLE);
}
delay_init(72);
NVIC_Configuration();
/*------------------- Resources Initialization -----------------------------*/
/* Configure the systick */
SysTick_Config();
/* Configure the GPIOs */
/* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_FLASH_Init();
USART_Configuration();
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF, &GPIO_InitStructure);
/* Get SPI Flash ID */
FLASH_ID = SPI_FLASH_ReadID();
/* Check the SPI Flash ID */
if(FLASH_ID == M25P64_FLASH_ID)
{
GPIO_SetBits(GPIOF, GPIO_Pin_0);
Delay(20); //*************5S
GPIO_ResetBits(GPIOF, GPIO_Pin_0);
Delay(20); //*************5S
GPIO_SetBits(GPIOF, GPIO_Pin_0);
Delay(20);
GPIO_ResetBits(GPIOF, GPIO_Pin_0);
}
else
{
GPIO_SetBits(GPIOF, GPIO_Pin_0);
}
k=0;
Vs1003_Init();
Mp3Reset();
Vs1003SoftReset();
VS_XDCS_CLR();
z=Vs1003_REG_Read(SPI_MODE);
USART_SendData(USART1,z);
z=Vs1003_REG_Read(SPI_CLOCKF);
USART_SendData(USART1,z);
z=Vs1003_REG_Read(SPI_AUDATA);
USART_SendData(USART1,z);
while (1)
{
while(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00); //等待DREQ為高
SPI2_ReadWriteByte(i);
USART_SendData(USART1,i);
}
}
VS驅動:
#include "stm32f10x_lib.h"
#include "includes.h"
#include "spec_rew.h"
//VS1003的全功能函數
//支持SIN測試和RAM測試
//并加入了VS1003的頻譜顯示代碼,不過說實話不咋地,還不如自己寫的頻譜分析,懷疑是不是真實的頻譜變換?
//正點原子@SCUT
//V1.1
#define SPI2_SPEED_2 0
#define SPI2_SPEED_8 1
#define SPI2_SPEED_16 2
#define SPI2_SPEED_256 3 //281K
/* Select SPI FLASH: ChipSelect pin low */
#define VS_XCS_SET() GPIOB->ODR|=(1<<12) //片選信號 PE12
#define VS_XCS_CLR() GPIOB->ODR&=~(1<<12) //片選信號
//VS1003設置參數
//0,高音控制;1,最低頻限;2,低音控制;3,最低頻限
//0,henh.1,hfreq.2,lenh.3,lfreq 5,主音量
//EEPROM地址:488~489 共2個
u8 VS_VOLT=200; //默認音量200
u8 VS_BASS=0; //默認非超重低音
//SPI1口讀寫一個字節
//TxData:要發送的字節
//返回值:讀取到的字節
u8 SPI2_ReadWriteByte(u8 TxData)
{
while((SPI2->SR&1<<1)==0);//等待發送區空
SPI2->DR=TxData; //發送一個byte
while((SPI2->SR&1<<0)==0);//等待接收完一個byte
return SPI2->DR; //返回收到的數據
}
/*******************************************************************************
* Function Name : SPI1_SetSpeed
* Description : SPI1設置速度為高速
* Input : u8 SpeedSet
* 如果速度設置輸入0,則低速模式,非0則高速模式
* SPI_SPEED_HIGH 1
* SPI_SPEED_LOW 0
* Output : None
* Return : None
*******************************************************************************/
void SPI2_SetSpeed(u8 SpeedSet)
{
SPI2->CR1&=0XFFC7;//Fsck=Fcpu/256
if(SpeedSet==SPI2_SPEED_2)//二分頻
{
SPI2->CR1|=0<<3;//Fsck=Fpclk/2=36Mhz
}else if(SpeedSet==SPI2_SPEED_8)//八分頻
{
SPI2->CR1|=2<<3;//Fsck=Fpclk/8=9Mhz
}else if(SpeedSet==SPI2_SPEED_16)//十六分頻
{
SPI2->CR1|=3<<3;//Fsck=Fpclk/16=4.5Mhz
}else //256分頻
{
SPI2->CR1|=7<<3; //Fsck=Fpclk/256=281.25Khz 低速模式
}
SPI2->CR1|=1<<6; //SPI設備使能
}
void VS_SET_VOL(u8 volt,u8 bass)
{
u16 temp_volt,temp_bass;
volt=255-volt;
temp_volt=volt;
temp_volt=(temp_volt<<8)+volt;
temp_bass=(temp_bass<<8)+bass;
Vs1003_CMD_Write(SPI_VOL,temp_volt); //設音量
Vs1003_CMD_Write(SPI_BASS,temp_bass);//BASS
}
//軟復位VS1003
void Vs1003SoftReset(void)
{
u8 retry;
while(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00);//等待軟件復位結束
SPI2_ReadWriteByte(0X00);//啟動傳輸
retry=0;
while(Vs1003_REG_Read(SPI_MODE)!=0x0C00)// 軟件復位,新模式
{
Vs1003_CMD_Write(SPI_MODE,0x0C00);// 軟件復位,新模式
delay_ms(2);//等待至少1.35ms
if(retry++>100)break;
}
while (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00);//等待軟件復位結束
retry=0;
while(Vs1003_REG_Read(SPI_CLOCKF)!=0X9800)//設置vs1003的時鐘,3倍頻 ,1.5xADD
{
Vs1003_CMD_Write(SPI_CLOCKF,0X9800);//設置vs1003的時鐘,3倍頻 ,1.5xADD
if(retry++>100)break;
}
retry=0;
while(Vs1003_REG_Read(SPI_AUDATA)!=0XAC44)//設置vs1003的時鐘,3倍頻 ,1.5xADD
{
Vs1003_CMD_Write(SPI_AUDATA,0XAC44);
if(retry++>100)break;
}
//Vs1003_CMD_Write(SPI_CLOCKF,0X9800);
//Vs1003_CMD_Write(SPI_AUDATA,0XBB81); //采樣率48k,立體聲
VS_SET_VOL(VS_VOLT,VS_BASS);
ResetDecodeTime();//復位解碼時間
//向vs1003發送4個字節無效數據,用以啟動SPI發送
VS_XDCS_CLR();//選中數據傳輸
SPI2_ReadWriteByte(0XFF);
SPI2_ReadWriteByte(0XFF);
SPI2_ReadWriteByte(0XFF);
SPI2_ReadWriteByte(0XFF);
VS_XDCS_SET();//取消數據傳輸
delay_ms(20);
}
//硬復位MP3
void Mp3Reset(void)
{
VS_XRESET_CLR();
delay_ms(20);
VS_XDCS_SET(); //取消數據傳輸
VS_XCS_SET();//取消數據傳輸
VS_XRESET_SET();
while(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00); //等待DREQ為高
delay_ms(20);
}
//正弦測試
void VsSineTest(void)
{
Mp3Reset();
Vs1003_CMD_Write(0x0b,0X2020); //設置音量
Vs1003_CMD_Write(SPI_MODE,0x0820);//進入vs1003的測試模式
while (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00); //等待DREQ為高
//向vs1003發送正弦測試命令:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
//其中n = 0x24, 設定vs1003所產生的正弦波的頻率值,具體計算方法見vs1003的datasheet
VS_XDCS_CLR();//選中數據傳輸
SPI2_ReadWriteByte(0x53);
SPI2_ReadWriteByte(0xef);
SPI2_ReadWriteByte(0x6e);
SPI2_ReadWriteByte(0x7E);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
delay_ms(100);
VS_XDCS_SET();
//退出正弦測試
VS_XDCS_CLR();//選中數據傳輸
SPI2_ReadWriteByte(0x45);
SPI2_ReadWriteByte(0x78);
SPI2_ReadWriteByte(0x69);
SPI2_ReadWriteByte(0x74);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
delay_ms(100);
VS_XDCS_SET();
//再次進入正弦測試并設置n值為0x44,即將正弦波的頻率設置為另外的值
VS_XDCS_CLR();//選中數據傳輸
SPI2_ReadWriteByte(0x53);
SPI2_ReadWriteByte(0xef);
SPI2_ReadWriteByte(0x6e);
SPI2_ReadWriteByte(0x44);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
delay_ms(100);
VS_XDCS_SET();
//退出正弦測試
VS_XDCS_CLR();//選中數據傳輸
SPI2_ReadWriteByte(0x45);
SPI2_ReadWriteByte(0x78);
SPI2_ReadWriteByte(0x69);
SPI2_ReadWriteByte(0x74);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
delay_ms(100);
VS_XDCS_SET();
}
//ram 測試
u16 regvalue ;
void VsRamTest(void)
{
Mp3Reset();
Vs1003_CMD_Write(SPI_MODE,0x0820);// 進入vs1003的測試模式
while (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00); // 等待DREQ為高
VS_XDCS_CLR(); // xDCS = 1,選擇vs1003的數據接口
SPI2_ReadWriteByte(0x4d);
SPI2_ReadWriteByte(0xea);
SPI2_ReadWriteByte(0x6d);
SPI2_ReadWriteByte(0x54);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
SPI2_ReadWriteByte(0x00);
delay_ms(50);
VS_XDCS_SET();
regvalue = Vs1003_REG_Read(SPI_HDAT0); // 如果得到的值為0x807F,則表明完好。
///printf("regvalueH:%x\n",regvalue>>8);//輸出結果
//printf("regvalueL:%x\n",regvalue&0xff);//輸出結果
}
//向VS1003寫命令
//address:命令地址
//data:命令數據
void Vs1003_CMD_Write(u8 address,u16 data)
{
while(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00);//等待空閑
SPI2_SetSpeed(SPI2_SPEED_256);//低速
VS_XDCS_SET(); //MP3_DATA_CS=1;
VS_XCS_CLR(); //MP3_CMD_CS=0;
SPI2_ReadWriteByte(VS_WRITE_COMMAND);//發送VS1003的寫命令
SPI2_ReadWriteByte(address); //地址
SPI2_ReadWriteByte(data>>8); //發送高八位
SPI2_ReadWriteByte(data); //第八位
VS_XCS_SET(); //MP3_CMD_CS=1;
SPI2_SetSpeed(SPI2_SPEED_16);//高速
}
//向VS1003寫數據
void Vs1003_DATA_Write(u8 data)
{
VS_XDCS_CLR(); //MP3_DATA_CS=0;
//while(VS_DREQ==0); //VS1003的DREQ為高才能寫入數據????這句可以不要??
SPI2_ReadWriteByte(data);
VS_XDCS_SET(); //MP3_DATA_CS=1;
VS_XCS_SET(); //MP3_CMD_CS=1;
}
//讀VS1003的寄存器
//讀VS1003
//注意不要用倍速讀取,會出錯
u16 Vs1003_REG_Read(u8 address)
{
u16 temp=0;
while(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == 0x00);//非等待空閑狀態
SPI2_SetSpeed(SPI2_SPEED_256);//低速
VS_XDCS_SET(); //MP3_DATA_CS=1;
VS_XCS_CLR(); //MP3_CMD_CS=0;
SPI2_ReadWriteByte(VS_READ_COMMAND);//發送VS1003的讀命令
SPI2_ReadWriteByte(address); //地址
temp=SPI2_ReadWriteByte(0xff); //讀取高字節
temp=temp<<8;
temp+=SPI2_ReadWriteByte(0xff); //讀取低字節
VS_XCS_SET(); //MP3_CMD_CS=1;
SPI2_SetSpeed(SPI2_SPEED_16);//高速
return temp;
}
//FOR WAV HEAD0 :0X7761 HEAD1:0X7665
//FOR MIDI HEAD0 ther info HEAD1:0X4D54
//FOR WMA HEAD0 :data speed HEAD1:0X574D
//FOR MP3 HEAD0 :data speed HEAD1:ID
//比特率預定值
const u16 bitrate[2][16]=
{
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}
};
//返回Kbps的大小
//得到mp3&wma的波特率
u16 GetHeadInfo(void)
{
unsigned int HEAD0;
unsigned int HEAD1;
HEAD0=Vs1003_REG_Read(SPI_HDAT0);
HEAD1=Vs1003_REG_Read(SPI_HDAT1);
switch(HEAD1)
{
case 0x7665:return 0;//WAV格式
case 0X4D54:return 1;//MIDI格式
case 0X574D://WMA格式
{
HEAD1=HEAD0*2/25;
if((HEAD1%10)>5)return HEAD1/10+1;
else return HEAD1/10;
}
default://MP3格式
{
HEAD1>>=3;
HEAD1=HEAD1&0x03;
if(HEAD1==3)HEAD1=1;
else HEAD1=0;
return bitrate[HEAD1][HEAD0>>12];
}
}
}
//重設解碼時間
void ResetDecodeTime(void)
{
Vs1003_CMD_Write(SPI_DECODE_TIME,0x0000);
Vs1003_CMD_Write(SPI_DECODE_TIME,0x0000);//操作兩次
}
//得到mp3的播放時間n sec
u16 GetDecodeTime(void)
{
return Vs1003_REG_Read(SPI_DECODE_TIME);
}
//加載頻譜分析的代碼到VS1003
void LoadPatch(void)
{
u16 i;
for (i=0;i<943;i++)Vs1003_CMD_Write(atab[i],dtab[i]);
delay_ms(10);
}
//得到頻譜數據
void GetSpec(u8 *p)
{
u8 byteIndex=0;
u8 temp;
Vs1003_CMD_Write(SPI_WRAMADDR,0x1804);
for (byteIndex=0;byteIndex<14;byteIndex++)
{
temp=Vs1003_REG_Read(SPI_WRAM)&0x63;//取小于100的數
*p++=temp;
}
}
void SPI2_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SPI1 GPIOA and GPIOB clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* Configure SPI1 pins: NSS, SCK, MISO and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure PB.12 as Output push-pull, used as Flash Chip select */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Deselect the FLASH: Chip Select high */
VS_XCS_SET();
/* SPI1 configuration */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
/* Enable SPI1 */
SPI_Cmd(SPI2, ENABLE);
}
//初始化VS1003的IO口
void Vs1003_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI2_Init(); //初始化VS1003的SPI及端口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOB , ENABLE);
/* Configure PA4 PA8 as output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//選擇PA4 PA8
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管腳頻率為50MHZ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //模式為推挽輸出
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOA寄存器
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;//選擇PX.8-11
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管腳頻率為50MHZ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //模式為推挽輸出
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOB寄存器
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;//選擇PX.8-11
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管腳頻率為50MHZ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //模式為推挽輸出
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化GPIOB寄存器
Mp3Reset(); //復位VS1003
} |