I am using the MSP430FG4618/MSP430F2013 experimenter’s board produced by TI to work out issues with the I2C implementation on various MSP430 chips. I have used the attached source code to initialize and try to generate a conversation between the two microcontrollers on this board, but the slave (the 2013) seems to hold the bus clock after the start condition. Is there anything obviously wrong with the way I’m initializing the UCSI on the master and the USI on the slave? Thanks very much for your consideration.
Note: the attached source files compile with GCC. The master is written for the MSP430FG4618, the slave is written for MSP430F2013, and is a pretty close port of TI’s slac080e example code.
Thanks again,
Woody
CODE
/*i2c slave, experimenter board.*/
#include <io.h>
#include <signal.h>
#include <stdbool.h>
#define sei() _BIS_SR(GIE)
#define cli() _BIC_SR(GIE)
char MST_Data = 0; // Variable for received data
char SLV_Addr = 0x66; // Address is 0x33<<1 for R/W
int I2C_State = 0; // State variable
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
BCSCTL1 = CALBC1_1MHZ; // Set DCO
DCOCTL = CALDCO_1MHZ;
P1OUT = 0xC0; // P1.6 & P1.7 Pullups
P1REN |= 0xC0; // P1.6 & P1.7 Pullups
P1DIR = 0xFF; // Unused pins as outputs
P2OUT = 0;
P2DIR = 0xFF;
USICTL0 = USIPE6+USIPE7+USISWRST; // Port & USI mode setup
USICTL1 = USII2C+USIIE+USISTTIE; // Enable I2C mode & USI interrupts
USICKCTL = USICKPL; // Setup clock polarity
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
sei();
//_EINT();
while(1)
{
LPM0; // CPU off, await USI interrupt
_NOP(); // Used for IAR
}
return 0;
}
//******************************************************************************
// USI interrupt service routine
//******************************************************************************
interrupt(USI_VECTOR) USI_TXRX (void)
{
if (USICTL1 & USISTTIFG) // Start entry?
{
P1OUT |= 0x01; // LED on: sequence start
I2C_State = 2; // Enter 1st state on start
}
switch(I2C_State)
{
case 0: // Idle, should not get here
break;
case 2: // RX Address
USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, RX address
USICTL1 &= ~USISTTIFG; // Clear start flag
I2C_State = 4; // Go to next state: check address
break;
case 4: // Process Address and send (N)Ack
if (USISRL & 0x01) // If read...
SLV_Addr++; // Save R/W bit
USICTL0 |= USIOE; // SDA = output
if (USISRL == SLV_Addr) // Address match?
{
USISRL = 0x00; // Send Ack
P1OUT &= ~0x01; // LED off
I2C_State = 8; // Go to next state: RX data
}
else
{
USISRL = 0xFF; // Send NAck
P1OUT |= 0x01; // LED on: error
I2C_State = 6; // Go to next state: prep for next Start
}
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
break;
case 6: // Prep for Start condition
USICTL0 &= ~USIOE; // SDA = input
SLV_Addr = 0x90; // Reset slave address
I2C_State = 0; // Reset state machine
break;
case 8: // Receive data byte
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x08; // Bit counter = 8, RX data
I2C_State = 10; // Go to next state: Test data and (N)Ack
break;
case 10:// Check Data & TX (N)Ack
USICTL0 |= USIOE; // SDA = output
if (USISRL == MST_Data) // If data valid...
{
USISRL = 0x00; // Send Ack
MST_Data++; // Increment Master data
P1OUT &= ~0x01; // LED off
}
else
{
USISRL = 0xFF; // Send NAck
P1OUT |= 0x01; // LED on: error
}
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
I2C_State = 6; // Go to next state: prep for next Start
break;
}
USICTL1 &= ~USIIFG; // Clear pending flags
}
#include <io.h>
#include <signal.h>
#include <stdbool.h>
#define sei() _BIS_SR(GIE)
#define cli() _BIC_SR(GIE)
char MST_Data = 0; // Variable for received data
char SLV_Addr = 0x66; // Address is 0x33<<1 for R/W
int I2C_State = 0; // State variable
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
BCSCTL1 = CALBC1_1MHZ; // Set DCO
DCOCTL = CALDCO_1MHZ;
P1OUT = 0xC0; // P1.6 & P1.7 Pullups
P1REN |= 0xC0; // P1.6 & P1.7 Pullups
P1DIR = 0xFF; // Unused pins as outputs
P2OUT = 0;
P2DIR = 0xFF;
USICTL0 = USIPE6+USIPE7+USISWRST; // Port & USI mode setup
USICTL1 = USII2C+USIIE+USISTTIE; // Enable I2C mode & USI interrupts
USICKCTL = USICKPL; // Setup clock polarity
USICNT |= USIIFGCC; // Disable automatic clear control
USICTL0 &= ~USISWRST; // Enable USI
USICTL1 &= ~USIIFG; // Clear pending flag
sei();
//_EINT();
while(1)
{
LPM0; // CPU off, await USI interrupt
_NOP(); // Used for IAR
}
return 0;
}
//******************************************************************************
// USI interrupt service routine
//******************************************************************************
interrupt(USI_VECTOR) USI_TXRX (void)
{
if (USICTL1 & USISTTIFG) // Start entry?
{
P1OUT |= 0x01; // LED on: sequence start
I2C_State = 2; // Enter 1st state on start
}
switch(I2C_State)
{
case 0: // Idle, should not get here
break;
case 2: // RX Address
USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, RX address
USICTL1 &= ~USISTTIFG; // Clear start flag
I2C_State = 4; // Go to next state: check address
break;
case 4: // Process Address and send (N)Ack
if (USISRL & 0x01) // If read...
SLV_Addr++; // Save R/W bit
USICTL0 |= USIOE; // SDA = output
if (USISRL == SLV_Addr) // Address match?
{
USISRL = 0x00; // Send Ack
P1OUT &= ~0x01; // LED off
I2C_State = 8; // Go to next state: RX data
}
else
{
USISRL = 0xFF; // Send NAck
P1OUT |= 0x01; // LED on: error
I2C_State = 6; // Go to next state: prep for next Start
}
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
break;
case 6: // Prep for Start condition
USICTL0 &= ~USIOE; // SDA = input
SLV_Addr = 0x90; // Reset slave address
I2C_State = 0; // Reset state machine
break;
case 8: // Receive data byte
USICTL0 &= ~USIOE; // SDA = input
USICNT |= 0x08; // Bit counter = 8, RX data
I2C_State = 10; // Go to next state: Test data and (N)Ack
break;
case 10:// Check Data & TX (N)Ack
USICTL0 |= USIOE; // SDA = output
if (USISRL == MST_Data) // If data valid...
{
USISRL = 0x00; // Send Ack
MST_Data++; // Increment Master data
P1OUT &= ~0x01; // LED off
}
else
{
USISRL = 0xFF; // Send NAck
P1OUT |= 0x01; // LED on: error
}
USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit
I2C_State = 6; // Go to next state: prep for next Start
break;
}
USICTL1 &= ~USIIFG; // Clear pending flags
}
CODE
/*i2c master, experimenter board.*/
#include <io.h>
#include <signal.h>
#include <stdbool.h>
#define sei() _BIS_SR(GIE)
#define cli() _BIC_SR(GIE)
static bool send_flag, timer;
interrupt (PORT1_VECTOR) toggle_yellow(void) {
P2OUT ^= BIT1; // Toggle P1.0 using exclusive-OR
P1IFG = 0;
send_flag = true;
}
interrupt (BASICTIMER_VECTOR) toggle_green(void) {
timer = true;
RTCCTL &= ~RTCFG;
}
static void init_i2c() {
UCB0CTL1 |= UCSWRST;
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;
UCB0CTL1 = UCSWRST + UCSSEL_2;
UCB0BR0 = 11;
UCB0BR1 = 00;
P3SEL |= 0x6;
UCB0CTL1 &= ~UCSWRST;
}
int main() {
WDTCTL = WDTPW + WDTHOLD; // Stop Watchdog Timer
P2DIR = BIT1 + BIT2;
RTCCTL = RTCIE + RTCMODE_0 + RTCTEV_1;
P1IE = BIT0;
init_i2c();
sei();
send_flag = false; //add a little delay....
while (send_flag == true);
send_flag = false;
for (;;) {
if ((send_flag == true) && (timer == true)) {
P2OUT ^= BIT2;
timer = false;
send_flag = false;
UCB0I2CSA = 0x066;
UCB0CTL0 = UCTR & UCTXSTT;
while (!(IFG2 & UCB0TXIFG)) {
if (send_flag == true) break;
}
if (UCB0STAT & UCNACKIFG) {
UCB0CTL0 |= UCTXSTP;
send_flag = false;
continue;
}
else {
UCB0TXBUF = 0xAA;
}
while (!(IFG2 & UCB0TXIFG)) {
if (send_flag == true) break;
}
UCB0CTL0 |= UCTXSTP;
send_flag = false;
}
}
}
#include <io.h>
#include <signal.h>
#include <stdbool.h>
#define sei() _BIS_SR(GIE)
#define cli() _BIC_SR(GIE)
static bool send_flag, timer;
interrupt (PORT1_VECTOR) toggle_yellow(void) {
P2OUT ^= BIT1; // Toggle P1.0 using exclusive-OR
P1IFG = 0;
send_flag = true;
}
interrupt (BASICTIMER_VECTOR) toggle_green(void) {
timer = true;
RTCCTL &= ~RTCFG;
}
static void init_i2c() {
UCB0CTL1 |= UCSWRST;
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;
UCB0CTL1 = UCSWRST + UCSSEL_2;
UCB0BR0 = 11;
UCB0BR1 = 00;
P3SEL |= 0x6;
UCB0CTL1 &= ~UCSWRST;
}
int main() {
WDTCTL = WDTPW + WDTHOLD; // Stop Watchdog Timer
P2DIR = BIT1 + BIT2;
RTCCTL = RTCIE + RTCMODE_0 + RTCTEV_1;
P1IE = BIT0;
init_i2c();
sei();
send_flag = false; //add a little delay....
while (send_flag == true);
send_flag = false;
for (;;) {
if ((send_flag == true) && (timer == true)) {
P2OUT ^= BIT2;
timer = false;
send_flag = false;
UCB0I2CSA = 0x066;
UCB0CTL0 = UCTR & UCTXSTT;
while (!(IFG2 & UCB0TXIFG)) {
if (send_flag == true) break;
}
if (UCB0STAT & UCNACKIFG) {
UCB0CTL0 |= UCTXSTP;
send_flag = false;
continue;
}
else {
UCB0TXBUF = 0xAA;
}
while (!(IFG2 & UCB0TXIFG)) {
if (send_flag == true) break;
}
UCB0CTL0 |= UCTXSTP;
send_flag = false;
}
}
}
Я не думаю, что моя помощь в переводе с английского необходима, не если я не прав просто дайте мне знать.