Forum: Compiler & IDEs uC-OS 2 Port ATmega128 Probleme


von Oyrer Andreas (Gast)


Lesenswert?

Hallo,

hab mir mal das uC-OSII angeschaut und einen fast fertigen Port 
verwendet. Funktioniert an sich, nur gibt es Probleme, wenn ich z.B. 
UART0 implementiere. Zu Beginn der ISR erhöhe ich den Nesting-Counter 
und sichere die Register. Beim Beenden rufe ich OSIntExit auf, worauf 
das OS schaut, ob ein Taskswitch erforderlich ist. Die Register werden 
am Ende wieder zurückgesichert.
Das Problem ist jetzt, dass komische Zeichen eintreffen, wenn ich 
schnell Daten an den UART sende. Wenn ich jede Sekunde 1-2 Bytes 
schicke, kein Problem.

Hat vielleicht jemand Erfahrungen mit uC-OSII und kann mir evtl. helfen?

Danke
mfg
Andreas

von Roland B. (micfan)


Lesenswert?

Hallo Andreas,
ich verwende ebenfalls das uC-OS 2 und benutze folgenden Port:
http://www.ee.lut.fi/staff/Julius.Luukko/ucos-ii/index.shtml
Habe bisher nur sehr gute Erfahrungen mit dem OS gemacht, läuft absolut 
stabil.

Als Basis für meine UART Routinen verwende ich
// AVR306: Using the AVR UART in C
// Routines for interrupt controlled UART

Hier ist die Senderoutine .. für ATMega128

#if defined(_AVR_ATmega128_)
//
// Send Data in Buffer
//
UCOSISR (USART0_UDRE_vect)
{
  PushRS();
  OSIntNesting++;
  if (OSIntNesting == 1) OSTCBCur->OSTCBStkPtr = (OS_STK *)SP;

  // Check if all data is transmitted
  if ( UART_TxHead != UART_TxTail )
  {
    // Calculate buffer index
    tmptail = ( UART_TxTail + 1 ) & UART_TX_BUFFER_MASK;
    UART_TxTail = tmptail;          // Store new index
    UDR0 = UART_TxBuf[tmptail];     // Start transmission
  }
  else
  {
    UCSR0B &= ~(1<<UDRIE0);         // Disable UDRIE interrupt
  }

  OSIntExit();
  PopRS();
}
#endif

Bei Bedarf kann ich dir die Routinen komplett zuschicken. Die passen 
halt nur für die entsprechende Portierung

Gruß
Roland

von Andreas (Gast)


Lesenswert?

Hallo Roland,

vielen Dank für deinen Tipp. Ich glaube, über den Port bin ich auch 
schon mal gestolpert... Werde mir das mal anschauen und dann melde ich 
mich wieder.

Hast du auch mal versucht, ein Event in UART-RX-Interrupt zu posten? Ich 
wollte damit anzeigen, dass neue Daten im Buffer sind, hatte aber genau 
das gleiche Problem, wie oben beschrieben.

Mein Test-Task sieht folgendermaßen aus (Echo zurücksenden):

void TASK2_Run(void * data)
{
  // init the uart
  UART0_Init(BR_9600);

  /* The data is not used. */
  data = data;

  for (;;)
  {
    while (UART0_DataAvailable())
    {
      // we got a new char
      INT8U res = UART0_Read();
      UART0_PutChar(res);
    }
    OSTimeDlyHMSM(0, 0, 0, 20);
  }
}

Danke
mfg
Andreas

von Andreas (Gast)


Lesenswert?

Hallo Roland,

habe jetzt den Port von dir verwendet, aber noch immer das gleiche 
Problem. Wenn ich viele Daten sende, dass hängt sich das OS auf. Muss 
weiter schauen, woran das liegen könnte. Kannst du mir vielleicht deine 
Portfiles geben, damit ich den Fehler eingrenzen kann.

Danke.
mfg
Andreas

von Roland B. (micfan)


Lesenswert?

Hallo Andreas,
natürlich soll sich die Task suspendieren, wenn keine Zeichen im 
Empfangspuffer vorhanden sind. D.h. getchar() legt sich mit einem 
OSSemPend(Uart0_RxSem, timeout, &err) schlafen. Die Empfangsinterrupt 
Routine informiert bzw. weckt via OSSemPost(Uart0_RxSem) die Task bzw. 
die Funktion getchar() auf. Die Task arbeitet dann solange bis der 
Puffer leer ist und legt sich wieder schlafen. Mann kann das auch mit 
Events lösen, diese sind aber mächtiger und deren zusätzlichen 
Möglichkeiten werden dafür nicht gebraucht.

