Forum: Mikrocontroller und Digitale Elektronik wait states ARM Cortex-M0


von Marvin0807 (Gast)


Lesenswert?

Hallo zusammen,

ich versuche einen LED-Streifen mit WS2812 LEDs zum Laufen zu bekommen. 
Dabei nutze ich die light_ws2812_ARM Bibliothek.

Ich bin den Anweisungen in der README-Datei gefolgt und die Anpassungen 
auf dem Mikrocontroller haben soweit funktioniert.
Allerdings leuchtet der Streifen nicht in der von mir gewünschten Farbe. 
Durch verschiedene Einstellungen an F_CPU und anschließende Messung mit 
einem Oszi vermute ich, dass dies mit den wait states zusammenhängt.

Wie kann ich die wait states auf 0 setzen?

Folgendes hat nicht funktioniert:

1.) Set FLASH access time in clocks

Chip_FMC_SetFLASHAccess( FLASHTIM_50MHZ_CPU )

2.) Place the function that writes the data into the main RAM region

 __RAMFUNC(RAM) void ws2812_sendarray(uint8_t *ledarray,int length);

Oder hatte jemand schon ein ähnliches Problem?

:
Beitrag #6270957 wurde von einem Moderator gelöscht.
von Stefan F. (Gast)


Lesenswert?

Marvin0807 schrieb:
> Wie kann ich die wait states auf 0 setzen?

Bei der STM32L0 und STM32F0 Serie ist das standardmäßig bereits 
deaktiviert.

SET_BIT(FLASH->ACR, FLASH_ACR_LATENCY); // 1 Wait state

CLEAR_BIT(FLASH->ACR, FLASH_ACR_LATENCY); // 0 Wait states

Der Flash Speicher fällt aber aus, denn du mit mehr als 24 MHz ohne 
Wait-State taktest.

Welchen Mikrocontroller verwendest du denn?

von PittyJ (Gast)


Lesenswert?

Ich hatte mal einen M0, bei dem mußte man die Waitstates hochsetzen, 
falls er mit 48 statt 32 MHz betrieben hat.
Stand ab Revision 1 dann auch im Handbuch.

Meistens sind die CPUs aber schnell genug. Daher vermute ich, dass der 
Programmierer nicht genau weiss, was er tut.

von MaWin (Gast)


Lesenswert?

PittyJ schrieb:
> Meistens sind die CPUs aber schnell genug.

Klar, aber die Wait States sind für die Peripherals, das Zeugs was an 
der superschnellen CPU hängt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

MaWin schrieb:
> aber die Wait States sind für die Peripherals

Nein, die sind für den Flash.

Das ist der langsamste Part überhaupt.

von MaWin (Gast)


Lesenswert?

Jörg W. schrieb:
> Nein, die sind für den Flash.

Der in der CPU wohnt, der direkt an die ALU getackert ist???

Ist der Speicher ist extern über einen BUS aun die CPU gekoppelt!

von Markus M. (adrock)


Lesenswert?

Doch, z.B. beim STM32F0 oder auch G0 muss man ab > 24MHz 1ws und > 48MHz 
2ws konfigurieren.

