Forum: Mikrocontroller und Digitale Elektronik STM32: Division durch Null


von Walter T. (nicolas)


Lesenswert?

Guten Morgen,

ich stehe gerade vor einem Rätsel. Ich wollte nur die Fehler-Ausgabe 
testen. Als praktischste Stelle kam mir ein Bresenham-Algorithmus vor, 
weil der häufig aufgerufen wurde.
1
    typedef struct State32_s
2
    {
3
        int32_t z;  /**< Zaehler */
4
        int32_t n;  /**< Nenner */
5
        int32_t r;  /**< Rest */
6
    }
7
    State32_t;
8
9
    State32_t GState = {.z = 300, .r = 0};
10
11
    static int32_t foo(void)
12
    {
13
        State32_t *State = &GState;
14
        
15
        int32_t dy = ((int64_t) State->z * dx + State->r)/State->n;
16
        State->r = ((int64_t) State->z * dx + State->r)%State->n;
17
18
        return dy;
19
    }

Mit dem Debugger habe ich State->n auf Null gesetzt. Von mir wurden auch 
keine extra Fehler-Handler als der HardFault_Handler() implementiert. 
Trotzdem wird diese Funktion mit State->n == 0 mehrmals durchlaufen, 
ohne dass ein Fehler auftritt. Der Rückgabewert wird auch weiter 
verwendet.

Was passiert hier?
Kann man in __eabi_ldivmod() irgendwie hineingucken?

: Bearbeitet durch User
von Ulf L. (ulf_l)


Lesenswert?

welchen Wert hat denn dx und welcher Wert wird in dy zurück geliefert ?

von Walter T. (nicolas)


Lesenswert?

Wenn dx = 29395, r = 0, ist dy = -1.

: Bearbeitet durch User
von . . (Gast)


Lesenswert?

Walter T. schrieb:

> Mit dem Debugger habe ich State->n auf Null gesetzt. Von mir wurden auch
> keine extra Fehler-Handler als der HardFault_Handler() implementiert.
> Trotzdem wird diese Funktion mit State->n == 0 mehrmals durchlaufen,
> ohne dass ein Fehler auftritt. Der Rückgabewert wird auch weiter
> verwendet.
>
> Was passiert hier?

https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
Da steht: "To enable hardware reporting of div0 errors we need to 
configure the CCR"

von Ulf L. (ulf_l)


Lesenswert?

Unabhängig von der fehlenden Error-Meldung:
Kann das der type-cast von 64Bit auf 32Bit sein ?
angenommen mit geteilt durch Null geht der 64Bit Wert auf den maximal 
positiven Wert
0X7FFF FFFF FFFF FFFF
wenn der cast daraus ein
0XFFFF FFFF
macht, käme -1 dabei heraus.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Das ließ sich ja einfach testen:
1
typedef struct State32_s
2
{
3
    int32_t z;  /**< Zaehler */
4
    int32_t n;  /**< Nenner */
5
    int32_t r;  /**< Rest */
6
}
7
State32_t;
8
9
State32_t GState = {.z = 300, .r = 0, .n = 0};
10
11
12
volatile int64_t temp = 0;
13
14
static int32_t foo(int32_t dx)
15
{
16
    State32_t *State = &GState;
17
18
    temp = ((int64_t) State->z * dx + State->r)/State->n;
19
    int32_t dy = temp;
20
    State->r = ((int64_t) State->z * dx + State->r)%State->n;
21
22
    return dy;
23
}
24
25
26
/* Funktion zum Testen von Sachen. */
27
exit_t runToShow(void)
28
{
29
    int32_t dx = 20000;
30
    volatile int32_t dy;
31
32
    dy = foo(dx);
33
    printf("dy = %i", dy);
34
35
    return EXIT_SUCCESS;
36
}

Ergebnis 1: Ja, Du hast Recht. Auf dem STM32 ist das tatsächlich ein von 
__eabi_ldivmod() bestmöglich behandelter Overflow.
temp = 0x7fffffffffffffff.

Ergebnis 2: Unter Windows (wo wahrscheinlich direkt die CPU den 
Divisionsbefehl bekommt) stürzt das wie erwartet gnadenlos ab.

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


Lesenswert?

Aus dem ARM Infocenter:
Integer division is implemented by calling the C library functions 
__aeabi_idiv and __aeabi_uidiv. These check for divison by zero. If 
integer division by zero is detected, a branch to __aeabi_idiv0 is made. 
So to trap the division by zero, all you need to do is place a 
breakpoint on __aeabi_idiv0.

Also für die 64Bit Version das Symbol im Linkerscript ersetzen und dann 
einen Hardfault selber aufrufen?

Ein 64Bit div kann der 32Bit ARM Kern ja nicht selber ausführen.
Aber wieso bläst du da auf 64Bit auf?
Der Bresenham ist ja zum Linien zeichnen auf Rastern für eine GUI oder?
Das wird dann ja recht langsam in Software.

Ansonsten hat ein gast schon geschrieben, dass auch das 32Bit HW Div0 
Trap erst aktiviert werden muss.
Weiteres hier dazu: Beitrag "ARM Cortex-M3/4/7 Faulthandler"

von Walter T. (nicolas)


Lesenswert?

Mw E. schrieb:
> So to trap the division by zero, all you need to do is place a
> breakpoint on __aeabi_idiv0.

Danke für den interessanten Aspekt.

Meine naive Frage: Wie setzt man denn einen Breakpoint in eine 
Library-Funktion mit einem grafischen Debugger? Mein erster Ansatz: 
Map-File aufrufen, nach der Funktion suchen und an die Adresse springen. 
(Erst einmal: Super, das das geht. Ein für mich neues und praktisches 
Hilfsmittel.) Geht es noch einfacher?

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


Lesenswert?

Kann der denn nicht dein Disasm des Projekts aufrufen und darin 
breakpoints setzen?

Ansonsten eben die Symbolersetzung per Linkerscript gegen eine Funktion 
die nur "bkpt #0" enthält".

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.