打印

STM32 DMA SPI 做从机通讯的问题

[复制链接]
1318|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本意是想做两片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  
}  

谢谢



SPI.png (17.89 KB )

SPI.png

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

65

主题

196

帖子

0

粉丝