Forum: Compiler & IDEs STM32 - CodeBench Lite - 64-bit Division


von Peter S. (sengp) Benutzerseite


Lesenswert?

Folgendes mir unerklärliche Verhalten:

Cross-Compiler: 2011.03 / 2011.09 und 2012.03 Versionen von Sourcery 
Codebench Lite.
Library: Newlib C Library (1.18.0-sg++) (stdlib.h) aus der Suite 
Sourcery CodeBench Lite.

Verhalten: sobald die Funktion "strtoull" im Programmcode eingebaut wird 
ist die Baudrate von USART1 vervierfacht. Keine Fehlermeldungen, keine 
Warnmeldungen beim compilieren, Programm läuft, Debugger läuft, evtl. 
geht das Programm manchmal in den HardFault_Handler interrupt.
Das selbe Verhalten tritt auf sobald folgendes irgendwo in das Programm 
eingebaut wird (also unabhängig davon ob dies auch ausgeführt wird):
1
long long test1 = 10, test2 = 4, test3;
2
test3 = test1 / test2;

Vermute, dass "strtoull" ebenfalls eine 64-bit Division enthält. Die 
64-Bit Division führt in jedem Falle zu dem Fehlverhalten.
Erhebliche Vergrößerung des Stacks erbringt keinerlei Veränderung des 
Verhaltens, selbst das Ergebnis der Division scheint korrekt (keine 
ausgiebigen Versuche, da eine Division dieser Art nicht benötigt wird).

Manual "Using the GNU Compiler Collection, chapter 6.9" sagt aus, dass: 
"(long long) divisions are open coded and are available only on machines
providing special support."

Die Frage ist:
Was passiert da? Schließlich ist die Baudrate unabhängig vom erzeugten 
Code und lediglich ein Wert in einem CPU-Register.
Erklärungen?

von Jim M. (turboj)


Lesenswert?

>  Was passiert da? Schließlich ist die Baudrate unabhängig vom erzeugten
> Code und lediglich ein Wert in einem CPU-Register.

Die meisten Cortex_M3 Libs die ich kenne erzeugen den Wert für die 
Baudrate dynamisch aus der aktuellen CPU Frequenz. Und weil da relevante 
Nachkommastellen auftreten könnnen wird mit 64 Bits gerechnet.

Abhilfe: Bei bekanntem CPU Takt die entsprechenden Werte von Hand - oder 
vom Compiler - ausrechnen (lassen) und in die Register eintragen.

Es könnte sein dass die Funtion nicht reentrant ist - dann darf man 
diese Berechnung der Baudrate nicht im Interrupt ausführen.

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Ja, 64bit-Division ist augenscheinlich in strtoll. Quellcodeteil der 
newlib sieht aber wenig dramatisch aus: 
http://sourceware.org/cgi-bin/cvsweb.cgi/src/newlib/libc/stdlib/strtoll_r.c?rev=1.3&content-type=text/x-cvsweb-markup&cvsroot=src 
. Unter bestimmten Bedingungen wird jedoch ein Fehlercode gesetzt, dabei 
wird in einen Struktur vorm Type __reent geschrieben. Beim Aufruf der 
"normalen" Funktion (nicht der _r-Variante) wird dann in 
impure_data.errno geschrieben. _impure_ptr zeigt auf diese globale 
Stuktur impure_data. Man kann also evtl. hier per Debugger nachverfolgen 
- erscheint aber wenig erfolgversprechend.

Problem könnte auch im Zusammenhang mit der Fehlerüberprüfung einer 
Divisiononsroutine in der libgcc liegen. Gibt es im Linkerscript 
Einträge für ARM.extab und ARM.exidx? Einige Versionen der libgcc haben 
Abhängigkeiten zur C++-Ausnahmeverarbeitung mitgezogen, selbst wenn man 
"reines" C nutzt. Im Zweifel und falls nicht schon drin, die die beiden 
Sections in das Linkerscript eintragen (siehe Beispiele in CS 
Installationsverzeichnis) und anhand des Map-Files prüfen, ob dort etwas 
von libgcc (und/oder libc) abgelegt wird (siehe vor allem nach 
libgcc/_udivdi3 und libgcc/_divdi3 jeweils einträge in extab und exidx, 
in exidx zusätzlich noch für libgcc/bpabi).

von (prx) A. K. (prx)


Lesenswert?

Jim Meba schrieb:
> Die meisten Cortex_M3 Libs die ich kenne erzeugen den Wert für die
> Baudrate dynamisch aus der aktuellen CPU Frequenz. Und weil da relevante
> Nachkommastellen auftreten könnnen wird mit 64 Bits gerechnet.

Sieht bei mir eher schlicht aus, STM32F1xx:
    unsigned apbclk = (info->dev == USART1) ? F_APB2 : F_APB1;
    info->dev->BRR = apbclk / baud;
Die 4 Nachkommstellen stehen im Baudratenregister. Ok, man könnte hier 
noch ein halbes Bit runden, aber ob das so wichtig ist? Weshalb man da 
64 Bits braucht erschliesst sich mir nicht.

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.