本帖最后由 sunsili 于 2021-11-28 20:34 编辑
FreeRTOS编码标准、测试和风格指南
编码标准 / MISRA 合规性下面列出了与 MISRA 标准的偏差: - 两个 API 函数有多个退出点。出于关键效率的原因,在这两种情况下允许偏差。
- 创建任务时,源代码通过操作内存地址来定位分配给创建任务的堆栈的起始地址和结束地址。该代码必须适用于移植 FreeRTOS 的所有架构 - 其中包括具有 8、16、20、24 和 32 位总线的架构。这不可避免地需要一些指针运算。使用指针算术时,会以编程方式检查算术结果的正确性。
- 默认情况下,跟踪宏为空,因此不生成任何代码。因此,MISRA 合规性检查是使用虚拟宏定义执行的。
- MISRA 规则在被认为合适的情况下逐行关闭(即,与小心不遵守规则相比,遵守规则被视为为深度嵌入式系统创建不太合适的代码)。每个这样的事件都伴随着使用特殊的 pc-lint MISRA 注释标记语法的理由。
FreeRTOS 使用许多不同的编译器构建,其中一些编译器比其他编译器更先进。因此,FreeRTOS 不使用由 C99 标准或自 C99 标准引入 C 语言的任何功能或语法。对此的一个例外是使用stdint.h头文件。该FreeRTOS的/来源/包括目录包含一个名为stdint.readme可以改名stdint.h提供必要建立FreeRTOS的最低stdint类型定义-要你的编译器不提供其自身。
测试本节介绍对通用代码(位于FreeRTOS/Source目录中的代码,由所有 FreeRTOS 内核端口构建)执行的测试,以及对可移植层代码(位于FreeRTOS/Source子目录中的代码)执行的测试/便携式目录)。 - 通用代码标准演示/测试文件试图提供“分支”测试覆盖率(在大多数情况下,这实际上实现了“条件”覆盖率,因为内核的编码风格专门为此目的而特意保持条件简单),从而测试确保“真”和“假” '通过每个决定的路径被执行。如果 'else' 路径为空,则使用 GCOV 通过将 mtCOVERAGE_TEST_MARKER() 宏定义为每个 'if()' 条件的 'else' 路径中的 NOP(无操作)指令来测量“分支”覆盖率。mtCOVERAGE_TEST_MARKER() 仅在测量测试覆盖率时定义 - 通常它是一个不生成任何代码的空宏。
- 端口层端口层代码使用“reg test”任务进行测试,对于支持中断嵌套的端口,使用“中断队列”任务进行测试。
“reg test”任务创建多个(通常为两个)任务,首先用已知值填充所有 CPU 寄存器,然后在其他测试连续执行时不断检查每个寄存器是否保持其预期的已知值(浸泡测试)。每个 reg 测试任务都使用唯一的值。
“中断队列”任务对嵌套至少三个深度的不同优先级的中断执行测试。宏用于将人为延迟插入代码中的相关点,以确保实现所需的测试覆盖率。
值得注意的是,这些测试的彻底性导致了多次在芯片中发现错误。 命名约定RTOS 内核和演示应用程序源代码使用以下约定: - 变量
- uint32_t类型的变量以ul为前缀,其中“u”表示“无符号”,“l”表示“long”。
- uint16_t类型的变量以us为前缀,其中“u”表示“unsigned”,“s”表示“short”。
- uint8_t类型的变量以uc为前缀,其中“u”表示“unsigned”,“c”表示“char”。
- 非 stdint 类型的变量以x为前缀。示例包括 BaseType_t 和 TickType_t,它们是可移植层定义的 typedef,分别用于架构的自然或最有效类型和用于保存 RTOS 滴答计数的类型。
- 非 stdint 类型的无符号变量有一个额外的前缀u。例如 UBaseType_t(无符号 BaseType_t)类型的变量以ux为前缀。
- size_t类型的变量也以x为前缀。>
- 枚举变量以e为前缀
- 指针有一个额外的前缀p,例如指向 uint16_t 的指针将有前缀pus。
- 根据 MISRA 指南,不合格的标准字符类型只允许包含 ASCII 字符并以c为前缀。
- 根据 MISRA 指南,char *类型的变量只允许保存指向 ASCII 字符串的指针,并以pc为前缀。
- 职能
- 文件范围静态(私有)函数以prv为前缀。
- 根据为变量定义的约定,API 函数以其返回类型为前缀,并为void添加前缀v。
- API 函数名称以定义它们的文件的名称开头。例如 v Task Delete 在 tasks.c 中定义,并且具有 void 返回类型。
- 宏
- 宏以定义它们的文件为前缀。前缀是小写。例如,配置USE_PREEMPTION 在 FreeRTOSConfig.h 中定义。
- 除了前缀之外,宏全部大写,并使用下划线分隔单词。
数据类型仅使用 stdint.h 类型和 RTOS 自己的 typedef,以下情况除外: - 字符根据 MISRA 指南,允许使用不合格的 char 类型,但仅当它们用于保存 ASCII 字符时。
- 字符 *根据 MISRA 指南,允许使用非限定字符指针,但仅当它们用于指向 ASCII 字符串时。当使用期望 char * 参数的标准库函数时,这消除了抑制良性编译器警告的需要,特别是考虑到一些编译器默认未限定的 char 类型是有符号的,而其他编译器默认非限定的 char 类型是无符号的。
每个端口定义了四种类型。这些是:
- TickType_t如果 configUSE_16_BIT_TICKS 设置为非零 (true),则 TickType_t 被定义为无符号 16 位类型。如果 configUSE_16_BIT_TICKS 设置为零 (false),则 TickType_t 被定义为无符号 32 位类型。有关完整信息,请参阅API 文档的自定义部分。
32 位架构应始终将 configUSE_16_BIT_TICKS 设置为 0。 - 基本类型_t这被定义为最有效、最自然的架构类型。例如,在 32 位架构上 BaseType_t 将被定义为 32 位类型。在 16 位架构上 BaseType_t 将被定义为 16 位类型。如果 BaseType_t 被定义为 char,则必须特别注意确保使用有符号字符作为函数返回值,这些值可以为负数以指示错误。
- UBaseType_t这是一个未签名的 BaseType_t。
- 堆栈类型_t定义为体系结构用于存储在堆栈上的项目的类型。通常,这在 16 位架构上是 16 位类型,在 32 位架构上是 32 位类型,尽管有一些例外。由 FreeRTOS 内部使用。
时尚指南- 缩进四个空格字符用于缩进。
- 注释注释永远不会通过第 80 列,除非它们跟随并描述一个参数。
不使用 C++ 风格的双斜线 (//) 注释。 - 布局
|