1
\$\begingroup\$

So I need to get an I2C up and running. To do so the µC relies on ISR's to push data byte by byte onto the data-line. So far so good I programmed my functions and ISR's to transmit and receive data. I enabled the Global Interrupt and the interrupts from the I2C, that i need for functioning. I can also visualize (via LCD) that the Interrupt Flag (say UCB0TXIFG, for transmission) is internally set.

Here's my problem: The interrupt just doesn't trigger. What I'm after is something that i have missed, that is normally done, but i forgot. I have a lot of programming experience and I had ISR's on Pins up and running.

If anyone has any idea, i would appreciate.

Regards, Steve Code down below.

MAIN:

int main(void) {
    // initialize MSP430 and its Ports...
    initMSP();
    if (port_init(8, 2) || port_init(8, 3) || port_init(8, 1)) {
        return 1;
    }
    // initialize the LCD
    lcd_init();
    peep();
    // Initialize the I2C-Hardware with correct address
    i2c_init(0x48); // initialize I2C with Address for the PCF8591T
    __enable_interrupt();
    peep();
    i2c_write(2, "Tÿ", 1); // Write something to bus. <Tÿ> is 0x54FF.
    lcd_putMsg("It's over...");
    while (1) {
        peep2();
        peep2();
    }
}

Comments:

  • peep-Functions just let an LED blink.
  • LCD works.
  • Port-Initialization works also.

I2C:

void i2c_init (unsigned char addr) {
    // initiate pins for use with I2C
    set_pin(6, 1, USCI);
    set_pin(7, 1, USCI);
    // Set I2C in reset state (hard)
    UCB0CTL1 |=  0x01;   // generate Software reset (!all current progress in transmission/reception is lost!)
    // Set up SMCLK Clock (SMLCK = MCLK = 16MHz => Divider for I2C is 160 for 100 kHz)
    BCSCTL2  &= ~0x0F;   // Sets DCO-Resistor to internal, SMCLK Divider to 1, and select DCOCLK for SMCLK
    // Set up I2C Interface Hardware
    UCB0CTL0  =  0x0F;   // 7-bit-mode, single-master, master mode, I2C-mode, synchronous
    UCB0CTL1 |=  0x81;   // SMCLK-Clock, I2C in Reset-State (Bits 6-1 are for online controlling)
    UCB0BR0   =  0xA0;   // Baudrate control register 0 + 1 (Baudrate = BR0 + BR1 * 256)
    UCB0BR1   =  0x00;   // for I2C the baudrate defines a clock prescaler, thus => 16MHz / 100kHz = 160 = 0xA0
    UCB0I2CIE =  0x04;   // only enable interrupt "UCNACKIFG" on NACK received.
    UCB0I2COA =  0x8004; // Don't respond to general call, Address of device is 0x04
    UCB0I2CSA =  0x0000 | (addr & 0x7F); // first chop eventually left MSB of <addr> then convert it to 16 bits.
    UC0IE    |=  0x0C;   // enable ISRs for UCB0TXIFG (Transmit) and UCB0RXIFG (Receive)
    IFG2     &= ~0x0C;   // kill all pending interrupts.
    // Activate I2C on Extension Board
    set_pin(3, 1, HIGH); // Activate I2C on Extension Board. (e.g. Connect XSDA/-SCL to I2C-Lines)
    // Release I2C from reset
    UCB0CTL1 &= ~0x01;   // Set Reset-Bit to Zero
    // Printing initialization message.
    (*print)("I2C initialized.Address: 0x");
    char ret0 = 'Y';
    char ret1 = 'Y';
    charToHex(addr & 0x7F, &ret0, &ret1);
    lcd_putChar(ret1);
    lcd_putChar(ret0);
    return;
}


/* only registers applicable from here:
 * UCB0CTL1 & ( BIT4 (UCTR)      | BIT2 (UCTXSTP)   | BIT1 (UCTXSTT) )
 * UC0IFG2  & ( BIT3 (UCB0TXIFG) | BIT2 (UCB0RXIFG) )
 * UCB0STAT & ( BIT4 (UCBBUSY)   | BIT3 (UCNACKIFG) )
 * */

