Forum: Mikrocontroller und Digitale Elektronik LPC1857 ARM Cortex M3 Problem mit EMC und SDRAM


von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Hallo alle zusammen,

ich versuche gerade die Kommunikation zwischen einem NXP LPC1857 und 
einem SDRAM MT48LC4M32B2P-6 hinzubekommen. Dazu verwende ich das KEIL 
MCB1857 Entwicklungsboard. Als Entwicklungsumgebung nutze ich LPCXpresso 
IDE mit dem LPC-Link.

Ich habe ein einfaches Projekt angelegt. Der EMC wird in der emc.c 
initialisiert und in der main.c wird dann ein Testprogramm ausgeführt, 
welches mir bei erfolgreichem Schreiben auf den SDRAM sowie bei 
fehlgeschlagenem Schreiben je eine LED ansteuert.

Mein Problem ist jetzt, dass es nicht funktioniert.

Als EMC Takt verwende ich 120MHz, die ich einfach nur in der 
CGU_Init()-Funktion mit SetPLL1(10) eingestellt hab.
Den CLK0 (rot) und den CKE0 (gelb) habe ich gemessen (siehe Bild im 
Anhang). Ich habe beide Signale mit einem anderen Board und einem 
funktionierenden Beispielcode verglichen. Also der Clock scheint schon 
mal in Ordnung zu sein.

Das Linker-Script habe ich manuell im MEMORY-Bereich erweitert (siehe 
Anhang SDRAM16).

Könnte sich bitte jemand meine Dateien mal ansehen, ob er eventuell den 
Fehler findet, warum ich keine erfolgreiche Kommunikation hinbekomme?

Vielen Dank! :-)

Beste Grüße,

Martin

von Martin (Gast)


Lesenswert?

Guten morgen :-)

hat jemand Erfahrungen mit den LPC18xx Controllern und Linker-Skripten 
in LPCXpresso IDE oder der Code Red IDE?

Reicht es folgende Einstellungen vorzunehmen:

In der ..._mem.ld Datei:
1
MEMORY 
2
{
3
   ...
4
   ...
5
   SDRAM (rwx) : ORIGIN = 0x28000000, LENGTH = 0x1000000
6
}
7
8
   ...
9
   ...
10
   __top_SDRAM = 0x28000000 + 0x10000000;

In der ... .ld Datei:

Erstellen einer section (Beispiel):
1
.VRAM (NOLOAD) : ALIGN(4)
2
{
3
    *(.VRAM)
4
} > SDRAM

Ist es ausreichend, nur die Einstellungen in der ...mem.ld vorzunehmen, 
um nur einen Wert in den Speicherbereich des SDRAM zu schreiben?

Die section benötige ich doch nur, wenn ich eine Variable oder eine 
Funktion in diesen Bereich ablegen will, oder?

Danke.

Mfg Martin

von Arne (Gast)


Lesenswert?

Martin schrieb:

> Mein Problem ist jetzt, dass es nicht funktioniert.
>
> Als EMC Takt verwende ich 120MHz

Der EMC in den LPC178x (!) verträgt nur 80MHz:
http://www.lpcware.com/content/forum/dk-57vts-lpc1788-configuring-emc-sdram

Würde mich wundern, wenn es beim LPC18xx anders wäre, es sei denn, es 
steht explizit im Usermanual.

bye, Arne

PS: SDRAM am LPC1788 steht mir auch noch bevor...

von Martin (Gast)


Lesenswert?

Hallo Arne,

danke für den Hinweis, ich werd gleich nochmal schauen, wie hoch die 
Frequenz sein darf.

Ein funktionierendes Beispiel für den EMC des 1788 findest du im BSP von 
emWin.

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Also die typische maximale EMC Frequenz ist 120MHz. Das heißt ich 
betreib den gerade am Maximum. Naja ich werd mal mit 60 oder 72MHz 
versuchen.

von Martin (Gast)


Lesenswert?

72MHz bringt auch keinen Erfolg..

von Arne (Gast)


Lesenswert?

Unterscheidet sich der EMC vom 178x zum 1857? Sonst könntest Du doch auf 
das emWin Bsp. zurückgreifen.
Ich meine der EMC ist sogar in LPC2xxx ARM7 drin.

von Arne (Gast)


Lesenswert?

