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.

MSP430FR2433: I2C communication error

Part Number: MSP430FR2433

Hi 2E2,

I am using the MSP430FR2433 and I want to communicate with the PN532 board via I2C. My goal is to send the following array (version_buff[9] = {0X00,0X00,0XFF,0X01,0XFF,0XD4,0X02,0XD5,0X00,}) to the PN532 and then save its response in a variable. I am using an example code but when I send UCB0TXBUF = TransmitRegAddr (I don't know why) it should read something and enter again in the interrupt. The second time I do not enter the interrupt and I get stuck in the line __bis_SR_register(LPM0_bits + GIE).

If someone can help me to solve the error or another way to send the array I mentioned before and then read a response.

Thank you.

#include "nfc.h"
#include "msp430.h"


typedef enum I2C_ModeEnum{
    IDLE_MODE,
    NACK_MODE,
    TX_REG_ADDRESS_MODE,
    RX_REG_ADDRESS_MODE,
    TX_DATA_MODE,
    RX_DATA_MODE,
    SWITCH_TO_RX_MODE,
    SWITHC_TO_TX_MODE,
    TIMEOUT_MODE
} I2C_Mode;

/*constantes de NFC*/
unsigned char TransmitBuffer[9] = {0};
unsigned char TXByteCtr = 0;
unsigned char ReceiveIndex = 0;
unsigned char ReceiveBuffer[50];
unsigned char RXByteCtr = 0;
unsigned char TransmitIndex = 0;
unsigned char imagen[150];

I2C_Mode MasterMode = IDLE_MODE;
unsigned char TransmitRegAddr = 0;

unsigned char nfc_buf[NFC_CMD_BUF_LEN];
static const unsigned char version_buff[9] = {0X00,0X00,0XFF,0X01,0XFF,0XD4,0X02,0XD5,0X00,};
unsigned char checksum;

I2C_Mode I2C_Master_WriteReg(unsigned char dev_addr, unsigned char reg_addr, const unsigned char *reg_data, unsigned char count);
I2C_Mode I2C_Master_ReadReg(unsigned char dev_addr, unsigned char reg_addr, unsigned char count);
void CopyArray(const unsigned char *source, unsigned char *dest, unsigned char count);
void Configuracion_I2C(void);


unsigned int get_version(void);

int main()
{
   WDTCTL = WDTPW | WDTHOLD;

   Configuracion_I2C();

   PM5CTL0 &= ~LOCKLPM5;

   __enable_interrupt();

       while(1)
        {
           get_version();

           unsigned int versiondata = get_version();  //guardar version en versiondata
                 if (! versiondata) {          //Si devuelve 0 es que no ha detectado
                         while (1);
                           }
                   while(1);

        }
}



void Configuracion_I2C(void)
{
    UCB0CTLW0 = UCSWRST;                                        // Enable SW reset
       UCB0CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK
       UCB0BRW = 160;                                          // fSCL = SMCLK/160 = ~100kHz
       UCB0I2CSA = PN532_I2C_ADDRESS;                          // Slave Address
       UCB0CTLW0 &= ~UCSWRST;                                  // Clear SW reset, resume operation
       UCB0IE |= UCNACKIE;

       P1SEL1 &= ~BIT3;
       P1SEL0 |= BIT3;

       P1SEL1 &= ~BIT2;
       P1SEL0 |= BIT2;
}


I2C_Mode I2C_Master_ReadReg(unsigned char dev_addr, unsigned char reg_addr, unsigned char count)
{
    /* Initialize state machine */
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;
    RXByteCtr = count;
    TXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;

    /* Initialize slave address and interrupts */
    UCB0I2CSA = dev_addr;
    UCB0IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
    UCB0IE &= ~UCRXIE;                       // Disable RX interrupt
    UCB0IE |= UCTXIE;                        // Enable TX interrupt

    UCB0CTLW0 |= UCTR + UCTXSTT;             // I2C TX, start condition
   __bis_SR_register(LPM0_bits + GIE);              // Enter LPM0 w/ interrupts*/

    return MasterMode;

}


I2C_Mode I2C_Master_WriteReg(unsigned char dev_addr, unsigned char reg_addr, const unsigned char *reg_data, unsigned char count)
{

    /* Initialize state machine */
    MasterMode = TX_REG_ADDRESS_MODE;
    TransmitRegAddr = reg_addr;

    //Copy register data to TransmitBuffer
    CopyArray(reg_data, TransmitBuffer, count);

    TXByteCtr = count;
    RXByteCtr = 0;
    ReceiveIndex = 0;
    TransmitIndex = 0;

    /* Initialize slave address and interrupts */
    UCB0I2CSA = dev_addr;
    UCB0IFG &= ~(UCTXIFG + UCRXIFG);       // Clear any pending interrupts
    UCB0IE &= ~UCRXIE;                       // Disable RX interrupt
    UCB0IE |= UCTXIE;                        // Enable TX interrupt

    UCB0CTLW0 |= UCTR;
    UCB0CTLW0 |= UCTXSTT;                   // I2C TX, start condition
    __bis_SR_register(LPM0_bits + GIE);              // Enter LPM0 w/ interrupts

    return MasterMode;
}

void CopyArray(const unsigned char *source, unsigned char *dest, unsigned char count)
{
    unsigned char copyIndex = 0;
    for (copyIndex = 0; copyIndex < count; copyIndex++)
    {
        *dest = *source;
        source++;
        dest++;
    }
}



#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
  //Must read from UCB0RXBUF
  unsigned char rx_val = 0;
  switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
  {
    case USCI_NONE:          break;         // Vector 0: No interrupts
    case USCI_I2C_UCALIFG:   break;         // Vector 2: ALIFG
    case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
      break;
    case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
    case USCI_I2C_UCSTPIFG:  break;         // Vector 8: STPIFG
    case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
    case USCI_I2C_UCTXIFG3:  break;         // Vector 12: TXIFG3
    case USCI_I2C_UCRXIFG2:  break;         // Vector 14: RXIFG2
    case USCI_I2C_UCTXIFG2:  break;         // Vector 16: TXIFG2
    case USCI_I2C_UCRXIFG1:  break;         // Vector 18: RXIFG1
    case USCI_I2C_UCTXIFG1:  break;         // Vector 20: TXIFG1
    case USCI_I2C_UCRXIFG0:                 // Vector 22: RXIFG0
        rx_val = UCB0RXBUF;
        if (RXByteCtr)
        {
          ReceiveBuffer[ReceiveIndex++] = rx_val;
          RXByteCtr--;
        }

        if (RXByteCtr == 1)
        {
          UCB0CTLW0 |= UCTXSTP;
        }
        else if (RXByteCtr == 0)
        {
          UCB0IE &= ~UCRXIE;
          MasterMode = IDLE_MODE;
          __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
        }
        break;
    case USCI_I2C_UCTXIFG0:                 // Vector 24: TXIFG0
        switch (MasterMode)
        {
          case TX_REG_ADDRESS_MODE:
              UCB0TXBUF = TransmitRegAddr;
              if (RXByteCtr)
                  MasterMode = SWITCH_TO_RX_MODE;   // Need to start receiving now
              else
                  MasterMode = TX_DATA_MODE;        // Continue to transmision with the data in Transmit Buffer
              break;

          case SWITCH_TO_RX_MODE:
              UCB0IE |= UCRXIE;              // Enable RX interrupt
              UCB0IE &= ~UCTXIE;             // Disable TX interrupt
              UCB0CTLW0 &= ~UCTR;            // Switch to receiver
              MasterMode = RX_DATA_MODE;    // State state is to receive data
              UCB0CTLW0 |= UCTXSTT;          // Send repeated start
              if (RXByteCtr == 1)
              {
                  //Must send stop since this is the N-1 byte
                  while((UCB0CTLW0 & UCTXSTT));
                  UCB0CTLW0 |= UCTXSTP;      // Send stop condition
              }
              break;

          case TX_DATA_MODE:
              if (TXByteCtr)
              {
                  UCB0TXBUF = TransmitBuffer[TransmitIndex++];
                  TXByteCtr--;
              }
              else
              {
                  //Done with transmission
                  UCB0CTLW0 |= UCTXSTP;     // Send stop condition
                  MasterMode = IDLE_MODE;
                  UCB0IE &= ~UCTXIE;                       // disable TX interrupt
                  __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
              }
              break;

          default:
              __no_operation();
              break;
        }
        break;
    default: break;
  }
}


unsigned int get_version(void)
{
    unsigned int version;


     I2C_Master_WriteReg(PN532_I2C_ADDRESS , 0, version_buff, 8);

     I2C_Master_ReadReg(PN532_I2C_ADDRESS ,0, 12);
     CopyArray(ReceiveBuffer, nfc_buf, 12);

    version = nfc_buf[7];
    version <<= 8;
    version |= nfc_buf[8];
    version <<= 8;
    version |= nfc_buf[9];
    version <<= 8;
    version |= nfc_buf[10];

    return version;
}

  • Hello,

    I noticed your count value of 8 in I2C_Master_WriteReg() is different than the buffer/array size of 9. If the PN532 is expecting 9 bytes, then perhaps that explains why it is not responding.

  • I have changed the count value to 9 in I2C_Master_WriteReg() and the problem remains as before.

  • This symptom sounds very much like a NACK. Unfortunately, the ISR doesn't do anything with UCNACKIFG, so the result would be a hang. You can try setting a breakpoint there, or look at USCI_B0:UCB0IFG in the CCS Registers view.

    What address are you using, i.e. what is the value of PN532_I2C_ADDRESS? If you're using the Adafruit board (#789), its product page says it should be 0x48.

  • Thanks for the help, I have corrected some errors and now I can send data and I can also read them. The only thing is that now, instead of reading what the pn532 should send, I read 0x80 all the time.... I don't know why. I think I'm sending the commands it needs...

  • What exactly are you sending (to get back the 0x80-s)? I'm not familiar with this device, but maybe someone will see something.

    I wasn't able to find a protocol definition (the NXP data sheet mostly talks about the onboard MCU), but Adafruit does have an Arduino driver you could reference.

  • For example when I type the command to get the pn532 version (0x00 0x00 0xFF 0x01 0xFE 0xD4 0x02 0x2A 0x00) what I get is 0x80 the number of times I have told it the size of the message back.

    On the other hand, if I write (0x00 0x00 0x00 0xFF 0x02 0xFE 0xD4 0x02 0x2A 0x00), I get 0x01 and it stops, does not enter the interrupt to read the next bytes it receives and stops forever.

    I think the correct command is the second one, but it does not raise the flag to enter the interrupt to read the next bytes, it only reads the first one (0x01).

  • I (still) don't know how this protocol works, but from what you're describing you write a (9-byte) Request "packet" and then read back a (8-byte?) Response packet.

    The code you started with is built around a "register" protocol model, where you read/write "memory" in the device, addressed by a 1-byte "register number". This model is common in I2C devices, but I'm starting to suspect it isn't suitable for this device.

    In particular

    1) WriteReg will prepend the "reg_number" you provide to each Request

    2) ReadReg will start by writing (the reg_number) to the device, and only then read the Response from it. (This operation is the primary reason for that state machine.)

    You may want to go through your protocol document and see what effect these extra actions will have.

    You might be able to morph this program into a request/response model (maybe by changing the state machine?), since the bulk of the code is still relevant. Alternatively, it might be easier to merge examples msp430fr243_euscib0_i2c_10.c and _i2c_15.c:

    https://dev.ti.com/tirex/explore/node?node=AJ4FbEhpy0QN9VgmlO5i8g__IOGqZri__LATEST

  • Ok, I think you are right. The idea is that I have to send a command to the PN532 and after it receives the command, it will respond with the number of bytes it needs. I have modified the code so that it only sends the command I want and then reads the response directly. The error I'm getting now is that it responds 0xFF all the time.

    For example, if I send the following command 00 00 FF 02 FE D4 02 2A 00 is to get the PN532 version and it should give me the following response: [  00 00 FF 00 FF 00] and [ 00 00 00 FF D5 03 32 01 01 06 07 E8 ]. The only answer I get is 0xFF all the time.

  • Not exactly RFID, but this I2C interface to a TI BQ device might help:https://training.ti.com/rapid-proto-fund-i2c-smbus 

    But nothing better than having an I2C bus analyzer (or even storage oscilloscope) for debug  

**Attention** This is a public forum