韦东山第一期课程内容概要

  • 1一个嵌入式程序要运行所需的东西
    • 1.1第一条指令:b reset
    • 1.2 reset要完成的事件
      • 1.2.1设置开门狗
      • 1.2.2设置时钟
      • 1.2.3判断启动方式并设置堆栈
      • 1.2.4代码重定位
    • 1.3执行main函数
  • 12 之前的汇总
  • 13 代码重定位
    • 13.1 段的概念以及重定位
      • 什么时候需要代码重定位
      • 裸板中“段”的概念
    • 13.2 链接脚本的引入与简单测试
      • 三种重定位方案
      • 链接脚本的编写(程序005_013_003)
    • 13.3 链接脚本的解析
      • 编写程序让BSS段对应的位置清0(程序006_013_003)
    • 13.4 拷贝代码和链接脚本的改进(007_013_004)
      • 拷贝代码的改进
      • 链接脚本的改进
    • 13.5 代码重定位和位置无关码(008_013_005)
      • 与位置无关的代码
    • 13.6 重定位代码和清除BSS段代码的C语言实现
  • 14 异常与中断
    • 14.1 概念引入与处理流程
    • 14.2 CPU模式(mode)、状态(state)以及寄存器
    • 14.3 Thumb指令集程序示例
    • 14.4 und异常模式程序示例
    • 14.5 swi异常模式程序示例
    • 14.6-7 按键中断程序
    • 14.8 定时器中断
  • 15 NOR Flash
    • 15.1 Nor Flash原理及硬件操作
  • 16 Nand Flash
    • 16.1 Nand Flash操作原理
  • 17 LCD
    • 17.1 LCD硬件原理
    • 17.2 S3C2440_LCD控制器
  • 18 ADC和触摸屏
    • 18.1 & 18.1 ADC采样原理和简单编程介绍
    • 18.3 & 18.4 触摸屏硬件原理和S3C2440的触摸屏接口
  • 19 I2C
    • 19.1 I2C协议与EEPROM
    • 19.2 S3C2440A的I2C控制器
  • 20 SPI
  • 21 MMU和Cach

1一个嵌入式程序要运行所需的东西

有些时候知识点学的太零碎,拿到一个项目不知道从哪里下手,下面讲一下如何从一个裸板开始编写程序。

1.1第一条指令:b reset

CPU运行的第一条指令不要认为是main函数,从两方面来讲。在物理上,CPU从片内4K的SRAM的首地址取指令然后执行(Nand启动),或者是nor的首地址取指令。在软件上,一般第一条指令是启动文件start.S里的第一条指令,比如:

.text
.global _start_start:b reset  /* vector 0 : reset */b do_und /* vector 4 : und */

这里第一条指令就是b reset。那么如何保证start.S文件的第一条指令就存放在物理上的首地址呢?这就需要编写makefile,在链接的时候将start文件排在最前面,也就是最左边,这样所最终编译出来的二进制文件的第一条指令就是b reset。
第一条指令往往是跳转到reset标签,这样每次上电就从reset开始

1.2 reset要完成的事件

跳转到reset后主要执行一些初始化,想象一下,我们每次断电再上电,都会执行一次reset,这里面需要对CPU进行配置,以便其能够很好的执行后面的程序。这些配置大部分是有默认值的,所以即使不配置或许也能运行程序,但那样就对整个程序的细节缺乏了解。

1.2.1设置开门狗

开门狗能够有效的防止程序跑飞,需要最开始就进行设置,就是操作一些寄存器,具体怎么设置看芯片手册。

1.2.2设置时钟

CPU的运行基于时钟信号,所以紧接着设置时钟。S3C2440A有三种时钟频率,FCLK HCLK PCLK,设置时钟主要就是配置三种时钟的具体频率。具体看操作手册。

1.2.3判断启动方式并设置堆栈

首先判断启动方式是设置堆栈的前提,启动方式不同堆栈的设置方法也有一些区别。堆栈的作用很多,如保存和恢复中断现场、保存函数的局部变量、传递函数参数等,所以需要进行设置。

1.2.4代码重定位

原因见13,注意一定要完成代码重定位以后才能打开全局中断。

1.3执行main函数

