This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/MSP430FR5989: Repeated start in I2C and receive only one byte

Part Number: MSP430FR5989

Tool/software: TI C/C++ Compiler

Hello,

I have a problem with receiving only one byte after a repeated start sequence. The easiest way to explain this is by example:

Working case, with STOP/START sequence

  1. Send START / W - set UCTXSTT and UCTR in UCBxCTLW0
  2. Send byte no 1
  3. Send byte no 2
  4. Send stop UCBxCTLW0  |= UCTXSTP
  5. Change mode to reading - clear UCTR in UCBxCTLW0
  6. Send START / R - set UCTXSTT and UCTXSTP in UCBxCTLW0
  7. Receive only one byte, after which MCU send NACK and STOP.

Non working case with repeated start sequence:

  1. Send START / W - set UCTXSTT and UCTR in UCBxCTLW0
  2. Send byte no 1
  3. Send byte no 2
  4. Change mode to reading - clear UCTR in UCBxCTLW0
  5. Send START / R - UCTXSTT and UCTXSTP in UCBxCTLW0
  6. Receive two bytes: the first one is ACKed and the second one is waiting for my move

I found a workaround for this problem, I am using UCASTPx mode 10b, which allows for automatic STOP generation after sending/receivng n-bytes. It looks like this:

  1. UCBxTBCNT = 0 (set counter to zero, what blocks auto STOP generation)
  2. Send START / W - set UCTXSTT and UCTR in UCBxCTLW0
  3. Send byte no 1
  4. Send byte no 2
  5. Change mode to reading - clear UCTR in UCBxCTLW0
  6. UCBxTBCNT = 0x01 ( set counter to 1  byte)
  7. Send START / R - UCTXSTT in UCBxCTLW0
  8. Receive only one byte, after which MCU send NACK and STOP.

My problems:

1. Why I2C doesn't work properly if i set UCTXSTT and UCTXSTP in repeated start mode?

2. The documentation contains a stipulation that modification of UCTBCNTx is possible only if UCSWRST is equal 1. I can not meet this condition because it will disable I2C and release SCL line, and repeated start become impossible. Do I have to worry about this stipulation?

Best regards,

Mateusz

  • Section 26.3.5.2.2 of the User's Guide says:

    A STOP condition is either generated by the automatic STOP generation or by setting the UCTXSTP bit. The next byte received from the slave is followed by a NACK and a STOP condition. This NACK occurs immediately if the eUSCI_B module is currently waiting for UCBxRXBUF to be read.

    So setting TXSTT and TXSTP at the same time is correct.

    The description of your code sounds OK. Apparently, the code does not actually do what you have described.

  • I've spent some time preparing the code that shows the case I am writing about. There are three cases:

    Case 1.

    After sending the command, I send a STOP. Then I set the flags UCTXSTT and UCTXSTP, which makes receiving only one byte. But because of the STOP slave "forgets" the command and send wrong answer.

    Case 2.

    After sending the command, I send repeated START. I receive the correct answer from slave, but MSP receiving two bytes.

    case 3.

    After sending the command, I send repeated START and STOP. I expected, that MSP send repeated start, and after receiving one byte send NACK and STOP. But MSP send first STOP and then START (not repeated START). 


    Here is code:

    void i2ctest(void) { volatile uint16_t tmp; prepareDevice(); /* Disable the USCI module and clears the other bits of control register */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) = UCSWRST; /* Clock prescaler - freq: 100KHz */ HWREG16(EUSCI_B1_BASE + OFS_UCBxBRW) = 80; /* Set slave address */ HWREG16(EUSCI_B1_BASE + OFS_UCBxI2CSA) = 0x64; /* UCCLTO_0 - Disable clock low time-out counter * UCASTP_1 - UCBCNTIFG is set with the byte counter reaching the threshold. * UCGLIT_0 - 50ns deglitch time */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW1) = UCCLTO_0 | UCASTP_1 | UCGLIT_0; /* * 7bit address * UCMST = Master mode * UCMODE_3 = I2C mode * UCSYNC = Synchronous mode * UCSSEL1, UCSSEL0 - clock source: SMCLK * UCTR Transmitter */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) |= UCMST + UCMODE_3 + UCSYNC | UCSSEL_3 | UCTR; /* Reset UCWRST bit to enable I2C module */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) &= ~(UCSWRST); /*Send start condition and wait for start/address sending complete */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) |= UCTXSTT; while (HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) & UCTXSTT); /* Send command to spi slave */ while (!(HWREG16(EUSCI_B1_BASE + OFS_UCBxIFG) & UCTXIFG0)); HWREG16(EUSCI_B1_BASE + OFS_UCBxTXBUF) = 0X02; while (!(HWREG16(EUSCI_B1_BASE + OFS_UCBxIFG) & UCTXIFG0)); switch (1) { case 1: /* Send stop and wait for sent*/ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) = (HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) & (~UCTR)) | UCTXSTP; while (HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) & UCTXSTP); /* Send start & stop */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) = (HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) & (~UCTR)) | UCTXSTT | UCTXSTP; break; case 2: /* Send repeated start */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) = (HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) & (~UCTR)) | UCTXSTT; break; case 3: /* Send repeated start and stop */ HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) = (HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) & (~UCTR)) | UCTXSTT | UCTXSTP; break; } while (!(HWREG16(EUSCI_B1_BASE + OFS_UCBxIFG) & UCRXIFG0)); HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) |= UCTXSTP; tmp = HWREG16(EUSCI_B1_BASE + OFS_UCBxRXBUF); while(1); }

  • The only difference between your code and driverlib's EUSCI_B_I2C_masterReceiveSingleByte() is that the latter uses two separate instructions to clear UCTR and to set UCTXSTT+UCTXSTP. I thought was just to be able to use "&=" and "|=", but your waveform shows that the hardware applies the TXSTP to the transmit transaction.

    So it appears when using a repeated start, you actually must change UCTR before TXSTP:

    	case 3:
    		/* Send repeated start and stop */
    		HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) &= ~UCTR;
    		HWREG16(EUSCI_B1_BASE + OFS_UCBxCTLW0) |= UCTXSTT | UCTXSTP;

**Attention** This is a public forum