MSPM0G3507 IIC

I2C pin映射表

I2C Peripheral I2C Serial Data Line(SDA) I2C Serial Clock line(SCL)
12C0 PA28(35)/PA0(33)/PA10(56) PA31(39)/PA1(34)/PA11(57)
I2C1 PA3(43)/PA10(56)/PA16(9)/PA18(11)/PA30(37)/PB3(51) PA4(44)/PA11(57)/PA15(8)/PA16(10)/PA29(36)/PB2(50)

I2C Controller & I2C Target

项目 Controller Target
角色 主动 被动
SCL 产生 不产生
START / STOP 产生 识别
选谁通信 自己决定 被选
数据方向 控制 跟随
可否多设备 可以 可以
固件复杂度 高(状态机)
多主 支持(少用) N/A

TI Drivers Config

c 复制代码
/*
 *  ======== I2C ========
 */
extern const uint_least8_t CONFIG_I2C_CONTROLLER_CONST;
#define CONFIG_I2C_0 0

/*
 *  ======== I2C ========
 */

extern const uint_least8_t CONFIG_I2C_TARGET_CONST;
#define CONFIG_I2C_TARGET_0 0
#define CONFIG_TI_DRIVERS_I2C_COUNT 1

/* ======== I2C Addresses and Speeds ======== */
#include <ti/drivers/I2C.h>

/* ---- CONFIG_I2C_TARGET I2C bus components ---- */

/* CONFIG_I2C_TARGET max speed (supported by all components) */
#define CONFIG_I2C_TARGET_MAXSPEED (400U) /* kbps */
#define CONFIG_I2C_TARGET_MAXBITRATE ((I2C_BitRate) I2C_400kHz)

/* Defines for I2C0 */
#define I2C0_INST I2C0
#define I2C0_INST_IRQHandler I2C0_IRQHandler
#define I2C0_INST_INT_IRQN I2C0_INT_IRQn

#define GPIO_I2C0_SDA_PIN (28)
#define GPIO_I2C0_IOMUX_SDA (IOMUX_PINCM3)
#define GPIO_I2C0_IOMUX_SDA_FUNC IOMUX_PINCM3_PF_I2C0_SDA

#define GPIO_I2C0_SCL_PIN (31)
#define GPIO_I2C0_IOMUX_SCL (IOMUX_PINCM6)
#define GPIO_I2C0_IOMUX_SCL_FUNC IOMUX_PINCM6_PF_I2C0_SCL

/* Defines for I2C1 */
#define I2C1_INST I2C1
#define I2C1_INST_IRQHandler I2C1_IRQHandler
#define I2C1_INST_INT_IRQN I2C1_INT_IRQn

#define GPIO_I2C1_SDA_PIN (35)
#define GPIO_I2C1_IOMUX_SDA (IOMUX_PINCM16)
#define GPIO_I2C1_IOMUX_SDA_FUNC IOMUX_PINCM16_PF_I2C1_SDA

#define GPIO_I2C1_SCL_PIN (34)
#define GPIO_I2C1_IOMUX_SCL (IOMUX_PINCM15)
#define GPIO_I2C1_IOMUX_SCL_FUNC IOMUX_PINCM15_PF_I2C1_SCL
c 复制代码
/*
 *  =============================== I2CTarget ===============================
 */

#include <ti/drivers/I2CTarget.h>
#include <ti/drivers/i2ctarget/I2CTargetMSPM0.h>

#define CONFIG_I2CTARGET_COUNT 1

/*
 *  ======== i2cObjects ========
 */
I2CTargetMSPM0_Object I2CTargetMSPM0Objects[CONFIG_I2CTARGET_COUNT];

/*
 *  ======== i2cHWAttrs ========
 */
