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.

I2C- MSP doesn't send data from UCB0TXBUF for 2nd byte to be sent

Other Parts Discussed in Thread: MSP430F2274, CC2500

Hello,

   I have to use I2C to communicate accelerometer -MMA8450 with MSP430F2274. I have to follow these steps for multiple byte READ-

1. Send slave address

2. Send register address I want to read (0x01)

3. Send a repeated START with slave address

4. Read data from accelerometer until STOP bit is sent.

The problem is- I can only finish Step 1. I send the slave address and receive an acknowledge from the device. But I cannot send the register address(of the accelerometer) from which I need to read the value. The data is not transmitted from the UCB0TXBUF when I enter the register address after the slave address is sent( from UCB0I2CSA) .

Can anyone find what is wrong with the code?? The code gets stuck at line " UCB0TXBUF = MSData;          // Load TX buffer-----------------------------2nd byte to be sent"

Thanks in advance.

  • girish KAMATH said:
      while(!(UCB0TXIFG & IFG2));                                               // wait for TX buffer to be empty

    You can be sure that TXIFG is set (and TXBUF is empty) when you set UCTXSTT and UCTR is set.

    girish KAMATH said:
      IFG2 &= ~UCB0TXIFG;                                                          // Clear USCI_B0 TX interrupt flag

    Don't! TXIFG is cleared as soon as you write to TXBUF or set TXSTP. It is unknown what happens when you manually clear it. It may mess-up the I2C state machine.

    girish KAMATH said:
      if(( UCB0STAT & UCNACKIFG) != 0)

    Right before this point, you should wait until UCTXSTT clears, indicating that the start byte has been sent and the ACK bit has been received (or not) (which won't happen unless you have written something to TXBUF, which you did).

    UCNACKIFG is only set after the start bit has been sent and the ACK bit has been received. However, UCTXIFG is set immediately at begin of the start byte, to allow seamless operation, even if is yet unknown whether the slave will answer at all.

    Where in your code do you actually check for the received bytes?

    'counter' must be declared volatile. PRxData too (actually, it is a volatile pointer to volatile data).

    girish KAMATH said:
        UCB0I2CSA = 0x38;                                                             // Slave addr reg for I2C with write

    Are you sure of this address? I2CSA is a 7 bit value without the R/W bit. be sure your slave really has address 0x38 (so the start byte will be 0x70 or 0x71). Else use 0x1c as slave address (resulting in 0x38/0x39 start byte)

    Finally, do you actually see the start byte on a scope? That means: do you have proper pull-up resistors on the SCL/SDA lines adn a common GND connection between master and slave?

  • Thanks for your response Jens

    Jens-Michael Gross said:
    Where in your code do you actually check for the received bytes?

    I have used the RX interrupt vector when I receive any data. But I never get the interrupt because I never get past the line of code which sends the 2nd byte containing register address of the slave which I want to read

    Jens-Michael Gross said:
       Are you sure of this address? I2CSA is a 7 bit value without the R/W bit. be sure your slave really has address 0x38 (so the start byte will be 0x70 or 0x71). Else use 0x1c as slave address (resulting in 0x38/0x39 start byte)

     I have included the write bit as well(Slave address is 0x1C). Do you mean I need to give I2CSA = 0x1C? If so,then how do I send the read/write bit? Read/write bit should be the 8th bit of the 1st byte sent when UCTXSTT is sent(making the 1st byte to be sent as 0x38). Isn't it correct ?

    Jens-Michael Gross said:
      Finally, do you actually see the start byte on a scope? That means: do you have proper pull-up resistors on the SCL/SDA lines adn a common GND connection between master and slave?

    (I have the pull up-resistors and common ground between master and slave)I am seeing the 1st byte sent on  the scope(with I2CSA = 0x38) and surprisingly the device acknowledges it(it sends a LOW on SDA after first 8 bits), but the clock stops after the 9th bit. i.e the register address within the slave(0x01) is not received by the slave (TXBUF does not send it).

  • girish KAMATH said:
    Do you mean I need to give I2CSA = 0x1C? If so,then how do I send the read/write bit?

    The R/W bit is automatically added by the USCI based on the UCTR bit. it takes the lower 7 bits of I2CSA as upper 7 bits of the start byte, and adds the inverted UCTR bit as LSB of the start byte.

    girish KAMATH said:
    and surprisingly the device acknowledges it(it sends a LOW on SDA after first 8 bits)

    To send a stop bit, the master has to make a low/high transition while SCL is high. So after a NACK has been received on the start byte, the master has to add another (dummy) bit cycle where SDA is turned into the proper state for a following start or stop condition. Probably that's what you see.
    The USCI is waiting for your decision to make either a stop or a repeated start after the NACK.
    Or your manual clear of TXIFG has confused the state machine. Well, I'd have to take a look at the logic analyzer output to see what's going on.

  • Hello Jens,

    I have attached the screen shot of the start byte sent. The slave sends a NACK. Could you tell the most common reasons for a slave to send NACK. I have kept I2CSA = 0x1D(the slave address can be 0x1D or 0x1C) as you suggested. The pins of accelerometer are connected as given in the data sheet. The code snippet is given below(after including all your suggestions). I have declared 'counter' and 'PRxData ' as volatile. What could be the error now? The code gets stuck at line 34.

  • What is the 7 bit slave address given in the datasheet of your slave? just enter that 7bit value as Hex in your UCB0I2CSA . 

    Your interrupt may need more changes for it to work.

  • Looking at your screenshot, it looks like the start byte is sent properly.

    SCL goes high, the SDA goes low (start condition). On the next 8 rising clock edges, 00111010 is sent. This is 0x3A, meaning 0x1d slave address and '0' R/W bit.

    Are you sure the slave address  is 0x1d? You say it can be 0x1c or 0x1d. What causes this difference? O port pin on the slave? Is it properly tied to the right level?

    On the next falling clock edge, teh USCI releases SDA, which in turn goes high. The slave doesn't pull it low (no ACK from slave). On the next rising edge, the NACK is recognized. The USCI sets UCNACKIFG and awaits your decision how to proceed: sending a stop to free the bus or sending a repeated start. For this, it pulls the clock low (so it can then change SDA to the required level for either stop or start) and keeps it low until you tell it how to go on. If you set UCTXSTP, you'll see that SDA goes low, then the rising clock edge comes, the SDA goes high again, generating a stop condition.

    The question is, why doesn't the slave ACK for slave address 0x1d and a low R/W bit.

    If I calculated right, your clock is ~55kHz. Fine. But what about the voltage levels? You have a high level of 2.0V (so you're running the MSP on 2V? At least the pull-ups only go to 2V). Is this high enough for the slave to be recognized at all? Check the slave datasheet.

  • I have figured out most of it. I am able to send the 1st byte with write bit and get an ACK, send byte containing the register I want to access in the slave with an ACK and again the repeated start with read bit. My next problem is that the slave is not sending me the data. I am checking the slave data sheet if I am missing something since I have set up I2C pretty correctly and the error now could lie in the slave accelerometer. 

    The slave device works at 1.8 V . I have used a voltage translator that had MSP on high voltage side and accelerometer on low voltage side. I have connected the scope on low voltage side. 

    My another question is - Is it possible to do step by step debugging using the IAR workbench for I2C? I tried to do step by step, but it does not show the single pulses on the scope, where each pulse represents a command execution.

  • Can you post a screenshot (good resolution, please) of the whole communication? I mean, from the start condition of the register write to the failed read.

    girish KAMATH said:
    The slave device works at 1.8 V .

    And the MSP? Since I2C works with pull-ups and not a push output, You might be able to connect the pull-ups to 1.8V and still drive the bus from an MSP with a higher VCC. The only thing is that the MSPs input high-voltage trigger level must be below 1.8V at this Vcc. Which is guaranteed for VCC <= 2.4V (worst case, 0.75*Vcc) and may work for Vcc up to 3.6V (0.5*Vcc).
    No voltage translator needed then.

    If you're using a voltage translator, this may confuse the USCI bus state detection when the signal direction changes.

    girish KAMATH said:
    Is it possible to do step by step debugging using the IAR workbench for I2C?

    Only if you do the I2C in software. The hardware doesn't care for CPU instructions. When the CPU sets a bit or writes to TXBUF, the hardware will continue on it own, whether the CPU is stopped or not -  until the next CPU action is required to continue. This is the main reason for having a hardware for I2C: not requiring code for every single step during the transfer.

  • I will post the screen shot soon. I have to get data from accelerometer using I2C and send it wirelessly using cc2500 chip. I had written code separately for wireless transmission and I2C communication. Wireless part is working fine, but the I2C part works fine sometimes and gets stuck at the statement just after the first STT is sent. 

    The complication is, both I2C and cc2500(SPI) uses channel B of MSP430F2274 and the pins of IO P3 overlap. I am disabling I2C after getting data and enabling cc2500 alternately. Wireless part uses timer to interrupt every 1ms to transmit. Hope this interrupt is not disrupting the I2C. 

  • girish KAMATH said:
    The complication is, both I2C and cc2500(SPI) uses channel B of MSP430F2274 and the pins of IO P3 overlap.

    An SPI slave won't care for the signals on the SCL/SDA lines as long as it isn't selected (slave CS is high).
    The I2C slaves will, however, listen to the SIMO/SOMI lines and try to interpret them as I2C bus signals. Which may cause the slave to go into an invalid state.

    It could help to simulate a fake start/stop cycle on SDA/SCL (using them in GPIO mode) to reset the bus, before using I2C again. But generally, it isn't a good idea to mix two different bus systems on the same pins.

    On 5x family, you could remap the port pins when switching the bus, so while the same USCI module is used, different pins are used for each job. But on 2x family, there is no port mapping. :(

    girish KAMATH said:
    The following two ISR routines are not used. However, some of the wireless // helper functions utilize them, so they are included here to avoid a full // program reset.

    If they are ever called, then this will also lock your CPU as they don't ever handle the interrupt, so it keeps pending.

    So either they are used, then they need to handle the interrupt properly and at the very least clear the IFG bit that caused them to be called, or they aren't called and therefore superfluous.

  • Hello Jens,

     When reading the slave device, I need to first send the register address of the slave I wish to read and then send the repeated START to start reading the device after setting the UCTR to 0(to set MSP as master receiver). but the repeated start never goes when I set the UCTR to 0 and then send START bit. Here is the code snippet :

    UCB0CTL1 |= UCTXSTT;              // Send Start and slave address
        UCB0TXBUF = 0x01;                 // Load TX buffer to send reg address
        while(( UCB0CTL1 & UCTXSTT) != 0); // Wait for address to be sent
        while(!(UCB0TXIFG & IFG2));
    
        I2CReadInit();                    // Init I2C module for a read operation
    while(UCB0STAT & UCBBUSY); // wait for channel to become free
        UCB0CTL1 |= UCTXSTT;              // re-start condition generation
    while (( UCB0CTL1 & UCTXSTT) != 0); // Wait for address to be sent

    The MSP doesn't send the second START in the code. Could you explain why?. The busy bit is set though.
  • Calling the I2CReadInit may reset the USCI or do other things that must not be done between the write and the repeated start for the read. This may stall the bus. And you might not need it anyway.

    Also, since you do not send a stop, the bus will still be busy - that's intentional.

    The BUSY bit is there to check if another rI2C master currently has a transfer running. For yourself, you should know that this is the case.

    After sending the address, just clear UCTR bit (to switch to read mode) and set UCTXSTT, to begin reading.

**Attention** This is a public forum