100% found this document useful (1 vote)
173 views7 pages

Mypwmlib

This module contains functions for driving motors using pulse-width modulation (PWM). It includes functions to initialize PWM on a single channel or multiple channels. It defines constants and variables for the channel configurations and initializes the PWM module, generator settings, duty cycles, and GPIO pins for the selected channels.

Uploaded by

api-398062839
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
173 views7 pages

Mypwmlib

This module contains functions for driving motors using pulse-width modulation (PWM). It includes functions to initialize PWM on a single channel or multiple channels. It defines constants and variables for the channel configurations and initializes the PWM module, generator settings, duty cycles, and GPIO pins for the selected channels.

Uploaded by

api-398062839
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

/****************************************************************************

Module
MyPWMLib.c

Description
This module contains functions that allow motors to be driven via PWM

****************************************************************************/

/*----------------------------- Include Files -----------------------------*/


/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "MyPWMLib.h"

// the headers to access the GPIO subsystem


#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "hw_nvic.h"
#include "hw_pwm.h"
#include "hw_timer.h"

// the headers to access the TivaWare Library


#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/pwm.h"

#include "BITDEFS.H"

/*----------------------------- Module Defines ----------------------------*/

/*---------------------------- Module Functions ---------------------------*/


/* prototypes for private functions for this machine.They should be functions
relevant to the behavior of this state machine
*/

static void My_Set_100DC(uint8_t Channel);


static void My_RestoreDC(uint8_t Channel);
static void My_Set_0DC(uint8_t Channel);

/*---------------------------- Module Variables ---------------------------*/


// everybody needs a state variable, you may need others as well.
// type of state variable should match htat of enum in header file

#define ONE_SEC 976


#define HUNDRED_MSEC (ONE_SEC / 10)
#define PWM_DIV 32
#define CLOCK_SPEED 40E6 //why not SYSCTLCLOCKGET??

#define BitsPerNibble 4

#define MAX_NUM_CHANNELS 16
#define GENA_NORMAL PWM_0_GENA_ACTCMPAU_ONE | PWM_0_GENA_ACTCMPAD_ZERO
#define GENB_NORMAL PWM_0_GENB_ACTCMPBU_ONE | PWM_0_GENB_ACTCMPBD_ZERO

#define BASE_FREQ 500


static uint8_t LocalDuty[MAX_NUM_CHANNELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0 };
static const uint32_t ChannelToPWM_MOD[MAX_NUM_CHANNELS] = {
PWM0_BASE, PWM0_BASE, PWM0_BASE, PWM0_BASE,
PWM0_BASE, PWM0_BASE, PWM0_BASE, PWM0_BASE,
PWM1_BASE, PWM1_BASE, PWM1_BASE, PWM1_BASE,
PWM1_BASE, PWM1_BASE, PWM1_BASE, PWM1_BASE
};
static const uint32_t ChannelToCTLOffset[MAX_NUM_CHANNELS >> 1] = {
PWM_O_0_CTL, PWM_O_1_CTL, PWM_O_2_CTL, PWM_O_3_CTL,
PWM_O_0_CTL, PWM_O_1_CTL, PWM_O_2_CTL, PWM_O_3_CTL
};
static const uint32_t ChannelToGENOffset[MAX_NUM_CHANNELS] = {
PWM_O_0_GENA, PWM_O_0_GENB, PWM_O_1_GENA, PWM_O_1_GENB,
PWM_O_2_GENA, PWM_O_2_GENB, PWM_O_3_GENA, PWM_O_3_GENB,
PWM_O_0_GENA, PWM_O_0_GENB, PWM_O_1_GENA, PWM_O_1_GENB,
PWM_O_2_GENA, PWM_O_2_GENB, PWM_O_3_GENA, PWM_O_3_GENB
};
static const uint32_t ChannelToLOADOffset[MAX_NUM_CHANNELS >> 1] = {
PWM_O_0_LOAD, PWM_O_1_LOAD, PWM_O_2_LOAD, PWM_O_3_LOAD,
PWM_O_0_LOAD, PWM_O_1_LOAD, PWM_O_2_LOAD, PWM_O_3_LOAD
};
static const uint32_t ChannelToCMPOffset[MAX_NUM_CHANNELS] = {
PWM_O_0_CMPA, PWM_O_0_CMPB, PWM_O_1_CMPA, PWM_O_1_CMPB,
PWM_O_2_CMPA, PWM_O_2_CMPB, PWM_O_3_CMPA, PWM_O_3_CMPB,
PWM_O_0_CMPA, PWM_O_0_CMPB, PWM_O_1_CMPA, PWM_O_1_CMPB,
PWM_O_2_CMPA, PWM_O_2_CMPB, PWM_O_3_CMPA, PWM_O_3_CMPB
};
static const uint32_t ChannelToGENConfig[MAX_NUM_CHANNELS] = {
GENA_NORMAL, GENB_NORMAL, GENA_NORMAL, GENB_NORMAL,
GENA_NORMAL, GENB_NORMAL, GENA_NORMAL, GENB_NORMAL,
GENA_NORMAL, GENB_NORMAL, GENA_NORMAL, GENB_NORMAL,
GENA_NORMAL, GENB_NORMAL, GENA_NORMAL, GENB_NORMAL
};
static const uint32_t ChannelToPORTOffset[MAX_NUM_CHANNELS] = {
GPIO_PORTB_BASE, GPIO_PORTB_BASE, GPIO_PORTB_BASE, GPIO_PORTB_BASE,
GPIO_PORTE_BASE, GPIO_PORTE_BASE, GPIO_PORTC_BASE, GPIO_PORTC_BASE,
GPIO_PORTD_BASE, GPIO_PORTD_BASE, GPIO_PORTA_BASE, GPIO_PORTA_BASE,
GPIO_PORTF_BASE, GPIO_PORTF_BASE, GPIO_PORTF_BASE, GPIO_PORTF_BASE
};
static const uint32_t ChanneltoPINOffset[MAX_NUM_CHANNELS] = { 6, 7, 4, 5, 4, 5, 4,
5, 0, 1, 6, 7, 0, 1, 2, 3 };

