Part Number: TM4C123GH6PM
Hi,
I need 8 PWM channels from the Tiva C series launchpad for controlling 4 half bridges .
As I am also using ADC peripheral for sensor feed back, i cannot use all 8 channels from the same PWM module using all 4 generators.
I ended up having to use 2 channels from module 0 and 6 channels from module 1 as follows:
//PWM 1 PA6 M1 PWM 2
//PWM 2 PA7 M1 PWM 3
//PWM 3 PE4 M0 PWM 2
//PWM 4 PE5 M0 PWM 3
//PWM 5 PF0 M1 PWM 4
//PWM 6 PF1 M1 PWM 5
//PWM 7 PF2 M1 PWM 6
//PWM 8 PF3 M1 PWM 7
In code composer studio, while stepping through the code, upon reaching the part in the code where i declare pin te to be PWM, the execution goes into fault ISR.
// PE4,PE5 from Module 0, Generator 2. PE4 and PE5 can also take signal from Module 1, Generator 1 GPIOPinTypePWM(GPIO_PORTE_BASE, GPIO_PIN_4|GPIO_PIN_5); GPIOPinConfigure(GPIO_PE4_M0PWM4);//PE4 GPIOPinConfigure(GPIO_PE5_M0PWM5);//PE5
The pins PE4 and PE5 are also listed under Module 1 Generator 1 in the data sheet page 1233 in spms376e.pdf.
They are also in Module 0 Generator 2.
Am I allowed to enable both the module and still use PE4 and PE5 through module 0?
Or is there somewhere else am going wrong?
I have attached full code to this post as a c (txt) file.
Thanks.
#include <stdbool.h>
#include <stdint.h>
// https://e2e.ti.com/support/microcontrollers/other/f/908/t/374640
//The Port Pins C0-3, D7 and F0/E7 are locked pins for specific functionality of JTAG, NMI and NMI respectively. To use them in GPIO or any other function they need to be unlocked and commit register be set. The following example function shows how to unlock and commit the Pins "before" calling any GPIO Pin Configuration Function
#include "inc/hw_memmap.h"
#include "inc/hw_GPIO.h" // To unlock PortF
#include "inc/hw_types.h"// To unlock PortF
#include "driverlib/gpio.h"
#include "driverlib/adc.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/pwm.h"
#include "utils/uartstdio.h"
//#define PWM_FREQUENCY 55
#define PWM_FREQUENCY 20000
// Prototypes for pwm duty cycle setting functions
//PWM 1 PA6 M1 PWM 2
//PWM 2 PA7 M1 PWM 3
//PWM 3 PE4 M0 PWM 2
//PWM 4 PE5 M0 PWM 3
//PWM 5 PF0 M1 PWM 4
//PWM 6 PF1 M1 PWM 5
//PWM 7 PF2 M1 PWM 6
//PWM 8 PF3 M1 PWM 7
void pf0pf1Duty(uint8_t,uint32_t);
void pf2pf3Duty(uint8_t,uint32_t);
void pe4pe5Duty(uint8_t,uint32_t);
void pa6pa7Duty(uint8_t,uint32_t);
// Function that uses SysCtlDelay function to generate delay
// One count input to SysCtlDelay gives 3 clock cycles delay
// Get the duration of one clock cycle from SysStlClockGet() function
void delayMS(uint16_t);
int main(void){
// Store the pwm clock , not pwm pulse train frequency.
// Load determines the value to which we count up before coming back to 0 in the PWM generator.
uint32_t uint32pwmClock,uint32Load;
// Duty cycle of the pwm, 4 pairs
uint8_t dutCyc_pf0pf1=10,dutCyc_pf2pf3=20,dutCyc_pe4pe5=30,dutCyc_pa6pa7=40;
// Check processor speed using SysCtlClockGet() function.
uint32_t processorSpeed;
// 40 MHz from PLL division.
// I am using the function call
// SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
// for setting the clock.
// I get the required (400/(2*5)) = 40MHz clock at the above settings.
// When I increase the SYSCTL_SYSDIV_5 factor to SYSCTL_SYSDIV_6, I get the expected 33.3 MHz clock.
// When I decrease the divisor from 5 to 3 and use SYSCTL_SYSDIV_3, I should get System control clock as 400/6 = 66.6 MHz
SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
processorSpeed = SysCtlClockGet();
// Do not attempt to remove hardware lock without enabling port first. It leads to fault isr
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)){
// Stay in loop till peripheral is ready.
}
// Unlock the Pin PF0 and Set the Commit Bit
// See data sheet table 10-1 for explanation of
// why this pin needs unlocking, page 650/1409, spms376e.pdf
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;
// Configure the PWM clock
// 66.66 MHz/32 = 2083.33 kHz PWM clock
// 40.00 MHz/32 = 1250.00 kHz PWM clock
SysCtlPWMClockSet(SYSCTL_PWMDIV_32);
// >>>>>>>>>>>>>>>>>Enable PWM module 0 and 1 <<<<<<<<<<<<<<<<<
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
/// There are 2 PWM modules, each module has 4 generators, each generator can output a pair of wm signals.
// We are using 3 generators from module 1 and 1 generator from module 0
// See table 20-1 on page 1233/1409 of spms376e.pdf
GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1); // PF0,PF1 from Module 1, Generator 2
GPIOPinConfigure(GPIO_PF0_M1PWM4);//PF0
GPIOPinConfigure(GPIO_PF1_M1PWM5);//PF1
GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_2|GPIO_PIN_3); // PF2,PF3 from Module 1, Generator 3
GPIOPinConfigure(GPIO_PF2_M1PWM6);//PF2
GPIOPinConfigure(GPIO_PF3_M1PWM7);//PF3
GPIOPinTypePWM(GPIO_PORTE_BASE, GPIO_PIN_4|GPIO_PIN_5); // PE4,PE5 from Module 0, Generator 2. PE4 and PE5 can also take signal from Module 1, Generator 1 but we are not using that.
GPIOPinConfigure(GPIO_PE4_M0PWM4);//PE4
GPIOPinConfigure(GPIO_PE5_M0PWM5);//PE5
GPIOPinTypePWM(GPIO_PORTA_BASE, GPIO_PIN_6|GPIO_PIN_7); // PE4,PE5 from Module 1, Generator 1
GPIOPinConfigure(GPIO_PA6_M1PWM2);//PA6
GPIOPinConfigure(GPIO_PA7_M1PWM3);//PA7
// We can get 2083.33Khz (for 66.6 MHz) or 1250.0kHz (for 40 MHz) pwm clock frequency
uint32pwmClock = SysCtlClockGet()/32; // Should be the same divisor used in SysCtlPWMClockSet( );
// From the pwm clock, get the load value for the desired PWM_frequency.
uint32Load = (uint32pwmClock / PWM_FREQUENCY) - 1;
// We can use up down mode for center aligned and down mode for left aligned signal.
PWMGenConfigure(PWM1_BASE, PWM_GEN_1, PWM_GEN_MODE_DOWN);
PWMGenConfigure(PWM1_BASE, PWM_GEN_2, PWM_GEN_MODE_DOWN);
PWMGenConfigure(PWM1_BASE, PWM_GEN_3, PWM_GEN_MODE_DOWN);
PWMGenConfigure(PWM0_BASE, PWM_GEN_2, PWM_GEN_MODE_DOWN);
// Load value upto which the counter goes up before jumping back to 1
PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, uint32Load);
PWMGenPeriodSet(PWM1_BASE, PWM_GEN_1, uint32Load);
PWMGenPeriodSet(PWM1_BASE, PWM_GEN_2, uint32Load);
PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, uint32Load);
// Assign duty cycle
pf0pf1Duty( dutCyc_pf0pf1, uint32Load);
pf2pf3Duty( dutCyc_pf2pf3, uint32Load);
pe4pe5Duty( dutCyc_pe4pe5, uint32Load);
pa6pa7Duty( dutCyc_pa6pa7, uint32Load);
// Enable the outputs
// See table 20-1 on page 1233/1409 of spms376e.pdf
PWMOutputState(PWM0_BASE, PWM_OUT_4_BIT, true);// PE4
PWMOutputState(PWM0_BASE, PWM_OUT_5_BIT, true);// PE5
PWMOutputState(PWM1_BASE, PWM_OUT_2_BIT, true);// PA6
PWMOutputState(PWM1_BASE, PWM_OUT_3_BIT, true);// PA7
PWMOutputState(PWM1_BASE, PWM_OUT_4_BIT, true);// PF0
PWMOutputState(PWM1_BASE, PWM_OUT_5_BIT, true);// PF1
PWMOutputState(PWM1_BASE, PWM_OUT_6_BIT, true);// PF2
PWMOutputState(PWM1_BASE, PWM_OUT_7_BIT, true);// PF3
// Enable generator block
PWMGenEnable(PWM1_BASE, PWM_GEN_1);
PWMGenEnable(PWM1_BASE, PWM_GEN_2);
PWMGenEnable(PWM1_BASE, PWM_GEN_3);
PWMGenEnable(PWM0_BASE, PWM_GEN_2);
while(1) {
}
return(0);
}
// 55 Hz pwm train on 0625kHz pwm clock gives 11363 pwm clocks per pwm cycle. for 50% duty cycle, that is 5681 cycles.
// 20 kHz pwm train on 1250kHz pwm clock gives 62 pwm clocks per pwm cycle. for 50% duty cycle, that is 31.
void pa6pa7Duty(uint8_t dutyCycle, uint32_t uint32Load){
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2, uint32Load*dutyCycle/100);
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_3, uint32Load*dutyCycle/100);
}
void pf0pf1Duty(uint8_t dutyCycle, uint32_t uint32Load){
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_4, uint32Load*dutyCycle/100);
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_5, uint32Load*dutyCycle/100);
}
void pf2pf3Duty(uint8_t dutyCycle, uint32_t uint32Load){
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6, uint32Load*dutyCycle/100);
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_7, uint32Load*dutyCycle/100);
}
void pe4pe5Duty(uint8_t dutyCycle, uint32_t uint32Load){
PWMPulseWidthSet(PWM0_BASE, PWM_OUT_4, uint32Load*dutyCycle/100);
PWMPulseWidthSet(PWM0_BASE, PWM_OUT_5, uint32Load*dutyCycle/100);
}
void delayMS(uint16_t ms) {
SysCtlDelay( (SysCtlClockGet()/(3*1000))*ms ) ;
}