ZHCAF21A February   2025  – August 2025 MSPM0C1105 , MSPM0C1106 , MSPM0G3507

 

  1.   1
  2. 1设计说明
  3. 2所需外设
  4. 3设计步骤
  5. 4设计注意事项
  6. 5软件流程图
  7. 6器件配置
  8. 7应用代码
  9. 8移植指南
  10. 9修订历史记录
  11.   商标

应用代码

缓冲器、计数器、枚举和标志的初始化如下所示。要更改 I2C 使用的特定值和 SPI 最大数据包大小,请修改文档开头的 #defines,如以下代码块所示。

#include "ti_msp_dl_config.h"

/* Maximum size of packet */
#define MAX_PACKET_SIZE      (4)

/* Data sent to Controller in response to Read transfer */
uint8_t gSPITxPacket[MAX_PACKET_SIZE] = {0x00};
uint8_t gI2CRxPacket[MAX_PACKET_SIZE];                               /* Data received from Controller during a Write transfer */
uint8_t gSPIRxData[MAX_PACKET_SIZE];

/* Counters for I2C RX & TX */
uint32_t gI2CTxCount;
uint32_t gI2CRxCount;

/* Counters for SPI RX & TX */
uint32_t gSPIRxCount;

/* Variable used to skip false I2C Trigger when first sending a message */
uint32_t count_skip = 0;

enum error_codes{
    NO_ERROR = 0,
    DATA_BUFFER_OVERFLOW,
    I2C_TARGET_TXFIFO_UNDERFLOW,
    I2C_TARGET_RXFIFO_OVERFLOW,
    I2C_TARGET_ARBITRATION_LOST,
    I2C_INTERRUPT_OVERFLOW
};

/* Indicates status of Bridge */
enum BridgeStates {
    I2C_RX_STATE = 0,
    SPI_TX_STATE,
    SPI_RX_STATE,
    I2C_TX_STATE
} gBridgeStates;

uint8_t gErrorStatus = NO_ERROR;

/* Flags */
bool gSpiTxReady = false;                                                   /* Flag to start SPI transfer */
bool gSpiTxOngoing = false;                                                 /* Flag to indicate SPI transfer Ongoing*/
bool gSpiRxDone = false;                                                    /* Flag to indicate SPI data has been received */
bool gSpiRxOngoing = false;                                                 /* Flag to indicate SPI data is being receive */
bool gI2cTxDone = false;                                                    /* Flag to start SPI transfer */

应用代码的主体相对较短。首先,器件和外设被初始化。然后,在开始传输之前处于空闲状态的 SPI TX 发生延迟,同时计数器和标志值也被初始化。接下来,会启用中断和事件,并运行包含桥接函数的主循环。

int main(void)
{
    SYSCFG_DL_init();

    /* Initialize variables to send data inside TX ISR */
    gI2CTxCount = 0;

    /* Initialize variables to receive data inside RX ISR */
    gI2CRxCount = 0;

    /* Initialize variables to receive data inside RX ISR */
    gSPIRxCount = 0;

    // Setting flags to default values
    gSpiTxReady = false;
    gSpiRxDone = false;

    /* Enabling Interrupts on I2C & SPI Modules */
    NVIC_EnableIRQ(I2C_INST_INT_IRQN);
    NVIC_EnableIRQ(SPI_INST_INT_IRQN);
    while (1) {
        bridge();
    }
}

桥接器有四种状态。第一种状态侧重于桥接器 I2C 目标器件接收数据。第二种状态在通过桥接器 SPI 控制器发送 I2C 目标器件接收到的数据时发生。然后,出现第三种状态,SPI 控制器等待来自外设的数据;最终进入第四种状态,在这种状态下,桥接 I2C 目标器件等待发送请求并从 SPI 外设发送数据。

void bridge(){
    switch (gBridgeStates) {
        case I2C_RX_STATE:
            if (gSpiTxReady){
                gBridgeStates = SPI_TX_STATE;
            }
            else {
                break;
            }
        case SPI_TX_STATE:
            gSpiTxReady = false;
            for(int i = 0; i < gI2CRxCount; i++){
                /* Transmit data out via SPI and wait until transfer is complete */
                DL_SPI_transmitDataBlocking8(SPI_INST, gSPITxPacket[i]);
            }
            gSpiTxOngoing = false;
            gBridgeStates = SPI_RX_STATE;
            break;
        case SPI_RX_STATE:
            if(gSpiRxDone){
                gSPIRxCount = 0;
                gBridgeStates = I2C_TX_STATE;
            }
            break;
        case I2C_TX_STATE:
            if(gI2cTxDone){
                gI2cTxDone = false;
                gBridgeStates = I2C_RX_STATE;
            }
            break;
        default:
            break;
    }
}

此代码的下一段是 I2C IRQ 处理程序。此代码用于处理桥接 I2C 目标中断情况。当挂起中断是检测到的 I2C 启动条件时,计数器变量和标志将被设置为默认值。当挂起中断表示 I2C RX FIFO 有数据可用时,如果还有空间,接收到的值将保存在 I2C RX 缓冲区中。如果没有更多的空间,接收到的值会被忽略。当挂起中断是 I2C TX FIFO 触发信号时,跳过计数器会增加并通过 I2C 发送数据,直至达到最大长度。如果 I2C TX 计数达到最大数据包计数且计数跳过计数器大于 1(假设来自 I2C 目标的第一个发送数据是 false 触发并且已经发生),则 I2C Tx“Done”标志变为 true。然后,如果桥接器检测到任何错误,则错误代码将通过桥接器 I2C 目标进行传输。

