单片机实现动态加代码探索01

2019-04-15 18:33发布

目标:实现类似于linux运行起来后,然后可以动态从其他地方拷贝一个可执行程序led来闪灯的功能 硬件平台:NUCLEO-f767ZI 思路:如题则需要两个.bin文件一个时os,一个是led.bin。但是单独编译led.bin是一个大问题,这里通过其他方法避过此问题。 首先采用freertos创建两个任务,一个闪烁led2,一个执行通讯任务。在建一个通过串口命令来启动删除的led3任务,并且将led3任务函数强制指定到0x81c0000(以下称addr1).然后我们将addr1处的.bin拷贝到0x8180000(以下称addr2)。当然也可以通过串口先把addr1出的led.bin上传至PC,然后下载至addr2,问题核心依旧回归何得到led.bin 1.comm.c #include "FreeRTOS.h" #include "task.h" #include "cmsis_os.h" #include "Comm.h" #include "usart.h" #include "string.h" #include "myAc.h" #include "my.h" #include "flash.h" #define RX_BUF_SIZE 1024 char RxBuffer[RX_BUF_SIZE]; uint16_t Rx_p=0; uint8_t frame_sta=0; void ReviceData(uint8_t a) { if(frame_sta==0) { if(Rx_pnum!=2){ Ac_pf("Parameter error "); FreeStringList(list); return; } if(0==strcmp(list->d[1],"0")){ LD2_sta=LD_OFF; } else if(0==strcmp(list->d[1],"1")){ LD2_sta=LD_ON; } else if(0==strcmp(list->d[1],"2")){ LD2_sta=LD_TWINKLE; } else{ Ac_pf("Parameter error "); } FreeStringList(list); } void loadstart_pro(char *a) { //预留 下载LED.bin启动信号 } void loadstop_pro(char *a) { //预留 下载LED.bin结束信号 } #include "app.h" osThreadId myTaskStartHandle; void (*TaskApp)(void const * argument); uint8_t parameters=0; void creattask_pro(char *a) { if(parameters==0) { //TaskApp=StartTaskApp; TaskApp = (void(*)(void const * ))(ADDR_FLASH_SECTOR_11); } else { TaskApp = (void(*)(void const * ))(ADDR_FLASH_SECTOR_10); //TaskApp=StartTaskApp; } osThreadDef(myTaskApp, TaskApp, osPriorityNormal, 0, 128); myTaskStartHandle = osThreadCreate(osThread(myTaskApp), ¶meters); Ac_pf("taskHandle=0x%07x ",(uint32_t)myTaskStartHandle); } void deltask_pro(char *a) { vTaskDelete(myTaskStartHandle); } void changeAppAddr(char *a) { _stringList *list; list = mtStrDiv(RxBuffer," "); if(list==NULL){ Ac_pf("err! HEAP full "); return ; } if(list->num!=2){ Ac_pf("Parameter error "); FreeStringList(list); return; } if(0==strcmp(list->d[1],"0")){ parameters=0; Ac_pf("APPFUN=0x%07x ",StartTaskApp); } else if(0==strcmp(list->d[1],"1")){ parameters=1; Ac_pf("APPFUN=0x%07x ",ADDR_FLASH_SECTOR_10); } else{ Ac_pf("Parameter error "); } FreeStringList(list); } void moveFun(char *a) { a=a; EraseAppRopm(); ReadAppRoom(); MoveAppRoom(); } /* */ _msg msgList[]= { {0,"LED_sta",2,LED_sta_pro}, {1,"loadstart",1,loadstart_pro}, {2,"loadstop",1,loadstop_pro}, {3,"creattask",1,creattask_pro}, {4,"deltask",1,deltask_pro}, {5,"changeApp",2,changeAppAddr}, {6,"moveApp",2,moveFun}, }; void CommTask() { uint8_t i; char *a; UART3_Callback=ReviceData; Rx_p=0; frame_sta = 0; while(1) { osDelay(50); if(frame_sta==1) { if(RxBuffer[Rx_p-1]==' ')RxBuffer[Rx_p-1]=0; if(RxBuffer[Rx_p-2]==' ')RxBuffer[Rx_p-2]=0; for(i=0;i 2.app.c #include "FreeRTOS.h" #include "task.h" #include "cmsis_os.h" #include "main.h" #include "gpio.h" /* */ osStatus (*mydelay)(uint32_t)=NULL; /* 从rtos系统创建任意任意flash地址的任务完全可行 但是 任务程序要使用其他函数就会出问题 实际反汇编表现为 BL.W (addr) ,其中addr并不是想要调用的函数入口地址 最终导致HardFault_Handler 通过函数指针引用可以解决上述问题 */ void StartTaskApp(void const * argument) { uint16_t ms=0; mydelay = (osStatus (*)(uint32_t))(osDelay); if(*(uint8_t*)argument==0)ms=200; else if(*(uint8_t*)argument==1)ms=1000; for(;;) { mydelay(ms);//直接调用osDelay 会变为 BL.W 后面的操作数不正确 //HAL_GPIO_TogglePin(LD3_GPIO_Port,LD3_Pin);//BL.W 死掉 GPIOB->ODR ^= GPIO_PIN_14; } } 使用说明 使用步骤建议
1.先串口发送 "LED_sta 2/r/n"使得LED2闪烁  指示运行状态
2."moveApp "  从0x81c0000拷贝LED3.bin到0x8180000  led2会暂定闪烁
3."changeApp 0 " LED3任务指向0x81c0000
4."creattask " 运行0x81c0000处的LED3 快速闪烁
5."deltask " 删除LED3任务
6."changeApp 1 " LED3任务指向0x8180000
7."creattask " 运行0x8180000处的LED3 慢速闪烁
8."deltask " 删除LED3任务   贴几张反汇编图片 先来错误的 再来正确的   最后来说说单独编译led.bin的问题 1.os调用led.bin还是很简单的,只要知道其地址即可,但是led.bin要调用os函数就比较难搞了,出问题的地方上文有说明,,os一旦发生变化,它的各个杉树地址大多会有变化,led.bin就要跟着变。那么如何才能方便的用呢,估计要自己定制编译器了。这也许就是Linux内核编译和驱动编译要用同一版本的原因。 源代码https://download.csdn.net/download/suxingtian/10678987