Forum: Mikrocontroller und Digitale Elektronik FreeRTOS Semaphore übergeben wenn Paket angekommen


von paule (Gast)


Lesenswert?

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

von Simon H. (simi)


Lesenswert?

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.

von paule (Gast)


Lesenswert?

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

von Simon H. (simi)


Lesenswert?

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.

von paule (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.