Forums

MSP430G2553 SPI for external ADC

Started by noefvillanueva July 12, 2013
Hello Everyone,

This is my first post here so please bear with me. Now I'm am working with the MSP430G2553 on the Launch pad to communicate with an external 16 bit ADC MAX1415. I need the higher resolution hence the reason I am not using the on board ADC. Now, I am trying to use SPI communication to connect to this ADC but I tried using the TI sample SPI code but was told it really was not a useful example. After searching I came up with the following code but for my CheckX I just get d255 = hFF. I think it spits this out if it doesn't find a slave. Now I'm just not sure if for SPI I need to use interrupts or is the way I laid out my code able to accomplish communication.

Thanks,

#include

unsigned long Check, Check1, Check2, Check3, Check4; //I put these checks to try and see what was being received

void PinSetup(); // Not sure if I need this since with another TI Micro I used in school I had to
void SpiSetup();
void SetMaxim();

void PinSetup()
{
P1OUT = 0x00; // P1 setup for LED & reset output
P1DIR |= BIT5 + BIT3; // P1 direction as output 1.5 = Reset 1.3=CS
P1SEL = BIT1 + BIT2 + BIT4; // [1.1 = SOMI-> PIN 13 DOUT of ADC] [1.2 = SIMO-> PIN 14 DIN of ADC]
P1SEL2 = BIT1 + BIT2 + BIT4; // Not Sure what the difference is between Sel1 and Sel2 seems redundant
}

void SpiSetup()
{
// UCMSB = Selects Most Sig Fig 1st // UCMST = Select the SPI Module as the Master // UCSYNC = Selecting Synchronous mode
UCA0CTL0 |= UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master Is UCCKPL needed???
UCA0CTL1 |= UCSSEL_2; // USCI Clock source will be SMCLK
UCA0BR0 |= 0x02; // /2
UCA0BR1 = 0; //
UCA0MCTL = 0; // No modulation
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**set low
}

void SetMaxim() // Trying to set up the ADC registers for clock rate and gain
{
P1OUT &= ~BIT5; // Pin 1.5 is pulled low to reset ADC
P1OUT |= BIT5; // After ADC is reset Pin 1.5 pulled high to prevent reset

P1OUT &= ~BIT3; // Pin 1.3 CS pulled low
UCA0TXBUF = 0x00; // Send Dummy to Start SPI

//IFG2 &= UCA0RXIFG; // Clear Flag Not sure if I need this????

while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = 0x20; // h20 to to tell ADC to be prepared to write to clock reg next

while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
Check = UCA0RXBUF;
UCA0TXBUF = 0xB3; // hB3 for ADC clock run at 1Mhz

while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
Check1 = UCA0RXBUF;
UCA0TXBUF = 0x10; // h10 to tell ADC to be prepared to write to the setup reg next

while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
Check2 = UCA0RXBUF;
UCA0TXBUF = 0x44; // h44 for ADC to setup

P1OUT |= BIT3; // Pull CS high
}

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //NV Need from here
PinSetup();
SpiSetup();
SetMaxim();
//IE2 |= UCA0RXIE; // Enable USCI0 RX and TX interrupt // Do I need interrupts for this??
//__bis_SR_register(LPM0_bits + GIE); // CPU off, enable interrupts
for(;;) // Just threw in this dumy infinite loop for later use
{}

}

Beginning Microcontrollers with the MSP430

Hi noefvillanueva (!?),

Often the first byte returning from a SPI slave is FF.

What do you see on the pins using a osci? Is it what you expect?

It is not easy to get SPI running with the UARTs, try bit banging (toggle
the SPI pins by software), when this is working, take a look at the spi
pins when using the uart.

Whats your name? ;-)

Matthias

"noefvillanueva" :