const I2CTargetMSPM0_HWAttrs I2CTargetMSPM0HWAttrs[CONFIG_I2CTARGET_COUNT] = {
    /* CONFIG_I2C_Target */
    /* LaunchPad I2C */
    {
        .i2c         = I2C1_INST,
        .intNum      = I2C1_INST_INT_IRQN,
        .intPriority = (~0),

        .sdaPincm    = GPIO_I2C1_IOMUX_SDA,
        .sdaPinIndex = GPIO_I2C1_SDA_PIN,
        .sdaPinMux   = GPIO_I2C1_IOMUX_SDA_FUNC,

        .sclPincm    = GPIO_I2C1_IOMUX_SCL,
        .sclPinIndex = GPIO_I2C1_SCL_PIN,
        .sclPinMux   = GPIO_I2C1_IOMUX_SCL_FUNC,

        .clockSource                 = DL_I2C_CLOCK_BUSCLK,
        .clockDivider                = DL_I2C_CLOCK_DIVIDE_1,
        .txIntFifoThr                = DL_I2C_TX_FIFO_LEVEL_BYTES_1,
        .rxIntFifoThr                = DL_I2C_RX_FIFO_LEVEL_BYTES_1,
        .isClockStretchingEnabled    = true,
        .isAnalogGlitchFilterEnabled = false,
    },
};

/*
 *  ======== I2C_config ========
 */
const I2CTarget_Config I2CTarget_config[CONFIG_I2CTARGET_COUNT] = {
    /* CONFIG_I2C_TARGET */
    /* LaunchPad I2C */
    {.object     = &I2CTargetMSPM0Objects[CONFIG_I2C_TARGET_0],
        .hwAttrs = &I2CTargetMSPM0HWAttrs[CONFIG_I2C_TARGET_0]},
};

const uint_least8_t CONFIG_I2C_0_CONST = CONFIG_I2C_TARGET_0;
const uint_least8_t I2CTarget_count    = CONFIG_I2CTARGET_COUNT;

/*
 *  =============================== I2C Controller ===============================
 */

#include <ti/drivers/I2C.h>
#include <ti/drivers/i2c/I2CMSPM0.h>

#define CONFIG_I2C_COUNT 1

/*
 *  ======== i2cObjects ========
 */
I2CMSPM0_Object I2CMSPM0Objects[CONFIG_I2C_COUNT];

/*
 *  ======== i2cHWAttrs ========
 */
const I2CMSPM0_HWAttrs I2CMSPM0HWAttrs[CONFIG_I2C_COUNT] = {
    /* CONFIG_I2C_CONTROLLER */
    /* LaunchPad I2C */
    {
        .i2c         = I2C0_INST,
        .intNum      = I2C0_INST_INT_IRQN,
        .intPriority = (~0),

        .sdaPincm    = GPIO_I2C0_IOMUX_SDA,
        .sdaPinIndex = GPIO_I2C0_SDA_PIN,
        .sdaPinMux   = GPIO_I2C0_IOMUX_SDA_FUNC,

        .sclPincm    = GPIO_I2C0_IOMUX_SCL,
        .sclPinIndex = GPIO_I2C0_SCL_PIN,
        .sclPinMux   = GPIO_I2C0_IOMUX_SCL_FUNC,

        .clockSource              = DL_I2C_CLOCK_BUSCLK,
        .clockDivider             = DL_I2C_CLOCK_DIVIDE_1,
        .txIntFifoThr             = DL_I2C_TX_FIFO_LEVEL_BYTES_1,
        .rxIntFifoThr             = DL_I2C_RX_FIFO_LEVEL_BYTES_1,
        .isClockStretchingEnabled = true,
        .i2cClk                   = I2C_CLOCK_MHZ,
    },
};

/*
 *  ======== I2C_config ========
 */
const I2C_Config I2C_config[CONFIG_I2C_COUNT] = {
    /* CONFIG_I2C_CONTROLLER */
    /* LaunchPad I2C */
    {.object     = &I2CMSPM0Objects[CONFIG_I2C_0],
        .hwAttrs = &I2CMSPM0HWAttrs[CONFIG_I2C_0]},
};

const uint_least8_t CONFIG_I2C_CONST = CONFIG_I2C_0;
const uint_least8_t I2C_count        = CONFIG_I2C_COUNT;

