Forum: Mikrocontroller und Digitale Elektronik Welcher Cortex M3?


von Gast (Gast)


Lesenswert?

Hallo,

ähnlich wie beim ARM7TDMI werden die Cortex M3 ja von verschiedenen 
Herstellern lizensiert und zusammen mit ihrer eigenen Peripherie als 
kaufbare Microcontroller produziert.

Gibt es irgendein Hersteller, dessen Peripherie und Support besonders 
gut ist?

Mir ist klar, dass es hierzu viele Meinungen gibt, aber genau die würden 
mich interessieren, um eine Entscheidung zu finden.

Vielen Dank im Voraus!

Grüße,
Gast

von Random .. (thorstendb) Benutzerseite


Lesenswert?

STM32F10x in Verbindung mit CMSIS würde ich empfehlen. Läuft 
super-stabil, recht simpel zu programmieren, und es gibt Tonnen von 
Examplecode.

My Prefered IDE: uVision4 :-)
Simulation (Core + Peripherals), ULINK/2/ME und J-Link.


VG,
/th.

von Erwin R. (er-tronik)


Lesenswert?

Es gibt zwar inzwischen einige Cortex-M3 Derivate verschiedener 
Hersteller, aber ich denke es haben sich 2 Hersteller am Markt 
etabliert. Zum einen ist das ST mit den STM32F10x und zum zweiten 
NXP/Philips mit den LPC17xx. Ich habe mit beiden gearbeitet, bevorzuge 
jedoch derzeit die LPC17xx, da sie gegenüber den neueren STM32F105/107 
unschlagbar im Preis- Leistungsverhältnis sind und nahezu dieselbe 
Peripherie bieten. Außerdem hat sich ST mit fehlerhaften Bootloadern in 
der neuen Generation selber ins Abseits katapultiert. Das soll zwar bei 
den neuen Versionen beseitigt sein, aber man weiß derzeit nie, welche 
man geliefert bekommt.

Zur Programmierung dieser Controller muß man sicher nicht teure 
Entwicklungssysteme kaufen, die "Random" vorgeschlagen hat. Zum Anfang 
(und sicher auch für später) tut es auch die freie Version des 
C-Compiler G++ von Codesourcery. Als Editor kann man so ziemlich alles 
nehmen, ich bevorzuge den UltraEdit32. Wer eine kostenlose IDE will, für 
den ist Eclipse sicher die erste Wahl.

Ob man einen Simulator und Debugger braucht, muß jeder selbst 
entscheiden. Ich brauchs nicht, zum debuggen gebe ich mir Daten über 
einen seriellen Port aus.

Zur Programmierung beider Serien ist kein JTAG-Adapter notwendig, es 
reicht bei beiden eine serielle Schnittstelle, bzw. ein 
USB/Seriell-Interface und das zum Controller passende Programmiertool, 
das in beiden Fällen kostenlos zu bekommen ist.

Ob man die Library CMSIS benutzt, muß auch jeder selber entscheiden. 
Natürlich ist die Programmierung hierdurch recht einfach, da man sich 
nicht in die Tiefen der Registerprogrammierung einarbeiten muß. Aber ich 
bin der Meinung, daß diese den Code nur unnötig aufbläht und damit 
natürlich unnützerweise langsam macht. In meinen Sourcen fimndet man 
deshalb keinerlei CMSIS, das Ergebnis ist ein kompakter und schneller 
Code.

Natürlich gibt es auch noch Cortex-M3 von anderen Herstellern wie Texas 
Instruments (vormals Luminary Micro), Atmel (AT91SAM3) und einigen 
Anderen. Einige haben den Markteinstieg verpaßt oder richten sich an 
andere Zielgruppen. Mit den Controllern von ST und NXP kannst du auf 
längere Sicht nichts verkehrt machen.

Erwin

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Erwin Reuss schrieb:
> Ob man die Library CMSIS benutzt, muß auch jeder selber entscheiden.
> Natürlich ist die Programmierung hierdurch recht einfach, da man sich
> nicht in die Tiefen der Registerprogrammierung einarbeiten muß. Aber ich
> bin der Meinung, daß diese den Code nur unnötig aufbläht und damit
> natürlich unnützerweise langsam macht. In meinen Sourcen fimndet man
> deshalb keinerlei CMSIS, das Ergebnis ist ein kompakter und schneller
> Code.

In dem Punkt muss ich dir wiedersprechen. Wenn ich CMSIS meine, meine 
ich im wesentlichen die core_cm3.c/.h.

In der c-datei sind intrinsic standards abgebildet, die dann über 
armcc/iarcc/gcc gleich funktionieren, interessant ist aber die 
core_cm3.h.

Dort sind ein haufen inline funktionen drin, die exact das machen, was 
man an deren stelle in den code schreiben müsste.
Das bläht absolut nix auf. Ich selbt bin überhaupt kein Fan von 
driverlibs, aber mag durchaus schlanke kleine helferlein.

Hier wird der NVIC (ein recht komplexes peripheral, was bisher die 
wenigsten verstanden haben) auf einen Satz einfacher Funktionen 
abstrahiert, die jeweils nur ein Register addressieren. (btw: Ich kenn 
den Core weil ich den entworfen und geschrieben hab ^^*grins*^^).

Beispiel 1 (Interrupt enable):
1
static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
2
{
3
  NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));                             /* enable interrupt */
4
}

Beispiel 2 (set priority):
1
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, int32_t priority)
2
{
3
  if(IRQn < 0) {
4
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); }  /* set Priority for Cortex-M3 System Interrupts */
5
  else {
6
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }         /* set Priority for device specific Interrupts      */
7
}

Wenn man verstanden hat, wie der NVIC funktioniert, erschliesst sich 
einem die Funktionsweise dieser beiden Beispiele sofort. Ist einem das 
noch nciht bekannt, rätzelt man mindestens ne Stunde über die beiden 
obigen Funktionen und das warum :-)

Der Unterschied ist, dass - nicht, wie bei DLs üblich - irgendwelche 
undurchsichtigen Monsterfunctions irgendwas magic-mässiges machen, 
sondern dass hier wirklich mal sinnvoll abstrahiert wurde.

Wenn hier irgendetwas fehlt, kann man problemlos einen Registerzugriff 
"manuell" hinterherschieben, ohne doppelten und somit langsameren Code 
zu haben.

Mein Ansatz war damals: Eine funktion (inline) per Register. Das lässt 
sich auf multiple Instanzen von Peripherals (z.B. GPIO) durch die 
übergabe der Pointer sehr einfach realisieren:
1
PortOut(GPIOA, data);

Damit hätte man eine sinnvolle Lib für Registerliebhaber. Leider liess 
sich das nur für den Core durchsetzen.

Die SysInit ist sicher zum Einstieg sinnvoll, was es an Sonderfunktionen 
sonst noch gibt entzieht sich z.Zt. meiner Kenntnis, da ich nur den 
Cortex-M3 Core der CMSIS pflege.

Schau da ruhig mal rein!


VG,
/th.

von Reinhard S. (rezz)


Lesenswert?

Erwin Reuss schrieb:

>
> Natürlich gibt es auch noch Cortex-M3 von anderen Herstellern wie Texas
> Instruments (vormals Luminary Micro)

Gerade Luminary hat massig Anschlussmöglichkeiten und dürfte durch den 
Aufkauf durch TI auch längerfristig Zukunft haben.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Gerade Luminary hat...

haben die inzwischen ihre Core-Locks in den Griff bekommen?

von blup (Gast)


Lesenswert?

Muss zustimmen. Verwende auch die CMSIS-Library. Der Unterschied ist 
zwischen selbst schreiben und CMSIS minimal (zugunsten CMSIS ;) ). Habe 
aber auch nicht lange dann manuell rumgemacht :D

Ansonsten kann ich auch, wie Erwin die LPC-Serie empfehlen. Wir hatten 
mit den gleichen Problemen beim ST F107 zu kämpfen :)
Der LPC1768 funktioniert wirklich wie er soll.

Von ST kannst aber zum Beispiel die älteren F103 nehmen. Maßenweise 
beispielcode für. Aber USB und CAN gehen nicht gleichzeitig, weswegen 
sie für mich nicht in Frage kamen.

LM bzw. jetzt TI war deutlich langsamer, deswegen gleich der Griff zum 
NXP.

Schöne Grüße aus Stuttgart

von Gast (Gast)


Lesenswert?

Bisher scheinen mich die LPCs eher zu überzeugen. Vor allem das 
Preis-/Leistungsverhältnis scheint erstaunlich gut zu sein.

Einen LPC1751 kriegt man sogar bei Farnell für 3,50eur und der hat 
schon USB.

Hört sich gut an! Und USB ist ein absolutes Muss für mich, da ich 
mittlerweile keinen einzigen PC mehr habe, der eine serielle oder 
parallelle Schnittstelle hat und ich auch keinen 3,50EUR teuren FT232 
verwenden möchte.

Der einzige Kritikpunkt scheint das 80pinnige Gehäuse zu sein. Hatte auf 
etwas mit 48pins gehofft, weil Platz auch oft viel Geld kostet.

