【 開始 】
今天移植CONTIKI NG內核調度,用上簡單事件驅動,先自報一下PC的環境:
1_> WINDOWS 7, 64bit
2_> IAR v7.7
3_> STM32F103vet6核心板
4_> CONTIKI NG源碼,推薦使用V4.6版本 ,V4.7以后,ARM-CMSIS是空的,可以到 https://github.com/ARM-software/CMSIS_5/releases 下載
第一步:
先下載contiki-NG源碼,並解壓后如下圖:

裁剪掉暫時不用文件,留下OS核心文件,如下圖:

第二步:
進入contiki_v4.7\examples內,只留下"hello-world"這個文件夾:

推介,用戶所有的應用工程都在examples里面,新建_stm32f10x及幾個備用文件夾:

碰到HK32F MM32F GD32F,都按照這個思路處理就好,這樣會比較精煉 簡潔。。。
第三步:
進入contiki_v4.7\os內,把一些高大上的,暫時又用不着的文件先裁剪掉,如下圖所示:


上圖的 “contiki-main.c” 也可裁剪掉的,因為在我們STM32單片機代碼中,有自己main.c文件;
剩下文件夾不要裁剪了,基本都是os核心了.后期都是按照工程實際要求,加入必要的
contiki_v4.7\os\lib或contiki_v4.7\os\dev的文件,也有可能用不上。。
第四步:
進入contiki_v4.7\arch內,裁剪掉"dev"這個文件夾 :

arch是用戶要實現的內容,倆個文件cpu和platform, 就是告訴我們,實現這倆文件后,可以快樂使用OS了
打開contiki_v4.7\arch\cpu目錄,也要裁剪掉一些暫時無用的文件:

arm是標准文件,留下CC2358是因為有一些系統必要的配置文件,可以復制或參考。。
我們進入ARM文件夾,如下圖:

這里要就說明一下,common 和 openocd我們暫時使不用的文件,但不打算裁剪掉它們.
打開CMSIS,會發現是空的,因為在github的contiki-ng-release-v4.7中,要鏈接到ARM軟件哪邊去下載了.......

我沒有去ARM哪邊下載CMSIS核心文件,打開已下載好的contiki-ng-release-v4.6,從里面提取現成的CMSIS.當然
也可以去STM32固件庫里去提取過來,基本套路都一樣。。
這樣CMSIS文件夾就有內容了,如下圖所示:

然后回到arch\cpu下,新建一個“stm32”文件,后放入一些與CPU相關文件,比如CPU的ADC IIC UART
這些庫函數(基於芯片手冊,官方STDP庫)。。。這樣contiki_v4.7\arch\cpu規划完成了。。

接下來打開contiki_v4.7\arch\platform,裁剪掉暫時不用的文件,如下圖:


新建一個“stm32”,就是我們的對應平台,主要放入一些類似,按鍵, LED, LCD等
實現函數,與硬件平台相關文件,(開發人員要實現的)。同理cc2538dk只是
參考信息,因OS要配備系統文件,會方便一點。
OK,今天就處理到這里,NG的源碼整理就是這些了,接下來就是移植進IAR跑STM32。
時間:2021-10-17
預准備好STM32官方的標准固件庫,或者基於固件庫的DEMO測試OK例程。
此時,要認真思考一下,如何將【標准固件庫】信息加入到CONTIKI中,最為合理。
第一步:
將官方一些固定的,基本不會改 變的,放在arch\cpu\stm32中,選擇STM32F10x_StdPeriph_Driver
內的inc, src就可以了,如下圖:

再提取STM32固件庫對IAR的啟動文件,也放在arch\cpu\stm32中,如下圖:

提取stm32f10x.h, system_stm32f10x.h, system_stm32f10x.c, 放在arch\cpu\stm32中:

以上就是提取STM32固件庫放到OS的CPU/STM32內的所有內容了,
將一些應用文件,平台上可能經常更改的放在\arch\platform\stm32里面,暫時把
stm32f10x_it.h, stm32f10x_it.c, stm32f10x_conf.h放進platform\stm32,下圖示:

