嵌入式开发--STM32H7系列的硬件SPI的读写函数问题
1 问题描述
需要读取BME280上的温度湿度和气压数据,通过SPI接口通讯,在F103上调试完成。
但是由于F103处理能力不够,换用了H750,于是移植BSP代码过去,但是在F1上跑得能正常运行的代码,在H7上跑不通。
按说HAL库是硬件无关的,可以直接移植。因为在HAL库内部封装了对于不同硬件的不同操作,所以对程序员来说,只需要面对统一接口,进行统一操作即可,但是我遇到坑了。
*故障是出在读取温度湿度和气压数据阶段,但是为了描述方便,我以读ID来举例,说明SPI的写函数,读函数,与写读一体函数的区别。
2 故障现象
在上电时先软件复位,再读取芯片ID,也就是读取0xd0寄存器,其数值应当是0x60,由此可以确定芯片已经正常复位,且SPI通讯正常。
逻辑分析仪的波形从上到下,依次是片选,时钟,从机(MISO),主机(MOSI)
2.1 SPI复位波形,正常
向0xE0写入0xB6
2.2 SPI读ID波形,正常
从0xd0读出数据,0x60,正常
2.3 SPI读ID波形,不正常
从机并没有发送0x60的ID号。
不下常的波形有2个,区别在于写和读操作中间阶段,是否有片选拉高再拉低的过程。代码见下方。
3 代码区别
3.1 正确读取的代码
u8 BME280_Read_ID(void)
{bme280_tx_data[0] = BME280_REG_ID;SPI2_CS(0);HAL_SPI_TransmitReceive(&BME280_SPI, bme280_tx_data, bme280_rx_data, 2, 10);SPI2_CS(1);return bme280_rx_data[1];
}
3.2 不正确读取的代码
u8 BME280_Read_ID(void)
{bme280_tx_data[0] = BME280_REG_ID;bme280_tx_data[1] = 0xb6;BME280_CS(0);HAL_SPI_Transmit(&BME280_SPI, bme280_tx_data, 1, 100);//无论片选是否有拉高再拉低这个动作,均无不能让从机正常发送波形
// BME280_CS(1);
// BME280_CS(0);HAL_SPI_Receive(&BME280_SPI, bme280_rx_data, 1, 100);BME280_CS(1);return bme280_rx_data[1];
}
尝试过将代码段中的注释去掉,来增加片选的拉高再拉低这个动作,均无不能让从机正常发送数据。
3.3 问题分析
分析波形可以发现,问题出在时钟的波形上,多出了下图框出的部分。
而最后的白色波形,即MISO,是有一个正常输出的,只是时机不对。
正确的代码波形
3.4 正确的代码有2个波型
3.3中,全程耗时很短,MCU是H750,波形很紧凑,片选并没有比时钟多出太多。
而2.2中的图,MCU是F103,虽然数据也正确,但片选的宽度比时钟多了太多太多,说明运行效率极低。
4 问题总结
对于F1来说,下面2段代码代码是等效的,但对于H750却不等效。
SPI2_CS(0);HAL_SPI_Transmit(&BME280_SPI, bme280_tx_data, 1, 100);HAL_SPI_Receive(&BME280_SPI, bme280_rx_data, 1, 100);SPI2_CS(1);
SPI2_CS(0);HAL_SPI_TransmitReceive(&BME280_SPI, bme280_tx_data, bme280_rx_data, 2, 10);SPI2_CS(1);
由此造成F1上的代码直接搬到H7,运行不了。区别就在于3.3章节的图形上,H7会多出一个时钟拉高再拉低的过程。
甚至下面的代码也不行
SPI2_CS(0);HAL_SPI_Transmit(&BME280_SPI, bme280_tx_data, 1, 100);SPI2_CS(1);SPI2_CS(0);HAL_SPI_Receive(&BME280_SPI, bme280_rx_data, 1, 100);SPI2_CS(1);
将片选强行拉高,再拉低,这会干扰BME280的运行,不能输出正确的寄存器内容
强烈建议写代码时,使用发收一体的HAL_SPI_TransmitReceive函数,而不是用发和收2个函数