Mit dem CubeMX oder dem alten Excel-Makro Tool ("AN4055 Clock 
configuration tool for STM32F0xx microcontrollers") wird auch schon der 
Startup-Code entsprechend generiert, so dass die WS korrekt konfiguriert 
werden.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Markus M. schrieb:
> Doch

Ironie, Markus, Ironie ...

von Marvin S. (marvin0807)


Lesenswert?

auweia schrieb im Beitrag #6270957:
> Wer nicht voellig geistig behindert ist, schaut einfach im
> Referenzmanual des Controllers im Abschnitt "Flash" nach.
Wenn ich es gefunden hätte, würde ich hier nicht fragen..

Ich verwende den LPC11C24.

von Johannes S. (Gast)


Lesenswert?

In einem deiner vielen Threads zu der WS2812 Ansteuerung hatte ich 
schonmal geschrieben das der LPC die auch gut per SPI treiben kann, da 
entfällt die taktabhängige Zyklenzählerei.

Beitrag #6271709 wurde von einem Moderator gelöscht.
von Nop (Gast)


Lesenswert?

Marvin S. schrieb:

> Wenn ich es gefunden hätte, würde ich hier nicht fragen..

Guckst Du UM10398 Kapitel 3.12: 
http://www.keil.com/dd/docs/datashts/nxp/lpc11xx/lpc111x_lpc11cxx_um.pdf

Du setzt die Waitstates natürlich, BEVOR Du die Frequenz mittels PLL 
raufsetzt.

Was auch noch schiefgehen kann, ist die PLL umzukonfigurieren, während 
der Chip schon von der PLL läuft. Oder die PLL konfigurieren und 
aufzuschalten, ohne zu warten, bis sie überhaupt eingeschwungen ist.

von temp (Gast)


Lesenswert?

Ich habe beim LPC11C24 die Erfahrung gemacht, dass es auch eine Rolle 
spielt wie und wo der Code der delay() Routine am Ende im Flash steht. 
Das hat sicher mit den Caching-Stategien zu tun die es das auch gibt. 
Bei mir äußerte sich das so, dass die Zeiten des Delays sich bei 
manchmal nach Codeänderungen völlig verändert haben obwohl an der 
Routine selbst nichts gemacht wurde. Ich habe mir dann so geholfen:
1
// Microsecond delay loop-
2
void DelayuS(uint32_t uS)
3
{
4
  uint32_t CyclestoLoops;
5
6
  CyclestoLoops = SystemCoreClock<<1;
7
  if (CyclestoLoops >= 2000000) 
8
    {
9
    CyclestoLoops /= 1000000;
10
    CyclestoLoops *= uS;
11
    } 
12
  else
13
    {
14
    CyclestoLoops *= uS;
15
    CyclestoLoops /= 1000000;
16
    }
17
18
  if  (CyclestoLoops <= 100)
19
    return;
20
  
21
  CyclestoLoops -= 320; // cycle count for entry/exit should be measured
22
  CyclestoLoops /= 8;   // 
23
24
  if (!CyclestoLoops)
25
    return;
26
27
  // Delay loop for Cortex M3 thumb2
28
  // das align 4 ist extrem wichtig, sonst 
29
  // sind Unterschiede im faktor 2 möglich jenachdem
30
  // wie der Code erzeugt wird
31
  __asm volatile 
32
    (
33
    // Load loop count to register
34
    " mov r3, %[loops]\n"
35
    " .align 4\n"
36
    "loop: sub r3,#1   \n" 
37
    "      bne loop  \n\n"
38
39
    : // No output registers
40
    : [loops] "r" (CyclestoLoops) // Input registers
41
    : "r3" // clobbered registers
42
    );
43
}

Entscheidend war das .align 4\n im Assemblercode. Das schaffte dann 
Reproduzierbare Ergebnisse.

von Markus M. (adrock)


Lesenswert?

Grundsätzlich sollte man - wie schon oben erwähnt - grundsätzlich 
überdenken ob man die ws2812 nicht per SPI ansteuern möchte.

Ich finde dieses Bitbanging ist eine absolute Krücke die es eigentlich 
zu vermeiden gilt.

von Nop (Gast)


Lesenswert?

temp schrieb:
> if  (CyclestoLoops <= 100)
>     return;
>
>   CyclestoLoops -= 320; // cycle count for entry/exit should be measured

Ich würde die 100 oben durch 320 ersetzen. Falls 100 < CyclestoLoops < 
320, wird das sonst wegen wrap-around eine sehr lange Delay-Loop.

Beitrag #6271989 wurde von einem Moderator gelöscht.
Beitrag #6272120 wurde von einem Moderator gelöscht.
von Marvin S. (marvin0807)


Lesenswert?

Nop schrieb:
> Guckst Du UM10398 Kapitel 3.12:
> http://www.keil.com/dd/docs/datashts/nxp/lpc11xx/lpc111x_lpc11cxx_um.pdf
Genau das habe ich ja mit der unter 1.) aufgeführten Anweisung gemacht. 
Nur dass dies der originale Aufruf war, der die Frequenz auf 50MHz 
setzt.

So wie du auch geschrieben hast, wird zuerst die eben beschriebene 
Anweisung ausgeführt und dann mittels PLL auf 4* 12MHz erhöht.

An die Lösung mit SPI habe ich mich schon letztes Mal gemacht, nachdem 
ich davon gehört habe. Da hatte ich ein wenig Probleme durch eine zu 
große Lücke zwischen der Übertragung von aufeinanderfolgenden Bytes. Das 
ganze beruht auf dem Beispiel von LPCOpen. Nichtsdestotrotz hätte ich 
gerne die Bibliothek hier zum Laufen gebracht..

Die Anwedung dieser Delay-Funktion verstehe ich nicht ganz um ehrlich zu 
sein. Aber vielen Dank für das Bereitstellen des Quellcodes!

Beitrag #6272254 wurde von einem Moderator gelöscht.
von Johannes S. (Gast)


Lesenswert?

Marvin S. schrieb:
> Da hatte ich ein wenig Probleme durch eine zu
> große Lücke zwischen der Übertragung von aufeinanderfolgenden Bytes. Das
> ganze beruht auf dem Beispiel von LPCOpen.

LPCOpen baut da eventuell zuviel Sicherheit ein, oder arbeitet mit 
Interrupts? Ein WS Bit muss in 3 SPI Bits gesendet werden, macht 24 Bit. 
Die kann man in 2x12 Bit @ 2,4 MHz verschicken. Beim Senden Pollen ob 
das Statusregister ready sagt, dann einfach die Daten ins DR schreiben.

von temp (Gast)


Lesenswert?

