ARM Cortex M0 system timer

#4492247
Lesenswert?

chris_ schrieb:

> Wenn ich es richtig verstehe, sind die Adressen über alle M0 fest
> vergeben:
> SysTick Control and Status : 0xE000E010
Da es sich um ein Feature des Cores handelt ist das anzunehmen.
Aber wer arbeitet denn mit der Adresse? Die sind alle per CMSIS 
definiert.

> Gibt es irgendwo Beispiel für die Konfiguration?
Bei Google massenhaft. Auch das Datenblatt dürfte sich darüber nicht 
ausschweigen.
Im Prinzip setzt du nur den Compare-Wert für den Interrupt und die 
ClockSource.
Gast #4492263
Lesenswert?

>Ansonsten findest Du die Beispiele typischerweise bei den
>Prozessorherstellern, die diesen Cortex implementieren.

Ja, das ist genau das Problem: Meine Hauptbeschäftigung ist momentan das 
Kämpfen mit den Tools.

Ich verwende gerade ASF und vorher AtmelSTART, beide sind scheinbar 
nicht kompatibel.

Mittlerweile habe ich das Modul in der ASF Konfiguration gefunden:

ASF-Modul: Delay routines ( service ) systick
Gast #4492270
Lesenswert?

Wenn ich mir die Routinen dort anschaue
1
void delay_init(void)
2
{
3
  cycles_per_ms = system_gclk_gen_get_hz(0);
4
  cycles_per_ms /= 1000;
5
  cycles_per_us = cycles_per_ms / 1000;
6

7
  SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
8
}
9

10
/**
11
 * \brief Delay loop to delay at least n number of microseconds
12
 *
13
 * \param n  Number of microseconds to wait
14
 */
15
void delay_cycles_us(
16
    uint32_t n)
17
{
18
  while (n--) {
19
    /* Devide up to blocks of 10u */
20
    delay_cycles(cycles_per_us);
21
  }
22
}
23

24
static inline void delay_cycles(
25
    const uint32_t n)
26
{
27
  if (n > 0) {
28
    SysTick->LOAD = n;
29
    SysTick->VAL = 0;
30

31
    while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)) {
32
    };
33
  }
34
}

dann sehe ich, dass der Systemcounter beim Aufruf des Delays auf Null 
gesetzt wird.

Mal ehrlich: wie bescheuert ist das denn? Der Systemcounter soll 
durchlaufen und nicht auf Null gesetzt werden.
So viel zu fertigen Libraries.
Moderator Persönliche Seite #4492296
Lesenswert?

Won K. schrieb:
> Das könnte daran liegen, daß das eine Delay-Routine und kein
> Systemcounter ist.

Systick ist aber per definitionem der Systemcounter.  Den setzt man
nicht für ein blödes Delay einfach auf 0.

Mein Rat an chris_: ASF ist (meine Meinung) ein aufgeblähter Sack
voller Makros und Funktionen.  Da gibt es Funktionen, die gerade mal
irgendein Bit in einem Steuerregister setzen oder löschen.  Ansonsten
ist das bloß obfuscation, was da betrieben wird.

Man kann den ASF-Code hin und wieder nehmen um mal reinzugucken, wie
sie dieses oder jenes Problem lösen.  Man kann auch ein paar Dinge,
die im Windschatten des ASF mitgeschleift werden (wie USB-Stacks
oder die FAT-FS Implementierung, die letztlich die von elmchan ist),
gut und gern in seinen Code integrieren.

Ansonsten kommst du aber besser, wenn du den Controller einfach vom
Datenblatt her verstehen lernst.  Ist ein bisschen komplexer als ein
AVR, aber nicht unendlich komplex.  Fang mit der blinkenden LED an,
also mit dem Beherrschen der Parallelports.  Wenn du das geschafft
hast, schau dir an, wie man die Systemtakte einstellt.  Das ist bei
SAMDxx mit seinen generic clocks erstmal ein Stück Arbeit, aber wenn
man das verstanden hat, ist man ein ganzes Stück weiter.

Irgendwo habe ich hier auch schon mal Codeschnipsel von mir gepostet,
als ich mich durch den SAMD20 gewühlt habe.  Kannst du als Anfang
nehmen.
Gast #4492662
Lesenswert?

Jörg W. schrieb:
> Ansonsten kommst du aber besser, wenn du den Controller einfach vom
> Datenblatt her verstehen lernst.

Endlich mal ein Satz, bei dem ich dir aus VOLLSTEM HERZEN zustimme. 
Den Beitrag von cyblord wegen CMSIS halte ich hingegen für weniger 
sinnvoll. Das CMSIS-Geprassel ist zwar nicht ganz so hirnrissig wie die 
ST-Lib, aber immer noch ein eigentlich unnützer Sack voll Obfuscation.