Kennt jemand sowas wie den LPC1751 in etwas kleinerer Bauform?

Grüße,
Gast

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> In dem Punkt muss ich dir wiedersprechen. Wenn ich CMSIS meine, meine
> ich im wesentlichen die core_cm3.c/.h.

So sieht das nur auf den ersten Blick aus. ARM selbst definiert den 
Begriff CMSIS nämlich für beides, sowohl das was ARM unabhängig von der 
Implementierung bieten kann, als auch für den herstellerabhängigen Teil 
mit Periphieriedefinitionen und ggf. Support-Funktionen. Siehe 
http://www.onarm.com/download/download378.asp.

> Dort sind ein haufen inline funktionen drin, die exact das machen, was
> man an deren stelle in den code schreiben müsste.

Nur dass viele dieser Funktionen in core_cm3 leider eben nicht inline 
sind, sondern für einen einzige Assembler-Befehl eine Funktion 
aufgerufen wird. Das Zeug gehört Inline in die core_cm3.h, nicht als 
Einzeiler in core_cm3.c. Mindestens bei GCC, inwieweit andere Compiler 
Inline-ASM können weiss ich nicht. Ist leider auch noch buggy 
(ldrex/strex mit Registerkonflikt).

von Random .. (thorstendb) Benutzerseite


Lesenswert?

A. K. schrieb:

> Nur dass viele dieser Funktionen in core_cm3 leider eben nicht inline
> sind, sondern für einen einzige Assembler-Befehl eine Funktion
> aufgerufen wird. Das Zeug gehört Inline in die core_cm3.h, nicht als
> Einzeiler in core_cm3.c. Mindestens bei GCC, inwieweit andere Compiler
> Inline-ASM können weiss ich nicht. Ist leider auch noch buggy
> (ldrex/strex mit Registerkonflikt).

das ist eigentlich so weit wie möglich inline gemacht, nur an einigen 
stellen mochter der compiler das nicht. Diese "Reste" sind in der .c zu 
finden. In der .h sind viele Intrinsics auch als #define oder inline 
gelöst.
Vielleicht hat sich ja z.B. am gcc was geändert, so dass es 
funktioniert.
Ich würde am liebsten komplett auf die core_cm3.c verzichten, aber z.Zt. 
gehts leider nciht ohne dieses vehikel.

VG,
/th.


PS: Wenn du was findest - her damit. Wird umgehend geändert. Kochen 
schliesslich alle nur mit Wasser :-)

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> das ist eigentlich so weit wie möglich inline gemacht, nur an einigen
> stellen mochter der compiler das nicht.

Im CMSIS V1.0 von ARM sind allerlei nützliche Einzeiler wie 
__set_BASEPRI im .c File, nicht im .h File.

> Diese "Reste" sind in der .c zu finden.

Ich wüsste beim GCC nicht, warum man das in .c reinpacken muss. Wenn der 
Assembler mal über STREX stoplern sollte, dann ist nicht der Compiler 
schuld, sondern die fehlerhaften "=r" an Stelle der korrekten "=&r", die 
den Compiler dazu bewegen können, das Adressregister zu recyceln, was 
der Befehl nicht so mag.

Ich habe den ganzen Kram sofort dorthin verfrachtet wohin er gehört (mit 
"static inline" verziert).

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Ich habe den ganzen Kram sofort dorthin verfrachtet wohin er gehört (mit
> "static inline" verziert).
magst mir das ma schicken (pm) oder hier ins forum stellen?
Ich würde dafür sorgen, dass es in die nä. Version der CMSIS kommt.


VG,
/th.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

A. K. schrieb:
> Random ... schrieb:
>> das ist eigentlich so weit wie möglich inline gemacht, nur an einigen
>> stellen mochter der compiler das nicht.
>
> Im CMSIS V1.0 von ARM sind allerlei nützliche Einzeiler wie
> __set_BASEPRI im .c File, nicht im .h File.

Beim ARM Compiler wird der Thumb-2 Befehlssatz nicht vom Inline
Assembler unterstützt. Stattdessen werden uns Compiler Intrinsics
nahegelegt. Ist auch prinzipiell besser, nur leider hat man "named
register variables" noch nicht für alle Register implementiert.

>> Diese "Reste" sind in der .c zu finden.
>
> Ich wüsste beim GCC nicht, warum man das in .c reinpacken muss.

Dar war Thorsten zu faul, das für GCC per #ifdef in der header Datei zu
implementieren :-)

Gruß
Marcus
http://www.doulos.com/arm/

von (prx) A. K. (prx)


Lesenswert?

Nun ja, werde sie halt heute reinstellen.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

