Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
QEMU
RT-Thread qemu mps2-an385 bsp 移植制作 :系统运行篇
发布于 2023-07-23 21:01:24 浏览:362
订阅该版
[tocm] [RT-Thread qemu mps2-an385 bsp 移植制作 :环境搭建篇](https://club.rt-thread.org/ask/article/c0be3f8a4b751b10.html) [RT-Thread qemu mps2-an385 bsp 移植制作 :BSP 制作篇](https://club.rt-thread.org/ask/article/c4d2aacf5ab2a160.html) [RT-Thread qemu mps2-an385 bsp 移植制作 :系统启动篇](https://club.rt-thread.org/ask/article/d9c2825cc94b8b39.html) [RT-Thread qemu mps2-an385 bsp 移植制作 :系统运行篇](https://club.rt-thread.org/ask/article/499d407fa948c318.html) ## 前言 - 前面已经让 RT-Thread 进入了 entry 入口函数,并且 调整 链接脚本,自动初始化与 MSH shell 的符号已经预留, 进入了 RT-Thread 的初始化流程 - 接下来:从 内存管理、系统tick 定时器、适配串口 uart 驱动三个模块入手,让RT-Thread 真正运行起来 ## 系统tick定时器 - 可以称之为 操作系统的心跳,一般是个周期性的定时器,比如 1ms 为周期,周期性的执行。 - 通过验证,`mps2-an385` 支持 systick 定时器,简单配置后,就可以实现 系统 tick 定时器功能 - 修改完善 `drv_common.c` ```c #include
#include
#include "CMSDK_CM3.h" #include "system_CMSDK_CM3.h" static uint32_t _systick_ms = 1; /** * This is the timer interrupt service routine. * */ void SysTick_Handler(void) { /* enter interrupt */ rt_interrupt_enter(); rt_tick_increase(); /* leave interrupt */ rt_interrupt_leave(); } /* SysTick configuration */ void rt_hw_systick_init(void) { SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); NVIC_SetPriority(SysTick_IRQn, 0xFF); _systick_ms = 1000u / RT_TICK_PER_SECOND; if(_systick_ms == 0) _systick_ms = 1; } ``` - `rt_hw_systick_init` 当前被 `board.c` 中的 `rt_hw_board_init` 调用,而 `rt_hw_board_init` 又被 RT-Thread `rtthread_startup` 调用, `rtthread_startup` 被 RT-Thread 入口函数 `entry` 调用,这个 `entry` 又被 启动文件 `Reset_Handler` 调用,`Reset_Handler` 是 MCU 上电执行的函数。 - 初始化 `rt_hw_systick_init` 后,VS Code gdb 调试,发现可以周期性进入 `SysTick_Handler`,也就是 systick 定时器的中断处理函数,在这个函数中,执行 `rt_tick_increase`,基于时间片的系统调度、系统定时与延时等,都依赖 系统 tick 定时器,也就是移植 RT-Thread,必须有周期性 tick 定时器 ![2023-07-23_202353.png](https://oss-club.rt-thread.org/uploads/20230723/6808f06addf2b239a728a0dede4fe09b.png) ## 系统内存管理 - ` mps2-an385` 的 RAM 4MB,当前内存配置在 board.h 中实现 ```c #ifndef __BOARD_H__ #define __BOARD_H__ #include
#if defined(__CC_ARM) extern int Image$$RW_IRAM1$$ZI$$Limit; #define HEAP_BEGIN ((void*)&Image$$RW_IRAM1$$ZI$$Limit) #elif defined(__GNUC__) extern int __bss_end__; #define HEAP_BEGIN ((void*)&__bss_end__) #endif #define HEAP_END (void*)(0x20000000 + 4 * 1024 * 1024) void rt_hw_board_init(void); void rt_hw_systick_init(void); #endif ``` - `mps2-an385` qemu 不需要配置系统的时钟,所以 `board.c` 主要用于实现 `rt_hw_board_init`,初始化内存、串口、系统 tick 定时器,并设置 MSH shell 串口终端 ```c #include
#include
#include "board.h" #include "drv_uart.h" void idle_wfi(void) { asm volatile ("wfi"); } /** * This function will initialize board */ void rt_hw_board_init(void) { /* initialize system heap */ rt_system_heap_init(HEAP_BEGIN, HEAP_END); /* initialize hardware interrupt */ rt_hw_systick_init(); rt_hw_uart_init(); rt_components_board_init(); rt_console_set_device(RT_CONSOLE_DEVICE_NAME); rt_thread_idle_sethook(idle_wfi); } ``` ## 串口驱动适配 - RT-Thread 具有 MSH shell 组件,这个组件在程序调试中非常的有用,合理的利用 shell,可以实现一些复杂的操作 - ` mps2-an385` 的串口配置并不复杂,不像STM32 那样有各种配置,所以当前简单的适配了一下,实现了串口中断接收、串口发送,即可让 MSH shell 串口正常工作 - 当前初步验证,` mps2-an385` `uart0` 可以正常用于 MSH shell - `drv_uart.c` 适配如下: ```c #include
#include
#include
#include "board.h" #include "CMSDK_CM3.h" enum { #ifdef BSP_USING_UART0 UART0_INDEX, #endif #ifdef BSP_USING_UART1 UART1_INDEX, #endif }; /* qemu uart dirver class */ struct uart_instance { const char *name; CMSDK_UART_TypeDef *handle; IRQn_Type irq_num; int uart_index; struct rt_serial_device serial; }; #if defined(BSP_USING_UART0) #ifndef UART0_CONFIG #define UART0_CONFIG \ { \ .name = "uart0", \ .handle = CMSDK_UART0, \ .irq_num = UART0RX_IRQn, \ .uart_index = UART0_INDEX, \ } #endif /* UART0_CONFIG */ #endif /* BSP_USING_UART0 */ #if defined(BSP_USING_UART1) #ifndef UART1_CONFIG #define UART1_CONFIG \ { \ .name = "uart1", \ .handle = CMSDK_UART1, \ .irq_num = UART1RX_IRQn, \ .uart_index = UART1_INDEX, \ } #endif /* UART1_CONFIG */ #endif /* BSP_USING_UART1 */ static struct uart_instance uart_obj[] = { #ifdef BSP_USING_UART0 UART0_CONFIG, #endif #ifdef BSP_USING_UART1 UART1_CONFIG, #endif }; static void uart_isr(struct rt_serial_device *serial) { /* UART in mode Receiver */ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); } void UART0RX_Handler(void) { #ifdef BSP_USING_UART0 uint32_t irq_status = 0x00; /* enter interrupt */ rt_interrupt_enter(); uart_isr(&(uart_obj[UART0_INDEX].serial)); irq_status = uart_obj[UART0_INDEX].handle->INTCLEAR; uart_obj[UART0_INDEX].handle->INTCLEAR = irq_status; /* leave interrupt */ rt_interrupt_leave(); #endif } void UART1RX_Handler(void) { #ifdef BSP_USING_UART1 uint32_t irq_status = 0x00; /* enter interrupt */ rt_interrupt_enter(); uart_isr(&(uart_obj[UART1_INDEX].serial)); irq_status = uart_obj[UART1_INDEX].handle->INTCLEAR; uart_obj[UART1_INDEX].handle->INTCLEAR = irq_status; /* leave interrupt */ rt_interrupt_leave(); #endif } static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) { struct uart_instance *instance; RT_ASSERT(serial != RT_NULL); instance = (struct uart_instance *)serial->parent.user_data; uart_obj[instance->uart_index].handle->BAUDDIV = 16; uart_obj[instance->uart_index].handle->CTRL = CMSDK_UART_CTRL_RXIRQEN_Msk | CMSDK_UART_CTRL_RXEN_Msk | CMSDK_UART_CTRL_TXEN_Msk; NVIC_EnableIRQ(uart_obj[instance->uart_index].irq_num); uart_obj[instance->uart_index].handle->STATE = 0; return RT_EOK; } static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg) { struct uart_instance *instance; RT_ASSERT(serial != RT_NULL); instance = (struct uart_instance *)serial->parent.user_data; switch (cmd) { case RT_DEVICE_CTRL_CLR_INT: /* disable rx irq */ instance->handle->CTRL &= ~CMSDK_UART_CTRL_RXIRQEN_Msk; break; case RT_DEVICE_CTRL_SET_INT: /* enable rx irq */ instance->handle->CTRL |= CMSDK_UART_CTRL_RXIRQEN_Msk; break; } return RT_EOK; } static int uart_putc(struct rt_serial_device *serial, char c) { struct uart_instance *instance; RT_ASSERT(serial != RT_NULL); instance = (struct uart_instance *)serial->parent.user_data; instance->handle->DATA = c; return 1; } static int uart_getc(struct rt_serial_device *serial) { int ch; uint32_t state = 0; struct uart_instance *instance; RT_ASSERT(serial != RT_NULL); instance = (struct uart_instance *)serial->parent.user_data; ch = -1; if (!instance) return ch; state = instance->handle->STATE; if (state) { ch = instance->handle->DATA & 0xff; instance->handle->STATE = 0; } return ch; } static const struct rt_uart_ops _uart_ops = { uart_configure, uart_control, uart_putc, uart_getc, }; int rt_hw_uart_init(void) { struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; rt_err_t result = 0; for (rt_size_t i = 0; i < sizeof(uart_obj) / sizeof(struct uart_instance); i++) { /* init UART object */ uart_obj[i].serial.ops = &_uart_ops; uart_obj[i].serial.config = config; /* register UART device */ result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &uart_obj[i]); RT_ASSERT(result == RT_EOK); } return result; } ``` - 串口适配的主要流程: 定义串口设备结构,实现 `uart_putc`, `uart_getc`, `uart_configure`,通过 `rt_hw_serial_register` 注册串口设备,编写 串口中断的处理函数 ## 系统运行 - 以上适配了 内存、系统 tick 定时器与 MSH shell 串口后,通过 `scons --menuconfig` 配置 MSH shell 串口为 `uart0`,RT-Thread 运行起来了 ![2023-07-23_204112.png](https://oss-club.rt-thread.org/uploads/20230723/569c009663e09c8aa8101d4ddbf7067b.png) - `./qemu.sh` 运行信息 ![2023-07-23_204606.png](https://oss-club.rt-thread.org/uploads/20230723/7176065bed2b83207ed508be7d0203f0.png) - 以上,说明RT-Thread qemu mps2-an385 bsp 制作初步完成,当前初步验证,无法支持文件系统,并且其他的外设欠缺资料,因为移植宣告完成。 - 可以通过 VS Code gdb 调试,熟悉 RT-Thread 系统调用、内存分配、测试验证各个 RT-Thread 功能模块 ## 小结 - 本篇通过 bsp 适配 内存管理、串口驱动、系统 tick 定时器,让 RT-Thread 跑起来,qemu mps2-an385 bsp 在 RT-Thread 上移植适配完成。
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
813
被采纳
177
关注TA
发私信
相关文章
1
Linux下的Qemu mini2440虚拟机(32位和64位)
2
有qemu Linux的rt-thread开发环境建立吗?
3
qemu+mini2440+bootloader问题
4
QEMU gdbstub 在Win7下的bug
5
请教如何在windows下使用qemu测试rrt0.31中的例子
6
QEMU运行os问题
7
QEMU-mini2440 模拟环境上运行RT-thread这篇
8
在Ubuntu上执行qemu的configure命令checkzlib失败
9
求大舅:telnet-连接QEMU时,QEMU segmentation fault 结束
10
RealTouch打算出QEMU模拟器吗
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1518
个答案
343
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
5
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部