rt-thread驱动构架之pin

先看手册中,GPIO的寄存器映射:
在这里插入图片描述
至少有两点可以确定:

  1. 从GPIOA到GPIOH,地址是连续的
  2. 每组GPIO基地址相差0x400

依据这,rt-thread在给GPIO编号的时候,给每组port定义一个偏移,偏移单位是0x400

port偏移几个单位
GPIOA0
GPIOB1
GPIOC2

比如,知道了GPIO的基地址是0x48000000,那么GPIOB的基地址是

0x48000000 + 0x400 * 1

rt-thread中给GPIO的编号规则是这样的:

pinnumber
PA0~PA150~15
PB0~PB1516~31
PC0~PC1532~47

drv_gpio.c文件中有如下代码:

#define PIN_NUM(port, no) (((((port) & 0xFu) << 4) | ((no) & 0xFu)))
#define PIN_PORT(pin) ((uint8_t)(((pin) >> 4) & 0xFu))
#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu))
...
#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))
#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin)))

比如:有一个pin的编号是33,经过以下宏运算
PIN_PORT(33) 结果是2
PIN_NO(33) 结果是1
PIN_STPORT(33) 结果是(GPIO_TypeDef *)(GPIOA_BASE + (0x400u * 2)),近一步宏替换后是(GPIO_TypeDef*)(0x48000800),这与官方手册和HAL库中定义是匹配的
PIN_STPIN(33) 结果是(uint16_t)(1)
所以,33对应的是PC1

相反地,知道管脚名得到编号就是这样的:

#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN) // 摘自drv_gpio.h

比如 GET_PIN(C, 1),一步步替换宏定义后

(rt_base_t)((16 * ( ((rt_base_t)GPIOC_BASE - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + 1) // 替换__STM32_PORT(C)
(rt_base_t)((16 * ( (0x48000800 - 0x48000000)/(0x0400UL) )) + 1) // 替换GPIOX_BASE
(rt_base_t)((16 * ( 2 )) + 1)
(rt_base_t)((32) + 1)

显然结果是33
rt_pin_mode, rt_pin_write, rt_pin_read等系统API都是都是基于pin编号来操作的

rt_pin_write(33, 0)  < = >  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);

drv_gpio.c中

static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{
    GPIO_TypeDef *gpio_port;
    uint16_t gpio_pin;

    if (PIN_PORT(pin) < PIN_STPORT_MAX)
    {
        gpio_port = PIN_STPORT(pin);
        gpio_pin = PIN_STPIN(pin);

        HAL_GPIO_WritePin(gpio_port, gpio_pin, (GPIO_PinState)value);
    }
}

pin.c中

int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
    _hw_pin.parent.type         = RT_Device_Class_Miscellaneous;
    _hw_pin.parent.rx_indicate  = RT_NULL;
    _hw_pin.parent.tx_complete  = RT_NULL;

    ...

    _hw_pin.ops                 = ops;
    _hw_pin.parent.user_data    = user_data;

    /* register a character device */
    rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);

    return 0;
}
...
void rt_pin_write(rt_base_t pin, rt_base_t value)
{
    RT_ASSERT(_hw_pin.ops != RT_NULL);
    _hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
}

pin.c文件中定义了一个rt_device_pin类型的变量_hw_pin,初始化注册的时候,其成员变量ops初始化为_stm32_pin_ops

const static struct rt_pin_ops _stm32_pin_ops =
{
    stm32_pin_mode,
    stm32_pin_write,
    stm32_pin_read,
    stm32_pin_attach_irq,
    stm32_pin_dettach_irq,
    stm32_pin_irq_enable,
    stm32_pin_get,
};
...
int rt_hw_pin_init(void) {
  ...
  return rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
}

rt_pin_write -> _hw_pin.ops->pin_write -> stm32_pin_write -> HAL_GPIO_WritePin

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值