0
\$\begingroup\$

I have an STM32H743 Nucleo board, accessing an external 16-bit SRAM memory chip using the Flexible Memory Controller (FMC).

8 and 16-bit writes return the same values when reading them back. However, 32 and 64-bit writes do not.

Writing in 16-bit chunks and then reading to 32-bit or 64-bit variables works OK. It is only 32 and 64-bit variable writes that cause a problem, where the values read afterwards return 0.

According to the user's manual, the FMC should split the write operation into multiple 16-bit ones automatically. Since 8-bit and 16-bit writes work without a problem, I conclude that the problem must be on the software side.

The external SRAM is set to device memory type. I've also tried setting it to strongly-ordered, using the MPU, but the problem remains.

What am I missing?

Below is the test code I am using:

uint8_t data = (uint8_t) 0x08;
*((uint8_t *) (SRAM_BANK_ADDR)) = data;
printf("8bit-value in SRAM 0x%x\n", *((uint8_t *) (SRAM_BANK_ADDR)));

uint16_t data2 = (uint16_t) 0x0016;
*((uint16_t *) (SRAM_BANK_ADDR)) = data2;
printf("16-bit value in SRAM 0x%x\n", *((uint16_t *) (SRAM_BANK_ADDR)));

uint16_t data3 = (uint16_t) 0x0032;
*((uint16_t *) (SRAM_BANK_ADDR)) = data3;
*((uint16_t *) (SRAM_BANK_ADDR | (0x02 << 1))) = data3;
*((uint16_t *) (SRAM_BANK_ADDR | (0x04 << 1))) = data3;
*((uint16_t *) (SRAM_BANK_ADDR | (0x06 << 1))) = data3;
printf("Value in SRAM as 32bit 0x%08lx\n", *((uint32_t *) (SRAM_BANK_ADDR)));
printf("Value in SRAM as 64bit 0x%016llx\n", *((uint64_t *) (SRAM_BANK_ADDR)));

uint32_t data4= (uint32_t) 0x3232;
*((uint32_t *) (SRAM_BANK_ADDR)) = data4;
HAL_Delay(1000); // Just to check whether it is a timing problem (?)

printf("Value in SRAM as 32bit 0x%08lx\n", *((uint32_t *) (SRAM_BANK_ADDR)));
printf("Value in SRAM as 64bit 0x%016llx\n", *((uint64_t *) (SRAM_BANK_ADDR)));

And the corresponding output:

8bit-value in SRAM 0x8
16-bit value in SRAM 0x16
Value in SRAM as 32bit 0x00320032
Value in SRAM as 64bit 0x0032003200320032
Value in SRAM as 32bit 0x00000000
Value in SRAM as 64bit 0x0000000000000000

For reference, this is the FMC configuration generated by the STM32CubeIDE:

/* FMC initialization function */
static void MX_FMC_Init(void)
{

  /* USER CODE BEGIN FMC_Init 0 */

  /* USER CODE END FMC_Init 0 */

  FMC_NORSRAM_TimingTypeDef Timing = {0};

  /* USER CODE BEGIN FMC_Init 1 */

  /* USER CODE END FMC_Init 1 */

  /** Perform the SRAM1 memory initialization sequence
  */
  hsram1.Instance = FMC_NORSRAM_DEVICE;
  hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
  /* hsram1.Init */
  hsram1.Init.NSBank = FMC_NORSRAM_BANK1;
  hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
  hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
  hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
  hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
  hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
  hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
  hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
  hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
  hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
  hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
  hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
  hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
  hsram1.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
  hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
  /* Timing */
  Timing.AddressSetupTime = 10;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 11;
  Timing.BusTurnAroundDuration = 10;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FMC_ACCESS_MODE_A;
  /* ExtTiming */

  if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
  {
    Error_Handler( );
  }

  HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);

  /* USER CODE BEGIN FMC_Init 2 */

  /* USER CODE END FMC_Init 2 */
}

==EDIT:

It seems there might actually be a problem with the hardware.

See the following example below:

while(1){
    *(uint16_t *) SRAM_BANK_ADDR = 68U;
    printf("Content of address: %d\n", *(uint16_t *) SRAM_BANK_ADDR);
    //Outputs (in each iteration): 68, 68, 68, 68
}

while(1){
    *(uint16_t *) SRAM_BANK_ADDR = 68U;
    HAL_Delay(1000);
    printf("Content of address: %d\n", *(uint16_t *) SRAM_BANK_ADDR);
    //Outputs (in each iteration): 4, 4, 516, 516, 516, 516, 516, ...
}


I'm guessing the chip is damaged, I will try with a new one.

===EDIT NR2:

A second chip shows the same behaviour, I will try a dedicated power supply, instead of powering the board through the debugger port.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ If by "it's a software problem" you mean that software isn't setting up the FMC correctly -- well, yes, and that's a strong contender for the actuall problem. However, I wouldn't call that a software problem per se., even though it's a problem that some software engineer needs to participate in fixing. If you mean you're not treating the memory space right in software -- then the "flexible" in "FMC" is a misnomer. Semiconductor companies have been making memory interfaces that can deal with this sort of stuff for decades. \$\endgroup\$
    – TimWescott
    Commented Oct 30, 2022 at 22:48
  • \$\begingroup\$ @TimWescott yes, I mean that my mistake is probably on the software side, i.e., instead of being a hardware design problem. I guess what I am looking for is whether someone else has made the same mistake, and what configuration they had to change in order to obtain the correct behaviour. \$\endgroup\$
    – Meruje
    Commented Oct 30, 2022 at 23:12
  • \$\begingroup\$ Do you mind showing us your hardware connections? Or is the SRAM the on-board part? \$\endgroup\$
    – Tom L.
    Commented Oct 31, 2022 at 19:53
  • \$\begingroup\$ @TomL. thanks for the comment. It led me to the solution for the problem. \$\endgroup\$
    – Meruje
    Commented Nov 1, 2022 at 16:07

1 Answer 1

1
\$\begingroup\$

So this was the problem.

When I designed the board, I used the STM32IDE to check which pins served which purpose. E.g., which pins are used for address lines, FMC_Ax, and so on.

It turns out that two different pins can be used for chip select FMC_NE1. I designed the board to use PD7. However, by default, the IDE sets PC7 to FMC_NE1, i.e., to be the one to control Chip Enable.

See the below image:

STM32CubeIDE showing the two possible pins for FMC_NE1

So, the Chip Enable was not being set, and so no write/read operations were actually being performed.

What I guess was happening was that when the write operation was close enough to the read operation, the MCU was reading the values it had just set for the data lines.

In a short enough interval of time, the data lines would still read the same values. However, has the memory chip was not actually driving the data lines, the data line values would eventually fluctuate to random values.

When a 32bit write was done to the memory for value 0x3232, it was split into a 0x0000 and a 0x3232 16-bit writes. I'm guessing the last write would be for the 0x0000, and hence the following read operations returned 0 as well.

I changed FMC_NE1 to pin PD7 and now everything works as it should.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you for following up with us. A weird problem indeed. \$\endgroup\$
    – Bryan
    Commented Nov 2, 2022 at 1:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.