小白之前学习过一段时间dsp,想用tms320f28335这款芯片来做一个mp3播放器,先用普中的一个f28335开发板做实验,历经了一些磨难终于做出来了一个mp3播放器,回头总结一下解码芯片和dsp芯片的通信,考虑到f28335和tf卡之间通信用的是硬件的spi模块,那么f28335和解码芯片vs1003b之间就需要用软件来模拟时序,网上有51和vs1003b之间通信的代码,在此基础上,我稍微做了修改,加了很多注释,变成f28335和vs1003b之间的通信代码:
/*
* smg.c
*
* Created on: 2019-05-02
*
*/
#include "smg.h"
unsigned char vol=0x10;
void Port_Init(void){
EALLOW;
SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1;// 开启GPIO时钟
//DREQ
GpioCtrlRegs.GPCMUX1.bit.GPIO76=0;
GpioCtrlRegs.GPCDIR.bit.GPIO76=0;
GpioCtrlRegs.GPCPUD.bit.GPIO76=0;
//MISO
GpioCtrlRegs.GPCMUX1.bit.GPIO75=0;
GpioCtrlRegs.GPCDIR.bit.GPIO75=0;
GpioCtrlRegs.GPCPUD.bit.GPIO75=0;//上面这两个是输入,其中MISO悬空用不到
//XRST
GpioCtrlRegs.GPCMUX1.bit.GPIO70=0;
GpioCtrlRegs.GPCDIR.bit.GPIO70=1;
GpioCtrlRegs.GPCPUD.bit.GPIO70=0;
//MOSI
GpioCtrlRegs.GPCMUX1.bit.GPIO71=0;
GpioCtrlRegs.GPCDIR.bit.GPIO71=1;
GpioCtrlRegs.GPCPUD.bit.GPIO71=0;
//SCLK
GpioCtrlRegs.GPCMUX1.bit.GPIO72=0;
GpioCtrlRegs.GPCDIR.bit.GPIO72=1;
GpioCtrlRegs.GPCPUD.bit.GPIO72=0;
//XCS
GpioCtrlRegs.GPCMUX1.bit.GPIO73=0;
GpioCtrlRegs.GPCDIR.bit.GPIO73=1;
GpioCtrlRegs.GPCPUD.bit.GPIO73=0;
//XDCS
//这个引脚给我的感觉好像没有用到
//其实是用到的,SCI_MODE初始化为0x0804(默认是0x0800)
//默认SDI in VS1002 Native Modes (New Mode) (就是上面那个8)
// In VS1002 native modes(SM NEWMODE is 1), byte synchronization is achieved by XDCS. The state of
// XDCS may not change while a data byte transfer is in progress.
//SM SDISHARE 为0,XDCS和XCS 是分开的,具体用法如下:
// XDCS XCS Active low chip select input. A high level forces the serial interface into
// standby mode, ending the current operation. A high level also forces serial
// output (SO) to high impedance state. If SM SDISHARE is 1, pin
// XDCS is not used, but the signal is generated internally by inverting
// XCS.高电平迫使进入备用状态,ending the current operation,低电平有效(选中,具体看时序图)
GpioCtrlRegs.GPCMUX1.bit.GPIO74=0;
GpioCtrlRegs.GPCDIR.bit.GPIO74=1;
GpioCtrlRegs.GPCPUD.bit.GPIO74=0;
EDIS;
}
//SCLK上升沿,从机读取数据(采样)
//spi 通信方式给VS1003b发送数据
//这里让我担心的是,F28335时钟太快了,VS1003b识别不了上升沿,下降沿,后来发现没问题
//XCS和写入数据之间的关系:
//Serial clock input. The serial clock is also used internally as the master
//clock for the register interface.
//SCK can be gated or continuous. In either case, the first rising clock edge
//after XCS has gone low marks the first bit to be written.//重点
//SI Serial input. If a chip select is active, SI is sampled on the rising CLK edge.
//读写频率要求(一开始有点担心,实践中没出现问题):
//Note: As tWL and tWH, as well as tH require at least 2 clock cycles, the maximum speed for the SPI
//bus that can easily be used is 1/6 of VS1003’s internal clock speed CLKI. Slightly higher speed can be
//achieved with very careful timing tuning. For details, see Application Notes for VS10XX.
//Note: Although the timing is derived from the internal clock CLKI, the system always starts up in 1.0×
//mode, thus CLKI=XTALI./
//SPI Input Clock Frequency CLKI/6 MHz
//CLKI Value for SCI reads. SCI and SDI writes allow CLK1/4.
//一个xCS上升沿之后就可以一直SDI了,而每个wr_command()都会有一个上升沿:
//SDI data is synchronized with a raising edge of xCS as shown in Figure 10. However, every byte doesn’t
//need separate synchronization.
void spi_write(unsigned char dat){//软件模拟spi通信时序
char i=0;
for(i=0;i<8;i++)
{
SCLK_SETL;
if(dat&0x80)//从最高位(MSB)开始
MOSI_SETH;
else
MOSI_SETL;
SCLK_SETH; //时钟上升沿,从机读取数据
dat<<=1;
}
}
//VS1003内部寄存器写入指令(先送MSB):
//The serial bus protocol for the Serial Command Interface SCI (Chapter 8.5) consists of an instruction
//byte, address byte and one 16-bit data word. Each read or write operation can read or write a single
//register. Data bits are read at the rising edge, so the user should update data at the falling edge. Bytes are
//always send MSb first.
//DREQ(data request)引脚的功能:
//The DREQ pin/signal is used to signal if VS1003’s FIFO is capable of receiving data. If DREQ is high,
//VS1003 can take at least 32 bytes of SDI data or one SCI command. When these criteria are not met,
//DREQ is turned low, and the sender should stop transferring new data.
void wr_command(unsigned char addr,unsigned char hdat,unsigned char ldat ){
//51单片机在检测输入之前要先拉高电位,但是dsp没有必要
while (!DREQ); //等待到VS1003可以接受数据
XCS_SETL; //片选,见数据手册7.7.3
spi_write(0x02);//写操作码,以下是操作码opcode
// READ 0b0000 0011 Read data
// WRITE 0b0000 0010 Write data
spi_write(addr);//寄存器地址
spi_write(hdat);//data高8位
spi_write(ldat);//data低8位
XCS_SETH; //XCS先低后高,一个命令写完。高电平关片选
}
void Mp3Reset(void){
XRST_SETL;//硬件复位
// XRESET的用法:
// When the XRESET -signal is driven low, VS1003 is reset and all the control registers and internal states
// are set to the initial values
DELAY_US(100);
XCS_SETH;
XDCS_SETH;//先进入备用状态,ending the current operation.
XRST_SETH;//硬件复位结束
//XCS 和 XDCS的用法:
// After a hardware reset (or at power-up) DREQ will stay down for at least 16600 clock cycles, which
// means an approximate 1.35 ms delay if VS1003 is run at 12.288 MHz. After this the user should set
// such basic software registers as SCI MODE, SCI BASS, SCI CLOCKF, and SCI VOL before starting
// decoding. See section 8.6 for details
wr_command(0x00,0x08,0x04);
//SCI_MODE调节0000 1000 0000 0100,(默认0x0800)
//第11位是1,调节成VS1002 native SPI modes
DELAY_US(10);
// 第2位是1,代表将进行软件复位:
// Software reset is initiated by setting SM RESET to 1. This bit is cleared automatically
// In some cases the decoder software has to be reset. This is done by activating bit 2 in SCI MODE register
// (Chapter 8.6.1). Then wait for at least 2 us, then look at DREQ. DREQ will stay down for at least 16600
// clock cycles, which means an approximate 1.35 ms delay if VS1003 is run at 12.288 MHz. After DREQ
// is up, you may continue playback as usual.
while (!DREQ);//软件复位结束,开始写寄存器
wr_command(0x02,0x00,0x55);
//设置重低音提升:SPI_BASS = 0x0055;表示50Hz以下低音获得5db提升,高音不提升。
// 0x2 rw 0 2100 CLKI BASS Built-in bass/treble enhancer
DELAY_US(10);
//有时候不要延时:
//This is the worst-case time that DREQ stays low after writing to this register. The user may choose to
//skip the DREQ check for those register writes that take less than 100 clock cycles to execute.
wr_command(0x03,0x98,0x00);
//设置VS1003的时钟:SCI_CLOCKF = 0x9800;表示3倍频,倍频增量1.5x,时钟频率12.288MHZ
// 0x3 rw 0 11000 XTALI5 CLOCKF Clock freq + multiplier
DELAY_US(10);
wr_command(0x05,0xbb,0x81);
//设置VS1003的采样率:SPI_AUDATA = 0xBB81,采样率48khz,立体声
//采样率常见44.1khz和48khz,采样率在这之上的,人耳几乎听不出区别了
//vs1003b几乎支持所有位率的mp3格式,位率和采样率不一样
//0x5 rw 0 3200 CLKI AUDATA Misc. audio data
DELAY_US(10);
wr_command(0x0b,vol,vol);
//音量左声道-17*0.5db,右声道-17*0.5db。
//0xB rw 0 2100 CLKI VOL Volume control
//关于音量调节我一直很糊涂,不晓得啥意思,手册上这么写:
// SCI VOL is a volume control for the player hardware. For each channel, a value in the range of 0..254
// may be defined to set its attenuation from the maximum volume level (in 0.5 dB steps). The left channel
// value is then multiplied by 256 and the values are added. Thus, maximum volume is 0 and total silence
// is 0xFEFE.
// Example: for a volume of -2.0 dB for the left channel and -3.5 dB for the right channel: (4*256) + 7
// = 0x407. Note, that at startup volume is set to full volume. Resetting the software does not reset the
// volume setting.
//Note: Setting SCI VOL to 0xFFFF will activate analog powerdown mode
//我对它的example这么理解,最高0dB,0x0407,代表左声道-4*0.5=-2.0,右声道-7*0.5=-3.5
DELAY_US(10);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(0);//向vs1003发送4个字节无效数据,用以启动SPI发送
//虽然和手册上面推荐的寄存器不一样,但是都是先初始化四个寄存器再写四个0。
//其实是初始化了5个寄存器,可能重要的是后面的写0操作
//数据手册推荐的步骤:
// All tests are started in a similar way: VS1003 is hardware reset, SM TESTS is set, and then a test
// command is sent to the SDI bus. Each test is started by sending a 4-byte special command sequence,
// followed by 4 zeros. The sequences are described below.
}
void send_dat(unsigned char dat){
while (!DREQ);//VS1003的DREQ为高,缓冲池数据少于32B
spi_write(dat);
}
代码的文件名之所以是smg.c,是因为这段代码在普中的tms320f28335开发板的数码管实验的程序上面改编的,他们两是有相似之处的,而且两者共用一些引脚,能通过数码管是否闪烁来初步预判f28335和vs1003b之间是否通信正常。这段代码本身并不长,但是注释特别多,有的注释是原来的51代码里面的注释,但大部分注释(英文注释),是我从vs1003b数据手册上面找到的,对相应模块的规定,也就是这些函数要这么写的理由。这个对小白的价值可能更大。
在main.c里面先#include “smg.h”,在调用这些函数即可,主函数里面还牵涉到tf卡的读写,就不列出了,主函数里面和vs1003b有关的函数有:Port_Init(); Mp3Reset(); XDCS_SETL;和send_dat();,顶层51单片机代码和dsp代码差别不大,不做赘述。
非科班dsp小白,如有错误虚心接受。