> Hello Everyone,
>
> This is my first post here so please bear with me. Now I'm am working
> with the MSP430G2553 on the Launch pad to communicate with an external
> 16 bit ADC MAX1415. I need the higher resolution hence the reason I am
> not using the on board ADC. Now, I am trying to use SPI communication to
> connect to this ADC but I tried using the TI sample SPI code but was
> told it really was not a useful example. After searching I came up with
> the following code but for my CheckX I just get d255 = hFF. I think it
> spits this out if it doesn't find a slave. Now I'm just not sure if for
> SPI I need to use interrupts or is the way I laid out my code able to
> accomplish communication.
>
> Thanks,
>
> #include unsigned long Check, Check1, Check2, Check3, Check4; //I put these
> checks to try and see what was being received
>
> void PinSetup(); // Not sure if I need this since with another TI Micro
> I used in school I had to void SpiSetup();
> void SetMaxim();
>
> void PinSetup()
> {
> P1OUT = 0x00; // P1 setup for LED & reset
> output P1DIR |= BIT5 + BIT3; // P1 direction
> as output 1.5 = Reset 1.3=CS P1SEL = BIT1 + BIT2 + BIT4;
> // [1.1 = SOMI-> PIN 13 DOUT of ADC] [1.2 = SIMO-> PIN
> 14 DIN of ADC] P1SEL2 = BIT1 + BIT2 + BIT4; // Not
> Sure what the difference is between Sel1 and Sel2 seems redundant
> }
>
> void SpiSetup()
> {
> // UCMSB = Selects Most Sig Fig 1st // UCMST = Select the SPI
> Module as the Master // UCSYNC = Selecting Synchronous mode
> UCA0CTL0 |= UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master Is
> UCCKPL needed??? UCA0CTL1 |= UCSSEL_2; // USCI
> Clock source will be SMCLK UCA0BR0 |= 0x02;
> // /2 UCA0BR1 = 0; //
> UCA0MCTL = 0; // No modulation
> UCA0CTL1 &= ~UCSWRST; // **Initialize USCI
> state machine**set low
> }
>
> void SetMaxim() // Trying to set up the ADC registers for clock rate and
> gain {
> P1OUT &= ~BIT5; // Pin 1.5 is pulled low to
> reset ADC P1OUT |= BIT5; // After ADC is
> reset Pin 1.5 pulled high to prevent reset
>
> P1OUT &= ~BIT3; // Pin 1.3 CS pulled low
> UCA0TXBUF = 0x00; // Send Dummy to Start SPI
>
> //IFG2 &= UCA0RXIFG; // Clear Flag Not sure if I need
> this????
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> UCA0TXBUF = 0x20; // h20 to to tell ADC to be
> prepared to write to clock reg next
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check = UCA0RXBUF;
> UCA0TXBUF = 0xB3; // hB3 for ADC clock run at 1Mhz
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check1 = UCA0RXBUF;
> UCA0TXBUF = 0x10; // h10 to tell ADC to be prepared
> to write to the setup reg next
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check2 = UCA0RXBUF;
> UCA0TXBUF = 0x44; // h44 for ADC to setup
>
> P1OUT |= BIT3; // Pull CS high
> }
>
> void main(void)
> {
> WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //NV
> Need from here PinSetup();
> SpiSetup();
> SetMaxim();
> //IE2 |= UCA0RXIE; // Enable USCI0 RX and TX
> interrupt // Do I need interrupts for this??
> //__bis_SR_register(LPM0_bits + GIE); // CPU off, enable
> interrupts for(;;) //
> Just threw in this dumy infinite loop for later use {}
>
> }

PxSEL and PxSEL2 are not redundant, together they determine the function of the port. Make sure your settings are correct to use them for SPI. Other than that, common problems with SPI are :

- SPI clk not inside range accepted by slave
- incorrect clock phase / polarity
- for some slave you need to send a pulse (via /CS or other input) to trigger execution of the command

Also make sure the timing e.g when you reset the slave is correct.