一切都设置好以后,可以使用跳转指令跳到main函数执行,比如在start.S里面写bl main或者ldr pc, =main,前者为相对跳转,后者为绝对跳转。start.S是汇编文件,我们很熟悉汇编里面标签的概念,这里main虽然写在main.c文件中,但在编译过程中,main.c也会被编译成汇编文件main.S,编译器会自动在main.S内容开始的地方打上一个main标签。具体可以参考09-9课的反汇编文件。
其实在start.S里调用main函数就是汇编和c的混合编程,汇编调用c程序,这里面主要用到ATPCS协议,这也是为什么需要先设置堆栈的原因之一,可能需要堆栈来传递参数。同理我们可以在bl main之前的reset过程中也调用一些函数,注意先根据ATPCS协议进行配置即可。

12 之前的汇总

1、一个linux程序系统中,BootLoader和驱动程序都有跟硬件打交道的部分,而这一部分的开发实际上和单片机裸机开发很像。BootLoader实际上就是一个单片机裸机开发的大全。

2、片内SRAM、NOR Flash 、 NAND Flash、片外SDRAM
Flash都是非易失存储器,而且可读可写,只不过Flash的每次写入都有轻微的破坏性,寿命有限。NOR Flash采用了类似SDRAM的随机读取技术,因此允许用户直接运行装载在NOR Flash里面的代码,降低了系统中SRAM的需求量。 NAND Flash的存取以“块”的形式来组织,通常一次读取2048字节(一块)。
jz2440上 NAND Flash大小为256M,NOR Flash为2M。除此之外jz2440上还有片外的32M大小的SDRAM作为片外内存(也是我们最熟悉的那个内存),S3C2440A片内还有4KB大小的SRAM作为片内的内存。
CPU执行的第一条指令可以从两个地方读取:片外(片指的是S3C2240A)的NOR Flash或者片外的Nand Flash。注意程序不能从内存启动,也就是说我们烧录的程序不是直接烧写到这32M内存中的。
对于 NAND Flash启动(第一条指令从 NAND Flash里取)的程序,硬件在开始时会将 NAND Flash的前4kb内的程序复制到片内SRAM用于程序启动,此时程序相当于就在SRAM里,可以随意读写,此时地址空间的0地址是片内SRAM的基地址。NAND Flash启动模式下,NOR Flash不能访问。
对于 NOR Flash启动,则直接从 NOR Flash的首地址取第一条程序,相当于程序从外存中直接读进来,这时候读可以随意读,但是写需要一些特定格式,此时地址空间的0地址是的NOR Flash基地址,片内SRAM的基地址从0x40000000开始(具体见S3C2440A芯片手册)。
对于C程序,全局变量在编辑好程序,编译成bin文件,烧写到Flash后,其位置就是固定的;而局部变量,是放在栈中,也就是片内4kSRAM中。如果是Nor启动,也就是说全局变量存放在Nor中,Nor是不能通过C语言去写入的,也就是说不能用C对Nor中的全局变量进行操作。

4、如果想看汇编的话,可以将得到的二进制程序进行反汇编,可以查看对应的汇编代码。(09.4)

5、c语言程序—汇编程序—二进制程序—以.bin的文件形式存放

6、int类型的最高位表示符号位,如果要用int * 来存放内存地址,应该用 unsigned int *,如:

unsigned int * pGPFCON=0x56000050;
unsigned int * pGPFDAT=0x56000054;

7、ARM中的BL指令
BL label 指令执行两个操作:(1)跳转到label处执行(函数调用)(2)将返回地址保存到LR寄存器

8、静态链接与动态链接
动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。
动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。

静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,
不过静态链接生成的程序体积较大。

gcc -c -o hello.o hello.c
gcc -o hello_shared  hello.o//默认为动态链接
gcc -static -o hello_static hello.o//使用 static 表示静态链接

13 代码重定位

13.1 段的概念以及重定位

主要介绍了为什么需要重定位,以及在裸板运行中“段”的概念。

什么时候需要代码重定位

对于NAND Flash启动,由于S3C2440A的片内SRAM只有4k,如果程序在Nand中超过4k,则前4k复制到SRAM,前4k的程序要负责将后续的程序复制到片外32M的SDRAM中,这叫做代码重定位
对于 NOR Flash启动,如果程序中含有需要写入操作的全局变量或者静态变量,则需要将这些变量复制到片外32M的SDRAM中,否则不能正常写入,这叫做代码重定位

裸板中“段”的概念

裸板不像有OS那样会给每个进程划分进程空间,裸板整个程序的运行就是一个进程,进程空间就是整个地址空间,整个地址空间被划分为代码段、可读可写数据段、只读数据段、初始值为0的数据段、注释段等等。可以在编译的时候,在makefile中指定每个段的起始地址。

