回顾:
面试题:谈谈对嵌入式的理解
1.明确:如何向下位机部署软件
  1.1.明确:嵌入式开发模式,画出简要的示意图
  1.2.看图明确接下来要完成的内容
      上位机搭建开发环境
          各种安装
      搞定下位机
              掌控硬件信息
                  粗看
                          三大件
                          外围
                  细看
                          原理图
                          手册
              部署uboot
                  TF卡
            掌握uboot常见的命令
                print
                    serverip
                    ipaddr
                setenv
                saveenv
                ping
                tftp
                update_mmc
                go  
                
2.面试题:谈谈对ARM处理器裸板编程的认识
  2.1.上来直接提出案例,阐述ARM裸板编程的流程。目前:先以LED开关灯为例,进行阐述解释说明 。
  2.2.明确相关概念 。
      计算机硬件层面包括:CPU和外设 。
      CPU一天到晚都是在跟外设进行数据通信。CPU访问外设都是以地址指针的形式访问
  2.3.紧接着分析用户需求。
      目前需求就是:开关灯
  2.4.掌控LED的硬件相关信息 。
      粗看:
          看位置
          硬件工程师
      细看:
          1.LED的原理图:
          通过原理图得到:

          1.1.务必画出一个简要的CPU访问操作LED的示意图。

                   

EMMC布线走空引脚 emmc153引脚定义_EMMC布线走空引脚


          1.2.看图阐述CPU核访问LED的流程

            CPU核以软件(地址指针)形式访问GPIO控制器内部的一大堆寄存器,本质就是给GPIO控制器发送控制操作命令 。

             

            GPIO控制器根据命令由硬件上自动操作对应的引脚(管脚)(无非就是高低电平)。

             

            引脚的状态(高/低电平)最终影响LED的状态(亮/灭)。

          1.3.结论:

                  接下来只要掌握GPIO控制器以及内部的一大堆寄存器的操作即可完成最终的LED的操作。

                  

          2.问:GPIO控制器以及内部一大堆的寄存器如何访问呢?

            答:由于GPIO控制器集成在S5P6818处理器的内部。要想知道GPIO控制器如何访问操作,只需看S5P6818处理器的芯片手册(说明书)。

        

        3.打开S5P6818处理器的芯片手册:

          resource/Datasheet/SEC_S5P6818X_Users_Manual_preliminary_Ver_0.00.pdf

          切记:尤其是处理器的芯片手册,只看跟目前研究的内容(GPIO控制器)相关的章节。


          结论:P739第16章讲解GPIO控制器



          3.1.看GPIO控制器相关的说明,罗列重要的跟将来软件操作相关的内容:

              1.S5P6818包含160个GPIO引脚

                分五组:A/B/C/D/E

                每一组:32个GPIO

                LED1对应的引脚为:GPIOC12(C组的第12个引脚)

              2.GPIO的输出操作,P742

                GPIO复用功能选择寄存器:指定GPIO引脚的复用功能 。

                GPIO输出使能寄存器:指定GPIO的输入或者输出功能 。

                GPIO输出寄存器:指定GPIO的输出值(0:低电平;1:高电平) 。

                结论:开关灯操作:

                1.首先配置GPIO复用功能选择寄存器,配置为GPIOC12这种功能 。

                2.然后配置GPIOC12为输出功能,配置GPIO输出使能寄存器 。

                3.最后:

                  开灯:配置GPIO输出寄存器为0

                  关灯:配置GPIO输出寄存器为1

                4.问:以上三个寄存器如何访问操作呢?

                  答:寄存器也是硬件,它同样是外设!

             3.相关寄存器的特性(P745):

               GPIOCOUT:输出寄存器

               基地址:0xC001C000

               BIT[12]=0:输出低电平,开灯

