目录
GPIO外设的配置流程
我们想要将CC1310芯片的某个引脚配置给GPIO外设使用,那么就必须确保芯片引脚与GPIO外设索引的引脚有正确的对应关系。
GPIO引脚配置的流程大致如下:
它主要分为对应引脚的初始化和对应GPIO外设的初始化。
引脚初始化
首先我们想要将CC1310的某个引脚作为GPIO引脚使用,我们必须要初始化该引脚
引脚的初始化主要可分为上图中的三个步骤。
引脚的声明
我这里说的声明并非像C语言的变量声明那样,而是CC1310的例程中,对每个引脚的物理地址都做了预定义,这个预定义我们可以再CC1310_LAUNCHPAD.h文件中看到。
注意这一步并非必须的,这样做只是方便了我们在编写程序时可以更加方便的理解程序,并且增强了代码整体的可移植性。但是如果我们使用这种引脚预定义的声明方式,那么我们必须要保证我们预定义的名称指向了我们想用的IO引脚的物理地址。
如下图所示:
这里再废话两句,为什么要添加引脚的预定义:
如果我想使用一个红色led灯作为CC1310工作状态的指示灯,并选择使用IO_0作为一个led灯的输出引脚,那么我将IO_0的物理地址预定义为CC1310_LAUNCHPAD_PIN_RLED,这样我们在编写应用程序时想要改变红色LED灯引脚电平时,就可以直接调用预定义的名称,这样会更加方便我们理解该引脚的作用。如果我们之后想用IO_6作为红色led灯的输出引脚,那么只用在这里把IO_0改为IO_6便可以了,而不需要修改我们编写的应用程序,这便增加了应用程序代码整体的可移植性。
并且如果之后想要之后再添加一个绿色led灯,来指示CC1310的另外一些工作的状态,我这里也可以提前预定义出来,并不设定实际的引脚物理地址,这样方便我们后续继续扩充程序功能。
添加引脚声明
我们在预定义了我们想要使用的引脚后,便可以在引脚初始化时使用它了。
但在引脚初始化之前,我们必须配置其相应的属性,这是在为引脚初始化时,将引脚和对应属性一起写入对应寄存器做准备。
我们可以在CC1310_LAUNCHPAD.c文件中找到下面这段代码:
/*
* =============================== PIN ===============================
*/
#include <ti/drivers/PIN.h>
#include <ti/drivers/pin/PINCC26XX.h>
const PIN_Config BoardGpioInitTable[] = {
CC1310_LAUNCHXL_PIN_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */
CC1310_LAUNCHXL_PIN_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */
CC1310_LAUNCHXL_PIN_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */
CC1310_LAUNCHXL_PIN_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */
CC1310_LAUNCHXL_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */
CC1310_LAUNCHXL_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */
CC1310_LAUNCHXL_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL, /* UART TX via debugger back channel */
CC1310_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */
CC1310_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */
CC1310_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */
PIN_TERMINATE
};
const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = {
.intPriority = ~0,
.swiPriority = 0
};
这段代码中的PIN_Config表单便是对程序中所有用到的所有引脚进行了属性配置。
如果我们想要新添加了某些引脚的预定义,便需要在改属性配置表中添加要使用的引脚名称,并为其加上我们想要其实现的引脚属性。
此外,该部分代码还规定了这些引脚产生的硬件和软件中断都是优先级最低的中断。
引脚初始化
在将要使用的引脚名称添加到引脚配置表后,便可以使用此表进行引脚的初始化过程了。
引脚的初始化时调用了PIN_init()函数完成的,在TI的例程中,该函数是在main函数中,调用Board_init函数时实现的。
我们点进去Board_init()函数,便可以发现该函数。
/*
* ======== CC1310_LAUNCHXL_initGeneral ========
*/
void CC1310_LAUNCHXL_initGeneral(void)
{
Power_init();
if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) {
/* Error with PIN_init */
while (1);
}
/* Perform board-specific initialization */
// Board_initHook();
}
/*
* ======== Board_init ========
*/
void Board_init(void)
{
CC1310_LAUNCHXL_initGeneral();
}
向PIN_init()函数中传入的PIN_Config表中的引脚都会被配置为GPIO引脚,并具有添加的引脚属性。
没有在PIN_Config表中的引脚都会被配置为输入输出都失能的状态。
注意:在同一个应用程序中,PIN_init()不可以被多次调用。
这里我想深究一下,PIN_init函数到底做了什么,表面上来看他是将BoardGpioInitTable数组中的对具体引脚的配置全部初始化到对应GPIO端口上,但是如果我们愿意尝试一下就会发现,有几个问题存在
-
没有在BoardGpioInitTable数组中配置引脚,但是在gpioPinConfigs数组(这个数组在后面介绍GPIO的部分可以看到)中存在的引脚就可以在GPIO_init后使用GPIO功能
-
如果我们只使用引脚,不使用GPIO模式,那我们是不是可以不进行不用进行PIN_init,这是不行的,不然PIN_open函数在调用时会卡死
-
我们在整个程序中用到的引脚不用全部在BoardGpioInitTable中列出,只要在PIN_open函数的数组中或BoardGpioInitTable数组中列出即可。
那么这个PIN_init函数到底对引脚的配置起着怎样的作用呢,为什么所使用的引脚不用在其输入数组中提及,但却又必须尽早调用,且全局仅能调用一次呢?
那我们跳进PIN_init函数中看一看,首先解答问题2,在PIN_init函数释放了阻塞PIN_open函数的信号量
他之所以重要是因为在其中创建了所有引脚的软硬件中断,这写引脚的信息是从PINCC26XX文件中映射过来的,所以不需要我们在调用PIN_init函数时输入。同时它也实现了GPIO的上电操作,并可以对写入BoardGpioInitTable中的引脚完成配置操作,这样也省去了我们之后再调用GPIO_setConfig函数对使用GPIO的引脚进行单独配置。(在gpioPinConfigs数组中完成对GPIO引脚的配置也可以起到相同的效果)
GPIO初始化
介绍完PIN初始化后,我们已经可以使用driver/PIN.h文件中提供的API使用这些引脚了,如果我们想要直接使用某些引脚实现IO功能的话可以直接调用PIN_open()函数,但是在有操作系统的应用程序中并不推荐这样做,因为这并非线程安全的。
上面PIN_init函数会将我们需要的引脚配置为GPIO可用的状态,但是在想使用这些引脚作为GPIO之前,还需要完成GPIO外设的初始化。
下面有关GPIO配置的操作都是在CC1310_LAUNCHPAD.c文件中完成的。
GPIO外设的实现
有关GPIO的配置信息,都是通过GPIO_Config结构体来保存的,其实例化代码如下:
const GPIOCC26XX_Config GPIOCC26XX_config = {
.pinConfigs = (GPIO_PinConfig *)gpioPinConfigs,
.callbacks = (GPIO_CallbackFxn *)gpioCallbackFunctions,
.numberOfPinConfigs = CC1310_LAUNCHXL_GPIOCOUNT,
.numberOfCallbacks = sizeof(gpioCallbackFunctions)/sizeof(GPIO_CallbackFxn),
.intPriority = (~0)
};
在该结构体的原型在GPIOCC26XX中定义,其中保存了GPIO可以控制的引脚、回调、中断等信息。
我们要做的便是在对GPIO_Config结构体实话化时,配置我们所用的实际引脚、中断与结构体的成员完成链接(对成员进行实例化赋值)。
在gpioPinConfig数组中添加要使用的引脚
我们想要使用GPIO控制红色LED灯的电平变化,则将其添加到gpioPinConfig数组中,并加上配置信息,其他预留引脚定义配置也可以添加到数组中,配置信息为NOT_CONFIG。
GPIO_PinConfig gpioPinConfigs[] = {
/* Input pins */
GPIOCC26XX_DIO_13 | GPIO_DO_NOT_CONFIG, /* Button 0 */
GPIOCC26XX_DIO_14 | GPIO_DO_NOT_CONFIG, /* Button 1 */
GPIOCC26XX_DIO_15 | GPIO_DO_NOT_CONFIG, /* CC1310_LAUNCHXL_SPI_MASTER_READY */
GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG, /* CC1310_LAUNCHXL_SPI_SLAVE_READY */
/* Output pins */
GPIOCC26XX_DIO_07 | GPIO_DO_NOT_CONFIG, /* Green LED */
GPIOCC26XX_DIO_00 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_HIGH , /* Red LED */
GPIOCC26XX_DIO_30 | GPIO_DO_NOT_CONFIG, /* TMP116_EN */
/* SPI Flash CSN */
GPIOCC26XX_DIO_20 | GPIO_DO_NOT_CONFIG,
/* SD CS */
GPIOCC26XX_DIO_21 | GPIO_DO_NOT_CONFIG,
/* Sharp Display - GPIO configurations will be done in the Display files */
GPIOCC26XX_DIO_24 | GPIO_DO_NOT_CONFIG, /* SPI chip select */
GPIOCC26XX_DIO_22 | GPIO_DO_NOT_CONFIG, /* LCD power control */
GPIOCC26XX_DIO_23 | GPIO_DO_NOT_CONFIG, /*LCD enable */
};
在gpioCallbackFunctions数组中添加要使用的回调函数
我们可以自定义某个引脚的回调函数,但该回调函数的指针需要传入GPIO_Config结构体中,在GPIO外设中注册回调函数的对应中断。
GPIO_CallbackFxn gpioCallbackFunctions[] = {
NULL, /* Button 0 */
NULL, /* Button 1 */
NULL, /* CC1310_LAUNCHXL_SPI_MASTER_READY */
NULL, /* CC1310_LAUNCHXL_SPI_SLAVE_READY */
};
添加对应引脚的索引号
我们在上面在gpioPinConfig数组中添加的均是使用到的引脚的物理地址和配置信息,但我们想要调用某个引脚,被非要找到这个引脚的物理地址,而只需要将其从储存它的数组中提取出来即可,也就是我们只需对该数组中的某个元素进行索引,因此我们必须定义与该数组中每个引脚成员对应的索引序号。
关于引脚索引信息的定义,我们是在CC1310_LAUNCHPAD.h文件中实现的,利用共用体完成定义。
其代码如下:
typedef enum CC1310_LAUNCHXL_GPIOName {
CC1310_LAUNCHXL_GPIO_S1 = 0,
CC1310_LAUNCHXL_GPIO_S2,
CC1310_LAUNCHXL_SPI_MASTER_READY,
CC1310_LAUNCHXL_SPI_SLAVE_READY,
CC1310_LAUNCHXL_GPIO_LED_GREEN,
CC1310_LAUNCHXL_GPIO_LED_RED,
CC1310_LAUNCHXL_GPIO_TMP116_EN,
CC1310_LAUNCHXL_GPIO_SPI_FLASH_CS,
CC1310_LAUNCHXL_SDSPI_CS,
CC1310_LAUNCHXL_GPIO_LCD_CS,
CC1310_LAUNCHXL_GPIO_LCD_POWER,
CC1310_LAUNCHXL_GPIO_LCD_ENABLE,
CC1310_LAUNCHXL_GPIOCOUNT
} CC1310_LAUNCHXL_GPIOName;
需要注意的是,我们调用的引脚的索引号必须与该引脚存在于gpioPinConfig数组中的位置保持一致。
初始化GPIO外设
在配置完gpioPIN_Table后,便可以调用GPIO_init()函数来进行GPIO外设的初始化了。
GPIO_init()函数会将我们配置的gpioPIN_Table和中断表中的引脚名称,按照其对应的索引号一一存入到GPIO外设的相应寄存器中。
在调用了GPIO_init()函数后,便完成了GPIO的初始化工作,之后便可以调用GPIO.h文件中的API来通过GPIO配置或控制相应的引脚了。
GPIO使用注意事项
(未完待续)~