当挂起中断是 I2C 停止条件时,器件会检查是否接收到数据;如果为 true(I2C 数据接收标志为 true),接收到的数据缓冲器将存储在发送数据缓冲器中,SPI TX“ready”标志设置为 true。如果未收到任何 I2C 数据,器件不会发送任何内容。该 ISR 还可处理 I2C 错误中断,方法是向错误状态变量(TXFIFO Underflow、RXFIFO Overflow、Target Arbitration Lost 和 Interrupt Overflow)分配适当的错误代码。

void I2C_INST_IRQHandler(void)
{
    static bool gI2CRxDone = false;     // Flag that indicates I2C data received
    switch (DL_I2C_getPendingInterrupt(I2C_INST)) {
        case DL_I2C_IIDX_TARGET_START:
            /* Initialize (resets) RX or TX after Start condition is received */
            gI2CTxCount = 0;
            gI2CRxCount = 0;
            gI2CRxDone   = false;
            /* Flush TX FIFO to refill it */
            DL_I2C_flushTargetTXFIFO(I2C_INST);
            break;
        case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
            /* Store received data in buffer */
            gI2CRxDone = true;
            while (DL_I2C_isTargetRXFIFOEmpty(I2C_INST) != true) {
                if(gI2CRxCount < MAX_PACKET_SIZE){
                    gI2CRxPacket[gI2CRxCount++] = DL_I2C_receiveTargetData(I2C_INST);
                }else{
                    /* Prevent overflow and just ignore data */
                    DL_I2C_receiveTargetData(I2C_INST);
                    gErrorStatus = DATA_BUFFER_OVERFLOW;
                }
            }
            break;
        case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER:                    // Restarts the flag
                /* Fill TX FIFO if there are more bytes to send */
                if (gI2CTxCount < MAX_PACKET_SIZE) {
                    count_skip += 1;
                    gI2CTxCount += DL_I2C_fillTargetTXFIFO(I2C_INST, &gSPIRxData[gI2CTxCount], (MAX_PACKET_SIZE - gI2CTxCount));
                    if(gI2CTxCount >= MAX_PACKET_SIZE && count_skip > 1){
                        gI2cTxDone = true;
                    }
                }
                if(gErrorStatus != NO_ERROR)
                {
                    /* Fill FIFO with error status after sending latest received
                     * byte */
                    while (DL_I2C_transmitTargetDataCheck(I2C_INST, gErrorStatus) != false);
                }
            break;
        case DL_I2C_IIDX_TARGET_STOP:
            /* If data was received, store it in SPI TX buffer */
            if (gI2CRxDone == true) {
                for (uint16_t i = 0; (i < gI2CRxCount) && (i < MAX_PACKET_SIZE); i++) {
                    gSPITxPacket[i] = gI2CRxPacket[i];
                    DL_I2C_flushTargetTXFIFO(I2C_INST);
                }
                gI2CRxDone = false;
                /* Set flag to indicate data ready for SPI TX */
                gSpiTxReady = true;
            }
            break;
        case DL_I2C_IIDX_TARGET_TXFIFO_UNDERFLOW:
            gErrorStatus = I2C_TARGET_TXFIFO_UNDERFLOW;
            break;
        case DL_I2C_IIDX_TARGET_RXFIFO_OVERFLOW:
            gErrorStatus = I2C_TARGET_RXFIFO_OVERFLOW;
            break;
        case DL_I2C_IIDX_TARGET_ARBITRATION_LOST:
            gErrorStatus = I2C_TARGET_ARBITRATION_LOST;
            break;
        case DL_I2C_IIDX_INTERRUPT_OVERFLOW:
            gErrorStatus = I2C_INTERRUPT_OVERFLOW;
            break;
        default:
            break;
    }
}

此子系统代码中的最后一段代码是 SPI IRQ 处理程序。SPI IRQ 处理程序会保存接收到的数据,并在 SPI 发送数据时设置“ongoing”传输标志。当 SPI RX 中断挂起时,器件将接收到的数据保存到 SPI RX 缓冲区,将 SPI RX“Ongoing”标志变为 true,并在 SPI RX 计数器达到最大长度时设置 SPI RX“Done”标志。

void SPI_INST_IRQHandler(void)
{
    switch (DL_SPI_getPendingInterrupt(SPI_INST)) {
        case DL_SPI_IIDX_RX:
            /* Read RX FIFO */
            if(gSPIRxCount < MAX_PACKET_SIZE){
                gSpiRxOngoing = true;
                gSPIRxData[gSPIRxCount++] = DL_SPI_receiveData8(SPI_INST);
                if(gSPIRxCount >= MAX_PACKET_SIZE){
                    gSpiRxDone = true;
                    gSpiRxOngoing = false;
                }
            }
            break;
        case DL_SPI_IIDX_TX:
            gSpiTxOngoing = true;
            break;
        default:
            break;
    }
}