More PDL Examples - Pulse-Width Modulators | Cypress Semiconductor
More PDL Examples - Pulse-Width Modulators
Last week I showed an example of using the PDL UART driver in a PSoC 6 application. Today I am going to show you a PWM and do more compare-and-contrast with the PDL-based code versus the generated API you might be used to with PSoC 4.
My project is going to use a PWM to blink an LED - because that has never been done before!!! If you have ever used PSoC Creator to make a design, you'll recognize what is going on here.
The schematic looks just like it would for PSoC 4. I have a fairly slow (1kHz) clock feeding the PWM and a pair of pins connected to the inverting ("pwm_n") and non-inverting ("pwm") outputs. I chose recognizable names for the components because it will help me describe the API usage better. I also routed the two pins to P1.5 and P13.7 on the Pioneer kit because, step back in amazement folks, those are the physical pins that connect to LED8 and LED9.
Inside the PWM customizer I chose a period of 1000 for a 1Hz blink rate (OK, the PWM counter is actually zero-based so it is a 0.999Hz rate, but who wants to do the math?). I set the compare value to 100 so the pins will blink either mostly-on or mostly-off.
When I build this design PSoC Creator pulls in the PDL driver and generates some configuration code (BlinkyPWM.*) to make it easy to use.
So, to write the firmware I have a couple of options. For the PWM component the authors include a thin "shim" that makes the PWM look identical to the PSoC 4 API. So the following code turns on the PWM and the pin blink away like troopers.
Now that is great, the whole application is almost indistinguishable from a PSoC 4 version. It is easy to write and it works perfectly. But this is a very simple application and that shim layer does not provide "instance-based API" for every PWM function. Eventually we are going to need to call the PDL directly. Let's start by replacing the _Start().
To do this you can look in two places - the PDL documentation or the generated code we are replacing! The PDL tells you how to write firmware that refers directly to the hardware. Here is the snippet of code it suggests you use to turn on a PWM.
/* Scenario: there is need to initialize
* the first (index = 0) PWM of the TCPWM0 block
* with the previously defined configuration settings
#define MY_TCPWM_PWM_NUM (0UL)
#define MY_TCPWM_PWM_MASK (1UL << MY_TCPWM_PWM_NUM)
if (CY_TCPWM_SUCCESS != Cy_TCPWM_PWM_Init(TCPWM0, MY_TCPWM_PWM_NUM, &config))
/* Handle possible errors */
/* Enable the initialized PWM */
/* Then start the PWM */
This example sets up counter 0 in block TCPWM0. Note that the documentation also tells you how to define the "config" struct in firmware. From here I can figure out that I need to call the following functions.
That all seems pretty easy but with PSoC Creator it is even easier because it generates macros for all the arguments - so I do not need to figure out which physical TCPWM block is used. Instead of "TCPWM0" I can just use "BlinkyPWM_HW". For "MY_TCPWM_PWM_NUM" I use "BlinkyPWM_CNT_NUM". I do not have to write the configuration struct because "BlinkyPWM_config" is created for me from the choices I made in the customizer dialog. And, finally, the trigger mask is "BlinkyPWM_CNT_MASK". Here is the code, which turns on the PWM just like the _Start() function.
Cy_TCPWM_PWM_Init( BlinkyPWM_HW, BlinkyPWM_CNT_NUM, &BlinkyPWM_config );
Cy_TCPWM_PWM_Enable( BlinkyPWM_HW, BlinkyPWM_CNT_NUM );
Cy_TCPWM_TriggerStart( BlinkyPWM_HW, BlinkyPWM_CNT_MASK );
OK, that's simple enough but there is a way to cheat! I like that plan! Take a look in the generated BlinkyPWM.c file and find the _Start() function itself. It looks like this.
if (0U == BlinkyPWM_initVar)
(void) Cy_TCPWM_PWM_Init(BlinkyPWM_HW, BlinkyPWM_CNT_NUM, &BlinkyPWM_config);
BlinkyPWM_initVar = 1U;
#if (BlinkyPWM_INPUT_DISABLED == 7UL)
#endif /* (BlinkyPWM_INPUT_DISABLED == 7UL) */
Surprise, surprise! It's basically identical code. This is really useful because, even if your development flow is to use PSoC Creator only to draw the schematic and do all your firmware in another IDE, you still get a lot of generated reference code which will work perfectly in your application.
With PDL (and the generated shim layer) we are just adding to your available choices for firmware development. Using PDL is not really any harder than before, plus it saves a lot of code bloat and is easier to use with revision control systems (the drivers do not generated with the design). Next week I'll add some more examples... closing out the PWM application with an interrupt component and an ISR handler.