This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Generating Pulses

Hello, I am trying to generate pulses with the nRF52832 chip.I created a basic setup for test purposes; I simply connected a LED to the PWM output, but even though I put 0 into the sequence duty cycle values my LED still light up. My code is below. I'd appreciate any help.

Regards.

Note: Since Keil is not updating nRF SDK on its servers I probably am using outdated things. Also, I'm using s210 softdevice

#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_gpiote.h"
#include "nrf_pwm.h"
#include "nrf_esb.h"
#include "nrf_error.h"
#include "nrf.h"
#include "nrf_drv_pwm.h"
int main(void)
{

nrf_pwm_values_common_t seq_values[1] = {0};

//nrf_pwm_sequence_t const seq =
//{
//    .values.p_common = seq_values,
//    .length          = NRF_PWM_VALUES_LENGTH(seq_values),
//    .repeats         = 0,
//    .end_delay       = 0
//};

uint32_t out_pins[4]={16,NRF_PWM_PIN_NOT_CONNECTED,NRF_PWM_PIN_NOT_CONNECTED,NRF_PWM_PIN_NOT_CONNECTED};
nrf_pwm_enable(NRF_PWM0);
nrf_pwm_pins_set(NRF_PWM0,out_pins);
nrf_pwm_configure(NRF_PWM0,NRF_PWM_CLK_1MHz,NRF_PWM_MODE_UP,64000);	
//nrf_pwm_sequence_set(NRF_PWM0,0,&seq);
nrf_pwm_seq_ptr_set(NRF_PWM0,0,seq_values);
nrf_pwm_seq_cnt_set(NRF_PWM0,0,NRF_PWM_VALUES_LENGTH(seq_values));
nrf_pwm_seq_refresh_set(NRF_PWM0,0,0);
nrf_pwm_seq_end_delay_set(NRF_PWM0,0,0);
nrf_pwm_loop_set(NRF_PWM0,200);
nrf_pwm_decoder_set(NRF_PWM0,NRF_PWM_LOAD_COMMON,NRF_PWM_STEP_AUTO);
    nrf_pwm_event_clear(NRF_PWM0, NRF_PWM_EVENT_LOOPSDONE);
    nrf_pwm_event_clear(NRF_PWM0, NRF_PWM_EVENT_SEQEND0);
    nrf_pwm_event_clear(NRF_PWM0, NRF_PWM_EVENT_SEQEND1);
    nrf_pwm_event_clear(NRF_PWM0, NRF_PWM_EVENT_STOPPED);
nrf_pwm_task_trigger(NRF_PWM0,NRF_PWM_TASK_SEQSTART0);
    while (1)
    {		

//			nrf_gpio_cfg(16,NRF_GPIO_PIN_DIR_OUTPUT,NRF_GPIO_PIN_INPUT_DISCONNECT,NRF_GPIO_PIN_NOPULL,NRF_GPIO_PIN_S0S1,NRF_GPIO_PIN_NOSENSE);
//			nrf_gpio_pin_toggle(16);
//			nrf_delay_ms(500);
				
				//if(nrf_pwm_event_check(NRF_PWM0,NRF_PWM_EVENT_SEQEND0))nrf_pwm_task_trigger(NRF_PWM0,NRF_PWM_TASK_SEQSTART0);
				
				
			

		}
}
Parents
  • Hi,

    I will strongly recommend to use the nrf_drv_pwm functions, and not use the PWM HAL(Hardware access layer) functions directly. Note that you are overflowing the COUNTERTOP register by using the value 64000. Max value is 32767.

    Also note that with the sequence duty cycle values the most significant bit[15] denotes the polarity. So if you want seq_value 0 to correspond to 0 V, you need to set bit 15 to 1. E.g. by using bitwise OR.

    seq_values->channel_0 = duty_cycle | 0x8000;
    

    Code example that shows how to set a duty cycle between 0 and 100 % that uses 10kHz PWM:

    #include <stdio.h>
    #include <string.h>
    #include "nrf_drv_pwm.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    #include "bsp.h"
    #include "nrf_drv_clock.h"
    #include "nrf_delay.h"
    
    
    #define OUTPUT_PIN 16
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    // Declare variables holding PWM sequence values. In this example only one channel is used 
    nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    
    // Set duty cycle between 0 and 100%
    void pwm_update_duty_cycle(uint8_t duty_cycle)
    {
    
        // Check if value is outside of range. If so, set to 0%
        if(duty_cycle >= 100)
        {
            seq_values->channel_0 = 0;
        }
        else
        {
            
            seq_values->channel_0 = duty_cycle | 0x8000; // Change polarity 
        }
       
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN, // channel 0
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 100,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    
    }
    
    
    int main(void)
    {
    
        // Start clock for accurate frequencies
        NRF_CLOCK->TASKS_HFCLKSTART = 1; 
        // Wait for clock to start
        while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
    
        pwm_init();
        pwm_update_duty_cycle(40);
    
        for (;;)
        {
    
        }
    }
    
    
    /** @} */
    
