LPC1857 ARM Cortex M3 Problem mit EMC und SDRAM

Gast #3194166
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
Angehängte Dateien:
Gast #3194369
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
Gast #3194419
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...
Gast #3194623
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.
Gast #3194718
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.
Gast #3194846
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.
Gast #3195519
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??
Gast #3202747
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
Gast #3203019
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..
Gast #3203038
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.
Gast #3203408
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?
Gast #3206025
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.
Gast #3206028
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.
Gast #3206950
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?
Gast #3207515
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!!! :-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren