Gpio¶
FAQ1 为什么配置了pin脚不生效?¶
当发现配置pin的pinmux没有生效时,可以检查HAL_PIN_Set()的参数是否正确:
int HAL_PIN_Set(int pad, pin_function func, int flags, int hcpu)
例:PA28,对应的是GPIO_A28,复制/粘贴后,忘记改了。
flags:内部上下拉状态;配置原则,参考: 低功耗指南 第3节 配置上下拉hcpu:用于区分大小核。大核pin PA是1,小核PIN PB是0。 发现有使用者复制,粘贴忘记改了,导致配置不生效。
FAQ2 为什么finsh命令: pin mode 配置上下拉无效?¶
现象描述:
计划通过finsh命令: pin mode 50 2 配置PA50 gpio输入上拉;
从下表枚举看,2 对应的输入上拉类型;
#define PIN_MODE_OUTPUT 0x00
#define PIN_MODE_INPUT 0x01
#define PIN_MODE_INPUT_PULLUP 0x02
#define PIN_MODE_INPUT_PULLDOWN 0x03
#define PIN_MODE_OUTPUT_OD 0x04
通过pin status 50检查效果,实际上PA50 并没有改变为上拉;
原因分析:
finsh命令 pin mode 对应的函数原型为cmd_pin。
cmd_pin 处理mode 参数的代码如下:
if (strcmp(argv[1], "mode") == 0)
{
struct rt_device_pin_mode m;
m.pin = atoi(argv[2]);
m.mode = atoi(argv[3]);
rt_device_control(device, 0, &m);
......
}
检查调用层级:rt_device_control()->sifli_pin_mode()->HAL_GPIO_Init()
HAL_GPIO_Init() 只配置hwp_gpiox寄存器功能,不具备配置pinmux的功能.
配置上下拉通过修改hwp_pinmux寄存器实现的。
解决方案:
改变上下拉的正确方式必须通过HAL_PIN_Set(int pad, pin_function func, int flags, int hcpu)。
例如:
//配置PA50为PULLUP
HAL_PIN_Set(PAD_PA50, GPIO_A50, PIN_PULLUP, 1);
FAQ3 为什么在bsp_pinmux.c 配置PA43为GPIO,实际通过pin status查看却变成了LCDC?¶
现象描述:
bsp_pinmux.c 配置PA43为GPIO,输出高电平。但实际上电平却为低。
通过finsh命令 pin status 43 检查发现PA43被配置成了LCDC。
原因分析:
通过检查原理图PA43被应用于LCDC控制, 如下图:
lcd 驱动会在开机和唤醒调用配置pinmux
解决方案: 最好根据原理图来分配合适gpio来使用,对于其他功能模块已经用的pin,最好不要使用。
FAQ4 PBR0作为电源控制Pin时,为什么必须被配置为force1?¶
原因分析:
PBR作为低功耗IO会被应用在低功耗场景,例如:睡眠和关机后依然输出pwm波形等。
PBR0 相对于其他PBR增加有一个特殊功能就是force1,即硬件强制PBR0输出高电平。
force1 一般会用在电源控制。
特别是当PBR0作为psram电源控制Pin时,没有被配置为force1, 在睡眠唤醒过程中可能存在瞬间的低电平,导致psram存储数据异常。对于 nand方案, 代码也是放在psram,所以代码会跑乱掉。
56X 一般会有PBR0 控制psram的电源,如下图:
解决方案:
一般PBR0作为电源控制Pin使用时, 都会在bsp_pinmux.c让PBR0 进入force1, 方法如下:
MODIFY_REG(hwp_rtc->PBR0R, RTC_PBR0R_SEL_Msk, MAKE_REG_VAL(0, RTC_PBR0R_SEL_Msk, RTC_PBR0R_SEL_Pos)); // 恢复PBR0 功能为 0
HAL_PBR0_FORCE1_ENABLE(); //使能PBR0 force 1
如果想PBR0退出force1,可以参考如下方法:
HAL_PBR0_FORCE1_DISABLE(); //禁止PBR0 force 1
MODIFY_REG(hwp_rtc->PBR0R, RTC_PBR0R_SEL_Msk, MAKE_REG_VAL(1, RTC_PBR0R_SEL_Msk, RTC_PBR0R_SEL_Pos)); // 切换PBR0 功能为 GPIO
HAL_PBR_ConfigMode(0, 1); // 配置 PBR0 为输出模式
HAL_PBR_WritePin(0, 0); // 配置 PBR0 输出0
FAQ5 如何睡眠后PBR1继续输出PWM波形?¶
PBR支持PBR_CLK_LP的功能,支持睡眠后持续输出LP的波形。
LP的波形和LXT_DISABLE有关:
LXT_DISABLE 使能, 去掉外部32k晶振,使用内部rc10k, lp 输出的是rc10k波形;
LXT_DISABLE 禁止, 使用外部32k晶振, lp 输出的是32k波形;
52x/56x/58x都支持PBR睡眠继续输出LP波形, 但配置方法有些许差异:
52x 配置PBR1 睡眠输出lp
52x的PBR0~PBR3 和 PA24 ~PA27复用pin。
所以,配置PBR1 的同时需要配置PA25.
步骤1: 配置PA25
PA25 配置上下拉为NOPULL,功能配置为模拟;
HAL_PIN_Set(PAD_PA25, GPIO_A25, PIN_NOPULL, 1);
HAL_PIN_Set_Analog(PAD_PA25, 1);
步骤2: 配置PBR1
PBR1 配置为功能1,即:PBR_CLK_LP, 输出
uint32_t val = hwp_rtc->PBR1R;
val &= ~(RTC_PBR1R_OE_Msk | RTC_PBR1R_SEL_Msk);
val |= (RTC_PBR1R_OE_Msk | MAKE_REG_VAL(1, RTC_PBR1R_SEL_Msk, RTC_PBR1R_SEL_Pos));
hwp_rtc->PBR1R = val;
由于验证时,LXT_DISABLE 使能,查看效果输出的频率在9k左右;
56x/58x 配置PBR1 睡眠输出lp
56x/58x的PBR都是单独的pin,可以直接配置PBR1。
uint32_t val = hwp_rtc->PBR1R;
val &= ~(RTC_PBR1R_OE_Msk | RTC_PBR1R_SEL_Msk);
val |= (RTC_PBR1R_OE_Msk | MAKE_REG_VAL(1, RTC_PBR1R_SEL_Msk, RTC_PBR1R_SEL_Pos));
hwp_rtc->PBR1R = val;