This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Master SPI application using MSP430G2553



I am pretty much certain this is a minor error, but I cannot find it for the life of me.

Communicating through USCI_B0, I am interfacing with memory.  I have a logic analyzer hooked up to the part.  This is based off of the msp430g2xx3_usci_spi_master sample project that comes with the CC.

I send my op codes for wren, write, and read and can see the commands reach the memory.  Since I am in SPI master mode, I understand that I need to provide a dummy write to receive the input data for my reads.

The logic analyzer confirms command sent (MOSI) and the data received (MISO) are correct. 

Here is where I am stuck:

In the code, I use:

lnum2 = UCB0RXBUF;

As I understand it, this is the buffer (8 bit) that is filled once my command is sent and by feeding to unsigned int (16 bit) should be no problem.  This does not work, lnum2 does not reflect the value that I can see from the logic analyzer.  Can anyone see what I am doing wrong?

Sorry about the code being a bit messy...

(see attached)

//******************************************************************************
//   MSP430G2xx3 Demo - USCI_A0, SPI 3-Wire Master Incremented Data
//
//   Description: SPI master talks to SPI slave using 3-wire mode. Incrementing
//   data is sent by the master starting at 0x01. Received data is expected to
//   be same as the previous transmission.  USCI RX ISR is used to handle
//   communication with the CPU, normally in LPM0. If high, P1.0 indicates
//   valid data reception.
//   ACLK = n/a, MCLK = SMCLK = DCO ~1.2MHz, BRCLK = SMCLK/2
//
//   Use with SPI Slave Data Echo code example. If slave is in debug mode, P3.6
//   slave reset signal conflicts with slave's JTAG; to work around, use IAR's
//   "Release JTAG on Go" on slave device.  If breakpoints are set in
//   slave RX ISR, master must stopped also to avoid overrunning slave
//   RXBUF.
//
//                    MSP430G2xx3
//                 -----------------
//             /|\|              XIN|-
//              | |                 |
//              --|RST          XOUT|-
//                |                 |
//                |             P1.2|-> Data Out (UCA0SIMO)
//                |                 |
//          LED <-|P1.0         P1.1|<- Data In (UCA0SOMI)
//                |                 |
//  Slave reset <-|P1.5         P1.4|-> Serial Clock Out (UCA0CLK)
//******************************************************************************
/*
 * ======== Standard MSP430 includes ========
 */
#include <msp430.h>
#define MYTRUE 1
#define MYFALSE 0
#define numcycles 10
/*
 * ======== Grace related declaration ========
 */
extern void CSL_init(void);

/*
 *  ======== main ========
 */
void adc2ascii(unsigned int anum);