--- In m..., "noefvillanueva" wrote:
>
> Hello Everyone,
>
> This is my first post here so please bear with me. Now I'm am working with the MSP430G2553 on the Launch pad to communicate with an external 16 bit ADC MAX1415. I need the higher resolution hence the reason I am not using the on board ADC. Now, I am trying to use SPI communication to connect to this ADC but I tried using the TI sample SPI code but was told it really was not a useful example. After searching I came up with the following code but for my CheckX I just get d255 = hFF. I think it spits this out if it doesn't find a slave. Now I'm just not sure if for SPI I need to use interrupts or is the way I laid out my code able to accomplish communication.
>
> Thanks,
>
> #include unsigned long Check, Check1, Check2, Check3, Check4; //I put these checks to try and see what was being received
>
> void PinSetup(); // Not sure if I need this since with another TI Micro I used in school I had to
> void SpiSetup();
> void SetMaxim();
>
> void PinSetup()
> {
> P1OUT = 0x00; // P1 setup for LED & reset output
> P1DIR |= BIT5 + BIT3; // P1 direction as output 1.5 = Reset 1.3=CS
> P1SEL = BIT1 + BIT2 + BIT4; // [1.1 = SOMI-> PIN 13 DOUT of ADC] [1.2 = SIMO-> PIN 14 DIN of ADC]
> P1SEL2 = BIT1 + BIT2 + BIT4; // Not Sure what the difference is between Sel1 and Sel2 seems redundant
> }
>
> void SpiSetup()
> {
> // UCMSB = Selects Most Sig Fig 1st // UCMST = Select the SPI Module as the Master // UCSYNC = Selecting Synchronous mode
> UCA0CTL0 |= UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master Is UCCKPL needed???
> UCA0CTL1 |= UCSSEL_2; // USCI Clock source will be SMCLK
> UCA0BR0 |= 0x02; // /2
> UCA0BR1 = 0; //
> UCA0MCTL = 0; // No modulation
> UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**set low
> }
>
> void SetMaxim() // Trying to set up the ADC registers for clock rate and gain
> {
> P1OUT &= ~BIT5; // Pin 1.5 is pulled low to reset ADC
> P1OUT |= BIT5; // After ADC is reset Pin 1.5 pulled high to prevent reset
>
> P1OUT &= ~BIT3; // Pin 1.3 CS pulled low
> UCA0TXBUF = 0x00; // Send Dummy to Start SPI
>
> //IFG2 &= UCA0RXIFG; // Clear Flag Not sure if I need this????
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> UCA0TXBUF = 0x20; // h20 to to tell ADC to be prepared to write to clock reg next
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check = UCA0RXBUF;
> UCA0TXBUF = 0xB3; // hB3 for ADC clock run at 1Mhz
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check1 = UCA0RXBUF;
> UCA0TXBUF = 0x10; // h10 to tell ADC to be prepared to write to the setup reg next
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check2 = UCA0RXBUF;
> UCA0TXBUF = 0x44; // h44 for ADC to setup
>
> P1OUT |= BIT3; // Pull CS high
> }
>
> void main(void)
> {
> WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //NV Need from here
> PinSetup();
> SpiSetup();
> SetMaxim();
> //IE2 |= UCA0RXIE; // Enable USCI0 RX and TX interrupt // Do I need interrupts for this??
> //__bis_SR_register(LPM0_bits + GIE); // CPU off, enable interrupts
> for(;;) // Just threw in this dumy infinite loop for later use
> {}
>
> }
>

Hello Matthias,

I thought with it being Yahoo it would come up with my name Noe.

Well the first thing I fixed was P1DIR was missing BIT4 so I was never outputting a clock so I added that and in the datasheet it also says P1SEL2 should be 0 for BIT4 so I changed that.

Then I added some delays in the setup first since the ADC needs some time for the internal oscillator to start up. The delays in between the different transfers seemed to have helped but I still don't receive what I expect. In the watch window hFA instead of h20, hE9 instead of hA5, hFF instead of h10, and hFF instead of h44.

I hooked up a logic level analyzer I can see that initially both SOMI and SIMO are 255 then SIMO just goes to 192 then 0 and I don't get why.
Thanks,
Noe

#include

unsigned int Check, Check1, Check2, Check3, Check4; //I put these checks to try and see what was being received

