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.

Serial Flash reading from SPI

Hi there,

I have a query about the SPI operation. I am interfacing serial flash over SPI. I'm first trying to read the device ID of flash . When I send the data over SPI, I always see the correct data on MOSI pin. But when I try to read the device ID on pin MISO, I always get 0xff. BTW I did set CS low and then sent the data.Once data sent and received, I did set CS to high once I get the data. I can see the clock signals on SPI CLK pin for data output but no clock signals for data input. I always get oxff as I can see on the UART. I am using the exact code as in the TI/Peripheral/SSI/SPI-MASTER.

Kindly could you please advise me on this. I have pasted my SPI configuration code below.

Thanks

Mohsin

//
// The SSI0 peripheral must be enabled for use.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

//
// For this example SSI0 is used with PortA[5:2]. The actual port and pins
// used may be different on your part, consult the data sheet for more
// information. GPIO port A needs to be enabled so these pins can be used.
// TODO: change this to whichever GPIO port you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

//
// Disable SSI function before configuring module
//
SSIDisable(SSI0_BASE);

//
//Set IO clock as SSI clock source
//
SSIClockSourceSet(SSI0_BASE, SSI_CLOCK_SYSTEM);

//
// Configure the pin muxing for SSI0 functions on port A2, A3, A4, and A5.
// This step is not necessary if your part does not support pin muxing.
// TODO: change this to select the port/pin you are using.
//
GPIOPinConfigure(GPIO_PA2_SSI0CLK);
//GPIOPinConfigure(GPIO_PA3_SSI0FSS);
GPIOPinConfigure(GPIO_PA4_SSI0RX);
GPIOPinConfigure(GPIO_PA5_SSI0TX);

//
// Configure the GPIO settings for the SSI pins. This function also gives
// control of these pins to the SSI hardware. Consult the data sheet to
// see which functions are allocated per pin.
// The pins are assigned as follows:
// PA5 - SSI0Tx
// PA4 - SSI0Rx
// PA3 - SSI0Fss
// PA2 - SSI0CLK
// TODO: change this to select the port/pin you are using.
//
GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);

//
// Configure and enable the SSI port for SPI master mode. Use SSI0,
// system clock supply, idle clock level low and active low clock in
// freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
// For SPI mode, you can set the polarity of the SSI clock when the SSI
// unit is idle. You can also configure what clock edge you want to
// capture data on. Please reference the datasheet for more information on
// the different SPI modes.
//
SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, 1000000, 8);

// Enable CS as GPIO
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_PIN_3);

