0

I have three INA226 current sensors connected to eUSCI_B, P1.6 and P1.7, on an MSP430FR5739 microcontroller.

My I2C write addr code gives just one NACKIFG, and then forever hangs. On the scope the signals look nearly perfect square, no overshoot and the rise and fall time is 10-20x less than pulse with time of a clock. I use 2k2 Pullups. The wires are about 8cm all together on a PCB.

Previously I even did not manage to get any interrupt, by moving the "UCB0IE |= UCNACKIE | ..." code outside of the UCWRST area, I at least got this one.

#include "i2c.h"
#include "main.h"
#include "uart.h"
#include "ina226.h"

volatile unsigned int RXByte=0;
unsigned char TXData[] ={0, 0, 0, 0};                    // Pointer to TX data
unsigned char TXByteCtr=0;
unsigned char TXByteCnt=0;
unsigned char RXByteCnt=0;
volatile unsigned int RXWord=0;

void init_i2c() {

    P1SEL1 |= (BIT7 | BIT6);
    P1SEL0 &= ~(BIT7 | BIT6);

    uart_puts("I2C initialized\n\r");
}

void i2c_write_addr(unsigned int addr, unsigned char byte) {

    UCB0CTL1 = UCSWRST; // Enable Module Reset
        UCB0CTL0 |= UCMODE_3 | UCMST; // I2C, Master mode, ACLK 12MHz
        UCB0CTL1 |= UCSSEL__ACLK;
        UCB0BRW = 120;//200; //15;       // 24MHz/240 = 100kHz Clock, 24MHz/60 = 400kHz
        UCB0I2CSA = addr;
        UCB0CTLW1 = UCASTP_2; // Automatic stop and interrupt, reduce deglich to 25 ns
        UCB0CTLW0 |= UCTR; //Tranciever
        UCB0TBCNT = 1;
    UCB0CTL1 &= ~UCSWRST;

    UCB0IE |= UCNACKIE | UCTXIE0 | UCRXIE | UCBCNTIE | UCNACKIE | UCSTTIE | UCSTPIE;

    TXData[0] = byte;
    TXByteCtr = 1; // Load TX byte counter

    while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition

    __bis_SR_register(GIE + CPUOFF);        // Enter LPM0 w/ interrupts

    uart_puts("i2c_write_addr 6\n\r");
}


#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCIB0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void)
#else
#error Compiler not supported!
#endif
{
    LED1OUT |= LED1B;
    switch(__even_in_range(UCB0IV,0x1E)) {
        case 0x00: break; // Vector 0: No interrupts break;
        case 0x02: break; // Vector 2: ALIFG break;
        case 0x04:        // Vector 4: NACKIFG break;
              UCB0CTL1 |= UCTXSTT;  // Resend I2C start condition
              uart_puts("NACKIFG\n\r");
              break;
        case 0x06: break; // Vector 6: STTIFG break;
        case 0x08: break; // Vector 8: STPIFG break;
        case 0x0a: break; // Vector 10: RXIFG3 break;
        case 0x0c: break; // Vector 14: TXIFG3 break;
        case 0x0e: break; // Vector 16: RXIFG2 break;
        case 0x10: break; // Vector 18: TXIFG2 break;
        case 0x12: break; // Vector 20: RXIFG1 break;
        case 0x14: break; // Vector 22: TXIFG1 break;
        case 0x16:        // Vector 24: RXIFG0 break;
              RXByte = UCB0RXBUF;    // Get RX data
              RXWord = RXWord <<8;
              RXWord |= RXByte;
              uart_puts("RXIFG0\n\r");
              break;
        case 0x18:        // Vector 26: TXIFG0 break;
            if (TXByteCtr)                      // Check TX byte counter
            {
                TXByteCtr--;
                UCB0TXBUF = TXData[TXByteCtr];    // Load TX buffer
            }
            else
            {
                //UCB0IFG &= ~UCTXIFG;            // Clear USCI_B0 TX int flag
                //UCB0CTLW0 |= UCTXSTP;
                __bic_SR_register_on_exit(CPUOFF);// Exit LPM0
            }
            uart_puts("TXIFG0\n\r");
            break;
        case 0x1a:        // Vector 28: BCNTIFG break;
              uart_puts("BCNTIFG\n\r");
              __bic_SR_register_on_exit(CPUOFF); // Exit LPM0
              break;
        case 0x1c:        // Vector 30: clock low timeout break;
          LED1OUT ^= LED1B;
          __bic_SR_register_on_exit(CPUOFF); // Exit LPM0
          uart_puts("CLKLOWTO\n\r");
          break;
        case 0x1e: break; // Vector 32: 9th bit break;
        default: break;
    }
}

And my stripped down main.c

void configure_clock()
{
    FRCTL0 = FWPW | NACCESS_2 | NPRECHG_1; // Change the NACCESS_x value to add the right amount of waitstates

    // Configure Clock System
    CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
    CSCTL1 = DCOFSEL_3 | DCORSEL;                       // Set DCO = 24MHz
    CSCTL2 = SELA__DCOCLK | SELS__DCOCLK | SELM__DCOCLK;// Set ACLK=VLO SMCLK=DCO
    CSCTL3 = DIVA__2 | DIVS__1 | DIVM__2;     // Set all dividers (A=12MHz, S=24MHz, M=12MHz)
    CSCTL0_H = 0;                             // Lock CS registers
}

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    configure_clock();

    //Configure Debug UART
    init_uart_115200();

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    //Configure i2c
    init_i2c();

    _enable_interrupts();

    i2c_write_addr(U3_ADDR, 0xFE); // Already stops here
    uart_puts("INA216 ID: ");
    uart_puti(i2c_read_uint(U3_ADDR));

    while (1) {}
}
Thomas
  • 1,468
  • 4
  • 14
  • 20
  • NACK means that the slave did not answer. Correct address? – CL. Nov 05 '17 at 22:00
  • That's right, but a new start condition inside the ISR (UCB0CTL1 |= UCTXSTT;) should actually start a new try, and if the sensor would not answer, should result in another NACK, and a loop of NACK. But I only get one NACK, and the ISR is never called again after that. – Thomas Nov 06 '17 at 09:23
  • What does `uart_puts` do? Can it be run from inside an interrupt handler? – CL. Nov 06 '17 at 09:50
  • uart_puts writes to my debug uart. it's without any interrupts etc. I do not know if it is possible, i know it worked once already. But I also already deleted it and let just the LED toggle, and i did not see it toggling on the scope. – Thomas Nov 06 '17 at 10:20
  • (If it runs too long, it blocks other interrupts.) – CL. Nov 06 '17 at 10:31
  • Doesn't the compiler complain when you write 16-bit values to an 8-bit part of a register? Please forget about UCB0CTL0/1 and always use the entire register. – CL. Nov 06 '17 at 10:33
  • Mhm it did not, i found many examples where these UCB0CTL0/1 registers were used. But if you recommend it I will switch back, anyway I tried both combinations already. – Thomas Nov 07 '17 at 13:44

0 Answers0