Forum: Mikrocontroller und Digitale Elektronik Bare-Metal ATSAM


von Rudolph R. (rudolph)


Angehängte Dateien:

Lesenswert?

Gestern ist mir aufgefallen, dass auf dem Trinket M0 eine APA102 LED mit 
drauf ist, da ich mit so einem Ding sowieso rumspielen wollte, war das 
die Gelegenheit das Trinket M0 mal auszupacken. :-)

Da das Board aber keinen SWD Stecker hat (nur zwei Lötpads),
habe ich etwas im Arduino Framework rumgespielt mit Hilfe von vscode und 
PlatformIO.
Der Projekt-Ordner ist durch das PlatformIO etwas aufgebläht, daher 
hängt nur die .ino mit an.

Und tolle Dinger diese APA102, der SPI läuft hier gerade so mit 24MHz 
vor sich hin.

Als natives Projekt würde der Code um die APA102 LED zu beschreiben 
nicht anders aussehen.
Dazu kommen würde noch den Core-Takt auf 48MHz zu stellen und vielleicht 
den Systick Timer einzurichten um das Test-Blinken nicht per delay() zu 
machen.

Zum Zitieren hänge ich die paar Zeilen auch direkt mit in den Text.

- Was ist jetzt die Frage dazu?

Keine konkrete dazu.
Aber hast Du vielleicht noch mehr solche Beispiele?
Wie könnte man das um DMA erweitern?

- Warum ist das dann nicht unter "Projekte & Code"?

Das ist jetzt als Projekt für sich so etwas dünn und die Idee ist 
eigentlich noch mehr solche Schnipsel einzusammeln.
Die Beispiele für ATSAM ohne ASF sind etwas dünn gesäht...
Wenn ein Mod da jetzt anderer Meinung ist, bitte verschieben.

1
#include "sam.h"
2
3
void init_spi(void)
4
{
5
  /* configure SERCOM1 MOSI on PA00 and SERCOM1 SCK on PA01 */
6
  REG_PORT_WRCONFIG0 =
7
    PORT_WRCONFIG_WRPINCFG |
8
    PORT_WRCONFIG_WRPMUX |
9
    PORT_WRCONFIG_PMUX(3) |    /* SERCOM1 */
10
    PORT_WRCONFIG_DRVSTR |
11
    PORT_WRCONFIG_PINMASK(0x03) | /* PA00 + PA01 */
12
    PORT_WRCONFIG_PMUXEN;
13
14
  REG_PM_APBCMASK |= PM_APBCMASK_SERCOM1;
15
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID_SERCOM1_CORE; /* setup SERCOM1 to use GLCK0 -> 48MHz */
16
  
17
  REG_SERCOM1_SPI_CTRLA = 0x00; /* disable SPI -> enable config */
18
  REG_SERCOM1_SPI_CTRLA = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(0); /* MSB first, CPOL = 0, CPHA = 0, SPI frame, master mode, PAD0 = MISO, PAD2 = MOSI, PAD3 = SCK */
19
  
20
  REG_SERCOM1_SPI_BAUD = 0; /* 48 / (2 * (baudval + 1)) -> @48Mhz: 0 = 24MHz, 5 = 4MHz, 23 = 1MHz, 47 = 500kHz */
21
  
22
  REG_SERCOM1_SPI_CTRLB = 0x00; /* receiver disabled, no hardware select, 8-bit */
23
  REG_SERCOM1_SPI_CTRLA |= SERCOM_SPI_CTRLA_ENABLE; /* activate SERCOM1 */
24
  while(REG_SERCOM1_SPI_SYNCBUSY & SERCOM_SPI_SYNCBUSY_ENABLE); /* wait for SERCOM1 to be ready */
25
}
26
27
void spi_transmit(uint8_t data)
28
{
29
  REG_SERCOM1_SPI_DATA = data;
30
  while((REG_SERCOM1_SPI_INTFLAG & SERCOM_SPI_INTFLAG_TXC) == 0);
31
}
32
33
/* write out data to a *single* APA102 LED as RGB */
34
void apa_write(uint32_t color)
35
{
36
  /* start frame */
37
  spi_transmit(0x00);
38
  spi_transmit(0x00);
39
  spi_transmit(0x00);
40
  spi_transmit(0x00);
41
42
  spi_transmit(0xff); /* 0b11100000 + brightness */ 
43
  spi_transmit(color); /* blue */
44
  spi_transmit(color >> 8); /* green */
45
  spi_transmit(color >> 16); /* red */
46
 }
47
48
void setup()
49
{
50
  init_spi();
51
}
52
53
void loop()
54
{
55
  apa_write(0x400000);
56
  delay(300);
57
  apa_write(0x004000);
58
  delay(300);
59
  apa_write(0x000040);
60
  delay(300);
61
}

: Bearbeitet durch User
von Rudolph R. (rudolph)