void PinSetup()
{
    P1OUT = 0x00;                           // P1 setup for LED & reset output
    P1DIR |= BIT3 + BIT4 + BIT5 + BIT6;            // P1 direction as output 1.5 = Reset 1.3=CS 1.6 = Blink LED
    P1SEL |= BIT1 + BIT2 + BIT4;            //    [1.1 = SOMI-> PIN 13 DOUT of ADC] [1.2 = SIMO-> PIN 14 DIN of ADC]
    P1SEL2 |= BIT1 + BIT2;            //    [1.1 = SOMI-> PIN 13 DOUT of ADC] [1.2 = SIMO-> PIN 14 DIN of ADC]
}

void SpiSetup()
{
    // UCMSB = Selects Most Sig Fig 1st //  UCMST = Select the SPI Module as the Master // UCSYNC = Selecting Synchronous mode
    //UCA0CTL0 |= UCMSB + UCMST + UCSYNC;  // 3-pin, 8-bit SPI master
    UCA0CTL1 |= UCSWRST;                       // **Put state machine in reset**
    UCA0CTL0 |= UCCKPH + UCCKPL + UCMSB + UCMST + UCSYNC;// made ucckpl ->ucckph
    UCA0CTL1 &= ~UCSSEL_2;                     // USCI Clock source will be SMCLK
    UCA0BR0 = 0x02;                          // /2
    UCA0BR1 = 0;                              // Clock divider
    UCA0MCTL = 0;                             // No modulation
    UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**set low
}

void SetMaxim() // Trying to set up the ADC registers for clock rate and gain
{
    //P1OUT &= ~BIT5;                   // Pin 1.5 is pulled low to reset ADC
    //_delay_cycles(1000000);
    P1OUT |= BIT5;                    // After ADC is reset Pin 1.5 pulled high to prevent reset
    //_delay_cycles(500);
    P1OUT &= ~BIT3;                  // Pin 1.3 CS pulled low
    //_delay_cycles(500);
    //IFG2 &= UCA0TXIFG;             // Clear Flag Not sure if I need this????
    //while ((UCA0STAT & UCBUSY));          // Transmission Done? Not sure if I need this????

    while (!(IFG2 & UCA0TXIFG));    // USCI_A0 TX buffer ready?
    UCA0TXBUF = 0x20;               // send h20 to tell ADC to be ready to write to clock next
    _delay_cycles(50);
    Check1 = UCA0RXBUF;

    while (!(IFG2 & UCA0TXIFG));    // USCI_A0 TX buffer ready?
    UCA0TXBUF = 0xA5;               // hA5 for ADC clock run at 2.5Mhz
    _delay_cycles(50);
    Check2 = UCA0RXBUF;

    while (!(IFG2 & UCA0TXIFG));    // USCI_A0 TX buffer ready?
    UCA0TXBUF = 0x10;               // h10 to tell ADC to be ready to write to the setup reg next
    _delay_cycles(50);
    Check3 = UCA0RXBUF;

    while (!(IFG2 & UCA0TXIFG));    // USCI_A0 TX buffer ready?
    UCA0TXBUF = 0x44;               // h44 for ADC to setup
    _delay_cycles(50);
    Check4 = UCA0RXBUF;

    P1OUT |= BIT3;                  // Pull CS high
}

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer  //NV Need from here
  PinSetup();
  SpiSetup();

  SetMaxim();
  //__bis_SR_register(LPM0_bits + GIE);       // CPU off, enable interrupts
  for(;;)                                      // Just threw in this dumy infinite loop for later use
  {
      _delay_cycles(100000);
      P1OUT ^= BIT6;                        // Toggle green LED (P1.6)
  }
}

________________________________
From: Matthias Weingart
To: m...
Sent: Monday, July 15, 2013 1:35 AM
Subject: [msp430] Re: MSP430G2553 SPI for external ADC

 
Hi noefvillanueva (!?),

Often the first byte returning from a SPI slave is FF.

What do you see on the pins using a osci? Is it what you expect?

It is not easy to get SPI running with the UARTs, try bit banging (toggle
the SPI pins by software), when this is working, take a look at the spi
pins when using the uart.

Whats your name? ;-)

Matthias

"noefvillanueva" :

