使用的是STM32F030F4P6,这是一个小封装的单片机,但是五脏俱全,很多功能,就是引脚不多。使用到SPI的时候感觉应该和以前用过的STM32F103系列是一样的,寄存器的结构几乎是完全一样的,寄存器操作的程序甚至都能兼容,但是在使用的时候就是调不通,耽误了不少时间。
SPI的引脚初始化和配置代码:
GPIO_InitStructure.GPIO_Pin = nIRQ_PIN;// | GPIO1_PIN | GPIO2_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7; //CRC 校验
SPI_Init(SPI1,&SPI_InitStruct);
SPI_Cmd(SPI1,ENABLE);
上面的代码检查了1000遍了,没有问题,SPI的收发函数也是从STM32F103系列单片机上移植过来的:
u8 SPI_RW(SPI_TypeDef* SPI,u8 TxData)
{
u16 retry=0;
while((SPI->SR&0x0002)==0) //等待发送区空
{
retry++;
if(retry>=200)return 0; //超时退出
}
SPI->DR=TxData; //发送一个byte
retry = 0;
while((SPI->SR&0x0001)==0) //等待接收完一个byte
{
retry++;
if(retry>=200)return 0; //超时退出
}
return SPI->DR; //返回收到的数据
}
用上面这个函数操作芯片的时候写入的数据和读出的数据是不一样的,怎么修改SPI的配置都不行......经过了很长时间,找不到问题,用逻辑分析仪查看一下波形吧......随便抓取了一个“SI4432_WR(0x00, 0xFF);”的执行波形如下:
上图信号分别为CS、SCK、MOSI和MISO,可以看到执行一次SI4432_WR函数SCK引脚发送了16个脉冲,按道理是8个脉冲才对,郁闷的一笔。然后是在没辙了,我把SI4432_WR函数改了一下(注释超时部分不影响),将发送部分从
SPI1->DR = data;
改成
*(uint8_t*)&(SPI1->DR)=data;
意思就是访问SPI1->DR的时候以byte类型访问。
u8 SPI_RW(u8 data)
{
u16 retry=0;
while((SPI1->SR&SPI_SR_TXE)==0) //等待发送区空
{
// retry++;
// if(retry>=200)return 0; //超时退出
}
*(uint8_t*)&(SPI1->DR)=data; //发送一个byte
retry = 0;
while ((SPI1->SR&SPI_SR_BSY)) //等待接收完一个byte
{
// retry++;
// if(retry>=200)return 0; //超时退出
}
return SPI1->DR; //返回收到的数据
}
依然抓取了“SI4432_WR(0x00, 0xFF);”的执行波形,第一张图为SI4432_WR函数发送地址数据0x00,第二张图为SI4432_WR函数发送0xFF(随意)产生8个脉冲读取寄存器数据:
按道理读出的数据应该是0x08,但是程序结果读到的数据都是0x00,也就是总线是对的了,但是还是没获得到正确的数据,在回到SI4432_WR函数,发现后面的返回过程中:
return SPI1->DR;
我再将它改成:
return *(uint8_t*)&(SPI1->DR);
然后程序的确就没问题了。
很奇怪这一点,为什么会这样,访问 SPI1->DR 寄存器的时候和访问方式还有关系,STM32F030的特点么这是?没有详细阅读文档,但是在网上找到一位网友也遇到这个问题了,也是修改访问方式解决的:https://www.amobbs.com/thread-5614282-1-1.html?_dsign=9ffc5097。