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:
+77
-30
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user