Forum: Mikrocontroller und Digitale Elektronik "NUCLEO"-Borads von GigaDevice


von U.G. L. (dlchnr)


Lesenswert?

Da die Nucleo-Boards von ST ja nicht für Projekte taugen, die vielleicht 
mal kommerziell werden, schaue ich mich nach passenden anderen Boards um 
und bin dabei auf die Boards der Fa. GigaDevice gestossen - die 
"Benamsung" der Boards deutet darauf hin, dass diese mit 
ST-ARM-Cortex-MCUs bestückt sind, aber anscheinend will man das nicht 
explizit sagen? Oder sind dort tatsächlich selbst entwickelte MCUs 
drauf, die nur "zufällig" ähnlich heißen, wie ähnliche ST-MCUs? Wer hat 
Erfahrungen mit diesen Boards - lassen sich die mit Atollic TrueSTUDIO 
programmieren?

von Mannomann (Gast)


Lesenswert?

U.G. L. schrieb:
> lassen sich die mit Atollic TrueSTUDIO programmieren?

Über den Rest kann ich keine Auskunft geben aber diese Frage
darf ich ohne weitere Erläuterungen als dümmlich einstufen.

von User (Gast)


Lesenswert?

GigaDevice stellt STM32-Clone her, ob die legal oder illegal kopiert 
sind ist die Frage.

von U.G. L. (dlchnr)


Lesenswert?

Mannomann schrieb:
> U.G. L. schrieb:
>> lassen sich die mit Atollic TrueSTUDIO programmieren?
>
> Über den Rest kann ich keine Auskunft geben aber diese Frage
> darf ich ohne weitere Erläuterungen als dümmlich einstufen.

Ich kann mir nicht vorstellen, dass sich die mit illegalen 
ST32F103-Clones auf einer ARM Limitied Webseite tummeln können, deshalb 
die Vermutung, dass dort letztlich doch ST-MCUs werkeln und dann wären 
die auch mit Atollic TrueSTUDIO programmierbar!

von ... (Gast)


Lesenswert?

> mit illegalen ST32F103-Clones auf einer ARM Limitied Webseite
> tummeln können

ARM-Know-How kann man bei ARM kaufen. Womoeglich haben sie die
Peripherie bei ST dazugekauft. Oder im Cleanroom nachentwickelt.

von Ralph S. (jjflash)


Lesenswert?

Die Firma GigaDevice wird wohl Controller der Fa. GigaDevice auf ihren 
Boards verwenden (wie bspw. GD32F103 anstelle von STM32F103).

In wie weit ein solchiger Chip ein illegaler Clone ist oder nicht, mögen 
andere bewerten.

Programmieren sollte sich das mit Atollic lassen, manche ST-Link zicken 
mit diesen Controllern jedoch etwas...

von U.G. L. (dlchnr)


Lesenswert?

Hab' mal den GD32E103VB mit dem STM32F104, insbesondere dem STM32F103VB 
bei ein paar Details verglichen:
1
 GD32E103VB: Cortex-M4  mit FPU, 120MHz, 32kB SRAM
2
STM32F103VB: Cortex-M3 ohne FPU,  72MHz, 20kB SRAM
Also eindeutig keine ST-MCUs - insofern erstaunt sogar, dass sich die 
lt. Ralph mit Atollic programmieren lassen!

von Bernd K. (prof7bit)


Lesenswert?

U.G. L. schrieb:
> Ich kann mir nicht vorstellen, dass sich die mit illegalen
> ST32F103-Clones auf einer ARM Limitied Webseite tummeln können, deshalb
> die Vermutung, dass dort letztlich doch ST-MCUs werkeln

Dort werkeln mit Sicherheit die GD32 welches legale STM32-Kompatible 
oder teilweise kompatible Weiterentwicklungen derselben sind. Warum 
sollte GigaDevice teure STM32 verbauen wenn sie selber STM32-kompatible 
MCUs herstellen und vertreiben?

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Ralph S. schrieb:
> In wie weit ein solchiger Chip ein illegaler Clone ist oder nicht, mögen
> andere bewerten.

Mit Sicherheit sind die legal sonst wären sie nicht offiziell bei Keil 
und bei Segger gelistet und supportet. Würde ein Unternehmen das so 
groß(!) auftritt (und auch so groß ist) wie GigaDevice und so 
unverhohlen und ganz offiziell STM-kompatible MCUs unter ihrem eigenen 
Namen verkauft (mitsamt von Grund auf neu(!) geschriebenen Datenblättern 
und Handbüchern und Appnotes und Peripheral-Libraries und Evalboards und 
Beispielcode) und es würde sich rausstellen daß die "Klone" auch nur 
einen Hauch von illegal sind würde der Skandal eigentlich Wellen 
schlagen müssen (Erschütterungen im Grundgefüge geradezu) die groß genug 
sind sind daß man schonmal was davon gehört haben müsste.

Ich halte es für vollkommen unwahrscheinlich daß hier irgendwas illegal 
ist, das wäre 12 Nummern größer als jeder bisherige Chinalklon, das wäre 
vom Umfang und von der Qualität eine völlig neue Dimension!

von Mike R. (thesealion)


Lesenswert?

U.G. L. schrieb:
> Da die Nucleo-Boards von ST ja nicht für Projekte taugen, die vielleicht
> mal kommerziell werden, schaue ich mich nach passenden anderen Boards um
> und bin dabei auf die Boards der ...


Warum taugen denn die Nucleo Boards nicht für kommerzielle Projekte?

(Ich meine ich würde sowieso nie ein Produkt mit eingebautem Prototypen 
Board entwickeln wollen, aber als schneller Einstieg sind die doch nicht 
verkehrt.)

von Bernd K. (prof7bit)


Lesenswert?

U.G. L. schrieb:
> Hab' mal den GD32E103VB mit dem STM32F104, insbesondere dem
> STM32F103VB
> bei ein paar Details verglichen: GD32E103VB: Cortex-M4  mit FPU, 120MHz,
> 32kB SRAM
> STM32F103VB: Cortex-M3 ohne FPU,  72MHz, 20kB SRAM
> Also eindeutig keine ST-MCUs - insofern erstaunt sogar, dass sich die
> lt. Ralph mit Atollic programmieren lassen!

Vergleich mal die Reference manuals, geh mal alle Peripheriegeräte und 
Register einzeln durch, die sind abwärtskompatibel bis aufs letzte Bit. 
Aber die Handbücher sind komplett neu geschrieben, keine einzige Zeile 
copy&paste.

Oftmals hilft es auch das Handbuchkapitel für ein Peripheriegerät mal 
beim jeweils anderen Hersteller zu lesen, dort ist der selbe Sachverhalt 
nochmal mit anderen Worten formuliert und anderen Diagrammen 
illustriert, bei Verständnisproblemen kann das helfen.

Manche Sachen sind auch leicht aufgebohrt, zum Beispiel der 
Flashcontroller bei STM32 kann nur 16-Bit schreiben, der von GigaDevice 
funktioniert exakt genauso bis aufs letzte Bit, unterstützt aber 16 
und 32 Bit Schreibzugriffe beim Programmieren.

Die haben wahrscheinlich einfach die selben IP-Cores gekauft wie ST, 
teilweise in neuerer Version und haben sie genauso zusammengestöpselt 
daß ein kompatibles Produkt entsteht. Oder vielleicht kauft auch ST sein 
ganzes Zeug die ganze Zeit über schon bei GigaDevice und hängt es nur 
nicht an die große Glocke, daher eventuell das nachhaltige Schweigen 
angesichts des rosa Elefanten im Raum?

Teilweise hat GigaDevice auch Chips für die es kein Äquivalent von ST 
gibt, die Peripheriegeräte kommen einem aus vielen anderen STM32 bekannt 
und vertraut vor aber die Zusammenstellung in der konkreten Form ist 
neu.


In der Keil-IDE werden die auch direkt supportet, zumindest gibt es bei 
Keil die entsprechenden "Device Family Packs" für die IDE zum Download. 
Auch der J-Link unterstützt viele davon direkt ohne daß man ihm einen 
kompatiblen STM vorgaukeln müsste.

: Bearbeitet durch User
von U.G. L. (dlchnr)


Lesenswert?

Mike R. schrieb:
>
> Warum taugen denn die Nucleo Boards nicht für kommerzielle Projekte?
>

Die Lizenz der NUCLEOs verbietet einen Weiterverkauf in einem Produkt.

von Mehmet K. (mkmk)


Lesenswert?

Vor geraumer Zeit hatte ich mich auch mal für die GigaDevices 
interessiert: unglaublich günstige Preise.
Bin dann aber bei ST geblieben.

Soweit ich es noch in Erinnerung habe, haben diese MCUs ihre 
Pogrammdaten in einem SerialFlash, die beim Programmstart ins SRam 
kopiert werden; deshalb haben die GigaDevices auch keine Wait-States.
Ein Bonus dieser Architektur ist, dass man neben Flash und SRam nun 
zusaetzlich einen internen DataFlash-Bereich hat, der bis zu 2MB 
betragen kann.
Worauf ich aber keine Antwort gefunden habe, war die Frage, ob man die 
Dinger auch mit dem ST-Link ansprechen kann.
Mit dem J-Link soll es aber gehen.

von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:
> Soweit ich es noch in Erinnerung habe, haben diese MCUs ihre
> Pogrammdaten in einem SerialFlash, die beim Programmstart ins SRam
> kopiert werden; deshalb haben die GigaDevices auch keine Wait-States.

Wo hast Du denn das her?

von Mehmet K. (mkmk)


Lesenswert?

Bernd K. schrieb:
> Wo hast Du denn das her?

Wie gesagt, das Ganze liegt etwas in der Vergangenheit.

Edit: werde bei Gelegenheit in meine Unterlagen schauen und wenn ich was 
finde hier posten.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Hast Recht, habs gefunden:

https://zeptobars.com/en/read/GD32F103CBT6-mcm-serial-flash-Giga-Devices

Das ist ja witzig! Mir ist schon eine gewisse Verzögerung aufgefallen 
beim Start aber das war nicht kritisch für meine Anwendung und ich habs 
auf das Warten auf die PLL in der SystemInit abgetan und nicht weiter 
drüber nachgedacht. Ich werd mal ein Pin-Wackeln in meinen Startup 
einbauen vor der SystemInit und messen wie lange das dauert.

Aber sie haben es hinbekommen das vollkommen transparent zu 
implementieren, ich hab kürzlich einen Bootloader portiert und das 
Schreiben des Flash funktioniert genau so und verhält sich genau so wie 
man es erwarten würde:

Löschen: FMC freischalten mit dem Unlock-key, PER bit setzen, adresse 
setzen, START bit setzen auf BUSY bit warten, LK Bit wieder setzen.

Schreiben: FMC freischalten mit dem Unlock-key, PG-Bit setzen, Daten 
ganz normal an die Adresse schreiben (auch 32-Bit zugriff ist erlaubt, 
jetzt ist mir auch klar warum, ist ja ganz normales RAM!), BUSY bit 
warten, nächstes Wort schreiben oder LK Bit wieder setzen.

Die Adressen sind ganz normal entweder ab 0x0 oder ab 0x8000000, alles 
verhält sich so wie man es erwarten wurde wenn das Flash tatsächlich an 
der Adresse wäre, es ist völlig transparent. Auch im Datenblatt oder im 
Handbuch ist nichts dergleichen erwähnt.

: Bearbeitet durch User
von Mehmet K. (mkmk)


Lesenswert?

Genau diesen Link wollte ich soeben posten ... aber Du warst schneller.
Es waren aber noch andere Einzelheiten, die mich davon abgehalten haben, 
auf GD32 umzuschwenken. Könnte jetzt diese aber nicht mehr aufzaehlen.

Edit: Was mir aber einen gewaltigen Eindruck hinterlassen hat, waren 
deren Libraries und Beispiel-Programme. Unglaublich, mit wieviel Hingabe 
sie diese erstellt haben. Kompliment.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:

> Edit: Was mir aber einen gewaltigen Eindruck hinterlassen hat, waren
> deren Libraries. Unglaublich, mit wieviel Hingabe sie diese erstellt
> haben. Kompliment.

Die sind aber leider noch im alten Stil, die Registerdefinitionen 
benutzen je ein Makro pro Register anstatt das im CMSIS-Stil mit structs 
zu machen. Die Abstraktion in den Libraries ist sehr dünn, Funktionen 
kapseln meistenteils nur ein einzelnes Bit setzen oder löschen, ich 
finde den Umgang damit etwas holprig, wenn man im Handbuch das Bit 
gefunden hat das man setzen oder löschen will muss man erst noch 
nachschauen welche Library-Funktion sie dafür vorgesehen haben um das zu 
machen und eventuell welches Enum man da reinfüttern muss um das zu 
bewirken.

Andererseits ist es aber zum Glück auch so simpel daß man Beispielcode 
der die Lib benutzt komplett von Hand durchgehen kann um zu sehen in 
welcher Reihenfolge man welche Register initialisieren muss um eine 
Peripherie zum Laufen zu bekommen ohne sich durch tausende von Zeilen zu 
quälen.

Und die Beispielprogramme für die Eval-Boards haben teilweise auch ein 
paar üble Bugs und teilweise enthalten sie chinesische Strings in 
irgendeiner chinesischen Windowskodierung anstelle von UTF8 und ein 
Compiler auf nem europäischen Rechner beschwert sich dann weil 
irgendwelche Stringliterale keinen Sinn ergeben.

Zum Glück gibts aber auch SVD-Dateien mit denen man sich die Headerfiles 
im gewohnten CMSIS Format selber erzeugen kann und auf deren Peripheral 
Library kann man dann komplett verzichten.

von Mehmet K. (mkmk)


Lesenswert?

Bist Du ganz auf die GD32-Serie umgestiegen? Oder ist es nur ein 
Spielzeug für die grauen Zellen?

von Bernd K. (prof7bit)


Lesenswert?

Ich werd mal versuchen die Zeiten für den Startup, den Page-Erase und 
das Programmieren von einem oder mehreren Worten ganzen Pages genau zu 
stoppen, ob man da irgendwelche störenden Abweichungen zu "normalem" 
Flash beobachten kann.

Ich werde allerdings einen GD32F350G6 verwenden (Cortex-M4 [leider aber 
ohne FPU!] mit 32k Flash in 1k Sektoren und 6k RAM) weil das der ist mit 
dem ich gerade zu tun habe (haben muss weil er nur 50 Cent kostet oder 
sowas in der Art). Der ähnlichste ST den ich bis jetzt gefunden habe 
wäre ein STM32F301 (aber nur ganz grob, hab noch nicht alles verglichen)

Vorher war ich mit Freescale (jetzt NXP) unterwegs.

von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:
> Bist Du ganz auf die GD32-Serie umgestiegen?

Cheffe kann den GD32F350C6 wohl irgendwo für 50 Cent das Stück besorgen, 
also fangen wir an in Zukunft den als Brot-und-Butter-MCU zu benutzen, 
auch weil der alte NXP (Freescale) der vorher diese Position innehatte 
immer teurer wurde.

Mit Eclipse/gcc/J-link hab ich ihn mittlerweile komplett im Griff, alles 
funktioniert, war eigentlich kein größeres Problem. Mal schaun wie er 
sich macht.

Kleine Layouts werden schonmal schwieriger werden hab ich mir vom 
Kollegen sagen lassen da man Vcc auf zwei gegenüberliegenden Seiten 
anschließen muß, man kann auch nicht irgendwie tricksen mit nem freien 
Portpin daneben, er wird überhaupt nicht booten wenn Analog-VCC nicht 
angeschlossen ist weil dann kein Takt läuft. Das ist schonmal ärgerlich.

von Mehmet K. (mkmk)


Lesenswert?

Waere nett, wenn Du hier oder in einem neuen Tread vom Erfolg oder 
Misserfolg berichten könntest.
Noch 'ne Frage: wie verhaelt sich der ST-Link mit diesen MCUs?

von U.G. L. (dlchnr)


Lesenswert?

Bezugsquellen für die NUCLEO-Alternativen von GigaDevice scheint es aber 
in Deutschland oder EU-Ausland nicht zu geben, oder ist da schon jemand 
fündig geworden?

Gleiches gilt, soweit ich das sehe, auch für die XNUCLEO-Boards von 
Waveshare!?

Kennt jemand andere Alternativen zu den NUCLEO-Boards mit ST-MCUs und 
dem Arduino typischen Header-Footprint?

von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:
> Noch 'ne Frage: wie verhaelt sich der ST-Link mit diesen MCUs?

Das muß jemand anderes beantworten, ich benutze nur J-Link. Der J-Link 
unterstützt viele von denen nativ aber noch nicht alle, dann kann man 
aber meist tricksen und einen anderen STM32 oder GD32 wählen der 
"zufällig" den selben FMC und die selbe Sektorgröße hat und dann gehts.

von Bernd K. (prof7bit)


Lesenswert?

GD32F350G6 (32k Flash):

28,5ms von Power-on bis zum Eintritt in den Reset-Vektor.
Während dieser Zeit braucht er etwa 2mA mehr als im sleep ("wfi").

(selbst gemessen denn im Datenblatt gibt es keine Angabe darüber).

: Bearbeitet durch User
von Mehmet K. (mkmk)


Lesenswert?

Bernd K. schrieb:
> 28,5ms

Ist alles andere als tragisch (zumindest für meine Anwendungen). Aber 
wie oben schon angedeutet, würden mich Deine Langzeit-Erfahrungen 
brennend interessieren.
Also nicht vergessen, hin und wieder von Deinen Erfolgen bzw. 
Misserfolgen hier zu berichten.

von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:
> würden mich Deine Langzeit-Erfahrungen
> brennend interessieren.

Wie der Name schon sagt wird das einige Zeit dauern.

Da ich aber mein Mundwerk sowieso nicht halten kann wenn mich 
irgendetwas etwas zutiefst verärgert oder außerordentlich erfreut werden 
vermutlich in unregelmäßigen Abständen Lobgesänge oder Verwünschungen zu 
lesen sein. Solange ich gar nichts sage ist alles im grünen Bereich ;-)

von Bernd K. (prof7bit)


Lesenswert?

Bernd K. schrieb:
> GD32F350G6 (32k Flash):
>
> 28,5ms

21,5ms

Ich hab mich vertippt! Es sind nur 21,5ms.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Bernd K. schrieb:
> Kleine Layouts werden schonmal schwieriger werden hab ich mir vom
> Kollegen sagen lassen da man Vcc auf zwei gegenüberliegenden Seiten
> anschließen muß, man kann auch nicht irgendwie tricksen mit nem freien
> Portpin daneben, er wird überhaupt nicht booten wenn Analog-VCC nicht
> angeschlossen ist weil dann kein Takt läuft. Das ist schonmal ärgerlich.

Ist bei den "echten" STM32 doch auch so, dass die Taktomäne (PLL) am 
AVCC hängt.

von Bernd K. (prof7bit)


Lesenswert?

Mw E. schrieb:
> Ist bei den "echten" STM32 doch auch so

Bei uns wird/wurde die ganze Zeit Kinetis L (Freescale, NXP) genutzt, 
die haben sowas nicht, deshalb die Umgewöhnung.

Hier ist übrigens schonmal was was mir säuerlich aufstößt:

* In Eclipse kann ich zwar das Device-Family-Pack für diesen Prozessor 
(und auch alle anderen von GigaDevice) installieren aber dennoch bekomm 
ich beim Debuggen nicht die Registeransicht der Peripheriegeräte. Ich 
weiß dass im Pack eine svd-Datei drin ist weil ich mir mal spaßeshalber 
die CMSIS-Headerfiles generieren hab lassen, vielleicht ist sie im 
falschen Ordner oder hat den falschen Namen so daß Eclipse sie nicht 
findet. Das ist schonmal ein bisschen ärgerlich, da bin ich schon etwas 
stärker verwöhnt von der IDE-Unterstützung bei Kinetis.

* Ebenfalls sauer stieß mir auf daß kein Startup-code und kein 
Linkerscript für gcc mitgeliefert wird, ich musste mir die bei nem 
anderen Prozessor klauen und passend machen. Hätt ich nicht schon Übung 
mit sowas hätte das auch wieder unnötig Zeit und Nerven gekostet. Andere 
Hersteller brechen sich schließlich auch keinen Zacken aus der Krone 
wenn sie funktionierenden gcc code beilegen.

* Die Unterstützung durch J-Link für neuere GD32 gibts noch nicht, hier 
könnte der GigaDevice ruhig mithelfen, J-Link ist das Standardwerkzeug 
schlechthin, den kann man nicht einfach ignorieren. Als Nutzer kann ich 
es provisorisch hinfrickeln indem ich dem J-Link nen ausreichend 
kompatiblen anderen Typen vorgaukle aber das ist keine Dauerlösung und 
reiner Zufall daß ST zufällig ähnliche oder weitgehend kompatible 
Prozessoren baut.


Kleinere Ärgernisse:

* Ich hab noch kein Anwenderforum mit Tech-Support gefunden so wie 
namhafte Hersteller das normalerweise betreiben. Zumindest nicht auf der 
englischsprachigen Seite für westliches Publikum. Wenn ich ein Problem 
hätte und danach googeln würde hätte ich 100% chinesische Treffer in der 
Ergebnisliste, mit fremdländischen Schriftzeichen die mir Unbehagen 
auslösen. Es scheint mir essentiell zu sein sich den ähnlichsten STM32 
rauszusuchen und bei Verständnisproblemen stattdessen nach STM32 zu 
googeln oder parallel zum Handbuch auch das entsprechende STM32-Handbuch 
zu lesen.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Bernd K. schrieb:
> In Eclipse kann ich zwar das Device-Family-Pack für diesen Prozessor
> (und auch alle anderen von GigaDevice) installieren aber dennoch bekomm
> ich beim Debuggen nicht die Registeransicht der Peripheriegeräte.

Das von GigaDevice gelieferte SVD ist nicht wohlgeformt!

Zum Beispiel (nach Installation des Device Family packs) in der Datei:

~/Packages/GigaDevice/GD32F3x0_DFP/1.0.1/SVD/GD32F3x0.svd

befinden sich ganz am Anfang 2 Leerzeichen:
1
bernd@bernd:~/Packages/GigaDevice/GD32F3x0_DFP/1.0.1/SVD $ head -4 GD32F3x0.svd 
2
  <?xml version="1.0" encoding="utf-8" standalone="no"?>
3
<device schemaVersion="1.1"
4
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
5
xs:noNamespaceSchemaLocation="CMSIS-SVD_Schema_1_1.xsd">

Diese beiden Leerzeichen am Anfang müssen entfernt werden, dann 
funktioniert das Peripheral View in Eclipse wieder.

Das scheint ein systematischer Fehler zu sein, alle Packs von denen 
enthalten eine svd mit zwei Leerzeichen am Anfang. Ich werd das jetzt 
mal an deren Support mailen, mal sehen ob man mit denen reden kann.

PS:
Ausschlaggebend für die angezeigten Register im Peripheral view ist 
welches Device in den Project-Properties eingestellt ist, NICHT in den 
Debuggereinstellungen, dort kann ein anderes Device angegeben werden um 
den J-Link zur Mitarbeit zu überreden, das hat auf das Peripheral View 
keine Auswirkungen.

: Bearbeitet durch User
von Bernd K. (prof7bit)



Lesenswert?

1kB löschen und 512B schreiben dauert 43ms
512B schreiben ohne löschen dauert 5.5ms

Die Zeiten schwanken etwas, ich hab auch Löschungen von 39ms gesehen und 
schreiben in weniger als 5ms.

Da ist außerdem noch Entschlüsseln und Prüfsumme drin weil ich das 
schnell mal mit meinem Bootloader gemessen habe, das wollt ich jetzt 
nicht extra rauswerfen nur um das zu messen aber das fällt auch kaum ins 
Gewicht.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Das mitgelieferte Headerfile beinhaltet diese lustige Definition die 
ganz frech mit stdbool.h kollidiert, ich frag mich was für ein komisches 
Kraut die dort geraucht haben, stdint.h wird dort ausgiebig benutzt aber 
mit stdbool.h haben sie es absichtlich inkompatibel gemacht und der 
Compiler meckert natürlich lautstark wenn man es mit eigenem Code 
mischen will der für stdbool.h geschrieben wurde!

1
typedef enum {FALSE = 0, TRUE = !FALSE} bool;


Zum Glück kann man diese Zeile gefahrlos auskommentieren und alles aus 
deren Library kompiliert danach immer noch denn diese alberne 
bool-Attrappe wird dort an keiner einzigen Stelle verwendet!

: Bearbeitet durch User
von UweBonnes (Gast)


Lesenswert?

Bernd K. schrieb:
>...
>
>
1
> typedef enum {FALSE = 0, TRUE = !FALSE} bool;
2
>
>
>
Das kam frueher in den STM Header auch vor. Dort muss auch schon 
besonders Rauchzeug rumgehen, um Dinge wie
stm32f078xx.h:#define PERIPH_BASE           ((uint32_t)0x40000000U)
zu schreiben

von Bernd K. (prof7bit)


Lesenswert?

UweBonnes schrieb:
> Dort muss auch schon
> besonders Rauchzeug rumgehen, um Dinge wie
> stm32f078xx.h:#define PERIPH_BASE           ((uint32_t)0x40000000U)
> zu schreiben

An der Zeile kann ich jetzt nichts sonderlich verwerfliches finden. Bei 
gd32 steht da:
1
#define APB1_BUS_BASE         ((uint32_t)0x40000000U)       /*!< apb1 base address                */
2
#define APB2_BUS_BASE         ((uint32_t)0x40010000U)       /*!< apb2 base address                */
3
#define AHB1_BUS_BASE         ((uint32_t)0x40020000U)       /*!< ahb1 base address                */
4
#define AHB2_BUS_BASE         ((uint32_t)0x48000000U)       /*!< ahb2 base address

Meinst Du die Tatsache daß das U suffix und der Cast doppelt gemoppelt 
sind? Davon gibts unzählige Beispiele, das stört mich jetzt nicht 
sonderlich, es ändert ja nichts an der Benutzbarkeit, höchstens daß beim 
Makro-Expandieren dann oft riesen Rattenschwänze rauskommen aber die 
bekommt ja keiner zu sehen außer dem Compiler.

Oder was meinst Du konkret?

von Uwe Bonnes (Gast)


Lesenswert?

Durch das uint32_t kannst man z.B. im Preprozessor nicht mehr 
herausbekommen, an welchen Bus  eine IP , z.B. USART1 haengt

#if USART1 < AHB2_BUS_BASE

geht nicht mehr wegen dieses ueberfluessigen uint32_t

von Bernd K. (prof7bit)


Lesenswert?

Uwe Bonnes schrieb:
> Durch das uint32_t kannst man z.B. im Preprozessor nicht mehr
> herausbekommen, an welchen Bus  eine IP , z.B. USART1 haengt

Die mitgelieferten Header/Libraries bei GD32 enthalten Definitionen und 
Funktionen um ein beliebiges Peripheriegerät einzuschalten (oder andere 
Sachen zu machen), unabhängig davon an welchem Bus es hängt. Zu diesem 
Zweck ist für jedes Peripheriegerät eine Konstante definiert die in den 
oberen Bits den Registeroffset und in den unteren Bits die Bitposition 
im betreffenden Register der RCU enthält.
1
#define RCU_REGIDX_BIT(regidx, bitpos)      (((uint32_t)(regidx)<<6) | (uint32_t)(bitpos))
2
3
typedef enum
4
{
5
    ...
6
    RCU_USART1  = RCU_REGIDX_BIT(IDX_APB1EN, 17U),
7
    ...
8
}rcu_periph_enum;

Und eine Funktion die die Arbeit tut:
1
void rcu_periph_clock_enable(rcu_periph_enum periph)
2
{
3
    RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
4
}

periph enthält alle Informationen die nötig sind um das Register und das 
Bit zu ermitteln die für dieses Gerät zuständig sind, RCU_REG_VAL() und 
RCU_BIT_POS() popeln das da wieder einzeln raus:
1
#define RCU_BASE              (AHB1_BUS_BASE + 0x00001000U)
2
#define RCU                   RCU_BASE
3
#define REG32(addr)           (*(volatile uint32_t *)(uint32_t)(addr))
4
5
#define RCU_REG_VAL(periph)   (REG32(RCU + ((uint32_t)(periph)>>6)))

und
1
#define RCU_BIT_POS(val)      ((uint32_t)(val) & 0x1FU)
2
#define BIT(x)                ((uint32_t)((uint32_t)0x01U<<(x)))

Das obige ist alles schon vorhanden, da muss ich mir keinen Wolf mehr 
tippen, da schreib ich einfach:
1
rcu_periph_clock_enable(RCU_USART1);

