You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
2.9 KiB
108 lines
2.9 KiB
#include "GPIO.h" |
|
|
|
#include <AP_HAL/AP_HAL.h> |
|
#if defined(HAL_NO_GCS) || defined(HAL_BOOTLOADER_BUILD) |
|
#define GCS_SEND_TEXT(severity, format, args...) |
|
#else |
|
#include <GCS_MAVLink/GCS.h> |
|
#endif |
|
|
|
extern const AP_HAL::HAL& hal; |
|
|
|
bool AP_HAL::PWMSource::set_pin(int16_t new_pin, const char *subsystem) |
|
{ |
|
if (new_pin == _pin) { |
|
// we've already tried to attach to this pin |
|
return interrupt_attached; |
|
} |
|
|
|
if (interrupt_attached) { |
|
if (!hal.gpio->detach_interrupt(_pin)) { |
|
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, |
|
"%s: Failed to detach interrupt from %d", |
|
subsystem, |
|
_pin); |
|
} |
|
interrupt_attached = false; |
|
} |
|
|
|
// don't want to try to attach more than once: |
|
_pin = new_pin; |
|
|
|
if (_pin <= 0) { |
|
// invalid pin |
|
return false; |
|
} |
|
|
|
// install interrupt handler on rising and falling edge |
|
hal.gpio->pinMode(_pin, HAL_GPIO_INPUT); |
|
if (!hal.gpio->attach_interrupt( |
|
_pin, |
|
FUNCTOR_BIND_MEMBER(&AP_HAL::PWMSource::irq_handler, |
|
void, |
|
uint8_t, |
|
bool, |
|
uint32_t), |
|
AP_HAL::GPIO::INTERRUPT_BOTH)) { |
|
// failed to attach interrupt |
|
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, |
|
"%s: Failed to attach interrupt to %d", |
|
subsystem, |
|
_pin); |
|
return false; |
|
} |
|
|
|
interrupt_attached = true; |
|
|
|
return interrupt_attached; |
|
} |
|
|
|
// interrupt handler for reading pwm value |
|
void AP_HAL::PWMSource::irq_handler(uint8_t a_pin, bool pin_high, uint32_t timestamp_us) |
|
{ |
|
if (pin_high) { |
|
_pulse_start_us = timestamp_us; |
|
return; |
|
} |
|
if (_pulse_start_us == 0) { |
|
// if we miss interrupts we could get two lows in a row. If |
|
// we miss interrupts we're definitely handing back bad |
|
// values anyway.... |
|
return; |
|
} |
|
_irq_value_us = timestamp_us - _pulse_start_us; |
|
_pulse_start_us = 0; |
|
|
|
// update fields for taking an average reading: |
|
_irq_value_us_sum += _irq_value_us; |
|
_irq_value_us_count++; |
|
} |
|
|
|
|
|
uint16_t AP_HAL::PWMSource::get_pwm_us() |
|
{ |
|
// disable interrupts and grab state |
|
void *irqstate = hal.scheduler->disable_interrupts_save(); |
|
const uint32_t ret = _irq_value_us; |
|
_irq_value_us = 0; |
|
hal.scheduler->restore_interrupts(irqstate); |
|
|
|
return ret; |
|
} |
|
|
|
uint16_t AP_HAL::PWMSource::get_pwm_avg_us() |
|
{ |
|
// disable interrupts and grab state |
|
void *irqstate = hal.scheduler->disable_interrupts_save(); |
|
uint32_t ret; |
|
if (_irq_value_us_count == 0) { |
|
ret = 0; |
|
} else { |
|
ret = _irq_value_us_sum / _irq_value_us_count; |
|
} |
|
_irq_value_us_sum = 0; |
|
_irq_value_us_count = 0; |
|
hal.scheduler->restore_interrupts(irqstate); |
|
|
|
return ret; |
|
}
|
|
|