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

PWM Duty Cycle Measurement Spike

The servo I use in my application uses a PWM signal  duty cycle to represent servo amperage level.

So, to measure servo amperage, I use a GPIOTE channel to capture the time between rising and falling edges of the servo's PWM  amperage signal.  I then have an interrupt handler that reads the GPIO pin to determine whether or not the time was for a peak or valley and I calculate duty cycle appropriately.

The problem is at low duty cycles, when triggered by a peak,  the signal occasionally  changes prior to reading the pin in the interrupt handler routine.   This result is an inaccurate spike in servo amperage.   As I use the valley routine to calculate duty cycle when I should have used a peak routine.

I recognize that it is a timing issue and would like to overcome this with a robust solution.  

Can I rely on the latch function instead of reading the pin to determine if I'm  measuring the width of the peak or the width of a valley?

Or alternatively, Can a I make a pin read and GPIOTE event via PPI?

I've attached the code of my interrupt handler in case you need more detail.

void servo_amps_input_handler (nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
		static uint32_t servo_first_edge_capture, servo_second_edge_capture;
		static float32_t last_good_servo_amps;
		static uint16_t state; 

// PPI (channel3) channel event captures NRF_TIMER4 CC[0]
		
    switch (servo_edge)
    {
				case 0UL:
						servo_first_edge_capture = NRF_TIMER4->CC[0];
						finished_getting_servo_data = false;
						state = nrf_gpio_pin_read(I_OUT);
						if (state == 1) hi_state = true;
						else hi_state = false;
						servo_edge++;
						//SEGGER_RTT_printf(0," 1st I_OUT edge capture %d,  \r\n", servo_first_edge_capture);				
						break;
 
        case (1UL):
						nrf_drv_gpiote_in_event_disable(I_OUT);    // disable I_OUT pin interrupt
						nrf_drv_timer_compare_int_disable(&TIMER_AMPS, NRF_TIMER_CC_CHANNEL2); // disable NO_PULSE interupt
						servo_second_edge_capture = NRF_TIMER4->CC[0];
						servo_pulse_count = servo_second_edge_capture - servo_first_edge_capture;
						if (servo_pulse_count == 0)
							{
								servo_AMPS = last_good_servo_amps;								
							}
						else
							{
								if (state == 1) //we measured duration of a high pulse
								{
									servo_AMPS = servo_duty_amps * (float32_t)servo_pulse_count / servo_period_count;
								}
								else  //we measured duration of a low pulse
								{
									servo_AMPS = servo_duty_amps * (1.F - ((float32_t)servo_pulse_count / servo_period_count));
									
								}
								last_good_servo_amps = servo_AMPS;
							}
						IFLG_get_servo_amps = false;
						finished_getting_servo_data = true; 
						servo_edge++;
						//SEGGER_RTT_printf(0," 2nd I_OUT edge capture %d,  \r\n", servo_second_edge_capture);	
							
						break;
     
        default:  //We should never hit this
						servo_edge++;
						break;             
    } 	
	
	
	
}

Parents
  • Can I rely on the latch function instead of reading the pin to determine if I'm  measuring the width of the peak or the width of a valley?

    As you already write: It may be that a toggle on a gpio port is so short, that by the time the interrupt is handled, then the pin have returned and thereby the actual source of the interrupt is not known. This is a problem if the pin is setup with SENSE signal, in that case you can read the LATCH register to find the actual pin that caused the interrupt yes. You will not be able to measure how short (in time) the toggling was, but I guess that may not be a problem, since you don't need very accurate precision (it's enough to know it was shorter than a few tens of us since that is the time it took for the interrupt handler to be executed). You can find description of the LATCH register in the GPIO chapter:
    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/gpio.html#concept_zyt_tcb_lr

    Or alternatively, Can a I make a pin read and GPIOTE event via PPI?

    I don't see any good way to do this, typically you can for instance capture events on pin change (connected to a timer), but I don't see any easy way for this pin to measure the length of the toggling (you would need to handle the interrupt between the two, and that is the problem in the first case).

    Kenneth

Reply
  • Can I rely on the latch function instead of reading the pin to determine if I'm  measuring the width of the peak or the width of a valley?

    As you already write: It may be that a toggle on a gpio port is so short, that by the time the interrupt is handled, then the pin have returned and thereby the actual source of the interrupt is not known. This is a problem if the pin is setup with SENSE signal, in that case you can read the LATCH register to find the actual pin that caused the interrupt yes. You will not be able to measure how short (in time) the toggling was, but I guess that may not be a problem, since you don't need very accurate precision (it's enough to know it was shorter than a few tens of us since that is the time it took for the interrupt handler to be executed). You can find description of the LATCH register in the GPIO chapter:
    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/gpio.html#concept_zyt_tcb_lr

    Or alternatively, Can a I make a pin read and GPIOTE event via PPI?

    I don't see any good way to do this, typically you can for instance capture events on pin change (connected to a timer), but I don't see any easy way for this pin to measure the length of the toggling (you would need to handle the interrupt between the two, and that is the problem in the first case).

    Kenneth

Children
Related