CH582 / CH592 OTA ,官方给出了例程,网上也有比较详细的说明,按步骤操作修改的话,基本上能顺利完成。
CH573 CH582 OTA例程讲解二(方式二:使用固定库+扩大APP程序空间)
这里我们先讲一下OTA的一些基本知识,弄懂这些后,我们不需要这些操作指引,也能快速的完成OTA的设置,并可以根据自己的实际需求灵活修改。而且一旦弄明白OTA的原理,其它MCU的在线升级也一样可以快速实现。
1、Firmware不能对自身进行在线升级,原因主要是Flash的访问冲突。解决办法有2个,一是把在线升级需要运行的所有代码复制到RAM中,并在RAM中运行,这样进入升级后,所有的代码都在RAM中,不会造成Flash访问的冲突;二是准备一段程序,专门用于在线升级,应用程序部分与在线升级部分程序分开。
第一种办法在20年前使用比较多,现在几乎淘汰了。CH582 / CH592 OTA就是使用的第二种办法。官方例程把整个Firmware分成4部分:Jump IAP,APP,IAP,LIB。我们在讲明白OTA的基本知识后,会适当的修改为3部分:APP,IAP,LIB。
2、我们已经知道,要实现OTA,Firmware至少要分成2部分,这两部分是相互独立的,我们可以理解为两个Firmware,为了区别,专门用于在线升级的部分我们用IAP表示,功能应用部分我们用APP表示。
原则上,MCU复位后,运行的是IAP,IAP判断是否需要OTA,如果需要OTA,那就运行IAP,等待更新APP;如果不需要OTA,程序跳转到APP起妈代码处,运行APP。
从上述说明中,我们知道IAP与我们开发的不带OTA的Firmware几乎是一样,只是IAP的功能只是用来对APP进行升级的。而APP则有所不同,因为APP的代码起始地址不是0000。这就要求我们开发的时候需要指定APP的代码起始地址。
3、通常情况下,我们明白上述2点就可以完成在线升级的开发。但CH582 / CH592 OTA,还需要再弄明白一点:IAP和APP有大量共用的代码,也就是BLE的库,这部分代码占用了150K以上的空间,IAP和APP如果使用独立的库,那就意味着300多K的Flash空间被BLE库占用。而象CH591系列及CH581系列只有192K的Flash,根据就没有办法实现OTA。所以我们需要把BLE库单独放在某个区域,让IAP和APP都能访问。我们需要告诉IAP、APP,BLE库的地址,并且在link的时候,不要把BLE库包含进去,从而大大节省Flash空间。
升级的时候也只是对APP进行升级,而库不升级。
这样根据前面讲述的3点,CH582 / CH592 OTA,Firmware分为3部分:IAP、APP、BLE LIB。(对很多通用MCU来说,在线升级只需要IAP、APP两部分)
接下来我们用CH592F及CH591F来实例说明OTA的修改及设置。
首先我们对官方例程OnlyUpdateApp_IAP作一定的修改,修改后,我们不再需要Jump IAP。
J 0x40000,是跳转到LIB中的程序段执行相应的程序。如果你用的库的起始地址不是0x40000,要修改为与库对应的值。
ota.h文件中,IMAGE_A_START_ADD是APP存放的Flash中的起始地址,大家可以根据自己的情况作出调整。
这里也提一下对OnlyUpdateApp_IAP工程的设置的修改,OnlyUpdateApp_IAP是官方提供的例程,正常情况下是不需要修改的,但如果用的是CH581及CH591系列的芯片,则必须修改相应的设置。
其中 CH59xBLE_ROM=1,告诉编译器,我们的Firmware使用的BLE LIB 不包含在Firmware中,而是存放在固定位置,而 LIB_FLASH_BASE_ADDRESSS=0x00040000,告诉编译器,BLE LIB存放在起始地址0x40000的Flash区域。这个地址不能随意修改,我们的LIB的起始地址是多少就必须是多少,比如CH591系列芯片,因为Flash的大小只有192K,所以我们只能用只包含外设功能的LIB(CH59xBLE_ROM_PERI.hex),这个库大小144K,库的起始地址0x0C000,所以如果您使用的是CH591系列的芯片,这里应该修改为:LIB_FLASH_BASE_ADDRESSS=0x000C000。同时,startup_CH592.S文件中最后的指令也要修改为:
其次,我们需要对自己开发完成的APP工程作类似的修改:
在link.ld文件中,搜索__global_pointer ,把原文中的 PROVIDE( __global_pointer$ = . + 0x800 );删除,修改成上图中所示值。目的应该是预留8K的RAM给LIB使用。
我们的APP的起始地址修改为0x4000,当然大家可以根据自己的情况作出调整。
同样,如果用的是CH591系列的芯片,这里也应该修改为J 0x0C000。
接下来,也要对APP的工程文件作对应的修改:
最后,我们需要增加进入OTA模式的程序代码,这个大家可以根据自己的情况来实现。
这里我们提供的一个实例是上位机通过发送相应的命令(其实就是一串字符)来进入OTA模式。
/*********************************************************************
* @fn simpleProfileChangeCB
*
* @brief Callback from SimpleBLEProfile indicating a value change
*
* @param paramID - parameter ID of the value that was changed.
* pValue - pointer to data that was changed
* len - length of data
*
* @return none
*/
void Jump_OTA(void);
static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len)
{
switch(paramID)
{
case SIMPLEPROFILE_CHAR1:
{
uint8_t newValue[SIMPLEPROFILE_CHAR1_LEN];
tmos_memcpy(newValue, pValue, len);
if (tmos_memcmp(newValue, "Update", len))
{
mDelaymS(5);
Jump_OTA();
}
// PRINT("profile ChangeCB CHAR1.. \n");
break;
}
#if 0
case SIMPLEPROFILE_CHAR3:
{
uint8_t newValue[SIMPLEPROFILE_CHAR3_LEN];
tmos_memcpy(newValue, pValue, len);
PRINT("profile ChangeCB CHAR3..\n");
break;
}
#endif
default:
// should not reach here!
break;
}
}
/* OTA 升级标志 */
#define IMAGE_OTA_FLAG 0x03
/* 存放在DataFlash地址,不能占用蓝牙的位置 */
#define OTA_DATAFLASH_ADD 0x00077000 - FLASH_ROM_MAX_SIZE
/* flash的数据临时存储 */
__attribute__((aligned(8))) uint8_t block_buf[16];
/*********************************************************************
* @fn Jump_OTA
*
* @brief 跳转OTA升级
*
* @return none
*/
void Jump_OTA(void)
{
uint16_t i;
uint32_t ver_flag;
/* 读取第一块 */
EEPROM_READ(OTA_DATAFLASH_ADD, (uint32_t *)&block_buf[0], 4);
/* 擦除第一块 */
EEPROM_ERASE(OTA_DATAFLASH_ADD, EEPROM_PAGE_SIZE);
/* 更新Image信息 */
block_buf[0] = IMAGE_OTA_FLAG;
/* 编程DataFlash */
EEPROM_WRITE(OTA_DATAFLASH_ADD, (uint32_t *)&block_buf[0], 4);
/* 软复位 */
SYS_ResetExecute();
}
当然你也可以通过按键或RF等方式来实现进入OTA模式。
至此,我们就完成了OTA的所有代码修改及工程设置,接下来只需要把我们得到的文件整合到一起并烧录到目标板上,就可以享受OTA升级方式了。
第一个文件是IAP,第二个是我们自己的APP ,第三个是LIB。