Das Abfragen mittels While Schleife kostet nur cpu Zeit und sind in 
einem RTOS fehl am Platz, eigentlich überall..
Dein UART0_DataAvailable() könnte sich ja suspendieren, nur dann ist 
dein OSTimeDlyHMSM(0, 0, 0, 20) überflüssig..

Beispiel für ein einfaches getchar(), ich gebe in der Praxis noch ein 
timeout mit, falls man nicht ewig warten kann, um eine Fehlersituation 
zu behandeln..

unsigned char uart_getchar( void )
{
  uint8_t   tmptail,
            err;

  if (UART_RxHead == UART_RxTail)
  {
    // no data available, suspend Task
    data_cnt = 0;
    OSSemPend(Uart0_RxSem, 0, &err);
  }

  // Calculate buffer index
  tmptail = (UART_RxTail+1) & UART_RX_BUFFER_MASK;
  UART_RxTail = tmptail;            // Store new index
  return UART_RxBuf[tmptail];       // Return data
}

und hier die zugehörige Interrupt Routine

#if defined(_AVR_ATmega128_)
UCOSISR (USART0_RX_vect)
{
  PushRS();
  OSIntNesting++;
  if (OSIntNesting == 1) OSTCBCur->OSTCBStkPtr = (OS_STK *)SP;

  data = UDR0;                  // Read the received data
  // Calculate buffer index
  tmphead = ( UART_RxHead + 1 ) & UART_RX_BUFFER_MASK;
  UART_RxHead = tmphead;        // Store new index

  // tmphead == UART_RxTail -> Receive buffer overflow !
  // hier kann man sich was nettes ausdenken, je nach Erforderniss..

  UART_RxBuf[tmphead] = data;   // Store received data in buffer
  data_cnt++;

  if (data_cnt == 1) OSSemPost(Uart0_RxSem);  // Notify getchar() / 
calling Task
  OSIntExit();
  PopRS();
}
#endif

Hoffe das hilft weiter, viel Erfolg!

Gruß
Roland

von Roland B. (micfan)


Lesenswert?

Hallo Andreas,
nur zur Sicherheit, ich verwende nicht die Beta Portversion !

Sorry, hatte ich vergessen zu erwähnen, ist schon so lange her..
Ich verwende die Version 1, d.h. die "141003" mit bugfix für avr_isr.h

Ist aber alles auf der Port Homepage beschrieben.

Ich schicke dir auch gerne die Dateien, dazu benötige ich deine Email 
Adresse..

Gruß
Roland

von Andreas O. (andio)


Lesenswert?

Hallo Roland,

danke für die Tipps. Habe auch die 141003 Version mit Bugfix verwendet. 
Hast du noch was zusätzlich am Port geändert? Welche OS_CRITICAL_METHOD 
verwendest du? Habe zuerst 1, dann 3 verwendet. Im Port ist aber wieder 
1.

Das mit der while-Schleife habe ich nur zum Testen gemacht. Sollte ja 
auch funktionieren, oder? Ich werde den UART nochmal umbauen und mit 
OSSemPost versehen. In meinen ersten Versuchen habe ich Events 
verwendet.

Email ist: andreas.oyrer@gmx.at

Danke für die Hilfe.

mfg
Andreas

von Roland B. (micfan)


Lesenswert?

Hallo Andreas,
ich verwende #define  OS_CRITICAL_METHOD    1

Am Port habe ich ansonsten nichts verändert. Der OS-TICK ist bei mir 
OS_TICKS_PER_SEC 50. Ich habe lediglich die Anregung von Julius Luuko 
umgesetzt und den OSUnMapTbl[] in das Programm Flash verlegt. Jetzt kann 
ich mit einem ATMega32 ohne RAM-Platznot 5 Tasks laufen lassen.

Ich schicke dir mal die Portroutinen und die UART Routinen.

Gruß
Roland


von Gerald (Gast)


Lesenswert?

wie viel speicher (flash, ram) braucht uC-OS 2 auf einem atmel 
atmega128?

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.