F3不能用位带操作GPIO之原由

最近用到STM32F303,在修改IO的时候,觉得用库操作太麻烦了,要自己一个一个修改,用宏定义也不解决,自然就会想到用位带操作。查M4的手册知道M4也是支持位带操作,F3系列也是属于M4内核,而且在405也是用位带操作,觉得F303也是一样可以做位带操作。直接先修改一个IO,调试却发现在,IO电平始终没有变化。查IO,初始化没有问题。再查位带宏定义:
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20)
#define GPIOB_ODR_Addr    (GPIOB_BASE+20)
#define GPIOC_ODR_Addr    (GPIOC_BASE+20)
第一次地址映射操作是内核决定的,F3跟F4都是相同的,这里不会有错。查ODR寄存器的偏移地址:
_IO uint16_t ODR;          /*!< GPIO port output data register,                           Address offset: 0x14 */
ODR的地址偏移了0x14,也就是20,也是对的。F4都可以用位带操作,F3却用不了,就觉得很奇怪。放了一段时间,不死心,继续查找问题。调试,看汇编代码,在位带操作IO那里打断点

可以看到,操作寄存器的地址是0X42010290,查M3的GPIO地址,
#define GPIOC_BASE            (AHB2PERIPH_BASE + 0x0800)
#define AHB2PERIPH_BASE       (PERIPH_BASE + 0x08000000)
#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
也就是GPIOC的地址是0x48000800。这明显就对不上,位带操作的地址都不是对应GPIO的ODR,当然操作不了GPIO的电平,这下死心了。
      死也要再死个明白,继续查M4的手册关于Memory System章节,可以看到位带操作地址有两个,Bit Band Region是直接位带操作(具体的可以百度),Bit Band Alias是间接位带操作,要做地址映射才能操作,所以才会BITBAND这个宏定义。只有寄存器的地址在Bit Badn Alias(0x42000000,0x43FFFFFF)地址区域内的才进行位带操作。F303的GPIO是属于AHB2,地址已经不在位置操作区域,所以地址映射后对应不是GPIO的寄存器,自然不能进行位带操作(ST这点也做得太坑了,为什么要把GPIO的归到AHB2)。M4的GPIO都在AHB1总线上,地址在位带操作地址区域自然可以用位带操作GPI,M1也是一样。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是 GD32F3GPIO 寄存器操作宏定义示例: ```c #define GPIO_BASE(port) (GPIOA_BASE + (port - GPIOA) * 0x0400U) // GPIO 基地址宏定义 #define GPIO_PIN(port, pin) (1U << (pin)) // GPIO 引脚宏定义 #define GPIO_MODER(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x00U)) // GPIO 模式寄存器宏定义 #define GPIO_OTYPER(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x04U)) // GPIO 输出类型寄存器宏定义 #define GPIO_OSPEEDR(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x08U)) // GPIO 输出速度寄存器宏定义 #define GPIO_PUPDR(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x0CU)) // GPIO 上下拉寄存器宏定义 #define GPIO_IDR(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x10U)) // GPIO 输入数据寄存器宏定义 #define GPIO_ODR(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x14U)) // GPIO 输出数据寄存器宏定义 #define GPIO_BSRR(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x18U)) // GPIO 置位/复位寄存器宏定义 #define GPIO_LCKR(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x1CU)) // GPIO 锁定寄存器宏定义 #define GPIO_AFRL(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x20U)) // GPIO 复用功能低位寄存器宏定义 #define GPIO_AFRH(port) (*(volatile uint32_t *)(GPIO_BASE(port) + 0x24U)) // GPIO 复用功能高位寄存器宏定义 ``` 使用这些宏定义,可以方便地对 GD32F3GPIO 寄存器进行操作,例如: ```c // 设置 GPIOA 的第 1 个引脚为输出模式,推挽输出,最大输出速度为 50MHz GPIO_MODER(GPIOA) |= (0x01U << (1U * 2U)); GPIO_OTYPER(GPIOA) &= ~(0x01U << 1U); GPIO_OSPEEDR(GPIOA) |= (0x03U << (1U * 2U)); // 设置 GPIOA 的第 2 个引脚为输入模式,上拉输入模式 GPIO_MODER(GPIOA) &= ~(0x03U << (2U * 2U)); GPIO_PUPDR(GPIOA) &= ~(0x03U << (2U * 2U)); GPIO_PUPDR(GPIOA) |= (0x01U << (2U * 2U)); // 读取 GPIOA 的第 2 个引脚的输入数据 uint32_t input_data = GPIO_IDR(GPIOA) & GPIO_PIN(GPIOA, 2U); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值