Ich wollte ein Stück Software, das in Assembler vorliegt, tracen, möglichst über SWO, also Nachrichten im SWV-View des STM32CubeIDE. Aus einem C-Beispielprogramm heraus lief es ja zuletzt. Die Tracefunktion ITM_SendChar(char); ist aber ein Stück aus einer C-Bibliothek, die dazugelinkt wird. Die habe ich ja in Assembler nicht. Ich kann vielleicht ein bißchen Assemblercode noch dazupacken, der vielleicht das SWV-Protokoll implementiert, aber wo und wie?
Also wirklich, das __STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) { if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ { while (ITM->PORT[0U].u32 == 0UL) { __NOP(); } ITM->PORT[0U].u8 = (uint8_t)ch; } return (ch); } in Assembler zu schreiben, kann doch wohl kein Problem sein, oder? Im Prinzip ist das doch nur ein UART (zumindest die übliche Einstellung), man schreibt das Byte ins Sende-FIFO, wenn Platz ist. Die Abfrage, ob "ITM enabled", kann man sich ja auch ggf. noch sparen. Für z. B. STM32H750 im RM0433, 60.6.3, ITM stimulus register 0, da ist die FIFO-Behandlung erklärt. Der kompliziertere Teil sind die ganzen Einstellungen davor.
Christoph K. schrieb: > ITM_SendChar(char); ist aber ein Stück aus einer C-Bibliothek, > die dazugelinkt wird. Die habe ich ja in Assembler nicht. Hast du ein Programm, in dem ITM_SendChar() in C funktioniert und in dem dein Stück Assembler auch drin ist? Dann könnte es mit 3 Zeilen Assembler funktionieren:
1 | .global ITM_SendChar |
2 | movs r0, #72 |
3 | bl ITM_SendChar |
72 ist der Anfang von "Hallo, Welt" ;)
Bauform B. schrieb: > Christoph K. schrieb: >> ITM_SendChar(char); ist aber ein Stück aus einer C-Bibliothek, >> die dazugelinkt wird. Die habe ich ja in Assembler nicht. > > Hast du ein Programm, in dem ITM_SendChar() in C funktioniert und in > dem dein Stück Assembler auch drin ist? Dann könnte es mit 3 Zeilen > Assembler funktionieren: >
1 | .global ITM_SendChar |
2 | > movs r0, #72 |
3 | > bl ITM_SendChar |
> 72 ist der Anfang von "Hallo, Welt" ;)
Nein, die Konstellation liegt so nicht vor. Ich muß die
C-Implementierung in Assemblercode einbinden.
Aber ich werde mich mal an das von A.B.(gast) Vorgeschlagene begeben.
Konnte jetzt ITM_SendString und ITM_SendChar in Assembler implementieren:
1 | .equ ITM , 0xE0000000 |
2 | main: |
3 | ldr r0,=hello |
4 | bl ITM_SendString |
5 | pop {r0,r1} |
6 | b . |
7 | hello: .asciz "hi!" |
8 | .global ITM_SendChar,ITM_SendString |
9 | |
10 | ITM_SendString: @ r0 - address of null-terminated String |
11 | push {r0-r1} |
12 | mov r1,r0 |
13 | 1: mov r0,#0 |
14 | ldrb r0,[r1] |
15 | cbz r0,2f |
16 | bl ITM_SendChar |
17 | add r1,#1 |
18 | b 1b |
19 | 2: pop {r0-r1} |
20 | bx lr |
21 | putchar: |
22 | ITM_SendChar: |
23 | push {r0-r1} |
24 | 1: ldr r1, = ITM |
25 | ldr r1,[r1] |
26 | cmp r1,#0 |
27 | beq 1b |
28 | ldr r1, = ITM |
29 | str r0,[r1] |
30 | pop {r0-r1} |
31 | bx lr |
Aber der Debugger (STM32CubeIDE) verhält sich merkwürdig. Es wird "hi!" in der SWV ITM Console ausgegeben, aber wenn ich durch ITM_SendSTring durchsteppe, findet die loop auch die terminierende 0, fällt durch auf Label 2: und steppe ich bis zum bx lr springt der Debugger zurück auf `add r1,#1` (!?). Auch seltsam sind die vielen (sehr vielen) blauen trace-messages Zeile 590 in simple.s im Debug Window. Modifiziere ich den Code etwas, so springt der Debugger auf die branch-Instruction zurück.
1 | .equ ITM , 0xE0000000 |
2 | main: |
3 | ldr r0,=hello |
4 | bl ITM_SendString |
5 | pop {r0,r1} |
6 | b . |
7 | hello: .asciz "hi!" |
8 | .global ITM_SendChar,ITM_SendString |
9 | |
10 | ITM_SendString: @ r0 - address of null-terminated String |
11 | push {r0-r1} |
12 | mov r1,r0 |
13 | 1: mov r0,#0 |
14 | ldrb r0,[r1],#1 |
15 | cbz r0,2f |
16 | bl ITM_SendChar |
17 | b 1b @ <<<<<<<<<\ |
18 | 2: pop {r0-r1} @ | erratischer Rücksprung des Debuggers nach dem bx lr |
19 | bx lr @ >>>>>>>/ |
20 | putchar: |
21 | ITM_SendChar: |
22 | push {r0-r1} |
23 | 1: ldr r1, = ITM |
24 | ldr r1,[r1] |
25 | cmp r1,#0 |
26 | beq 1b |
27 | ldr r1, = ITM |
28 | str r0,[r1] |
29 | pop {r0-r1} |
30 | bx lr |
Kann es sein, dass du gerade die falschen Register rettest? Bei r0 sollte klar sein, dass du das nicht retten musst. r1 bis r3 darfst du bei Bedarf auch "zerstören". Umgekehrt benutzt du das lr um ITM_SendChar() aufzurufen, aber das wird noch für die Rückkehr nach main gebraucht, sollte also gerettet werden. Ganz nebenbei finde ich den Namen putchar schöner als ITM_SendChar. Bei letzterem denke ich, dass das eine CubeMX-Funktion ist.
Bauform B. schrieb: > Kann es sein, dass du gerade die falschen Register rettest? Bei r0 > sollte klar sein, dass du das nicht retten musst. r1 bis r3 darfst du > bei Bedarf auch "zerstören". Umgekehrt benutzt du das lr um > ITM_SendChar() aufzurufen, aber das wird noch für die Rückkehr nach main > gebraucht, sollte also gerettet werden. > > Ganz nebenbei finde ich den Namen putchar schöner als ITM_SendChar. Bei > letzterem denke ich, dass das eine CubeMX-Funktion ist. Danke. Wertvoller Tipp. Ja klar, bei geschachtelten Subroutine Aufrufen muß man eingangs in der SR push {...,rl} und den return mit pop {...,pc} machen. ARM hat ja keine "RET" Instruction, mit der die Returnadresse vom Stack geholt wird. Bereinige das gerade, aber Auprobieren kann ich es erst nach dem Fußballspiel. Und ITM_SendChar wird durch putchar ersetzt. Hatte ich ja schon vorgesehen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.