> Hello Everyone,
>
> This is my first post here so please bear with me. Now I'm am working
> with the MSP430G2553 on the Launch pad to communicate with an external
> 16 bit ADC MAX1415. I need the higher resolution hence the reason I am
> not using the on board ADC. Now, I am trying to use SPI communication to
> connect to this ADC but I tried using the TI sample SPI code but was
> told it really was not a useful example. After searching I came up with
> the following code but for my CheckX I just get d255 = hFF. I think it
> spits this out if it doesn't find a slave. Now I'm just not sure if for
> SPI I need to use interrupts or is the way I laid out my code able to
> accomplish communication.
>
> Thanks,
>
> #include
>
> unsigned long Check, Check1, Check2, Check3, Check4; //I put these
> checks to try and see what was being received
>
> void PinSetup(); // Not sure if I need this since with another TI Micro
> I used in school I had to void SpiSetup();
> void SetMaxim();
>
> void PinSetup()
> {
> P1OUT = 0x00; // P1 setup for LED & reset
> output P1DIR |= BIT5 + BIT3; // P1 direction
> as output 1.5 = Reset 1.3=CS P1SEL = BIT1 + BIT2 + BIT4;
> // [1.1 = SOMI-> PIN 13 DOUT of ADC] [1.2 = SIMO-> PIN
> 14 DIN of ADC] P1SEL2 = BIT1 + BIT2 + BIT4; // Not
> Sure what the difference is between Sel1 and Sel2 seems redundant
> }
>
> void SpiSetup()
> {
> // UCMSB = Selects Most Sig Fig 1st // UCMST = Select the SPI
> Module as the Master // UCSYNC = Selecting Synchronous mode
> UCA0CTL0 |= UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master Is
> UCCKPL needed??? UCA0CTL1 |= UCSSEL_2; // USCI
> Clock source will be SMCLK UCA0BR0 |= 0x02;
> // /2 UCA0BR1 = 0; //
> UCA0MCTL = 0; // No modulation
> UCA0CTL1 &= ~UCSWRST; // **Initialize USCI
> state machine**set low
> }
>
> void SetMaxim() // Trying to set up the ADC registers for clock rate and
> gain {
> P1OUT &= ~BIT5; // Pin 1.5 is pulled low to
> reset ADC P1OUT |= BIT5; // After ADC is
> reset Pin 1.5 pulled high to prevent reset
>
> P1OUT &= ~BIT3; // Pin 1.3 CS pulled low
> UCA0TXBUF = 0x00; // Send Dummy to Start SPI
>
> //IFG2 &= UCA0RXIFG; // Clear Flag Not sure if I need
> this????
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> UCA0TXBUF = 0x20; // h20 to to tell ADC to be
> prepared to write to clock reg next
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check = UCA0RXBUF;
> UCA0TXBUF = 0xB3; // hB3 for ADC clock run at 1Mhz
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check1 = UCA0RXBUF;
> UCA0TXBUF = 0x10; // h10 to tell ADC to be prepared
> to write to the setup reg next
>
> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
> Check2 = UCA0RXBUF;
> UCA0TXBUF = 0x44; // h44 for ADC to setup
>
> P1OUT |= BIT3; // Pull CS high
> }
>
> void main(void)
> {
> WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //NV
> Need from here PinSetup();
> SpiSetup();
> SetMaxim();
> //IE2 |= UCA0RXIE; // Enable USCI0 RX and TX
> interrupt // Do I need interrupts for this??
> //__bis_SR_register(LPM0_bits + GIE); // CPU off, enable
> interrupts for(;;) //
> Just threw in this dumy infinite loop for later use {}
>
> }


[Non-text portions of this message have been removed]

Noe Villanueva :

> Then I added some delays in the setup first since the ADC needs some
> time for the internal oscillator to start up. The delays in between the
> different transfers seemed to have helped but I still don't receive what
> I expect. In the watch window hFA instead of h20, hE9 instead of hA5,
> hFF instead of h10, and hFF instead of h44.

Check the hint from distantship; i think you can do it in the UART setup...
- incorrect clock phase / polarity

M.