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