器件型号: MSP430FR5962
我的 μ I²C 通信遇到了问题、从器件正确初始化、但当我尝试读取多个字节时、通信随机停止、SCL 和 SDA 线路都一直处于低电平。 单字节读取始终有效、没有任何问题、但只要我执行多字节读取、总线就会在事务期间意外挂起。 似乎从器件未释放线路、或者主器件在等待字节就绪情况时卡住、从而导致总线保持繁忙状态、直到复位。 我需要帮助了解 I²C I ² C 总线为何专门在多字节读取期间锁定、以及如何防止 SCL 和 SDA 被无限期拉至低电平。
#include <msp430.h>
#include <stdint.h>
#include <msp430fr5992.h>
/* Generic typedefs */
typedef unsigned char UINT8;
typedef unsigned short UINT16;
/* -----------------------
GENERIC DEFINITIONS
------------------------ */
#define DEVICE_ADDR_1 0x42
#define DEVICE_ADDR_2 0x44
#define DEVICE_ADDR_3 0x46
#define REG_READ_FIFO 0x01
UINT8 ReceiveBuffer[20] = {0};
UINT8 TransmitBuffer[20] = {0};
UINT8 RXByteCtr = 0, TXByteCtr = 0;
UINT8 ReceiveIndex = 0, TransmitIndex = 0;
UINT8 i2c_busy = 0;
volatile UINT8 *i2c_tx_ptr, *i2c_rx_ptr;
/* ============================================================
I2C MASTER INITIALIZATION
============================================================ */
void clock_init( void )
{
PM5CTL0 &= ~LOCKLPM5;
CSCTL0_H = CSKEY_H ; // Unlock CS registers
CSCTL1 = DCOFSEL_4 + DCORSEL ; // Set DCO to 16MHz
CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__HFXTCLK ; // Set set ACLK = LFXT1;MCLK = DCO
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1 ; // Set all dividers to 1
CSCTL4 = HFFREQ_2 | HFXTDRIVE_3;
CSCTL4 &= ~HFXTOFF ;
CSCTL0_H = 0;
}
void init_i2c_master(void)
{
/* Configure pins P7.0 = SDA, P7.1 = SCL (eUSCI_B2) */
P7SEL0 |= BIT0 | BIT1;
P7SEL1 &= ~(BIT0 | BIT1);
UCB2CTLW0 = UCSWRST;
UCB2CTLW0 |= UCSSEL__SMCLK | UCMODE_3 | UCMST | UCSYNC | UCSWRST;
UCB2BRW = 100;
UCB2I2CSA = DEVICE_ADDR_1; /* default – will be changed per call */
UCB2IFG = 0;
UCB2CTLW0 &= ~UCSWRST;
}
/* Simple memcpy */
void CopyArray(UINT8 *source, UINT8 *dest, UINT8 count)
{
for (UINT8 i = 0; i < count; i++)
dest[i] = source[i];
}
/* Timeouts */
#define I2C_TIMEOUT_LOOPS 30000u
#define I2C_POST_STOP_DELAY_CYCLES 0u
static int i2c_wait_for_ifg(UINT16 mask)
{
UINT16 t = I2C_TIMEOUT_LOOPS;
while (!(UCB2IFG & mask))
{
if (--t == 0) return 0;
}
return 1;
}
static int i2c_wait_for_ctl_clear(UINT16 mask)
{
UINT16 t = I2C_TIMEOUT_LOOPS;
while (UCB2CTLW0 & mask)
{
if (--t == 0) return 0;
}
return 1;
}
static void i2c_issue_stop_and_wait(void)
{
UCB2CTLW0 |= UCTXSTP;
i2c_wait_for_ctl_clear(UCTXSTP);
__delay_cycles(I2C_POST_STOP_DELAY_CYCLES);
}
/* ============================================================
GENERIC I2C WRITE
============================================================ */
UINT8 i2c_master_write(UINT8 dev, UINT8 reg, UINT8 *data, UINT8 count)
{
if (!i2c_wait_for_ctl_clear(UCTXSTP)) return 0;
UCB2I2CSA = dev;
UCB2IFG = 0;
UCB2CTLW0 |= UCTR | UCTXSTT;
if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
if (UCB2IFG & UCNACKIFG) { i2c_issue_stop_and_wait(); return 0; }
UCB2TXBUF = reg;
if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
if (UCB2IFG & UCNACKIFG) { i2c_issue_stop_and_wait(); return 0; }
for (UINT8 i = 0; i < count; i++)
{
UCB2TXBUF = data[i];
if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
if (UCB2IFG & UCNACKIFG) { i2c_issue_stop_and_wait(); return 0; }
}
i2c_issue_stop_and_wait();
return 1;
}
/* ============================================================
GENERIC I2C READ
============================================================ */
UINT8 i2c_master_read(UINT8 dev, UINT8 reg, UINT8 count, UINT8 *rx_buf)
{
if (!i2c_wait_for_ctl_clear(UCTXSTP)) return 0;
UCB2I2CSA = dev;
UCB2IFG = 0;
UCB2CTLW0 |= UCTR | UCTXSTT;
if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
if (UCB2IFG & UCNACKIFG) { i2c_issue_stop_and_wait(); return 0; }
UCB2TXBUF = reg;
if (!i2c_wait_for_ifg(UCTXIFG)) { i2c_issue_stop_and_wait(); return 0; }
if (UCB2IFG & UCNACKIFG) { i2c_issue_stop_and_wait(); return 0; }
UCB2CTLW0 &= ~UCTR;
UCB2CTLW0 |= UCTXSTT;
if (!i2c_wait_for_ctl_clear(UCTXSTT)) { i2c_issue_stop_and_wait(); return 0; }
if (count == 1) UCB2CTLW0 |= UCTXSTP;
for (UINT8 i = 0; i < count; i++)
{
if (!i2c_wait_for_ifg(UCRXIFG)) { i2c_issue_stop_and_wait(); return 0; }
rx_buf[i] = UCB2RXBUF;
if (i == count - 2) UCB2CTLW0 |= UCTXSTP;
}
if (!i2c_wait_for_ctl_clear(UCTXSTP)) return 0;
return count;
}
/* ============================================================
MAIN LOOP (GENERIC VERSION)
============================================================ */
int main(void)
{
clock_init();
init_i2c_master();
UINT8 buf1[5], buf2[5], buf3[5];
while (1)
{
i2c_master_read(DEVICE_ADDR_1, REG_READ_FIFO, 5, buf1);
i2c_master_read(DEVICE_ADDR_2, REG_READ_FIFO, 5, buf2);
i2c_master_read(DEVICE_ADDR_3, REG_READ_FIFO, 5, buf3);
__delay_cycles(10000);
}
}

.