Dialog DA14531 - PWM

Pulse Width Modulation(PWM) is the method of creating analog signals by modifying the time a digital signal is high or low. A frequency is decided for the digital signal and in each time frame, the duration of the time when the signal is high (on time) and low (off time) is changed to recreate various properties of an analog signal.

On the DA14531, TIMER0 and TIMER2 can generate PWM signals. TIMER0 has 2 PWM output channels and TIMER2 has 6 output pins. The output channels can be mapped to any pin. TIMER2 is dedicatedly used for generating PWM signals.

The two output channels of PWM0, are PWM0 and PWM1. PWM1 is an inverted version of PWM0 i.e. when PWM0 is high, PWM 1 is low and vice versa.

The important registers used are TIMER0_CTRL_REG, TIMER0_RELOAD_M_REG, TIMER0_RELOAD_N_REG, and TIMER0_ON_REG.

TIMER0_CTRL_REG is used to select the clock, decide on the operation mode of Timer0, enable the timer and configure the prescaler.

TIMER0_RELOAD_M_REG sets the number of cycles for which the signal is high.

TIMER0_RELOAD_N_REG sets the number of cycles for which the signal is low.

TIMER0_ON_REG decides the period at which SWTIM interrupt will be triggered.

Project setup

The project with the code for this tutorial is available on Github at https://github.com/vicara-hq/da14531-tutorials

Download the project and copy it. The project has to be placed inside the Dialog SDK6 folder. Navigate to <SDK6_ROOT>/projects/target_apps/template and paste it in this folder. The project is a modified version of the empty_peripheral_template project provided by Dialog. But to keep this tutorial series as open source as possible, all the following steps will use the SmartSnippets Studio.

Hardware overview

We will use a DA145xx Pro motherboard with a DA14531 Tiny modules daughterboard. Ensure that the URX and UTX pins on J1 has jumpers which connect it to their respective adjacent pins. This allow us to receive and send the UART data over USB.

Code Overview

The aim of this tutorial is to use PWM to decrease the brightness of the LED on the DA14531 daughterboard.

First step is to configure the pin connected to the LED in the user_periph_setup.c file.

void GPIO_reservations(void)
{
   RESERVE_GPIO(LED, GPIO_PORT_0, GPIO_PIN_9, PID_PWM0);
}void set_pad_functions(void)
{
   GPIO_ConfigurePin(GPIO_PORT_0, GPIO_PIN_9, OUTPUT, PID_PWM0, true);
}

The LED is connected to P0.09. We configure pin 9 to output the PWM0 signal.

uint16_t on_cycles = 0;
uint16_t off_cycles = 100;void pwm_init();static tim0_2_clk_div_config_t clk_div_config =
{
   .clk_div  = TIM0_2_CLK_DIV_8
};void timer_update()
{
   on_cycles += 2;
   off_cycles -= 2;

   if(on_cycles == 102)
   {
       on_cycles = 0;
       off_cycles = 100;
   }
   timer0_set_pwm_high_counter(on_cycles);
   timer0_set_pwm_low_counter(off_cycles);
}void pwm_init()
{
   timer0_stop();
   timer0_register_callback(NULL);
   timer0_2_clk_enable();
   timer0_2_clk_div_set(&clk_div_config);
   //Clock input frequency is 16 Mhz / (8 * 10) = 200 khz
   timer0_init(TIM0_CLK_FAST, PWM_MODE_ONE, TIM0_CLK_DIV_BY_10);    //SWTIM interrupt is triggered every 20000 * (200 khz) = 100 ms
   timer0_set(20000, on_cycles, off_cycles);
   timer0_register_callback(timer_update);    timer0_enable_irq();
   timer0_start();
}

The clk_div_config structure configures the prescaler of the clock signal sent to the TIMER0 module. We set it at 8, so the input signal to TIMER0 is divided by 8.

In pwm_init, TIMER0 is initialized, the input clock is set to the fast clock i.e. 16 MHz and the input clock signal prescaler is set to 10. So the clock frequency at TIMER0 is

16 MHz (fast clock) / 8 -> 2 MHz / 10 -> 200 KHz

The timer0_set set the time period for triggering the timer interrupt and the initial values for the TIMER0_RELOAD_M_REG and TIMER0_RELOAD_N_REG.

Each time the interrupt is triggered, the on duration is slowly increased and the off duration is reduced. This is done in the timer_update function.

The timer is configured and started in the custom app_on_init callback. For more details about the custom callback, take a look at my tutorial on GPIOs, buttons and LEDs.

void user_app_on_init()
{
   pwm_init();
   default_app_on_init();
}

Testing

Build the project and program it onto the DA14531 devkit. You will notice that the brightness of the LED slowly increases till it reaches the peak values. Once it hits the peak, the high duration and low duration values are reset i.e. the LED will be off and the cycle repeats.