使用正点原子F407的IAP例程时,发现了一个问题,在进行IAP升级后,APP中的串口无法使使用,串口接收不到中断,printf会卡死。
造成这种现象的原因可能是因为外设在bootloader中初始化的时候,对串口进行了一些映射无法被复位中断重置。
在经过不(tong)懈(ku)的debug后,发现在跳转到APP之前,需要先关闭所有中断响应,并将初始化后的外设复位,跳转到app后再打开中断就解决了。
//jump2app之前操作
INTX_DISABLE();
USART_DeInit(USART1);
//进入main之后操作
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x10000);
INTX_ENABLE();
其中的开启中断和关闭中断是用汇编实现的,学过arm课程的应该都很容易看懂,没学过的也不用深究。
//关闭所有中断(但是不包括fault和NMI中断)
__asm void INTX_DISABLE(void)
{
CPSID I
BX LR
}
//开启所有中断
__asm void INTX_ENABLE(void)
{
CPSIE I
BX LR
}
而对中断向量表进行偏移设置,网上包括原子都有大量文献说明。
对于工程:
其中bootloader其实什么都不用做修改。
target这里也不需要做什么修改。
代码这里做下修改就可以了。
而APP在编译前需要修改target:
如果不做修改,生成的map对应会有问题。app会从8000000开始找代码运行。
如果在下载那里改成对应的地址区域,就可以直接下载到0x08010000开始的地址。
下面随便记录一下其他内容~
void USART_DeInit(USART_TypeDef* USARTx)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
if (USARTx == USART1)
{
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, DISABLE);
}
//省略其他外设枚举
}
再往下看可以发现:
void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RCC_APB2_RESET_PERIPH(RCC_APB2Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RCC->APB2RSTR |= RCC_APB2Periph;
}
else
{
RCC->APB2RSTR &= ~RCC_APB2Periph;
}
}
查阅手册发现:
那么这里的操作就是先复位串口1,再取消复位串口1。
这样就可以解决因为bootloader初始化外设之后留下的bug。