用过STM32的童鞋们都知道,STM32在GPIO配置时都需要选择一个GPIO速率,对于STM32F103系列芯片来说最快的配置应该是50Mhz左右(没记错的话)。那么这个50Mhz究竟代表了什么,我们今天详细探讨。
顺便的话就是测试一些常用硬件接口(硬件SPI为例)与软件模拟(软件SPI为例)的性能差别。(之前有老师说硬件spi和软件spi速度没什么区别,在此实践论证一下)。
先论证的芯片是STM32F103C8T6
首先是GPIO口配置,这里直接测试GPIOA的PA1:
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
/*Configure GPIO pins : PA0 PA1 PA2 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL;//无上拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;//GPIO高速
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
上述配置是用STM32CUBEMX配置的,只能配置GPIO速率为GPIO_SPEED_FREQ_HIGH,其实应该就是和库函数配置的50Mhz差不多。
GPIO配置完成开始测试,先使用HAL库的GPIO操作代码:
while (1)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
}
毫无疑问,这里会产生一个方波,这个方波的频率就是使用HAL库操作时GPIO的最大速率。但结果强差人意:
图里可以清晰看到,使用HAL库操作GPIO也就1.6M左右的速率,和50M相差甚远。查阅一番资料后发现HAL库为了可读性增加了大量冗余,因此HAL代码运行效率不如直接操作寄存器,直接操作寄存器或使用汇编语言会增加运行效率。
下面搞起寄存器:
修改主函数代码如下:
while (1)
{
GPIOA->ODR=1<<1;//PA1置1
GPIOA->ODR=0<<1;//PA1置0
}
这下在此用示波器观察波形:
可以发现,速率直接快了四五倍,到了8M左右,看来确实优化挺大,但还是和50M差距甚远。
但其实自己也知道,STM32F103的通用IO口能做到这个地步也几乎是极限了,即使使用汇编提升效果也有限。
但突然之前有老师说硬件spi和软件spi速度没什么区别,在此正好实践论证一下,看看硬件SPI的SCK引脚是输出频率最大能到多少。
使用STM32CUBEMX配置硬件spi,因为使用的是STM32F103C8并且系统频率为72M,所以SPI的时钟频率最大只能设置为18M。STM32CUBEMX配置硬件spi的图如下:
主循环里面代码也很简单,不停用SPI传输就行了:
while (1)
{
HAL_SPI_Transmit(&hspi1,&test,1,1);
}
好啊,下面来看看硬件SPI性能怎么样,下面是SPI的SCK的示波器观察图片:
大概18M左右,这比只有8M左右的GPIO速率快的多的多。因此硬件SPI的上限速率无疑比软件模拟SPI快不少。但即使这样,大多数传感器类的SPI通信器件支持的SPI时钟也大多在10M以下,只有一些FLASH等芯片(如W25Q128)会支持20M以上的SPI时钟。所以一般情况下软件SPI确实够用,虽然软件SPI用DMA比较麻烦。
再论证的芯片是STM32H743
H743是个极品,我的测试结果居然表明它的性能和F103的性能相差没有我想象的那么大。(没有打开mpu和cache等辅助)
先上时钟配置,时钟我直接拉到最大的480M。
然后就是配置GPIO,依旧是把PA1的性能拉满,代码如下:
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
/*Configure GPIO pin : PA1 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
这里速率是GPIO_SPEED_FREQ_VERY_HIGH,是所能配置的最快的了,应该50Mhz快不少,具体是多少没了解过,知道的可以评论区告诉我。
先试试HAL库操作:
while (1)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
}
下面放实际的IO口波形图:
大概2.39MHZ,比F103快了几乎一倍不到,但就这???毕竟主频快了6倍左右,APB时钟也快了近3倍,结果IO速率就快一倍也有点强差人意,不知道是不是有什么错误如果大家发现可以指正。
下面测试STM32H743直接寄存器操作IO口,代码依旧简单:
while (1)
{
GPIOA->ODR=1<<1;
GPIOA->ODR=0<<1;
}
下面测试一下这个24M的硬件SPI的SCK,配置如下。
这个SPI时钟最高可以配置到96M,但是配置24M以上的波形几乎不能看,可能是手里H743板子设计有问题。
依旧是简单的代码:
while(1)
{
HAL_SPI_Transmit(&hspi1,&test,1,1);
}
看下波形吧:
就是24M,还挺准不错,就是波形比较差,可能是硬件设计问题。
STM32F103C8和STM32H743都测试结束,结果强差人意。