Hello All,
My project would be to create 4 MSP430G2553 MCUs via I2C. One master 3 slaves, master asking the slave, then the slave responding. After I2C transmission the slave would do it's job (GPIO settings, checking interrupts, etc.) The master would also check for interrupts from GPIO.
For the firt step I would like to create a simple code with 2 launchpads. If the pushbutton at P1.3 is pressed, then the mater would start transmitting data to the slave. For Master code I used the combination of
msp430g2xx3_uscib0_i2c_12.c
and
msp430g2xx3_P1_02.c
with some modifications
for the slave the code is unchanged msp430g2xx3_uscib0_i2c_12.c later though I also want to add a loop and do some action (GPIO mainly, one AD converting)
Could you please "Help me get my feet back on the ground!" ? :-) Thanks.
MASTER
#include <msp430.h>
#define NUM_BYTES_TX 3 // How many bytes?
#define NUM_BYTES_RX 2
int RXByteCtr, RPT_Flag = 0; // enables repeated start when 1
volatile unsigned char RxBuffer[128]; // Allocate 128 byte of RAM
unsigned char *PTxData; // Pointer to TX data
unsigned char *PRxData; // Pointer to RX data
unsigned char TXByteCtr, RX = 0;
unsigned char MSData = 0x55;
void Setup_TX(void);
void Setup_RX(void);
void Transmit(void);
void Receive(void);
unsigned char flag=0;
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
/*mod start*/
P1DIR |= BIT0; // Set P1.0 to output direction
P1IE |= BIT3; // P1.3 interrupt enabled
P1IES |= BIT3; // P1.3 Hi/lo edge
P1REN |= BIT3; // Enable Pull Up on SW2 (P1.3)
P1OUT=0;
P1IFG &= ~BIT3; // P1.3 IFG cleared
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
/* mod end*/
__bis_SR_register(CPUOFF + GIE);
while(1){
switch(flag)
{
case 1:
{
//Transmit process
Setup_TX();
RPT_Flag = 0;
RPT_Flag = 1;
Transmit();
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
//Receive process
Setup_RX();
Receive();
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
flag=0;
}
break;
default:
{
}
}
}
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^= BIT0; // P1.0 = toggle
P1IFG &= ~BIT3; // P1.3 IFG cleared
flag=1;
__bic_SR_register_on_exit(CPUOFF);
}
//-------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C slave
// to the MSP430 memory. It is structured such that it can be used to receive
// any 2+ number of bytes by pre-loading RXByteCtr with the byte count.
//-------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
if(RX == 1){ // Master Recieve?
RXByteCtr--; // Decrement RX byte counter
if (RXByteCtr)
{
*PRxData++ = UCB0RXBUF; // Move RX data to address PRxData
}
else
{
if(RPT_Flag == 0)
UCB0CTL1 |= UCTXSTP; // No Repeated Start: stop condition
if(RPT_Flag == 1){ // if Repeated Start: do nothing
RPT_Flag = 0;
}
*PRxData = UCB0RXBUF; // Move final RX data to PRxData
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}}
else{ // Master Transmit
if (TXByteCtr) // Check TX byte counter
{
UCB0TXBUF = MSData++; // Load TX buffer
TXByteCtr--; // Decrement TX byte counter
}
else
{
if(RPT_Flag == 1){
RPT_Flag = 0;
PTxData = &MSData; // TX array start address
TXByteCtr = NUM_BYTES_TX; // Load TX byte counter
__bic_SR_register_on_exit(CPUOFF);
}
else{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
}
}
void Setup_TX(void){
_DINT();
RX = 0;
IE2 &= ~UCB0RXIE;
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent// Disable RX interrupt
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x48; // Slave Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0TXIE; // Enable TX interrupt
}
void Setup_RX(void){
_DINT();
RX = 1;
IE2 &= ~UCB0TXIE;
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x48; // Slave Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0RXIE; // Enable RX interrupt
}
void Transmit(void){
PTxData = &MSData; // TX array start address
TXByteCtr = NUM_BYTES_TX; // Load TX byte counter
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}
void Receive(void){
PRxData = (unsigned char *)RxBuffer; // Start of RX buffer
RXByteCtr = NUM_BYTES_RX-1; // Load RX byte counter
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTXSTT; // I2C start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}
SLAVE (unchanged) msp430g2xx3_uscib0_i2c_13.c
#include <msp430.h>
#define NUM_BYTES 2 // How many bytes?
//**** Please note this value needs to be the same as NUM_BYTES_RX in the
// associated master code. This definition lets the slave know when to
// switch from RX interrupt sources to TX interrupt sources. This is
// important since the interrupt vectors are shared by TX and RX flags.
unsigned char *PTxData; // Pointer to TX data
unsigned char *PRxData; // Pointer to RX data
volatile unsigned char RxBuffer[128]; // Allocate 128 byte of RAM
char SLV_Data = 0x11;
volatile unsigned char TXByteCtr, RXByteCtr, RX = 0;
volatile unsigned char RxBuffer[128]; // Allocate 128 byte of RAM
void USCI_SLAVE_SETUP(void);
void Setup_RX(void);
void Receive(void);
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
while(1){
USCI_SLAVE_SETUP();
}
}
//------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move data from MSP430 memory to the
// I2C master. PTxData points to the next byte to be transmitted, and TXByteCtr
// keeps track of the number of bytes transmitted.
//------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
if(RX == 0){ UCB0TXBUF = SLV_Data++; // Transmit data at address PTxData
TXByteCtr++; // Increment TX byte counter
}
if(RX == 1){*PRxData++ = UCB0RXBUF; // Move RX data to address PRxData
RXByteCtr++; // Increment RX byte count
if(RXByteCtr >= NUM_BYTES){ // Received enough bytes to switch
RX = 0; // to TX?
IE2 &= ~UCB0RXIE;
IE2 |= UCB0TXIE;
RXByteCtr = 0;
}
}
}
//------------------------------------------------------------------------------
// The USCI_B0 state ISR is used to wake up the CPU from LPM0 in order to do
// processing in the main program after data has been transmitted. LPM0 is
// only exit in case of a (re-)start or stop condition when actual data
// was transmitted.
//------------------------------------------------------------------------------
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
if(RX == 0){ UCB0STAT &= ~(UCSTPIFG + UCSTTIFG); // Clear interrupt flags
if (TXByteCtr) // Check TX byte counter
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0 if data was
} // transmitted
if(RX == 1){UCB0STAT &= ~(UCSTPIFG + UCSTTIFG); // Clear interrupt flags
}
}
void Setup_RX(void){
_DINT();
RX = 1;
IE2 &= ~UCB0TXIE; // Disable TX interrupt
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode
UCB0I2COA = 0x48; // Own Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE |= UCSTPIE + UCSTTIE; // Enable STT and STP interrupt
IE2 |= UCB0RXIE; // Enable RX interrupt
}
void Receive(void){
PRxData = (unsigned char *)RxBuffer; // Start of RX buffer
RXByteCtr = 0; // Clear RX byte count
TXByteCtr = 0;
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
// Remain in LPM0 until master
// finishes TX
}
void USCI_SLAVE_SETUP(void){
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
Setup_RX();
Receive();
}