C und volatile

  • C

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von thefiloe.

    C und volatile

    Hallo @ all,

    ich habe da ein gewisses Problem in C bzw. eine Frage. Und zwar bekomme ich
    ständig eine Warnung wo ich nicht weiss wie ich diese lösen kann.

    C-Quellcode

    1. void ringbuffer_Init(volatile ringbuffer8_t* inst)
    2. {
    3. inst->readPointer = &inst->Buffer[0]; //Warnung bei &inst....
    4. inst->writePointer = &inst->Buffer[0]; //Warnung bei &inst....
    5. inst->BufElements = 0;
    6. }

    Das Problem ist, das ich volatile benötige. da jedoch &inst nicht mitmacht, wird das "wegoptimiert" wodurch mein Programm wiederum nicht mehr korrekt geht.

    Hat da jemand schon Erfahrung damit gemacht bzw. eine Ahnung was ich hinzufügen müsste?

    Thx

    ~gfc

    gfcwfzkm schrieb:

    eine Warnung
    Welche?
    Kannst Du ein Code-Snippet posten, das kompilierbar ist und diesen Effekt reproduziert?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Moin,

    mit & holst du dir die Adresse der Variable. * ist der Dereferenzieurngsoperator. Bei Strukturen kann auch -> angewendet werden, um die Adresse zu dereferenzieren.
    Also wäre dein Code z. B. inst->readPointer = inst->Buffer[0];
    Mit freundlichen Grüßen,
    Thunderbolt

    Thunderbolt schrieb:

    dein Code
    Nö.

    C-Quellcode

    1. inst->readPointer = inst->Buffer;
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Die Lösung wurde bereits gepostet.

    Aber um das mal Allgemein klar zu machen, volatile wirst du wohl nie brauchen. Das ist eher für ganz spezielle Dinge:
    z.B. setzen eines Registers mit sich selbst um einen Wechsel in den UserMode zu erzwingen - würde natürlich wegoptimert werden, weil es dasselbe ist wie x=x, aber man braucht es, weil im Hintergrund tatsächlich noch etwas anderes passiert. Das ist eigt. mal eines der wenigen Beispiele und zwar aus dem Bereich der OS Programmierung->nah an der Hardware.
    Was anderes das mir vlt. noch einfällt ist, falls du einen Algorithmus voll und ganz für deine Hardware/speziellen Fall optimiert hast und du nicht willst, dass die Compiler-Optiierung dadrinne rumpfuscht. Aber i.d.r. sind die Optimierungen ziemlich gut und ergibt nur Sinn die zu verhindern, wenn du mit Assembler rumpfuschst/eine spezielle Funktion anders optimieren willst wie den rest...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    hmm. Hätte da noch ein Problem zu volatile und low-level.
    Und zwar bin ich an einer Bibliothek für die Serielle Schnittstelle dahinter. Dort verwende ich einen Ring-Buffer. Aber genau dieser macht Probleme.
    Wenn ich eine Zeichenkette senden will, speichert er diese in einem Ringbuffer und startet die Interrupt-Gesteuerte Übertragung. Im Interrupt holt er sich nach und nach die Zeichen vom Buffer und sendet diese.
    Jedoch setzten teilweise Zeichen aus oder ganze Wörter werden doppelt gesendet. Soweit ich gelesen habe sollte volatile doch genau das verhindern, oder?
    Spoiler anzeigen

    C-Quellcode

    1. /*
    2. * GD_UART.c
    3. *
    4. * Created: 25.08.2014 13:34:12
    5. * Author: gespa1
    6. */
    7. #include "UART.H"
    8. #include <avr/interrupt.h>
    9. #if defined(UDR0)
    10. #define UDR_0 UDR0
    11. #define UCSRA_0 UCSR0A
    12. #define U2X_0 U2X0
    13. #define UBRRH_0 UBRR0H
    14. #define UBRRL_0 UBRR0L
    15. #define UCSRB_0 UCSR0B
    16. #define UCSRC_0 UCSR0C
    17. #define UCSZ0_0 UCSZ00
    18. #define UCSZ1_0 UCSZ01
    19. #define USBS_0 USBS0
    20. #define RXC_0 RXC0
    21. #define UDRE_0 UDRE0
    22. #define RXEN_0 RXEN0
    23. #define TXEN_0 TXEN0
    24. #define RXCIE_0 RXCIE0
    25. #define TXCIE_0 UDRIE0
    26. #define RX_INTERRUPT USART0_RX_vect
    27. #define TX_INTERRUPT USART0_UDRE_vect
    28. #elif defined(UDR)
    29. #define UDR_0 UDR
    30. #define UCSRA_0 UCSRA
    31. #define U2X_0 U2X
    32. #define UBRRH_0 UBRRH
    33. #define UBRRL_0 UBRRL
    34. #define UCSRB_0 UCSRB
    35. #define UCSRC_0 UCSRC
    36. #define UCSZ0_0 UCSZ0
    37. #define UCSZ1_0 UCSZ1
    38. #define USBS_0 USBS
    39. #define RXC_0 RXC
    40. #define UDRE_0 UDRE
    41. #define RXEN_0 RXEN
    42. #define TXEN_0 TXEN
    43. #define RXCIE_0 RXCIE
    44. #define TXCIE_0 UDRIE
    45. #define RX_INTERRUPT USART_RX_vect
    46. #define TX_INTERRUPT USART_UDRE_vect
    47. #endif
    48. /* Rx/Tx Ringbuffer (FIFO) */
    49. typedef struct ringbuffer8_t
    50. {
    51. unsigned char Buffer[UART_BUFLENGTH];
    52. unsigned char BufElements;
    53. unsigned char *readPointer;
    54. unsigned char *writePointer;
    55. } ringbuffer8_t;
    56. static unsigned char UART0_Rx_Error;
    57. static volatile ringbuffer8_t UART0_Rx_Buffer;
    58. static volatile ringbuffer8_t UART0_Tx_Buffer;
    59. #if defined(UDR1)
    60. static volatile ringbuffer8_t UART1_Rx_Buffer;
    61. static volatile ringbuffer8_t UART1_Tx_Buffer;
    62. static unsigned char UART1_Rx_Error;
    63. #endif
    64. /* Speichervariablen für Interrupt-Funktionen*/
    65. void (*uart_user_onReceive0)(unsigned int);
    66. void (*uart_user_onTransmit0)(void);
    67. void (*uart_user_onBufferFull0)(void);
    68. #if defined(UDR1)
    69. void (*uart_user_onReceive1)(unsigned int);
    70. void (*uart_user_onBufferFull1)(void);
    71. void (*uart_user_onTransmit1)(void);
    72. #endif
    73. static uint8_t uart_INT = 0;
    74. void ringbuffer_Init(volatile ringbuffer8_t* inst)
    75. {
    76. inst->readPointer = (volatile)&inst->Buffer[0];
    77. inst->writePointer = (volatile)&inst->Buffer[0];
    78. inst->BufElements = 0;
    79. }
    80. unsigned char ringbuffer_Read(volatile ringbuffer8_t* inst)
    81. {
    82. inst->BufElements--;
    83. if(inst->readPointer > (volatile)&inst->Buffer[UART_BUFLENGTH-1])
    84. {
    85. inst->readPointer = (volatile)&inst->Buffer[0];
    86. }
    87. return *inst->readPointer++;
    88. }
    89. void ringbuffer_Write(volatile ringbuffer8_t* inst, unsigned char data)
    90. {
    91. inst->BufElements++;
    92. if(inst->writePointer > (volatile)&inst->Buffer[UART_BUFLENGTH-1])
    93. {
    94. inst->writePointer = (volatile)&inst->Buffer[0];
    95. }
    96. *inst->writePointer++ = data;
    97. }
    98. unsigned char uart_init(uint16_t BAUD)
    99. {
    100. if (BAUD & 0x8000)
    101. {
    102. UCSRA_0 |= (1<<U2X_0);
    103. BAUD &=~0x8000;
    104. }
    105. // Baudrate setzten
    106. UBRRH_0 = (unsigned char)(BAUD>>8);
    107. UBRRL_0 = (unsigned char)BAUD;
    108. // Empfänger und sender aktivieren sowie Interrupts einstellen
    109. UCSRB_0 = (1<<TXEN_0) | (1<<RXEN_0) | (1<<RXCIE_0);
    110. UCSRC_0 = (1<<UCSZ0_0) | (1<<UCSZ1_0);
    111. return NO_ERROR;
    112. }
    113. unsigned char uart_off(void)
    114. {
    115. UCSRB_0 = 0x00;
    116. UCSRC_0 = 0x00;
    117. uart_INT = 0;
    118. return NO_ERROR;
    119. }
    120. /* Gibt den akuellsten Wert
    121. vom Buffer zurück */
    122. unsigned int uart_getc(void)
    123. {
    124. unsigned char _error = NO_ERROR;
    125. struct ringbuffer8_t tempbuf = UART0_Rx_Buffer;
    126. if(tempbuf.BufElements==0) return (NO_DATA_RECEIVED << 8);
    127. if (!(uart_INT & (1<<0))) _error = UART0_Rx_Error;
    128. UART0_Rx_Error = NO_ERROR;
    129. return ((_error << 8) & ringbuffer_Read(&tempbuf));
    130. }
    131. unsigned char uart_putc(char data)
    132. {
    133. UCSRB_0 &=~ (1<<TXCIE_0);
    134. if(UART0_Tx_Buffer.BufElements>=UART_BUFLENGTH)
    135. {
    136. return (BUFFER_FULL);
    137. }
    138. ringbuffer_Write(&UART0_Tx_Buffer, data);
    139. UCSRB_0 |= (1<<TXCIE_0);
    140. return (NO_ERROR);
    141. }
    142. void uart_putsc(char data)
    143. {
    144. if(UART0_Tx_Buffer.BufElements>=UART_BUFLENGTH)
    145. {
    146. return (BUFFER_FULL);
    147. }
    148. ringbuffer_Write(&UART0_Tx_Buffer, data);
    149. }
    150. unsigned char uart_puts(unsigned char *data, unsigned char nlength)
    151. {
    152. UCSRB_0 &=~ (1<<TXCIE_0);
    153. if((UART0_Tx_Buffer.BufElements+nlength)>=UART_BUFLENGTH)
    154. {
    155. return (BUFFER_FULL);
    156. }
    157. while (*data)
    158. {
    159. uart_putsc(*data++);
    160. }
    161. UCSRB_0 |= (1<<TXCIE_0);
    162. return (NO_ERROR);
    163. }
    164. void uart_onReceive(void (*function)(unsigned int))
    165. {
    166. uart_user_onReceive0 = function;
    167. uart_INT |= (1<<0);
    168. }
    169. void uart_onRxBufferFull(void (*function)(void))
    170. {
    171. uart_user_onBufferFull0 = function;
    172. uart_INT |= (1<<2);
    173. }
    174. void uart_onTransmit(void (*function)(void))
    175. {
    176. uart_user_onTransmit0 = function;
    177. uart_INT |= (1<<1);
    178. }
    179. ISR(RX_INTERRUPT)
    180. {
    181. if(uart_INT & (1<<0)) uart_user_onReceive0(uart_getc);
    182. if(UART0_Rx_Buffer.BufElements>=UART_BUFLENGTH)
    183. {
    184. UART0_Rx_Error = BUFFER_FULL;
    185. if(uart_INT & (1<<2)) uart_user_onBufferFull0();
    186. }
    187. else
    188. {
    189. ringbuffer_Write(&UART0_Rx_Buffer, UDR_0);
    190. }
    191. }
    192. /* UART Transmit Interrupt
    193. Sendet zusätzlich ein Interrupt an die user-Funktion
    194. wenn alle Daten gesendet wurden */
    195. ISR(TX_INTERRUPT)
    196. {
    197. UART0_Tx_Buffer.readPointer = UART0_Tx_Buffer.readPointer;
    198. if(UART0_Tx_Buffer.BufElements==0)
    199. {
    200. UCSRB_0 &=~ (1<<TXCIE_0);
    201. if(uart_INT & (1<<1)) uart_user_onTransmit0();
    202. }
    203. else
    204. {
    205. UDR_0 = ringbuffer_Read(&UART0_Tx_Buffer);
    206. }
    207. }
    208. #if defined(UDR1)
    209. unsigned char uart_init1(uint16_t BAUD)
    210. {
    211. if (BAUD & 0x8000)
    212. {
    213. UCSR1A |= (1<<U2X1);
    214. BAUD &=~0x8000;
    215. }
    216. // Baudrate setzten
    217. UBRR1H = (unsigned char)(BAUD>>8);
    218. UBRR1L = (unsigned char)BAUD;
    219. // Empfänger und sender aktivieren sowie Interrupts einstellen
    220. UCSR1B = (1<<TXEN1) | (1<<RXEN1) | (1<<RXCIE1);
    221. // Datenformat
    222. UCSR1C = (1<<UCSZ10) | (1<<UCSZ11) | (1<<USBS1);
    223. return NO_ERROR;
    224. }
    225. unsigned char uart_off1(void)
    226. {
    227. UCSR1B = 0x00;
    228. UCSR1C = 0x00;
    229. uart_INT = 0;
    230. return NO_ERROR;
    231. }
    232. unsigned int uart_getc1(void)
    233. {
    234. unsigned char _error = NO_ERROR;
    235. struct ringbuffer8_t tempbuf = UART1_Rx_Buffer;
    236. if(tempbuf.BufElements==0)
    237. {
    238. return (NO_DATA_RECEIVED << 8);
    239. }
    240. if (!(uart_INT & (1<<0)))
    241. {
    242. _error = UART0_Rx_Error;
    243. }
    244. UART1_Rx_Error = NO_ERROR;
    245. return ((_error << 8) & ringbuffer_Read(&tempbuf));
    246. }
    247. unsigned char uart_putc1(char data)
    248. {
    249. UCSR1B &=~ (1<<UDRIE1);
    250. if(UART1_Tx_Buffer.BufElements==UART_BUFLENGTH)
    251. {
    252. return (BUFFER_FULL);
    253. }
    254. ringbuffer_Write(&UART1_Tx_Buffer,data);
    255. UCSR1B |= (1<<UDRIE1);
    256. return (NO_ERROR);
    257. }
    258. unsigned char uart_puts1(char *data, unsigned char nlength)
    259. {
    260. UCSR1B &=~ (1<<UDRIE1);
    261. if(UART1_Tx_Buffer.BufElements>=UART_BUFLENGTH)
    262. {
    263. return (BUFFER_FULL);
    264. }
    265. while (*data)
    266. {
    267. uart_putc(*data++);
    268. }
    269. UCSR1B |= (1<<UDRIE1);
    270. return (NO_ERROR);
    271. }
    272. void uart_onReceive1(void (*function)(unsigned int))
    273. {
    274. uart_user_onReceive1 = function;
    275. uart_INT |= (1<<3);
    276. }
    277. void uart_onTransmit1(void (*function)(void))
    278. {
    279. uart_user_onTransmit1 = function;
    280. uart_INT |= (1<<4);
    281. }
    282. void uart_onRxBufferFull1(void (*function)(void))
    283. {
    284. uart_user_onBufferFull1 = function;
    285. uart_INT |= (1<<5);
    286. }
    287. ISR(USART1_RX_vect)
    288. {
    289. if(uart_INT & (1<<3))
    290. {
    291. uart_user_onReceive1(uart_getc);
    292. }
    293. if(UART1_Rx_Buffer.BufElements==UART_BUFLENGTH)
    294. {
    295. UART1_Rx_Error = BUFFER_FULL;
    296. if(uart_INT & (1<<5))
    297. {
    298. uart_user_onBufferFull1();
    299. }
    300. }
    301. else
    302. {
    303. ringbuffer_Write(&UART1_Rx_Buffer, UDR1);
    304. }
    305. }
    306. ISR(USART1_TX_vect)
    307. {
    308. if(UART1_Rx_Buffer.BufElements==0)
    309. {
    310. UCSR1C &=~ (1<<TXCIE1);
    311. if(uart_INT & (1<<1))
    312. {
    313. uart_user_onTransmit1();
    314. }
    315. }
    316. else
    317. {
    318. UDR1 = ringbuffer_Read(&UART1_Tx_Buffer);
    319. }
    320. }
    321. #endif


    Genau habe ich das Problem in Zeile 218 (Sende-Interrupt) und 147 / 168 (Funktionen zum hinzufügen von Zeichen in den Buffer und zum Starten der Übertragung)

    Ich verstehe allmähnlich wirklich nicht warum es nicht funktionieren will. Im Simulator sehe ich das von dem struct ringbuffer8_t namens 'UART0_Tx_Buffer' immer '*readPointer' und '*writePointer' nicht übernommen werden. Und das für genau zwei Zeichen. Und das habe ich auch während dem Programm (also nicht nur am Anfang).

    Es ist so als wird die Variable im Interrupt nicht mit der Globalen Variable Synchronisiert.

    Brauche da einen kleinen Anstupps zur Lösung bitte.

    ~gfc

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „gfcwfzkm“ ()

    volatile verhindert nur Compiler Optimierung mehr nicht.

    C-Quellcode

    1. struct ringbuffer8_t tempbuf = UART1_Rx_Buffer;

    das ist mir z.B. aufgefallen. Vmtl. nicht so gewollt. tempbuf ist dann nämlich eine Kopie des UART1_Rx_Buffer und somit hat die spätere aktion auf tempbuf. Z.B. ringbuffer_Read/Write keine auswirkung auf UART1_Rx_Buffer.
    Und ich finde dein Programm ziemlich unübersichtlich, auch wenn C nicht OOP ist kann man das ganze besser unterteilen.
    Z.B. grad den Ringbuffer einfach in ne extra Datei, kannst dann ja schön includen. Außerdem kannst du dann die Komponenten getrennt voneinander Testen und so den Fehler finden. Im Prinzip Unit Tests machen...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    @gfcwfzkm Kannst Du bitte um den Code einen Expander machen?

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Thunderbolt schrieb:

    dass Buffers ein Array auf Pointer darstellt

    Ist aufgrund des Namens auch nachvollziehbar. Ein Buffer ist meistens ein byte-array. In C ist das (sofern dynamische Größe benötigt) ein char*. Wenn es also Buffers heißt geht man davon aus, dass es mehrere Buffer sind -> char**.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.