Cortex M3 delay 1us

0

Estoy intentando lograr un retraso de 1us para poder conducir un bus de 1 cable. Mi proceso está trabajando en 10Mhz PCLK, así que intenté usar la función de temporizador con desbordamiento en el 10º ciclo. Por alguna razón me da una resolución de 6,2ish. No sé por qué ...

void _delay_us (int a_us)
{
LPC_TIM_TypeDef *timer = LPC_TIM0;
timer->MCR=0X0000000A; 
timer->TCR=0x02; //reset timer
timer->TC=0;
timer->PC=0;
timer->PR = 0x00000000;
timer->MR0=a_us;
timer->TCR=0x01; //start timer
while(timer->TC!=timer->MR0); //wait here up to match
}

La siguiente prueba fue "desperdiciar" 10 ciclos con asm nop (que por documentación debería tomar 1 instrucción de 32 bits), pero eso tampoco funcionó (el ejemplo es solo 3 nops, lo que toma alrededor de 0.6us, independientemente del número de nops) ... Ahora, eso es un rompecabezas. para bucle debe tomar 4 ciclos para a_us = 1? ¿De dónde vinieron otros 2?

void _delay_us (int a_us)
{
int i;
for(i=0; i<a_us; ++i){
    __asm__ volatile (
       "nop\n\t"
       "nop\n\t"
       "nop\n\t"    );
       }
 }

Pero el compilador parece optimizar los nop sin tomar ningún ciclo de proceso ...

Lo que hice es este bucle:

void _delay_us (int a_us)
{
int i;
int a, b;
for(i=0; i<a_us; ++i){
        for (a=0;a<6;a++){
        b++;
        }
       }
}

Este es un enfoque totalmente heurístico, medido por un osciloscopio. Si lo cuento bien, debería hacer 21 operaciones (supongo que 16 bits), por lo que debería ser de alrededor de 10 ciclos. Da alrededor de 1us de retraso, pero no me gusta ...

¿Hay alguna forma mejor de lograr un retraso en el uso?

    
pregunta Gossamer

3 respuestas

2

Si está tratando de obtener una sincronización precisa en un microcontrolador, realmente necesita configurar el temporizador del hardware para que interrumpa en el momento exacto que especifique en lugar de realizar una encuesta con el software y luego compararlo con un valor. Es probable que su CPU no pueda tomar todos esos datos y procesarlos a tiempo antes de que se suponga que suceda el próximo evento. El hardware está hecho específicamente para tener una sincronización precisa en los eventos.

Parece que podría estar intentando generar algún tipo de forma de onda usando estos valores de retardo. Si es así, normalmente se pueden programar utilizando la función de "comparación de salida" de un temporizador, que podría alternar un puerto de salida exactamente cuando se alcanza un valor de temporizador especificado.

    
respondido por el mattgately
1

Lo que termino con, es la rutina del ensamblador sin usar C a su alrededor como lo intenté antes con loop y nops ...

__asm void _delay_us (int a_us)
{
    CBZ R0, end
    MOV R1, #14
loop2
    MOV R2, R0

loop        
    NOP
    SUB R2, R2, #1
    CMP R2, #0
    BNE loop
    SUB R1, R1, #1
    CMP R1, #0
    BNE loop2
end
    BX lr
}

De esta manera no tengo que preocuparme por cómo terminará en código ASM, simplemente lo usa tal como está.

Una optimización adicional sería usar la función inline . De esa manera no perdería más ciclos para almacenar registros, cargar funciones, ejecutarlos, restaurar registros ... Pero luego aumentaría el tamaño de la ROM final.

    
respondido por el Gossamer
0

Habrá un montón de contabilidad asociada con el manejador de interrupciones, copiando y almacenando el contenido del puntero del programa y los registros importantes, y luego restaurándolos cuando finalice la interrupción. Sospecho que esto se comportará como una sobrecarga fija, pero puede tener que ver con su cadena de herramientas. Probablemente podría escribir su propio controlador de interrupciones si está 100% seguro de qué registros necesita mantener y qué puede tirar, pero por un retraso de 1us, la interrupción no es el primer método que intentaría. Noops es lo que usaría, y como se mencionó anteriormente, deberás prestar atención al ensamblaje que te da tu compilador.

    
respondido por el Scott Seidman

Lea otras preguntas en las etiquetas