chore: New module/serial API (#3055)

* WiP: new module interface

* WiP: softserial timer DMA

* WiP: setup() and send() in one step

and remove methods specific to internal or external module

* fixes and extra port config

* horus targets

* module ports have moved

* T8 support (only internal module)

* fix nv14

* stupid GCC....

* disable BT

* remove nv14 telem driver

* remove old aux serial driver

* Move module buffers out of pulses.h

* Soft serial fixes and PXX1 support

* Fixed PPM module output

* Fixed CLI

* compilation fixes

* Ported bluetooth and flysky gimbal to new serial driver

* Re-enable soft-serial RX

* fixes and cleanup

* nv14 fixes

* Fix flysky gimbals

* Ghost module

* 16 bytes of RAM

* Remove getByte from module API

* Ghost cleanup

* fix: _half_duplex_input() must be called after usart init

* WiP

* more cleanup

* Remove board specific settings from PXX1 / PXX2 drivers

* A bit of PXX2 header cleanup

* Add support for OVER8 and ONEBIT

* Add some support for inverters (NV14 / EL18)

* Support NV14 power fixes in generic board

* Fix polarity handling

* Fix RX DMA

* Fix mixer not running

* Add soft-serial polarity control

* Quick fix for telemetry polling while module port is changed

* Fix bootloader DEBUG

* Fix MPM telemetry

* Fix pulse start

* DSM2 soft-serial fallback

* DSMP async module restart

* Fix CRSF LUA upstream

* Remove global variable telemetryProtocol

* Use HAL/LL constants

* Fix various issue with AFHDS3 and NV14/EL18 internal module

* Fixed S.PORT unit tests

* fix: update widx after writing at current index

* fix: init error condition

* Fix: possible infinite loop in _find_port()

* Add support for bidir S.PORT init

* Add support for "getLastByte" in HW serial driver

* PXX1: Add support for S.PORT based on IDLE callback

* Fix rebase error

* Fix softserial _rx_fifo_push()

* Add softserial support for waitForTxCompleted()

* Fix MPM flashing (internal / external)

* Fixed external MPM

* Activate RX DMA on internal module

Seems to work with serial passthrough without issues, at least on the L3R PRO.

* Fix softserial DMA on stdlcd F4 targets

* Add softserial support for 32bit timers (mostly TIM2)

* More precise soft-serial

* Fix MPM update using inverters & HW uart

* Raise S.PORT DMA/USART IRQ prio to achieve faster switching to input

* Remove useless delays

* Fix flashing external ELRS module

* Added a retry mechanism for FrSky S.PORT update

* Remove useless enableRx()

* External FrSky modules are all flashed via S.PORT

* Remove power management unit update

This was only used on the first batch of X-lite.
This commit is contained in:
Raphael Coeffic
2023-02-09 19:44:32 +10:00
committed by GitHub
parent d80adc6c4d
commit 72193eda82
189 changed files with 7960 additions and 8364 deletions
+77 -30
View File
@@ -21,14 +21,17 @@
#include <climits>
#include "ppm.h"
#include "hal/module_port.h"
#include "mixer_scheduler.h"
#include "opentx.h"
// Minimum space after the last PPM pulse in us
#define PPM_SAFE_MARGIN 3000 // 3ms
template <class T>
uint16_t setupPulsesPPM(PpmPulsesData<T>* ppmPulsesData, uint8_t channelsStart,
int8_t channelsCount)
uint16_t setupPulsesPPM(T*& data, uint8_t channelsStart, int8_t channelsCount)
{
uint16_t total = 0;
int16_t PPM_range = g_model.extendedLimits ?
@@ -40,16 +43,13 @@ uint16_t setupPulsesPPM(PpmPulsesData<T>* ppmPulsesData, uint8_t channelsStart,
// The pulse ISR is 2mhz that's why everything is multiplied by 2
uint8_t firstCh = channelsStart;
uint8_t lastCh =
min<uint8_t>(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount);
ppmPulsesData->ptr = ppmPulsesData->pulses;
uint8_t lastCh = min<uint8_t>(MAX_OUTPUT_CHANNELS, firstCh + 8 + channelsCount);
for (uint32_t i = firstCh; i < lastCh; i++) {
int16_t v =
limit((int16_t)-PPM_range, channelOutputs[i], (int16_t)PPM_range) +
2 * PPM_CH_CENTER(i);
*ppmPulsesData->ptr++ = v;
*data++ = v;
total += v;
}
@@ -58,8 +58,9 @@ uint16_t setupPulsesPPM(PpmPulsesData<T>* ppmPulsesData, uint8_t channelsStart,
void setupPulsesPPMTrainer()
{
auto p_data = trainerPulsesData.ppm.pulses;
uint16_t total = setupPulsesPPM<trainer_pulse_duration_t>(
&trainerPulsesData.ppm, g_model.trainerData.channelsStart,
p_data, g_model.trainerData.channelsStart,
g_model.trainerData.channelsCount);
uint32_t rest = PPM_TRAINER_PERIOD_HALF_US();
@@ -72,42 +73,88 @@ void setupPulsesPPMTrainer()
if (rest >= USHRT_MAX - 1)
rest = USHRT_MAX - 1;
*trainerPulsesData.ppm.ptr++ = (uint16_t)rest;
*p_data++ = (uint16_t)rest;
// stop mark so that IRQ-based sending
// knows when to stop
*trainerPulsesData.ppm.ptr = 0;
*p_data = 0;
trainerPulsesData.ppm.ptr = p_data;
}
static void setupPulsesPPMModule(uint8_t module)
static uint32_t setupPulsesPPMModule(uint8_t module, pulse_duration_t*& data)
{
PpmPulsesData<pulse_duration_t>* data = nullptr;
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
if (module == INTERNAL_MODULE) {
data = &intmodulePulsesData.ppm;
} else
#endif
{
data = &extmodulePulsesData.ppm;
}
setupPulsesPPM(&extmodulePulsesData.ppm,
auto start = data;
setupPulsesPPM(data,
g_model.moduleData[module].channelsStart,
g_model.moduleData[module].channelsCount);
// Set the final period to 1ms after which the
// PPM will be switched OFF
*data->ptr++ = PPM_SAFE_MARGIN * 2;
*data++ = PPM_SAFE_MARGIN * 2;
return data - start;
}
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
void setupPulsesPPMInternalModule()
static void* ppmInit(uint8_t module)
{
setupPulsesPPMModule(INTERNAL_MODULE);
}
#if defined(HARDWARE_INTERNAL_MODULE)
// only external module supported
if (module == INTERNAL_MODULE) return nullptr;
#endif
void setupPulsesPPMExternalModule()
{
setupPulsesPPMModule(EXTERNAL_MODULE);
auto delay = GET_MODULE_PPM_DELAY(module) * 2;
etx_timer_config_t cfg = {
.type = ETX_PWM,
.polarity = GET_MODULE_PPM_POLARITY(module),
.cmp_val = (uint16_t)delay,
};
auto mod_st = modulePortInitTimer(module, ETX_MOD_PORT_TIMER, &cfg);
if (!mod_st) return nullptr;
mixerSchedulerSetPeriod(module, PPM_PERIOD(module));
return (void*)mod_st;
}
static void ppmDeInit(void* ctx)
{
auto mod_st = (etx_module_state_t*)ctx;
modulePortDeInit(mod_st);
}
static void ppmSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
{
// TODO:
(void)channels;
(void)nChannels;
auto mod_st = (etx_module_state_t*)ctx;
auto module = modulePortGetModule(mod_st);
pulse_duration_t* pulses = (pulse_duration_t*)buffer;
auto length = setupPulsesPPMModule(module, pulses);
auto drv = modulePortGetTimerDrv(mod_st->tx);
auto drv_ctx = modulePortGetCtx(mod_st->tx);
auto delay = GET_MODULE_PPM_DELAY(module) * 2;
etx_timer_config_t cfg = {
.type = ETX_PWM,
.polarity = GET_MODULE_PPM_POLARITY(module),
.cmp_val = (uint16_t)delay,
};
drv->send(drv_ctx, &cfg, buffer, length);
// PPM_PERIOD is not a constant! It can be set from UI
mixerSchedulerSetPeriod(module, PPM_PERIOD(module));
}
const etx_proto_driver_t PpmDriver = {
.protocol = PROTOCOL_CHANNELS_PPM,
.init = ppmInit,
.deinit = ppmDeInit,
.sendPulses = ppmSendPulses,
.processData = nullptr,
};