mysql 移植ucos_基于STM32F767的UCOSIII移植学习
(一)移植前的準備
1.HAL庫基本工程模板
新建一個工程模塊,其中包含LED驅動和串口驅動程序即可,用于驗證UCOS-III系統(tǒng)能夠正常工作。
2.UCOS-III源碼準備
去Micrium官網(wǎng)下載最新的UCOSIII源碼,下載地址:Micrium官網(wǎng)下載地址,沒有注冊過的用戶需要注冊一下,我自己注冊的過程都是淚。由于我選擇的是正點原子F7的開發(fā)板,所以在官網(wǎng)上選擇合適源碼時就選擇F7的。具體版本選擇下圖中19年2月6號的版本:
下載完成之后發(fā)現(xiàn),發(fā)現(xiàn)源碼文件夾中東西很多大部分都是和網(wǎng)絡移植相關的,目前我們只移植最新版本的UCOSIII,所以這些文件夾都不需要去看。進入源碼目錄下的uCOS-III文件夾,發(fā)現(xiàn)里面只有針對IAR的編譯器的文件,難道MDK就涼涼了嗎?凡是先不要慌,雖然編譯器不同,但是實現(xiàn)的功能就是相同的,并不會影響到移植后操作系統(tǒng)的運行。
UCOSIII的移植
(一)源碼文件的摘選
1.在準備好的工程文件夾下新建一個UCOS-III目錄,用于存放和UCOSIII相關的所有代碼。在UCOS-III目錄下新建如下目錄,用于UCOS源碼的分類。
(1)將源碼目錄Micrium_STM32F746G-DISCO_Crypto\Micrium\Software\uC-CPU下的文件全部拷貝到我們創(chuàng)建的uC-CPU目錄下,為了減少文件夾的個數(shù),我把ARM-Cortex-M\ARMv7-M目錄下和ARM-Cortex-M\ARMv7-M\ARM目錄下的文件都移到了自己創(chuàng)建的uC-CPU目錄下了。這里我要說明下一下IAR和ARM目錄下的文件,除了匯編文件有些不同以外,頭文件內容都是相同的,這邊選擇ARM目錄下的匯編文件還是IAR目錄下的匯編文件都行,因為我們都是要修改成MDK支持的形式的。
(2)將源碼目錄Micrium_STM32F746G-DISCO_Crypto\Micrium\Software\uC-LIB文件夾下的文件全部拷貝到自己創(chuàng)建的uC-LIB目錄下,這邊我直接把Micrium\Software\uC-LIB\Ports\ARM-Cortex-M4\RealView目錄下的文件和其他文件放在了一個文件夾下,具體如下圖所示:
由于我們使用的是MDK編譯,所以這邊選擇的是RealView目錄下的匯編文件,具體什么原因的話,網(wǎng)上有很多解釋,我就不復制他們的解釋了。
(3)將Micrium_STM32F746G-DISCO_Crypto\Micrium\Software\uCOS-III目錄下的文件全部拷貝到自己創(chuàng)建uCOS-III目錄下。點開Ports的目錄,發(fā)現(xiàn)最后只有一個IAR文件下,這邊我們先不用關注,只需將文件都拷貝過來,具體內容如下圖所示:
(4)將源碼例程目錄Micrium_STM32F746G-DISCO_Crypto\ST\STM32F746G_Disco\Crypto下的部分文件和OS3下的部分文件拷貝到自己創(chuàng)建的UCOS-CONFIG文件夾下。具體文件如下圖所示:
在源碼例程文件中,發(fā)現(xiàn)很多都是網(wǎng)絡相關的移植代碼,所以沒有拷貝過來。但是有一個clk_cfg.h很明顯不是和網(wǎng)絡相關的,為什么不移植過來呢?從名字上看就是和時鐘相關的,難道說不需要時鐘配置嗎?時鐘當然是需要配置的,但是裸機工程中時鐘已經(jīng)配置OK了,這邊和時鐘相關的文件也就不需要了,后面操作系統(tǒng)的時鐘需要自己通過HAL庫配置,這邊就不詳細說明了。
(5)將Micrium_STM32F746G-DISCO_Crypto\ST\BSP\STM32F746G_Disco目錄下的bsp_cpu.c文件拷貝到自己創(chuàng)建的UCOS-BSP目錄下,并且新建一個bsp_cpu.h頭文件(用于包含操作系統(tǒng)的頭文件)。其他文件都不需要拷貝,大多是和芯片外設相關的初始化。
(二)文件添加
(1)打開MDK工程,將拷貝的文件添加至工程當中,具體內容如下圖所示:
以及頭文件路徑添加,如下圖所示:
上述文件都添加完成之后,點擊編譯,提示下圖錯誤:
出現(xiàn)unknown opcode什么的錯誤,而且出現(xiàn)在os_cpu_a.asm文件中,那就打開這個匯編文件看一下,是什么問題,發(fā)現(xiàn)PUBLIC關鍵字都沒有標藍,那肯定是由于這個關鍵字不是MDK的關鍵字,所以講PUBLIC修改為MDK所用的關鍵字EXPORT,具體EXPORT這個關鍵字怎么來的,我是查看了其他版本的UCOS在STM32的移植,看到用的是這個關鍵字,就直接抄過來了。還有錯誤與FPU相關,如下圖所示:
#ifdef __ARMVFP__
EXPORT OS_CPU_FP_Reg_Push
EXPORT OS_CPU_FP_Reg_Pop
#endif
查看了正點原子的移植手冊,發(fā)現(xiàn)上面說到
Cortex-M7內核中有個Lazy Stacking的功能,如果使用FPU功能的話就需要關閉這個功能,需要修改startup_stm32f767xx.s匯編文件,在里面關閉這個功能。
具體代碼如下所示:
IF {FPU} != "SoftVFP"
; Enable Floating Point Support at reset for FPU
LDR.W R0, =0xE000ED88 ; Load address of CPACR register
LDR R1, [R0] ; Read value at CPACR
ORR R1, R1, #(0xF <<20) ; Set bits 20-23 to enable CP10 and CP11 coprocessors
; Write back the modified CPACR value
STR R1, [R0] ; Wait for store to complete
DSB
; Disable automatic FP register content
; Disable lazy context switch
LDR.W R0, =0xE000EF34 ; Load address to FPCCR register
LDR R1, [R0]
AND R1, R1, #(0x3FFFFFFF) ; Clear the LSPEN and ASPEN bits
STR R1, [R0]
ISB ; Reset pipeline now the FPU is enabled
ENDIF
在startup_stm32f767xx.s中就如下圖所示:
修改完這些,接下去就解決… error: A1163E: Unknown opcode ARMVFP , expecting opcode or Macro 這個錯誤。將原先的判斷語句修改為如下語句:
IF {FPU} != "SoftVFP"
EXPORT OS_CPU_FP_Reg_Push
EXPORT OS_CPU_FP_Reg_Pop
ENDIF
IF {FPU} != "SoftVFP"
OS_CPU_FP_Reg_Push
MRS R1, PSP ; PSP is process stack pointer
CBZ R1, OS_CPU_FP_nosave ; Skip FP register save the first time
VSTMDB R0!, {S16-S31}
LDR R1, =OSTCBCurPtr
LDR R2, [R1]
STR R0, [R2]
OS_CPU_FP_nosave
BX LR
ENDIF
IF {FPU} != "SoftVFP"
OS_CPU_FP_Reg_Pop
VLDMIA R0!, {S16-S31}
LDR R1, =OSTCBHighRdyPtr
LDR R2, [R1]
STR R0, [R2]
BX LR
ENDIF
修改完成之后,再次編譯,依舊存在 error: A1163E: Unknown opcode RSEG , expecting opcode or Macro 的錯誤,這主要是由于編譯器關鍵字的問題,所以這里直接借鑒其他其他版本在MDK上的移植。具體修改代碼如下:
PRESERVE8
THUMB
AREA CODE, CODE, READONLY
再次編譯,發(fā)現(xiàn)這個匯編文件中還有一個警告: warning: A1581W: Added 2 bytes of padding at address 0x112,這是提示地址沒對齊,那就在末尾添加一個對齊指令,具體代碼如下:
OS_CPU_PendSVHandler
CPSID I ; Cortex-M7 errata notice. See Note #5
MOV32 R2, OS_KA_BASEPRI_Boundary ; Set BASEPRI priority level required for exception preemption
LDR R1, [R2]
MSR BASEPRI, R1
DSB
ISB
CPSIE I
MRS R0, PSP ; PSP is process stack pointer
STMFD R0!, {R4-R11, R14} ; Save remaining regs r4-11, R14 on process stack
MOV32 R5, OSTCBCurPtr ; OSTCBCurPtr->StkPtr = SP;
LDR R1, [R5]
STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been saved
MOV R4, LR ; Save LR exc_return value
BL OSTaskSwHook ; Call OSTaskSwHook() for FPU Push & Pop
MOV32 R0, OSPrioCur ; OSPrioCur = OSPrioHighRdy;
MOV32 R1, OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
MOV32 R1, OSTCBHighRdyPtr ; OSTCBCurPtr = OSTCBHighRdyPtr;
LDR R2, [R1]
STR R2, [R5]
ORR LR, R4, #0x04 ; Ensure exception return uses process stack
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
LDMFD R0!, {R4-R11, R14} ; Restore r4-11, R14 from new process stack
MSR PSP, R0 ; Load PSP with new process SP
MOV32 R2, #0 ; Restore BASEPRI priority level to 0
MSR BASEPRI, R2
BX LR ; Exception return will restore remaining context
ALIGN
END
再次編譯,os_cpu_a.asm文件內沒有錯誤,還有兩個小錯誤:
將os_cpu_c.c中os.h的頭文件路徑修改意見,將bsp_cpu.c中的bsp_clk.h頭文件注釋掉,再次編譯。報錯信息如下圖:
發(fā)現(xiàn)報錯信息都在bsp_cpu.c當中,而且都是和時鐘頻率相關的,打開源碼例程中的bsp_clk.c文件,查看BSP_ClkFreqGet()函數(shù),發(fā)現(xiàn)里面調用的函數(shù)不就是HAL庫提供的嗎,那我們直接將bsp_cpu.c中的時鐘獲取函數(shù)修改為HAL庫提供的函數(shù),不就OK了嗎。修改后的代碼如下所示:
#if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
void CPU_TS_TmrInit (void)
{
CPU_INT32U fclk_freq;
CPU_INT32U reg_val;
/* ---- DWT WRITE ACCESS UNLOCK (CORTEX-M7 ONLY!!) ---- */
reg_val = CPU_BSP_REG_DWT_LSR; /* Read lock status register. */
if ((reg_val & CPU_BSP_BIT_DWT_LSR_SLI) != 0) { /* Check if Software lock control mechanism exits */
if ((reg_val & CPU_BSP_BIT_DWT_LSR_SLK) != 0) { /* Check if DWT access needs to be unlocked */
CPU_BSP_REG_DWT_LAR = CPU_BSP_DWT_LAR_KEY; /* Unlock DWT write access. */
}
}
fclk_freq = HAL_RCC_GetHCLKFreq();
CPU_BSP_REG_DEMCR |= DEF_BIT_24; /* Set DEM_CR_TRCENA */
CPU_BSP_REG_DWT_CR |= DEF_BIT_00; /* Set DWT_CR_CYCCNTENA */
CPU_TS_TmrFreqSet((CPU_TS_TMR_FREQ)fclk_freq);
}
#endif
#if (CPU_CFG_TS_32_EN == DEF_ENABLED)
CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts)
{
CPU_INT64U ts_us;
CPU_INT64U fclk_freq;
fclk_freq = HAL_RCC_GetHCLKFreq();
ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
return (ts_us);
}
#endif
#if (CPU_CFG_TS_64_EN == DEF_ENABLED)
CPU_INT64U CPU_TS64_to_uSec (CPU_TS64 ts_cnts)
{
CPU_INT64U ts_us;
CPU_INT64U fclk_freq;
fclk_freq = HAL_RCC_GetHCLKFreq();
ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
return (ts_us);
}
#endif
修改完之后,再次編譯,發(fā)現(xiàn)了很多重復定義的錯誤,都適合__dbg_ucos-iii.c文件相關,那就直接移除掉這個文件,再編譯看看結果如何。
編譯之后發(fā)現(xiàn)只有一個未定義的錯誤,打開os_cpu.h頭文件,發(fā)現(xiàn)了下面這行代碼:
#define OS_TASK_SW_SYNC() __ISB()
明明定義了,卻還是提示未定義的錯誤,那我搜索了一下__ISB()函數(shù),在cmsis_armcc.h中明確定義了,難道沒添加頭文件引起的嗎,那就添加頭文件再編譯一下,報錯信息更多了,那很明顯不是這個問題了。看到cmsis_armcc.h中有這一行代碼:
#define __ISB() do {\
__schedule_barrier();\
__isb(0xF);\
__schedule_barrier();\
} while (0U)
那就直接修改成
#define OS_TASK_SW_SYNC() __isb(0xF)
這樣編譯倒是沒問題了。但是系統(tǒng)運行起來有沒有問題就不知道,先這么做吧,這個頭文件中還有一行代碼也需要修改:
#ifdef__ARMVFP__
#define OS_CPU_ARM_FP_EN 1u
#else
#define OS_CPU_ARM_FP_EN 0u
#endif
修改為
#ifdef __TARGET_FPU_SOFTVFP
#define OS_CPU_ARM_FP_EN 1u
#else
#define OS_CPU_ARM_FP_EN 0u
#endif
編譯后無錯誤。現(xiàn)在這系統(tǒng)能夠正常運行起來了嗎?講實話我也不太清楚,那就測試一下吧。
(三)測試系統(tǒng)
拷貝如下代碼至main.c中。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "bsp_cpu.h"
//任務優(yōu)先級
#define START_TASK_PRIO2
//任務堆棧大小
#define START_STK_SIZE 512
//任務控制塊
OS_TCB StartTaskTCB;
//任務堆棧
CPU_STK START_TASK_STK[START_STK_SIZE];
//任務函數(shù)
void start_task(void *p_arg);
//任務優(yōu)先級
#define LED0_TASK_PRIO3
//任務堆棧大小
#define LED0_STK_SIZE 128
//任務控制塊
OS_TCB Led0TaskTCB;
//任務堆棧
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];
void led0_task(void *p_arg);
//任務優(yōu)先級
#define LED1_TASK_PRIO4
//任務堆棧大小
#define LED1_STK_SIZE 128
//任務控制塊
OS_TCB Led1TaskTCB;
//任務堆棧
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
//任務函數(shù)
void led1_task(void *p_arg);
//任務優(yōu)先級
#define FLOAT_TASK_PRIO5
//任務堆棧大小
#define FLOAT_STK_SIZE256
//任務控制塊
OS_TCBFloatTaskTCB;
//任務堆棧
CPU_STKFLOAT_TASK_STK[FLOAT_STK_SIZE];
//任務函數(shù)
void float_task(void *p_arg);
/*****************************************************************************************************************************************
* Function Name: main
* Input: None
* Output: None
* Returns: None
* Description: 主函數(shù)
* Note: None
*****************************************************************************************************************************************/
int main(void)
{
OS_ERR err;
CPU_SR_ALLOC();
HW_Init();
MT_Init();
OSInit(&err); //初始化UCOSIII
CPU_CRITICAL_ENTER(); //進入臨界區(qū)
//創(chuàng)建開始任務
OSTaskCreate((OS_TCB * )&StartTaskTCB,//任務控制塊
(CPU_CHAR* )"start task", //任務名字
(OS_TASK_PTR )start_task, //任務函數(shù)
(void* )0,//傳遞給任務函數(shù)的參數(shù)
(OS_PRIO )START_TASK_PRIO, //任務優(yōu)先級
(CPU_STK * )&START_TASK_STK[0],//任務堆棧基地址
(CPU_STK_SIZE)START_STK_SIZE/10,//任務堆棧深度限位
(CPU_STK_SIZE)START_STK_SIZE,//任務堆棧大小
(OS_MSG_QTY )0,//任務內部消息隊列能夠接收的最大消息數(shù)目,為0時禁止接收消息
(OS_TICK )0,//當使能時間片輪轉時的時間片長度,為0時為默認長度,
(void * )0,//用戶補充的存儲區(qū)
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR|OS_OPT_TASK_SAVE_FP, //任務選項,為了保險起見,所有任務都保存浮點寄存器的值
(OS_ERR * )&err);//存放該函數(shù)錯誤時的返回值
CPU_CRITICAL_EXIT();//退出臨界區(qū)
OSStart(&err); //開啟UCOSIII
while(1)
{
}
}
//開始任務函數(shù)
void start_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;
CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); //統(tǒng)計任務
#endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN//如果使能了測量中斷關閉時間
CPU_IntDisMeasMaxCurReset();
#endif
#ifOS_CFG_SCHED_ROUND_ROBIN_EN//當使用時間片輪轉的時候
//使能時間片輪轉調度功能,設置默認的時間片長度s
OSSchedRoundRobinCfg(DEF_ENABLED,10,&err);
#endif
CPU_CRITICAL_ENTER();//進入臨界區(qū)
//創(chuàng)建LED0任務
OSTaskCreate((OS_TCB * )&Led0TaskTCB,
(CPU_CHAR* )"led0 task",
(OS_TASK_PTR )led0_task,
(void* )0,
(OS_PRIO )LED0_TASK_PRIO,
(CPU_STK * )&LED0_TASK_STK[0],
(CPU_STK_SIZE)LED0_STK_SIZE/10,
(CPU_STK_SIZE)LED0_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR|OS_OPT_TASK_SAVE_FP,
(OS_ERR * )&err);
//創(chuàng)建LED1任務
OSTaskCreate((OS_TCB * )&Led1TaskTCB,
(CPU_CHAR* )"led1 task",
(OS_TASK_PTR )led1_task,
(void* )0,
(OS_PRIO )LED1_TASK_PRIO,
(CPU_STK * )&LED1_TASK_STK[0],
(CPU_STK_SIZE)LED1_STK_SIZE/10,
(CPU_STK_SIZE)LED1_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR|OS_OPT_TASK_SAVE_FP,
(OS_ERR * )&err);
//創(chuàng)建浮點測試任務
OSTaskCreate((OS_TCB * )&FloatTaskTCB,
(CPU_CHAR* )"float test task",
(OS_TASK_PTR )float_task,
(void* )0,
(OS_PRIO )FLOAT_TASK_PRIO,
(CPU_STK * )&FLOAT_TASK_STK[0],
(CPU_STK_SIZE)FLOAT_STK_SIZE/10,
(CPU_STK_SIZE)FLOAT_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR|OS_OPT_TASK_SAVE_FP,
(OS_ERR * )&err);
CPU_CRITICAL_EXIT();//進入臨界區(qū)
OSTaskSuspend((OS_TCB*)&StartTaskTCB,&err);//掛起開始任務
}
//led0任務函數(shù)
void led0_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
HW_Led0_On(); //LED0打開
OSTimeDlyHMSM(0,0,0,200,OS_OPT_TIME_HMSM_STRICT,&err); //延時200ms
HW_Led0_Off(); //LED0關閉
OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_HMSM_STRICT,&err); //延時500ms
}
}
//led1任務函數(shù)
void led1_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
HW_Led1_On();
HW_Delay_ms(500);//延時500ms
HW_Led1_Off();
HW_Delay_ms(500);
OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_HMSM_STRICT,&err);
}
}
//浮點測試任務
void float_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
static double double_num=0.00;
while(1)
{
double_num+=0.01f;
CPU_CRITICAL_ENTER();//進入臨界區(qū)
printf("double_num的值為: %.4f\r\n",double_num);
CPU_CRITICAL_EXIT();//退出臨界區(qū)
OSTimeDlyHMSM(0,0,0,20,OS_OPT_TIME_HMSM_STRICT,&err);
}
}
編譯后,燒寫進開發(fā)板,查看現(xiàn)象:LED燈沒亮;那系統(tǒng)肯定沒有運行起來,通過Debug看看哪里出問題了,結果發(fā)現(xiàn)程序停在了如下地方:
那說明是PendSV中斷處理出了問題,看看整個工程中哪里需要調整。os_cpu_a.asm匯編文件中定義了OS_CPU_PendSVHandler函數(shù),這是Micrium官方移植例程中修改了PendSV中斷函數(shù)的名稱,所以這邊需要修改回來,然后再編譯報該函數(shù)的重定義錯誤。
這邊屏蔽掉stm32f7xx_it.c中的PendSV_Handler函數(shù)定義,再次編譯;沒有報錯,那就再下載驗證一下。結果還是失敗了,那就再Debug一下,看看是哪里的問題,發(fā)現(xiàn)程序運行之后,開始任務調度之后就掛在空閑任務上。找來找去沒發(fā)現(xiàn)什么問題,本來都準備放棄了,后來看到操作系統(tǒng)的時間都是通過滴答定時器中斷產生的,然后仔細看了一下代碼,雖然使用了滴答定時器,但是沒有使用中斷,那趕緊加上試試,順便將stm32f7xx_it.h中定義的滴答定時器中斷函數(shù)屏蔽掉。編譯之后沒報錯,那就在測試一下。終于,LED燈如愿的閃爍起來 ,串口也正常工作起來了,說明操作系統(tǒng)真正運行起來了。
下面附上移植后的工程。
鏈接:https://pan.baidu.com/s/1AGw1SWNMI_BpX7NLsxvQdg
提取碼:bzne
復制這段內容后打開百度網(wǎng)盤手機App,操作更方便哦
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結
以上是生活随笔為你收集整理的mysql 移植ucos_基于STM32F767的UCOSIII移植学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: word删除所有的回车、空格
- 下一篇: 米家电磁炉显示e10_米家电磁炉e10故