Diferencia entre revisiones de «C10 - Finite State Machine»
Ir a la navegación
Ir a la búsqueda
Sin resumen de edición |
|||
| Línea 134: | Línea 134: | ||
En la siguiente imagen se puede ver una máquina de estados finita de las dos funciones:<br> | En la siguiente imagen se puede ver una máquina de estados finita de las dos funciones:<br> | ||
[[File: edx-fsm-systick-delay.png|400px]]<br> | [[File: edx-fsm-systick-delay.png|400px]]<br> | ||
<br> | |||
= Structures = | |||
<br> | |||
<br> | <br> | ||
Revisión del 15:12 18 mar 2015
Introducción
El microcontrolador cuenta de dos fuentes para el oscilador:
- Interna
- El oscilador interno del uC TM4C va a 16Mhz con una presicón de ±1% poco preciso
- Consume poca corriente
- Externa
- Se puede configurar el cristal a diferentes velocidades según las necesidades
- Son mucho mas preciso que el interno
- Consumen más corriente y espacio en el PCB
Phase-Lock-Loop (PLL)
Que és? Cómo funciona?
- Permite seleccionar un cristal externo
- Permite seleccionar la velocidad del cristal y por tanto del procesador
- Permite seleccionar la velocidad del bus del sistema
- Para poder llevar a cabo estas dos operaciones necesitamos manipular dos registros
- SYSCTL_RCC_R
- SYSCTL_RCC2_R
En la siguiente imagen se ven los registros que van asociados al PLL
![]()
Los datos que nos interesan:
- En el registro SYSCTL_RCC_R el campo XTAL
- Este se compone de 5 bits - del bit 10 al bit 6
- El campo XTAL configura la velocidad del cristal. En la tabla de abajo se ven la codificacion de la velocidad en hexadecimal
- En el registro SYSCTL_RCC2_R el campo SYSDIV2
- Este campo se compone de 7 bits - del bit 28 al bit 22
- Configura la velocidad del bus del sistema
- La fórmula para calcular es:
Ej.
En el campo SYSDIV2 pondremos el valor 4
(Hay que tener en cuenta que a el número n velocidad del reloj)
Codificación velocidad cristal en hexadecimal:
![]()
Notas:
- No se si está bien explicada la función del PLL de ajustar la velocidad del reloj/bus. En las prácticas se ve como ponen a 80Mhz "algo". Yo creia que era el cristal, pero viendo la tabla de arriba el cristal como máximo puede ir a 25Mhz.
- El campo SYSDIV2 parece ser el encargado de configurar la velocidad del bus y vemos que lo puedes poner a 80Mhz, por lo tanto lo que creo que cambian en las prácticas es la velocidad de bus, no la cristal en si.
- También tendria que mirar que es el reloj del bus y como afecta a la velocidad de proceso del uC
Usar PLL
Hay dos formas de activar PLL:
- A través de una libreria
- La mejor solucion porque es mas estable
- El código se puede portar más fácil a otro micro
- Accediendo directamente a los registros
Accediendo manualmente
- Paso 0: Usar RCC2 porque provee más opciones
- Paso 1: Poner bit 11 de BYPASS2 a 1
- PLL esta bypassed y no hay system clock divider
- Paso 2: Seleccionar la velocidad del cristal a través del campo XTAL
- Los bits de OSCSRC2 se hacen clear para seleccionar el main oscillator como oscillator clock source
- Paso 3: Hacer clear al PWRDN2 (bit 13) para activar el PLL
- Paso 4: Configurar y activar el divisor del reloj usando el campo SYSDIV2
- Explicado en el apartado anterior la fórmula para calcular el bus del reloj a través del SYSDIV2
- Paso 5: Esperar a que el PLL se estabilize
- Cuando el PLLRIS (bit 6) del <b<SYSCTL_RIS_R sea high estará estabilizado
- Paso 6: Hacer clear al bit BYPASS2 para conectar el PLL
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
Accurate Time Delays Using SysTick
El temporizador SysTick funciona de la siguiente manera:
- Se coloca el numero de ciclos de reloj que se quieren dejar pasar (hacer el delay) en el registro RELOAD
- Cada ciclo de reloj se resta un bit al número introducido en RELOAD
- Cuando se pasa del numero 1 al numero 0 el bit 16 del registro CTRL se pone en 1. Esto nos indica que el contador ha llegado a su fin
Delay
- Por lo visto como funciona el SysTick timer podemos utilizarlo para crear una función delay precisa
- Cada iteración de Systick tarda 1 ciclo de reloj
Ej: Si el bus del sistema va a 80Mhz
por operación
- Sabiendo lo que tarda cada iteración podemos calcular cuantas iteraciones son necesarias para tener un delay de Xms
Ej: Si queremos calcular un delay de 10ms. n es el número que pondremos en el registro RELOAD
Ej código:
#define NVIC_ST_CTRL_R (*((volatile unsigned long *)0xE000E010)) //Registro CTRL
#define NVIC_ST_RELOAD_R (*((volatile unsigned long *)0xE000E014)) //Registro RELOAD
#define NVIC_ST_CURRENT_R (*((volatile unsigned long *)0xE000E018)) //Registro CURRENT
void SysTick_Init(void){
NVIC_ST_CTRL_R = 0; // disable SysTick during setup
NVIC_ST_CTRL_R = 0x00000005; // enable SysTick with core clock
}
// The delay parameter is in units of the 80 MHz core clock. (12.5 ns)
void SysTick_Wait(unsigned long delay){
NVIC_ST_RELOAD_R = delay-1; // se resta 1 a delay porque la cuenta la haria de 8000000 a 0 que son 800001 veces
NVIC_ST_CURRENT_R = 0; // any value written to CURRENT clears
while((NVIC_ST_CTRL_R&0x00010000)==0){ // esperamos a que el bit 16 de CTRL pase a 1
}
}
- Como el SysTick timer solo admite un numero de 24 bits, por lo tanto como máximo se puede hacer un delay de 200ms
- Para poder hacer un delay más grande se puede usar un bucle que vaya llamando a SysTick cada Xms
- En el ejemplo de abajo se ve como se crea un bucle que llama las veces que queramos a la función SysTick_Wait10ms que tarda 10ms en acabarse. Por lo tanto si queremos un delay de 100ms tenemos que llamar a la función 10 veces
// 800000*12.5ns equals 10ms
void SysTick_Wait10ms(unsigned long delay){
unsigned long i;
for(i=0; i<delay; i++){
SysTick_Wait(800000); // wait 10ms
}
}
En la siguiente imagen se puede ver una máquina de estados finita de las dos funciones:
![]()
Structures