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

PWM finish flag

If I use PWM "nrf_drv_pwm_simple_playback" and that will go to "start_playback"

How can I catch end point after it finish entire function?

BTW, the process will keep about 10 sec

Thank you!

    static nrf_pwm_values_individual_t seq0_values[]={
		...
	};

	nrf_pwm_sequence_t const seq0 = {
		.values.p_individual = seq0_values,
		.length = NRF_PWM_VALUES_LENGTH(seq0_values),
		.repeats = 300,
		.end_delay = 0
	};

    nrf_drv_pwm_simple_playback(&m_pwm0, &seq0, 1, NRF_DRV_PWM_EVT_FINISHED);

edit

Frøysa Sir,

Your solution is for simple sequence, and I have to use muti pwm mode, like this

void whiteTenSec(void)

{
  if (m_used & USED_PWM(0))
	{
			nrf_drv_pwm_uninit(&m_pwm0);
	}
	printf("whiteTenSec \r\n");
	enum{
		TOP = 255,
		STEP_COUNT = 25,
		TIMES = 200
	};

    uint32_t err_code;
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            pin12 | NRF_DRV_PWM_PIN_INVERTED, // channel 0 B
            pin13 | NRF_DRV_PWM_PIN_INVERTED, // channel 1 G
            pin14 | NRF_DRV_PWM_PIN_INVERTED, // channel 3 R
	    NRF_DRV_PWM_PIN_NOT_USED
        },
        .irq_priority = APP_IRQ_PRIORITY_LOW,
        .base_clock   = NRF_PWM_CLK_125kHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = TOP,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    err_code = nrf_drv_pwm_init(&m_pwm0, &config0, NULL);
    APP_ERROR_CHECK(err_code);
    m_used |= USED_PWM(0);

		static nrf_pwm_values_individual_t seq0_values[]={
		{0x80, 0x80, 0x80}
		};
		
		nrf_pwm_sequence_t const seq0 = {
			.values.p_individual = seq0_values,
			.length = NRF_PWM_VALUES_LENGTH(seq0_values),
			.repeats = 5000,
			.end_delay = 0
		};
		
		static nrf_pwm_values_individual_t seq1_values[]={
		{0xff, 0xff, 0xff}
		};
		
		nrf_pwm_sequence_t const seq1 = {
			.values.p_individual = seq1_values,
			.length = NRF_PWM_VALUES_LENGTH(seq1_values),
			.repeats = 1,
			.end_delay = 0
		};
		
		nrf_drv_pwm_complex_playback(&m_pwm0, &seq0, &seq1, 1, NRF_DRV_PWM_EVT_FINISHED);
}

and

void blinkyRed(void)
{
	  if (m_used & USED_PWM(0))
	{
			nrf_drv_pwm_uninit(&m_pwm0);
	}
	enum{
		TOP = 255,
		STEP_COUNT = 255,
		TIMES = 10 
	};

    uint32_t err_code;
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            pin12 | NRF_DRV_PWM_PIN_INVERTED, // channel 0 B
            pin13 | NRF_DRV_PWM_PIN_INVERTED, // channel 1 G
            pin14 | NRF_DRV_PWM_PIN_INVERTED, // channel 2 R
						NRF_DRV_PWM_PIN_NOT_USED
        },
        .irq_priority = APP_IRQ_PRIORITY_LOW,
        .base_clock   = NRF_PWM_CLK_125kHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = TOP,
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    err_code = nrf_drv_pwm_init(&m_pwm0, &config0, NULL);
    APP_ERROR_CHECK(err_code);
    m_used |= USED_PWM(0);


		static nrf_pwm_values_individual_t seq0_values[]={
			{0xff,0xff,0x80},
			{0xff,0xff,0x80},
			{0xff,0xff,0x80},
			{0xff,0xff,0x80},
			{0xff,0xff,0x80}
		};
		
		static nrf_pwm_values_individual_t seq1_values[]={
			{0xff,0xff,0xff},
			{0xff,0xff,0xff},
			{0xff,0xff,0xff},
			{0xff,0xff,0xff},
			{0xff,0xff,0xff}
		};
		

		
		nrf_pwm_sequence_t const seq0 = {
			.values.p_individual = seq0_values,
			.length = NRF_PWM_VALUES_LENGTH(seq0_values),
			.repeats = 50,
			.end_delay = 1
		};
		
		nrf_pwm_sequence_t const seq1 = {
			.values.p_individual = seq1_values,
			.length = NRF_PWM_VALUES_LENGTH(seq1_values),
			.repeats = 50,
			.end_delay = 1
		};
		
		nrf_drv_pwm_complex_playback(&m_pwm0, &seq0, &seq1, 1, NRF_DRV_PWM_FLAG_LOOP);
		}
}

