【STM32】位带操作

一、位带操作

1.意义

回想以前写51代码

​ P0 = 0x10; //将P0端口设置为0x10 P1_0=1; //将P1端口0号引脚设置为高电平 a = P2_2; //获取P2端口2号引脚的电平

根据上述的方法,我们可以发现快速定位修改某个引脚的电平还有获取引脚的状态

2.原因

GPIO_SetBits、GPIO_ResetBits、GPIO_WriteBit操作IO口的性能 没有达到极致,因为这些函数都需要进行现场保护和现场恢复的动作,比较耗时间 ,没有进行一步到位,使用位带操作则没有上述的烦恼,简单快速!

示例1:

c 复制代码
 GPIO_SetBits(GPIOF,GPIO_Pin_9); 
 修改为 PFout(9)=1;              

示例2:

c 复制代码
GPIO_ResetBits(GPIOF,GPIO_Pin_9); 

修改为 PFout(9)=0;          

因为使用对引脚设置电平或读取电平,库函数效率是不高的,很难应付高性能的场合,如下代码,修改某引脚电平要执行起码3行代码,还不包括隐含的调用函数与函数返回的过程。

c 复制代码
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{   
	/* Check the parameters */                        		assert_param(IS_GPIO_ALL_PERIPH(GPIOx));   	           	   assert_param(IS_GPIO_PIN(GPIO_Pin));    
    GPIOx->BSRRL = GPIO_Pin; 
}   

寄存器地址分析

二、《Cortex M3与M4权威指南》章节6.7 P206

1.背景

位带操作常用于I/O高度密集访问的芯片。

Bit-band operation support allows a single load/store operation to access (read/write) to a single data bit. In the Cortex-M3 and Cortex-M4 processors, this is supported in two pre-defined memory regions(静态映射) called bit-band regions. One of them is

There are two regions of memory for bit-band operations:

• 0x20000000~0x200FFFFF (SRAM, 1MB)

0x40000000~0x400FFFFF (Peripherals, 1MB)

2.映射表

3.公式

关于IO引脚对应的访问地址,可以参考以下公式寄存器的位带别名地址 = 0x42000000 + (寄存器的地址-0x40000000)32 + 引脚编号x

三、寄存器地址与别名地址转换技巧

1.确定某端口访问起始地址,如端口F访问起始地址为GPIOF_BASE

c 复制代码
#define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)
c 复制代码
typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint16_t BSRRL;    /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */
  __IO uint16_t BSRRH;    /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

2.根据要访问的寄存器地址计算偏移值,如计算

GPIOF的ODR寄存器地址 = GPIOF_BASE+0x14;

3.根据以下公式进行换算

​ 寄存器的位带别名地址 = 0x42000000 + (寄存器的地址-0x40000000)32 + 引脚编号4

详细示意图参考如下:

4.PF9引脚的位带别名地址

示例1:

   uint32_t *PF9_BitBand = (uint32_t *)(0x42000000 + (GPIOF_BASE + 0x14 - 0x40000000)*32 + 9*4);               

示例2:

uint32_t *PF9_BitBand   = (uint32_t *)(0x42000000 + ((uint32_t)&GPIOF->ODR - 0x40000000)*32 + 9*4);
c 复制代码

四、代码调整

将端口的访问封装为Pxout、Pxin,例如端口F引脚电平设置PFout,端口A引脚电平读取PAin。

#define PFout(x) *(volatile uint32_t *)(0x42000000 + (GPIOF_BASE + 0x14 - 0x40000000)32 + x4)

#define PAin(x) *(volatile uint32_t *)(0x42000000 + (GPIOA_BASE + 0x10 - 0x40000000)32 + x4)

五、编译优化

5.1 优化等级

优化:编译器想尽办法去压缩程序存储空间,提高运行速度。类比:新的电脑安装一个win10,默认的win10的存储空间占用是比较大、运算速度不是最快,会安装一些优化软件来优化win10,优化过后,会发现系统盘剩余空间增加了,win10的运行速度也增加了。

