ARM

1、ARM之指令集精讲

 

2、ARM之蜂鸣器播放音乐
  ARM裸机开发:
  学习ARM裸机开发是为系统移植和驱动打基础,了解一下ARM处理器相关的寄存器,51和STM32中的寄存器有限,而ARM中的寄存器有几千个,通过裸机开发来了解ARM中的寄存器,因为他要完成一定功能,配置的寄存器要比我们做51单片机或STM32单片机要复杂很多。
  带操作系统的开发,ARM处理器,高端处理器做开发。
  学习ARM处理器的体系结构、架构、指令集、裸机开发,为你后边学系统移植和驱动打一个好的基础。
  裸机开发、驱动开发、系统开发。
  实际领域中一般不会用ARM裸机开发,学习裸机开发是为系统开发打基础。
  通过软件编程驱动一个硬件,怎么能把这个硬件驱动起来,就需要查看电路图。
  PWM:脉冲宽度调制(脉冲:一个周期 宽度:一个周期内高电平所占的位宽),即一个周期内高内高电平所占的位宽是可以调节的。

  占空比:就是输出的PWM中,高电平保持的时间与该PWM的时钟周期的时间之比。
  f=1/T 人能听到的是20~20000HZ
  有源蜂鸣器和无源蜂鸣器,无源蜂鸣器需要对引脚不停地进行高低电平切换。
  
  exynos4412芯片:每个引脚有不同的功能
  GPD0CON寄存器:控制GPDO组引脚的功能
 
  分频:分频是指将意单一频率信号的频率降低为原来的1/N,就叫N分频。实现分频的电路或装置称为“分频器”。这里的分频上针对单频信号而言的。
  如把33MHZ的信号2分频得到16.5MHZ的信号,3分频得到11MHZ的信号,10分频得到3.3MHZ的信号。
 
  exynos4412的PWM定时器有5个16 位定时器,其中定时器0、定时器1、定时器2 与定时器3 具有脉冲宽度调制(PWM)功能,定时器4 仅供内部定时而没有输出引脚。定时器0 具有死区生成器,可以控制大电流设备。
  定时器0与定时器1 共用一个8bit 预分频器,定时器2、定时器3 与定时器4 共用另一个8bit 预分频器,每个定时器都有一个时钟分频器,时钟分频器有5种分频输出(1/2,1/4,1/8,1/16 和外部时钟TCLK)。每个定时器都从时钟分频器接收的时钟信号,时钟分频器从相应的8bit 预分频器接收时钟信号。可编程8bit 预分频器根据存储在TCFG0 和TCFG1 中的数据对PCLK 进行分频。
  当时钟被使能后,定时器计数缓冲寄存器(TCNTBn)把计数初值下载到递减计数器中。定时器比较缓冲寄存器(TCMPBn)把其初始值下载到比较寄存器中,并将该值和递减计数器的值进行比较。这种基于TCNTBn 和TCMPBn 的双缓冲特性使定时器在频率和占空比变化时产生稳定的输出。
  每个定时器都有一个专用的由定时器时钟驱动的16 位递减计数器。当递减计数器的计数值达到0 的时,就会产生定时器中断请求来通知CPU 定时器操作完成。当定时器递减计数器达到0 的时候相应的TCNTBn 的值会自动重载到递减计数器中以继续下次操作。然而,如果定时器停止了,比如在定时器运行时清除TCON 中的定时器使能位,TCNTBn 的值不会被重载到递减计数器中。
  TCMPBn 的值用于脉冲宽度调制(PWM)。当定时器的递减计数器的值和比较寄存器的值相匹配的时候,定时器控制逻辑将改变输出电平。因此,比较寄存器决定了PWM 输出的开关时间。
  exynos4412的PWM定时器特性:
    5 个16bit 定时器
    两个8bit 预分频器和两个4bit 分频器
    输出波形的占空比可编程(PWM)
    自动重载模式或者单脉冲模式
    具有死区生成器
  exynos4412的PWM定时器的结构框图如图所示:

 

      图S3C2410 PWM定时器功能框图
  图中的死区功能(Dead Zone)用于电源设备的PWM 控制。这个功能允许在一个设备关闭和另一个设备开启之间插入一个时间间隔。这个时间间隔可以防止两个设备同时被启动。TOUT0 是定时器0 的PWM 输出,nTOUT0 是TOUT0 的反转信号。如果死区功能被使 能,TOUT0 和nTOUT0 的输出波形就变成了TOUT0_DZ 和nTOUT0_DZ(如图10-2所示)。 nTOUT0_DZ 在TOUT1 脚上产生。在死区间隔内,TOUT0_DZ 和nTOUT0_DZ 就不会同时翻转了。注意:在使能Dead Zone时TOUT1就是图10-2中的nTOUT0。
   相关寄存器:

  TCFG0寄存器:它配置两个8位的预分频器的值和死区长度,控制一级分频器,分频值和死区长度的都是为0~254

  TCFG1寄存器:指定控制5个MUX选择位的值,控制二级分频器

