kwseeker

学编程:找代码,读代码,改代码,写代码;少看书。但少看不是不看,看一本书要限制在一天内。任务是通读书中主要的概念,明白大致是干什么用的,形成一个大概的框架;然后一周内干掉书中全部代码,代码不理解再浏览书中相关章节,注意是浏览。或者刷博客。代码实在刷不懂,可以先刷后面,待日后重新刷;因为书中代码有些部分可能出自后面的章节。代码总是在多次刷过之后,拨开乌云见日月的。。。

导航

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)具体功能实现

posted on 2015-05-12 23:55  kwseeker  阅读(390)  评论(0编辑  收藏  举报