目标:实现类似于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