//
// Enable the SSI0 module.
//
SSIEnable(SSI0_BASE);

  • Hello Mohsin,

    The SSI on TM4C123 requires that when reading a data from the external device, you would need a dummy write to the SSIDATA register to generate clock on the SPI bus. Only when the SSIDATA register is written will it generate clock for the RXDATA line to be samples by the SSI Controller and then be made available for Read.

    BTW, the code post does not show how you are writing or reading. Configuration looks fine.

    Regards

    Amit

  • Hi Amit,

    Thanks for reply.

    Like you said, please find my complete code attached.

    Regards,

    Moz

    #define NUM_SSI_DATA            8
    
    void InitFlashHardware();
    void TestFlashWriteRead();
    
    //*****************************************************************************
    //
    // This function sets up UART0 to be used for a console to display information
    // as the example is running.
    //
    //*****************************************************************************
    void
    InitConsole(void)
    {
    	//
    	// Enable GPIO port A which is used for UART0 pins.
    	// TODO: change this to whichever GPIO port you are using.
    	//
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
    	//
    	// Configure the pin muxing for UART0 functions on port A0 and A1.
    	// This step is not necessary if your part does not support pin muxing.
    	// TODO: change this to select the port/pin you are using.
    	//
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    
    	//
    	// Enable UART0 so that we can configure the clock.
    	//
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
    	//
    	// Use the internal 16MHz oscillator as the UART clock source.
    	//
    	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
    	//
    	// Select the alternate (UART) function for these pins.
    	// TODO: change this to select the port/pin you are using.
    	//
    	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
    	//
    	// Initialize the UART for console I/O.
    	//
    	UARTStdioConfig(0, 115200, 16000000);
    }
    
    uint32_t pui32DataTx[NUM_SSI_DATA];
    uint32_t pui32DataRx[NUM_SSI_DATA];
    uint32_t ui32Index;
    
    int
    main(void)
    {
    
    	//
    	// Set the clocking to run directly from the external crystal/oscillator.
    	// TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
    	// crystal on your board.
    	//
    	SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
    			SYSCTL_XTAL_16MHZ);
    
    	//
    	// Set up the serial console to use for displaying messages.  This is
    	// just for this example program and is not needed for SSI operation.
    	//
    	InitConsole();
    
    	//
    	// Display the setup on the console.
    	//
    	UARTprintf("SSI ->\n");
    	UARTprintf("  Mode: SPI\n");
    	UARTprintf("  Data: 8-bit\n\n");
    
    	InitFlashHardware();
    
    	for (;;){
    		TestFlashWriteRead();
    	}
    
    }
    
    void InitFlashHardware()
    {
    
    	//
    	// The SSI0 peripheral must be enabled for use.
    	//
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    
    	//
    	// For this example SSI0 is used with PortA[5:2].  The actual port and pins
    	// used may be different on your part, consult the data sheet for more
    	// information.  GPIO port A needs to be enabled so these pins can be used.
    	// TODO: change this to whichever GPIO port you are using.
    	//
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
    	//
    	// Disable SSI function before configuring module
    	//
    	SSIDisable(SSI0_BASE);
    
    	//
    	//Set IO clock as SSI clock source
    	//
    	SSIClockSourceSet(SSI0_BASE, SSI_CLOCK_SYSTEM);
    
    	//
    	// Configure the pin muxing for SSI0 functions on port A2, A3, A4, and A5.
    	// This step is not necessary if your part does not support pin muxing.
    	// TODO: change this to select the port/pin you are using.
    	//
    	GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    	GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    	GPIOPinConfigure(GPIO_PA4_SSI0RX);
    	GPIOPinConfigure(GPIO_PA5_SSI0TX);
    
    	//
    	// Configure the GPIO settings for the SSI pins.  This function also gives
    	// control of these pins to the SSI hardware.  Consult the data sheet to
    	// see which functions are allocated per pin.
    	// The pins are assigned as follows:
    	//      PA5 - SSI0Tx
    	//      PA4 - SSI0Rx
    	//      PA3 - SSI0Fss
    	//      PA2 - SSI0CLK
    	// TODO: change this to select the port/pin you are using.
    	//
    	GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);
    
    	//
    	// Configure and enable the SSI port for SPI master mode.  Use SSI0,
    	// system clock supply, idle clock level low and active low clock in
    	// freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
    	// For SPI mode, you can set the polarity of the SSI clock when the SSI
    	// unit is idle.  You can also configure what clock edge you want to
    	// capture data on.  Please reference the datasheet for more information on
    	// the different SPI modes.
    	//
    	SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
    			SSI_MODE_MASTER, 1000000, 8);
    
    	//	Enable CS as GPIO
    	GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
    	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_PIN_3);
    
    	//
    	// Enable the SSI0 module.
    	//
    	SSIEnable(SSI0_BASE);
    
    }
    
    void TestFlashWriteRead()
    {
    	//
    	// Read any residual data from the SSI port.  This makes sure the receive
    	// FIFOs are empty, so we don't read any unwanted junk.  This is done here
    	// because the SPI SSI mode is full-duplex, which allows you to send and
    	// receive at the same time.  The SSIDataGetNonBlocking function returns
    	// "true" when data was returned, and "false" when no data was returned.
    	// The "non-blocking" function checks if there is any data in the receive
    	// FIFO and does not "hang" if there isn't.
    	//
    	while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
    	{
    	}
    
    	//	Set CS Low
    	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, 0);
    
    	//
    	// Initialize the data to send.
    	//
    	pui32DataTx[0] = 0x90;
    	pui32DataTx[1] = 0;//	dummy
    	pui32DataTx[2] = 0;//	dummy
    	pui32DataTx[3] = 0;//	dummy
    	//
    	// Display indication that the SSI is transmitting data.
    	//
    	UARTprintf("Sent:\n  ");
    
    	//
    	// Send 4 bytes of data.
    	//
    	for(ui32Index = 0; ui32Index < 4; ui32Index++)
    	{
    		//
    		// Display the data that SSI is transferring.
    		//
    		UARTprintf("%d", pui32DataTx[ui32Index]);
    
    		//
    		// Send the data using the "blocking" put function.  This function
    		// will wait until there is room in the send FIFO before returning.
    		// This allows you to assure that all the data you send makes it into
    		// the send FIFO.
    		//
    		SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
    	}
    
    	//
    	// Wait until SSI0 is done transferring all the data in the transmit FIFO.
    	//
    	while(SSIBusy(SSI0_BASE))
    	{
    	}
    
    	//
    	// Display indication that the SSI is receiving data.
    	//
    	UARTprintf("\nReceived:\n  ");
    
    	//
    	// Receive 2 bytes of data.
    	//
    	for(ui32Index = 0; ui32Index < 2; ui32Index++)
    	{
    		//
    		// Receive the data using the "blocking" Get function. This function
    		// will wait until there is data in the receive FIFO before returning.
    		//
    		SSIDataGet(SSI0_BASE, &pui32DataRx[ui32Index]);
    
    		//
    		// Since we are using 8-bit data, mask off the MSB.
    		//
    		pui32DataRx[ui32Index] &= 0x00FF;
    
    		//
    		// Display the data that SSI0 received.
    		//
    		UARTprintf("%2x ", pui32DataRx[ui32Index]);
    	}
    
    	// Set CS high
    	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_PIN_3);
    }
    

  • Hello Mohsin,

    The change is to the read from SSI FIFO. It is the last two bytes that will have the data and not the first two bytes.

        for(ui32Index = 0; ui32Index < 4; ui32Index++)
        {

            //
            // Receive the data using the "blocking" Get function. This function
            // will wait until there is data in the receive FIFO before returning.
            //
            SSIDataGet(SSI0_BASE, &pui32DataRx[ui32Index]);

            //
            // Since we are using 8-bit data, mask off the MSB.
            //
            pui32DataRx[ui32Index] &= 0x00FF;

            //
            // Display the data that SSI0 received.
            //
            UARTprintf("%2x ", pui32DataRx[ui32Index]);
        }

    Regards

    Amit

  • I just wrote a SSI program.  I don't understand what you are doing with pin3.  Shouldn't

    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2); be

    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3|GPIO_PIN_2); and let the system take care of pin3?

  • Hello Donald,

    SPI flash memories require that the CS be low for multiple bytes. However the SSI Controller requires that the FIFO be not empty else it would make CS high, causing the previous transaction to be terminated. Hence PIN-3 which is CS, is used as GPIO so that the software can decide when the SSI transaction is complete.

    Regards

    Amit

  • Did you try 

    SSIDataGet(DISPLAY_SSI_BASE, data);
    while(SSIBusy(DISPLAY_SSI_BASE))
    {}

    instead of the blocking?

  • Sorry about that DISPLAY_SSI_BASE should be SSI0_BASE. 

  • Hi Donald,

    Thanks for your support. I'm able to solve my problem.

    Regards,

    Mohsin

  • Hi Mohsin.

    I'm having the same problem with my board.

    Can you please tell how you solved the 0xFF problem ?

    Thank you.