Hi,
My USI i2c LCD code does not want to work properly if SD16_A interrupt is not disabled.
These 2 lines do not work (see in the code below)
LCD_Cmd(0xC0); // Set Line2 (position for output)
printf ("%u ",SD16MEM0); // SD16MEMO
and LCD freezed with last message [Ready for start!]
The code works fine if I disable SD16_A interrupt before USI i2C LCD output.
(just uncomment 2 lines ### inside while (1) cycle)
Could you explain, why there is a conflict between SD16_A and USI interrupts?
/******************************************************************************
* SD16_A + I2C output (23 Feb 2015)
******************************************************************************/
// BASED ON TI SAMPLE APPLICATION:
//******************************************************************************
//
//
// MSP430F20x3 Demo - SD16A, Sample A1+ Continuously, Set P1.0 if > 0.3V
//
// Description: A continuous single-ended sample is made on A1+ using internal
// VRef Unipolar output format used.
// Inside of SD16 ISR, if A1 > 1/2VRef (0.3V), P1.0 set, else reset.
// ACLK = n/a, MCLK = SMCLK = SD16CLK = default DCO
//
// MSP430F20x3
// ------------------
// /|\| XIN|-
// | | |
// --|RST XOUT|-
// | |
// Vin+ -->|A2+ P1.4 (4) |
// |A2- = VSS P1.0|-->LED
// | |
//
// M. Buccini / L. Westlund
// Texas Instruments Inc.
// October 2005
// Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.40A
//******************************************************************************
#include "msp430f2013.h"
#include "stdbool.h"
// Function Definitions
void Master_Transmit(void); // DRIVER I2C LCD WX1602
void Master_Recieve(void);
void Setup_USI_Master_TX(void);
void Setup_USI_Master_RX(void);
void Data_TX (void);
void Data_RX (void);
void LCD_Init(void); // FRIVER LCD
void LCD_Cmd(unsigned char sym);
void LCD_Print(unsigned char sym);
void LCD_Clear(void);
void Clear_Line1 (void);
void Clear_Line2 (void);
void printf(char *, ...);
void putc (unsigned char c);
unsigned char number_of_bytes = 1;
// Variables
unsigned char *MST_Data;
const unsigned char Slave_Address = 0x74; //WX1602
int I2C_State, Bytecount, Transmit_i2c = 0; // State variable
unsigned int i; // for loop variable
// LCD specific commands
unsigned char init[12] = {0,0,0x35,0x02,0x04,0x08,0x12,0x41,0x98,0x34,0x06,0x0C};
unsigned char symbol[3] = {0x40,0x40,0x35};
unsigned char command[3] = {0,0,0xC0};
unsigned char clear[3] = {0,0,0x02};
// *************************************************************************
// *************************************************************************
// *************************************************************************
// *************************************************************************
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // SMCLK = DCO = 1MHz
// Hello world!
P1DIR |= BIT0; // LED1 (red)
P1OUT |= BIT0; // Turn on RED LED at P1.0
__delay_cycles (400000); // Delay
P1OUT &= ~BIT0; // Turn off RED LED at P1.0
__delay_cycles (100000); // Delay
LCD_Init();
printf ("23.02.2015 ");
LCD_Cmd(0xC0); // Set Line 2
printf ("Sigma-Delta ADC ");
__delay_cycles (500000); // just delay
// SD16_A Init
// ===========
SD16CTL = SD16REFON + SD16SSEL_1; // 1.2V ref, SMCLK
SD16INCTL0 = SD16INCH_2; // P1.4 A2+/-
SD16CCTL0 = SD16UNI; // 256OSR, unipolar, interrupt enable
SD16CCTL0 |= SD16OSR_1024; // over sample rate is 1024
SD16CCTL0 |= SD16IE; // interrupt enable
__delay_cycles (50000); // Delay for 1.2V ref startup
Clear_Line2 ();
printf ("Ready for start!");
__delay_cycles (800000); // just delay 0.8 sec
while(1)
{
// SD16CCTL0 |= SD16IE; // ### interrupt enable
SD16CCTL0 |= SD16SC; // Set bit to start conversion
__bis_SR_register(LPM0_bits + GIE); // wait for SD16_A interrupt
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// IF WE DO NOT DISABLE SD16_A INTERRUPT
// WE CANT SEE ANYTHING NEW ON LCD - WHY?
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// SD16CCTL0 &= ~SD16IE; // ### interrupt disable
LCD_Cmd(0xC0); // Set Line2 (position for output)
printf ("%u ",SD16MEM0); // SD16MEMO
P1OUT |= BIT0; // Turn on RED LED at P1.0
__delay_cycles (100000); // Delay for LED indication
P1OUT &= ~BIT0; // Turn off RED LED at P1.0
__delay_cycles (300000); // Delay for LCD indication
}
}
//******************************************************************************
// DRIVER I2C LCD WX1602
//******************************************************************************
void LCD_Init(void)
{
// LCD PORT INIT
// -------------
P1OUT |= BIT7+BIT6+BIT2; // P1.6 & P1.7 - I2C, P1.2-Power-On-Rest
P1REN |= BIT7+BIT6; // P1.6 (blue wire) & P1.7 (green wire) Pullups
P1DIR |= BIT7+BIT6+BIT2; // LCD pins as outputs
__delay_cycles (100000); // Delay for LCD POR
P1OUT &= ~BIT2; // finish LCD power on reset (P1.2)
__delay_cycles (1000); // Delay
// send initializatuion string into LCD
number_of_bytes = 11;
MST_Data = init; // pointer to chunk of bytes
Setup_USI_Master_TX(); // I2C to tx mode
USICTL1 |= USIIFG; // Set flag and start communication
LPM0; // CPU off, await USI interrupt
__delay_cycles (1000);
}
// **************************************************
void LCD_Cmd(unsigned char sym)
{
command[2] = sym; // change dummy byte to char for output
number_of_bytes = 2;
MST_Data = command;
Setup_USI_Master_TX();
USICTL1 |= USIIFG; // Set flag and start communication
LPM0; // CPU off, await USI interrupt
__delay_cycles (1000); // Delay
}
// **************************************************
void LCD_Print(unsigned char sym)
{
symbol[2] = (sym ^ 0x80); // because of [char table not equal to HD44780]
number_of_bytes = 2;
MST_Data = symbol;
Setup_USI_Master_TX();
USICTL1 |= USIIFG; // Set flag and start communication
LPM0; // CPU off, await USI interrupt
}
// **************************************************
void LCD_Clear(void)
{
number_of_bytes = 2;
MST_Data = clear;
Setup_USI_Master_TX();
USICTL1 |= USIIFG; // Set flag and start communication
LPM0; // CPU off, await USI interrupt
for( i = 0; i < 80; i++ )
{
LCD_Print(' ');
}
}
// **************************************************
void Clear_Line2 (void)
{
LCD_Cmd(0xC0); // Set Line2
for( i = 0; i < 16; i++ )
{
LCD_Print(' ');
}
LCD_Cmd(0xC0); // Set Line2
}
// ********************************************
void Clear_Line1 (void)
{
LCD_Cmd(0x80); // Set Line1
for( i = 0; i < 16; i++ )
{
LCD_Print(' ');
}
LCD_Cmd(0x80); // Set Line1
}
/******************************************************
// SD16_A interrupt
******************************************************/
#pragma vector = SD16_VECTOR
__interrupt void SD16ISR(void)
{
SD16CCTL0 &= ~SD16IFG ;
__low_power_mode_off_on_exit () ;
}
/******************************************************
// USI interrupt service routine
// Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14
// Data Recieve : state 0 -> 2 -> 4 -> 6 -> 8 -> 14
******************************************************/
#pragma vector = USI_VECTOR
__interrupt void USI_TXRX (void)
{
switch(__even_in_range(I2C_State,14))
{
case 0: // Generate Start Condition & send address to slave
Bytecount = 0;
USISRL = 0x00; // Generate Start Condition...
USICTL0 |= USIGE+USIOE;
USICTL0 &= ~USIGE;
if (Transmit_i2c == 1){
USISRL = Slave_Address; // Address is 0x74 << 1 bit + 0 (rw)
}
if (Transmit_i2c == 0){
USISRL = Slave_Address+1; // Address is 0x74 << 1 bit
}
USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
I2C_State = 2; // next state: rcv address (N)Ack
break;
case 2: // Receive Address Ack/Nack bit
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit
I2C_State = 4; // Go to next state: check (N)Ack
break;
case 4: // Process Address Ack/Nack & handle data TX
if(Transmit_i2c == 1)
{
USICTL0 |= USIOE; // SDA = output
if (USISRL & 0x01) // If Nack received...
{ // Send stop...
USISRL = 0x00;
USICNT |= 0x01; // Bit counter=1, SCL high, SDA low
I2C_State = 14; // Go to next state: generate Stop
}
else
{ // Ack received, TX data to slave...
MST_Data = MST_Data + 1;
USISRL = *MST_Data;
USICNT |= 0x08; // Bit counter = 8, start TX
I2C_State = 10; // next state: receive data (N)Ack
Bytecount++;
break;
}
}
if(Transmit_i2c == 0)
{
if (USISRL & 0x01) // If Nack received
{ // Prep Stop Condition
USICTL0 |= USIOE;
USISRL = 0x00;
USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
I2C_State = 8; // Go to next state: generate Stop
}
else{ Data_RX();} // Ack received
}
break;
case 6: // Send Data Ack/Nack bit
USICTL0 |= USIOE; // SDA = output
if (Bytecount <= number_of_bytes-2)
{ // If this is not the last byte
USISRL = 0x00; // Send Ack
I2C_State = 4; // Go to next state: data/rcv again
Bytecount++;
}
else //last byte: send NACK
{
USISRL = 0xFF; // Send NAck
I2C_State = 8; // stop condition
}
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
break;
case 8: // Prep Stop Condition
USICTL0 |= USIOE; // SDA = output
USISRL = 0x00;
USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
I2C_State = 14; // Go to next state: generate Stop
break;
case 10: // Receive Data Ack/Nack bit
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
I2C_State = 12; // Go to next state: check (N)Ack
break;
case 12: // Process Data Ack/Nack & send Stop
USICTL0 |= USIOE;
if (Bytecount == number_of_bytes) // If last byte
{
USISRL = 0x00;
I2C_State = 14; // Go to next state: generate Stop
USICNT |= 0x01; // set count=1 to trigger next state
}
else
{
Data_TX(); // TX byte
}
break;
case 14:// Generate Stop Condition
USISRL = 0x0FF; // USISRL = 1 to release SDA
USICTL0 |= USIGE; // Transparent latch enabled
USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled
I2C_State = 0; // Reset state machine for next xmt
LPM0_EXIT; // Exit active for next transfer
break;
}
USICTL1 &= ~USIIFG; // Clear pending flag
}
// *****************************************************************************
void Data_TX (void)
{
MST_Data = MST_Data + 1;
USISRL = *MST_Data; // Load data byte
USICNT |= 0x08; // Bit counter = 8, start TX
I2C_State = 10; // next state: receive data (N)Ack
Bytecount++;
}
// *****************************************************************************
void Data_RX (void)
{
USICTL0 &= ~USIOE; // SDA = input --> redundant
USICNT |= 0x08; // Bit counter = 8, RX data
I2C_State = 6; // Next state: Test data and (N)Ack
}
// *****************************************************************************
void Setup_USI_Master_TX (void)
{
__disable_interrupt();
Bytecount = 0;
Transmit_i2c = 1;
USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
__enable_interrupt();
}
// *****************************************************************************
void Setup_USI_Master_RX (void)
{
__disable_interrupt();
Bytecount = 0;
Transmit_i2c = 0;
USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clks: SCL = SMCLK/128
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
__enable_interrupt();
}
// *****************************************************************************
void Master_Transmit(void)
{
Setup_USI_Master_TX();
USICTL1 |= USIIFG; // Set flag and start communication
LPM0; // CPU off, await USI interrupt
}
// *****************************************************************************
void Master_Recieve(void)
{
Setup_USI_Master_RX();
USICTL1 |= USIIFG; // Set flag and start communication
LPM0; // CPU off, await USI interrupt
}
/*****************************************************************
* puts() is used by printf() to display or send a string.
* This function determines where printf prints to.
* It could send a string out over UART, another option could be
* to display the string on an LCD display.
*****************************************************************/
void puts(char *s)
{
char c;
// Loops through each character in string 's'
while (c = *s++)
{
LCD_Print (c);
}
}
/****************************************************************
* putc() is used by printf() to display or send a character.
* This function determines where printf prints to.
***************************************************************/
void putc (unsigned char c)
{
LCD_Print (c);
}