Softserial with monotimer and bidir
This commit is contained in:
parent
b2c32b84e3
commit
97b5dbc386
|
@ -34,6 +34,7 @@
|
|||
#include "drivers/light_led.h"
|
||||
#include "drivers/flash.h"
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/serial.h"
|
||||
|
||||
#include "fc/rc_controls.h"
|
||||
|
||||
|
@ -86,6 +87,7 @@
|
|||
#define mixerConfig(x) (&masterConfig.mixerConfig)
|
||||
#define airplaneConfig(x) (&masterConfig.airplaneConfig)
|
||||
#define failsafeConfig(x) (&masterConfig.failsafeConfig)
|
||||
#define serialPinConfig(x) (&masterConfig.serialPinConfig)
|
||||
#define serialConfig(x) (&masterConfig.serialConfig)
|
||||
#define telemetryConfig(x) (&masterConfig.telemetryConfig)
|
||||
#define ibusTelemetryConfig(x) (&masterConfig.telemetryConfig)
|
||||
|
@ -173,6 +175,7 @@ typedef struct master_s {
|
|||
airplaneConfig_t airplaneConfig;
|
||||
|
||||
failsafeConfig_t failsafeConfig;
|
||||
serialPinConfig_t serialPinConfig;
|
||||
serialConfig_t serialConfig;
|
||||
telemetryConfig_t telemetryConfig;
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "drivers/io.h"
|
||||
|
||||
typedef enum portMode_t {
|
||||
MODE_RX = 1 << 0,
|
||||
MODE_TX = 1 << 1,
|
||||
|
@ -68,6 +70,21 @@ typedef struct serialPort_s {
|
|||
serialReceiveCallbackPtr rxCallback;
|
||||
} serialPort_t;
|
||||
|
||||
#if defined(USE_SOFTSERIAL1) || defined(USE_SOFTSERIAL2)
|
||||
# ifdef USE_SOFTSERIAL2
|
||||
# define SERIAL_PORT_MAX_INDEX (RESOURCE_SOFT_OFFSET + 2)
|
||||
# else
|
||||
# define SERIAL_PORT_MAX_INDEX (RESOURCE_SOFT_OFFSET + 1)
|
||||
# endif
|
||||
#else
|
||||
# define SERIAL_PORT_MAX_INDEX RESOURCE_SOFT_OFFSET
|
||||
#endif
|
||||
|
||||
typedef struct serialPinConfig_s {
|
||||
ioTag_t ioTagTx[SERIAL_PORT_MAX_INDEX];
|
||||
ioTag_t ioTagRx[SERIAL_PORT_MAX_INDEX];
|
||||
} serialPinConfig_t;
|
||||
|
||||
struct serialPortVTable {
|
||||
void (*serialWrite)(serialPort_t *instance, uint8_t ch);
|
||||
|
||||
|
|
|
@ -25,8 +25,12 @@
|
|||
#include "build/build_config.h"
|
||||
#include "build/atomic.h"
|
||||
|
||||
#include "build/debug.h"
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "config/config_master.h"
|
||||
|
||||
#include "nvic.h"
|
||||
#include "system.h"
|
||||
#include "io.h"
|
||||
|
@ -44,21 +48,29 @@
|
|||
#define MAX_SOFTSERIAL_PORTS 1
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
TIMER_MODE_SINGLE,
|
||||
TIMER_MODE_DUAL,
|
||||
} timerMode_e;
|
||||
|
||||
typedef struct softSerial_s {
|
||||
serialPort_t port;
|
||||
|
||||
IO_t rxIO;
|
||||
IO_t txIO;
|
||||
const timerHardware_t *rxTimerHardware;
|
||||
volatile uint8_t rxBuffer[SOFTSERIAL_BUFFER_SIZE];
|
||||
|
||||
const timerHardware_t *txTimerHardware;
|
||||
const timerHardware_t *timerHardware;
|
||||
const timerHardware_t *exTimerHardware;
|
||||
uint32_t ccEnableBit;
|
||||
|
||||
volatile uint8_t rxBuffer[SOFTSERIAL_BUFFER_SIZE];
|
||||
volatile uint8_t txBuffer[SOFTSERIAL_BUFFER_SIZE];
|
||||
|
||||
uint8_t isSearchingForStartBit;
|
||||
uint8_t rxBitIndex;
|
||||
uint8_t rxLastLeadingEdgeAtBitIndex;
|
||||
uint8_t rxEdge;
|
||||
uint8_t rxActive;
|
||||
|
||||
uint8_t isTransmittingData;
|
||||
int8_t bitsLeftToTransmit;
|
||||
|
@ -70,23 +82,20 @@ typedef struct softSerial_s {
|
|||
uint16_t receiveErrors;
|
||||
|
||||
uint8_t softSerialPortIndex;
|
||||
timerMode_e timerMode;
|
||||
|
||||
timerCCHandlerRec_t timerCb;
|
||||
timerOvrHandlerRec_t overCb;
|
||||
timerCCHandlerRec_t edgeCb;
|
||||
} softSerial_t;
|
||||
|
||||
extern timerHardware_t* serialTimerHardware;
|
||||
extern softSerial_t softSerialPorts[];
|
||||
static const struct serialPortVTable softSerialVTable; // Forward
|
||||
|
||||
extern const struct serialPortVTable softSerialVTable[];
|
||||
static softSerial_t softSerialPorts[MAX_SOFTSERIAL_PORTS];
|
||||
|
||||
|
||||
softSerial_t softSerialPorts[MAX_SOFTSERIAL_PORTS];
|
||||
|
||||
void onSerialTimer(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||
void onSerialTimerOverflow(timerOvrHandlerRec_t *cbRec, captureCompare_t capture);
|
||||
void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||
|
||||
void setTxSignal(softSerial_t *softSerial, uint8_t state)
|
||||
static void setTxSignal(softSerial_t *softSerial, uint8_t state)
|
||||
{
|
||||
if (softSerial->port.options & SERIAL_INVERTED) {
|
||||
state = !state;
|
||||
|
@ -99,20 +108,83 @@ void setTxSignal(softSerial_t *softSerial, uint8_t state)
|
|||
}
|
||||
}
|
||||
|
||||
void serialInputPortConfig(ioTag_t pin, uint8_t portIndex)
|
||||
// XXX CCEnableBit: Compute CCxE bit.
|
||||
// XXX (Note: timer.c:timerChICPolarity() uses "TIM_CCER_CC1P << timHw->channel".)
|
||||
|
||||
static uint32_t CCEnableBit(int channel)
|
||||
{
|
||||
IOInit(IOGetByTag(pin), OWNER_SERIAL_RX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
#ifdef STM32F1
|
||||
IOConfigGPIO(IOGetByTag(pin), IOCFG_IPU);
|
||||
uint32_t bit;
|
||||
|
||||
#if defined(STM32F7)
|
||||
switch (channel) {
|
||||
case TIM_CHANNEL_1:
|
||||
bit = TIM_CCER_CC1E;
|
||||
break;
|
||||
case TIM_CHANNEL_2:
|
||||
bit = TIM_CCER_CC2E;
|
||||
break;
|
||||
case TIM_CHANNEL_3:
|
||||
bit = TIM_CCER_CC3E;
|
||||
break;
|
||||
case TIM_CHANNEL_4:
|
||||
bit = TIM_CCER_CC4E;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
IOConfigGPIO(IOGetByTag(pin), IOCFG_AF_PP_UP);
|
||||
switch (channel) {
|
||||
case TIM_Channel_1:
|
||||
bit = TIM_CCER_CC1E;
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
bit = TIM_CCER_CC2E;
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
bit = TIM_CCER_CC3E;
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
bit = TIM_CCER_CC4E;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
static void serialOutputPortConfig(ioTag_t pin, uint8_t portIndex)
|
||||
static void serialInputPortActivate(softSerial_t *softSerial)
|
||||
{
|
||||
IOInit(IOGetByTag(pin), OWNER_SERIAL_TX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
IOConfigGPIO(IOGetByTag(pin), IOCFG_OUT_PP);
|
||||
softSerial->rxActive = true;
|
||||
#ifdef STM32F1
|
||||
IOConfigGPIO(softSerial->rxIO, IOCFG_IPU);
|
||||
#else
|
||||
IOConfigGPIO(softSerial->rxIO, IOCFG_AF_PP_UP);
|
||||
#endif
|
||||
|
||||
softSerial->isSearchingForStartBit = true;
|
||||
softSerial->rxBitIndex = 0;
|
||||
|
||||
// Enable input capture
|
||||
|
||||
softSerial->timerHardware->tim->CCER |= softSerial->ccEnableBit;
|
||||
}
|
||||
|
||||
static void serialInputPortDeActivate(softSerial_t *softSerial)
|
||||
{
|
||||
// Disable input capture
|
||||
|
||||
softSerial->timerHardware->tim->CCER &= ~softSerial->ccEnableBit;
|
||||
|
||||
IOConfigGPIO(softSerial->rxIO, IOCFG_IN_FLOATING);
|
||||
softSerial->rxActive = false;
|
||||
}
|
||||
|
||||
static void serialOutputPortActivate(softSerial_t *softSerial)
|
||||
{
|
||||
IOConfigGPIO(softSerial->txIO, IOCFG_OUT_PP);
|
||||
}
|
||||
|
||||
static void serialOutputPortDeActivate(softSerial_t *softSerial)
|
||||
{
|
||||
IOConfigGPIO(softSerial->txIO, IOCFG_IN_FLOATING);
|
||||
}
|
||||
|
||||
static bool isTimerPeriodTooLarge(uint32_t timerPeriod)
|
||||
|
@ -120,10 +192,12 @@ static bool isTimerPeriodTooLarge(uint32_t timerPeriod)
|
|||
return timerPeriod > 0xFFFF;
|
||||
}
|
||||
|
||||
static void serialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference, uint32_t baud)
|
||||
static void serialTimerConfigureTimebase(const timerHardware_t *timerHardwarePtr, uint32_t baud)
|
||||
{
|
||||
uint32_t clock = SystemCoreClock;
|
||||
uint32_t baseClock = SystemCoreClock / timerClockDivisor(timerHardwarePtr->tim);
|
||||
uint32_t clock = baseClock;
|
||||
uint32_t timerPeriod;
|
||||
|
||||
do {
|
||||
timerPeriod = clock / baud;
|
||||
if (isTimerPeriodTooLarge(timerPeriod)) {
|
||||
|
@ -136,10 +210,9 @@ static void serialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t
|
|||
}
|
||||
} while (isTimerPeriodTooLarge(timerPeriod));
|
||||
|
||||
uint8_t mhz = SystemCoreClock / 1000000;
|
||||
uint8_t mhz = baseClock / 1000000;
|
||||
|
||||
timerConfigure(timerHardwarePtr, timerPeriod, mhz);
|
||||
timerChCCHandlerInit(&softSerialPorts[reference].timerCb, onSerialTimer);
|
||||
timerChConfigCallbacks(timerHardwarePtr, &softSerialPorts[reference].timerCb, NULL);
|
||||
}
|
||||
|
||||
static void serialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity)
|
||||
|
@ -156,14 +229,6 @@ static void serialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity)
|
|||
TIM_ICInit(tim, &TIM_ICInitStructure);
|
||||
}
|
||||
|
||||
static void serialTimerRxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference, portOptions_t options)
|
||||
{
|
||||
// start bit is usually a FALLING signal
|
||||
serialICConfig(timerHardwarePtr->tim, timerHardwarePtr->channel, (options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
timerChCCHandlerInit(&softSerialPorts[reference].edgeCb, onSerialRxPinChange);
|
||||
timerChConfigCallbacks(timerHardwarePtr, &softSerialPorts[reference].edgeCb, NULL);
|
||||
}
|
||||
|
||||
static void resetBuffers(softSerial_t *softSerial)
|
||||
{
|
||||
softSerial->port.rxBufferSize = SOFTSERIAL_BUFFER_SIZE;
|
||||
|
@ -177,71 +242,131 @@ static void resetBuffers(softSerial_t *softSerial)
|
|||
softSerial->port.txBufferHead = 0;
|
||||
}
|
||||
|
||||
serialPort_t *openSoftSerial(softSerialPortIndex_e portIndex, serialReceiveCallbackPtr rxCallback, uint32_t baud, portOptions_t options)
|
||||
serialPort_t *openSoftSerial(softSerialPortIndex_e portIndex, serialReceiveCallbackPtr rxCallback, uint32_t baud, portMode_t mode, portOptions_t options)
|
||||
{
|
||||
softSerial_t *softSerial = &(softSerialPorts[portIndex]);
|
||||
|
||||
#ifdef USE_SOFTSERIAL1
|
||||
if (portIndex == SOFTSERIAL1) {
|
||||
softSerial->rxTimerHardware = &(timerHardware[SOFTSERIAL_1_TIMER_RX_HARDWARE]);
|
||||
softSerial->txTimerHardware = &(timerHardware[SOFTSERIAL_1_TIMER_TX_HARDWARE]);
|
||||
}
|
||||
#endif
|
||||
int pinCfgIndex = portIndex + RESOURCE_SOFT_OFFSET;
|
||||
|
||||
#ifdef USE_SOFTSERIAL2
|
||||
if (portIndex == SOFTSERIAL2) {
|
||||
softSerial->rxTimerHardware = &(timerHardware[SOFTSERIAL_2_TIMER_RX_HARDWARE]);
|
||||
softSerial->txTimerHardware = &(timerHardware[SOFTSERIAL_2_TIMER_TX_HARDWARE]);
|
||||
}
|
||||
#endif
|
||||
ioTag_t tagRx = serialPinConfig()->ioTagRx[pinCfgIndex];
|
||||
ioTag_t tagTx = serialPinConfig()->ioTagTx[pinCfgIndex];
|
||||
|
||||
softSerial->port.vTable = softSerialVTable;
|
||||
const timerHardware_t *timerRx = timerGetByTag(tagRx, TIM_USE_ANY);
|
||||
const timerHardware_t *timerTx = timerGetByTag(tagTx, TIM_USE_ANY);
|
||||
|
||||
IO_t rxIO = IOGetByTag(tagRx);
|
||||
IO_t txIO = IOGetByTag(tagTx);
|
||||
|
||||
if (options & SERIAL_BIDIR) {
|
||||
// If RX and TX pins are both assigned, we CAN use either with a timer.
|
||||
// However, for consistency with hardware UARTs, we only use TX pin,
|
||||
// and this pin must have a timer.
|
||||
if (!timerTx)
|
||||
return NULL;
|
||||
|
||||
softSerial->timerHardware = timerTx;
|
||||
softSerial->txIO = txIO;
|
||||
softSerial->rxIO = txIO;
|
||||
IOInit(txIO, OWNER_SERIAL_TX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
} else {
|
||||
if (mode & MODE_RX) {
|
||||
// Need a pin & a timer on RX
|
||||
if (!(tagRx && timerRx))
|
||||
return NULL;
|
||||
|
||||
softSerial->rxIO = rxIO;
|
||||
softSerial->timerHardware = timerRx;
|
||||
IOInit(rxIO, OWNER_SERIAL_RX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
}
|
||||
|
||||
if (mode & MODE_TX) {
|
||||
// Need a pin on TX
|
||||
if (!tagTx)
|
||||
return NULL;
|
||||
|
||||
softSerial->txIO = txIO;
|
||||
softSerial->exTimerHardware = timerTx;
|
||||
IOInit(txIO, OWNER_SERIAL_TX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
softSerial->ccEnableBit = CCEnableBit(softSerial->timerHardware->channel);
|
||||
|
||||
//debug[2] = softSerial->ccEnableBit;
|
||||
|
||||
softSerial->port.vTable = &softSerialVTable;
|
||||
softSerial->port.baudRate = baud;
|
||||
softSerial->port.mode = MODE_RXTX;
|
||||
softSerial->port.mode = mode;
|
||||
softSerial->port.options = options;
|
||||
softSerial->port.rxCallback = rxCallback;
|
||||
|
||||
resetBuffers(softSerial);
|
||||
|
||||
softSerial->isTransmittingData = false;
|
||||
|
||||
softSerial->isSearchingForStartBit = true;
|
||||
softSerial->rxBitIndex = 0;
|
||||
softSerial->softSerialPortIndex = portIndex;
|
||||
|
||||
softSerial->transmissionErrors = 0;
|
||||
softSerial->receiveErrors = 0;
|
||||
|
||||
softSerial->softSerialPortIndex = portIndex;
|
||||
softSerial->rxActive = false;
|
||||
softSerial->isTransmittingData = false;
|
||||
|
||||
softSerial->txIO = IOGetByTag(softSerial->txTimerHardware->tag);
|
||||
serialOutputPortConfig(softSerial->txTimerHardware->tag, portIndex);
|
||||
// Configure master timer (on RX); time base and input capture
|
||||
|
||||
softSerial->rxIO = IOGetByTag(softSerial->rxTimerHardware->tag);
|
||||
serialInputPortConfig(softSerial->rxTimerHardware->tag, portIndex);
|
||||
serialTimerConfigureTimebase(softSerial->timerHardware, baud);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, (options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
|
||||
setTxSignal(softSerial, ENABLE);
|
||||
delay(50);
|
||||
// Initialize callbacks
|
||||
timerChCCHandlerInit(&softSerial->edgeCb, onSerialRxPinChange);
|
||||
timerChOvrHandlerInit(&softSerial->overCb, onSerialTimerOverflow);
|
||||
|
||||
serialTimerTxConfig(softSerial->txTimerHardware, portIndex, baud);
|
||||
serialTimerRxConfig(softSerial->rxTimerHardware, portIndex, options);
|
||||
// Configure bit clock interrupt & handler.
|
||||
// If we have an extra timer (on TX), it is initialized and configured
|
||||
// for overflow interrupt.
|
||||
// Receiver input capture is configured when input is activated.
|
||||
|
||||
if ((mode & MODE_TX) && softSerial->exTimerHardware && softSerial->exTimerHardware->tim != softSerial->timerHardware->tim) {
|
||||
softSerial->timerMode = TIMER_MODE_DUAL;
|
||||
serialTimerConfigureTimebase(softSerial->exTimerHardware, baud);
|
||||
timerChConfigCallbacks(softSerial->exTimerHardware, NULL, &softSerial->overCb);
|
||||
timerChConfigCallbacks(softSerial->timerHardware, &softSerial->edgeCb, NULL);
|
||||
} else {
|
||||
softSerial->timerMode = TIMER_MODE_SINGLE;
|
||||
timerChConfigCallbacks(softSerial->timerHardware, &softSerial->edgeCb, &softSerial->overCb);
|
||||
}
|
||||
|
||||
if (!(options & SERIAL_BIDIR)) {
|
||||
serialOutputPortActivate(softSerial);
|
||||
setTxSignal(softSerial, ENABLE);
|
||||
}
|
||||
|
||||
serialInputPortActivate(softSerial);
|
||||
|
||||
return &softSerial->port;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
|
||||
//
|
||||
// Serial engines
|
||||
//
|
||||
|
||||
void processTxState(softSerial_t *softSerial)
|
||||
{
|
||||
uint8_t mask;
|
||||
|
||||
if (!softSerial->isTransmittingData) {
|
||||
char byteToSend;
|
||||
if (isSoftSerialTransmitBufferEmpty((serialPort_t *)softSerial)) {
|
||||
// Transmit buffer empty.
|
||||
// Start listening if not already in if half-duplex
|
||||
if (!softSerial->rxActive && softSerial->port.options & SERIAL_BIDIR) {
|
||||
serialOutputPortDeActivate(softSerial);
|
||||
serialInputPortActivate(softSerial);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// data to send
|
||||
byteToSend = softSerial->port.txBuffer[softSerial->port.txBufferTail++];
|
||||
char byteToSend = softSerial->port.txBuffer[softSerial->port.txBufferTail++];
|
||||
if (softSerial->port.txBufferTail >= softSerial->port.txBufferSize) {
|
||||
softSerial->port.txBufferTail = 0;
|
||||
}
|
||||
|
@ -251,6 +376,12 @@ void processTxState(softSerial_t *softSerial)
|
|||
softSerial->bitsLeftToTransmit = TX_TOTAL_BITS;
|
||||
softSerial->isTransmittingData = true;
|
||||
|
||||
if (softSerial->rxActive && (softSerial->port.options & SERIAL_BIDIR)) {
|
||||
// Half-duplex: Deactivate receiver, activate transmitter
|
||||
serialInputPortDeActivate(softSerial);
|
||||
serialOutputPortActivate(softSerial);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -288,9 +419,7 @@ void prepareForNextRxByte(softSerial_t *softSerial)
|
|||
softSerial->isSearchingForStartBit = true;
|
||||
if (softSerial->rxEdge == LEADING) {
|
||||
softSerial->rxEdge = TRAILING;
|
||||
serialICConfig(
|
||||
softSerial->rxTimerHardware->tim,
|
||||
softSerial->rxTimerHardware->channel,
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel,
|
||||
(softSerial->port.options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling
|
||||
);
|
||||
}
|
||||
|
@ -347,18 +476,24 @@ void processRxState(softSerial_t *softSerial)
|
|||
}
|
||||
}
|
||||
|
||||
void onSerialTimer(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
||||
void onSerialTimerOverflow(timerOvrHandlerRec_t *cbRec, captureCompare_t capture)
|
||||
{
|
||||
UNUSED(capture);
|
||||
softSerial_t *softSerial = container_of(cbRec, softSerial_t, timerCb);
|
||||
//debug[0]++;
|
||||
|
||||
processTxState(softSerial);
|
||||
processRxState(softSerial);
|
||||
softSerial_t *softSerial = container_of(cbRec, softSerial_t, overCb);
|
||||
|
||||
if (softSerial->port.mode & MODE_TX)
|
||||
processTxState(softSerial);
|
||||
|
||||
if (softSerial->port.mode & MODE_RX)
|
||||
processRxState(softSerial);
|
||||
}
|
||||
|
||||
void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
||||
{
|
||||
UNUSED(capture);
|
||||
//debug[1]++;
|
||||
|
||||
softSerial_t *softSerial = container_of(cbRec, softSerial_t, edgeCb);
|
||||
bool inverted = softSerial->port.options & SERIAL_INVERTED;
|
||||
|
@ -371,12 +506,12 @@ void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
|||
// synchronise bit counter
|
||||
// FIXME this reduces functionality somewhat as receiving breaks concurrent transmission on all ports because
|
||||
// the next callback to the onSerialTimer will happen too early causing transmission errors.
|
||||
TIM_SetCounter(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->tim->ARR / 2);
|
||||
if (softSerial->isTransmittingData) {
|
||||
TIM_SetCounter(softSerial->timerHardware->tim, softSerial->timerHardware->tim->ARR / 2);
|
||||
if ((softSerial->timerMode != TIMER_MODE_DUAL) && softSerial->isTransmittingData) {
|
||||
softSerial->transmissionErrors++;
|
||||
}
|
||||
|
||||
serialICConfig(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
softSerial->rxEdge = LEADING;
|
||||
|
||||
softSerial->rxBitIndex = 0;
|
||||
|
@ -394,13 +529,17 @@ void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
|||
|
||||
if (softSerial->rxEdge == TRAILING) {
|
||||
softSerial->rxEdge = LEADING;
|
||||
serialICConfig(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
} else {
|
||||
softSerial->rxEdge = TRAILING;
|
||||
serialICConfig(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, inverted ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Standard serial driver API
|
||||
//
|
||||
|
||||
uint32_t softSerialRxBytesWaiting(const serialPort_t *instance)
|
||||
{
|
||||
if ((instance->mode & MODE_RX) == 0) {
|
||||
|
@ -455,7 +594,10 @@ void softSerialWriteByte(serialPort_t *s, uint8_t ch)
|
|||
void softSerialSetBaudRate(serialPort_t *s, uint32_t baudRate)
|
||||
{
|
||||
softSerial_t *softSerial = (softSerial_t *)s;
|
||||
openSoftSerial(softSerial->softSerialPortIndex, s->rxCallback, baudRate, softSerial->port.options);
|
||||
|
||||
softSerial->port.baudRate = baudRate;
|
||||
|
||||
serialTimerConfigureTimebase(softSerial->timerHardware, baudRate);
|
||||
}
|
||||
|
||||
void softSerialSetMode(serialPort_t *instance, portMode_t mode)
|
||||
|
@ -468,19 +610,17 @@ bool isSoftSerialTransmitBufferEmpty(const serialPort_t *instance)
|
|||
return instance->txBufferHead == instance->txBufferTail;
|
||||
}
|
||||
|
||||
const struct serialPortVTable softSerialVTable[] = {
|
||||
{
|
||||
.serialWrite = softSerialWriteByte,
|
||||
.serialTotalRxWaiting = softSerialRxBytesWaiting,
|
||||
.serialTotalTxFree = softSerialTxBytesFree,
|
||||
.serialRead = softSerialReadByte,
|
||||
.serialSetBaudRate = softSerialSetBaudRate,
|
||||
.isSerialTransmitBufferEmpty = isSoftSerialTransmitBufferEmpty,
|
||||
.setMode = softSerialSetMode,
|
||||
.writeBuf = NULL,
|
||||
.beginWrite = NULL,
|
||||
.endWrite = NULL
|
||||
}
|
||||
static const struct serialPortVTable softSerialVTable = {
|
||||
.serialWrite = softSerialWriteByte,
|
||||
.serialTotalRxWaiting = softSerialRxBytesWaiting,
|
||||
.serialTotalTxFree = softSerialTxBytesFree,
|
||||
.serialRead = softSerialReadByte,
|
||||
.serialSetBaudRate = softSerialSetBaudRate,
|
||||
.isSerialTransmitBufferEmpty = isSoftSerialTransmitBufferEmpty,
|
||||
.setMode = softSerialSetMode,
|
||||
.writeBuf = NULL,
|
||||
.beginWrite = NULL,
|
||||
.endWrite = NULL
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@ typedef enum {
|
|||
SOFTSERIAL2
|
||||
} softSerialPortIndex_e;
|
||||
|
||||
serialPort_t *openSoftSerial(softSerialPortIndex_e portIndex, serialReceiveCallbackPtr rxCallback, uint32_t baud, portOptions_t options);
|
||||
serialPort_t *openSoftSerial(softSerialPortIndex_e portIndex, serialReceiveCallbackPtr rxCallback, uint32_t baud, portMode_t mode, portOptions_t options);
|
||||
|
||||
// serialPort API
|
||||
void softSerialWriteByte(serialPort_t *instance, uint8_t ch);
|
||||
|
|
|
@ -3342,6 +3342,8 @@ const cliResourceValue_t resourceTable[] = {
|
|||
#ifdef LED_STRIP
|
||||
{ OWNER_LED_STRIP, &ledStripConfig()->ioTag, 0 },
|
||||
#endif
|
||||
{ OWNER_SERIAL_TX, &serialPinConfig()->ioTagTx[0], SERIAL_PORT_MAX_INDEX },
|
||||
{ OWNER_SERIAL_RX, &serialPinConfig()->ioTagRx[0], SERIAL_PORT_MAX_INDEX },
|
||||
};
|
||||
|
||||
static void printResource(uint8_t dumpMask, const master_t *defaultConfig)
|
||||
|
|
|
@ -428,6 +428,175 @@ void resetBatteryConfig(batteryConfig_t *batteryConfig)
|
|||
batteryConfig->consumptionWarningPercentage = 10;
|
||||
}
|
||||
|
||||
// Default pin (NONE).
|
||||
// XXX Does this mess belong here???
|
||||
#ifdef USE_UART1
|
||||
# if !defined(UART1_RX_PIN)
|
||||
# define UART1_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART1_TX_PIN)
|
||||
# define UART1_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_UART2
|
||||
# if !defined(UART2_RX_PIN)
|
||||
# define UART2_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART2_TX_PIN)
|
||||
# define UART2_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_UART3
|
||||
# if !defined(UART3_RX_PIN)
|
||||
# define UART3_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART3_TX_PIN)
|
||||
# define UART3_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_UART4
|
||||
# if !defined(UART4_RX_PIN)
|
||||
# define UART4_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART4_TX_PIN)
|
||||
# define UART4_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_UART5
|
||||
# if !defined(UART5_RX_PIN)
|
||||
# define UART5_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART5_TX_PIN)
|
||||
# define UART5_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_UART6
|
||||
# if !defined(UART6_RX_PIN)
|
||||
# define UART6_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART6_TX_PIN)
|
||||
# define UART6_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_UART7
|
||||
# if !defined(UART7_RX_PIN)
|
||||
# define UART7_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART7_TX_PIN)
|
||||
# define UART7_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_UART8
|
||||
# if !defined(UART8_RX_PIN)
|
||||
# define UART8_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(UART8_TX_PIN)
|
||||
# define UART8_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_SOFTSERIAL1
|
||||
# if !defined(SOFTSERIAL1_RX_PIN)
|
||||
# define SOFTSERIAL1_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(SOFTSERIAL1_TX_PIN)
|
||||
# define SOFTSERIAL1_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_SOFTSERIAL2
|
||||
# if !defined(SOFTSERIAL2_RX_PIN)
|
||||
# define SOFTSERIAL2_RX_PIN NONE
|
||||
# endif
|
||||
# if !defined(SOFTSERIAL2_TX_PIN)
|
||||
# define SOFTSERIAL2_TX_PIN NONE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void resetSerialPinConfig(serialPinConfig_t *pSerialPinConfig)
|
||||
{
|
||||
for (int port = 0 ; port < SERIAL_PORT_MAX_INDEX ; port++) {
|
||||
pSerialPinConfig->ioTagRx[port] = IO_TAG(NONE);
|
||||
pSerialPinConfig->ioTagTx[port] = IO_TAG(NONE);
|
||||
}
|
||||
|
||||
for (int index = 0 ; index < SERIAL_PORT_COUNT ; index++) {
|
||||
switch (serialPortIdentifiers[index]) {
|
||||
case SERIAL_PORT_USART1:
|
||||
#ifdef USE_UART1
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART1)] = IO_TAG(UART1_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART1)] = IO_TAG(UART1_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USART2:
|
||||
#ifdef USE_UART2
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART2)] = IO_TAG(UART2_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART2)] = IO_TAG(UART2_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USART3:
|
||||
#ifdef USE_UART3
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART3)] = IO_TAG(UART3_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART3)] = IO_TAG(UART3_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USART4:
|
||||
#ifdef USE_UART4
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART4)] = IO_TAG(UART4_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART4)] = IO_TAG(UART4_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USART5:
|
||||
#ifdef USE_UART5
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART5)] = IO_TAG(UART5_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART5)] = IO_TAG(UART5_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USART6:
|
||||
#ifdef USE_UART6
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART6)] = IO_TAG(UART6_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART6)] = IO_TAG(UART6_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USART7:
|
||||
#ifdef USE_UART7
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART7)] = IO_TAG(UART7_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART7)] = IO_TAG(UART7_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USART8:
|
||||
#ifdef USE_UART8
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART8)] = IO_TAG(UART8_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_USART8)] = IO_TAG(UART8_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_SOFTSERIAL1:
|
||||
#ifdef USE_SOFTSERIAL1
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_SOFTSERIAL1)] = IO_TAG(SOFTSERIAL1_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_SOFTSERIAL1)] = IO_TAG(SOFTSERIAL1_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_SOFTSERIAL2:
|
||||
#ifdef USE_SOFTSERIAL2
|
||||
pSerialPinConfig->ioTagRx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_SOFTSERIAL2)] = IO_TAG(SOFTSERIAL2_RX_PIN);
|
||||
pSerialPinConfig->ioTagTx[SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(SERIAL_PORT_SOFTSERIAL2)] = IO_TAG(SOFTSERIAL2_TX_PIN);
|
||||
#endif
|
||||
break;
|
||||
case SERIAL_PORT_USB_VCP:
|
||||
break;
|
||||
case SERIAL_PORT_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SWAP_SERIAL_PORT_0_AND_1_DEFAULTS
|
||||
#define FIRST_PORT_INDEX 1
|
||||
#define SECOND_PORT_INDEX 0
|
||||
|
@ -747,6 +916,8 @@ void createDefaultConfig(master_t *config)
|
|||
config->gpsConfig.autoBaud = GPS_AUTOBAUD_OFF;
|
||||
#endif
|
||||
|
||||
resetSerialPinConfig(&config->serialPinConfig);
|
||||
|
||||
resetSerialConfig(&config->serialConfig);
|
||||
|
||||
resetProfile(&config->profile[0]);
|
||||
|
|
|
@ -352,14 +352,12 @@ serialPort_t *openSerialPort(
|
|||
#endif
|
||||
#ifdef USE_SOFTSERIAL1
|
||||
case SERIAL_PORT_SOFTSERIAL1:
|
||||
serialPort = openSoftSerial(SOFTSERIAL1, rxCallback, baudRate, options);
|
||||
serialSetMode(serialPort, mode);
|
||||
serialPort = openSoftSerial(SOFTSERIAL1, rxCallback, baudRate, mode, options);
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_SOFTSERIAL2
|
||||
case SERIAL_PORT_SOFTSERIAL2:
|
||||
serialPort = openSoftSerial(SOFTSERIAL2, rxCallback, baudRate, options);
|
||||
serialSetMode(serialPort, mode);
|
||||
serialPort = openSoftSerial(SOFTSERIAL2, rxCallback, baudRate, mode, options);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
|
|
@ -81,6 +81,8 @@ typedef enum {
|
|||
|
||||
extern const serialPortIdentifier_e serialPortIdentifiers[SERIAL_PORT_COUNT];
|
||||
|
||||
#define SERIAL_PORT_IDENTIFIER_TO_RESOURCE_INDEX(x) (((x) <= SERIAL_PORT_USART8) ? (x) : (RESOURCE_SOFT_OFFSET + ((x) - SERIAL_PORT_SOFTSERIAL1)))
|
||||
|
||||
//
|
||||
// runtime
|
||||
//
|
||||
|
|
|
@ -68,7 +68,8 @@
|
|||
#define USE_UART1
|
||||
#define USE_UART2
|
||||
#define USE_UART3
|
||||
#define SERIAL_PORT_COUNT 4
|
||||
#define USE_SOFTSERIAL1
|
||||
#define SERIAL_PORT_COUNT 5
|
||||
|
||||
#define UART1_TX_PIN PA9
|
||||
#define UART1_RX_PIN PA10
|
||||
|
@ -79,8 +80,9 @@
|
|||
#define UART3_TX_PIN PB10 // PB10 (AF7)
|
||||
#define UART3_RX_PIN PB11 // PB11 (AF7)
|
||||
|
||||
#define USE_I2C
|
||||
#define I2C_DEVICE (I2CDEV_1) // PB6/SCL, PB7/SDA
|
||||
#undef USE_I2C
|
||||
//#define USE_I2C
|
||||
//#define I2C_DEVICE (I2CDEV_1) // PB6/SCL, PB7/SDA
|
||||
|
||||
#define USE_ESCSERIAL
|
||||
#define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1
|
||||
|
|
|
@ -125,11 +125,23 @@
|
|||
#define UART6_RX_PIN PC7
|
||||
#define UART6_TX_PIN PC6
|
||||
|
||||
#define USE_SOFTSERIAL1
|
||||
//#define SOFTSERIAL1_RX_PIN PC8 // S5_IN (TIM8 CH3)
|
||||
//#define SOFTSERIAL1_TX_PIN PC9 // S6_IN (TIM8 CH4)
|
||||
|
||||
#define USE_SOFTSERIAL2
|
||||
// Special case of using different timers for RX and TX
|
||||
//#define SOFTSERIAL2_RX_PIN PA1 // PWM5, LED_STRIP
|
||||
//#define SOFTSERIAL2_TX_PIN PA8 // PWM6
|
||||
// Experimental (untested)
|
||||
//#define SOFTSERIAL2_RX_PIN PA8 // PWM6
|
||||
//#define SOFTSERIAL2_TX_PIN PB15 // S2_IN
|
||||
|
||||
#define SERIAL_PORT_COUNT 6 //VCP, USART1, USART3, USART6, SOFTSERIALx2
|
||||
|
||||
#define USE_ESCSERIAL
|
||||
#define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1
|
||||
|
||||
#define SERIAL_PORT_COUNT 4 //VCP, USART1, USART3, USART6
|
||||
|
||||
#define USE_SPI
|
||||
|
||||
#define USE_SPI_DEVICE_1
|
||||
|
|
|
@ -157,7 +157,10 @@
|
|||
#define UART6_RX_PIN PC7
|
||||
#define UART6_TX_PIN PC6
|
||||
|
||||
#define SERIAL_PORT_COUNT 4 //VCP, USART1, USART3, USART6
|
||||
#define USE_SOFTSERIAL1
|
||||
#define USE_SOFTSERIAL2
|
||||
|
||||
#define SERIAL_PORT_COUNT 6 //VCP, USART1, USART3, USART6, SOFTSERIALx2
|
||||
|
||||
#define USE_ESCSERIAL
|
||||
#define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1
|
||||
|
|
Loading…
Reference in New Issue