STM32 UART Ringbuffer richtig lesen

OP #7658111
Lesenswert?

Ich habe einen Ringbuffer mit Größe 20 und empfange 13 Bytes. Wenn ich den Code laufen lasse kommt aber nur jede 20. Nachricht ordentlich an. Wenn ich mir das mal in einer Tabelle darstelle dann sehe ich das Muster wiederholt sich nach 20 Zeilen.

Im Debugger habe ich das Gefühl dass DMA1_Channel5->CNDTR mir nicht immer die richtige Antwort gibt. Wie finde ich raus ob es überhaupt das richtige Register ist? Es ist ein STM32F103C8T6.

gerechnet habe ich es genauso wie in der Excel Tabelle

1
#define KM_MAX_RXBUFF 20
2
static uint8_t last_pointer_position;
3
static uint8_t recent_pointer_position;
4
static uint8_t Rx_message_length = 13;
5
static uint8_t KM_Message[KM_MAX_RXBUFF];
6
HAL_UART_Receive_DMA(&huart1, (uint8_t *)KM_ctx->RxBuff, KM_MAX_RXBUFF;
7

8
recent_pointer_position = KM_MAX_RXBUFF-DMA1_Channel5->CNDTR;
9
if (recent_pointer_position < Rx_message_length) {
10
    last_pointer_position = KM_MAX_RXBUFF + recent_pointer_position - Rx_message_length;
11
}
12
else {
13
    last_pointer_position = recent_pointer_position - Rx_message_length;
14
}
15

16
if(recent_pointer_position > last_pointer_position){
17
    memcpy(KM_Message, KM_ctx->RxBuff+last_pointer_position, Rx_message_length);
18
}
19
else {
20
    memcpy(KM_Message, KM_ctx->RxBuff+last_pointer_position, KM_MAX_RXBUFF-last_pointer_position);
21
    memcpy(KM_Message+KM_MAX_RXBUFF-last_pointer_position, KM_ctx->RxBuff, recent_pointer_position);
22
}

Unter der Bedingung das CNDTR auf die Position des 13. empfangenen Bytes zeigt klappt es, aber sonst nicht.

Das zweite Problem ist dass es auch mal mehr oder weniger als 13 Bytes sein können, daher war der ursprüngliche Code anders. Hier habe ich aber das gleiche Problem, nur jede 20. Nachricht passt.

https://github.com/aIecxs/EBiCS_Firmware/blob/3d38ccf/Src/display_kingmeter.c#L319

(es funktioniert wenn ich den ganzen Branch kompiliere, aber nicht wenn ich nur das memcpy() in einen anderen Branch übernehme)

https://github.com/EBiCS/EBiCS_Firmware/blob/90f6ad2/Src/display_kingmeter.c#L373

Angehängte Dateien:
OP #7658426
Lesenswert?

Also noch mal die Frage, ist DMA1_Channel5->CNDTR für HAL_UART_Receive_DMA(&huart1) immer der richtige Channel? Ich weiß man könnte auch über HAL gehen, aber ich würde es bevorzugen das richtige Register direkt zu fragen.

Daher die Frage wie uart1 DMA und Channel in Beziehung stehen. Habe noch mal hier reingeguckt aber konnte eine solche Beziehung nicht finden.

https://www.mikrocontroller.net/topic/goto_post/7522051

OP #7658795
Lesenswert?

Hab es gefunden in stm32f1xx_hal_msp.c aber nicht rausbekommen wo mein Fehler liegt.

1
/* USART1_RX Init */
2
hdma_usart1_rx.Instance = DMA1_Channel5;
3
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
4
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
5
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
6
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
7
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
8
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
9
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;

Im Code werden allerdings Interrupts deaktiviert und die Prioritäten sind geändert - werde die Änderungen mal nachziehen vielleicht klappt es dann.

1
/* USART1 interrupt Init */
2
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
3
HAL_NVIC_EnableIRQ(USART1_IRQn);
4
/* USER CODE BEGIN USART1_MspInit 1 */
5

6
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 1, 0);
7
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
8

9
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 3, 1);
10
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
OP #7658956
Lesenswert?

Daran liegt es nicht. Ich lese den Ringbuffer falsch. Was mir fehlt ist eine Länge. Die Position vorher/nachher reicht dafür nicht, man müsste auch wissen wie oft zwischendurch gesprungen wurde.

Andreas B. schrieb:

HAL_USART_RxHalfCpltCallback bzw. HAL_USART_RxCpltCallback sind wo?

Was soll mir das nützen? Ich bräuchte etwas dass mir das Ende des Ringbuffers meldet. Ein (MBTC) Memory Buffer Transfer Complete Flag.

OP #7659790
Lesenswert?

Ja, ich kenne auch das Startbyte und im vierten Byte steht die Länge. Aber das reicht nicht um die Länge der Nachricht zu ermitteln. Ich habe das Gefühl der Buffer wird oft mehr als einmal überschrieben, in solchen Fällen muss man den Buffer dann verwerfen. Außerdem sollte es auch unabhängig vom Inhalt möglich sein. Ich schaue mir noch mal die Interrupts an, am Code kann es nicht liegen.

#7660177
Lesenswert?

Alexander schrieb:

Andreas B. schrieb:

HAL_USART_RxHalfCpltCallback bzw. HAL_USART_RxCpltCallback sind wo?

Was soll mir das nützen? Ich bräuchte etwas dass mir das Ende des Ringbuffers meldet. Ein (MBTC) Memory Buffer Transfer Complete Flag.

Nun ja, das HTIF bzw. TCIF lösen einen Interrupt nach Hälfte bzw. nach vollständigem Transfer aus ... Die Callbacks reagieren genau darauf. Die beiden Interrupts kann man natürlich auch in Eigenregie aktivieren und abarbeiten, dann muss das HAL-Zeugs aber (teilweise) in die Tonne.

OP #7660372
Lesenswert?

Also irgendwas ist nicht richtig konfiguriert. DMA1_Channel5->CNDTR passt nicht mit dem zusammen was gerade in KM_ctx->RxBuff geschrieben wurde, habs im Debugger gesehen. Teilweise werden Variablen auch wegoptimiert. Habe es mit static volatile versucht aber es wurde nicht besser.

Wenn ich im Debugger recent_pointer_position, last_pointer_position gemäß der Exceltabelle setze dann funktioniert das memcpy() auch richtig.

Das SetPriority und EnableIRQ ist doppelt drin, einmal in stm32f1xx_hal_msp.c und einmal in main.c kann es daran liegen? Habe den Code so von Hochsitz C. (hochsitzcola) übernommen.

OP #7661787
Lesenswert?

Ich hab den Unterschied gefunden. Habe es so übernommen, nun funktioniert es.

https://github.com/EBiCS/EBiCS_Firmware/blob/90f6ad2/Src/stm32f1xx_it.c#L363

Interrupt wird über das IDLE Bit ausgelöst, also Ende der Nachricht - nicht über TCIF Ende des Buffers. Es klappte vorher nur zufällig bei jedem 20. Durchgang wenn Ende der Nachricht = Ende des Buffers war.

https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx/blob/main/README.md#dma-httc-and-uart-idle-combination-details

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren