liamjeal 发表于 2012-9-5 15:27:21

coocox学习系列之CoX_GPIO篇

本帖最后由 liamjeal 于 2012-9-13 11:30 编辑

附件的word文档,值得看。CoX统一ARM Cortex MCU软件接口标准, 这篇文章带你了解CoX是怎么诞生的,也可以帮助了解一些底层软件思想。

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的指针就可以调用GPIO的API操作了,而且这个指针还可以被驱动嵌套使用。有兴趣的可以参考NUC140-LB Board的CoOS例程,这个在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通用接口的时候,是从以下角度出发考虑的:
配置一个GPIO管脚线
方向配置:
      输入   
      输出
      硬件功能
外围功能配置:
Pad配置:
      驱动能力大小(电流)
      开源/推挽
      弱上拉/下拉电阻
GPIO管脚数据控制
输出高/低电平
获取管脚输入值
输入中断(EXTI)
上升沿检测
下降沿检测
上/下沿检测
低电平检测
高电平检测
APIs分组完成以下几大功能:        配置GPIO管脚线的函数:
        xGPIODirModeSet
        xGPIOSPinDirModeSet
        xGPIOPinConfigure
        读回GPIO管脚线模式配置的函数:
        xGPIODirModeGet
        还有很方便的函数,可以将GPIO配置成想要的功能:
        xGPIOSPinTypeGPIOInput
        xGPIOSPinTypeGPIOOutput
        xSPinTypeADC
        xSPinTypeI2C
        xSPinTypeSPI
        xSPinTypeTimer
        xSPinTypeUART
        xSPinTypeACMP
        处理GPIO中断的APIs
        xGPIOPinIntCallbackInit
        xGPIOPinIntEnable
        xGPIOSPinIntEnable
        xGPIOPinIntDisable
        xGPIOSPinIntDisable
        xGPIOPinIntStatus
        xGPIOPinIntClear
        xGPIOSPinIntClear
        处理GPIO Pin状态的APIs
        xGPIOPinRead
        xGPIOSPinRead
        xGPIOPinWrite
        xGPIOSPinWrite1.3通用非强制接口
通用非强制接口是一部MCU通有的功能,而不是所有MCU都具有的功能接口:        xGPIOSPinTypeGPIOOutputOD
        xGPIOSPinTypeGPIOOutputQB
        xSPinTypePWM
        xSPinTypeEXTINT
        xSPinTypeEBICoX的宏定义的参数和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的实现方式如下:#definex GPIOPinWrite(ulPort,ulPins,ucVal)                              \
      GPIOPinWrite(ulPort, ulPins, ucVal)进行了一次宏定义包装罢了,对应的参数也是进行的一次宏定义比如:#define xGPIO_PIN_0             GPIO_PIN_02.设计技巧简介
GPIO的CoX接口创新性的提出了Short Pin,比如PA0 是GPIOA的Pin0脚,它的定义如下:#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_0GPIOPinWrite(GPA0, ucVal)会进一步展开为GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0, ucVal),这个函数在厂商库里面定义了的,所以实现了Pin写的功能。
另外Short Pin对GPIO管脚的外设多功能复用操作也带来了极大的方便,比如配置PD5为I2C的clock脚功能,如下: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宏定义如下:
#define GPIO_PD5_I2C0SCK      0x00003510
这个是根据多功能复用进行的编码,视不同的芯片,这个编码方式灵活多变。

还有一些接口完全是为了移植方便性而产生的,比如xGPIOSPinToPort, 这个接口是由Short Pin就可以得到这个Pin所对应的PORT Base,而在CoX.SYSCTL中有一个接口xSysCtlPeripheralEnable2是使用外设地址Base为参数使能这个外设 (在SYSCTL中维护了一个外设BASE-ID-INT的表),它实现的时候,是进行了一个Base到外设ID的一个转换,最终还是调用xSysCtlPeripheralEnable使能外设的。但是有了这个功能,也很利于基于CoX驱动组件的移植性,例如在AD7415温度传感器是通过I2C接口进行数据通信的,在这个驱动组件头文件中, 只需要考虑一下四个元素就可以平滑的使得这个驱动组件移植到其他的MCU上(比如NUC1xx,或者STM32F1xx)://
//! Config the device i2c Address
//
#define AD7415_I2C_ADDRESS      0x48

//
//! Config the devide i2c bus master
//
#define AD7415_MASTER_BASE   xI2C0_BASE

//
//! 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 );
        }
       
}

┏ωǒ┛菰独 发表于 2012-9-5 15:55:32

先顶一个:lol

┏ωǒ┛菰独 发表于 2012-9-5 15:58:07

cox 和stellaris的厂商库的语法是比较类似的是吧?

liamjeal 发表于 2012-9-5 16:23:50

┏ωǒ┛菰独 发表于 2012-9-5 15:58 static/image/common/back.gif
cox 和stellaris的厂商库的语法是比较类似的是吧?

恩是的,当时看到TI厂商库语法比较好,借鉴了不少

liamjeal 发表于 2012-9-6 11:49:24

CoX是统一ARM Cortex MCU软件接口标准,这一文章可以让你知道CoX是怎么来的,对编程思想也有帮助。

chenzhm 发表于 2012-9-13 14:36:03

直观感觉着个编程语言有点复杂:L:L

liamjeal 发表于 2012-9-13 15:24:21

chenzhm 发表于 2012-9-13 14:36 static/image/common/back.gif
直观感觉着个编程语言有点复杂

哈哈,这可使得arm mcu简单化了额

Randy 发表于 2012-9-17 19:50:19

写的很详细,顶一个,如果有快试用版玩就爽了!!!

liamjeal 发表于 2012-9-17 19:54:23

Randy 发表于 2012-9-17 19:50 static/image/common/back.gif
写的很详细,顶一个,如果有快试用版玩就爽了!!!

:lolcox有了。CoIDE直接勾选可以用了

liamjeal 发表于 2012-9-17 19:55:07

Randy 发表于 2012-9-17 19:50 static/image/common/back.gif
写的很详细,顶一个,如果有快试用版玩就爽了!!!

试用版,只需要有块M0 或者M3的就可以了

liamjeal 发表于 2012-9-17 19:55:33

Randy 发表于 2012-9-17 19:50 static/image/common/back.gif
写的很详细,顶一个,如果有快试用版玩就爽了!!!

到时候去抢楼
页: [1]
查看完整版本: coocox学习系列之CoX_GPIO篇