Bueno, aquí dejo una versión NO FUNCIONAL del driver de la UART. Con vuestros comentarios espero poder hacerlo funcionar correctamente, así que espero que os animéis!!
Cumple los tres conceptos basicos que creo que debe cumplir un driver:
Impide que más de una tarea maneje la UART al mismo tiempo.
Libera a las tareas del control de las interrupciones.
Libera al usuario de la configuracion a bajo nivel.
Se divide en 2 archivos: uart_driver.h y uart_driver.c, y se apoya en las funciones del archivo uart.h que proporciona Microchip.
El archivo uart_driver.h declara las siguientes funciones:
int InitUART1_driver(void);
Inicializa los recursos que comunicarán la uart con la aplicacion (2 queues y un mutex).
void OpenUART1_driver(unsigned int config1,unsigned int config2, unsigned int ubrg);
Configura y arranca la uart.
void CloseUART1_driver(void);
Para la uart.
unsigned int ReadUART1_driver(void);
Lee un dato de la cola de recepción de la uart. Este dato habrá sido introducido en la cola en la función _ISR __attribute__((interrupt)) _U1RXInterrupt.
void WriteUART1_driver(unsigned int data);
Escribe un dato en cola de transmisión de la uart. Este dato será extraído de la cola en la funcion _ISR __attribute__((interrupt)) _U1TXInterrupt.
// UART_DRIVER.H
#ifndef UART_DRIVER_H
#define UART_DRIVER_H
#include "UART.H"
#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"
int InitUART1_driver(void);
void OpenUART1_driver(unsigned int config1,unsigned int config2, unsigned int ubrg);
void CloseUART1_driver(void);
unsigned int ReadUART1_driver(void);
void WriteUART1_driver(unsigned int data);
//void _ISR _U2TXInterrupt(void);
//void _ISR _U2RXInterrupt(void);
#endif // #ifndef UART_DRIVER_H
// UART_DRIVER.C
#ifndef UART_DRIVER_C
#define UART_DRIVER_C
#include "UART_DRIVER.H"
static xSemaphoreHandle xMutexUartDriver;
static xQueueHandle xQueueUartDriverTx;
static xQueueHandle xQueueUartDriverRx;
int InitUART1_driver(void){
if( NULL == ( xMutexUartDriver = xSemaphoreCreateMutex() ) )
return -1;
if( NULL == ( xQueueUartDriverTx = xQueueCreate( 4, sizeof( unsigned int ) ) ) )
return -1;
if( NULL == ( xQueueUartDriverRx = xQueueCreate( 4, sizeof( unsigned int ) ) ) )
return -1;
vQueueAddToRegistry( xMutexUartDriver, ( signed portCHAR * ) "xMutexUartDriver" );
vQueueAddToRegistry( xQueueUartDriverTx, ( signed portCHAR * ) "xQueueUartDriverTx" );
vQueueAddToRegistry( xQueueUartDriverRx, ( signed portCHAR * ) "xQueueUartDriverRx" );
return 0;
}
void OpenUART1_driver(unsigned int config1,unsigned int config2, unsigned int ubrg){
if( pdTRUE == xSemaphoreTake( xMutexUartDriver, portMAX_DELAY ) ){
OpenUART1( config1, config2, ubrg );
ConfigIntUART1( UART_RX_INT_EN & UART_RX_INT_PR7 & UART_TX_INT_EN & UART_TX_INT_PR7 ); // Como trabajar correctamente con los defines de uart.h?
}
return;
}
void CloseUART1_driver(void){
CloseUART1();
ConfigIntUART1( UART_RX_INT_DIS & UART_TX_INT_DIS );// Como trabajar correctamente con los defines de uart.h?
xSemaphoreGive( xMutexUartDriver );
return;
}
unsigned int ReadUART1_driver(void){
unsigned int data;
xQueueReceive( xQueueUartDriverRx, &data, portMAX_DELAY );
return data;
}
void WriteUART1_driver(unsigned int data){
xQueueSend( xQueueUartDriverTx, ( void * ) &data, portMAX_DELAY );
if( uxQueueMessagesWaiting( xQueueUartDriverTx ) ) // ¿¿??
IFS0bits.U1TXIF = 1; // ¿¿??
return;
}
void _ISR __attribute__((interrupt)) _U1RXInterrupt( void ){
//void __attribute__((__interrupt__, auto_psv)) _U1RXInterrupt( void ){
unsigned int data;
IFS0bits.U1RXIF = 0; // Clear flag
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
data = ReadUART1();
xQueueSendFromISR( xQueueUartDriverRx, &data, &xHigherPriorityTaskWoken );
return;
}
void _ISR __attribute__((interrupt)) _U1TXInterrupt( void ){
//void __attribute__((__interrupt__, auto_psv)) _U1TXInterrupt( void ){
unsigned int data;
IFS0bits.U1TXIF = 0; // Clear flag
portBASE_TYPE xTaskWokenByReceive = pdFALSE;
xQueueReceiveFromISR( xQueueUartDriverTx, ( void * ) &data, &xTaskWokenByReceive );
WriteUART1( data );
return;
}
#endif // #ifndef UART_DRIVER_C
y aquí un ejemplo de su uso con FreeRTOS
void vTaskUARTTEST( void * pvParameters ){
unsigned int value1=0, value2=0, value3=0, value4=0;
AD1PCFG = 0xFFFF; // Configura los pines del puerto A como digitales. Solo para el PIC24.
asm volatile ( "MOV #OSCCON, w1 \n" "MOV #0x46, w2 \n" "MOV #0x57, w3 \n" "MOV.b w2, [w1] \n" "MOV.b w3, [w1] \n" "BCLR OSCCON,#6");
RPOR7bits.RP15R = 3; // RP15 is UART1TX
RPINR18bits.U1RXR = 14; // UART1RX is RP14
asm volatile ( "MOV #OSCCON, w1 \n" "MOV #0x46, w2 \n" "MOV #0x57, w3 \n" "MOV.b w2, [w1] \n" "MOV.b w3, [w1] \n" "BSET OSCCON, #6" );
while(1){
OpenUART1_driver( 0x8000, 0x0400, 12 );
unsigned int data = 100;
do{
WriteUART1_driver( data );
data = ReadUART1_driver();
}while( data != 100 );
CloseUART1_driver();
}
}
int main(){
if( InitUART1_driver() )
return -1;
if( pdPASS != ( xTaskCreate( vTaskUARTTEST, ( signed portCHAR * ) "UARTTEST,", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, &xHandleADC ) ) )
return -1;
vTaskStartScheduler();