*(volatile unsigned long *)0xC001C000 &= ~(1 << 12);                     
                美化: 
                #define GPIOCOUT *(volatile unsigned long *)0xC001C000
                GPIOCOUT &= ~(1 << 12); 
                 
                BIT[12]=1:输出高电平,关灯 
                GPIOCOUT |= (1 << 12); 
                 
                GPIOCOUTENB:输出使能寄存器 
                基地址:0xC001C004 
                BIT[12]=1:配置为输出功能 
                #define GPIOCOUT (*(volatile unsigned long *)0xC001C004) 
                GPIOCOUTENB |= (1 << 12); 
                 
                GPIOCALTFN0:复用功能选择寄存器0(P757) 
                基地址:0xC001C020 
                BIT[25:24]=01   //注意在P68  
                GPIOCALTFN0 &= ~(3 << 24); 
                GPIOCALTFN0 |= (1 << 24);  
                 
                至此:硬件信息的掌控完毕! 
                 
       2.5.一旦硬件信息掌控完毕,编写LED的操作软件 
           1.明确:嵌入式软件开发分为两类 
             裸板程序: 
                     下位机不会运行操作系统(linux/windows/vxworks),运行的程序就一个,单任务运行 。
                     标准C的库函数一律不能使用,例如:printf。 
                      
             基于操作系统程序:后续慢慢讲解 
             结论:首先要明确LED的程序属于哪类。此时此刻,此LED程序为裸板程序。          
            
           2.明确:裸板程序的编程框架 
             开发语言:一般C语言或者汇编 。
             “硬件初始化”:硬件外设正式工作之前,将其工作参数,工作状态配置完毕 。
             框架: 
             //裸板程序的入口函数名随便定义,不一定非要是main 
             void xxx(void) { 
                      
                     //硬件初始化函数 
                     xxx_init(); 
                     /* 
                     led_init(); //初始化LED 
                     uart_init(); //初始化串口 
                     net_init(); //初始化网络 
                     mmc_init(); //初始化EMMC 
                     bt_init(); //初始化蓝牙 
                     lcd_init(); //初始化LCD显示屏 
                     ... 
                      
                     */ 
                      
                     while(1) { 
                          //做业务:根据用户需求,操作硬件外设 
                          /* 
                            led_on(); 
                            delay(); 
                            led_off(); 
                            delay(); 
                          */ 
                     } 
             }        
                
           3.编写LED裸板程序,实现交替闪烁 
             实施步骤: 
             上位机执行: 
             sudo chown tarena /opt -R 
             sudo chgrp tarena /opt -R 
             mkdir /opt/arm/day03/1.0 -p 
             cd /opt/arm/day03/1.0 
             vim led.h //声明 
             vim led.c //定义 
                     
                    注意:vim的使用 
                    1.vim多屏显示(命令行模式下) 
                  vs 文件名 //左右分屏 
                  sp 文件名 //上下分屏 
                  切换快捷键:ctrl + ww 
           
                  复制粘贴: 
                  shift+v:行选 
                  ctrl+v:列选 
           
                          
            
           4.问:如何编译LED的程序呢? 
             答:明确:势必不能用gcc编译(针对于X86架构),所以:务必先在上位机部署添加交叉编译器。 
                 上位机添加ARM架构交叉编译器的流程: 
                 4.1.获取交叉编译器 
                 resource/编译器/arm-cortex_a9-eabi-4.7-eglibc-2.18.tar 
                 拷贝到linux和windows共享目录中 
                 cp arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz /opt/ 
                  
                 4.2.上位机添加 
                 cd /opt/ 
                 tar -xvf arm-cortex_a9-eabi-4.7-eglibc-2.18.tar.gz 
                 得到新目录:arm-cortex_a9-eabi-4.7-eglibc-2.18 
                 mv arm-cortex_a9-eabi-4.7-eglibc-2.18 toolchains 
                 ls /opt/toolchains/bin/ 
                    arm-cortex_a9-linux-gnueabi-gcc //ARM架构的gcc编译器
                  
                 sudo vim /etc/environment 
                 在PATH中添加/opt/toolchains/bin,例如: 
                 PATH=/opt/toolchains/bin:... 
                 保存退出 
                  
                 重启上位机linux系统 
                  
                 4.3.测试交叉编译器 
                 上位机执行: 
                 arm-cortex_a9-linux-gnueabi-gcc -v //查看交叉编译器的版本 
                  
                 4.4.交叉编译LED程序 
                 cd /opt/arm/day03/1.0 
         arm-cortex_a9-linux-gnueabi-gcc -nostdlib -c -o led.o led.c
                 说明: 
                 -nostdlib:告诉编译器,此程序不使用标准C库 
                 -c:只编译不链接 
 
                 
