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的事件入口及传输入口进行配置。
我没有用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网上资料较多,而且也用的极其大众化,所以直接贴驱动代码。
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的存储地址,这样就不会出错了。
首先整体简述下传输过程,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的存储地址,这样就不会出错了。
相关文章推荐
- 对STM32 HAL库的一些思考(一)SPI通信的数据格式问题
- 与下位机通信时最好不要做其他工作 否则容易导致数据传输异常
- Android 2.0上使用蓝牙通信代码片断(服务端、客户端、数据传输)
- APUE读书笔记-16网络通信-05数据传输
- 和菜鸟一起学linux总线驱动之初识spi驱动数据传输流程
- 通信常识:波特率、数据传输速率与带宽的相互关系【转】
- 用c#编写通过无线网(例如CDMA)传输数据的通信程序
- [通信资料] 杂网络环境下数据传输的保证:揭秘WS-RM协议
- stm32 SPI DMA读取ADS8345数据
- [DSP(TI)]DSP 数据的定标(定点DSP如何做浮点)
- DSP/BIOS环境下的数据通信
- Q格式(Q15)DSP上浮点数据定点化处理
- 火牛(STM32) 多路ADC采样数据经过RS485传输到另一块ARM板路虎(LPC1768)
- STM32与FPGA通信写数据出错问题解决方法
- C6000系列C64X DSP EDMA/QDMA小结——数据传输和优化
- 安全通信/数据可靠传输模型
- STM32与FPGA通信写数据出错问题解决方法
- STM32 SPI1 remap时,与调试端口的冲突解决办法
- STM32的SPI查询方式传输测试
- stm32 SPI 收发数据