Und fertig. Ich finde das gar nicht mal so unclever denn das schrumpft 
hinterher in jedem Falle alles zuverlässig zusammen zu sowas:
1
 8001174:  4a03        ldr  r2, [pc, #12]  ; (8001184)
2
 8001176:  6813        ldr  r3, [r2, #0]
3
 8001178:  f443 3300   orr.w  r3, r3, #131072  ; 0x20000
4
 800117c:  6013        str  r3, [r2, #0]
5
 ...
6
 8001184:  4002101c   .word  0x4002101c

Warum willst Du im Preprozessor wissen an welchem Bus der USART hängt?

Und falls wirklich nötig kannst Du das if nicht auch einfach in C 
hinschreiben, das wäre wahrscheinlich auch einfacher zu lesen als 
bedingte Kompilierung überall und da der Ausdruck in der Bedingung ja 
schon zur Compilezeit bekannt und konstant ist wird er im Falle von 
false an der Stelle überhaupt keinen Code erzeugen.

Das ganze obige Makrogedöns könnte man wahrscheinlich auch einfach in C 
hinschreiben mit inline-Funktionen, dank Constant-Propagation würde sich 
das auch alles genauso zur Compilezeit komplett in Wohlgefallen auflösen 
und am Ende nur noch die obigen paar Zeilen asm stehen bleiben.

: Bearbeitet durch User
von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Interessant, dass ich es ohne zu wissen bei meinen STM32 Projekten so 
gelöst habe wie GigaDevices.

Nur was der STM32 HAL da wieder baut ist totale Grütze.
Wenn man die Hardware initialisiert schaltet der HAL nicht den RCC Takt 
dafür ein, nein das muss man per Hand mit nem __makro 
(__USART1_CLK_ENABLE) vorher selber machen.

von Uwe Bonnes (Gast)


Lesenswert?

Bernd K. schrieb:

> Das obige ist alles schon vorhanden, da muss ich mir keinen Wolf mehr
> tippen, da schreib ich einfach:
>
>
1
> rcu_periph_clock_enable(RCU_USART1);
2
>
>

> Und fertig. Ich finde das gar nicht mal so unclever denn das schrumpft
> hinterher in jedem Falle alles zuverlässig zusammen zu sowas:
>

Und was machts Du wenn Deine Funktion sowohl mit USART1 als auc mit 
USAR2,... funktionieren soll?

von Bernd K. (prof7bit)


Lesenswert?

Uwe Bonnes schrieb:
> Und was machts Du wenn Deine Funktion sowohl mit USART1 als auc mit
> USAR2,... funktionieren soll?

Das ist nicht meine Funktion sondern wird so von denen geliefert und die 
funktioniert so wie sie gemacht ist logischerweise mit jedem beliebigen 
Peripheriegerät. Oder versteh ich Deine Frage jetzt irgendwie falsch?

: Bearbeitet durch User
von Uwe Bonnes (Gast)


Lesenswert?

Du benutzt rcu_periph_clock_enable(RCU_USART1); irgendwo, in einer 
Deiner Funktionen. Um Deine Funktion geht es. Was, wenn diese Funktion 
auch mit anderen U(S)ARTs umgehen koennen soll?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Dann kricht die Funktion rcu_periph_clock_enable() eben ein anderen enum 
member übergeben.
Der Hauptfunktion muss man ja auch sagen welcher UART das sein soll.

Aufgeschmissen biste da beim STM32 HAL, der hat das nur als Makro 
"__USART1_CLK_ENABLE"

Also echt, Leute gibts...

von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:
> Edit: Was mir aber einen gewaltigen Eindruck hinterlassen hat, waren
> deren Libraries und Beispiel-Programme. Unglaublich, mit wieviel Hingabe
> sie diese erstellt haben. Kompliment.

Aaaalso...

Ich ich habe jetzt mittlerweile ein paar Tage Vollzeit an dem Teil 
herumgemacht. Und jetzt denke ich ist ein an der Zeit mal ein paar enste 
Worte zu der besagten Library zu sagen.

Ich gebe ein Beispiel:

Ausgehend von Beispielcode soll ich solche Sachen machen (unter 
anderem):
1
    timer_oc_parameter_struct tops;
2
    tops.ocpolarity         = TIMER_OC_POLARITY_HIGH;
3
    tops.outputstate        = TIMER_CCX_ENABLE;
4
    timer_channel_output_config(TIMER1, TIMER_CH_0, &tops);

Und auf der rechten Seite hab ich das Timer-Kapitel im Handbuch 
aufgeschlagen. was geschieht hier? Schauen wir nach:
1
/*!
2
    \brief      configure TIMER channel output function
3
    \param[in]  timer_periph: please refer to the following parameters
4
    \param[in]  channel: 
5
      \arg        TIMER_CH_0: TIMER channel 0(TIMERx(x=0..2,13..16))
6
      \arg        TIMER_CH_1: TIMER channel 1(TIMERx(x=0..2,14))
7
      \arg        TIMER_CH_2: TIMER channel 2(TIMERx(x=0..2))
8
      \arg        TIMER_CH_3: TIMER channel 3(TIMERx(x=0..2))
9
    \param[in]  ocpara: TIMER channeln output parameter struct
10
                outputstate: TIMER_CCX_ENABLE,TIMER_CCX_DISABLE
11
                outputnstate: TIMER_CCXN_ENABLE,TIMER_CCXN_DISABLE
12
                ocpolarity: TIMER_OC_POLARITY_HIGH,TIMER_OC_POLARITY_LOW
13
                ocnpolarity: TIMER_OCN_POLARITY_HIGH,TIMER_OCN_POLARITY_LOW
14
                ocidlestate: TIMER_OC_IDLE_STATE_LOW,TIMER_OC_IDLE_STATE_HIGH
15
                ocnidlestate: TIMER_OCN_IDLE_STATE_LOW,TIMER_OCN_IDLE_STATE_HIGH
16
    \param[out] none
17
    \retval     none
18
*/
19
void timer_channel_output_config(uint32_t timer_periph, uint16_t channel, timer_oc_parameter_struct* ocpara)
20
{
21
    switch(channel){
22
    /* configure TIMER_CH_0 */
23
    case TIMER_CH_0:
24
        /* reset the CH0EN bit */
25
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
26
        /* set the CH0EN bit */
27
        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->outputstate;
28
        /* reset the CH0P bit */
29
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0P);
30
        /* set the CH0P bit */
31
        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->ocpolarity;
32
33
        if((TIMER0 == timer_periph) || (TIMER14 == timer_periph) || (TIMER15 == timer_periph) || (TIMER16 == timer_periph)){
34
            /* reset the CH0NEN bit */
35
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NEN);
36
            /* set the CH0NEN bit */
37
            TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->outputnstate;
38
            /* reset the CH0NP bit */
39
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NP);
40
            /* set the CH0NP bit */
41
            TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->ocnpolarity;
42
            /* reset the ISO0 bit */
43
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO0);
44
            /* set the ISO0 bit */
45
            TIMER_CTL1(timer_periph) |= (uint32_t)ocpara->ocidlestate;
46
            /* reset the ISO0N bit */
47
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO0N);
48
            /* set the ISO0N bit */
49
            TIMER_CTL1(timer_periph) |= (uint32_t)ocpara->ocnidlestate;
50
        }
51
        TIMER_CHCTL0(timer_periph) &= ~(uint32_t)TIMER_CHCTL0_CH0MS;
52
        break;
53
    /* configure TIMER_CH_1 */
54
    case TIMER_CH_1:
55
        /* reset the CH1EN bit */
56
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
57
        /* set the CH1EN bit */
58
        TIMER_CHCTL2(timer_periph) |= (uint32_t)(ocpara->outputstate << 4U);
59
        /* reset the CH1P bit */
60
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1P);
61
        /* set the CH1P bit */
62
        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocpolarity) << 4U);
63
64
        if(TIMER0 == timer_periph){
65
            /* reset the CH1NEN bit */
66
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1NEN);
67
            /* set the CH1NEN bit */
