16F883 - SPI - Interrupcion

Todos los Microcontroladores y sus diferentes "familias". Todo este espacio es tuyo para mostrar tu código, consultar con los que más conocen del tema y para disfrutar de estos increíbles y poderosos componentes electrónicos.

Moderador: HJ

16F883 - SPI - Interrupcion

Notapor elgarbe » Mar Jun 11, 2013 10:15 pm

Hola, estoy leyendo la cagad... de hoja de datos del 16F883 y no logro entender si el mismo genera una interrupcion en el módulo SSP, configurado como SPI Master, al finalizar el envío de un byte.
En la página 184 del DS dice lo siguiente: "Generally, the MSSP Interrupt is used to determine when the transmission/reception has completed", pero en otra parte explica "Once the 8 bits of data have been received, that byte is moved to the SSPBUF register. Then, the buffer full-detect bit BF of the SSPSTAT register and the interrupt flag bit SSPIF of the PIR1 register are set", pero nunca habla de que pasa cuando un byte termina de ser enviado por el SPI....

Alguien sabe si genera interrupcion o no? sino no me va a quedar otra que programar y simular :x

Saludos
A palabras producidas por mentes inoperantes órganos auditivos en posicion de relax

You can be anything you want to be just turn yourself into anything you think that you could ever be - Freddie Mercury
Avatar de Usuario
elgarbe
 
Mensajes: 261
Registrado: Jue Mar 21, 2013 8:27 pm
Ubicación: Villa Ramallo - Buenos Aires - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor Switchxxi » Mar Jun 11, 2013 10:37 pm

Pagina 32:
Bit 7 del registro INTCON: Habilita todas las interrupciones.
Bit 6 del registro INTCON: Habilita las interrupciones de los periféricos. (SPI entre ellos).

Pagina 33: Bit 3 del registro PIE1:

SSPIE:Master Synchronous Serial Port (MSSP) Interrupt Enable bit
1= Enables the MSSP interrupt
0= Disables the MSSP interrupt

(Habilita la interrupción por envío/recepción)

Pagina 35: Bit 3 del registro PIR1:

SSPIF: Master Synchronous Serial Port (MSSP) Interrupt Flag bit
1= The MSSP interrupt condition has occurred, and must be cleared in software before returning from the Interrupt Service Routine. The conditions that will set this bit are:
(SPI) A transmission/reception has taken place

(Bandera de ocupado/ya enviado y/o libre)

Pagina 12: es un diario xD.
En mis circuitos, el humo no se cobra, va de regalo.
            Imagen
Avatar de Usuario
Switchxxi
 
Mensajes: 215
Registrado: Sab Mar 23, 2013 4:10 pm
Ubicación: Bs. As - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor Suky » Mar Jun 11, 2013 10:41 pm

Hola! Claro, cuando se termina de enviar o se recibe un byte, que en SPI es lo mismo, se activa la interrupción.

Saludos
Avatar de Usuario
Suky
 
Mensajes: 12
Registrado: Jue Abr 04, 2013 7:29 pm
Ubicación: Argentina

Re: 16F883 - SPI - Interrupcion

Notapor elgarbe » Mar Jun 11, 2013 11:02 pm

Tiempo record!

Gracias a los dos, mientras ustedes respondían lo simulé y verifique que se genera la interrupcion...

Acá estaba la clave:
"Pagina 35: Bit 3 del registro PIR1:

SSPIF: Master Synchronous Serial Port (MSSP) Interrupt Flag bit
1= The MSSP interrupt condition has occurred, and must be cleared in software before returning from the Interrupt Service Routine. The conditions that will set this bit are:
(SPI) A transmission/reception has taken place"

Gracias!
A palabras producidas por mentes inoperantes órganos auditivos en posicion de relax

You can be anything you want to be just turn yourself into anything you think that you could ever be - Freddie Mercury
Avatar de Usuario
elgarbe
 
Mensajes: 261
Registrado: Jue Mar 21, 2013 8:27 pm
Ubicación: Villa Ramallo - Buenos Aires - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor elgarbe » Jue Jun 20, 2013 10:18 pm

Bueno, seguimos avanzando con las pruebas del SPI para el POV.

