嵌入式第一课笔记

2019-07-12 23:54发布

三个要求:
1.建议安装纯linux系统
  友情提示:备份重要的私人资料
  ubuntu,fedora,kali
2.建议搭建嵌入式linux开发环境
  tftp
  nfs
  linux串口终端工具:kermit/minicom
  linux源码阅读工具:ctags/cscope
  linux远程登录工具:openssh-server
  linux编辑器vim 
  拷贝vim的配置文件和功能插件:
  /home/tarena/.vimrc
  /home/tarena/.vim 
3.每天半小时笔试题
  www.baidu.com
  www.google.com + 英文


案例:给一个开发板,如何将系统部署起来?
面试题:谈谈对嵌入式的理解?
面试题:谈谈对嵌入式软件编程的理解?
面试题:谈谈对嵌入式linux系统的理解?
面试题:谈谈对linux系统启动的理解?  


实施步骤:
1.了解开发板的硬件特性
  1.1.宏观上掌握开发板具有的硬件接口
      必要接口:
      串口:搞清楚用的是哪个串口
           搞清楚串口是并行还是交叉
      网口:用于tftp和NFS网络调试
      USB口:用于软件下载和调试 
      不必要接口:根据用户需求来添置
      SD卡接口
      TF卡接口
      音频口
      HDMI
      按键:独立式按键和矩阵式按键
      LED告警指示灯(呼吸灯)
      ...
  1.2.微观上了解硬件特性
      结合开发板原理图
      重点关注开发板上的一些外围芯片跟CPU之间的通信接口,        例如,AT24C02存储器,采用I2C总线接口;外置的RTC实时    时钟芯片,采用SPI总线接口;外置DS18B20温度传感    器,采用1-wired(单总线)接口....
      不同的接口,将来在软件上的操作方法不一致!
  
  如果硬件上不太懂,不太明白,问硬件工程师!
  
2.部署软件内容
  2.1.明确配套的软件一般都是由芯片厂家或者开发板的厂家提供,千万不要从头从零自己去所谓的"移植"
  2.2.获取交叉编译器,部署交叉编译器的环境变量
      从官方获取
      从arm-linux官方获取编译器
      利用crosstool-ng工具自己制作(自动)
      单独下载gcc,glibc....自己制作(手动)
  2.3.部署uboot
      获取官员uboot源码
      解压源码
      进入源码
      make distclean //获取最最干净的源码
      make xxx_config //配置源码.xxx_config通过阅读Makefile文件来获取,一般来说xxx就是开发板的名称
      make all //编译,结果生成u-boot.bin可执行文件
      烧写
      局部移植:现有的开发板有可能和官方提供的参考板有些外围接口不太一致,需要对官方的uboot源码进行局部的修改。
      终点关注uboot的平台头文件:include/configs/xxx.h
      
      如果在官方的uboot中添加额外的功能:logo显示或者组合按键功能一般都在main_loop函数中
      
      面试题:谈谈对uboot的认识!
   
   2.4.linux内核部署
       获取官方的内核源码
       make distclean //获取干净的源码,执行一次即可
       make xxx_defconfig //配置源码,xxx_defconfig来源于       arch/arm/configs/xxx_defconfig
       make zImage //编译内核,arch/arm/boot/zImage
       多多看一个重要的平台代码文件:
        arch/arm/mach-s5pv210/mach-cw210.c
        此文件设计硬件相关的内容,跟移植和驱动开发相关
       
   2.5.部署根文件系统rootfs
       1.可以采用官方的根文件系统
        又大,臃肿,很多内容用不着!
       2.利用busybox,自己制作
        体力活!
       
   2.6.驱动开发
       根据开发板的外设,完成外设的设备驱动
       了解外设的硬件接口:GPIO,SPI,I2C,UART...
       了解外设的硬件特性:看芯片手册
       编写设备驱动
       编写测试用例
       
3.设置启动参数
  bootcmd:用于加载和引导内核
  bootargs:用于给内核传递参数,告诉内核将来如何挂接根文件   系统
  注意:给内核传递启动参数的方法有两种:
  1.利用uboot的bootargs
  2.内核自身来传递
    进入内核源码
    make menuconfig
    Boot options->
     ()  Default kernel command string (NEW)//内核默认的启动参数信息,将光标移动到此位置,按回车键进入,设置内核的启动参数,例如:
     root=/dev/nfs nfsroot=...
     
    [ ]Always use the default kernel command string 
     如果选择为*,使用内核自己的参数信息
     如果不选择,默认使用uboot的参数信息
 
4.内核挂接NFS网络文件系统的注意事项:
  1.安装nfs网络服务
  2.sudo vim /etc/exports添加共享目录的支持
  3.重启NFS网络服务
    sudo /etc/init.d/nfs-kernel-server restart 
  4.内核要支持NFS网络文件系统
    进入内核源码
    make menuconfig
        File systems  --->   
          [*] Network File Systems  ---> 
          [*]Root file system on NFS
         
案例:将官方的内核在CW210开发板运行,并且采用NFS网络文件系统
实施步骤:
操作内核:
1.从ftp/drv下载官方内核源码:kernel.tar.bz2
2.修改/opt目录的用户和组
  sudo chown tarena /opt -R
  sudo chgrp tarena /opt -R
3.cp kernel.tar.bz2 /opt/ 
4.cd /opt/
5.tar -jxvf kernel.tar.bz2 //生成kernel目录(源码根目录)
6.cd kernel
7.make distclean //只执行一次
8.make cw210_defconfig //配置针对CW210开发板
9.make zImage //编译
10.cp arch/arm/boot/zImage /tftpboot 


