I2C总线协议图解

I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。

I2C通信方式为半双工,只有一根SDA线,同一时间只可以单向通信,RS485也为半双工,SPI和UART为双工。

继续阅读I2C总线协议图解

白皮书:ARM big.LITTLE 系统的软件技术

ARM big.LITTLE 系统的软件技术

Robin Randhawa,首席工程师2013 4

简介

移动应用已经发生了显著变化,当今的消费者更多地将智能手机应用于大部分互联生活。其中既包括高性能任务,例如网络浏览、导航和游戏,也包括那些要求不太苛刻的“始终在线,始终连接”后台任务,例如语音呼叫、社交网络和电子邮件服务。因此,移动电话已经成为很多消费者必不可少的计算设备。同时,平板电脑等新型移动设备也在重新定义计算平台,以应对消费者的需求。这一趋势为消费者创造了全新的内容互动方式,将以往只可能在固定设备上实现的应用带到移动设备上。这才是真正的智能下一代计算。

摩尔定律将如何往下发展?人们过去预测集成电路上可容纳的晶体管数目每隔 18 个月会增加一倍,直至从数千个增加至数十亿个晶体管,但如果真正审视单个处理器,却会发现它的性能增长停滞不前,因为您可以在系统中消耗的电能已经达到峰值。

对于未来的任何一款处理器,散热必然会限制其速度的大幅提高。一旦达到器件的热障,器件会融化,如果是在移动电话上,设备会开始发热,让用户感到不适。除了物理散热问题之外,能效也会变得相当低。如果调节处理器实施,使其速度逐渐加快,则其能耗将呈指数级增长,而为了增加最后这一丁点的性能,却会导致成本大幅提升。过去,尺寸增大一倍也意味着速度提高一倍,但到了现在,尺寸增大一倍却只能将速度提高几个百分点,因此出于复杂性的原因,效益不复存在,这也是单核系统的速度达到极限的原因之一。

如果您无法让单核运行更快,则必须增加核心的数量。这样做的好处还包括让每个核心能够匹配其承担的工作负载,这正是 ARM big.LITTLE™ 处理概念的用武之地。

Big.LITTLE处理技术可以解决我们当前面临的一个最大难题:扩展消费者的“始终在线,始终连接”移动体验,同时改进性能,延长电池续航时间。实现这一目标的方式是将“big”多核处理器与“LITTLE”多核处理器配合使用,根据性能要求,为适当的任务无缝选择适当的处理器。重要的是,这种动态选择对在处理器上运行的应用程序软件或中间件是透明的。 设备中采用的最新一代big.LITTLE 设计将高性能Cortex™-A15 多处理器集群与高能效Cortex-A7 多处理器集群组合在一起。这些处理器保持了 100% 架构兼容性,并且具有相同的功能(支持 LPAE 和虚拟化扩展,以及 NEON™ VFP 等功能单元),这使得针对一种处理器类型编译的软件应用程序能够在其他处理器上运行,而无需进行修改。
继续阅读白皮书:ARM big.LITTLE 系统的软件技术

Ti CC1310 SDK版本兼容

在开发Ti CC1310应用的时候遇到了SDK版本兼容问题。早期的应用都是从SDK 1.60版本的例子中修改得来的,最近在升级到SDK 2.x版本的时候遇到了编译不通过的问题。主要是某些变量名的定义改变了。

但是,翻遍了代码也没找打一个SDK版本宏。

于是只能通过ti/devices/cc13x0/driverlib/driverlib_release.h文件里面的DRIVERLIB_RELEASE_BUILD的版本号来进行区分,根据数字的不同来使用不同的代码,例子如下:

#include <ti/devices/cc13x0/driverlib/driverlib_release.h>

/*SDK 1_60_00_21*/
#if (DRIVERLIB_RELEASE_BUILD <= 50218)
const DisplaySharp_HWAttrs displaySharpHWattrs = {
    .spiIndex    = CC1310_LAUNCHXL_SPI0,
    .csPin       = CC1310_LAUNCHXL_LCD_CS,
    .extcominPin = CC1310_LAUNCHXL_LCD_EXTCOMIN,
    .powerPin    = CC1310_LAUNCHXL_LCD_POWER,
    .enablePin   = CC1310_LAUNCHXL_LCD_ENABLE,
    .pixelWidth  = BOARD_DISPLAY_SHARP_SIZE,
    .pixelHeight = BOARD_DISPLAY_SHARP_SIZE,
    .displayBuf  = sharpDisplayBuf,
};
#else /*SDK 2_10_02_10*/
const DisplaySharp_HWAttrsV1 displaySharpHWattrs = {
    .spiIndex    = CC1310_LAUNCHXL_SPI0,
    .csPin       = CC1310_LAUNCHXL_LCD_CS,
    .powerPin    = CC1310_LAUNCHXL_LCD_POWER,
    .enablePin   = CC1310_LAUNCHXL_LCD_ENABLE,
    .pixelWidth  = BOARD_DISPLAY_SHARP_SIZE,
    .pixelHeight = BOARD_DISPLAY_SHARP_SIZE,
    .displayBuf  = sharpDisplayBuf,
};
#endif
/*
 *  =============================== RF Driver ===============================
 */
#include <ti/drivers/rf/RF.h>

/*SDK 1_60_00_21*/
#if (DRIVERLIB_RELEASE_BUILD <= 50218)
const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = {
    .hwiCpe0Priority = ~0,
    .hwiHwPriority   = ~0,
    .swiCpe0Priority =  0,
    .swiHwPriority   =  0,
};
#else /*SDK 2_10_02_10*/
const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = {
    .hwiPriority        = ~0,       /* Lowest HWI priority */
    .swiPriority        = 0,        /* Lowest SWI priority */
    .xoscHfAlwaysNeeded = true,     /* Keep XOSC dependency while in stanby */
    .globalCallback     = NULL,     /* No board specific callback */
    .globalEventMask    = 0         /* No events subscribed to */
};
#endif

