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.

MSP430F5529 SPI not receiving data

Other Parts Discussed in Thread: MSP430F5529

Hello!

I'm hoping someone will be able to point me in the right direction. I'm working on getting my MSP430F5529 to read the device ID from a WinBond Flash device. At this point, I am able to successfully send the command to read the device ID and have the flash chip reply properly (I have verified this with a signal analyzer).

My issue however, is that the device ID and manufacturer ID always return 0. Any idea why the MSP would be confused about what value is coming into SOMI when electrically the right bits are on the line?

Here is my code:

uint08 ManufacturerID = 2;
uint08 DeviceID = 2;

void main(void)
{
	// Stop watchdog timer to prevent time out reset
	WDTCTL = WDTPW + WDTHOLD;

	Powerup();
	SPI_Enable(TRUE);

	//select a flash chip to read, pull down CS line.
	FLASH_FlashSelect(1);

	//read the device ID
	retval = DLPCFLASH_GetFlashID(&ManufacturerID, &DeviceID);

	//close SPI communication, release CS line.
	FLASH_FlashSelect(0);

}

void SPI_Enable (BOOL Enable)
{
	if (Enable)
	{
		// SPI clk configuration
		GPIO_SetBits(&P2SEL, SPICLK_MSP);

		// SPI Data configuration
		P3SEL |= SPIDOUT_MSP + SPIDIN_MSP;
		// Reset USCI
		UCA0CTL1 |= UCSWRST;

		// Configure 3 pin, 8-bit SPI master operation
		SPI_ClockMode (SPI_MODE_1); //use SPI_MODE_1 for proper operation.
		UCA0CTL0 |= UCMST + UCSYNC + UCMSB; //master mode, synchronous, MSB first
		UCA0CTL1 |= UCSSEL_2; //SMCLK
		UCA0BR0 = 0;                           // No frequency division
		UCA0BR1 = 0;
		UCA0MCTL = 0;                          // No modulation
		GPIO_ClearBits(&UCA0CTL1, UCSWRST); // Re initialize USCI
	}
	else
	{
		GPIO_ClearBits(&P2SEL, SPICLK_MSP); // Configure as GPIO
		GPIO_ClearBits(&P2DIR, SPICLK_MSP); // Configure P2 as Input
	}
}

int08 DLPCFLASH_GetFlashID (uint08 *ManufacturerID, uint08 *DeviceID)
{
	const uint08 ReadLength = 2, WriteLength = 4;
	uint08 TxData[4];
	uint08 RxData[2];
	TxData[0] = FLASH_CMD_GET_MANUFACTURER_ID;
	TxData[1] = SPI_DUMMY_BYTE;
	TxData[2] = SPI_DUMMY_BYTE;
	TxData[3] = SPI_DUMMY_BYTE;
	if (SPI_SendReceiveData (RxData, TxData, ReadLength, WriteLength) != PASS)
	{
		return FAIL;
	}
	*ManufacturerID = RxData[0];
	*DeviceID = RxData[1];
	return PASS;
}

int08 SPI_SendReceiveData (uint08 *ReadData, uint08 *WriteData,
		uint16 ReadLength, uint16 WriteLength)
{
	int i = 0, j = 0;
	uint16 MaxLength = WriteLength;
	TxData = WriteData;
	RxData = ReadData;
	BytesRead = 0;
	for (j = 0; j < MaxLength; j++)
	{
		i = 0;
		while (!(UCA0IFG & UCTXIFG));		// While TX buffer not ready
		{
			if (i > 100)
			{
				STS_SetStatus (STS_SPI_BUS_BUSY);
				return FAIL;
			}
			i++;
		}
		UCA0TXBUF = TxData[j];
		_delay_cycles (SPI_WRITE_DELAY_CYCLES);	// Add time between transmissions to make sure slave can process information

	}
	for (j = 0; j < ReadLength; j++)
	{
		UCA0TXBUF = (SPI_DUMMY_BYTE); // Send dummy byte to trigger reading data
		RxData[j] = UCA0RXBUF;	// Synchronously read data from slave
	}

	return PASS;
}

For reference, here is a screen grab of the signal analyzer:

Thanks,

