I am trying to set up a I2C communication with a I2C Display. Since I am a beginner I am struggling with the I2C interface.
My new Launch Pad and a PCB are already working fine. I have had a working communication via I2C to the same Display with other Hardware and the USI interface of a different MSP430 model. However, the MSP430G2553 does not have USI so that I had to reprogramm my software to the USCI Communication.
The Problem is, that the SCL and SDA are both going up to high state as soon as I activate the 4.5 k Ohm Pull up resistors.
However, the scope shows that they both never come back to low state anymore.
There is something wrong with my USCI Code but I can not find the error.
I found other users with similar Questions about USCI in this Forum but non of the proposed Solutions seems to fix my problem.
What did I do wrong? I would really appreciate your Help.
Here is my code. It uses the TI USCI communication library without DMA with my slight modifications.
#include "msp430G2553.h"
#include "TI_USCI_I2C_master.h"
unsigned char InitDisplayUSCI[] =
{
0x38, 0x80, // Function Set : Interface=8bit Lines=2 DoubleHight=0 InstructionTable(IS)=0, Command C0 RS 000000: CO=1 RS=0
0x39, 0x80, // Function Set : Interface=8bit Lines=2 DoubleHight=0 InstructionTable(IS)=0, Command C0 RS 000000: CO=1 RS=0
0x1C, 0x80, // Internal OSC freq: Bias=1/4 Frequency=4, Command C0 RS 000000: CO=1 RS=0
0x7F, 0x80, // Contrast Set: Displayspannung=78 0x70 bis 0x7F, Command C0 RS 000000: CO=1 RS=0
0x5E, 0x80, // Pwr/ICON/Contrast Set: Icons=1 Booster=1 Contrast=2, Command C0 RS 000000: CO=1 RS=0
0x6B, 0x80, // Follower Control: Follower=1 Verstaerkung=2 (6A) (0-7), Command C0 RS 000000: CO=1 RS=0
// Wait 200 ms for Power Stable before Display ON... (clear unused icons instead)
0x40, 0xC0, // Set Antenna Icon Address
0x00, 0x80, // Clear Antenna Icon
0x42, 0xC0, // Set Phone Icon Address
0x00, 0x80, // Clear Phone Icon
0x44, 0xC0, // Set Alarm Icon Address
0x00, 0x80, // Clear Alarm Icon
0x4B, 0xC0, // Set NoSound Icon Address
0x00, 0x80, // Clear NoSound Icon
0x4F, 0xC0, // Set Money Icon Address
0x00, 0x80, // Clear Money Icon
// Wait time is over now, Switch Display On
0x0F // Display On: DisplayOn=1 CursorOn=1 CursorPos=1
};
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
// Beschleunigungssensor und I2C Stromversorgung
P3DIR |= 0x20; // Setzte P3.5 in Output Richtung
P3OUT |= 0x20; // I2C Stromversorgung einschalten auf P3.5
// Display Stromversorgung
P3DIR |= 0x80; // Set P3.7 to output direction
P3OUT |= 0x80; // Turn on Display on P3.7
BCSCTL1 = CALBC1_1MHZ; // Set DCO
DCOCTL = CALDCO_1MHZ;
_EINT();
//__enable_interrupt();
TI_USCI_I2C_transmitinit(0x7C,0x08); // init transmitting with USCI
while ( TI_USCI_I2C_notready() ); // wait for bus to be free
TI_USCI_I2C_transmit(0x20,InitDisplayUSCI); // transmit Init Display Command
// The code runs thru to here but there is no communication on the SDA and SCL pins.
// If I set the breakpoint on the LPM3 line it is triggered. Therefore the hole code is executed...
LPM3;
}
Then there is the modified I2C Library. My changes are marked in Red.
TI_USCI_I2C_master.h
#define SDA_PIN 0x80 // msp430G2553 UCB0SDA pin
#define SCL_PIN 0x40 // msp430G2553 UCB0SCL pin
void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale);
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale);
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field);
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field);
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address);
unsigned char TI_USCI_I2C_notready();
The code of the I2C Library has also been altered slightly to fit the Device.
TI_USCI_I2C_master.c
#include "msp430G2553.h" // device specific header
#include "TI_USCI_I2C_master.h"
signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;
//------------------------------------------------------------------------------
// void TI_USCI_I2C_receiveinit(unsigned char slave_address,
// unsigned char prescale)
//
// This function initializes the USCI module for master-receive operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//-----------------------------------------------------------------------------
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
unsigned char prescale){
P1SEL |= SDA_PIN + SCL_PIN; // 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 = prescale; // set prescaler
UCB0BR1 = 0;
UCB0I2CSA = slave_address; // set slave address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE = UCNACKIE;
IE2 = UCB0RXIE; // Enable RX interrupt
}
//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmitinit(unsigned char slave_address,
// unsigned char prescale)
//
// This function initializes the USCI module for master-transmit operation.
//
// IN: unsigned char slave_address => Slave Address
// unsigned char prescale => SCL clock adjustment
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
unsigned char prescale){
P1SEL |= SDA_PIN + SCL_PIN; // 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 = prescale; // set prescaler
UCB0BR1 = 0;
UCB0I2CSA = slave_address; // Set slave address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE = UCNACKIE;
IE2 = UCB0TXIE; // Enable TX ready interrupt
}
//------------------------------------------------------------------------------
// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-receiver mode.
//
// IN: unsigned char byteCount => number of bytes that should be read
// unsigned char *field => array variable used to store received data
//------------------------------------------------------------------------------
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
TI_receive_field = field;
if ( byteCount == 1 ){
byteCtr = 0 ;
__disable_interrupt();
UCB0CTL1 |= UCTXSTT; // I2C start condition
while (UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition
__enable_interrupt();
} else if ( byteCount > 1 ) {
byteCtr = byteCount - 2 ;
UCB0CTL1 |= UCTXSTT; // I2C start condition
} else
while (1); // illegal parameter
}
//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-transmit mode.
//
// IN: unsigned char byteCount => number of bytes that should be transmitted
// unsigned char *field => array variable. Its content will be sent.
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
TI_transmit_field = field;
byteCtr = byteCount;
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
}
//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
//
// This function is used to look for a slave address on the I2C bus.
//
// IN: unsigned char slave_address => Slave Address
// OUT: unsigned char => 0: address was not found,
// 1: address found
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
ucb0i2cie = UCB0I2CIE; // restore old UCB0I2CIE
ie2_bak = IE2; // store IE2 register
slaveadr_bak = UCB0I2CSA; // store old slave address
UCB0I2CIE &= ~ UCNACKIE; // no NACK interrupt
UCB0I2CSA = slave_address; // set slave address
IE2 &= ~(UCB0TXIE + UCB0RXIE); // no RX or TX interrupts
__disable_interrupt();
UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP; // I2C TX, start condition
while (UCB0CTL1 & UCTXSTP); // wait for STOP condition
returnValue = !(UCB0STAT & UCNACKIFG);
__enable_interrupt();
IE2 = ie2_bak; // restore IE2
UCB0I2CSA = slaveadr_bak; // restore old slave address
UCB0I2CIE = ucb0i2cie; // restore old UCB0CTL1
return returnValue; // return whether or not
// a NACK occured
}
//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_notready()
//
// This function is used to check if there is commuincation in progress.
//
// OUT: unsigned char => 0: I2C bus is idle,
// 1: communication is in progress
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_notready(){
return (UCB0STAT & UCBBUSY);
}
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
if (UCB0STAT & UCNACKIFG){ // send STOP if slave sends NACK
UCB0CTL1 |= UCTXSTP;
UCB0STAT &= ~UCNACKIFG;
}
}
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
if (IFG2 & UCB0RXIFG){
if ( byteCtr == 0 ){
UCB0CTL1 |= UCTXSTP; // I2C stop condition
*TI_receive_field = UCB0RXBUF;
TI_receive_field++;
}
else {
*TI_receive_field = UCB0RXBUF;
TI_receive_field++;
byteCtr--;
}
}
else {
if (byteCtr == 0){
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
}
else {
UCB0TXBUF = *TI_transmit_field;
TI_transmit_field++;
byteCtr--;
}
}
}