Angehängte Dateien:

Lesenswert?

Das Interesse ist zwar offenbar recht dünn, aber da ich praktisch keine 
Beispiele im Netz finden konnte wie man bei den ATSAM den DMA benutzt, 
hängt hier mal mein Test-Projekt dazu an.
Das ist immer noch im Arduino Framework, als PlatformIO Projekt.

Bis auf delay() wird allerdings keine Arduino Funktion verwendet und 
auch keine Library vorausgesetzt, die eigentliche Funktion wird durch 
direktes Beschreiben der Register erreicht.

Das Adafruit Trinket M0 hat eine APA102 LED verbaut, das macht es für 
diese Spielerei perfekt.
Wenn da ein SWD Header dran wäre, dann hätte ich ein Atmel Studio 
Projekt erstellt.
Die Funktionen init_spi(), init_dma() und apa_dma_write() würden dann 
allerdings exakt genau so aussehen.


Ich hatte zwei wesentliche Probleme mit dem DMA.

Das erste war das mir zunächst nicht klar war, wie man einen Transfer 
überhaupt anschiebt.
Mit dem Trigger auf SERCOM1 TX sah es für mich zunächst so aus, als 
könnte ich den ersten Transfer nicht auslösen.
Der Transfer geht allerdings los wenn man im CHCTRLA Register das ENABLE 
bit setzt.

Das zweite war die Quell-Adresse.
Ich bin einfach blind davon ausgegangen, dass die Quell- und die 
Ziel-Adresse die Anfangs-Adressen sind von denen aus der DMAC weiter 
zählt.
Es sind aber die Adressen an denen der DMAC ankommen soll wenn der 
Transfer durch ist - aus welchem Grund auch immer.

"Bits 31:0 – SRCADDR[31:0] Transfer Source Address
This bit group holds the source address corresponding to the last beat 
transfer address in the block
transfer."

"Bits 31:0 – DSTADDR[31:0] Transfer Destination Address
This bit group holds the destination address corresponding to the last 
beat transfer address in the block
transfer."

In dem Fall Speicher zu Peripherie wird die Quell-Adresse hochgezählt, 
die Ziel-Adresse aber nicht.

Nach der Beschreibung würde ich allerdings die Adresse des letzten 
Elementes in einem Array angeben und nicht etwa die erste Adresse hinter 
dem Array.

Hier noch direkt die schlapp 90 Zeilen zum Zitieren um Fehler 
aufzuzeigen oder Fragen zu stellen:
1
#include "sam.h"
2
3
static DmacDescriptor dmadescriptor __attribute__((aligned(16))) SECTION_DMAC_DESCRIPTOR;
4
static DmacDescriptor dmawriteback __attribute__((aligned(16))) SECTION_DMAC_DESCRIPTOR;
5
6
#define DATA_LENGTH 12
7
8
uint8_t led_data[DATA_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};
9
10
void init_spi(void)
11
{
12
  /* configure SERCOM1 MOSI on PA00 and SERCOM1 SCK on PA01 */
13
  REG_PORT_WRCONFIG0 =
14
    PORT_WRCONFIG_WRPINCFG |
15
    PORT_WRCONFIG_WRPMUX |
16
    PORT_WRCONFIG_PMUX(3) |    /* SERCOM1 */
17
    PORT_WRCONFIG_DRVSTR |
18
    PORT_WRCONFIG_PINMASK(0x03) | /* PA00 + PA01 */
19
    PORT_WRCONFIG_PMUXEN;
20
21
  REG_PM_APBCMASK |= PM_APBCMASK_SERCOM1;
22
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID_SERCOM1_CORE; /* setup SERCOM1 to use GLCK0 -> 48MHz */
23
  
24
  REG_SERCOM1_SPI_CTRLA = 0x00; /* disable SPI -> enable config */
25
  REG_SERCOM1_SPI_CTRLA = SERCOM_SPI_CTRLA_MODE(3) | SERCOM_SPI_CTRLA_DOPO(0); /* MSB first, CPOL = 0, CPHA = 0, SPI frame, master mode, PAD0 = MISO, PAD2 = MOSI, PAD3 = SCK */
26
  
27
  REG_SERCOM1_SPI_BAUD = 0; /* 48 / (2 * (baudval + 1)) -> @48Mhz: 0 = 24MHz, 5 = 4MHz, 23 = 1MHz, 47 = 500kHz */
28
  
29
  REG_SERCOM1_SPI_CTRLB = 0x00; /* receiver disabled, no hardware select, 8-bit */
30
  REG_SERCOM1_SPI_CTRLA |= SERCOM_SPI_CTRLA_ENABLE; /* activate SERCOM1 */
31
  while(REG_SERCOM1_SPI_SYNCBUSY & SERCOM_SPI_SYNCBUSY_ENABLE); /* wait for SERCOM1 to be ready */
32
}
33
34
void init_dma(void)
35
{
36
  REG_PM_APBBMASK |= PM_APBBMASK_DMAC;
37
  REG_PM_AHBMASK |= PM_AHBMASK_DMAC;
38
39
  REG_DMAC_BASEADDR = (uint32_t) &dmadescriptor;
40
  REG_DMAC_WRBADDR = (uint32_t) &dmawriteback;
41
  REG_DMAC_PRICTRL0 = 0; /* all off, reset-default */
42
43
  REG_DMAC_CHCTRLB = DMAC_CHCTRLB_TRIGACT_BEAT | DMAC_CHCTRLB_TRIGSRC(SERCOM1_DMAC_ID_TX); /* beat-transfer, SERCOM1 TX Trigger, level 0, channel-event input / output disabled */
44
  REG_DMAC_CTRL = DMAC_CTRL_LVLEN0 | DMAC_CTRL_DMAENABLE; /* enable level 0 transfers, enable DMA */
45
  REG_DMAC_CHID = 0; /* select channel 0, reset-default */
46
47
  dmadescriptor.BTCTRL.reg = DMAC_BTCTRL_SRCINC | DMAC_BTCTRL_VALID; /* increase source-address, beat-size = 8-bit */
48
  dmadescriptor.BTCNT.reg = DATA_LENGTH;
49
  dmadescriptor.SRCADDR.reg = (uint32_t) &led_data[DATA_LENGTH]; /* note: last entry in array + 1 */
50
  dmadescriptor.DSTADDR.reg = (uint32_t) &REG_SERCOM1_SPI_DATA;
51
  dmadescriptor.DESCADDR.reg = 0; /* no next descriptor */
52
}
53
54
/* write out data to APA102 LED as RGB */
55
void apa_dma_write(uint32_t color)
56
{
57
  if((REG_DMAC_CHCTRLA & DMAC_CHCTRLA_ENABLE) == 0)
58
  {
59
    led_data[5] = color; /* blue */
60
    led_data[6] = (color >> 8); /* green */
61
    led_data[7] = (color >> 16); /* red */
62
    REG_DMAC_CHCTRLA = DMAC_CHCTRLA_ENABLE;
63
  }
64
 }
