Bueno señores, pues voy a poner como funcionan los buffers de un pic el cual tiene el CAN integrado. Yo uso el 18F46K80 por lo que en otros pics puede cambiar, que no tengan los mismos buffers, pero se puede aplicar a cualquier pic en mayor o menor medida.
Para empezar empezamos por lo sencillo, una breve explicacion. Este pic tiene 3 buffers para enviar, 2 buffers para recibir, y 6 buffers adicionales para configurarlos segun queramos (RX/TX). Ahora os preguntareis, para que tantos buffers? Pues sencillo, si tenemos una aplicacion que envia mensajes sin parar con 1 solo buffer nos veriamos limitado a esperar que ese buffer quede libre y luego enviar el siguiente mensaje. Para aplicaciones que no se deben bloquear estos buffers nos son de mucha utilidad.
Es decir seria de la siguiente manera:
-Buscamos buffer libre (bit TXB*CON:TXREQ=0)
-Escribimos los datos (tamaño, filtro, datos...)
-Declaramos la prioridad del mensaje (TXB*CON:TXPRI<0:1>) entre 0 y 3 (3 mayor prioridad, 0 menor).
-Ponemos el TXB*CON.TXREQ=1 para solicitar el envio.
*El mismo modulo se encarga de verificar que mensaje tiene mayor prioridad (TXPRI) y envia ese, es decir si llenamos los 3 buffers a la vez, ponemos a uno 0, al otro 1, y al otro 3, el modulo enviara primero el 0, luego 1 y luego 3...
Con todo esto nos olvidamos de tener que poner el while(!TXREQ); unicamente tendriamos que poner un control de errores (TXERR) para verificar que mensaje nos da error de envio, y decidir si abortarlo, dejarlo hasta que se envie... Eso ya al gusto del programador.
Ahora me preguntareis, que rollo tener que estar mirando si el TXB0 esta libre, luego el TXB1.... No hay problema, yo he hecho lo siguiente:
En la funcion de CAN INIT he declarado un array de punteros (global) donde se guarda la direccion de TXB0CON, TXB1CON, TXB2CON...
Ejemplo:
char *txcon[2];
txcon[0]=&TXB0CON; txcon[1]=&TXB1CON; ....
Unicamente tendriamos que poner un for con if(! (*txcon[ x] & 0b1000)) { entonces usamos ese buffer x... }
Ahora, vale muy bien, y como escribimos los filtros, DLC, ... sencillo:
Todos los buffers tienen su memoria por orden, es decir TXB0CON, TXB0SIDH, SIDL, EIDH, EIDL, DLC, D0, D1, D2.... D7.
Para escribir el dlc del buffer 2 por ejemplo seria:
*(txcon[2]+5)=dlc;
Para el D0:
*(txcon[2]+6)=data0;
Facil no? Para gente que sepa usar punteros sera muy sencillo.
Ahora, como se configuran los buffers "extras" que nos regalan microchip?, los buffers se llaman B0CON, B1CON.... B5CON
Tenemos un registro que se llama BSEL0 (mirar el datasheet para mas info). Para configurar por ejemplo el buffer 5 y 4 como TX seria:
BSEL0=0b11000000
de los bit (7:2) es el buffer 5 al 0; 1=TX, 0=RX.