修订历史
版本号 | 修订日期 | 修订的章节 | 修订的内容 |
---|---|---|---|
1.0 | 2019/11/19 | N/A | 初始版本 |
2.0 | 2020/1/22 | N/A | 修正了部分文字说明 |
3.0 | 2021/9/01 | 4、5、6 | 评估板更新为Nuclei MCU200T IDE更新为Nuclei Studio |
1. 概述
N100内核用户将通过本文,快速掌握该内核应用开发的必要知识点。包括:内核及配套SoC的背景知识介绍、应用实例解析及其软硬件快速启动方法。
中断应用,是N100内核应用中的重点和难点。本文第一个应用实例,将着重讲解N100内核的中断使用方法。通过对例程解析,使用户在最短的时间内,熟练掌握中断应用并移植到定制化应用项目的开发中。
为了使用户能对以上介绍的应用实例,进行快速启动和实践操作。本文将基于芯来科技推出的蜂鸟FPGA评估板,介绍硬件快速启动方法和应用实例的调试运行流程。
2. 背景知识——N100系列处理器内核
Nuclei N100处理器内核(简称N100内核)主要面向极低功耗与极小面积的场景而设计,非常适合于替代传统的8051内核或者ARM Cortex-M0系列内核应用于IoT或其他低功耗场景。
详情请参见《Nuclei_N100系列简明数据手册》了解其详情。
2.1. 指令集介绍
N100内核遵循标准的RISC-V指令集标准。
详情请参见《Nuclei_N100系列指令架构手册》第1.1节和第1.2节,了解其详情。
2.2. CSR寄存器
RISC-V的架构中定义了一些控制和状态寄存器(Control and Status Register,CSR),用于配置或记录一些运行的状态。CSR寄存器是处理器核内部的寄存器,使用其专有的12位地址编码空间。详情请参见《Nuclei_N100系列指令架构手册》第1.3节了解其详情。
2.3. N100系列内核特权架构介绍
N100系列内核支持一个特权模式(Privilege Modes):机器模式(Machine Mode)。
2.4. N100系列内核异常机制
异常(Exception)机制,即处理器核在顺序执行程序指令流的过程中突然遇到了异常的事情而中止执行当前的程序,转而去处理该异常。异常发生后,处理器会进入异常服务处理程序。
详情请参见《Nuclei_N100系列指令架构手册》第3章了解其详情。
2.5. N100系列内核中断机制
中断(Interrupt)机制,即处理器核在顺序执行程序指令流的过程中突然被别的请求打断而中止执行当前的程序,转而去处理别的事情,待其处理完了别的事情,然后重新回到之前程序中断的点继续执行之前的程序指令流。详情请参见《Nuclei_N100系列指令架构手册》第4章了解其详情。
2.6. N100系列内核TIMER和IRQC介绍
2.6.1. TIMER简介
计时器单元(Timer Unit,TIMER),在N100系列内核中主要用于产生计时器中断(Timer Interrupt)和软件中断(Software Interrupt)。详情请参见《Nuclei_N100系列指令架构手册》第5.1节了解其详情。
2.6.2. IRQC简介
N100系列内核支持在RISC-V标准CLIC基础上简化而来的“私有中断控制器(Priviate Interrupt Controller,简称IRQC)”,用于管理所有的中断源。详情请参见《Nuclei_N100系列指令架构手册》第4.3节了解其详情。
IRQC单元生成一根中断线,发送给处理器内核(作为中断目标),其关系结构如图2-1所示。
2.6.3. 中断屏蔽
N100内核的中断可以被屏蔽掉, CSR寄存器mstatus的MIE域控制中断的全局使能。
对于不同的中断类型而言,IRQC统一管理外部中断、软件中断以及计时器中断。IRQC为每个中断源分配了各自的中断使能寄存器,用户可以通过配置IRQC寄存器来管理各个中断源的屏蔽,达到使能或屏蔽某一个对应的中断的效果。详情请参见《Nuclei_N100系列指令架构手册》第4.4节了解其详情。
2.6.4. 中断级别、优先级与仲裁
当多个中断同时出现时,需要进行仲裁。对于N100系列内核处理器而言,IRQC统一管理所有的中断。IRQC的每个中断源有固定的的优先级(中断源的编号越大则优先级越高),当多个中断同时发生时,IRQC会仲裁出优先级最高的中断,如图 2-2中所示。详情请参见《Nuclei_N100系列指令架构手册》第4.5节了解其详情。
在下文讲解的Demo_irqc实例中,按键1外部中断和按键2外部中断的使用的中断源编号,分别为3、4。当这2个中断并发时,经过仲裁后,内核将优先响应优先中断源编号为4的中断,即按键2外部中断。
2.6.5. 中断服务程序
当处理器内核响应并进入中断后,立即根据中断源编号跳转至该中断对应的中断服务程序开始执行。譬如下文讲解的Demo_irqc实例中,函数button_1_handler()是按键1外部中断的服务程序,函数button_2_handler()是按键2外部中断的服务程序。
注意:Nuclei的N200及以上型号(如N200,N300,N600,N900等)支持向量模式和非向量两种模式。
2.6.6. 中断嵌套
N100系类内核主要面向超低功耗场景的超小面积的实现,为了简化设计,缩减面积,N100系类内核不支持中断嵌套。
注意:Nuclei的N200及以上型号(如N200,N300,N600,N900等)支持中断嵌套特性。
2.6.7. 中断咬尾
N100系类内核主要面向超低功耗场景的超小面积的实现,为了简化设计,缩减面积,N100系类内核不支持中断咬尾。
注意:Nuclei的N200及以上型号(如N200,N300,N600,N900等)支持中断咬尾特性。
3. 背景知识——N100系列内核配套SoC
N100系列内核配套的MCU级别SoC,该SoC用于N100系列处理器内核的原型验证和用户评估。
3.1. N100系列内核配套SoC框图
N100系列内核配套SoC的框图如图 3-1所示:
3.2. N100系列内核配套SoC储存资源
如图3-1中所示,N100系列内核配套SoC中的存储器资源分为片上存储资源和片外Flash存储资源。
有关N100系列内核配套SoC存储资源的详细介绍,请参见文档《Nuclei_N100系列配套SoC介绍》。
3.3. N100系列内核配套SoC外设介绍
有关N100系列内核配套SoC外设的详细介绍,请参见文档《Nuclei_N100系列配套SoC介绍》。
4. 应用实例解析——Demo_irqc
4.1. Demo_irqc简述
Demo_irqc程序是一个完整的示例程序,相比Dhrystone和CoreMark这样纯粹的跑分程序,Demo_irqc更加接近一个常见的嵌入式应用程序,它使用到了SoC系统中的外设,调用了中断服务程序等,其功能简述如下:
-
通过printf函数输出一串“RISC-V”logo的字符,printf输出将会通过UART串口重定向至主机PC的屏幕上。
-
等待通过getc函数输入一个字符,然后将得到的字符通过printf输出到主机PC的屏幕上。
-
进入死循环不断地对SoC的GPIO 13的输出管脚进行翻转,如果使用示波器观测此GPIO输出管脚,可以看到其产生规律的输出方波。
-
评估板上的两个用户按键(BTN_L和BTN_R),位置如图4-1所示,分别对应N100配套SoC的GPIO[0]和GPIO[1]管脚,这两个GPIO管脚各自作为一个IRQC的外部中断,在其中断服务程序中会将对GPIO[21]、GPIO[22]的输出管脚(分别对应评估板的绿灯、蓝灯)进行设置,从而造成评估板上绿灯、蓝灯的颜色发生变化。
4.2. Demo_irqc程序代码结构
用户可以通过GitHub链接:https://github.com/riscv-mcu/n100-sdk,获取完整程序代码。
在n100-sdk环境中,Demo_irqc示例程序的相关代码结构如下所示。
n100-sdk // 存放n100-sdk的目录
n100-sdk // 存放n100-sdk的目录
|----software // 存放示例程序的源代码
|----Demo_irqc // Demo_irqc示例程序目录
|----demo_irqc.c //Demo_irqc的示例Demo程序代码
|----Makefile //Makefile脚本
Makefile为主控制脚本,其代码片段如下:
//指明生成的elf文件名
TARGET = Demo_irqc
//指明Demo_irqc程序所需要的特别的GCC编译选项
CFLAGS += -O2
BSP_BASE = ../../bsp
//指明Demo_irqc程序所需要的C源文件
C_SRCS += Demo_irqc.c
//调用板级支持包(bsp)目录下的common.mk
include $(BSP_BASE)/core/env/common.mk
4.3. Demo_irqc程序解析
4.3.1. 主程序流程图
4.3.2. 用户按键中断处理函数流程图
4.3.3. 快速移植中断应用
本节将结合Demo_irqc源码来详细介绍如何快速使用N100系列处理器内核中断。
-
步骤一:
-
外部中断GPIO初始化
// n100-sdk/software/Demo_irqc/Demo_irqc.c代码片段
#define BUTTON_1_GPIO_OFFSET 0
#define BUTTON_2_GPIO_OFFSET 1
//按键1(BTN_L)对应管脚为MCU_GPIO 0
//按键2(BTN_R)对应管脚为MCU_GPIO 1
#define IRQC_INT_DEVICE_BUTTON_1 (SOC_IRQC_INT_GPIO_BASE + BUTTON_1_GPIO_OFFSET)
#define IRQC_INT_DEVICE_BUTTON_2 (SOC_IRQC_INT_GPIO_BASE + BUTTON_2_GPIO_OFFSET)
//配置IRQC中断源映射
//设置评估板上按键相关的GPIO寄存器
//通过“与”操作将GPIO_OUTPUT_EN寄存器某些位清0,即将评估板按键对应的GPIO输出使能关闭
GPIO_REG(GPIO_OUTPUT_EN) &=
~(
(0x1 << BUTTON_1_GPIO_OFFSET) |
(0x1 << BUTTON_2_GPIO_OFFSET)
);
//通过“与”操作将GPIO_PULLUP_EN寄存器某些位清0,即将评估板按键对应的GPIO输入上拉关闭
GPIO_REG(GPIO_PULLUP_EN) &=
~(
(0x1 << BUTTON_1_GPIO_OFFSET) |
(0x1 << BUTTON_2_GPIO_OFFSET)
);
//通过“或”操作将GPIO_INPUT_EN寄存器某些位设置为1,即将评估板按键对应的GPIO输入使能关闭
GPIO_REG(GPIO_INPUT_EN) |=
(
(0x1 << BUTTON_1_GPIO_OFFSET) |
(0x1 << BUTTON_2_GPIO_OFFSET)
);
//通过“或”操作将GPIO_RISE_IE寄存器某些位设置为1,即将评估板按键对应的GPIO管脚设置为上升沿触发的中断来源
GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_1_GPIO_OFFSET);
GPIO_REG(GPIO_RISE_IE) |= (1 << BUTTON_2_GPIO_OFFSET);
- 步骤二:IRQC初始化
Demo_irqc例程中,使用函数config_irqc_irqs ()完成对计时器中断和两个按键中断的初始化。其代码片段如下:
// n100-sdk/software/Demo_irqc/Demo_irqc.c代码片段
//设置irqc_irq3的中断处理函数为BUTTON_1_HANDLER
#define BUTTON_1_HANDLER irqc_irq3_handler
//设置irqc_irq4的中断处理函数为BUTTON_2_HANDLER
#define BUTTON_2_HANDLER irqc_irq4_handler
void config_irqc_irqs(){
//通过配置IRQC的寄存器使能“”计时器中断“和”“评估板两个按键的GPIO中断”。注意://IRQC_enable_interrupt的函数原型定义在bsp/core/drivers/func.c中
irqc_enable_interrupt (IRQC_INT_DEVICE_BUTTON_1);
irqc_enable_interrupt (IRQC_INT_DEVICE_BUTTON_2);
//评估板两个按键BTN_L和BTN_R的GPIO中断分别使用优先级为3和4的中断
}
- 步骤三:编写中断处理函数
在MCU200T FPGA评估板上,例程中使用到的两个用户按键,分别连接至GPIO0和GPIO1上,这两个GPIO管脚各自作为一个IRQC的外部中断。Demo_irqc使用这两个外部中断,所以定义了button_1_handler和button_2_handler分别作为它们的中断处理函数,其代码如下:
//向量处理模式时,由于在跳入中断服务程序之前,处理器并没有进行上下文的保存,因此,理论上中断服务程序函数本身不能够进行子函数的调用(即必须是 Leaf Function)。
//此处BUTTON_1_HANDLE明显会调用其他的子函数,如果不加处理则会造成功能的错误。为了规避这种情形,当中断被设置为“向量模式”时,用户必须使用特殊的 __attribute__ (( interrupt))来修饰该中断服务程序函数,那么编译器会自动的进行判断,当编译器发现该函数调用了其他子函数时,便会自动的插入一段代码进行上下文的保存。
void __attribute__ ((interrupt)) BUTTON_1_HANDLER(void) {
printf ("%s","----Begin button1 handler\n");
// 点亮绿灯
GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << GREEN_LED_GPIO_OFFSET);
GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_1_GPIO_OFFSET);
// 等待2秒钟
wait_seconds(2);
printf ("%s","----End button1 handler\n");
};
void __attribute__ ((interrupt)) BUTTON_2_HANDLER(void) {
printf ("%s","--------Begin button2 handler\n");
// 点亮蓝灯
GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << BLUE_LED_GPIO_OFFSET);
GPIO_REG(GPIO_RISE_IP) = (0x1 << BUTTON_2_GPIO_OFFSET);
// 等待2秒钟
wait_seconds(2);
printf ("%s","--------End button2 handler\n");
};
有关N100系列内核中断机制以及中断控制器的详细介绍,请参见文档《Nuclei_N100系列指令架构手册》第4章和第5章内容。
5. 快速上手——基于n100-sdk的Demo_irqc软硬件快速上手
用户购买到的MCU200T FPGA评估板,在出厂时如果已经预烧写了N100内核及其配套SoC,用户可以直接把评估板,“当作”一颗集成了N100系列内核的MCU来进行开发和调试。如果用户需要自己烧写N100内核及其配套SoC,关于FPGA评估板程序的烧写方法,请用户参见文档《Nuclei_N100系列配套FPGA实现》。
下文将介绍在Linux环境下,使用n100-sdk来进行软硬件快速启动。SDK使用Linux Makefile进行项目和文件的组织,适用于开发水平较高的用户。
注意:关于Linux环境下SDK的详细介绍和更多的软件示例,请用户参见《Nuclei_N100系列SDK使用说明》。
5.1. 第一步:硬件线缆连接
-
将MCU200T FPGA评估板的“DC 12V 电源输入接口”通过配套稳压源与电源插座连接;
-
将蜂鸟下载器通过排线连接至MCU200T FPGA评估板;
-
将蜂鸟下载器连接至调试主机PC的USB接口;
-
将评估板电源开关拨至“ON”档,接通电源。
5.2. 第二步:设置下载器在Linux系统中的USB权限
如果使用Linux操作系统,需要按照如下步骤保证正确的设置蜂鸟下载器的USB权限。详细内容请参见文档《Nuclei_N100系列SDK使用说明》第2章。
5.3. 第三步:将Demo_irqc程序下载至评估板并运行
Demo_irqc示例可运行于N100内核及配套SoC评估板平台中,使用基于Linux的SDK来进行演示。关于Linux环境下SDK的详细介绍,请用户参见《Nuclei_N100系列SDK使用说明》。
具体操作方法按照如下步骤进行:
// 注意:确保在n100-sdk中正确的安装了RISC-V GCC工具链,请参见《Nuclei_N100系列SDK使用说明》了解其详情。
// 步骤一:参照《Nuclei_N100系列SDK使用说明》中描述的方法,编译Demo_irqc示例程序,使用如下命令:
make dasm PROGRAM=demo_irqc CORE=n101 DOWNLOAD=flash
//注意:此处指定DOWNLOAD=flash选项,则采用“将程序从Flash上载至ILM进行执行的方式”进行编译,请参见《Nuclei_N100系列SDK使用说明》了解更多详情。
// 步骤二:参照《Nuclei_N100系列SDK使用说明》中描述的方法,将编译好的Demo_irqc程序下载至FPGA评估板中,使用如下命令:
make upload PROGRAM=demo_irqc CORE=n101 DOWNLOAD=flash
// 步骤三:参照《Nuclei_N100系列SDK使用说明》中描述的方法,在FPGA评估板上运行Demo_irqc程序:
// 由于示例程序将需要通过UART打印结果到主机PC的显示屏上。参考《Nuclei_N100系列SDK使用说明》
// 所述方法将串口显示电脑屏幕设置好,使得程序的打印信息能够显示在电脑屏幕上。
//
// 由于步骤二已经将程序烧写进FPGA评估板的Flash之中,因此每次按评估板的
// MCU_RESET按键,则处理器复位开始执行Demo_irqc程序,并将RISC-V字符串打印至主
// 机PC的串口显示终端上,如图 5-3所示,然后用户可以输入任意字符(譬如字母y),
// 程序继续运行,通过按评估板上的BTN_L、BTN_R按键可分别点亮绿灯、蓝灯。
6. 快速上手——基于Nuclei Studio IDE的Demo_irqc软硬件快速上手
用户购买到的MCU200T FPGA评估板,在出厂时如果已经预烧写了N100内核及其配套SoC,用户可以直接把评估板,“当作”一颗集成了N100系列内核的MCU来进行开发和调试。如果用户需要自己烧写N100内核及其配套SoC,关于FPGA评估板程序的烧写方法,请用户参见文档《Nuclei_N100系列配套FPGA实现》。
N100系列提供图形化集成开发环境(IDE,Integrated Development Environment)——Nuclei Studio。用户可以基于上述的FPGA评估板,结合IDE,进行完整的嵌入式软件开发和调试,详细介绍请参见参见单独文档《Nuclei_N100系列IDE使用说明》。
注意:IDE使用可视化集成开发环境进行项目和文件的组织,适用于习惯图形化开发环境的用户。