米尔mys-8mmx开发板试用体验测评二
近期,米尔科技发布新品“mys-8mmx”开发板的评测,吸引了广大开发者的围观,上周小编在公众号发布1篇优秀的测评报告,后台收到了各位小伙伴的留言和咨询,想必还有很多的疑问,为加深各位对米尔mys-8mmx开发板的了解,再同步一篇电路城优秀测评者的测评报告,希望能帮助各位开发者缩短开发周期。
想要了解优秀测评者“robe.zhang”关于mys-8mmx开发板测评原文的可以复制下方链接查看:
https://www.cirmall.com/bbs/thread-208807-1-1.html
想要了解mys-8mmx开发板可以去米尔pg电子娱乐试玩官网查看具体的产品介绍:
http://www.myir-tech.com/product/mys-8mmx.htm
需要购买mys-8mmx开发板的可以复制下方链接购买:
https://detail.tmall.com/item.htm?id=646134511777
01
笔者想用 nfs 文件系统,方便后续开发,试了一下开发板预装系统uboot 不支持网络功能,编译前,不支持网络
重新编译 uboot 增加网络功能:
编译 uboot 的过程废了点时间,由于米尔 sdk使用 yocto 作为开发工具,yocto是个集成的开发工具,功能大而全,好处多多,也有不方便的地方,国内工程师估计都知道,那就是拉取源码太难了,笔者没用 yocto 而是一个个单独编译,然后再手工打包,这个环节废了点时间。
02
跑起网络服务器上的 ubuntu 20.04 系统,也就是把 uboot 放在 sd 卡上,其他的所有一切包括内核、驱动、设备树、文件系统等等所有的东西都放在服务器上,这种方式好处很明显,对开发过程极其友好,比如修改内核,服务器编译后,板子重启搞定,不用自己再把内核复制到板子上,比如修改设备树,服务器编译后,板子重启搞定,不用自己复制,比如调整驱动,比如写个应用程序,只要编译完,服务器上有的东西,板子上也能找到,就是这么方便。
比如笔者的 sd 卡,只烧写 flash.bin文件,甚至一个分区都不存在,因为笔者压根就不用 sd 卡的任何分区,所以 sd 卡有没有分区无所谓
uubntu 文件系统在电脑上,在这里:
以下是启动记录:
boot_log.txt
到此,整个开发环境搭建起来了,所有镜像和文件重新调整添加网络文件系统支持,并编译出来,编译的所有文件全部调试验证成功了,接下来可以愉快的开发了笔者整个编译过程是一个个手工单独编译的,手工单独编译要对各个文件包有所了解,编译过程是有点繁琐,优势也很明显,速度很快,非常快,大约 20 分钟就可以全部编译一遍,如果是增量编译,1分钟内搞定,再加上网络文件系统加成,1分钟内编译完重启完看到验证的结果;笔者后续会频繁编译内核,调整设备树,编译速度快就能快速迭代加快开发速度。用 yocto 编译的话,省事方便,但是速度慢,如果公司配有很牛逼的开发服务器集群,那可以。
03
适配了自己的 ubuntu 20.04 文件系统,wifi 无法正常使用,检查了一下,是因为内核需要两个文件,ubuntu 系统镜像中没有。
一个文件是 firmware,另一个文件是 nvram,在 emmc 中原文件系统如下路径中:
/lib/firmware/bcmd/fw_bcm43456c5_ag_apsta.bin
/lib/firmware/bcmd/nvram_ap6256.txt
直接从 emmc 复制过来,复制到 nfs ubuntu 文件系统中同样的路径下
重启生效,就能驱动了,也能连上 wifi 网络
文中提到的内容只是需要调整修改的,其他没说的不用动。
两个 usb 接口也可以使用了:
hdmi 显示器也正常工作
网络文件系统 ubuntu 20.04 基本就绪,没啥大问题了
04
本文重点内容有三个:1,驱动模型如何建立2,设备树如何被解析3,在理解 1 和 2 基础上,会很自然的理解如何向设备树添加节点platform 驱动模型建立
内核驱动模型中有 bus,device,driver,分别对应 struct bus_type,struct device,struct device_driver 三个结构体,或者说三个对象也行,platform_bus , platform_device, platform_driver 是对 struct bus_type,struct device,struct device_driver 的继承,可以把 platform 平台看作是bus,device,driver的更高一级对象。
platform 驱动中的 bus 和 device 是内核创建的,比如以下代码,注册了 platform_bus
有了 platform_bus 之后,需要有 platform_device ,platform_device 也是内核模块的形式注册的
of_platform_default_populate_init 这个函数解析设备树,解析时有规则的,结合imx8mm 平台来说,解析了以下所有节点及其一级子节点,也就是设备书中的以下节点创建了 device 设备,并且创建他们子节点的 device 设备,子节点再往下的节点,不解析不创建device,留作 platform_driver 去解析创建。(设备树如何被解析)
有了 platform_bus 也创建了 platform_device 设备,还差 platform_driver,platform_driver 就是驱动,并且是 soc 芯片级别的驱动,这个有芯片原厂搞定,比如imx8mm 有以下 platform_driver:这个是 sdma 的驱动,以此为例,其他类同。
platform 平台 bus,device,driver 几乎全部有厂商提供,用户基本是无感的。他默默在背后工作,但是初学者根本不知道他的存在。这是platform 平台完整的驱动模型。
理解此文基础上,再继续看笔者往期文章才能理解 iic 总线框架:
【alinx axu2cgb试用】从linux 驱动模型的角度看 iic 总线框架
https://www.cirmall.com/bbs/thread-208032-1-1.html
深入看 iic 设备树,i2c1 位于aips3 的一级子节点,i2c1 会被创建 platform_device,
i2c 驱动注册为platform_driver:
内核一开始注册了 platform_bus,也创建了 i2c1 的 platform_device,也注册了i2c1的 platform_driver,组成一个完整的 platform 驱动模型,他们就会工作了,i2c 适配器/主机能正常工作了。
(文章中的 i2c 适配器,就是 i2c 主机,i2c 控制器,对应驱动中的 i2c adapter;文章中的 i2c 设备,是 i2c 从机,对应驱动中的 i2c client)
i2c 驱动模型建立
i2c 适配器用的 platform 平台驱动模型,对你没有看错,笔者也么有写错,i2c 适配器用的 platform 平台驱动模型,和 i2c 总线没有半毛钱关系。
i2c 总线用在哪呢?用在 i2c 设备上。
i2c 适配器的 platform_driver 会去注册 adapter
解析 adapter 所有子节点注册为 i2c client 设备 (i2c device),现在有了 i2c device
内核会注册创建 i2c 总线
内核也会注册 client 驱动(i2c driver)注册,如下;
有 i2c 总线,有 i2c device设备(i2c client 设备),有 i2c driver (i2c client 驱动),组成一个完整的 i2c 总线模型,这个总线主要为 i2c 设备服务。
i2c 主机使用 platform 平台总线,i2c 从机使用 i2c 总线,是不是很难理解?驱动源码就是这样的。
linux 内核驱动中的总线,并不是硬件中的总线,也不是传输信息的,而是为了设备和驱动更容易的适配的,是设备和驱动的一种组织形式。
最难理解的地方就是 i2c 主机和 i2c 从机没使用同一个总线,分别使用了 platform 总线和 i2c 总线,能问出这个问题的根源是用硬件总线的概念去想当然的理解驱动中的总线,潜意识完全错误,硬件总线和驱动中的总线,完全是两个东西,应该这么去理解:1,硬件中的总线,是传输信息的,硬件上主从机位于同一条 i2c 总线,主从机是可以通信的。
2,驱动中的总线仅仅是设备和驱动的组织形式,方便设备和驱动适配的。只要 i2c 主机设备和驱动适配 ok 主机就会工作,i2c 从机设备和驱动适配 ok 从机就会工作。分别使用了 platform 总线和 i2c 总线,并不影响 i2c 主机和 i2c 从机正常适配,正常工作。
结果就是 linux 驱动让 i2c 主从机都可以正常工作,硬件让主从机又能相互通信,那就可以了。
linux 驱动仅仅是让硬件工作起来,别强求 i2c 主从机必须位于同一条总线,不在同一条总线没关系;硬件的总线是通信的,i2c 主从机要想通信必须位于同一条总线,没的商量。
platform 是 arm linux 驱动中最基础的平台,用的多,也最容易追踪分析,是软件中驱动模块部分抽象出来的一种模型,用于组织设备和驱动的一种方式,其他 i2c ,spi 总线和 platform 平台驱动模型类似各有差异,i2c 和 spi 驱动模型都是在 platform 平台驱动中再次建立起来的,platform 平台驱动注册 i2c / spi 设备,和内核注册的 i2c 总线、i2c driver 组成 i2c 驱动模型。
没有 设备树 对应的节点,就没有 platform device,没有 platform device 仅有 platform bus 和 platform driver 不能组成完整的驱动模型,就无法工作。无法工作,platform driver 就不能 match 就无法 probe,无法 probe 就不能添加 i2c device,仅有 i2c 总线和 i2c driver 不能组成i2c 总线完整的驱动模型,i2c 也就不能工作。所以向设备树添加节点,很重要,相当于给驱动模型添加 device。
如何向设备树添加节点设备树,这个名字说明他的数据结构是树,树中的每个节点是设备。向设备树中添加节点,就是向 linux 中添加设备,树,就要求你添加到合适的位置,合适的层级。向设备树添加节点是有规则的,规则是由设备树被解析的规则决定的,内核怎么解析设备树你就怎么添加添加设备节点,必须添加到指定位置添加自己的设备节点,必须添加到文中图片列出的节点的一级子节点,二级和再深的节点,添加了也没用,因为内核根本不去创建更深层次节点设备。也不是完全不可以,你添加后节点还是存在的,只存在设备树中,驱动模型中是不存在,需要你自己去建立驱动模型。接下来笔者运用设备树等不同的方法自己创建一条总线,建立起这个总线的驱动模型,让设备和驱动正常适配、probe、正常工作起来。
长按二维码 关注pg电子娱乐试玩
想要了解mys-8mmx开发板可以去米尔pg电子娱乐试玩官网查看具体的产品介绍:
http://www.myir-tech.com/product/mys-8mmx.htm
需要购买mys-8mmx开发板的可以复制下方链接购买:
part.1
开箱上电&系统烧录&文件系统移植&wifi模块驱动加载
part.2
1. void mainwindow::lcd_show_ascii_64(uint32_t x,uint32_t y,uint32_t fontcolor,uint32_t backcolor,char word)
2. {
3. int i,j,k;
4. unsigned char temp;
5. word -= 0x20;
6. for(j=0;j<64;j )
7. {
8. for(i=0;i<4;i )
9. {
10. temp = ascii_font_64[j*4 i word*256];
11. for(k=0;k<8;k )
12. {
13. if(temp & 0x80)
14. framebuffer_lcd[i*8 k x lcd_width*(j y)] = fontcolor;
15. else
16. framebuffer_lcd[i*8 k x lcd_width*(j y)] = backcolor;
17. temp<<=1;
18. }
19. }
20. }
21. }
22.
23. void mainwindow::lcd_show_ascii_string_64(uint32_t x,uint32_t y,uint32_t wordcolor,uint32_t backcolor,char s[])
24. {
25. int i=0;
26. for(i=0;s[i]!='\0';i )
27. lcd_show_ascii_64(x i*32,y,wordcolor,backcolor,s[i]);
28. }
29.
30. int mainwindow::lcd_effect(char *dev)
31. {
32. int fd_lcd = open(dev , o_rdwr);
33. if(fd_lcd == -1)
34. {
35. qdebug("open lcd failed!");
36. return -1;
37. }
38. write(fd_lcd , framebuffer_lcd , lcd_width * lcd_height * 4);
39. ::close(fd_lcd);
40. return 0;
41. }
可以看出,在qt下操作文件字符设备与普通系统编程并没有明显区别,唯一不同的是,qt下使用文件关闭函数需要添加双冒号::close(),防止与qt自带的close()函数产生冲突。在mainwindow类任意位置打开/dev/fb0外设后,即可进行ascii码符号的显示:
1. lcd_show_ascii_string_64(0 , 0 , 0 , lcd_color_cyan_32 , (char *)"elecfans.com");
2. lcd_show_ascii_string_64(0 , 64 , 0 , lcd_color_cyan_32 , (char *)"donatello1996");
3. lcd_effect((char*)fb_dev);
非常简单愉快就玩成了,看看x11vnc远程终端显示效果,这也就是hdmi实际显示是输出内容:
当然了,如果不设置环境变量qt_qpa_platform的话,x11终端下启动的x11应用就会在远程机器上直接显示(远程机器就是我的电脑):
设置qt_qpa_platform之后,可以将启动界面映射到任意framebuffer外设上:
1. export qt_qpa_platform=linuxfb:tty=/dev/fb0
part.3
编译内核镜像&与usbhid设备通信
如果想用一种简单的方式控制更多外设的话,除了添加扩展芯片,还有一种项目上用得比较多的方式是usbhid通信,将开发板作为主机,通过usb接口与支持usbhid协议的从机进行通信,这个方法非常简单,刚入门嵌入式的小白也必须熟练掌握,只需要应用层开发的知识和皮毛的驱动层开发知识。要想使用这种方式进行通信,板子的内核镜像就必须支持usbhid设备的检测与读写,检测是没什么问题的,但是能不能映射到设备文件,供开发者进行读写操作,那就需要检查内核编译选项了,这里刚好是比较坏的一种情况,米尔厂家出厂镜像是没有打开usbhid通信的,必须让开发者重新编译内核镜像,那么这里就涉及到内核编译的知识了:下载并解压内核源码镜像:
1. https://github.com/myir-dev/myir-imx-uboot.git
编译选项采用米尔mys-8mmx开发板的编译选项mys_iot_defconfig:
1. /home/myir-imx-linux-develop/arch/arm64/configs/
2. make mys_iot_defconfig
这边还需要注意的是内核镜像的版本与使用内核源码编译第三方驱动ko文件的版本必须相同,在内核源码一级目录处可以找到配置的位置:
使用menuconfig打开内核编译选项, device drivers > hid support的 /dev/hidraw raw hid device support选项要打开,或者是在配置文件中添加此项配置的环境变量:
配置完毕之后,替换image内核文件覆盖出厂内核文件:
1. mount /dev/mmcblk1p1 /media
2. mmcblk1是开发板的sd卡,mmcblk1p1是sd卡的fat分区,存放内核文件的位置:
重新启动之后,将usbhid设备插到板子的usb接口:
在/dev目录下找到/dev/hidraw设备:
安装-ludev软件库:
1. apt install udev
使用代码读写hid设备:
1. handle = hid_open(2020, 2020, null);
2. res = hid_read(handle, buf, sizeof(buf));
part.4
使用libjpeg库和giflib库显示jpg图片和gif图片
linux系统编程中对jpg和gif图片的显示都有集成的软件库可以用,显示jpg图片可用libjpeg库,可以直接用apt在线安装apt install libjpeg62-turbo libjpeg62-turbo-dev对于arm64架构的系统,会有turbo关键字,而在x86架构系统上面,直接安装libjpeg62即可。安装完毕之后,开发板的板上代码可以使用jpeglib.h提供的函数接口进行jpg文件的软件解码,直接读取jpg文件并显示在framebuffer外设之上,
具体函数如下:-struct jpeg_decompress_struct cinfo;
用于存放jpg文件解码数据的结构体-jsamparray buffer;
存放一行图像数据的结构体-jpeg_create_decompress(&cinfo);
初始化jpeg_decompress结构体对象的函数-jpeg_stdio_src(&cinfo,input_file);-
指定解压缩数据源
1. void lcd_rgb888_show_jpg_file(char *dev , int xpos , int ypos , char *filename)
2. {
3. //int fjpg;
4. int i,j;
5. file *input_file = fopen(filename,"rb");
6. struct jpeg_decompress_struct cinfo;
7. //jpeg图像在解码过程中
8. //使用jpeg_decompress_struct类型的结构体来表示
9. //图像的所有信息都存储在结构体中
10.
11. struct jpeg_error_mgr jerr;
12. //定义一个标准的错误结构体
13.
14. jsamparray buffer;
15. //用于存取一行数据
16. //fjpg = open((char *)"/home/fa/1.jpg",o_rdonly);
17. cinfo.err = jpeg_std_error(&jerr);
18. //绑定错误处理结构对象
19.
20. jpeg_create_decompress(&cinfo);
21. //初始化cinfo结构
22.
23. jpeg_stdio_src(&cinfo,input_file);
24. //指定解压缩数据源
25.
26. jpeg_read_header(&cinfo,true);
27. //获取文件信息
28.
29. jpeg_start_decompress(&cinfo);
30. //开始解压缩
31.
32. int width = cinfo.output_width;
33. //图像宽度
34. int height = cinfo.output_height;
35. //图像高度
36. int depth = cinfo.output_components;
37. //图像深度38. uint8_t img_byte = cinfo.jpeg_color_space;
39. //像素字节数(1/2/3/4个字节,对应8/16/24/32位格式)
40.
41. memset(bmp_buf , 0 , sizeof(unsigned char) * width * height * depth);
42.
43. buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo,jpool_image , width * depth , 1);
44. //分配一行数据空间
45. point = bmp_buf;
46. while(cinfo.output_scanline < height)//逐行读取位图数据
47. {
48. jpeg_read_scanlines(&cinfo , buffer , 1);
49. //读取一行jpg图像数据到buffer
50. memcpy(point , *buffer , width * depth);
51. //将buffer中的数据逐行给src_buff
52. point = width * img_byte;
53. //指针偏移一行
54. }
55.
56. jpeg_finish_decompress(&cinfo);//解压缩完毕
57.
58.
59. for(i = 0 ; i < lcd_height ; i )
60. {
61. for(j = 0 ; j < lcd_width ; j )
62. if(i <= height && j <= width)
63. {
64. uint32_t temp = bmp_buf[(i * width j) * 3] << 16 |
65. bmp_buf[(i * width j) * 3 1] << 8 |
66. bmp_buf[(i * width j) * 3 2];
67. framebuffer_lcd[(i ypos)*(lcd_width) j xpos] = temp;
68.
69. }
70. //else framebuffer_lcd[(i ypos)*(lcd_width) j xpos]=0;
71. }
72. int fd_lcd = open(dev , o_rdwr);
73. write(fd_lcd , framebuffer_lcd , lcd_width * lcd_height * 2);
74. close(fd_lcd);
}
米尔电子 嵌入式pg电子娱乐试玩的解决方案专家“米尔myir”公众号☞不定期分享产品资料及干货☞第一时间发布米尔最新资讯
米尔,专注嵌入式处理器模块设计和研发,是领先的嵌入式软硬件方案的供应商。米尔在嵌入式领域具有20年的行业技术经验,为客户提供专业的arm工业控制板、arm开发板、arm核心板、arm开发工具、充电桩计费控制单元及充电控制板等产品和技术服务。此外,米尔还可通过涵盖众多arm处理器及操作系统的专业技术提供定制设计pg电子娱乐试玩的解决方案,通过专业且高效率服务帮助客户加速产品上市进程。
长按二维码 关注pg电子娱乐试玩
想要了解更多信息,欢迎联系pg网赌软件深圳总部电话:0755-25622735 18924653967地址:深圳坂田云里智能园2栋6楼上海办事处电话:021-62087019 18924632515北京办事处电话:010-84675491 13316862895pg网赌软件的技术支持电话:027-59621648邮箱:support.cn@myirtech.com