PIC24 Oscilador interno y ciclos de instrucción

6

Tengo algo de experiencia relativa en AVR pero solo mínimo con PIC. Para iniciar un proyecto, solo quería verificar que pude hacer que el oscilador interno funcionara a la frecuencia correcta. Entonces, mi primera prueba fue cambiar un pin y ver la frecuencia que tengo. El primer código de prueba fue

#include <p24F16KA102.h>

_FOSCSEL(FNOSC_FRCDIV  & FNOSC_PRI );    
_FOSC( POSCMOD_HS  );

int main(void)
{       
    AD1PCFG = 0xffff;   //make ADC pins all digital
    TRISA = 0;          //Make all PORTAs all outputs

    while (1)
    {
        LATAbits.LATA6= ~LATAbits.LATA6;     
    } 
    return 0;
}

La frecuencia medida en el RA6 es de aproximadamente 59 KHZ. Esto parecía una locura de un reloj de 8MHZ. Parece ser que los LATAbits y la negación requieren 14 Instrucciones !!

He buscado en Internet para minimizar las instrucciones para simplemente cambiar un pin y descubrí un ensamblaje integrado de BTG, así que repetí el código anterior reemplazando los LATAbits con __ builtin_btg (& LATA, 6);

Ahora el desensamblaje muestra que hay 3 instrucciones para ejecutar el ciclo y el cambio

029A  202C40     mov.w #0x2c4,0x0000
029C  A26010     btg [0x0000],#6
029E  37FFFD     bra 0x00029a

¡Ahora la frecuencia en PIN RA6 es 201 KHZ!

¿Qué estoy haciendo mal aquí? He probado los bits de configuración del MPLAB sin el código, etc. Esta bien ? ¿Un reloj de 8MHZ producirá 201KHZ como la mejor opción para alternar un PIN?

Es muy probable que esté haciendo algo mal, por eso decidí publicar esto aquí después de pasar más de 6 horas probando.

Por las hojas de datos, sé que cada instrucción requiere 4 ciclos de reloj, pero no estoy seguro de los ciclos de instrucción, los ciclos de reloj y los ciclos de ejecución. Apreciaré cualquier ayuda u orientación. Quizás estoy más acostumbrado a 8 bits, donde la proporción de ciclos de reloj es menor. ¿Cuál es la forma más fácil y segura de verificar la frecuencia del reloj?

Bien, gracias a todos por todas las respuestas, ya que todas me dieron una dirección a seguir. Acabo de probar las sugerencias de Olin y Madmanguruman. Como no encontré una forma directa de colocar asm en línea con etiquetas de dirección como loop: a continuación, he creado un archivo test1.s con una función llamada loop1 con el código dado por Olin a continuación y lo llamé como se muestra en el código abajo:

 #include <p24F16KA102.h>

_FOSCSEL(FNOSC_FRCDIV  & FNOSC_PRI );    
_FOSC( POSCMOD_HS  );
extern int loop1(void);
int main(void)
{       
    AD1PCFG = 0xffff;   //make ADC pins all digital
    TRISA = 0;          //Make all PORTAs all outputs

    loop1();
    return 0;
}

Ahora la frecuencia medida en RA6 es de aproximadamente 335 KHZ. El bucle se ejecuta cada 1,47 microsegundos (670 KHZ). Por supuesto, esto es el doble de la frecuencia anterior ya que el alcance mide dos ciclos de bucle, el RA6 es alto y el RA6 es bajo.

Luego, el uso de la información de Olin debajo de la frecuencia de reloj debe ser 12 X 680KHZ = 8.16MHZ.

Lo único que no tengo claro al 100% es cómo se define la frecuencia de las instrucciones, es decir, ¿debería tener el tiempo que RA6 es alto (o bajo) como período ?, entonces 1 instrucción parece ser 2 ciclos de ck o ... ¿debo usar el tiempo que RA6 es alto, luego bajo, luego de nuevo a alto como el período? en este caso, entonces debería ser de 4 ciclos ck por instrucción.

Lo anterior es una cuestión de definición. Mi pregunta principal se responde como (gracias a toda su ayuda en este foro) Estoy seguro de que la CK debe ser de 8 MHZ, entonces, sé que la frecuencia máxima posible para cambiar el PIN de un puerto es de aproximadamente 335 KHZ con la ck a 8MHZ (aquí significa la definición estándar de frecuencia). Además, al utilizar el PLL puedo duplicar o cuadruplicar esa tasa.

    
pregunta Jose Vicente

2 respuestas

2

Lo que estás haciendo mal es hacer suposiciones a nivel de instrucción sobre el código compilado. Si desea probar la velocidad de ejecución de las instrucciones, debe escribir un bucle conocido en el ensamblador. Por ejemplo:

loop:
         btg     LATA, #6
         bra     loop

A continuación, cuenta cuidadosamente cuántos ciclos en un ciclo de salida RA6 completo. Desde la hoja de datos o el manual de referencia de los programadores, puede ver que tgat BTG toma un ciclo de instrucciones y BRA dos. Por lo tanto, cada iteración de bucle toma 3 ciclos, y toma dos iteraciones para un ciclo completo de RA6, por lo que RA6 debe alternar a 1/6 la velocidad de instrucción, o Fcy / 6 utilizando símbolos de la documentación de Microchip.

Ahora verifique si esa parte usa 2 o 4 relojes por ciclo de instrucción. Digamos que este utiliza 2, por lo que ahora la frecuencia RA6 es Fosc / 12.

A continuación, debe pasar por los ajustes de configuración y ver exactamente cómo se deriva el oscilador. Puede ser bastante complicado en algunas de las partes más nuevas. Muchos de ellos tienen un estado de cadena de reloj adicional que se puede ajustar en el tiempo de ejecución, por lo que también debe mirar el código, no solo la configuración. Puede haber varias pulsaciones de reloj, divisores y, por lo general, un PLL que es un multiplicador, pero también generalmente con su conjunto de divisores. Eventualmente, debería poder comenzar con su frecuencia de cristal o la frecuencia del oscilador interno si está usando eso, siga a través de toda la cadena del reloj, determine cuál es la frecuencia del reloj de instrucción, luego divida eso entre 6 para obtener la frecuencia RA6. / p>     

respondido por el Olin Lathrop
0

Agregue un retraso conocido a su código; p.ej. 1 ms de retraso. El código compilado se optimizará para la frecuencia que el compilador conoce y, si esa es la misma que la del reloj RC establecido, usted medirá un bloque de 500Hz en la salida. Sin un retraso conocido, solo puede verificar el tiempo analizando el código de máquina compilado.

La frecuencia de salida con el retardo propuesto será proporcional a la frecuencia RC real.

    
respondido por el jippie

Lea otras preguntas en las etiquetas