Other Parts Discussed in Thread: MSP430F5438, MSP430F5438A
Hi Folks,
I am seeing a problem with the F28027 LaunchPad I2C That makes me think I am misunderstanding how the I2C should work when transmitting in slave-transmitter mode.
My configuration for the I2C is as follows:
/* Setup I/O lines. */ GPIO_setDirection(gpio, (GPIO_Number_e)GPIO_SCL_LINE_NUMBER, GPIO_Direction_Input); /* GPIO 33 for clock. */ GPIO_setPullUp (gpio, (GPIO_Number_e)GPIO_SCL_LINE_NUMBER, GPIO_PullUp_Enable); GPIO_setMode (gpio, (GPIO_Number_e)GPIO_SCL_LINE_NUMBER, GPIO_33_Mode_SCLA); GPIO_setDirection(gpio, (GPIO_Number_e)GPIO_SDA_LINE_NUMBER, GPIO_Direction_Input); /* GPIO 28 for data. */ GPIO_setPullUp (gpio, (GPIO_Number_e)GPIO_SDA_LINE_NUMBER, GPIO_PullUp_Enable); GPIO_setMode (gpio, (GPIO_Number_e)GPIO_SDA_LINE_NUMBER, GPIO_28_Mode_SDDA); /* Initialise I2C bus peripheral. */ i2c->I2CSAR = 0U; /* Clear slave address. */ i2c->I2CMDR |= I2C_I2CMDR_FREE_BIT; /* Stop free run on breakpoint for debug breakpoints. */ i2c->I2CMDR &= ~I2C_I2CMDR_BC_BITS; /* Set bit count to 8 bits per byte. */ i2c->I2CMDR &= ~I2C_I2CMDR_MST_BIT; /* Select slave mode. */ i2c->I2COAR = 0x50; i2c->I2CPSC = 0x04U & I2C_I2CPSC_IPSC_BITS; /* Prescalar = 4, so module clock = 12Mhz. */ i2c->I2CCLKL = 0x0AU; /* T_low = T_mod * (ICCL + d) = 1.25 us. NB: Must be non-zero. */ i2c->I2CCLKH = 0x0AU; /* T_high = T_mod * (ICCH + d) = 1.25 us. NB: Must be non-zero. */ i2c->I2CIER |= (uint16_t)I2C_IntEn_NACK; /* Enable AAS, P, NACK and transmit and receive register ready interrupts. */ i2c->I2CIER |= (uint16_t)I2C_IntEn_Rx_Rdy; i2c->I2CIER |= (uint16_t)I2C_IntEn_Tx_Rdy; i2c->I2CIER |= (uint16_t)I2C_IntEn_Stop; i2c->I2CIER |= (uint16_t)I2C_IntEn_Slave_Addr; i2c->I2CMDR |= I2C_I2CMDR_IRS_BIT; /* Enable I2C. */ i2c->I2CSTR = 0xFFFFU; /* Clear the I2C status register. */ /* Configure I2C interrupt. */ PIE_registerPieIntHandler(pie, PIE_GroupNumber_8, PIE_SubGroupNumber_1, (intVec_t)&i2c_isr); PIE_enableInt(pie, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); CPU_enableInt(cpu, CPU_IntNumber_8);
The ISR for the I2C is currently very simple. It does nothing with received data except read it out of the receive register and when transmitting it should place some dummy data (0x55h) in the transmit register when a repeated start uses a read bit and every time the register becomes empty after that, until the master sends a stop.
__interrupt static void i2c_isr (void) {
I2C_Obj * i2c = (I2C_Obj *)i2cHandle;
I2C_IntSource_e source = (I2C_IntSource_e)i2c->I2CISRC;
I2C_Status_e status = (I2C_Status_e)i2c->I2CSTR;
volatile uint_least8_t d = 0U;
if (source == I2C_IntSrc_Slave_Addr) {
flags.direction = ((status & I2C_Status_Slave_Dir) > 0) ? I2C_Direction_Read : I2C_Direction_Write; /* Record the R/W# bit. */
if (!flags.start) { /* Check if this is the first START or if it is a REPEATED START. */
flags.start = true; /* Flag start of communication. */
if (flags.direction == I2C_Direction_Read) {
asm(" ESTOP0"); /* Halt if START has READ bit. */
}
} else if (flags.direction == I2C_Direction_Read) {
i2c->I2CDXR = 0x0055U; /* Transmit first byte after REPEATED START. */
} else {
asm(" ESTOP0"); /* Halt if REPEATED START has WRITE bit. */
}
} else if (source == I2C_IntSrc_Rx_Rdy) {
d = i2c->I2CDRR; /* Clear the receive register. */
} else if (source == I2C_IntSrc_Tx_Rdy) {
i2c->I2CDXR == 0x0055U; /* Transmit some dummy data. */
} else if (source == I2C_IntSrc_NACK) {
asm(" ESTOP0"); /* Halt if NACK received. */
} else if (source == I2C_IntSrc_Stop) {
flags.start = false; /* End of the communication, reset flags. */
flags.direction = I2C_Direction_Write;
} else {
asm(" ESTOP0"); /* Incorrect interrupt source. */
}
PIE_clearInt(pie, PIE_GroupNumber_8); /* Set the PIEACK bit for the PIE group. */
return;
}
However, what actually happens, is the start and write portions of a communication works OK, as does the following repeated start, the first 0x55h is transmitted, but then the CLK line is held low indefinitely. The expected interrupt for Tx_Rdy after the first 0x55h is transmitted never seems to occur! So the Tx_Rdy, NACK, Stop and else branches of the ISR's if are never taken...
Have I misunderstood how the I2C works in slave transmitter mode? Maybe it is down to the BCM setting?
Thanks for any help!