操作根文件系统
11.cp /home/tarena/workdir/rootfs/rootfs /opt/ -frd
12.sudo vim /etc/exports 添加/opt/rootfs的支持
13.sudo /etc/init.d/nfs-kernel-server restart 重启服务


设置启动参数:
14.进入uboot的命令行模式
15.setenv bootcmd tftp 20008000 zImage ; bootm 20008000
16.setenv bootargs root=/dev/nfs nfsroot=192.168.1.8:/opt/rootfs ip=192.168.1.110:192.168.1.8:192.168.1.1:255.255.255.0::eth0:on init=/linuxrc console=ttySAC0,115200
17.saveenv


内核自身来传递参数:
18.cd /opt/kernel
   make menuconfig
   Boot options->
     ()  Default kernel command string (NEW)//内核默认的启动参数信息,将光标移动到此位置,按回车键进入,设置内核的启动参数,例如:
     root=/dev/nfs nfsroot=192.168.1.8:/opt/rootfs 
ip=192.168.1.110:192.168.1.8:192.168.1.1:255.255.255.0::eth0:on init=/linuxrc console=ttySAC0,115200 
    [*]Always use the default kernel command string 
   保存退出
   make zImage
   cp arch/arm/boot/zImage /tftpboot


19.进入uboot
   setenv bootargs  //清除uboot的bootargs
   saveenv


20.重启开发板,看内核是否能挂接NFS网络文件系统


**********************************************************
2.linux内核基本编程框架
  2.1.回顾应用程序的基本编程框架
  #include
  ...
  int main(int argc, char *argv[])
  {
  printf("hello,world ");
  ...
  return 0;
  }
  特点:
  1.头文件是标准C的头文件
  2.printf函数是标准C的库函数,对应的库libc*
  3.main函数是程序的入口函数
  4.return表示程序的出口
  5.argc,argv分别表示命令行传参的个数和参数信息


  2.2.linux内核基本的编程框架
  例子代码helloworld.c:
  #include
  #include
  ...
  static int helloworld_init(void)
  {
  printk("hello,world ");
  ...
  return 0; //执行成功返回0,执行失败返回负值
  }
  static void helloworld_exit(void)
  {
  printk("good bye! ");
  ...
  }
  module_init(helloworld_init);
  module_exit(helloworld_exit);
  MODULE_LICENSE("GPL");
  内核程序特点:
  1.使用的头文件都位于内核源码中
  2.使用调用的函数的定义都位于内核源码中
  3.module_init修饰的函数helloworld_init就是内核程序的入口函数,类似main函数,入口函数的返回值为int,参数为void
  4.module_exit修饰的函数helloworld_exit就是内核程序的出口函数,类似return 0;返回值,形参都是void
  5.任何一个内核程序(.c),都必须添加GPL许可声明,必须添加:
    MODULE_LICENSE("GPL");
  6.内核程序的入口函数执行完毕,并不代表内核程序结束,恰恰相反,内核程序而是刚刚开始,仅仅是存在于内存中,供应用程序来访问使用;
  7.内核程序的出口函数执行完毕,这个内核程序将会从内存中剔除


  2.3.问:如何编译内核程序(关键要指定内核源码)
      答:编写Makefile即可
      Makefile文件的模板:
      obj-m += helloworld.o
      #说明:将helloworld.c最终编译成对应的二进制可执行文件helloworld.ko
      all: 
      make -C /opt/kernel SUBDIRS=$(PWD) modules
      #说明:
  make -C /opt/kernel:到/opt/kernel目录下执行make命令
  SUBDIRS=$(PWD):$(PWD)代表helloworld.c所在的路径,把路径信息给SUBDIRS(表示内核的一个子目录)
  modules:告诉内核,对于helloworld.c所在目录下的文件采用模块编译,就是将.c->.ko
      clean:
      make -C /opt/kernel SUBDIRS=$(PWD) clean


案例:编写第一个内核程序
实施步骤:
PC执行:
1.mkdir /opt/drivers/day01/1.0 -p
2.cd /opt/drivers/day01/1.0
3.vim helloworld.c 内容如下
  #include
  #include
  static int helloworld_init(void) //入口函数
  {
  printk("hello,world ");
  return 0; //执行成功返回0,执行失败返回负值
  }
  static void helloworld_exit(void) //出口函数
  {
  printk("good bye! ");
  }
  module_init(helloworld_init);
  module_exit(helloworld_exit);
  MODULE_LICENSE("GPL");


4.vim Makefile 内容如下:
  obj-m += helloworld.o
  all: 
      make -C /opt/kernel SUBDIRS=$(PWD) modules
  clean:
  make -C /opt/kernel SUBDIRS=$(PWD) clean
 
5.make 编译
6.结果是helloworld.c有了一个对应的helloworld.ko
7.cp helloworld.ko /opt/rootfs/ //将可执行文件拷贝到开发板
8.问:如何在开发板上运行内核程序呢?让他和zImage混呢?
  答:
  ARM板操作:
  利用insmod,rmmod,lsmod进行对内核模块操作
  insmod:加载内核程序到内核中(内存中)
  加载内核程序时,如果内核程序有入口函数,内核调用此函数;如果没有入口函数,没关系,照样加载到内存中!
  insmod helloworld.ko
  lsmod:查看当前内核中加载了哪些内核模块,内核程序
        lsmod
  rmmod:删除内核模块,内核程序从内核(从内存中),如果内核程序有出口函数,此时调用出口函数,如果没有出口函数,没关系,照样删除!
  rmmod helloworld
  lsmod