Hallo zusammen,
ich habe hier einen Effekt, den ich nicht nachvollziehen kann: Ich
empfange Datenpakete an der USART1 eines STM32, die im vierten Byte eine
Längeninformation enthalten. Sobald ich diese Längeninformation habe,
möchte ich von Interrupt-Betrieb auf DMA umschalten. Dazu konfiguriere
ich in der USART-Interrupt-Routine den DMA:
1 | // Configure and activate DMA for reception
|
2 | DMA_Cmd(DMA1_Channel5, DISABLE);
|
3 | // Set DMA address
|
4 | DMA1_Channel5->CMAR = (uint32_t)&(receptionBuffer[bufferWriteIndex].buffer[4]);
|
5 | // Set received length
|
6 | DMA1_Channel5->CNDTR = receptionBuffer[bufferWriteIndex].buffer[3];
|
7 | DMA_Cmd(DMA1_Channel5, ENABLE);
|
Nun wird aber - für mich überraschend - in meinem Buffer das Längen-Byte
zweimal abgelegt, einmal durch den USART-Interrupt (gewünscht) und
einmal durch den DMA (unerwünscht). Aus einem Paket
0xFF 0xFF 0x01 0x02 0x01 0xFB
mit der Längeninformation 0x02 wird damit
0xFF 0xFF 0x01 0x02 0x02 0x01. Eigentlich müsste durch das Auslesen per
1 | // Get received byte
|
2 | receivedByte = USART_ReceiveData(USART1);
|
doch der USART-Buffer geleert worden sein?! Auch ein vorheriges
manuelles Rücksetzen des RXNE-Flags ändert nichts. Warum erkennt der DMA
das Byte trotzdem noch einmal als "neu" empfangen? Im Reference Manual
konnte ich bisher keine Erklärung finden...
Im Anhang ist mein kompletter Quellcode mit Initialisierung der USART
und des DMA. Hier meine etwas verkürzte USART-Interrupt-Routine:
1 | void USART1_IRQHandler(void) {
|
2 |
|
3 | // Private variables
|
4 | uint8_t receivedByte;
|
5 |
|
6 | // USART receive data register is not empty
|
7 | if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
|
8 |
|
9 | // Get received byte
|
10 | receivedByte = USART_ReceiveData(USART1);
|
11 |
|
12 | // If packet does not start with two start bytes, refuse packet and reset
|
13 | // reception buffer
|
14 | if ((receptionBuffer[bufferWriteIndex].length < 2) && (receivedByte != 0xFF)) {
|
15 |
|
16 | // Reset reception buffer
|
17 | receptionBuffer[bufferWriteIndex].length = 0;
|
18 |
|
19 | return;
|
20 |
|
21 | }
|
22 |
|
23 | // If packet length is not valid, refuse packet and reset reception buffer
|
24 | if ((receptionBuffer[bufferWriteIndex].length == 3) && ((receivedByte < 2) || (receivedByte > 250))) {
|
25 |
|
26 | // Reset reception buffer
|
27 | receptionBuffer[bufferWriteIndex].length = 0;
|
28 |
|
29 | return;
|
30 |
|
31 | }
|
32 |
|
33 | // Copy received byte to buffer and increase buffer length
|
34 | receptionBuffer[bufferWriteIndex].buffer[receptionBuffer[bufferWriteIndex].length++] = receivedByte;
|
35 |
|
36 | // If packet length is known, configure and activate DMA for reception
|
37 | if (receptionBuffer[bufferWriteIndex].length == 4) {
|
38 |
|
39 | // Configure and activate DMA for reception
|
40 | DMA_Cmd(DMA1_Channel5, DISABLE);
|
41 | // Set DMA memory address
|
42 | DMA1_Channel5->CMAR = (uint32_t)&(receptionBuffer[bufferWriteIndex].buffer[4]);
|
43 | // Set DMA length
|
44 | DMA1_Channel5->CNDTR = receptionBuffer[bufferWriteIndex].buffer[3];
|
45 | DMA_Cmd(DMA1_Channel5, ENABLE);
|
46 |
|
47 | }
|
48 |
|
49 | }
|
50 |
|
51 | }
|