RT-Thread qemu mps2-an385 bsp 移植制作 :系统运行篇

news2024/11/29 0:37:55

前言

  • 前面已经让 RT-Thread 进入了 entry 入口函数,并且 调整 链接脚本,自动初始化与 MSH shell 的符号已经预留, 进入了 RT-Thread 的初始化流程

  • 接下来:从 内存管理、系统tick 定时器、适配串口 uart 驱动三个模块入手,让RT-Thread 真正运行起来

系统tick定时器

  • 可以称之为 操作系统的心跳,一般是个周期性的定时器,比如 1ms 为周期,周期性的执行。

  • 通过验证,mps2-an385 支持 systick 定时器,简单配置后,就可以实现 系统 tick 定时器功能

  • 修改完善 drv_common.c

#include <rtthread.h>
#include <board.h>
#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 定时器

在这里插入图片描述

系统内存管理

  • mps2-an385 的 RAM 4MB,当前内存配置在 board.h 中实现
#ifndef __BOARD_H__
#define __BOARD_H__

#include <rtconfig.h>

#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 串口终端
#include <rthw.h>
#include <rtthread.h>
#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 适配如下:

#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#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 运行起来了

在这里插入图片描述

  • ./qemu.sh 运行信息

在这里插入图片描述

  • 以上,说明RT-Thread qemu mps2-an385 bsp 制作初步完成,当前初步验证,无法支持文件系统,并且其他的外设欠缺资料,因为移植宣告完成。

  • 可以通过 VS Code gdb 调试,熟悉 RT-Thread 系统调用、内存分配、测试验证各个 RT-Thread 功能模块

小结

  • 本篇通过 bsp 适配 内存管理、串口驱动、系统 tick 定时器,让 RT-Thread 跑起来,qemu mps2-an385 bsp 在 RT-Thread 上移植适配完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/779673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue-组件高级(下)

一、目标 能够知道如何使用ref引用DOM和组件实例能够知道$nextTick的调用时机能够说出keep-alive元素的作用能够掌握插槽的基本用法能够知道如何自定义指令 二、目录 ref引用动态组件插槽自定义指令Table案例 ref引用 1.什么是ref引用 ref用来辅助开发者在不依赖于jQuery的…

基于Android的自助导游系统的设计与实现(论文+源码)_kaic

摘 要 随着人们的生活水平的提高&#xff0c;外出旅游已经成为人们放松休闲的主要活动之 一。传统的旅游方式都是团队组织&#xff0c;这在很大程度上制约了游客游玩的自主性。 本文充分利用无线互联网技术的优点&#xff0c;以智能手机作为移动终端&#xff0c;设计一款自助 …

react实现路由跳转动画

下载插件 npm i react-transition-group 配置路由 import { createBrowserRouter as ReactRouter,Navigate } from "react-router-dom";import App from ../App.js import Login from "../view/login.js"; import Home from "../home.js"; co…

Django笔记之in查询及date日期相关过滤操作

这一篇介绍关于范围&#xff0c;日期的筛选 inrangedateyearweekweekdayquarterhour 1、in in 对应于 MySQL 中的 in 操作&#xff0c;可以接受数组、元组等类型数据作为参数&#xff1a; Blog.objects.filter(id__in[1,2,3])对应的 SQL 是&#xff1a; select * from blo…

Linux Shell 脚本编程学习之【第4章 awk命令最详细(第二部分)】

第4章 awk命令最详细 &#xff08;第二部分&#xff09; 1 awk编程1.1 awk模式匹配 2 awk编程示例2.1 第一种调用方式2.2 第二种调用方式2.3 第三种调用方式2.4 记录和域2.5 变量运算2.6 改变分隔符 3 关系和布尔运算符3.1 匹配正则表达式~符号 1 awk编程 awk 是一种编程语言&…

【C++11】智能指针的定义 和 种类 及 使用

智能指针 定义 为什么需要智能指针 在C中&#xff0c;动态分配内存是一项常见的任务&#xff0c;但手动管理分配和释放内存可能会导致很多问题&#xff0c;如内存泄漏、悬垂指针以及多次释放同一块内存等。为了避免这些问题&#xff0c;引入了智能指针的概念&#xff0c;它们…

MySQL主从复制原理及配置

目录 一、MySQL主从复制原理 1、什么是主从复制 2、主从复制原理 二、主从复制配置 1、主服务器数据库配置 &#xff08;1&#xff09;设置server-id值并开启binlog参数&#xff0c;启用二进制日志功能后&#xff0c;重启数据库。 &#xff08;2&#xff09;建立同步账号&a…

LabVIEW基础-lvlib库

