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:

GPIO_SetBits(GPIOF,GPIO_Pin_9);

修改为

PFout(9)=1;

示例2:

GPIO_ResetBits(GPIOF,GPIO_Pin_9);

修改为

PFout(9)=0;

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

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高度密集访问的芯片。

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/WEBRESOURCEd5ee5ae6ffbd4dcaeec70eddd5b11957/48317

        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

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/6CB8B8043D704DD0A8A7AC31848EC63B/43088

 

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

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

• 0x40000000~0x400FFFFF (Peripherals, 1MB)

2.映射表

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/BD82CB5A69FF4DF88DDAD5B58535ED70/43076

 

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/3A5B6ADFD7AA4D48A04CFC96A9F165E4/43085

3.公式

关于IO引脚对应的访问地址,可以参考以下公式

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

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

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

#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)

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;

IDR寄存器

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/WEBRESOURCEb3d7ce5f529f9188bd5ebb4d756a29b1/143619

 

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/WEBRESOURCE978b95c3e00af18eb712e78593c1c935/143617

 

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

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

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

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

详细示意图参考如下:

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/WEBRESOURCEf68f587e02e38790f732236ba7891378/153500

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);

四、代码调整

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

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

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

五、编译优化

5.1 优化等级

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

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

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

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

-O2:推荐优化等级,在程序存储空间和程序运行速度取得平衡点。(企业降本增效)

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

示例1:-O0

0

示例1:-O2

0

按键例子1,在-O2的等级优化,任何时刻按下按键,灯无法响应:

#define PAin(n) *((uint32_t *)(0x42000000 + (((uint32_t)&GPIOA->IDR) - 0x40000000)*32 + (n)*4))

PFout(9) = PAin(0);

经过编译阶段,会得到恒定的结果。

PFout(9)=1;

按键例子2,在-O2的等级优化,任何时刻按下按键,灯能够立即响应点亮或熄灭:

#define PAin(n) *((volatile uint32_t *)(0x42000000 + (((uint32_t)&GPIOA->IDR) - 0x40000000)*32 + (n)*4))

PFout(9) = PAin(0);

编译器不会去优化*((volatile uint32_t *)(0x42000000 + (((uint32_t)&GPIOA->IDR) - 0x40000000)*32 + (n)*4))变为恒定的值;

而是每次都是小心翼翼地取执行*((volatile uint32_t *)(0x42000000 + (((uint32_t)&GPIOA->IDR) - 0x40000000)*32 + (n)*4)),读取该地址上的值。

PFout(9) = PAin(0);

六、volatile关键字

1.应用场景

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

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

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

exti0_volatile.zip

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

硬件寄存器_volatile.zip

volatile修饰字段告诉编译器不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。

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

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

  • 不添加volatile关键字

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/CAAC633E80624FEBAC77B3437AD6DF5C/43092

 

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/FEDF052FFAC64786A5850B4A6BD83F13/43089

 

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/WEBRESOURCEf80f43cb9ec7380cc7dd883c7240d593/152188

 

七、仿真调试

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

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/WEBRESOURCE6f88522cd952b73aacfe90de57182e26/153509

重点提示,若进入调试环境提示JLink的问题,如下图。

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/5B84FC1B7EB64426B000819913192D91/71276

原因如下:

1.MDK没有用温工推荐的版本,而下载了更高的版本。(极有可能这个问题)

2.硬件连接接触不良。

 

https://note.youdao.com/yws/public/resource/b994246549f84052c3cad3ea416ccf64/xmlnote/A96F9C4878D545059F4AFC8F9E3CE45F/WEBRESOURCE3cc0601886897a9683fa0d5d964afcc5/144946

原因如下:需要注册MDK,如果没有注册,默认是评估版本,限制程序的运行大小,不能超过32KB。 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿文的储物间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值