SWD调试在STM32中REMAP调试的深入探究
1.当不重映射时,默认TIM2四个的IO口是PA0、PA1、PA2、PA3
开启重映射__HAL_AFIO_REMAP_TIM2_ENABLE()
2.要使用PA15、PB3、PA2、PA3的端口组合,要调用下面的语句进行部分重映射:
__HAL_AFIO_REMAP_TIM2_PARTIAL_1()
3.要使用PA0、PA1、PB10、PB11的端口组合,要调用下面的语句进行部分重映射:
__HAL_AFIO_REMAP_TIM2_PARTIAL_2()
4.要使用PA15、PB3、PB10、PB11的端口组合,要调用下面的语句进行完全重映射:
__HAL_AFIO_REMAP_TIM2_ENABLE()
同时还要禁用JTAG功能,PA15、PB3、PB10、PB11才会正常输出。
那么使用了重映射之后会导致一个问题,程序download一次后,第二次download就提示no target connect,除非长按reset键才能继续下载程序。
该问题讨论可在此问答中找到答案
从该帖子找到的精辟回答如下
The problem is that the STM32F1 series has one register AFIO_MAPR
which contains thesettings for remapping various peripherals and for enabling/disabling the JTAG/SWD connectionto your debugger. And to makethis more complicated, the bits in that register which enable/disable theJTAG/SWD settings (bits 24-26
) arewrite-only so their existing state cannot be read.
This means that any attempt to change the settings of thevarious "peripheral remap" bits, by doing a read-modify-writesequence to this register, could read differentvalues instead of the real current valuesin the JTAG/SWD bits. Then, when the write to the register is done, your debugger access stopsbecause whatever was read from those JTAG/SWD bits, is written back to them.(Other effects have also been reported, but I won't go into that now).
From what I could find without installing the HAL, the macrosused are:
#define __HAL_AFIO_REMAP_TIM1_ENABLE()
MODIFY_REG(AFIO->MAPR, AFIO_MAPR_TIM1_REMAP, AFIO_MAPR_TIM1_REMAP_FULLREMAP)
and MODIFY_REG
is:
#define MODIFY_REG(REG, CLEARMASK, SETMASK)
WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
So as you see, MODIFY_REG
isdoing a read-modify-write and you don't know what values it will read fromJTAG/SWD bits 24-26
andhence what values it will write back to there! The values read from those bitsare "undefined" (to quote ST) and I know I have read different valuesfrom the same STM32F1 at different times.
The "fix" I have used with the SPL, is to change anyremapping code to specifically set the JTAG/SWD bits which you want, wheneveryou write to the AFIO_MAPR
register. You will need to figure out how you want to do the same with the HALcode. One way is to use a temporary variable so, from memory, the sequencebecomes:
· Read AFIO_MAPR register intotemp variable
· Change desired peripheralremap bits in the temp variable
· Mask out bits 24-26 in thetemp variable
· Set bits 24-26 in the tempvariable to whatever I wanted (therefore ignoring whatever their, likelyincorrect, "read" value was)
· Write temp variable toAFIO_MAPR
__HAL_AFIO_REMAP_I2C1_ENABLE()中会执行类似reg |= xxx_enable的操作
该操作会读寄存器,然后或上某个使能位
然而由于SWJ_CFG[2]位的Write Only特性,导致寄存器读出来后不是实际的值
解决方法:在使用了引脚复用的宏之后需要调用一次__HAL_AFIO_REMAP_SWJ_NOJTAG(),该宏的解释如下:
/**
* @brief Enable the Serial wire JTAG configuration
* @note NOJTAG: JTAG-DP Disabledand SW-DP Enabled
* @retval None
*/
#define__HAL_AFIO_REMAP_SWJ_NOJTAG() do{CLEAR_BIT(AFIO->MAPR, AFIO_MAPR_SWJ_CFG); \
SET_BIT(AFIO->MAPR, AFIO_MAPR_SWJ_CFG_JTAGDISABLE); \
}while(0U)
我们追一下CLEAR_BIT(AFIO->MAPR,AFIO_MAPR_SWJ_CFG);
可以发现#defineCLEAR_BIT(REG, BIT) ((REG) &=~(BIT))
继续追该宏使用的参数AFIO->MAPR,AFIO_MAPR_SWJ_CFG,其中MAPR为复用寄存器,而AFIO_MAPR_SWJ_CFG追到最后为0x07000000(过程比较多,就不赘述了),再通过&= ~(BIT)操作,得出&=~(0111000000000000000000000000)
最后结果为&=11111000111111111111111111111111
这个时候可以看出来在CLEAR_BIT(AFIO->MAPR,AFIO_MAPR_SWJ_CFG);宏的作用是使得MAPR寄存器的Bits 26:24重置为0。
可以发现是重新复位了SWJ,也就是重置了JTAG位的功能。
接下来我们再看SET_BIT(AFIO->MAPR,AFIO_MAPR_SWJ_CFG_JTAGDISABLE);
功能函数#defineSET_BIT(REG, BIT) ((REG) |= (BIT))
直接追AFIO_MAPR_SWJ_CFG_JTAGDISABLE,最后得出该值是0x02000000
所以该值操作为|=02000000,即|=00000 010 000000000000000000000000
重新看该值010在寄存器的作用,可以发现现在使能了SWD的调试功能了。