BTW: hast Du da nicht ein Henne-Ei Problem?
Der StartUp Code "kennt" anhand des Linkerskripts das externe SDRAM und 
versucht u.U. da das BSS zu nullen, bzw. das DATA Segment aus dem
int. Flash dahin zu kopieren. Und das alles bevor der EMC samt SDRAM 
korrekt konfiguriert ist?

Ich werde bei mir einen Bootloader programmieren, der das ext.RAM vom 
Linkerskript nicht kennt, aber den EMC und das SDRAM bereits korrekt 
initialisiert. Dann erfolgt der Sprung in die Applikation, die vom 
Linkerskript das ext.RAM bereits kennt. Dann kann vom BSS/DATA kopieren 
nichts schief gehen.

von Martin (Gast)



Lesenswert?

Im Wesentlichen habe ich die EMC Configuration vom 1788 genommen. Es 
mussten nur die Pinkonfigurationsregister für den 1857 angepasst werden 
und halt die Daten vom neuen SDRAM.

Trotzdem gehts nicht.

Zum Linker-Script:

Ich kann ja zum einen den SDRAM unter MCU Settings per Edit im Memory 
Configuration Editor hinzufügen. Danach "Manage Linker script" auswählen 
und das Linker script wird automatisch erstellt. Dabei entstehen neben 
der Memory-Region "SDRAM" auch noch .DATA- und .BSS-Sektionen für 
"SDRAM".
Zum anderen kann man "Manage Linker Script" auch abwählen und das 
existierende (ohne SDRAM) manuell bearbeiten. Im emWin-Beispiel vom 1788 
wurden lediglich die Einträge für die Memory-Region in der _mem.ld Datei 
vorgenommen und die Sektionen .GUI_RAM und .VRAM in der .ld erstellt. Da 
gibt es keine .DATA oder .BSS-Sektionen für den SDRAM.
Also habe ich mich an das Beispiel gehalten und nur eine neue 
Memory-Region für den SDRAM erstellt, da ich im Moment für den Test die 
.VRAM und .GUI_RAM Sektionen nicht benötige. Ich habe nichts bei .DATA 
und .BSS programmiert.

Wie sollte denn das Linker-Skript richtig programmiert werden? Benötige 
ich die .DATA- und .BSS-Sektionen?

Anbei habe ich die Linker-skript Dateien vom emWin BSP anghängt.

von Martin (Gast)


Lesenswert?

Ich habe jetzt noch einmal meine Testroutine geändert. Jetzt sieht es so 
aus, als ob das Schreiben auf den SDRAM funktioniert.

Testroutine vorher:
1
unsigned int SDRAM_Test (void)             
2
                            // Test-Routine aus der NXP AppNote 10771
3
{
4
  unsigned int i;
5
  // 32 bits access
6
  for (i = 0; i < 0x2000000; i+=sizeof(unsigned int))
7
  {
8
    *(unsigned int *)((unsigned int )SDRAM_BASE_ADDR+i) = i;
9
  }
10
  for (i = 0; i < 0x2000000; i+=sizeof(unsigned int ))
11
  {
12
     if (*(unsigned int *)((unsigned int )SDRAM_BASE_ADDR+i) != i)
13
     {
14
         return(0);
15
     }
16
  }
17
  
18
  return(1);
19
}

Aktuelle Testroutine:
1
unsigned int SDRAM_Test (void)             
2
                            // Test-Routine aus der NXP AppNote 10771
3
{
4
  unsigned int i;
5
  // 32 bits access
6
  for (i = 0; i < 0x2000000; i+=sizeof(unsigned int))
7
  {
8
     *(unsigned int *)((unsigned int )SDRAM_BASE_ADDR+i) = i;
9
          
10
     if (*(unsigned int *)((unsigned int )SDRAM_BASE_ADDR+i) != i)
11
     {
12
         return(0);
13
     }
14
  }
15
  
16
  return(1);
17
}

Jetzt müsste es doch so sein, dass der aktuelle Wert von i an die Stelle 
SDRAM_BASE_ADDR+i geschrieben und gleich im Anschluss überprüft wird.

Vorher wurden alle Werte i nacheinander in den SDRAM geschrieben. Danach 
wurden wieder alle Werte i hochgezählt und überprüft. Dabei werden sich 
ja bestimmte Werte überschrieben haben und es kam zum Fehlschlagen der 
Überprüfung.

