Hallo, ich nutze zur Zeit im FreeRTOS für den Empfang eines Pakets eine Queue in der Interruptroutine. Dabei die QueueSendFromISR. Mir ist aufgefallen, das nach zufälliger Zeit die Kommunikation zwischen 2 Modulen stehen bleibt. Dabei vermute ich, dass es an der Empfangsroutine liegt, da Daten gesendet werden aber nichts mehr empfangen werden kann. Zusätzlich habe ich in der Doku gelesen, das es uneffektiv ist eine Queue in der Interruptroutine zu verwenden. Ansatz jetzt wäre, die Daten in der Inerruptroutine in einen Buffer zu schreiben und wenn das Paket komplett empfangen wurde, in einen Task zu wechseln, der auswertet. Wie bekomme ich es hin, das erst das ganze Paket empfangen wird? Ich gehe davon aus das das Abbruchkriterium wohl der Ablauf von Ticks sein wird, ehe die Semaphore übergeben wird? Vielleicht kann mir jemand einen Tipp geben. Gruß paule
So aus dem Stehgreif: Die empfangenen Daten in der ISR soweit analysieren, dass das Ende eines Frames erkannt wird, und dann mittels QueueSendFromISR eine Meldung abschicken (ev. mit Pointer auf den Buffer und Länge der Meldung). Wenn Du den Buffer gross genug machst, kannst Du ihn auch als Ringbuffer beschreiben und jeweils den richtigen Pointer mitgeben. Die empfangende Routine muss dann einfach schnell genug abarbeiten, bevor dieser Bereich wieder überschrieben wird.
Hallo, ich habe nur so verstanden beim Lesen, das ich die QueueSendFromISR nicht verwenden soll um meine Daten zu sammeln und bereitzustellen für einen anderen Task. Oder meinst du nur über QueueSend nur den Pointer und die Länge übermitteln? Da ich je nach Paketinhalt das Paket weiterschicken muss oder nicht, dauert das sicherlich in der ISR zu lange sort eine Auswertung vorzunehmen. Stimmt einen Ringpuffer kann ich dann auch in der ISR beschreiben lassen und den dann im Task auswerten. Was meinst du mit "den richtigen Pointer mitgeben" ? Von wem an wen? Gruß paule
Vielleicht habe ich Dich auch falsch verstanden. Was sicherlich ganz schlecht ist, ist, jedes Byte einzeln über eine Queue zu jagen. Deswegen mein (nö, eigentlich Dein) Vorschlag, die vorerst einfach mal zu sammeln. Die Abbruchbedingung kann ja auch, wenn eine Frameerkennung für die ISR zu komplex ist, einfach sein: Wenn 128 Bytes da sind, schick die mal weg. Und das Framing dann dem Empfänger der Meldung (der Queue) überlassen. paule schrieb: > Was meinst du mit "den richtigen Pointer > mitgeben" ? Von wem an wen? Ich stelle mir das z.B. so vor: 512 Byte Framebuffer. Der wird immer wieder überschrieben. (2er Potenz, um das modulo einfach zu halten). Immer, wenn ein Frame empfangen wurde (oder eben ein 128-Byte-"Paket"), eine Message in die Queue schicken, dass bei Adresse x y Bytes gelesen werden können (im Fall von fixen Paketen à 128 Byte wäre y halt immer 128). So hast Du den Overhead des byteweisen Verschickens über die Queue eliminiert, und der Empfänger der Messages muss einfach genug schnell den Bytehaufen abarbeiten, bevor er wieder überschrieben wird.
Hallo, okay, habe mir jetzt einen Ringpuffer gebaut, der so aussieht:
1 | #define ENOERR 0 /* No error */ |
2 | #define ENOSPC 28 /* No space left on device */ |
3 | #define ESPIPE 29 /* Illegal seek */ |
4 | |
5 | #define BUFFER_SIZE 512 ///< Size of buffer
|
6 | #define BUFFER_MASK (BUFFER_SIZE-1)
|
7 | |
8 | int head; |
9 | int tail; |
10 | int full; |
11 | int next; |
12 | uint16_t data[BUFFER_SIZE]; |
13 | |
14 | |
15 | void init_ring() |
16 | {
|
17 | head=0; |
18 | tail=0; |
19 | full=0; |
20 | next=0; |
21 | }
|
22 | |
23 | |
24 | int ring_in (uint16_t byte) |
25 | {
|
26 | next = ((head+1) & BUFFER_MASK); // Maske um den Puffer vor Überlauf zu schützen, Modulo 2 |
27 | data[head] = byte; // Buffer wird byte zugewiesen |
28 | head = next; |
29 | USART3->CR1 |= USART_FLAG_TXE; |
30 | /if (ring_full()) |
31 | return -ENOSPC; // Index wird neu übernommen |
32 | return ENOERR; |
33 | }
|
Diesen Puffer lasse ich jetzt also in der Routine beschreiben. Bei mir wird ein Paket maximal 265 Bytes lang. Die Länge des Frames steht immer an derselben Stelle:
1 | //******************************************************************************
|
2 | // USART3 IRQ Handler
|
3 | //******************************************************************************
|
4 | |
5 | void USART3_IRQHandler(void) |
6 | {
|
7 | uint16_t sr = USART3->SR; |
8 | portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; |
9 | portBASE_TYPE xTaskWokenByReceive = pdFALSE; |
10 | // Check for received Data
|
11 | if (sr & USART_SR_RXNE) |
12 | {
|
13 | ch = (uint16_t) USART3->DR; |
14 | ring_in(ch); |
15 | // xQueueSendFromISR (hSerialRx, &ch, &xHigherPriorityTaskWoken);
|
16 | }
|
17 | |
18 | // Check if transmit buffer is empty
|
19 | if (sr & USART_SR_TXE) |
20 | {
|
21 | if(txReadPtr < txWritePtr) |
22 | {
|
23 | uint16_t byte = txReadPtr==0 ? 0x100 : 0; |
24 | byte |= txBuffer[txReadPtr++]; |
25 | USART3->DR = byte; |
26 | }
|
27 | else
|
28 | // disable TXE interrupt
|
29 | USART3->CR1 &= ~USART_CR1_TXEIE; |
30 | }
|
31 | }
|
So fülle ich also dann meinen Ringpuffer mit Zeichen. Jetzt weiss ich aber nicht, wie ich die Abbruchbedingung gestalten soll,so das der Frane übergeben werden kann. Wüsste ich dieses würde ich dann in eine Queue die Adresse wo zu lesen ist und wieviel zu lesen ist hinschreiben, dann kann die Auswertung erfolgen und dementsprechend weitergesendet werden, das habe ich verstanden. Gruß paule
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.