65
66
void setup()
67
{
68
   init_spi();
69
   init_dma();
70
}
71
72
void loop()
73
{
74
  apa_dma_write(0x400000);
75
  delay(300);
76
77
  apa_dma_write(0x004000);
78
  delay(300);
79
80
  apa_dma_write(0x000040);
81
  delay(300);
82
83
  apa_dma_write(0x000000);
84
  delay(500);
85
}

von Rudolph R. (rudolph)


Angehängte Dateien:

Lesenswert?

Hier mal ein kleines Beispiel als AS7 Projekt, so ohne AFS.

Ich bin gerade dabei eine Platine mit einem ATSAME51J19A in Betrieb zu 
nehmen.
Das lässt sich so aber auch direkt auf den D51 übertragen.
Das sind übrigens Cortex M4F mit 120MHz.

Ich habe einen 16MHz Quarz an XIN1 / XOUT1 angeschlossen, eine Debug-LED 
an PA02.

Der wesentliche Teil in dem Projekt ist die init_clock() Funktion.
Der Quarz wird aktiviert, dann eine PLL konfiguriert und schliesslich 
der Takt-Generator für den Core auf die PLL umgestellt.

Erwähnenswert ist, die verwendete DPLL0 benötigt einen Takt von 32kHz 
bis 3,2MHz als Eingangs-Frequenz.
Es gibt aber einen Vor-Teiler im DPLLCTRLB Register mit dem ich die 
16MHz erstmal auf 2MHz runter stelle.
Das ist erwähnenswert, weil das im Atmel-Start verbugt ist, der 
Vor-Teiler wird einfach nicht berücksichtigt.
Beim C21 ist mir das auch schon aufgefallen, dort habe ich als ich 
anfing mit den ATSAM zu spielen den Quarz-Takt erstmal durch eine GCLK 
Unit geschickt um den runter zu teilen für die PLL - das geht auch im 
Atmel-Start, ist nur komplett überflüssig.

Zusätzlich etwas lästig war, dass die Register-Namen im Datenblatt nicht 
mit denen in den Includes übereinstimmen.
DPLL0CTRLB -> REG_OSCCTRL_DPLLCTRLB0
Wenn man das mit anderen Units vergleicht ist das Datenblatt fehlerhaft.

von Martin K. (martin_k662)


Lesenswert?

Hey,
ich benutze ebenfalls die ATSAMs ohne ASF, funktioniert soweit echt gut, 
DMA ging auch einfach.

Ich hab allerdings ein anderes Problem, und zwar kann ich nicht von 
einem EXTI ein Event zum Retriggern eines TC senden.

