在使用Ti CC1310
的硬件I2C
与外部设备进行通信的时候,无法长时间稳定运行,尤其是平时的测试开发板,使用杜邦线连接的情况下。
同等情况下的SPI
总线,一般不会发生此类问题,因此怀疑是GPIO
管脚的驱动能力不足导致的。
我的工程是通过简单修改Ti CC1310 SDK
自带的Code Composer Studio
的例子工程而创建的,因此存在已经进行过默认配置的CC1310_LAUNCHXL.c
,CC1310_LAUNCHXL.h
这两个文件。用Code Composer Studio
完全重新创建的工程,缺乏必要的默认配置。因此,我们还是建议根据Ti CC1310 SDK
自带的例子进行修改,而不是完全从头创建工程。
我们研究I2C
初始化GPIO
管脚的代码在simplelink_cc13x0_sdk_2_30_00_20/source/ti/drivers/i2c/I2CCC26XX.c
,相关的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
/* * ======== I2CCC26XX_initIO ======== * This functions initializes the I2C IOs. * * @pre Function assumes that the I2C handle is pointing to a hardware * module which has already been opened. */ static int I2CCC26XX_initIO(I2C_Handle handle, void *pinCfg) { I2CCC26XX_Object *object; I2CCC26XX_HWAttrsV1 const *hwAttrs; I2CCC26XX_I2CPinCfg i2cPins; PIN_Config i2cPinTable[3]; uint32_t i=0; /* Get the pointer to the object and hwAttrs */ object = handle->object; hwAttrs = handle->hwAttrs; /* If the pinCfg pointer is NULL, use hwAttrs pins */ if (pinCfg == NULL) { i2cPins.pinSDA = hwAttrs->sdaPin; i2cPins.pinSCL = hwAttrs->sclPin; } else { i2cPins.pinSDA = ((I2CCC26XX_I2CPinCfg *)pinCfg)->pinSDA; i2cPins.pinSCL = ((I2CCC26XX_I2CPinCfg *)pinCfg)->pinSCL; } /* Handle error */ if(i2cPins.pinSDA == PIN_UNASSIGNED || i2cPins.pinSCL == PIN_UNASSIGNED) { return I2C_STATUS_ERROR; } /* Configure I2C pins SDA and SCL*/ i2cPinTable[i++] = i2cPins.pinSDA | PIN_INPUT_EN | PIN_PULLUP | PIN_OPENDRAIN; i2cPinTable[i++] = i2cPins.pinSCL | PIN_INPUT_EN | PIN_PULLUP | PIN_OPENDRAIN; i2cPinTable[i++] = PIN_TERMINATE; /* Allocate pins*/ object->hPin = PIN_open(&object->pinState, i2cPinTable); if (!object->hPin) { return I2C_STATUS_ERROR; } /* Set IO muxing for the UART pins */ PINCC26XX_setMux(object->hPin, i2cPins.pinSDA, IOC_PORT_MCU_I2C_MSSDA); PINCC26XX_setMux(object->hPin, i2cPins.pinSCL, IOC_PORT_MCU_I2C_MSSCL); return I2C_STATUS_SUCCESS; } |
从上面的代码中,我们发现GPIO
管脚的驱动能力没有设置,根据CC13x0, CC26x0 SimpleLink ™ Wireless MCU Technical Reference Manual中的介绍,我们发现,如果不设置,默认情况下是PIN_DRVSTR_MIN(< (*) Lowest drive strength)
。这个驱动模式下,最省电,但是当有干扰存在的情况下,最容易导致出现错误。
查找Ti CC1310
提供的I2C
驱动程序,没有找到可以设置管脚驱动能力的接口。
网上有人通过直接修改Ti CC1310
提供的I2C
驱动程序,也就是simplelink_cc13x0_sdk_2_30_00_20/source/ti/drivers/i2c/I2CCC26XX.c
里的初始化代码(见上面的代码段)增加驱动能力属性来实现这个功能。
但是这种修改方式不推荐,修改的侵入太强。
从GPIO
的操作函数中,我们找到如下函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/** @brief Returns pin configuration * * @param pinId Pin ID * @return Current pin configuration as a device-independent #PIN_Config value * @note The pin ID is embedded in return value. * @note There is usually a device-specific version of this function that * returns device-specific options * @par Usage * @code * // Get config of pin 14 to be able to revert later * myPinConfig = PIN_getConfig(PIN_ID(14)); * // ... * // Lots of pin reconfigurations * // ... * // Restore previous configuration * PIN_setConfig(hPins, PIN_BM_ALL, myPinConfig); * @endcode */ extern PIN_Config PIN_getConfig(PIN_Id pinId); /** @brief Sets complete pin configuration * * @param handle Handle provided by previous call to PIN_open() * @param updateMask Bitmask specifying which fields in cfg that should take * effect, the rest keep their current value. * @param pinCfg #PIN_Config entry with pin ID and pin configuration * @return #PIN_SUCCESS if successful, else error code * @par Usage * @code * // Set drive strength on pin 15 * PIN_setConfig(hPins, PIN_BM_DRVSTR, PIN_ID(15)|PIN_DRVSTR_MAX); * @endcode */ extern PIN_Status PIN_setConfig(PIN_Handle handle, PIN_Config updateMask, PIN_Config pinCfg); |
我们尝试从上层找到I2C
驱动使用的GPIO
管脚,然后调整其驱动能力。
1 2 3 |
/* I2C */ #define CC1310_LAUNCHXL_I2C0_SCL0 (IOID_5) #define CC1310_LAUNCHXL_I2C0_SDA0 (IOID_6) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/* * =============================== I2C =============================== */ #include <ti/drivers/I2C.h> #include <ti/drivers/i2c/I2CCC26XX.h> I2CCC26XX_Object i2cCC26xxObjects[CC1310_LAUNCHXL_I2CCOUNT]; const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2CCOUNT] = { { .baseAddr = I2C0_BASE, .powerMngrId = PowerCC26XX_PERIPH_I2C0, .intNum = INT_I2C_IRQ, .intPriority = ~0, .swiPriority = 0, .sdaPin = CC1310_LAUNCHXL_I2C0_SDA0, .sclPin = CC1310_LAUNCHXL_I2C0_SCL0, } }; const I2C_Config I2C_config[CC1310_LAUNCHXL_I2CCOUNT] = { { .fxnTablePtr = &I2CCC26XX_fxnTable, .object = &i2cCC26xxObjects[CC1310_LAUNCHXL_I2C0], .hwAttrs = &i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2C0] } }; const uint_least8_t I2C_count = CC1310_LAUNCHXL_I2CCOUNT; |
从上面我们看到I2C
句柄的.object
指针指向了I2CCC26XX_Object
类型的结构体,这个结构体在simplelink_cc13x0_sdk_2_30_00_20/source/ti/drivers/i2c/I2CCC26XX.c
里的static int I2CCC26XX_initIO(I2C_Handle handle, void *pinCfg)
函数中被初始化,这个结构体记录了详细的GPIO
操作句柄。
因此我们可以使用如下的代码对GPIO
管脚的驱动能力进行调整:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include <ti/drivers/I2C.h> #include <ti/drivers/i2c/I2CCC26XX.h> #include "CC1310_LAUNCHXL.h" static I2C_Handle initI2c(void) { I2C_Params i2cParams; /* Create I2C for usage */ I2C_Params_init(&i2cParams); i2cParams.bitRate = I2C_400kHz; i2cParams.transferMode = I2C_MODE_BLOCKING; I2C_Handle i2c = I2C_open(Board_I2C_TMP, &i2cParams); if (NULL == i2c) { return NULL; } /* Change I2C Pin Drive Strength*/ /*CC1310_LAUNCHXL.c I2CCC26XX_Object i2cCC26xxObjects[CC1310_LAUNCHXL_I2CCOUNT];*/ I2CCC26XX_Object* i2cObj = i2c->object; if (NULL != i2cObj) { PIN_Config pinCfg = PIN_getConfig(PIN_ID(CC1310_LAUNCHXL_I2C0_SDA0)); PIN_Status status = PIN_setConfig(i2cObj->hPin, PIN_BM_ALL, pinCfg | PIN_DRVSTR_MAX); if (PIN_SUCCESS != status){ I2C_close(i2c); return NULL; } pinCfg = PIN_getConfig(PIN_ID(CC1310_LAUNCHXL_I2C0_SCL0)); status = PIN_setConfig(i2cObj->hPin, PIN_BM_ALL, pinCfg | PIN_DRVSTR_MAX); if (PIN_SUCCESS != status){ I2C_close(handle->i2c); return NULL; } } return i2c; } |