TCON寄存器:设置5个定时器的打开、关闭等

  [0]:0:关闭定时器0 1:打开定时器0
  [1]:0:无操作 1:将比较寄存器TCMPB0和计数寄存器TCNTB0中的值自动加载到定时器0中
  [2]:0:上电时时钟信号不发生翻转 1:上电时时钟信号发生翻转
  PWM上电时默认初始电平为低电平,根据比较寄存器和计数寄存器的值发生相应的翻转。如果将[2]设置为1,上电时的初始电平就是高电平了。
  [3]:0:只产生一个方波 1:产生连续的方波
 
  TCNTB0寄存器:设置计数寄存器0的初始值

  TCMPB0寄存器:设置比较寄存器0的值

  TCNTO0寄存器:保存计数器改变后的值

  1)共5个16位的定时器,定时器0、1、2、3都带有脉冲宽度调制功能(PWM);
  2)每个定时器都有一个比较缓存寄存器(TCMPB)和一个计数缓存寄存器(TCNTB);
  给计数器设置一个初值
  3)定时器0、1共享一个8位的预分频器(预定标器),定时器2、3、4共享另一个8位的预分频器(预定标器),其值范围是0~254(结合寄存器说明),一级分频,可以分到0~254;
  4)定时器0、1共享一个时钟分频器,定时器2、3、4共享另一个时钟分频器,这两个时钟分频器都能产生5种不同的分频信号值(即:1/2、1/4、1/8、1/16和TCLK),二级分频;
  5)两个8位的预分频器prescaler是可编程的且根据装载的值来对PCLK进行分频,预分频器和时钟分频器的值分别存储在定时器配置寄存器TCFG0和TCFG1中;
  6)有一个TCON控制寄存器控制着所有定时器的属性和状态,TCON的第0~7位控制着定时器0、第8~11位控制着定时器1、第12~15位控制着定时器2、第16~19位控制着定时器3、第20~22位控制着定时器4。
 
  还是根据S3C2440手册的描述和上图的结构,要开始一个PWM定时器功能的步骤如下(假设使用的是第一个定时器):
 
  1)分别设置定时器0的预分频器值和时钟分频值,以供定时器0的比较缓存寄存器和计数缓存寄存器用;
  2)设置比较缓存寄存器TCMPB0和计数缓存寄存器TCNTB0的初始值(即定时器0的输出时钟频率);
  3)关闭定时器0的死区生成器(设置TCON的第4位);
  4)开启定时器0的自动重载(设置TCON的第3位);
  5)关闭定时器0的反相器(设置TCON的第2位);
  6)开启定时器0的手动更新TCNTB0&TCMPB0功能(设置TCON的第1位);
  7)启动定时器0(设置TCON的第0位);
  8)清除定时器0的手动更新TCNTB0&TCMPB0功能(设置TCON的第1位)。
 
  由此可以看到,PWM的输出频率跟比较缓存寄存器和计数缓存寄存器的取值有关,而比较缓存寄存器和计数缓存寄存器的值又跟预分频器和时钟分频器的值有关;要使用PWM功能其实也就是对定时器的相关寄存器进行操作。手册上也有一个公式:定时器输出频率 = PCLK / {预分频器值 + 1} / 时钟分频值。下面我们来通过一个蜂鸣器的实例来说明PWM功能的使用。
 
#include “exynos_4412"
//音乐数组
//第2N个元素表示声调,第2N+1个元素表示该声调的时间
unsigned char MUSIC[500]={   }

unsigned int Num = 0void Dealy_Ms(unsigned int Time)
{
    unsigend int i,j;
    for(i=0;i<Time;i++)
    for(j=0;j<2500;j++);
}
void main(void)
{
    GPD0.CON = GPD0.CON & (~(0XF << 0)) | (0X2 << 0);
    /*将GPD0_0管脚设置成PWM功能*/
    PWM.TCFG0 = PWM.TCFG0 & (~(0XFF)) | 99;
    /*一级分频100000000/(99+1)=1000000*/
    PWM.TCFG1 = PWM.TCFG1 & (~(0XF)) ;
    /*二级分频1000000/1=1000000*/
    PWM.TCON = PWM.TCON | ( 1<< 3);
    /*打开自动重装载功能,设置器产生连续的方波*/
    PWM.TCNTB0 = 1000;
    /*设置频率为1MHZ/1000=1000HZ 周期为1/1000HZ=1ms*/
    PWM.TCMPB0 = 500;
    /*设置占空比500/1000=50%*/
    PWM.TCON = PWM.TCON | (1 << 1);
    /*手动将TCNTB0中的值加载到TCNTB0,第一次必须将比较寄存器和计数寄存器中的值手动加载到定时器中*/
    PWM.TCON = PWM.TCON | 1;
    /*打开计定时器0*/
    PWM.TCON=PWM.TCON & ~(1 << 1);
    /*关闭手动装载*/
    while(1)
    {
        PWM.TCON = PWM.TCON | (1 << 3);
        PWM.TCNTB0 = MUSIC[2*NUM] << 5;
        PWM.TCMPB0 = PWM.TCNTB0/2;
        PWM.TCON = PWM.TCON | (1 << 1);
        PWM.TCON = PWM.TCON | 1;
        PWM.TCON = PWM.TCON | ~(1 << 1);
        Dealy_Ms(MUSIC[2*Num+1]*5); //改变延时时间
        Num++;
        if(Num == 200)
        {
            Num = 0;
        }
    }
}