unsigned char MST_Data, SLV_Data;
volatile unsigned int i;
//char uart_data[256] = "abc\r\n";
float curr_V;
unsigned int charge_cnt;
int bytes_wr;
int first_run;
unsigned char digit[8];
unsigned int lnum;
unsigned int lnum2;
void main(int argc, char *argv[])
{
    CSL_init();                               //confirmation copy

    CCTL0 = CCIE;                             // CCR0 interrupt enabled
    CCR0 = 5000;
    TACTL = TASSEL_1 + MC_2 + TAIE;           // ACLK, contmode, interrupt enabled
    if (first_run)
    {
      charge_cnt = 0;
      bytes_wr = 0;
      lnum2 = 0xBD;
      first_run = MYFALSE;
    }


    //P1OUT &= ~BIT5;                           // Now with SPI signals initialized,
    //P1OUT |= BIT5;                            // reset slave
    P2OUT |= BIT1;                       // Vdd
    __delay_cycles(400);                 // Wait for slave to initialize
    P2OUT |= BIT5;                       // /RST high
    MST_Data = 0x01;                          // Initialize data values
    SLV_Data = 0x00;

    //P2OUT
    //UCA0TXBUF = 0x41;                     // Transmit first character
    //UCB0TXBUF = MST_Data;                     // Transmit first character

//---------------------------------------------
    int x;
    while (!(IFG2 & UCB0TXIFG));              // USCI_A0 TX buffer ready?

    MST_Data++;                               // Increment master value
    SLV_Data++;                               // Increment expected slave value

    ADC10CTL0 &= ~ENC;
    while (ADC10CTL1 & BUSY);               // Wait if ADC10 core is active
    ADC10CTL0 |= ENC + ADC10SC;
    ////__bis_SR_register(CPUOFF + GIE);        // LPM0 with interrupts enabled

    lnum = ADC10MEM;
    if (lnum < 512)
    {
//    	P2OUT |= BIT1;
//    	__delay_cycles(100);
//    	P2OUT &= ~BIT1;
//    	charge_cnt++;
    }

    //UCB0TXBUF = MST_Data;                     // Send next value

        P2OUT &= ~BIT0;                     // /CE low
        __delay_cycles(numcycles);                     // Add time between transmissions to
        UCB0TXBUF = 0x06;                     // WREN
        __delay_cycles(numcycles);                     // Add time between transmissions to
        P2OUT |= BIT0;                    // /CE high


        P2OUT &= ~BIT0;                     // /CE low
        __delay_cycles(numcycles);                     // Add time between transmissions to
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0x02;                 // write op code
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0x01;                 // write MSB address
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0xD9;                 // write LSB address
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0xAA;                 // write 1byte
        __delay_cycles(numcycles);                     // Add time between transmissions to
        P2OUT |= BIT0;                    // /CE high


    //UCB0TXBUF = MST_Data;                     // Send next value
for (x = 0; x < 50; x++)
{
                P2OUT &= ~BIT0;                     // /CE low
                __delay_cycles(numcycles);                     // Add time between transmissions to
                while (!(IFG2 & UCB0TXIFG));
                UCB0TXBUF = 0x05;                 // read op code
                //while (!(IFG2 & UCB0TXIFG));
                //UCB0TXBUF = 0x01;                 // write MSB address
                //while (!(IFG2 & UCB0TXIFG));
                //UCB0TXBUF = 0xD9;                 // write LSB address
                while (!(IFG2 & UCB0TXIFG));
                UCB0TXBUF = 0x00;                 // dummy for clock
                while (!(IFG2 & UCB0RXIFG));
                lnum2 = UCB0RXBUF;                 // write 1byte
                __delay_cycles(numcycles);                     // Add time between transmissions to
                P2OUT |= BIT0;                    // /CE high
}

P2OUT &= ~BIT0;                     // /CE low
__delay_cycles(numcycles);                     // Add time between transmissions to
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = 0x03;                 // read op code
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = 0x01;                 // write MSB address
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = 0xD9;                 // write LSB address
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = 0x00;                 // dummy for clock
while (!(IFG2 & UCB0RXIFG));            // RXBUF ready?
//while (!(UCB0RXIFG));
lnum2 = UCB0RXBUF;                 // write 1byte
__delay_cycles(numcycles);                     // Add time between transmissions to
P2OUT |= BIT0;                    // /CE high

                adc2ascii(lnum2);

    __delay_cycles(numcycles);                     // Add time between transmissions to
//------------------------------------------------
    //__bis_SR_register(LPM0_bits + GIE);       // CPU off, enable interrupts
    while(1);
}