So.
1
/* SCS_BA = 0xE000E000 */
2
/* Sysem Tick */
3
#define SYST_CSR        (*((volatile unsigned long *) (SCS_BA+0x00000010)))
4
#define SYST_RVR        (*((volatile unsigned long *) (SCS_BA+0x00000014)))
5
#define SYST_CVR        (*((volatile unsigned long *) (SCS_BA+0x00000018)))
6

7
/* initialisiert den SysTick mit 10 ms Tickzeit */
8
void InitSystick (void)
9
{ long L;
10
  L = Quarzfrequenz / 100;  // sollte 10 ms ergeben
11
  SYST_CVR = SYST_RVR = L;
12
  System_Tick = Ticks = Stunden = Minuten = Sekunden = 0;
13
  SYST_CSR = ENA_TICK_INT | ENA_SYSTICK;
14
}
15

16
/******* Interrupt vom SysTick-Counter *************/
17

18
__irq void SysTick_Handler (void)
19
{ SYST_CSR &=  ~(COUNTFLAG);
20
  ++System_Tick;
21
  ++Ticks;               /* Uhrzeit weiterstellen */
22
  if (Ticks >= 100)
23
  { ++Sekunden;
24
    if (Sekunden>59)
25
    { Sekunden = 0;
26
      ++Minuten;
27
      if (Minuten>59)
28
      { Minuten = 0;
29
        ++Stunden;
30
      }
31
    }
32
    Ticks = 0;
33
  }
34
}

Da der Systick Teil der CPU-Konstruktion von ARM ist und eben keine 
drangebeppte Peripherie eines Chipherstellers, sollte das auch so wie 
dargestellt klappen (Beispiel stammt aus ner Nuvoton-M051-Kiste).

Aber:

Der Systick ist m.W. ein Downcounter, dessen tieferer Zweck darin 
besteht, Interrupts für Uhr/RTOS auszulösen. Er ist kein Zähler für 
Mikrosekunden. Wer sowas brauchen will, sollte sich was anderes 
ausdenken, z.B. einen Timer.

W.S.
Gast #4492682
Lesenswert?

chris_ schrieb:

> Ich brauche die Zeit in Mikrosekunden vom Systemstart an.

Manche Cortex-M haben ein Debug Modul namens DWT (Data Watchpoint and 
Trace). Da gibt's das Cycle Count Register DWT_CYCCNT (0xE0001004), das 
die CPU-Zyklen zählt. Perfekt ist es auch nicht, weil man es einschalten 
muss, aber immer noch besser als der SysTick.

siehe: ARM® v7-M Architecture Reference Manual
Gast #4500372
Lesenswert?

Jörg Wunsch
>Mein Rat an chris_: ASF ist (meine Meinung) ein aufgeblähter Sack
>voller Makros und Funktionen.  Da gibt es Funktionen, die gerade mal
>irgendein Bit in einem Steuerregister setzen oder löschen.  Ansonsten
>ist das bloß obfuscation, was da betrieben wird.

Ja, ich komme immer mehr dazu, Deinem Rat zu folgen.

while(1)
{
  gpio_set_pin_level(LED,  0);
  gpio_set_pin_level(LED,  1);
}

Ergibt

2.5 us HIGH
1.86 us LOW

auf einem 48Mhz ATSAMD21G18.

Das sind ja ähnlich schlechte Zeiten wie bei der ARDUINO-Funktion 
digitalWrite.

Mache ich etwas falsch, oder ist die ASF so langsam?
Gast #4500395
Lesenswert?

>Bei welchem Takt ist das denn?

Jetzt wo Du es sagst ...

Ich habe das System mit AtmelSTART hier konfiguriert:

Beitrag "Re: Arduino Zero mit ArduinoStart Konfigurieren"

Die "Clock-Distribution" ist mir da nicht ganz klar. Ich glaube, die MCU 
läuft mit 8MHz.

( Wer's ausprobieren will: einfach die angegebene Konfiguration in den 
WebBrowser laden. Es gibt dann einen Tab, in dem die Clock-Verteilung 
angezeigt wird )
Moderator Persönliche Seite #4500430
Lesenswert?

chris_ schrieb:
> Ich kann Dir die Konfiguration zeigen ...

Dein Prozessor wird sicher keine bunten Bildchen ausführen, ich
möchte schon den Sourcecode dafür sehen. ;-)

p.s.: Für 8 MHz wären die Werte nicht so prickelnd, aber es würde
mich nicht wundern, wenn das dann der Overhead von ASF ist.

