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.

An I2C Slave problem???

Other Parts Discussed in Thread: CC430F6137

Hi All,

 

I’m working on the eZ430 HW and need to build an I2C Slave protocol from PIN1.6, P1.7 or P1.5.

After looking on the cc430x613x_uscib0_i2c_07.c and the cc430x613x_uscib0_i2c_05.c

It seems that the (CC430F137 HW) USCI_B I2C Mode supplies it on other pins i.e. P2.6 and P2.7.

Is there a way to switch those pins from P2.6 and P2.7 to PIN1.6, P1.7 or P1.5 on that program?

Like the followings?

//******************************************************************************

//  CC430F613x Demo - USCI_B0 I2C Slave Rx and Tx single bytes from MSP430 Master

//

//  Description: This demo connects two MSP430's via the I2C bus. The master

//  transmits to the slave. This is the slave code. The interrupt driven

//  data reception is demonstrated using the USCI_B0 RX interrupt.

//  ACLK = n/a, MCLK = SMCLK = default DCO = ~1.045MHz

//

//

//                                /|\  /|\

//               CC430F6137      10k  10k     CC430F6137

//                   slave         |    |        master

//             -----------------   |    |   -----------------

//           -|XIN  P1.6/UCB0SDA|<-|----+->|P2.6/UCB0SDA  XIN|-

//            |                 |  |       |                 | 32kHz

//           -|XOUT             |  |       |             XOUT|-

//            |     P1.7/UCB0SCL|<-+------>|P2.7/UCB0SCL     |

//            |                 |          |            

//

//   M Morales

//   Texas Instruments Inc.

//   April 2009

//   Built with CCE Version: 3.2.2 and IAR Embedded Workbench Version: 4.11B

//******************************************************************************

 

#include "cc430x613x.h"

 

volatile unsigned char RXData;

 

void main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                   // Stop WDT

 

  PMAPPWD = 0x02D52;                                     // Get write-access to port mapping regs

  P1MAP6 = PM_UCB0SDA;                               // Map UCB0SDA output to P1.6

  P1MAP7 = PM_UCB0SCL;                               // Map UCB0SCL output to P1.7

  PMAPPWD = 0;                                                 // Lock port mapping registers

  PMAPPWD = 0;                                                 // Lock port mapping registers

 

  P1SEL |= BIT6 + BIT7;                                      // Select P1.6 & P1.7 to I2C function

   

  UCB0CTL1 |= UCSWRST;                                 // Enable SW reset

  UCB0CTL0 = UCMODE_3 + UCSYNC;             // I2C Slave, synchronous mode

  UCB0I2COA = 0x48;                                          // Own Address is 048h

  UCB0CTL1 &= ~UCSWRST;                             // Clear SW reset, resume operation

 

UCB0IE |= UCTXIE + UCSTTIE + UCSTPIE;      // Enable RX + TX interrupts

 

  while (1)

  {

    __bis_SR_register(LPM0_bits + GIE);        // Enter LPM0, enable interrupts

    __no_operation();                                       // Set breakpoint >>here<< and read

  }                                                                     // RXData

}

 

// USCI_B0 Data ISR

#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

         UCB0IFG &= ~UCSTTIFG;                   // Clear start condition int flag

         break;

  case  8:                                                       // Vector  8: STPIFG

         TXData++;                                          // Increment TXData

         UCB0IFG &= ~UCSTPIFG;                // Clear stop condition int flag

         break;

  case 10:                                                    // Vector 10: RXIFG

         RXData = UCB0RXBUF;                   // Get RX data

         __bic_SR_register_on_exit(LPM0_bits);   // Exit LPM0

        break;

  case 12:                                                   // Vector 12: TXIFG 

         UCB0TXBUF = TXData;                   // TX data

         break;

  default: break;

  }

}

 

 !!!Note I've changed the Ports to P2.6 and P2.7 to P1.6 and P1.7.!!!!

 

Thanks a lot,