3、ARM之中断GIC分析

  ARM中断处理(第6章、第9章)

  中断是处理器的核心,

  软中断16个,私有外部中断16个,公共外部中断128个(按键、串口、定时器等)。
  cc2530、cc2540:中断源大概有16个 ,采用增强型80c51内核

 

  上拉电阻:电阻有一端接电源正极
  下拉电阻:电阻有一端接电源负极
 
  GPX1CON寄存器:设置引脚功能

  GPX1PUD寄存器:设置引脚上下拉
  EX_INT41CON寄存器:设置触发方式
  EXT_INT41_FLTCON0和EXT_INT41_FLTCON0寄存器:这两个寄存器用来管理一组(8个)引脚,用来滤波的。在芯片内部是有专门滤波的电路的。可以软件滤波也可以硬件滤波,硬件滤波可以节约一些CPU的时间。
  EXT_INT41_PEND寄存器:用来清除中断
 
  r0~r15、cpsr是工作寄存器,是由ARM公司提供的,它在CPU内部,它没有地址,ARM公司为每个寄存器分配一个编号,一条指令是32位,寄存器占这条指令的4位。
  其余的是控制寄存器是由各个厂商提供的,用来控制硬件。它就是给一段连续的32位内存空间起了一个名字,生成相应的寄存器,只要在这块内存空间中写入相应的数据,我们就能控制硬件实现一定的功能。
 
 
  外部中断传递流程:

  GIC中断管理器:用来管理所有中断的,比如中断的优先级等
  CPU上只有一个IRQ(中断请求)引脚,GIU和CPU之间只有一根线,同一时间只能处理一个中断。
  外部GPIO(芯片外围电路)有128个中断,当有多个中断同时产生时,GIC中断管理器就会对多个中断进行优先级的设置,将优先级高的先通过IRQ送往CPU进行处理
 
  多个中断同时出现先处理哪一个--------优先级
  正在处理一个中断,又来一个中断--------先处理完当前中断,在处理下一个中断
  当前处理的是哪个中断---------中断号
 
  多个GPIO------->GIC中断管理器---------->CPU
  GIC为每一个中断分配一个唯一的中断号
  在ARM中,中断时不允许嵌套的,当CPU已经开始处理一个中断时,必须要把当前中断处理完才能处理下一个中断,尽管当前的中断优先级低也是一样,不会说是在一个中断未处理完时进入下一个中断。
  单片机的中断是可以嵌套的,stm32中的中断管理器是NVIC。
  ARM的处理速度最大是1.4G,我们一般用的是1G,单片机的处理速度最大是24M或72M。

  Exynos4412为四核处理器

 

 

  设置GIC控制器过程:
 

 

 

  Exynos4412中断相关寄存器:
    CPU接口寄存器:ICCICR_CPU0、ICCPMR_CPU0、ICCIAR_CPU0、ICCEOIR_CPU0
    CPU分配器寄存器:ICDISR1、ICDICER1、ICDICPR1、ICDIPTR8
    ICCICR_CPU0寄存器:
    ICDISER寄存器:使能寄存器,开关
    ICDIPTR寄存器:每8位控制一个CPU
    ICDICPR寄存器:用来清除分配器这一层的中断
    ICDDCR寄存器:GIC的总开关,使能GIC
    ICCIPMR寄存器:设置中断优先级
    ICCICR寄存器:用来选择由哪个CPU来处理中断
    ICCIAR寄存器:获取当前正在处理的中断的中断号
    ICCEORI寄存器:清除CPU这一层的中断,当CPU处理完一个中断后,该寄存器就清除掉这个中断

 

  
  CPU中断处理流程:
  IRQ:不同的中断
  四大不三小步:它是由CPU自动完成的,算是一个保存现场,完后跳转到异常处理程序(异常向量表)。
  (1)、拷贝CPSR到SPSR_<mode>
  (2)、设置适当的CPSR位:
    A、改变处理器状态进入ARM态
    B、改变处理器模式进入相应的异常模式
    C、设置中断禁止位禁止相应中断(如果需要)
  (3)、保存返回地址到LR_<mode>
  (4)、设置PC为相应的异常向量
  异常处理程序:在异常程序里面还要进行压栈保护,完后跳转到中断处理函数。
  中断处理函数:该函数中包括160个所有中断的处理函数,根据中断号来调用相应的中断处理函数(switch选择语句)处理不同的中断
  调用函数:通过调用的函数来处理中断
posted @ 2024-11-02 16:16  孤情剑客  阅读(232)  评论(0)    收藏  举报