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.

MSP430 SPI Slave RX Interrupt Debugging Steps

Other Parts Discussed in Thread: MSP430FR5739

I'm currently having issues with getting my project off the ground.  I'm working with the MSP430FR5739 to act as an SPI Slave, and I'm discovering that the code I've written never enters the SPI Receive Interrupt I've set up.  I've verified that everything is connected in the right place, and I've verified (with an oscilloscope) that the SCLK, SS, and MOSI pins are being properly sent to the MSP430 FRAM chip. 

I suspect that the problem is being caused by some concept in the MSP430's SPI that I'm missing.  I'll go over the concepts now, and if needed, I'll post my code upon request.

To start, this is how I initialize the SPI.  This is done after the Watchdog timer has been stopped, when the clock has been initialized, when the Temperature Sensor has been turned off, and when the GPIO pins have been initialized.

  1. Stop Watchdog Timer
  2. Set UCSWRST
  3. Initialize clock (to 24 MHz in my case)
  4. Turn off Temperature sensors
  5. Initialize GPIO pins for 4-pin SPI
  6. Initialize SPI
    1. UCCKPH = 0;  Data is changed on the first UCLK edge and captured on the following edge.
    2. UCCKPL = 1; Clock polarity high
    3. UCMSB = 1; Set for MSB first select.
    4. UC7BIT = 0; Set for 8-bit character length
    5. UCMST = 0; SPI slave mode
    6. UCMODEx = 10b; 4-Pin SPI, w/ UCxSTE Active Low (UCMODE1 = 1)
    7. UCSELx = 00b: Reserved (Since UCxCLK is always used in slave mode).
    8. UCSYNC = 1; Synchronous mode enable (was 1 in some places)
    9. UCA0BR0 = 0x02; Bit clock prescaler setting set for a divisor of 2
    10. UCA0MCTLW = 0; No modulation
  7. Clear UCSWRST
  8. Enable USCI_A0 RX interrupt
  9. MPUCTL0 = MPUPW;  Write PWD to access MPU registers
  10. MPUCTL0 = MPUPW+MPUENA;  Enable MPU protection
  11. Enable GIE Interrupt

Once all of the system is initialized, I've load the TXBUF before the master even asserts STE (aka SS or CS).  After that, I set up my SPI Receive ISR so that it just echos the received data in the UCA0RXBUF register back into the UCA0TXBUF.  However, when looking through the oscilloscope, I can tell that the ISR is never started.  Below is the setup of my ISR

#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
	STROBE1_TOGGLE;
	while (!(UCA0IFG&UCTXIFG));		//USCI_A0 TX buffer ready?
	UCA0TXBUF = UCA0RXBUF;			//Echo received data
	UCA0IFG &= ~UCRXIFG;
    __bic_SR_register_on_exit(CPUOFF);// Wake up to setup next TX
}


 */
// trap isr assignation - put all unused ISR vector here
#pragma vector = ADC10_VECTOR, PORT2_VECTOR,PORT1_VECTOR,\
	TIMER0_A0_VECTOR, TIMER0_A1_VECTOR, WDT_VECTOR, COMP_D_VECTOR, \
	DMA_VECTOR,	PORT3_VECTOR, PORT4_VECTOR, RTC_VECTOR, \
	SYSNMI_VECTOR, TIMER0_B0_VECTOR, TIMER0_B1_VECTOR, \
	TIMER1_A0_VECTOR, TIMER1_A1_VECTOR, TIMER1_B0_VECTOR, \
	TIMER1_B1_VECTOR, TIMER2_B0_VECTOR, TIMER2_B1_VECTOR, \
	UNMI_VECTOR, USCI_A1_VECTOR, USCI_B0_VECTOR
__interrupt void TrapIsr(void)
{
  // this is a trap ISR - check for the interrupt cause here by
  // checking the interrupt flags, if necessary also clear the interrupt
  // flag
}

