先看手册中,GPIO的寄存器映射:
至少有两点可以确定:
- 从GPIOA到GPIOH,地址是连续的
- 每组GPIO基地址相差
0x400
依据这,rt-thread在给GPIO编号的时候,给每组port定义一个偏移,偏移单位是0x400
port | 偏移几个单位 |
---|---|
GPIOA | 0 |
GPIOB | 1 |
GPIOC | 2 |
… | … |
比如,知道了GPIO的基地址是0x48000000
,那么GPIOB的基地址是
0x48000000 + 0x400 * 1
rt-thread中给GPIO的编号规则是这样的:
pin | number |
---|---|
PA0~PA15 | 0~15 |
PB0~PB15 | 16~31 |
PC0~PC15 | 32~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