您的位置:首页 > 其它

DSP与STM32的SPI通信调试及浮点数据传输调试

2016-09-06 14:10 232 查看
        硬件环境:DSP为TMS320C6722,STM32为STM32F103ZG,两控制芯片为SPI三线连接,即SPI_SOMI,SPI_SIMO,SPI_CLK三线.

        首先整体简述下传输过程,DSP与STM32为SPI三线连接,无片选信号;DSP有一GPIO引脚连接至STM32外部中断引脚(在此处称为DataReady引脚);SPI虽然为全双工,但是在此项目中只需要DSP传输给STM32的数据,而不关心STM32传输给DSP的数据。STM32作为主机,DSP作为从机。为了节约CPU,从主机均使用SPI的DMA传输。数据传输的整体流程是这样的:DSP准备好数据后,会通过DataReady引脚由低电平变为高电平来触发STM32的外部中断,STM32在外部中断中将DMA开启,然后数据开始传输,STM32传输完成进入DMA传输完成中断,关闭DMA,STM32对收到的数据进行处理。

        下面简述DSP这边需要做的工作:

        熟悉C672x系列的人都知道,DMA在此系列芯片中占有相当大的作用(在C672x中称为dMAX)。DMA在C672x中可以进行数据传输、接收外部中断信号、触发CPU中断等等。

        对SPI及DMA进行配置:先对SPI进行配置,具体流程参考C672x的SPI手册(下面我也会贴出代码);然后对DMA的事件入口及传输入口进行配置。

        

#define   SPIGCR0       0x0000
#define   SPIGCR1       0x0001
#define   SPIINT0       0x0002
#define   SPILVL        0x0003
#define   SPIFLG        0x0004
#define   SPIPC0        0x0005
#define   SPIPC1        0x0006
#define   SPIPC2        0x0007
#define   SPIPC3        0x0008
#define   SPIPC4        0x0009
#define   SPIDAT0       0x000E
#define   SPIDAT1       0x000F
#define   SPIBUF        0x0010
#define   SPIDELAY      0x0012
#define   SPIFMT0       0x0014
#define   SPIFMT1       0x0015
#define   SPIFMT2       0x0016
#define   SPIFMT3       0x0017

#define   DEPR          0x0000
#define   DEER          0x0001
#define   DEDR          0x0002
#define   DEHPR         0x0003
#define   DELPR         0x0004
#define   DEFR          0x0005
#define   DTCR0         0x001F

#define   TransferEntry0        0x0000
#define   TransferEntry1        0x0001
#define   TransferEntry2        0x0002
#define   TransferEntry3        0x0003
#define   TransferEntry4        0x0004
#define   TransferEntry5        0x0005
#define   TransferEntry6        0x0006
#define   TransferEntry7        0x0007

#define   DMAX_DATA_TRANSFER_COUNT   8

volatile unsigned int * spi0_ptr   =  (unsigned int *) 0x47000000;
volatile unsigned int * dMAX_ptr   =  (unsigned int *) 0x60000008;
volatile unsigned int * SPI0RX_EventEntry    =  (unsigned int *) 0x62008034;
volatile unsigned int * SPI0RX_TransferEntry =  (unsigned int *) 0x620081D4;

Uint16  srcData[DMAX_DATA_TRANSFER_COUNT];
Uint16  dstData[DMAX_DATA_TRANSFER_COUNT];

void spi0_configuration(void)
{
spi0_ptr[SPIGCR0] = 0x00000001;         //SPI0 is Released from Software Reset
spi0_ptr[SPIGCR1] = 0x00000000;         //SPI0 Disable,LOOPBACK Disable,Active Mode,Slave Mode
spi0_ptr[SPIPC0]  = 0x00000E00;         //SOMI,SIMO,CLK default as SPI Functional Pins
spi0_ptr[SPIPC1]  = 0x00000000;         //SOMI,SIMO,CLK default as SPI Functional Pins
spi0_ptr[SPIDAT1] = 0x00000000;         //select SPIFMAT0
spi0_ptr[SPIFMT0] = 0x00026310;         //MSB,Polarity=1,Phase=0,Prescale=99(1MHz),Charlen=16
spi0_ptr[SPIINT0] = 0x00010000;         //only DMA enabled
spi0_ptr[SPILVL]  = 0x00000000;         //all mapped to interrupted to INT0

//Configure dMAX
dMAX_ptr[DEDR] |= 0x00002000;           //Disable Event13
dMAX_ptr[DEFR] |= 0x00002000;           //Write 1 to Clear Flag
dMAX_ptr[DEPR] |= 0x00002000;           //High Polarity
dMAX_ptr[DELPR]|= 0x00002000;           //Low priority
SPI0RX_EventEntry[0x0000] = 0x1201D4A2; //Configure Event Entry13

//dMAX Transfer Entry
SPI0RX_TransferEntry[TransferEntry0] = (Uint32)srcData;
SPI0RX_TransferEntry[TransferEntry1] = (Uint32)dstData;
SPI0RX_TransferEntry[TransferEntry2] = DMAX_DATA_TRANSFER_COUNT;
SPI0RX_TransferEntry[TransferEntry3] = DMAX_DATA_TRANSFER_COUNT;
SPI0RX_TransferEntry[TransferEntry4] = (Uint32)srcData;
SPI0RX_TransferEntry[TransferEntry5] = (Uint32)dstData;
SPI0RX_TransferEntry[TransferEntry6] = (Uint32)srcData;
SPI0RX_TransferEntry[TransferEntry7] = (Uint32)dstData;

dMAX_ptr[DEER] |= 0x00002000;             //Enable Event13
spi0_ptr[SPIGCR1] |= 0x01000000;          //Enable SPI0
}


        我没有用TI公司提供的CSL库,一开始是倾向于用CSL库的,但是在调试过程中发现麻烦重重,有些繁琐,而且好多函数不可见,封装在了.lib库里,远不如自己写驱动更简单方便。在main函数中调用上面的驱动函数后,只要STM32一开启DMA,就会有数据进入到C6722的SPI数据寄存器中,C6722就会触发SPI的DMA,传输开始。而且在传输过程中不需要CPU干预。

        还有一个问题需要注意。SPI0的三个引脚SPI_SOMI,SPI_SIMO,SPI_CLK跟C6722的Parallel Flash启动有关,上电时刻三个引脚的状态直接决定Parallel Flash启动能不能成功。刚开始调试时,DSP与STM32均下载好程序后,发现DSP无法启动,后来在DSP的仿真状态下查看CFGPIN0寄存器发现SPI_CLK的引脚状态为1(若想Parallel Flash启动成功,SPI_CLK的引脚状态应该为0)。后来仔细想,在STM32中没放程序的时候DSP启动没问题,所以可能是STM32的SPI驱动程序使得SPI_CLK的引脚状态在DSP捕获其时发生了变化,所以我在STM32调用SPI的驱动程序之前加了个延时,然后就好了,DSP可以正常启动。

        接下来是STM32这方面需要做的工作:

        STM32网上资料较多,而且也用的极其大众化,所以直接贴驱动代码。

         

