本意是想做两片STM32 SPI 双机通讯。 现在通过网购的一个SPI转USB做SPI主站来调试我其中一块板子,板子上的STM32做
做SPI从站。实验方法是SPI转USB的设备发送24个字节给stm32,同时stm32返回24个字节其中最后一个字节是加和校验。
当作为从机的stm32间隔一定时间没有收到数据则应该重新初始化自己的SPI发送缓冲区。实验结果如下图
颜色不一致的是两次不同的接收。
可以看到当stm32收到第一个24字节数据后返回的数据0x01至0x17再加上一个字节0x14加和校验一共是24个字节 是正确的。
但是当间隔一定时间再次收到第二组24个字节后返回的是0x01 0x01 0x02.....0x17。可以看到收到了两次0x01。收到第三组24个字节后返回的数据是
0x14 0x01......0x17。虽然stm32通过定时器判断 长时间没有接收数据后就想通过程序初始化DMA发送缓冲区。但是我初始化后还是会出现上面的问题。
我分析是作为从机的stm32 的SPI-DR发送没有清除。因为stm32上电第一次运行时SPI-DR发送是空的 所以第一次发送的数据是对的(对应下图中第一组数据0x01....0x14)。经过间隔收到的第二组数据前面多了一个0x01的原因是第一次发送完数据后下一次应该发送的是0x01 虽然我做了初始化但是没有清除SPI-DR的值 所以当再次发送时 先把上次缓存再SPI-DR的值0x01 发送出去然后发送接下来的0x01...0x17。后面的数据也是这个逻辑。
现在我想问。我如何才能清除SPI-DR的发送缓存让每次都能从SPI发送的内存里重新取数据。
再判断长时间没有收到数据的TIM2的中断函数里做了如下程序
memcpy(SPI2_TxBuf,SPI2_TxBuftest,sizeof(SPI2_TxBuf));//将AD滤波之后的值放入SPI2 DMA发送地址
CheckSumSPI2=CheckSum_CalcSPI2(SPI2_TxBuf,sizeof(SPI2_TxBuf)-1);
*(SPI2_TxBuf+SPI2_DMA_RECE_SHIFT_Val.CheckSumShift)=CheckSumSPI2;
SPI_DMA_Config();
意为把SPI 发送DMA的内存取数据更新然后执行SPI_DMA_Config();重新初始化SPI2的DMA
SPI_DMA_Config()函数内容如下
void SPI_DMA_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
DMA_InitTypeDef DMA_Initstructure;
NVIC_InitTypeDef NVIC_InitStructure;//NVIC初始化结构体
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
CRC_ResetDR();
/* 设置 SPI2 引脚: SCK, MISO 和 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);
DMA_DeInit(DMA1_Channel4);//SPI2对应的DMA通道数
DMA_Initstructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR;//外设地址(u32)SPI2_DR_Address;
DMA_Initstructure.DMA_MemoryBaseAddr = (u32)&SPI2_RxBuf;//内存地址,就是你想要把采样值存在那个变量的地址
//DMA_Initstructure.DMA_MemoryBaseAddr = (u32)(&SPI2_RxBuf+tmp22/*SPI2_DMA_RECE_SHIFT_Val.MachineTypeShift*/);
DMA_Initstructure.DMA_DIR = DMA_DIR_PeripheralSRC ;//方向
DMA_Initstructure.DMA_BufferSize = SPI2_RxDataLength;//-tmp22/*SPI2_DMA_RECE_SHIFT_Val.MachineTypeShift*/;//开辟SPI2_RxDataLength个连续的DMA存储单元
DMA_Initstructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable ;//外设地址不变
DMA_Initstructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//内存地址自增
DMA_Initstructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte ;//设置外设数据长度为子字节
DMA_Initstructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte ;//设置DMA存储数据长度为字节
DMA_Initstructure.DMA_Mode = DMA_Mode_Circular ;//循环模式
DMA_Initstructure.DMA_Priority = DMA_Priority_VeryHigh ;//DMA优先级为高
DMA_Initstructure.DMA_M2M = DMA_M2M_Disable ;
DMA_Init(DMA1_Channel4 , &DMA_Initstructure );
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel4 , ENABLE );
DMA_DeInit(DMA1_Channel5);
DMA_Initstructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR; //设置 接收外设(0x4001300C) 地址(源地址)
DMA_Initstructure.DMA_MemoryBaseAddr = (u32)&SPI2_TxBuf; //设置 SRAM 存储地址(源地址)
DMA_Initstructure.DMA_DIR = DMA_DIR_PeripheralDST; //传输方向 内存-外设
DMA_Initstructure.DMA_BufferSize = SPI2_TxDataLength; //设置 SPI1 接收长度
DMA_Initstructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址增量(不变)
DMA_Initstructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址增量(变化)
DMA_Initstructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设传输宽度(字节)
DMA_Initstructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存传输宽度(字节)
DMA_Initstructure.DMA_Mode = DMA_Mode_Circular; //传输方式,一次传输完停止,不重新加载
DMA_Initstructure.DMA_Priority = DMA_Priority_VeryHigh; //中断方式-高(三级)
DMA_Initstructure.DMA_M2M = DMA_M2M_Disable; //内存到内存方式禁止
DMA_Init(DMA1_Channel5, &DMA_Initstructure);
DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel5 , ENABLE );
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;//两线全双工的通讯模式
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave ;//从机模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b ;//数据格式为2进制8位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//空闲时,时钟极性为低电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//第二个时钟沿采集数据
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//配置NSS引脚为软件模式,一般一主一从的情况下用此模式
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8 ;//设置波特率分频值为2,即18Mhz。因为SPI2挂在低速时钟APB1上
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ;//设置高位数据在先
SPI_InitStructure.SPI_CRCPolynomial = 7;//此处设置CRC校验中的多项式。本程序不用CRC校验,所以随便设了个值。
SPI_Init(SPI2 , &SPI_InitStructure );
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);//使能SPI DMA
SPI_Cmd(SPI2 , ENABLE);//使能SPI2
}
谢谢
|