- 2024-06-15
-
发表了主题帖:
《RISC-V 开放架构设计之道》- RISC-V开放架构设计简读
一、前言
感谢eeworld电子工程世界提供《RISC-V开放架构设计之道》书籍测评,书中并没有过多繁琐介绍riscv的概念,也没有过多强调riscv的好处,更多介绍的是riscv的简洁、免费、开放的思想。
如同书中一位大佬推荐所说的:这本方便的小书轻松地总结了RISC-V指令集架构所有的基本要素,是学生和从业者的完美参考指南。
RISC-V,是比较大体、宽泛的概念,但是书中内容很简短,内容插入了不少插图以及RISCV的参考卡,说是参考指南一点也不过分;加之目录介绍很清晰,从riscv32的基础整数指令集RV32I、乘法和除法指令集M扩展、原子指令集A扩展、单双精度浮点数指令集RV32F/RV32D、压缩指令RV32C、以及汇编语言和向量RV32V。以及后续的RV64介绍。
而刚好先楫的处理器作为典型标准的RISCV处理器,当然也支持上述的指令集,并且还有所扩充。以实际的硬件进行书籍分享是最好不过的思路了。比如先楫的HPM5300系列。
本系列文章更多是讲一些基础只知识,利用HPM5300EVK配合SEGGER Embedded Studio这个IDE通过查看机器码和汇编来分析RISCV的一些指令集,以此能对riscv有一定的了解兴趣。
本书内容目录比较多,系列文章定期分享RISCV的每个指令集基础。
二、导读
如果想要接触riscv,那么典型的reference card(参考卡)不可或缺,你会发现相比其他的指令集架构,riscv真的相对简洁了不少(基础的就只有两页),而且操作码7位,相当可自由扩充127个扩展指令,这也是riscv的开放自由思想。这里截图一小部分,需要了解的可以搜下riscv cheat sheet。
链接:https://www.cl.cam.ac.uk/teaching/1617/ECAD+Arch/files/docs/RISCVGreenCardv8-20151013.pdf
(一)RV32I指令格式
如书中描述,RV32I 基础指令集的一页图形表示。 对于每幅图, 将有下划线的字母从左到右连接起来,即可组成完整的 RV32I 指令集。对于每一个图,集合标志{}内列举了指令的所有变体,变体用加下划线的字母或下划线字符_表示。特别的,下划线字符_表示对于此指令变体不需用字符表示。 例如,下图表示了这四个 RV32I 指令: slt, slti, sltu, sltiu:
书中展示了6种基本指令格式,分别是用于寄存器-寄存器操作的 R 类型指令,用于短立即数和访存 load 操作的 I 型指令,用于访存 store 操作的 S 型指令,用于条件跳转操作的 B 类型指令,用于长立即数的 U 型指令和用于无条件跳转的 J 型指令。
这里使用最简单的U类型种的lui指令,配合利用HPM5300EVK配合SEGGER Embedded Studio来进行说明上述所说的指令格式是什么意思。
随便打开hpm_sdk一个例子,从左边的汇编窗口找到lui的汇编,比如以下:
可以看到,ses这个IDE对于汇编和机器码呈现还是是否直观的,对于不熟悉gdb调试又想查看汇编的开发者是十分友好的。
对于左边的8000452a指的是存储到flash的机器码的flash地址,中间的E40007B7就是机器码,最右边就是汇编部分。
hpm单片机支持压缩指令集RV32C,所以机器码有些会是16位,这对于固件空间的缩小利用是有一定帮助的。
可以分析下E40007B7这个机器码对应的Lui指令格式,如下图可看到
E40007B7的低7位代表操作码opcode,也就是lui的操作码(0b0110111),7到11bit是5位目的寄存器(0b01111),这很奇妙,5bit宽度刚好是32,对应的就是寄存器的长度(32bit),换成十六进制就是15,对应的通用寄存器就是X15,也就是别名a5寄存器。
高11位就是立即数,对应的十六进制就是0xE4000,最终根据该机器码可以反汇编得到:
把一个20位的立即数0xE4000加载到a5寄存器,对应的汇编指令就是:lui a5, 0xE4000,刚好可以对上ses IDE的汇编显示。
(二)RISCV通用寄存器
无论是RISCV32还是RISCV64,他的通用寄存器的数量都是32个,分别是x0~x31,当然为了方便汇编编写,每个寄存器也有别名,在参考卡中如下:
RISC-V 有足够多的寄存器来达到两全其美的结果:既能将操作数存放在寄存器中,同时也能减少保存和恢复寄存器的次数。其中的关键在于,在函数调用的过程中不保留部分寄存器存储的值,称它们为临时寄存器;另一些寄存器则对应地称为保存寄存器。不再调用其它函数的函数称为叶函数。当一个叶函数只有少量的参数和局部变量时,它们可以都被存储在寄存器中,而不会“溢出(spilling)”到内存中。但如果函数参数和局部变量很多,程序还是需要把寄存器的值保存在内存中,不过这种情况并不多见。
这里说明下caller是调用者,调用(或执行)一个函数的代码段或者函数,是主动发起函数调用的一方,可以理解是"甲方"。
callee是被调用者,被调用的函数本身,是被动接收函数调用并且执行对应操作的一方,可以理解是"乙方"。
从上面的表格知道,从通用寄存器上看,X0到X31,调用者需要保存的通用寄存器16个,剩下的是被调用者需要保存的寄存器。
这里可以从函数调用阶段来进行说明通用寄存器的作用,配合利用HPM5300EVK配合SEGGER Embedded Studio,使用helloworld例子来说明。
函数调用基本分为以下几个阶段,在书中也提到:
1、进入到被调用者函数的开始位置(caller需要保存的)
2、将函数传参存储到指定寄存器上
这里就是上图的x10~x17,相比其他指令集架构参数依赖于内存,也就是需要保存在栈中,riscv反而可以通过寄存器保存参数,最多可以存储8个参数,当然超过的也会存储到内存中。一般应用还是推荐不要多余8个参数传参。
那么我们进入到board_timer_create API中,传参是300和board_led_toggle函数指针。那么将会存储在x10和x11这两个寄存器上。
可以看到,x10现在是300,是符合预期的,对于x11是0x8000669e,我们可以在SES IDE中的汇编窗口查到该函数地址。
0x8000669e对应的就是board_led_toggle,这也是符合预期的。
3、获取函数局部资源变量保存在寄存器,并执行函数中的指令,可以看到寄存器窗口会发生不同的赋值变化
4、执行完毕之后将返回值存储到调用者能够访问的位置(X10寄存器),恢复寄存器,出栈释放局部资源
5、返回进行下一个调用函数位置。
在ses IDE中也展示了main调用者主函数调用被调用者函数的一些汇编代码过程。
三、总结
1、riscv的书籍众多,RISC-V开放架构设计之道这本书籍值得阅读,书中内容简洁但又不缺完整,而且丰富的参考卡可作为riscv的日常参考指南所用
2、对于技术书籍,需要有一个实操机会可以加深印象,先楫的处理器内核遵守risv规范,具有多种扩展指令集,而其配套的SEGGER Embedded Studio这个IDE通过查看机器码和汇编,让一些不熟悉gdb调试的开发者,是一个值得推荐的实操平台。
- 2024-06-04
-
回复了主题帖:
先楫开发板HPM6360EVK下载,GDB连接失败 Connecting ‘GDB Server’ using ‘local...
估计Openocd在后台运行,杀掉这个后台吧,任务管理器打开找下用户的运行后台,找到openocd.exe,点结束任务。
- 2024-05-24
-
回复了主题帖:
共读入围:《RISC-V开放架构设计之道》
个人信息无误
- 2024-02-27
-
回复了主题帖:
【先楫HPM6750EVK2测评】求教SGGER Embeded Studio中jlink如何配置
lugl4313820 发表于 2024-2-27 14:19
连接是成功的,但是go了以后就提示这个。
请用start_gui工具生成,不要用ses本身的csp生成,入门不合适。
-
回复了主题帖:
【先楫HPM6750EVK2测评】求教SGGER Embeded Studio中jlink如何配置
- 2024-02-22
-
发表了主题帖:
《RT-Thread设备驱动开发指南》进阶篇--动手驱动先楫LCD外设
一、概述
经过上一篇的《《RT-Thread设备驱动开发指南》基础篇--以先楫bsp的hwtimer设备为例》阐述,可以大致了解到RT-thread设备驱动开发的方法步骤,开发指南中的进阶篇外设主要是比基础篇外设复杂点的外设设备,分别是SDIO、Touch、LCD、sensor、MTD nor、MTD nand、脉冲编码器、加解密设备、PM设备。
对于进阶篇的外设,本文不对先楫已经支持的进阶外设进行阐述,而是进行一次动手实践驱动一个先楫尚未适配的驱动外设-LCD,来更加深入开发RT-thread的设备驱动。
二、开发方法
(一)RT-thread的LCD驱动框架介绍
LCD驱动,跟其他外设也类似,无非就是IO设备管理框架-->LCD设备驱动框架->LCD设备驱动。
IO设备管理层主要为设备框架提供统一的操作接口,包括rt_device_read/write/open/close/control等。而做好一个外设驱动,最终的目标就是应用上使用这些统一操作接口,无需理会底层操作。
LCD设备驱动框架层是RT-thread对LCD基本功能的抽象,是一层通用的软件层,和硬件平台无关,抽象了LCD设备的类型定义和具体的操作方法,其框架源码在rtdef.h中
LCD的信息结构 rt_device_graphic_info,定义了像素格式,位宽,宽高、显存地址等。
LCD的操作接口rt_device_graphic_ops,定义了LCD的绘图操作,比如像素点、画线等操作。
LCD的控制命令,比如更新显存、开关LCD、获取信息、等待VSYNC等。
LCD的像素格式
可见,RT-thread对于LCD的抽象操作还是比较直观,完成以上的操作,再借助IO设备管理层提供的注册接口rt_device_register进行注册,即可使用IO设备管理接口操作LCD。
(二)先楫LCDC外设介绍
对于先楫的LCDC外设硬件控制器
在HPM6750上有RGB控制器,支持24位的RGB显示接口
在HPM6800上,支持2 个 4 Lane MIPI-DSI/LVDS-Tx 显示接口
对于在RT-thread上,也支持了hpm_sdk的panel组件,涵盖了hpm6750和hpm6800的显示适配。
对于hpm_sdk的panel组件介绍,可以参考文章《[hpm_application]选先楫!爽跑1080P or 720Pmipi屏的单片机》
对于使用LCD硬件控制器(RGB,MIPI DSI)通信的屏幕,LCD设备驱动只需要实现LCD设备的操作方法struct rt_device_ops即可,比如control接口里更新硬件控制器的缓存区即可控制屏幕绘图。
如此一来,配合先楫适配好的RT-thread BSP,可以很顺手得适配好LCD的驱动,按先楫BSP的driver照葫芦画瓢个drv_lcd。
(三)创建LCD设备
下面来创建先楫的LCD设备。LCD设备模型从struct rt_device结构体中派生,并添加自己的私有数据。
成员主要有LCD的基地址,中断号,互斥锁,LCD名称等。
实例化一个lcd的设备数组,可以存在多个lcd设备,里面包含设备的初始化参数。
(四)实现LCD设备的操作方法
按照以上的定义,已经实例化了一个hpm_lcd_ops结构体,然后需要实现对应的操作函数,也就是LCD设备定义操作方法。对于LCD设备来说,只有其中的init和control操作方法才有意义,而本文实现的也是这两个接口,分别是hpm_lcd_init、hpm_lcd_control。
1、init:初始化LCD设备
对于该操作方法,先楫的LCD驱动代码不需要执行任何操作,只需要在注册初始化LCD即可。
2、control:控制LCD设备
应用程序也可以对LCD设备进行控制,通过control方法完成。原型如下:
其中参数cmd包含了控制LCD的方式,通用设备命令可取以下宏定义:
当然在最新的rtthread 5.0.2当中也更新了几个命令
本文在这里主要实现以下几个命令
(1)RTGRAPHIC_CTRL_RECT_UPDATE 更新显存
对于显存的更新,可以使用控制器自身定义的显存也可以使用传入的显存地址,在先楫的手册中有提到影子寄存器加载使能功能,也就是显存会在下一个VSYNC到达加载,这样可以做到显示的完整更新。
而在hpmicro的驱动中也提供了该API:lcdc_layer_set_next_buffer,这里适配的驱动使用第一层layer。
故可以下实现:
(2)RTGRAPHIC_CTRL_WAIT_VSYNC 等待帧完成
为了保证传输的高效和防撕裂,这里使用中断方式传输一帧,再下一帧更新之前等待VSYNC完毕。
(3)RTGRAPHIC_CTRL_GET_INFO 获取LCD信息
主要获取LCD的像素格式、宽高等,传递给args参数
(4)RTGRAPHIC_CTRL_POWERON 和RTGRAPHIC_CTRL_POWEROFF 亮屏和息屏
调用hpm_sdk的panel组件接口即可。
(五)注册LCD设备
使用IO设备框架的rt_device_register完成注册,主要关注设备操作方法的赋值部分,以及保存lcd设备示例赋值给lcd的user_data成员。
(六)驱动配置
在board的Kconfig中使能LCD,该宏控制LCD驱动相关代码是否添加到工程中
另外添加panel组件,该宏先楫已经实现,这里使用的是hpm6750,故只有RGB接口。
在驱动drivers的SConscript文件添加LCD驱动的判断选项,如果使能,drv_lcd.c则会被添加到工程中。
(七)驱动验证
注册设备之后,LCD设备将会在IO设备管理器中出现,我们使用hpm6750evkmini的wifi_web_camera_demo这个官方示例作为验证,烧录验证,使用list device命令查看到注册的设备已经包含了LCD设备。
在wifi_web_camera_demo的示例上,在获取camera图像的接口中,添加lcd的设备操作,把图像显示到LCD上,只需要先打开lcd,然后进行control,两条语句就可以实现显示,特别方便操作。
最终可以实现使用简单的IO设备即可操作LCD
- 2024-02-19
-
发表了主题帖:
《RT-Thread设备驱动开发指南》基础篇--以先楫bsp的hwtimer设备说起
一、概述
(一)RT-Thread设备驱动
《RT-Thread设备驱动开发指南》书籍是RT-thread官方出品撰写,系统讲解RT-thread IO设备驱动开发方法,从三方面进行讲解。
基础篇:对RT-thread以及设备框架进行介绍,再分别介绍基于IO框架中常用的外设设备,分别是UART、PIN、SPI/QSPI、HWTIMER、PWM、RTC、ADC、DAC、WDT。
进阶篇:介绍基于IO框架中稍比基础篇复杂的外设设备,分别是SDIO、Touch、LCD、sensor、MTD nor、MTD nand、脉冲编码器、加解密设备、PM设备。
高级篇:介绍更为复杂的外设设备,分别是WLAN、ETH、audio mic、audio sound、USB、CAN。
(二)先楫hpmicro bsp
为了深入了解本书的内容,得有一个单片机平台进行案例剖析,除了本书籍以STM32的arm平台进行介绍,还可以以先楫hpmicro单片机系列的riscv平台进行讲解。
刚好先楫在rtthread的bsp贡献上,也是十分丰富。无论是在rtthread studio的bsp包上,还是rtthread仓库的bsp支持上,都有提供了对应的支持。
rtthread studio的SDK支持,包括了先楫目前所有的MCU系列。
而在RT-thread上,bsp包的驱动支持上,也包括了rtthread大部分设备驱动。
二、开发方法
(一)层级结构
RT-Thread 提供了一套简单的 I/O 设备模型框架,如下图所示,它位于硬件和应用程序之间,共分成三层,从上到下分别是 I/O 设备管理层、设备驱动框架层、设备驱动层。
而作为单片机的定时器外设hwtimer功能,要对接到该IO设备框架,需要实现hwtimer设备的操作方法、设备的注册、以及驱动的配置和驱动验证。本文也是基于该开发方法进行阐述。
上述对应的三层驱动层,在源码上,可以device->hwtimer->drv_hwtimer,其中drv_hwtimer是先楫官方实现的对接框架的驱动层。
而设备驱动框架层,提供了ops操作接口,分别以下的接口需要驱动开发者实现注册。
(二)创建hwtimer设备
对hwtimer设备来说,在驱动开发时,需要先从rt_hwtimer_t结构中派生出新的hwtimer设备模型,然后根据自己的设备类型定义私有数据域。
同样先楫的hwtimer drivers也定义了自己的由rt_hwtimer_t派生出来的hwtimer设备。
当然一个MCU也支持多个hwtimer,一个hwtimer驱动可以支持多个hwtimer设备,可以通过使能BSP_USING_GPTMRx进行开启
(三)实现hwtimer设备的操作方法
该操作方法就是上述所说的ops操作结构,属于驱动共用部分,也就是多个hwtimer设备可以共用一个ops操作。同样先楫也实现了该操作方法,并且注册到自身的hwtimer的父类hwtimer的ops中。
简单举例个操作方法的实现,比如获取设备当前值count_get,原型如下:
rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer);
而先楫实现的count_get是以上的hpm_hwtimer_count_get,可以看到,内部是先从timer获取厂家自身定义的hwtimer设备,再从里面获取硬件定时器的基地址控制句柄,然后使用先楫自身的驱动API获取定时器的计数值进行返回。
(四)注册hwtimer设备
注册hwtimer设备,rtthread的IO设备框架提供了一个API:rt_device_hwtimer_register
从传参句柄可知道,注册时需要提供设备句柄timer,设备名称name,用户自定义data作为传参。
在先楫的drv_hwtimer的驱动中,创建了个全局的hwtimer设备数组,里面包含了hwtimer的所有信息,包括设备名称。然后在注册初始化当中,轮询该数组使能的定时器设备依次注册到rtthread的hwtimer设备当中。
在开发指南当中,特别提到了一个注意点,hwtimer设备句柄需要实现rt_hwtimer_info,定义硬件定时器的特征信息,如计数的最大最小频率,最大计数值以及计数方向,而先楫也同样进行了实现。
(五)hwtimer设备中断处理
在开发指南中,该部分也需要实现,目的是将定时时间导致的中断事件通知到hwtimer设备驱动框架,让驱动框架完成后续的处理并通知应用层。而该通知事件API则是rt_device_hwtimer_isr,该函数由rtthread的hwtimer设备驱动框架提供。
MCU下的hwtimer驱动,需要在中断处理函数调用rt_device_hwtimer_isr函数,以便通知hwtimer设备驱动框架对应中断的发生。
在先楫的hwtimer驱动中也是基于这个实现通知事件。
从以上代码可知,hpmicro实现的hwtimer设备驱动接管了定时器的通用中断服务函数hpm_hwtmr_isr,然后内部调用了rtthread的hwtimer设备驱动框架提供的rt_device_hwtimer_isr中断处理函数,通知设备框架对应的定时器定时时间到达。
(六)驱动配置
1、Kconfig配置
驱动配置主要通过Kconfig实现,这里使用hpm6750evk2的bsp V1.4.1作为说明。
在board文件夹中,有个Kconfig配置了hpm6750evk2的板载驱动信息。对于定时器驱动的相关选项如下:
RT_USING_HWTIMER:RT-thread的hwtimer设备驱动框架下的代码对应的宏定义,控制hwtimer的驱动框架的相关代码是否会添加到工程中
BSP_USING_GPTMR:先楫的hwtimer驱动下的代码对应的宏定义,控制先楫的hwtimer驱动是否会添加到工程中
BSP_USING_GPTMR1: 使用先楫的定时器1
2、SConscript配置
libraries/drivers/SConscript文件为hwtimer驱动添加判断选项,如果定义了BSP_USING_GPTMR,则对应的驱动文件drv_hwtimer就会被添加到工程的源文件中。
三、驱动验证
使用hpm6750evk2的bsp V1.4.1作为说明,新建timer_demo的示例工程。
编译烧录代码,使用list_device查看设备,可以看到注册的设备已经包含了hwtimer这个设备。
运行自带的shell命令hwtimer_sample,该命令会运行5s的定时,查看readme文档
四、总结
1、基础篇包含UART、PIN、SPI/QSPI、HWTIMER、PWM、RTC、ADC、DAC、WDT这些外设,本文以先楫适配的HWTIMER驱动进行说明,能感受到先楫对于rtthread驱动适配的完整性。
2、除了本文阐述的外设,其他基础外设同样适配完整。
- 2024-02-04
-
回复了主题帖:
【先楫HPM6750EVK2测评】Jlink下载出错
检查下线吧
- 2024-02-01
-
回复了主题帖:
HPM6750 rt-thread SPI ST7796S 驱动分享(2) __关于挂载 SPI 设备函数的提问
默认的SPI总线使能了硬件CS,对应的cs引脚可以看pinmux.c中的init_spi_pins 这个API。
SPI device是在spi bus总线上的,可以多个spi device对应多个cs_pin。
所以无论你的SPI device设备是否开启cs_pin,对应的硬件cs都会存在。
而你的spi device设备开不开cs_pin由你自己决定。
1、如果你开了cs_pin,你都IO去操作这个cs pin。那么SPI总线上就存在硬件CS和你自己的cs_pin
2、如果你不开,那么这个SPI总线上就只存在硬件CS那个引脚。
-
回复了主题帖:
HPM6750 rt-thread SPI ST7796S 驱动分享(1)
上月底先楫发布了rtthread bsp1.4了,支持了GET_PIN。可以考虑升级下。
- 2024-01-31
-
回复了主题帖:
【年终总结颁奖】2024,让我们保持热爱,奔赴下一场山海!
已确认个人信息无误
- 2024-01-30
-
发表了主题帖:
《年终总结》我的2023
本帖最后由 RCSN 于 2024-1-30 16:28 编辑
翻了下,好像2022和2019没做总结,看了下以往的总结,感觉感慨万千,感谢eeworld从2015年毕业陪伴到现在,还有eeworld的各位大佬。
【再见2021,你好2022】2022一起践行:回首2021,展望2022 - 聊聊、笑笑、闹闹 - 电子工程世界-论坛 (eeworld.com.cn)
【2021一起践行】回首2020,展望2021 - 聊聊、笑笑、闹闹 - 电子工程世界-论坛 (eeworld.com.cn)
回首2018,展望2019 - 聊聊、笑笑、闹闹 - 电子工程世界-论坛 (eeworld.com.cn)
难忘2017-徘徊的一年 - 聊聊、笑笑、闹闹 - 电子工程世界-论坛 (eeworld.com.cn)
年终总结--充满收获,有得有失的一年 - 聊聊、笑笑、闹闹 - 电子工程世界-论坛 (eeworld.com.cn)
2015年到2022年,生活上从毕业生存、开始有存款、结婚、欠债还款之路、又开始存款。工作上,每一次的新环境,对着未来的憧憬和期待,是让我前进的动力之一。
2023年,生活多了一个小情人,让自己的生活变得更加美好,也对未来充满着希望。虽然这段时间是有点累,但是看来小情人每天的新变化,也足够开心满足。我媳妇,从一个少女变成母亲,同样很伟大,经历了产前产后的煎熬、痛苦、劳累,真心感觉媳妇很不容易。
2024年,一家三口,点点滴滴,懂得情趣,充满乐趣,不失志趣。一切安好,身体健康,万事如意。
2023年,工作上,换了个新环境,很喜欢现在的工作环境,切合自己的兴趣爱好,我想,这是我理想中的工作,很开心,我拥有了这份理想。
感谢eeworld的测评机会,我相信,认真对待每次测评,机会都在身边。
2024年,努力朝着自己的目标前进---"多记录,多折腾。"
- 2024-01-26
-
回复了主题帖:
HPM6750驱动问题
尹小舟 发表于 2024-1-26 10:23
我的SDK就是1.4的,就是最新的
驱动全部卸载了,再重新安装,你这驱动看起来就是老的。按照最新的env的tools来
-
回复了主题帖:
HPM6750驱动问题
请用最新的sdk_env里面的tools驱动。如果找不到可以访问 sdk_env: hpm sdk env (gitee.com)