ZHCAF20A February 2025 – August 2025 MSPM0G3507
缓冲器、计数器、枚举和标志的初始化如下所示。要更改 SPI 使用的特定值和最大 I2C 数据包大小,请修改文档开头的 #defines,如以下代码块所示。
#include "ti_msp_dl_config.h"
/* Delay for 5ms to ensure SPI TX is idle before starting transmission */
#define SPI_TX_DELAY (160000)
/*Define max packet sizes*/
#define MAX_PACKET_SIZE 4
/*SPI Buffers & Variables*/
uint8_t gSPITxData[MAX_PACKET_SIZE];
uint8_t gSPIRxData[MAX_PACKET_SIZE];
volatile uint8_t gSPIRxCount = 0; // Variable to track # of bytes SPI Received
/*I2C Controller Buffers & Variable*/
uint8_t gI2CTxData[MAX_PACKET_SIZE];
uint8_t gI2CRxData[MAX_PACKET_SIZE];
volatile uint8_t gI2CAddress = 0x48; // Target Address to communicate to
volatile uint8_t gI2CTxCount = 0; // Variable to track # of bytes I2C Transmitted
volatile uint8_t gI2CRxCount = 0; // Variable to track # of bytes I2C Received
volatile uint8_t rxTemp = 0;
/* Indicates status of Bridge */
enum BridgeStates {
SPI_RX_STATE = 0,
I2C_TX_STATE,
I2C_RX_STATE,
SPI_TX_STATE
} gBridgeStates;
/* Indicates status of I2C Controller */
enum I2cControllerStatus {
I2C_C_STATUS_IDLE = 0,
I2C_C_STATUS_TX_COMPLETE,
I2C_STATUS_RX_STARTED,
I2C_C_STATUS_RX_INPROGRESS,
I2C_STATUS_RX_COMPLETE
} gI2cControllerStatus;
void bridge(void);
应用代码的主体相对较短。首先,器件外设和中断被初始化。然后,在开始传输之前处于空闲状态的 SPI TX 发生延迟,同时状态和标志值也被初始化。接下来,具有桥接器功能的主循环将会运行。
int main(void)
{
SYSCFG_DL_init();
/* Activate Interrupts */
NVIC_ClearPendingIRQ(SPI_INST_INT_IRQN);
NVIC_EnableIRQ(SPI_INST_INT_IRQN);
NVIC_EnableIRQ(I2C_INST_INT_IRQN);
/* Optional delay to ensure SPI TX is idle before starting transmission */
delay_cycles(SPI_TX_DELAY);
/*Initial states*/
gBridgeStates = SPI_RX_STATE;
gI2cControllerStatus = I2C_C_STATUS_IDLE;
/* Start bridge */
while (1) {
bridge(); // Runs bridge
}
}桥接器有四种状态。第一个状态侧重于将数据从 SPI RX 缓冲器传输到 I2C TX 缓冲器,同时在 SPI 外设接收到最大封装大小后清除 SPI RX 缓冲器。第二种状态则是将数据从 I2C TX 缓冲器传输到 I2C 目标器件。然后,在第三种状态下,I2C 控制器会向 I2C 目标器件发送请求数据信号,并在重新收集数据后将 I2C RX 缓冲器传输到 SPI TX 缓冲器,同时清除 I2C RX 缓冲器。最后的状态则是以 SPI TX 缓冲器的内容填充 SPI 目标器件,等待 FIFO 变空(控制器请求获取数据),使 SPI RX 再次中断,然后重新启动桥接器。
void bridge(){
uint8_t i=0; uint8_t j=0;uint8_t k=0; // Setting counter variables
switch (gBridgeStates) {
case SPI_RX_STATE:
if (gSPIRxCount >= MAX_PACKET_SIZE){
// Storing data from SPI Buffer to message that is addressed to Bridge A
for(k = 0; k < MAX_PACKET_SIZE; k++){
gI2CTxData[k] = gSPIRxData[k];
gSPIRxData[k] = 0;
}
// Resetting gSPIRxCount variable
gSPIRxCount = 0;
gBridgeStates = I2C_TX_STATE;
}
else {
break;
}
case I2C_TX_STATE:
// Sending the I2C WRITE message to the 9724
gI2CTxCount = DL_I2C_fillControllerTXFIFO(I2C_INST, &gI2CTxData[0], MAX_PACKET_SIZE);
/* Send the packet to the target. This function will send Start + Stop automatically. */
while (!(DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_IDLE));
DL_I2C_startControllerTransfer(I2C_INST, gI2CAddress, DL_I2C_CONTROLLER_DIRECTION_TX, MAX_PACKET_SIZE);
/* Wait until the Controller sends all bytes AKA the I2C_C_STATUS_TX_COMPLETE to be true */
while (gI2cControllerStatus != I2C_C_STATUS_TX_COMPLETE) {
__WFE();
}
while (DL_I2C_getControllerStatus(I2C_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
gI2cControllerStatus = I2C_C_STATUS_IDLE;
gBridgeStates = I2C_RX_STATE; // Move to next Bridge stage
break;
case I2C_RX_STATE:
/* Add delay between transfers */
delay_cycles(1000);
/* Send a read request to Target */
gI2cControllerStatus = I2C_STATUS_RX_STARTED;
DL_I2C_startControllerTransfer(I2C_INST, gI2CAddress, DL_I2C_CONTROLLER_DIRECTION_RX, MAX_PACKET_SIZE);
/* Wait for all bytes to be received in interrupt */
while (gI2cControllerStatus != I2C_STATUS_RX_COMPLETE) {
__WFE();
}
while (DL_I2C_getControllerStatus(I2C_INST) &
DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
/* Waiting for I2C Rx buffer interrupt to happen AKA When expected package size
is received from I2C Target */
if(gI2CRxCount >= MAX_PACKET_SIZE){
// Extract the received bytes from the I2C read and store them in SPI buffer #2 (Tx)
for(j = 0; j < MAX_PACKET_SIZE; j++){
gSPITxData[j] = gI2CRxData[j];
gI2CRxData[j] = 0;
}
// Resetting gI2CRxCount variable
gI2CRxCount = 0;
gI2cControllerStatus = I2C_C_STATUS_IDLE;
gBridgeStates = SPI_TX_STATE; // Move to next Bridge stage
}
break;
case SPI_TX_STATE:
DL_SPI_fillTXFIFO8(SPI_INST, &gSPITxData[0], MAX_PACKET_SIZE);
while(!DL_SPI_isTXFIFOEmpty(SPI_INST));
DL_SPI_enableInterrupt(SPI_INST, DL_SPI_INTERRUPT_RX);
gBridgeStates = SPI_RX_STATE;
break;
}
}此示例的下一部分是 SPI IRQ 处理程序。本示例仅使用了一个中断:SPI RX。激活后,数据先存储在时间变量中,然后再存储在 SPI RX FIFO 缓冲器中。然后,如果 SPI RX 计数器小于最大封装大小,则 SPI RX 计数器会增加;否则,SPI RX FIFO 中断会被禁用。
void SPI_INST_IRQHandler(void)
{
switch (DL_SPI_getPendingInterrupt(SPI_INST)) {
case DL_SPI_IIDX_RX:
rxTemp = DL_SPI_receiveDataBlocking8(SPI_INST);
gSPIRxData[gSPIRxCount] = rxTemp;
if (gSPIRxCount >= MAX_PACKET_SIZE){
DL_SPI_disableInterrupt(SPI_INST, DL_SPI_INTERRUPT_RX);
}else {
gSPIRxCount++;
}
break;
default:
break;
}
}本示例中的最后一段代码是 I2C IRQ 处理程序。该示例中的两个中断分别是控制器 TX Done 和控制器 RX FIFO Trigger。触发 TX Done 后,I2C 控制器状态会更新为“TX 已完成”。当触发 RX FIFO Trigger 时,I2C 控制器状态会更新为“RX 进行中”;I2C RX 缓冲器会接收存储在 I2C RX FIFO 中的所有消息,并将 I2C 控制器状态设置为“I2C RX 完成”。
void I2C_INST_IRQHandler(void)
{
switch (DL_I2C_getPendingInterrupt(I2C_INST)) {
case DL_I2C_IIDX_CONTROLLER_TX_DONE:
gI2cControllerStatus = I2C_C_STATUS_TX_COMPLETE;
break;
case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
gI2cControllerStatus = I2C_C_STATUS_RX_INPROGRESS;
/* Receive all bytes from target */
while (DL_I2C_isControllerRXFIFOEmpty(I2C_INST) != true){
if(gI2CRxCount < MAX_PACKET_SIZE) {
gI2CRxData[gI2CRxCount++] = DL_I2C_receiveControllerData(I2C_INST);
}else{
DL_I2C_receiveControllerData(I2C_INST);
}
}
gI2cControllerStatus = I2C_STATUS_RX_COMPLETE;
break;
default:
break;
}
}