13.2 链接脚本的引入与简单测试

注:下面所涉及的所有知识都可以在GNU的官方文档:Using LD, the GNU linker
http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html

由于Nor启动时主要问题就是全局变量无法写入,而全局变量存放在数据段中,其他代码存放在代码段中,对Nor启动下的重定位,有三种方案。三种解决方案的手段主要是通过编写链接脚本来实现。

三种重定位方案

第一种是在makefile中将数据段的起始地址设置为SDRAM的起始地址(如果不设置,默认是数据段紧挨着代码段,而代码段一般从0地址开始),S3C2440中SDRAM的起始地址是0x30000000,也就是说在编译形成bin文件后,bin文件的代码段一般是地址0x00000000开始,然后中间空出一大段区域,在0x30000000开始的地方存放数据段,代码如下:
arm-linux-ld -Ttext 0 -Tdata 0x30000000 start.o led.o uart.o init.o main.o -o sdram.elf
这样做的缺点是会形成一个很大的bin文件,而显然bin文件应该尽可能小才对。注意,不要臆想直接将代码段和数据段的起始地址都设置到SDRAM,Nor启动时第一条代码只能从nor从取得。
第二种是,代码和数据段紧挨着,烧写到Nor。运行时,在代码段的程序中,编写程序将全局变量复制到SDRAM区域。
第三种是,代码和数据段紧挨着,烧写到Nor。运行时,在代码段的程序中,编写程序将整个程序复制到SDRAM区域。

链接脚本的编写(程序005_013_003)

新建一个后缀为.lds的链接脚本文件,将其加入到makefile中,脚本功能是将所有段都紧挨着一起存放,脚本编写如下:

SECTIONS {.text   0  : { *(.text) }  .rodata  : { *(.rodata) }.data 0x30000000 : AT(0x800) { *(.data) }.bss  : { *(.bss) *(.COMMON) }
}

其中,对于.data 0x30000000 : AT(0x800) { *(.data) }, 0x30000000表示希望数据段存放的地址(程序执行时,也就是main函数执行时,会认为数据段在0x30000000开始的地址里),AT(0x800)表示实际在链接成bin文件时,还是将数据段加在代码段后面(避免bin文件过大),0x800是例子程序的代码段所需的bin文件空间,实际编程时不可能直接写0x800,稍后会有改进。
写完以后放在makefile同一目录下,makefile改写:
arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf
如果这样直接去编译链接烧写然后执行的话(不管是nand还是nor启动),会出现乱码,因为我们实际上数据段还是在nor里面,并没有真正在0x30000000里存放数据,执行main函数过程中会取不到数据(main函数试图从0x3000000开始的地方去取)。我们需要在start.s文件里,在跳转到main函数之前,将存放在nor中的数据段复制到0x3000000开始的地址空间中,也就是SDRAM中。start.s的简略修改如下,真实编程不可能直接写0x800。

 /* 重定位data段 */bl sdram_init //注意一定要初始化SDRAM,否者写不进0x30000000mov r1, #0x800ldr r0, [r1]mov r1, #0x30000000str r0, [r1]bl main

以上程序很简略,因为我们是事先看了反汇编代码,知道代码段结尾是0x800,而且知道数据段只有一个字节,得写一个更通用得重定位代码,主要解决两个问题,一是自动计算数据段大小,而是自动计算代码段结尾的位置(也就是数据段的bin起始地址)。通用代码如下:

SECTIONS {.text   0  : { *(.text) }.rodata  : { *(.rodata) }.data 0x30000000 : AT(0x800) { data_load_addr = LOADADDR(.data);data_start = . ;*(.data) data_end = . ;}.bss  : { *(.bss) *(.COMMON) }
}

以下是start.S:

bl sdram_init    /* 重定位data段 */ldr r1, =data_load_addr  /* data段在bin文件中的地址, 加载地址 */ldr r2, =data_start      /* data段在重定位地址, 运行时的地址 */ldr r3, =data_end         /* data段结束地址 */cpy:ldrb r4, [r1]strb r4, [r2]add r1, r1, #1add r2, r2, #1cmp r2, r3bne cpybl main

13.3 链接脚本的解析

主要分析上面写的那个链接脚本的语法和内部机理,这里手动加上行号。

SECTIONS {1、   .text   0  : { *(.text) }
2、   .rodata  : { *(.rodata) }
3、   .data 0x30000000 : AT(0x800)
4、   {
5、      data_load_addr = LOADADDR(.data);
6、      data_start = . ;
7、      *(.data)
8、      data_end = . ;
9、   }
10、   .bss  : { *(.bss) *(.COMMON) }
}

