Debido a una materia del posgrado de Sistemas Embebidos del Instuto Universitario Aeronautico, que pedia realizar un pequeño proyecto donde se implemente un sistema embebido con el RTOS uCOS, me parecio una buena oportunidad de adaptar el
driver grafico LCD para FREERTOS para que funcione en uC/OS-II.
Como la libreria estaba pensada para usar con un RTOS, fue relativamente sencillo adaptarla para que funcione con las funciones que implementa uC/OS para:
- Creacion de tareas
- Destruccion de tareas
- Pasaje de argumentos a tareas
- Semaforos, señalizacion y sincronizacion
- Manejo de memoria y errores
Lo que mas me complico fue en si el port (o adaptacion del uCOS a un micro/compilador) para C18, por el modelo de memoria que este cuenta (modelo de bancos y punteros de memoria separados para objetos en ram y rom).
Utilice C18 por questiones de tiempo y disponibilidad, ya que los micros que tenia (AT91SAM7, LPC1104, DSPIC, PIC24) no tenia todo lo necesario para hacerlo funcionar (en algunos tenia el port para el micro pero no la IDE, o el debugguer, en otro no tenia el port, etc).
Adicionalmente en este proyectito dejo una demo actualizada para el port del C30 (linea DSPIC y PIC24) y (espero que no haya inconvenientes) todos los sources del uCOS desde el 2.50 al 2.90.
Solo a modo de ejemplo dejo la parte de la demo que muestra como se utiliza, es muy simple, se inicializa con una funcion que se le pasa el stack que requerira y la primera de 2 prioridades que utilizara.
Despues cada tarea se le pasa por parametros el objeto especifico (pixel, linea, rectangulo, circulo, bitmaps, etc).
void demoTask(void *pdata)
{
INT16S size;
INT8U cnt;
const INT8U **messagesPtr;
//Initialize LCD Services (uses priorities 3, 4, 5)
vGlcdInit(&lcdTaskStk[0], sizeof(lcdTaskStk), 3);
for(;;)
{
/*Init fillscreen object*/
fillScr.offset.x = fillScr.offset.y = 0; //Offset for the source in X and Y
fillScr.param.color = PX_COMB_PASTE; //Coloring method
fillScr.size.x = fillScr.size.y = 1; //One byte long in X and Y
fillScr.data = pclean; //Source of the data
/*Call to the method "Clear all screen"*/
cGlcdFillScr( &fillScr );
/*Draw 2 rectangles*/
rectangle.posIni.x = 0; rectangle.posFin.x = 127;
rectangle.posIni.y = 0; rectangle.posFin.y = 63;
rectangle.param.color = PX_COMB_ON;
rectangle.param.getSet = SET;
rectangle.param.limited = 1; rectangle.param.optimized = 1;
for (cnt = 0; cnt < 2; cnt++)
{
rectangle.posIni.x = cnt * 2; rectangle.posFin.x = 127 - cnt * 2;
rectangle.posIni.y = cnt * 2; rectangle.posFin.y = 63 - cnt * 2;
cGlcdRectangle(&rectangle);
OSTimeDly(2);
}
//Draw a splitting line
line.param.color = PX_COMB_ON;
line.param.getSet = SET;
line.param.limited = 1;
line.param.optimized = 1;
line.posIni.x = 63;
line.posIni.y = 2;
line.posFin.x = 63;
line.posFin.y = 60;
cGlcdLine(&line);
/*Init text object*/
text1.window.pos.x = 3;
text1.window.pos.y = 3; //Position of the text window
text1.window.size.x = 58;
text1.window.size.y = 58; //Size of the text window
text1.string.pos.x = text1.string.pos.y = 0; // Initial position of text in the window
text1.string.param.color = PX_COMB_PASTE;
text1.string.param.optimized = 1;
text1.string.param.limited = 1;
text1.string.tabspace = xGlcdGetDefTAB(4); // Size of tab space
text1.font.size.x = 5; text1.font.size.y = 6; //Size of font
text1.font.data = font5_6;
messagesPtr = messages;
//Print a message 20 times
for (cnt = 0; cnt < 20; cnt++)
{
//Set Message
text1.string.data = (const INT8U *) *messagesPtr++;
//Print Messages
cGlcdPrintf( &text1 );
//Delay 500 ms
OSTimeDlyHMSM(0, 0, 2, 0);
if (*messagesPtr == 0) { messagesPtr = messages; }
}
bitmap.param.limited = 0; //Limit to screen size
bitmap.param.optimized = 1; //Optimized routine
bitmap.source.size.x = 16; bitmap.source.size.y = 16; //Size of the bitmap source
bitmap.size = bitmap.source.size; //Size of the desired bitmap
bitmap.source.offset.x = bitmap.source.offset.y = 0;
bitmap.param.color = PX_COMB_XOR; //Negate
bitmap.source.data = pball; //Data of the bitmap
for (cnt = 0; cnt < 200; cnt++ )
{
bitmap.
pos.
x = ((INT16U
)sin(cnt
) * 48)/64; bitmap.
pos.
y = ((INT16U
)sin(cnt
+ 32) * 48)/64;
/*Call to the method "place bitmap"*/
cGlcdBitmapSet( &bitmap );
OSTimeDly(5);
/*Restore by negating*/
cGlcdBitmapSet( &bitmap );
}
}
}
Aca las funciones (solo dos son ejecutadas en el momento, la inicializacion y el pixel, que cuenta con semaforizacion), el resto llama a un arrancador generico de tareas.
void vGlcdInit(void *stack, INT16U size, INT8U prios);
#define cGlcdPixel(pixel) cGlcdPixelInt(pixel, TRUE /*use locks*/)
#define cGlcdFillScr(fillData) cGlcdTaskStarter(vGlcdFillScr /*Starts a FillScr task*/ , (void *)fillData, 0)
#define cGlcdBitmapSet(bitmap) cGlcdTaskStarter(vGlcdBitmapSet /*Starts a GlcdBitmapSet task*/, (void *)bitmap, 0)
#define cGlcdBitmapGet(bitmap) cGlcdTaskStarter(vGlcdBitmapGet /*Starts a GlcdBitmapGet task*/, (void *)bitmap, 0)
#define cGlcdLine(line) cGlcdTaskStarter(vGlcdLine /*Starts a GlcdLine task*/, (void *)line, 0)
#define cGlcdFloodFill(floodFill) cGlcdTaskStarter(vGlcdFloodFill /*Starts a GlcdFloodFill task*/, (void *)floodFill, 0)
#define cGlcdCircle(circle) cGlcdTaskStarter(vGlcdCircle /*Starts a GlcdCircle task*/, (void *)circle, 0)
#define cGlcdPrintf(text) cGlcdTaskStarter(vGlcdPrintf /*Starts a GlcdPrintf task*/, (void *)text, 1)
#define cGlcdRectangle(rectangle) cGlcdTaskStarter(vGlcdRectangle /*Starts a GlcdRectangle task*/, (void *)rectangle, 1)
Aqui subo un video pero es mucho mas limitado que el demo del link que pase al principio, debido a la poca memoria del PIC, y que todos los objetos constantes los vuelca en RAM (si, una porqueria) hay que usar el qualifier
rom para que lo mande a rom pero los punteros de rom no tienen visibilidad de ram con lo que hay que duplicar metodos y no vale la pena ensuciar el driver.
Nota: no se rian del audio que tiene, era para sacarle el original que se escuchaban los autos pasar.Como nota adicional, este port de MCC18 esta mejorado del original de Nathan Brown, este usa como tick del sistema el CCP que genera una interrupcion sin latencias por cuestiones de recarga del timer y tiene listo el uso del puerto serie a traves del RTOS con mutex y semaforizacion.
Link al codigo