El lunes programamos un 16F883 con la configuracion del SPI y enviando un dato cada 1mSeg y pudimos observar con el osciloscopio la señal de CLK generada con junto al dato transmitido. Les explique lo de los registros de desplazamiento y ahora estoy viendo algunas rutinas para mostrarles como llenarlos y demás. Pero me encuentro con una gran duda.
Primero el código:

Código: Seleccionar todo
/*
 * File:   main.c
 * Author: elgarbe
 *
 * Created on 12 de junio de 2013, 19:01
 */

#define _XTAL_FREQ 4000000 // Indicamos a que frecuencia de reloj esta funcionando el micro
//Funciones para delay's. No son muy precisas por lo que vi en el osciloscopio
//REVISAR
#pragma intrinsic(_delay)
extern void _delay(unsigned long);
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>         // Librería XC8. Este include termina incluyendo al 16F883.h
//#include <delays.h>     // Para utilizar demoras en nuestro código debemos incluir la librería delays.h.

//Includes locales, configuracion de fusibles y del IO
#include "configuracion_de_fuses.c"
#include "configuracion_hard.c"

//bit flagToggleFlanco=0;      // Flag para cambiar de flanco
int cntRegDes = 0;

/********** Funcion para la ISR (Rutina de Servicio de Interrupcion) **********/
void interrupt interrupciones (void) {
    //Verifico que interrupcion se disparó
    if (TMR0IE && TMR0IF){      // se verifica si la interrupcion es por TMR0
        TMR0IF = 0;             // Pongo en 0 el Flag de interrupcion del TMR0
    }
    if (SSPIE && SSPIF){        // se verifica si la interrupcion es por SPI
        if(++cntRegDes == 5){   // Primero lleno los 5 Registros
            PORTCbits.RC2 = 1;  // Luego mando la señal de latch
            PORTCbits.RC2 = 0;  //Sin delay, no hace falta
            cntRegDes = 0;
        }
        SSPIF = 0;     //Borro el flag de interrupcion de SPI
    }

}
/* el resto de las interrupciones utilizadas se deben analizar a coninuacion*/


/*------------------------DECLARACION DE FUNCIONES---------------------------*/

void conf_oscilador (void); // Configuracion del oscilador
void conf_puertos (void);   // Configuracion de puertos I/O
void conf_timer0 (void);    // Configuracion registros TIMER0
void conf_timer1 (void);    // Configuracion registros TIMER1
void conf_spi (void);       // Configuracion registros SPI
void clr_tira_pov(void);

/*************************** Programa Principal ******************************/
 void main(void) {
    conf_oscilador ();
    conf_puertos ();
    conf_timer0 ();
    conf_timer1 ();
    conf_spi();

    INTCONbits.TMR0IE = 1;      //Habilito interrupcion por TMR0
    SSPIF = 0;                  // Borro el flag de interrupcion de SPI
    PIE1bits.SSPIE = 1;         //Habilito interrupciom por SPI
    INTCONbits.GIE = 1;         //Habilito Interrupcion Global

    PORTCbits.RC2 = 0;
    clr_tira_pov();

    /*-------------------------- Bucle infinito ------------------------------*/
    int i;
    do{
        for(i = 0; i<255; i++){
            SSPBUF = i;
            __delay_ms(100);
            SSPBUF = i;
            __delay_ms(100);
            SSPBUF = i;
            __delay_ms(100);
            SSPBUF = i;
            __delay_ms(100);
            SSPBUF = i;
//            PORTCbits.RC2 = 1;  // Luego mando la señal de latch
//            PORTCbits.RC2 = 0;  //Sin delay, no hace falta

            __delay_ms(1000);
        }
    }while(1);
}


/*------------------------------FUNCIONES------------------------------------*/

/* Funcion para la configuracion del oscilador del pic16f88 */
void conf_oscilador (void) {

    OSCCONbits.IRCF2 = 1;
    OSCCONbits.IRCF1 = 1;
    OSCCONbits.IRCF0 = 0; // IRCF <2:0> = 110 setea Fosc 4MHz

    OSCCONbits.SCS = 0; /* SCS = 0 Modo del oscilador definido por
                         * FOSC <2:0> en #pragma config FOSC = INTOSCIO */
}
/* Funcion para la configuracion de los puertos entrada salida del pic 16f88 */
void conf_puertos (void) {

    ANSEL=0x00;         //Todos entrada/salida digitales - Puerto A.
    ANSELH=0x00;        //Todos entrada/salida digitales - Puerto B.
    TRISA=0x00;    //Todos como SALIDA-
    TRISB=0XFF;      //Todos como ENTRADA.
    TRISC=0X00;      //Todos como SALIDA-
    PORTC=0;
    PORTA=0;
}