Shimon.

 

  • By default, UCB0SDA and SCL are also located on P1.2/P1.3. I don't know what these pins are connected to on your PCB, but you maybe need to map PM_ANALOG to these pins to disable them, or their (latched, if not selected) input value will be OR'd with your P1.6/P1.7, resulting an always high data (NACK) read.

  • Hi Jens,

     

    Thanks for your answer I know that by default they are on P1.2 and P1.3.

    My problem is that on my HW P1.2 and P1.3 are connected to the LCD, and I need to connect the P1.6 and P1.7 for the I2C communication.

    And I have only the mentioned pins (i.e. P1.6 and P1.7)

    That’s the reason of my question if there is a way I’ll be very happy to know how exactly I should do it (I.e. use the USCI_B I2C Mode for that purposes)?

    Without any harm the LCD communication…

     

    Thanks,

    Shimon.

  • That's why I said you should not only map them to a different pin, but also 'unmap' them from the original location (PM_ANALOG' is a 'no digital funciton' dummy). If they are mapped to two port pins, even if only selected on one, this has side-effects.

  • Hi Jens,

     

    As you know I’m really new on that system and I really don’t know how to do it.

    Can you please show me how to do it?

     

    Waiting,

    Shimon.

  • In your original code where you map P1.6 and P1.7, just map P1.2 and P1.3 to PM_ANALOG and this should disconnect the original pins from USCI_B as Jens suggests.

  • Hi,

    Let me check it to see if you mean as follows:

    PMAPPWD = 0x02D52; // Get write-access to port mapping regs

    P1MAP2 = PM_ANALOG;

    P1MAP3 = PM_ANALOG;

    P1MAP6 = PM_UCB0SDA; // Map UCB0SDA output to P1.6

    P1MAP7 = PM_UCB0SCL; // Map UCB0SCL output to P1.7

    PMAPPWD = 0; // Lock port mapping registers

    PMAPPWD = 0; // Lock port mapping registers

    .

    .

    .

    And all of the rest of the program will stay as it was…

     

    ð  The thing that I don’t understand is wont it harm the SEGs (for the LCD) that P1.2 and P1.3 are mapped and connected?

     

    Waiting,

    Shimon.

  • Shimon Shamsiyan said:
    The thing that I don’t understand is wont it harm the SEGs (for the LCD) that P1.2 and P1.3 are mapped and connected?

    No. The port mapping controller manages the internal mapping of the digital signals to the port logic. If you use the pins as LCD segment drivers, the LCD logic deactivates the digital output and input drivers of the port logic. However, the remaining part of the port logic has the signals still mapped, and there is no logical 'maybe' or 'not available', even though the physical connection to the pin has been sewered.

  • Hi All,

    I’ve just checked that program and it seems that it’s not getting any interrupts at all while there is a good connection to those ports and there is an I2C master transport to it.

    Can you all give me a suggestion what’s wrong with it?

     

    Thanks,

    Shimon.

  • Shimon Shamsiyan said:
    Can you all give me a suggestion what’s wrong with it?

    Two possible reasons come in mind.

    First is that the master doesn't use the correct address. You use 0x48 as own address, so the master needs to send 0x90 for write and 0x91 for read in its start condition. If a different address is sent, then the USCI will ignore it and not trigger any interrupts.

    Second is the port mapping. The PMM can oly be accessed once after power-on. So if you use any library function (e.g. for the SimplicyTI) that does any port mapping, your efforts to map the USCI pins are futile, even though the code may be correct. It is simply ignored then.

    BTW, you do not enable RXIE, so if the master sends a write request, you won't handle it and the I2C bus is stalled forever. (IIRC you may handle unwanted write transmissions in teh STT interrupt by setting NACK).
    Manually clearing UCTXSTT in the STT interrupt makes no sense anyway. This interrupt should notify you that you were addressed by the master. At the same time (with lower priority) the TXIFG bit is set, if it is a transmit request.

    Also, UCTR is set/cleared to notify you on the STT interrupt whether it was a transmit or receive request. At this point, I think you can set UCTXNACK instead of writing to TXBUF, to turn the request down. However, If the master sends a receive request, I think there's no way denying it. Maybe you can still set UCTXNACK if the ACK cycle hasn't been completed yet, that measn if your ISR is fast enough. Otherwise you'll get the first byte and maybe even a second byte before the USCI sends the NACK and ends the unwanted transfer.

  • Hi All,

    I’ve tried the following code and it seems that there isn’t any interrupt at all:

     

    #include "cc430x613x.h"

     

    unsigned char *PRxData;                     // Pointer to RX data

    unsigned char RXByteCtr;

    volatile unsigned char RxBuffer[128];       // Allocate 128 byte of RAM

    unsigned char *PTxData;                     // Pointer to TX data

    const unsigned char TxData[] =              // Table of data to transmit

    {

      0x11,

      0x22,

      0x33,

      0x44,

      0x55

    };

     

    void main(void)

    {

      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

     

      PMAPPWD = 0x02D52;                        // Get write-access to port mapping regs 

      P2MAP6 = PM_UCB0SDA;                      // Map UCB0SDA output to P2.6

      P2MAP7 = PM_UCB0SCL;                      // Map UCB0SCL output to P2.7

      PMAPPWD = 0;                              // Lock port mapping registers

     

      P2SEL |= BIT6 + BIT7;                     // Select P2.6 & P2.7 to I2C function

     

      UCB0CTL1 |= UCSWRST;                      // Enable SW reset

      UCB0CTL0 = UCMODE_3 + UCSYNC;             // I2C Slave, synchronous mode

      UCB0I2COA = 0x48;                         // Own Address is 048h

      UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation

      UCB0IE |= UCTXIE + UCSTPIE + UCSTTIE + UCRXIE;     // Enable STT, STP & RX interrupt

     

      while (1)

      {

        PRxData = (unsigned char *)RxBuffer;    // Start of RX buffer

        RXByteCtr = 0;                          // Clear RX byte count

           PTxData = (unsigned char *)TxData;      // Start of TX buffer

        __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts

                                                // Remain in LPM0 until master

                                                // finishes TX

        __no_operation();                       // Set breakpoint >>here<< and read

      }                                         // read out the RxData buffer

    }

     

    //------------------------------------------------------------------------------

    // The USCI_B0 data ISR RX vector is used to move received data from the I2C

    // master to the MSP430 memory.

    //------------------------------------------------------------------------------

    //------------------------------------------------------------------------------

    // The USCI_B0 state ISR TX vector is used to wake up the CPU from LPM0 in order

    // to process the received data in the main program. LPM0 is only exit in case

    // of a (re-)start or stop condition when actual data was received.

    //------------------------------------------------------------------------------

    #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:                                  // Vector  6: STTIFG

        UCB0IFG &= ~UCSTTIFG;

        break;

      case  8:                                  // Vector  8: STPIFG

        UCB0IFG &= ~UCSTPIFG;

        if (RXByteCtr)                          // Check RX byte counter

          __bic_SR_register_on_exit(LPM0_bits);

        break;

      case 10:                                  // Vector 10: RXIFG

        *PRxData++ = UCB0RXBUF;                 // Get RX'd byte into buffer

        RXByteCtr++;

        break;

      case 12:                                   // Vector 12: TXIFG 

        UCB0TXBUF = *PTxData++;                 // Transmit data at address PTxData

        break;

      default: break;

      } 

    }

     

    It just stacked on the __no_operation();// Set breakpoint >>here<< and read

     

    But when I’ve used the following code:

     

      PMAPPWD = 0x02D52;                           // Get write-access to port mapping regs

     

      P1MAP2 = PM_ANALOG;                                // Disconnect P1.2 from PM_UCB0SCL

      P1MAP3 = PM_ANALOG;                                // Disconnect P1.3 from PM_UCB0SDA

     

      P1MAP5 = PM_UCB0SDA;                                // Map UCB0SDA output to P1.5

      P1MAP6 = PM_UCB0SCL;                                  // Map UCB0SCL output to P1.6

     

      PMAPPWD = 0;                                       // Lock port mapping registers

     

     

      UCB0CTL1 |= UCSWRST; // eUSCI_B in reset state

      UCB0CTLW0|= UCMODE_3; // I2C slave mode

      UCB0I2COA = 0x48; // own address is 48hex

      P1SEL |= BIT5 + BIT6; // configure I2C pins (device specific)

      UCB0CTL1 &= ~UCSWRST; // eUSCI_B in operational state

      UCB0IE |= UCTXIE + UCRXIE; // enable TX&RX-interrupt

      GIE; // general interrupt enable

     

     

      while (1)

      {

        __enable_interrupt();

        PRxData = (unsigned char *)RxBuffer;    // Start of RX buffer

        RXByteCtr = 0;                          // Clear RX byte count

        PTxData = (unsigned char *)TxData;      // Start of TX buffer

        __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts

                                                // Remain in LPM0 until master

                                                // finishes TX

        __no_operation();                       // Set breakpoint >>here<< and read

      }                                         // read out the RxData buffer

    }

     

     

     

    // USCI_B0 Data ISR

    #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

             UCB0IFG &= ~UCSTTIFG;                  // Clear start condition int flag

             break;

      case  8:                                       // Vector  8: STPIFG

             TXData++;                              // Increment TXData

              UCB0IFG &= ~UCSTPIFG;                  // Clear stop condition int flag

              break;

      case 10:                                       // Vector 10: RXIFG

             RXData[Counter] = UCB0RXBUF;            // Get RX data

             Counter++;

             __bic_SR_register_on_exit(LPM0_bits);   // Exit LPM0

             break;

      case 12:  

            UCB0TXBUF = TXData;                     // TX data

             break;

      default: break;

      }

    }

     

    There was interrupt but when it got to the:

    P1SEL |= BIT5 + BIT6; // configure I2C pins (device specific)

    The SDA line maid a contention (i.e. the master kept sending the information but the slave i.e. the cc430 derived that line to HIGH logic)

     

    I really don’t know how to fix it, have you got any ideas?

    BTW: the I2C Master is sending a GOOD I2C protocol with address 0x49.

     

    Thanks,

    Shimon.

  • Hi Shimon,

    i was just contacted by one of our distributor regarding this question from you. I just want to check first whether  you have solved the problem, since it has been a week since your last post.

    If not, could you tell me what is your current problem with the code?

  • Shimon Shamsiyan said:
        __no_operation();                       // Set breakpoint >>here<< and read

    If you put a breakpoint on this line and expect a transfer being done when it is hit, you might be wrong.

    Breakpoints are hit when an instruction is fetched from flash. Howeve,r thsi instruction is fetched when the previous one is executed,. SO the breakpoitn is hit the very moment the CPU tries to go into LPM. And while the debugger is performing the break, the actual transfer attempt of the master passes by, unnoticed by the halted MSP.

    Put a second nop and put the breakpoint on the second one and try again.

    Hwoever, I added some comments to this (or rahter a later(?) version of this code) in your other thread.

**Attention** This is a public forum