68
            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->outputnstate) << 4U);
69
            /* reset the CH1NP bit */
70
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1NP);
71
            /* set the CH1NP bit */
72
            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnpolarity) << 4U);
73
            /* reset the ISO1 bit */
74
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO1);
75
            /* set the ISO1 bit */
76
            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 2U);
77
            /* reset the ISO1N bit */
78
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO1N);
79
            /* set the ISO1N bit */
80
            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnidlestate) << 2U);
81
        }
82
        
83
        if(TIMER14 == timer_periph){
84
            /* reset the ISO1 bit */
85
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO1);
86
            /* set the ISO1 bit */
87
            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 2U);
88
        }
89
        
90
        TIMER_CHCTL0(timer_periph) &= ~(uint32_t)TIMER_CHCTL0_CH1MS;
91
        break;
92
    /* configure TIMER_CH_2 */
93
    case TIMER_CH_2:
94
        /* reset the CH2EN bit */
95
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2EN);
96
        /* set the CH2EN bit */
97
        TIMER_CHCTL2(timer_periph) |= (uint32_t)(ocpara->outputstate << 8U);
98
        /* reset the CH2P bit */
99
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2P);
100
        /* set the CH2P bit */
101
        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocpolarity) << 8U);
102
103
        if(TIMER0 == timer_periph){
104
            /* reset the CH2NEN bit */
105
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2NEN);
106
            /* set the CH2NEN bit */
107
            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->outputnstate) << 8U);
108
            /* reset the CH2NP bit */
109
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2NP);
110
            /* set the CH2NP bit */
111
            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnpolarity) << 8U);
112
            /* reset the ISO2 bit */
113
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO2);
114
            /* set the ISO2 bit */
115
            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 4U);
116
            /* reset the ISO2N bit */
117
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO2N);
118
            /* set the ISO2N bit */
119
            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnidlestate) << 4U);
120
        }
121
        TIMER_CHCTL1(timer_periph) &= ~(uint32_t)TIMER_CHCTL1_CH2MS;
122
        break;
123
    /* configure TIMER_CH_3 */
124
    case TIMER_CH_3:
125
        /* reset the CH3EN bit */
126
        TIMER_CHCTL2(timer_periph) &=(~(uint32_t)TIMER_CHCTL2_CH3EN);
127
        /* set the CH3EN bit */
128
        TIMER_CHCTL2(timer_periph) |= (uint32_t)(ocpara->outputstate << 12U);
129
        /* reset the CH3P bit */
130
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH3P);
131
        /* set the CH3P bit */
132
        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocpolarity) << 12U);
133
134
        if(TIMER0 == timer_periph){
135
            /* reset the ISO3 bit */
136
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO3);
137
            /* set the ISO3 bit */
138
            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 6U);
139
        }
140
        TIMER_CHCTL1(timer_periph) &= ~(uint32_t)TIMER_CHCTL1_CH3MS;
141
        break;
142
    default:
143
        break;
144
    }
145
}

Holla, die Waldfee! Aber OK, das meiste kann der Compiler direkt 
wegoptimieren, ist ja alles zur Kompilezeit konstant.

Aber was macht der da jetzt konkret, was macht TIMER_CCX_ENABLE? Ich 
muss den Code der Library studieren um zu sehen daß da in dem Fall 
dieses Bit
1
#define TIMER_CHCTL2_CH0EN               BIT(0)              /*!< channel 0 enable */

gesetzt wird. Ja klar, jetzt im Nachhinein ist auch klar warum die das 
so genannt haben aber diese ganzen Konstanten für die Libraryfunktionen 
kollidieren mit dem Namensraum und der Namenskonvention für 
Registerbits, das ist ein einziges unleserliches Verwirrspiel!

Ws ist wenn ich den umgekehrten Weg gehen will? Ich sehe im Handbuch daß 
ich FOOBIT in BAZREG von PERIPH setzen will, ohne die Library hätte ich 
einfach gesagt
1
PERIPH_BAZREG |= PERIPH_BAZREG_FOOBIT;

Oder im CMSIS-Stil:
1
PERIPH->BAZREG |= PERIPH_BAZREG_FOOBIT_Msk;

Da kann ich mich vorwärts wie rückwärts zwischen Handbuch und Code 
bewegen und sehe sofort was ich gemacht habe.

Mit dieser Library jedoch müsste ich wenn ich sie verwenden wollte:
* raten anhand des Funktionsnamens on es das gewünschte tut oder
* den code der Library durchsuchen nach einer Erwähnung des Registers 
und/oder des Bits
* den code und den header studieren um herauszufinden was ich der 
Funktion übergeben muss um das gewünschte Bit zu sezen.

Das ist sehr ermüdend!

Reverse-Engineering des Beispielcode um zurück zu den Registern und Bits 
zu kommen ist genauso ermüdend und nervenaufreibend.

* Fast alle diese Libraryfunktionen setzen nur einzelne Bits
* Die Parameter die man den Funktionen übergibt sind meist eben jene 
bits, aber leider getarnt unter anderen Namen, und nochdazu verseuchen 
sie mit ihrer chaotischen Benamung komplett den Namensraum für die 
echten Bits und Register und machen Autocomplete zum Glücksspiel!

Manche Funktionen sind ganz nett, wie zum Beispiel die oben schon 
erwähnten rcu_* Funktionen oder zum Beipsiel die universelle Berechnung 
der Baudrate eines beliebigen USART bei beliebiger Taktkonfiguration, 
aber 99% der Funktionen sind im Wesentlichen sinnlos und dienen nicht 
der Abstraktion sondern nur der Verschleierung und Verwirrung, oder 
zumindest ist die Dokumentation in Verbindung mit der Library vollkommen 
nichtexistent und unbrauchbar.

Die Library könnte vielleicht funktionieren wenn die Dokumentation 
derselben in das Reference-Manual eingearbeitet wäre und dort direkt mit 
dem verknüpft wäre was dort über die Funktion der Hardware steht. Ohne 
das ist es ein kompletter Irrsinn, ein Such- und Ratespiel und zu 
versuchen es mit der Library zu machen kostet doppelt so viel Zeit und 
Nerven als ohne. Und der Code wird auch nicht übersichtlicher, im 
Gegenteil!

#####################

Es gibt jedoch einen Ausweg und ich glaube den werde ich beschreiten 
bevor mich dieser Krampf hier noch in den Wahnsinn treibt und den Code 
mehrerer geplanter zukünftiger Projekte unwiederbringlich kontaminiert 
und auf ewig die Handbremse einrastet und endloses Leid bringt über mich 
und meinen Kollegen der dann später ebenfalls damit arbeiten muß:
1
SVDConv GD32F3x0.svd --generate=header --fields=macro

Das erzeugt eine Headerdatei im gewohnten CMSIS-Stil (mit structs für 
die Peripherie und defines für die Bitmasken) so daß man mit dem Ding 
endlich vernünftig auf Registerebene arbeiten kann und die Peripheral 
library fliegt ersatzlos raus.

Ich muss allerdings die SystemInit() portieren denn die benutzt noch die 
alten Header, aber ich glaube das ist ein geringer Preis für die 
Aussicht endlich gescheite Header zu haben und nach Handbuch 
programmieren zu können und nicht mehr von dieser undokumentierten 
Library und ihren chaotischen und irreführenden Namenskonventionen 
gebremst zu werden.

: Bearbeitet durch User
von Mehmet K. (mkmk)


Lesenswert?