/* Funcion para la configuracion del modulo Timer0 como temporizador */
void conf_timer0 (void) {

    // Configuración del timer 0. Con Osc de 4MHz la frecuencia de entrada del TMR
    // es 1MHz, con el prescaler en 256 tenemos una cuenta cada 256uSeg. Al ser
    // de 8 bits tenemos interrupcion cada 65,535 mSeg.
    TMR0 = 0;
    OPTION_REGbits.PS0 = 1;
    OPTION_REGbits.PS1 = 1;
    OPTION_REGbits.PS2 = 1;     //Prescaler en 256
    OPTION_REGbits.PSA = 0;     //Prescaler al TMR0 y no al WDT
    OPTION_REGbits.T0CS = 0;    //Clock Source es el Ciclo de Instruccion
}

/* Funcion para la configuracion del modulo Timer1 como temporizador */
void conf_timer1 (void) {

    // Configuración del timer 1. Con Osc de 4MHz la frecuencia de entrada del TMR
    // es 1MHz, con el prescaler en 1 tenemos una cuenta cada 1uSeg. Al ser
    // de 16 bits tenemos interrupcion cada 65,535 mSeg.
    // El timer 1 se usa como base de tiempos de CCP2
    TMR1 = 0;
    T1CONbits.T1CKPS = 0x00;    //Prescaler en 2 -> XX00
    T1CONbits.TMR1ON = 1;       //Enable Timer1
}

/* Funcion para la configuracion del modulo SPI como Master */
void conf_spi(void){

    SSPCONbits.SSPEN = 0;   // Deshabilitamos el modulo SPI
    SSPSTATbits.CKE = 1;    // Para elegir Modo 2
    SSPCONbits.CKP = 1;     // Para elegir Modo 2
    SSPCONbits.SSPM = 0;    // Velocidad = Fosc/4
    SSPIF = 0;              // Borro el flag de interrupcion de SPI
    SSPCONbits.SSPEN = 1;   // Habilitamos el modulo SPI
}

/* Funcion para la configuracion del modulo SPI como Master */
void clr_tira_pov(void){
    SSPBUF=0x00;
    __delay_us(100);
    SSPBUF=0x00;
    __delay_us(100);
    SSPBUF=0x00;
    __delay_us(100);
    SSPBUF=0x00;
    __delay_us(100);
    SSPBUF=0x00;
    __delay_us(100);
    SSPBUF=0x00;
    __delay_us(100);
    PORTCbits.RC2 = 1;  // Luego mando la señal de latch
    PORTCbits.RC2 = 0;  //Sin delay, no hace falta
    cntRegDes = 0;
}


Esta en XC8, pero es muy entendible.
Estoy tratando de manejar todo con interrupciones. La idea es la siguiente: Coloco el primero de los 5 bytes a enviar a la tira de led's, al hacer esto el SPI comienza a enviar datos, cuando termina se produce la interrupcion. En ese lugar chequeo un contador hasta 5, cuando llega la cuenta mando la señal de LATCH y pongo a 0 el contador. Esto funciona bien. Pero el problema viene en saber cuando puedo escrivir un nuevo dato en el buffer del SPI. Yo en el código escrivo un byte, espero un tiempo y luego escrivo el otro byte en el buffer, pero me pasa que si ese tiempo es muy chico aparentemente el SPI no ha terminado de enviar el dato, porque se me saltea números, en cambio, cuando aumento el tiempo entre actualizaciones del buffer haí si funciona bien... tendría que escrivir el buffer antes de salir de la interrupcion? de esa forma me aseguro de enviar el dato ni bien es posible?

Saludos!
A palabras producidas por mentes inoperantes órganos auditivos en posicion de relax

You can be anything you want to be just turn yourself into anything you think that you could ever be - Freddie Mercury
Avatar de Usuario
elgarbe
 
