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.

MSP430G2553: Difficulty running SPI I/F as Master -- 4 wire I/F, get only one interrupt with multi-byte xfer

Part Number: MSP430G2553
Other Parts Discussed in Thread: MSP430WARE, , MSP-FET

SYNOPSIS of Issue -- DSP chip ran the SPI I/F too fast for G2553 chip to handle the SPI traffic as a slave so in a fall-back position reworked the G2553 code to work as  SPI Master (wilth the DSP as a slave instead) at a leisurely rate of ~9600 bits/sec. 

Try as I might, I can only get the first interrupt for a multi-char transfer and after the byte is placed in TXBUF in the ISR, no SPI clock or SOMI clocks or bits ensue from the port as one would expect (using a SALEAE Pro Logic16 Analyzer to examine the SPI I/F to include the SPI enable signal which operates as expected.

FACTS BEARING:  I have made sure that SMCLK is the specifed clock, I have poured over the Family Users Guide, the Product Review Guide, and Errata documents (all verified as latest versions) looking for any missing initialization, clocking, or control info and can't find anything "wrong" even though common sense says there must be. I had found references to an ME2 SFR the G2553 does not support according to the MSP-FET430UIF debbugger screen using IAR 8.0 with 7.11.1 build chain in debug mode and this control register does not show up -- I thought I had found the problem in that the SPI peripheral was not enabled but turned out to be a "red-herring".  There are two chunks of code that follows the text of this message -- the G2553 SPI master init with a putstr (Put String) function and RX/TX ISR's and another chunk of the SPI slave for the F28069 DSP chip.  The focus should be on the G2553 since it is not working as a proper master, the DSP code for completeness only.  I am an experienced embedded firmware developer with 8, 16, and 32 bit processor experience with Motorola, TI, ST-Micro, and Infineon processor code with many successful interface developements with RS232, RS485, SPI, and I2C and have never stumbled into a head-scratcher like this one.  Ouch!

SYMPTOM:  The port has all the appearance of not actually running -- the TXBUF is loaded but no SPI clocks or data is transmitted -- as if the shift register out the port pin is not or cannot run and thereby preventing the TXBUF IFG bit from getting set for the next byte.

Please help.

Respectfully,

Keith Abell

Senior Firmware Engineer, Intellipower Inc.

=============== Target SPI Master code in MSP430G2553 device  - Initialization and ISR's

/*!    @file        ucb0_SPI.c
 *    @author     Keith Abell
 *
 *    @brief        Performs UCB0 SPI Interface functions for the processor.
 *
 * TARGET:         MSP430G2553 device
 *

void initializeUCB0_Spi(void)
{
    UCB0CTL1__SPI = UCSWRST;                          // Disable the UCB peripheral
    UCB0CTL0__SPI = UCMSB | UCMODE_2 | UCSYNC;        // MSB first as slave, 4-Pin STE active Lo, Synchronous
//  UCB0CTL0__SPI |= UCCKPH + UCCKPL;                 // For now, use Phase/Polarity = 00, Data chg on rising edge, capture on trailing edge, clock normally low
    UCB0CTL1__SPI |= UCSSEL_2;                        // SMCLK, Enabled. USCI logic held in reset state

    UCB0CTL0__SPI |= UCMST;                                         // Or in master mode control bit

// CRYSTAL_X2 is 16Mhz defined in another .h file
#define BAUDRATE ( ( CRYSTAL_X2 / SPIbaudrate ) )     // Round BAUDRATE down to nearset integer -- use crystal and SPIbaudrate from system_ModF_Proc.h
    UCB0BR0__SPI = (0xFF & BAUDRATE)+1;                  // Set low order baudrate register, round up by 1
    UCB0BR1__SPI = (0xFF & (BAUDRATE>>8));             // Set high order baudrate register -- Buadrate = (256*hivalue)+lowvalue

    UCB0CTL1__SPI &= ~(unsigned int) UCSWRST;         // Enable the UCB peripheral
    USART_RX_INT_ENABLE;
//    USART_TX_INT_ENABLE;                                           // Turn on TX interrupt only when ready to send a message
    return;                                                                              // Bye
}                                                                                           // End of initializeUCB0_Spi

// Note:  The test string is defined in main.c and calls this routine to start the xfer by simply making the chip enable active and turing on the SPI RX and TX interrupts by setting the appropriate IE2 enable bits using the macros shown below...

void usart_putstr (char *string)
{
    usart_tx_char_count = strlen (string);

    if ( usart_tx_char_count <= USART_TXBUFSIZE )
    {
       DSP_CE_ENABLE;                                           // turn on SPI enable to talk to DSP
       USART_TX_INT_ENABLE;                                // Make sure TX interrupts are enabled -- Note: once all characters are transfered, TX interrupts will be turned off by the ISR
       USART_RX_INT_ENABLE;                               // Ditto RX interrupts
    }
}





// USCIAB0RX interrupt service routine
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX (void)
{
    // This is an RX interrupt

    static unsigned char tempchar;
    if ( IFG2 & UCB0RXIFG )
    {
        tempchar = UCB0RXBUF;                             // Clears UCB0RXIFG
        temp_rx_buffer[temp_rx_idx++] = UCB0STAT__SPI;    // Save error flags in circular buffer
        if ( temp_rx_idx == ( USART_RXBUFSIZE+1 ) )
        {
            temp_rx_idx = 0;
        }
        if (usart_rx_char_count == USART_RXBUFSIZE)
        {
           return;
        }
        if ( tempchar != SYN )                                       // Do not store Sync Idle chars -- just idling
        {
          usart_rx_buffer[usart_rx_write_index++] = tempchar;         // store received byte and inc receive index
          if (usart_rx_write_index == (USART_RXBUFSIZE+1) )          // if write index was just incremented past the buffer size  reset it
          {
             usart_rx_write_index = 0;
          }
          usart_rx_char_count++;                                     // char received, inc count
          switch(tempchar)
          {
             case STX:
                 mspData.StartOfMsgFlag = TRUE;                      // Signal start of message received
                 break;
             case ETX:
                 mspData.RcvDSPmsgFlag = TRUE;                       // Signal end of message received -- will need to check simple checksum
                 usart_rx_buffer[usart_rx_write_index++] = NULL;     // Stuff null into buffer after ETX for string processing
                 if (usart_rx_write_index == (USART_RXBUFSIZE+1) )   // if write index was just incremented past the buffer size, reset it
                 {
                     usart_rx_write_index = 0;
                 }
                 break;
              default:                                               // OK, not special character, just keep going
                 break;
            }
        }
    }
}

// USCIAB0TX interrupt service routine
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX (void)
{
    if ( IFG2 & UCB0TXIFG )
    {
        // This is a TX interrupt
        if (usart_tx_char_count > 0)                             // send if chars are in buffer
        {
            UCB0TXBUF = mspData.msgStr[usart_tx_read_index++];  // load tx register, inc index
            if ( usart_tx_read_index == (USART_TXBUFSIZE+1) )     // if index was incremented one larger than max, reset to 0
            {
                usart_tx_read_index = 0;
            }
            usart_tx_char_count-- ;                                 // char sent, dec count
            //LedUPS1(LED_RED);
//            Do_a_nop;
        }
        else
        {
//  KRA EDIT -- need to rework this to send default char (SYN) if we are transmitting to get response of command sent to DSP.  For now, just kill TX INT enable
//              I am trying to get message transmits as master to work at the moment -- not so worried about receives and dummy transmits to get a response from
//              the DSP as slave
//          UCB0TXBUF = SYN;                         // buffer empty, send Synch instead -- won't clock out unless Masteer (DSP) sends us something
                                                                       //   and we have been enabled (spien1 high).
            USART_TX_INT_DISABLE;              // Turn off TX interrupt
        }
    }
}



=============== Target slave code in FMS320F28069 device -Initialization and ISR's



/*!    @file        hal_spi_flash.c
 *     @author  Keith Abell
 *     @brief     Performs Hardware Access Level control of SPI interface to External Serial SPI Flash Device and MSP430.
 *
 * TARGET:         TMS320F28069 device
 *

// KRA EDIT -- This init routine now sets the DSP up as slave -- we initialize the SPI clock subsystem registers but since the
//   SPI master bit is not set, the SPI clock will be ignored and depend solely on the G2553 SPI clock as master.
void init_hal_spi_flash (void)
{
    unsigned int i;

   FLASH_CE_DISABLE;                                                        // Deselect the SPI Serial Flash (Output is HIGH)
  MSP430_CE_DISABLE;                                                        // Deselect the MSP430 (Output is HIGH)
  spiPort.rxWriteIndex = spiPort.rxReadIndex = spiPort.rxCharCount = 0;    // Flush and prepare the SPI Receive  Buffer
  spiPort.txWriteIndex = spiPort.txReadIndex = spiPort.txCharCount = 0;    // Flush and prepare the SPI Transmit Buffer
  spiPort.checkCount = 0;
  SpiaRegs.SPICCR.bit.SPISWRESET = 0;                // Reset the SPI Interface on the DSP
  EALLOW;                                                                    // Allow Protected Access to Registers
  PieVectTable.SPIRXINTA = &spiaFlashReceiveIsr;            // Set the Interrupt Routine for Receive
  PieVectTable.SPITXINTA = &spiaFlashTransmitIsr;            // Set the Interrupt Routine for Transmit
  EDIS;                                                                    // Disallow Protected Access to Registers
  EALLOW;                                                                    // Allow Protected Access to Registers
  GpioCtrlRegs.GPBMUX2.bit.GPIO50  = 0;            // SPI Enable 0 - Serial Flash, configured as GPIO
  GpioCtrlRegs.GPBPUD.bit.GPIO50   = 0;            // *Enable pullups
  GpioCtrlRegs.GPBDIR.bit.GPIO50   = 1;                // Make this pin an output
  GpioCtrlRegs.GPAMUX2.bit.GPIO29  = 0;            // SPI Enable 1 - Local MSP430 Real Time Clock, configured as GPIO
  GpioCtrlRegs.GPAPUD.bit.GPIO29   = 0;            // *Enable pullups
  GpioCtrlRegs.GPADIR.bit.GPIO29   = 1;                // Make this pin an output
  GpioCtrlRegs.GPAPUD.bit.GPIO5    = 0;                // *Enable pull-up on  GPIO5 (SPISIMOA)
  GpioCtrlRegs.GPAQSEL1.bit.GPIO5  = 3;            // Asynchronous input GPIO5 (SPISIMOA)
  GpioCtrlRegs.GPADIR.bit.GPIO5    = 1;                // SPISIMOA is an output GPIO
  GpioCtrlRegs.GPAMUX1.bit.GPIO5   = 2;             // Configure GPIO5 as SPISIMOA
  GpioCtrlRegs.GPAPUD.bit.GPIO17   = 0;            // *Enable pull-up on  GPIO17 (SPISOMIA)
  GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3;            // Asynchronous input GPIO17 (SPISOMIA)
  GpioCtrlRegs.GPADIR.bit.GPIO17   = 0;                // SPISOMIA is an input GPIO
  GpioCtrlRegs.GPAMUX2.bit.GPIO17  = 1;            // Configure GPIO17 as SPISOMIA
  GpioCtrlRegs.GPAPUD.bit.GPIO18   = 0;            // *Enable pull-up on  GPIO18 (SPICLKA)
  GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3;            // Asynchronous input GPIO18 (SPICLKA)
  GpioCtrlRegs.GPADIR.bit.GPIO18   = 1;                // SPICLKA is an output GPIO
  GpioCtrlRegs.GPAMUX2.bit.GPIO18  = 1;            // Configure GPIO18 as SPICLKA
  EDIS;                                                                    // Disallow Protected Access to Registers
  SpiaRegs.SPICCR.bit.SPICHAR            = 7;                                // Select 8-bit character output (x + 1)
// KRA EDIT -- we will use Mode 0 (Pol), 0 (Pha) -- Data out on rising edge (no delay) and sample data on rising edge
// KRA EDIT -- settled on for 00 pol/pha -- pol/pha compatible with Serial Flash as well as MPS430G2553 also set for 0,0
  SpiaRegs.SPICCR.bit.CLKPOLARITY       = 0;                            // Data out on falling clock edge with input on rising edge
  SpiaRegs.SPICTL.bit.CLK_PHASE             = 0;                                                     // Normal SPI Clocking Scheme with no delay
  SpiaRegs.SPICCR.bit.SPILBK        = 0;                            // SPI loop back mode is disabled
  SpiaRegs.SPICTL.bit.MASTER_SLAVE    = 0;                            // SPI is configured as a SLAVE now
  SpiaRegs.SPICTL.bit.OVERRUNINTENA    = 0;                            // Disable RECEIVER OVERRUN Flag bit interrupts
  SpiaRegs.SPICTL.bit.TALK            = 1;        // Let the SPI peripheral Talk
  SpiaRegs.SPIPRI.bit.FREE            = 1;        // Emulator breakpoints will not disturb transmissions
//   KRA Comment -- the baud rate defined by BRR can be slowed down by changing the LSPCLK divisor of SYSCLKOUT (or 90Mhz) by changing the
//   LSPCLK bits in the LOSPCP pre-scalar register to a max of 7b for a divide by 14 up from 4 with other selections in between
//   Note the LSPCLK is the basic clock driving all SPI and SCI UART devices to baud-rate selection must take this into account
//   Since we can easily generate a 9600 baud SCI clock for UARTs with a divide by 4 on LSPCLK but 175K bits/sec for SPI 
//   is a "little fast"...we will go as slow as we can but turns out is still too fast for the G2553
//   LSPCLK that is 90Mhz/14 ~ 6.42 Mhz and with a BITRATECONTROL of (127+1) yields a bit rate of 50.22K or ~6278 bytes/sec
  EALLOW;
  SysCtrlRegs.LOSPCP.all = 0x0007;                                                                          // Set pre-scalor for LSPCLK to 12 (see 1.4.1.2 in tech ref) (protected reg)
  EDIS;
  SpiaRegs.SPIBRR = BITRATECONTROL;             // Set bit rate
  SpiaRegs.SPIFFTX.bit.SPIRST = 0;                // The SPI Transmit and Receive Channels can resume
  SpiaRegs.SPIFFTX.bit.SPIFFENA = 1;                // SPI FIFO enhancements enabled
  SpiaRegs.SPIFFTX.bit.TXFIFO = 0;                // Clear out FIFO, reset pointer, and hold in Reset
  SpiaRegs.SPIFFTX.bit.TXFFINTCLR = 1;                // Clear the TXFIFINT flag
  SpiaRegs.SPIFFTX.bit.TXFFIL = 1;                // Set to zero
  SpiaRegs.SPIFFTX.bit.TXFFIENA = 0;                // For now, disable TX FIFO Interrupt -- wait until rdy to Xmit
  SpiaRegs.SPIFFRX.bit.RXFIFORESET = 0;            // Reset FIFO to zero and hold in reset
  SpiaRegs.SPIFFRX.bit.RXFFINTCLR = 1;            // Clear any pending interrupts
  SpiaRegs.SPIFFRX.bit.RXFFIENA = 1;                                // Enable RX FIFO interrupt
  SpiaRegs.SPIFFRX.bit.RXFFIL = 1;                                // FIFO generates interrupt on 1 or more characters received
  SpiaRegs.SPIFFCT.bit.TXDLY = 0;                // No delays in FIFO transmit of bits;
  SpiaRegs.SPIFFTX.bit.SPIRST = 1;                // The SPI Transmit and Receive Channels can resume
  SpiaRegs.SPICTL.bit.SPIINTENA = 1;                // SPI Interrupts Enabled
  SpiaRegs.SPICCR.bit.SPISWRESET = 1;                // Relinquish SPI from Reset
  SpiaRegs.SPIFFTX.bit.TXFIFO = 1;                // Release FIFO for normal operations
  SpiaRegs.SPIFFRX.bit.RXFIFORESET = 1;            // Release FIFO for use
  PieCtrlRegs.PIECTRL.bit.ENPIE = 1;                // Enable PIE Block... just in case
  PieCtrlRegs.PIEIER6.bit.INTx1 = 1;                // Enable PIE Group 6, INT 1
  PieCtrlRegs.PIEIER6.bit.INTx2 = 1;                // Enable PIE Group 6, INT 2
  IER |= M_INT6;                                                            // Core enable interrupt for SPI block+
  spiFlashData.currentCommand  = flashNoOperation;        // Idle the SPI Flash State Machine
  spiFlashData.subState = 1;                    // Preset to subState 1
  spiFlashData.devicePresent   = FALSE;                // Preset so that there is no device present
  spiFlashData.commandComplete = FALSE;            // Command is complete as there is none at this point

  pEventData->msp430Data.msgFail = NOTBUSY;
  pEventData->msp430Data.lengthOfData = MAX_MSP430_STRING;
  pEventData->msp430Data.MSP_WriteIdx = 0;
  pEventData->msp430Data.MSP_ReadIdx = 0; 
  for (i = 0; i < MAX_MSP430_STRING ; i++ )
  {
        pEventData->msp430Data.MSP430_ReadBuffer[i] = 0;
        pEventData->msp430Data.MSP430_WriteBuffer[i] = 0;
  }
 for (i = 0; i < FLASH_BUFSIZE; i++)
 {
        tempMspWrBuffer[i]= tempMspRdBuffer[i] = 0;
  }
  tmpMspRdIdx = tmpMspWrIdx = 0;
  pEventData->Spi_Port_Busy = PORT_FLASH_BUSY;
  spiPort.rxCharCount = spiPort.txCharCount = spiPort.txWriteIndex = spiPort.rxWriteIndex = 0;
  spiPort.txReadIndex = spiPort.rxReadIndex = spiPort.checkCount =0 ;

   for (i = 0; i < FLASH_BUFSIZE; i++ )
   {
         spiPort.rxBuffer [i] = 0;
         spiPort.txBuffer [i] = 0;
    }
    Do_a_nop;
    return;
}       // End of init_hal_spi_flash


__interrupt void spiaFlashTransmitIsr (void)
{
//    static unsigned int delay;
    unsigned char tempData;                                            // Temporary data variable
    if (pEventData->Spi_Port_Busy == PORT_MSP430_BUSY)
    {
        if( pEventData->msp430Data.MSP_WriteIdx > MAX_MSP430_STRING )
        {
            pEventData->msp430Data.MSP_WriteIdx = 0;                // Wrap the buffer pointer
        }
        if ( pEventData->msp430Data.xmitcnt != 0 )
        {
            tempData = pEventData->msp430Data.MSP430_WriteBuffer[pEventData->msp430Data.MSP_WriteIdx++];        // Char to write
            if( tmpMspWrIdx > FLASH_BUFSIZE )
            {
                tmpMspWrIdx = 0;
            }
            tempMspWrBuffer[tmpMspWrIdx++] = tempData;      // Unconditional save of every Tx char pulled/sent from write buffer
            tempData <<= 8;                                                                     // Shift it to the left
            tempData &= 0xFF00;                                                          // Mask off don't care
//            for ( delay = 0; delay < 8000; delay++){};                         // Wait awhile
            SpiaRegs.SPITXBUF = tempData;                                     // Load the transmit register with the data
            pEventData->msp430Data.xmitcnt--;                               // Decrement count, stop when 0;
        }
        else
        {
            SPI_TX_INT_DISABLE;                                                    // Stop transmitting new chars
//            MSP430_CE_DISABLE;                                                   // Need to wait for FIFO to clear
        }
    }

// KRA EDIT -- The code below is only for Serial Flash operations!!!    Receive ISR for MSP430 and Serial Flash follows after this ISR end.
    else if (pEventData->Spi_Port_Busy == PORT_FLASH_BUSY)
            {
                 if (SpiaRegs.SPIFFTX.bit.TXFFST < 1)        // Make sure there is room in the FIFO (only four locations)
                                 {
        if (spiPort.txCharCount)           // OK, are there still characters in the buffer...
                                        {
                                              tempData = spiPort.txBuffer [spiPort.txReadIndex++];        // Yes, Load the data, make left justified and inc the index
                                              tempData <<= 8;                              // Shift it to the left
              tempData &= 0xFF00;
                                              SpiaRegs.SPITXBUF = tempData;            // Load the transmit register with the data
                                              spiPort.txCharCount--;                // Character was sent, so decrement the count
                                               if (spiPort.txReadIndex >= FLASH_BUFSIZE)        // Check if we are at the end of the circular buffer...
                                               {
                                    spiPort.txReadIndex = 0;                // Reset the index if so
                                               }                                                        // End of buffer check
         }
         else //  OK, no characters remaining...                                                    // Else if no more characters to send...
         {
                                               SPI_TX_INT_DISABLE;                // Turn off TX interrupt
                                         }    // End of buffer checks
                                  }     // End of FIFO full check
             }
      SpiaRegs.SPIFFTX.bit.TXFFINTCLR = 1;                            // Clear Interrupt flag
      PieCtrlRegs.PIEACK.bit.ACK6     = 1;                            // Issue PIE acknowledge
}                                                                    // End of __interrupt void spiFlashTransmitIsr

__interrupt void spiaFlashReceiveIsr (void)
{
    static unsigned int errorcount = 0;                             // Set it to 0 to start
    unsigned char tempData;                                            // Read data temporary data variable
    tempData = SpiaRegs.SPIRXBUF;
//    unsigned char tempMspWrBuffer[FLASH_BUFSIZE*2], tempMspRdBuffer[FLASH_BUFSIZE*2];
//    unsigned int  tmpMspRdIdx = 0;

    if ( pEventData->Spi_Port_Busy == PORT_MSP430_BUSY)
    {
        if( tmpMspRdIdx > FLASH_BUFSIZE)
        {
            tmpMspRdIdx = 0;
        }
        tempMspRdBuffer[tmpMspRdIdx++] = tempData;                  // Unconditional save of every receive char in circular buffer
        if ( pEventData->msp430Data.msgFail == BUSYREAD )           // This could be a spurious read during a write: chk for SYN char @else
        {
            if (pEventData->msp430Data.MSP_ReadIdx == 0)            // Are we waiting on STX?
            {
               if ( tempData == STX )
               {
                   pEventData->msp430Data.MSP430_ReadBuffer[pEventData->msp430Data.MSP_ReadIdx++] = tempData;
               }
               else if ( tempData == SYN)    // No, character is not  an STX...IDLE character?
                    {
                        // Ok, assume we are till in proper communication -- keep going but only for so many chars...
                        if ( errorcount++ > MAX_MSP_RCVCHAR_ERR )
                        {
                            // Ok, we've waited 4 msec for the start of a response...it isn't coming
                            Process_MSP_Rcv_error();
                        }
                    }
                    else        // No STX or SYN char and the read count is still 0...report error
                    {
                        // Ok, wasn't an STX or a SYN synch character -- we are really out of sequence
                        Process_MSP_Rcv_error();
                    }
            }
            else    // OK, we've got an STX or the IDX would still be 0, check for ETX and stuff char
            {
                if ( pEventData->msp430Data.MSP_ReadIdx < MAX_MSP430_STRING)
                {
                    pEventData->msp430Data.MSP430_ReadBuffer[pEventData->msp430Data.MSP_ReadIdx++] = tempData;
                    if ( tempData == ETX)
                    {
                        // OK, we have terminated with an ETX with the buffer less than full so report OK, end of BUSYREAD
                        pEventData->msp430Data.msgFail = OK;
                        pEventData->msp430Data.lengthOfData = pEventData->msp430Data.MSP_ReadIdx;   // Idx is char count
                        pEventData->msp430Data.MSP_ReadIdx = 0;                                     // Clear read idx for next RCV
                        pEventData->msp430Data.MSP_WriteIdx = 0;                                    // Clear write idx for next RCV
                        // Turn off SPI Transmit interrupts to turn off receive!  We are only Xmitting to read chars!
                        SPI_TX_INT_DISABLE;
                    }
                }
                else    // We have filled up the receive buffer...rcv error
                {
                    Process_MSP_Rcv_error();
                }
            }

            Do_a_nop;
        }
        else  if ( pEventData->msp430Data.msgFail == BUSYWRITE )       // substate should == BUSYWRITE so handle write return byte
              {
                  if ( tempData != SYN )                               // Skip this character -- junk, don't need to save or read 'em
                  {
//                      __asm("        ESTOP0");     // Uncomment for debugging purposes    // Not working as expected...research
                  }
              }
              else //  We aren't in either BUSYREAD or BUSYWRITE, we shouldn't be in PORT_MSP430_BUSY mode!
              {
                  // We are in definite "lost" territory, wrap up an error
                  __asm("        ESTOP0");     // Uncomment for debugging purposes        // Not working as expected...research
              }
    }

// KRA EDIT -- The code below is only for Serial Flash operations!!!

    else if ( pEventData->Spi_Port_Busy == PORT_FLASH_BUSY )                // If we are not flash busy than clear the interrupt
         {                                                                   //   and return
            if( tmpFlashRdIdx > FLASH_BUFSIZE )
            {
                tmpFlashRdIdx = 0;
            }
            tempFlashRdBuffer[tmpFlashRdIdx++] = tempData;                  // Unconditional save of every receive char in circular buffer
             if ( spiPort.rxCharCount < FLASH_BUFSIZE )                     // Make sure we have room, otherwise report error
             {
                 spiPort.rxBuffer [spiPort.rxWriteIndex++] = tempData;      // Store the rcvd byte and increment the receive index
                 if (spiPort.rxWriteIndex >= FLASH_BUFSIZE)                 // Check if we are at the end of the circular buffer...
                 {
                     spiPort.rxWriteIndex = 0;                              // Reset the index if so
                 }                                                          // End of buffer check
                 spiPort.rxCharCount++;                                     // Character was received, so increment the count
             }
             else                                                           // Report SPI flash error
             {
                 pEventData->Spi_Port_Busy = PORT_FLASH_ERR;                // Report RCVERR
                 spiPort.rxCharCount = 0;                                   // Setup for new Flash receive
                 spiPort.rxWriteIndex = 0;                                  //    ditto
                 spiPort.rxReadIndex = 0;                                   //    ditto
                 SPI_TX_INT_DISABLE;                                        // Stop the carnage
             }
         }
         else   // Oops!  We're not either MSP or Flash BUSY!  Stuff the character in the buffer for debug...
         {
             if( tmpFlashRdIdx > FLASH_BUFSIZE )
             {
                 tmpFlashRdIdx = 0;
             }
             tempFlashRdBuffer[tmpFlashRdIdx++] = tempData;                 // Unconditional save of every receive char in circular buffer
             spiPort.rxCharCount = 0;                                       // Setup for new Flash receive
             spiPort.rxWriteIndex = 0;                                      //    ditto
             spiPort.rxReadIndex = 0;                                       //    ditto
             SPI_TX_INT_DISABLE;                                            // Stop the carnage
             __asm("        ESTOP0");                                       // Not working as expected...research
         }
    SpiaRegs.SPIFFRX.bit.RXFFOVFCLR = 1;                                    // Clear Overflow flag
    SpiaRegs.SPIFFRX.bit.RXFFINTCLR = 1;                                    // Clear Interrupt flag
    PieCtrlRegs.PIEACK.bit.ACK6     = 1;                                    // Issue PIE acknowledge
}   // End of __interrupt void spiFlashReceiveIsr

void Process_MSP_Rcv_error(void)
{
    // Ok, clean up receive -- 0 out Idx'es, report FAIL msgFail
    pEventData->msp430Data.MSP_ReadIdx = 0;                                 // Clear read idx
    pEventData->msp430Data.MSP_WriteIdx = 0;                                // Clear write idx
    pEventData->msp430Data.msgFail = FAIL;
    // Better turn off SPI Transmit interrupts to turn off receive!
    SPI_TX_INT_DISABLE;
}

#endif

  • Hi Keith,

    Are you using any low power modes in your application? If so which ones are you using?

    Also, I recommend reading through the General and SPI sections of Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430 MCUs.

    Best regards,

    Caleb Overbay

  • Caleb,

    No, our solution does not require any low-power modes -- we are running flat out so no "gotchas" moving from one power mode to another. Any other questions or inputs on my issue?  I will take a look at the document(s) you provided a link to in order to glean what I can.  I have also downloaded a CCS-6.1.2 that I was able to get a version of Grace downloaded and installed as an add-n and am in process of creating a test version of our SPI master I/F with the intent of looking for what I am missing in my project code.  I will let you know if I have a breakthrough with either path and update you as to needing more help.

    I have a related question as it relates to TI or third party FAE's in the Orange County area (or near Orange, CA) that could meet me at the workplace to work the issue if it continues for any length or time...I was trying to find a TI sales office that might have on-location FAE help I could draw from as an additional possibility.  Can you provide a sales office phone number?  With all of the high-tech in the Orange Cty/LA area I can't imagine there would not be TI resources local to the area.

    Regards,

    Keith Abell

  • Hi Keith,

    I don't see anything in your code that is obviously incorrect. If possible, I'd like to see a reduced code set with only the code required to recreate the issue so I can test this out on my end. I also would not recommend using Grace as it has been deprecated and is no longer supported. Instead, please refer to the examples provided in MSP430Ware that can be found in the TI Resource Explorer. I think the one that may be most helpful is the following example:
    dev.ti.com/.../

    Also, it looks like your sourcing the SPI module from SMCLK. Can you output SMCLK to a pin and verify it is oscillating correctly?

    Regarding TI FAE support. The best place to receive debug support is on this forum. I'm confident we'll be able to pinpoint what is causing the issue. If we're unable to solve the issue on the forum, we can then discuss other possibilities.

    Best regards,
    Caleb Overbay
  • Caleb,

    I can set up the code to output the SMCLK but not sure it is necessary for the following assumption based on an experience I had with the F28069 DSP.

    Since I can write data to the registers and observe them in the debugger to include a breakpoint in the TX ISR, there is overwhelming evidence that the SMCLK is running.  I had a situation in my DSP slave code where I could not get the port to initialize only to find out I had turned off the SPIENABLEACLK (which I needed since I was on SPI port A) and left the BCLK on.  I flipped the CLKS to ACLK on and BCLK off and voila!  I could initialize the DSP SPI port.  I presume the G2553 would be the same -- no SMCLK, no register responses to writes as it relates to the port registers.

    Thoughts?

    I have trapped the example code you referenced -- as it happens I had taken a link to the  MSP430Ware web page and downloaded the lastest version which I did not have so I have all of the example codes to leverage as needed.

    Regards,

    Keith

  • Hi Keith,

    I'm not sure I understand your reasoning behind SMCLK. Writing data to the registers of the MSP430 is based on MCLK. The SMCLK is used by peripherals like the USCI_B SPI module but does not actually facilitate the writing to that specific modules registers.

    I'm suspicious that SMCLK is not oscillating properly and therefore the USCI_B module isn't receiving a clock.

    Best regards,
    Caleb Overbay
  • I don't see where you're setting P1.5-7 for the alternate function in P1SELx. (See also SLAS735J Table 19.)

    You need to "hand over" the pins to the SPI unit or you won't see any activity on the pins.
  • Dear Bruce & Caleb,

    Oh dear, for a short while I thought you might be on to something based on your input I hadn't enabled the SPI function on those GPIO pins P1.5-7 but were dashed -- seems I managed to miss including the GPIO setup initialization I am including below and you will note that the SPI function on those pins is, in fact, enabled in BOLD BLUE.  Sorry 'bout that.  I am in the middle of trying Caleb's idea of putting out the SMCLK requiring mods to my G2553 code and the DSP slave code to accommodate that -- I will add to this thread once I have an answer to Caleb's question "is the SMCLK running?" -- we'll see shortly.  Note also that the global interrupt enable is turned on at the end of the GPIO/HW init function so interrupts are in face enabled along with the SPI RX and TX interrupts in the usart_putstr function of my previous input.

    Regards,  Keith

    void initializeHardware (void)
    {
        WDTCTL = WDTPW | WDTHOLD;                                        // Stop watchdog timer from timing out during initial start-up
        P1OUT  = 0;                                                                             // Port 1 Output Registers -> All data to zero
        P1SEL  = BIT5 | BIT6 | BIT7;                                                 // Port 1 Port Select 1 Registers -> Select UCB SPI peripheral P1.5-7
        P1SEL2 = BIT5 | BIT6 | BIT7;                                                // Port 1 Port Select 2 Registers -> Select UCB SPI peripheral P1.5-7
        P1DIR  = BIT3 | BIT6;                                                               // Port 1 Direction Registers -> P1.3 and P1.6 are outputs
    //    P1IES  = BIT4;                                                                        // Port 1 Interrupt Edge Select Registers -> P1.4 Trigger High-to-Low Transition
        P1IES  = 0;                                                                               // Port 1 No interrupts
        P1IFG  = 0;                                                                               // Port 1 Interrupt Flag Registers -> None
    //    P1IE   = BIT4;                                                                         // Enable P1.4 Interrupt
        P1IE   = 0;                                                                                // Disable P1.4 Interrupts
        P2OUT  = BIT0;                                                                       // Port 2 Output Registers -> All data to zero except DSP SPI Enable, P2.0 = 1;
        P2SEL  = 0;                                                                             // Port 2 Port Select 1 Registers -> Select All I/O
        P2SEL2 = 0;                                                                            // Port 2 Port Select 2 Registers -> Select All I/O
        P2DIR  = BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5;                     // Port 2 Direction Registers -> P2.0-5 are outputs
        P2IES  = 0;                                                                              // Port 2 Interrupt Edge Select Registers -> None
        P2IFG  = 0;                                                                              // Port 2 Interrupt Flag Registers -> None
        P3OUT  = BIT4;                                                                       // Port 3 Output Registers -> All data to zero except for P3.4
        P3SEL  = 0;                                                                             // Port 3 Port Select 1 Registers -> Select All I/O
        P3SEL2 = 0;                                                                                // Port 3 Port Select 2 Registers -> Select All I/O
        P3DIR  = BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7;    // Port 3 Direction Registers -> P3.0-7 are all outputs
        BCSCTL2  = SELM_0 | DIVM_0 | DIVS_0;                                 // DCOCLK, Divide by 1, Divide by 1
        DCOCTL = BCSCTL1 = 0x00;                                               // Clear the clock registers
        DCOCTL   = CALDCO_16MHZ;                                             // Set up DCO frequency
        BCSCTL1  = XT2OFF | DIVA_0|CAL_BC1_16MHZ;               // Disable XT2CLK, Divide by 1 for ACLK --> used for RTC @ 32.768 Khz
                                                                                                         //   and calibrate DCO @16Mhz
        BCSCTL3  = XT2S_0 | LFXT1S_0 | XCAP_3;                        // 0.4- to 1-MHz crystal, 32768-Hz crystal on LFXT1, ~12.5 pF (for 15 pf caps)
        initializeADC();                                                                        // Initialize ADC processes and hardware
        timerRTC_initialize();                                                              // Initialize Timer processes and hardware
        initializeUCB0_Spi();                                                               // Initialize SPI Interface and processes
        WDTCTL = WDTPW | WDTHOLD | WDTNMI;                     // Stop watchdog timer from timing out and use NMI function
        __enable_interrupt();                                                               // Let rip the dogs of war
        return;                                                                                      // Bye
    }                               // End of initializeHardware routine

  • > P2SEL = 0; // Port 2 Port Select 1 Registers -> Select All I/O

    Careful here: P2SEL is 0xC0 at reset, to enable XIN/XOUT for the 32kHz crystal. You appear to be using that crystal; if so, you should preserve this setting. P2SEL2=0 is fine. (See also SLAU144J Table 8-2.)

    This probably isn't causing the symptom you describe, but it's something to watch out for.

  • Hi Keith,

    Thanks for providing the GPIO initialization info. I still think a simplified code example would be the best way for me to help you debug this. That way I can see the definition of all the macros you are using a verify correctness.

    Any updates on the SMCLK experiment? Given the code you've posted above, it looks like you're setting it up correctly.

    Best regards,
    Caleb Overbay
  • Bruce, Caleb,

    Well, SMCLK is being generated on P1.4 as requested for a check -- but now I have a new mystery on my hands.  The updated GPIO and clock initialization routine further with input from Bruce and the SMCLK is showing up but not at 16Mhz as one would expect with DCOCLK driving it with divide-by-1  -- say what?  The analyzer measures it as ~316KHz which about 50 times to slow relative to the DCO clock (see PIX below -- one with SMCLK timing measurement and one of the "runaway"  SPICLK.  Also, it isn't clear why the SPICLK is running away -- the transmit interrupts are not even yet enabled (I suspect runaway occurs after initializing the clock subsytem and SPI ports but I haven't set up an experiment yet to determine that.  But so you know, it just keeps running with the debugger halted with the feature to stop the clocks when the debugger stops and there hasn't been any attempt to stuff a character in the TXBUF to this point.  At the moment it seems I take one step forward and the proverbial two steps back.  One other setup item -- to keep the DSP slave from confusing the issue  I did a flash erase to put it into a Hi-Z state -- don't interfere with the SPI master G2553 so A) the MISO line will be at an inactive high state and B) shouldn't affect operation of the SPI master.  Any new thoughts?  How could the DCOCLK run so slow if the SMCLK is a direct reflection of the speed of DCOCLK?  I'm stumped on this clock issue -- totally unexpected.  And yes, I verified the clock was coming off of P1.4 or Pin 6 of the 28 pin version of the G2553.  Turned out it was a better idea to examine SMCLK than I had originally thought (my apologies Caleb!).  You will note that from afar the SPI clock mirrors the speed of SMCLK but there appears to be some dithering going on -- depending on where you put the measurement annotations you can get some variance to the SPICLK period and frequency which also doesn't make a lot of sense against a fixed SMCLK frequency -- and my BR baudrate divisor should be slowing it down to ~9600 bits/sec -- another anomaly.

    Caleb,

    The effort to pare down the code such that you can try to run it in your shop certainly can be done but will take some time -- I will need to create a duplicate project in my IAR workspace and delete some files wholesale and perform some complex edits to make sure I don't eliminate the wrong code and be able to make sure it builds.  I don't know if you are using IAR or CCS -- if CCS you might have to edit various compiler related directives to get the code to build.  If you are using the latest MSP430 IAR Workbench 8.0 (version 8.0.12.5110 shared components with IDE version 7.11.1) it should build with few or no errors.  But this could take until sometime tomorrow at the earliest.  I presume you are looking for a source base with just my SPI master and associated initialization a driver code (small test routine in main) to exercise the SPI master function -- yes?

    Regards, Keith

    Updated Initialization to enable SMCLK, the XIN/XOUT for the 32.768Khz Clock crystal (thanks Bruce!) and corrections to date.

    void initializeHardware (void)
    {
        WDTCTL = WDTPW | WDTHOLD;                                          // Stop watchdog timer from timing out during initial start-up
        P1OUT  = 0;                                                                             // Port 1 Output Registers -> All data to zero
    // KRA EDIT -- temporary test of SMCLK out SPIENA* pin with G2553 as Master (don't need SPIENA at the moment)
        P1SEL  = BIT4 | BIT5 | BIT6 | BIT7;                                         // Port 1 Port Select 1 Registers -> Select SMCLK peripheral P1.4
                                                                                                          //   and Port 1 Port Select 1 Registers -> Select UCB SPI peripheral P1.5-7
        P1SEL2 = BIT5 | BIT6 | BIT7;                                                   // Port 1 Port Select 2 Registers -> Select UCB SPI peripheral P1.5-7
    // KRA EDIT -- temporary test of SMCLK out SPIENA* pin with G2553 as Master (don't need SPIENA at the moment)
        P1DIR  = BIT3 | BIT4 | BIT6;                                                    // Port 1 Direction Registers -> P1.3, P1.4, and P1.6 are outputs
    //    P1IES  = BIT4;                                                                       // Port 1 Interrupt Edge Select Registers -> P1.4 Trigger High-to-Low Transition
        P1IES  = 0;                                                                               // Port 1 No interrupts
        P1IFG  = 0;                                                                              // Port 1 Interrupt Flag Registers -> None
    //    P1IE   = BIT4;                                                                        // Enable P1.4 Interrupt
        P1IE   = 0;                                                                                // Disable P1.4 Interrupts
    // KRA EDIT -- temporary (??) use of P2.0 as DSP SPI enable
        P2SEL  = BIT6 | BIT7;                                                             // Port 2 Port Select 1 Registers -> Select All I/O EXCEPT XIN, XOUT for clock xtal
        P2SEL2 = 0;                                                                             // Port 2 Port Select 2 Registers -> Select All I/O
        P2OUT  = BIT0;                                                                        // Port 2 Output Registers -> All data to zero except DSP SPI Enable, P2.0 = 1;
        P2DIR  = BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT7;          // Port 2 Direction Registers -> P2.0-5 are outputs, P2.7 is XOUT, P2DIR.7 = 1
        P2IES  = 0;                                                                               // Port 2 Interrupt Edge Select Registers -> None
        P2IFG  = 0;                                                                               // Port 2 Interrupt Flag Registers -> None
        P3OUT  = BIT4;                                                                        // Port 3 Output Registers -> All data to zero except for P3.4
        P3SEL  = 0;                                                                              // Port 3 Port Select 1 Registers -> Select All I/O
        P3SEL2 = 0;                                                                                // Port 3 Port Select 2 Registers -> Select All I/O
        P3DIR  = BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7;    // Port 3 Direction Registers -> P3.0-7 are all outputs
        BCSCTL2  = SELM_0 | DIVM_0 | DIVS_0;                                 // DCOCLK, Divide by 1, Divide by 1 for both MCLK  & SMCLK
        DCOCTL = BCSCTL1 = 0x00;                                              // Clear the clock registers
        DCOCTL   = CALDCO_16MHZ;                                            // Set up DCO frequency
        BCSCTL1  = XT2OFF | DIVA_0|CAL_BC1_16MHZ;             // Disable XT2CLK, Divide by 1 for ACLK --> used for RTC @ 32.768 Khz
                                                                                                       //   and calibrate DCO @16Mhz
        BCSCTL3  = XT2S_0 | LFXT1S_0 | XCAP_3;                       // 0.4- to 1-MHz crystal, 32768-Hz crystal on LFXT1, ~12.5 pF (for 15 pf caps)
        initializeADC();                                                                       // Initialize ADC processes and hardware
        timerRTC_initialize();                                                              // Initialize Timer processes and hardware
        initializeUCB0_Spi();                                                              // Initialize SPI Interface and processes
        WDTCTL = WDTPW | WDTHOLD | WDTNMI;                      // Stop watchdog timer from timing out and use NMI function
        __enable_interrupt();                                                              // Let rip the dogs of war
        return;                                                                                     // Bye
    }               // End of initializeHardware routine

  • > BCSCTL1 = XT2OFF | DIVA_0|CAL_BC1_16MHZ; // Disable XT2CLK, Divide by 1 for ACLK --> used for RTC @ 32.768 Khz

    Is CAL_BC1_16MHZ different from CALBC1_16MHZ?

    I sympathize with the problem of "whittling" things down, but sometimes all it takes is a typo.
  • Bruce,

    Logical question.  Haven't checked the standard headers for CCS but CAL_BC1_16MHZ is the same essential value as the one you mentioned in your email but is the standard value in the IAR standard header files for the G2553.  It held me up early on using the G2553 names for certain things only to find out IAR had put there own spin.  Not sure why they chose what they did but didn't want to mess with their names for IAR update compatibility.  Hopefully Caleb or yourself if you get involved looking at my test source  the IAR related items won't get too much in your way -- I hope to get out my test harness code sometime today in response to Caleb's desire to get my errant code to test.  I am in the process of stripping all superfluous code not related to the SPI master test functions.

    Regards, Keith

  • Hi Keith,

    Thanks for the detailed update. I'll wait to comment until you send out the test harness code as to not bog you down with requests. Additionally, let me know which version of IAR you're using so I can ensure everything is compatible when I try to import the project.

    Best regards,
    Caleb Overbay
  • Caleb,

    Here is the project zipped up in a directory with both .c and .h files.  I have pasted the "About IAR" information window to show the version I am using (essentially the latest 7.11.1 version.  Let me know if the zip file upload did not work well.  If we need to I can send you a dropbox link -- I'll just need the appropriate email to send you the link unless you want to provide an FTP connection.   I really do appreciate the help -- I have wondered if my G2553 chip has gotten damage in some weird way.

    Oops -- the IAR window paste didn't show up...use IAR Embedded Workbench for MSP430 IDE, including complete build chain and debugger.  Ver 7.11.1 along with IAR Embedded Workbench shared components Ver 8.0.12.5110.

    Regards, Keith

    E2E_G2553_SPI_Master_Test_Project.zip

  • My (ancient) copy of IAR doesn't have CAL_BC1_16MHZ, but I ran across this item:

    e2e.ti.com/.../1089911

    which suggests that CAL_BC1_16MHz is a TLV index (specifically 1), where CALBC1_16MHZ should be an address in Flash, looking something like (0x10F9u). SLAU735J (p. 29) says that setting RSEL=1 gets you around 150kHz.

    You may want to check your copy of msp430g2553.h again.

    [Edit: Fixed RSEL mis-quote.]

  • Brian,

    Good find...oh, so subtle...

    Oops!  After digging into the user guide (TLV section 24) and doing a search on the header files I discovered I had the DCO calibration correct:

     /* DCOCTL  Calibration Data for 16MHz  */

    __no_init volatile unsigned __READ char CALDCO_16MHZ @ 0x10F8;

    which allows me to use the statement DCOCTL = CALDCO_16MHZ; an it proper sets it to 0x8C, the value of 0x10F8.

    Turns out there were two pairs of datum in the header file -- one set references the proper calibration data directly out of the calibration data, the other set are offsets from the address of the TAG_DCO_30 tag at 0x10F6 :

     /* DCOCTL  Calibration Data for 16MHz  */

    __no_init volatile unsigned __READ char CALDCO_16MHZ @ 0x10F8;

     /* BCSCTL1 Calibration Data for 16MHz  */

    __no_init volatile unsigned __READ char CALBC1_16MHZ @ 0x10F9;

    #define CAL_DCO_16MHZ          (0x0002u)  /* Index for DCOCTL  Calibration Data for 16MHz */

    #define CAL_BC1_16MHZ          (0x0003u)  /* Index for BCSCTL1 Calibration Data for 16MHz */

    I managed to use the offset for CAL_BC1_16MHZ instead of the proper CALBC1_16MHZ READ construct which goes to the correct calibration data address proper.  I will fix this and "see what happens"...could be "interesting"...

    Regards, Keith

  • Bruce (sorry -- don't know why I call you Brian, probably because I have a relation by that name), Caleb,

    I have both good and bad news:

    The Good -- Thanks to Bruce's catch of the CAL_BC1_16MHZ vs CALBC1_16MHZ issue above, I now have a 16Mhz SMCLK (implying a 16Mhz DCO CLK) and the SPI clock is not running away.  So Caleb -- in the code I sent you update the BCSCTL1 initialization register in system_hardware.c as follows:

        BCSCTL1 = CALBC1_16MHZ;                                                       //  Add this line
    //  BCSCTL1  = XT2OFF | DIVA_0|CAL_BC1_16MHZ;                       // Comment out this line

    The Bad --  I get the SPI slave enable labeled DSP CE for DSP "chip enable" going low but still no traffic (no SPI clocks, no data transfer) -- the first byte is in TXBUF but it still seems as though the shift register is not doing its thing and the port never goes !UCBUSY and the next TX interrupt does not occur.  Can you verify for me there is no ME2 register in the G2553 device?  I had found a "module enable" bit4 that would enable the USART1 in SPI mode which struck me as possibly why the port wasn't running only to discover that it appeared this register was not defined in the G2553 and the port was always enabled if initialized via other means.

    We are making some progress.  Do you have any "early results" on the source I sent you via a zip file?  Let me know if it got stripped off due to security concerns.

    Regards, Keith

  • Hi Keith,

    Thanks for the update. I'm still combing through the code you've provided. Even for a stripped down version its a good amount of code. I'd like to note that the G2553 does not have a USART module so there is no ME2 register. The G2553 has a USCI module that performs the SPI communication. It's much simpler and more reliable to use than the USART module.

    Can you load this example onto your MSP430G2553 and see if there is any activity on the SPI output? This example has been tested and verified to operate correctly. If there is still no output, I think it's highly likely that the chip you're using has been damaged:


    Best regards,
    Caleb Overbay

  • Caleb,

    If the MSP430 link in your last response to the issue was intended to go to some MSP430Ware project it only took me to the MSP430G2553 Specification and Documentation page.  There was no link to a project.

    I have downloaded MSP430Ware so if it is a project as part of it, let me know the name unless a link is easier for you.

    Thanks for help.  I have been concerned about a chip failure -- odd one at that but stranger things over the decades of embedded development have happened...usually if one of MSP "fries" it is catastrophic and won't program anymore which this chip doesn't seem to fall into that category.  But running some canned demo FW would be a good check of such things.

    Regards, Keith

  • Hi Keith,

    I just finished reviewing your code. I don't see anything being setup incorrectly, besides the clock which was caught by Bruce. You should be seeing some kind of output on the SPI lines. I'm trying to test the code on a board I have here but my version of IAR is having some trouble loading code via the ez-430 on the G2 launchpad.

    Here is the link to the example I'd like you to try out:
    dev.ti.com/.../

    Best regards,
    Caleb Overbay
  • Caleb,

    The launch pad device has the 14-pin debug header on it so you could bypass the onboard ez-430. You'd have to take most of the jumpers off to the right of the 14-pin header and then connect a MSP-FET or MSP-FET430UIF debugger or other compatible emulator/debugger to the Launchpad...just a suggestion.

    I will make yet-another-project and try the code you suggested and will let you know what I find out.

    Regards, Keith
  • Caleb,

    Ignore part of my last message -- I was looking at my FRAM launchpad, not the G2553 and noticed the 2553 LP DID NOT have the 14-pin debug port unlike the FRAM5969 LP.  So bypassing it wouldn't work.  You could bring in my source into a CCS project and make whatever few changes you'd have to make in the compiler syntax to get it to build/run which probably would be able to work with the ez-430 connection.  I am having trouble with my own G2553 launch pad device -- I loaded the code from the debugger and in debug mode discovered the whole memory space is zeroes which does not make sense since an erased chip should be FF's.  Gotta load up my stand-alone FET-MSP tool to see if I can read the chip contents via the ez-430 I/F...<sigh>...I am on a very winding road...glad this week is coming to a close...

    Regards,

    Keith

  • > UCB0CTL0__SPI = UCMSB | UCMODE_2 | UCSYNC; // MSB first as slave, 4-Pin STE active Lo, Synchronous

    UCMODE=2 is 4-wire, including STE, but you're not using STE (rather doing /CS with a different pin). Whatever you're using P1.4 (UCB0STE) for is leaving it high, so the SPI unit is recognizing a conflict and shutting down the SPI (see also SLAU144J sec 16.3.3.1).

    Try UCMODE=0 instead:

    > UCB0CTL0__SPI = UCMSB | UCMODE_0 /*was _2*/ | UCSYNC; // MSB first as slave, 4-Pin STE active Lo, Synchronous
  • Bruce,

    You missed the code in the lines following...since I wanted to be able to easily turn master mode on or off easily I wrote my master intended code thus -- the line in BOLD RED or's in the master mode bit so the enabling or disabling of the port is on the remote processor, not my G2553 master (at one time I was intending to use the G2553 as the slave but it seemed the slowest speed the 28069 DSP could run the SPI port was still too fast for the G2553 so I have had to swap the modes.

     The following code excerpt is exactly the code I have sent you and Caleb on this topic:

       UCB0CTL0__SPI = UCMSB | UCMODE_2 | UCSYNC;        // MSB first as slave, 4-Pin STE active Lo, Synchronous
                                                          //    For now, use Phase/Polarity = 00, Data chg on rising edge, capture on trailing edge, clock normally low
        UCB0CTL1__SPI |= UCSSEL_2;                        // SMCLK, Enabled. USCI logic held in reset state

    // KRA EDIT -- if we want to test this port as master, we will need the following statements to set the baudrate and force master mode
        UCB0CTL0__SPI |= UCMST;                           // Or in master mode control bit        NOTE:  I did it this way so I can simply comment out the line that makes it a master without having to edit the line above setting UCB0CTL0_SPI.

    Regards, Keith

  • Did you try the change I suggested? When I tried it, your code succeeded.

    You're running a 3-wire master (since the SPI unit isn't controlling STE/CS), but you're telling the SPI unit it's a 4-wire (master). This causes it to trip over the condition described in SLAU144J sec 16.3.3.1, which produces the symptom you described.
  • Hi Keith,

    I think Bruce is on the right track with this one. You've setup your MSP430G2553 to work as a 4-pin SPI master. This means the USCI_B module will try to control the UCB0STE line (P1.4) when sending data to the slave. You currently have your code setup to output SMCLK on P1.4 instead of giving control of the pin to the USCI_B module. This conflict could be causing the USCI_B module to behave unexpectedly, as you're observing.

    Since you're manually controlling a GPIO for CS functionality, I recommend what Bruce suggested. Using UCMODE_0 ( 3-pin SPI) while manully controlling the CS pin should resolve this conflict. Can you try this out and let us know the results?

    Best regards,
    Caleb Overbay
  • Brian,

    Talk about confusing documentation...the following snippet (16.4.1 of the users guide) suggests that UCxSTE is only used to control the SLAVE, not the master...

    UCMODEx Bits 2-1 USCI mode. The UCMODEx bits select the synchronous mode when UCSYNC = 1.
                                    00 3-pin SPI
                                    01 4-pin SPI with UCxSTE active high: slave enabled when UCxSTE = 1
                                    10 4-pin SPI with UCxSTE active low: slave enabled when UCxSTE = 0
                                    11 I2C mode

    I am using a port-pin to control UCxSTE.  So I assumed I was  a 4-pin Master...so then 16.3.3.1 contradicts this and introduces the notion of Multi-masters and that the 4-pin master can be taken off line if it's UCxSTE is not enabled...<sigh>...this is what it is  but it would have been nice if the documentation in the user guide mentioned this in 16.4..1 description  of the MODEx bits.  I will recommend this on the TI documentation comment link once I try this.  Based on what I now know from a big-picture perspective, good catch.  Bad documentation can get you in trouble.  All this time I assumed single master, multi-slave -- not multi-master multi-slave...flexible but always with the resultant complexity.

    Regards, Keith

  • This is in response to Caleb's input where he stated " I think Bruce is on the right track "  which I am in agreement with Bruce's position but not exactly as you stated in the body of the email....

    You stated " This means the USCI_B module will try to control the UCB0STE line (P1.4) when sending data to the slave"  -- the UCB0STE line is only and always an input.  Neither a local Master or Slave can control the STE line coming into the processor that the Master or Slave is running on.  In 4-wire Master mode an inactive input on the local UCB0STE keeps the master from transmitting because it assumes another master is busy which might be useful.  Since the satellite G2553 code I am working on might need to operate as a master back to the DSP as a slave;  also, the DSP has SPI flash as a slave on the same bus which means it must be the master to the serial flash.  I may need the develop the mechanism to turn the DSP master into a slavenotion of multi-master to coordinate traffic on the bus.  I just didn't realize that the local master could be set up this way and that in master mode, the local UCB0STE input would be ignored.   Oops!

  • OK Gentlemen:  Brian & Caleb,

    Seems Brian's suggestion using 3-Wire master mode worked and only proves no  SPI I/F is necessarily totally like another.  The concept of Master-Slave or Master -Multi-Slave is very common and is how many descriptions of the interface are documented.  I am going to recommend some changes to the user guide when I get a chance so the subtle implications of a 4-wire Master is better documented.  In any case I have the information I need to move forward with my development efforts and this post signifies problem resolution.

    Thanks for the help guys!

    Regards, Keith

  • Keith,

    I'm glad we were able to figure this one out! Also, I'll provide your feedback regarding the UG to the appropriate team here at TI. Let me know if you have any further questions.

    Best regards,
    Caleb Overbay

**Attention** This is a public forum