Servus Bernd
Zuerst einmal ein Dankeschön für all Deine Rückmeldungen, die ich sehr 
aufmerksam lese.
Deine Kritik an den Libs ist natürlich berechtigt. Mein Eindruck (liegt 
jetzt aber schon reichlich in der Vergangenheit) war sehr positiv. Ich 
muss aber eingestehen, dass ich nicht so wie Du es jetzt tust ins Detail 
gegangen bin.
Bin sehr gespannt, wie Dein Resümee ausfallen wird, wenn Du all die 
Klippen umschifft hast.

von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:
> Servus Bernd
> Zuerst einmal ein Dankeschön für all Deine Rückmeldungen, die ich sehr
> aufmerksam lese.
> Deine Kritik an den Libs ist natürlich berechtigt. Mein Eindruck (liegt
> jetzt aber schon reichlich in der Vergangenheit) war sehr positiv.

Die Lib ist eigentlich ganz nützlich, aber die Schmerzen die ich 
verspüre kommen hauptsächlich von den 2 Punkten:

* Dokumentation der Hardware und Dokumentation der Library haben keine 
Verbindung zueinander, Übersetzen von einem zum Anderen ist äußerst 
mühselig (klares Dokumentationsproblem)

* Bezeichner die von der Library verwendet werden sind wild gemischt mit 
Bezeichnern der Register und Bits mit gleichen Namensprefixen, das 
erzeugt immense Verwirrung und Verwechslungsgefahr wenn man mit dem 
Autocomplete nach dem richtigen Bezeichner sucht.

Ich bin echt hin und hergerissen, ich hab mal angefangen alles was ich 
bis jetzt habe auf CMSIS umzustellen aber das ist auch ein 
Monsterprojekt, und jeglicher Beispielcode wird dann sofort wertlos. Muß 
noch male ne Nacht drüber schlafen.

Ich will meinen Kinetis zurück :-(

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Bernd K. schrieb:
> das ist ein einziges unleserliches Verwirrspiel!
> ein Such- und Ratespiel

Dies und gleich zwei Bugs die meine ersten beiden Programme betragen 
sind mein persönlicher Grund, die HAL links liegen zu lassen.

> Es gibt jedoch einen Ausweg...
> Das erzeugt eine Headerdatei im gewohnten CMSIS-Stil

Da kommst du einfacher ran:
Kopiere aus dem STM32CubeF3 Paket zwei Verzeichnisse in dein Projekt:
1
    Drivers/CMSIS/Include
2
    Drivers/CMSIS/Device/ST/STM32F1xx/Include
In der Datei stm32f3xx.h kommentierst du dann die richtige Zeile für 
deinen µC aus. Das funktioniert mit allen anderen STM32 Serien ebenso.

Was die Startup-Files und das Linkerscript angehen:

Die "System Workbench for STM32" generiert Dir alle nötigen Files, wenn 
du ein neues Projekt mit der Option "No firmware" erstellst. Du musst 
wie gesagt nur diese beiden CMSIS Verzeichnisse dazu kopieren.

Das Atollic TrueStudio kann das leider nicht. Es gibt zwar einen 
vielversprechenden Assistenten dazu, aber der führt in eine Sackgasse 
weil die Auswahl-Liste der Mikrocontroller leer ist. Das zumindest vor 
ein paar Wochen noch, als ich es mal wieder mit der neuesten Version 
versuchte.

von Bernd K. (prof7bit)


Lesenswert?

Stefanus F. schrieb:
> Da kommst du einfacher ran:
> Kopiere aus dem STM32CubeF3 Paket zwei Verzeichnisse in dein Projekt:
> Drivers/CMSIS/Include
>     Drivers/CMSIS/Device/ST/STM32F1xx/Include
> In der Datei stm32f3xx.h kommentierst du dann die richtige Zeile für
> deinen µC aus. Das funktioniert mit allen anderen STM32 Serien ebenso.

Aber das beinhaltet dann die Registernamen und Bits für den STM32. Und 
die heißen alle komplett anders bei GD32 Du findest kein Register und 
kein Bit das den selben Namen wie bei seinem STM Gegenstück hat! das 
GD32 Handbuch wäre dann für die Tonne und ich müsste das STM32 Handbuch 
nehmen.

Und für meinen GD32 gibts keine 100% Entsprechung von ST. Ich würd schon 
lieber das Orginalhandbuch nehmen wollen. STM32 nur als Ergänzung, als 
zweite Meinung im Zweifelsfall sozusagen.

Außerdem halte ich Cube installieren (womöglich noch vorher bei ST 
registrieren) nur um an ne einzelne Headerdatei zu kommen für 42 mal 
umständlicher als mir das einfach mal eben schnell aus dem DFP zu 
ziehen. Startup und SystemInit hab ich schon.

Ich bin nur noch ein bisschen mit mir selbst am Hadern ob ich den Weg 
mit dem (von GD nicht offiziell supporteten) CMSIS einschlagen soll oder 
ob ich mich mit deren Library bzw. deren altmodische Art der 
Registerdefinitionen anfreunde und einen Weg finde die Schmerzen beim 
Umgang damit zu lindern. Vielleicht gibt sich das etwas wenn ich 
irgendwann die Peripheriegeräte besser kennengelernt habe, es ist halt 
schwer sie wirklich schnell und eingehend kennenzulernen wenn immer 
ständig diese dicke undurchdringliche Gummihülle dazwischen sein soll.

von Stefan F. (Gast)


Lesenswert?

Bernd K. schrieb:
> Außerdem halte ich Cube installieren (womöglich noch vorher bei ST
> registrieren) nur um an ne einzelne Headerdatei zu kommen für 42 mal
> umständlicher

Musst du nicht, die sogenannten "Firmware" Pakete kannst du einzeln 
downloaden. Es sind ZIP Dateien. Link für STM32F3: 
https://www.st.com/en/embedded-software/stm32cubef3.html

> Aber das beinhaltet dann die Registernamen und Bits für
> den STM32. Und die heißen alle komplett anders bei GD32

Ja sorry, das habe ich mir wohl zu einfach vorgestellt.

Aber ist schon komisch, dass deine Kritik an deren HAL genau so auch auf 
die HAL von STM32 zutrifft. Ich habe gar nicht gemerkt, dass du von 
einer anderen geschrieben hattest.

von John P. (brushlesspower)


Lesenswert?

Woher bezieht Ihr eure GD32 Nucleos, bzw eure GD32 Controller?


Direkt von Ali?

von Mehmet K. (mkmk)


Lesenswert?

Ich habe meine von LCSC bezogen:
https://lcsc.com/products/GigaDevice_918.html?q=GD32

von Bernd K. (prof7bit)


Lesenswert?

Vorsicht vor dem Beispielcode!

Der ist mit ziemlich heißer Nadel gestrickt und sollte nicht 
unreflektiert gecopypastet und adaptiert werden, es scheint absolut 
NOTWENDIG sich diese Structs und die Funktionen genau anzusehen bevor 
man sie benutzt.

Zitat Beispielcode (gekürzt und kommentiert)
1
void timer_config(void)
2
{
3
    timer_oc_parameter_struct timer_ocintpara;
4
5
[...]
6
7
    /* CH1,CH2 and CH3 configuration in PWM mode0 */
8
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
9
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
10
11
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12
    // die anderen vier Felder in dem obigen Struct
13
    // sind jetzt aber nicht initialisiert weil das
14
    // eine uninitialisierte lokale Variable ist!
15
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16
17
    timer_channel_output_config(TIMER1,TIMER_CH_1,&timer_ocintpara);
18
    timer_channel_output_config(TIMER1,TIMER_CH_2,&timer_ocintpara);
19
    timer_channel_output_config(TIMER1,TIMER_CH_3,&timer_ocintpara);
20
21
[...]
22
23
}

Wenn ich jetzt den Beispielcode leicht anpasse weil ich statt Timer 1 
lieber Timer 0, 14, 15 oder 16, Kanal 0 nehmen will (oder alle Kanäle 
mit Timer 0) wo es zusätzliche Funktionen gibt die ich aber nicht 
brauche dann knallt es weil er Datenmüll aus den uninitialisierten 
Feldern einfach so direkt in voller Breite in irgendwelche Register 
kippt (siehe unten).

Der obige Beispielcode ist schlampig! Beispiele sollten aber 
vorbildlich sein! Diese structs müssen sauber initialisiert werden!

Hier auszugsweise was die Funktion macht:
1
void timer_channel_output_config(uint32_t timer_periph, uint16_t channel, timer_oc_parameter_struct* ocpara)
2
{
3
    switch(channel){
4
    /* configure TIMER_CH_0 */
5
    case TIMER_CH_0:
6
        /* reset the CH0EN bit */
7
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
8
        /* set the CH0EN bit */
9
        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->outputstate;
10
        /* reset the CH0P bit */
11
        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0P);
12
        /* set the CH0P bit */
13
        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->ocpolarity;
14
15
        if((TIMER0 == timer_periph) || (TIMER14 == timer_periph) || (TIMER15 == timer_periph) || (TIMER16 == timer_periph)){
16
            /* reset the CH0NEN bit */
17
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NEN);
18
            /* set the CH0NEN bit */
19
            TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->outputnstate;
20
            /* reset the CH0NP bit */
21
            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NP);
22
            /* set the CH0NP bit */
23
            TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->ocnpolarity;
24
            /* reset the ISO0 bit */
25
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO0);
26
            /* set the ISO0 bit */
