fix pwm_out: avoid race condition when setting mode

Bootup failed in some cases with:
ERROR [mixer] can't reset mixers on /dev/pwm_output1

The reason was the mode change was not applied yet.
This commit is contained in:
Beat Küng
2021-04-12 17:05:53 +02:00
committed by Lorenz Meier
parent 18f17dcb96
commit faaee0f077
2 changed files with 22 additions and 4 deletions

View File

@@ -580,9 +580,9 @@ void PWMOut::Run()
// push backup schedule // push backup schedule
ScheduleDelayed(_backup_schedule_interval_us); ScheduleDelayed(_backup_schedule_interval_us);
if (_new_mode_request.load() != _mode) { if (_new_mode_request.load() != MODE_NO_REQUEST) {
set_mode(_new_mode_request.load()); set_mode(_new_mode_request.load());
_new_mode_request.store(_mode); _new_mode_request.store(MODE_NO_REQUEST);
} }
_mixing_output.update(); _mixing_output.update();
@@ -1762,6 +1762,22 @@ int PWMOut::fmu_new_mode(PortMode new_mode)
return OK; return OK;
} }
void PWMOut::request_mode(Mode new_mode)
{
if (_new_mode_request.load() != MODE_NO_REQUEST) {
PX4_ERR("already being set"); // not expected to happen
return;
}
_new_mode_request.store(new_mode);
ScheduleNow();
// wait until processed
int max_time = 1000;
while (_new_mode_request.load() != MODE_NO_REQUEST && max_time-- > 0) {
px4_usleep(1000);
}
}
namespace namespace
{ {

View File

@@ -118,6 +118,8 @@ public:
MODE_4CAP, MODE_4CAP,
MODE_5CAP, MODE_5CAP,
MODE_6CAP, MODE_6CAP,
MODE_NO_REQUEST
}; };
PWMOut() = delete; PWMOut() = delete;
@@ -157,7 +159,7 @@ public:
int set_mode(Mode mode); int set_mode(Mode mode);
Mode get_mode() { return _mode; } Mode get_mode() { return _mode; }
void request_mode(Mode new_mode) { _new_mode_request.store(new_mode); } void request_mode(Mode new_mode);
static int set_i2c_bus_clock(unsigned bus, unsigned clock_hz); static int set_i2c_bus_clock(unsigned bus, unsigned clock_hz);
@@ -181,7 +183,7 @@ private:
Mode _mode{MODE_NONE}; Mode _mode{MODE_NONE};
px4::atomic<Mode> _new_mode_request{MODE_NONE}; px4::atomic<Mode> _new_mode_request{MODE_NO_REQUEST};
uint32_t _backup_schedule_interval_us{1_s}; uint32_t _backup_schedule_interval_us{1_s};