TODOPIC

Microcontroladores PIC => dsPIC => Mensaje iniciado por: Nocturno en 17 de Diciembre de 2006, 04:46:57

Título: Retardos con precisión para dsPIC33F
Publicado por: Nocturno en 17 de Diciembre de 2006, 04:46:57
Tras una nueva semana de pelea en plena arena, he conseguido implementar funciones para hacer retardos de microsegundos y milisegundos que son independientes de la velocidad con la que trabaja el micro.

Las funciones son las siguientes:

Código: [Seleccionar]
#define MIPS 50

/*********************************************/
/**  Función para hacer un retardo de 1 ms  **/
/**             www.elrebujito.es           **/
/**              Nocturno - 2006            **/
/**    Válida para MIPS >= 0.002 (4KHz)     **/
/*********************************************/

#define delay_1ms() asm("REPEAT #%0\n NOP\n REPEAT #%0\n NOP\n REPEAT #%0\n NOP\n REPEAT #%0\n NOP" :: "i" (MIPS*250-2))

/*********************************************/
/**  Función para hacer un retardo de 10 us **/
/**             www.elrebujito.es           **/
/**              Nocturno - 2006            **/
/**    Válida para MIPS >= 0.2 (400KHz)     **/
/*********************************************/

#define delay_10us() asm("REPEAT #%0\n NOP" :: "i" (MIPS*10-2))


/*********************************************/
/**  Función para hacer un retardo de 1 us  **/
/**             www.elrebujito.es           **/
/**              Nocturno - 2006            **/
/**     Válida para MIPS>=2 (>4MHz)         **/
/*********************************************/

#define delay_1us() asm("REPEAT #%0\n NOP" :: "i" (MIPS-2))

/*********************************************/
/**  Función para hacer un retardo de x us  **/
/**             www.elrebujito.es           **/
/**              Nocturno - 2006            **/
/**       Válida para MIPS>=16 (>32MHz)     **/
/**        Valores de x: de 0 a 65535       **/
/*********************************************/

void delay_us(unsigned int x) {
asm ("REPEAT #%0\n NOP" :: "i" (MIPS-16));
while ((x--)!=1) {
asm ("REPEAT #%0\n NOP" :: "i" (MIPS-7));
};
};

/*********************************************/
/**  Función para hacer un retardo de x ms  **/
/**             www.elrebujito.es           **/
/**              Nocturno - 2006            **/
/**      Válida para MIPS>=0.24 (>48KHz)    **/
/**        Valores de x: de 0 a 65535       **/
/*********************************************/

void delay_ms(unsigned int x)
 {
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-5));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-5));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-6));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-6));
while ((x--)!=1) {
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-4));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-3));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-3));
asm ("REPEAT #%0\n NOP" :: "i" (MIPS*250-3));
};
 }

Como véis, al final he tenido que pasar por la piedra del ASM y pese a que he refunfuñado todo lo que podía, la precisión de los delays es sorprendente; sólo se ejecutan los ciclos que tienen que ejecutarse: ni uno más y por supuesto ni uno menos.

Otra cosa que podréis observar es que hay mucho código con #define, por lo que al compilar se realizan las sustituciones correspondientes y queda un código extremadamente pequeño y compacto.

En función de la velocidad de proceso de nuestro dsPIC33F, que como sabéis puede ir a muchas frecuencias distintas hasta un máximo de 50MIPS, podréis usar algunas funciones u otras. Esto es debido a que si trabajamos a frecuencias lentas, los ciclos de instrucción necesarios para hacer los cálculos van comiéndose el tiempo del delay, hasta que llegamos a un punto que nos hemos pasado. No obstante, he dejado delante de cada función una recomendación de la velocidad mínima a emplear y los límites del parámetro x.

La principal ventaja de estos retardos es su precisión y lo poco que ocupan, pero tienen un gran inconveniente: si durante un retardo salta una interrupción y el flujo de programa se va a ejecutarla, cuando vuelva seguirá por donde iba por lo que nuestro retardo habrá aumentado todo el tiempo que duró la interrupción.

Tengo casi acabadas y espero publicarlas en breve unas rutinas para generar retardos con el Timer, lo que nos permite generar retardos que no se vean afectados por dicho efecto.

Quedo a vuestra disposición para cualquier comentario.
Título: Re: Retardos con precisión para dsPIC33F
Publicado por: Nocturno en 17 de Diciembre de 2006, 16:28:07
Bien, ya he probado y asegurado el código para la generación de retardos con el Timer.

Aquí os lo dejo para vuestro uso y disfrute:

Código: [Seleccionar]
#define MIPS 20