1、表示所有程序的text段,放在bin文件0地址开始的地方,整个程序包含start.o led.o uart.o init.o main.o等多个子程序,每个子程序都有自己的代码段数据段。这些代码段从0开始存放,谁先存谁后存取决于Makefile语句中的左右顺序,比如这里就是最先是start.o的代码段,其次是 led.o的,最后是main.o,一般第一个最好是start.o,后面就无所谓了,因为start.o里会执行程序的跳转。
2、紧挨着代码段放所有文件的只读数据段
3、7、放所有文件的数据段,数据段bin地址为0x800开始,实际运行时重定位到0x30000000
6、变量data_start等于当前地址
8、 data_end等于当前地址,由于6和8之间执行了存放数据段的指令,data_start和data_end的差值就是数据段的大小。
10、程序运行时,bss段紧挨着数据段存放,其首地址为0x3xxxxxxx,在bin文件中不放bss和common,需要程序运行时把bss段对应的空间清0,否则会声明为0的变量会是乱码。

编写程序让BSS段对应的位置清0(程序006_013_003)

想要实现功能,需要知道bss段存放的具体地址,需要修改链接脚本和start.S,修改后的如下:

SECTIONS {.text   0  : { *(.text) }.rodata  : { *(.rodata) }.data 0x30000000 : AT(0x800) { data_load_addr = LOADADDR(.data);data_start = . ;*(.data) data_end = . ;}bss_start = .;.bss  : { *(.bss) *(.COMMON) }bss_end = .;
}
bl sdram_init    /* 重定位data段 */ldr r1, =data_load_addr  /* data段在bin文件中的地址, 加载地址 */ldr r2, =data_start      /* data段在重定位地址, 运行时的地址 */ldr r3, =data_end         /* data段结束地址 */cpy:ldrb r4, [r1]strb r4, [r2]add r1, r1, #1add r2, r2, #1cmp r2, r3bne cpy/* 清除BSS段 */ldr r1, =bss_startldr r2, =bss_endmov r3, #0
clean:strb r3, [r1]add r1, r1, #1cmp r1, r2bne cleanbl main

13.4 拷贝代码和链接脚本的改进(007_013_004)

拷贝代码的改进

start.S中进行数据拷贝的时候,用的是ldrb和strb两个字节访问指令,而SDRAM和Nor分别是32位和16位,以字节访问效率太低,极大增加了硬件操作次数,改进为用ldr和str两个字操作的指令。

链接脚本的改进

因为换成了str和ldr,这些指令按字访问,所操作的地址需要向4对齐(因为是32位机器),在链接脚本里让数据段和bss段向4对齐

13.5 代码重定位和位置无关码(008_013_005)

之前所讲的都是只将数据段重定位,现在考虑将整个程序从Nor上重定位。最终生成的bin文件分为两个部分,一部分是实现真正功能所需的,一部分是完成重定位的。之前我们所写的链接脚本称为分体的链接脚本,即它的代码段和数据段是分开的,数据段经历重定位后与代码段隔很远,一般不用这种链接脚本,也就是一般都是直接将整个程序进行重定位,这需要新的链接脚本。

SECTIONS
{. = 0x30000000;//表示整个程序最初地址从0x30000000开始运行__code_start = .;//标号,表示程序段开始的内存地址. = ALIGN(4);//保证4字节对齐.text      :{*(.text)}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);__bss_start = .;//标号,表示BSS段开始的内存地址.bss : { *(.bss) *(.COMMON) }_end = .;//标号,表示整个程序结束的内存地址
}

与位置无关的代码

接下来修改启动文件start.S,将整个程序重定位。start.S实际上其整个bin文件最开始执行的语句,我们在链接脚本中指定CPU从0x30000000取第一条指令,但是如果程序通过eop最初烧写到Nor,CPU执行的第一条指令也是从Nor读取,而不是从0x30000000,这些最开始的程序需要完成整个实际程序的重定位,这些最开始的程序本来应该位于0x30000000开始,但是实际位于0地址开始,这些代码跟地址无关,称为位置无关码。我们把整个start.S拿出来分析其运行过程:

.text
.global _start_start:/* 关闭看门狗 */ldr r0, =0x53000000  //整个程序中cpu执行的第一条指令.....中间省略很多............bl sdram_init/* 重定位text, rodata, data段整个程序 */mov r1, #0ldr r2, =_start      /* 第1条指令运行时的地址 */ldr r3, =__bss_start    /* bss段的起始地址,表示程序结束的地址,bss段不需要复制 */cpy:ldr r4, [r1]str r4, [r2]add r1, r1, #4add r2, r2, #4cmp r2, r3ble cpy/* 清除BSS段 */ldr r1, =__bss_startldr r2, =_endmov r3, #0
clean:str r3, [r1]add r1, r1, #4cmp r1, r2ble clean//在跳转到main以前,都是用b和bl,用的相对跳转,程序还是运行在nor上//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

整个CPU从start标签处开始运行,start对应的第一条指令(ldr r0, =0x53000000 )存放在nor中,地址编号为0地址,程序计数器PC最初始的值就是0地址,PC中始终存放下一条将要执行的指令的地址。程序从start标签依次运行,直到指令ldr pc, =main之前,所有指令都是位置无关码,因为在这些代码里,没有使用绝对地址,都是使用的相对地址。所谓相对地址,CPU在取下一条指令时,都是从PC中去读地址,再发地址信号给内存控制器,最终得到想要的数据。程序从start标签开始顺序取指并运行,直到遇到第一个跳转指令,跳转指令有相对跳转和绝对跳转两种方式,常见的B和BL都是相对跳转,是将PC的值在原来的基础上加上一个偏移量得到新的地址存在PC中,基础PC地址原本在Nor中,加偏移量也还是在Nor中,所以程序可以正确运行。在用位置无关码将整个程序(包括位置无关码本身)全部复制到SDRAM后,就可以直接用绝对地址跳转到main所在位置,不要跳转到0x30000000,因为0x30000000存放的是start标签所对应的ldr r0, =0x53000000,直接用ldr pc, =main,将main函数入口的绝对地址0x3xxxxxxx传给PC,程序接着从main开始运行,之后的程序用相对或绝对跳转都可以,因为PC的基础值已经是0x3开头。

13.6 重定位代码和清除BSS段代码的C语言实现

汇编就ok,暂时没看。注:13.5所讲的重定位是将程序全部复制,这种方法是nor和nand通用的。这里写的程序有一个缺陷,对于nand启动,如果最终编译出来的bin文件大于4k,由于是硬件自动将nand前4k复制到片内sram,可能导致4k里面是残缺的代码,没办法运行,需要编写程序将整个程序读到SDRAM,解决方法在17.3:编程_框架与准备。

14 异常与中断

14.1 概念引入与处理流程

异常是包含中断的,中断只是异常的一种。ARM处理器包含七种异常,注意这并不等同ARM处理器的7种模式。

对于异常,主要可以分为中断的初始化(注意好像只有中断才需要初始化,异常已经初始化好了)、异常的产生以及异常的处理三个部分。
中断的初始化主要分为:a、设置中断源使其可以发出中断信号,比如设置定时器以多久的周期发出中断信号;b、设置中断控制器,主要是设置哪些中断源被屏蔽,多个中断同时发生时的中断优先级;c、CPU自身有一个总开关,使能所有中断。

异常的产生,以按键中断为例子。当一个引脚被设置为中断,按键按下时发送中断信号到中断控制器,如果该按键中断没有被屏蔽且当前没有更高优先级的中断,则中断控制器将中断信号发送给CPU,CPU硬件会在每执行完一条指令后检查是否收到中断信号,若收到中断信号则开始处理中断。

异常的处理,主要是保存现场,跳转到异常处理程序,恢复现场。跳转到事先写好的异常处理程序:首先不同的异常(包括中断)会有不同的处理程序,固定的异常类型对应的处理程序的跳转地址存放在固定的内存地址中(异常向量表),CPU在检测到异常信号后,识别出引起该信号的异常类型(硬件),接着从中断向量表中取出对应的跳转指令跳转到对应的处理程序(CPU识别异常类型跳到类型对应的异常向量,取出其中的指令然后执行该条指令,这个过程是CPU硬件决定的。我们可以软件决定的是在中断向量表对应的地方放入一条跳转指令,以及决定该跳转指令具体跳转到哪一个地址)。中断向量表的具体位置定义在start.S中。下面是AMR920T的一个start.S,具体位置取决于芯片手册

.globl _start
_start: b       resetldr    pc, _undefined_instructionldr   pc, _software_interruptldr  pc, _prefetch_abortldr  pc, _data_abortldr  pc, _not_usedldr    pc, _irq  //发生中断时,强制执行这个跳转指令,跳去irq的地址去执行ldr   pc, _fiq

