白姐透特今晚开什么码

打印

[应用方案]M484的另类玩法,跑“linux”

[复制链接]
771|17
跳转到指定楼层
楼主
本帖最后由 vsfopen 于 2019-12-20 13:06 编辑

首先,这里打引号的linux并不是正常的Linux或者uClinux,这些对M484来说还是太过于庞大了。
这里的linux是自己基于VSF模拟出来的linux环境,可以编译一些linux的应用代码。

最早做这个还是2年前,客户需要定制一个方案,提供了3个linux的源代码,需要移植到MCU里去。
3个linux的源代码,规模在几十万行,这个直接移植一定吐血。
然后就突发奇想,是不是可以在MCU里,模拟出一个linux环境,让linux的应用代码,直接可以编译?
于是,就有了目前的VSF里的linux子系统,最近把linux子系统也移植到了最新版本的VSF,并且开源了。

大致的目录结构:

一些代码:
  1. int main(void)
  2. {
  3.     __usrapp_common_init();

  4.     vsf_trace(VSF_TRACE_INFO, "start linux..." VSF_TRACE_CFG_LINEEND);
  5.     vk_fs_init();

  6.     vsf_linux_stdio_stream_t stream = {
  7.         .in     = (vsf_stream_t *)&VSF_DEBUG_STREAM_RX,
  8.         .out    = (vsf_stream_t *)&VSF_DEBUG_STREAM_TX,
  9.         .err    = (vsf_stream_t *)&VSF_DEBUG_STREAM_TX,
  10.     };
  11.     vsf_linux_init(&stream);
  12.     return 0;
  13. }
复制代码

这里,调用vsf_linux_init的时候,传入默认stdio的流。

  1. vsf_err_t vsf_linux_init(vsf_linux_stdio_stream_t *stdio_stream)
  2. {
  3.     VSF_LINUX_ASSERT(stdio_stream != NULL);
  4.     memset(&__vsf_linux, 0, sizeof(__vsf_linux));
  5.     __vsf_linux.stdio_stream = *stdio_stream;
  6.     vsf_linux_glibc_init();

  7.     // create kernel process(pid0)
  8.     if (NULL != vsf_linux_start_process_internal(0, __vsf_linux_kernel_thread, vsf_prio_0)) {
  9.         return VSF_ERR_NONE;
  10.     }
  11.     return VSF_ERR_FAIL;
  12. }