static uint8_t PWMDuty;

/*------------------------------ Module Code ------------------------------*/

// Performs all operations to initialize PWM0 signal


void My_PWM_Init(uint16_t Frequency)
{
// enable the clock to the PWM0 Module
HWREG(SYSCTL_RCGCPWM) |= SYSCTL_RCGCPWM_R0;

// enable the clock to port B (where this module outputs PWM)


HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R1;

// select PWM clock as system clock (why do I want to divide this?)


HWREG(SYSCTL_RCC) = (HWREG(SYSCTL_RCC) & ~SYSCTL_RCC_PWMDIV_M) |
(SYSCTL_RCC_USEPWMDIV | SYSCTL_RCC_PWMDIV_32);

// check to see if PWM module ready


while ((HWREG(SYSCTL_PRPWM) & SYSCTL_PRPWM_R0) != SYSCTL_PRPWM_R0)
{
;
}

// disable PWM while init


HWREG(PWM0_BASE + PWM_O_0_CTL) = 0;

// program 1 during rising and 0 during falling


HWREG(PWM0_BASE + PWM_O_0_GENA) = GENA_NORMAL;

// set the PWM period (1/2 the desired high time)


uint16_t PWMInterval = (uint16_t)((SysCtlClockGet() / PWM_DIV) / Frequency);

HWREG(PWM0_BASE + PWM_O_0_LOAD) = ((PWMInterval) >> 1);

// set the initial duty cycle to 0% (Period/2 - DesiredHighTime/2)


HWREG(PWM0_BASE + PWM_O_0_CMPA) = HWREG(PWM0_BASE + PWM_O_0_LOAD);

// enable the PWM output


HWREG(PWM0_BASE + PWM_O_ENABLE) = PWM_ENABLE_PWM0EN;

// configure Port B pin as output for PWM0


HWREG(GPIO_PORTB_BASE + GPIO_O_AFSEL) |= BIT6HI;

// now need to map PWM to PB6 alternate function MUX


HWREG(GPIO_PORTB_BASE + GPIO_O_PCTL) = (HWREG(GPIO_PORTB_BASE + GPIO_O_PCTL) &
0xf0ffffff) + (4 << (6 * BitsPerNibble));

// enable pin 6 on Port B for digital I/O


HWREG(GPIO_PORTB_BASE + GPIO_O_DEN) |= BIT6HI;

// make pin 6 digital output


HWREG(GPIO_PORTB_BASE + GPIO_O_DIR) |= BIT6HI;

// set the up/down count mode, enable the PWM generator, generator update locally
synchronized to zero
HWREG(PWM0_BASE + PWM_O_0_CTL) = (PWM_0_CTL_MODE | PWM_0_CTL_ENABLE |
PWM_0_CTL_GENAUPD_LS);
}

// Initialize up to 8 PWM channels on Module0 (1 module, 4 generators, 8 PWM lines)


void My_PWM_Init_Many(uint8_t HowMany)
{
static uint8_t i;

// enable the clock to the PWM0 Module


HWREG(SYSCTL_RCGCPWM) |= SYSCTL_RCGCPWM_R0;

// enable the minimal ports for the number of PWM lines needed
// always enable the clock to port B (channels 0-3)
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R1;
// enable port E if needed (channels 4,5)
if (HowMany > 4)
{
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R4;
}
// enable port C if needed (channels 6,7)
if (HowMany > 6)
{
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R2;
}

// select PWM clock as system clock with /32 divisor


HWREG(SYSCTL_RCC) = (HWREG(SYSCTL_RCC) & ~SYSCTL_RCC_PWMDIV_M) |
(SYSCTL_RCC_USEPWMDIV | SYSCTL_RCC_PWMDIV_32);
// check to see if PWM0 module ready
while ((HWREG(SYSCTL_PRPWM) & SYSCTL_PRPWM_R0) != SYSCTL_PRPWM_R0)
{
;
}

// set generator options (PWM0-3) in PWM0 module


// disable generators while configuring, set all generators to 500Hz initially
for (i = 0; i < HowMany; i += 2)
{
HWREG(PWM0_BASE + ChannelToCTLOffset[i >> 1]) = 0;
HWREG(PWM0_BASE + ChannelToLOADOffset[i >> 1]) = (SysCtlClockGet() / PWM_DIV /
BASE_FREQ) >> 1; //SYSCLK with 32 divisor for 500Hz frequency
}
// configure GenA or GenB for center-aligned up-down counting
for (i = 0; i < HowMany; i++)
{
HWREG(PWM0_BASE + ChannelToGENOffset[i]) = ChannelToGENConfig[i];
}

// set all duty cycles to 0% initially


for (i = 0; i < HowMany; i++)
{
My_PWM_SetDuty(50, i);
}

// enable the generator outputs


for (i = 0; i < HowMany; i++)
{
HWREG(PWM0_BASE + PWM_O_ENABLE) |= PWM_ENABLE_PWM0EN << i;
}

// configure pins for alternate function, mux in a value of 4 for PWM alt function,
enable as digital output
for (i = 0; i < HowMany; i++)
{
HWREG(ChannelToPORTOffset[i] + GPIO_O_AFSEL) |= GPIO_PIN_0 <<
ChanneltoPINOffset[i];
HWREG(ChannelToPORTOffset[i] + GPIO_O_PCTL) = (HWREG(ChannelToPORTOffset[i] +
GPIO_O_PCTL) & ~(0x0000000f << (BitsPerNibble * ChanneltoPINOffset[i]))) + (4 <<
(ChanneltoPINOffset[i] * BitsPerNibble)); //THIS IS PROBABLY WHAT'S WRONG
HWREG(ChannelToPORTOffset[i] + GPIO_O_DEN) |= GPIO_PIN_0 <<
ChanneltoPINOffset[i];
HWREG(ChannelToPORTOffset[i] + GPIO_O_DIR) |= GPIO_PIN_0 <<
ChanneltoPINOffset[i];
}

// enable the generator and update locally synchronized to zero


for (i = 0; i < HowMany; i += 2)
{
HWREG(PWM0_BASE + ChannelToCTLOffset[i >> 1]) = (PWM_0_CTL_MODE |
PWM_0_CTL_ENABLE | PWM_0_CTL_GENAUPD_LS);
}

printf("My_PWM_Init_Many successful\n\r");
}

//init PWM just for channel 10 (PA6) for reload IR out (M1,PWM1,GenA)
void My_PWM_Init_Channel10(void)
{
// channel 10 for PA6
uint8_t i = 10;

// enable the clock to the PWM1 Module


HWREG(SYSCTL_RCGCPWM) |= SYSCTL_RCGCPWM_R1;

// enable the clock to port A


HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R0;

// select PWM clock as system clock with /32 divisor


HWREG(SYSCTL_RCC) = (HWREG(SYSCTL_RCC) & ~SYSCTL_RCC_PWMDIV_M) |
(SYSCTL_RCC_USEPWMDIV | SYSCTL_RCC_PWMDIV_32);

// check to see if PWM1 module ready


while ((HWREG(SYSCTL_PRPWM) & SYSCTL_PRPWM_R1) != SYSCTL_PRPWM_R1)
{
;
}
// set generator options M1 in PWM1 module
// disable generators while configuring, set generator to 500Hz initially
HWREG(ChannelToPWM_MOD[i] + ChannelToCTLOffset[i >> 1]) = 0;
HWREG(ChannelToPWM_MOD[i] + ChannelToLOADOffset[i >> 1]) = (SysCtlClockGet() /
PWM_DIV / 500) >> 1; //SYSCLK with 32 divisor for 500Hz frequency

// configure GenA for center-aligned up-down counting


HWREG(ChannelToPWM_MOD[i] + ChannelToGENOffset[i]) = ChannelToGENConfig[i];

// set duty cycle to 0% initially


My_PWM_SetDuty(0, i);

// enable the generator outputs


HWREG(ChannelToPWM_MOD[i] + PWM_O_ENABLE) |= PWM_ENABLE_PWM0EN << (i - 8);

// configure pins for alternate function, mux in a value of 4 for PWM alt function,
enable as digital output
HWREG(ChannelToPORTOffset[i] + GPIO_O_AFSEL) |= GPIO_PIN_0 <<
ChanneltoPINOffset[i];
HWREG(ChannelToPORTOffset[i] + GPIO_O_PCTL) = (HWREG(ChannelToPORTOffset[i] +
GPIO_O_PCTL) & ~(0x0000000f << (BitsPerNibble * ChanneltoPINOffset[i]))) + (5 <<
(ChanneltoPINOffset[i] * BitsPerNibble)); //THIS IS PROBABLY WHAT'S WRONG
HWREG(ChannelToPORTOffset[i] + GPIO_O_DEN) |= GPIO_PIN_0 <<
ChanneltoPINOffset[i];
HWREG(ChannelToPORTOffset[i] + GPIO_O_DIR) |= GPIO_PIN_0 <<
ChanneltoPINOffset[i];

// enable the generator and update locally synchronized to zero


HWREG(ChannelToPWM_MOD[i] + ChannelToCTLOffset[i >> 1]) = (PWM_1_CTL_MODE |
PWM_1_CTL_ENABLE | PWM_1_CTL_GENAUPD_LS);

printf("My_PWM_Init_Channel10 successful\n\r");
}