2. 顶层配置常量(句柄索引)

下面这些通常来自 ti_drivers_config.h / SysConfig,用于把"逻辑名"映射成数组下标。

c 复制代码
/*
 *  ======== I2C ========
 */
extern const uint_least8_t CONFIG_I2C_CONTROLLER_CONST;
#define CONFIG_I2C_0 0

/*
 *  ======== I2C ========
 */
extern const uint_least8_t CONFIG_I2C_TARGET_CONST;
#define CONFIG_I2C_TARGET_0 0
#define CONFIG_TI_DRIVERS_I2C_COUNT 1
  • CONFIG_I2C_0 / CONFIG_I2C_TARGET_0数组索引(0 表示第 1 个实例)。
  • CONFIG_TI_DRIVERS_I2C_COUNT:I2C 实例数量(这里是 1,指 controller 侧的数量;target 侧有自己单独的 CONFIG_I2CTARGET_COUNT)。

3. I2C 速率/比特率宏

c 复制代码
#include <ti/drivers/I2C.h>

/* CONFIG_I2C_TARGET max speed (supported by all components) */
#define CONFIG_I2C_TARGET_MAXSPEED (400U) /* kbps */
#define CONFIG_I2C_TARGET_MAXBITRATE ((I2C_BitRate) I2C_400kHz)
  • CONFIG_I2C_TARGET_MAXSPEED:更像是"文档级别的能力描述"(单位 kbps)。
  • CONFIG_I2C_TARGET_MAXBITRATE:实际给 TI-Drivers 用的枚举值(这里是 400kHz)。

4. 外设实例、中断号、PinMux(最关键)

这一段把硬件资源"起别名",供后面的 HWAttrs 引用。

4.1 I2C0(Controller)

c 复制代码
#define I2C0_INST I2C0
#define I2C0_INST_IRQHandler I2C0_IRQHandler
#define I2C0_INST_INT_IRQN I2C0_INT_IRQn

#define GPIO_I2C0_SDA_PIN (28)
#define GPIO_I2C0_IOMUX_SDA (IOMUX_PINCM3)
#define GPIO_I2C0_IOMUX_SDA_FUNC IOMUX_PINCM3_PF_I2C0_SDA

#define GPIO_I2C0_SCL_PIN (31)
#define GPIO_I2C0_IOMUX_SCL (IOMUX_PINCM6)
#define GPIO_I2C0_IOMUX_SCL_FUNC IOMUX_PINCM6_PF_I2C0_SCL
  • I2C0_INST:指向硬件寄存器基址(MSPM0 的 DriverLib 风格)。
  • I2C0_INST_INT_IRQN:NVIC 中断号。
  • GPIO_I2C0_IOMUX_*:IOMUX 的 PinCM 寄存器(决定某个管脚复用为 I2C SDA/SCL)。
  • GPIO_I2C0_*_PIN:TI GPIO 驱动里的"pin index"(用于 GPIO driver 层)。

4.2 I2C1(Target)

c 复制代码
#define I2C1_INST I2C1
#define I2C1_INST_IRQHandler I2C1_IRQHandler
#define I2C1_INST_INT_IRQN I2C1_INT_IRQn

#define GPIO_I2C1_SDA_PIN (35)
#define GPIO_I2C1_IOMUX_SDA (IOMUX_PINCM16)
#define GPIO_I2C1_IOMUX_SDA_FUNC IOMUX_PINCM16_PF_I2C1_SDA

#define GPIO_I2C1_SCL_PIN (34)
#define GPIO_I2C1_IOMUX_SCL (IOMUX_PINCM15)
#define GPIO_I2C1_IOMUX_SCL_FUNC IOMUX_PINCM15_PF_I2C1_SCL

同理:这里把 Target 侧 挂在 I2C1,引脚也与 I2C0 不同。


5. I2CTarget(从机)配置

c 复制代码
#include <ti/drivers/I2CTarget.h>
#include <ti/drivers/i2ctarget/I2CTargetMSPM0.h>

#define CONFIG_I2CTARGET_COUNT 1

