Okay I can't for the life of me find my last master code. Here is the
latest I have. I doesn't support the variable length recieve that the
slave does. The stuff i can't find had the variable length recieve
working. YMMV. Compiles with CCS in win XP in Virtual Box on a
macbook runnng 10.5.8
Lots of useful stuff here and the display routines can be lifted for
other stuff too.
//
******************************************************************************
// I2C Master Receiver,
// double byte read
// single byte write
//
// 5 OCT 2010
//
Author:tsc...@gmail.com
// free to use for non-commercial use with attribution.
// Some parts from or inspired by TI example code by
// Z. Albus, R. B. Elliott and H. Grewal.
//
******************************************************************************
#include <msp430g2231.h>
//My display routines
void formatAndSend(char data);
void dispClear(int arg);
void dispSend4(char data);
void dispSend8(char data);
void dispGo(int row, int col);
void wait(int max);
char rs=0; //(0,1) register select for displaychar SLV_data =
0x00;
char SLV_Addr = 0x50; // Address is 0x48 << 1 bit + 1 for Read
char toggle1; // just a var to switch between first and second byte
char RWbit = 1; // (0,1) 0= writeto slave, 1= read from slave
char counter1=0; //just a counter to insert write cycles for fun
int I2C_State = 0; // State variable
void main(void){
volatile unsigned int i; // Use volatile to prevent removal
//Clocks
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF){while(1);}
// If calibration constants are erased do not load, trap CPU!!
BCSCTL1 = CALBC1_1MHZ; // Set DCO
DCOCTL = CALDCO_1MHZ;
//Pin Setup
P1SEL &= 0x06; //clear 39, don't care 0xC0
P1REN = 0xC6; //set 0xC0, clear 0x39
P1DIR |= 0x39; //set 0x39
P2SEL = 0x00; //clear 0xC0
P2DIR = 0xFF; //set 0xC0
P2REN = 0x00; //clear 0xC0
//Display init
rs=0;
dispSend4(0x20);
dispSend8(0x28);
dispSend8(0x0e);
dispSend8(0x06);
rs=1;
//Display form
dispSend8('1');
dispSend8(':');
dispGo(2,1);
dispSend8('2');
dispSend8(':');
dispGo(1,1);
//USI init
USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup
USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt
USICKCTL = USIDIV_3+USISSEL_2+USICKPL; // Setup USI clocks: SCL =
SMCLK/8 (~120kHz)
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
_EINT();
while(1){
counter1++; //Counter1 is used to send a write to the Slave once
every 50 transactions
if(counter1 > 49){
counter1=0;
RWbit = 0;
SLV_Addr = 0x50;
}
else{
RWbit = 1;
SLV_Addr = 0x51;
}
dispGo(1,7);
formatAndSend(counter1);
dispSend8(' ');
formatAndSend(SLV_Addr); //Shows the slave address including RWbit
USICTL1 |= USIIFG; // Set flag and start communication
LPM0; // CPU off, await USI interrupt
_NOP(); // Used for IAR
for (i = 0; i < 5000; i++); // Dummy delay between communication
cycles
}
}
/******************************************************
// USI interrupt service routine
//
// States Function
// ----------------- -------------
// 0 - 2 - 4 setup always happens
// \
// 10 nack recieved, end
// or
// 18 - 20 - 10 Write byte to slave
// or
// 6 - 14 - 16 - 8 - 10 read bytes from slave
//*****************************************************/
#pragma vector = USI_VECTOR
__interrupt void USI_TXRX (void){
switch(I2C_State){
case 0:
//Generate start condition
//Prep address to send
//case 0 is manually tiggered by setting the interrupt flag
USISRL = 0x00; // Generate Start Condition
USICTL0 |= USIGE+USIOE;
USICTL0 &= ~USIGE;
USISRL = SLV_Addr;//(SLV_Addr | RWbit); // Build and transmit
address, R/W = 1
USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
I2C_State = 2; // Go to next state: receive address (N)Ack
break;
case 2:
//Byte(address + R/W) just sent
//prep to recieve bit from slave, ack or nack
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:
//bit just recieved
//RWbit=1->Read
//Ack ->prep to receive byte and continue communication
//Nack->prep for issuing STOP condition
//RWbit=0->Write
//prep to send byte
if (RWbit == 1){
//Read Code
if (USISRL & 0x01){
// If Nack received Prep Stop Condition
USICTL0 |= USIOE;
USISRL = 0x00;
USICNT |= 0x01; // Bit counter = 1, SCL high, SDA low
I2C_State = 10; // Go to next state:
}
else{
// Ack received, Receive Data from slave
USICNT |= 0x08; // Bit counter = 8, RX data
I2C_State = 6; // Go to next state:
}
}
else{
//Write Code
USISRL = 77;
USICTL0 |= USIOE; // SDA = output
USICNT |= 0x08; // TX a byte
I2C_State = 18;
}
break;
case 6:
//First Byte just recieved
//Formated display of data
//Prep to send N/Ack bit
USICTL0 |= USIOE; // SDA = output
dispGo(1,3);
formatAndSend(USISRL);
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
I2C_State = 14; // Go to next state
break;
case 8:
//Bit just sent
//Prep Stop Condition
USICTL0 |= USIOE; // SDA = output
USISRL = 0x00;
USICNT |= 0x01; // Bit counter = 1, SCL high, SDA low
I2C_State = 10; // Go to next state: generate Stop
break;
case 10:
//coming from case 8 or 4 or __
//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 transmission
LPM0_EXIT; // Exit active for next transfer
break;
case 14:
//Just sent bit
//Prep to recieve second byte
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x08; // Bit counter = 8, RX data
I2C_State = 16; // Go to next state: Test data and (N)Ack
break;
case 16:
//Second Byte just recieved
//Formated display of data
//Prep to send N/Ack bit
USICTL0 |= USIOE; // SDA = output
dispGo(2,3);
formatAndSend(USISRL);
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
I2C_State = 8; // Go to next state: prep stop
break;
case 18:
//Just wrote byte to slave
//prep to recieve bit
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit
I2C_State = 20;
break;
case 20:
//just recieved bit
//prep to stop
USICTL0 |= USIOE;
USISRL = 0x00;
USICNT |= 0x01; // Bit counter = 1, SCL high, SDA low
I2C_State = 10; // Go to next state:
break;
}
USICTL1 &= ~USIIFG; // Clear pending flag
}
//
******************************************************************************
// Display routines for use with a HD44780 series display driver chip
// My display uses a HD44780A00
//
// PINOUT
// P1.0 E enable/clock
// P1.3 RS register select ,1=char data, 0=commands
// P1.4 DB4 data LSB
// P1.5 DB5
// P2.6 DB6
// P2.7 DB7 data MSB
//
******************************************************************************
void formatAndSend(char data){
//To turns an 8-bit unsigned integer value into
//three decimal digits and sends to display
char temp;
temp=(data/100)+0x30;
dispSend8(temp);
temp=((data/10)%10)+0x30;
dispSend8(temp);
temp=(data%10)+0x30;
dispSend8(temp);
}
void dispClear(int arg){
//arg Action
//--- ------------------
// 0 clear whole screen
// 1 clear first line
// 2 clear second line
//else clear whole screen
char i=0;
switch (arg){
case 1:
dispGo(1,1);
for(i=0;i<16; i++){
dispSend8(0x20);}
dispGo(1,1);
break;
case 2:
dispGo(2,1);
for(i=0;i<16; i++){
dispSend8(0x20);}
dispGo(2,1);
break;
case 0:
default:
rs = 0;
dispSend8(0x01);
rs = 1;
dispGo(1,1);
break;
}
}
void dispGo(int row, int col){
//Move cursor to row and column
char send=0;
send=(((row-1)*0x40)+(col-1))|0x80;
rs=0;
dispSend8(send);
rs=1;
}
void dispSend4(char data){
//takes the 4 MSB bits of data and formats for
//this pin set up
int pulsewidth;
if (rs==1) {pulsewidth=10;P1OUT |= 0x08;}//set the clock rate and set
the RS line
else {pulsewidth=50;P1OUT &= 0xf7;}
//set up the data output
P1OUT = ((0x30 & data) | (0xcf & P1OUT));
P2OUT = data; //six bits have no pins
//Pulse the E line
wait(pulsewidth); //wait time
P1OUT |= 0x01; //clock high
wait(pulsewidth); //wait time
P1OUT ^= 0x01; //clock low
}
void dispSend8(char data){
//breaks 8 bits into two 4 bit chunks for sending to the display
//lower 4 bits of sent data are ignored
dispSend4(data);
data= data<<4;
dispSend4(data);
}
void wait(int max){
int i=0;
for(i=0;i<max; i++); //wait time
}