其他的就是动态链接库的位置不同,导致链接的时候报告找不到链接库,需要重新设置一下,或者简单的移除一些找不到的库即可,例子中并没有用到全部的链接库。

Code Composer Studio 8.2运行时对象查看器Runtime Object View (ROV)

Code Composer Studio 8.2提供的Runtime Object View (ROV)是一个非常好用的功能,能动态监视系统的运行情况。

该功能需要使用TI-RTOS的应用才可以正常使用。

下面是官方的参考文档:
继续阅读Code Composer Studio 8.2运行时对象查看器Runtime Object View (ROV)

GCC支持在代码中对头文件是否存在的判断(__has_include)

我们在实际编写代码的时候,经常需要判断当前编译环境是否存在我们需要的头文件,如果不存在,则使用其他头文件代替。

以前这个操作都是通过外部的configure文件生成Makefile的时候指定。

最近的GCC已经增加了__has_include这个内置函数判断头文件是否存在。

这个功能最早是Clang实现的,现在GCC终于补上了这个功能。

例子如下:

#ifdef __has_include
#  if __has_include(<optional>)
#    include <optional>
#    define have_optional 1
#  elif __has_include(<experimental/optional>)
#    include <experimental/optional>
#    define have_optional 1
#    define experimental_optional
#  else
#    define have_optional 0
#  endif
#endif

Code Composer Studio 8.2.0.00007 ,GCC 5支持这个内置函数。

参考链接


解决Ti CC1310上I2C驱动能力不足(稳定性)问题

在使用Ti CC1310的硬件I2C与外部设备进行通信的时候,无法长时间稳定运行,尤其是平时的测试开发板,使用杜邦线连接的情况下。

同等情况下的SPI总线,一般不会发生此类问题,因此怀疑是GPIO管脚的驱动能力不足导致的。

我的工程是通过简单修改Ti CC1310 SDK自带的Code Composer Studio的例子工程而创建的,因此存在已经进行过默认配置的CC1310_LAUNCHXL.cCC1310_LAUNCHXL.h这两个文件。用Code Composer Studio完全重新创建的工程,缺乏必要的默认配置。因此,我们还是建议根据Ti CC1310 SDK自带的例子进行修改,而不是完全从头创建工程。

我们研究I2C初始化GPIO管脚的代码在simplelink_cc13x0_sdk_2_30_00_20/source/ti/drivers/i2c/I2CCC26XX.c,相关的代码如下:

/*
 *  ======== 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的操作函数中,我们找到如下函数:

/** @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管脚,然后调整其驱动能力。

/* I2C */
#define CC1310_LAUNCHXL_I2C0_SCL0            (IOID_5) 
#define CC1310_LAUNCHXL_I2C0_SDA0            (IOID_6)
/*
 *  =============================== 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管脚的驱动能力进行调整:

#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;
}

参考链接


Raspberry Pi Zero W解决调试信息不足的问题(以libzmq-dev为例)

最近在参照 树莓派实时系统下脚本语言的选择(应当使用Lua而不是Python) 调用调试lua-zmq的时候,发现使用PAIR模式进行线程之间通信,长时间运行后会出现死锁的情况。

当我们需要跟踪问题的时候,使用apt-get安装的版本缺乏必要的调试信息。

我们可以手工安装调试信息包,如下:

$ sudo apt install libzmq-dbg

# 系统默认的lua 5.1的符号信息使用如下命令安装
$ sudo apt-get install liblua5.1-0-dbg

# libreadline提供了多个版本(5,6,7),根据需要下载对应的版本
$ sudo apt-get install libreadline6-dbg

# sudo apt-get install search libtinfo* 根据返回的结果安装
$ sudo apt-get install libtinfo5-dbg

我们也可以从源代码重新编译一份,如下:

# 打开源代码的源
$ sudo sed -i "s/^#deb-src/deb-src/g" /etc/apt/sources.list

# 安装必要的编译工具
$ sudo apt-get install build-essential devscripts lintian

$ cd ~

# 下载源代码,此处不可sudo,否则后续操作会出现权限问题
$ apt-get source libzmq-dev

$ cd zeromq*/

# 安装依赖项
$ sudo apt-get install libpgm-dev

$ sudo apt-get install uuid-dev

$ debuild -us -uc -b

$ cd ..

$ sudo dpkg -i libzmq-dev*.deb

$ sudo dpkg -i libzmq-dbg*.deb

$ sudo ldconfig

以上是针对Debian安装包来进行的处理,然而对于luarocks安装的插件来说,默认luarocks是不能编译调试版本的,此时就需要我们手工编译了。我们以lua-zmq为例子,参考如下:

$ sudo apt-get -y install cmake

$ git clone git://github.com/Neopallium/lua-zmq.git

$ git checkout v1.1

$ cd lua-zmq ; mkdir build ; cd build

$ cmake -DCMAKE_BUILD_TYPE=Debug ..

$ make

$ sudo make install

$ sudo ldconfig

macOS High Sierra(10.13.6)使用HL-340(CH340/CH341)芯片的USB转串口设备

最近开发需要,购买了一堆的USB转串口设备,在Linux下面都是免驱动的,但是到了macOS High Sierra(10.13.6)上,无法正常识别。在Linux上通过lsusb可以看到如下信息:

Bus 001 Device 008: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter

继续阅读macOS High Sierra(10.13.6)使用HL-340(CH340/CH341)芯片的USB转串口设备