/*********************************************/
/**  Función para hacer un retardo de x us  **/
/**  utilizando el Timer e interrumpible    **/
/**  generada automáticamente por asistente **/
/**             www.elrebujito.es           **/
/**              Nocturno - 2006            **/
/**        Válida para MIPS>=1 (>2MHz)      **/
/**         Valores de x: x*MIPS-30>0       **/
/*********************************************/

void Tdelay_us(unsigned int x) {
  TMR9=-(x*MIPS-30);
  T9CON = 0x8080;
  while (IFS3bits.T9IF==0);
  IFS3bits.T9IF=0;
};

/*********************************************/
/**  Función para hacer un retardo de x ms  **/
/**  utilizando el Timer e interrumpible    **/
/**  generada automáticamente por asistente **/
/**             www.elrebujito.es           **/
/**              Nocturno - 2006            **/
/**        Válida para MIPS>=1 (>2MHz)      **/
/**              Valores de x: >1           **/
/*********************************************/

void Tdelay_ms(unsigned long x) {
  unsigned long Limite;
  Limite = x*MIPS*1000-48;
  TMR8=-(Limite);
  TMR9=(-Limite)>>16;
  T8CON = 0x8008;
  while (IFS3bits.T9IF==0);
  IFS3bits.T9IF=0;
};

He aprovechado para diseñar un nuevo asistente (http://elrebujito.es/modules.php?name=Content&pa=list_pages_categories&cid=2) en El Rebujito (http://www.elrebujito.es) al que sólo hay que meter los MIPS, el método a utilizar (ciclos o Timer) y elegir el nº del timer para que nos entregue el código más adecuado a cada configuración.

Podéis ver el asistente aquí:
33F - Asistente para la generación automática de retardos (http://elrebujito.es/modules.php?name=Content&pa=showpage&pid=8)
Título: Re: Retardos con precisión para dsPIC33F
Publicado por: LABmouse en 17 de Diciembre de 2006, 21:33:55
Des pues de ver el resultado de su trabajo, solo queda decir. ¡Buen trabajo! Felicitaciones y  gracias por compartirlo.
Título: Re: Retardos con precisión para dsPIC33F
Publicado por: Sispic en 18 de Diciembre de 2006, 03:17:40
Ademas  hacia falta ... se acabó contar cada vez con los dedos los nops  para cada clock . :-)
Título: Re: Retardos con precisión para dsPIC33F
Publicado por: togarha en 17 de Enero de 2007, 07:31:25
Buenas!!!

En el mismo C30 hay una funcion " __delay32(unsigned long ciclos) " escrita en ensamblador donde tienes un delay exacto tambien....

saludos
Título: Re: Retardos con precisión para dsPIC33F
Publicado por: Nocturno en 17 de Enero de 2007, 07:52:26
Pues qué guay. De haberlo sabido antes ni toco el asm :D
Título: Re: Retardos con precisión para dsPIC33F
Publicado por: togarha en 17 de Enero de 2007, 08:49:29
jejejeje, no hay nada como empaparse de los foros de microchip ;)

por si a alguien le interesa y no lo encuentra esta en:

..\Microchip\MPLAB C30\src\pic30

es el archivo "delay32.s" lo incluis en el proyecto y a funcionar. Yo luego, en mi ".h" principal me creo los siguientes defines:

// External oscillator frequency with PLL enable
#define SYSCLK          8000000
#define FCY            SYSCLK*4/2


// Defines para calcular los ciclos para determinados tiempos
// Se suma uno al final para asegurarnos que tenemos el tiempo minimo deseado
// en caso de que la division no fuese exacta
#define   US_10         (1*FCY/100000)+1
#define   US_25         (25*FCY/1000000)+1
#define   US_50         (5*FCY/100000)+1
#define   US_100         (1*FCY/10000)+1
#define   US_250         (25*FCY/100000)+1
#define   US_500         (5*FCY/10000)+1

#define   MS_10         (1*FCY/100)+1
#define   MS_25         (25*FCY/1000)+1
#define   MS_50         (5*FCY/100)+1
#define   MS_100         (1*FCY/10)+1
#define   MS_250         (25*FCY/100)+1
#define   MS_500         (5*FCY/10)+1


luego ya solamente hay que hacer:

__delay32( MS_500 );
Título: Re: Retardos con precisión para dsPIC33F
Publicado por: Nocturno en 06 de Mayo de 2010, 07:33:23
Amigos, tras la migración de mi web se jodieron los scripts que ejecutan el asistente.
Acabo de repararlos y ya está otra vez operativo:
Asistente para la generación automática de retardos (http://www.micropic.es/index.php?option=com_content&view=article&id=33:33f-asistente-para-la-generacion-automatica-de-retardos&catid=36:asistentes&Itemid=63)