@@ -1145,257 +1145,6 @@ C.M.@hit 2019.09.09
11451145
11461146
11471147
1148- ## 第二部分 架构规范
1149-
1150- ### 一、顶层架构
1151-
1152- #### 1.1. 设计概述
1153-
1154- 整个架构的顶层设计主要分为三层,由下至上依次为:运行时环境(Runtime Environment,RTE)、系统驱动层(System Driver Layer,DRV),应用软件层(Application Layer,APP)。RTE提供对基础外设的初始化;DRV提供对具体设备的访问、任务间通信、任务管理,并对同一类设备提供接口抽象;应用软件层包含界面绘制、控制逻辑等高端功能
1155-
1156-
1157-
1158- #### 1.2. 运行时环境(RTE)
1159-
1160- RTE提供了对基础外设(如PIT、DMA、XBAR、AOI等设备)的初始化与配置。大部分工作都可以由配置工具直接生成,开发者要做的主要是对配置工具生成的代码进行查漏和补全。RTE并不提供对底层外设的访问功能。
1161-
1162- 一部分RTE内容直接由NXP MCUXpresso实现,无需自行编写。
1163-
1164- RTE还提供初始化注册的功能,任何硬件初始化都应在RTE内置位对应标志位。
1165-
1166-
1167-
1168- #### 1.3. 系统驱动层(DRV)
1169-
1170- DRV层包括两个部分:系统组件和驱动组件。驱动组件主要提供对具体外设的访问,包括高级外设的初始化、读写操作、控制逻辑。对于一些常用的外设(如IMU,摄像头,电机等),DRV层还应提供统一的接口以供应用层访问。系统组件的功能主要包括:定时任务和事件触发器的管理,处理计时、延迟、中断路由等系统服务,提供异常处理、外部数传逻辑等相关功能。
1171-
1172- 和电脑上运行的操作系统一样,驱动和系统总是密不可分的,系统必须包含一些自身运行所必须的驱动。因而系统部分的代码往往会包含对所需外设的控制。这是一个介于单片机底层和上层逻辑之间的连接层。而独立于系统部分之外的驱动部分,则对系统部分有较高的依赖性,各种限制也较多。不同驱动之间禁止直接互相通信,而必须通过向系统注册观察者的方式接收通知;驱动层必须能够自动更新相关的数据,并产生对应的事件或消息。
1173-
1174- 这里系统层的消息架构采用观察者模式。
1175-
1176-
1177-
1178- #### 1.4. 应用软件层(APP)
1179-
1180- APP软件通常面向DRV层或APP自身的内部组件工作。对于智能车而言,APP组件通常包括以下几部分:控制逻辑、数据存储、界面与I/O、图像等高端数据处理。一般的,控制逻辑、数据存储、界面与I/O共同构成一个MVC系统,而数据处理往往作为控制逻辑的子系统出现,但工作相对独立,更多依赖于下层驱动的时序。
1181-
1182- 在这个MVC系统中,数据存储模块集中了控制逻辑所需的全部变量,称为“模型”(Model)。界面与I/O主要包括用户界面逻辑、Flash或SD卡等NV存储、蓝牙串口或Wi-Fi数传的高端逻辑、上位机通信逻辑等,称为“观察者”(Viewer)。控制逻辑主要的作用是对用户操作和传感器状态等输入做出响应,根据这些输入的变量计算输出,被称为“控制器”(Controller)。
1183-
1184- 我们将在控制逻辑部分采用状态模式,实现一个状态机。
1185-
1186- 我们将在界面的菜单部分采用命令模式(用于处理业务逻辑)和责任链模式(用于处理操作输入),在Console命令行部分采用解释器。
1187-
1188-
1189-
1190- ### 二、 设计模式
1191-
1192- #### 2.1. 单件模式
1193-
1194- #### 2.2. 观察者模式
1195-
1196- #### 2.3. 状态模式
1197-
1198- #### 2.4. 命令模式
1199-
1200- #### 2.5. 责任链模式
1201-
1202- #### 2.6. 解释器模式
1203-
1204-
1205-
1206- ### 三、 框架规范
1207-
1208- #### 3.1. 驱动系统层接口
1209-
1210- 1. 定时中断管理器(PITMGR)
1211-
1212- - 概述
1213-
1214- 定时中断管理器的模块名为PITMGR,包括两个文件,`pitmgr.hpp`和`pitmgr.cpp`。
1215-
1216- 定时中断管理器属于驱动系统层的系统部分,主要通过PIT硬件计时,向系统提供全寿命计时器(Lifetime Counter,LTC)、精准延迟计时、定时任务管理等功能。PIT硬件在PITMGR中初始化和配置。通常情况下配置如下:Chnl0和Chnl1通过ChainMode连接成一个64位定时器,作为LTC。NXP非常贴心地在SDK中为我们准备了读取LTC的函数`uint64_t PIT_GetLifetimeTimerCount(PIT_Type* base);`,可以直接调用。这个LTC同时用作延时功能。Chnl2配置为定时周期为1ms的定时器,开启中断,为系统服务提供节拍。Chnl3按需配置。
1217-
1218- - C语言接口
1219-
1220- `const uint64_t pitmgr_pitClkFreq;` 常量,定义了PIT时钟频率,需要根据具体单片机的时钟配置修改。
1221-
1222- `status_t PITMGR_Init(void);` PIT初始化与配置。
1223-
1224- `uint64_t getLTC(void);` 获取LTC计数。**注意:PIT是自动重装减法计数器。**需要用`ULLONG_MAX-PIT_GetLifetimeTimerCount(PIT);`得到从0开始的计数。
1225-
1226- `uint64_t getLTC_us(void);` 获取LTC计数的微秒数。
1227-
1228- `uint64_t getLTC_ms(void);` 获取LTC计数的毫秒数。
1229-
1230- `void delay(uint64_t _t);` 通过LTC进行时钟级别的延时。
1231-
1232- `void delay_us(uint64_t _t);` 通过LTC进行微秒级延时。
1233-
1234- `void delay_ms(uint64_t _t);` 通过LTC进行毫秒级延时。
1235-
1236- `typedef void (*pitmgr_handler_t)(void);` 定时任务函数指针。
1237-
1238- ```c
1239- enum pptFlag_t : uint32_t
1240- {
1241- pitmgr_pptEnable = 1 << 0,
1242- pitmgr_pptRunOnce = 1 << 1,
1243- };
1244- ```
1245-
1246- 标志位枚举,PIT系统中断服务的属性flag。`enable`指当前任务的启用状态,`runOnce`指该任务是否运行一次后自动禁用。还可按需添加更多flag。
1247-
1248-
1249-
1250- ```c
1251- struct pitmgr_handle_t
1252- {
1253- uint32_t ms, mso;
1254- pitmgr_handler_t handler;
1255- uint32_t pptFlag;
1256- };
1257- ```
1258-
1259- 任务控制结构体。其中`ms`表示运行周期,`mso`表示运行相位(通俗讲就是该任务会在第`k*ms+mso`毫秒时被执行)。该机制是用于平衡每一个毫秒的负载。假如A任务每2ms运行一次,用时20us,B任务每5ms运行一次,用时100us,则第10毫秒共用时120us。如果这样的累积事件越累越多,有可能导致在特定的节拍处用时超过1ms的定时周期,导致定时周期的不稳定。`handler`用于存储任务的函数指针,`pptFlag`用于存储前面enum所定义的属性flag。
1260-
1261-
1262-
1263- `const uint32_t pitmgr_isrSetSize;` 简单起见,这里不再对系统定时中断服务的数组采用动态内存,而是简单定义一个绝对够用大小。当然也可以自己实现一个链表,这部分可以自由发挥。
1264-
1265- `uint32_t pitmgr_isrSetCnt;` 这个变量用于存储当前系统定时中断服务数组中系统定时中断的个数。
1266-
1267- `pitmgr_handle_t pitmgr_isrSet[pitmgr_isrSetSize];` 这就是系统定时中断服务数组了。
1268-
1269- `uint32_t pitmgr_timer_ms;` 这是PIT中断的毫秒计时变量。亦可在`isr`函数内静态定义。
1270-
1271- `void PITMGR_setup(pitmgr_handle_t* _handle, uint32_t _ms, uint32_t _mso, handler_t _handler, uint32_t _ppt);` 这是一个内部函数,用于设置一个handle。
1272-
1273- `void PITMGR_setEnable(pitmgr_handle_t* _handle, uint8_t _b)` 这是一个内部函数,用于设置一个handle的启用状态。这里uint8_t实际用作bool,因为C语言没有原生的bool(我不喜欢boolean)。
1274-
1275- `pitmgr_handle_t* PITMGR_Insert(uint32_t _ms, uint32_t _mso, handler_t _handler, uint32_t _ppt);` 如果数组未满,这个函数用于向数组末尾插入一个系统定时中断服务,它会使`pitmgr_isrSetCnt`增加1,并返回指向所插入的`pitmgr_handle_t`结构体的指针。如果数组已满,(在DEBUG配置下)应当`assert`失败,并(在RELEASE配置下)返回`NULL`。注:性能考虑,`assert`在RELEASE配置下往往被忽略。**注意:该函数需要暂时关闭PIT中断。**
1276-
1277- `status_t PITMGR_Remove(pitmgr_handle_t* _handle );` 该函数为可选函数,用于删除一个特定的系统定时中断任务。由于采用了数组的存储方式,删除非末尾的节点可能存在困难。该函数返回操作的结果。对于需要频繁开关的系统定时中断任务,建议使用`pptFlag`设置启用和禁用,而不是反复添加和删除任务。
1278-
1279- `void PITMGR_Isr(void);` 该函数为本模块的中断处理函数,中断服务函数将调用此函数来实现对系统定时中断任务的处理。此函数用于处理PITMGR内部的业务逻辑,而并不负责清除PIT硬件的标志位。标志位由PIT的IRQHandler清除。
1280-
1281-
1282-
1283- - C++接口
1284-
1285- ```c++
1286- class pitmgr_t
1287- {
1288- public:
1289-
1290- //LifeTimeCounter
1291- static uint64_t getLTC(void);
1292- static uint64_t getLTC_us(void);
1293- static uint64_t getLTC_ms(void);
1294- //delay using LifeTimeCounter
1295- static void delay(uint64_t _t);
1296- static void delay_us(uint64_t _t);
1297- static void delay_ms(uint64_t _t);
1298-
1299- //isr service manager
1300- typedef void (*handler_t)(void);
1301- enum pptFlag_t : uint32_t
1302- {
1303- enable = 1 << 0,
1304- runOnce = 1 << 1,
1305- //msgWake = 1 << 2,
1306- };
1307- static std::list<pitmgr_t> isrSet;
1308- static uint32_t timer_ms;
1309-
1310- static pitmgr_t& insert(uint32_t _ms, uint32_t _mso, handler_t _handler, uint32_t _ppt);
1311- static status_t remove(pitmgr_t& _handle);
1312- static void isr(void);
1313-
1314- //isr service content
1315- uint32_t ms, mso;
1316- handler_t handler;
1317- uint32_t pptFlag;
1318-
1319- void setup(uint32_t _ms, uint32_t _mso, handler_t _handler, uint32_t _ppt);
1320- void setEnable(bool _b);
1321- pitmgr_t(void);
1322- private:
1323-
1324- pitmgr_t(uint32_t _ms, uint32_t _mso, handler_t _handler, uint32_t _ppt);
1325-
1326- };
1327- ```
1328-
1329-
1330-
1331-
1332-
1333-
1334-
1335-
1336-
1337- 2. 外部中断管理器(EXTMGR)
1338-
1339-
1340-
1341- 3. 串口管理器(UARTMGR)
1342-
1343-
1344-
1345- 4. I2C通用接口与SPI通用接口
1346-
1347-
1348-
1349- 5. 电机与舵机驱动接口(MOTOR/SERVO)
1350-
1351-
1352-
1353- 6. IMU惯导驱动接口(DRVIMU)
1354-
1355-
1356-
1357- 7. 显示屏幕接口(DISP)
1358-
1359-
1360-
1361-
1362-
1363- #### 3.2. 应用软件层框架
1364-
1365- 1. 顶层MVC框架
1366-
1367-
1368-
1369- 2. 数据存储框架
1370-
1371-
1372-
1373- 3. 控制状态机框架
1374-
1375-
1376-
1377- 4. NV存储接口(NVSTO)
1378-
1379-
1380-
1381- 5. 界面显示适配器(APPUI)
1382-
1383-
1384-
1385- 6. 菜单逻辑接口(APPUI_MENU)
1386-
1387-
1388-
1389- 7. 日志与命令行接口(APPUI_DLOG)
1390-
1391-
1392-
1393- 8. 图像显示接口(APPUI_IMAGE)
1394-
1395-
1396-
1397- 9. 通用数传接口
1398-
13991148
14001149
14011150
0 commit comments