Passt meine Überlegung oder hab ich da einen Denkfehler drin? Das 
Programm funktioniert jedenfalls erst einmal.

von Martin (Gast)


Lesenswert?

Ich habe jetzt noch einmal die Test_SDRAM - Routine vom emWin LPC1788 
Board support package ausprobiert und festgestellt, dass meine 
Kommunikation mit dem SDRAM nicht funktioniert.

Warum klappt es aber mit der Test-Routine aus dem letzten Post? Kann es 
sein, dass ich dort gar nicht wirklich auf den SDRAM schreibe??

von Lothar (Gast)


Lesenswert?

Habe nichts mit dem LPC1857 gemacht, aber der soll doch kompatibel zum 
LPC4357 sein bzw. umgekehrt, und damit vielleicht auch der EMC:

http://www.lpc4350.com/lpc43xx/Examples/SDRAM_Test/

von Martin (Gast)


Lesenswert?

Habs immer noch nicht hinbekommen :-(

Hab jetzt folgende EMC_Init-Routine:
1
void emc_WaitUS(volatile uint32_t us)
2
{
3
  us *= ((SystemCoreClock / 1000000)/3);
4
  while(us--);
5
}
6
7
void emc_WaitMS(volatile uint32_t ms)
8
{
9
  ms *= ((SystemCoreClock / 1000)/3);
10
  while(ms--);
11
}
12
13
/*********************************************************************
14
*
15
*       _EMC_Init()
16
*
17
*  Purpose:
18
*    Initializes external memory controller for SDRAM
19
*/
20
21
void _EMC_Init(void) {
22
23
  volatile U32 CmdDly;
24
  volatile U32 Dummy;
25
  volatile U32 i;
26
27
  LPC_SCU->EMCDELAYCLK  = 0x7777;
28
  //LPC_CREG->CREG6 |= (1 << 16);
29
30
  LPC_EMC->CONTROL   = 0x1;           // EMC enable
31
  LPC_EMC->CONFIG    = 0x0;        //Little Endian Mode
32
  //
33
  // Port init
34
  //
35
  LPC_SCU->SFSP1_7 = (MD_PLN_FAST | FUNC3);  //D0
36
  LPC_SCU->SFSP1_8 = (MD_PLN_FAST | FUNC3);  //D1
37
  LPC_SCU->SFSP1_9 = (MD_PLN_FAST | FUNC3);  //D2
38
  LPC_SCU->SFSP1_10 = (MD_PLN_FAST | FUNC3); //D3
39
  LPC_SCU->SFSP1_11 = (MD_PLN_FAST | FUNC3); //D4
40
  LPC_SCU->SFSP1_12 = (MD_PLN_FAST | FUNC3); //D5
41
  LPC_SCU->SFSP1_13 = (MD_PLN_FAST | FUNC3); //D6
42
  LPC_SCU->SFSP1_14 = (MD_PLN_FAST | FUNC3); //D7
43
  LPC_SCU->SFSP5_4 = (MD_PLN_FAST | FUNC2);  //D8
44
  LPC_SCU->SFSP5_5 = (MD_PLN_FAST | FUNC2);  //D9
45
  LPC_SCU->SFSP5_6 = (MD_PLN_FAST | FUNC2);  //D10
46
  LPC_SCU->SFSP5_7 = (MD_PLN_FAST | FUNC2);  //D11
47
  LPC_SCU->SFSP5_0 = (MD_PLN_FAST | FUNC2);  //D12
48
  LPC_SCU->SFSP5_1 = (MD_PLN_FAST | FUNC2);  //D13
49
  LPC_SCU->SFSP5_2 = (MD_PLN_FAST | FUNC2);  //D14
50
  LPC_SCU->SFSP5_3 = (MD_PLN_FAST | FUNC2);  //D15
51
  LPC_SCU->SFSPD_2 = (MD_PLN_FAST | FUNC2);  //D16
52
  LPC_SCU->SFSPD_3 = (MD_PLN_FAST | FUNC2);  //D17
53
  LPC_SCU->SFSPD_4 = (MD_PLN_FAST | FUNC2);  //D18
54
  LPC_SCU->SFSPD_5 = (MD_PLN_FAST | FUNC2);  //D19
55
  LPC_SCU->SFSPD_6 = (MD_PLN_FAST | FUNC2);  //D20
56
  LPC_SCU->SFSPD_7 = (MD_PLN_FAST | FUNC2);  //D21
57
  LPC_SCU->SFSPD_8 = (MD_PLN_FAST | FUNC2);  //D22
58
  LPC_SCU->SFSPD_9 = (MD_PLN_FAST | FUNC2);  //D23
59
  LPC_SCU->SFSPE_5 = (MD_PLN_FAST | FUNC3);  //D24
60
  LPC_SCU->SFSPE_6 = (MD_PLN_FAST | FUNC3);  //D25
61
  LPC_SCU->SFSPE_7 = (MD_PLN_FAST | FUNC3);  //D26
62
  LPC_SCU->SFSPE_8 = (MD_PLN_FAST | FUNC3);  //D27
63
  LPC_SCU->SFSPE_9 = (MD_PLN_FAST | FUNC3);  //D28
64
  LPC_SCU->SFSPE_10 = (MD_PLN_FAST | FUNC3); //D29
65
  LPC_SCU->SFSPE_11 = (MD_PLN_FAST | FUNC3); //D30
66
  LPC_SCU->SFSPE_12 = (MD_PLN_FAST | FUNC3); //D31
67
68
  LPC_SCU->SFSP2_9 = (MD_PLN_FAST | FUNC3);  //A0
69
  LPC_SCU->SFSP2_10 = (MD_PLN_FAST | FUNC3); //A1
70
  LPC_SCU->SFSP2_11 = (MD_PLN_FAST | FUNC3); //A2
71
  LPC_SCU->SFSP2_12 = (MD_PLN_FAST | FUNC3); //A3
72
  LPC_SCU->SFSP2_13 = (MD_PLN_FAST | FUNC3); //A4
73
  LPC_SCU->SFSP1_0 = (MD_PLN_FAST | FUNC2);  //A5
74
  LPC_SCU->SFSP1_1 = (MD_PLN_FAST | FUNC2);  //A6
75
  LPC_SCU->SFSP1_2 = (MD_PLN_FAST | FUNC2);  //A7
76
  LPC_SCU->SFSP2_8 = (MD_PLN_FAST | FUNC3);  //A8
77
  LPC_SCU->SFSP2_7 = (MD_PLN_FAST | FUNC3);  //A9
78
  LPC_SCU->SFSP2_6 = (MD_PLN_FAST | FUNC2);  //A10
79
  LPC_SCU->SFSP2_2 = (MD_PLN_FAST | FUNC2);  //A11
80
  LPC_SCU->SFSP2_1 = (MD_PLN_FAST | FUNC2);  // A12
81
  LPC_SCU->SFSP2_0 = (MD_PLN_FAST | FUNC2);  //A13
82
  LPC_SCU->SFSP6_8 = (MD_PLN_FAST | FUNC1);  //A14
83
  LPC_SCU->SFSP6_7 = (MD_PLN_FAST | FUNC1);  // A15
84
  LPC_SCU->SFSPD_16= (MD_PLN_FAST | FUNC2);  // A16
85
  LPC_SCU->SFSPD_15= (MD_PLN_FAST | FUNC2);  // A17
86
  LPC_SCU->SFSPE_0 = (MD_PLN_FAST | FUNC3);  // A18
87
  LPC_SCU->SFSPE_1 = (MD_PLN_FAST | FUNC3);  // A19
88
  LPC_SCU->SFSPE_2 = (MD_PLN_FAST | FUNC3);  // A20
89
  LPC_SCU->SFSPE_3 = (MD_PLN_FAST | FUNC3);  // A21
90
  LPC_SCU->SFSPE_4 = (MD_PLN_FAST | FUNC3);  // A22
91
  LPC_SCU->SFSPA_4 = (MD_PLN_FAST | FUNC3);  // A23*/
92
93
  LPC_SCU->SFSP1_3 = (MD_PLN_FAST | FUNC3);  // OE
94
  LPC_SCU->SFSP1_6 = (MD_PLN_FAST | FUNC3);  //WE
95
  LPC_SCU->SFSP1_4 = (MD_PLN_FAST | FUNC3);  // BLS0
96
  LPC_SCU->SFSP6_6 = (MD_PLN_FAST | FUNC1);  // BLS1
97
  LPC_SCU->SFSPD_13 = (MD_PLN_FAST | FUNC2);  // BLS2
98
  LPC_SCU->SFSPD_10 = (MD_PLN_FAST | FUNC2);  // BLS3
99
  LPC_SCU->SFSP1_5 = (MD_PLN_FAST | FUNC3);  // CS0
100
  LPC_SCU->SFSP6_3 = (MD_PLN_FAST | FUNC3);  // CS1
101
  LPC_SCU->SFSPD_12 = (MD_PLN_FAST | FUNC2);  // CS2
102
  LPC_SCU->SFSPD_11 = (MD_PLN_FAST | FUNC2);  // CS3
103
  LPC_SCU->SFSP6_4 = (MD_PLN_FAST | FUNC3);  //CAS
104
  LPC_SCU->SFSP6_5 = (MD_PLN_FAST | FUNC3);  //RAS
105
  LPC_SCU->SFSCLK_0 = (MD_PLN_FAST | FUNC0);  //CLK0
106
  LPC_SCU->SFSCLK_1 = (MD_PLN_FAST | FUNC0);  //CLK1
107
  LPC_SCU->SFSCLK_2 = (MD_PLN_FAST | FUNC0);  //CLK2
108
  LPC_SCU->SFSCLK_3 = (MD_PLN_FAST | FUNC0);  //CLK3
109
  LPC_SCU->SFSP6_9 = (MD_PLN_FAST | FUNC3);  //DYCS0
110
  LPC_SCU->SFSP6_1 = (MD_PLN_FAST | FUNC1);  // DYCS1
111
  LPC_SCU->SFSPD_14 = (MD_PLN_FAST | FUNC2);  // DYCS2
112
  LPC_SCU->SFSPE_14 = (MD_PLN_FAST | FUNC3);   // DYCS3
113
  LPC_SCU->SFSP6_11 = (MD_PLN_FAST | FUNC3); //CKE0
114
  LPC_SCU->SFSP6_2 = (MD_PLN_FAST | FUNC1);   // CKEOUT1
115
  LPC_SCU->SFSPD_1 = (MD_PLN_FAST | FUNC2);   // CKEOUT2
116
  LPC_SCU->SFSPE_15 = (MD_PLN_FAST | FUNC3);   // CKEOUT3
117
  LPC_SCU->SFSP6_12 = (MD_PLN_FAST | FUNC3);  //DQMOUT0
118
  LPC_SCU->SFSP6_10 = (MD_PLN_FAST | FUNC3);  //DQMOUT1
119
  LPC_SCU->SFSPD_0 = (MD_PLN_FAST | FUNC2);   //DQMOUT2
120
  LPC_SCU->SFSPE_13 = (MD_PLN_FAST | FUNC3);  //DQMOUT3
121
  //
122
  // Setup EMC config for SDRAM, timings for 72MHz bus => 13,9ns
123
  // SDRAM: MT48LC4M32B2 on Keil MCB1857 Board
124
  //
125
  LPC_EMC->DYNAMICCONFIG0    = 0x00004500; //128Mb, 4Mx32, 4 banks, 12 rows, 8 columns
126
  
127
  LPC_EMC->DYNAMICRP         = 0x1;    // tRP = n + 1 clock cycles # min. 18ns
128
  LPC_EMC->DYNAMICRAS        = 0x3;    // tRAS = n + 1 clock cycles # min. 42ns
129
  LPC_EMC->DYNAMICSREX       = 0x5;    // tSREX = tXSR = n + 1 clock cycles # min. 70ns
130
  LPC_EMC->DYNAMICAPR        = 0x1;    // no tAPR => using tRCD = n + 1 clock cycles # min. 18ns
131
  LPC_EMC->DYNAMICDAL        = 0x5;    // tDAL = n clock cycles  # 5Cks = min. 30ns
132
  LPC_EMC->DYNAMICWR         = 0x1;    // tWR = n + 1 clock cycles  # min. 12ns
133
  LPC_EMC->DYNAMICRC         = 0x4;    // tRC = n + 1 clock cycles # min. 60ns
134
  LPC_EMC->DYNAMICRFC        = 0x4;    // tRFC = n + 1 clock cycles # min. 60ns
135
  LPC_EMC->DYNAMICXSR        = 0x4;   // tXSR = n + 1 clock cycles # min. 60ns
136
  LPC_EMC->DYNAMICRRD        = 0x1;    // tRRD = n + 1 clock cycles # min. 12ns
137
  LPC_EMC->DYNAMICMRD        = 0x1;    // tMRD = n + 1 clock cycles # 2CKs = min. 12ns
138
  //emc_WaitMS(200);
139
  LPC_EMC->DYNAMICCONTROL    = 0x00000183;
140
  emc_WaitMS(100);
141
  LPC_EMC->DYNAMICCONTROL    = 0x00000103;
142
  LPC_EMC->DYNAMICREFRESH    = 0x00000002;  // n * 16 clock cycles
143
  //for (i = 0; i < 0x80; i++);               // Wait 128 AHB clock cycles
144
  emc_WaitMS(100);
145
  LPC_EMC->DYNAMICREFRESH    = 50;  // n * 16 clock cycles (~ 1 pro MHz)
146
  LPC_EMC->DYNAMICRASCAS0    = 0x00000202;
147
  LPC_EMC->DYNAMICCONFIG0    = 0x00004500;
148
  //emc_WaitUS(200);
149
  //
150
  // Init SDRAM
151
  //
152
  LPC_EMC->DYNAMICCONTROL    = 0x00000083;// CLock Enable = driven HIGH, CLKOUT runs continously, Issue MODE command
153
  Dummy = *((volatile U32*)(SDRAM_BASE_ADDR | (0x22 << (2+8+2))));  // 4 burst, 2 CAS latency
154
  Dummy = Dummy;
155
  //for (i = 0; i < 0x80; i++);
156
  LPC_EMC->DYNAMICCONTROL = 0x00000000;//NORMAL;                             // Issue NORMAL command
157
  LPC_EMC->DYNAMICCONFIG0 = 0x00084500;//128Mb, 4Mx32, 4 banks, 12 rows, 8 columns, buffer enable
158
  }

Ich will den SDRAM mit emWin nutzen. Rufe _EMC_Init() in der HWConf.c 
unter _low_level_init() auf.

Wenn ich die .GUI_RAM section im RamLoc32 lasse, dann läuft es und ich 
bekomme etwas auf dem Display angezeigt. Will ich aber nun die section 
in den SDRAM verlinken, dann funktioniert es nicht mehr.


Reicht es im Linker script aus, wenn ich den Eintrag wie folgt mache?
(Ich nutze LPCXpresso IDE)

in der ...mem.ld-Datei
1
MEMORY
2
{
3
  /* Define each memory region */
4
  MFlashA512 (rx) : ORIGIN = 0x1a000000, LENGTH = 0x80000 /* 512k */
5
  MFlashB512 (rx) : ORIGIN = 0x1b000000, LENGTH = 0x80000 /* 512k */
6
  RamLoc32 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000 /* 32k */
7
  RamLoc40 (rwx) : ORIGIN = 0x10080000, LENGTH = 0xa000 /* 40k */
8
  RamAHB32 (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 /* 32k */
9
  RamAHB16 (rwx) : ORIGIN = 0x20008000, LENGTH = 0x4000 /* 16k */
10
  RamAHB_ETB16 (rwx) : ORIGIN = 0x2000c000, LENGTH = 0x4000 /* 16k */
11
  SDRAM (rwx) : ORIGIN = 0x28000000, LENGTH = 0x01000000 /* 16M */
12
13
}
14
  /* Define a symbol for the top of each memory region */
15
  __top_MFlashA512 = 0x1a000000 + 0x80000;
16
  __top_MFlashB512 = 0x1b000000 + 0x80000;
17
  __top_RamLoc32 = 0x10000000 + 0x8000;
18
  __top_RamLoc40 = 0x10080000 + 0xa000;
19
  __top_RamAHB32 = 0x20000000 + 0x8000;
20
  __top_RamAHB16 = 0x20008000 + 0x4000;
21
  __top_RamAHB_ETB16 = 0x2000c000 + 0x4000;
22
  __top_SDRAM = 0x28000000 + 0x1000000;

und in der .ld-Datei
1
          ...
2
/* MAIN BSS SECTION */
3
    .bss : ALIGN(4)
4
    {
5
        _bss = .;
6
        *(.bss*)
7
        *(COMMON)
8
        . = ALIGN(4) ;
9
        _ebss = .;
10
        PROVIDE(end = .);
11
    } > RamLoc32
12
    
13
    .GUI_RAM (NOLOAD): ALIGN(4)        /* hier ist mein Eintrag */
14
    {
15
      *(.GUI_RAM)
16
    } > SDRAM 
17
        
18
    /* NOINIT section for RamLoc40 */
19
    .noinit_RAM2 (NOLOAD) : ALIGN(4)
20
    {
21
      *(.noinit.$RAM2*)
22
      *(.noinit.$RamLoc40*)
23
       . = ALIGN(4) ;
24
    } > RamLoc40 
25
    /* NOINIT section for RamAHB32 */
26
    .noinit_RAM3 (NOLOAD) : ALIGN(4)
27
    {
28
      *(.noinit.$RAM3*)
29
30
            ...

Habe ich irgendeine Einstellung oder Anpassung beim Portieren vergessen 
bzw. übersehen?

Kann mir vielleicht jemand helfen oder bestätigen, dass die 
Initialisierungsfunktion bzw. der Aufruf im Linker-script in Ordnung 
sind?

Gruß Martin

von Arne (Gast)


Lesenswert?

Zum Code kann ich nix sagen, aber Warteroutinen wie oben durchzuführen 
ist m.E. nach "bäääähhh".
Warum nimmst Du nicht den M3 internen Cyclecounter?

von Martin (Gast)


Lesenswert?

Guten Morgen Arne,

der Cyclecounter sagt mir noch gar nichts oder meinst du damit den 
Systick? Ich wollte die Warteroutine sowieso noch auf Systick 
umstricken. Das werd ich wahrscheinlich gleich mal machen. An irgendwas 
muss es ja liegen..

von Arne (Gast)


Lesenswert?

Nein.. nicht den Systick (wobei Du beim LPC18xx ja auch noch den RIT 
hättest). Ich meine den Cyclecounter, den jeder M3 im Kern haben sollte 
und der mit jedem ALU Clock inkrementiert wird (wie z.B. m.W. auch ab 
Pentium P5). Ist im M3 ein 32bit Counter.
Ich schalte an 0xE000EDFC Bit 24 ein und an 0xE0001000 Bit 0 und Bit 12.
Der Counterwert liegt an 0xE0001004.
Zieh dir mal 
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0337i/DDI0337I_cortexm3_r2p1_trm.pdf
Dort Kap.8.2. Ich hab mir da ein kleines API herum gebastelt.

von Martin (Gast)


Lesenswert?

Hab mir jetzt mal den Cycle Counter angeschaut. Das klingt ja schon mal 
nicht schlecht. Wie gehe ich dann mit dem Counterwert um?
Ich verwende einen 72MHz Systemtakt. Also muss der Counter bis 72 
zählen, damit ich 1 µs erhalte. Jetzt kann ich ja ein Tap bei Bit 6 oder 
10 festlegen. So wie ich das verstanden habe, zählt, sobald CYCCNT 
dieses Tap-Bit erreicht hat, der POSTCNT ein Bit runter.
Der Anfangswert von POSTCNT wird mit POSTPRESET festgelegt. Wenn der 
Countdown (POSTCNT) == 0 ist, dann wird ein PC Sample Event ausgelöst.

Damit kann ich aber meinen Zählwert von 72 nicht realisieren (nur mit 
einem gewissen Fehler)(da Tap-Bit 6 = 64 und Tap-Bit 10 = 1024 ist).
Also kann ich mir doch das ganze so vorstellen, als ob das Tap-Bit für 
den Prescaler steht - Prescaler 64 oder 1024 !?

Will ich 1 ms haben, dann muss der Counter bis 72000 zählen. Jetzt kann 
ich das Bit 6 als Tap-Bit wählen und den POSTPRESET mit 1125 vorladen. 
Das PC Sample Event gibt mir dann die Millisekunde an.

Arne, wie hast du das gelöst?

von Arne (Gast)


Lesenswert?

Sicher, dass Du da nicht was verkomplizierst?
1. setze das TCRA Bit: Schreibe (1 << 12) in 0xE000EDFC
2. lass den Counter loslaufen: schreibe ((1u << 12u) | (1u << 0)) an 
0xE0001000
3. lese für Zeitmessungen 0xE0001004 als uint32_t aus.

Jetzt kannst Du Dir eine Wait Funktion basteln oder eine 
wieviele-Ticks-sind-seit-Zeitstempel-x-vergangen Funktion. Umrechnen von 
Ticks in µs und zurück kannst Du ja generisch machen, so dass das immer 
funktioniert, egal welcher Takt an der ALU anliegt.

von Arne (Gast)


Lesenswert?

Fehler vom Amt.
Es muss heißen:
1. setze das TCRA Bit: Schreibe (1 << 24) in 0xE000EDFC

Bau mal so eine Warteschleife von 1s Blinktakt:
1
while(1) {
2
    LED_ON();
3
    Wait(72000000); /* warte 72Mio clocks = 1s */
4
    LED_OFF();
5
    Wait(72000000); /* warte 72Mio clocks = 1s */
6
}
Häng ein Oszi an die LED und schaue, ob die Flanken schön mit 1s kommen.
Sollte klappen.

von Martin (Gast)


Lesenswert?

Hi Arne,

ja das klappt auch super!! Danke für deine Tips. Den Timer zu 
realisieren ist ja wirklich nicht ganz so kompliziert, wenn man es mal 
gemacht hat. Für Werte im Millisekundenbereich bekomme ich auch relativ 
genaue Zeiten hin, aber im 100µs-Bereich und darunter macht sich der 
Fehler bemerkbar.

Hier mal mein Code:
1
#define CoreClock 72000000
2
3
/* ========== Debug Watchpoint Timer - DWT ============ */
4
#define DWT_CTRL   *((volatile unsigned long *) (0xE0001000))  
5
#define DWT_CYCCNT   *((volatile unsigned long *) (0xE0001004))  
6
#define DWT_ENABLE   *((volatile unsigned long *) (0xE000EDFC))  
7
8
void emc_WaitUS(volatile uint32_t us)
9
{
10
  DWT_ENABLE |= (1 << 24);          //enable DWT
11
  DWT_CTRL = (1 << 12) | (1 << 0);      //Bit 0:  Enable CYCCNT
12
                       
13
  DWT_CYCCNT = 0;
14
  while (DWT_CYCCNT < ((CoreClock/1000000)*us));
15
}
16
17
void emc_WaitMS(volatile uint32_t ms)
18
{
19
  DWT_ENABLE |= (1 << 24);          //enable DWT
20
  DWT_CTRL = (1 << 12) | (1 << 0);      //Bit 0:  Enable CYCCNT
21
                          
22
  DWT_CYCCNT = 0;
23
  while (DWT_CYCCNT < ((CoreClock/1000)*ms));
24
}

Liegt der Fehler im µs-Bereich am DWT Timer oder eher an meinem Code 
(der WHILE-Schleife)?

Ich werde morgen gleich mal den EMC mit dem Timer testen.

Glaube aber, dass das nicht das eigentliche Problem ist. Muss ich 
eigentlich beim Einbinden des externen Speichers im Startup-Code etwas 
ändern oder reicht die Änderung im Linker-Script?

von Arne (Gast)


Lesenswert?

Bei den Warteschleifen kommt es ja i.d.R. nur darauf an eine Mindestzeit 
nicht zu unterschreiten. Dafür ist das Ding ganz nützlich.

von Martin (Gast)


Lesenswert?

Hi Arne,

hab es jetzt hinbekommen, die _EMC_Init() wurde an der falschen Stelle 
aufgerufen. Hab jetzt die _low_level_init() in die startup-Datei 
integriert (wie im emWin_EA1788_BSP), sodass der EMC vor der main() 
initialisiert wird.

Dann habe ich die Initialisierung noch mal fein abgestimmt und für die 
Wartezeiten den Cycle Counter verwendet. Jetzt gehts... :-)

VIELEN DANK!!! :-)

von Heiner (Gast)


Lesenswert?

Na dann kannst Du Dich ja jetzt an den RAM-Test wagen:
http://www.barrgroup.com/Embedded-Systems/How-To/Memory-Test-Suite-C

Dass EMC_Init() vor dem Kopieren des DATA Segmentes in das SDRAM und 
auch vor dem Ausnullen des BSS geschehen muss war schon klar, oder?

Ansonsten hast Du das von mir eingangs erwähnte "Henne-Ei" Problem.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.