Wenn ich vom EXTI ein SW-Interrupt per Event auslöse, komme ich dort 
hin, wenn ich das Event das zum Timer gehen soll per Software auslöse, 
wird der Timer auch nicht neu getriggert.

Vielleicht hast du dazu ja eine Idee (bin unter GCC unter Linux)

Gruß,
Martin

von Rudolph R. (rudolph)


Lesenswert?

Keinen Plan, ich kratze da noch an der Oberfläche und das wird auch noch 
länger so bleiben, so hemmungslos vollgestopft wie die Dinger sind. :-)


Erstmal war ich froh, dass ich meinen "CAN-Treiber" praktisch ohne 
Änderungen vom C21 übernehmen konnte.
Ich habe nur andere Pins und einen anderen Takt.

Jetzt versuche ich gerade den Bootloader zu portieren und habe erstmal 
festgestellt, dass der NVMTRL sich doch ganz gut vom C21 unterscheidet.

Neben dem Systick-Timer habe ich gerade mal einen TC im C21 benutzt um 
eine Laufzeit-Messung von zwei Funktionen zu machen.

Und zwischendurch hatte ich mal den ADC am C21 konfiguriert um das mal 
auszuprobieren, da kam aber bedingt durch meine Platine nur Grütze raus.
Beim E51 bin ich mal gespannt, die A Revision hat noch genug Probleme 
und einen Fädeldraht habe ich schon gezogen um VREFA mit VDDA zu 
verbinden.

Am C21 bin ich auch noch dran zwei SERCOMs für LIN Master und Slave zu 
benutzen, das funktioniert wenigstens so grundsätzlich. :-)

SERCOM als SPI über DMA habe ich dann auch benutzt um vom C21 aus ein 
FT813 basiertes Display anzusteuern, ebenso in ersten Tests eines mit 
einem BT815.


Eigentlich beschäftige ich mich überhaupt nur mit den Dingern weil die 
iso CAN-FD können und als Bonus auch noch gerade Automotive zertifiziert 
werden.
Für den E51 habe ich eigentlich noch gar keine Verwendung.

von ThomasF (Gast)


Lesenswert?

Martin K. schrieb:
> Wenn ich vom EXTI ein SW-Interrupt per Event auslöse, komme ich dort
> hin, wenn ich das Event das zum Timer gehen soll per Software auslöse,
> wird der Timer auch nicht neu getriggert.

Ich bin bei den ATSAMD51 auch "Bare-Metal" unterwegs.
Ist schon viel Arbeit bis da mal was läuft aber wenn man das
Konzept und den CM4F (ARMv7-M Architektur) verstanden hat ist es auch
nicht schwerer wie ein AVR Xmega.


Vielleicht hilft dir das Code-Beispiel weiter.
TC3 (OVF) startet über einen Event den TC2.
TC User Events müssen nicht Synchron sein. (Auskommentierte Zeilen)


TC3->COUNT16.EVCTRL.bit.OVFEO = true;


TC2->COUNT8.CTRLBSET.bit.ONESHOT = true;
TC2->COUNT8.EVCTRL.bit.EVACT     = TC_EVCTRL_EVACT_START_Val;
TC2->COUNT8.EVCTRL.bit.TCEI      = true;


MCLK->APBBMASK.bit.EVSYS_ = true;
//GCLK->PCHCTRL[EVSYS_GCLK_ID_0].reg   = GCLK_PCHCTRL_GEN(GEN_GCLK_192M) 
| GCLK_PCHCTRL_CHEN;

EVSYS->Channel[0].CHANNEL.bit.EVGEN  = EVSYS_ID_GEN_TC3_OVF;
EVSYS->Channel[0].CHANNEL.bit.PATH   = 
EVSYS_CHANNEL_PATH_ASYNCHRONOUS_Val;
//EVSYS->Channel[0].CHANNEL.bit.EDGSEL = 
EVSYS_CHANNEL_EDGSEL_RISING_EDGE_Val;

EVSYS->USER[EVSYS_ID_USER_TC2_EVU].bit.CHANNEL = (0+1);  // Channel + 1

von Mike (Gast)


Lesenswert?

Hallo zusammen,

ich hätte auch mal eine Frage zu Atsam ohne ASF. Hantiere aktuell mit 
einem Same70 Xplained board rum. Bisher läuft es gut ohne Asf und nur 
mit dem Sam DFP aber ich hänge gerade an dem verketten von zwei 16bit 
Timern um eine 32bit 150ms timer zu erzeugen. Vieles konnte ich mir 
durch Zerlegung der Asf Funktionen und dem Datenblatt gut herleiten, 
aber bei 32Bit Timern war dies bisher nicht erfolgreich.
Vielleicht hat ja jemand eine gute Quelle oder kleines Beispiel.

Danke + Grüße

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


Lesenswert?

Mike schrieb:
> aber bei 32Bit Timern war dies bisher nicht erfolgreich.

Zeig mal, was du schon hast.