文章目录 lvlib库llb库lvlib与llb的区别lvlib常见错误断开vi与库之间的连接 lvlib库 文件-新建-库&#xff0c;创建一个项目库文件。能在项目中创建的文件类型&#xff0c;都可以在库中创建。 在lvlib上右键-添加-文件&#xff0c;将被选中的文件放到lvlib中。被添加进lvlib的…

【PostgreSQL内核学习(八)—— 查询执行(查询执行策略)】

查询执行 查询执行概述查询执行策略可优化语句和数据定义语句四种执行策略策略选择实现Portal执行的过程 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊重他人的知识产权和学术成果&#xff0c;力求遵循合理使用原则&#xff0c;并在适用的…

大数据分析案例-基于LightGBM算法构建乳腺癌分类预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

即时通信的方法和webSocket的具体使用

前言 之前遇到过需要即时通讯的场景&#xff0c;刚开始使用的是通过轮询的方式&#xff0c;定时器3秒向服务器请求一次数据&#xff0c;后面发现如果在手机端长时间打开使用此功能的页面&#xff0c;可能会发生手机发热&#xff0c;甚至卡顿的现象。最后改用webSocket&#xf…

js 过滤两个数组中的相同元素

1. filter 和 find 、some ,includes结合使用 let arr [1, 2, 3, 4, 5]; let arr2 [3, 4, 5, 6, 7];const arr3 arr.filter((item) > arr2.includes(item)); const arr4 arr.filter((item) > arr2.find((item2) > item2 item)); const arr5 arr.filter((item)…

Vue3+ElementPlus+TS实现右上角消息数量实时更新

Vue3ElementPlusTS实现右上角消息数量实时更新 背景 项目需求&#xff0c;前端右上角铃铛图标 显示接收到的消息通知&#xff0c;并且显示消息数量以及实时更新。&#xff08;一般是点击操作按钮后增加一条消息通知&#xff0c;图标上的数字也随之更新&#xff09; 【原来的想…

uniapp 微信小程序 姓名脱敏 substring报错问题:Cannot read property ‘substring‘ of undefined

效果图&#xff1a; 刘德华----------刘* 加v-if判断是因为如果是后台数据返回的字段&#xff0c;如果不加判断&#xff0c;substring的时候有可能数据还没渲染完&#xff0c;会报错 <text v-if"userName">{{userName.substring(0, 1) *}}</text>

【Duilib】错误:红色波浪线,无法打开源文件“stdafx.h”

问题 Duilib工程可以编译&#xff0c;但是智能提示&#xff1a;错误&#xff1a;红色波浪线&#xff0c;无法打开源文件“stdafx.h”。 解决方法 1、确认stdafx.h文件位置在vcxproj文件同一目录&#xff0c;并且stdafx.h已添加至DUILIB工程。 2、DUILIB项目属性\C/C\常规 页面…

(css)原生html实现遮罩层弹窗

(css)原生html实现遮罩层弹窗 效果&#xff1a; html <div class"overlay"><div class"content"><!-- 需要遮罩的内容 --> <el-table :data"tableData" size"mini" class"table-class" border stripe…

AutoSAR系列讲解(实践篇)7.4-实验:配置SWCRTE

注意: 实验篇是重点,有条件的同学最好跟着做一遍,然后回头对照着7.1-7.3理解其配置的目的和意义。实验下篇将在7.7节中继续做 一、实验概览 1、实验目的 通过本次实验,主要是让大家对Dev的配置有一个全流程的学习。这里会用到前两节的内容,将其串联起来,让大家能完整的…

【git基本使用】

初识git 一、git安装 1.1 Linux-centos 如果你的的平台是centos&#xff0c;安装git相当简单&#xff0c;以我的centos7.6为例&#xff1a; ⾸先&#xff0c;你可以试着输⼊Git&#xff0c;看看系统有没有安装Git&#xff1a; git-bash: git: command not found 出现像上⾯…

linux同时安装JDK8和JDK11并指定默认版本

1、安装OpenJDK11 yum install java-11-openjdk2、安装OpenJDK 8 yum install java-8-openjdk3.查看Java版本列表 alternatives --list4、查看当前Java版本 java -version5、更改Java版本 alternatives --config java6、设置JAVA_HOME环境变量 vi /etc/profile.d/java.sh…

多线程(JavaEE初阶系列3)

目录 前言&#xff1a; 1.中断一个线程 2.等待一个线程-join() 2.1join()无参调用的使用 2.2join()有参调用的使用 3.线程的状态 3.1观察线程的所有状态 4.多线程带来的风险—线程安全 4.1观察线程不安全 4.2该问题出现的原因 4.3线程不安全问题的解决 4.3.1synchro…