I2CTargetMSPM0_Object I2CTargetMSPM0Objects[CONFIG_I2CTARGET_COUNT];

const I2CTargetMSPM0_HWAttrs I2CTargetMSPM0HWAttrs[CONFIG_I2CTARGET_COUNT] = {
    {
        .i2c         = I2C1_INST,             /* 选择 I2C 硬件实例:I2C1 */
        .intNum      = I2C1_INST_INT_IRQN,    /* 对应 NVIC IRQn */
        .intPriority = (~0),                 /* 中断优先级:(~0) 通常表示"使用默认/最低/不配置",取决于驱动实现 */

        .sdaPincm    = GPIO_I2C1_IOMUX_SDA,   /* SDA 的 PinCM 寄存器 */
        .sdaPinIndex = GPIO_I2C1_SDA_PIN,    /* SDA 的 GPIO pin index */
        .sdaPinMux   = GPIO_I2C1_IOMUX_SDA_FUNC, /* SDA 复用功能选择 */

        .sclPincm    = GPIO_I2C1_IOMUX_SCL,
        .sclPinIndex = GPIO_I2C1_SCL_PIN,
        .sclPinMux   = GPIO_I2C1_IOMUX_SCL_FUNC,

        .clockSource                 = DL_I2C_CLOCK_BUSCLK,  /* I2C 外设时钟源:BUSCLK */
        .clockDivider                = DL_I2C_CLOCK_DIVIDE_1,/* 时钟分频 */
        .txIntFifoThr                = DL_I2C_TX_FIFO_LEVEL_BYTES_1, /* TX FIFO 中断阈值 */
        .rxIntFifoThr                = DL_I2C_RX_FIFO_LEVEL_BYTES_1, /* RX FIFO 中断阈值 */
        .isClockStretchingEnabled    = true, /* Target 侧常用:允许时钟拉伸,给软件处理时间 */
        .isAnalogGlitchFilterEnabled = false /* 模拟毛刺滤波:根据板级/线长/噪声情况决定 */
    },
};

const I2CTarget_Config I2CTarget_config[CONFIG_I2CTARGET_COUNT] = {
    {
        .object  = &I2CTargetMSPM0Objects[CONFIG_I2C_TARGET_0],
        .hwAttrs = &I2CTargetMSPM0HWAttrs[CONFIG_I2C_TARGET_0]
    },
};

const uint_least8_t I2CTarget_count = CONFIG_I2CTARGET_COUNT;

5.1 为什么 .object.hwAttrs 要分开?

  • .hwAttrs硬件属性(寄存器基址、引脚、中断等),基本是"只读常量"。
  • .object运行态对象 (驱动内部状态、锁、缓冲等),由驱动在 *_open() 时初始化。

这种设计能让一个驱动支持多个实例:每个实例一份 object + 一份 hwAttrs。

5.2 时钟拉伸(Clock Stretching)要不要开?

  • Target 侧建议默认开:主机可能连续读/写;如果回调/处理不够快,拉伸 SCL 能避免丢字节。
  • 但如果主机不允许拉伸或对拉伸敏感,就要谨慎(看主机 I2C 控制器/驱动是否容忍)。

6. I2C Controller(主机)配置

c 复制代码
#include <ti/drivers/I2C.h>
#include <ti/drivers/i2c/I2CMSPM0.h>

#define CONFIG_I2C_COUNT 1

I2CMSPM0_Object I2CMSPM0Objects[CONFIG_I2C_COUNT];