So far, I've tried with different SPI settings to make sure that it isn't what I've set.  I've also used a Strobe Bit and the oscilloscope to test how far the program actually goes.  All these attempts have come to no avail, and I'm stumped on what else to try.  Any suggestions would be appreciated.  Thank you

  • Update:  I've been testing the setup of my GPIO pins, as well as finding out what my code is exactly doing.  Below is a setup for my GPIO (for those who are interested)

    // Configure SPI Pins
    // Pin 1.5 set for Serial Clock Out (UCA0CLK)
    // Pin 1.4 set for SS (Slave Select) (UCA0STE)
    P1SEL1 |= SPI_CLK + SPI_SS;
    
    // Configure SPI pins P2.0 and P2.1
    // Pin 2.0 set for Data Out (UCA0SIMO) and as an output
    // Pin 2.1 set for Data In (UCA0SOMI)
    P2SEL1 |= MOSI + MISO;
    P2DIR |= MISO;

    I've also set it up so that unused pins are disabled.  Below is that setup for some of the pins

    // P2.3 - P2.7 are unused
    P2OUT &= ~(BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
    P2DIR &= ~BIT3 + BIT4 + BIT5 + BIT6 + BIT7;
    P2REN |= (BIT3 + BIT4 + BIT5 + BIT6 + BIT7);

    The reason why I mentioned this is that I suspect that my code is getting trapped into something else.  I have it setup so that it stays in an infinite while loop inside the main program.  There were a couple of tests I've tried. 

    One was that I tested to see if it would detect the SS pin to go low, and I tested this to see if it ever leaves the infinite while loop by making my strobe pin go high if that case was detected.  This case was not detected, even though I can see the SS pin go low on the oscilloscope.  I understand that the way I have my GPIO pins set up may cause this test to be invalid, so I tried something else.

    Another test I tried was to see if the UCBUSY flag in the UCA0STATW register ever indicates that the SPI is busy (using a similar strategy as above).  It was able to detect, but at different times to when the SCLK should be detected to be busy.  Specifically, it sometimes begins to indicate that it is busy at the beginning of when the clock is running, and then much later on after a few series of commands later.

    I'm not sure if the program is removing itself from the main class, or if the SPI module is indeed working.  Please help!

  • Hey! So I moved to another topic in this thread, and got my answer with what I had missing with setting up my interrupt for my SPI module.

    What I first did was that I turned on both my RX and TX interrupts in the enabler register.  After that, I discovered through Brian Boorman that I shouldn't be using the interrupt flags for the Transmit and Receive Interrupts, nor should I be waiting for them. Brian elaborates

    Brian Boorman said:

    There should be no reason to loop on the IFG flags - this can hang your program if the reason for the ISR is something other than the TX interrupt.

    Basically, the interrupt can get called for either a receive event or a transmit event. Using the IV register gets you the correct reason for the ISR being called so you can do the appropriate action.

    If you want to use the IFG flags, then check them independently (and don't wait on them). Also remember that if you go this route, you must clear the flags manually in your code. (Using IV clears automatically)

    In other words, I should use the UCA0IV instead of the UCA0IFG for stepping through my ISR.  That way, I will let the ISR flow seamlessly through my program.  Follow the link for more information.


    With that said, I think I'm going to close this conversation, seeing that I'm the only one contributing.  Follow the links through the posts to find out more information.

  • dauletle said:
    With that said, I think I'm going to close this conversation, seeing that I'm the only one contributing.

    Sorry I didn't answer earlier. :)
    Not every question will be answered same day. Most people here are doing the forum work in their spare time.

    Even though you got an answer in a diferent thread (well, that's why the forum ahs a history and a search function: one can find answers that have been already written), some comments on your code:

    Setting UCABR0 makes no sense in slave mode, setting PxDIR for the pins used by USCI is not needed too, the USCI controls the direction.
    And maybe enabling the MPU protection should be done _before_ doing all the rest.

  • Jens-Michael Gross said:
    Setting UCABR0 makes no sense in slave mode

    That's what I figured, since the datasheet says the UCxCLK is always used in slave mode.  I didn't know that I should be setting a Baud Rate to capture the bits, but then again, figured that would be the problem with why I'm not properly receiving SPI data.

    Jens-Michael Gross said:
    setting PxDIR for the pins used by USCI is not needed too

    Agreed, since the Secondary module function is already selected for the pin. Removing that part of the code doesn't change the problem though.

    Jens-Michael Gross said:
    And maybe enabling the MPU protection should be done _before_ doing all the rest.

    I've changed the code so that this is set after stopping the watchdog timer, and no changes were made to how the MSP430 is functioning.

**Attention** This is a public forum