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 read (write address to read)

Other Parts Discussed in Thread: CC430F5133

Hello,

I'm trying to readout a sensor MMA7660FC with I2C on an cc430f5133. The I2c send commands seem to work alright, but when I want to receive i have to do the following:

send startcondition+write->send the byteaddress to read-> send repeated start+no_read -> receive byte from the sensor -> stop or read another byte. Now I've been looking at a lot of code allready and i've also scanned through some questions in this forum but I just cannot find out how to implement this correct in the cc430code. I checked the signals with a Oscilloscoop and something seems to go wrong. The code is partwise coppied from from the code examples of the cc430. I also noticed that transmission of the byte 0x00 (in case 12 in the code) doesn't work (It looks like the hardware doesn't notice that a byte is written into UCB0TXBUF how can i resolve this and what is the correct way to do a repeated start -> first write then read to/from a slave? Or does someone have some example code that i can studie?

My code looks as follows:

// I think setup of the I2c is correct because sending works and is acked by the slave. 

//*********** the receiving function ********

unsigned char I2C_receive(unsigned char registernr,unsigned char nrof_bytes, unsigned char* RxBuffer )
{
    data_to_send[0]=registernr;                                // register where the read is started
    TXByteCtr=255;                                                      // special  value
    bytes_to_receive=nrof_bytes;                             // nr of bytes that should be received
    PRxData = (unsigned char *)RxBuffer;             // PRxData points to start of buffer
    while (UCB0CTL1 & UCTXSTP);                       // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT;                     // first the start condition has to be sent
    __bis_SR_register(GIE);
    __no_operation();
    return 1;
}

//*********** and the interrupt routing *******

#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
  switch(__even_in_range(UCB0IV,12))
  {
  case  0: break;                           // Vector  0: No interrupts
  case  2: break;                           // Vector  2: ALIFG
  case  4: break;                           // Vector  4: NACKIFG
  case  6: break;                           // Vector  6: STTIFG
  case  8: break;                           // Vector  8: STPIFG stop has been sent
  case 10:                                      // Vector 10: RXIFG
        bytes_to_receive--;                     // Decrement RX byte counter
        if (bytes_to_receive)
      {
            *PRxData++ = UCB0RXBUF;               // Move RX data to prxdata and increase pointer
          if (bytes_to_receive == 1)            // Only one byte left?
              UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
          //UCB0CTL1 |= UCTXNACK;             // cleared after nack is transmitter not needed because generating UCTSTP gives nack and stop page 647
      }
      else
      {
          *PRxData = UCB0RXBUF;                 // Move final RX data to PRxData
          //__bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
      }
      break;
  case 12:                                  // Vector 12: TXIFG
      // check for busy transmission -> stop condition send?
    if (TXByteCtr==255)                          // when special nr of bytes is received there is only one byte to send and no stop has to be sent
    {
        UCB0TXBUF = 0x00;                        //data_to_send[0];          // send one byte then go in receive mode
        //UCB0CTL1  |= UCTXSTP;
        TXByteCtr=0;                          // set TX byte counter to 0
        __delay_cycles(100);
        UCB0CTL1 &= ~UCTR;                      // activate receiving mode
        UCB0CTL1 |= UCTXSTT;
    }
    else if (TXByteCtr)                          // Check TX byte counter
    {
      UCB0TXBUF = *PTxData++;                   // Load TX buffer with the data to send
      TXByteCtr--;                          // Decrement TX byte counter
    }
    else
    {
      UCB0CTL1 |= UCTXSTP;                  // I2C stop condition after next acknowlege of slave
      UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
      //__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 (has not been entered hence commented)
    }
    break;
  default: break;
  }
}