const I2CMSPM0_HWAttrs I2CMSPM0HWAttrs[CONFIG_I2C_COUNT] = {
    {
        .i2c         = I2C0_INST,            /* 选择 I2C0 作为 controller */
        .intNum      = I2C0_INST_INT_IRQN,
        .intPriority = (~0),

        .sdaPincm    = GPIO_I2C0_IOMUX_SDA,
        .sdaPinIndex = GPIO_I2C0_SDA_PIN,
        .sdaPinMux   = GPIO_I2C0_IOMUX_SDA_FUNC,

        .sclPincm    = GPIO_I2C0_IOMUX_SCL,
        .sclPinIndex = GPIO_I2C0_SCL_PIN,
        .sclPinMux   = GPIO_I2C0_IOMUX_SCL_FUNC,

        .clockSource              = DL_I2C_CLOCK_BUSCLK,
        .clockDivider             = DL_I2C_CLOCK_DIVIDE_1,
        .txIntFifoThr             = DL_I2C_TX_FIFO_LEVEL_BYTES_1,
        .rxIntFifoThr             = DL_I2C_RX_FIFO_LEVEL_BYTES_1,
        .isClockStretchingEnabled = true,    /* Controller 也可支持拉伸(对端拉伸时能正确等待) */
        .i2cClk                   = I2C_CLOCK_MHZ /* 这里通常是"输入时钟(MHz)"或派生时钟配置常量,供驱动计算时序 */
    },
};

const I2C_Config I2C_config[CONFIG_I2C_COUNT] = {
    {
        .object  = &I2CMSPM0Objects[CONFIG_I2C_0],
        .hwAttrs = &I2CMSPM0HWAttrs[CONFIG_I2C_0]
    },
};

const uint_least8_t I2C_count = CONFIG_I2C_COUNT;

i2cControllerThread

此处连接了IMU

c 复制代码
/*
 *  ======== i2cControllerThread ========
 */
void *i2cControllerThread(void *arg0) {
    int8_t i;
    I2C_Handle i2cHandle;
    I2C_Params i2cParams;
    I2C_Transaction i2cTransaction;

    I2C_Params_init(&i2cParams);
    i2cParams.bitRate = I2C_100kHz;
    i2cHandle         = I2C_open(CONFIG_I2C_0, &i2cParams);
    if (i2cHandle == NULL) {
        Display_printf(g_display, 0, 0, "Error Initializing I2C\n");
        while (1) {
        }
    } else {
        Display_printf(g_display, 0, 0, "I2C Initialized!\n");
    }

    Display_printf(g_display, 0, 0, "Starting the i2ccontroller example\n");


    /* Common I2C transaction setup */
    i2cTransaction.writeBuf   = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf    = rxBuffer;
    i2cTransaction.readCount  = 0;

    /*
     * Determine which I2C sensors are present by querying known I2C
     * target addresses.
     */
    for (i = TMP_COUNT - 1; i >= 0; i--) {
        i2cTransaction.targetAddress = sensors[i].address;
        txBuffer[0]                  = sensors[i].resultReg;

        if (I2C_transfer(i2cHandle, &i2cTransaction)) {
            targetAddress = sensors[i].address;
            Display_printf(g_display, 0, 0,
                "Detected TMP%s sensor with target"
                " address 0x%x\n",
                sensors[i].id, sensors[i].address);
        } else {
            i2cErrorHandler(&i2cTransaction);
        }
    }

    /* If we never assigned a target address */
    if (targetAddress == 0) {
        Display_printf(g_display, 0, 0, "Failed to detect a sensor!\n");
        I2C_close(i2cHandle);
        while (1) {
        }
    }

    Display_printf(g_display, 0, 0, "\nUsing last known sensor for samples.");
    i2cTransaction.targetAddress = targetAddress;


    while (1) {
           sleep(1);
    /* If the detected sensor is QMI8658A, read WHO_AM_I and Revision ID */
    if (targetAddress == 0x6A) {
        i2cTransaction.targetAddress = targetAddress;

        /* Read WHO_AM_I (reg 0x00) using write-then-read sequence */
        txBuffer[0] = 0x00;
        i2cTransaction.writeCount = 1;
        i2cTransaction.readCount = 1;
        if (!I2C_transfer(i2cHandle, &i2cTransaction)) {
            i2cErrorHandler(&i2cTransaction);
        } else {
            Display_printf(g_display, 0, 0, "QMI8658A WHO_AM_I: 0x%02x\n", rxBuffer[0]);
        }

        /* Read Revision ID (reg 0x01) using write-then-read sequence */
        txBuffer[0] = 0x01;
        i2cTransaction.writeCount = 1;
        i2cTransaction.readCount = 1;
        if (!I2C_transfer(i2cHandle, &i2cTransaction)) {
            i2cErrorHandler(&i2cTransaction);
        } else {
            Display_printf(g_display, 0, 0, "QMI8658A Revision ID: 0x%02x\n", rxBuffer[0]);
        }
    }
    }
}

