-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aa96deb
commit b05ebc2
Showing
199 changed files
with
37,258 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
############################################################################ | ||
# | ||
# Copyright (c) 2015-2020 PX4 Development Team. All rights reserved. | ||
# | ||
# Redistribution and use in source and binary forms, with or without | ||
# modification, are permitted provided that the following conditions | ||
# are met: | ||
# | ||
# 1. Redistributions of source code must retain the above copyright | ||
# notice, this list of conditions and the following disclaimer. | ||
# 2. Redistributions in binary form must reproduce the above copyright | ||
# notice, this list of conditions and the following disclaimer in | ||
# the documentation and/or other materials provided with the | ||
# distribution. | ||
# 3. Neither the name PX4 nor the names of its contributors may be | ||
# used to endorse or promote products derived from this software | ||
# without specific prior written permission. | ||
# | ||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
# POSSIBILITY OF SUCH DAMAGE. | ||
# | ||
############################################################################ | ||
|
||
set(PARAM_PREFIX PWM_MAIN) | ||
|
||
if(CONFIG_BOARD_IO) | ||
set(PARAM_PREFIX PWM_AUX) | ||
endif() | ||
|
||
px4_add_module( | ||
MODULE drivers__pwm_out | ||
MAIN pwm_out | ||
COMPILE_FLAGS | ||
-DPARAM_PREFIX="${PARAM_PREFIX}" | ||
SRCS | ||
PWMOut.cpp | ||
PWMOut.hpp | ||
MODULE_CONFIG | ||
module.yaml | ||
DEPENDS | ||
arch_io_pins | ||
mixer_module | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
menuconfig DRIVERS_PWM_OUT | ||
bool "pwm_out" | ||
default n | ||
---help--- | ||
Enable support for pwm_out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,336 @@ | ||
/**************************************************************************** | ||
* | ||
* Copyright (c) 2012-2022 PX4 Development Team. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions | ||
* are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* 2. Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in | ||
* the documentation and/or other materials provided with the | ||
* distribution. | ||
* 3. Neither the name PX4 nor the names of its contributors may be | ||
* used to endorse or promote products derived from this software | ||
* without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
****************************************************************************/ | ||
|
||
#include "PWMOut.hpp" | ||
|
||
#include <px4_platform_common/sem.hpp> | ||
|
||
PWMOut::PWMOut() : | ||
OutputModuleInterface(MODULE_NAME, px4::wq_configurations::hp_default) | ||
{ | ||
_pwm_mask = ((1u << DIRECT_PWM_OUTPUT_CHANNELS) - 1); | ||
_mixing_output.setMaxNumOutputs(DIRECT_PWM_OUTPUT_CHANNELS); | ||
|
||
// Getting initial parameter values | ||
update_params(); | ||
} | ||
|
||
PWMOut::~PWMOut() | ||
{ | ||
/* make sure servos are off */ | ||
up_pwm_servo_deinit(_pwm_mask); | ||
|
||
perf_free(_cycle_perf); | ||
perf_free(_interval_perf); | ||
} | ||
|
||
bool PWMOut::update_pwm_out_state(bool on) | ||
{ | ||
if (on && !_pwm_initialized && _pwm_mask != 0) { | ||
|
||
for (int timer = 0; timer < MAX_IO_TIMERS; ++timer) { | ||
_timer_rates[timer] = -1; | ||
|
||
uint32_t channels = io_timer_get_group(timer); | ||
|
||
if (channels == 0) { | ||
continue; | ||
} | ||
|
||
char param_name[17]; | ||
snprintf(param_name, sizeof(param_name), "%s_TIM%u", _mixing_output.paramPrefix(), timer); | ||
|
||
int32_t tim_config = 0; | ||
param_t handle = param_find(param_name); | ||
param_get(handle, &tim_config); | ||
|
||
if (tim_config > 0) { | ||
_timer_rates[timer] = tim_config; | ||
|
||
} else if (tim_config == -1) { // OneShot | ||
_timer_rates[timer] = 0; | ||
|
||
} else { | ||
_pwm_mask &= ~channels; // don't use for pwm | ||
} | ||
} | ||
|
||
int ret = up_pwm_servo_init(_pwm_mask); | ||
|
||
if (ret < 0) { | ||
PX4_ERR("up_pwm_servo_init failed (%i)", ret); | ||
return false; | ||
} | ||
|
||
_pwm_mask = ret; | ||
|
||
// set the timer rates | ||
for (int timer = 0; timer < MAX_IO_TIMERS; ++timer) { | ||
uint32_t channels = _pwm_mask & up_pwm_servo_get_rate_group(timer); | ||
|
||
if (channels == 0) { | ||
continue; | ||
} | ||
|
||
ret = up_pwm_servo_set_rate_group_update(timer, _timer_rates[timer]); | ||
|
||
if (ret != 0) { | ||
PX4_ERR("up_pwm_servo_set_rate_group_update failed for timer %i, rate %i (%i)", timer, _timer_rates[timer], ret); | ||
_timer_rates[timer] = -1; | ||
_pwm_mask &= ~channels; | ||
} | ||
} | ||
|
||
_pwm_initialized = true; | ||
|
||
// disable unused functions | ||
for (unsigned i = 0; i < _num_outputs; ++i) { | ||
if (((1 << i) & _pwm_mask) == 0) { | ||
_mixing_output.disableFunction(i); | ||
} | ||
} | ||
} | ||
|
||
up_pwm_servo_arm(on, _pwm_mask); | ||
return true; | ||
} | ||
|
||
bool PWMOut::updateOutputs(bool stop_motors, uint16_t outputs[MAX_ACTUATORS], | ||
unsigned num_outputs, unsigned num_control_groups_updated) | ||
{ | ||
/* output to the servos */ | ||
if (_pwm_initialized) { | ||
for (size_t i = 0; i < num_outputs; i++) { | ||
if (!_mixing_output.isFunctionSet(i)) { | ||
// do not run any signal on disabled channels | ||
outputs[i] = 0; | ||
} | ||
|
||
if (_pwm_mask & (1 << i)) { | ||
up_pwm_servo_set(i, outputs[i]); | ||
} | ||
} | ||
} | ||
|
||
/* Trigger all timer's channels in Oneshot mode to fire | ||
* the oneshots with updated values. | ||
*/ | ||
if (num_control_groups_updated > 0) { | ||
up_pwm_update(_pwm_mask); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
void PWMOut::Run() | ||
{ | ||
if (should_exit()) { | ||
ScheduleClear(); | ||
_mixing_output.unregister(); | ||
|
||
exit_and_cleanup(); | ||
return; | ||
} | ||
|
||
perf_begin(_cycle_perf); | ||
perf_count(_interval_perf); | ||
|
||
_mixing_output.update(); | ||
|
||
/* update PWM status if armed or if disarmed PWM values are set */ | ||
bool pwm_on = true; | ||
|
||
if (_pwm_on != pwm_on) { | ||
if (update_pwm_out_state(pwm_on)) { | ||
_pwm_on = pwm_on; | ||
} | ||
} | ||
|
||
// check for parameter updates | ||
if (_parameter_update_sub.updated()) { | ||
// clear update | ||
parameter_update_s pupdate; | ||
_parameter_update_sub.copy(&pupdate); | ||
|
||
// update parameters from storage | ||
update_params(); | ||
} | ||
|
||
// check at end of cycle (updateSubscriptions() can potentially change to a different WorkQueue thread) | ||
_mixing_output.updateSubscriptions(true); | ||
|
||
perf_end(_cycle_perf); | ||
_first_update_cycle = false; | ||
} | ||
|
||
int PWMOut::task_spawn(int argc, char *argv[]) | ||
{ | ||
PWMOut *instance = new PWMOut(); | ||
|
||
if (!instance) { | ||
PX4_ERR("alloc failed"); | ||
return -1; | ||
} | ||
|
||
_object.store(instance); | ||
_task_id = task_id_is_work_queue; | ||
instance->ScheduleNow(); | ||
return 0; | ||
} | ||
|
||
void PWMOut::update_params() | ||
{ | ||
uint32_t previously_set_functions = 0; | ||
|
||
for (size_t i = 0; i < _num_outputs; i++) { | ||
previously_set_functions |= (uint32_t)_mixing_output.isFunctionSet(i) << i; | ||
} | ||
|
||
updateParams(); | ||
|
||
// Automatically set PWM configuration when a channel is first assigned | ||
if (!_first_update_cycle) { | ||
for (size_t i = 0; i < _num_outputs; i++) { | ||
if ((previously_set_functions & (1u << i)) == 0 && _mixing_output.functionParamHandle(i) != PARAM_INVALID) { | ||
int32_t output_function; | ||
|
||
if (param_get(_mixing_output.functionParamHandle(i), &output_function) == 0) { | ||
// Servos need PWM rate 50Hz and disramed value 1500us | ||
if (output_function >= (int)OutputFunction::Servo1 | ||
&& output_function <= (int)OutputFunction::ServoMax) { // Function got set to a servo | ||
int32_t val = 1500; | ||
PX4_INFO("Setting channel %i disarmed to %i", (int) val, i); | ||
param_set(_mixing_output.disarmedParamHandle(i), &val); | ||
|
||
// If the whole timer group was not set previously, then set the pwm rate to 50 Hz | ||
for (int timer = 0; timer < MAX_IO_TIMERS; ++timer) { | ||
|
||
uint32_t channels = io_timer_get_group(timer); | ||
|
||
if ((channels & (1u << i)) == 0) { | ||
continue; | ||
} | ||
|
||
if ((channels & previously_set_functions) == 0) { // None of the channels was set | ||
char param_name[17]; | ||
snprintf(param_name, sizeof(param_name), "%s_TIM%u", _mixing_output.paramPrefix(), timer); | ||
|
||
int32_t tim_config = 0; | ||
param_t handle = param_find(param_name); | ||
|
||
if (param_get(handle, &tim_config) == 0 && tim_config == 400) { | ||
tim_config = 50; | ||
PX4_INFO("setting timer %i to %i Hz", timer, (int) tim_config); | ||
param_set(handle, &tim_config); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Motors need a minimum value that idles the motor and have a deadzone at the top of the range | ||
if (output_function >= (int)OutputFunction::Motor1 | ||
&& output_function <= (int)OutputFunction::MotorMax) { // Function got set to a motor | ||
int32_t val = 1100; | ||
PX4_INFO("Setting channel %i minimum to %i", (int) val, i); | ||
param_set(_mixing_output.minParamHandle(i), &val); | ||
val = 1900; | ||
PX4_INFO("Setting channel %i maximum to %i", (int) val, i); | ||
param_set(_mixing_output.maxParamHandle(i), &val); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
int PWMOut::custom_command(int argc, char *argv[]) | ||
{ | ||
return print_usage("unknown command"); | ||
} | ||
|
||
int PWMOut::print_status() | ||
{ | ||
perf_print_counter(_cycle_perf); | ||
perf_print_counter(_interval_perf); | ||
_mixing_output.printStatus(); | ||
|
||
if (_pwm_initialized) { | ||
for (int timer = 0; timer < MAX_IO_TIMERS; ++timer) { | ||
if (_timer_rates[timer] >= 0) { | ||
PX4_INFO_RAW("Timer %i: rate: %3i", timer, _timer_rates[timer]); | ||
uint32_t channels = _pwm_mask & up_pwm_servo_get_rate_group(timer); | ||
|
||
if (channels > 0) { | ||
PX4_INFO_RAW(" channels: "); | ||
|
||
for (uint32_t channel = 0; channel < _num_outputs; ++channel) { | ||
if ((1 << channel) & channels) { | ||
PX4_INFO_RAW("%" PRIu32 " ", channel); | ||
} | ||
} | ||
} | ||
|
||
PX4_INFO_RAW("\n"); | ||
} | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int PWMOut::print_usage(const char *reason) | ||
{ | ||
if (reason) { | ||
PX4_WARN("%s\n", reason); | ||
} | ||
|
||
PRINT_MODULE_DESCRIPTION( | ||
R"DESCR_STR( | ||
### Description | ||
This module is responsible for driving the output pins. For boards without a separate IO chip | ||
(eg. Pixracer), it uses the main channels. On boards with an IO chip (eg. Pixhawk), it uses the AUX channels, and the | ||
px4io driver is used for main ones. | ||
)DESCR_STR"); | ||
|
||
PRINT_MODULE_USAGE_NAME("pwm_out", "driver"); | ||
PRINT_MODULE_USAGE_COMMAND("start"); | ||
PRINT_MODULE_USAGE_DEFAULT_COMMANDS(); | ||
|
||
return 0; | ||
} | ||
|
||
extern "C" __EXPORT int pwm_out_main(int argc, char *argv[]) | ||
{ | ||
return PWMOut::main(argc, argv); | ||
} |
Oops, something went wrong.