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.

CCS/MSP430FR6047: I2C on UCB1 (P5.5 and P5.6) Not Working

Part Number: MSP430FR6047
Other Parts Discussed in Thread: MSP-TS430PZ100E, MSP-FET

Tool/software: Code Composer Studio

Hello!

I used the following code to use New Haven's LCD through I2C successfully with TDC1000-TDC7200 EVM (MS430F5528).

I recently bought MSP-TS430PZ100E and trying to achieve the same using P5.5 and P5.6. But it doesn't work. The LCD doesn't show anything and the pins doesn't show any sign of life when tested by oscilloscope. What am I missing or doing wrong? Here's the code. (I also tried the same using the sample codes from TI but none seems to give me any result.)

/*
* lcd.c
*
* Created on: 2015. 12. 9.
* Author: User
*/
#include <msp430.h>
#include <stdint.h>
#include "lcd.h"


uint8_t firstLine[20];
uint8_t secondLine[20];

#define LCD_I2C_PxOUT P5OUT //Port5
#define LCD_I2C_Px_IN P5IN //Port5
#define LCD_I2C_PxDIR P5DIR //Port4
#define LCD_I2C_SDA_PIN BIT5 //P5.5
#define LCD_I2C_SCL_PIN BIT6 //P5.6

/****************************************************
* Initialization For ST7036i *
*****************************************************/

unsigned int Slave= 0x78;
unsigned int Comsend = 0x00;
unsigned int Datasend=0x40;

/* A crude delay function. Tune by changing the counter value. */
void delay( unsigned int n ) {
volatile int i;

for( ; n; n-- ) {
for( i = 0; i < 50; i++ );
}
}


void data_read(void ) {
LCD_I2C_PxDIR &= ~LCD_I2C_SDA_PIN; // float to get ready to read
}

void data_high(void ) {

LCD_I2C_PxDIR &= ~LCD_I2C_SDA_PIN; // float pin to go high
delay( 5 );

}

void data_low(void ) {

LCD_I2C_PxOUT &= ~LCD_I2C_SDA_PIN; // assert low
LCD_I2C_PxDIR |= LCD_I2C_SDA_PIN;
delay( 5 );
}

void clk_high(void) {

LCD_I2C_PxDIR &= ~LCD_I2C_SCL_PIN; // float pin to go high
delay( 10 );

}

void clk_low(void) {

LCD_I2C_PxOUT &= ~LCD_I2C_SCL_PIN; // assert low
LCD_I2C_PxDIR |= LCD_I2C_SCL_PIN;
delay( 5 );
}
/*****************************************************/
/****************************************************
* I2C Start *
*****************************************************/
void I2C_Start(void)
{
__bic_SR_register(GIE);

P5SEL0 &= ~(BIT5 | BIT6);
P5SEL1 |= BIT5 | BIT6;
clk_high();
data_high();
data_low();
clk_low();
__bis_SR_register(GIE);

/*****************************************************/
/****************************************************
* I2C Stop *
*****************************************************/
void I2C_Stop(void)
{
__bic_SR_register(GIE);

data_low();
clk_low();
clk_high();
data_high();
__bis_SR_register(GIE);
}

/*****************************************************/
/****************************************************
* Output command or data via I2C *
*****************************************************/
void I2C_out(unsigned char d) //I2C Output
{
__bic_SR_register(GIE);

int n;

for( n = 0; n < 8; n++ )
{
if( d & 0x80 )
{
data_high();
}
else
{
data_low();
}

clk_high();
clk_low();

d <<= 1; // Shift next bit into position.
}

data_read(); // Set data line to receive.
clk_high(); // Clock goes high to wait for acknowledge.

// Slave will pull data line low to acknowledge.
//while( P1IN & I2C_SDA )
while( LCD_I2C_Px_IN & LCD_I2C_SDA_PIN )
{
// Else toggle the clock line and check again
clk_low();
data_high();
}

clk_low();
__bis_SR_register(GIE);
}

void init_LCD()
{
I2C_Start();

I2C_out( 0x78 ); // Slave address of the LCD panel.
I2C_out( 0x00 ); // Control byte: all following bytes are commands.
I2C_out( 0x38 ); // 8-bit bus, 2-line display, normal instruction mode.
delay( 10 );

I2C_out( 0x39 ); // 8-bit bus, 2-line display, extension instruction mode.
delay( 10 );

I2C_out( 0x14 ); // Bias set to 1/5.
I2C_out( 0x78 ); // Contrast set.
I2C_out( 0x5E ); // Icon display on, booster on, contrast set.
I2C_out( 0x6D ); // Follower circuit on, amplifier=1?
I2C_out( 0x0F ); // Display on, cursor off.
I2C_out( 0x01 ); // Clear display.
I2C_out( 0x06 ); // Entry mode set to cursor-moves-right.
delay( 10 );

I2C_Stop();
}

/* Sends the "clear display" command to the LCD. */
void clear_display(void)
{
I2C_Start();

I2C_out( 0x78 ); // Slave address of panel.
I2C_out( 0x00 ); // Control byte: all following bytes are commands.
I2C_out( 0x01 ); // Clear display.

I2C_Stop();
}

/*****************************************************/
/****************************************************
* Send string of ASCII data to LCD *
*****************************************************/
//이건 내가 만든 것
void PutOneChar(unsigned char* text)
{
__bic_SR_register(GIE);

I2C_Start();
I2C_out(0x78);
I2C_out(0x40);
I2C_out(*text);
I2C_Stop();
__bic_SR_register(GIE);

}
void Show(unsigned char *text)
{
//__bic_SR_register(GIE);

int n;

I2C_Start();

I2C_out( 0x78 ); // Slave address of panel.
I2C_out( 0x40 ); // Control byte: data bytes follow, data is RAM data.

for( n = 0; n < 20; n++ ) {
I2C_out( *text );
text++;
}
I2C_Stop();
//__bic_SR_register(GIE);
}

void MoveCursor(uint8_t nPos)
{
//__bic_SR_register(GIE);

I2C_Start();

I2C_out( 0x78 ); // Slave address of panel.
I2C_out( 0x00 ); // Control byte: all following bytes are commands.
I2C_out(0x80 + nPos);
I2C_Stop();
//__bis_SR_register(GIE);

}

void ShowBothLines()
{
//__bic_SR_register(GIE);

MoveCursor(0x00);
Show(firstLine);
MoveCursor(0x40);
Show(secondLine);
//__bis_SR_register(GIE);

// __delay_cycles(2500);
}
/*****************************************************/
/*****************************************************/
/*****************************************************/

Please help me. 

Sukho

  • I suspect you need "PM5CTL0 &= ~LOCKLPM5;" somewhere. This is not (usually) required on the F5 series, but it is on the FR6 series.

  • Dear Mr. McKenney;

    I sure did. The main code is as below (Also, the clock is set to 8 MHz. If this should have something to do with I2C working or not).

    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop WDT

    // Configure GPIO
    P1OUT &= ~(BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7); // Clear P1.0 output latch for a defined power-on state
    P1DIR |= (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7); // Set P1.0 to output direction

    Set_Clock();

    init_LCD();
    Show("MaxiFlo Heat Meter");

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

    while(1)
    {
    P1OUT ^= (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7); // Toggle LED

    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    __delay_cycles(100000);
    //Show("MaxiFlo Heat Meter");
    }
    }

  • So, what does your program do now that you've added that?

  • I meant that I had already had that part in the code when I asked this question.

    I also tried the example code, "msp430fr60x7_eusci_i2c_standard_master.c". But it doesn't seem to output anything through P5.5 and P5.6.

    What am I doing wrong???

    Please help me. I'm raking my brain for over 1 and a half week.

  • >P5SEL0 &= ~(BIT5 | BIT6);
    >P5SEL1 |= BIT5 | BIT6;

    Sorry, I missed these before. These put the pins under the control of the hardware I2C. To do software I2C (via GPIO), you should not do this. (I.e. Remove these lines.)

    --------------------

    msp430fr60x7_eusci_i2c_standard_master.c appears to use pins P1.6-7, not P5.5-6.

    http://dev.ti.com/tirex/explore/node?node=AG5STm.qMws-eKOuCPgqbA__IOGqZri__LATEST

  • Mr. McKenney;

    Oh, I see. Thanks. That method is not taking the advantage of the I2C functionality. It's uses what they call "bit banging", right?

    Anyways, I now get the outputs from P5.5 & P5.6 but somehow the MCU and the LCD are not talking to each other. I think that the MCU is not sending the message in the correct format. So, I captured the oscilloscope screen. The waveforms of both SCL and SDA don't seem right. They look somewhat crooked to my very novice eye. What do you suggest I try now to solve this? Please help me again.

    Regarding the TI's example code, yes. They use P1.6-7. But I cannot use it because the target board is using them for JTAG (MSP-FET). So, I opted for UCB1 P5.5-6. And I believe I revised the relevant elements in the rest of the example code to be coherent with that change.

    You shall know that your help is keeping me going... I appreciated it and await your help again.

  • The usual cause for slow (rising) edges is pullup resistors that are too weak. Software can accommodate to some extent by slowing down the I2C clock -- in your original code, that's the delay() function. [Unsolicited: I don't recommend doing a delay using a for() loop. I suggest __delay_cycles() instead.]

    Unless you're very confident of this bit-banging implementation, I recommend using the hardware I2C. The changes I recall are (1) the port pins (as you mentioned), (2) UCB0->UCB1, (3) USCI_B0_VECTOR->USCI_B1_VECTOR.

  • Thank you. And sorry for this late action.

    After getting some good waveform following your guidance,  realized that the pin orders were the other way around. How stupid of me. I managed to display the letters on the LCD.. Voila! But not quite so.

    There's still a strange thing. That is. when I connect the USB cable of the MSP-FET. The LCD doesn't wake up. And the LEDs in the 'while' loop doesn't blink. 

    Only when I short the SDA and SCL just briefly, the while loop starts working. And only after I initialize the LCD again, I start to see the LCD working. From this moment until I unplug the MSB-FET cable, the LCD keeps working no matter how many times I debug and load the programs on the Flash. But once I unplug the cable, I have to short SDA and SCL (P5.5 & P5.6, and also P5.3 & P5.4 act the same way)..

    Why do I have to short SDA and SCL? What am I doing wrong? Is there any way, I can go about not shorting SDA and SCL pins?

    I tried the hardware way but I don't see any output from the pins. I'll try more of it when I get over the hurdle.

    Please help me again......

  • One thing that I notice is that you're clearing LOCKLPM5 rather late. Clearing LOCKLPM5 clears the (locked) startup state for the GPIOs, so they're not fully functional until you do that.

    Init_LCD in particular depends on having fully-functioning GPIOs.

    There's usually no particular harm in clearing LOCKLPM5 very early, even right at the beginning. I suggest you try putting it, say, after your P1 configuration.

  • Mr. McKenney;

    Oh, that... I'll surely do that tomorrow. But let me tell you that I somehow managed to get it working by a giving long delay before initializing the LCD. But maybe that's not the right way. I'll follow your advice!!!

    Thank you. Nice man!

**Attention** This is a public forum