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.
Tool/software: Code Composer Studio
Hi,
I'm struggeling with making i2c communication work properly. I'm working on MSP430F5529, I2C target device is DS2482-100 but right now I'm testing I2C communication on LCD (because I'm sure hardware connection and commands are fine, I got it working with MSP430G2452).
The code I'm running is:
#include <msp430.h> volatile unsigned char PTxData; // Pointer to TX data volatile unsigned char TXByteCtr; unsigned int i = 0; const unsigned char TxData[] = // Table of data to transmit { 0x78, 0xF1, 0x67, 0xC0, 0x40, 0x50, 0x2B, 0xEB, 0x81, 0x5F, 0x89, 0xAF }; int main(void) { UCB0IE = 0x00; WDTCTL = WDTPW + WDTHOLD; // Stop WDT P3SEL |= 0x03; while (1) { _disable_interrupts(); // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz UCB0BR1 = 0; UCB0I2CSA = 0x60; // Slave Address is 048h UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE |= UCTXIE; // Enable TX interrupt UCB0IFG = 0xFF; _enable_interrupts(); unsigned int over = 0; _delay_cycles(100000); over = 0; i = 0; while (over == 0) { _delay_cycles(1000); // Delay required between transaction PTxData = TxData[i]; TXByteCtr = sizeof TxData; UCB0CTL1 |= UCTR + UCTXSTT; i++; if (i > TXByteCtr) over = 1; while (UCB0CTL1 & UCTXSTP) ; // Ensure stop condition got sent } } } #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 { 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 case 10: break; // Vector 10: RXIFG case 12: // Vector 12: TXIFG if (TXByteCtr) // Check TX byte counter { UCB0TXBUF = PTxData; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB0CTL1 |= UCTXSTP; // I2C stop condition UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } default: break; } }
This:
const unsigned char TxData[] = // Table of data to transmit { 0x78, 0xF1, 0x67, 0xC0, 0x40, 0x50, 0x2B, 0xEB, 0x81, 0x5F, 0x89, 0xAF };
are commands that should init LCD and set random pixels on it but nothing happens.
I only have single channel osciloscope, these are readings of SDA and SCL lines:
Time laps differ for SDA (50us) and SCL(20us).
What am I doing wrong?
And what about launchpad jumpers? Should I keep all as it was or should I change something? Previous photos were with all jumpers as they were, now I'm thinking maybe it's wrong? I tried to run programm with RXD and TXD jumpers taken off, here's what I got:
This was both SCL line.
Best regards,
toann
I commented line:
UCB1IE |= UCTXIE;
because the program was stacking in
__TI_ISR_TRAP: BIS.W #(0x0010),SR JMP __TI_ISR_TRAP //<-here
Then I checked registers. It looks like the value in UCB1TXBUF is changing but the output (SDA line) is the value of UCB1I2CSA all the time. I have also set some breakpoints:
case 12: if (TXByteCtr) { UCB1TXBUF = PTxData; //<- here TXByteCtr--; } else { UCB1CTL1 |= UCTXSTP; UCB1IFG &= ~UCTXIFG; //<- and here __bic_SR_register_on_exit(LPM0_bits); }
but the program never stopped there.
Whole code right now:
const unsigned char TxData[] = // Table of data to transmit { 0x78 , 0xF1 , 0x67 , 0xC0 , 0x40 , 0x50 , 0x2B , 0xEB , 0x81 , 0x5F , 0x89 , 0xAF }; int main(void) { UCB1IE = 0x00; WDTCTL = WDTPW + WDTHOLD; // Stop WDT P4SEL |= 0x06; while (1) { __disable_interrupt(); // Assign I2C pins to USCI_B0 UCB1CTL1 |= UCSWRST; // Enable SW reset UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB1BR0 = 12; // fSCL = SMCLK/12 = ~100kHz UCB1BR1 = 0; UCB1I2CSA = 0x78; // Slave Address is 048h UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation // UCB1IE |= UCTXIE; // Enable TX interrupt UCB1IFG = 0x00; __enable_interrupt(); unsigned int over = 0; _delay_cycles(100000); over = 0; i = 0; while (over == 0) { _delay_cycles(100); // Delay required between transaction PTxData = TxData[i]; UCB1TXBUF = PTxData; TXByteCtr = sizeof TxData; UCB1CTL1 |= UCTR + UCTXSTT; i++; if (i > TXByteCtr) over = 1; while (UCB1CTL1 & UCTXSTP) ; // Ensure stop condition got sent } } } #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 { switch (__even_in_range(UCB1IV, 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 case 10: break; // Vector 10: RXIFG case 12: // Vector 12: TXIFG if (TXByteCtr) // Check TX byte counter { UCB1TXBUF = PTxData; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB1CTL1 |= UCTXSTP; // I2C stop condition UCB1IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } default: break; } }
Oscilloscope readings:
Okay, so I moved all from main() into ISR:
UCB1CTL1 |= UCTR + UCTXSTT; while (over == 0) { _delay_cycles(100); // Delay required between transaction }
case 12: // Vector 12: TXIFG TXByteCtr = sizeof TxData; while (over == 0) { if (i < TXByteCtr) // Check TX byte counter { UCB1TXBUF = TxData[i]; // Load TX buffer i++; //TXByteCtr--; // Decrement TX byte counter while (UCB1CTL1 & UCTXSTP) ; } else { over = 1; UCB1CTL1 |= UCTXSTP; // I2C stop condition UCB1IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag over = 1; __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } }
SCL is still being held down for some reason but finally something else than 0x78 showed up on SDA.
I still didn't manage to get it working :( I tried MSP4320F55xx_uscib0_i2c_08.c, also didn't work. I first of all I figured out I had some problems with timing (that's why SCL seemed to be hold by slave, it was waiting for response that couldn't be sent because of bad timing). Now the timing is fine, SCL looks good but SDA keeps sending slave address instead of data I'm expecting it to be sending.
Can you please check again if I'm not making some stupid mistakes?
const unsigned char TxData[] = // Table of data to transmit { 0x00,0xF1, 0x67}; int main(void) { UCB1IE = 0x00; WDTCTL = WDTPW + WDTHOLD; // Stop WDT P4SEL |= 0x06; initClock(); while (1) { __disable_interrupt(); // Assign I2C pins to USCI_B0 UCB1CTL1 |= UCSWRST; // Enable SW reset UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB1BR0 = 32; // fSCL = SMCLK/12 = ~100kHz //2===209k, 3==200k, 6==40k UCB1BR1 = 32; UCB1I2CSA = 0x7A; // Slave Address is 048h UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB1IE |= UCTXIE; // Enable TX interrupt UCB1IFG = 0x00; __enable_interrupt(); UCB1CTL1 |= UCTR + UCTXSTT; TXByteCtr = sizeof TxData; if (over == 1) { over = 0; __delay_cycles(100000); __delay_cycles(100000); } P2OUT |=128; } } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B1_VECTOR __interrupt void USCI_B1_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B1_VECTOR))) USCI_B1_ISR (void) #else #error Compiler not supported! #endif { switch (__even_in_range(UCB1IV, 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 case 10: break; // Vector 10: RXIFG case 12: // Vector 12: TXIFG if (i < TXByteCtr) // Check TX byte counter { UCB1TXBUF = TxData[i]; // Load TX buffer i++; //TXByteCtr--; // Decrement TX byte counter while (UCB1CTL1 & UCTXSTP) ; } else { over = 1; UCB1CTL1 |= UCTXSTP; // I2C stop condition UCB1IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag i = 0; __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } default: break; } }
When I try debug this example, program never reaches __no_operation(), it hangs somewhere between leaving "case 12" and __no_operaton(). When I paused debugging, all that was there was "No source available for "0x2402". At the same time register UCB0TXBUF contains first element of TxData.
Yes, all I changed was slave address, TxData and B0 register to B1.
#include <msp430.h> unsigned char *PTxData; // Pointer to TX data unsigned char TXByteCtr; const unsigned char TxData[] = // Table of data to transmit { 0xF1, 0x67, 0xC0, 0x40, 0x50, 0x2B, 0xEB, 0x81, 0x5F, 0x89, 0xAF }; int main(void) { unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT P4SEL |= 0x06; // Assign I2C pins to USCI_B1 UCB1CTL1 |= UCSWRST; // Enable SW reset UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB1BR0 = 2; // fSCL = SMCLK/12 = ~100kHz UCB1BR1 = 0; UCB1I2CSA = 0x78; // Slave Address is 048h UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB1IE |= UCTXIE; // Enable TX interrupt while (1) { for (i = 0; i < 10; i++) ; // Delay required between transaction PTxData = (unsigned char *) TxData; // TX array start address // Place breakpoint here to see each // transmit operation. TXByteCtr = sizeof TxData; // Load TX byte counter UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts __no_operation(); // Remain in LPM0 until all data // is TX'd while (UCB1CTL1 & UCTXSTP) ; // Ensure stop condition got sent } } //------------------------------------------------------------------------------ // The USCIAB1TX_ISR is structured such that it can be used to transmit any // number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData // points to the next byte to transmit. //------------------------------------------------------------------------------ #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B1_VECTOR __interrupt void USCI_B1_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B1_VECTOR))) USCI_B1_ISR (void) #else #error Compiler not supported! #endif { switch (__even_in_range(UCB1IV, 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 case 10: break; // Vector 10: RXIFG case 12: // Vector 12: TXIFG if (TXByteCtr) // Check TX byte counter { UCB1TXBUF = *PTxData++; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB1CTL1 |= UCTXSTP; // I2C stop condition UCB1IFG &= ~UCTXIFG; // Clear USCI_B1 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } default: break; } }
Based on the F5 User Guide (SLAU208P) Table 38-11 and the LCD data sheet p. 5 (tables at bottom) I think you want to use I2CSA=0x3C (Command) and 0x3D (Data). The USCI will shift that value and OR in the (inverted) UCTR bit for you.
This is different from the USI since for that you need to construct your own address byte (doing the shift+OR yourself).
[Edit: Fix UCTR sense.]
**Attention** This is a public forum