6 votos

¿Cómo funciona __delay_cycles?

Estoy usando un msp430g2553 y ajustando el reloj a 1Mhz:

BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;

He cronometrado un ciclo de 5 millones y inesperadamente tarda unos 6 segundos (esperaba 5). El bucle que he utilizado es:

int i;
for(i=0;i<5000;i++)
    __delay_cycles(1000);

He leído sobre el uso de interrupciones (probablemente basado en Timer_A, etc) pero me gustaría evitar eso por ahora.

Así que mi pregunta es: ¿cómo puedo implementar un argumento constante sleep basado en __delay_cycles?

Edición posterior

Montaje para:

void delay1000() {
        __delay_cycles(1000);
}

es:

delay1000:
    0c3b4: 04 12                     PUSH    R4
    0c3b6: 04 41                     MOV     SP,      R4
    0c3b8: 24 53                     INCD    R4
    0c3ba: 3f 40 4c 01               MOV     #0x014c, R15    // 332 decimal (1000/3 -> DEC, TST and JNZ)
    0c3be: 1f 83                     DEC     R15
    0c3c0: 0f 93                     TST     R15
    0c3c2: fd 23                     JNZ     delay1000+0xa
    0c3c4: 03 43                     NOP     
    0c3c6: 03 43                     NOP     
    0c3c8: 34 41                     POP     R4
    0c3ca: 30 41                     RET

8voto

Passerby Puntos 28913

De la Guía del usuario del compilador MSP430 Optimizing C/C++ v 3.1 (SLAU132c.pdf) pp. 109:

El intrínseco __delay_cycles inserta código para consumir precisamente el número de ciclos especificados sin efectos secundarios. El número de ciclos retrasados debe ser una constante en tiempo de compilación.

Se trata de una función intrínseca, diseñada específicamente para agotar los ciclos. Debería servir para al menos ese número de ciclos. Puedes cambiar 1000 por otra cosa (debe ser una constante, no puede ser una variable). Tanto el bucle for como la llamada a la función se sumarán al retraso.

Además:

sí con el código habrá un pequeño error de "offset" y "ganancia" en el retardo real que se obtiene. El código es bueno para garantizar un cierto retraso mínimo, con un error muy pequeño en la dirección positiva. Por eso el retardo dentro del bucle se eligió bastante grande ("ms"). Si necesitas un retardo exacto, la mejor manera sería usar un temporizador. Pero pero si por alguna razón quieres usar retardos de SW, te recomendaría codificar una función en ensamblador en lugar de medir la función C. Podrías compensar en la propia función los errores de "offset" y "ganancia" de la llamada y la sobrecarga del bucle. Además, nuestros IDEs tienen ciclo que podría utilizar para analizar la función de retardo. Pero para los retrasos del SW, ten en cuenta que las interrupciones podrían entrar en acción (si están habilitadas) y cambiar el retardo observable resultante.

Empleados de TI en sus foros de apoyo.

7voto

SandeepJ Puntos 1339

Mira el desensamblaje del código, recuerda que el bucle for agrega algunas instrucciones que toman algunos ciclos. Con un bucle de 5000, estos ciclos extra se sumarán. Además, cómo delay_cycles() se aplica puede suponer una gran diferencia.
Puedes contar los ciclos de cada bucle en el simulador, hacer las cuentas y compensar los ciclos añadidos pasando el valor apropiado.

Por supuesto, la mejor manera de obtener una sincronización precisa es usar interrupciones, pero dices que quieres evitarlas por ahora.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X