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
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
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
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
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
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
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
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