Ich habe hier ein kleines Problem, für welches ich zwar einen Workaround
habe, aber nicht sicher bin, ob das ein GCC Bug ist.
Und zwar sollen im Code Zeichen asynchron über den UART gelesen werden
bis ein gültiges Längenbyte (!=0) kommt. Über den Code Stil kann man
streiten, aber er sollte so funktionieren, und tat das auch bis wir Link
Time Optimization verwendeten und dabei ein Call durch Inlinen ersetzt
wurde.
Ich hab als Beispiel was gebastelt, das diese Auffälligkeiten zeigt,
dabei sind 3 Beispiele zu sehen, im ersten wird bei der if Überprüfung
in der Schleife der zweite Teil weggelassen, obwohl auf (volatile ...)
gecastet. Darf der Compiler das, obwohl ich ihm sage die Variable kann
sich (durch die UART ISR) ändern?
Bei den beiden anderen Varianten wird alles wie gewünscht ausgeführt. Am
besten man kompiliert das immer nur mit einer Schleife, dann sieht man
im Listing was ich meine. Optimierung ist -Os mit GCC 4.7.2 von
Launchpad
Plattform ist ein STM32
1 | #include <stdint.h>
|
2 |
|
3 | static char m_cRecBuffer[23];
|
4 |
|
5 | void __attribute__((noinline)) uart_read_async(uint8_t* pa_pcBuffer, int pa_nLen)
|
6 | {
|
7 | volatile uint8_t * pUartBusy = (volatile uint8_t*)0x42;
|
8 | *pUartBusy = 1;
|
9 | }
|
10 |
|
11 | uint8_t __attribute__((noinline)) uart_is_busy()
|
12 | {
|
13 | volatile uint8_t * pUartBusy = (volatile uint8_t*)0x42;
|
14 | return *pUartBusy;
|
15 | }
|
16 |
|
17 | void _exit(int pa_Exit)
|
18 | {
|
19 | }
|
20 |
|
21 | int main(void)
|
22 | {
|
23 |
|
24 | m_cRecBuffer[0] = 0;
|
25 | uart_read_async(&m_cRecBuffer[0], 1);
|
26 |
|
27 | // some pointer to uart driver status, changed in uart ISR
|
28 | volatile uint8_t * p_UartBusy = (volatile uint8_t*)0x42;
|
29 |
|
30 | // not working
|
31 | /*
|
32 | * second condition in if is ignored (0 == (volatile uint8_t)m_cRecBuffer[0])
|
33 | */
|
34 | while ((0 == (volatile uint8_t)m_cRecBuffer[0])) {
|
35 | if (*p_UartBusy != 0 && (0 == (volatile uint8_t)m_cRecBuffer[0])) {
|
36 | uart_read_async(&m_cRecBuffer[0], 1);
|
37 | }
|
38 | }
|
39 |
|
40 | // working
|
41 | while ((0 == (volatile uint8_t)m_cRecBuffer[0])) {
|
42 | if (uart_is_busy() != 0 && (0 == (volatile uint8_t)m_cRecBuffer[0])) {
|
43 | uart_read_async(&m_cRecBuffer[0], 1);
|
44 | }
|
45 | }
|
46 |
|
47 | // working
|
48 | volatile uint8_t * pcLen = (volatile uint8_t*) &m_cRecBuffer[0];
|
49 | while (0 == *pcLen) {
|
50 | if (*p_UartBusy != 0 && 0 == *pcLen) {
|
51 | uart_read_async(&m_cRecBuffer[0], 1);
|
52 | }
|
53 | }
|
54 | }
|