Jump to content
43oh

MSP430G2553 SPI Slave mode behaviour


Recommended Posts

As a part of my teaching work, I wanted to demonstrate connecting Raspberry Pi-2 (as SPI Master) to MSP430 LP with MSP430G2553 (as SPI Slave), as an alternative to Arduino-Uno as a SPI Slave. It was aimed at utilizing the ADC's of either of these micro-controller boards, as Raspberry Pi-2 does not have ADC modules. The working of Arduino Uno as the SPI Slave device was smooth and painless, but I spent many hours getting the MSP430G2553 working as a SPI SLave. Ultimately, I hit upon a hack (if there was one) and MSP430G2553 started working as SPI Slave! However, I do not understand why this hack works, or, why such a hack is needed at all. I shall appreciate any hints, help, explanations regarding this. I hope to be excused for this long posting.

--------------- SPI Master code: helloArdu.c ---------------------

/**********************************************************
 SPI_Hello_Arduino
   Configures an Raspberry Pi as an SPI master and  
   demonstrates bidirectional communication with an
   Arduino Slave by repeatedly sending the text
   "Hello Arduino" and receiving a response

***********************************************************/

#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <cstring>
#include <iostream>

using namespace std;

int fd;
unsigned char hello[] = {'H','e','l','l','o',' ',
                           'A','r','d','u','i','n','o'};
unsigned char result;
int spiTxRx(unsigned char txDat);

int main (void){
  fd = open("/dev/spidev0.0", O_RDWR);
  unsigned int speed = 1000000;
   ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
  while (1){
      for (int i = 0; i < sizeof(hello); i++) {
         result = spiTxRx(hello);
         cout << result;
         usleep (10);   
      }
  }
}

 

int spiTxRx(unsigned char txDat){
   unsigned char rxDat;
   struct spi_ioc_transfer spi;
   memset (&spi, 0, sizeof (spi));
  spi.tx_buf        = (unsigned long)&txDat;
  spi.rx_buf        = (unsigned long)&rxDat;
  spi.len           = 1;
  ioctl (fd, SPI_IOC_MESSAGE(1), &spi);
  return rxDat;
}
--------------------------------------------------------------------------

 

The Arduino Uno Slave code is:

---------------------- helloRaspi.ino --------------------------------

/*************************************************************
 SPI_Hello_Raspi
   Configures an ATMEGA as an SPI slave and demonstrates
   bidirectional communication with an Raspberry Pi SPI master
   by repeatedly sending the text "Hello Raspi"
****************************************************************/

unsigned char hello[] = {'H','e','l','l','o',' ',
                         'R','a','s','p','i','\n'};
byte marker = 0;
void setup (void) {
  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);
}

 

void loop (void){
  if((SPSR & (1 << SPIF)) != 0) {
    SPDR = hello[marker];
    marker++;
    if(marker > sizeof(hello)){
      marker = 0;
    }  
  }    
}
-------------------------------------------------------------------------

 

My Slave code for MSP430G2553 is:

------------------------- helloRaspi.c -------------------------------

#include "msp430g2553.h"
#include <string.h>

unsigned char cmdbuf[20];
char cmd_index=0;
unsigned char hello[] = "Hello Raspi \n";
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  P1DIR |= BIT0 + BIT6;  
  while (!(P1IN & BIT5));

  P1SEL = BIT5 + BIT6+ BIT7;
  P1SEL2 = BIT5 + BIT6 + BIT7;
  P2SEL = BIT0;
  P2SEL2 = BIT0;
  UCB0CTL1 = UCSWRST;                       // **Put state machine in reset**
  UCB0CTL0 |=  UCCKPL + UCMSB + UCMODE_2 + UCSYNC; // 3-pin, 8-bit SPI master
  UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine*
  IE2 |= UCB0RXIE;                          // Enable USCI0 RX interrupt
  IE2 |= UCB0TXIE;
  __bis_SR_register(LPM4_bits + GIE);       // Enter LPM4, enable interrupts

}  // end main()

 