unsigned char i2c_write(unsigned char length, unsigned char * txData, unsigned char stop) {
    lcd_putMsg("Waiting...      UCB0TXIFG is "); // Debug Message.
    if (IFG2 & UCB0TXIFG) {
        lcd_putNumber(1);
    } else {
        lcd_putNumber(0);
    }
    peep();
    // Before writing, you should always check if the last STOP-condition has already been sent.
    while (UCB0CTL1 & UCTXSTP);
    transferFinished = 0; // Reset Software Flag
    // rw_mem is a volatile container to hand necessary data
    // to ISR and back to MAIN; initialized here
    rw_mem.lenght = length;
    rw_mem.stop = stop;
    rw_mem.currByte = 0;
    rw_mem.txData = txData;
    rw_mem.outcome = 0;
    UCB0CTL1 |= UCTR; // Set Transmitter-Mode
    UCB0CTL1 |= UCTXSTT; // Start Protocol
    // Here MSP430 should jump immediately into ISR for UCB0TXIFG (Family Guide S.460)
    while(!transferFinished) { // Wait for transfer to be finished.
        peep(); // Peep helps determine if UC is stuck...
        lcd_putMsg("Waiting...      UCB0TXIFG is "); // Debug Message.
        if (IFG2 & UCB0TXIFG) {
            lcd_putNumber(1);
        } else {
            lcd_putNumber(0);
        }
    }
    return rw_mem.outcome;
}

void i2c_read(unsigned char length, unsigned char * rxData) {
    // Before writing, you should always check if the last STOP-condition has already been sent.
    while (UCB0CTL1 & UCTXSTP);


    if (length == 1) {
        // Todo: If you only want to receive one byte, you instantly have to write a STOP-condition
        // after the START-condition got sent.
    }

    // Wait for transfer to be finished.
    // Info: In TI's sample code, low-power mode statements are inserted,
    // also waiting for the transfer to be finished.
    while(!transferFinished);
}

// Vector for UCB0(T/R)XIFG (only in I2C)
// UCB0TXIFG    / TRANSMIT
// UCB0RXIFG    / RECEIVE
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{ // first check which interrupt actually triggered the ISR
    lcd_putMsg("Heading to ISR"); // Debug
    if (IFG2 & UCB0TXIFG) { // TX triggered ISR
        // check were the writing process it at exactly
        if (rw_mem.currByte >= rw_mem.lenght) { // length equals currByte => All bytes were written
            transferFinished = 1; // Transfer is finished
            rw_mem.outcome = 0; // Outcome of transfer was positive (all bytes transferred and acknowledged)
            if (rw_mem.stop) {UCB0CTL1 |=  UCTXSTP;} // Initiate Stop if appropriate
            IFG2  &= ~UCB0TXIFG; // Clear ISR-Flag
        } else { // in the other case, bytes are left
            UCB0TXBUF = rw_mem.txData[rw_mem.currByte]; // write next byte to buffer
            rw_mem.currByte++; // iterate counter on step up
            // I did not clearly see, from Family Guide,
            // if Flag-Reset is done by software or hardware,
            // though it says not explicitly to do so
            IFG2  &= ~UCB0TXIFG; // Clear ISR-Flag
        }
    }
    if (IFG2 & UCB0RXIFG) { // RX triggered ISR
        transferFinished = 1;
    }
lcd_putMsg("Leaving ISR"); // Debug
peep();
__delay_cycles(160000000); // 10 seconds
}

// Vector for status Flags (only in I2C)
// UCNACKIFG    / NACK
// UCSTPIFG     / STOP
// UCSTTIFG     / START
// UCALIFG      / ARBITRATION LOST
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{ // as of now, NACK is the only possible flag. Implementing if-loop none-the-less for redudancy's sake
    if (UCB0STAT & UCNACKIFG) { // NACK triggered ISR
        rw_mem.outcome = 1; // Outcome of Transfer was negative. (NACK)
        transferFinished = 1; // transfer is UNSUCCESSFULLY finished.
        UCB0CTL1 |=  UCTXSTP; // Initiate Stop
        UCB0STAT &= ~UCNACKIFG; // Resetting flag, again guide is unclear.
    }
}

So, the problem is, that decpite the flag UCB0TXIFG being 1 its interrupt UCB0TXIE enabled and the GIE enabled, The vector USCIAB0TX_ISR does not trigger.

Would appreciate any ideas.

Thanks in advance.

EDIT: enter image description here

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Please show an oscilloscope or logic analyzer trace of the I²C lines. \$\endgroup\$
    – CL.
    May 25, 2023 at 19:59

1 Answer 1

1
\$\begingroup\$

So I solved it in the meantime…

My problem was, that I had reset the hold bit (UCB0CTL1 &= ~0x01) after enabling the Interrupts (IFG2) in the I2c_init function, which where then reseted and thus not triggering.

So to solve the problem just switch the Statement UCB0CTL1 &= ~0x01; to before UCB0I2CIE = 0x04;

You can also look up section 13.1.7 of the family guide for more info on that.

Cheers guys.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.