void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_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_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);

SPI_Cmd(SPI1, DISABLE);
SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
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);
SPI1->CR1 |= 1<<9  ;
SPI1->CR1 |= 1<<8  ;
SPI1->CR2 |= 1<<0;
SPI1->CR2 |= 1<<1;

SPI_Cmd(SPI1, ENABLE); //ʹÄÜSPIÍâÉè
}

void SPI1_DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA_DeInit(DMA1_Channel2);
DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPI1_RX_Buff;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = SPI1_ReciveBufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel2, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);

DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = SPI1_DR_Addr;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(SPI1_TX_Buff);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = SPI1_SendBufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
}

void EXTI15_10_IRQHandler(void)           //External Interrupt(Signal from DSP)
{
if(EXTI_GetITStatus(EXTI_Line12)!=RESET)
{
EXTI_ClearITPendingBit(EXTI_Line12);

DMA_Cmd(DMA1_Channel2, ENABLE); //Enable DMA,Start Transfer
DMA_Cmd(DMA1_Channel3, ENABLE);
GPIO_ResetBits(GPIOE, GPIO_Pin_7);
}
}

void DMA1_Channel2_IRQHandler(void)   //Transfer Data Finished Interrupt
{
if(DMA_GetITStatus(DMA1_IT_TC2)!=RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC2);
DMA_Cmd(DMA1_Channel2, DISABLE);
DMA_Cmd(DMA1_Channel3, DISABLE);

DMA1_Channel2->CNDTR = SPI1_ReciveLength;
DMA1_Channel3->CNDTR = SPI1_ReciveLength;

Parse_Receive_Data();         //Parse the Data Received from DSP
}
}

         DMA的开启工作及传输完成所做的工作在代码中均有体现,不多说了。
        
        下面说下浮点数据的传输。用C6722就是因为其强大的数据处理能力,所以在传输给STM32的数据中自然缺不了浮点数。
        关于浮点数据的存储可以参考下面的链接:http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html
        我们以DSP传送浮点数data=8.25到STM32为例,简述下所要做的工作。
        DSP方面:若所有传送的数据都要放入Uint16  srcData[  ] 数组中,假设data放入数组最初的位置。浮点数在DSP占据32位,所以要存放在 srcData[ 0 ] 和 srcData[ 1 ] 中.
        处理如下:
        Uint16  *temp;
        temp = (Uint16 *)&data;
        srcData[ 0 ] =*temp;
        srcData[ 1 ] =*(temp+1);
        这样就将一个浮点数存入到了srcData[  ] 数组中。
        
        STM32方面:SPI的DMA传输完成后,会将数据存放在uint16_t    dstData[   ]数组中,我们要做的是将浮点数data提取出来。假设data传送过来存放到了dstData[ 0 ]和dstData[ 1 ]  中。处理如下:
        float  data_copy;
        uint16_t  *temp;
        temp = (uint16_t  *)&data_copy;
        *temp=dstData[ 0 ];
        *(temp+1)=dstData[ 1 ];
        这样就将接收到的8.25存放到了 data_copy中。注意,千万不能直接这样做:       

        float  data_copy;
        data_copy=dstData[ 1 ]<<16|dstData[ 0 ];
        我们知道,8.25存储在内存中是0x41040000,若按上面的方法做,因为dstData[  ]为16位无符号整形,所以直接赋给浮点型后data_copy=0x4E820800(以浮点数的方式存储数值大小为无符号整形0x41040000的数据)。因此定义一个指针,指向data_copy的存储地址,这样就不会出错了。       
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: