# 初识源码
# 获取源码
TIP
初学者请选择master分支, 产品应用可选择经过严格验证的release版本。
# Windows
WSL2 + Ubuntu 提供的是一个虚拟机环境。将源码放置在 Ubuntu 中,相比放在 Windows 中,编译速度会大幅提升。
- 启动 Ubuntu
- 找到 Ubuntu 根路径
- 建议的源码存放路径
\\wsl.localhost\Ubuntu-22.04\home\lo
1
TIP
- 上述路径可以在 Github for Windows 中正常使用。
- 如有安全提示,一律选择"信任"。
- Windows 与 MacOS/Ubuntu 采用的换行符不一致,Git Clone 源码之前需修改设置:
- 获取源码
- 查看状态
# 展开源码
# MacOS & Ubuntu
将 MadOS 文件夹拖入 VSCode 中:
# Windows
将 VSCode 连接至 Ubuntu,再通过文件->打开文件夹找到 MadOS
# 目录结构
# 开发者无需关心的内容以 n 标记。
# 开发者可以参考的内容以 - 标记。
# 开发者需要关心的内容以 y 标记。
MadOS
├─ .vscode/ # n : VSCode 相关配置
├─ app/ # y : 项目源码(其中每个子目录为一个项目)
│ ├─ backup # n : 旧版MadOS中的工程备份。
│ ├─ lesson001/ # - : MadOS应用教程第一课,稍后我们会展开分析它。
│ ├─ LoKernel/ # n : MadOS内核压力测试。
│ ├─ LoNode/ # - : LoBoard开发板配套例程,不断完善中。
│ └─ ... # - : 未来,我们将开放更多示例供开发者参考。
├─ arch/ # n : MCU架构相关源码
├─ build/ # n : 编译过程文件存放处(源码编译时自动生成)
├─ device/ # n : 设备模块源码
├─ driver/ # n : 驱动源码
├─ kernel/ # n : 内核源码
├─ library/ # n : 第三方库源码
├─ tools/ # n : MadOS环境配置相关工具
├─ .gitattributes # n : git属性文件
├─ .gitignore # n : git过滤文件
├─ app_switcher.sh # y : 工作App切换器,详见后述。
├─ elibs.mk # n : 第三方库配置
├─ LICENSE # n : 许可证
├─ main.mk # n : 真实主编译文件(临时生成)
├─ Makefile # n : 影子主编译文件
└─ rules.mk # n : 编译规则定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
TIP
- 如果您是操作系统爱好者,也许对 arch、kernel、device、driver 中的内容会感兴趣。
- 如果您是初学者、开发者,则只需关心 app ,即您的项目源码,以便快速实现想法。
- MadOS尚未包含某些驱动或第三方库,如有需要,您可:
- 求助 FAQ
- 访问 社区 (opens new window)
- 联系 我们
# 切换项目
在 MadOS 根目录下有名为 app_switcher.sh 的脚本,用以切换当前工作项目:
# export MADOS_WORKING_APP=LoKernel
# export MADOS_WORKING_APP=LoNode
export MADOS_WORKING_APP=lesson001
1
2
3
2
3
将 lesson001 前的注释去掉,并注释其他项目,然后在 VSCode 中运行 config 任务:
TIP
终端 -> 运行任务 -> config
MadOS is ready... Enjoy yourself!
1
# 项目结构
lesson001
├─ CfgApp.mk # 项目配置
├─ CfgDevs.c # 设备列表
├─ CfgUser.h # 用户配置
├─ main.c # 工程源码(主文件)
└─ Makefile # 编译文件
1
2
3
4
5
6
2
3
4
5
6
TIP
- 如果您是初学者、开发者,只需关心 main.c ,即您的项目源码,以便快速实现想法。
- 为便于后续学习,我们依然对每个文件进行初步介绍,您可快速浏览,以备不时之需。
# CfgApp.mk
# MCU架构配置
export MCU_ARCH = armv7-m
export MCU_VER = cortex-m3
export MCU_PREFIX = stm32f10x
export MCU_SUFFIX = cl
export MCU_RAM_SIZE = 0x10000
export MCU_FLS_SIZE = 256K
# 工程特定编译选项
export PRJ_CFLAGS = -Os
export PRJ_LDFLAGS = --specs=nano.specs
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# CfgDevs.c
// 第一课中未启用任何设备,设备列表为空。
#include "MadDev.h"
MadDev_t *DevsList[] = {
MAD_DEVP_END
};
1
2
3
4
5
2
3
4
5
# CfgUser.h
// MadOS支持最大256个任务优先级,数字越大优先级越低。
// 开发者需根据自身需要进行配置,并避开MadOS内部已使用的优先级。
// 最低优先级为空闲线程使用,次低优先级为统计线程(可选)使用,另建议保留优先级 0。
enum {
THREAD_PRIO_SYS_RUNNING = 1, // 标记系统正在运行的线程(周期性闪烁Led)
THREAD_PRIO_DRIVER_ETH // 编译网络驱动层所需
};
// 通常,中断优先级都与驱动相关。
// 中断优先级统一于此处枚举,便于高级开发者查阅、更改。
// 优先级1、15为MadOS内部保留,其余优先级可供项目使用。
enum {
ISR_PRIO_SYSTICK = 1,
ISR_PRIO_ARCH_MEM,
ISR_PRIO_DISK,
ISR_PRIO_ETH,
ISR_PRIO_DEV_USART,
ISR_PRIO_TTY_USART,
ISR_PRIO_PENDSV = 15
};
// 堆空间定义(硬件相关)
#define MAD_OS_STACK_SIZE (56 * 1024)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Makefile
# 将项目路径下所有.c文件输入编译系统。
export TEMP = $(BUILD_DIR)/app
ASMS =
SRCS = $(wildcard *.c)
include $(RULES)
after_all:
$(LD) $(wildcard $(BUILD_DIR)/app/*.o) $(LDFLAGS) -o $(TARGET).elf
$(OCPY) -O ihex $(TARGET).elf $(TARGET).hex
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# main.c
#include "MadOS.h" // MadOS核心头文件
#include "CfgUser.h" // 用户配置头文件
// 运行时堆栈 (8Bytes-Align for Float)
MadAligned_t MadStack[MAD_OS_STACK_SIZE / MAD_MEM_ALIGN] = { 0 };
// 函数声明
static void madStartup(MadVptr exData);
// 初始化
int main()
{
...
}
// 线程
static void madStartup(MadVptr exData)
{
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 运行时堆栈
运行时堆栈的空间由硬件决定。
任何项目的运行时堆栈皆可由下式定义:
MadAligned_t MadStack[MAD_OS_STACK_SIZE / MAD_MEM_ALIGN] = { 0 };
1
# 初始化
下述初始化流程可适用于任何项目。
启动MadOS后,程序会跳转至新建线程中运行。
第一课中,我们只建立一个线程,意在简明,线程优先级取 0。
int main()
{
madCopyVectorTab(); // 将中断向量表复制到RAM中
madOSInit(MadStack, MAD_OS_STACK_SIZE); // MadOS初始化
madThreadCreate(madStartup, 0, MAD_OS_STACK_SIZE / 2, 0); // 新建线程
madOSRun(); // 启动MadOS
while(1); // !永远不该运行至此!
} // 以上是MadOS的启动过程,初学者不必深究,随后的学习中会逐步了解其原理
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 线程
开发者在线程中实现想法,每个线程都是一个无限循环。
TIP
使用线程管理API,可以新建、挂起、恢复、删除线程。
static void madStartup(MadVptr exData)
{
GPIO_InitTypeDef pin; // GPIO临时变量
MadBool flag = MFALSE; // LED状态标志
(void)exData; // 防止编译器产生警告
// 初始化GPIOE-1,用于控制LED开关。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
pin.GPIO_Mode = GPIO_Mode_Out_PP;
pin.GPIO_Pin = GPIO_Pin_1;
pin.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &pin);
// 初始化SysTick,脉动间隔1ms。
madInitSysTick(DEF_SYS_TICK_FREQ, DEF_TICKS_PER_SEC);
// 线程主循环
while(1) {
madTimeDly(500); // 延时500ms
flag = !flag; // LED状态取反
if(flag) GPIO_ResetBits(GPIOE, GPIO_Pin_1); // 开灯
else GPIO_SetBits(GPIOE, GPIO_Pin_1); // 关灯
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
TIP
- 无OS环境,通常使用空循环方式延时:
- 无法精准延时
- 大量浪费MCU时间
void delay(int i) { while(i--); }
1
- MadOS环境,SysTick 初始化后提供了精准的心跳,根据心跳的频率可得精准延时。
- 运行30天,实测误差小于1微秒()
madTimeDly(1000 * 3600 * 24 * 30); // 通常,madTimeDly以ms为单位。
1
# 编译项目
# 首次编译
在VSCode中运行 rebuild 任务
TIP
终端 -> 运行任务 -> rebuild
# 普通编译
在VSCode中运行 build 任务
TIP
终端 -> 运行任务 -> build
# 编译结果
...
Building ... Done.
1
2
2
编译成功后,MadOS根目录下会生成 build 文件夹:
build
├─ app/ # 存放项目相关编译过程文件
├─ arch/ # 存放芯片相关编译过程文件
├─ dev/ # 存放设备相关编译过程文件
├─ drv/ # 存放驱动相关编译过程文件
├─ kernel/ # 存放内核相关编译过程文件
├─ HiMadOS.elf # 调试文件
├─ HiMadOS.hex # 烧录文件
├─ HiMadOS.ld # 链接脚本
├─ libarch.a # 芯片库文件
├─ libdev.a # 设备库文件
├─ libdrv.a # 驱动库文件
└─ libkernel.a # 内核库文件
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
TIP
build 内生成的目录 / 文件与项目配置有关,开发者无需关心。
# 调试项目
将 STLink 分别与 LoBoard(开发板)、电脑连接,并给 LoBoard 通电:
TIP
- MacOSX / Ubuntu 需安装 libusb 。
- Windows 需安装 ST 官方提供的STLink驱动 (opens new window)。
- 如果您需要购买 STLink 或 LoBoard ,请移步至我们的小店 (opens new window)。
在 VSCode 中启动调试:
正常启动调试后,程序会暂停在 main 函数起始位置:
TIP
按 F5 或 点击调试工具栏中的 继续 按钮,程序继续执行。