Nop schrieb:
>> if  (CyclestoLoops <= 100)
>>     return;
>>
>>   CyclestoLoops -= 320; // cycle count for entry/exit should be measured
>
> Ich würde die 100 oben durch 320 ersetzen. Falls 100 < CyclestoLoops <
> 320, wird das sonst wegen wrap-around eine sehr lange Delay-Loop.

Da gebe ich dir völlig Recht.

von temp (Gast)


Lesenswert?

Markus M. schrieb:
> Grundsätzlich sollte man - wie schon oben erwähnt - grundsätzlich
> überdenken ob man die ws2812 nicht per SPI ansteuern möchte.
>
> Ich finde dieses Bitbanging ist eine absolute Krücke die es eigentlich
> zu vermeiden gilt.

Oder nimm ein Bluepill Board und schieb die Daten per DMA raus, das hab 
ich auch schon mal für 8 Kanäle gleichzeitig gemacht.

Beitrag #6272793 wurde von einem Moderator gelöscht.
Beitrag #6272803 wurde von einem Moderator gelöscht.
Beitrag #6272807 wurde von einem Moderator gelöscht.
Beitrag #6272910 wurde von einem Moderator gelöscht.
von Marvin S. (marvin0807)


Lesenswert?

Johannes S. schrieb:
> LPCOpen baut da eventuell zuviel Sicherheit ein, oder arbeitet mit
> Interrupts?

Es kann zwischen einem Polling- und einem Interrupt-Modus gewählt 
werden. So wie ich das sehe wird also in dem von mir gewählten Modus 
nicht mit Interrupts gearbeitet. Das Verhalten wurde auch schon hier 
beschrieben
https://community.nxp.com/thread/487020. Ich werde nun so wie du 
beschrieben hast versuchen direkt in das DR zu schreiben.

Zu dem anderen hätte ich aber trotzdem noch eine Frage.

Die entscheidenende Funktion in der ws_light Bibliothek sieht wie folgt 
aus:
1
void ws2812_sendarray(uint8_t *data,int datlen)
2
{
3
  uint32_t maskhi = ws2812_mask_set;
4
  uint32_t masklo = ws2812_mask_clr;
5
  volatile uint32_t *set = ws2812_port_set;
6
  volatile uint32_t *clr = ws2812_port_clr;
7
  uint32_t i;
8
  uint32_t curbyte;
9
10
  while (datlen--) {
11
    curbyte=*data++;
12
13
  asm volatile(
14
      "    lsl %[dat],#24        \n\t"
15
      "    movs %[ctr],#8        \n\t"
16
      "ilop%=:              \n\t"
17
      "    lsl %[dat], #1        \n\t"
18
      "    str %[maskhi], [%[set]]    \n\t"
19
#if (w1&1)
20
      ws2812_DEL1
21
#endif
22
#if (w1&2)
23
      ws2812_DEL2
24
#endif
25
#if (w1&4)
26
      ws2812_DEL4
27
#endif
28
#if (w1&8)
29
      ws2812_DEL8
30
#endif
31
#if (w1&16)
32
      ws2812_DEL16
33
#endif
34
      "    bcs one%=          \n\t"
35
      "    str %[masklo], [%[clr]]    \n\t"
36
      "one%=:                \n\t"
37
#if (w2&1)
38
      ws2812_DEL1
39
#endif
40
#if (w2&2)
41
      ws2812_DEL2
42
#endif
43
#if (w2&4)
44
      ws2812_DEL4
45
#endif
46
#if (w2&8)
47
      ws2812_DEL8
48
#endif
49
#if (w2&16)
50
      ws2812_DEL16
51
#endif
52
      "    sub %[ctr], #1        \n\t"
53
      "    str %[masklo], [%[clr]]    \n\t"
54
      "    beq  end%=          \n\t"
55
#if (w3&1)
56
      ws2812_DEL1
57
#endif
58
#if (w3&2)
59
      ws2812_DEL2
60
#endif
61
#if (w3&4)
62
      ws2812_DEL4
63
#endif
64
#if (w3&8)
65
      ws2812_DEL8
66
#endif
67
#if (w3&16)
68
      ws2812_DEL16
69
#endif
70
71
      "    b   ilop%=          \n\t"
72
      "end%=:                \n\t"
73
      :  [ctr] "+r" (i)
74
      :  [dat] "r" (curbyte), [set] "r" (set), [clr] "r" (clr), [masklo] "r" (masklo), [maskhi] "r" (maskhi)
75
      );
76
  }
77
}

Wie hat der User temp sich jetzt mit der Delay-Funktion beholfen? Bei 
ihm scheint die Sache ja auf dem gleichen Controller zu laufen...

von Marvin S. (marvin0807)


Lesenswert?

> Markus M. schrieb:
> Oder nimm ein Bluepill Board und schieb die Daten per DMA raus, das hab
> ich auch schon mal für 8 Kanäle gleichzeitig gemacht.
Ich brauch den Controller aktuell wegen einer anderen Funktionalität, 
aber ich werde es im Hinterkopf behalten:)

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.