Ich habe hier funktionierendes timer chaining, allerdings ist es 
proprietärer Code, den ich jetzt nicht 1:1 posten kann. Ich könnte aber 
deinen Implementierungsversuch gegen unseren Code vergleichen.

von Rudolph R. (rudolph)


Lesenswert?

Hmm, ist der SAME70 wirklich so viel anders als der SAMC21?
Beim SAMC21 werden die Timer nämlich automatisch verkettet wenn man den 
ersten eines Paares auf 32 Bit einstellt.
Das fängt ja auch schon damit an, dass man nicht jedem Timer einen 
eigenen Takt zuweisen kann, sondern das die in Paaren zusammen gelegt 
sind.

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


Lesenswert?

Rudolph R. schrieb:
> Hmm, ist der SAME70 wirklich so viel anders als der SAMC21?

Ja, ist er. Er hat die Dinosaurier-Peripherie von SAM3/SAM4 geerbt.

Seltsam nur dass, obwohl designierter Nachfolger u.a. von SAM4E, dessen 
32-bit-Timer nicht übernommen worden sind, sondern wieder die ollen 
16bittigen von SAM4S. Aber Verketten von Timern war da trotzdem schon 
immer vorgesehen.

SAMC/SAMD haben eine völlig andere Peripherie.

: Bearbeitet durch Moderator
von Mike (Gast)


Lesenswert?

Rudolph R. schrieb:
> SAMC21

Jörg W. schrieb:
> Mike schrieb:
>> aber bei 32Bit Timern war dies bisher nicht erfolgreich.
>
> Zeig mal, was du schon hast.
>
> Ich habe hier funktionierendes timer chaining, allerdings ist es
> proprietärer Code, den ich jetzt nicht 1:1 posten kann. Ich könnte aber
> deinen Implementierungsversuch gegen unseren Code vergleichen.

Hi,

erstmal Danke für Eure Feedbacks. Aktuell habe ich noch nichts richtiges 
was sinnvoll als Referenz vorzeigbar ist. Klemmt gerade auch noch an ein 
paar anderen Ecken. Ich werde aber sobald es codetechnisch was gibt, 
dass hier zur Diskussion/Zerfleischung posten :)

@Rudolph, das dachte ich mir nämlich auch, da es zu den MCUs ein paar 
sinnvolle AppNotes bzgl. 32Bit Timern gibt, aber leider wie schon 
erwähnt, sind die Timer beim e70 anders implementiert.

Grüße

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


Lesenswert?

Leider ist das, was Atmel da "Appnote" nennt, mittlerweile fast nur noch 
etwas Dokumentation für ihre ASF-"Treiber" und nichts mehr, was einem 
zeigt, wie man die Hardware tatsächlich benutzt.

von Rudolph R. (rudolph)


Lesenswert?

Jörg W. schrieb:
> Rudolph R. schrieb:
>> Hmm, ist der SAME70 wirklich so viel anders als der SAMC21?
>
> Ja, ist er. Er hat die Dinosaurier-Peripherie von SAM3/SAM4 geerbt.

Danke, dann werde ich wohl erstmal nicht über den E51 mit seinem 120MHz 
M4F hinaus gehen.

Jörg W. schrieb:
> Leider ist das, was Atmel da "Appnote" nennt, mittlerweile fast nur noch
> etwas Dokumentation für ihre ASF-"Treiber" und nichts mehr, was einem
> zeigt, wie man die Hardware tatsächlich benutzt.

Oh ja, den CAN-Treiber für den C21/E51 zu schreiben war auch nicht ganz 
lustig.
Zum Glück ist das ein Bosch M_CAN und Microchip damit nicht die einzige 
Quelle für Dokumentation.

Was mich noch ein klein wenig stört, ich habe meine Warnings auf 
-pedantic gesetzt.
Und beim Rebuild hagelt es erstmal einen Satz Warnungen für das 
startup_samc21.c: "warning: ISO C forbids conversion of function pointer 
to object pointer type"

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


Lesenswert?

Rudolph R. schrieb:
> Und beim Rebuild hagelt es erstmal einen Satz Warnungen für das
> startup_samc21.c: "warning: ISO C forbids conversion of function pointer
> to object pointer type"

Pah. Sowas macht man ja auch nicht – wenngleich es beim ARM keine so 
große Geige spielt.

von Rudolph R. (rudolph)


Lesenswert?

Tja, so lief das zuletzt bei Atmel.
Und Microchip ist da auch nicht besser, dass die die Includes mit den 
3.x Packs durch die Mangel gedreht haben - bin ich kein Fan von.

von Ingolf T. (Firma: Pitius Tec S.L.) (seahawkibiza)


Lesenswert?

Naja...
Microchip supportet alle SAM auch nur halbherzig.
Auf Fragen nach Assembler bekommt man nur: This was the first question 
of this kind and we don't support assembler.

Nice.