void USCIA0RX_ISR(void)
{
/*
    //int x;
    while (!(IFG2 & UCB0TXIFG));              // USCI_A0 TX buffer ready?

    MST_Data++;                               // Increment master value
    SLV_Data++;                               // Increment expected slave value

    ADC10CTL0 &= ~ENC;
    while (ADC10CTL1 & BUSY);               // Wait if ADC10 core is active
    ADC10CTL0 |= ENC + ADC10SC;
    ////__bis_SR_register(CPUOFF + GIE);        // LPM0 with interrupts enabled

    lnum = ADC10MEM;
    if (lnum < 512)
    {
//    	P2OUT |= BIT1;
//    	__delay_cycles(100);
//    	P2OUT &= ~BIT1;
//    	charge_cnt++;
    }

    //UCB0TXBUF = MST_Data;                     // Send next value

        P2OUT &= ~BIT0;                     // /CE low
        __delay_cycles(50);                     // Add time between transmissions to
        UCB0TXBUF = 0x06;                     // WREN
        __delay_cycles(50);                     // Add time between transmissions to
        P2OUT |= BIT0;                    // /CE high


        P2OUT &= ~BIT0;                     // /CE low
        __delay_cycles(50);                     // Add time between transmissions to
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0x02;                 // write op code
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0x01;                 // write MSB address
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0xD9;                 // write LSB address
        while (!(IFG2 & UCB0TXIFG));
        UCB0TXBUF = 0x02;                 // write 1byte
        __delay_cycles(50);                     // Add time between transmissions to
        P2OUT |= BIT0;                    // /CE high


    //UCB0TXBUF = MST_Data;                     // Send next value

                P2OUT &= ~BIT0;                     // /CE low
                __delay_cycles(50);                     // Add time between transmissions to
                while (!(IFG2 & UCB0TXIFG));
                UCB0TXBUF = 0x05;                 // read op code
                //while (!(IFG2 & UCB0TXIFG));
                //UCB0TXBUF = 0x01;                 // write MSB address
                //while (!(IFG2 & UCB0TXIFG));
                //UCB0TXBUF = 0xD9;                 // write LSB address
                while (!(IFG2 & UCB0RXIFG));
                lnum2 = UCB0RXBUF;                 // write 1byte
                __delay_cycles(50);                     // Add time between transmissions to
                P2OUT |= BIT0;                    // /CE high

                adc2ascii(lnum2);

    __delay_cycles(50);                     // Add time between transmissions to
    */
}                                           // make sure slave can keep up


void TIMER_ISR(void)
{
/*
    //adc2ascii((lnum/1023)*3600);
    adc2ascii(lnum);
    adc2ascii(charge_cnt);
    //delay_ms(500);     */
    while (!(IFG2 & UCA0TXIFG));              // USCI_A0 TX buffer ready?
    UCA0TXBUF = '\r';                         // Send next value
    while (!(IFG2 & UCA0TXIFG));              // USCI_A0 TX buffer ready?
    UCA0TXBUF = '\n';                         // Send next value

  CCR0 += 5000;                            // Add Offset to CCR0
}

void adc2ascii(unsigned int anum)
 {
   int i=0;
   while(anum >= 10)
   {
     digit[i] = anum % 0x0a;
     anum = anum / 0x0a;
     i++;
   }
   digit[i] = anum;
   while(i>=0)
   {
     while (!(IFG2 & UCA0TXIFG));              // USCI_A0 TX buffer ready?
     UCA0TXBUF = digit[i] + 48;//uart_data[x];//ADC10MEM;                     // Send next value
     digit[i] = 0;
     i--;
   }
   //delay_ms(500);
   while (!(IFG2 & UCA0TXIFG));              // USCI_A0 TX buffer ready?
   UCA0TXBUF = ' ';                         // Send next value
   while (!(IFG2 & UCA0TXIFG));              // USCI_A0 TX buffer ready?
   UCA0TXBUF = ' ';                         // Send next value
}
 

 

/*
 *  ==== DO NOT MODIFY THIS FILE - CHANGES WILL BE OVERWRITTEN ====
 *
 *  Generated from
 *      C:/ti/grace_1_10_04_36/packages/ti/mcu/msp430/csl/communication/USCI_A0_init.xdt
 */

#include <msp430.h>

/*
 *  ======== USCI_A0_init ========
 *  Initialize Universal Serial Communication Interface A0 SPI 2xx
 */