das ist so nicht ganz richtig, und auch nicht fair.

Als das implementiert wurde, habe ich schon versucht, alles in das 
headerfile zu packen, aber sobald parameter dazukamen, sträubte sich der 
gcc, es gab Probleme. Hatte mit AAPCS (gcc macht die ganze 
Registerzuordnung selbst, daher stehen in dem ASM kram ja auch variablen 
drin und keine Register) zu tun, Problem war die Werteübergabe / der 
Returnwert. Und um sicherzustellen, dass es immer funktioniert, hab 
ich halt Funktionen drumgebaut.

Z.B.:
1
static __INLINE void __WFI()                      { __ASM volatile ("wfi");   }

gegenüber:
1
extern uint16_t __LDREXH(uint16_t *addr);
2
...
3
4
uint16_t __LDREXH(uint16_t *addr)
5
{
6
    uint16_t result=0;
7
  
8
   __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
9
   return(result);
10
}


@Markus: Bessere Vorschläge werden gerne angenommen! Nur bitte sachlich 
bleiben...

Ansonsten hätte ich ja - wie du sicherlich sehen kannst - einfach nur 
die Zeile mit __ASM(...) ins Headerfile packen müssen,was erheblich 
weniger Arbeit ist.

Diese Funktionen liessen sich übrigends nicht (gcc) als static inline 
compilieren.



VG,
/th.

von (prx) A. K. (prx)


Lesenswert?

Erwin Reuss schrieb:

> Außerdem hat sich ST mit fehlerhaften Bootloadern in
> der neuen Generation selber ins Abseits katapultiert.

Beim Errata Sheet der LPC1700 frage ich mich allerdings, ob das wirklich 
ernst gemeint ist, oder ob der Beta-Test grad erst beginnt. Da ist man 
in der Branche und grad auch bei NXP ja andere Listen gewohnt.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Random ... schrieb:
> Hatte mit AAPCS (gcc macht die ganze Registerzuordnung selbst, daher
> stehen in dem ASM kram ja auch variablen drin und keine Register) zu
> tun, Problem war die Werteübergabe / der Returnwert. Und um
> sicherzustellen, dass es immer funktioniert, hab ich halt
> Funktionen drumgebaut.

Nur mal so zu meinem Verständnis (ich verwende GCC nicht sehr oft),
was ist denn hier das eigentliche Problem? Ist das mal wieder ein
ARM-GCC Bug?

Gruß
Marcus
http://www.doulos.com/arm/

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> drin und keine Register) zu tun, Problem war die Werteübergabe / der
> Returnwert.

Worin konkret? Das ist übliche GCC Praxis seit Jahren. Auch mit 
Parametern.

Ein Problem ist jedenfalls
1
uint32_t __STREXW(uint32_t value, uint32_t *addr)
2
{
3
   uint32_t result=0;
4
  
5
   __ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
6
   return(result);
7
}
denn da muss wie schon erwähnt unbedingt "=&r" rein, damit er die 
Register von addr/value nicht für result wiederverwendet. Tut er in der 
bestehenden Version zufällig bis zur nächsten Compilerversion nicht, 
aber als inline-Version kann das schon mal vorkommen. Das result=0 
vorneweg nützt nicht, schadet nicht.

> Diese Funktionen liessen sich übrigends nicht (gcc) als static inline
> compilieren.

Warum nicht? Auch das ist gängige Praxis.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

Wo wir grad dabei sind: Weshalb eigentlich uint16_t statt uint32_t als 
Return-Wert in
1
uint16_t __LDREXH(uint16_t *addr)
2
{
3
    uint16_t result=0;
4
5
   __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
6
   return(result);
7
}

Ebenso STREXB/H. Es führt nur dazu, dass der Aufrufer routinemässig eine 
Erweiterung auf 32-Bit durchführen muss, weil er mit 16-Bit Werten in 
Registern (ausser beim Store) nichts anfangen kann. Passend erweitert 
werden sie von den LDREX*/STREX* Befehlen sowieso schon.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> denn da muss wie schon erwähnt unbedingt "=&r" rein, damit er die
> Register von addr/value nicht für result wiederverwendet.
warum?

technisch ist doch gegen
r0 = r0 + r1
nichts einzuwenden...

Funktionieren tuts, der Test hat jeweils hingehauen (CodeSourcery, 
Raisonance).

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Wo wir grad dabei sind: Weshalb eigentlich uint16_t statt uint32_t
> als Return-Wert in ...

LDREX Halfword

:-)

Darum sind dererlei auch drei drin. Wenn du (int) möchtest, verwende 
bitte auch die LDREX :-)

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> technisch ist doch gegen
> r0 = r0 + r1
> nichts einzuwenden...