以上就是提取STM32固件庫放到OS的platform/STM32內的所有內容。STM32固件庫不要了,
可以丟棄了。
第二步:
現在開始思考一些CONTIKI必要系統文件,一般從OS文件名可以大該看出,帶xx_conf的文件,
就是給用戶配置的文件;而帶xx_arch的,就是用戶自己實現的文件。一個配置文件和實現文件的過程。
(如果少這一步,很多OS功能無法正常使用,或者沒有真正使用CONTIKI進行工作)
因為第一次移植,我們會全部從CC2538里面進行提取。。后期自行進一步精簡。
先找到board.h contiki-conf.h platform.c,放入到arch\platform\stm32中

繼續從CC2538里面進行提取文件,這次去找clock.c cc2538-conf.h cc2538-def.h
將它們放入arch\cpu\stm32中,並改名為如下圖:

到此為止,contiki_v4.7\arch下的cpu和platform全部實現了,OS內CC2538已沒有價值,可以丟棄了。
第三步:
把contiki_v4.7\os下的contiki-main.c, 復制到contiki_v4.7\examples\_stm32f10x里面,
在_stm32f10x內建立基於STM32F的空項目:

打開IAR v7.x,點擊Project-->create new project...選擇Empty project:

取名為contiki並保存在contiki_v4.7\examples\_stm32f10x里面,如下圖:


(注:上圖中,請選擇Debug,后文會提及到原因)
簡單配置一下IAR,其他的暫時默認就好,可以后期再調整:


接下來就是在IAR建立對應的文件夾,加入對應的.H .C文件,I配置所有OS的工程路徑,
這個過程很無聊。。要有耐心。。不要錯心大意。。
第四步:
移植CONTIKI有三大部份:contiki_v4.7\os, contiki_v4.7\examples, contiki_v4.7\arch
還是比較簡單的,你會發現都是2個或3個文件夾事情,這個OS算是很精煉了。。。
先移植contiki_v4.7\os部份,移植了我認為要使用到的具體文件,如下圖:


這份contiki_v4.7\os全部移植完了,
接下來移植contiki_v4.7\arch部份,如下圖:

arch/platform部份,如下圖:

arch/examples部份,如下圖:

算是移植完了三大文件contiki_v4.7\os, contiki_v4.7\examples, contiki_v4.7\arch,
第五步:
先加入OS所有工程路經,改動一些C實現文件,IAR中進行編譯,出錯后再進行修正,
以下是IAR工程路經:
$PROJ_DIR$ $PROJ_DIR$\user $PROJ_DIR$\user\inc $PROJ_DIR$\user\src $PROJ_DIR$\user\dev $PROJ_DIR$\..\..\os $PROJ_DIR$\..\..\os\sys $PROJ_DIR$\..\..\os\lib $PROJ_DIR$\..\..\os\dev $PROJ_DIR$\..\..\arch $PROJ_DIR$\..\..\arch\cpu $PROJ_DIR$\..\..\arch\cpu\arm $PROJ_DIR$\..\..\arch\cpu\arm\CMSIS $PROJ_DIR$\..\..\arch\cpu\arm\cortex-m $PROJ_DIR$\..\..\arch\cpu\arm\cortex-m\cm3 $PROJ_DIR$\..\..\arch\cpu\stm32 $PROJ_DIR$\..\..\arch\cpu\stm32\inc $PROJ_DIR$\..\..\arch\cpu\stm32\src $PROJ_DIR$\..\..\arch\cpu\stm32\starup_iar $PROJ_DIR$\..\..\arch\platform $PROJ_DIR$\..\..\arch\platform\stm32 $PROJ_DIR$\..\..\examples $PROJ_DIR$\..\..\examples\hello-world $PROJ_DIR$\..\..\examples\_stm32f10x $PROJ_DIR$\..\..\examples\_stm32f10x\inc $PROJ_DIR$\..\..\examples\_stm32f10x\src $PROJ_DIR$\..\..\examples\_stm32f10x\dev
另外設置STM32的內存容量如下圖:

把examples\_stm32f10x下的contiki-main.c改為如下內容:
#include "contiki.h" #include "platform.h" #include <stdio.h> #include <stdint.h> /*---------------------------------主MAIN入口--------------------------------*/ void main (void) { platform_init_stage_one(); //platform-1 //rtimer_init(); //未實現功能 process_init(); process_start(&etimer_process, NULL); ctimer_init(); platform_init_stage_two(); //platform-2 platform_init_stage_three(); //platform-3 autostart_start(autostart_processes); //自動啟動 //process_start(&xx_xx, NULL); //手動啟動 /*---------------------------------主循環體----------------------------------*/ char ch; while(1){ do{ ch = process_run(); //runing } while(ch > 0); //platform_idle(); //sleep未實現功能 } }
把\arch\platform\stm32下的platform.c改為如下內容,后期進行補全:
#include "contiki.h" #include "lib/sensors.h" #include "sys/platform.h" #include <stdint.h> #include <string.h> #include <stdio.h> /*---------------------------------------------------------------------------*/ void platform_init_stage_one(void) { } /*---------------------------------------------------------------------------*/ void platform_init_stage_two() { } /*---------------------------------------------------------------------------*/ void platform_init_stage_three() { } /*---------------------------------------------------------------------------*/ void platform_idle() { }
然后第一次進行IAR編譯,收獲28個ERROR,找不到CC2538_XXX,把相關文件改為stm32_xxx


在arch\cpu\stm32下,補充rtimer-arch.h文件,這個系統配置之前漏了吧,改為如下:
/* * \file * Real-timer header file for stm32 * \author * lijian */ #ifndef RTIMER_ARCH_H_ #define RTIMER_ARCH_H_ //#define RTIMER_ARCH_RES_341US 0 //#define RTIMER_ARCH_RES_171US 1 //#define RTIMER_ARCH_RES_85US 2 #define RTIMER_ARCH_RES_100US 3 // stm32新加的 #include "contiki-conf.h" #include "clock.h" #ifdef RTIMER_ARCH_CONF_RESOLUTION #define RTIMER_ARCH_RESOLUTION RTIMER_ARCH_CONF_RESOLUTION // CONF 配置值arm-def.h處 #else /* RTIMER_ARCH_CONF_RESOLUTION */ #define RTIMER_ARCH_RESOLUTION RTIMER_ARCH_RES_100US // 默認值,可以更改 #endif /* RTIMER_ARCH_CONF_RESOLUTION */ #if RTIMER_ARCH_RESOLUTION == RTIMER_ARCH_RES_100US #define RTIMER_ARCH__PRESCALER 10 // #define RTIMER_ARCH_SECOND 12760 // 示波器實測為xxx us #endif rtimer_clock_t rtimer_arch_now(void); void rtimer_arch_disable_irq(void); void rtimer_arch_enable_irq(void); #endif /* RTIMER_ARCH_H_ */
經過上面的處理后,再進行編譯,這時候只有7個ERRORS了:

將stm32-def.h的LINE:66行注示掉,這是CC2538的信息:

將contiki_v4.7\arch\cpu\stm32下的clock.c進行更改,先改成如下圖:
#include <stdint.h> #include <stdio.h> #include "contiki.h" #include "clock.h" #include "etimer.h" #include "rtimer.h" #include "stm32f10x.h" #include "stm32f10x_conf.h" static volatile clock_time_t current_clock; static volatile unsigned long current_seconds = 0; static unsigned int second_current_clockdown = CLOCK_SECOND; /*---------------------------------------------------------------------------*/ void SysTick_Handler(void) { (void)SysTick->CTRL; SCB->ICSR = SCB_ICSR_PENDSTCLR; current_clock++; if(etimer_pending() && etimer_next_expiration_time() <= current_clock) { etimer_request_poll(); } if(--second_current_clockdown == 0) { current_seconds++; second_current_clockdown = CLOCK_SECOND; } } /*---------------------------------------------------------------------------*/ void clock_init(void) { if (SysTick_Config(SystemCoreClock / CLOCK_SECOND)) { while(1); } } /*---------------------------------------------------------------------------*/ clock_time_t clock_time(void) { return current_clock; } /*-----------------將CPU延遲i*j的倍數NOP--------------------------------------*/ void clock_delay(unsigned int i) { for(; i > 0; i--) { /* 需要修改成XXX值 */ unsigned j; for(j = 50; j > 0; j--) { asm("nop"); } } } /*---------等待1*N毫秒。------------------------------------------------------*/ void clock_wait(clock_time_t i) { clock_time_t start; start = clock_time(); while(clock_time() - start < (clock_time_t) i); } /*---------------------------------------------------------------------------*/ unsigned long clock_seconds(void) { return current_seconds; }
再一次進行IAR編譯,這時候只有5個ERRORS了:

在contiki_v4.7\os\dev下的slip.c,是網絡功能的驅動,我們也把它從IAR裁剪掉。。

再一次進行IAR編譯,只有1個ERRORS了:

在把stm32f10x_it.c內的void SysTick_Handler(void)屏蔽掉或進行弱定義,因為我們在clock.c已經定義了。
LOG.h報個錯,也是關與NET網絡聯連的,我們給它也 // 屏蔽掉:

最后打開IAR,確認設置一下工程選項,如下圖:



再一次進行IAR編譯,這時候只有0個ERRORS了:

報謙了,又粗心大意了,哎,日常糾正錯誤了,。。
就是重新配置芯片型號,路經什么的,也很簡單。搞起來。。。

這是arch\platform\stm32的platform.c更新內容,先這樣改:

最后進行IAR編譯,沒有毛病了吧 ! !

在hello-world.c的測試源碼加上斷點,然后接上開發板進行仿真,1秒一次斷點,正常了。。。。

最后,我們改一下hello-world.c文件內容,驅動一個IO口吧:
#include "contiki.h" #include <stdio.h> /* For printf() */ ///////////////////////////GPIO測試PC6 PC7 //////////////////////////////////// void GPIOB_Initt()//引腳的 { //啟用GPIOB外設時鍾,設置IO口時要選配置好,要不后面無用。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_DeInit(GPIOC);//為上電初始值 //匿名結構體別名, 段變量名, 直接設置參數(3個數據) GPIO_InitTypeDef GPIO_InitStructure = { GPIO_Pin_7|GPIO_Pin_6, //1 參數PIN8 GPIO_Speed_2MHz, //2 參數2M速度 GPIO_Mode_Out_PP }; //3 參數推挽輸出 GPIO_Init(GPIOC, &GPIO_InitStructure);// 將3個參數初始化到GPIOB_PIN8,是指針,要放入地址。 } /*---------------------------------------------------------------------------*/ PROCESS(hello_world_process, "Hello world process"); AUTOSTART_PROCESSES(&hello_world_process); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(hello_world_process, ev, data) { static struct etimer timer; static bool aa; // 測試值 GPIOB_Initt(); // 初始化GPIOC_7 PROCESS_BEGIN(); /* Setup a periodic timer that expires after 1 seconds. */ etimer_set(&timer, CLOCK_SECOND * 1); while(1) { //printf("Hello, world\n"); GPIO_WriteBit(GPIOC, GPIO_Pin_7,aa=!aa); // 測試值在變化,PC7在取反 /* Wait for the periodic timer to expire and then restart the timer. */ PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer)); etimer_reset(&timer); } PROCESS_END(); } /*---------------------------------------------------------------------------*/
燒入STM32開發板后,PC7腳的LED正在1秒一次的閃爍,STM32移植CONTIKI結束了,伙伴們 再見!!!

==== END ====