void USCI_A0_init(void)
{


    /* Disable USCI */
    UCA0CTL1 |= UCSWRST;
    UCB0CTL1 |= UCSWRST;

    /* disable ADC10 during initialization */
    ADC10CTL0 &= ~ENC;


    /* 
     * Control Register 0
     * 
     * ~UCCKPH -- Data is changed on the first UCLK edge and captured on the following edge
     * UCCKPL -- Inactive state is high
     * UCMSB -- MSB first
     * ~UC7BIT -- 8-bit
     * UCMST -- Master mode
     * UCMODE_0 -- 3-Pin SPI
     * UCSYNC -- Synchronous Mode
     * 
     * Note: ~<BIT> indicates that <BIT> has value zero
     */
    UCB0CTL0 = /*UCCKPL +*/ UCCKPH + UCMSB + UCMST + UCMODE_0; //+ UCSYNC;
    ADC10CTL0 = ADC10IE + ADC10ON + /*REFON +*/ ADC10SHT_3 + SREF_0;
    
    /* 
     * Control Register 1
     * 
     * UCSSEL_2 -- SMCLK
     * UCSWRST -- Enabled. USCI logic held in reset state
     */
    UCA0CTL1 = UCSSEL_2 + UCSWRST;
    UCB0CTL1 = UCSSEL_2 + UCSWRST;
    ADC10CTL1 = CONSEQ_0 + ADC10SSEL_0 + ADC10DIV_3 + SHS_0 + INCH_0;
    //ADC10CTL0 |= ENC;
    
    /* Bit Rate Control Register 0 */
    UCA0MCTL = UCBRF_0 + UCBRS_1;
    UCA0BR0 = 104;
    UCB0BR0 |= 0x1;
    UCB0BR1 = 0;

    
    /* Software delay for REFON to settle */
    __delay_cycles(30000);

    /* enable ADC10 */
    ADC10CTL0 |= ENC;

    /* Enable USCI */
    UCA0CTL1 &= ~UCSWRST;
    UCB0CTL1 &= ~UCSWRST;
}

  • Jonathan Hunter1 said:
    As I understand it, this is the buffer (8 bit) that is filled once my command is sent and by feeding to unsigned int (16 bit) should be no problem.

    Yes.

    Jonathan Hunter1 said:
    This does not work, lnum2 does not reflect the value that I can see from the logic analyzer.  Can anyone see what I am doing wrong?

    I ddin't look intot he code, btu maybe the double-bufferign is fooing you.

    When you put your first dummy byte into TXBUF, the last command byte probably hasn't been sent completely (or has just moved into the output shift register and didn't even start to be sent), and the current content of RXBUF is the return for the second last command byte.

  • Jens,

    You were absolutely correct!  I needed another dummy write (2 bytes total - 16 clock ticks)  to get the information moved to the variable after the op code and address bytes were sent.  Thanks so much for your input!

    Best Regards

  • Hi Jens,

    Can't we simply read on the master? Do I have to send the dummy byte on TXBUF every time? Is there a work around this?

    Thanks.

  • Salil Rajadhyaksha said:
    Is there a work around this?

    No, because it's how SPI works. There is only a clock signal, no direction or R/W signal nor a transaction header like the I2C start byte.

    When a clock pulse comes, one bit is shifted out and one bit is shifted in. Always. Even if no-on is listening to the sent bit or providing a bit to read.

    Of course, if you are slave and don't want to send something (just listening to the master) you don't need to write to TXBUF. Then IIRC the last byte written to TXBUF will be sent over and over again. Also, when you're just sending, you can ignore the bytes you receive while doing so. But on hardware level, each clock pulse sends a bit and receives a bit.
    And to make the master generate a clock pulse (or rather 8) on the USCI module, you need to write something to TXBUF. Even if you just want to read. (on USI module, you write the number of bits to transceive in the count register, to start the transfer)
    On the bottom line, it makes no difference. Whether you clock the bus to receive data and leave the output idle, or whether you send a dummy byte, won't make a difference. This or that way you'll have to initiate the transfer anyway, so it is the same effort too.

**Attention** This is a public forum