跳转到执行对应的异常处理程序后,在异常处理程序中,会首先进行保存现场,主要是将本来在执行的正常程序的所有寄存器内容保存到堆栈中(包括PC寄存器);随后对异常进行处理,由前面的start.S可以看到,中断向量表里面分类分得很大,并不是具体到按键中断这种尺度,比如我执行了ldr pc, _irq,跳转irq对应的程序,该程序还需要分辨具体是哪个中断源,比如按键或者时钟,然后还要跳转到具体处理按键或者时钟的处理程序;最后恢复现场,主要是将堆栈中的内容从重新赋值给寄存器,此时PC寄存器恢复到中断发生前,随后正常执行程序。

14.2 CPU模式(mode)、状态(state)以及寄存器

讲ARM芯片架构的七种模式,两种状态(ARM和Thumb),以及诸如CPSR之类的寄存器。没看视频

14.3 Thumb指令集程序示例

没看

14.4 und异常模式程序示例

在程序中故意加入一条未定义指令,编写异常处理程序来观察现象。
步骤一:写一条未定义指令,这里注意避开ARM已经有的指令编码
步骤二:编写异常处理程序。这里主要注意一点,由ARM上电复位后处于管理模式,所以我们在reset中设置的堆栈实际上是管理模式下的堆栈,而我们在处理异常时处于未定义模式,需要设置未定义模式下的堆栈.

注意里面有些重定位的问题以及定义字符串以后4字节对齐的问题,尤其是重定位的问题。

14.5 swi异常模式程序示例

swi是人为产生的软件中断,CPU七种运行模式中,一般程序都运行在用户模式,其他六种模式可以通过修改CPSR寄存器的值来改变模式,而用户模式不可以通过改变CPSR来改变模式。用户模式下受到很多限制,比如不允许访问硬件(一般正规程序的设定,我们的程序没这个限制),如果在用户模式想访问硬件,需要通过swi进入管理模式,流程和und异常差不多。

swi异常其实就是我们熟知的系统调用

14.6-7 按键中断程序

与14.5和14.4不同的是,中断是硬件产生的,硬件类别多种多样,比如按键中断,中断的处理相比异常有一些不同。一是初始化:1设置中断源能够发出中断信号(这里是按键按下能够发出信号,配置GPIO口),2设置中断控制器,3设置CPU总开关(CPSR中的I位)。

这里不看视频了,自己动手,查芯片手册,看课堂笔记,实现按某个键,对应某个灯亮,自己编写程序才能提高自己。

中断相比与异常而言:中断在处理时要分辨不同的中断源(定时器、按键等),中断在处理完后要记得清除掉该中断。

14.8 定时器中断

同样自己查阅资料,实现定时器中断,使得led1间隔1秒闪烁 .
思考一个问题,定时器中断触发后,在处理中断的过程中,定时器还在计数吗?假设定时器1秒钟触发一次中断,如果中断处理程序的运行时间超过1秒中怎么办。

15 NOR Flash

15.1 Nor Flash原理及硬件操作

首先说明一个问题,为什么nor比nand小而且更贵但nor仍然有在用呢?原因是nor比nand安全可靠,nand可能出现位反转和坏块,nor不会,一些关键的比如内核这类代码,可以存放在nor里,一些不重要的大量的数据可以存放在nand里。(12年视频这么说的,现在nand和nor具体优劣来看,nand坏的几率比较小)。

16 Nand Flash

16.1 Nand Flash操作原理

Nand Flash本质上是一个存储芯片,对于我们用的这个Nand Flash存储芯片,只有一组数据线,同时起到传地址、传数据、传控制指令的作用,有一些引脚来完成这种分时复用的功能,当然还有片选信号引脚。

对Nand Flash芯片的操作,或者说对任何存储器芯片的操作,就是CPU对该芯片上某个内存单元的读写操作。读操作:CPU选中该芯片,发出地址,发出读命令,芯片准备好数据,发出“数据准备好了”信号,CPU读。写操作:CPU选中该芯片,发出地址,发出写入命令(脉冲),CPU写入数据。

对于存储芯片的程序上的操作,一是结合该存储芯片自己的芯片手册,二是结合S3C2440自己的芯片手册,看里面的nand flash控制器。