Dazu kommt, das viele Datasheets einfach fehlerhaft sind und man selbst 
per try & error allies rausfinden muss.
Zur Zeit setzen wir atsamc21, atsaml21, atsame70 und atsams70 ein.
Alle in C und Assembler, weil C und c++ einfach zu wirren Code für 
hartes Realtime erzeugen.

Klar kann man Initialisierungen mit C erschlagen, aber wenn es dann 
drauf an kommt, nutzt man DMA, Events und Assembler um clocksynchron 
arbeiten zu können.

Gern würde ich mich Mal mit anderen austauschen, die die prozis ebenso 
benutzen....

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


Lesenswert?

Ingolf T. schrieb:
> Gern würde ich mich Mal mit anderen austauschen, die die prozis ebenso
> benutzen....

Wir benutzen sie (derzeit SAME70, früher SAM4E), aber zu Assembler haben 
wir uns bislang noch nicht hinreißen lassen. :) Wir haben auch harte 
Timings, aber die Synchronisation erfolgt dann immer mit Timern.

Prinzipiell ist der Assembler ja aber erstmal ein GNU Assembler, oder 
was benutzt ihr?

von Ingolf T. (Firma: Pitius Tec S.L.) (seahawkibiza)


Lesenswert?

Ja, halt der Gnu Assembler unter Ärmel Studio 7.
Aber der E70 hat 6 Waitstates im Flash...
Also muss man den Code im Ram laufen lassen.
Geht das unter C?

Im Assembler ja.

Mit Taktsynchron meine ich Mainclk synchron.

Im Flash kann ich auch keinen selbstmodifizierenden Code schreiben.

Braucht's aber manchmal. Zeit ist fast immer zu knapp  ;-(

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


Lesenswert?

Ingolf T. schrieb:
> Ja, halt der Gnu Assembler unter Ärmel Studio 7.

Sowas nimmt bei uns glaub' ich niemand. Ich nehme sowieso Emacs, die 
Kollegen Eclipse oder inzwischen auch VScode.

> Aber der E70 hat 6 Waitstates im Flash...

Ja, aber auch Cache.

Für Full speed müsste man ohnehin TCM benutzen, machen wir bislang 
nicht.

> Also muss man den Code im Ram laufen lassen.
> Geht das unter C?

Warum sollte das denn nicht gehen? Das hat doch nichts mit der 
Programmiersprache zu tun, sondern nur mit der Organisation der 
Linkerscripts und des Startup-Codes (die leider bei ARM so ziemlich 
jeder für sich selbst strickt).

Auch dein Assembler assembliert schließlich nicht direkt in den RAM …

> Mit Taktsynchron meine ich Mainclk synchron.

Brauchen wir nicht, unsere Synchronitätsanforderungen beziehen sich auf 
die Peripherie.

> Im Flash kann ich auch keinen selbstmodifizierenden Code schreiben.

Sowas habe ich das letzte Mal beim Z80 gemacht / benötigt.

: Bearbeitet durch Moderator
von Ingolf T. (Firma: Pitius Tec S.L.) (seahawkibiza)


Lesenswert?

Klar, TCM ist Pflicht.
Den Code kann man nie für RAM compilieren, sondern muss den per Hand 
kopieren.

Aber wenn man nur wenige us Zeit hat und einige Filter berechnen muss, 
geht es nicht anders, trotz FPU.

OK, ich benutze auch Keil.
Eclipse ist mir zu aufgeblasen.

EMACs schau ich mir Mal an....

Aber so schlimm finde ich die GUI von Atmel gar nicht... ;-)

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


Lesenswert?

Ingolf T. schrieb:
> Klar, TCM ist Pflicht.

Was mich an TCM stört ist, dass man den nur gleichermaßen auf Daten und 
Befehle partitionieren kann. Mir würde es an manchen Stellen völlig 
reichen, ihn für die Befehle zu verwenden – bei den Daten muss ich mir 
dann sonst erst Konzepte ausdenken, was in dem TCM überhaupt liegt.

> Den Code kann man nie für RAM compilieren, sondern muss den per Hand
> kopieren.

Die üblichen Kombinationen von startup/linker script haben dafür schon 
Vorkehrungen, da muss man nichts manuell nachhelfen. Einfach die 
Funktion als
1
__attribute__((section(".ramfunc")))

markieren (vielleicht gibt es auch einen besser lesbaren Alias dafür, 
weiß ich gerade nicht), und sie wird automatisch beim Start kopiert.

> Eclipse ist mir zu aufgeblasen.

Das sind doch aber alle diese großen IDEs, Atmel Studio ist da nicht 
anders.

> EMACs schau ich mir Mal an....

Lieber nicht. :) Ist 'ne ganz andere Philosophie. Da muss man 
reinwachsen.

Ich mach das aber schon seit mehr als 25 Jahren, und musste seitdem 
praktisch meine Gewohnheiten nicht ändern – obwohl sich meine 
Aufgabenfelder massiv geändert haben.

