前言
STM32F10X SPI1挂接在ABP2时钟总线,SPI2和SPI3挂接在ABP1时钟总线。ABP1速率最大36M,ABP2速率最大72M。如下图所示。
SPI2和SPI3速率错误原因
RT-Thread基于芯片建立的工程,官方驱动库drv_spi.c中,stm32_spi_init()函数设置SPI速率部分程序如下所示。
uint32_t SPI_APB_CLOCK;
#if defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0)
SPI_APB_CLOCK = HAL_RCC_GetPCLK1Freq();
#elif defined(SOC_SERIES_STM32H7)
SPI_APB_CLOCK = HAL_RCC_GetSysClockFreq();
#else
SPI_APB_CLOCK = HAL_RCC_GetPCLK2Freq();
#endif
if (cfg->max_hz >= SPI_APB_CLOCK / 2)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 4)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 8)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 16)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 32)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 64)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 128)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
}
else
{
/* min prescaler 256 */
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
}
也就是说RT-Thread官方库中并没有对STM32F10X的SPI1和SPI2,3作区分,统一用ABP2时钟频率做分频。这会导致SPI2和SPI3实际频率是设置频率的一半。
解决办法
在设置分频前判断一下当前是哪个SPI接口,并读取不同的时钟总线频率即可。修改后的stm32_spi_init()函数如下。只是增加了if判断。
uint32_t SPI_APB_CLOCK;
#if defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0)
SPI_APB_CLOCK = HAL_RCC_GetPCLK1Freq();
#elif defined(SOC_SERIES_STM32H7)
SPI_APB_CLOCK = HAL_RCC_GetSysClockFreq();
#else
if(spi_handle->Instance==SPI1)//增加对SPI接口号的判断
{
SPI_APB_CLOCK = HAL_RCC_GetPCLK2Freq();
}
else
{
SPI_APB_CLOCK = HAL_RCC_GetPCLK1Freq();
}
#endif
if (cfg->max_hz >= SPI_APB_CLOCK / 2)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 4)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 8)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 16)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 32)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 64)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
}
else if (cfg->max_hz >= SPI_APB_CLOCK / 128)
{
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
}
else
{
/* min prescaler 256 */
spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
}