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.

LM4F232H5QD SPI Problem (With Microchip W25X16 SPI Flash)

Dear All,

For my case, I am using W25X16 SPI Flash in SSI1 Module of LM4F.

I wanna transmit one byte (0xAB) to spi flash, and the register address of flash is 0x000000. And after transmission, I also want to receive the data I sent before.
But unlucky, I can not receive the data I send. The code as below, plz help me to check it :

Thank you in advance.

 

void Timer0_ISR( void ) ;
void Init_SPI( void ) ;
void    SendByte( unsigned char data ) ;
void ReceiveByte( void ) ;

#define   W25X16_CS_0   GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_3, 0x00 ) ;
#define   W25X16_CS_1   GPIOPinWrite( GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3 ) ;

volatile char  GetData = 0 ;
volatile long  Cnt32_1 = 0, ReadData = 0 ;

//================================================================//
void SendByte( unsigned char data )
{
 unsigned long NullData ;
 SSIDataPut( SSI1_BASE, data ) ;
 SSIDataGet( SSI1_BASE, &NullData ) ;
}
//----------------------------------------------------------------//
void ReceiveByte( void )
{
 SSIDataPut( SSI1_BASE, 0xFF ) ; 

 SSIDataGet( SSI1_BASE, &ReadData ) ;
}

//----------------------------------------------------------------//
void Init_SPI( void )
{
 // Using Winbond SPI Flash W25X16BV ( 2M Bytes )
 // PF0 (RX) --> DO  ( MISO)
 // PF1 (TX) --> DIO (MOSI)
 // PF2 (Clk) --> CLK
 // PF3 (Fss) --> /CS
 //========================<Initial>========================//
 SysCtlPeripheralEnable( SYSCTL_PERIPH_SSI1 ) ;

 SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF ) ;
 GPIOPinConfigure( GPIO_PF0_SSI1RX ) ;
 GPIOPinConfigure( GPIO_PF1_SSI1TX ) ;
 GPIOPinConfigure( GPIO_PF2_SSI1CLK ) ;
 GPIOPinTypeSSI( GPIO_PORTF_BASE,  GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 ) ;
 GPIODirModeSet( GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_DIR_MODE_OUT ) ;
 GPIOPadConfigSet( GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD ) ;

 SSIConfigSetExpClk( SSI1_BASE, SysCtlClockGet( ), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8 ) ;
 SSIEnable( SSI1_BASE ) ;
 W25X16_CS_1 ;
 //========================<Write>========================//

 // Step 1.Program Enable
 W25X16_CS_0  ;
 SendByte( 0x06 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 W25X16_CS_1 ;

 // Step 2.Sector Erase
 W25X16_CS_0  ;

 SendByte( 0x20 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 
 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }

 W25X16_CS_1 ;

 do
 {
  W25X16_CS_0  ;
  SendByte( 0x50 ) ;
  while( SSIBusy( SSI1_BASE ) ) { }
  ReceiveByte( ) ;
  W25X16_CS_1  ;
 }
 while( ReadData == 0x03 ) ;
 
 // Step 3.Program Enable
 W25X16_CS_0  ;
 SendByte( 0x06 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 W25X16_CS_1 ;

 // Step 4.Page Program
 W25X16_CS_0  ;
 SendByte( 0x02 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }

 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }

 SendByte( 0xAB ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 W25X16_CS_1  ;

 do
 {
  W25X16_CS_0  ;
  SendByte( 0x50 ) ;
  while( SSIBusy( SSI1_BASE ) ) { }
  ReceiveByte( ) ;
  W25X16_CS_1  ;
 }
 while( ReadData == 0x03 ) ;
 
 //========================<Read>========================//
 W25X16_CS_0  ;

 SendByte( 0x0B ) ;
 while( SSIBusy( SSI1_BASE ) ) { }

 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }
 SendByte( 0x00 ) ;
 while( SSIBusy( SSI1_BASE ) ) { }

 SendByte( 0xFF ) ;         // Make 8-clock
 while( SSIBusy( SSI1_BASE ) ) { }

 ReceiveByte( ) ;
 while( SSIBusy( SSI1_BASE ) ) { }

 W25X16_CS_1  ;

 GetData = ReadData ;                              // Receive the data I sent before.

}
//----------------------------------------------------------------//
void Timer0_ISR( void )
{
 TimerIntClear( TIMER0_BASE, TIMER_TIMA_TIMEOUT ) ;
 TimerLoadSet(TIMER0_BASE, TIMER_A, 80000);

 Init_SPI( ) ;
}
//================================================================//