Reply
  • Hi,

    I will strongly recommend to use the nrf_drv_pwm functions, and not use the PWM HAL(Hardware access layer) functions directly. Note that you are overflowing the COUNTERTOP register by using the value 64000. Max value is 32767.

    Also note that with the sequence duty cycle values the most significant bit[15] denotes the polarity. So if you want seq_value 0 to correspond to 0 V, you need to set bit 15 to 1. E.g. by using bitwise OR.

    seq_values->channel_0 = duty_cycle | 0x8000;
    

    Code example that shows how to set a duty cycle between 0 and 100 % that uses 10kHz PWM:

    #include <stdio.h>
    #include <string.h>
    #include "nrf_drv_pwm.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    #include "bsp.h"
    #include "nrf_drv_clock.h"
    #include "nrf_delay.h"
    
    
    #define OUTPUT_PIN 16
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    
    // Declare variables holding PWM sequence values. In this example only one channel is used 
    nrf_pwm_values_individual_t seq_values[] = {0, 0, 0, 0};
    nrf_pwm_sequence_t const seq =
    {
        .values.p_individual = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };
    
    
    // Set duty cycle between 0 and 100%
    void pwm_update_duty_cycle(uint8_t duty_cycle)
    {
    
        // Check if value is outside of range. If so, set to 0%
        if(duty_cycle >= 100)
        {
            seq_values->channel_0 = 0;
        }
        else
        {
            
            seq_values->channel_0 = duty_cycle | 0x8000; // Change polarity 
        }
       
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
    }
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                OUTPUT_PIN, // channel 0
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
                NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 100,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        // Init PWM without error handler
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    
    }
    
    
    int main(void)
    {
    
        // Start clock for accurate frequencies
        NRF_CLOCK->TASKS_HFCLKSTART = 1; 
        // Wait for clock to start
        while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
    
        pwm_init();
        pwm_update_duty_cycle(40);
    
        for (;;)
        {
    
        }
    }
    
    
    /** @} */
    
Children
  • I feel sorry to ask this but I did not understand the 'polarity' concept. What exactly is it?

  • The PWM module implements a counter that is counting up to the countertop value you set. In my example code the PWM module is counting up to the value 100. I have set the flag NRF_DRV_PWM_FLAG_LOOP, so it will restart the counting when it comes to 100 and start over from 0.

    While the PWM module is counting on it’s way to 100, it will reach the number set by the sequence value. This can in my example be minimum 0 and max 100. When this value is reached, the PWM output signal will be toggled/reversed. Let’s say that the sequence value is set to 60, and that the PWM started with a low signal(0 volt). It will then switch to output a high signal(e.g. 3V) when it reach 60, and be high(3V) until it reaches 100(countertop value).

    The bit[15] in seq_value determines if we start with the signal high or low(if we should have a rising or falling edge when we reach the seq_value). If you set the bit[15] to 0, the signal starts low, and goes high when you reach the seq_value. If you set the bit[15] to 1, the signal starts high and goes low.

    More information can be found here.

Related