von Ingolf T. (Firma: Pitius Tec S.L.) (seahawkibiza)


Lesenswert?

Nun, ich programmiere seit 1983 in Assembler oder Maschinencode 
(damals). Erst 4bit, dann 8bit, heute 32bit 8 cores (propeller) oder 
Arm.

Meist Controller für komplizierteste Regelalgorithmen.

Die Umgebungen sind mir relativ egal, Propeller hat nur Simulator, Debug 
so gut wie unmöglich.

Arm ist ganz gut, Dank Segger auch recht gut debugbar.

Was bei ATSam doof ist, man muss alles selber rausfinden.
Bei Microchip als Firma kann ich auch urgent cases öffnen, aber meist 
erkläre ich dann dem Support-Mitarbeiter wie es funktioniert.

Manchmal ist der Support auch gut. Zum Beispiel als ich eine Exel Liste 
der Pinbelegung wollte, um das Layout schneller zu machen ;-)

Aber es tauchen immer wieder Unstimmigkeiten auf.
Aber des gibt kaum Leute, die die CPUs so richtig nutzen....

von Alexxx (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe mir eine Mini-HAL geschrieben - im Anhang (mit Doxygen-Doku)
Das mit der DMA ist so komplex, dass die Routinen eine große 
Erleichterung sind. Wichtig ist jedoch, dass man das mit den 
Descriptoren verstanden hat.

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


Lesenswert?

Ingolf T. schrieb:
> Bei Microchip als Firma kann ich auch urgent cases öffnen, aber meist
> erkläre ich dann dem Support-Mitarbeiter wie es funktioniert.

First-level support hatte Atmel schon vor Jahren nach Indien 
ausgelagert, in der Hoffnung, dass man mit sowas die Aktionäre glücklich 
macht.

Der indische Support-Mitarbeiter wird danach bewertet, wie schnell er 
die Cases abarbeiten kann. Wenn du wirklich einen Bug findest, dann 
musst du ihm folglich so klar wie möglich machen, dass das nicht seine 
Schuld ist und er es nur „nach oben“ weiterreichen darf – dann hat er 
seinen Anteil am Case getan, und danach geht die Sache zu den 
tatsächlichen Chip-Designern in Frankreich oder Norwegen.

Nichts gegen die Inder als solches: aber sie sind einfach räumlich und 
logistisch viel zu weit weg von den Entwicklern.

> Nun, ich programmiere seit 1983 in Assembler oder Maschinencode
> (damals)

Maschinencode habe ich nur ganz wenig machen müssen, Assembler damals 
schon, aber ich war heilfroh, dass man auf CP/M größere Projekte in 
Turbo-Pascal bauen konnte. Mein EPROM-Programmer wäre in Assembler 
wahrscheinlich ein Mannjahr gewesen, bei schlechterem Featureset. In 
Pascal musste man nur, nachdem erstmal alles geht, die innere Schleife 
hernach in Assembler umschreiben, danach war das Programm gut und 
schnell, und es hat weniger als einen Mannmonat gekostet.

Ich kann den ARM-Assemblercode lesen, bin aber froh drüber, das nicht 
selbst schreiben und vor allem pflegen zu müssen.

: Bearbeitet durch Moderator
von Ingolf T. (Firma: Pitius Tec S.L.) (seahawkibiza)


Lesenswert?

Das der loader (*flash.ld) eine funktion relocaten kann, ist klar.

Aber der thumb Befehlssatz ist wirklich sehr optimiert und weil es zum 
Beispiel keinen Befehl gibt, ein Register mit einem 32bit Direktwert zu 
laden, und die meisten bedingten Sprünge nur short gehen, muss der Code 
sehr optimiert geschrieben werden und man muss wissen, wo Daten liegen 
und auch Springtabellen anlegen etc. Jeder unnötige Befehl ist ein Takt 
zuviel.

Weil wir gerade bei __attribute( sind, wo gibt es denn eine Liste aller 
möglichen Attribute? Bei gnu-Assembler gibts einige erklärt, aber nicht 
alle.
Bei ARM gibt es auch gute Doku, leider finde ich auch dort nicht alles.
Kann aber auch daran liegen, das ich es einfach nicht finde. Problem ist 
immer, etwas zu suchen, von dem man nicht weiß, wie es heißt. Und wenn 
ich weiß, wie es heißt, brauche ich es nicht mehr zu suchen :-)

Was mir fehlt ist ein gutes Tutorial zum Assembler und Debugger.
Teilweise ist es nicht möglich, einen Breakpoint hinter ein Label zu 
setzen. Warum das so ist, habe ich noch nicht herausgefunden. Mal klappt 
es, mal nicht. Hängt scheinbar vom Allignment ab.


Ebenso sind die Prozessoren innerhalb einer Serie (ATSAMC21, D21, L21) 
teilweise extrem verschieden. Das geht mit der PLL los und endet bei der 
DMA, die z.B. beim L-Typ die Deskriptoren im LPRAM braucht.
Dazu kommt, das man bei Microchip die Doku scheinbar "global" hält. Z.B. 
ob ein TCC nun 2 oder 4 CC-egister hat, merkt man erst bei einem 
Hardfault() :-)
Im Handbuch steht halt nur "..bis zu 4 CC[]".
Und wenn man den ersten Prototyp baut, muss man sich für ein Pinout 
entscheiden, da man den Prozessoren keine Pinmatrix geschenkt hat. Das 
Aussuchen der Pins ist extrem aufwändig und Fehlerbehaftet. Eigentlich 
weiß man erst, wenn man den Code fertig hat, welche Pins man benutzen 
kann. Dann muss man eh den Prototyp noch mal routen :-)

