专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

coocox学习系列之CoX_GPIO篇

作者:未知   来源:互联网   点击数:  更新时间:2014年08月16日   【字体:

1.GPIO接口设计思想

1.1CoX.GPIO发展过程,历史版本
     CoX第一版从2009年开始,从CoX诞生开始,CoX的目标就是要做到在M系列的CPU上实现平滑移植。所以,GPIO的实现,第一版首先实现了,IO的模式配置(输入、输出)和管脚的上拉、下拉配置;然后,实现了IO管脚的状态读写。具体可以从接口定义清晰的看出来:
typedef struct {
  COX_Status (*Init) (COX_PIO_Dev pio);
  COX_Status (*Dir (COX_PIO_Dev pio, uint8_t dir);
  uint8_t     (*Out (COX_PIO_Dev pio, uint8_t level);
  uint8_t     (*Read) (COX_PIO_Dev pio);
  COX_Status (*Cfg (COX_PIO_Dev pio, uint8_t index, uint32_t arg, uint32_t*pre_arg);
} COX_PIO_PI_Def;
typedef const COX_PIO_PI_Def COX_PIO_PI;
这样的实现,确实可以大大减小IO操作的移植,因为我们在每个厂商实现一套API,以新唐为例:
COX_PIO_PI pi_pio =
{
       NUC_GPIO_Init,
       NUC_GPIO_SetDir,
       NUC_GPIO_Out,
       NUC_GPIO_Read,
       NUC_GPIO_Cfg 
};
在使用的时候,我们仅仅需要使用pi_pio的指针就可以调用GPIOAPI操作了,而且这个指针还可以被驱动嵌套使用。有兴趣的可以参考NUC140-LB BoardCoOS例程,这个在www.coocox.org官网可以下载到。
然而,第一版有几个明显的不足:
1.                实现的功能很少,只有IO的基本配置和读写操作,没有外部中断实现,没有多功能配置实现,以及一些其他特殊的功能。
2.                采用了结构体的形式,代码的可读性大大降低,效率也不高。
3.                CoX代码不能搞定所有基本的事情,在使用CoX库的使用还必须和厂商库配套使用。
4.                CoX在第一版更多的注重外设模块的移植,而忽略了系统。
    所以,CoX需要改进、升级。经常一年多时间的积累,在2011年开始推出CoX 2.0版本,这个版本解决了上述所有的缺点的同时,保留了CoX设计的初衷——那就是在M系类CPU上面的通用性。下面,详细介绍2.0版的CoX.GPIO接口。
1.2通用强制接口
通用强制接口是提取的一套ARM Cortex M0/M3所有厂商系列MCU都具有的功能接口。本篇以新唐M051为例讲解CoX.GPIO,其他系列大同小异, 提取GPIO通用接口的时候,是从以下角度出发考虑的:
u      配置一个GPIO管脚线
l        方向配置:
n        输入  
n        输出
n        硬件功能
l        外围功能配置:
l        Pad配置:
n        驱动能力大小(电流)
n        开源/推挽
n        弱上拉/下拉电阻
u      GPIO管脚数据控制
l        输出高/低电平
l        获取管脚输入值
u      输入中断(EXTI)
l        上升沿检测
l        下降沿检测
l        /下沿检测
l        低电平检测
l        高电平检测
 
APIs分组完成以下几大功能:
u      配置GPIO管脚线的函数:
l        xGPIODirModeSet
l        xGPIOSPinDirModeSet
l        xGPIOPinConfigure
u      读回GPIO管脚线模式配置的函数:
l        xGPIODirModeGet
u      还有很方便的函数,可以将GPIO配置成想要的功能:
l        xGPIOSPinTypeGPIOInput
l        xGPIOSPinTypeGPIOOutput
l        xSPinTypeADC
l        xSPinTypeI2C
l        xSPinTypeSPI
l        xSPinTypeTimer
l        xSPinTypeUART
l        xSPinTypeACMP
u      处理GPIO中断的APIs
l        xGPIOPinIntCallbackInit
l        xGPIOPinIntEnable
l        xGPIOSPinIntEnable
l        xGPIOPinIntDisable
l        xGPIOSPinIntDisable
l        xGPIOPinIntStatus
l        xGPIOPinIntClear
l        xGPIOSPinIntClear
u      处理GPIO Pin状态的APIs
l        xGPIOPinRead
l        xGPIOSPinRead
l        xGPIOPinWrite
l        xGPIOSPinWrite
 
1.3通用非强制接口
 通用非强制接口是一部MCU通有的功能,而不是所有MCU都具有的功能接口:
l        xGPIOSPinTypeGPIOOutputOD
l        xGPIOSPinTypeGPIOOutputQB
l        xSPinTypePWM
l        xSPinTypeEXTINT
l        xSPinTypeEBI
 
CoX的宏定义的参数和APIs都是以' x '开头的, 体现出CoX接口的特征。比如将 GPIOA Pin0配置成输出模式, 代码如下:
xGPIODirModeSet(xGPIO_PORTA_BASE, xGPIO_PIN_0, xGPIO_DIR_MODE_OUT);
函数和形式参数都是x开头。
1.4厂商库特色接口
特色接口是包括了通用性接口,和MCU特有功能的接口。比如:
void GPIOPinDebounceEnable(unsigned long ulPort, unsigned long ulPins);并不是通用强制型或者通用非强制型,而是MCU特有的功能,就是在厂商库特色接口这一组。
 
另外厂商库接口也实现了MCU其他所有的功能,比如:
void GPIOPinWrite(unsigned long ulPort, unsigned long ulPins,
                      unsigned char ucVal);
也实现了GPIO管脚线模式的配置,这个在CoX接口的xGPIOPinWrite也是这个功能。其实这个时候xGPIOPinWrite的实现方式如下:
#define xGPIOPinWrite(ulPort, ulPins, ucVal)                                  \
        GPIOPinWrite(ulPort, ulPins, ucVal)
进行了一次宏定义包装罢了,对应的参数也是进行的一次宏定义比如:
#define xGPIO_PIN_0             GPIO_PIN_0
 
2.设计技巧简介
GPIOCoX接口创新性的提出了Short Pin,比如PA0 GPIOAPin0脚,它的定义如下:
#define PA0                     PA0
 
自从有了Short Pin之后,对GPIO的操作简单多了,例如比如将GPIOA Pin0配置成输出模式,并输出高电平, 代码如下:
xGPIODirModeSet(xGPIO_PORTA_BASE, xGPIO_PIN_0, xGPIO_DIR_MODE_OUT);
xGPIOPinWrite(xGPIO_PORTA_BASE, xGPIO_PIN_0, 1);
现在用Short Pin作为参数,上面的功能可以这样实现:
xGPIOSPinTypeGPIOOutput(PA0);
xGPIOSPinWrite(PA0, 1);
上面的Short Pin到底是如何实现的呢?看起来很神奇,以xGPIOSPinWrite为例说明它的实现过程:
#define xGPIOSPinWrite(eShortPin, ucVal)                                      \
        GPIOSPinWrite(eShortPin, ucVal)
#define GPIOSPinWrite(eShortPin, ucVal)                                       \
        GPIOPinWrite(G##eShortPin, ucVal)
关于##, 其实是宏定义里面的高级用法,它是一个连接符,遇到此连接符,宏会一直展开下去,直到不能展开为止。G##eShortPin其实会连接为GPA0,而GPA0同样是个宏定义,如下:
#define GPA0                    GPIO_PORTA_BASE, GPIO_PIN_0
GPIOPinWrite(GPA0, ucVal)会进一步展开为
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0, ucVal),这个函数在厂商库里面定义了的,所以实现了Pin写的功能。
 
另外Short PinGPIO管脚的外设多功能复用操作也带来了极大的方便,比如配置PD5I2Cclock脚功能,如下:
xSPinTypeI2C(I2C0SCK, PD5);
是不是很简单!!!上面的实现如下:
#define xSPinTypeI2C(ePeripheralPin, eShortPin)                              \
do                                                                    \
                                                                    \
         GPIOSPinConfigure(ePeripheralPin, eShortPin);                      \
         GPIOSPinFunctionSet(GPIO_FUNCTION_I2C,eShortPin);             \
                                                                   \
while(0)
    #define GPIOSPinConfigure(ePeripheralPin, eShortPin)                          \
       GPIOPinConfigure(GPIO_##eShortPin##_##ePeripheralPin)
上面的会连接成这样GPIOPinConfigure(GPIO_PD5_I2C0SCK), GPIO_PD5_I2C0SCK宏定义如下:

这个是根据多功能复用进行的编码,视不同的芯片,这个编码方式灵活多变。
 

//! Config the device i2c Address
//
#define AD7415_I2C_ADDRESS      0x48
 
//
//! Config the devide i2c bus master
//

//
//! Config the i2c SDA pin
//
#define AD7415_PIN_I2CSDA        PA8
 
//
//! Config the i2c SCL pin
//
#define AD7415_PIN_I2CSCK        PA9
因为有了xI2C0_BASE在驱动中就可以使能这个I2C外设,有了连接的管脚也就可以使能对应的GPIO PORT, xSysCtlPeripheralEnable2(AD7415_MASTER_BASE); 这里不在需要给出I2C0的外设使能ID,或者GPIOA的外设使能ID 用户移植的时候只需要从硬件连接角度出发,用了那个I2C, 管脚是怎么连接的,而不需要考虑其他的元素。

3. GPIO接口使用示例与移植
下面给出一个CoX.GPIO的示例,都是使用的通用强制型的接口,因此下面的例子在所有Cortex M0/M3上都是平滑移植的, 类似一个简单的电灯程序。
void Blinky(void)
{
    unsigned long i;
      
    //
    // Initionalize system clock.
    //
    xSysCtlPeripheralClockSourceSet( 12000000,  xSYSCTL_XTAL_12MHZ );
      
    //
    // Set GPIO port c pin 0 , 1 output mode.
    //
    xGPIODirModeSet( xGPIO_PORTC_BASE, xGPIO_PIN_0, xGPIO_DIR_MODE_OUT );
    xGPIODirModeSet( xGPIO_PORTC_BASE, xGPIO_PIN_1, xGPIO_DIR_MODE_OUT );
      
    while (1)
    {
            //
        // Delay some time.
        // 
        for( i = 0; i < 0x1FFFF; i++ )
             
            //
        // Output high level.
        // 
        xGPIOPinWrite( xGPIO_PORTC_BASE, xGPIO_PIN_0 | xGPIO_PIN_1, 1 );
             
           for( i = 0; i < 0x1FFFF; i++ )
             
           //
        // Output low level.
        // 
        xGPIOPinWrite( xGPIO_PORTC_BASE, xGPIO_PIN_0 | xGPIO_PIN_1, 0 );
       }
      
}

关闭窗口

相关文章