本篇將是系列文章的最后一篇,在MCU上進(jìn)行實(shí)際的部署。 小編就不再給大家復(fù)習(xí)歷史了,直接開始正題。如果想溫習(xí)前兩部分內(nèi)容,請點(diǎn)擊此處和此處。
首先給大家介紹一下我們將要使用的離線Flash燒寫工具,名為JFlashLite,他有一個兄弟叫JFLash,既然是Lite就是輕量版本的JFlash工具。
當(dāng)然,需要大家自行下載Segger Jlink工具包。是的,我們需要一條JLink。隨后找到JFlashLite工具,他長這樣(請忽略這里的1176,我們還沒有配置):
比起下圖他的哥哥JFlash,是不是很清爽的界面:
當(dāng)然,我們今天的主角是JFlashLite,稍后會介紹如何進(jìn)行配置并下載
程序編寫
工具介紹完了,下面正式開始編寫配套程序,所使用的平臺是i.MX RT1060, 開發(fā)板是IMXRT1060EVKB:
劃分FLASH以及sdram區(qū)域,sdram區(qū)域負(fù)責(zé)加載flash中內(nèi)容,加速內(nèi)存訪問:我們的開發(fā)板上有一個8MB的Flash,內(nèi)存映射地址為0x60000000,首先保留1MB的頭部區(qū)域以存儲代碼,其作用后續(xù)會提到。那么我們就剩下7MB大小的空間,由于數(shù)據(jù)一般較大,劃分4MB作為數(shù)據(jù)存儲區(qū),剩下的3MB存儲模型。同樣的,在sdram區(qū)域,內(nèi)存映射地址為0x80000000也同樣開辟這樣大的兩塊內(nèi)存區(qū),不過,為了防止數(shù)據(jù)溢出,我們僅針對于sdram區(qū)域,在數(shù)據(jù)區(qū)和模型區(qū)中間插入256B的數(shù)據(jù)保護(hù)區(qū),并填充0xdeadbeef,最終的內(nèi)存布局如下:
Flash上內(nèi)存分配
Sdram內(nèi)存分配
利用JflashLite工具進(jìn)行燒寫:
打開JFlashLite工具點(diǎn)擊…選擇器件為1062xxxxA:
選擇對應(yīng)的數(shù)據(jù)文件以及模型進(jìn)行燒寫,燒寫地址要依據(jù)上述定義的分配,即模型數(shù)據(jù)燒寫到0x60100000,圖像數(shù)據(jù)燒寫到0x60400000:
選擇好之后,點(diǎn)擊Program Device即可進(jìn)行燒寫;針對于模型數(shù)據(jù),yao注意將以.tflite結(jié)尾的模型文件,重命名為.bin文件。
Scf文件編寫,主要考慮到,運(yùn)行時,將flash中的數(shù)據(jù),拷貝到sdram中,以提高運(yùn)行速度,這里聲明兩個區(qū)域負(fù)責(zé)存儲ER_tflite_model以及ER_test_data
#define m_text_start 0x80000400 #define FLASH_LOAD 7 * 1024 * 1024 LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_start { ; load region size_region VECTOR_ROM m_interrupts_start FIXED m_interrupts_size { ; load address = execution address * (.isr_vector,+FIRST) } ER_m_text m_text_start FIXED m_text_size - FLASH_LOADER_SIZE { ; load address = execution address * (InRoot$$Sections) .ANY (+RO) } #if (defined(FLASH_LOAD)) ER_ test_data +0 EMPTY 4 * 1024 * 1024 {} ER_PLACEHOLDER1 +0 EMPTY FILL 0xdeadbeef 256{} ER_tflite_model +0 EMPTY 3 * 1024 * 1024 {} ER_PLACEHOLDER2+0 EMPTY FILL 0xdeadbeef 256{} ER_EMPTY m_text_start + m_text_size EMPTY 0{} #endif
主代碼編寫,針對于邊界溢出檢測代碼,簡單起見,只檢測首地址處值,不同則表示溢出,死循環(huán)等待
typedef struct { uint32_t n, h, w, c; uint8_t data[0]; }data_t; // use a split area, total 7MB: // tflite model 3MB // img_data 4MB #define FLASH_BASE (0x60100000) #define MB(x) (x * 1024 * 1024) #define lr_model_data_len (MB(3)) #define lr_model_data FLASH_BASE #define lr_model_data_end (lr_model_data + lr_model_data_len) #define lr_img_data_len (MB(4)) #define lr_img_data (lr_model_data_end) // 0x60200000 #define lr_img_data_end (lr_img_data + lr_img_data_len) // declare the sdram memory extern uint8_t Image$$ER_tflite_model$$ZI$$Base[]; #define model_data Image$$ER_tflite_model$$ZI$$Base extern uint8_t Image$$ER_test_data$$ZI$$Base[]; #define img_data Image$$ER_test_data$$ZI$$Base extern uint8_t Image$$ER_PLACEHOLDER1$$ZI$$Base[]; #define PLACEHOLDER1 Image$$ER_PLACEHOLDER1$$ZI$$Base extern uint8_t Image$$ER_PLACEHOLDER2$$ZI$$Base[]; #define PLACEHOLDER2 Image$$ER_PLACEHOLDER2$$ZI$$Base #define DO_MEMCPY(name) memcpy((void*)name, (void*)lr_##name, lr_##name##_len) #define PRE_INIT() do{ DO_MEMCPY(model_data); DO_MEMCPY(img_data); while(0xdeadbeef != *(uint32_t*) PLACEHOLDER1) ; while(0xdeadbeef != *(uint32_t*) PLACEHOLDER2) ; }while(0);
定義好了一些宏之后,就是模型的初始化函數(shù):
void tflite_engine_init(){ #ifdef FLASH_LOAD PRE_INIT() #endif SysTick_Config(CLOCK_GetCoreSysClkFreq() / 1000); MODEL_AllocateTensor((void*)tensorArena, sizeof(tensorArena)); if (MODEL_Init(model_data) != kStatus_Success) { PRINTF("Failed initializing model"); for (;;) {} } }
測試數(shù)據(jù)如何獲取呢,利用我們剛才定義的data_t結(jié)構(gòu)體:
data_t *image = (data_t*)img_data; image_data_ptr = image->data;
這樣,我們就拿到了存儲在flash并且已經(jīng)被搬運(yùn)到了sdram上的數(shù)據(jù)了,接下來就是編譯運(yùn)行了。
實(shí)際運(yùn)行與測試
測試時候,要注意首先確保我們的開發(fā)板已經(jīng)是XIP啟動,即從Nor Flash啟動,并且保證在flash的頭部,燒寫過一個完整的可執(zhí)行鏡像,比如hello_world程序,其中會包含F(xiàn)lash的一些配置信息,這一步小編就不再舉例,還請大家自行準(zhǔn)備。
這樣,我們的BootRom會據(jù)此幫我們配置好Flash,程序中就不用手動調(diào)用Flash的初始化代碼了。
還要注意,代碼要全部運(yùn)行在SDRAM或是其他介質(zhì)上,因?yàn)槲覀円呀?jīng)將flash據(jù)為己有了。
下面是內(nèi)存鏡像的樣子,首先是model:
再者是測試數(shù)據(jù),前四個uint32類型的數(shù)據(jù)剛好是小編這里定義的數(shù)據(jù)長度100張128*128*3的rgb彩色圖:
連上板子和PC,并打開串口控制臺即可查看輸出結(jié)果,小編所選用的模型是一個水果識別的模型,下面是最后一組數(shù)據(jù)的輸出結(jié)果,證明我們的程序運(yùn)行成功!
展望
當(dāng)然,小編給大家分享的這個方法,不僅可以應(yīng)用在神經(jīng)網(wǎng)絡(luò)AI推理上,可以當(dāng)作一個低配版的flashloader,以供大家靈活地更新靜態(tài)數(shù)據(jù)資源。
-
mcu
+關(guān)注
關(guān)注
146文章
17148瀏覽量
351198 -
FlaSh
+關(guān)注
關(guān)注
10文章
1635瀏覽量
148028 -
工具包
+關(guān)注
關(guān)注
0文章
46瀏覽量
9536
原文標(biāo)題:一種基于MCU的神經(jīng)網(wǎng)絡(luò)模型在線更新方案之MCU實(shí)戰(zhàn)篇
文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論