IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于qemu-riscv从0开始构建嵌入式linux系统ch3. 添加中断控制器、串口、pflash支持 -> 正文阅读

[嵌入式]基于qemu-riscv从0开始构建嵌入式linux系统ch3. 添加中断控制器、串口、pflash支持

基于qemu-riscv从0开始构建嵌入式linux系统ch3. 添加中断控制器、串口、pflash支持

添加串口支持

真实板卡的初期调试中,串口打印可谓神器,几乎所以的IC都会带有串口这个外设,因此我们也需要添加串口到我们的定义中。

  • 首先添加三个串口基地址,之所以添加三个的目的是为了后面我们可能会在多个权限域空间内跑不同的系统因此可能需要不同权限的串口打印输出。
{
    [QUARD_STAR_UART0] = { 0x10000000,         0x100 },
    [QUARD_STAR_UART1] = { 0x10001000,         0x100 },
    [QUARD_STAR_UART2] = { 0x10002000,         0x100 },
}
  • 在初始化函数中调用serial_mm_init创建串口实例,这个串口仿真ns16550a的定义,在后续opensbi、u-boot、kernel中都自带这个串口的驱动,方面后面移植。
serial_mm_init(system_memory, memmap[QUARD_STAR_UART0].base,
    0, qdev_get_gpio_in(DEVICE(mmio_plic), QUARD_STAR_UART0_IRQ), 399193,
    serial_hd(0), DEVICE_LITTLE_ENDIAN);
serial_mm_init(system_memory, memmap[QUARD_STAR_UART1].base,
    0, qdev_get_gpio_in(DEVICE(mmio_plic), QUARD_STAR_UART1_IRQ), 399193,
    serial_hd(1), DEVICE_LITTLE_ENDIAN);
serial_mm_init(system_memory, memmap[QUARD_STAR_UART2].base,
    0, qdev_get_gpio_in(DEVICE(mmio_plic), QUARD_STAR_UART2_IRQ), 399193,
    serial_hd(2), DEVICE_LITTLE_ENDIAN);

注意上述qdev_get_gpio_in函数用来配置串口中断信号,因此我们必须要增加中断控制器的相关代码才能正确使用串口。

添加中断控制器

既然串口需要使用到中断,后续很多外设都需要中断控制器,因此我们在这一节将中断控制器一并添加了。

  • 依然是增加中断控制器基地址,RISCV标准的中断控制器分为两部分内核中断CLINT(Core Local Interrupt)和外设中断控制器Platform-Level Interrupt Controller(PLIC),CLINT在每一个smp架构下每个core都各有自己私有的中断,PLIC则是所以core共用的外部中断控制器。
{
    [QUARD_STAR_CLINT] = {  0x2000000,       0x10000 },
    [QUARD_STAR_PLIC]  = {  0xc000000, QUARD_STAR_PLIC_SIZE(QUARD_STAR_CPUS_MAX * 2) },
}
  • 在初始化函数内,分别使用以下两个函数创建相关ip,注意要根据内核smp个数分别为每个core创建对应的资源。
sifive_clint_create
sifive_plic_create

截止目前,我们有了中断控制器和串口,就可以进行简单的串口功能测试了,但遗憾的是目前还没有可存放我们的固件程序并加载到ddr中使用的设备,因此我们打算增加pflash仿真器件作为固件的载体。

添加pflash支持

pflash是并行flash,目前真实的器件已经很少见了,市面上常见的是qspi的nor flash作为低阶固件的载体,而nor flash一般都支持XIP运行,那么基本上等同于pflash了,那么为了方便我们就使用qemu提供的plash作为早期固件的载体。

  • 依然是增加pflash的基地址,这里不是寄存器,而是pflash的数据起始地址,大小是32M,完全足够我们存放固件了。
{
    [QUARD_STAR_FLASH] = { 0x20000000,     0x2000000 },
}
  • 创建pflash器件并映射到我们的系统总线对应地址上,最后将其关联到“-drive if=pflash,bus=0,unit=0,…………”的qemu参数上,这样启动仿真时就可以加载固件文件到这片flash上,以下这些代码都不难理解,这里不在赘述。
static PFlashCFI01 *quard_star_flash_create(RISCVVirtState *s,
                                       const char *name,
                                       const char *alias_prop_name)
{
    DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);

    qdev_prop_set_uint64(dev, "sector-length", QUARD_STAR_FLASH_SECTOR_SIZE);
    qdev_prop_set_uint8(dev, "width", 4);
    qdev_prop_set_uint8(dev, "device-width", 2);
    qdev_prop_set_bit(dev, "big-endian", false);
    qdev_prop_set_uint16(dev, "id0", 0x89);
    qdev_prop_set_uint16(dev, "id1", 0x18);
    qdev_prop_set_uint16(dev, "id2", 0x00);
    qdev_prop_set_uint16(dev, "id3", 0x00);
    qdev_prop_set_string(dev, "name", name);

    object_property_add_child(OBJECT(s), name, OBJECT(dev));
    object_property_add_alias(OBJECT(s), alias_prop_name,
                              OBJECT(dev), "drive");

    return PFLASH_CFI01(dev);
}

static void quard_star_flash_map(PFlashCFI01 *flash,
                            hwaddr base, hwaddr size,
                            MemoryRegion *sysmem)
{
    DeviceState *dev = DEVICE(flash);

    assert(QEMU_IS_ALIGNED(size, QUARD_STAR_FLASH_SECTOR_SIZE));
    assert(size / QUARD_STAR_FLASH_SECTOR_SIZE <= UINT32_MAX);
    qdev_prop_set_uint32(dev, "num-blocks", size / QUARD_STAR_FLASH_SECTOR_SIZE);
    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);

    memory_region_add_subregion(sysmem, base,
                                sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
                                                       0));
}

s->flash = quard_star_flash_create(s, "quard-star.flash0", "pflash0");
pflash_cfi01_legacy_drive(s->flash, drive_get(IF_PFLASH, 0, 0));
quard_star_flash_map(s->flash, virt_memmap[QUARD_STAR_FLASH].base,
                        virt_memmap[QUARD_STAR_FLASH].size, system_memory);
  • 最后修改quard_star_setup_rom_reset_vec函数中bootrom的跳转地址为pflash上的地址。

到这里本篇顺利完成。这一节主要添加中断控制,串口,flash。下一篇就要开始制作一个简单的固件加载到flash中简单测试以下串口输出是否正常。

本教程的
github仓库:https://github.com/QQxiaoming/quard_star_tutorial
gitee仓库:https://gitee.com/QQxiaoming/quard_star_tutorial
本节所在tag:ch3

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-10 11:36:45  更:2021-07-10 11:36:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 9:50:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计