你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們介紹的是超級下載算法開發筆記(2)之識別當前i.MXRT型號。html
文接上篇 《超級下載算法(RT-UFL)開發筆記(1) - 執行在不一樣CM內核下》,咱們已經解決了超級下載算法可以在i.MXRT全系列下執行的問題,如今咱們往前繼續推動項目。由於這個超級下載算法未來要跑在不少個芯片型號上,有時候由於型號間差別,咱們不得不針對性地弄出不一樣代碼處理分支,而這一切的前提是咱們能動態地獲取當前芯片型號。算法
本篇是開發筆記第二篇,我們就重點聊聊如何讓超級下載算法知道當前跑在哪一個i.MXRT型號下。數組
恩智浦當前MCU產品線衆多,i.MXRT是2018年纔開始推出的新系列,在這以前恩智浦主推的MCU是經典的Kinetis和LPC系列,痞子衡對這兩個系列產品也很是熟,型號信息在Kinetis和LPC上都有展示。微信
Kinetis系列有一個專門存放型號信息的寄存器即SIM->SDID,這個寄存器設計得很是經典,其FAMILYID + SUBFAMID + SERIESID區域組合將Kinetis系列的家族分類特性展現得淋漓盡致。架構
LPC系列存放型號信息的寄存器是SYSCON->DEVICE_ID0,這個寄存器是另一種設計風格,低20bit直接就是LPC系列號的值,好比LPC54114xxx型號其SYSCON->DEVICE_ID0[19:0] = 0x54114,是否是簡單粗暴。ide
咱們知道i.MXRT從架構上分爲四位數和三位數兩大陣營,四位數源自i.MX應用處理器,三位數源自LPC系列,咱們分別來看。函數
翻看i.MXRT四位數典型型號i.MXRT1060的參考手冊,並無找到任何有關型號信息的寄存器,僅有UID寄存器,但UID跟芯片型號無關。四位數上找不到型號信息寄存器,也跟其源於i.MX有關,畢竟MPU不像MCU那樣會細分特別多的型號。ui
再看i.MXRT三位數典型型號i.MXRT600的參考手冊,咱們找到了型號信息,在SYSCTL0->PRODUCT_ID寄存器中,細看其寄存器設計,仍是能看出LPC的影子的,SYSCTL0->PRODUCT_ID[15:4]直接就是系列號的值。.net
根據上一節的分析,咱們幾乎不能用傳統Kinetis或LPC上型號信息寄存器那一套方式來統一獲取i.MXRT型號,那有沒有替代方法呢?答案固然是有。靈感來自於痞子衡以前研究i.MXRT的ROM API時寫過的一篇文章 《瞭解i.MXRTxxx系列ROM API及其與i.MXRT1xxx系列的差別》,i.MXRT系列所有都有BootROM,每一個型號的ROM區域內容並不盡然相同,咱們能夠經過讀幾個ROM區域不一樣位置的值來定位型號。設計
i.MXRT四位數(都是CM7內核)的ROM基址是0x200000,而i.MXRT三位數(都是CM33內核)的ROM基址是0x3000000,基址是有差別的,因此咱們首先須要先找出一種方法來區分基址,這裏能夠藉助ARM Cortex-M內核模塊SCB裏的CPUID寄存器。
翻看ARM Cortex-M內核的Generic User Guide,能夠找到以下CPUID寄存器的定義,其中CPUID[PartNo]中記錄了內核版本,CM7的值是0xC27,CM33的值是0xD21。
咱們能夠很容易寫出以下ufl_get_core_type()函數。
/* See Part number of core in Cortex-Mx Generic UG */ #define CORE_ID_CM33 (0xD21) #define CORE_ID_CM7 (0xC27) typedef enum _core_type { kCoreType_Invalid = 0U, kCoreType_CM33 = 1U, kCoreType_CM7 = 2U, } core_type_t; static core_type_t ufl_get_core_type(void) { core_type_t coreType = kCoreType_Invalid; uint32_t coreid = (SCB->CPUID & SCB_CPUID_PARTNO_Msk) >> SCB_CPUID_PARTNO_Pos; switch (coreid) { case CORE_ID_CM33: coreType = kCoreType_CM33; break; case CORE_ID_CM7: coreType = kCoreType_CM7; break; default: break; } return coreType; }
有了ufl_get_core_type()函數,咱們即可以進一步寫出以下ufl_get_imxrt_chip_id()函數,s_romFingerprint[]結構體數組預先存放所有i.MXRT型號的ROM定位信息(此處僅示例了RT600和RT1060),咱們選了ROM偏移0x8000、0xa000、0xc000處的四字節數據來定位,如後期隨着型號的增多,出現定位位置處數據所有雷同的巧合的話,能夠更改定位位置保證定位數據必定不相同。
typedef enum _rt_chip_id { kChipId_Invalid = 0xFFU, kChipId_RT6xx = 1U, kChipId_RT106x = 2U, } rt_chip_id_t; #define RT_ROM_BASE_CM33 (0x03000000u) #define RT_ROM_BASE_CM7 (0x00200000u) #define ROM_FP_OFFSET1 (0x8000) #define ROM_FP_OFFSET2 (0xa000) #define ROM_FP_OFFSET3 (0xc000) typedef struct _rom_fingerprint { uint32_t chipId; uint32_t content[3]; } rom_fingerprint_t; static const rom_fingerprint_t s_romFingerprint[] = { {kChipId_RT6xx, {0xb108f82a, 0x0200f2c5, 0x0070f104} }, // From ROM 2.0rc5.1 {kChipId_RT106x, {0xb0893000, 0x80dbf000, 0xf2c44100} }, // From ROM 1.0rc3 }; rt_chip_id_t ufl_get_imxrt_chip_id(void) { rt_chip_id_t chipId = kChipId_Invalid; core_type_t coreType; uint32_t rtRomBase = 0; coreType = ufl_get_core_type(); if (kCoreType_CM33 == coreType) { rtRomBase = RT_ROM_BASE_CM33; } else if (kCoreType_CM7 == coreType) { rtRomBase = RT_ROM_BASE_CM7; } else {} do { uint32_t content[3]; content[0] = *(uint32_t *)(rtRomBase + ROM_FP_OFFSET1); content[1] = *(uint32_t *)(rtRomBase + ROM_FP_OFFSET2); content[2] = *(uint32_t *)(rtRomBase + ROM_FP_OFFSET3); uint32_t idx = sizeof(s_romFingerprint) / sizeof(rom_fingerprint_t); while (idx--) { if (!memcmp(s_romFingerprint[idx].content, content, sizeof(content))) { chipId = (rt_chip_id_t)s_romFingerprint[idx].chipId; break; } } } while (0); return chipId; }
至此,超級下載算法開發筆記(2)之識別當前i.MXRT型號痞子衡便介紹完畢了,掌聲在哪裏~~~
文章會同時發佈到個人 博客園主頁、CSDN主頁、知乎主頁、微信公衆號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就能夠在手機上第一時間看了哦。