本帖最后由 wangqy_ic 于 2022-3-14 22:40 编辑
这两天处理了一个关于 JTAG 相关管脚复用为 GPIO 的一个问题,整理一下免得大家再在这个问题耗费时间。
【问题描述】
我的板子上需要把 PB3 当做一个普通的数字输出口。根据手册说明,需要把 JTAG 关掉(可以开启 SWD),再按 GPIO 配置为合适的输出功能。一般的操作(包括官方提供的示例里)关键代码就两行:
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO, ENABLE);
GPIO_ConfigPinRemap(GPIO_RMP_SW_JTAG_SW_ENABLE, ENABLE);
第一行开启 AFIO 电源,第二行关掉 JTAG,开启 SWD。
然后就是初始化 GPIO,这部分代码就省略了。
在官方示例里,这两行代码完全没有问题。但是在我实际的工程项目中,这两行并不起效。
【问题排查】
测试,有如下结果:
官方示例代码+开发板 --> OK。
官方示例代码+自有板子 --> OK。
自有代码+开发板 --> FAIL。
自有代码+自有板子 --> FAIL。
那问题肯定是在自己的代码里。反复检查核对,各个寄存器相关值都是没问题,除了 AFIO->RMP_CFG 这个寄存器的 SW_JTAG_CFG 值不一致。
核对手册,有如下描述:
读取 SW_JTAG_CFG 返回未定义的值。
问题就出在这个点:我自己的代码里,后续还会复用另外的管脚,会多次操作 AFIO->RMP_CFG 这个寄存器。
虽然每次都是 读-改-写 的方式:
reg_val = AFIO->RMP_CFG;
reg_val &= ~(MASK);
reg_val |= VAL;
AFIO->RMP_CFG = reg_val;
但是由于 SW_JTAG_CFG 的值不能正确读取,所以每次修改前读取到的 SW_JTAG_CFG 的值可能都不是正确的,错误的值会被写到 SW_JTAG_CFG 进而导致后续的问题。
【处理办法】
嗯……很丑陋的一个解决办法:在每次修改 AFIO->RMP_CFG 后,再写个合适的值到 SW_JTAG_CFG 位置,我的代码里是 2。
// ...
// Ensure RMP_CFG.SW_JTAG_CFG=2
reg_val = AFIO->RMP_CFG;
reg_val &= (~(7UL << 24));
reg_val |= (2UL << 24);
AFIO->RMP_CFG = reg_val;
其他的复用管脚,也要特别注意这个问题。
以上,做个记录,大家遇到问题也省些时间……
-- END --
|