Mensajes: 261
Registrado: Jue Mar 21, 2013 8:27 pm
Ubicación: Villa Ramallo - Buenos Aires - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor Switchxxi » Jue Jun 20, 2013 10:56 pm

Hola, Elgarbe. No veo la necesidad de esperar una determinada cantidad de tiempo para enviar otro dato, ademas que yo lo haría de otra forma.

Para empezar no pondría un retardo fijo sino que haría uso de lo que me ofrece Microchip: Miro la bandera de que se esta enviando información para saber cuando se termino de hacerlo:

Envio Byte
while ((SSPSTAT & 1) == 0) {} // Espero a que el bit 0 del registro SSPSTAT sea 1
Envio byte
Etc...

Con eso evito de que si tarda mas del retardo que pongo no me genere problemas, ademas que apenas este listo puedo enviar otro dato y no pierdo tiempo.

Segundo que la señal de latch la tienes que enviar si o si después de cargar los 5 registros de desplazamiento para que pase los valores a la salida (a no ser que uses otro integrado que no sea el 74hc595).

Tercero yo lo haría así:

Después de calcular cada cuanto tengo que enviar cada linea calculo el timer para ese valor y habilito la interrupción.
Al entrar a la rutina de la interrupción: envío los 5 bytes a la salida así:


Envío byte = Dirección + 0;
while ((SSPSTAT & 1) == 0) {} // Espero a que el bit 0 del registro SSPSTAT sea 1
Envío byte = Dirección + 1;
while ((SSPSTAT & 1) == 0) {} // Espero a que el bit 0 del registro SSPSTAT sea 1
Envío byte = Dirección + 2;
Etc...
Direccion += 5; // Aumento la dirección de los datos a leer
Envío la señal de latch y regreso de la interrupción.

Con eso ya no necesito usar la interrupción por SPI sino solamente la del Timer con lo que el programa se agiliza en la parte de la interrupción ya que no tiene que perder tiempo comprobando si se produjo por SPI o por el Timer.
En mis circuitos, el humo no se cobra, va de regalo.
            Imagen
Avatar de Usuario
Switchxxi
 
Mensajes: 215
Registrado: Sab Mar 23, 2013 4:10 pm
Ubicación: Bs. As - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor elgarbe » Vie Jun 21, 2013 12:49 pm

Switchxxi escribió:Hola, Elgarbe. No veo la necesidad de esperar una determinada cantidad de tiempo para enviar otro dato, ademas que yo lo haría de otra forma.

La necesidad de esperar un tiempo para el siguiente dato es para asegurar que el anterior ya haya sido transmitido. Si o si debo esperar un tiempo, dicho tiempo puede estar delimitado por un delay o por otra forma (pooling, interrupcion, etc.)

Switchxxi escribió:Para empezar no pondría un retardo fijo sino que haría uso de lo que me ofrece Microchip: Miro la bandera de que se esta enviando información para saber cuando se termino de hacerlo:

Envio Byte
while ((SSPSTAT & 1) == 0) {} // Espero a que el bit 0 del registro SSPSTAT sea 1
Envio byte
Etc...

Con eso evito de que si tarda mas del retardo que pongo no me genere problemas, ademas que apenas este listo puedo enviar otro dato y no pierdo tiempo.

Esto resuelve el problema, pero tengo como regla general cuando estoy con los tiempos de micro justos, no usar pooling. Quedarme en una bucle infinito esperando por una señal es una pérdida de tiempo. Ojo, el delay tambien es una perdida de tiempo por eso lo quiero eliminar.

Switchxxi escribió:Segundo que la señal de latch la tienes que enviar si o si después de cargar los 5 registros de desplazamiento para que pase los valores a la salida (a no ser que uses otro integrado que no sea el 74hc595).