//update the PWM frequency by group


void My_PWM_SetFreq(uint16_t Frequency, uint8_t Group)
{
uint16_t PWMInterval = (uint16_t)((SysCtlClockGet() / PWM_DIV) / Frequency);
if (Group < 4)
{
HWREG(PWM0_BASE + ChannelToLOADOffset[Group]) = (PWMInterval >> 1);
}
else
{
HWREG(PWM1_BASE + ChannelToLOADOffset[Group]) = (PWMInterval >> 1);
}

uint8_t ChannelA = Group * 2;


uint8_t ChannelB = Group * 2 + 1;
My_PWM_SetDuty( LocalDuty[ChannelA], ChannelA); // need to reset the CMPA value
My_PWM_SetDuty( LocalDuty[ChannelB], ChannelB); // need to reset the CMPB value
}

//update the PWM period by group (ONLY FOR SERVOS ON CHANNELS 2,3,4)
void My_PWM_SetPeriod(uint16_t Period, uint8_t Group)
{
HWREG(PWM0_BASE + ChannelToLOADOffset[Group]) = (Period >> 1);
}

//update the PWM pulse width by channel (ONLY FOR SERVOS ON CHANNELS 2,3,4)
void My_PWM_SetPulseWidth(uint16_t PulseWidth, uint8_t Channel)
{
uint32_t CurrentLoadValue = HWREG(PWM0_BASE + ChannelToLOADOffset[Channel >> 1]);
HWREG(PWM0_BASE + ChannelToCMPOffset[Channel]) = (CurrentLoadValue - (PulseWidth
>> 1));
}

// Set the duty cycle (0-100%) for a specific PWM channel (0-15)
void My_PWM_SetDuty(uint8_t DutyCycle, uint8_t Channel)
{
LocalDuty[Channel] = DutyCycle;
if (DutyCycle == 100)
{
My_Set_100DC(Channel);
}
else if (DutyCycle == 0)
{
My_Set_0DC(Channel);
}
else
{
My_RestoreDC(Channel);
if (Channel < 8)
{
HWREG(PWM0_BASE + ChannelToCMPOffset[Channel]) = 1 + HWREG(PWM0_BASE +
ChannelToLOADOffset[Channel >> 1]) * (100 - DutyCycle) / 100;
}
else
{
HWREG(PWM1_BASE + ChannelToCMPOffset[Channel]) = 1 + HWREG(PWM1_BASE +
ChannelToLOADOffset[Channel >> 1]) * (100 - DutyCycle) / 100;
}
}
}

// set to 100% duty


static void My_Set_100DC(uint8_t Channel)
{
if (Channel < 8)
{
HWREG(PWM0_BASE + ChannelToGENOffset[Channel]) = PWM_0_GENA_ACTZERO_ONE;
}
else
{
HWREG(PWM1_BASE + ChannelToGENOffset[Channel]) = PWM_1_GENA_ACTZERO_ONE;
}
}

// set to 0% duty
static void My_Set_0DC(uint8_t Channel)
{
if (Channel < 8)
{
HWREG(PWM0_BASE + ChannelToGENOffset[Channel]) = PWM_0_GENA_ACTZERO_ZERO;
}
else
{
HWREG(PWM1_BASE + ChannelToGENOffset[Channel]) = PWM_1_GENA_ACTZERO_ZERO;
}
}

// restore the normal actions


static void My_RestoreDC(uint8_t Channel)
{
if (Channel < 8)
{
HWREG(PWM0_BASE + ChannelToGENOffset[Channel]) = ChannelToGENConfig[Channel];
}
else
{
HWREG(PWM1_BASE + ChannelToGENOffset[Channel]) = ChannelToGENConfig[Channel];
}
}

You might also like