在实际项目的开发过程中,QEMU也非常的有用,例如当进行网络编程时,往往都会直接使用socket编程,其上层接口符合POSIX接口,这样上层应用的开发和底层驱动便可以很简单的分离出来,将工作细节进行合理的划分。而当进行嵌入式GUI编程设计时,也可以通过framebuffer,来进行各种界面的设计。同时,如果想新学习一款嵌入式编程语言,或者深入理解一些处理器的架构方面的知识,通过裸机编程,直接到QEMU上运行也能够非常方便的进行探究工作。
下面举出一些QEMU实际好用的应用来进行详细的描述。
QEMU的是指令翻译进行的,所以可以根据实际的需求进行相应的裸机开发和学习,比如语言学习\嵌入式C语言\嵌入式RUST语言,等等项目。一些github上的好用学习型的项目也会对QEMU进行支持,用RUST语言在arm上的编程,即使手上没有很好的硬件的条件,也能够去学习RUST语言在嵌入式编程上的使用。
针对arm的编程,QEMU也可以模拟出许多的架构出来,通过对这些架构的学习和掌握,可以加快对架构编程的理解。
./qemu-system-arm -M virt -cpu ?
Available CPUs:
arm1026
arm1136
arm1136-r2
arm1176
arm11mpcore
arm926
arm946
cortex-a15
cortex-a7
cortex-a8
cortex-a9
cortex-m0
cortex-m3
cortex-m33
cortex-m4
cortex-m55
cortex-m7
cortex-r5
cortex-r5f
max
pxa250
pxa255
pxa260
pxa261
pxa262
pxa270-a0
pxa270-a1
pxa270
pxa270-b0
pxa270-b1
pxa270-c0
pxa270-c5
sa1100
sa1110
ti925t
然而嵌入式开发往往会和硬件打交道,QEMU也提供了不同类别的硬件,比如flash,网卡,sd卡,中断,串口等等,这些对于学习不同的体系架构,也有着非常关键的作用。
比如学习cortex-m3或者aarch64编程,采用qemu,运行自己写的裸机代码,能够非常方便的进行各种实验。
在进行rtos的开发过程中,经常会采用qemu作为调试工具,进行龙芯、树莓派、riscv相关的开发和验证工作。在rtos中,比较关键的是上下文的切换,通过对寄存器信息的保存和恢复,另外就是中断的处理,能够很好的理解架构的底层编程方式。
以前的时候,也做过aarch64上的QEMU编程,也是最开始基于QEMU,然后慢慢的移植到树莓派上面,因为外设一致,代码层面不用改变,直接可以将QEMU运行通过的固件放到树莓派的sd卡中也一样能够正常的运行。
rt-thread/bsp/raspberry-pi/raspi3-64
中编译的固件在qemu上的运行效果,基本上完成对aarch64体系架构中的栈帧、中断、mmu的支持,以及外设部分SD卡、图形、串口、mbox的支持。该固件也可以直接放到树莓派硬件的sd卡中运行,其效果和在qemu效果一样。qemu-system-riscv64 -M nuclei_n,download=ilm -cpu nuclei-nx600fdp -nodefaults -nographic -serial stdio -kernel CMSIS/nmsis_release/NMSIS/DSP/Examples/RISCV/riscv_matrix_example/dsp_example.elf
nmsis
是基于arm的cmsis
在riscv上的一份移植,其中实现了许多的加速运算的demo,比如矩阵运算,卷积,图像处理等等,这些指令同样也可以在nuclei qemu中计算出正确的结果。qemu-system-riscv32 -M nuclei_n,download=ilm -cpu nuclei-n201 -nodefaults -nographic -serial stdio -kernel application/rtthread/msh/msh.elf
Nuclei SDK Build Time: May 31 2021, 11:48:18
Download Mode: ILM
CPU Frequency 168290222 Hz
\ | /
- RT - Thread Operating System
/ | \ 3.1.3 build May 31 2021
2006 - 2019 Copyright by rt-thread team
Hello RT-Thread!
msh >
msh >ps
thread pri status sp stack size max used left tick error
-------- --- ------- ---------- ---------- ------ ---------- ---
tshell 6 ready 0x000000d8 0x00001000 10% 0x0000000a 000
tidle 7 ready 0x00000078 0x00000200 23% 0x00000020 000
main 2 suspend 0x000000b8 0x00000400 17% 0x00000013 000
msh >
也可以支持其他的rtos,例如下面的ucosii和freertos等等。
ucosii的运行效果如下:
qemu-system-riscv32 -M nuclei_n,download=ilm -cpu nuclei-n201 -nodefaults -nographic -serial stdio -kernel application/ucosii/demo/demo.elf
Nuclei SDK Build Time: May 31 2021, 11:49:45
Download Mode: ILM
CPU Frequency 182521692 Hz
Start ucosii...
create start task success
start all task...
task3 is running... 1
task2 is running... 1
task1 is running... 1
task3 is running... 2
task2 is running... 2
task3 is running... 3
task2 is running... 3
task1 is running... 2
task3 is running... 4
task2 is running... 4
task3 is running... 5
task2 is running... 5
freertos的运行效果如下:
qemu-system-riscv32 -M nuclei_n,download=ilm -cpu nuclei-n201 -nodefaults -nographic -serial stdio -kernel application/freertos/demo/demo.elf
Nuclei SDK Build Time: May 31 2021, 11:49:45
Download Mode: ILM
CPU Frequency 232205516 Hz
Before StartScheduler
Enter to task_1
task1 is running 0.....
Enter to task_2
task2 is running 0.....
timers Callback 0
timers Callback 1
task1 is running 1.....
task2 is running 1.....
timers Callback 2
timers Callback 3
task1 is running 2.....
task2 is running 2.....
由于QEMU的网络可以直接连接主机的网络,对这方面的研究可以从网络协议栈,网络的上层应用编程等等进行研究。例如去研究lwip协议栈的实现等等。
我写过一个QEMU上的e1000网卡设备的驱动,针对于qemu riscv64的virt版本。
https://github.com/bigmagic123/rt-thread/tree/riscv_virt_network
针对rt-thread的qemu riscv的virt64版本,可以进行如下的设置。
最后可以测试一下web的通信情况。
因为嵌入式编程的实现,也会多少涉及到图形编程,当接上LCD屏后,其中的显示驱动对上层应用暴露出来的实际上是一块显存,通过对显存的读写,flush进行lcd的图像更新。
在图像编程方面,QEMU也提供了显示窗口。这种显示窗口可以为gui相关的开发工作带来很多便捷。
关于嵌入式图像编程,可以参考
rt-thread\bsp\raspberry-pi\raspi3-64
相关的bsp,只需要完善显示程序即可。
可以寻找一张bmp的图片,图片大小为800x480的图片。
利用Image2Lcd的工具进行图像转换成数组。
#define LCD_BUF_SIZE (800 * 480)
extern unsigned char gImage_1[];
void lcd_test()
{
struct rt_device *lcd;
struct rt_device_graphic_info *test_lcd_info;
test_lcd_info = rt_malloc(sizeof( struct rt_device_graphic_info));
//找到lcdlcd = (struct rt_device *)rt_device_find("lcd");
rt_kprintf("lcd get info:\n");
rt_device_control(lcd, RTGRAPHIC_CTRL_GET_INFO, test_lcd_info);
rt_kprintf("lcd width is %d\n", test_lcd_info->width);
rt_kprintf("lcd height is %d\n", test_lcd_info->height);
rt_kprintf("lcd bpp is %d\n", test_lcd_info->bits_per_pixel);
rt_memcpy(test_lcd_info->framebuffer, &gImage_1[0], LCD_BUF_SIZE*4);
//刷新图片
rt_device_control(lcd, RTGRAPHIC_CTRL_RECT_UPDATE, NULL);
rt_thread_delay(20);
}
如果要进行触摸操作,qemu也进行了基本的支持,只需移植相关的底层驱动即可进行开发工作,非常的高效和方便。
进行Linux开发工作,如果深入去学习某一个设备的开发,当然少不了不断的对Linux的内核部分进行编译和下载,这是一个十分耗时的工作,如果只是进行应用程序的开发,可能感觉不到许多的差别,但是一旦涉及到Linux内核的分析,频繁的下载也会浪费大量的时间。
当使用QEMU后,这种问题将会得到很好的解决,采用QEMU进行内核层面的裁剪,进行内核层面模块化的验证工作后,再进行移植,让其变得更加通用,不仅仅针对这个项目有效,而且也为自己积累了很多经验。
从分析linux的loader,分析Linux的驱动框架,内存管理,多核管理等等,都能够非常方便进行调试工作。
接触很多软件开发工作中,使用QEMU确实能够在一定程度上节省时间,提高软件调试与分析的效率。
用软件模拟硬件的操作行为,本质上来说和实际的硬件操作区别不大,因为在嵌入式编程中,最底层的指令集的行为已经在QEMU中实现的很好了,硬件模拟方面,QEMU也大致能够模拟操作寄存器后,处理器的行为,这些在对QEMU的底层支持和学习的过程中已经进行了大量的实验和研究。
理解QEMU的使用,会对嵌入式软件原理有着更加深刻的理解,从更大的层面上来说,虚拟化的行为本来就是一种很好的解决方案,去设计一个嵌入式软件方案,去演示一个底层软件,或者节约下载调试时间,开发嵌入式上层业务系统软件的功能层面来说,QEMU都是值得去研究和使用的工具。
1.浅谈传感器市场的发展趋势~
2.目前全球MCU的现状~
3.芯片缺货实情难判断,有MCU厂已进入对峙期~
4.【喂到嘴边了的模块】超级嵌入式系统“性能/时间”工具箱~
5.国产32位MCU未来要怎样发展?
6.做嵌入式软件开发提高代码编译速度的几种方法~
免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。