gcc 预处理 汇编 未链接的二进制文件 可执行程序

一般编译器,优化有多个等级:-O0、-O1、-O2、-O3。

-O0:缺省优化级别,一般情况下不压缩程序存储空间,不提高程序运行速度,保证程序的可靠执行。

-O1:轻度优化,轻度压缩程序存储空间,轻度优化程序运行速度。

-O2:推荐优化等级,在程序存储空间和程序运行速度取得平衡点。

-O3:最高级别的优化等级,有可能导致程序不能运行,也会使用以空间换时间的方法,导致程序体积增大。

示例1:-O0

示例1:-O2

按键例子1,任何时刻按下按键,灯无法响应:

​ #define PAin(n) *((uint32_t *)(0x42000000 + (((uint32_t)&GPIOA->IDR) - 0x40000000)*32 + (n)*4)) PFout(9) = PAin(0); 经过编译阶段,会得到恒定的结果。 PFout(9)=1;

按键例子2,任何时刻按下按键,灯能够立即响应点亮或熄灭:

c 复制代码
              

六、volatile关键字

1.应用场景

volatile关键字分析,往往应用在三种场合

1)多线程编程共享全局变量的时候,该全局变量要加上volatile进行修饰,让编译器不要省略该变量的访问。

2)裸机编程的时候,某函数与中断服务函数共享全局变量的时候,该全局变量要加上volatile进行修饰,让编译器不要省略该变量的访问。

3)ARM定义寄存器的时候,寄存器是指向一个地址,要加上volatile进行修饰,让编译器不要优化而省略该变量的访问。

编译器不要优化该变量指的是防止编译器出现优化过度,导致代码运行失效。

加上volatile关键字生成的汇编代码会发生明显的变化,同样调用delay函数,灯的速度发生变化!

2.delay函数在-O2等级,是否添加volatile关键字,反汇编分析。

七、仿真调试

仿真调试实时跟踪代码的运行,程序出现问题并能跟踪到问题所在。能够观察变量的变化、逐步执行代码。

相关推荐
Q83431581915 分钟前
JL6107S 7端口管理型MAC(1*RGMII+1*SGMII)千兆以太网交换机芯片P2P替代RTL8367S
网络·嵌入式硬件·网络协议·硬件工程·信息与通信·p2p
梦境虽美,却不长19 分钟前
51单片机快速入门之独立按键
单片机·嵌入式硬件·51单片机
梦境虽美,却不长1 小时前
51单片机快速入门之定时器和计数器
单片机·嵌入式硬件·51单片机
光子物联单片机2 小时前
零基础国产GD32单片机编程入门(二十五)USB口介绍及CDC类虚拟串口通讯详解及源码
单片机·嵌入式硬件·mcu·gd32
QQ19284999062 小时前
基于单片机的水产养殖饲料自动投喂系统
单片机·嵌入式硬件
Nice__J3 小时前
电机驱动开发之驱动板
驱动开发·嵌入式硬件
汽车电子助手3 小时前
如何制作Vector Vflash中加载的DLL文件--自动解锁刷写过程中27服务
开发语言·单片机·嵌入式硬件
让开,我要吃人了5 小时前
OpenHarmony鸿蒙开发( Beta5.0)智能油烟机开发实践
驱动开发·嵌入式硬件·华为·移动开发·harmonyos·鸿蒙·openharmony
OH五星上将5 小时前
OpenHarmony(鸿蒙南向开发)——轻量系统芯片移植指南(二)
嵌入式硬件·移动开发·harmonyos·移植·openharmony·鸿蒙开发
深圳九鼎创展5 小时前
RK3588九鼎创展方案在Arm集群服务器的项目中的应用分析
运维·服务器·arm开发·人工智能·嵌入式硬件·物联网·iot