复制代码
linux初始化的时候,启动pid0,这个也就是内核任务。

  1. static int __vsf_linux_kernel_thread(int argc, char *argv[])
  2. {
  3.     int err;

  4.     __vsf_linux.kernel_process = vsf_linux_get_cur_process();
  5. #ifndef WEAK_VSF_LINUX_CREATE_FHS
  6.     err = vsf_linux_create_fhs();
  7. #else
  8.     err = WEAK_VSF_LINUX_CREATE_FHS();
  9. #endif
  10.     if (err) { return err; }

  11.     // create init process(pid1)
  12.     vsf_linux_start_process_internal(0, __vsf_linux_init_thread, VSF_LINUX_CFG_PRIO_HIGHEST);

  13.     vsf_linux_sig_handler_t *handler;
  14.     vsf_linux_process_t *process;
  15.     vsf_evt_t evt;
  16.     unsigned long sig_mask;
  17.     int sig;
  18.     while (1) {
  19.         evt = vsf_thread_wait();
  20.         VSF_LINUX_ASSERT(VSF_EVT_MESSAGE == evt);

  21.         process = vsf_eda_get_cur_msg();
  22.         sig_mask = process->sig.pending.sig[0] & ~process->sig.mask.sig[0];
  23.         while (sig_mask) {
  24.             sig = ffz(~sig_mask);
  25.             sig_mask &= ~(1 << sig);

  26.             handler = NULL;
  27.             __vsf_dlist_foreach_unsafe(vsf_linux_sig_handler_t, node, &process->sig.handler_list) {
  28.                 if (_->sig == sig) {
  29.                     handler = _;
  30.                     break;
  31.                 }
  32.             }
  33. ......
复制代码
内核任务会先调用vsf_linux_create_fhs,建立虚拟文件系统;然后启动pid1,也就是init进程;后面就是各个任务的signal处理。

  1. static int __vsf_linux_init_thread(int argc, char *argv[])
  2. {
  3.     return execl("/sbin/init", "init", NULL);
  4. }
复制代码
pid1 init进程就简单了,直接exec /sbin/init。

这里,就需要先说一下fhs的建立,在用户的应用层代码里:
  1. int vsf_linux_create_fhs(void)
  2. {
  3.     int fd;

  4. #if VSF_USE_LINUX_BUSYBOX == ENABLED
  5.     busybox_install();
  6. #endif

  7. #if VSF_USE_LINUX_LIBUSB == ENABLED
  8.     fd = creat("/sbin/lsusb", 0);
  9.     if (fd >= 0) {
  10.         vsf_linux_fs_bind_executable(fd, lsusb_main);
  11.         close(fd);
  12.     }
  13.     libusb_init(NULL);
  14. #endif

  15. #if VSF_USE_MEMFS
  16.     if (mkdir("/fakefat32", 0)) {
  17.         return -1;
  18.     }
  19.     fd = open("/fakefat32", 0);
  20.     if (fd >= 0) {
  21.         close(fd);
  22.         mount(NULL, "/fakefat32", &vk_memfs_op, 0, &__usrapp_common.fs.memfs_info);
  23.     }
  24. #endif

  25. #if VSF_USE_WINFS
  26.     if (mkdir("/winfs", 0)) {
  27.         return -1;
  28.     }
  29.     fd = open("/winfs", 0);
  30.     if (fd >= 0) {
  31.         close(fd);
  32.         mount(NULL, "/winfs", &vk_winfs_op, 0, &__usrapp_common.fs.winfs_info);
  33.     }
  34. #endif
  35.     return 0;
  36. }
复制代码
这里就是使能busybox的时候,安装busybox;使能libusb的时候,安装lsusb程序(入口在lsusb_main);然后,安装fakefat32文件系统和winfs文件系统(只有用VC的时候,才会安装)。

  1. static int init_main(int argc, char *argv[])
  2. {
  3.     return vsh_main(argc, argv);
  4. }

  5. static int busybox_bind(char *path, vsf_linux_main_entry_t entry)
  6. {
  7.     int fd = open(path, 0);
  8.     if (fd < 0) {
  9.         fd = creat(path, 0);
  10.     }
  11.     if (fd >= 0) {
  12.         vsf_linux_fs_bind_executable(fd, entry);
  13.         close(fd);
  14.     }
  15.     return fd;
  16. }

  17. int busybox_install(void)
  18. {
  19.     if (mkdir("/sbin", 0)) {
  20.         return -1;
  21.     }

  22.     if (    busybox_bind("/sbin/init", init_main) < 0
  23.         ||  busybox_bind("/sbin/ls", ls_main) < 0
  24.         ||  busybox_bind("/sbin/cd", cd_main) < 0
  25.         ||  busybox_bind("/sbin/pwd", pwd_main) < 0
  26.         ||  busybox_bind("/sbin/cat", cat_main) < 0
  27.         ||  busybox_bind("/sbin/echo", echo_main) < 0) {
  28.         return -1;
  29.     }

  30.     static const char *path[] = {
  31.         "/sbin/",
  32.         NULL,
  33.     };
  34.     vsh_set_path((char **)path);
  35.     return 0;
  36. }
复制代码
busybox install的时候,也就是安装几个可执行的入口。其中,init_main连接到了/sbin/init,所以,linux的init进程,会调用到这里。这里实际就是启动vsh(自己写的一个小型shell,功能简单代码少,真正的busybox里的shell不是M484里可以放下的)。

这里就是大概的启动流程了。

上截图:


IAR和VC用的是同一份代码,不同的配置。
VC上跑的是VSF的模拟运行环境,模拟了一个单核心MCU,64个中断优先级,32个SWI。

M484上的资源占用:
就图示的简单demo,由于使用了linux而增加的代码资源大概不到10K。
当然,如果移植其他Linux应用的话,根据应用使用的API,会有不同。
目前已经支持的一些接口:libusb, pthread, 基本posix,简单的进程和线程控制API
马上会增加:socket(支持AF_UNIX,老版本VSF里就已经搞定了,客户要移植的代码,就是需要socket)
针对MCU实现的,虽然不是啥都有,但是至少可以缺啥补啥。


环境搭建:
1. 安装IDE,如果使用M484,安装IAR8.4;如果使用VC,安装VS2019,注意需要安装clang编译器
2. 下载VSF:http://github.com/vsfteam/vsf.git
3. 打开工程:vsf\source\example\project\iar_8.4\vsf_template.eww;vsf\source\example\project\vc\vsf_template.sln
4. 选择配置,IAR里选择linux_m484;VC下选择vsf_linux_win,设置为启动项目,设置编译配置,选择编译vsf_linux_win,设置目标为x86。
5. 编译运行,如果是M484的话,固件会模拟出一个CDC串口,使用putty等串口中断打开这个串口(终端配置里,选择Implicit CR in every LF)。USB主机口可以接一些USB设备,通过lsusb可以显示(不显示HUB)。

相关资料

沙发
|2019-12-19 15:51|只看该作者
板凳
|2019-12-19 15:52|只看该作者
厉害,驱动屏幕效果如何
地板
 楼主|2019-12-19 16:19|只看该作者
heisexingqisi 发表于 2019-12-19 15:52
厉害,驱动屏幕效果如何

还没做屏幕功能,这个linux里其实没有太好的小资源库。
UI的话,我们基本都是使用我们自己的tgui,或者lvgl。
这些可以和linux子系统同时运行的。
5
|2019-12-19 17:24|只看该作者
用终端操作的,工程可研打包分享分享吗
6
|2019-12-19 17:24|只看该作者
我也想体验一下。
7
 楼主|2019-12-19 17:35|只看该作者
zhuotuzi 发表于 2019-12-19 17:24
我也想体验一下。

在github里,已经开源,m484的部分,等我晚上更新上去就可以访问了
8
|2019-12-19 17:43|只看该作者
vsfopen 发表于 2019-12-19 17:35
在github里,已经开源,m484的部分,等我晚上更新上去就可以访问了

好,非常期待,我晚上泡妞回来看。
9
|2019-12-20 00:03|只看该作者
M451可以跑吗
10
 楼主|2019-12-20 12:54|只看该作者
本帖最后由 vsfopen 于 2019-12-20 13:15 编辑

环境搭建:
1. 安装IAR 8.4
2. 下载:http://github.com/vsfteam/vsf.git
3. 打开工程:vsf\source\example\project\iar_8.4\vsf_template.eww
4. 选择配置:linux_m484
5. 编译,下载,运行
6. 使用putty打开CDC串口(不是nulink模拟的串口,而是484模拟的串口)
7. 看到命令提示符之后,就可以输入命令了


11
 楼主|2019-12-20 14:12|只看该作者
本帖最后由 vsfopen 于 2019-12-20 19:45 编辑

http://raw.githubusercontent.com/mevdschee/2048.c/master/2048.c


12
|2019-12-20 14:33|只看该作者
非常厉害,高人啊
13
 楼主|2019-12-20 19:45|只看该作者
移植Linux的USB摄像头驱动,这里为了方便开发调试,直接使用了VSF的PC端环境,使用VisualStudio开发。代码和m484端的一样,只是USB的驱动使用winusb,而不是484的ohci。‘


14
|2019-12-20 21:41|只看该作者

非常厉害,高人啊
15
|2019-12-20 21:58|只看该作者
高手,这是高手。
16
 楼主|2019-12-22 01:35|只看该作者
libusb基本搞定,后面准备tcpip以及linux里的socket
以前用linux子系统,跑的代码,其实也就是利用了libusb和tcpip以及简单的文件系统操作,然后还有一些加密库openssl
17
|2019-12-22 08:14|只看该作者
请问一下有stm32的bsp么?
18
 楼主|2019-12-24 04:24|只看该作者
zxq6 发表于 2019-12-22 08:14
请问一下有stm32的bsp么?

你是指是否支持STM32吧,ARCH部分应该都没问题,系统可以跑起来,但是要用libusb的话,需要开发一个dwcotg的hcd驱动
扫描二维码,随时随地手机跟帖

本版积分规则

我要发帖投诉建议创建版块

快速回复

您需要登录后才可以回帖
登录 | 注册

论坛热帖

在线客服 快速回复 返回顶部返回列表