Ein ARM ist kein AVR, der innerhalb eines CPU/IO-Taktes ein Pin
setzen oder löschen kann, aber ein wenig schneller könnte er schon
sein.
Gast #4500617
Lesenswert?

Jörg W. schrieb:
> Ein ARM ist kein AVR, der innerhalb eines CPU/IO-Taktes ein Pin
> setzen oder löschen kann

Selbstverständlich gibt es ARM die das können z.B. ein LPC800 mit 30 MHz 
verwendet die CPU Clock direkt als Peripheral Clock und hat 
bit-addressierbare GPIO-Register (kein Bit-banding). Damit kommen auch 
30 MHz raus (kein sauberes Rechteck mehr allerdings)

        MOVS R0, #0
        MOVS R1, #1
loop
        STRB R0, [PIN0BASE, #0]       ; clear P0.0
        STRB R1, [PIN0BASE, #0]       ; set P0.0
        B    loop

Nebenbei bemerkt, ich habe hier einen 72 MHz 8051 EFM8LB, der kann Pins 
mit 72 MHz toggeln. Wenn man das also braucht ...
Moderator Persönliche Seite #4500635
Lesenswert?

Lothar schrieb:
> Selbstverständlich gibt es ARM die das können z.B. ein LPC800 mit 30 MHz
> verwendet die CPU Clock direkt als Peripheral Clock und hat

Wenn ich mir dein Beispiel ansehe, sollte das mit dem SAMDxx auch
so (ähnlich) gehen.  Auch er kann CPU und Peripheral Clock bis
maximal 48 MHz synchron takten.

> Damit kommen auch
> 30 MHz raus (kein sauberes Rechteck mehr allerdings)

Glaube ich dir nicht. :-)

Mit 30 MHz CPU-Takt kannst du in Software maximal 15 MHz am Ausgang
erzeugen, da du zwei Befehle für eine volle Signalperiode brauchst. ;-)
(Das ist noch ohne den Schleifenbefehl.)

SAMDxx hat auch ein Pin-Toggle-Register, damit könnte man sogar einen
symmetrischen Rechteck bauen (ein store und ein branch).  Hat der TE
aber nicht benutzt.
Gast #4500691
Lesenswert?

>Dein Prozessor wird sicher keine bunten Bildchen ausführen, ich
>möchte schon den Sourcecode dafür sehen. ;-)

Hallo Jörg,

eigentlich bin ich ein Freund der bunten Bildchen, oder wie einer der 
Softwarearchitekten mal sagte:

"Ein Bild sagt mehr als tausend Worte"

Man kann direkt dieses File nehmen

http://www.mikrocontroller.net/attachment/285487/ArduinoZero_ADC_SERIAL_EXAMPLE.atstart

Dann in AtmelSTART laden ( => load project links unten )
http://start.atmel.com/

Deshalb ist es ja mehr als ein Bild. Man kann direkt konfigurieren. 
Scheinbar per trag&drop. Ich schaffe es, damit den 8MHz internal Clock 
mit der PLL zu verbinden. Aber das Ganze sieht dann irgendwie nach 
"zirkulärem" Kurzschluss aus.
Moderator Persönliche Seite #4500713
Lesenswert?

chris_ schrieb:

> eigentlich bin ich ein Freund der bunten Bildchen

Ich nicht, weil die CPU eben keine Bilder ausführt.

Das Ding ist doch nur ASF 2.0.  Alles, was hinter den Bildchen
passiert, sind wieder blackboxes.  Da merkst du beispielsweise nicht,
dass der dort benutzte delay-Kram dir den SysTick-Timer zerschießt
(für jedes delay() wird der neu auf 0 gesetzt, was völlig tödlich
ist, wenn du den noch anderweitig nehmen willst).

Wie ich oben schon schrieb: das ist kein AVR mehr, aber das ist auch
kein ARMv11 oder sowas.  Die Details der Hardware kann man schon noch
verstehen bei diesen kleinen ARMs.  Bei den größeren benutzt man dann
ein Betriebssystem und verlässt sich drauf, dass die OS-Hersteller
ihre Arbeit ordentlich getan haben.  Dann benutzt man aber die
Hardware nicht mehr direkt, sondern nur noch über das API des OSes.

Klar kann man nun diesen Atmel-START-Kram als „Mini-OS“ betrachten,
aber ehrlich: dann kannst du lieber Arduino als API nehmen, das ist
zumindest inzwischen hinreichend gut in der Praxis erprobt.
Gast #4500785
Lesenswert?

Jörg W. schrieb:
> Mit 30 MHz CPU-Takt kannst du in Software maximal 15 MHz am Ausgang

