This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

PWM output with BeagleBone Black / set duty cycle

Genius 5820 points
Other Parts Discussed in Thread: SYSCONFIG

Hi,

I need to output some signals with varying pulse-pause-ratio. Setting up EHRPWM2B to output some frequency (and change this frequency) was no problem using the evmAM335x-example "ehrpwm_haptics". Some initialisation routines had to be copied to the BeagleBone Black Starterware code since they did not exist there, but the whole thing is working well now.

Now following questions come up:

- What has to be done to modify the pulse-pause-ratio? Currently the example is running at 50% duty cycle only.

- Which call is enabling the frequency output? I'm thinking about preparing the subsystem during initialisation phase and having only a few, fast calls left to start frequency output as soon as it is needed.

- And independent from the question regarding duty cycle: is it possible to output just one shot, means send exactly one pulse of defined length?

Thanks!

  • Hi,

    Please find the below explanation:

    - What has to be done to modify the pulse-pause-ratio? Currently the example is running at 50% duty cycle only.

    EHRPWM has the sub-module Action Qualifier(AQ), in which the action on the pwm output can be configured based on the events like time base counter equals to zero, equals to period, equals to counter comparator A value ...etc. By programming these events properly, the duty cycle can be varied.

    Please use the following StarterWare APIs to program AQ "EHRPWMConfigureAQActionOnB()" , "EHRPWMConfigureAQActionOnA()". Please refer the section 15.2.2.5 Action-Qualifer(AQ) Submodule of AM335x TRM to get better understanding of the above module.

    - Which call is enabling the frequency output? I'm thinking about preparing the subsystem during initialisation phase and having only a few, fast calls left to start frequency output as soon as it is needed.

    The following two APIs are needed to configure the time base clock and output frequency "EHRPWMTimebaseClkConfig()"     and   "EHRPWMPWMOpFreqSet()".

    - And independent from the question regarding duty cycle: is it possible to output just one shot, means send exactly one pulse of defined length?

    In pwm, software forced one time or continuous actions can be configured on the pwm output, to force the pwm output. These can be used to define the pwm output. Please refer the same ActionQualifier section to get the understanding of software forced events. Please refer the following StarterWare APIs to generate software forced events "EHRPWMSWForceA()", "EHRPWMSWForceB()", "EHRPWMAQContSWForceOnA()", "EHRPWMAQContSWForceOnB()".

    Thanks,

    M.Jyothi Kiran

     

  • What routines have to be copied to what Beaglebone Black code? to beaglebone.h? Please help me with this! Thank you!

  • This code is working fine for me:

    PWMSSModuleClkConfig(1);
    EHRPWMClockEnable(SOC_PWMSS1_REGS);
    PWMSSTBClkEnable(1);
    EHRPWMTimebaseClkConfig(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,SOC_EHRPWM_1_MODULE_FREQ);
    EHRPWMPWMOpFreqSet(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,
                       (unsigned int)(SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL)/1000, // 100 kHz -> this value specifies frequency
                       (unsigned int)EHRPWM_COUNT_UP,(bool)EHRPWM_SHADOW_WRITE_DISABLE);
    EHRPWMTimebaseSyncDisable(SOC_EPWM_1_REGS);
    EHRPWMSyncOutModeSet(SOC_EPWM_1_REGS, EHRPWM_SYNCOUT_DISABLE);
    EHRPWMTBEmulationModeSet(SOC_EPWM_1_REGS, EHRPWM_STOP_AFTER_NEXT_TB_INCREMENT);
    EHRPWMLoadCMPA(SOC_EPWM_1_REGS,
                   0, // counter value specifies pulse width -> set a value >0 here
                   (bool)EHRPWM_SHADOW_WRITE_DISABLE,(unsigned int)EHRPWM_COMPA_NO_LOAD,(bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    EHRPWMConfigureAQActionOnA(SOC_EPWM_1_REGS,
                               EHRPWM_AQCTLA_ZRO_EPWMXAHIGH,
                               EHRPWM_AQCTLA_PRD_DONOTHING,
                               EHRPWM_AQCTLA_CAU_EPWMXALOW,
                               EHRPWM_AQCTLA_CAD_DONOTHING,
                               EHRPWM_AQCTLA_CBU_DONOTHING,
                               EHRPWM_AQCTLA_CBD_DONOTHING,
                               EHRPWM_AQSFRC_ACTSFA_DONOTHING);
    EHRPWMDBOutput(SOC_EPWM_1_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);
    EHRPWMChopperDisable(SOC_EPWM_1_REGS);
    EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_ONESHOT);
    EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_CYCLEBYCYCLE);
    EHRPWMHRDisable(SOC_EPWM_1_REGS);
    

    This makes use of EHRPWM1A output. Please do not forget to set proper pin-muxing before!

  • Ok understood, but how can I set the pin mux to Beaglebone black in this case? I must use EPWM2PinMuxSetup() or GpioPinMuxSetup(GPIO_0_23,4). Thank you!

  • I'm using the code generated by TI's Pin-Mux-Tool. Alternatively you can check out some of the existing pinmux-examples, change the pin number and specify the correct mode, this should work too.

  • thx.  i'll give it a try...........don

  • hi again.  i got your code snippet to compile & link ok, after i borrowed the functions

    PWMSSModuleClkConfig(1);

    PWMSSTBClkEnable(1);

    from /ti/starterware.../platform/evmAM335x/pwmss.c  .  is that where you got them? 

    i just fried my bone, but i have 2 more coming.  i'm looking forward to testing this. 

    thanks, later............don

  • Could you please send your pinmux setup, because I'm trying and trying, but no success get some signal on the pin. Thanks!

  • For EHRPWM1A I'm using this:

    #define CONTROL_PADCONF_GPMC_A2                   0x0848
    
    #define AM335X_CTRL_BASE  0x44E10000
    
    #define MUX_VAL(OFFSET,VALUE)\
    	HWREG(AM335X_CTRL_BASE + (OFFSET))=VALUE;
    
    MUX_VAL(CONTROL_PADCONF_GPMC_A2, (IDIS | PD | MODE6 ));

    This is taken out of the code generated with TI's pin-mux-tool. Please note: you may change CONTROL_PADCONF_GPMC_A2 to the value that corresponds to the PWM-output you are using in your case.

  • Thank you so much!!! Works!!!

  • hi qxc. i am getting nothing from my pwm output pin.
    i realize you are driving at 100kHz.

    i am trying to drive a rc-servo (50 Hz, 50% duty cycle).

    please confirm a few parameters that you are using:

    SOC_EHRPWM_1_MODULE_FREQ ???

    CLOCK_DIV_VAL ???

    EHRPWM1A output:

    header pin: P9_14

    Mode 6

    addr 0x848

    ehrpwm1A_mux1

    IDIS 0<<5

    PD 0<<3

    MODE6 6

    the resultant TBPRD is 1000. no?

    i am using the pinmux setup you gave a few days ago.
    thanks for your help........don

  • Hi Don,

    SOC_EHRPWM_1_MODULE_FREQ and CLOCK_DIV_VAL use the values out of the EHRPWM-example that comes with starterware.

    May be you have a problem with the pulse width? When it is too big for the used frequency (or still 0 like in my example) you will never get a frequency at output.

    And I'd recommend to use an oscilloscope to check the output - just to avoid you still have a frequency but one that is way too high to cause any effect with your drive.

  • Hi again.  The example I am using is ehrpwm_haptics.c in

    ti\starterware...\examples\evmAM335x\ehrpwm_haptics  .  

    Is that correct?  There is no PWM example for the beaglebone.  

    The values there are:  

    SOC_EHRPWM_1_MODULE_FREQ  =  100MHz

    CLOCK_DIV_VAL = 10.  

    Your example posted in this forum has a frequency of 100kHz.  

    SYSCLKOUT = 1GHz

    1GHz = SOC_EHRPWM_1_MODULE_FREQ x CLOCK_DIV_VAL    ok that checks

    SOC_EHRPWM_1_MODULE_FREQ / 1000 = 100kHz    ok that checks

    Yet the servo does not move when I scale down the frequency to 50Hz.  

    I noticed that time base period TBPRD and time base counter TBCNT registers are both 16 bit.  

    Maybe at 50 Hz there is an overflow.  So I re-scaled TBPRD and TBCNT within 16 bits.  Still 

    no movement on the servo.

    I will need a scope to solve this.  Those TRM documenters and driver programmers really need

    to work together and use real-world nomenclature.  This simple task is not clear at all.  

    thx.......don

  • At moment I got a frequency of 1.250Mhz and is possible adjust the duty cycle that I want. To get this, you have to do simple calculations in this line "(unsigned int)(SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL)/1000" if whith this value 1000 I got 100khz  how much I have to put to get 1Mhz for example, and on duty is similar on the line "EHRPWMLoadCMPA(SOC_EPWM_1_REGS, 0,..." you adjust like you wish with the same calculation before cited. But a problem I realised is that with high frequencies you have to do some adjusts in this calculations to get what you want exactly.

  • Hi Rodrigo.  OK maybe my CMPA value is wrong.  

    In your example, what CMPA value will give a duty cycle of 50%?

    thanks...........don 

  • ok, i got a scope.  the ehrpwm1a works as expected in linux. 

    still, i get nothing on the pin running bare metal.  i will start over with the code you posted. 

    i must be mistaken with pinmux or initialization or something. 

    i am using ccsv5.5.  is that ok?

    thx..............don

  • Hi Rodrigo.  I cannot get a PWM signal from any pin at any frequency.  The oscilloscope works

    and I can get PWM signals from linux.  So I am missing something.   Can you please send me

    your code that works?   thanks alot.............don

  • #include "soc_AM335x.h"
    #include "interrupt.h"
    #include "hw_types.h"
    #include "ehrpwm.h"
    #include "beaglebone.h"
    #include "uartStdio.h"
    #include "pin_mux.h"
    
    
    #define CLOCK_DIV_VAL                 (10)
    #define SOC_EHRPWM_1_MODULE_FREQ      (100000000)
    
    /****************************************************************************/
    /*              LOCAL FUNCTION PROTOTYPES                                   */
    /****************************************************************************/
    static void EHRPWMConfigure(void);
    /****************************************************************************/
    /*             LOCAL FUNCTION DEFINITIONS                                   */
    /****************************************************************************/
    
    int main(void)
    {
    	PWMSSModuleClkConfig(1);
    
        //EPWM2PinMuxSetup();
        GpioPinMuxSetup(GPIO_1_18, 6);
    
        /* Enable Clock for EHRPWM in PWM sub system */
        EHRPWMClockEnable(SOC_PWMSS1_REGS);
    
        /* Enable Timer Base Module Clock in control module */
        PWMSSTBClkEnable(1);
    
        /* EHRPWM is configured to generate PWM waveform on EPWMBxB Pin*/
        EHRPWMConfigure();
    
        while(1);
    }
    
    static void EHRPWMConfigure(void)
    {
      
        /* TimeBase configuration */
        /* Configure the clock frequency */
    	EHRPWMTimebaseClkConfig(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,SOC_EHRPWM_1_MODULE_FREQ);
    
        /* Configure the period of the output waveform */
    	EHRPWMPWMOpFreqSet(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,
    	                   (unsigned int)(SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL)/7, // 100 kHz -> this value specifies frequency
    	                   (unsigned int)EHRPWM_COUNT_UP,(bool)EHRPWM_SHADOW_WRITE_DISABLE);
    
    
        /* Disable synchronization*/
    	EHRPWMTimebaseSyncDisable(SOC_EPWM_1_REGS);
    
        /* Disable syncout*/
    	EHRPWMSyncOutModeSet(SOC_EPWM_1_REGS, EHRPWM_SYNCOUT_DISABLE);
    
        /* Configure the emulation behaviour*/
    	EHRPWMTBEmulationModeSet(SOC_EPWM_1_REGS, EHRPWM_STOP_AFTER_NEXT_TB_INCREMENT);
    
        /* Configure Counter compare cub-module */
        /* Load Compare A value */
    
    	EHRPWMLoadCMPA(SOC_EPWM_1_REGS,
    	               2, // counter value specifies pulse width -> set a value >0 here
    	               (bool)EHRPWM_SHADOW_WRITE_DISABLE,(unsigned int)EHRPWM_COMPA_NO_LOAD,(bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    
        /* Load Compare B value */
        EHRPWMLoadCMPB(SOC_EPWM_1_REGS,
                       0,
                       (bool)EHRPWM_SHADOW_WRITE_DISABLE,
                       (unsigned int) EHRPWM_COMPB_NO_LOAD,
                       (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    
        /* Configure Action qualifier */
        /* Toggle when CTR = CMPA */
        EHRPWMConfigureAQActionOnA(SOC_EPWM_1_REGS,
                                   EHRPWM_AQCTLA_ZRO_EPWMXAHIGH,
                                   EHRPWM_AQCTLA_PRD_DONOTHING,
                                   EHRPWM_AQCTLA_CAU_EPWMXALOW,
                                   EHRPWM_AQCTLA_CAD_DONOTHING,
                                   EHRPWM_AQCTLA_CBU_DONOTHING,
                                   EHRPWM_AQCTLA_CBD_DONOTHING,
                                   EHRPWM_AQSFRC_ACTSFA_DONOTHING);
    
    
        /* Bypass dead band sub-module */
        EHRPWMDBOutput(SOC_EPWM_1_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);
    
        /* Disable Chopper sub-module */
        EHRPWMChopperDisable(SOC_EPWM_1_REGS);
        //EHRPWMConfigureChopperDuty(SOC_EPWM_1_REGS, EHRPWM_CHP_DUTY_87_5_PER);
    
        /* Disable trip events */
        EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_ONESHOT);
        EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_CYCLEBYCYCLE);
    
        /* Event trigger */
        /* Generate interrupt every 3rd occurance of the event */
        EHRPWMETIntPrescale(SOC_EPWM_1_REGS, EHRPWM_ETPS_INTPRD_THIRDEVENT);
        /* Generate event when CTR = CMPB */
        EHRPWMETIntSourceSelect(SOC_EPWM_1_REGS, EHRPWM_ETSEL_INTSEL_TBCTREQUCMPBINC);
    
        /* Disable High resolution capability */
        EHRPWMHRDisable(SOC_EPWM_1_REGS);
    
    }

    This code is working to me! Sorry the delay!

  • Hi Rodrigo.  thanks, i am working on your example.  The functions:

        PWMSSModuleClkConfig(1);
          PWMSSTBClkEnable(1);

     are not in the drivers build for the bbb.  

    How did you resolve their references?

    thx..........don

  • To fix this, you have to add the "../AM335X/binary/armv7a/cgt_ccs/am335x/evmAM335x/platform.lib" on file search path, because this function belong to this platform. CCS is very tiring to work, because you have to set every steps carefully again and again, project after project, if not, wont work. 

  • ok.  muchos gracias.  i never would have guessed it.  ccs is a big pain.  but i need it to get started.  then i will bypass it all.  i will be running circles around these guys in a year.  do you use jtag?  which one?  

    now i cannot debug.  the connection to xds100v2 is good, but programs do not load.  i think it is windows, other os functions are misbehaving.  

  • At moment I'm not debugging because here in Brazil this cable xds100v2 is too expensive and I have no money to buy. I just ask to my  college to buy this, but they did not answer me yet.

  • hi again rodrigo.  i finally got my xds100v2 working again. 

    it was the wifi driver on my laptop!?!  (1 week lost thanks to microsoft) 

    now, about adding the evmAM335x/platform.lib into my bbb build, i included the path:

    "C:\ti\AM335X_StarterWare_02_00_01_01\binary\armv7a\cgt_ccs\am335x\evmAM335x\platform\Debug\platform.lib"

    in the ARM Linker File Search Path.  the project builds and loads but does not run.  it seems there are other routines inserted into the build.  and i make no code changes whatsoever. 

    can you think of any ccs settings i am missing?   thanks.............don

  • Please send me the error screen log!

    I gave up of the CCS and now I'm working with Linux using the simpler MAKE ALL at the console after change something.

  • hi rodrigo.  there were no errors, it compiled & linked ok.  since then, i cheated and copied the needed routines from the library into my main program.  and voila, it worked!  the pwm puts out a 1.25 MHz pulse, 25% duty cycle.  

    i think i will give up on ccs also, it took me a month to get a pwm signal!  most of the time i was trying to figure out how to use the ccs.  is there a doc on how to build with make?  can you post your makefile when you get it going?  

    thanks............don

  • I don't know what problems you have with CCS. It is nothing more than an Eclipse-clone which itself uses plain Makefiles in background. So when you have troubles with CCS you will have them with the Makefiles too.

    Using Linux there are a few problems with the CCS-installation which will also occur when using the naked Makefiles (some directories write protected where libraries have to be built into, some tools named as ".exe" while they do not use these extensions under Linux). But once these things are solved it is working smoothly.

  • I'm using CCS on Windows! The problem with CCS is that every project have to be setup LIBS, PATHS, build steps and etc.

    This is too annoying!

    If have a way to define this easier or permanent, I'll be grateful.

    And no on Linux haven't to set every project the PATHS and etc, like on CCS. Do you have to set once, and done. 

  • Hi Don!!! I'm so happy to get help you!!! In my case I took about 6 months to see a PWM signal. But this is like that!
    About de "makefile", this is ready to use on ../AM335X/build/armv7a/gcc/am335x/beaglebone/ here have one makefile that will compile every examples and inside each example have a particular makefile.
    Read the AM335X manual and take a look the easy configs to do this work.

  • i'm with rodrigo on this.  ccs is way too cumbersome.  it took me a week to install it.  and i had to re-install it twice.  and i still do not know how i overcame the many little problems along the way to get gpioLEDblink working.  i could not probe it or make educated guesses or copy someone else's setup.  simply put, it is not intuitive.  i like the xds100 jtag debugger.  other than that, the fancy gui, i have no use for.  

    i will give you an example.  there is a starterware manifest i need to modify and i still cannot find it:  

    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH

    this is a starterware pwm thing, nothing to do with ccs.  but the application builds, so it must be somewhere.  why can't ccs tell me where f*&#! it is?  

    or i want to copy a ccs project, rename it and modify it?  ccs does not do this!  duh?  

    qxc, you must be experienced with ccs to the point where you thoroughly know your way around.  i cannot jeopardize the success of my job with a tool that i cannot rely upon.  in this ever-increasing complexity we need to rationalize and simplify.  i want to spend my time designing/debugging code.  not trying to get the s/w tools to work.  

    so, without the help of you guys on this forum, i would never have gotten this sorted out. thanks,

    happy hacking.....don

  • Don Lawrence said:

    i will give you an example.  there is a starterware manifest i need to modify and i still cannot find it:  

    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH

    this is a starterware pwm thing, nothing to do with ccs.  but the application builds, so it must be somewhere.  why can't ccs tell me where f*&#! it is?  

    Easy answer for this: you do not have the function to go to this define, because you use the free yersion. When you pay a lot of money to TI for the full version, you get back all the standard Eclipse-features that are locked in the freely downloadable CCS-variant.

  • hi qxc.   u get what u pay 4.   touche........don

  • Rodrigo:

    This is a question regarding the code that you have posted (above). I have the code working but I don't understand HOW to use, I guess. Really simply, what do I need to change in order to have the PWM output at 65%? And also, say 80%? Or what about 99%?? 

    Like I say, your code works for me but I'm completely "in-the-dark" as to what to change to get different percentages on the output. . 

    Thank you in advance!

    Dean

  • hi dean. i took rodrigo's code and got it working for an rc-servo (50 hz).
    i did not fully clean up the starterware obfuscation (yet), as i am busy
    hacking some other subsystems. here is the code (i hope it uploads).
    see #define PERIOD_VAL_50HZ. i did not clean up the SOC_EHRPWM_1_MODULE_FREQ & CLOCK_DIV_VAL pretzel logic
    in the call to function EHRPWMPWMOpFreqSet, which is definitely wrong.
    so you will need an oscilloscope to get another frequency... but
    the pulse width logic is clear. it moves the servo back & forth.
    happy hacking............dd

    /*
    * \file gpioLEDpwm.c
    *
    * \brief This application uses a GPIO pin to blink the LED (heartbeat)
    * and activate ehrpwm1A (pin P9_14)
    *
    * The GPIO pin GPIO1[23] is used as an output pin (a USER LED).
    *
    */
    #include "soc_AM335x.h"
    #include "beaglebone.h"
    #include "gpio_v2.h"
    #include "hw_control_AM335x.h" // pwm includes
    #include "ehrpwm.h"
    #include "evmAM335x.h"
    #include "hw_cm_per.h"
    #include "interrupt.h"
    #include "hw_types.h"
    #include "pin_mux.h" // end pwm includes
    /*****************************************************************************
    ** INTERNAL MACRO DEFINITIONS
    *****************************************************************************/
    #define GPIO_INSTANCE_ADDRESS (SOC_GPIO_1_REGS)
    #define GPIO_INSTANCE_PIN_NUMBER (23)
    #define CLOCK_DIV_VAL (256) // pwm
    #define SOC_EHRPWM_1_MODULE_FREQ (100000000) // pwm
    #define PERIOD_VAL_50HZ (8860) // pwm
    /*****************************************************************************
    ** EXTERNAL FUNCTION PROTOTYPES
    *****************************************************************************/
    void PWMSSTBClkEnable(unsigned int instance); // pwm
    void PWMSSModuleClkConfig(unsigned int instanceNum); // pwm
    /*****************************************************************************
    ** INTERNAL FUNCTION PROTOTYPES
    *****************************************************************************/
    static void Delay(unsigned int count);
    static void EHRPWMConfigure(void); // pwm
    /*
    ** The main function. Application starts here.
    */
    int main()
    {
    unsigned int i, direction;
    /* Enabling functional clocks for GPIO1 instance. */
    GPIO1ModuleClkConfig();
    /* Selecting GPIO1[23] pin for use. */
    GPIO1Pin23PinMuxSetup();
    /* Enabling the GPIO module. */
    GPIOModuleEnable(GPIO_INSTANCE_ADDRESS);
    /* Resetting the GPIO module. */
    GPIOModuleReset(GPIO_INSTANCE_ADDRESS);
    /* Setting the GPIO pin as an output pin. */
    GPIODirModeSet(GPIO_INSTANCE_ADDRESS,
    GPIO_INSTANCE_PIN_NUMBER,
    GPIO_DIR_OUTPUT);
    PWMSSModuleClkConfig(1); // pwm init stuff
    PWMSSModuleClkConfig(0); // pwm init stuff
    GpioPinMuxSetup(GPIO_1_18, 6); // pin P9_14 ehrpwm1A
    GpioPinMuxSetup(GPIO_1_19, 6); // pin P9_16 ehrpwm1B
    GpioPinMuxSetup(GPIO_3_14, 1); // pin P9_31 ehrpwm0A
    GpioPinMuxSetup(GPIO_3_15, 1); // pin P9_29 ehrpwm0B
    /* Enable Clock for EHRPWM in PWM sub system */
    EHRPWMClockEnable(SOC_PWMSS1_REGS);
    EHRPWMClockEnable(SOC_PWMSS0_REGS);
    /* Enable Timer Base Module Clock in control module */
    PWMSSTBClkEnable(1);
    PWMSSTBClkEnable(0);
    /* EHRPWM is configured to generate PWM waveform on EPWMBxB Pin*/
    EHRPWMConfigure(); // pwm init ends
    i = 14;
    direction = 1;
    while(1) {
    if(direction == 1) i++;
    if(direction == 0) i--;
    GPIOPinWrite(GPIO_INSTANCE_ADDRESS, GPIO_INSTANCE_PIN_NUMBER, GPIO_PIN_HIGH);
    Delay(0x2FFFF);
    GPIOPinWrite(GPIO_INSTANCE_ADDRESS, GPIO_INSTANCE_PIN_NUMBER, GPIO_PIN_LOW);
    Delay(0x3FFFF);
    GPIOPinWrite(GPIO_INSTANCE_ADDRESS, GPIO_INSTANCE_PIN_NUMBER, GPIO_PIN_HIGH);
    Delay(0x1FFFF);
    GPIOPinWrite(GPIO_INSTANCE_ADDRESS, GPIO_INSTANCE_PIN_NUMBER, GPIO_PIN_LOW);
    Delay(0xAFFFF);
    EHRPWMLoadCMPA(SOC_EPWM_1_REGS,
    PERIOD_VAL_50HZ/i, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPA_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    EHRPWMLoadCMPB(SOC_EPWM_1_REGS,
    PERIOD_VAL_50HZ/i, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPB_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    EHRPWMLoadCMPA(SOC_EPWM_0_REGS,
    PERIOD_VAL_50HZ/i, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPA_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    EHRPWMLoadCMPB(SOC_EPWM_0_REGS,
    PERIOD_VAL_50HZ/i, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPB_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    if(i <= 10) direction = 1;
    if(i >= 20) direction = 0;
    }
    }
    /*****************************************************************************
    ** INTERNAL FUNCTION DEFINITIONS
    *****************************************************************************/
    /*
    ** A gpio function which is used to generate a delay.
    */
    static void Delay(volatile unsigned int count)
    {
    while(count--);
    }

    static void EHRPWMConfigure(void) // ddl from rodrigo.c
    {
    unsigned int neutral_position = PERIOD_VAL_50HZ/15; // denominator 20 FULL LEFT - 15 NEUTRAL - 10 FULL RIGHT
    /* TimeBase configuration */
    /* Configure the clock frequency */
    EHRPWMTimebaseClkConfig(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,SOC_EHRPWM_1_MODULE_FREQ);
    EHRPWMTimebaseClkConfig(SOC_EPWM_0_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,SOC_EHRPWM_1_MODULE_FREQ);
    /* Configure the period of the output waveform */
    EHRPWMPWMOpFreqSet(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,
    (unsigned int)(SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL)/PERIOD_VAL_50HZ, // period specifies freq
    (unsigned int)EHRPWM_COUNT_UP,(bool)EHRPWM_SHADOW_WRITE_DISABLE);
    EHRPWMPWMOpFreqSet(SOC_EPWM_0_REGS,SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,
    (unsigned int)(SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL)/PERIOD_VAL_50HZ, // period specifies freq
    (unsigned int)EHRPWM_COUNT_UP,(bool)EHRPWM_SHADOW_WRITE_DISABLE);
    /* Disable synchronization*/
    EHRPWMTimebaseSyncDisable(SOC_EPWM_1_REGS);
    EHRPWMTimebaseSyncDisable(SOC_EPWM_0_REGS);
    /* Disable syncout*/
    EHRPWMSyncOutModeSet(SOC_EPWM_1_REGS, EHRPWM_SYNCOUT_DISABLE);
    EHRPWMSyncOutModeSet(SOC_EPWM_0_REGS, EHRPWM_SYNCOUT_DISABLE);
    /* Configure the emulation behaviour*/
    EHRPWMTBEmulationModeSet(SOC_EPWM_1_REGS, EHRPWM_STOP_AFTER_NEXT_TB_INCREMENT);
    EHRPWMTBEmulationModeSet(SOC_EPWM_0_REGS, EHRPWM_STOP_AFTER_NEXT_TB_INCREMENT);
    /* Configure Counter compare cub-module */
    /* Load Compare A value */
    EHRPWMLoadCMPA(SOC_EPWM_1_REGS,
    neutral_position, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPA_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    /* Load Compare B value */
    EHRPWMLoadCMPB(SOC_EPWM_1_REGS,
    neutral_position, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPB_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    /* Load Compare A value */
    EHRPWMLoadCMPA(SOC_EPWM_0_REGS,
    neutral_position, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPA_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    /* Load Compare B value */
    EHRPWMLoadCMPB(SOC_EPWM_0_REGS,
    neutral_position, // counter specifies pulse width
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int)EHRPWM_COMPB_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    /* Configure Action qualifier */
    /* Toggle when CTR = CMPA */
    EHRPWMConfigureAQActionOnA(SOC_EPWM_1_REGS,
    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH,
    EHRPWM_AQCTLA_PRD_DONOTHING,
    EHRPWM_AQCTLA_CAU_EPWMXALOW,
    EHRPWM_AQCTLA_CAD_DONOTHING,
    EHRPWM_AQCTLA_CBU_DONOTHING,
    EHRPWM_AQCTLA_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFA_DONOTHING);
    /* Toggle when CTR = CMPB */
    EHRPWMConfigureAQActionOnB(SOC_EPWM_1_REGS,
    EHRPWM_AQCTLB_ZRO_EPWMXBHIGH,
    EHRPWM_AQCTLB_PRD_DONOTHING,
    EHRPWM_AQCTLB_CAU_DONOTHING,
    EHRPWM_AQCTLB_CAD_DONOTHING,
    EHRPWM_AQCTLB_CBU_EPWMXBLOW,
    EHRPWM_AQCTLB_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFB_DONOTHING);
    /* Toggle when CTR = CMPA */
    EHRPWMConfigureAQActionOnA(SOC_EPWM_0_REGS,
    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH,
    EHRPWM_AQCTLA_PRD_DONOTHING,
    EHRPWM_AQCTLA_CAU_EPWMXALOW,
    EHRPWM_AQCTLA_CAD_DONOTHING,
    EHRPWM_AQCTLA_CBU_DONOTHING,
    EHRPWM_AQCTLA_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFA_DONOTHING);
    /* Toggle when CTR = CMPB */
    EHRPWMConfigureAQActionOnB(SOC_EPWM_0_REGS,
    EHRPWM_AQCTLB_ZRO_EPWMXBHIGH,
    EHRPWM_AQCTLB_PRD_DONOTHING,
    EHRPWM_AQCTLB_CAU_DONOTHING,
    EHRPWM_AQCTLB_CAD_DONOTHING,
    EHRPWM_AQCTLB_CBU_EPWMXBLOW,
    EHRPWM_AQCTLB_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFB_DONOTHING);
    /* Bypass dead band sub-module */
    EHRPWMDBOutput(SOC_EPWM_1_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);
    EHRPWMDBOutput(SOC_EPWM_0_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);
    /* Disable Chopper sub-module */
    EHRPWMChopperDisable(SOC_EPWM_1_REGS);
    EHRPWMChopperDisable(SOC_EPWM_0_REGS);
    /* Disable trip events */
    EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_ONESHOT);
    EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_CYCLEBYCYCLE);
    EHRPWMTZTripEventDisable(SOC_EPWM_0_REGS,(bool)EHRPWM_TZ_ONESHOT);
    EHRPWMTZTripEventDisable(SOC_EPWM_0_REGS,(bool)EHRPWM_TZ_CYCLEBYCYCLE);
    /* Disable High resolution capability */
    EHRPWMHRDisable(SOC_EPWM_1_REGS);
    EHRPWMHRDisable(SOC_EPWM_0_REGS);
    }

    /**
    * \brief This function Enables TBCLK(Time Base Clock) for specific
    * EPWM instance of pwmsubsystem.
    *
    * \param instance It is the instance number of EPWM of pwmsubsystem.
    *
    **/
    void PWMSSTBClkEnable(unsigned int instance) // ddl copied from pwmss.c
    {
    switch(instance)
    {

    case 0:
    HWREG(SOC_CONTROL_REGS + CONTROL_PWMSS_CTRL) |=
    CONTROL_PWMSS_CTRL_PWMSS0_TBCLKEN;
    break;

    case 1:
    HWREG(SOC_CONTROL_REGS + CONTROL_PWMSS_CTRL) |=
    CONTROL_PWMSS_CTRL_PWMMS1_TBCLKEN;
    break;

    case 2:
    HWREG(SOC_CONTROL_REGS + CONTROL_PWMSS_CTRL) |=
    CONTROL_PWMSS_CTRL_PWMSS2_TBCLKEN;
    break;

    default:
    break;
    }
    }

    /**
    * \brief This function configures the L3 and L4_PER system clocks.
    * It also configures the system clocks for the specified ePWMSS
    * instance.
    *
    * \param instanceNum The instance number of ePWMSS whose system clocks
    * have to be configured.
    *
    * 'instanceNum' can take one of the following values:
    * (0 <= instanceNum <= 2)
    *
    * \return None.
    *
    */
    void PWMSSModuleClkConfig(unsigned int instanceNum) // ddl copied from pwmss.c
    {
    HWREG(SOC_PRCM_REGS + CM_PER_L3S_CLKSTCTRL) |=
    CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_PRCM_REGS + CM_PER_L3S_CLKSTCTRL) &
    CM_PER_L3S_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKSTCTRL) |=
    CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKSTCTRL) &
    CM_PER_L3_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_PRCM_REGS + CM_PER_L3_INSTR_CLKCTRL) |=
    CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_PRCM_REGS + CM_PER_L3_INSTR_CLKCTRL) &
    CM_PER_L3_INSTR_CLKCTRL_MODULEMODE) !=
    CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE);

    HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKCTRL) |=
    CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKCTRL) &
    CM_PER_L3_CLKCTRL_MODULEMODE) != CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE);

    HWREG(SOC_PRCM_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) |=
    CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_PRCM_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
    CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL) !=
    CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKSTCTRL) |=
    CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP;

    while((HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKSTCTRL) &
    CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL) !=
    CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP);

    HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKCTRL) |=
    CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKCTRL) &
    CM_PER_L4LS_CLKCTRL_MODULEMODE) != CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE);

    if(0 == instanceNum)
    {
    HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS0_CLKCTRL) |=
    CM_PER_EPWMSS0_CLKCTRL_MODULEMODE_ENABLE;

    while(CM_PER_EPWMSS0_CLKCTRL_MODULEMODE_ENABLE !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS0_CLKCTRL) &
    CM_PER_EPWMSS0_CLKCTRL_MODULEMODE));

    while((CM_PER_EPWMSS0_CLKCTRL_IDLEST_FUNC <<
    CM_PER_EPWMSS0_CLKCTRL_IDLEST_SHIFT) !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS0_CLKCTRL) &
    CM_PER_EPWMSS0_CLKCTRL_IDLEST));

    }
    else if(1 == instanceNum)
    {
    HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS1_CLKCTRL) |=
    CM_PER_EPWMSS1_CLKCTRL_MODULEMODE_ENABLE;

    while(CM_PER_EPWMSS1_CLKCTRL_MODULEMODE_ENABLE !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS1_CLKCTRL) &
    CM_PER_EPWMSS1_CLKCTRL_MODULEMODE));

    while((CM_PER_EPWMSS1_CLKCTRL_IDLEST_FUNC <<
    CM_PER_EPWMSS1_CLKCTRL_IDLEST_SHIFT) !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS1_CLKCTRL) &
    CM_PER_EPWMSS1_CLKCTRL_IDLEST));

    }
    else if(2 == instanceNum)
    {
    HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS2_CLKCTRL) |=
    CM_PER_EPWMSS2_CLKCTRL_MODULEMODE_ENABLE;

    while(CM_PER_EPWMSS2_CLKCTRL_MODULEMODE_ENABLE !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS2_CLKCTRL) &
    CM_PER_EPWMSS2_CLKCTRL_MODULEMODE));

    while((CM_PER_EPWMSS2_CLKCTRL_IDLEST_FUNC <<
    CM_PER_EPWMSS2_CLKCTRL_IDLEST_SHIFT) !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS2_CLKCTRL) &
    CM_PER_EPWMSS2_CLKCTRL_IDLEST));
    }
    else
    {

    }

    while(!(HWREG(SOC_PRCM_REGS + CM_PER_L3S_CLKSTCTRL) &
    CM_PER_L3S_CLKSTCTRL_CLKACTIVITY_L3S_GCLK));

    while(!(HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKSTCTRL) &
    CM_PER_L3_CLKSTCTRL_CLKACTIVITY_L3_GCLK));

    while(!(HWREG(SOC_PRCM_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
    (CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L3_GCLK |
    CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK)));

    while(!(HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKSTCTRL) &
    (CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK )));

    }


    /******************************* End of file *********************************/
  • Don:

    Hey, thanks for giving me some pointers! I appreciate your help.

    Dean
  • no problem.  when you get your version working, post it for me. 

    it will save me time later................dd

  • Ok, here is what I'm using to control an LCD backlight with PWM output. It is "functional" for what I'm needing but that's about it. . . . :

    #include "soc_AM335x.h"
    #include "interrupt.h"
    #include "hw_types.h"
    #include "ehrpwm.h"
    #include "pin_mux.h"

    ///////////////////////////////////////
    // Declare Variables
    ///////////////////////////////////////
    int PWM_BRIGHTNESS = 4;
    #define PWM_CLOCK_DIV_VAL 10
    #define SOC_EHRPWM_1_MODULE_FREQ (100000000)

    extern void PWMSSModuleClkConfig(unsigned int instanceNum);
    extern void GpioPinMuxSetup(unsigned int offsetAddr, unsigned int padConfValue);
    extern void PWMSSTBClkEnable(unsigned int instance);

    ///////////////////////////////////////////////////////////////////////////////
    // FUNCTION: configBacklight()
    //
    // PARAMETERS:
    // None
    //
    // DESCRIPTION:
    // This is the function to initialize the PWM which controls the LCD
    // backlight.
    ///////////////////////////////////////////////////////////////////////////////
    void configBacklight(void)
    {
    /* setup PWM clock */
    PWMSSModuleClkConfig(1);

    /* PWM pin-muxing */
    GpioPinMuxSetup(GPIO_1_18, 6);

    /* Enable Clock for EHRPWM in PWM sub system */
    EHRPWMClockEnable(SOC_PWMSS1_REGS);

    /* Enable Timer Base Module Clock in control module */
    PWMSSTBClkEnable(1);

    /* TimeBase configuration */
    /* Configure the clock frequency */
    EHRPWMTimebaseClkConfig(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/PWM_CLOCK_DIV_VAL,SOC_EHRPWM_1_MODULE_FREQ);

    /* Configure the period of the output waveform */
    EHRPWMPWMOpFreqSet(SOC_EPWM_1_REGS,SOC_EHRPWM_1_MODULE_FREQ/PWM_CLOCK_DIV_VAL,
    (unsigned int)(SOC_EHRPWM_1_MODULE_FREQ/PWM_CLOCK_DIV_VAL)/7, // 100 kHz -> this value specifies frequency
    (unsigned int)EHRPWM_COUNT_UP,(bool)EHRPWM_SHADOW_WRITE_DISABLE);


    /* Disable synchronization*/
    EHRPWMTimebaseSyncDisable(SOC_EPWM_1_REGS);

    /* Disable syncout*/
    EHRPWMSyncOutModeSet(SOC_EPWM_1_REGS, EHRPWM_SYNCOUT_DISABLE);

    /* Configure the emulation behaviour*/
    EHRPWMTBEmulationModeSet(SOC_EPWM_1_REGS, EHRPWM_STOP_AFTER_NEXT_TB_INCREMENT);

    /* Configure Counter compare cub-module */
    /* Load Compare A value */

    EHRPWMLoadCMPA(SOC_EPWM_1_REGS,
    PWM_BRIGHTNESS, // counter value specifies pulse width -> set a value >0 here
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,(unsigned int)EHRPWM_COMPA_NO_LOAD,(bool)EHRPWM_CMPCTL_OVERWR_SH_FL);

    /* Load Compare B value */
    EHRPWMLoadCMPB(SOC_EPWM_1_REGS,
    0,
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,
    (unsigned int) EHRPWM_COMPB_NO_LOAD,
    (bool)EHRPWM_CMPCTL_OVERWR_SH_FL);

    /* Configure Action qualifier */
    /* Toggle when CTR = CMPA */
    EHRPWMConfigureAQActionOnA(SOC_EPWM_1_REGS,
    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH,
    EHRPWM_AQCTLA_PRD_DONOTHING,
    EHRPWM_AQCTLA_CAU_EPWMXALOW,
    EHRPWM_AQCTLA_CAD_DONOTHING,
    EHRPWM_AQCTLA_CBU_DONOTHING,
    EHRPWM_AQCTLA_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFA_DONOTHING);


    /* Bypass dead band sub-module */
    EHRPWMDBOutput(SOC_EPWM_1_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);

    /* Disable Chopper sub-module */
    EHRPWMChopperDisable(SOC_EPWM_1_REGS);

    /* Disable trip events */
    EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_ONESHOT);
    EHRPWMTZTripEventDisable(SOC_EPWM_1_REGS,(bool)EHRPWM_TZ_CYCLEBYCYCLE);

    /* Event trigger */
    /* Generate interrupt every 3rd occurance of the event */
    EHRPWMETIntPrescale(SOC_EPWM_1_REGS, EHRPWM_ETPS_INTPRD_THIRDEVENT);
    /* Generate event when CTR = CMPB */
    EHRPWMETIntSourceSelect(SOC_EPWM_1_REGS, EHRPWM_ETSEL_INTSEL_TBCTREQUCMPBINC);

    /* Disable High resolution capability */
    EHRPWMHRDisable(SOC_EPWM_1_REGS);
    }

    ///////////////////////////////////////////////////////////////////////////////
    // FUNCTION: setBacklight()
    //
    // PARAMETERS:
    // int newPWM
    //
    // DESCRIPTION:
    // This is the function sets the "value" (i.e

    // brightness) for the LCD backlight PWM.

    // 0 = off through 10 = full bright
    ///////////////////////////////////////////////////////////////////////////////

    void setBacklight(int newPWM)
    {
    /* setup PWM clock */
    PWM_BRIGHTNESS = newPWM;

    EHRPWMLoadCMPA(SOC_EPWM_1_REGS,
    PWM_BRIGHTNESS, // counter value specifies pulse width -> set a value >0 here
    (bool)EHRPWM_SHADOW_WRITE_DISABLE,(unsigned int)EHRPWM_COMPA_NO_LOAD,(bool)EHRPWM_CMPCTL_OVERWR_SH_FL);
    }

  • Hi again Dean. OK, I finally finished cleaning up the PWM bare metal driver for the Beaglebone Black.
    I did PWM output for ehrpwm0/1/2 channels A & B. So it will give you 6 programmable pwm channels
    at your desired period and duty cycle. It is about 500 lines and includes baremetal gpio & pinmux .
    Hackaway.............

    //
    // pwmx.c
    //
    // pwm test application - 50Hz varying duty cycle for RC-servo control
    // activate ehrpwm0A (pin P9_31), ehrpwm0B (pin P9_29),
    // ehrpwm1A (pin P9_14), ehrpwm1B (pin P9_16)
    // ehrpwm2A (pin P8_19), ehrpwm2B (pin P8_13)
    // also blinks LED USR2 - GPIO1[23]
    //
    #include "bbbpwm.h"
    //
    // local functions
    //
    void GPIOModuleEnab(unsigned int baseAdd) {
    if(baseAdd == SOC_GPIO_1_REGS) {
    // write to MODULEMODE field of CM_PER_GPIO1_CLKCTRL reg
    HWREG(SOC_CM_PER_REGS + CM_PER_GPIO1_CLKCTRL) |= CM_PER_GPIO1_CLKCTRL_MODULEMODE_ENABLE;
    // wait for MODULEMODE field to attain value
    while(CM_PER_GPIO1_CLKCTRL_MODULEMODE_ENABLE !=
    (HWREG(SOC_CM_PER_REGS + CM_PER_GPIO1_CLKCTRL) &
    CM_PER_GPIO1_CLKCTRL_MODULEMODE));
    // write to OPTFCLKEN_GPIO_1_GDBCLK bit in CM_PER_GPIO1_CLKCTRL
    HWREG(SOC_CM_PER_REGS + CM_PER_GPIO1_CLKCTRL) |=
    CM_PER_GPIO1_CLKCTRL_OPTFCLKEN_GPIO_1_GDBCLK;
    // wait for OPTFCLKEN_GPIO_1_GDBCLK bit to attain value
    while(CM_PER_GPIO1_CLKCTRL_OPTFCLKEN_GPIO_1_GDBCLK !=
    (HWREG(SOC_CM_PER_REGS + CM_PER_GPIO1_CLKCTRL) &
    CM_PER_GPIO1_CLKCTRL_OPTFCLKEN_GPIO_1_GDBCLK));
    // wait for IDLEST field in CM_PER_GPIO1_CLKCTRL register to attain value
    while((CM_PER_GPIO1_CLKCTRL_IDLEST_FUNC <<
    CM_PER_GPIO1_CLKCTRL_IDLEST_SHIFT) !=
    (HWREG(SOC_CM_PER_REGS + CM_PER_GPIO1_CLKCTRL) &
    CM_PER_GPIO1_CLKCTRL_IDLEST));
    // wait for CLKACTIVITY_GPIO_1_GDBCLK bit in CM_PER_L4LS_CLKSTCTRL reg to attain value
    while(CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_GPIO_1_GDBCLK !=
    (HWREG(SOC_CM_PER_REGS + CM_PER_L4LS_CLKSTCTRL) &
    CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_GPIO_1_GDBCLK));
    }
    // clear DISABLEMODULE bit in CTRL register (enab the module)
    HWREG(baseAdd + GPIO_CTRL) &= ~(GPIO_CTRL_DISABLEMODULE);
    // set SOFTRESET bit in System Configuration reg
    HWREG(baseAdd + GPIO_SYSCONFIG) |= (GPIO_SYSCONFIG_SOFTRESET);
    // wait until GPIO Module is reset
    while(!(HWREG(baseAdd + GPIO_SYSSTATUS) & GPIO_SYSSTATUS_RESETDONE));
    }
    void GPIODirectionSet(unsigned int baseAdd, unsigned int pinNo, unsigned int pinDir) {
    // check if pin is to be an output
    if(GPIO_DIR_OUTPUT == pinDir) {
    HWREG(baseAdd + GPIO_OE) &= ~(1 << pinNo);
    } else {
    HWREG(baseAdd + GPIO_OE) |= (1 << pinNo);
    }
    }
    void GPIOPinWrite(unsigned int baseAdd, unsigned int pinNo, unsigned int pinValue) {
    if(pinValue == 1) {
    HWREG(baseAdd + GPIO_SETDATAOUT) = (1 << pinNo);
    } else {
    HWREG(baseAdd + GPIO_CLEARDATAOUT) = (1 << pinNo);
    }
    }
    //
    // simple PinMux setup
    //
    // GPIOaddr - GPIO address from pin_mux.h (and Mode7 column of Header Table in BBB_SRM)
    // modeValue - select mode 0 to 7
    //
    void GPIOPinMuxSetup(unsigned int GPIOaddr, unsigned int modeValue) {
    HWREG(SOC_CONTROL_REGS + GPIOaddr) = (modeValue);
    }
    //
    // set clock divider of time-based clock
    //
    // see TBCTL register in TRM
    //
    // prescale - time-based clock prescale value
    // choose a value = 14 * X (X = 1,2,4,8...128)
    //
    void PWMTBClkDiv(unsigned int baseAddr, unsigned int prescale) {
    unsigned int clkDiv = prescale;
    unsigned int hspClkDiv;
    unsigned int lspClkDiv, lspClkDivSetting = 0;
    if(clkDiv > EHRPWM_TBCTL_HSPCLKDIV_14) { // 0xE
    hspClkDiv = EHRPWM_TBCTL_HSPCLKDIV_DIVBY14; // 0x7
    lspClkDiv = clkDiv/EHRPWM_TBCTL_HSPCLKDIV_14;
    while(lspClkDiv > 1) {
    lspClkDiv = lspClkDiv >> 1;
    lspClkDivSetting++;
    }
    } else {
    hspClkDiv = clkDiv/2;
    lspClkDivSetting = EHRPWM_TBCTL_HSPCLKDIV_DIVBY1; // divide by 1
    }
    HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
    (~EHRPWM_TBCTL_CLKDIV)) | ((lspClkDivSetting <<
    EHRPWM_TBCTL_CLKDIV_SHIFT) & EHRPWM_TBCTL_CLKDIV);
    HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
    (~EHRPWM_TBCTL_HSPCLKDIV)) | ((hspClkDiv <<
    EHRPWM_TBCTL_HSPCLKDIV_SHIFT) & EHRPWM_TBCTL_HSPCLKDIV);
    }
    //
    // set PWM output period (time-based clock period)
    //
    // see TBPRD register in TRM
    //
    // pwmPeriod - desired output pwm period in milliseconds
    // eg pwmPeriod = 20 will yield an output frequency of 50Hz
    //
    void PWMPeriodSet(unsigned int baseAddr, unsigned int pwmPeriod) {
    unsigned int tbPeriod = pwmPeriod*TICKS_PER_MS;
    unsigned int counterDir = EHRPWM_COUNT_UP;
    char enableShadowWrite = EHRPWM_SHADOW_WRITE_ENABLE;
    HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
    (~EHRPWM_PRD_LOAD_SHADOW_MASK)) | ((enableShadowWrite <<
    EHRPWM_TBCTL_PRDLD_SHIFT) & EHRPWM_PRD_LOAD_SHADOW_MASK);
    HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
    (~EHRPWM_COUNTER_MODE_MASK)) | ((counterDir <<
    EHRPWM_TBCTL_CTRMODE_SHIFT) & EHRPWM_COUNTER_MODE_MASK);
    if(EHRPWM_COUNT_UP_DOWN == counterDir) {
    HWREGH(baseAddr + EHRPWM_TBPRD) = (unsigned short)tbPeriod/2;
    } else {
    HWREGH(baseAddr + EHRPWM_TBPRD) = (unsigned short)tbPeriod;
    }
    }
    //
    // load counter compare register A
    //
    // CMPAVal must be less than TBPRD
    // see Counter-Compare Submodule in TRM
    //
    // this will hang the mpu if u try to load a
    // pwm module that has NOT been initialized
    //
    char PWMLoadCMPA(unsigned int baseAddr, unsigned int CMPAVal) {
    char enableShadowWrite = EHRPWM_SHADOW_WRITE_ENABLE;
    unsigned int ShadowToActiveLoadTrigger = EHRPWM_COMPA_LOAD_COUNT_EQUAL_ZERO_OR_PERIOD;
    char OverwriteShadowFull = EHRPWM_CMPCTL_OVERWR_SH_FL;
    char status = FALSE;
    if((OverwriteShadowFull) || ((HWREGH(baseAddr+EHRPWM_CMPCTL) & EHRPWM_CMPCTL_SHDWAFULL)
    == EHRPWM_SHADOW_A_EMPTY)) {
    HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL) &
    (~EHRPWM_CMPCTL_SHDWAMODE)) | ((enableShadowWrite <<
    EHRPWM_CMPCTL_SHDWAMODE_SHIFT) & EHRPWM_CMPCTL_SHDWAMODE);
    HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL) &
    (~EHRPWM_COMPA_LOAD_MASK)) |((ShadowToActiveLoadTrigger <<
    EHRPWM_CMPCTL_LOADAMODE_SHIFT) & EHRPWM_COMPA_LOAD_MASK);
    HWREGH(baseAddr + EHRPWM_CMPA) = CMPAVal & EHRPWM_CMPA_CMPA;
    status = TRUE;
    }
    return status;
    }
    //
    // load counter compare register B
    //
    // CMPBVal must be less than TBPRD
    // see Counter-Compare Submodule in TRM
    //
    char PWMLoadCMPB(unsigned int baseAddr, unsigned int CMPBVal) {
    char enableShadowWrite = EHRPWM_SHADOW_WRITE_ENABLE;
    unsigned int ShadowToActiveLoadTrigger = EHRPWM_COMPB_LOAD_COUNT_EQUAL_ZERO_OR_PERIOD;
    char OverwriteShadowFull = EHRPWM_CMPCTL_OVERWR_SH_FL;
    char status = FALSE;
    if((OverwriteShadowFull) || ((HWREGH(baseAddr+EHRPWM_CMPCTL) & EHRPWM_CMPCTL_SHDWBFULL)
    == EHRPWM_SHADOW_B_EMPTY)) {
    HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL) &
    (~EHRPWM_CMPCTL_SHDWBMODE)) | ((enableShadowWrite <<
    EHRPWM_CMPCTL_SHDWBMODE_SHIFT) & EHRPWM_CMPCTL_SHDWBMODE);
    HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL) &
    (~EHRPWM_COMPB_LOAD_MASK)) |((ShadowToActiveLoadTrigger <<
    EHRPWM_CMPCTL_LOADBMODE_SHIFT) & EHRPWM_COMPB_LOAD_MASK);
    HWREGH(baseAddr + EHRPWM_CMPB) = CMPBVal & EHRPWM_CMPB_CMPB;
    status = TRUE;
    }
    return status;
    }
    void PWMconfigAQActionOnA(unsigned int baseAddr,
    unsigned int zero,
    unsigned int period,
    unsigned int CAUp,
    unsigned int CADown,
    unsigned int CBUp,
    unsigned int CBDown,
    unsigned int SWForced) {
    HWREGH(baseAddr + EHRPWM_AQCTLA) =
    ((CBDown << EHRPWM_AQCTLA_CBD_SHIFT) & EHRPWM_AQCTLA_CBD) |
    ((CBUp << EHRPWM_AQCTLA_CBU_SHIFT) & EHRPWM_AQCTLA_CBU) |
    ((CADown << EHRPWM_AQCTLA_CAD_SHIFT) & EHRPWM_AQCTLA_CAD) |
    ((CAUp << EHRPWM_AQCTLA_CAU_SHIFT) & EHRPWM_AQCTLA_CAU) |
    ((period << EHRPWM_AQCTLA_PRD_SHIFT) & EHRPWM_AQCTLA_PRD) |
    ((zero << EHRPWM_AQCTLA_ZRO_SHIFT) & EHRPWM_AQCTLA_ZRO);
    HWREGH(baseAddr + EHRPWM_AQSFRC) = (HWREGH(baseAddr + EHRPWM_AQSFRC) &
    (~EHRPWM_AQSFRC_ACTSFA)) | ((SWForced <<
    EHRPWM_AQSFRC_ACTSFA_SHIFT) & EHRPWM_AQSFRC_ACTSFA);
    }
    void PWMconfigAQActionOnB(unsigned int baseAddr,
    unsigned int zero,
    unsigned int period,
    unsigned int CAUp,
    unsigned int CADown,
    unsigned int CBUp,
    unsigned int CBDown,
    unsigned int SWForced) {
    HWREGH(baseAddr + EHRPWM_AQCTLB) =
    ((CBDown << EHRPWM_AQCTLB_CBD_SHIFT) & EHRPWM_AQCTLB_CBD) |
    ((CBUp << EHRPWM_AQCTLB_CBU_SHIFT) & EHRPWM_AQCTLB_CBU) |
    ((CADown << EHRPWM_AQCTLB_CAD_SHIFT) & EHRPWM_AQCTLB_CAD) |
    ((CAUp << EHRPWM_AQCTLB_CAU_SHIFT) & EHRPWM_AQCTLB_CAU) |
    ((period << EHRPWM_AQCTLB_PRD_SHIFT) & EHRPWM_AQCTLB_PRD) |
    ((zero << EHRPWM_AQCTLB_ZRO_SHIFT) & EHRPWM_AQCTLB_ZRO);
    HWREGH(baseAddr + EHRPWM_AQSFRC) =
    (HWREGH(baseAddr + EHRPWM_AQSFRC) & (~EHRPWM_AQSFRC_ACTSFB)) |
    ((SWForced << EHRPWM_AQSFRC_ACTSFB_SHIFT) & EHRPWM_AQSFRC_ACTSFB);
    }
    //
    // heavily hacked config code from rodrigo in brazil
    //
    // pwmx: bit1-pwm0, bit2-pwm1, bit3-pwm2 (0-disable or 1-enable PWM module X)
    // pwmPeriod: period of pwm output in msec
    //
    void PWMconfig(unsigned int pwmx, unsigned int pwmPeriod) {
    // config L3_PER and L4_PER clocks
    HWREG(SOC_PRCM_REGS + CM_PER_L3S_CLKSTCTRL) |= CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP;
    while((HWREG(SOC_PRCM_REGS + CM_PER_L3S_CLKSTCTRL) &
    CM_PER_L3S_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3S_CLKSTCTRL_CLKTRCTRL_SW_WKUP);
    HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKSTCTRL) |= CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;
    while((HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKSTCTRL) &
    CM_PER_L3_CLKSTCTRL_CLKTRCTRL) != CM_PER_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);
    HWREG(SOC_PRCM_REGS + CM_PER_L3_INSTR_CLKCTRL) |=
    CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE;
    while((HWREG(SOC_PRCM_REGS + CM_PER_L3_INSTR_CLKCTRL) &
    CM_PER_L3_INSTR_CLKCTRL_MODULEMODE) != CM_PER_L3_INSTR_CLKCTRL_MODULEMODE_ENABLE);
    HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKCTRL) |= CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE;
    while((HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKCTRL) &
    CM_PER_L3_CLKCTRL_MODULEMODE) != CM_PER_L3_CLKCTRL_MODULEMODE_ENABLE);
    HWREG(SOC_PRCM_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) |=
    CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP;
    while((HWREG(SOC_PRCM_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
    CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL) != CM_PER_OCPWP_L3_CLKSTCTRL_CLKTRCTRL_SW_WKUP);
    HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKSTCTRL) |= CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP;
    while((HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKSTCTRL) &
    CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL) != CM_PER_L4LS_CLKSTCTRL_CLKTRCTRL_SW_WKUP);
    HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKCTRL) |= CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE;
    while((HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKCTRL) &
    CM_PER_L4LS_CLKCTRL_MODULEMODE) != CM_PER_L4LS_CLKCTRL_MODULEMODE_ENABLE);
    if(pwmx & 0x1) { // config EPWMSS0 clock
    HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS0_CLKCTRL) |=
    CM_PER_EPWMSS0_CLKCTRL_MODULEMODE_ENABLE;
    while(CM_PER_EPWMSS0_CLKCTRL_MODULEMODE_ENABLE !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS0_CLKCTRL) & CM_PER_EPWMSS0_CLKCTRL_MODULEMODE));
    while((CM_PER_EPWMSS0_CLKCTRL_IDLEST_FUNC << CM_PER_EPWMSS0_CLKCTRL_IDLEST_SHIFT) !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS0_CLKCTRL) & CM_PER_EPWMSS0_CLKCTRL_IDLEST));
    }
    if(pwmx & 0x2) { // config EPWMSS1 clock
    HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS1_CLKCTRL) |=
    CM_PER_EPWMSS1_CLKCTRL_MODULEMODE_ENABLE;
    while(CM_PER_EPWMSS1_CLKCTRL_MODULEMODE_ENABLE !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS1_CLKCTRL) & CM_PER_EPWMSS1_CLKCTRL_MODULEMODE));
    while((CM_PER_EPWMSS1_CLKCTRL_IDLEST_FUNC << CM_PER_EPWMSS1_CLKCTRL_IDLEST_SHIFT) !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS1_CLKCTRL) & CM_PER_EPWMSS1_CLKCTRL_IDLEST));
    }
    if(pwmx & 0x4) { // config EPWMSS2 clock
    HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS2_CLKCTRL) |=
    CM_PER_EPWMSS2_CLKCTRL_MODULEMODE_ENABLE;
    while(CM_PER_EPWMSS2_CLKCTRL_MODULEMODE_ENABLE !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS2_CLKCTRL) & CM_PER_EPWMSS2_CLKCTRL_MODULEMODE));
    while((CM_PER_EPWMSS2_CLKCTRL_IDLEST_FUNC << CM_PER_EPWMSS2_CLKCTRL_IDLEST_SHIFT) !=
    (HWREG(SOC_PRCM_REGS + CM_PER_EPWMSS2_CLKCTRL) & CM_PER_EPWMSS2_CLKCTRL_IDLEST));
    }
    // wait on L3 & L4 clock activity
    while(!(HWREG(SOC_PRCM_REGS + CM_PER_L3S_CLKSTCTRL) &
    CM_PER_L3S_CLKSTCTRL_CLKACTIVITY_L3S_GCLK));
    while(!(HWREG(SOC_PRCM_REGS + CM_PER_L3_CLKSTCTRL) &
    CM_PER_L3_CLKSTCTRL_CLKACTIVITY_L3_GCLK));
    while(!(HWREG(SOC_PRCM_REGS + CM_PER_OCPWP_L3_CLKSTCTRL) &
    (CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L3_GCLK |
    CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK)));
    while(!(HWREG(SOC_PRCM_REGS + CM_PER_L4LS_CLKSTCTRL) &
    (CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK )));
    if(pwmx & 0x1) { // PWM0
    HWREG(SOC_PWMSS0_REGS + PWMSS_CLOCK_CONFIG) |= PWMSS_EHRPWM_CLK_EN_ACK; // enable PWMSSx clocks
    HWREG(SOC_CONTROL_REGS + CONTROL_PWMSS_CTRL) |= CONTROL_PWMSS_CTRL_PWMSS0_TBCLKEN; // enable Timer Base Module Clock in Control Module
    PWMTBClkDiv(SOC_EPWM_0_REGS, PWM_PRESCALE); // config time-base clock
    PWMPeriodSet(SOC_EPWM_0_REGS, pwmPeriod); // config PWM period
    PWMconfigAQActionOnA(SOC_EPWM_0_REGS, // config Action Qualifiers for PWM0A
    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH, // high when CTR = 0
    EHRPWM_AQCTLA_PRD_DONOTHING,
    EHRPWM_AQCTLA_CAU_EPWMXALOW, // low when CTR = CMPA
    EHRPWM_AQCTLA_CAD_DONOTHING,
    EHRPWM_AQCTLA_CBU_DONOTHING,
    EHRPWM_AQCTLA_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFA_DONOTHING);
    PWMconfigAQActionOnB(SOC_EPWM_0_REGS, // PWM0B
    EHRPWM_AQCTLB_ZRO_EPWMXBHIGH, // high when CTR = 0
    EHRPWM_AQCTLB_PRD_DONOTHING,
    EHRPWM_AQCTLB_CAU_DONOTHING,
    EHRPWM_AQCTLB_CAD_DONOTHING,
    EHRPWM_AQCTLB_CBU_EPWMXBLOW, // low when CTR = CMPB
    EHRPWM_AQCTLB_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFB_DONOTHING);
    }
    if(pwmx & 0x2) { // PWM1
    HWREG(SOC_PWMSS1_REGS + PWMSS_CLOCK_CONFIG) |= PWMSS_EHRPWM_CLK_EN_ACK;
    HWREG(SOC_CONTROL_REGS + CONTROL_PWMSS_CTRL) |= CONTROL_PWMSS_CTRL_PWMSS1_TBCLKEN;
    PWMTBClkDiv(SOC_EPWM_1_REGS, PWM_PRESCALE);
    PWMPeriodSet(SOC_EPWM_1_REGS, pwmPeriod);
    PWMconfigAQActionOnA(SOC_EPWM_1_REGS, // PWM1A
    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH, // high when CTR = 0
    EHRPWM_AQCTLA_PRD_DONOTHING,
    EHRPWM_AQCTLA_CAU_EPWMXALOW, // low when CTR = CMPA
    EHRPWM_AQCTLA_CAD_DONOTHING,
    EHRPWM_AQCTLA_CBU_DONOTHING,
    EHRPWM_AQCTLA_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFA_DONOTHING);
    PWMconfigAQActionOnB(SOC_EPWM_1_REGS, // PWM1B
    EHRPWM_AQCTLB_ZRO_EPWMXBHIGH, // high when CTR = 0
    EHRPWM_AQCTLB_PRD_DONOTHING,
    EHRPWM_AQCTLB_CAU_DONOTHING,
    EHRPWM_AQCTLB_CAD_DONOTHING,
    EHRPWM_AQCTLB_CBU_EPWMXBLOW, // low when CTR = CMPB
    EHRPWM_AQCTLB_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFB_DONOTHING);
    }
    if(pwmx & 0x4) { // PWM2
    HWREG(SOC_PWMSS2_REGS + PWMSS_CLOCK_CONFIG) |= PWMSS_EHRPWM_CLK_EN_ACK;
    HWREG(SOC_CONTROL_REGS + CONTROL_PWMSS_CTRL) |= CONTROL_PWMSS_CTRL_PWMSS2_TBCLKEN;
    PWMTBClkDiv(SOC_EPWM_2_REGS, PWM_PRESCALE);
    PWMPeriodSet(SOC_EPWM_2_REGS, pwmPeriod);
    PWMconfigAQActionOnA(SOC_EPWM_2_REGS, // PWM2A
    EHRPWM_AQCTLA_ZRO_EPWMXAHIGH, // high when CTR = 0
    EHRPWM_AQCTLA_PRD_DONOTHING,
    EHRPWM_AQCTLA_CAU_EPWMXALOW, // low when CTR = CMPA
    EHRPWM_AQCTLA_CAD_DONOTHING,
    EHRPWM_AQCTLA_CBU_DONOTHING,
    EHRPWM_AQCTLA_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFA_DONOTHING);
    PWMconfigAQActionOnB(SOC_EPWM_2_REGS, // PWM2B
    EHRPWM_AQCTLB_ZRO_EPWMXBHIGH, // high when CTR = 0
    EHRPWM_AQCTLB_PRD_DONOTHING,
    EHRPWM_AQCTLB_CAU_DONOTHING,
    EHRPWM_AQCTLB_CAD_DONOTHING,
    EHRPWM_AQCTLB_CBU_EPWMXBLOW, // low when CTR = CMPB
    EHRPWM_AQCTLB_CBD_DONOTHING,
    EHRPWM_AQSFRC_ACTSFB_DONOTHING);
    }
    return;
    }
    //
    // spin your wheels
    //
    void Delay(volatile unsigned int count) {
    while(count--);
    }
    //
    // main program
    //
    // move a RC-servo back and forth and watch das-blinken-light!
    //
    void main() {
    unsigned int i, delta, base, direction, tbprd;
    GPIOModuleEnab(GPIO_ADDR); // enable GPIO module
    GPIODirectionSet(GPIO_ADDR, LED_USR2, GPIO_DIR_OUTPUT); // set GPIO pin as output
    GPIOPinMuxSetup(GPIO_1_23, 7); // muxout LED USR2
    GPIOPinMuxSetup(GPIO_0_22, 4); // pin P8_19 ehrpwm2A
    GPIOPinMuxSetup(GPIO_0_23, 4); // pin P8_13 ehrpwm2B
    GPIOPinMuxSetup(GPIO_1_18, 6); // pin P9_14 ehrpwm1A
    GPIOPinMuxSetup(GPIO_1_19, 6); // pin P9_16 ehrpwm1B
    GPIOPinMuxSetup(GPIO_3_14, 1); // pin P9_31 ehrpwm0A
    GPIOPinMuxSetup(GPIO_3_15, 1); // pin P9_29 ehrpwm0B
    PWMconfig(0x7, PWM_PERIOD_MS); // config PWM 0, 1, 2
    base = (TICKS_PER_MS * PWM_PERIOD_MS)/20; // 1ms base pulse width - RC Servo
    delta = base/10; // .1ms pulse width increment
    i = 4;
    direction = 1;
    while(1) {
    if(direction == 1) i++;
    if(direction == 0) i--;
    tbprd = base + (delta * i);
    PWMLoadCMPA(SOC_EPWM_0_REGS, tbprd);
    PWMLoadCMPB(SOC_EPWM_0_REGS, tbprd);
    PWMLoadCMPA(SOC_EPWM_1_REGS, tbprd);
    PWMLoadCMPB(SOC_EPWM_1_REGS, tbprd);
    PWMLoadCMPA(SOC_EPWM_2_REGS, tbprd);
    PWMLoadCMPB(SOC_EPWM_2_REGS, tbprd);
    if(i <= 0) direction = 1;
    if(i >= 10) direction = 0;
    GPIOPinWrite(GPIO_ADDR, LED_USR2, 1);
    Delay(0x2FFFF);
    GPIOPinWrite(GPIO_ADDR, LED_USR2, 0);
    Delay(0x3FFFF);
    GPIOPinWrite(GPIO_ADDR, LED_USR2, 1);
    Delay(0x1FFFF);
    GPIOPinWrite(GPIO_ADDR, LED_USR2, 0);
    Delay(0xAFFFF);
    }
    }

    and the header file bbbpwm.h :

    //
    // bbbpwm.h - pwm library header file
    //
    //#include "soc_AM335x.h"
    #define SOC_GPIO_1_REGS (0x4804C000)
    #define SOC_PWMSS0_REGS (0x48300000)
    #define SOC_PWMSS1_REGS (0x48302000)
    #define SOC_PWMSS2_REGS (0x48304000)
    #define SOC_EPWM_REGS (0x00000200)
    #define SOC_EPWM_0_REGS (SOC_PWMSS0_REGS + SOC_EPWM_REGS)
    #define SOC_EPWM_1_REGS (SOC_PWMSS1_REGS + SOC_EPWM_REGS)
    #define SOC_EPWM_2_REGS (SOC_PWMSS2_REGS + SOC_EPWM_REGS)
    #define SOC_ECAP_REGS (0x00000100) // ecap0 not
    #define SOC_ECAP_0_REGS (SOC_PWMSS0_REGS + SOC_ECAP_REGS) // implemented
    #define SOC_CONTROL_REGS (0x44E10000)
    #define SOC_PRCM_REGS (0x44E00000)
    #define SOC_CM_PER_REGS (SOC_PRCM_REGS + 0)

    //#include "beaglebone.h"
    //#include "gpio_v2.h"
    #define GPIO_DIR_OUTPUT (GPIO_OE_OUTPUTEN_ENABLED)
    #define GPIO_OE_OUTPUTEN_ENABLED (0x0u)
    #define GPIO_CTRL (0x130)
    #define GPIO_CTRL_DISABLEMODULE (0x00000001u)
    #define GPIO_SYSCONFIG (0x10)
    #define GPIO_SYSCONFIG_SOFTRESET (0x00000002u)
    #define GPIO_SYSSTATUS (0x114)
    #define GPIO_SYSSTATUS_RESETDONE (0x00000001u)
    #define GPIO_OE (0x134)
    #define GPIO_CLEARDATAOUT (0x190)
    #define GPIO_SETDATAOUT (0x194)

    //#include "hw_control_AM335x.h"
    #define CONTROL_PWMSS_CTRL (0x664)
    #define CONTROL_PWMSS_CTRL_PWMSS0_TBCLKEN (0x00000001u)
    #define CONTROL_PWMSS_CTRL_PWMSS1_TBCLKEN (0x00000002u)
    #define CONTROL_PWMSS_CTRL_PWMSS2_TBCLKEN (0x00000004u)

    #include "ehrpwm.h" // do not remove, too many defines needed here

    //#include "hw_pwmss.h"
    #define PWMSS_CLOCK_CONFIG 0x08
    #define PWMSS_EHRPWM_CLK_EN_ACK 0x100

    //#include "evmAM335x.h"

    #include "hw_cm_per.h" // do not remove, too many defines needed here

    //#include "interrupt.h"

    //#include "hw_types.h"
    #define HWREG(x) (*((volatile unsigned int *)(x)))
    #define HWREGH(x) (*((volatile unsigned short *)(x)))
    #define TRUE 1
    #define FALSE 0

    //#include "pin_mux.h"
    #define GPIO_0_22 (0x0820)
    #define GPIO_0_23 (0x0824)
    #define GPIO_1_18 (0x0848)
    #define GPIO_1_19 (0x084c)
    #define GPIO_3_14 (0x0990)
    #define GPIO_3_15 (0x0994)
    #define GPIO_1_23 (0x085c) // spoof LED USR2
    //
    // internal macros
    //
    #define GPIO_ADDR SOC_GPIO_1_REGS // for LED USR2
    #define LED_USR2 23 // LED USR2
    #define SOC_EHRPWM_1_MODULE_FREQ 100000000 // SYSCLKOUT [10 ns/tick]
    #define PWM_PRESCALE 224 // pwm clk divider - TBCLK
    #define TICKS_PER_MS 446 // ticks per msec pwm output period
    #define PWM_PERIOD_MS 20 // desired pwm output period in ms
    // PWM_PRESCALE of 224 = 14 * X (X = 1, 2, 4...128), see TBCTL Register
    // TICKS_PER_MS * PWM_PERIOD_MS = period of pwm output in ticks = TBPRD (only 16 bits)
    // FINITO

    Also, use this command file, from one of the starterware examples.
    I wasted alot of time with flakey-intermittently failing images that weren't linked/built properly.
    None of this is documented for noobs. Copy it into your pwm workspace dir.

    /****************************************************************************/
    /* LNK32.CMD - v4.5.0 COMMAND FILE FOR LINKING TMS470 32BIS C/C++ PROGRAMS */
    /* */
    /* Usage: lnk470 <obj files...> -o <out file> -m <map file> lnk32.cmd */
    /* cl470 <src files...> -z -o <out file> -m <map file> lnk32.cmd */
    /* */
    /* Description: This file is a sample command file that can be used */
    /* for linking programs built with the TMS470 C/C++ */
    /* Compiler. Use it as a guideline; you may want to change */
    /* the allocation scheme according to the size of your */
    /* program and the memory layout of your target system. */
    /* */
    /* Notes: (1) You must specify the directory in which run-time support */
    /* library is located. Either add a "-i<directory>" line to */
    /* this file, or use the system environment variable C_DIR */
    /* to specify a search path for libraries. */
    /* */
    /* (2) If the run-time support library you are using is not */
    /* named below, be sure to use the correct name here. */
    /* */
    /****************************************************************************/
    -stack 0x0008 /* SOFTWARE STACK SIZE */
    -heap 0x2000 /* HEAP AREA SIZE */
    -e Entry
    /* Since we used 'Entry' as the entry-point symbol the compiler issues a */
    /* warning (#10063-D: entry-point symbol other than "_c_int00" specified: */
    /* "Entry"). The CCS Version (5.1.0.08000) stops building from command */
    /* line when there is a warning. So this warning is suppressed with the */
    /* below flag. */

    --diag_suppress=10063

    /* SPECIFY THE SYSTEM MEMORY MAP */

    MEMORY
    {
    DDR_MEM : org = 0x80000000 len = 0x7FFFFFF /* RAM */
    }

    /* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY */

    SECTIONS
    {
    .text:Entry : load > 0x80000000

    .text : load > DDR_MEM /* CODE */
    .data : load > DDR_MEM /* INITIALIZED GLOBAL AND STATIC VARIABLES */
    .bss : load > DDR_MEM /* UNINITIALIZED OR ZERO INITIALIZED */
    /* GLOBAL & STATIC VARIABLES */
    RUN_START(bss_start)
    RUN_END(bss_end)
    .const : load > DDR_MEM /* GLOBAL CONSTANTS */
    .stack : load > 0x87FFFFF0 /* SOFTWARE SYSTEM STACK */
    }

    It all looks very large, but this is all self-contained, no hidden functions.
    In CCS/Properties/ARM Linker/File Search Path add only 1 library I could not suss-out:
    C:\ti\AM335X_StarterWare_02_00_01_01\binary\armv7a\cgt_ccs\am335x\system_config\Debug\system.lib
    You can easily code-in the manifests and eliminate some of the HAL functions to reduce size.

    I encourage others in the bare-metal community to break-out the other subsystems on the bone.
    We can all benefit and build bullet-proof lightning-fast applications.
    The Sitara documentation looks good, but it is a tough cookie.
    I will post UART and MMC/SDcard soon.

    hack-on my brothers!!!!!!!!!!!!!!! dd
  • > I encourage others in the bare-metal community to break-out the other subsystems on the bone.
    > We can all benefit and build bullet-proof lightning-fast applications.
    > The Sitara documentation looks good, but it is a tough cookie.

    I wonder it it worth to set up an own GitHub project to further develop StarterWare (which seems to be forgotten by TI). I found some interesting code here:

    groups.google.com/forum

    It contains code for full PRU-initialisation and -usage which isn't documentend anywhere else in this way.
  • Hi qxc. Good to see you are still here. Yeah, do a github and I'll put my stuff in it.
    We really need to disseminate drivers that everyone can use.
    I spent 8 months slogging thru CCS6 and starterware without actually doing application-side programming.
    I would gladly spare other noobs the punishment I went thru to get the drivers to do a minimal control system.
    One would think TI would write noob-usable drivers before they released their hardware.
    The Linux HAL drivers must exist, but where are they?
    I really need bare metal i2c also.
    Is PRU really worth it? I am not a big proponent of parallel-computing.
    hack-on............dd
  • Hi Don,

    as usual it higly depends on your application - but the two PRU units are a cool feature when you have some devices which can be controlled from them. You get two additional, mainly independent cores which can help you to save a lot of computing power in main core.

  • Hi again. I decided to stick it all in github. See ddlawrence/noobware.

    later.............dd
  • Hi Rodrigo

    I am having trouble with the PWM starterware example on the beaglebone black. I have copied your code above and I have linked the evmAM335x platform library correctly but it does not work. I am using the XDS100v2 debugger and I monitoring the TBCNT register of ePWM1. The value never changes, which indicates that the counter isn't running, therefore no PWM :(.

    Is there something I am missing that is required to get your code working (other than linking the libraries and setting up function prototypes in the beaglebone.h header file)? I'm using t CCS 6.1.0.00104 and StarterWare_02_00_01_01.

    Thanks in advance!
  • Hi Roland.  I am not Rodrigo, but I eventually got his PWM example to work.  

    I suggest you take the code I posted earlier on this thread, follow the instructions within,

    starting from a new empty CCS project.  

    later......................dd

  • Thank you for the reply Don.

    I have since got it working by changing from the ti compiler to the gcc compiler. Did you get it to work with the ti compiler?
  • yes i used the ti compiler in ccs6.  

    however i failed to get it going with gcc.

    how did u do it?  is there a doc?  did u use ccs?

    thx............dd

  • I struggled with the TI compiler on windows. So I switched to Ubuntu and used the gcc compiler. So it may have been something on windows that was causing the problem.

    I copied and pasted the "cpld.c" file and the "pwmss.c" into the beaglebone "platform" folder. I then built the gcc version of the platform library again for the beaglebone with make. I then copied the appropriate function prototypes into the "beaglebone.h" header. Then I started a new ccs6 gcc project for the beaglebone, linked the libraries (drivers, platform, etc.), added the headers and copied and pasted the code from the evmAM355x pwm example into the new "main.c" (changing the headers to the correct ones for beaglebone and changing the pin mux function to GpioPinMuxSetup(GPIO_0_23, 4)). It worked first time.
  • Yeah I had a heck of a time with windows, tcc, ccs.  But it works acceptably now, until it hiccups again ;). Fixing the problems taught me many lessons of dubious value.  Do you know if GCC will work on windows?

    I would go with linux, but I don't have a spare machine.  Life goes on.  Thanks for the tips..........dd

  • Don:

    Yes, the GCC-Arm compiler tool-chain will work under Windows. I use it all the time.

    I downloaded the tool-chain called: "gcc-arm-none-eabi-4_7-2012q4-20121208-win32.exe" (there maybe later ones available by now) and installed it.

    Sincerely,

    Dean