初始化 I2C(Controller/主机)

  • I2C_Params_init(&i2cParams);
  • i2cParams.bitRate = I2C_100kHz;:把总线速率设为 100kHz
  • I2C_open(CONFIG_I2C_0, &i2cParams);:打开在 SysConfig 里配置的 I2C0(主机侧)。失败就打印并死循环。

准备一个通用的 I2C 事务结构

I2C_Transaction

  • i2cTransaction.writeBuf = txBuffer; writeCount = 1;
  • i2cTransaction.readBuf = rxBuffer; readCount = 0;
  • 这意味着默认事务是"写 1 字节、读 0 字节"(常用于探测:只要地址 ACK 就算设备存在)。

探测传感器是否存在(靠 ACK 判断)

  • sensors[] 里目前只有一个:地址 0x6A(标识字符串 "QMI8658A")
  • 循环里做:
  1. i2cTransaction.targetAddress = sensors[i].address;
  2. txBuffer[0] = sensors[i].resultReg;(这里是 0x00)
  3. 调用 I2C_transfer(...)
  • 因为 readCount = 0,所以这次 transfer 实际上就是"向 0x6A 写 1 个字节(0x00)"。如果对方存在并 ACK,就认为检测到了设备,并把 targetAddress 记下来。

若没探测到任何设备就退出

  • targetAddress == 0 表示没找到(因为静态变量默认 0,且只有成功时才赋值为 0x6A)
  • 会 I2C_close(i2cHandle); 然后死循环。

主循环:每秒读取两个寄存器(WHO_AM_I 和 Revision)

  • while(1) { sleep(1); ... }
  • 仅当 targetAddress == 0x6A 才执行读取:
    读 WHO_AM_I:
    txBuffer[0]=0x00; writeCount=1; readCount=1;
    I2C_transfer(...):这是典型的 write-then-read(先写寄存器地址,再重复起始读回 1 字节)
    打印 rxBuffer[0]
  • 读 Revision:
    txBuffer[0]=0x01; writeCount=1; readCount=1;
    同样 transfer 并打印

错误处理

  • 任何 I2C_transfer 失败都会走 i2cErrorHandler(&i2cTransaction);
  • 它根据 transaction->status 打印 timeout、NACK、bus busy 等具体原因。
相关推荐
rosemary5128 小时前
MSPM0G3507 ADC
ti·mspm0
高旭的旭1 个月前
CCS编译速度优化
ti·环境搭建·ccs
hazy1k1 个月前
MSPM0L1306 从零到入门:第七章 通用定时器(GPTIM) —— 成为时间的主宰
stm32·单片机·嵌入式硬件·mcu·物联网·esp32·ti
hazy1k2 个月前
MSPM0L1306 从零到入门:第二章 GPIO 从入门到精通 —— 点亮你的第一颗LED
stm32·单片机·嵌入式硬件·esp32·ti·mspm0
一知半解的大飞3 个月前
TI CCS软件安装
ti·ccs·mspm0·sysconfig工具
昔时扬尘处5 个月前
【C2000】C2000例程使用介绍
ti·ccs·c2000·c2000ware sdk·实时控制mcu
toradexsh6 个月前
Yocto meta-toradex-security layer 使用 TI AM62 安全启动功能
linux·安全·arm·ti·am62
菜菜why6 个月前
MSPM0G3507学习笔记(一) 重置版:适配逐飞库的ti板环境配置
笔记·学习·电赛·嵌入式软件·mspm0
诗丶远方的田筠8 个月前
TI dsp FSI (快速串行接口)
ti·dsp·fsi·快速串行接口