arm-cortex_a9-linux-gnueabi-ld -nostartfiles -nostdlib  -Ttext=0x48000000  -o  led.elf led.o
 
                说明: 
                 arm...ld:链接器 
                 -nostartfiles:告诉链接器,此代码无需启动文件 
                 -Ttext=0x48000000:告诉链接器,代码段的起始地址为0x48000000(下位机的内存地址) 
                                 -o led.elf:链接生成ELF格式的可执行文件 
                                 切记:此时此刻led.elf不能在没有操作系统的环境中运行 
                                  
                                 arm-cortex_a9-linux-gnueabi-objcopy -O binary led.elf led.bin
                                 说明:利用arm...objcopy工具将ELF格式的可执行文件 
                                       再次获取到其中的真正的二进制文件信息 
                                       led.elf:橘子(带皮) 
                                       led.bin:果肉 
                                       objcopy:去皮工具 
                                        
                                 cp led.bin /tftpboot //拷贝到下载目录 
                                  
                                 绝招:反汇编 
                      arm-cortex_a9-linux-gnueabi-objdump -D led.elf > led.dis  
                                 led.dis:反汇编文件 
                                 vim led.dis //只需关注一个内容即可 
                                 <0x48000000>:led_test  
                         如果看到以上信息说明:led_test函数的地址为0x48000000。说明程序的编译是对的! 
                                  
                          5.下位机测试 
                            重启下位机,进入uboot命令行模式,执行: 
                            ping 192.168.1.8 
                            tftp 48000000 led.bin 
                            go 48000000 
                          
                          6.验证入口地址特性 
                            cd /opt/arm/day03/1.0 
                            vim led.c //将delay函数的定义放在led_test函数定义的前面 
                            保存退出 
                            ①.arm-cortex_a9-linux-gnueabi-gcc -nostdlib -c -o led.o led.c
                            ②.arm-cortex_a9-linux-gnueabi-ld -nostartfiles -nostdlib  
                                        -Ttext=0x48000000 -o led.elf led.o 
                            ③.arm-cortex_a9-linux-objcopy -O binary led.elf led.bin
                            ④.arm-cortex_a9-linux-objdump -D led.elf > led.dis 
                            ⑤.vim led.dis  
                            查看0x48000000这个地址对应的函数是:led_test?delay? 
                             
                            切记:编译器链接是从文件的头到尾进行链接(从上到下) 
                             
                            作业:实现一个跑马灯 
                            LED1亮->LED2亮->LED3亮->LED4亮->LED1灭->... 
                             
                            作业:实现蜂鸣器的操作 
 ************************************************ 
 2.面试题:谈谈对UART的理解 
   2.1.首先要交待计算机中常见的几种硬件通信方式 
       硬件通信接口 
       明确:计算中包括:CPU和外设。 
             CPU一天到晚和外设进行数据交互通信 
       问:CPU和外设数据通信的方式方法有哪些呢? 
       答:计算机中CPU和外设进行硬件通信的方式 
           通信接口有以下几种: 
           1.GPIO通信方式,例如:LED灯,蜂鸣器等 。
           2.UART串口通信方式,例如:GPS,GPRS,BT等 。
           3.I2C总线通信方式,例如:重力传感器,三轴加速度传感器,触摸屏等 。
           4.SPI总线通信方式,例如:Norflash闪存,触摸屏等 。
           5.1-Wire(一线式)总线通信方式,例如:温度传感器,EEPROM存储器等 。
           所以:这里开始讲解UART,如果可以,也可以阐述一下I2C总线 。
     
    2.2.UART串口的定义 
        定义就九个字:通用串行异步收发器 。
        进一步的对定义进行解释说明: 
        “通用”:UART串口应用非常广泛 
        ”串行“:CPU和外设进行数据通信时,只需一根信号线即可 。
               此信号线又称数据线,也就是说CPU和外设进行数据通信时,是一个bit位一个bit位的传输: 
               切记:UART数据传输从低位开始! 
               例如:CPU向BT发送一个0x95这个数据 
               数据线的操作如下: 
               高->低->高->低->高->低->低->高 
               1   0   1   0   1   0    0  1 
 
       顺便侃侃串行的死对头:并行 
       “并行”:CPU和外设数据传输时,需要多根信号线(数据线),8/16/32根,那么也就是一次数据传输可以同时传输8bit/16bit/32bit
 
       顺便再看看并行和串行的对比: 
        传输速度:一般来说并行快于串行 。
        传输距离:串行更适合远距离传输 。
        抗干扰性:串行抗干扰性更好。                                       
               
              “异步”:首先要明确:CPU的数据处理速度要远远快于外设。 
                      所以CPU和外设进行数据传输时,务必要考虑数据同步。 
 
                     “数据同步”:CPU向设备发送数据以后,要确保外设能够正常的将数据接收到,接收完整!
 
                     计算机中数据同步的方法有两种:异步和同步 。
                       
 异步定义:双方在数据正式传输时,只要保证数据同步即可 。传输前和传输以后,无需考虑数据同步。异步具体如何实现数据同步关键在于协议中!这里待会儿讲讲UART的协议,即可了解何为异步!
                       
 同步定义:CPU和外设进行数据传输时,如果采用同步方式保证数据同步,那么CPU和外设之间不仅仅有数据线,还需要一根时钟控制信号线,此信号线就是用来实现双方的数据同步,此时此刻,务必画图举例子说明即可!
                                参见:uart2.bmp 
                                以CPU向外设LM77发送1和0为例:
                                CPU在时钟线为电平时,将数据1放到数据线上(拉高数据线) 
                                设备就会在同周期的高电平从数据线上读取数据                                                    
                                          结论:低放高取
                                           
                 收发器:接收和发送数据的硬件单元。         
                 CPU给外设发送数据: 
                         CPU就是发送器,外设就是接收器。 
                 外设给CPU发送数据: 
                         外设是发送器,CPU是接收器 。