# Hello World
# 新建项目
TIP
有时,Copy->Paste是解决问题的最佳方式。
# Copy
复制lesson01:
# Paste
粘贴至App目录下,并重命名为lesson02:
# Switch
最后,在app_switcher.sh中添加并切换至lesson02项目:
# export MADOS_WORKING_APP=LoKernel
# export MADOS_WORKING_APP=LoNode
# export MADOS_WORKING_APP=lesson001
export MADOS_WORKING_APP=lesson002
1
2
3
4
2
3
4
TIP
编辑app_switcher.sh后记得运行config及rebuild任务,以便正确重构新项目。
# 标准输出
# 设备文件
device 目录下已为开发者提供了标准字符设备 DevTty.c
device
├─ stm32f10x
│ ├─ DevTty.c # 标准字符设备
│ ├─ ... # 其他设备
│ └─ Makefile # 编译文件
└─ Makefile # 编译文件
1
2
3
4
5
6
2
3
4
5
6
# 设备描述
#include <stdarg.h>
#include <stdio.h>
#include "MadDev.h"
#include "usart_char.h"
#include "CfgUser.h"
// 定义底层接口
static mUsartChar_t port;
// 定义中断函数
static void Dev_Irq_Handler(void) { mUsartChar_Irq_Handler(&port); }
// 定义底层接口初始化参数
static const mUsartChar_InitData_t LowArgs = {
USART2,
DMA1_Channel7,
DMA1_Channel6,
{
GPIO_Remap_USART2,
{ GPIOD, GPIO_Pin_5 },
{ GPIOD, GPIO_Pin_6 }
},
ISR_PRIO_TTY_USART,
115200, // 波特率
USART_WordLength_8b, // 数据位
USART_StopBits_1, // 停止位
USART_Parity_No, // 校验模式
USART_Mode_Rx | USART_Mode_Tx,
USART_HardwareFlowControl_None, // 流控模式
DMA_Priority_Low,
DMA_Priority_Low,
Dev_Irq_Handler
};
// 定义设备初始化参数
static const MadDevArgs_t Args = {
MAD_WAITQ_DEFAULT_SIZE, // 等待队列长度
128, // 发送缓存尺寸
128, // 接收缓存尺寸
&LowArgs
};
// 定义设备
MadDev_t Tty = { "tty", &port, &Args, &MadDrvUartChar, NULL };
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
27
28
29
30
31
32
33
34
35
36
37
38
39
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
27
28
29
30
31
32
33
34
35
36
37
38
39
TIP
MadOS使用设备文件管理设备,设备文件与硬件平台相关。
通常,设备文件由MadOS提供或由驱动工程师制作,app开发者无需关心底层细节。
设备文件中包含默认的初始化参数,对于tty设备,开发者只需关心:
功能 | 说明 |
---|---|
波特率 | 按需设置 |
数据位 | 按需设置 |
停止位 | 按需设置 |
校验方式 | 按需设置 |
硬件流控 | 按需设置(通常无需关心) |
等待队列 | 按需设置(通常无需关心) |
缓存尺寸 | 按需设置(通常无需关心) |
# 设备列表
将标准输出设备(Tty)加入设备列表(CfgDevs.c):
#include "MadDev.h"
extern MadDev_t Tty;
MadDev_t *DevsList[] = {
&Tty,
MAD_DEVP_END
};
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
TIP
使用设备列表,read、write等原子操作中,可一步定位设备,大幅提升读写效率。
# 修改源码
# main()
为后续调试方面,我们把基本的硬件初始化都放在前部。
int main()
{
do { // Enable GPIOs and DMAs
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
} while(0);
do { // 25MHz-Output For IP101A
GPIO_InitTypeDef gpio;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
gpio.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOA, &gpio);
RCC_MCOConfig(RCC_MCO_HSE);
} while(0);
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
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
27
28
29
# madStartup()
在线程中加入标准输出设备初始化及打印函数。
static void madStartup(MadVptr exData)
{
// 初始化SysTick,脉动间隔1ms。
madInitSysTick(DEF_SYS_TICK_FREQ, DEF_TICKS_PER_SEC);
// 初始化标准C库
Newlib_Init();
// 初始化 tty 用作标准输出
MAD_LOG_INIT();
// 输出 Hello World !
printf("Hello World !\n");
// 线程主循环
while(1) {
// 近乎无限休眠
madTimeDly(0xFFFFFFFF);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 调试程序
# 设置串口工具
连接开发版的调试串口(J16)与开发主机的USB端口,并启动串口调试工具。
TIP
默认串口参数:
功能 | 说明 |
---|---|
波特率 | 115200 |
数据位 | 8 |
停止位 | 1 |
校验方式 | 无 |
# 启动调试
从vscode中启动调试,可在串口调试工具中看到输出: