Auf einem selbst entwickeltes Board mit einem STM32F746 verwende ich
einen SDRAM IC (4 Bänke, 16-Daten-Bits, 256Mb). Bisher habe ich einen
MT48LC16M16A2 von Micron verwendet, nun möchte ich stattdessen einen
NDS36PT5-20ET von Insignis benutzen.
(Datenblatt: http://insignis-tech.com/download/145)
Der Micron IC funktioniert (auf dem gleichen Board) problemlos, aber ich
bekomme den Insignis IC einfach nicht zum Laufen. In meinem kleinen
Testprogramm
1 | uint32_t i;
|
2 | for (i = 0; i < 16384; i += 2) {
|
3 | *(__IO uint16_t *) (SDRAM_BASE + i) = i & 0xffff; //SDRAM_BASE=0xC000k
|
4 | }
|
5 |
|
6 | for (i = 0; i < 16384; i += 2) {
|
7 | uint16_t data = *(__IO uint16_t *) (SDRAM_BASE + i);
|
8 | if (data != (i & 0xffff)) {
|
9 | while (1); // breakpoint here
|
10 | }
|
11 | }
|
liefert der erste Lesezugriff 0x3ffe anstatt 0 zurück.
Der STM32F746 läuft mit 200 MHz, der FMC und das SDRAM daher mit 100
MHz. Ein FMC-Zylkus dauert also 10 ns. Das SDRAM IC ist für 200 MHz
ausgelegt. Ich habe dann die Zeitabgaben für 200 MHz aus dem Datenblatt
(Bild 1) jeweils durch 10 ns geteilt und aufgerundet, um die Anzahl der
FMC-Zyklen für CubeMX zu erhalten (Bild 2). Write recovery time müsste 1
sein, wird aber von CubeMX auf 2 gesetzt.
Als CAS Latency habe ich 3 gewählt. Die Refresh-Rate ist (64 / 8192 *
100) * 1000 - 20 (die *1000 ergeben sich durch den Einheitenfehler, den
die Formel macht).
Das SDRAM wird mit diesem Code initialisiert, was dem Datenblatt (Bild
3) entspricht.
1 | static void SDRAM_Init()
|
2 | {
|
3 | FMC_SDRAM_CommandTypeDef Command;
|
4 |
|
5 | __IO uint32_t tmpmrd =0;
|
6 | /* Step 3: Configure a clock configuration enable command */
|
7 | Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
|
8 | Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
|
9 | Command.AutoRefreshNumber = 1;
|
10 | Command.ModeRegisterDefinition = 0;
|
11 | HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
|
12 |
|
13 | /* Step 4: Insert 100 us minimum delay */
|
14 | /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
|
15 | HAL_Delay(1);
|
16 |
|
17 | /* Step 5: Configure a PALL (precharge all) command */
|
18 | Command.CommandMode = FMC_SDRAM_CMD_PALL;
|
19 | Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
|
20 | Command.AutoRefreshNumber = 1;
|
21 | Command.ModeRegisterDefinition = 0;
|
22 | HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
|
23 |
|
24 | /* Step 6 : Configure a Auto-Refresh command */
|
25 | Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
|
26 | Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
|
27 | Command.AutoRefreshNumber = 2; // Insignis SDRAM
|
28 | Command.ModeRegisterDefinition = 0;
|
29 | HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
|
30 |
|
31 | /* Step 7: Program the external memory mode register */
|
32 | tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | // 0
|
33 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | // 0
|
34 | SDRAM_MODEREG_CAS_LATENCY_3 | // 0x30
|
35 | SDRAM_MODEREG_OPERATING_MODE_STANDARD | // 0
|
36 | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; // 0x200
|
37 |
|
38 | Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
|
39 | Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
|
40 | Command.AutoRefreshNumber = 1;
|
41 | Command.ModeRegisterDefinition = tmpmrd;
|
42 | HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
|
43 |
|
44 | /* Step 8: Set the refresh rate counter: (64 ms / 8192 x Freq) - 20 */
|
45 | hsdram1.Instance->SDRTR |= ((uint32_t)761); // 2HCLK, Insignis SDRAM
|
46 | }
|
Wie gesagt, auf dem gleichen Board läuft ein SDRAM von Micron ohne
Probleme, so dass ich Fehler im Layout eigentlich ausschließen möchte.
Außerdem habe ich zwei Boards gelötet, was Lötfehler vermeiden sollte.
Aber welchen Fehler habe ich bei der Konfiguration gemacht? Wie könnte
ich das Problem weiter einkreisen?