Normalerweise nicht. Nur gibt ein paar Befehle, bei denen bestimmte 
Überlappungen von der Befehlsreferenz ausdrücklich verboten werden. 
ADD gehört nicht dazu, STREX jedoch schon.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> LDREX Halfword
>
> Darum sind dererlei auch drei drin. Wenn du (int) möchtest, verwende
> bitte auch die LDREX :-)

Jetzt wäre mal ein weiterer Blick in die Referenz fällig. Was macht
   LDREXH r0,[r1]
denn genau:
   r0[0..15] = memory
   r0[16..31] = 0

Eine Funktion
1
uint32_t __LDREXH(uint16_t *addr)
2
{
3
    uint32_t result;
4
5
   __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
6
   return(result);
7
}
entspricht also exakt dem Maschinenbefehl.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

ei, da scheint tatsächlich ein fehler drinzusein, denn die Adresse muss 
latürnich 32bit sein ^^

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> ei, da scheint tatsächlich ein fehler drinzusein, denn die Adresse muss
> latürnich 32bit sein ^^

Ist sie doch?!?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

uint32_t __LDREXH(uint16_t *addr)

argh ihr habt es geschafft, mich völlig zu verwirren confused

Richtig müsste es heissen:
uint16_t __LDREXH(uint16_t *addr)

LDREX Halfword bekommt einen 16bit pointer auf eine variable, und gibt 
einen 16bit wert zurück.

Also warum willste da 32bit return haben?

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> LDREX Halfword bekommt einen 16bit pointer auf eine variable, und gibt
> einen 16bit wert zurück.

Wenn damit der Maschinenbefehl gemeint ist: NEIN.

LDREX Halfword bekommt einen 32-Bit Pointer auf eine 16-Bit Variable, 
und gibt einen 32-Bit Wert zurück. Genau wie LDR Unsigned Halfword.

Schau mal in die Befehlsreferenz!

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Schau mal in die Befehlsreferenz!
Lt. Quick Reference Card gibt der LDREXH die Bits [15..0] zurück.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

A. K. schrieb:
> LDREX Halfword bekommt einen 32-Bit Pointer auf eine 16-Bit Variable,
> und gibt einen 32-Bit Wert zurück. Genau wie LDR Unsigned Halfword.

Ist zwar technisch nicht ganz verkehrt, aber der Prototyp einer Funktion
gibt ja letztlich auch die Intention des Entwicklers an. Und die besteht
hier nun mal darin, ein Halbwort zu laden.

Gruß
Marcus
http://www.doulos.com/arm/

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Ok, was bleibt?

Es ist alles korrekt, trotz des fehlenden =&r funktioniert es 
(schliesslich ist der Kram nicht ungetestet rausgegangen, dazu gehört 
noch ein Verifikationsprogramm, in welchem die CMSIS zerlegt wird).

Offen ist noch der Punkt, ob der gcc mittlerweile __ASM(...) als 
__INLINE unterstützt, denn das war bisher nicht der Fall.
Daher existiert der Kram in der nervigen .c datei, die wir selbst auch 
gerne loswerden wollen.


VG,
/th.

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


Lesenswert?

Random ... schrieb:

> Offen ist noch der Punkt, ob der gcc mittlerweile __ASM(...) als
> __INLINE unterstützt, ...

Nein.  Aber __asm und __inline unterstützt er schon seit mehr als
10 Jahren.  (C ist case sensitive.)

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:
> Ok, was bleibt?
>
> Es ist alles korrekt, trotz des fehlenden =&r funktioniert es
> (schliesslich ist der Kram nicht ungetestet rausgegangen, dazu gehört
> noch ein Verifikationsprogramm, in welchem die CMSIS zerlegt wird).

Das hängt hochgradig von der Registerallokationsstrategie an. Was in 
4.3.2 funktionierte kann in 4.3.3 in die Hose gehen. So geschehen:
http://www.st.com/mcu/forums-cat-9006-23.html

