zoukankan      html  css  js  c++  java
  • ARM1138@PWM例程分析

    1. Buzzer例程控制原理

    由ARM1138原理图可得:Buzzer使用CCP3(对应GPIO-G组0x40026000,4号引脚0x00000010)作为输入引脚;

    Buzzer例程结构

    涉及的库函数使用绿色粗体表示

    SysCtlPeripheralEnable(KEY_PERIPH);  当多个管脚处于同一个端口时,使能单个端口(设备的基地址 SYSCTL_PERIPH_I2C1 、 SYSCTL_PERIPH_PWM 、 SYSCTL_PERIPH_QEI0)

    SysCtlPeripheralDisable(KEY_PERIPH);  禁止一个外设(设备的基地址)

    GPIOPinTypeGPIOInput(KEY_PORT , KEY_PIN);  设置引脚为输入状态(端口基地址+偏移地址)

    GPIOPinRead(KEY_PORT , KEY_PIN);  读取指定管脚上出现的值(端口基地址+偏移地址) 

    下面以SysCtlPeripheralDisable(unsigned long ulPeripheral);分析一下函数工作原理(寄存器地址映射原理):

    核心的宏:HWREG(g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)]) &= ~SYSCTL_PERIPH_MASK(ulPeripheral)

    我们以本例中KEY_PERIPH(实际上是SYSCTL_PERIPH_GPIOG)为参数进行说明:如下可见它的值为0x20000040,

    等式的左边:

    1) 经过第一个宏处理取得上值的高四bits即0x2; (其实是将内存分为8个256M的内存块来管理,看目标寄存器是处于哪一个内存块中);

    2) 经过第二个宏处理取得值 SYSCTL_RCGC20x400FE108 列出的偏移量是相对于0x400F.E000的系统控制基址的寄存器地址的十六进制增量。 )即;通过RCGC2寄存器对目标设备进行控制;(每个内存块对应其自己的配置寄存器)

    3) 经过第三个宏(*((volatile unsigned long *)(x))),即指向了寄存器RCGC2的空间

    等式右边:~(((0x20000040) & 0xffff) << (((0x20000040) & 0x001f0000) >> 16)) = 0xffffffbf (有效的是bf -> 10111111)

    为了更好理解右式引入Enable的核心宏表达式

    HWREG(g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)]) |= SYSCTL_PERIPH_MASK(ulPeripheral);

    (((0x20000040) & 0xffff) << (((0x20000040) & 0x001f0000) >> 16)) = 0x00000040 (有效位40-> 01000000)

    让我想起了常用的“&=”(某位置0,其余位不变) 还有 “|=”(某位置1,其余位不变)

    综上:disable相应外设即是通过配置运行模式下的寄存器RCGC2。同时得 0x20000040 前1字节是为了分块,后2字节是为了配置寄存器的值。

    不过前第二字节是为了什么?关键是弄明白这句的意思(((0x20000040) & 0x001f0000) >> 16)? 

    然后通过查阅《lm3s1138》的数据手册中对RCGC2寄存器的描述,即可明白整个函数的控制过程。

    void SysCtlPeripheralDisable(unsigned long ulPeripheral)
    {
        //
        // Check the arguments.
        //
        ASSERT((ulPeripheral == SYSCTL_PERIPH_ADC) ||
               (ulPeripheral == SYSCTL_PERIPH_CAN0) ||
               (ulPeripheral == SYSCTL_PERIPH_CAN1) ||
               (ulPeripheral == SYSCTL_PERIPH_CAN2) ||
               (ulPeripheral == SYSCTL_PERIPH_COMP0) ||
               (ulPeripheral == SYSCTL_PERIPH_COMP1) ||
               (ulPeripheral == SYSCTL_PERIPH_COMP2) ||
               (ulPeripheral == SYSCTL_PERIPH_ETH) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOA) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOB) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOC) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOD) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOE) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOF) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOG) ||
               (ulPeripheral == SYSCTL_PERIPH_GPIOH) ||
               (ulPeripheral == SYSCTL_PERIPH_HIBERNATE) ||
               (ulPeripheral == SYSCTL_PERIPH_I2C0) ||
               (ulPeripheral == SYSCTL_PERIPH_I2C1) ||
               (ulPeripheral == SYSCTL_PERIPH_PWM) ||
               (ulPeripheral == SYSCTL_PERIPH_QEI0) ||
               (ulPeripheral == SYSCTL_PERIPH_QEI1) ||
               (ulPeripheral == SYSCTL_PERIPH_SSI0) ||
               (ulPeripheral == SYSCTL_PERIPH_SSI1) ||
               (ulPeripheral == SYSCTL_PERIPH_TIMER0) ||
               (ulPeripheral == SYSCTL_PERIPH_TIMER1) ||
               (ulPeripheral == SYSCTL_PERIPH_TIMER2) ||
               (ulPeripheral == SYSCTL_PERIPH_TIMER3) ||
               (ulPeripheral == SYSCTL_PERIPH_UART0) ||
               (ulPeripheral == SYSCTL_PERIPH_UART1) ||
               (ulPeripheral == SYSCTL_PERIPH_UART2) ||
               (ulPeripheral == SYSCTL_PERIPH_UDMA) ||
               (ulPeripheral == SYSCTL_PERIPH_USB0) ||
               (ulPeripheral == SYSCTL_PERIPH_WDOG));
    
        //
        // Disable this peripheral.
        //
        HWREG(g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)]) &=
            ~SYSCTL_PERIPH_MASK(ulPeripheral);
    }
    
    /**************************************************************/
    
    //***********************************************
    //
    // This macro extracts the array index out of the peripheral number.
    //
    //***********************************************
    #define SYSCTL_PERIPH_INDEX(a)  (((a) >> 28) & 0xf)
    
    /**************************************************************/
    
    static const unsigned long g_pulRCGCRegs[] =
    {
        SYSCTL_RCGC0,
        SYSCTL_RCGC1,
        SYSCTL_RCGC2
    };
    
    
    /**************************************************************/
    
    #define HWREG(x)                                                              
            (*((volatile unsigned long *)(x)))
    ......
    
    /**************************************************************/
    
    #define SYSCTL_PERIPH_MASK(a)   (((a) & 0xffff) << (((a) & 0x001f0000) >> 16))
    
    /**************************************************************/
    #define SYSCTL_PERIPH_WDOG      0x00000008  // Watchdog
    #define SYSCTL_PERIPH_HIBERNATE 0x00000040  // Hibernation module
    #define SYSCTL_PERIPH_ADC       0x00100001  // ADC
    #define SYSCTL_PERIPH_PWM       0x00100010  // PWM
    #define SYSCTL_PERIPH_CAN0      0x00100100  // CAN 0
    #define SYSCTL_PERIPH_CAN1      0x00100200  // CAN 1
    #define SYSCTL_PERIPH_CAN2      0x00100400  // CAN 2
    #define SYSCTL_PERIPH_UART0     0x10000001  // UART 0
    #define SYSCTL_PERIPH_UART1     0x10000002  // UART 1
    #define SYSCTL_PERIPH_UART2     0x10000004  // UART 2
    #ifndef DEPRECATED
    #define SYSCTL_PERIPH_SSI       0x10000010  // SSI
    #endif
    #define SYSCTL_PERIPH_SSI0      0x10000010  // SSI 0
    #define SYSCTL_PERIPH_SSI1      0x10000020  // SSI 1
    #ifndef DEPRECATED
    #define SYSCTL_PERIPH_QEI       0x10000100  // QEI
    #endif
    #define SYSCTL_PERIPH_QEI0      0x10000100  // QEI 0
    #define SYSCTL_PERIPH_QEI1      0x10000200  // QEI 1
    #ifndef DEPRECATED
    #define SYSCTL_PERIPH_I2C       0x10001000  // I2C
    #endif
    #define SYSCTL_PERIPH_I2C0      0x10001000  // I2C 0
    #define SYSCTL_PERIPH_I2C1      0x10004000  // I2C 1
    #define SYSCTL_PERIPH_TIMER0    0x10100001  // Timer 0
    #define SYSCTL_PERIPH_TIMER1    0x10100002  // Timer 1
    #define SYSCTL_PERIPH_TIMER2    0x10100004  // Timer 2
    #define SYSCTL_PERIPH_TIMER3    0x10100008  // Timer 3
    #define SYSCTL_PERIPH_COMP0     0x10100100  // Analog comparator 0
    #define SYSCTL_PERIPH_COMP1     0x10100200  // Analog comparator 1
    #define SYSCTL_PERIPH_COMP2     0x10100400  // Analog comparator 2
    #define SYSCTL_PERIPH_GPIOA     0x20000001  // GPIO A
    #define SYSCTL_PERIPH_GPIOB     0x20000002  // GPIO B
    #define SYSCTL_PERIPH_GPIOC     0x20000004  // GPIO C
    #define SYSCTL_PERIPH_GPIOD     0x20000008  // GPIO D
    #define SYSCTL_PERIPH_GPIOE     0x20000010  // GPIO E
    #define SYSCTL_PERIPH_GPIOF     0x20000020  // GPIO F
    #define SYSCTL_PERIPH_GPIOG     0x20000040  // GPIO G
    #define SYSCTL_PERIPH_GPIOH     0x20000080  // GPIO H
    #define SYSCTL_PERIPH_UDMA      0x20002000  // uDMA
    #define SYSCTL_PERIPH_USB0      0x20100001  // USB0
    #define SYSCTL_PERIPH_ETH       0x20105000  // ETH
    #define SYSCTL_PERIPH_IEEE1588  0x20100100  // IEEE1588
    #define SYSCTL_PERIPH_PLL       0x30000010  // PLL
    #define SYSCTL_PERIPH_TEMP      0x30000020  // Temperature sensor
    #define SYSCTL_PERIPH_MPU       0x30000080  // Cortex M3 MPU
    

      

    (1)JTAG_Wait();  //防止JTAG失效;按住KEY2然后复位,程序会进入死循环。

    防止JTAG失效这句话真是太含蓄了(很烦这个词,刚开始被说得云里雾里的),其实就是防止JTAG管脚被复用为GPIO管脚时在某些特定情况(详见手册)下被锁死(无法下载程序)的情况。关于防锁死程序原理:http://blog.163.com/liyupeng_china/blog/static/18464392820125199343114/

    注意:由于所有的位都在复位时都会清零,因此在默认的情况下,这些GPIO线路设置GPIO模式。所以为保险起见,应加入下面的代码。以等待速度较慢的JTAG先对相应的GPIO复用脚设置为JTAG的模式。

    void JTAG_Wait(void)
    {
        SysCtlPeripheralEnable(KEY_PERIPH);     //使能KEY所在的GPIO端口,从刚才的分析即是使RCGC2 GPIOG位置1
        GPIOPinTypeGPIOInput(KEY_PORT , KEY_PIN);    // 设置KEY所在管脚为输入
        if ( GPIOPinRead(KEY_PORT , KEY_PIN)  ==  0x00 )   //  如果复位时按下KEY,则进入
        {
            for (;;);                                      //  死循环,以等待JTAG连接
        }
        SysCtlPeripheralDisable(KEY_PERIPH);               //  禁止KEY所在的GPIO端口,使RCGC2 GPIOG位置0
    }

      

    (2)SystemInit(); 

    下面分析一下下面的初始化函数都干了什么事(前3个函数)。

    1.SysCtlLDOSet(); 控制LDO

    LDO的作用:查了好些资料,也没弄明白LDO在1138中的具体作用,如果只是稳压,那么输出2.5V电压是做什么的?

    2.SysCtlClockSet(); 设置系统时钟

    ulConfig 参数是几个不同值的逻辑或,这些值中的某些值组合成组,其中只有一组值能被选用。

    1)系统时钟分频器:SYSCTL_SYSDIV_1、SYSCTL_ SYSDIV_2、SYSCTL_SYSDIV_3 、 …、SYSCTL_SYSDIV_64 (在 Sandstorm-class 器 件 中 , 只 有SYSCTL_SYSDIV_1 到 SYSCTL_SYSDIV_16 是有效的。)

    2)外部晶体频率:SYSCTL_XTAL_1MHZ 、SYSCTL_XTAL_1_84MHZ 、 SYSCTL_XTAL_2MHZ 、 SYSCTL_XTAL_2_45MHZ 、SYSCTL_XTAL_3_57MHZ 、 SYSCTL_XTAL_3_68MH 、 SYSCTL_XTAL_4MHZ 、SYSCTL_XTAL_4_09MHZ 、 SYSCTL_XTAL_4_91MHZ 、 SYSCTL_XTAL_5MHZ 、SYSCTL_XTAL_5_12MHZ 、 SYSCTL_XTAL_6MHZ 、 SYSCTL_XTAL_6_14MHZ 、SYSCTL_XTAL_7_37MHZ 、 SYSCTL_XTAL_8MHZ 、 SYSCTL_XTAL_8_19MHZ 、SYSCTL_XTAL_10MHZ 、 SYSCTL_XTAL_12MHZ 、 SYSCTL_XTAL_12_2MHZ 、SYSCTL_XTAL_13_5MHZ 、 SYSCTL_XTAL_14_3MHZ 、 SYSCTL_XTAL_16MHZ 或SYSCTL_XTAL_16_3MHZ (低于 SYSCTL_XTAL_3_57MHZ 的值在 PLL 被操作时无效。在Sandstorm-class 和 Fury-class 器件中,高于 SYSCTL_XTAL_8_19MHZ 的值是无效的。)

    3)振荡器源:SYSCTL_OSC_MAIN 、 SYSCTL_OSC_INT 、SYSCTL_OSC_INT4、SYSCTL_OSC_INT30 或 SYSCTL_OSC_EXT32 (在 Standstorm-class器件中,SYSCTL_OSC_INT30 和 SYSCTL_OSC_EXT32 是无效的。SYSCTL_OSC_EXT32只可用于具有休眠模式的器件,并只在休眠模块已被使能时有效。)

    使用 SYSCTL_USE_OSC | SYSCTL_OSC_MAIN 来选择由主振荡器提 供 系 统 时 钟 。 为 了 使 系 统 时 钟 由 PLL 来 提 供 , 请 使 用 SYSCTL_USE_PLL |SYSCTL_OSC_MAIN,并根据 SYSCTL_XTAL_xxx 值选择合适的晶体。

    3.SysCtlClockGet(); 获取系统时钟

    void  SystemInit(void)
    {
        SysCtlLDOSet(SYSCTL_LDO_2_50V);        //  设置LDO输出电压
    
        SysCtlClockSet(SYSCTL_USE_OSC |        //  系统时钟设置,采用主振荡器
                       SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_6MHZ |
                       SYSCTL_SYSDIV_1);
    
        TheSysClock  =  SysCtlClockGet();      //  获取系统时钟,单位:Hz
    
        BuzzerInit();                          //  蜂鸣器初始化
    }
    
    void  BuzzerInit(void)
    {
        SysCtlPeriEnable(CCP3_PERIPH);                              //  使能CCP3所在的GPIO端口(GPIOG)
        GPIOPinTypeTimer(CCP3_PORT , CCP3_PIN);                     //  配置CCP3所在管脚(G4)为Timer功能(定时器1 TimerB)
    
        SysCtlPeriEnable(SYSCTL_PERIPH_TIMER1);                     //  使能TIMER1模块
    
        TimerConfigure(TIMER1_BASE ,                                //  配置Timer1B为16位PWM
                       TIMER_CFG_16_BIT_PAIR | TIMER_CFG_B_PWM);
    }
    

    1138芯片资料有关定时器的设置过程:

     

    (3)具体功能实现

  • 相关阅读:
    配置JDK环境变量
    yum 卸载安装的软件包及依赖
    常用命令--patch
    Git 源码编译安装
    基础Git命令
    下载资源的一些方法
    Python/Jupyter小技巧
    欺诈类Kaggle竞赛赛题描述
    工作小笔记
    进入互联网数据分析岗位需要明白的一些事
  • 原文地址:https://www.cnblogs.com/kwseeker-bolgs/p/4499103.html
Copyright © 2011-2022 走看看