Schön wäre es, wenn man wirklich mal ein Board "sticky" machen könnte, 
und jeder schreibt seine erkannten Anomalien bzw. Tricks rein, damit man 
nicht immer stundenlang suchen muss.

Das Programmieren des eigentlichen Problems geht am schnellsten. Am 
längsten dauert es jedesmal, herauszufinden was nun wieder anders ist...

von S. R. (svenska)


Lesenswert?

Ingolf T. schrieb:
> Jeder unnötige Befehl ist ein Takt zuviel.

Bist du sicher, dass du nicht irgendwelchen Gespenstern hinterherjagst?

Weil:
> Was mir fehlt ist ein gutes Tutorial zum Assembler und Debugger.

In den meisten Anwendungen besteht keine Notwendigkeit, Assembler zu 
verwenden - für das gesamte Projekt schon garnicht. Mikrooptimierungen 
kann der Compiler in aller Regel besser und zuverlässiger durchführen 
als der Mensch, wenn das Problem nicht äußerst scharf abgegrenzt ist.

Und selbst, wenn es dir wirklich auf die Takte ankommt, weil du in 
Echtzeit einem VGA-Signal hinterherlaufen willst - warum nimmst du dann 
nicht einfach den nächstschnelleren Prozessor?

Davon abgesehen... ja, ich habe einen SAM3X auch bare-metal programmiert 
- an der Universität, nicht für die Realität. Bis auf absolute Ausnahmen 
sehe ich darin keinen Nutzen.

Ingolf T. schrieb:
> Bei gnu-Assembler gibts einige erklärt, aber nicht alle.

Der Quelltext deiner speziellen Version sollte die Eigenheiten alle 
kennen. Ansonsten halte ich mich eher an die Dokumentation zu GCC und 
LD, wo einige Dinge auftauchen.

Ingolf T. schrieb:
> Bei ARM gibt es auch gute Doku, leider finde ich auch dort nicht alles.

Meiner Erinnerung nach findet sich bei ARM hauptsächlich Dokumentation 
zur ARM-Toolchain, die sich in den Feinheiten deutlich von der GNU-Welt 
unterscheidet.

von Ingolf T. (Firma: Pitius Tec S.L.) (seahawkibiza)


Lesenswert?

> Bist du sicher, dass du nicht irgendwelchen Gespenstern hinterherjagst?

> Und selbst, wenn es dir wirklich auf die Takte ankommt, weil du in
> Echtzeit einem VGA-Signal hinterherlaufen willst - warum nimmst du dann
> nicht einfach den nächstschnelleren Prozessor?


Weil es in der Serienfabrikation auch auf jeden Cent ankommt.
VGA wäre noch harmlos.
Oft hat man nur einige us Zeit und muss da viele Dinge berechnen. Im 
Detail kann ich da nichts erzählen, wegen viel Geheimhaltungsklauseln 
der Kunden.

Deswegen kann man in offenen Foren auch keine Hilfe erwarten. Und der 
Support ist halt nicht sooo gut.

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


Lesenswert?

Ingolf T. schrieb:
> Oft hat man nur einige us Zeit und muss da viele Dinge berechnen.

Es ist aber auch meine Erfahrung, dass gerade Rechnungen der Compiler 
oft besser hinbekommt, als man sich das selbst im Assemblercode 
abbrechen könnte – auch bei Mikrosekunden. Das Byte Flash kostet im 
Allgemeinen sowieso viel weniger als die Ingenieursstunden, die man 
aufwänden muss, um ebendieses Byte einzusparen.

So viel Magie ist ja an der Assemblerprogrammierung hier sowieso nicht 
dran, zumal es ein typischer RISC-Prozessor ist.

von S. R. (svenska)


Lesenswert?

Ingolf T. schrieb:
> Weil es in der Serienfabrikation auch auf jeden Cent ankommt.

Naja, die meisten, die solche Fragen stellen, jagen Gespenstern 
hinterher, deswegen frug ich nach.

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.