void main( void )
{
     // Init Clk
 SysCtlClockSet( SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN ) ;
 
 // Init Timer
 SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER0 ) ;
 TimerConfigure( TIMER0_BASE, TIMER_CFG_PERIODIC ) ;
 TimerLoadSet(TIMER0_BASE, TIMER_A, 80000);
 TimerIntRegister( TIMER0_BASE, TIMER_A, Timer0_ISR ) ;
 TimerIntEnable( TIMER0_BASE, TIMER_TIMA_TIMEOUT ) ;
 IntEnable(INT_TIMER0A);
 TimerEnable( TIMER0_BASE, TIMER_A ) ;

 while( 1 )
 {
           ;
 }
}

 

 

 

  • This isn't answering your question, but is something I notice about your code.

    You don't need any of the loops waiting for the SSI to not be busy,  Since both of your read and write functions do a call to SSIDataGet(), the SSI transaction is guaranteed to be complete when the function returns.

    As for your question - it's unclear exactly what's going wrong.  Just saying something doesn't work doesn't give us any hints about what is and isn't working,  What happens when you run your code?

  • Dear

    Thank you for your hint.

    In Init_SPI( ), I transmit 0xAB to 0x000000 register of flash first. Then, I hope I can read 0xAB from 0x000000 register as well.

    But actually, When I read the value from 0x000000 by ReceiveByte( ), the value alway is 0x00.

     

  • Can someone help me to solve this problem ??

    Thank you in advance.

  • Can someone help me to solve this problem ??  = ="

    Thank you in advance.

  • I have this exact same problem with silicon A1.  There is no errata for the SSI and I have doubled-checked my initialisation code against the ssi_master example.  The SSI1RX pin (PF0) is assigned to the alternate function with GPIOPinConfigure(GPIO_PF0_SSI1RX) and GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0).  The SPI transmits fine, but always reads back zeroes with SSIDataGet(), even though I've tied the PF0 pin high (to +3.3V).  I've tried SSIDataGetNonBlock(), and also the ROM_xxx versions of the functions.  I've even tried adding the RX pin to a call to GPIOPadConfigSet().  Nothing works.

    Here is my initialisation code:

    // On Port F:
    #define IN_DATA     GPIO_PIN_0
    #define OUT_DATA     GPIO_PIN_1
    #define SPI_CLK      GPIO_PIN_2
    #define STROBE    GPIO_PIN_3

        // Enable the power and clock to the SSI1 module:
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);

        // Enable the power and clock to Port F:
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

        // Set the appropriate pins to SPI function:
        ROM_GPIOPinConfigure(GPIO_PF0_SSI1RX);
        ROM_GPIOPinConfigure(GPIO_PF1_SSI1TX);
        ROM_GPIOPinConfigure(GPIO_PF2_SSI1CLK);

        // Fss = STROBE.  We need to keep this as a GPIO in order to emulate
        // the original timing and to transmit the checksum after the packet
        // with STROBE high:
        // Do not ROM_GPIOPinConfigure(GPIO_PF3_SSI1FSS);
        ROM_GPIODirModeSet(GPIO_PORTF_BASE, STROBE, GPIO_DIR_MODE_OUT);
        ROM_GPIOPadConfigSet(GPIO_PORTF_BASE, STROBE, GPIO_STRENGTH_2MA,
                             GPIO_PIN_TYPE_STD);

        // Fss = RX_LATCH.  Same comment as above:
        ROM_GPIOPinTypeSSI(GPIO_PORTF_BASE, IN_DATA | OUT_DATA | SPI_CLK /* | STROBE */);

        ROM_SSIConfigSetExpClk(SSI1_BASE, ROM_SysCtlClockGet(), SSI_FRF_MOTO_MODE_3,
                               SSI_MODE_MASTER, 74000, 8);

        ROM_SSIEnable(SSI1_BASE);
        
        // Clear the receive FIFO:
        while (ROM_SSIDataGetNonBlocking(SSI1_BASE, &dummy_receive_value) > 0)
        {
            // Discard the data.
        }

    Here is my loop to send/receive on the SPI:

        unsigned long int out_char, return_char;

        // Lower STROBE:
        ROM_GPIOPinWrite(GPIO_PORTF_BASE, STROBE, 0);

        // Wait 285 microseconds:
        ROM_SysCtlDelay(285ULL * ROM_SysCtlClockGet() / 1000000 / 3);

        for (i = 0; i < PACKET_SIZE; i++)
        {
            out_char = out_packet[i];
            ROM_SSIDataPut(SSI1_BASE, out_char);

            while (ROM_SSIBusy(SSI1_BASE))   // Not actually necessary since we're calling ROM_SSIDataGet().
            {
                // Wait.
            }

            // Get the return data octet:
            ROM_SSIDataGet(SSI1_BASE, &return_char);
            return_packet[i] = return_char;     // This is ALWAYS zero, even with the RX line tied high.

            // Wait 19 microseconds:
            ROM_SysCtlDelay(19ULL * ROM_SysCtlClockGet() / 1000000 / 3);
        }

        // Raise STROBE:
        ROM_GPIOPinWrite(GPIO_PORTF_BASE, STROBE, STROBE);

    The SSIDataPut() data comes out fine.  But SSIDataGet() always reads back zeroes.

    I (and I'm sure Che-Chia Li) would appreciate if a T.I. employee can comment on this.  Thanks.

  • Hi,

    I have noticed you use twice in your write routine the instruction SendByte(0x50); if you meant to read status register of your memory then the op-code for that is 0x05.  Why don't you use some nice defines like 

    #define GET_STATUS_REG_CMD  0x05

    #define SECTOR_ERASE_CMD     0x20

    to avoid mistakes?

    As you may be noticed reading various posts (and that from slandrum, cb1, cb1_mobile) they repeated that SPI sending and receiving is a simultaneous process - so your read routine make the same mistake to send two separate commands - sending a dummy 0xFF after sending the address would be enough to receive data - check your NullData to see its content.

    Petrei 

  • [/quote]

    William Hue said:
    SSI1RX pin (PF0) is assigned to the alternate function with GPIOPinConfigure(GPIO_PF0_SSI1RX) and GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_0). 

    [quote user="William Hue"] even though I've tied the PF0 pin high (to +3.3V). 

    While both of these actions are necessary - they are not sufficient (even in combination) - to liberate PF0 from its default, NMI config!  You must precede any such, "pin-liberating" via the UNLock Procedure which is detailed w/in MCU Datasheet.  (required for any/all JTAG pins, PF0 and PD7!)

    Poster Petrei  effectively  summarizes past advice/guidance - little to add...  (thus - do as he advises...)

    note: forum "quote facility" somewhat "under the influence" this morn.  (Not this guy!   Dreaded Offense - "PWI" posting while intox ...  not in practice here/now/... at least not yet) 

     

  • Thanks, cb1_mobile!  After re-reading the datasheet a few times, I finally understand that, while PF0 doesn't default to the NMI function (PF0 defaults to GPIO), it is a protected pin and the unlock sequence must preceed the code that configures it to be an SSI pin.  Finding the names of the register #defines also took some digging, so here is the new initialisation code for the benefit of others:

    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"

        // Set the appropriate pins to SPI function:
        HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY_DD;    // Unlock the GPIOCR.
        HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0xff;  // Allow the alternate function change to PF0.
        ROM_GPIOPinConfigure(GPIO_PF0_SSI1RX);
        ROM_GPIOPinConfigure(GPIO_PF1_SSI1TX);
        ROM_GPIOPinConfigure(GPIO_PF2_SSI1CLK);

    Here are two related threads:

    http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/471/t/199847.aspx
    http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/471/t/171296.aspx

    Thanks also go to Alex Bestavros of T.I. for his prompt response via e-mail.

  • You are most welcome William.  Would you be so good as to reward my post (the only one identifying your real issue) with a Verified Answer tick?

  • cb1_mobile said:
    Would you be so good as to reward my post (the only one identifying your real issue) with a Verified Answer tick?

    He can't, as he posted in a thread that someone else started.

  • Ai Carumba!  Hoist by my own petard - thank you for the heads-up.  (will surely need a "double" later tonight...)

    This arcane rule stinks. (imho)  Logical that follow-on poster, "piggy-backed" here - while I'm glad to have helped - reward now hangs in the wings till (and if) some kind TI reviewer deems answer "worthy." 

  • hi,

    i am using code composer studio v5.3 for stellaris LM4F232H5QD,whenever i am building basic wifi application, i am getting error while debug time,i.e(inside spi write function ) spi write is not happening(for cc3000 device),so how to resolve this issue,please help me.
    when i run this code in IAR it works straightly,is there any thing i have to add extra in ccs to work basic wifi application.