I want to see the situation is: white 10s -> red blink

but there is: white 1s -> redblink

Thanks again for your help...

Parents
  • Hello James

    When the PWM has finished a sequence it generates a NRF_DRV_PWM_EVT_FINISHED event. When you initialized your PWM instance you defined a call-back function. That function is called whenever the PWM module generates an event, and you can check for the NRF_DRV_PWM_EVT_FINISHED there and act accordingly. You call the nrf_drv_pwm_simple_playback like this

      nrf_drv_pwm_simple_playback(&m_pwm0, &seq0, 1, NRF_DRV_PWM_EVT_FINISHED);
    

    The documentation for the simple playback function states,

    uint32_t nrf_drv_pwm_simple_playback(nrf_drv_pwm_t const * const p_instance,
                                         nrf_pwm_sequence_t const * p_sequence,
                                         uint16_t                   playback_count,
                                         uint32_t                   flags);
    

    And regarding the flags argument the documentation states

    * @param[in] flags          Additional options. Pass any combination of
     *                           @ref nrf_drv_pwm_flag_t "playback flags", or 0
     *                           for default settings.
    

    The last argument for the playback function is the flags as defined in nrf_drv_pwm_flag_t, so this is not the correct place to use NRF_DRV_PWM_EVT_FINISHED, which is defined as a nrf_drv_pwm_evt_type_t type. In the flags you can tell the PWM module to generate separate events for sequence0 and sequence1, however from what I can see it should not be necessary to do that if you're only using one sequence. Then you just need to look for the NRF_DRV_PWM_EVT_FINISHED event in the call-back function.

    EDIT

    Attached below is a main file based on the pwm driver example from SDK 14.2. It has two sequences which are triggered by pressing either button 1 or 2 on the DK. If one of the sequences is triggered while one is already running it is queued by setting a flag.

    Do note that due to the way the handler is written, if sequence 0 is queued it will always execute before a queued sequence 1. So if sequence 0 is continuously triggered, sequence 1 will never execute. A better way to implement it would be to use a buffer which stores each queued element.

    The PWM is configured in individual mode with channel 0 and 1 set to different leds. Sequence values are set globabl so the bsp and PWM handler have access to them when calling the pwm_simple_playback function. The sequences here are set to simply blink the leds for roughly 10 seconds. The duration can be altered in different ways, you can alter the PWM frequency, the repetition of each sequence element, or the wanted number of blinks. There is one more element in each sequence than what is strictly needed, it's just there to smoothen the transition between two consecutive executions of the same sequence. The strength of the leds can be altered by changing the numeric value given to the channels in the configuration.

    main.c

    EDIT 2

    I used the pwm_simple_simple function as that was in your original question.

    I have tested your code and it seemingly works as you describe. White light lasts for 10.12 seconds before the PWM finishes. So I believe the source of your problem with the white light only lasting 1 second is elsewhere in your code.

    One question though, is there a specific reason why you uninitialized and reinitialize PWM instance 0 at the start of every function? You could simply init the PWM module once, and just update the sequences.

    Also, as I mentioned in my previous answer, your use of NRF_DRV_PWM_EVT_FINISHED as a flag is strictly speaking not valid. NRF_DRV_PWM_EVT_FINISHED is defined as zero, which is the default value passed to the playback function when no flags are used, so it has no effect on how the playback function executes.

    I have added another main file, this one uses the complex function and is based on your code. However I have made some modifications. I have moved the initialization of the PWM to a separate function as I only use one instance in this example. I have also added a 4th element in each sequence. This element is just a dummy element to make sure the unused pin doesn't cause any problem. See this case for more information. In the whiteTenSec function I use the same values as you do except I use the NRF_DRV_PWM_FLAG_STOP flag, and I suppress the evt_finished event. In the PWM event handler I execute the second function on the STOP event, this is just for testing purposes. Sequence 1 in this function is never properly executed due to the finished event being generated as the last value is loaded from RAM rather than after it is executed. This is stated at the bottom of page 499 in the product specification, see just below table 1 in this link.

    In the blinkyRed I use the LOOP flag, due to Errata 183 I have two entries in Sequence 1, otherwise it would cut the execution of sequence 1 short. The repeats are therefore halved compared to that of sequence 0. The resulting blinking Led has a period of 1 second, the same as in your code.

    I also made it so pressing button 1 calls WhiteTenSec, and button 2 calls blinkyRed for testing purposes.

    main.c

    Best regards

    Jørn Frøysa