JZ2440是一个板子,Nand Flash芯片在板子上,在PCB板上,类似本科智能车焊的那种芯片。板子上的主控芯片是S3C2440,S3C2440是SOC系统,S3C2440里面有CPU,也有许多的外设控制器,其中就有Nand Flash控制器。

如果去看Nand Flash存储芯片的芯片手册,会发现要操作Nand Flash其实挺复杂的,需要符合它的时序,需要进行一些繁琐的操作,而S3C2440里面的Nand Flash控制器会简化这些操作,使得我们只需要操作S3C2440芯片中的相关寄存器即可,有相关的寄存器去存数据、地址以及控制命令。

17 LCD

17.1 LCD硬件原理

阅读LCD芯片手册,得到引脚的时序和极性,再阅读SOC手册,SOC的LCD控制器也有时序图,根据LCD手册将引脚和时序赋值给LCD控制器。

17.2 S3C2440_LCD控制器

LCD控制器通过系统总线(ASB)以DMA的方式从显存中取数据。
我们是16位BPP,这个可以通过寄存器设置LCD控制器,显存中以一个字(32位)为单位,一个字中低16位为第一个像素,高16位为第二个像素。

代码和注释主要集中在mypro_03,但是03运行不了,无法解决,实际能运行的是04。学到7_编程_简单测试就没学了。

18 ADC和触摸屏

18.1 & 18.1 ADC采样原理和简单编程介绍

没看,无用

18.3 & 18.4 触摸屏硬件原理和S3C2440的触摸屏接口

程序逻辑框架在第三小节8:30,第四小节参考S3C2440手册给出了具体的程序编写框架。具体框架如下:
1、首先需要对ADC进行初始化
主要是设置ADC的工作时钟,ADC原始时钟是CPU外设时钟PCLK,PCLK通过时钟系统进行设置,之前已经设置为50MHZ,这里主要通过ADCCON寄存器设置分频系数,具体见手册的频率公式。
2、程序初始运行时没有笔按下触摸屏,设置ADCTSC寄存器为等待中断模式,这里的等待中断模式指的是触摸屏正在等待中断,按下或者松开触摸屏都会产生中断。
3、设置INTMSK和INTSUBMASK寄存器,使能ADC和触摸屏中断。
4、在程序运行过程中,有笔按下触摸屏,会产生触摸屏中断,应编写触摸屏中断处理程序。由于触摸屏松开或者按下都会产生触摸屏中断,需要在处理程序中读取ADCUPDN寄存器来判断是松开还是按下。若是按下导致的中断,则在程序中将ADCTSC设置为自动测量XY模式,随后通过ADCCON打开ADC,硬件会自动测量XY的值,并将值保存到ADCDAT0和ADCDAT1寄存器,测量并保存后硬件会自动发出ADC中断;若是松开导致的中断,则将ADCTSC设置为等待中断模式(等待触摸屏再次按下)。
5、在ADC中断处理程序中将ADCDAT0和ADCDAT1中的值读取到程序中,设置ADCTSC为等待中断模式(等待触摸屏松开),为了处理长按和滑动的情况,还需要启动定时器(不然长按只会触发一次ADC读取,因为这个ADC在开启一次后会自动关闭),启动定时器后ADC中断程序就可以返回了,定时器启动后对应的定时器中断处理程序会周期性的运行。
6、在定时器中断处理程序中,检查笔是否松开(读取ADCUPDN寄存器),若松开则直接返回,若仍然按下,则再次启动ADC。

第七小节有关于start.S中重定位代码超过4k的解决办法。

19 I2C

19.1 I2C协议与EEPROM

讲解I2C的接口连线,用老师给学生传球的例子讲解I2C的传输格式。具体看“嵌入式总线与通信”

19.2 S3C2440A的I2C控制器

根据19.1所述,我们最简只需要两个引脚就可以模拟I2C的主设备,但是这样的模拟需要手动编写代码去解析I2C数据帧,很麻烦。S3C2440A有集成专门的I2C控制器,帮我们完成了解析数据帧的工作,没有I2C控制器,我们需要一位一位的往两个引脚上读写数据,有了I2C控制器后,我们只需要在对应的寄存器里面读写数据就行了。这也是大多数通信协议控制器的功能。

20 SPI

没看

21 MMU和Cach

没看