Thank You,
Geert Verhaeg

  • Geert Verhaeg said:
    unsigned char I2C_receive

    You know that when this function returns, you don't have received anythign yet? Mos tlikely the start condition is currently being transmitted. I'm just askign because you didn't post how the funciton is used by your main code. You also didn't post the USCI init code.

    However, as soon as you set UCTXSTT and TXIE and GIE, the TX ISR is triggered. At this point, the start condition hasn't bee sent yet, let alone the slave addressed. When the slave doesn't ACK, you'll get an NACKIFG interrupt (if enabled) and the byte already written to TXBUF is discarded. If the slave did send an ACK, the already written content of TXBUF is moved into the output shift register and another TX interrupt is fired. THIS is the moment to clear UCTR and send the repeated start. In your code you're setting UCTXSTT long before the first (and only) data byte has been sent.

    So try
    if (TXByteCtr==255) { UCB0TXBUF= 0; TXByteCtr=254;}
    else if (TXByteCtr==254){ TXByteCtr=0; UCB0CTL1 &=~UCTR; UCB0CTL1|= UCTXSTT;}
    else if...

    And you definitely should handle UCNACKIFG.

    BTW, I hope you have declared all those global variables that are set in main and used in the ISR and maybe checked in main again as volatile? If not, do so, or else comile roptiization may break the assumed synchronization between main thread and ISRs

  • Hey,

    Thank you for your fast reaction: I tried to adapt the code with your hints. I already understood that the function hadn't sent/received the bytes yet at return, but thats why I implemented some dalays and try to handle the transmissions and receptions in the interupts. I also hadn't handled UCNACKIFG so i programmed this in the code but it still doesn't do what I expect it do do: At the bottom is my code. When I track the code with a scope i see several things happen:

    1) The first byte in I2C_send_byte(0x07,0x09); is not sent.

    2) Earlier I saw that the acknowledge clock cycle was given just before the next byte was sent is this normal behavior?

    3) when stepping through the code i didn't get to the receiving part so I realy don't have a clue if its even near functional code

    Main code:

    #define PRESCALE 12
    #define slave_address  0x4C

    #include "cc430f5133.h"
    #include "I2C.h"

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P1DIR |= 0x01;                            // P1.0 output
      PMAPPWD = 0x02D52;                        // Get write-access to port mapping regs
      P2MAP6 = PM_UCA0RXD;                      // Map UCA0RXD output to P2.6
      P2MAP7 = PM_UCA0TXD;                      // Map UCA0TXD output to P2.7
      PMAPPWD = 0;                              // Lock port mapping registers
      P2DIR |= BIT7;                            // Set P2.7 as TX output
      P2SEL |= BIT6 + BIT7;                     // Select P2.6 & P2.7 to UART function

    /*
      TA1CTL = TASSEL_2 + MC_2 + TACLR;         // SMCLK, contmode, clear TAR
      UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
      UCA0CTL1 |= UCSSEL_1;                     // CLK = ACLK
      UCA0BR0 = 0x0D;                           // 2400 (see User's Guide)
      UCA0BR1 = 0x00;                           //
      UCA0MCTL |= UCBRS_6+UCBRF_0;              // Modulation UCBRSx=6, UCBRFx=0
      UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    */

      unsigned char RxBuffer[3];
      //char a=0;

      while(1)
      {
          I2C_init(slave_address);                    // start I2c
          I2C_send_byte(0x07,0x09);                    // Send the mode of the sensor to the sensor: address 0x07 mode 0x09
          __delay_cycles(100);
          I2C_receive(0x00,3,RxBuffer);                // receive 3 bytes x,y,z (starting from 0 in Rxbuffer)

          /*for(a=0;a!=3;a++)
          {
              while (!(UCA0IFG&UCTXIFG));             // USCI_A1 TX buffer ready?
              UCA0TXBUF = RxBuffer[a];                  // TX -> RXed character
          }*/

          P1OUT ^= 0x01; //led -> to see if while loop is being executed
          __delay_cycles(100000); // SW Delay of 10000 cycles at 1Mhz
      }
    }

    Included code I2C.c :

    #include "cc430f5133.h"
    #include "I2C.h"

    volatile unsigned char data_to_send[2];
    volatile unsigned char data_received;
    volatile unsigned char TXByteCtr;
    volatile unsigned char bytes_to_receive;
    volatile unsigned char *PRxData;                     // Pointer to RX data
    volatile unsigned char *PTxData;                     // Pointer to TX data

    void I2C_init(unsigned char slaveaddress)                       // initialize the I2C master interface. Need to be called only once
    {
          //while doing adjustments it's is safer to reset the I2C port hence set UCSWRST
          PMAPPWD = 0x02D52;                            // Get write-access to port mapping regs
          P1MAP3 = PM_UCB0SDA;                          // Map UCB0SDA output to P1.3
          P1MAP2 = PM_UCB0SCL;                          // Map UCB0SCL output to P1.2
          PMAPPWD = 0;                                  // Lock port mapping registers

          P1SEL |=   BIT2 + BIT3;;                         // Assign I2C pins to USCI_B0
          UCB0CTL1 = UCSWRST;                             // Enable SW reset
          UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;           // I2C Master, synchronous mode ucmst tells this is the master
          UCB0CTL1 = UCSSEL_2 + UCSWRST;                  // Use SMCLK, keep SW reset

          // bit rate control registers
          UCB0BR0 = 12;                                   // set prescaler to 12 to have 100khz operation
          UCB0BR1 = 0;                                      //

          UCB0I2CSA = slaveaddress;                      // set slave address just the 7 bit address
          UCB0CTL1 &= ~UCSWRST;                           // Clear SW reset, resume operation
          UCB0IE |= UCTXIE|UCRXIE|UCNACKIE;                // Enable TXint RXint and the not acknowledge interrupt
          __delay_cycles(50);
          __bis_SR_register(GIE);                       // enable interrupts
    }

    unsigned char I2C_send_byte(unsigned char regaddress, unsigned char byte)
    {
        data_to_send[0]=regaddress;                        // where to write the byte
        data_to_send[1]=byte;                            // what byte to write
        TXByteCtr=2;                                    // # bytes to write
        PTxData = (unsigned char *)data_to_send;        // pointer to data to send
        while (UCB0CTL1 & UCTXSTP);                        // make sure stop condition has been sent
        UCB0TXBUF = *PTxData++;                            // put first data in buffer
        TXByteCtr--;                                    // decrease counter for #bytes that still have to be put in buffer
        UCB0CTL1 |= UCTR + UCTXSTT;                     // I2C TXmode, send start condition
        __bis_SR_register(GIE);
        __no_operation();
        return 1;
    }

    unsigned char I2C_receive(unsigned char registernr,unsigned char nrof_bytes, unsigned char* RxBuffer )
    {
        TXByteCtr=255;                                            // 'special' value
        bytes_to_receive=nrof_bytes;                            // nr of bytes that should be received
        PRxData = (unsigned char *)RxBuffer;                     // PRxData points to start of buffer
        while (UCB0CTL1 & UCTXSTP);                             // Ensure stop condition got sent
        UCB0TXBUF = registernr;                                    // put registernr in buffer
        UCB0CTL1 |= UCTR + UCTXSTT;                              // send the start condition
        __bis_SR_register(GIE);
        __no_operation();
        return 1;
    }

    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    {
      switch(__even_in_range(UCB0IV,12))
      {
      case  0: break;                           // Vector  0: No interrupts
      case  2: break;                           // Vector  2: ALIFG
      case  4:                                  // Vector  4: NACKIFG
                  UCB0CTL1 |= UCTXSTP;                  //when an acknowledge is missing the slave gets a stop condition
                  UCB0IFG &= ~UCTXIFG;
                  break;
      case  6: break;                           // Vector  6: STTIFG
      case  8: break;                           // Vector  8: STPIFG stop has been sent
      case 10:                                  // Vector 10: RXIFG
            bytes_to_receive--;                   // Decrement RX nr of bytes still to receive counter
            if (bytes_to_receive)
          {
                *PRxData++ = UCB0RXBUF;           // Move RX data to prxdata and increase pointer
              if (bytes_to_receive == 1)        // Only one byte left?
                  UCB0CTL1 |= UCTXSTP;          // Generate I2C stop condition (with a nack before that, which is handled by hardware automatically)
          }
          else
          {
              *PRxData = UCB0RXBUF;                 // Move final RX data to PRxData
          }
          break;
      case 12:                                      // Vector 12: TXIFG
        if (TXByteCtr==255){                        // when 'special' nr of bytes there is only one byte to send and no stop has to be sent
            UCB0CTL1 &= ~UCTR;                          // activate receiving mode
            TXByteCtr=0;                              // set TX byte counter to 0
            UCB0CTL1 |= UCTXSTT;                    // give green light for a repeated start (start read)
        }
        else if (TXByteCtr){                           // Check if TX byte counter not zero
             UCB0TXBUF = *PTxData++;                   // Load TX buffer with next byte and increase pointer
             TXByteCtr--;                              // Decrement TX byte counter
        }
        else{
            UCB0CTL1 |= UCTXSTP;                  // I2C stop condition after next acknowlege of slave
            UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
        }
        break;
      default: break;
      }
    }

    kind regards

    Geert

  • I don't see anyplace in your code where you wait for an I2C transaction to finish before you initiate another transaction. After calling an I2C transaction you should wait for the UCBBUSY bit to clear before you call another I2C transaction. The __delay_cycle may not be long enough and your I2C_sendbyte may not be finishing before you call I2C_receive. Also, make sure that the UCBBUSY bit is set before you start testing whether it has cleared. I had to do that in my code because it looks like the UCBBUSY bit does not get set immediatley after a I2C transaction is started. I had to add 2 nops between setting the UCTXSTT bit and checking the state of the UCBBUSY bit, before I saw a High on the UCBBUSY bit.

    Also it looks like you are sending two repeated starts, one in the ISR for TXIFG and one in the I2C_receive call. Remove the one in the ISR and just make sure that you don't generate a stop in the ISR.

    And in the I2C_receive call, you are setting UCTR instead of clearing UCTR, so you are still in transmit mode.

  • Hey Timothy Barr,

    I adapted the code with the part in blue put after the UCB0CTL1 |= UCTR + UCTXSTT and setting interrupt enable in the I2c_send_byte routine

    __no_operation();
    __no_operation();
    while(UCB0STAT & UCBBUSY);                        // Wait for the bus to be free then return

    I'm going to try this as soon as i have the possibiltiy.

    The reason for the repeated start is the following: In the I2C_receive I want to receive a byte from a certain register of the sensor. This means I first want to send a byte which tells the sensor which register it has to read from->(UCB0CTL1 |= UCTR + UCTXSTT).

    Then I want to receive the byte from that register by sending a repeated start with send/receive bit cleared (in order to receive)-> the code in the ISR for TXIFG

    UCB0CTL1 &= ~UCTR;

    UCB0CTL1 |= UCTXSTT;              

    I don't have any idea if this is a nice way to do this, because i have almost no experience with the cc430. Perhaps it's worth to mention that I checked the commands with an AVR and the I2c commands for the sensor seem to be correct because I can extract data from the sensor with the AVR.


    Kind regards,

    Geert

  • Hello all,

    Just checked the code and the following happened:

    The while(UCB0STAT & UCBBUSY); command seemed to work (I checked it with a scope) but in order to send all the bytes I had to place the first byte that i wanted to send in the txbuffer in the interrupt. When I did this before i do: UCB0CTL1 &= UCTR | UCTXSTT; The first byte to sent is not sent. When I do this in the interrupt routine this part of the code works fine.

    Then when I try to receive data in the main I2C_receive(), then I have two problems:

    - The byte 0x00 is not recognized by the txbuffer when i try to write 0x01 then it sends the byte without a problem, so it looks like writing 0x00 is not recognized as a txbuffer write and 0x01 is.

    - Here I also had to move the transmission of the byte into the interrupt handler.

    Can anyone explain this behavior because I don't know where I have to look further?


    Kind regards,

    Geert


  • Hello,

    I think I almost tried all possible things to get 0x00 to send but I can't make it happen.

    Then I tried to leave that problem for a moment and I tried to receive one byte from another register and nack it followed by a stop condition. And this somehow seems to be a hard thing to do also, because I can't get the I2c module to nack the first byte, It Nacks the second received byte and then sends a stop condition.

    Is there anyone who recognizes these problems and knows how to fix it, or has some example code that I can have a look at, because i'm pretty sure google hasn't got the answer and i have gone through a lot of topics on this forum.

    Geert

  • Okey finally

    I managed to get the code working! It seemed that I was looking at the wrong interrupt flags at the wrong places and now it works correct. Also sending 0x00; I couldn't get the CC430f5133 I2C module to receive only one byte, because somehow I can't make the module to nack and send a stop condition after the first byte it receives. I solved this by creating a dummy where the next byte the sensor passes me can be placed. The code is below:

    Main.c

    #define PRESCALE 12
    #define slave_address  0x4C

    #include "cc430f5133.h"
    #include "I2C_master.h"

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P1DIR |= 0x01;                            // P1.0 output
      PMAPPWD = 0x02D52;                        // Get write-access to port mapping regs
      P2MAP6 = PM_UCA0RXD;                      // Map UCA0RXD output to P2.6
      P2MAP7 = PM_UCA0TXD;                      // Map UCA0TXD output to P2.7
      PMAPPWD = 0;                              // Lock port mapping registers
      P2DIR |= BIT7;                            // Set P2.7 as TX output
      P2SEL |= BIT6 + BIT7;                     // Select P2.6 & P2.7 to UART function

    /*
      TA1CTL = TASSEL_2 + MC_2 + TACLR;         // SMCLK, contmode, clear TAR
      UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
      UCA0CTL1 |= UCSSEL_1;                     // CLK = ACLK
      UCA0BR0 = 0x0D;                           // 2400 (see User's Guide)
      UCA0BR1 = 0x00;                           //
      UCA0MCTL |= UCBRS_6+UCBRF_0;              // Modulation UCBRSx=6, UCBRFx=0
      UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    */

      unsigned char RxBuffer[3];
      //char a=0;
      I2C_init(slave_address);                    // start I2c
      while(1)
      {
          I2C_send_byte(0x07,0x09);                    // Send the mode of the sensor to the sensor: address 0x07 mode 0x09
          I2C_receive(0x07,1,RxBuffer);                // receive 3 bytes x,y,z (starting from 0 in Rxbuffer)

          /*for(a=0;a!=3;a++)
          {
              while (!(UCA0IFG&UCTXIFG));             // USCI_A1 TX buffer ready?
              UCA0TXBUF = RxBuffer[a];                  // TX -> RXed character
          }*/

          P1OUT ^= 0x01; //led -> to see if while loop is being executed
          __delay_cycles(100000); // SW Delay of 10000 cycles at 1Mhz
      }
    }


    I2C_master.c

    #include "cc430f5133.h"
    #include "I2C_master.h"

    volatile unsigned char data_to_send[2];                 // now it is only possible to send 1 byte
    volatile unsigned char one_byte=0;                     // indicator to indicate whether there is only 1 byte to be received
    volatile unsigned char TXByteCtr;                      // counts the nr of bytes that still have to be transmitted
    volatile unsigned char bytes_to_receive;             // counts the nr of bytes that still have to be received
    volatile unsigned char *PRxData;                     // Pointer to RX data
    volatile unsigned char *PTxData;                     // Pointer to TX data
    volatile unsigned char dummy=0;                         // dummy byte to receive second byte in (in the case only one byte has to be received


    void I2C_init(unsigned char slaveaddress)              // initialize the I2C master interface. Need to be called only once
    {
          //while doing adjustments it's is safer to reset the I2C port hence set UCSWRST
          PMAPPWD = 0x02D52;                            // Get write-access to port mapping regs
          P1MAP3 = PM_UCB0SDA;                          // Map UCB0SDA output to P1.3
          P1MAP2 = PM_UCB0SCL;                          // Map UCB0SCL output to P1.2
          PMAPPWD = 0;                                  // Lock port mapping registers

          P1SEL |=   BIT2 + BIT3;;                         // Assign I2C pins to USCI_B0
          UCB0CTL1 = UCSWRST;                             // Enable SW reset
          UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;           // I2C Master, synchronous mode ucmst tells this is the master
          UCB0CTL1 = UCSSEL_2 + UCSWRST;                  // Use SMCLK, keep SW reset

          // bit rate control registers
          UCB0BR0 = 12;                                   // set prescaler to 12 to have 100khz operation
          UCB0BR1 = 0;                                      //

          UCB0I2CSA = slaveaddress;                      // set slave address just the 7 bit address
          UCB0CTL1 &= ~UCSWRST;                           // Clear SW reset, resume operation
          UCB0IE = UCTXIE|UCRXIE|UCNACKIE;                // Enable TXint RXint and the not acknowledge interrupt
          __delay_cycles(50);
          __bis_SR_register(GIE);                       // enable interrupts
    }

    unsigned char I2C_send_byte(unsigned char regaddress, unsigned char byte)
    {
        data_to_send[0]=regaddress;                        // where to write the byte
        data_to_send[1]=byte;                            // what byte to write
        TXByteCtr=2;                                    // # bytes to write
        PTxData = (unsigned char *)data_to_send;        // pointer to data to send
        while (UCB0CTL1 & UCTXSTP);                        // make sure stop condition has been sent
        UCB0CTL1 |= UCTR + UCTXSTT;                     // I2C TXmode, send start condition
        __no_operation();
        __no_operation();
        while(UCB0STAT & UCBBUSY);                        // Wait for the bus to be free then return
        return 1;
    }

    unsigned char I2C_receive(unsigned char registernr,unsigned char nrof_bytes, unsigned char* RxBuffer )
    {
        TXByteCtr=255;                                            // 'special' value to indicate that transmission is started in order to receive after that
        bytes_to_receive=nrof_bytes;                            // nr of bytes that should be received
        PRxData = (unsigned char *)RxBuffer;                     // PRxData points to start of buffer
        if(nrof_bytes==1)
            one_byte=2;                                            // indicates only one byte has to be received
        else
            one_byte=0;                                            // indicates more bytes will be received
        while (UCB0CTL1 & UCTXSTP);                             // Ensure stop condition got sent
        data_to_send[0]=registernr;
        PTxData = (unsigned char *)data_to_send;
        UCB0CTL1 |= UCTR + UCTXSTT;                             // I2C TXmode, send start condition
        __no_operation();
        __no_operation();
        while(UCB0STAT & UCBBUSY);                                // bus is busy
        return 1;
    }

    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    {
      switch(__even_in_range(UCB0IV,12))
      {
      case  0: break;                           // Vector  0: No interrupts
      case  2: break;                           // Vector  2: ALIFG
      case  4:                                  // Vector  4: NACKIFG
                  UCB0CTL1 |= UCTXSTP;                  //when an acknowledge is missing the slave gets a stop condition
                  UCB0IFG &= ~UCTXIFG;
                  break;
      case  6: break;                           // Vector  6: STTIFG
      case  8: break;                           // Vector  8: STPIFG stop has been sent
      case 10:                                  // Vector 10: RXIFG
            bytes_to_receive--;                   // Decrement RX nr of bytes still to receive counter
            if(one_byte==2)
            {
                UCB0CTL1 |= UCTXSTP;
                *PRxData = UCB0RXBUF;             // Move final RX data to PRxData
                one_byte--;
            }
            else if(one_byte==1)
            {
                dummy=UCB0RXBUF;
                one_byte=0;
            }
            else if (bytes_to_receive && one_byte==0)
          {
                *PRxData++ = UCB0RXBUF;           // Move RX data to prxdata and increase pointer
              if (bytes_to_receive == 1)        // Only one byte left?
                  UCB0CTL1 |= UCTXSTP;          // Generate I2C stop condition (with a nack before that, which is handled by hardware automatically)
          }
          else
          {
              *PRxData = UCB0RXBUF;                 // Move final RX data to PRxData
          }
          break;
      case 12:                                      // Vector 12: TXIFG
        if (TXByteCtr==255){                        // when 'special' nr of bytes there is only one byte to send and no stop has to be sent
            UCB0TXBUF = *PTxData;                     // address to start read
            while(!(UCB0IFG&UCTXIFG));                // wait until the byte is transmitted
            TXByteCtr=0;                              // set TX byte counter to 0
            UCB0CTL1 &= ~UCTR;                          // activate receiving mode
            UCB0IFG &= ~UCTXIFG;
            UCB0CTL1 |= UCTXSTT;                    // give green light for a repeated start (start read) one byte stop directly

        }
        else if (TXByteCtr){                           // Check if TX byte counter not zero
             UCB0TXBUF = *PTxData++;                 // Load TX buffer with next byte and increase pointer
             TXByteCtr--;                              // Decrement TX byte counter
        }
        else{
            UCB0CTL1 |= UCTXSTP;                      // I2C stop condition after next acknowlege of slave
            UCB0IFG &= ~UCTXIFG;                      // Clear USCI_B0 TX int flag
        }
        break;
      default: break;
      }
    }

    Regards,

    Geert


  • Geert Verhaeg said:
    When I did this before i do: UCB0CTL1 &= UCTR | UCTXSTT; The first byte to sent is not sent.

    If you take a look athte USCi I2C description, thsi is obvious. TXBUF is cleared when UCTXSTT is set. And TXIFG is immediately set. That's intentional. The transfer begins with TXSTT, not before.

    Geert Verhaeg said:
    - The byte 0x00 is not recognized by the txbuffer when i try to write 0x01 then it sends the byte without a problem, so it looks like writing 0x00 is not recognized as a txbuffer write and 0x01 is.

    No, TXBUF makes no assumptions abotu what the sent data is or not. It simply shifts out the data bit by bit, not knowing or care for what these bits are.

    Geert Verhaeg said:
    Can anyone explain this behavior because I don't know where I have to look further?

    In teh users guide. The USCI I2C section contains nice drawing about what is done by USCI or has to be done by software and when.

  • Geert Verhaeg said:
    I couldn't get the CC430f5133 I2C module to receive only one byte, because somehow I can't make the module to nack and send a stop condition after the first byte it receives.

    That's normal. Because the USCI doesn't wait for the software to read RXBUF before the next byte is received. THis is called double-buffering and maximizes throughput. However, if the software is lazy, it will result in one byte more received than expected (which then has to be discarded). 'Lazy' means that the software doesn't set UCTXNACK and UCTXSTP before the ACK cycle of the jsu treceived byte has finished. Which is a really short time window, especially on slow MCLK and fast I2CCLK.
    And yes, a dummy byte if there is nothing more to be sent, is the usual way this is handled by I2C slaves.

  • If you look at the examples of receive code for the I2C module, you will see that if only one byte is to be received the code waits for the START condition to end so that it can send an STOP condition right after. This is how to handle the double buffering issue for the UCSI I2C hardware. 

  • Timothy Barr said:
    If you look at the examples of receive code for the I2C module, you will see that if only one byte is to be received the code waits for the START condition to end so that it can send an STOP condition right after. This is how to handle the double buffering issue for the UCSI I2C hardware. 

    Well, if MCLK is fast and I2CCLK is slow, this could result in no byte being sent. It's possible that when UCTXSTT clears, the transfer of the byte in TXBUF hasn't yet started and setting UCTXSTP might discard it. It is better to wait for TXIFG being set too. This also would conform with the diagram in the users guide.

**Attention** This is a public forum