Search code examples
carmembeddedstm32stm32f4discovery

Cannot read from/write to external SRAM using FMC on STM32F429I-Disco board


I am currently using a STM32F429I Disco board with full FMC (FSMC on F407) pins to try to connect to IS62WV51216BLL SRAM module from Waveshare without much success.

The main SRAM test/initialization code has been given down below. Apologies for the length of the post. I have tried checking and comparing with all the available codes in the internet, but somehow, it just does not initialize [test value is not returned]

The code was built and debugged in IAR workbench

SRAM_ADR

#define SRAM_ADR   ((uint32_t)0x60000000)
#define SRAM_END   SRAM_ADR + ((uint32_t)0x7FFFF) // not required for test

SRAM initialization, read, and write Code

//--------------------------------------------------------------
// Includes
//--------------------------------------------------------------
#include "stm32_ub_sram.h"


//--------------------------------------------------------------
// Internal Function
//--------------------------------------------------------------
void P_SRAM_InitIO(void);
void P_SRAM_InitFMC(void);


//--------------------------------------------------------------
// Initialize External SRAM
// Return_value :
//  -> ERROR   , when SRAM does not configured properly
//  -> SUCCESS , when SRAM configured successfully
//--------------------------------------------------------------
ErrorStatus UB_SRAM_Init(void)
{
  ErrorStatus ret_value = ERROR;
  uint16_t oldvalue, isvalue;

  // IO-Lines initialization
  P_SRAM_InitIO();
  // FMC initialization
  P_SRAM_InitFMC();

  //-----------------------------------------
  // Check the SRAM live or dead
  // Depends on testing the Adress 0x00
  //-----------------------------------------
  oldvalue = UB_SRAM_Read(0x00);
  UB_SRAM_Write(0x00, 0x5A3C);
  isvalue = UB_SRAM_Read(0x00);
  UB_SRAM_Write(0x00, oldvalue); 

  if(isvalue == 0x5A3C)
    ret_value = SUCCESS; // RAM verification

  return(ret_value);
}


//--------------------------------------------------------------
// Internal Function
// Initialize all IO-Pins for the SRAM
//--------------------------------------------------------------
void P_SRAM_InitIO(void)
{

  GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable GPIOs clock */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE
                         | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG, ENABLE);

  /* Common GPIO configuration */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;     // STM32F429I Only support speeds up to 90Mhz
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;

  /*-- SRAM GPIOs Configuration --------------------------------------------------*/
  /*
  +-------------------+------------------+-------------------+
  | PD14 <-> FMC_D0   | PF0  <-> FMC_A0  | PE0  <-> FMC_NBL0 |
  | PD15 <-> FMC_D1   | PF1  <-> FMC_A1  | PE1  <-> FMC_NBL1 |
  | PD0  <-> FMC_D2   | PF2  <-> FMC_A2  | PD4  <-> FMC_NOE  |
  | PD1  <-> FMC_D3   | PF3  <-> FMC_A3  | PD5  <-> FMC_NWE  |
  | PE7  <-> FMC_D4   | PF4  <-> FMC_A4  | PD7  <-> FMC_NE1  |
  | PE8  <-> FMC_D5   | PF5  <-> FMC_A5  |-------------------+
  | PE9  <-> FMC_D6   | PF12 <-> FMC_A6  |
  | PE10 <-> FMC_D7   | PF13 <-> FMC_A7  |
  | PE11 <-> FMC_D8   | PF14 <-> FMC_A8  |
  | PE12 <-> FMC_D9   | PF15 <-> FMC_A9  |
  | PE13 <-> FMC_D10  | PG0  <-> FMC_A10 |
  | PE14 <-> FMC_D11  | PG1  <-> FMC_A11 |
  | PE15 <-> FMC_D12  | PG2  <-> FMC_A12 |
  | PD8  <-> FMC_D13  | PG3  <-> FMC_A13 |
  | PD9  <-> FMC_D14  | PG4  <-> FMC_A14 |
  | PD10 <-> FMC_D15  | PG5  <-> FMC_A15 |
  +-------------------| PD11 <-> FMC_A16 |
                      | PD12 <-> FMC_A17 |
                      | PD13 <-> FMC_A18 |
                      | PE3  <-> FMC_A19 |
                      +------------------+
  */

  //-----------------------------------------
  // All pins for Port-D initialization
  //-----------------------------------------
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource0,  GPIO_AF_FMC);       // PD0 = FMC_D2
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource1,  GPIO_AF_FMC);       // PD1 = FMC_D3
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource4,  GPIO_AF_FMC);       // PD4 = FMC_NOE
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource5,  GPIO_AF_FMC);       // PD5 = FMC_NWE
  // GPIO_PinAFConfig(GPIOD, GPIO_PinSource7,  GPIO_AF_FMC);       // PD7 = FMC_NE1
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource8,  GPIO_AF_FMC);       // PD8 = FMC_D13
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource9,  GPIO_AF_FMC);       // PD9 = FMC_D14
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource10,  GPIO_AF_FMC);      // PD10 = FMC_D15
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource11,  GPIO_AF_FMC);      // PD11 = FMC_A16
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource12,  GPIO_AF_FMC);      // PD12 = FMC_A17
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource13,  GPIO_AF_FMC);      // PD13 = FMC_A18
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource14,  GPIO_AF_FMC);      // PD14 = FMC_D0
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource15,  GPIO_AF_FMC);      // PD15 = FMC_D1

  // Structure for Port-D
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0  | GPIO_Pin_1  | GPIO_Pin_4  | GPIO_Pin_5
                                // | GPIO_Pin_7 
                                | GPIO_Pin_8  | GPIO_Pin_9  | GPIO_Pin_10
                                | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14
                                | GPIO_Pin_15;

  // Configure Port-D
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  //-----------------------------------------
  // All pins for Port-E initialization
  //-----------------------------------------
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource0,  GPIO_AF_FMC);       // PE0 = FMC_NBL0
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource1,  GPIO_AF_FMC);       // PE1 = FMC_NBL1
  // GPIO_PinAFConfig(GPIOE, GPIO_PinSource3,  GPIO_AF_FMC);       // PE3 = FMC_A19
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource7,  GPIO_AF_FMC);       // PE7 = FMC_D4
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource8,  GPIO_AF_FMC);       // PE8 = FMC_D5
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource9,  GPIO_AF_FMC);       // PE9 = FMC_D6
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FMC);       // PE10 = FMC_D7
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FMC);       // PE11 = FMC_D8
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FMC);       // PE12 = FMC_D9
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FMC);       // PE13 = FMC_D10
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FMC);       // PE14 = FMC_D11
  GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FMC);       // PE15 = FMC_D12

  // Structure for Port-E
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 // | GPIO_Pin_3
                                | GPIO_Pin_7
                                | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11
                                | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  // Configure Port-E
  GPIO_Init(GPIOE, &GPIO_InitStructure);

  //-----------------------------------------
  // All pins for Port-F initialization
  //-----------------------------------------
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource0,  GPIO_AF_FMC);       // PF0 = FMC_A0
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource1,  GPIO_AF_FMC);       // PF1 = FMC_A1
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource2,  GPIO_AF_FMC);       // PF2 = FMC_A2
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource3,  GPIO_AF_FMC);       // PF3 = FMC_A3
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource4,  GPIO_AF_FMC);       // PF4 = FMC_A4
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource5,  GPIO_AF_FMC);       // PF5 = FMC_A5
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_FMC);       // PF12 = FMC_A6
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_FMC);       // PF13 = FMC_A7
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_FMC);       // PF14 = FMC_A8
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_FMC);       // PF15 = FMC_A9

  // Structure for Port-F
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3
                                | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13
                                | GPIO_Pin_14 | GPIO_Pin_15;

  // Configure Port-F
  GPIO_Init(GPIOF, &GPIO_InitStructure);

  //-----------------------------------------
  // All pins for Port-G initialization
  //-----------------------------------------
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource0,  GPIO_AF_FMC);       // PG0 = FMC_A10
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource1,  GPIO_AF_FMC);       // PG1 = FMC_A11
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource2,  GPIO_AF_FMC);       // PG2 = FMC_A12
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource3,  GPIO_AF_FMC);       // PG3 = FMC_A13
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource4,  GPIO_AF_FMC);       // PG4 = FMC_A14
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource5,  GPIO_AF_FMC);       // PG5 = FMC_A15
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource10,  GPIO_AF_FMC);      // PG10 = FMC_NE3
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource12,  GPIO_AF_FMC);      // PG12 = FMC_NE4

  // Structure for Port-G
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3
                                | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_10 | GPIO_Pin_12;

  // Configure Port-G
  GPIO_Init(GPIOG, &GPIO_InitStructure);
}


//--------------------------------------------------------------
// Internal Function
// Initialize FSMC for the SRAM
//--------------------------------------------------------------
void P_SRAM_InitFMC(void)
{
  FMC_NORSRAMInitTypeDef        FMC_NORSRAMInitStructure;
  FMC_NORSRAMTimingInitTypeDef  FMC_NORSRAMTimingInitStructure;

#if 0
  // De-initialize for re-initialize
  FMC_NORSRAMDeInit(FMC_Bank1_NORSRAM3);                        // From FMC_Bank1_NORSRAM1 -> 3
#endif

  /* Enable FMC clock */
  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);

  //-----------------------------------------
  // Structure for Timing
  //----------------------------------------- 
  FMC_NORSRAMTimingInitStructure.FMC_AddressSetupTime = SRAM_FMC_AST;        // 3
  FMC_NORSRAMTimingInitStructure.FMC_AddressHoldTime = SRAM_FMC_AHT;         // 0
  FMC_NORSRAMTimingInitStructure.FMC_DataSetupTime = SRAM_FMC_DST;           // 3
  FMC_NORSRAMTimingInitStructure.FMC_BusTurnAroundDuration = 0;              
  FMC_NORSRAMTimingInitStructure.FMC_CLKDivision = 0;
  FMC_NORSRAMTimingInitStructure.FMC_DataLatency = 0;
  FMC_NORSRAMTimingInitStructure.FMC_AccessMode = FMC_AccessMode_A;

  //-----------------------------------------
  // Structure for Bank-1 / PSRAM-1
  //----------------------------------------- 
  FMC_NORSRAMInitStructure.FMC_Bank = FMC_Bank1_NORSRAM3;       // From FMC_Bank1_NORSRAM1 -> 3
  FMC_NORSRAMInitStructure.FMC_DataAddressMux = FMC_DataAddressMux_Disable;
  FMC_NORSRAMInitStructure.FMC_MemoryType = FMC_MemoryType_SRAM;              // Workaround for 'Free GPIO Pin' <- NOR
  FMC_NORSRAMInitStructure.FMC_MemoryDataWidth = FMC_NORSRAM_MemoryDataWidth_16b;
  FMC_NORSRAMInitStructure.FMC_BurstAccessMode = FMC_BurstAccessMode_Disable;
  FMC_NORSRAMInitStructure.FMC_AsynchronousWait = FMC_AsynchronousWait_Disable;
  FMC_NORSRAMInitStructure.FMC_WaitSignalPolarity = FMC_WaitSignalPolarity_Low; 
  FMC_NORSRAMInitStructure.FMC_WrapMode = FMC_WrapMode_Disable;
  FMC_NORSRAMInitStructure.FMC_WaitSignalActive = FMC_WaitSignalActive_BeforeWaitState;
  FMC_NORSRAMInitStructure.FMC_WriteOperation = FMC_WriteOperation_Enable;
  FMC_NORSRAMInitStructure.FMC_WaitSignal = FMC_WaitSignal_Disable;
  FMC_NORSRAMInitStructure.FMC_ExtendedMode = FMC_ExtendedMode_Disable;
  FMC_NORSRAMInitStructure.FMC_WriteBurst = FMC_WriteBurst_Disable;
  FMC_NORSRAMInitStructure.FMC_ReadWriteTimingStruct = &FMC_NORSRAMTimingInitStructure;
  FMC_NORSRAMInitStructure.FMC_WriteTimingStruct = &FMC_NORSRAMTimingInitStructure;

  // Configure FSMC
  FMC_NORSRAMInit(&FMC_NORSRAMInitStructure);

  // Enable Bank-1 / PSRAM-1
  FMC_NORSRAMCmd(FMC_Bank1_NORSRAM3, ENABLE);                   // From FMC_Bank1_NORSRAM1 -> 3

}


//--------------------------------------------------------------
// Sends 16-bit value to the external SRAM
//--------------------------------------------------------------
void UB_SRAM_Write(uint32_t adr, uint16_t wert)
{
  // Transfer 16-bits data to the memory
  *(uint16_t *) (SRAM_ADR + adr) = wert;
}


//--------------------------------------------------------------
// Reads 16-bit value from the external SRAM
//--------------------------------------------------------------
uint16_t UB_SRAM_Read(uint32_t adr)
{
  uint16_t ret_wert = 0;

  // Read 16-bits data from the memory
  ret_wert = *(__IO uint16_t*) (SRAM_ADR + adr);

  return(ret_wert);
}

Is there any missing points that I should check before doing this?


Solution

  • From a software perspective you've got a mismatch between your bank selection and your base address. The FMC banks are arranged as 4x64Mb (banks 1,2,3,4) with the following base addresses:

    bank 1: 0x60000000
    bank 2: 0x64000000
    bank 3: 0x68000000
    bank 4: 0x6C000000
    

    It's confusing that ST refer to the 64Mb ranges as banks themselves when they are really sub-banks of the larger bank #1 that's allocated to NOR/PSRAM.

    You've defined this:

    #define SRAM_ADR   ((uint32_t)0x60000000)
    
    // [...]
    
    FMC_NORSRAMCmd(FMC_Bank1_NORSRAM3, ENABLE);
    

    As you can see you've got a mismatch between bank selection (#3) and base address selection (#1). You need to get them aligned.

    If you continue to have issues after fixing this then look at your timing calculations and definitely the electrical connections.