27
            TIMER_CTL1(timer_periph) |= (uint32_t)ocpara->ocidlestate;
28
            /* reset the ISO0N bit */
29
            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO0N);
30
            /* set the ISO0N bit */
31
            TIMER_CTL1(timer_periph) |= (uint32_t)ocpara->ocnidlestate;
32
        }
33
34
[...]

Also: Beispielcode ganz langsam durchgehen, Zeile für Zeile, inclusive 
der Funktionen die er aufruft und immer mitdenken, also genauso intensiv 
studieren und denken als wenn man direkt aus dem RefMan die Register von 
Hand bearbeiten würde! Keine Zeitersparnis!

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Bernd K. schrieb:
> Cheffe kann den GD32F350C6 wohl irgendwo für 50 Cent das Stück besorgen

Ähem... gehe ich recht in der Annahme, daß dieser Chip keinen USB-Core 
hat?
Ich sehe da je 2 Stück USART, I2C, SPI und CAN, dazu 1x I2S - aber 
keinerlei USB.

W.S.

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

W.S. schrieb:
> Ähem... gehe ich recht in der Annahme, daß dieser Chip keinen USB-Core
> hat?
> Ich sehe da je 2 Stück USART, I2C, SPI und CAN, dazu 1x I2S - aber
> keinerlei USB.

Laut RefMan gibts einen USB full speed device oder host.
1
 Supports USB 2.0 host mode at Full-Speed (12Mb/s) or Low-Speed (1.5Mb/s).
2
 Supports USB 2.0 device mode at Full-Speed (12Mb/s).
3
 Supports OTG protocol with HNP (Host Negotiation Protocol) and SRP (Session Request Protocol).
4
 Supports all the 4 types of transfer: control, bulk, interrupts and isochronous.
5
 Includes a USB transaction scheduler in host mode to handle USB transaction request efficiently.
6
 Includes a 1.25KB FIFO RAM.
7
 Supports 8 channels in host mode.
8
 Includes 2 transmit FIFOs (periodic and non-periodic) and a receive FIFO (shared by all channels) in host mode.
9
 Includes 4 transmit FIFOs (one for each IN endpoint) and a receive FIFO (shared by all OUT endpoints) in device mode.
10
 Supports 4 OUT and 4 IN endpoints in device mode.
11
 Supports remote wakeup in device mode.
12
 Includes a Full-Speed USB PHY with OTG protocol supported.
13
 Time intervals of SOFs is dynamic adjustable in host mode
14
 Supports output SOF pulse to PAD.
15
 Supports detecting ID pin level and VBUS voltage.
16
 Needs external component to supply power for connected USB device in host mode or OTG A-device mode.

RefMan hat ein Kapitel darüber, Register sind alle definiert in den 
Headern, Pins sind laut Datenblatt auch rausgeführt, auch bei meinem 
kleinen QFN28, benutzt hab ich ihn aber noch nicht.

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

Datenblatt und RM

von W.S. (Gast)


Lesenswert?

Bernd K. schrieb:
> RefMan hat ein Kapitel darüber,

Danke, werd ich mir mal zu Gemüte ziehen. Aber seltsam erscheint's mir 
doch. Wäre mir ja aufgefallen, wenn's auf der Herstellerseite zu lesen 
wäre.

W.S.

von Bernd K. (prof7bit)


Lesenswert?

Ach übrigens: der kat keine (ich wiederhole KEINE) FPU, obwohls ein M4 
ist. FPU ist auch bei M4 optional.

von Mehmet K. (mkmk)


Lesenswert?

Bernd, schon lange kein Feedback mehr von Dir gelesen.

von Bernd K. (prof7bit)


Lesenswert?

Mehmet K. schrieb:
> Bernd, schon lange kein Feedback mehr von Dir gelesen.

Hatte Urlaub. Und dann ist noch Arbeit an nem anderen älteren Projekt 
angefallen das Priorität hat.

von Bernd K. (prof7bit)


Lesenswert?

Jetzt könnt ich die Chinesen ohrfeigen! :-(

Da kleben die schon extra ein separates serielles Flash obendrauf und 
führen sämtlichen Code grundsätzlich immer vom RAM aus, aber wenn man 
ein Page-Erase und ein Flash-Write durchführt dann stallt die ganze 
Codeausführung trotzdem!

Das wäre doch DER Vorteil gewesen, noch viel nützlicher als 0 
Waitstates!

Stattdessen emulieren die (aus Kompatibilitätsgründen?) immer noch einen 
komplett unnötigen Bus-Stall (im RAM!) der bei dieser Architektur 
eigentlich gar nicht mehr nötig wäre! So ein verschenktes Potential!

Im Reference-Manual steht übrigens kein Sterbenswörtchen von einem 
Bus-Stall, nichts davon wird auch nur andeutungsweise irgendwo erwähnt! 
Es wird also (indirekt) etwas versprochen (kein Stall) aber dann 
überraschenderweise doch nicht geliefert!

Also Vorsicht! 40...50ms komplette Blockade können eine verdammt lange 
Zeit sein.

von foobar (Gast)


Lesenswert?

Btw, ist es möglich, einen Teil dieses Shadow-RAM als Daten-RAM zu 
benutzen?  Ich suche schon ne Weile eine MCU in dieser Klasse mit 
64-80kB RAM und wenn ich das Shadow-RAM z.B. auf 64k Flash, 64k RAM 
splitten könnnte, wäre das genau das richtige.  Eventuelle 
Geschwindigkeitseinbußen beim Zugriff wären akzeptabel.

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.