韦东山第一期课程内容概要相关推荐

  1. 韦东山第三期课程内容概要

    韦东山第三期课程内容概要 1文件浏览器&数码相框 1.1 数码相框之系统框架 2.1 数码相框-字符的编码方式 2.2 数码相框-字符的点阵表示 2.3.1 数码相框-freetype理论介绍 ...

  2. 韦东山第一期学习笔记——重定位

    重定位 说明 必须知道的几个概念 什么是代码重定位? 什么是位置无关码 什么是运行地址 为什么要代码重定位? nand flash启动的情况 nor flash启动的情况 两种方式的重定位 代码重定位 ...

  3. 韦东山第一二期衔接课程内容概要

    韦东山第一二期衔接课程内容概要 0 使得一个裸板Jz2440能运行linux应用程序的过程 1 uboot启动内核总结 1.1 u-boot分析之编译体验 1.2 u-boot分析之Makefile结 ...

  4. Linux 声卡驱动程序-韦东山-专题视频课程

    Linux 声卡驱动程序-2513人已学习 课程介绍         3期的声卡驱动更详细,推荐. 课程收益     熟悉内核声卡驱动框架 讲师介绍     韦东山 更多讲师课程     2003 年 ...

  5. 2014年YY公开课录像-韦东山-专题视频课程

    2014年YY公开课录像-5641人已学习 课程介绍         2014年在YY举办的公开课录像,现场回答网友提的普遍性问题 课程收益     回答网友提的普遍性问题 讲师介绍     韦东山 ...

  6. 米斯特web安全培训第一期课程目录

    1.白帽子修炼第一步(理论篇)-①(密码mst001) 什么是黑客 有哪些专业术语 如何学习这门技术 视频地址:理论篇-1 2.白帽子修炼第一步(理论篇)-②(密码mst002) 了解基本的漏洞类型 ...

  7. 【数据库课程设计】课程内容概要

    现本科三年级下学期,关于数据库课程设计要求如下: 1.学习并掌握工具 powerdesigner 16 要求:熟练掌握 2.选题的语义描述 要求:第7周提交(当前周次:3周) 3.数据库系统设计 概念 ...

  8. iMeta期刊纸质版开始免费订阅(包邮)——第一期创刊收藏版

    点击蓝字 关注我们 iMeta期刊纸质版开始免费订阅啦!!! iMeta是世界上第一本专注于宏基因组.微生物组和生物信息前沿交叉的期刊,第一期微生物组的元宇宙即将发布,为方便国内同行阅读和收藏,现全面 ...

  9. kettle大于0的转换成1_第一期实训周:基于Python+MySQL+Kettle+R的某网站数据采集分析...

    ↓ 基于Python+MySQL+Kettle+R的 某网站数据采集分析 哈喽!各位学员们 咱们第一期课程就要开始了 下面划重点! 一 高校院系 齐鲁工业大学数学与统计学院应用统计系 二 实训日期 2 ...

最新文章

  1. 用JAVASCRIPT实现静态对象、静态方法和静态属性
  2. Linux下查看磁盘挂载的三种方法
  3. 敏捷制造:并不是你想像的矛盾体
  4. 堆栈的定义与操作-顺序存储,链式存储(C语言)
  5. iOS关于rar解压第三方库Unrar4iOS使用总结
  6. codeforce C. Okabe and Boxes
  7. Arcgis Engine矢量裁剪栅格,调用Mask工具相关代码
  8. js table的所有td 按行合并
  9. 双系统环境下 CentOS 挂载 Windows NTFS 磁盘分区
  10. python apply函数_8 个 Python 高效数据分析的技巧
  11. finalize()与PhantomReference学习笔记
  12. matlab 滤波器设计 coe_巴特沃斯滤波器
  13. 基于BIM+3DGIS的智慧城市基础设施管理
  14. 基于FusionInsight Manager的大数据架构图
  15. 移动体验大作战,冰桶算法全盘点
  16. win10服务器网页打不开怎么办,win10系统ie浏览器有些网页打不开怎么回事
  17. 如何使用JMeter自身代理录制测试脚本
  18. 关于hive当中的double的数据类型
  19. Unicable命令设置
  20. 一个只完成了一部分的小游戏。。。

热门文章

  1. PYTHON 之 COROUTINE
  2. Labview的Modbus通信
  3. 今天给大家介绍一下虚拟人工智能“Jill Waston”
  4. WPF window窗体的关闭事件Closing 和Closed
  5. JAVA中Switch中使用Enum枚举类
  6. Redis集群方案及框架
  7. 再谈“国人为什么这么轻视技术”
  8. 【监听微信公众号消息】
  9. 【Android驱动】闪光灯flashlight的记录
  10. 让Mac系统始终不休眠的设置技巧