Código: Seleccionar todo
    if (SSPIE && SSPIF){        // se verifica si la interrupcion es por SPI
        if(++cntRegDes == 5){   // Primero lleno los 5 Registros
            PORTCbits.RC2 = 1;  // Luego mando la señal de latch
            PORTCbits.RC2 = 0;  //Sin delay, no hace falta
            cntRegDes = 0;
        }

Ese código en la interrupcion hace lo que dices. Cuenta 5 interrupciones por envío de datos y en el 5° manda la señal de LATCH.

Switchxxi escribió:Tercero yo lo haría así:
Después de calcular cada cuanto tengo que enviar cada linea calculo el timer para ese valor y habilito la interrupción.
Al entrar a la rutina de la interrupción: envío los 5 bytes a la salida así:
Envío byte = Dirección + 0;
while ((SSPSTAT & 1) == 0) {} // Espero a que el bit 0 del registro SSPSTAT sea 1
Envío byte = Dirección + 1;
while ((SSPSTAT & 1) == 0) {} // Espero a que el bit 0 del registro SSPSTAT sea 1
Envío byte = Dirección + 2;
Etc...
Direccion += 5; // Aumento la dirección de los datos a leer
Envío la señal de latch y regreso de la interrupción.

Estoy de acuerdo con la primera parte, lo que nosotros estamos pensando (e hicimos en el pov del año pasado) en la entrada CCP2 tengo un sensor que me da 1 pulso por vuelta. Con 2 señales de dicho sensor obtengo las RPM del motor (que pueden variar levemente, por eso lo actualizamos vuelta a vuelta) con ese dato y la resolucion radial obtenemos cada cuanto tengo que escrivir un radio nuevo. Ese tiempo lo escrivimos en el TMR0 y éste me interrumpe cuando tengo que enviar datos.
Con lo que no estoy del todo de acuerdo es con la parte de pooling, y estar todo ese tiempo en la interrupcion sin hacer nada.... eso no me convence...

Switchxxi escribió:Con eso ya no necesito usar la interrupción por SPI sino solamente la del Timer con lo que el programa se agiliza en la parte de la interrupción ya que no tiene que perder tiempo comprobando si se produjo por SPI o por el Timer.


Para mi tiene que ser todo por interrupcion para aprovechar al máximo los tiempos del micro... El hecho de verificar porque cosa fue la interrupcion no es una cuestion mía, tengo entendido que así se hace en XC8, hay una sola funcion de interrupcion y uno debe verificar que la produjo.

Ahora estoy testeando este código de interrupcion:
Código: Seleccionar todo
void interrupt interrupciones (void) {
    //Verifico que interrupcion se disparó
    if (TMR0IE && TMR0IF){      // se verifica si la interrupcion es por TMR0
        TMR0IF = 0;             // Pongo en 0 el Flag de interrupcion del TMR0
    }
    if (SSPIE && SSPIF){        // se verifica si la interrupcion es por SPI
        if(++cntRegDes == 5){   // Primero lleno los 5 Registros
            PORTCbits.RC2 = 1;  // Luego mando la señal de latch
            PORTCbits.RC2 = 0;  //Sin delay, no hace falta
            cntRegDes = 0;
        }
        else{
            SSPBUF = nextData;
        }
        SSPIF = 0;     //Borro el flag de interrupcion de SPI
    }

}

Con este código me aseguro de escrivir el buffer ni bien es posible, sin chequear el flag de la transmision. Ni bien entro en la interrupcion del SPI es porque ya se envió el dato anterior, por lo que puedo escrivir en ese momento un nuevo dato...

Estoy por simular esto, despues pongo los resultados...

Saludos y gracias!
A palabras producidas por mentes inoperantes órganos auditivos en posicion de relax

You can be anything you want to be just turn yourself into anything you think that you could ever be - Freddie Mercury
Avatar de Usuario
elgarbe
 
Mensajes: 261
Registrado: Jue Mar 21, 2013 8:27 pm
Ubicación: Villa Ramallo - Buenos Aires - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor Switchxxi » Vie Jun 21, 2013 2:35 pm

:lol:

Desde luego que no es conveniente los loops para esperar a que se envíen los datos. Pero en el primer programa hacías una cosa y ahora haces otra. :lol:

En el primer programa, que estas usando para pruebas, usas retardos y dijiste que tienes problemas de que se saltean datos. Por eso di una solución a probar ya que no se si ahí radica el problema.
Si tu pones un retardo de X ms y tarda mas o tarda menos puede que llegue a haber un problema, al chequear la bandera para saber si se termino de enviar es la mejor forma ya que te aseguras si o si que el dato fue enviado por lo que el buffer esta vació. Ademas de que cuentas con la ventaja de que no necesitas ir jugando con los tiempos para encontrar el mejor retardo.
Ademas de que si por ejemplo usas retardos de 100ms y tarda en enviar un byte 10ms estas perdiendo tiempo, con el loop te aseguras de que apenas esta listo puedes enviar el siguiente dato.

Nuevamente, lo que dije fue para el primer programa, no diciendo con esto que uses esa técnica en el reloj POV. Al usar interrupciones por fin de envío (cosa que no usas en el primer programa ya que solo chequeas si ya se enviaron los 5 bytes para dar el pulso de latch) ya puedes estar tranquilo que tiene tiempo para hacer otras cosas mientras el micro solito se encarga de enviar los datos.

De todas formas hay que ver cuanto ganas en tiempo usando interrupción por SPI. Imagino que hay herramientas para medir la duración de cada cosa pero nunca las use así que no sabría decirte en el lenguaje C. Pero en ASM, que es mas fácil o relativamente mas fácil de medir puedes comprobar si te conviene una u otra aproximación.
Me explico:

Sin interrupción por SPI:

Envías byte 1 ---- X tiempo
loop ---- X tiempo (aca el tiempo sera lo que tarda en enviar los 8 bits mas 3 ciclos)

Con esta técnica el tiempo muerto entre envíos es lo que tarda en enviar el dato el micro.

Con interrupción por SPI:

Salto a la interrupción --- X tiempo
Comprobar porque fue la interrupción --- X tiempo
Verificar si ya se enviaron los 5 bytes --- X tiempo
colocar el byte para que sea enviado --- X tiempo
volver de la interupcion --- X tiempo

Como se ve quizás desde que entra a la interrupción hasta que sale perdés el mismo tiempo que enviar un byte sin ella. Obviamente que sin interrupción perdés tiempo hasta que se envíen 5 bytes, con interrupción no.
La contra es que se complica un poco mas el programa.

De todas formas tu ya habías calculado que tiempo, entre lineas tenias. Yo usaría, si me alcanza:

interrupción:
- verifico si es por una linea nueva.
- Envío los 5 bytes
- Pulso de STR.
- Vuelvo

¿ Porque ? simple: Si usas todo por interrupciones ¿ que es lo que hará el micro mientras no se encuentre en una de ella sino en el programa principal ? ¿ Que tarea puede estar haciendo el micro cuando no este en una interrupción si todo lo manejaras con ellas ?
¿ Por miedo a que llegue una interrupción de linea o de cuadro mientras pierdes tiempo enviando datos ? Entonces se anidan interrupciones ya que tienes Stack de sobra :lol:

Son dos maneras de encarar el problema y todo depende de los tiempos y como estructures el programa ya que, lo que dije antes de enviar 5 bytes seguidos siempre se hará, eso, en la rutina de la interrupción cuando llegue la interrupción de nueva linea, que se supone llegara muchísimo después de lo que pueda tardarse en enviar los 5 bytes.
Ademas de que al principio había dicho los loops para ver si así dejabas de perder datos en el programa de prueba que pusiste al principio que nada tiene que ver con el segundo :lol:

Saludos.
- Javier -
En mis circuitos, el humo no se cobra, va de regalo.
            Imagen
Avatar de Usuario
Switchxxi
 
Mensajes: 215
Registrado: Sab Mar 23, 2013 4:10 pm
Ubicación: Bs. As - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor elgarbe » Vie Jun 21, 2013 6:05 pm

Me rindo ante la evidencia:

Imagen

Esto es un debug del SPI, el código que envía los primeros 5 "0" es el siguiente:

Código: Seleccionar todo
void clr_tira_pov(void){
    PIE1bits.SSPIE = 0;         //Deshabilito interrupciom por SPI
    SSPBUF=0x00;
    while ((SSPSTAT & 1) == 0);
    SSPBUF=0x00;
    while ((SSPSTAT & 1) == 0);
    SSPBUF=0x00;
    while ((SSPSTAT & 1) == 0);
    SSPBUF=0x00;
    while ((SSPSTAT & 1) == 0);
    SSPBUF=0x00;
    while ((SSPSTAT & 1) == 0);
    PORTCbits.RC2 = 1;          // Luego mando la señal de latch
    PORTCbits.RC2 = 0;          //Sin delay, no hace falta
    SSPIF = 0;
    PIE1bits.SSPIE = 1;         //Habilito interrupciom por SPI
}


El segundo grupo de "0" es enviado por mi codigo con interrupciones.
Main:
Código: Seleccionar todo
    do{
        for(i = 0; i<255; i++){
            nextData = i;
            SSPBUF = i;
        }
    }while(1);


Interrupcion:
Código: Seleccionar todo
    if (SSPIE && SSPIF){        // se verifica si la interrupcion es por SPI
        if(++cntRegDes == 5){   // Primero lleno los 5 Registros
            PORTCbits.RC2 = 1;  // Luego mando la señal de latch
            PORTCbits.RC2 = 0;  //Sin delay, no hace falta
            cntRegDes = 0;
        }
        else{
            SSPBUF = nextData;
        }
        SSPIF = 0;     //Borro el flag de interrupcion de SPI
    }


Conclusion:
Con pooling:

33uSeg tiempo total x 5 bytes

6,5 uSeg tiempo muerto entre 1 byte y segundo
3 useg tiempo muerto entre 2 byte y tercero y entre el resto

Con interrupcion:

133 useg tiempo total x 5 byte

25,5 useg tiempo muerto entre 1 byte y segundo
30 useg tiempo muerto entre 2 byte y tercero y entre el resto

Si bien el micro está "libre" pierde 100uSeg entre idas y vueltas lo que lo hace estar al limite de uso. A 20MHz mejorará, pero igual hay bastante tiempo muertos en saltos y verificaciones.

En cuanto a pooling es mucho más rápido en el global y a 20MHz me dejaría bastante tiempo entre envío y envío, por lo que se podría implementar sin problemas.

Ahora, se podría mejorar aún más estimo el código ya que el tiempo que le toma enviar 1 byte al módulo SPI es de 3,5uSeg x 5 = 17,5useg... quizá escriviendo esa parte del código en assembler podría ganar más tiempo aún... será significativa esa ganancia? Alguien que se anime a escrivir esas líneas "optimizadas" en assembler?

Gracias javier por el intercambio, son estas "discuciones" las que nos llevan a provar una y otra alternativa y ver cuál se adapta mejor a nuestra necesidad.

Saludos!
A palabras producidas por mentes inoperantes órganos auditivos en posicion de relax

You can be anything you want to be just turn yourself into anything you think that you could ever be - Freddie Mercury
Avatar de Usuario
elgarbe
 
Mensajes: 261
Registrado: Jue Mar 21, 2013 8:27 pm
Ubicación: Villa Ramallo - Buenos Aires - Argentina

Re: 16F883 - SPI - Interrupcion

Notapor elgarbe » Vie Jun 21, 2013 6:13 pm

Switchxxi escribió:¿ Porque ? simple: Si usas todo por interrupciones ¿ que es lo que hará el micro mientras no se encuentre en una de ella sino en el programa principal ? ¿ Que tarea puede estar haciendo el micro cuando no este en una interrupción si todo lo manejaras con ellas ?


Solo un agregado con respecto a esto. El reloj pov puede tener que atender muchas cosas aparte de dibujar. Por ejemplo, el cálculo de la posicion de las agujas y el llenado de las matrices de dibujo con esa info. Si ademas agrego la fecha y hora en formato digital en otra área, el cálculo de las mismas o la obtension de ellas desde un RTC... Si quisiera poner en hora el reloj en marcha, deberá leer un sensor óptico y quizá mostrar un menu de opciones... obviamente que para todo esto estamos hablando de tiempos del orden de los 500mseg o de 1 segundo y PUEDE que no sea tan crítico, pero cosas para hacer hay muchas entre envío y envío de informacion.

Saludos!
A palabras producidas por mentes inoperantes órganos auditivos en posicion de relax

You can be anything you want to be just turn yourself into anything you think that you could ever be - Freddie Mercury
Avatar de Usuario
elgarbe
 
Mensajes: 261
Registrado: Jue Mar 21, 2013 8:27 pm
Ubicación: Villa Ramallo - Buenos Aires - Argentina

Siguiente

Volver a Microcontroladores

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado