Other Parts Discussed in Thread: PCF8574, PCF8574A
Tool/software: Code Composer Studio
Hi, i have some issues in displaying some characters like the typpical 'Hello World' on my LCD 1602 using I2C communication protocol. I think that the problem is related to the ISR of I2C because when i execute the code step by step it blocks there and appears this message (which i don't know what it really means..):
I also paste my code to make sure that if anyone see any other problem which could cause me another problem in future or an optimization idea. All will be apreciate it. Thanks a lot!
#include <msp430.h>
#include <stdint.h>
#include <stdio.h>
// Variables for the LCD:
typedef unsigned char byte;
#define Enable_LCD 0x04
#define iluminacion_LCD 0x08
#define comando_LCD 0x00
#define dato_LCD 0x01
#define LCD_PCF8574_ADDRESS 0x3F
uint8_t *PTxData; // Pointer TX
uint8_t TXByteCtr; // Counter of bytes send
uint16_t volatile contador_milisegundos; // for counting ms for delay_ms
void Inicializacion_Relojes(void)
{
__bis_SR_register(SCG0); // Disable the FLL control loop
UCSCTL0 = 0x0000;
UCSCTL1 = DCORSEL_5; // range de 16MHz
UCSCTL2 = FLLD_0 | 487;
// (N + 1) * (FLLRef/n) = Fdcomsp430
// (487 + 1) * (32768/1) = 16MHz
UCSCTL3 = 0; // FLL SELREF = XT1CLK y divisor de FLL = 1 (FLLREFDIV = FLLREFCLK/1)
UCSCTL4 |= SELA_0 | SELS_4 | SELM_4;
// UCSCTL5 |= DIVA_0 | DIVS_0;
__bic_SR_register(SCG0); // Enable the FLL control loop
}
void USCIB1_init(byte slave_address)
{
P4SEL |= BIT2 | BIT1; // P4.1 --> UCB1SDA
// P4.2 --> UCB1SCL
UCB1CTL1 |= UCSWRST;
UCB1CTL0 |= (UCMST | UCMODE_3 | UCSYNC); // UCMST: Master; UCMODE_3: Modulo USCI como I2C; UCSYNC: Modo Sincrono
UCB1CTL1 |= (UCSSEL_2 | UCSWRST); // UCSSEL_2: SMCLK; UCSWRST: Usci sigue en estado Reset
UCB1BR0 = 160; // fSCL = SMCLK(16MHz)/160 = 100kHz
UCB1BR1 = 0;
UCB1I2CSA = slave_address;
UCB1CTL1 &= ~UCSWRST;
UCB1IE |= UCTXIE;
}
void delay_ms(uint16_t tiempo_milisegundos)
{
contador_milisegundos = 0;
TA1CTL |= MC_1; // UP MODE
TA1CCTL0 |= CCIE;
while(contador_milisegundos < tiempo_milisegundos);
TA1CTL |= MC_0; // STOP MODE
}
void init_TimerA1_ms(void) // Timer for counting every ms
{
TA1CCR0 = 16000-1;
TA1CTL |= TASSEL_2 | MC_0; // Reloj SMCLK, Frecuencia: 16 MHz. Modo Stop.
}
void I2C_send(byte addr, byte *buffer, byte numero_datos)
{
UCB1I2CSA = addr;
PTxData = buffer;
TXByteCtr = numero_datos;
UCB1CTL1 |= (UCTR | UCTXSTT);
__bis_SR_register(LPM0_bits + GIE);
__no_operation();
while(UCB1CTL1 & UCTXSTP);
}
void lcd_send_nibble_cmd(byte dato)
{
byte buffer[2];
byte dato_I2C_H;
dato_I2C_H = dato & 0xF0;
buffer[0] = dato_I2C_H | iluminacion_LCD | Enable_LCD | comando_LCD;
buffer[1] = dato_I2C_H | iluminacion_LCD | comando_LCD;
I2C_send(LCD_PCF8574_ADDRESS, buffer, 2);
}
void lcd_send_byte_data(byte dato)
{
byte buffer[4];
byte dato_I2C_H, dato_I2C_L;
dato_I2C_H = dato & 0xF0;
dato_I2C_L = (dato << 4) & 0xF0;
buffer[0] = dato_I2C_H | iluminacion_LCD | Enable_LCD | dato_LCD;
buffer[1] = dato_I2C_H | iluminacion_LCD | dato_LCD;
buffer[2] = dato_I2C_L | iluminacion_LCD | Enable_LCD | dato_LCD;
buffer[3] = dato_I2C_L | iluminacion_LCD | dato_LCD;
I2C_send(LCD_PCF8574_ADDRESS, buffer, 4);
}
void lcd_send_byte_cmd(byte dato)
{
byte buffer[4];
byte dato_I2C_H, dato_I2C_L;
dato_I2C_H = dato & 0xF0;
dato_I2C_L = (dato << 4) & 0xF0;
buffer[0] = dato_I2C_H | iluminacion_LCD | Enable_LCD | comando_LCD;
buffer[1] = dato_I2C_H | iluminacion_LCD | comando_LCD;
buffer[2] = dato_I2C_L | iluminacion_LCD | Enable_LCD | comando_LCD;
buffer[3] = dato_I2C_L | iluminacion_LCD | comando_LCD;
I2C_send(LCD_PCF8574_ADDRESS, buffer, 4);
}
void init_LCD_PCF8574(void)
{
delay_ms(20);
lcd_send_nibble_cmd(0x30);
delay_ms(5);
lcd_send_nibble_cmd(0x30);
delay_ms(1);
lcd_send_nibble_cmd(0x30);
delay_ms(5);
lcd_send_nibble_cmd(0x20); // LCD data bus with 4 bits
delay_ms(1);
lcd_send_byte_cmd(0x28); // N=1: 2 Filas; F=0: 5x8 puntos
delay_ms(1);
lcd_send_byte_cmd(0x08); // Display off, Cursor off, Blink off
delay_ms(1);
lcd_send_byte_cmd(0x01); // Clear Screen, Cursor Home
delay_ms(2);
lcd_send_byte_cmd(0x07); // Entry mode set; I/D=1: Incremento; S=1: Scroll de Display
delay_ms(10);
lcd_send_byte_cmd(0x0C); // Display ON, Cursor OFF, Cursor Blink
delay_ms(10); //
}
void lcd_setCursor(byte fila, byte columna)
{
byte address;
if (fila == 0){ // First row
address = 0;
}
else address = 0x40; // Segund row
address |= columna; // Para tener 0x00 + Columna (Fila1)
// Para tener 0x40 + Columna (Fila2)
lcd_send_byte_data(0x80 | address); // Set DDRAM Address
delay_ms(2);
}
void lcd_print(byte *string, uint8_t fila, uint8_t columna)
{
uint8_t tamaño; // Variable to count characters
lcd_setCursor(fila,columna);
while(*string != '\0')
{
lcd_send_byte_data(*string++);
tamaño++;
if(tamaño > (16-columna))
{
lcd_send_byte_cmd(0x18); // Display shift to left
}
}
delay_ms(2);
}
void main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
Inicializacion_Relojes();
USCIB1_init(LCD_PCF8574_ADDRESS);
init_TimerA1_ms();
__enable_interrupt();
init_LCD_PCF8574();
lcd_print("Hello World!",0,0);
}
#pragma vector=TIMER1_A0_VECTOR
__interrupt void timer1_A0_ISR(void){
contador_milisegundos++; // increment variable ms
TA1CCTL0 &= ~CCIFG;
}
#pragma vector = USCI_B1_VECTOR
__interrupt void usci_b1_isr(void)
{
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;
}
}