Las recomendaciones que te puedo dar y que haria a mi gusto:
Personalmente:
- Usar #fast_io , no me gusta nada que CCS decida agregarte instrucciones extras, esto va a ayudar con la velocidad que salen tus datos a los registros de desplazamiento.
- Yo personalmente hubiera usado un SPI por hardware y no uno por software ( si el envio de los datos lo podrias haber realizado por SPI ) Creo que es mas rapido, ya que cada ciclo de reloj interno tendrias un dato, mientras que con los for tal ves se tome mas de un ciclo.
Con esto me aseguraria que los datos se envien lo mas rapido posible. Ahora sigamos analizando el programa. A tu programa lo haria de esta manera:
volatile int *ptrdatos = CORAZON;
volatile bool mostrar_activo;
void main(){
//Aca configuracion de lo que sea
set_tris_x();
mostrar_activo=0;
activo_interrupciones();
while(1){
if(mostrar_activo){
if(timer2_OV){
spi_write(*ptrdatos++);
while(spi_activo);
strobe_off();
strobe_on();
Limpio_flag_TMR2();
}
}
}
if(ptrdatos==(CORAZON+760)) {
disable_interrupts();
mostrar_activo=0;
enable_interrupts();
}
}
}
//Interrupcion de paso por 0, Utilizo el CCP para medir el tiempo entre los pulsos (Alta prioridad asi utiliza los registros sombras/dobles como quieras llamarle)
void ISR_RB0_o_CCP(){
int Valor_CCP; // Tiempo entre pulsos
Valor_CCP = Obtener_CCP();
set_timer_2(Valor_CCP/95); // (760/8) Aca preferiria usar un valor multiplo de 2, como 512 pixels, de esa forma queda 64 y se pierde menos tiempo
ptr_datos=CORAZON; //Reinicio lo que tengo que mostrar
mostrar_activo=1;
}
De esa forma, en el cruce por 0 ocurre lo siguiente:
- Hago que comienze de 0 los datos,
- tomo el tiempo que tardo la ultima vuelta ( tal ves falte agregar una proteccion de la primer vuelta ),
- Procedo a cargar el timer con el valor obtenido, asi ese timer es quien me dicta en el programa principal cuando enviar los datos. Util para un cambio de velocidad!
- Hago que mi puntero a los datos apunte nuevamente al comienzo, es decir llego a 0 y comienza de 0. (Caso que hizo la vuelta completa y por mal calculo del tiempo no llego a mostrar todo)
- Y habilito al programa principal a mostrar.
En el programa principal:
- Solo pregunto si debo comenzar a mostrar. Si no debo mostrar no hago nada ( podria apagar todo los leds )
- Si debo mostrar pregunto si el timer ya paso ( hay que arreglarlo para el primer dato ) , si paso el tiempo correcto envio datos y activo e latch, y espero nuevamente por el timer
- Si por alguna casualidad se calculo mal el tiempo, quiere decir que se va a enviar todo mas rapido, para eso esta el ultimo if, diciendo que si llego al maximo, que apague el mostrar.
No todo es bueno, hay algunas cosas que deben ocurrir para que esto funcione bien:
- Lo que esta dentro del if(timer2_OV) debe ejecutarse antes que se produzca el overflow del timer2, tambien podrias poner el manejo del latch al comienzo + el while del SPI, de esa forma el latch te queda para el primer valor, se le da mas tiempo al SPI para terminar y retrasa lo menos posible esa parte
- Deberias obtener el valor del CCP mas grande posible, con el menor preescaler disponible, de esa forma al dividirlo tenes una mayor precision, y luego colocarlo en un timer con un preescaler aun menor, vas a tener que adaptarlo aca ( sea multiplicando o no )
- Lamentablemente tu programa debe durar menos de lo que se envian los datos, si por alguna razon esto no ocurre veras una imagen distorsionada. Aunque si tu delay estaba cerca del valor en el que mostrabas cada seccion eso te deja con un muy buen tiempo, en 100us deberias ser capaz de alojar unas 1200 instrucciones. Y al SPI le tomaria creo que 0.66us enviar todo
(si es que envia a Fosc/4)
A mi gusto, es lo que yo haria. Tiene mas "configuracion" pero intentaria utilizar los modulos hardware completos antes de hacerlo todo por software. Igual sobre gustos es decision de cada uno.
Con respecto a tu programa:
- tenes un delay y es MALO,
- por otro lado tenes un for() para los pixels y digamos que tambien es malo ya que estas obligado a pasar por todos los pixeles antes de comenzar de vuelta, esto lo intente evitar como lo programe, en cada vuelta es posible pararlo, en tu caso deberias agregar 2 condiciones (if + break;) mas para romper los 2 for.
- Tu codigo de interrupcion deberia tardar lo menos posible, no creo que sea prudente enviar datos por SPI por software, ya que lo que haces es que si tarda mucho estarias trabando otra posible interrupcion que venga, tal ves hasta perdiendo una vuelta.
Espero que de algo sirva y no me este equivocando, ahi juanperser ya tiene experiencia realizando uno, asi que el te dira si esta correcto o no lo mio, o estoy diciendo barbaridades.