Paul

  • Hi Paul, 

    After looking over your code, I think your problem is in the SPI_SendRecieveData function. More specifically, the for loop that reads from UCA0RXBUF.

    In this for loop you are immediately reading the buffer after placing the dummy byte in UCA0TXBUF and not giving the device enough time to actually transmit the dummy byte and receive data. Placing while (!(UCA0IFG & UCTXIFG)); just after the write to UCA0TXBUF should solve your issue. 

    Try this out and let me know if it solves your issue. 

    Best regards, 

    Caleb Overbay

  • You must not read RXBUF without checking for RXIFG first.
    And SPI always both sends and receives, so RXIFG will also be set after each of the first four bytes.
  • Hi Caleb and Clemens,

    Thanks for both your inputs. I tried the following:

    for (j = 0; j < ReadLength; j++)
    	{
    		UCA0TXBUF = (SPI_DUMMY_BYTE); // Send dummy byte to trigger reading data
    		while(!(UCA0IFG & UCTXIFG));
    		RxData[j] = UCA0RXBUF;	// Synchronously read data from slave
    	}

    and

    for (j = 0; j < ReadLength; j++)
    	{
    		while(!(UCA0IFG & UCTXIFG)); //while TX buffer not ready.
    		UCA0TXBUF = (SPI_DUMMY_BYTE); // Send dummy byte to trigger reading data
    		while(!(UCA0IFG & UCRXIFG));
    		RxData[j] = UCA0RXBUF;	// Synchronously read data from slave
    	}

    Neither appeared to work. Any other thoughts on what this might be? Initialization errors? I've checked with my signal analyzer that the signal is making it all the way to the MSP430 - there is no break between the SPI Flash output line and MSP430 receive line.

    I've also checked my functions to make sure that the value would be properly passed back and stored in ManufacturerID and DeviceID. In CCS I have a expression set up to read those values and a break point set up at the end of Main() to check them.

    Thanks so much for the help,

    Paul

  • Hi Paul,

    To know if everything is initialized correctly, I'll need to see into the functions you use in SPI_Enable:

    1. SPI_ClockMode
    2. GPIO_Set/ClearBits
    3. The values of SPI_MODE_1, SPIDOUT_MSP, SPIDIN_MSP, and SPICLK_MSP

    Also, I never saw you enable either the transmit or receive interrupts for the SPI module. Without these enabled, I would expect a statement like while(!(UCA0IFG & UCRXIFG)); to just spin forever. 

    Edit: Disregard the last statement. The interrupt flag will still be set regardless of whether interrupts are enabled.

    Best regards, 

    Caleb Overbay

  • Caleb,

    Thanks for the help. I've cleaned up the code, so now all should be clear:

    uint08 ManufacturerID = 2;
    uint08 DeviceID = 2;
    uint08 retval = 0;
    
    void main(void)
    {
    	// Stop watchdog timer to prevent time out reset
    	WDTCTL = WDTPW + WDTHOLD;
    
    	//init ports.
    	P2SEL  = 0;
    	P2OUT  = 0;
    	P3OUT |= 0;
    	P3SEL |= 0;
    
    	//power up the regulators on the board. Enable SPI
    	Powerup();
    	SPI_Enable(TRUE);
    
    	//select a flash chip to read, pull down CS line.
    	FLASH_FlashSelect(1);
    
    	//read the device ID
    	retval = DLPCFLASH_GetFlashID(&ManufacturerID, &DeviceID);
    
    	//close SPI communication, release CS line.
    	FLASH_FlashSelect(0);
    }
    
    void SPI_Enable (BOOL Enable)
    {
    	if (Enable)
    	{
    		// SPI clk configuration
    		P2SEL |= SPICLK_MSP; //BIT7
    
    		// SPI Data configuration
    		P3SEL |= SPIDOUT_MSP + SPIDIN_MSP; //BIT3 + BIT4
    		// Reset USCI
    		UCA0CTL1 |= UCSWRST;
    
    		// Configure 3 pin, 8-bit SPI master operation
    		UCA0CTL0 |= UCMST + UCSYNC + UCMSB + UCCKPH; //master mode, synchronous, MSB first
    		UCA0CTL1 |= UCSSEL_2; //SMCLK
    		UCA0BR0 = 0;                           // No frequency division
    		UCA0BR1 = 0;
    		UCA0MCTL = 0;                          // No modulation
    		UCA0CTL1 &= ~UCSWRST; // Re-initialize USCI
    	}
    	else
    	{
    		P2SEL &= ~SPICLK_MSP; // Configure as GPIO, BIT7
    		P2DIR &= ~SPICLK_MSP; // Configure as Input, BIT7
    	}
    }
    
    int08 DLPCFLASH_GetFlashID (uint08 *ManufacturerID, uint08 *DeviceID)
    {
    	const uint08 ReadLength = 2, WriteLength = 4;
    	uint08 TxData[4];
    	uint08 RxData[2];
    	TxData[0] = FLASH_CMD_GET_MANUFACTURER_ID;
    	TxData[1] = SPI_DUMMY_BYTE; //0x00, could be 0xFF
    	TxData[2] = SPI_DUMMY_BYTE;
    	TxData[3] = SPI_DUMMY_BYTE;
    	if (SPI_SendReceiveData (RxData, TxData, ReadLength, WriteLength) != PASS)
    	{
    		return FAIL;
    	}
    	*ManufacturerID = RxData[0];
    	*DeviceID = RxData[1];
    	return PASS;
    }
    int08 SPI_SendReceiveData (uint08 *ReadData, uint08 *WriteData, uint16 ReadLength, uint16 WriteLength)
    {
    	int i = 0, j = 0;
    	uint16 MaxLength = WriteLength;
    	TxData = WriteData;
    	RxData = ReadData;
    	BytesRead = 0;
    	for (j = 0; j < MaxLength; j++)
    	{
    		i = 0;
    		while (!(UCA0IFG & UCTXIFG));		// While TX buffer not ready
    		{
    			if (i > 100)
    			{
    				STS_SetStatus (STS_SPI_BUS_BUSY);
    				return FAIL;
    			}
    			i++;
    		}
    		UCA0TXBUF = TxData[j];
    		_delay_cycles (SPI_WRITE_DELAY_CYCLES);	// Add time between transmissions to make sure slave can process information
    	}
    	for (j = 0; j < ReadLength; j++)
    	{
    		while(!(UCA0IFG & UCTXIFG)); //while TX buffer not ready.
    		UCA0TXBUF = (SPI_DUMMY_BYTE); // Send dummy byte to trigger reading data
    		while(!(UCA0IFG & UCRXIFG)); //while TX buffer not ready.
    		RxData[j] = UCA0RXBUF;	// Synchronously read data from slave
    	}
    	return PASS;
    }
    

    Let me know if you have any more questions.

    Paul

  • As I said, RXIFG is still set from the previous for SPI transactions. You'd have to wait for the fourth byte to be received and then to clear RXIFG before doing the two actual reads.

    And it might be a better idea not to split the function into separate write+read parts; just write and read six bytes in both directions.
  • Thanks Clemens. I threw the below line in between the two for loops to clear the flag:
    UCA0IFG &= ~UCRXIFG;

    Didn't seem to change anything....I'm still perplexed. I'll take a look at how to write some nice code that does everything all at once, without the seperate read and write.

    -Paul
  • Hi Paul,

    That is perplexing that it's not working properly. After you restructure your code, can you let us know if you're still having issues?

    Best regards,
    Caleb Overbay
  • Hi Caleb,

    I've made an even cleaner version of the code that can now be run on a Launchpad if so desired. To try to debug this further, I've used a Launchpad and wired it to the SPI Flash chip to see if it's somehow hardware related on my board. It doesn't appear to be.

    For brevity, I've attached my full code in a txt file: 

    #include <msp430.h> 
    
    typedef unsigned       char uint08;
    typedef   signed       char  int08;
    typedef unsigned        int uint16;
    typedef   signed        int  int16;
    typedef unsigned       long uint32;
    typedef   signed       long  int32;
    typedef unsigned       char   BOOL;
    
    #define VOID void
    #define SPI_DUMMY_BYTE	(uint08)0x00
    
    void Powerup(void);
    void SPI_Enable (BOOL Enable);
    void FLASH_FlashSelect(BOOL Enable);
    int08 DLPCFLASH_GetFlashID (uint08 *ManufacturerID, uint08 *DeviceID);
    int08 SPI_SendReceiveData (uint08 *ReadData, uint08 *WriteData, uint16 ReadLength, uint16 WriteLength);
    void GPIO_InitPorts(void);
    
    void main(void)
    {
    	uint08 ManufacturerID = 2;
    	uint08 DeviceID = 2;
    	uint08 retval = 0;
    
    	// Stop watchdog timer to prevent time out reset
    	WDTCTL = WDTPW + WDTHOLD;
    
    	//define the ports with names that match schematic
    	GPIO_InitPorts();
    	
    	//power up the regulators on the board. Enable SPI
    	Powerup();
    	SPI_Enable(1);
    
    	//select a flash chip to read, pull down CS line.
    	FLASH_FlashSelect(1);
    
    	//read the device ID
    	retval = DLPCFLASH_GetFlashID(&ManufacturerID, &DeviceID);
    
    	//close SPI communication, release CS line.
    	FLASH_FlashSelect(0);
    
    	//blink the LED when the read is done, if the flashID passes.
    	if (retval == 1){
    		volatile unsigned int i;
    		P5DIR |= BIT6;                            // P1.0 set as output
    		while(1)                                  // continuous loop
    		{
    			P5OUT ^= BIT6;                          // XOR P1.0
    			for(i=50000;i>0;i--);                   // Delay
    		}
    	}
    }
    
    void Powerup(void)
    {
    	P8OUT &= ~BIT0;  // Assert FPGA_CONFIGZ. This will reset FPGA
    	P4OUT |= BIT1; // De-assert MSP LED Enable
    	P3OUT |= BIT7; // Enable core voltage
    	__delay_cycles (120000);
    	P5OUT |= BIT7; // Enable 3.3V
    	__delay_cycles (120000); // Wait for 120 ms to release reset
    	P8OUT |= BIT2; // Enable 3.3V
    }
    
    void SPI_Enable (BOOL Enable)
    {
    	if (Enable)
    	{
    		// SPI clk configuration
    		P2SEL |= BIT7;
    
    		// SPI Data configuration
    		P3SEL |= BIT3 + BIT4;
    		// Reset USCI
    		UCA0CTL1 |= UCSWRST;
    
    		// Configure 3 pin, 8-bit SPI master operation
    		UCA0CTL0 |= UCMST + UCSYNC + UCMSB + UCCKPH; //master mode, synchronous, MSB first
    		UCA0CTL1 |= UCSSEL_2; //SMCLK
    		UCA0BR0 = 0;                           // No frequency division
    		UCA0BR1 = 0;
    		UCA0MCTL = 0;                          // No modulation
    		UCA0CTL1 &= ~UCSWRST; // Re initialize USCI
    	}
    	else
    	{
    		P2SEL &= ~BIT7; // Configure as GPIO, BIT7
    		P2DIR &= ~BIT7; // Configure as Input, BIT7
    	}
    }
    
    void FLASH_FlashSelect(BOOL Enable)
    {
    	if (Enable)
    	{
    		// Select FPGA Flash
    		P6OUT ^= BIT3;
    		// Un-select DLPC300 flash
    		P1OUT &= ~BIT6;
    	}
    	else
    	{
    		// Un-select FPGA flash
    		P6OUT |= BIT3; //reassert P6OUT.3 to HIGH.
    	}
    }
    
    int08 DLPCFLASH_GetFlashID (uint08 *ManufacturerID, uint08 *DeviceID)
    {
    	const uint08 ReadLength = 2, WriteLength = 4;
    	uint08 TxData[4];
    	uint08 RxData[2];
    	TxData[0] = 0x90;
    	TxData[1] = SPI_DUMMY_BYTE;
    	TxData[2] = SPI_DUMMY_BYTE;
    	TxData[3] = SPI_DUMMY_BYTE;
    
    	if (SPI_SendReceiveData (RxData, TxData, ReadLength, WriteLength) != 1)
    	{
    		return 0;
    	}
    	*ManufacturerID = RxData[0];
    	*DeviceID = RxData[1];
    	return 1;
    }
    
    int08 SPI_SendReceiveData (uint08 *ReadData, uint08 *WriteData, uint16 ReadLength, uint16 WriteLength)
    {
    	uint08 *TxData;
    	uint08 *RxData;
    	int j = 0;
    	uint16 MaxLength = WriteLength+ReadLength;
    	TxData = WriteData;
    	RxData = ReadData;
    	for (j = 0; j < MaxLength; j++)
    	{
    		while (!(UCA0IFG & UCTXIFG));		// While TX buffer not ready
    		if (j < WriteLength)
    		{
    			UCA0TXBUF = TxData[j];
    			_delay_cycles (40);	// Add time between transmissions to make sure slave can process information
    		}
    		if (j >= WriteLength)
    		{
    			UCA0TXBUF = SPI_DUMMY_BYTE;
    			RxData[j] = UCA0RXBUF;
    		}
    	}
    	return 1;
    }
    
    void GPIO_InitPorts(void)
    {
    	P1OUT   = BIT6;    // Set Output low
    	P1SEL   = 0;    // Select GPIO capability in Port P1
    	P1DIR   = (BIT1 | BIT5 | BIT6);    // Set GPIO as inputs
    #if TEST_MODE
    	P1DIR |= LED_ENABLE;
    #endif
    #if FAN_ON
    	P2OUT = (BIT3);
    #else
    	P2OUT   = 0;
    #endif
    	P2SEL   = 0;
    	P2DIR   = (BIT3); // SPI is disabled by default.
    	P3OUT   |= 0;
    	P3SEL   |= 0;
    	P3DIR   |= (BIT5 | BIT6 | BIT7 );
    	P4OUT   = (BIT1 | BIT7);
    	P4SEL   = 0;
    	P4DIR   = (BIT0 | BIT1 | BIT6 | BIT7);
    	P5OUT   = 0;
    	P5SEL   = (BIT2 | BIT3 | BIT4 | BIT5);
    	P5DIR   = (BIT6 | BIT7);
    	P6SEL   = 0; //set these pins to GPIO mode.
    	P6DIR   = (BIT0 | BIT3); //set both of these signals as outputs, not high impedance inputs
    	P6OUT   = (BIT0 | BIT3); //set both of these signals as HIGH outputs
    	P7OUT   = 0;
    	P7SEL   = 0;
    	P7DIR   = 0xFF; //Entire port is output
    	P8OUT   = BIT0;
    	P8SEL   = 0;
    	P8DIR   = (BIT0 | BIT2);
    	// hold I2C in reset to conserve power
    	UCB0CTL1 |= UCSWRST;
    }

    I'll highlight my combined SPI RxTx code here:

    int08 SPI_SendReceiveData (uint08 *ReadData, uint08 *WriteData, uint16 ReadLength, uint16 WriteLength)
    {
    	uint08 *TxData;
    	uint08 *RxData;
    	int j = 0;
    	uint16 MaxLength = WriteLength+ReadLength;
    	TxData = WriteData;
    	RxData = ReadData;
    	for (j = 0; j < MaxLength; j++)
    	{
    		while (!(UCA0IFG & UCTXIFG));		// While TX buffer not ready
    		if (j < WriteLength)
    		{
    			UCA0TXBUF = TxData[j];
    			_delay_cycles (40);	// Add time between transmissions to make sure slave can process information
    		}
    		if (j >= WriteLength)
    		{
    			UCA0TXBUF = SPI_DUMMY_BYTE;
    			RxData[j] = UCA0RXBUF;
    		}
    	}
    	return 1;
    }

    I have verified that this works electrically and I am still seeing the same behavior with regards to my MSP not appearing to store the values being sent in on SPI.

    Thanks for all help,

    Paul

  • Hi Paul,

    I'll take a look at your code a little closer and see if I can find the issue. At first glance though, I see you didn't include the wait on the RXIFG after placing the dummy byte into the UCA0TXBUF. This is something you will need in your code for it to operate properly even though it might not be the issue right now.

    Best regards,
    Caleb Overbay
  • Alright - I think I fixed it. I didn't know if I needed both RX and TX flag checking.

    int08 SPI_SendReceiveData (uint08 *ReadData, uint08 *WriteData, uint16 ReadLength, uint16 WriteLength)
    {
    	uint08 *TxData;
    	uint08 *RxData;
    	int j = 0;
    	uint16 MaxLength = WriteLength+ReadLength;
    	TxData = WriteData;
    	RxData = ReadData;
    	for (j = 0; j < MaxLength; j++)
    	{
    		while (!(UCA0IFG & UCTXIFG));		// While TX buffer not ready
    		if (j < WriteLength)
    		{
    			UCA0TXBUF = TxData[j];
    			_delay_cycles (40);	// Add time between transmissions to make sure slave can process information
    		}
    		if (j >= WriteLength)
    		{
    			UCA0TXBUF = SPI_DUMMY_BYTE;
    			while (!(UCA0IFG & UCRXIFG));
    			RxData[j] = UCA0RXBUF;
    		}
    	}
    	return 1;
    }

    Thanks!

    Paul

  • Hi Paul,

    You said this fixed your issue or are you still experiencing it? Also you should be clearing the UCRXIFG bit in the UCA0IFG register before placing the dummy byte in the transmit buffer.

    This is because there is still a "leftover" interrupt flag waiting to be cleared from when you sent the read device ID command. If it's not cleared, the wait after filling the buffer won't really have an affect.

    Best regards,
    Caleb Overbay
  • Ah sorry - issue is still there, I was just saying I think I fixed not having the RXIFG check. I'll add a line for clearing the register as well.

    Thanks,
    Paul
  • Hi Caleb,

    I was able to put a SPI Flash chip on a breadboard and interface it with a launchpad. When I use that set-up, the code works perfectly and the value is stored correctly. I guess the issue must lie somewhere on my hardware then.

    Thanks so much for all the help - sorry to lead you on a goose chase. I do appreciate the code tips and tweaks though, I'm sure it wouldn't have worked otherwise.

    -Paul

**Attention** This is a public forum