// PWMDual1.c // Runs on TM4C123 // Use PWM0/PB6 and PWM1/PB7 to generate two square waves with 50% duty cycle // and 180 degrees out of phase. // Daniel Valvano // September 10, 2013 // Please note: /* This is a modified version from original Jonathan Valvano's routine This is an example routine I prepared to handle a hobby servo motor by PWM tested with a EK-TM4C123GXL board TM4C123. Connections are: PD0 is for PWM input on servo motor Tested with a standard Tower Pro MG90S Micro servo motor where 20 milliseconds is the standard period for the PWM input 0.9 ms is for +90º position 1.65 ms is for 0º position 2.4 ms is for -90 º position by Francisco Dominguez Roman 2014 Twitter: @Franciscodr blog http://www.gestionconsult.es/blog/ more information of robotics at http://letsmakerobots.com/content/lets-learn-basics-robotics-edxs-embedded-systems-shape-world and http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/342633/1201161.aspx */ /* This example accompanies the book "Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers", ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2013 Program 6.7, section 6.3.2 Copyright 2013 by Jonathan W. Valvano, valvano@mail.utexas.edu You may use, edit, run or distribute this file as long as the above copyright notice remains THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. For more information about my classes, my research, and my books, see http://users.ece.utexas.edu/~valvano/ */ #define PWM1_ENABLE_R (*((volatile unsigned long *)0x40029008)) #define PWM_ENABLE_PWM3EN 0x00000002 // PWM1 Output Enable #define PWM_ENABLE_PWM2EN 0x00000001 // PWM0 Output Enable #define PWM1_0_CTL_R (*((volatile unsigned long *)0x40029040)) #define PWM_0_CTL_MODE 0x00000002 // Counter Mode #define PWM_1_CTL_ENABLE 0x00000001 // PWM Block Enable #define PWM1_0_LOAD_R (*((volatile unsigned long *)0x40029050)) #define PWM1_0_CMPA_R (*((volatile unsigned long *)0x40029058)) #define PWM1_0_CMPB_R (*((volatile unsigned long *)0x4002905C)) #define PWM1_0_GENA_R (*((volatile unsigned long *)0x40029060)) #define PWM_1_GENA_ACTCMPBD_ZERO 0x00000800 // Set the output signal to 0 #define PWM_1_GENA_ACTCMPBU_ONE 0x00000300 // Set the output signal to 1 #define PWM1_0_GENB_R (*((volatile unsigned long *)0x40029064)) #define PWM_1_GENB_ACTCMPAD_ZERO \ 0x00000080 // Set the output signal to 0 #define PWM_1_GENB_ACTCMPAU_ONE 0x00000030 // Set the output signal to 1 #define GPIO_PORTD_AFSEL_R (*((volatile unsigned long *)0x40007420)) #define GPIO_PORTD_DEN_R (*((volatile unsigned long *)0x4000751C)) #define GPIO_PORTD_AMSEL_R (*((volatile unsigned long *)0x40007528)) #define GPIO_PORTD_PCTL_R (*((volatile unsigned long *)0x4000752C)) #define SYSCTL_RCC_R (*((volatile unsigned long *)0x400FE060)) #define SYSCTL_RCC_USEPWMDIV 0x00100000 // Enable PWM Clock Divisor #define SYSCTL_RCC_PWMDIV_M 0x000E0000 // PWM Unit Clock Divisor #define SYSCTL_RCC_PWMDIV_64 0x000A0000 // PWM clock /64 #define SYSCTL_RCGC0_R (*((volatile unsigned long *)0x400FE100)) #define SYSCTL_RCGC0_PWM0 0x00100000 // PWM Clock Gating Control #define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108)) #define SYSCTL_RCGC2_GPIOD 0x00000008 // Port D Clock Gating Control //#define PWM0_1_GENA_R (*((volatile unsigned long *)0x400280A0)) #define SYSCTL_RCGC_PWM_R (*((volatile unsigned long *)0x400FE640)) // #define SYSCTL_RCGC_PWM 0x00000002 // PWM Clock Gating Control (WRONG ONE) #define SYSCTL_RCGC_PWM0 0x00000001 // PWM Clock Gating Control // period is 16-bit number of PWM clock cycles in one period (3<=period) // PWM clock rate = processor clock rate/SYSCTL_RCC_PWMDIV // = BusClock/64 // = 3.2 MHz/64 = 50 kHz (in this example) void PWM1Dual_Init(unsigned long period2, unsigned short dcpwm2, unsigned short dcpwm3){ volatile unsigned long delay; // SYSCTL_RCGC_PWM_R |= SYSCTL_RCGC_PWM; // 1) activate PWM1 (WRONG ONE) // SYSCTL_RCGC_PWM_R |= SYSCTL_RCGC_PWM0; // 1) activate PWM1 SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOD; // 2) activate port D delay = SYSCTL_RCGC2_R; // allow time to finish activating GPIO_PORTD_AFSEL_R |= 0x03; // enable alt funct on PD1-0 GPIO_PORTD_PCTL_R &= ~0x000000FF; // configure PD1-0 as PWM1 GPIO_PORTD_PCTL_R |= 0x00000055; GPIO_PORTD_AMSEL_R &= ~0x03; // disable analog functionality on PD1-0 GPIO_PORTD_DEN_R |= 0x03; // enable digital I/O on PD1-0 SYSCTL_RCC_R |= SYSCTL_RCC_USEPWMDIV; // 3) use PWM divider SYSCTL_RCC_R &= ~SYSCTL_RCC_PWMDIV_M; // clear PWM divider field SYSCTL_RCC_R += SYSCTL_RCC_PWMDIV_64; // configure for /64 divider PWM1_0_CTL_R = 0; // 4) disable PWM while initializing //PWM0, Generator B (PWM0/PB6) goes to 0 when count==CMPA counting down and 1 when count==CMPA counting up PWM1_0_GENA_R = (PWM_1_GENA_ACTCMPBD_ZERO|PWM_1_GENA_ACTCMPBU_ONE); //PWM0, Generator B (PWM1/PB7) goes to 0 when count==CMPA counting down and 1 when count==CMPA counting up PWM1_0_GENB_R = (PWM_1_GENB_ACTCMPAD_ZERO|PWM_1_GENB_ACTCMPAU_ONE); PWM1_0_LOAD_R = (period2 - 1)/2; // 5) count from zero to this number and back to zero in (period - 1) cycles PWM1_0_CMPA_R = (period2*dcpwm3)/100; // 6) count value when PWM1/PD0 toggles PWM1_0_CMPB_R = (period2*dcpwm2)/100; // 6) count value when PWM1/PD1 toggles // 7) start PWM0 in Count Up/Down mode PWM1_0_CTL_R |= (PWM_0_CTL_MODE|PWM_1_CTL_ENABLE); // enable PWM1-0 PWM1_ENABLE_R |= (PWM_ENABLE_PWM1EN|PWM_ENABLE_PWM0EN); } // change period // period is 16-bit number of PWM clock cycles in one period (3<=period) void PWM1Dual_Period(unsigned short dcpwm2, unsigned short dcpwm3){ unsigned long period2; period2 = PWM1_0_LOAD_R; PWM1_0_CMPA_R = (period2*(101-dcpwm3))/100; // 8) count value when PWM1/PD1 toggles PWM1_0_CMPB_R = (period2*(65536-dcpwm2))/65535; // 9) count value when PWM0/PD0 toggles }