最近移植工程,需要把F407的工程移植到H7系列中去,原先的工程SPI是直接操作寄存器去发送和接收与其它芯片通信!在移植到H7的工程里后,测试发现,SPI通信的出现问题,通过仿真调试和示波器测试信号(时钟和片选信号),最后发现卡在了判断接收的while判断上!
时钟树配置

spi的时钟频率为183.3MHZ,2倍频后为91.6MHZ,4倍频为45.8MHZ

spi的代码配置

在main.c中使用spi的相关库函数去接收和发送,进行验证!

cpp
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);//片选拉低
HAL_SPI_TransmitReceive(&hspi1,Txbuf_inv16,Rxbuf_inv16,4,1000);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);//片选拉高
delay(50);//延时50us
在main函数前定义的接收和发送数组,这里发送的是16位数据;
cpp
uint16_t Txbuf_inv16[4] = {0x0001,0x0002,0x0003,0x0004};//测试使用
uint16_t Rxbuf_inv16[4] = {0,0,0,0};
通过示波器采集的信号(片选和时钟)如下:总共花费2.6us左右时间!

频率也为45MHZ,跟预期结果相符!
后面将SPI1的发送和接收修改成操作寄存器:
cpp
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // CS低电平(有效)
for (uint8_t s = 0; s < 4; s++)
{
//----------- 发送 -----------//
while((SPI1->SR&1<<1)==0); //等待发送区空
*((__IO uint16_t *)&SPI1->TXDR) = Txbuf_inv16[s];
//----------- 接收 -----------//
while((SPI1->SR&1<<0)==0); //等待接收完
Rxbuf_inv16[s] = *((__IO uint16_t *)&SPI1->RXDR);
}
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // CS高电平(无效)
delay(50);//延时50us
发现程序会卡在while((SPI1->SR&1<<0)==0);这一行,导致片选无法拉高,时钟信号没有!
先看一下SR寄存器(状态寄存器)的介绍:


参考网上一些历程改为:
cpp
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // CS低电平(有效)
SPI1->CR1|=1<<0; //SPE=1,使能SPI1
SPI1->CR1|=1<<9; //CSTART=1,启动传输
for (uint8_t s = 0; s < 4; s++) {
//----------- 发送 -----------//
while((SPI1->SR&1<<1)==0); //等待发送区空
*((__IO uint16_t *)&SPI1->TXDR) = Txbuf_inv16[s];
//----------- 接收 -----------//
while((SPI1->SR&1<<0)==0); //等待接收完一个byte
Rxbuf_inv16[s] = *((__IO uint16_t *)&SPI1->RXDR);
SPI1->IFCR|=3<<3; //EOTC和TXTFC置1,清除EOT和TXTFC位
}
SPI1->CR1&=~(1<<0); //SPE=0,关闭SPI1,会执行状态机复位/FIFO重置等操作
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // CS高电平(无效)
delay(50);
发现可以执行,并且可以检测到信号!频率45MHZ,共花费3.28us时间!

CR1寄存器(控制寄存器 1)



IFCR(中断/状态标志清零寄存器)寄存器

后面又将SPI改为2分频,也就是91MHZ,经过测试,库函数和寄存器操作,时钟频率都可以达到91MHZ,并且总共花费时间两者相差不大(1.7~1.8us)!