Hast recht.

> SAMDxx hat auch ein Pin-Toggle-Register

Hat der LPC800 auch, das ist aber nicht schneller weil z.B. für P0.4:

        MOVS R0, #10000B
loop
        STR  R0, [NOT0]
        B    loop

Aber wenn wir schon bei Bildern sind, mach doch mal Messungen am SAMDxx, 
habe gehört dort soll der Zugriff auf Pin-Toggle-Register zwei Zyklen 
dauern
Moderator Persönliche Seite #4500801
Lesenswert?

Lothar schrieb:
> Aber wenn wir schon bei Bildern sind, mach doch mal Messungen am SAMDxx,
> habe gehört dort soll der Zugriff auf Pin-Toggle-Register zwei Zyklen
> dauern

Geht zumindest erstmal nicht aus dem Datenblatt hervor.

Was mir beim Lesen auffällt ist, dass man DIR, IN und OUT auch
direkt über den IOBUS der CPU lesen oder schreiben kann (braucht
aber eine andere IO-Adresse).  Das wäre allerdings nur dann schneller,
wenn man den CLK_PORT_APB langsamer konfiguriert hat als den CPU-Takt.

Muss mal gucken, wenn ich meinen SAMD20 mal wieder in den Fingern
habe, kann ich das mal testen.
Gast #4501383
Lesenswert?

>> Mit 30 MHz CPU-Takt kannst du in Software maximal 15 MHz am Ausgang

>Hast recht.

>> SAMDxx hat auch ein Pin-Toggle-Register

>Hat der LPC800 auch, das ist aber nicht schneller weil z.B. für P0.4:
>
>        MOVS R0, #10000B
>loop
>        STR  R0, [NOT0] % 1 cycle ?
>        B    loop       % 2 cycles ?

Wie das? Loop unrolling?
#4501450
Lesenswert?

chris_ schrieb:
> Hier die neue Konfiguration:
> http://www.mikrocontroller.net/attachment/286592/FastCpuClockSetup_48MHz.atzip
>
> Rein optisch sieht das Ganze in AtmelSTART etwas verworren aus:
>
> interner 8MHz Clock => Clock Generator 1 ==> PLL 48MHz ==>
> Clock-Generator 0 ==> CPU-Clock
>
> Warum das Ganze so kompliziert sein muss, weiß ich nicht.

Ja da lob ich mir die grafische Darstellung im CubeMX. Da ist der 
Clocktree auch als Tree dargestellt und nebenbei praktisch genau so wie 
im Datenblatt. Absolut übersichtliche Sache.
Moderator Persönliche Seite #4501542
Lesenswert?

Cyblord -. schrieb:
> Da ist der Clocktree auch als Tree dargestellt und nebenbei praktisch
> genau so wie im Datenblatt.

Wie willst du etwas, was potenziell Rückführungen hat (wie im Bild
zu erkennen), als Baum darstellen?  Hast du schon mal Bäume gesehen,
die rückwärts wieder in sich hinein wachsen?

Das Diagramm ist so verkehrt nicht, allerdings helfen einem eben die
bunten Bildchen nicht darüber hinweg, wenn man die Grundsätze dieser
generischen Taktgeneratoren (GCLK) nicht verstanden hat.  Nun,
zumindest warnen sie einen offensichtlich sogar vor Missgriffen, wie
eben völlig übertakteten PLLs hier.  Man muss dann nur die Warnungen
auch noch beherzigen.
Gast #4501548
Lesenswert?

>Ja da lob ich mir die grafische Darstellung im CubeMX.

Hört sich gut an. Ich kenne CubeMX nicht, habe aber gerade mal gesucht:

STM32CubeMX: STM32Cube initialization code generator

Naja, für STM32. Ich habe leider einen SAMD20.
Gast #4501552
Lesenswert?

> Nun, zumindest warnen sie einen offensichtlich sogar vor Missgriffen,
> wie eben völlig übertakteten PLLs hier.

Das soll ja der große Vorteil dieser Konfigurationstools sein: Wenn sie 
geschickt gemacht sind, bewahren sie einem vor falscher Konfiguration 
und sorgen für eine gute Übersicht.

Ich bin ja sowieso der Meinung, dass die wesentliche Arbeit in der 
Informatik der Umgang mit schlecht gemachter Software oder Tools ist. Da 
hat sich in den letzten 3 Jahrzehnten nichts geändert.
Wie viele hundert Stunden habe ich schon mit der Konfiguration 
irgendwelcher Prozessorregister zugebracht? Ich weiß es nicht. Was ich 
aber weiß: ich bin es leid.

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