int index = 0;
__attribute__((interrupt(USCIAB0TX_VECTOR))) void USCI0TX_ISR (void){
  UCB0TXBUF = hello[index]<<1;   // <---- Note this hack
  index++;
  if(index == 13) index = 0;
}
 __attribute__((interrupt(USCIAB0RX_VECTOR))) void USCI0RX_ISR (void){
  char value = UCB0RXBUF;
  if (cmd_index == 13) {
    if (strncmp(cmdbuf, "Hello Arduino", 13) == 0) {
      P1OUT |= BIT0;
    } else {
      P1OUT &= ~BIT0;
    }
    cmd_index = 0;
  } else {
    cmdbuf[cmd_index] = value;
    cmd_index++;
  }

}

-------------------------------------------------------------------------

 

Note the hack indicated by <---, where the character to be transmitted to back to RaspberryPi is shifted to left by one bit.

Without this hack, which would be normal way, I found that, e,g, Character 'A' (0x41) sent was received as 0xA0, indicating that the character bits are being rotated to the right one place. With this hack, transmission was fine!

 

Why this is so? Am I missing something or doing something wrong? Digging various discussion lists and forums, unfortunately, have not given any clue. There are plenty of example code for MSP430G2553 working in SPI Master mode, but few for Slave mode.

Link to post
Share on other sites

You are right, hardly anybody uses USCI Slave mode for SPI or I2C!

 

Looking at the chip's errata sheet though, check out USCI40:

http://www.ti.com/lit/er/slaz440g/slaz440g.pdf page 9

 

attachicon.gifg2553usci40.png

Speaking of which, I have need right now in a project for I2C slave mode . . . which does not seem to be effected by this hardwre bug. I hope.

Link to post
Share on other sites

Looking at the chip's errata sheet though, check out USCI40:

http://www.ti.com/lit/er/slaz440g/slaz440g.pdf page 9

 

That bug only happens with UCCKPH=1, which isn't the case in the slave code shown. I suspect the problem might just be a mismatch between the Raspberry Pi's SPI mode and the one selected on the g2553. That can manifest as a one-bit offset in one direction or the other.

 

You can use ioctl(fd, SPI_IOC_WR_MODE, &mode) to set the mode on the raspi end. Doing that means you can avoid setting UCCKPH=1 on the g2553 and not have to worry about the USCI40 problem. The bad news is that the arduino slave code will need changing to match.

 

I think that setting SPI_MODE_3 on the raspi will match what you've selected on the g2553, and will let you remove the bit shift workaround.

Link to post
Share on other sites

That bug only happens with UCCKPH=1, which isn't the case in the slave code shown. I suspect the problem might just be a mismatch between the Raspberry Pi's SPI mode and the one selected on the g2553. That can manifest as a one-bit offset in one direction or the other.

 

You can use ioctl(fd, SPI_IOC_WR_MODE, &mode) to set the mode on the raspi end. Doing that means you can avoid setting UCCKPH=1 on the g2553 and not have to worry about the USCI40 problem. The bad news is that the arduino slave code will need changing to match.

 

I think that setting SPI_MODE_3 on the raspi will match what you've selected on the g2553, and will let you remove the bit shift workaround.

The "bad" thing about this situation is *if* one wanted to change to SPI slave mode in Linux . . . You can't  without writing the driver yourself. In Linux, there is no SPI slave mode . . . SPI devices in Linux must be master, unless again. You write your own driver. Which is not exactly as simple as one may think. I've looked into it some . . .

Link to post
Share on other sites

Tested helloArdu.c with SPI_MODE_3 as suggested by Tripwire, works! Thanks. However, the helloRaspi.ino code does not work. I have two options: (i) use two versions of helloArdu.c (one with SPI_MODE_0 for Arduino as Slave and second with SPI_MODE_3 for MSP430 as Slave), or, (ii) Rewrite Arduino code using its SPI library where mode control is available.

Both are acceptable as far as teaching is concerned.

 

Thanks all for the help.

 

In passing, I feel that with great popularity of Raspberry Pi -2 (and now -3), which unfortunately does not have ADC's, low-cost micro-controllers having ADC built-in would be a good possibility. Cost will be comparable to ADC chips with SPI interface (like MCP3008), but with added advantage of on-board pre-processing of analog data and additional GPIO functions.

 

In view of the above, a few more example code using MSP430G2553 (and other MSP430 series members) working in Slave SPI will be very helpful.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...