arm-hitex-elf-gcc.exe -c -gdwarf-2 -MD -O0 -trigraphs -mcpu=cortex-m3 
-mthumb -Wall -fsigned-char -mlittle-endian -mfpu=vfp -xc 
-mno-thumb-interwork -mno-tpcs-frame -I.\Source\ -o .\objects\core_cm3.o 
.\Source\core_cm3.c
/cygdrive/c/DOKUME~1/cad/LOKALE~1/Temp/ccXXSLdu.s: Assembler messages:
/cygdrive/c/DOKUME~1/cad/LOKALE~1/Temp/ccXXSLdu.s:694: Error: selected 
processor does not support `strex r3,r3,[r2]'

> Offen ist noch der Punkt, ob der gcc mittlerweile __ASM(...) als
> __INLINE unterstützt, denn das war bisher nicht der Fall.

GCC tut das schon seit sehr langer langer Zeit. Wobei die Dinger (__ASM, 
__INLINE) natürlich anders heissen.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

...ohne worte :-)
1
/* define compiler specific symbols */
2
#if defined   ( __CC_ARM   )
3
  #define __ASM            __asm           /*!< asm keyword for armcc          */
4
  #define __INLINE         __inline        /*!< inline keyword for armcc        */
5
6
#elif defined ( __ICCARM__ )
7
  #define __ASM           __asm            /*!< asm keyword for iarcc           */
8
  #define __INLINE        inline           /*!< inline keyword for iarcc. Only avaiable in High optimization mode! */
9
  #define __nop           __no_operation   /*!< no operation intrinsic in iarcc */
10
11
#elif defined (  __GNUC__  )
12
  #define __ASM             asm            /*!< asm keyword for gcc            */
13
  #define __INLINE          inline         /*!< inline keyword for gcc         */
14
#endif

von Werner (Gast)


Lesenswert?

@random

>> Gerade Luminary hat...
>
> haben die inzwischen ihre Core-Locks in den Griff bekommen?

Hat du eine Quelle oder kannst das näher beschreiben ?


Danke.

von (prx) A. K. (prx)


Lesenswert?

Da liegt der Hase im Pfeffer. Damit ist man abhängig davon, ob ANSI 
Kompatibilität gefragt ist. Dann nämlich geht das so nicht.

Was immer geht:
1
#elif defined (  __GNUC__  )
2
  #define __ASM             __asm            /*!< asm keyword for gcc            */
3
  #define __INLINE          __inline         /*!< inline keyword for gcc         */
4
#endif

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

>> Schau mal in die Befehlsreferenz!
> Lt. Quick Reference Card gibt der LDREXH die Bits [15..0] zurück.

Die Refcard interessiert mich in diesem Zusammenhang nicht, die ist 
keine komplette Befehlsbeschreibung. Die ARMv7 Referenz schon eher.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Die Refcard interessiert mich in diesem Zusammenhang nicht, die ist
> keine komplette Befehlsbeschreibung.
Willste damit sagen, dass die falsch ist?
Auch im Netz steht es so - in der kompletten Referenz...


Sooo, gerade mal getestet mit latest code sourcery.
Entgegen meinen obigen Ausführungen lag damals das Problem nicht bei asm 
und inline, sondern dem ganzen in Verbindung mit static, was bei 
funktionen im headerfile ja notwendig ist.

Dies hier ist nun compilierbar:
1
static __INLINE uint8_t __MY_LDREXB(uint8_t *addr)
2
{
3
    uint8_t result;
4
  
5
   __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
6
   return(result);
7
}

Jetzt wäre noch die Frage, ob man das noch kürzer bekommt ...


VG,
/th.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Frage ist jetzt noch, ob man das ganze irgendwie in ein #define 
verpacken kann....

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Auch im Netz steht es so - in der kompletten Referenz...

Aus der ARMv7 Referenz:

"LDREXH

Load Register Exclusive Halfword derives an address from a base register
value, loads a halfword from memory, zero-extends it to form a 32-bit
word, writes it to a register ..."

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Frage ist jetzt noch, ob man das ganze irgendwie in ein #define
> verpacken kann....

Was genau willst du da noch verpacken?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Dies hier ist compilierbar (ungetestet):
1
#define MY_LDREXB(addr, result)   { __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) ); }
2
3
MY_LDREXB(&sem, val);

Ziel ist es, vom c file wegzukommen.
Das ist nur ein vehikel für das, was die compiler (damals) nicht 
konnten/können.


VG,
/th.

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Dies hier ist compilierbar (ungetestet):

Aber Unsinn.

Was hast du gegen die Inline-Funktion? Präprozessor-Makros sind bei GCC 
vollkommen unnötig, die "static __inline" Variante ist das Optimum.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

sooo .....

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0098a/armccref_cjaeccjj.htm


Where:

ptr

    points to the address of the data to be loaded from memory. To 
specify the type of the data to be loaded, cast the parameter to an 
appropriate pointer type.

Ich denke, damit ist die CMSIS richtig :-)

Geladen wird B/H/W in ein W Register (alles bei ARM ist 32Bit. Danach 
muss man das interpretieren wie gewünscht.
Da ich 16 Bit erwarte, wenn ich 16Bit lade, passt das.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Was hast du gegen die Inline-Funktion? Präprozessor-Makros sind bei GCC
> vollkommen unnötig, die "static __inline" Variante ist das Optimum.

Ich habe nix dagegen. Sie sind sauber, übersichtlich, schnell.
Das static ist hier notwendig gegen includes in verschiedenen Modulen.

Es geht nur darum, Marcus' Vorwurf der Faulheit auszuhebeln ^^

Der gcc Kram für die CMSIS war bei weitem der grösste Batzen Arbeit des 
CMSIS CM3 Core :-) Und natürlich kann man nur das umsetzen, was derzeit 
vom jeweiligen Compiler unterstützt wird. Und da kam nun mal bei asm ein 
"not allowed" vom Compiler ^^

Da das jetzt aber scheinbar funktioniert, werden wir das umsetzten, 
testen und mit der nächsten Version rausgeben.


Btw: Ich würde mir deine Version gerne mal ansehen :-)


VG,
/th

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


Lesenswert?

Random ... schrieb:

> Es ist alles korrekt, trotz des fehlenden =&r funktioniert es

"Absence of evidence is no evidence of absence."

So, wie ich eure Diskussion verstanden habe, ist das =&r sehr wohl
notwendig.  Dass es bei dir erst einmal funktioniert, ist purer
Zufall.  Um den derart funktionierenden Code in nicht (mehr)
funktionierenden umzuwandeln bedarf es dann noch nicht einmal eines
Compilerupgrades (neue Version belegt gerne mal die Register anders),
sondern es genügt bei der inline-Variante dann ganz simpel, dass
sich das Drumrum der aufgerufenen inline-Funktion ändert, schon
knallt's.

Solange deine Bibliotheksfunktion in einem separaten C-File compiliert
worden ist, war das was anderes: sobald das mit einer Compilerversion
funktioniert, hängt das Compilat dann nicht mehr vom restlichen
Sourcecode des Anwenders ab, da es ja erst vom Linker eingebunden wird.

Eine Erklärung für die Wirkung des &-Modifiers (wenn auch für den
AVR, aber sollte für deine ARM-Problematik nachvollziehbar sein) findest
du auch hier:

http://www.nongnu.org/avr-libc/user-manual/inline_asm.html#io_ops

von (prx) A. K. (prx)


Lesenswert?

Jörg Wunsch schrieb:

> Solange deine Bibliotheksfunktion in einem separaten C-File compiliert
> worden ist, war das was anderes:

Sogar in der separat übersetzten Version hat es bereits mal geknallt, 
wie der oben erwähnte Link ins STM32-Forum zeigt.

von (prx) A. K. (prx)


Angehängte Dateien:

Lesenswert?

Random ... schrieb:

> Btw: Ich würde mir deine Version gerne mal ansehen :-)

Bittesehr. Ich hatte CMSIS 1.20 aus der STM32 Lib 3.1.2 als Basis
verwendet und da ist __asm bereits enthalten - aber natürlich nicht die
dazu passenden Funktionen.

Ich hatte für mich den ganzen non-GCC Kram rausgeworfen um den
Überblick zu behalten. Tip: deutliche Trennlinien zwischen den Varianten
der verschiedenen Compiler kosten den Compiler nichts, machen den Code
aber lesbarer.

Ich nehme an, die "naked" Verzierungen der PSP/MSP-Funktionen haben 
einen tieferen Sinn, der sich mir nur noch nicht erschlossen hat. Die 
kann man natürlich nicht exakt so wie im Original inlinen ;-).

von J. V. (janvi)


Lesenswert?

Ist ja nett dass ihr meinen Thread vom STM Forum bereits hier 
diskutiert.
(Hallo prx - beste Grüße aus Stuttgart)

>http://www.st.com/mcu/forums-cat-9006-23.html
>arm-hitex-elf-gcc.exe -c -gdwarf-2 -MD -O0 -trigraphs -mcpu=cortex-m3
>-mthumb -Wall -fsigned-char -mlittle-endian -mfpu=vfp -xc
>-mno-thumb-interwork -mno-tpcs-frame -I.\Source\ -o .\objects\core_cm3.o
>.\Source\core_cm3.c

schliesslich muß nicht jeder selber drüberstolpern. Der -mfpu=vfp switch 
ist für den CM3 übrigens hochgradiger Schwachsinn da keine HW Floatpoint 
und nur deshalb drinnen, weil die Hitex Template den drinnen hatte. 
Sobald die C- Laufzeit Lib verwendet werden soll krachts. Darüber hinaus 
hat der Startup Code aus der periph_lib V3.1.2 noch mehrere weitere 
heftige Fehler worüber ich obigen Thread bereits akutalisiert habe. 
Jedenfalls scheint es von NXP diesbezüglich gar nichts zu geben (?) 
während STM wenigstens noch was fehlerhaftes liefert.

Nun aber der Hammer: Übersetzt man die V3.1.2 mit einem GCC von 
Codesourcery, z.Bsp. mit der Oberfläche von Raisonance, so kriegt man 
gar nichts mit und alles scheint in bester Ordnung zu sein. Eine 
Nachfrage beim Raisonance Support hat ergeben, daß die Entwickler dort 
über die Fehler von STM wissen, diese bei STM bereits reklamiert haben 
und selbst eine korrigiert Version in ihrer Lib eingebaut haben. Daher 
kriegt man als normaler Anwender nix mit. Erst beim F107 mussten die 
einen externen Startup drüber setzen, in der Periph_lib V3.1.2 ist aber 
nur der low density startup Schrott.

Falls jemand weis, warum STM in ihren Beispielen die eigenen Header 
doppelt neu definiert, bitte melden (Bsp. siehe im STM Forum Thread 
"Multiple channel ADC"

Aber genug - ich mach mal weiter oben einen neuen Thread zu Hitex auf.
So langsam krieg ich mit dem Teil nämlich graue Haare und wünsche mir, 
dass die Werbeleute meinem Kunden beibringen warum es nur bei mir ein 
viertel Jahr dauert bis man durchblickt und irgendwas geht ...

von Random .. (thorstendb) Benutzerseite


Lesenswert?

@A.K.:

Vielen Dank. Im Grunde hast du ja nur die Funktionen aus der .c in die 
.h kopiert und mit static inline verziert. Das funzte damals halt nicht 
(irgendwas mit inline assembly not allowed in wasAuchImmer, ist ne 
Weile her.

Wir werden die CMSIS dahingehend überarbeiten.

Btw: Auch bei dir ist kein =&r drin ^^

---
Mal ne generelle Frage zum gcc, da ich - wenn ASM - fast nur mit dem 
armcc unterwegs bin:
Hält sich der gcc-arm an die AAPCS (also r0..r3 = parameter, r0 = 
return) ?
Ich bin nämlich bei meiner recherche damals darüber gestolpert, dass dem 
nicht zwingend so ist ...



VG,
/th.

von J. V. (janvi)


Lesenswert?

Hallo Thorsten - falls du zu den Machern von CMSIS gehörst (bei Keil ?)
Das strex Problem interessiert mich momentan nicht, aber es wäre nett, 
wenn du noch dazu was sagen könntest:

1) in den startup.s fehlende .thumb_func zum setzen des T-Bits
2) Header Hierarchie in Bezug auf das assert_param Makro
3) wiederholte Define von absoluten Registeradressen in main.c 
Beispielen

von (prx) A. K. (prx)


Lesenswert?

Random ... schrieb:

> Btw: Auch bei dir ist kein =&r drin ^^

Ähm....
1
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );

Ich habe das nur dort reingeschrieben wo es erforderlich ist.

> Hält sich der gcc-arm an die AAPCS (also r0..r3 = parameter, r0 =
> return) ?

So weit ich weiss ja.

> Ich bin nämlich bei meiner recherche damals darüber gestolpert, dass dem
> nicht zwingend so ist ...

Details?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

verweise mal hier drauf zur weiteren diskussion:
Beitrag "CMSIS und GNU Support"

VG,
/th.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

>> Ich bin nämlich bei meiner recherche damals darüber gestolpert, dass dem
>> nicht zwingend so ist ...
>
>Details?

Muss ich passen, weiss ich nimmer :-)

Das ist aber der Grund, warum ich das so kompliziert gemacht hab, 
anstatt die Parameter einfach in die Register zu laden (siehe armcc).

z.B. hier, da ist nix drin von wegen parameter und return, da ich vom 
AAPCS ausgehen kann:
1
__ASM uint32_t __get_PRIMASK(void)
2
{
3
  mrs r0, primask
4
  bx lr
5
}


VG,
/th.

von (prx) A. K. (prx)


Lesenswert?

A. K. schrieb:

> Ich habe das nur dort reingeschrieben wo es erforderlich ist.

PS: Und wo ich von janvi drauf gestossen wurde ;-). LDREX könnte wohl 
auch welche brauchen ;-)

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Random ... schrieb:
> Hält sich der gcc-arm an die AAPCS (also r0..r3 = parameter, r0 =
> return) ?

Ja. Auf jeden Fall länger als es CMSIS gibt.

Gruß
Marcus
http://www.doulos.com/arm/

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.