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.
183 lines
4.1 KiB
183 lines
4.1 KiB
/* |
|
(c) 2017 night_ghost@ykoctpa.ru |
|
|
|
*/ |
|
|
|
#pragma GCC optimize ("O2") |
|
|
|
#include "gpio_hal.h" |
|
#include <boards.h> |
|
|
|
#include <exti.h> |
|
|
|
#include "GPIO.h" |
|
#include "Scheduler.h" |
|
#include "RCOutput.h" |
|
|
|
|
|
|
|
using namespace F4Light; |
|
|
|
void GPIO::_pinMode(uint8_t pin, uint8_t mode) |
|
{ |
|
gpio_pin_mode outputMode; |
|
bool pwm = false; |
|
|
|
switch(mode) { // modes defined to be compatible so no transcode required |
|
case OUTPUT: |
|
case OUTPUT_OPEN_DRAIN: |
|
case INPUT: |
|
// case INPUT_FLOATING: synonim and cause doubled 'case' |
|
case INPUT_ANALOG: |
|
case INPUT_PULLUP: |
|
case INPUT_PULLDOWN: |
|
outputMode = (gpio_pin_mode)mode; |
|
break; |
|
|
|
case PWM: |
|
outputMode = GPIO_AF_OUTPUT_PP; |
|
pwm = true; |
|
break; |
|
|
|
case PWM_OPEN_DRAIN: |
|
outputMode = GPIO_AF_OUTPUT_OD; |
|
pwm = true; |
|
break; |
|
|
|
default: |
|
assert_param(0); |
|
return; |
|
} |
|
|
|
|
|
const stm32_pin_info &p = PIN_MAP[pin]; |
|
|
|
const gpio_dev* dev = p.gpio_device; |
|
uint8_t bit = p.gpio_bit; |
|
const timer_dev * timer = p.timer_device; |
|
|
|
gpio_set_mode(dev, bit, outputMode); |
|
|
|
if (pwm && timer != NULL) { |
|
gpio_set_speed(dev, bit, GPIO_speed_25MHz); // cleanflight sets 2MHz |
|
gpio_set_af_mode(dev, bit, timer->af); |
|
timer_set_mode(timer, p.timer_channel, TIMER_PWM); // init in setupTimers() |
|
} else { |
|
gpio_set_af_mode(dev, bit, 0); // reset |
|
} |
|
} |
|
|
|
|
|
void GPIO::pinMode(uint8_t pin, uint8_t output){ |
|
|
|
if ((pin >= BOARD_NR_GPIO_PINS)) return; |
|
|
|
_pinMode(pin, output); |
|
} |
|
|
|
|
|
uint8_t GPIO::read(uint8_t pin) { |
|
if (pin >= BOARD_NR_GPIO_PINS) return 0; |
|
|
|
return _read(pin); |
|
} |
|
|
|
|
|
void GPIO::write(uint8_t pin, uint8_t value) { |
|
if ((pin >= BOARD_NR_GPIO_PINS)) return; |
|
|
|
#ifdef BUZZER_PWM_HZ // passive buzzer |
|
|
|
// AP_Notify Buzzer.cpp don't supports passive buzzer so we need a small hack |
|
if(pin == BOARD_BUZZER_PIN){ |
|
if(value == HAL_BUZZER_ON){ |
|
const stm32_pin_info &p = PIN_MAP[pin]; |
|
const timer_dev *dev = p.timer_device; |
|
if(dev->state->freq==0) { |
|
configTimeBase(dev, 0, BUZZER_PWM_HZ * 10); // it should be personal timer |
|
} |
|
_pinMode(pin, PWM); |
|
uint32_t n = RCOutput::_timer_period(BUZZER_PWM_HZ, dev); |
|
timer_set_reload(dev, n); |
|
timer_set_compare(dev, p.timer_channel, n/2); |
|
return; |
|
} else { |
|
_pinMode(pin, OUTPUT); // to disable, just change mode |
|
} |
|
} |
|
#endif |
|
|
|
_write(pin, value); |
|
} |
|
|
|
|
|
void GPIO::toggle(uint8_t pin) |
|
{ |
|
if ((pin >= BOARD_NR_GPIO_PINS)) return; |
|
|
|
_toggle(pin); |
|
} |
|
|
|
|
|
/* Interrupt interface: */ |
|
bool GPIO::_attach_interrupt(uint8_t pin, Handler p, uint8_t mode, uint8_t priority) |
|
{ |
|
if ( (pin >= BOARD_NR_GPIO_PINS) || !p) return false; |
|
|
|
const stm32_pin_info &pp = PIN_MAP[pin]; |
|
|
|
exti_attach_interrupt_pri((afio_exti_num)(pp.gpio_bit), |
|
gpio_exti_port(pp.gpio_device), |
|
p, exti_out_mode((ExtIntTriggerMode)mode), |
|
priority); |
|
|
|
return true; |
|
} |
|
|
|
void GPIO::detach_interrupt(uint8_t pin) |
|
{ |
|
if ( pin >= BOARD_NR_GPIO_PINS) return; |
|
|
|
exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit)); |
|
} |
|
|
|
|
|
|
|
/* Alternative interface: */ |
|
AP_HAL::DigitalSource* GPIO::channel(uint16_t pin) { |
|
|
|
if ((pin >= BOARD_NR_GPIO_PINS)) return NULL; |
|
|
|
return get_channel(pin); |
|
} |
|
|
|
|
|
void DigitalSource::mode(uint8_t md) |
|
{ |
|
gpio_pin_mode outputMode; |
|
|
|
switch(md) { |
|
case OUTPUT: |
|
case OUTPUT_OPEN_DRAIN: |
|
case INPUT: |
|
// case INPUT_FLOATING: |
|
case INPUT_ANALOG: |
|
case INPUT_PULLUP: |
|
case INPUT_PULLDOWN: |
|
outputMode = (gpio_pin_mode)md; |
|
break; |
|
|
|
// no PWM via this interface! |
|
default: |
|
assert_param(0); |
|
return; |
|
} |
|
|
|
gpio_set_mode( _device, _bit, outputMode); |
|
gpio_set_speed(_device, _bit, GPIO_speed_100MHz); // to use as CS |
|
} |
|
|
|
void digitalWrite(uint8_t pin, uint8_t value) { F4Light::GPIO::_write(pin, value); } |
|
uint8_t digitalRead(uint8_t pin) { return F4Light::GPIO::_read(pin); } |
|
|
|
void digitalToggle(uint8_t pin) { return F4Light::GPIO::_toggle(pin); }
|
|
|