Reply
  • Hello James

    When the PWM has finished a sequence it generates a NRF_DRV_PWM_EVT_FINISHED event. When you initialized your PWM instance you defined a call-back function. That function is called whenever the PWM module generates an event, and you can check for the NRF_DRV_PWM_EVT_FINISHED there and act accordingly. You call the nrf_drv_pwm_simple_playback like this

      nrf_drv_pwm_simple_playback(&m_pwm0, &seq0, 1, NRF_DRV_PWM_EVT_FINISHED);
    

    The documentation for the simple playback function states,

    uint32_t nrf_drv_pwm_simple_playback(nrf_drv_pwm_t const * const p_instance,
                                         nrf_pwm_sequence_t const * p_sequence,
                                         uint16_t                   playback_count,
                                         uint32_t                   flags);
    

    And regarding the flags argument the documentation states

    * @param[in] flags          Additional options. Pass any combination of
     *                           @ref nrf_drv_pwm_flag_t "playback flags", or 0
     *                           for default settings.
    

    The last argument for the playback function is the flags as defined in nrf_drv_pwm_flag_t, so this is not the correct place to use NRF_DRV_PWM_EVT_FINISHED, which is defined as a nrf_drv_pwm_evt_type_t type. In the flags you can tell the PWM module to generate separate events for sequence0 and sequence1, however from what I can see it should not be necessary to do that if you're only using one sequence. Then you just need to look for the NRF_DRV_PWM_EVT_FINISHED event in the call-back function.

    EDIT

    Attached below is a main file based on the pwm driver example from SDK 14.2. It has two sequences which are triggered by pressing either button 1 or 2 on the DK. If one of the sequences is triggered while one is already running it is queued by setting a flag.

    Do note that due to the way the handler is written, if sequence 0 is queued it will always execute before a queued sequence 1. So if sequence 0 is continuously triggered, sequence 1 will never execute. A better way to implement it would be to use a buffer which stores each queued element.

    The PWM is configured in individual mode with channel 0 and 1 set to different leds. Sequence values are set globabl so the bsp and PWM handler have access to them when calling the pwm_simple_playback function. The sequences here are set to simply blink the leds for roughly 10 seconds. The duration can be altered in different ways, you can alter the PWM frequency, the repetition of each sequence element, or the wanted number of blinks. There is one more element in each sequence than what is strictly needed, it's just there to smoothen the transition between two consecutive executions of the same sequence. The strength of the leds can be altered by changing the numeric value given to the channels in the configuration.

    main.c

    EDIT 2

    I used the pwm_simple_simple function as that was in your original question.

    I have tested your code and it seemingly works as you describe. White light lasts for 10.12 seconds before the PWM finishes. So I believe the source of your problem with the white light only lasting 1 second is elsewhere in your code.

    One question though, is there a specific reason why you uninitialized and reinitialize PWM instance 0 at the start of every function? You could simply init the PWM module once, and just update the sequences.

    Also, as I mentioned in my previous answer, your use of NRF_DRV_PWM_EVT_FINISHED as a flag is strictly speaking not valid. NRF_DRV_PWM_EVT_FINISHED is defined as zero, which is the default value passed to the playback function when no flags are used, so it has no effect on how the playback function executes.

    I have added another main file, this one uses the complex function and is based on your code. However I have made some modifications. I have moved the initialization of the PWM to a separate function as I only use one instance in this example. I have also added a 4th element in each sequence. This element is just a dummy element to make sure the unused pin doesn't cause any problem. See this case for more information. In the whiteTenSec function I use the same values as you do except I use the NRF_DRV_PWM_FLAG_STOP flag, and I suppress the evt_finished event. In the PWM event handler I execute the second function on the STOP event, this is just for testing purposes. Sequence 1 in this function is never properly executed due to the finished event being generated as the last value is loaded from RAM rather than after it is executed. This is stated at the bottom of page 499 in the product specification, see just below table 1 in this link.

    In the blinkyRed I use the LOOP flag, due to Errata 183 I have two entries in Sequence 1, otherwise it would cut the execution of sequence 1 short. The repeats are therefore halved compared to that of sequence 0. The resulting blinking Led has a period of 1 second, the same as in your code.

    I also made it so pressing button 1 calls WhiteTenSec, and button 2 calls blinkyRed for testing purposes.

    main.c

    Best regards

    Jørn Frøysa

Children
Related