PWM3 por Hardware
Aqui se muestra como configurar el PWM3 por hardware para quitarle la carga al procesador y al SYSTICK-TIMER.
/*Inizializar el PWM */
void PWM_Init(void){
// Clock setting for PWM and GPIO PORT
SYSCTL->RCGCPWM |= 2; /* Enable clock to PWM1 module */
SYSCTL->RCGCGPIO |= 0x20; /* Enable system clock to PORTF */
SYSCTL->RCC |= (1<<20); /* Enable System Clock Divisor function */
SYSCTL->RCC |= 0x000E0000; /* Use pre-divider valur of 64 and after that feed clock to PWM1 module*/
/* Setting of PF2 pin for M1PWM6 channel output pin */
GPIOF->AFSEL |= (1<<2); /* PF2 sets a alternate function */
GPIOF->PCTL &= ~0x00000F00; /*set PF2 as output pin */
GPIOF->PCTL |= 0x00000500; /* make PF2 PWM output pin */
GPIOF->DEN |= (1<<2); /* set PF2 as a digital pin */
PWM1->_3_CTL &= ~(1<<0); /* Disable Generator 3 counter */
PWM1->_3_CTL &= ~(1<<1); /* select down count mode of counter 3*/
PWM1->_3_GENA = 0x0000008C; /* Set PWM output when counter reloaded and clear when matches PWMCMPA */
PWM1->_3_LOAD = 5000; /* set load value for 50Hz 80MHz/64 = 1.25MHz and (1.23MHz/5000) */
PWM1->_3_CMPA = 4999; /* set duty cyle to to minumum value*/
PWM1->_3_CTL = 1; /* Enable Generator 3 counter */
PWM1->ENABLE = 0x40; /* Enable PWM1 channel 6 output */
}
void PWM_Init(void){
// Clock setting for PWM and GPIO PORT
SYSCTL->RCGCPWM |= 2; /* Enable clock to PWM1 module */
SYSCTL->RCGCGPIO |= 0x20; /* Enable system clock to PORTF */
SYSCTL->RCC |= (1<<20); /* Enable System Clock Divisor function */
SYSCTL->RCC |= 0x000E0000; /* Use pre-divider valur of 64 and after that feed clock to PWM1 module*/
/* Setting of PF2 pin for M1PWM6 channel output pin */
GPIOF->AFSEL |= (1<<2); /* PF2 sets a alternate function */
GPIOF->PCTL &= ~0x00000F00; /*set PF2 as output pin */
GPIOF->PCTL |= 0x00000500; /* make PF2 PWM output pin */
GPIOF->DEN |= (1<<2); /* set PF2 as a digital pin */
PWM1->_3_CTL &= ~(1<<0); /* Disable Generator 3 counter */
PWM1->_3_CTL &= ~(1<<1); /* select down count mode of counter 3*/
PWM1->_3_GENA = 0x0000008C; /* Set PWM output when counter reloaded and clear when matches PWMCMPA */
PWM1->_3_LOAD = 5000; /* set load value for 50Hz 80MHz/64 = 1.25MHz and (1.23MHz/5000) */
PWM1->_3_CMPA = 4999; /* set duty cyle to to minumum value*/
PWM1->_3_CTL = 1; /* Enable Generator 3 counter */
PWM1->ENABLE = 0x40; /* Enable PWM1 channel 6 output */
}
1. Lo primero que tenemos que hacer habilitar el reloj del PWM en el registro RCGCPWM.
2. Se requiere habilitar el reloj del Puerto F, ya que el PWM esta en la terminal PF2
3. Se habilita el Bit 20 del registro RCC (USEPWMDIV).
4. Se carga el valor de E los bits 19-17 (PWMDIV) del registro RCC.
Posteriormente se configura el PF2 para que sea funcion alternativa y el valor adecuado en el PCTL como se muestra en el codigo y que copiamos aquí con el objetivo de clarificar.
/* Setting of PF2 pin for M1PWM6 channel output pin */
GPIOF->AFSEL |= (1<<2); /* PF2 sets a alternate function */
GPIOF->PCTL &= ~0x00000F00; /*set PF2 as output pin */
GPIOF->PCTL |= 0x00000500; /* make PF2 PWM output pin */
GPIOF->DEN |= (1<<2); /* set PF2 as a digital pin */
Despues se configura el CTL del PWM, deshabilitados el generador 3, seleccionamos el modo de decrementador del contador 3 y le de indicamos al PWM que se recargue cuando el valor del contador sea igual al del PWMCPA.
PWM1->_3_CTL &= ~(1<<0); /* Disable Generator 3 counter */
PWM1->_3_CTL &= ~(1<<1); /* select down count mode of counter 3*/
PWM1->_3_GENA = 0x0000008C; /* Set PWM output when counter reloaded and clear when matches PWMCMPA */
Por último en las siguientes lineas de codigo configuramos como debede de trabajar el PWM en la práctica.
Load es el regustro que nos permite configurar el periodo del PWM. En este caso a 5000, lo que equivale a (1/80MHz)*5000 = 4ms
Donde 4ms equivale a 250Hz. Es decir que el PWM tendra una frecuencia de 250Hz.
El registro CMPA nos permite cargar el Duty-Cicle (D). Para este ejemplo si quisieramos un D = 75%, el valor del CMPA debería ser de 3750. Aplicando una simple regla de 3.
Si 5000 es a 100 cuanto sería 75%?, resulta en 3750. Finalmente, activamos el contador y habilitamos el PWM en PWM1->ENABLE = 0x40;
PWM1->_3_LOAD = 5000; /* set load value for 50Hz 80MHz/64 = 1.25MHz and (1.23MHz/5000) */
PWM1->_3_CMPA = 4999; /* set duty cyle to to minumum value*/
PWM1->_3_CTL = 1; /* Enable Generator 3 counter */
PWM1->ENABLE = 0x40; /* Enable PWM1 channel 6 output */
/* Setting of PF2 pin for M1PWM6 channel output pin */
GPIOF->AFSEL |= (1<<2); /* PF2 sets a alternate function */
GPIOF->PCTL &= ~0x00000F00; /*set PF2 as output pin */
GPIOF->PCTL |= 0x00000500; /* make PF2 PWM output pin */
GPIOF->DEN |= (1<<2); /* set PF2 as a digital pin */
Despues se configura el CTL del PWM, deshabilitados el generador 3, seleccionamos el modo de decrementador del contador 3 y le de indicamos al PWM que se recargue cuando el valor del contador sea igual al del PWMCPA.
PWM1->_3_CTL &= ~(1<<0); /* Disable Generator 3 counter */
PWM1->_3_CTL &= ~(1<<1); /* select down count mode of counter 3*/
PWM1->_3_GENA = 0x0000008C; /* Set PWM output when counter reloaded and clear when matches PWMCMPA */
Por último en las siguientes lineas de codigo configuramos como debede de trabajar el PWM en la práctica.
Load es el regustro que nos permite configurar el periodo del PWM. En este caso a 5000, lo que equivale a (1/80MHz)*5000 = 4ms
Donde 4ms equivale a 250Hz. Es decir que el PWM tendra una frecuencia de 250Hz.
El registro CMPA nos permite cargar el Duty-Cicle (D). Para este ejemplo si quisieramos un D = 75%, el valor del CMPA debería ser de 3750. Aplicando una simple regla de 3.
Si 5000 es a 100 cuanto sería 75%?, resulta en 3750. Finalmente, activamos el contador y habilitamos el PWM en PWM1->ENABLE = 0x40;
PWM1->_3_LOAD = 5000; /* set load value for 50Hz 80MHz/64 = 1.25MHz and (1.23MHz/5000) */
PWM1->_3_CMPA = 4999; /* set duty cyle to to minumum value*/
PWM1->_3_CTL = 1; /* Enable Generator 3 counter */
PWM1->ENABLE = 0x40; /* Enable PWM1 channel 6 output */
Decargar el Codigo: Click aquí
// Tambien puede copiar y pegar este codigo:
#include "TM4C123GH6PM.h"
#include "TM4C123.h" // Device header
#include <stdint.h>
// configure the system to get its clock from the PLL
#define SYSCTL_RIS_R (*((volatile unsigned long *)0x400FE050))
#define SYSCTL_RCC_R (*((volatile unsigned long *)0x400FE060))
#define SYSCTL_RCC2_R (*((volatile unsigned long *)0x400FE070))
void PWM_Init(void);
void PLL_Init(void);
__asm void
Delay(unsigned long n)
{
SUBS R0, #1
BNE Delay
bx LR ;//the link register is providing the address to branch to.
}
int main(void)
{
int duty_cycle = 4999;
PLL_Init();
PWM_Init();
while(1)
{
duty_cycle = duty_cycle - 10;
if (duty_cycle <= 0)
duty_cycle = 5000;
PWM1->_3_CMPA = duty_cycle;
Delay(13333333); // delay ~0.5 sec at 80 MHz
}
}
void PWM_Init(void){
// Clock setting for PWM and GPIO PORT
SYSCTL->RCGCPWM |= 2; /* Enable clock to PWM1 module */
SYSCTL->RCGCGPIO |= 0x20; /* Enable system clock to PORTF */
SYSCTL->RCC |= (1<<20); /* Enable System Clock Divisor function */
SYSCTL->RCC |= 0x000E0000; /* Use pre-divider valur of 64 and after that feed clock to PWM1 module*/
/* Setting of PF2 pin for M1PWM6 channel output pin */
GPIOF->AFSEL |= (1<<2); /* PF2 sets a alternate function */
GPIOF->PCTL &= ~0x00000F00; /*set PF2 as output pin */
GPIOF->PCTL |= 0x00000500; /* make PF2 PWM output pin */
GPIOF->DEN |= (1<<2); /* set PF2 as a digital pin */
PWM1->_3_CTL &= ~(1<<0); /* Disable Generator 3 counter */
PWM1->_3_CTL &= ~(1<<1); /* select down count mode of counter 3*/
PWM1->_3_GENA = 0x0000008C; /* Set PWM output when counter reloaded and clear when matches PWMCMPA */
PWM1->_3_LOAD = 5000; /* set load value for 50Hz 80MHz/64 = 1.25MHz and (1.23MHz/5000) */
PWM1->_3_CMPA = 4999; /* set duty cyle to to minumum value*/
PWM1->_3_CTL = 1; /* Enable Generator 3 counter */
PWM1->ENABLE = 0x40; /* Enable PWM1 channel 6 output */
}
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 10001111
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL, DIV400
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock, 400/(4+1) = 80MHz
// 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;
}
// Tambien puede copiar y pegar este codigo:
#include "TM4C123GH6PM.h"
#include "TM4C123.h" // Device header
#include <stdint.h>
// configure the system to get its clock from the PLL
#define SYSCTL_RIS_R (*((volatile unsigned long *)0x400FE050))
#define SYSCTL_RCC_R (*((volatile unsigned long *)0x400FE060))
#define SYSCTL_RCC2_R (*((volatile unsigned long *)0x400FE070))
void PWM_Init(void);
void PLL_Init(void);
__asm void
Delay(unsigned long n)
{
SUBS R0, #1
BNE Delay
bx LR ;//the link register is providing the address to branch to.
}
int main(void)
{
int duty_cycle = 4999;
PLL_Init();
PWM_Init();
while(1)
{
duty_cycle = duty_cycle - 10;
if (duty_cycle <= 0)
duty_cycle = 5000;
PWM1->_3_CMPA = duty_cycle;
Delay(13333333); // delay ~0.5 sec at 80 MHz
}
}
void PWM_Init(void){
// Clock setting for PWM and GPIO PORT
SYSCTL->RCGCPWM |= 2; /* Enable clock to PWM1 module */
SYSCTL->RCGCGPIO |= 0x20; /* Enable system clock to PORTF */
SYSCTL->RCC |= (1<<20); /* Enable System Clock Divisor function */
SYSCTL->RCC |= 0x000E0000; /* Use pre-divider valur of 64 and after that feed clock to PWM1 module*/
/* Setting of PF2 pin for M1PWM6 channel output pin */
GPIOF->AFSEL |= (1<<2); /* PF2 sets a alternate function */
GPIOF->PCTL &= ~0x00000F00; /*set PF2 as output pin */
GPIOF->PCTL |= 0x00000500; /* make PF2 PWM output pin */
GPIOF->DEN |= (1<<2); /* set PF2 as a digital pin */
PWM1->_3_CTL &= ~(1<<0); /* Disable Generator 3 counter */
PWM1->_3_CTL &= ~(1<<1); /* select down count mode of counter 3*/
PWM1->_3_GENA = 0x0000008C; /* Set PWM output when counter reloaded and clear when matches PWMCMPA */
PWM1->_3_LOAD = 5000; /* set load value for 50Hz 80MHz/64 = 1.25MHz and (1.23MHz/5000) */
PWM1->_3_CMPA = 4999; /* set duty cyle to to minumum value*/
PWM1->_3_CTL = 1; /* Enable Generator 3 counter */
PWM1->ENABLE = 0x40; /* Enable PWM1 channel 6 output */
}
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 10001111
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL, DIV400
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock, 400/(4+1) = 80MHz
// 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;
}