因为我现在使用的单片机使用了大量原厂提供的库函数和标准初始化例程,而这一部分例程很大程度上都是通用的,而且无论是在boot里还是APP1还是APP2都要调用这部分程序,那为什么不将这部分共用的程序都放在同一片FLASH里,通过某种方式统一调用呢?
而实现这种方法的方式其实非常简单就是使用函数指针,只要函数指针指能够指向对应API所在Flash的地址,就能实现相应的功能。
具体方法如下:在boot中的某个位置固定好函数映射的地址表,然后再APP中调用
/*boot中使用*/
#if ThisBoot==1
/*----------------------------------------------------------------------
//固化API函数表
-----------------------------------------------------------------------*/
const uint32_t func_table[] __attribute__((section(".ARM.__at_0x00001000"))) =
{
//注:这里会存在一些警告,无可避免
//注:顺序要想改必须同步更改 API_xxx_Loc
#if API_UseADC>0
(uint32_t)&API_ADC,
#else
(uint32_t)API_ADC_Loc, //如果不用于占位
#endif
#if API_UseETIM>0
(uint32_t)&API_Etim_Init,
#else
(uint32_t)API_ETIM_Loc,//如果不用于占位
#endif
#if API_UseIIC>0
(uint32_t)&API_I2C_Init,
(uint32_t)&API_EEPROM_Read,
(uint32_t)&API_EEPROM_Write,
#else
(uint32_t)API_I2C_Init_Loc,//如果不用于占位
(uint32_t)API_I2C_Read_Loc,
(uint32_t)API_I2C_Write_Loc,
#endif
#if API_UseLPTIM>0
(uint32_t)&API_LPTIM_Init,
#else
(uint32_t)API_LPTIM_Loc,//如果不用于占位
#endif
#if API_UseRTC>0
(uint32_t)&API_RTC_Init,
(uint32_t)&API_GetTime,
(uint32_t)&API_SetTIME,
#else
(uint32_t)API_RTC_Init_Loc,//如果不用于占位
(uint32_t)API_GetTime_Loc,
(uint32_t)API_SetTIME_Loc,
#endif
#if API_UseUart>0
(uint32_t)&API_Uartx_Init,
(uint32_t)&API_Uart_Send,
#else
(uint32_t)API_Uart_Init_Loc,//如果不用于占位
(uint32_t)API_Uart_Send_Loc,
#endif
#if API_UseLPUart>0
(uint32_t)&API_LPUart_Init,
(uint32_t)&API_LPUart_Send,
#else
(uint32_t)API_LPUart_Init_Loc,//如果不用于占位
(uint32_t)API_LPUart_Send_Loc,
#endif
#if API_UseDataUp>0
(uint32_t)&API_UpData,
#else
(uint32_t)API_UpData_Loc,
#endif
#if API_UseNB>0
(uint32_t)&API_NB_Init,
(uint32_t)&API_NB_Link,
(uint32_t)&API_NB_Connect,
(uint32_t)&API_NB_UartRx,
(uint32_t)&API_NB_UartTx,
(uint32_t)&API_NB_Clock,
(uint32_t)&API_NB_End,
(uint32_t)&API_NB_RxData,
#else
(uint32_t)API_NB_Init_Loc,
(uint32_t)API_NB_Link_Loc,
(uint32_t)API_NB_Connect_Loc,
(uint32_t)API_NB_UartRx_Loc,
(uint32_t)API_NB_UartTx_Loc,
(uint32_t)API_NB_Clock_Loc,
(uint32_t)API_NB_End_Loc,
(uint32_t)API_NB_RXDATA_Loc,
#endif
#if API_UseLCD>0
(uint32_t)&API_Init_LCD,
#else
(uint32_t)API_LCD_Loc,
#endif
#if API_UseAES>0
(uint32_t)&API_AES,
#else
(uint32_t)API_AES_Loc,
#endif
#if API_UseIIC>0
(uint32_t)&G_I2C_Read_Contin_Step,
(uint32_t)&G_I2C_Write_Contin_Step,
#else
(uint32_t)API_I2C_Read_Com_Loc,//如果不用于占位
(uint32_t)API_I2C_Write_Com_Loc,
#endif
(uint32_t)99
};
/*----------------------------------------------------------------------
//固化SYS函数表,不可更改
-----------------------------------------------------------------------*/
const uint32_t sys_table[] __attribute__((section(".ARM.__at_0x00000950"))) =
{
(uint32_t)&TicksDelayMs,
(uint32_t)&TicksDelayUs,
(uint32_t)&AnalogIO,
(uint32_t)&InputtIO,
(uint32_t)&OutputIO,
(uint32_t)&AltFunIO,
(uint32_t)&CloseeIO,
(uint32_t)&Init_System,
(uint32_t)&Sleep,
(uint32_t)&RchfAdjust
};
#endif
然后定义好函数指针,在APP中使用,方法如下
/*在APP中调用固化在boot中的函数*/
#if API_UseIIC>0
void API_I2C_Init(void)
{
api_iicinit iic=(void (*)(void))(table_base[API_I2C_Init_Loc] | 0x1);
iic();
}
uint08 API_EEPROM_Read(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len)
{
api_iicop iicrd=(uint08 (*)(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len))(table_base[API_I2C_Read_Loc] | 0x1);
return iicrd(Device,Addr,AddrLen,Buf,Len);
}
uint08 API_EEPROM_Write(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len)
{
api_iicop iicwt=(uint08 (*)(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len))(table_base[API_I2C_Write_Loc] | 0x1);
return iicwt(Device,Addr,AddrLen,Buf,Len);
}
uint08 API_I2C_Read_Com(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len)
{
api_iicop iicrd=(uint08 (*)(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len))(table_base[API_I2C_Read_Com_Loc] | 0x1);
return iicrd(Device,Addr,AddrLen,Buf,Len);
}
uint08 API_I2C_Write_Com(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len)
{
api_iicop iicwt=(uint08 (*)(uint08 Device, uint16 Addr, uint08 AddrLen, uint08 *Buf, uint16 Len))(table_base[API_I2C_Write_Com_Loc] | 0x1);
return iicwt(Device,Addr,AddrLen,Buf,Len);
}
#endif
通过这种方式,原先APP需要50K左右的代码量,减少至20K,boot原先16K代码量增至进40K,如果不使用外挂Flash远程升级APP2,可以节约很多空间。