本程序经验证可实现DSP和ARM的SPI通讯。
一、 SPI的通信协议
SPI(Serial Peripheral Interface)是一种串行同步通讯协议,由一个主设备和一个或多个从设备组成,主设备启动一个与从设备的同步通讯,从而完成数据的交换。SPI 接口一般由4根线组成,CS片选信号(有的单片机上也称为NSS),SCLK时钟信号线,MISO数据线(主机输入从机输出),MOSI数据线(主机输出从机输入),CS 决定了唯一的与主设备通信的从设备,如没有CS 信号,则只能存在一个从设备,主设备通过产生移位时钟信号来发起通讯。通讯时主机的数据由MISO输入,由MOSI 输出,输入的数据在时钟的上升或下降沿被采样,输出数据在紧接着的下降或上升沿被发出(具体由SPI的时钟相位和极性的设置而决定)。
串行协议框图
二、 例程
DSP TMS320F2808PZA做主机,ARM STM32F103VCT6做从机实现两芯片的SPI通讯。
1、 ARM从机例程。
ARM使用SPI1且工作于从模式。从机的SPI一直都是处于等待状态,一旦主机有数据发送过来,从机立即进入中断进行接收。接收数据的同时也向主机发送数据。
void SPI_Init_user(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_Cmd(SPI1, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
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_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
}
中断优先级配置
void NIV(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
中断服务程序
void SPI1_IRQHandler(void)
{
static u16 b=0;
OSIntEnter();
GPIO_SetBits(GPIOE, GPIO_Pin_5);
if (SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_RXNE) == SET)
{
SPI_I2S_ClearITPendingBit( SPI1 , SPI_I2S_IT_RXNE ) ;
rdata_SPI[b]=SPI_I2S_ReceiveData(SPI1);
SPI_I2S_SendData(SPI1, sdata[b]);
b++;
if(b==16)b=0;
}
OSIntExit();
}
2、 DSP主机例程。
DSP使用SPIA且工作于主机模式。使用定时发送的方式给从机发数据。
SPIA_GPIO引脚初始化
void InitSpiaGpio()
{
EALLOW
GpioCtrlRegs.GPAQSEL2.bit.GPIO16 = 3
GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3
GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3
GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3
GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1
GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1
GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1
EDIS
}
SPI_FIFO初始化
void spi_fifo_init(void)
{
SpiaRegs.SPIFFTX.all=0xE040
SpiaRegs.SPIFFRX.all=0x204f
SpiaRegs.SPIFFCT.all=0x0
}
SPI工作方式配置
void spi_init(void)
{
SpiaRegs.SPICCR.all =0x004F
SpiaRegs.SPICTL.all =0x0006
//TALK=1使能主机发送, SPI中断不使能. 时钟相位为:数据在第2个时钟边沿被选择
SpiaRegs.SPIBRR =0x007F
//SpiaRegs.SPIBRR=24
SpiaRegs.SPICCR.all =0x00CF
SpiaRegs.SPIPRI.bit.FREE = 1
}
在主程序中定时500ms向从机发送数据,时间可由自己定。即每500ms调用下面函数一次。
void SPI_service()
{
int16 j,tmp
sdata[0]=0x0c
sdata[1]=TEMP
for ( j=0
{
tmp=sdata[j]
SpiaRegs.SPITXBUF=tmp
while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { } //接收FIFO为空时,等待!
// 检查返回数据
rdata_SPI[j] = SpiaRegs.SPIRXBUF
if(rdata_SPI[1]==0x0c) //收到正确的帖头
{
for(h=0
{
rdata[h]=rdata_SPI[h]
}
}
}
}