前言:在给项目中使用的M0芯片做IAP功能时一切一切都是那么的自然水到渠成,但是笔者在实现完IAP功能后,却发现APP端挂载的单总线功能崩溃了,最开始没有怀疑是bootload导致的。因为笔者在使用同一篇代码的时候单总线挂载的设备不同,延时也不同。最开始想着是不是硬件问题。两块板子,一块是校准过的光板,另外一个是装机的整版,笔者也分不清到底为啥光板时序就正确,能跑通,而整机就有问题,所以在对整机进行长达两三天的修理,后发现也还是一样一无所获。后思考是否是软件问题,最开始又怀疑是否是时钟导致的,后重新整理代码,发现M0的时钟他所使用的是内部高速时钟,我根本就没有配置,所以时钟也不对。再尝试对引脚抓波发现其超时时间固定,再尝试单独使用app程序后发现外挂的设备又能够正常使用。所以笔者就感觉可能是bootload问题,后对bootload检查参考官方给的sdk历程进行对比,经过两天的查找终于给我放弃了,找不到原因。最终只好求助官方技术支持。将现象给其介绍后,终于是找到原因了。
M0芯片本身没有办法进行重定向中断向量表,所以APP的中断向量是会到BOOT的中断向量表,boot中的中断服务函数会再跳转到APP的中断向量表,有boot的话APP的中断会多进一次中断服务函数,时间会长一点。
给的分析图如下:
相对于其他芯片,可以直接重定向中断,延时就不会受到影响。笔者使用的是systick中断,做us级别延时,每次进需要进中断时候就会先进入IAP程序代码,后再跳转到APP中,每次延时越小,受到影响越大。使用单总线延时,us级别的,一下子就超时了。
总的来就是这么在做IAP分区的时候记得M0的芯片没有重定向功能,所有中断需要先返回bootload中触发后再跳转到APP中运行
针对M0芯片,不同的M0 类型的芯片可以实现不同的中断方式,小编使用的是手动跳转,直接在bootload中转到APP应用中。
/*!* @file apm32f00x_int.c** @brief Main Interrupt Service Routines** @version V1.0.1** @date 2022-04-11** @attention** Copyright (C) 2018-2022 Geehy Semiconductor** You may not use this file except in compliance with the* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).** The program is only for reference, which is distributed in the hope* that it will be usefull and instructional for customers to develop* their software. Unless required by applicable law or agreed to in* writing, the program is distributed on an "AS IS" BASIS, WITHOUT* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions* and limitations under the License.*/#include "config.h"
typedef void (*INTERRUPT_FUNCTION)(void);#if defined (__CC_ARM)/* Indicates that the current interrupt vector */
uint32_t FLASH_interrupt_vector __attribute__((at(0x20000004))) = IAP_INTERRUPT_VECTOR;/* application interrupt vector address */
INTERRUPT_FUNCTION APP_interrupt_vector_addr __attribute__((at(0x20000000))) = (INTERRUPT_FUNCTION)0;#elif defined (__ICCARM__)
#pragma location = 0x20000000
__root INTERRUPT_FUNCTION APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)0;;
#pragma location = 0x20000004
__root uint32_t FLASH_interrupt_vector = IAP_INTERRUPT_VECTOR;#else
/* application interrupt vector address */
INTERRUPT_FUNCTION APP_interrupt_vector_addr __attribute__((section(".my_data"))) = (INTERRUPT_FUNCTION)0;/* Indicates that the current interrupt vector */
uint32_t FLASH_interrupt_vector __attribute__((section(".my_data"))) = IAP_INTERRUPT_VECTOR;#endif/*!* @brief This function handles NMI exception** @param None** @retval None** @note*/void NMI_Handler(void){if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_NonMaskableInt_IRQn_APP_ADDR;APP_interrupt_vector_addr();}}/*!* @brief This function handles Hard Fault exception** @param None** @retval None** @note*/
void HardFault_Handler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_HardFault_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles SVCall exception** @param None** @retval None** @note*/
void SVC_Handler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_SVC_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles PendSV_Handler exception** @param None** @retval None** @note
// */
void PendSV_Handler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_PendSV_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles SysTick exception** @param None** @retval None** @note*/
void SysTick_Handler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){APM_DelayIsr();}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_SysTick_IRQn_APP_ADDR;APP_interrupt_vector_addr();}}
/*!* @brief This function handles WUPT exception** @param None** @retval None*/
void WUPT_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_WUPT_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
/*!* @brief This function handles TMR4 exception** @param None** @retval None** @note*/
void TMR4_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_TMR4_IRQn_APP_ADDR;APP_interrupt_vector_addr();} }
/*!* @brief This function handles RCM exception** @param None** @retval None*/
void RCM_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_RCM_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
/*!* @brief This function handles EINTA exception** @param None** @retval None*/
void EINTA_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_EINTA_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles EINTB exception** @param None** @retval None*/
void EINTB_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_EINTB_IRQn_APP_ADDR;APP_interrupt_vector_addr();}}/*!* @brief This function handles EINTC exception** @param None** @retval None*/
void EINTC_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_EINTC_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles EINTD exception** @param None** @retval None*/
void EINTD_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_EINTD_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles SPI exception** @param None** @retval None*/
void SPI_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_SPI_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
/*!* @brief This function handles USART1 receiver exception** @param None** @retval None** @note*/
void USART1_RX_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){Uart1RxIsr();}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_USART1_RX_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles USART1 transmitter exception** @param None** @retval None** @note*/void USART1_TX_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_USART1_TX_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
/*!* @brief This function handles ADC exception** @param None** @retval None** @note*/
/*****************************************************************************函 数 名 : ADC_IRQHandler功能描述 : adc 中断函数输入参数 : void返 回 值 : void作 者 : Bright创建日期 : 20250620
*****************************************************************************/
void ADC_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_ADC_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
/*****************************************************************************函 数 名 : TMR2_CC_IRQHandler功能描述 : TIMER2定时中断输入参数 : void返 回 值 : void作 者 : Bright创建日期 : 20250620
*****************************************************************************/
void TMR2_CC_IRQHandler(void)//定时器溢出异常
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_TMR2_CC_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}void TMR2_UO_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_TMR2_UO_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
void IIC_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){I2C_Isr(); }else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_IIC_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
/*!* @brief This function handles TIMER1 update/overflow/underflow/trigger/break exception** @param None** @retval None*/
void TMR1_UT_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_TMR1_UT_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles TIMER1 capture/compare exception** @param None** @retval None*/
void TMR1_CC_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_TMR1_CC_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
void TMR1A_UT_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_TMR1A_UT_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
void TMR1A_CC_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_TMR1A_CC_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
void FLASH_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_FLASH_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}
/*!* @brief This function handles USART2 TX exception** @param None** @retval None*/
void USART2_TX_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_USART2_TX_IRQn_APP_ADDR;APP_interrupt_vector_addr();}
}/*!* @brief This function handles USART2 RX exception** @param None** @retval None*/
void USART2_RX_IRQHandler(void)
{if (FLASH_interrupt_vector == IAP_INTERRUPT_VECTOR){}else if (FLASH_interrupt_vector == APP1_INTERRUPT_VECTOR){APP_interrupt_vector_addr = (INTERRUPT_FUNCTION)*(uint32_t*)APP1_USART2_RX_IRQn_APP_ADDR;APP_interrupt_vector_addr();}}
其实也不同的M0芯片也可以有不同的做法,解决这个问题,有的芯片可以直接采用物理方式,直接将App的中断向量表从Flash复制到SRAM起始地址。直接解决重复中断问题。不同的M0芯片支持不同的方式。
至于之前挂载外设可以,换个整机不行,与同事探讨给出的解释是外设可能存在输入影响导致,个人感觉不太像,不太接受这个解释,暂时先放在这里,如果有遇到类似问题的朋友,可以留个言,小编也想知道为啥。