Softserial with monotimer and bidir

This commit is contained in:
jflyper 2017-02-04 21:43:41 +09:00 committed by borisbstyle
parent b2c32b84e3
commit 97b5dbc386
11 changed files with 450 additions and 100 deletions

View File

@ -34,6 +34,7 @@
#include "drivers/light_led.h" #include "drivers/light_led.h"
#include "drivers/flash.h" #include "drivers/flash.h"
#include "drivers/display.h" #include "drivers/display.h"
#include "drivers/serial.h"
#include "fc/rc_controls.h" #include "fc/rc_controls.h"
@ -86,6 +87,7 @@
#define mixerConfig(x) (&masterConfig.mixerConfig) #define mixerConfig(x) (&masterConfig.mixerConfig)
#define airplaneConfig(x) (&masterConfig.airplaneConfig) #define airplaneConfig(x) (&masterConfig.airplaneConfig)
#define failsafeConfig(x) (&masterConfig.failsafeConfig) #define failsafeConfig(x) (&masterConfig.failsafeConfig)
#define serialPinConfig(x) (&masterConfig.serialPinConfig)
#define serialConfig(x) (&masterConfig.serialConfig) #define serialConfig(x) (&masterConfig.serialConfig)
#define telemetryConfig(x) (&masterConfig.telemetryConfig) #define telemetryConfig(x) (&masterConfig.telemetryConfig)
#define ibusTelemetryConfig(x) (&masterConfig.telemetryConfig) #define ibusTelemetryConfig(x) (&masterConfig.telemetryConfig)
@ -173,6 +175,7 @@ typedef struct master_s {
airplaneConfig_t airplaneConfig; airplaneConfig_t airplaneConfig;
failsafeConfig_t failsafeConfig; failsafeConfig_t failsafeConfig;
serialPinConfig_t serialPinConfig;
serialConfig_t serialConfig; serialConfig_t serialConfig;
telemetryConfig_t telemetryConfig; telemetryConfig_t telemetryConfig;

View File

@ -17,6 +17,8 @@
#pragma once #pragma once
#include "drivers/io.h"
typedef enum portMode_t { typedef enum portMode_t {
MODE_RX = 1 << 0, MODE_RX = 1 << 0,
MODE_TX = 1 << 1, MODE_TX = 1 << 1,
@ -68,6 +70,21 @@ typedef struct serialPort_s {
serialReceiveCallbackPtr rxCallback; serialReceiveCallbackPtr rxCallback;
} serialPort_t; } 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 { struct serialPortVTable {
void (*serialWrite)(serialPort_t *instance, uint8_t ch); void (*serialWrite)(serialPort_t *instance, uint8_t ch);

View File

@ -25,8 +25,12 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "build/atomic.h" #include "build/atomic.h"
#include "build/debug.h"
#include "common/utils.h" #include "common/utils.h"
#include "config/config_master.h"
#include "nvic.h" #include "nvic.h"
#include "system.h" #include "system.h"
#include "io.h" #include "io.h"
@ -44,21 +48,29 @@
#define MAX_SOFTSERIAL_PORTS 1 #define MAX_SOFTSERIAL_PORTS 1
#endif #endif
typedef enum {
TIMER_MODE_SINGLE,
TIMER_MODE_DUAL,
} timerMode_e;
typedef struct softSerial_s { typedef struct softSerial_s {
serialPort_t port; serialPort_t port;
IO_t rxIO; IO_t rxIO;
IO_t txIO; 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]; volatile uint8_t txBuffer[SOFTSERIAL_BUFFER_SIZE];
uint8_t isSearchingForStartBit; uint8_t isSearchingForStartBit;
uint8_t rxBitIndex; uint8_t rxBitIndex;
uint8_t rxLastLeadingEdgeAtBitIndex; uint8_t rxLastLeadingEdgeAtBitIndex;
uint8_t rxEdge; uint8_t rxEdge;
uint8_t rxActive;
uint8_t isTransmittingData; uint8_t isTransmittingData;
int8_t bitsLeftToTransmit; int8_t bitsLeftToTransmit;
@ -70,23 +82,20 @@ typedef struct softSerial_s {
uint16_t receiveErrors; uint16_t receiveErrors;
uint8_t softSerialPortIndex; uint8_t softSerialPortIndex;
timerMode_e timerMode;
timerCCHandlerRec_t timerCb; timerOvrHandlerRec_t overCb;
timerCCHandlerRec_t edgeCb; timerCCHandlerRec_t edgeCb;
} softSerial_t; } softSerial_t;
extern timerHardware_t* serialTimerHardware; static const struct serialPortVTable softSerialVTable; // Forward
extern softSerial_t softSerialPorts[];
extern const struct serialPortVTable softSerialVTable[]; static softSerial_t softSerialPorts[MAX_SOFTSERIAL_PORTS];
void onSerialTimerOverflow(timerOvrHandlerRec_t *cbRec, captureCompare_t capture);
softSerial_t softSerialPorts[MAX_SOFTSERIAL_PORTS];
void onSerialTimer(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
void onSerialRxPinChange(timerCCHandlerRec_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) { if (softSerial->port.options & SERIAL_INVERTED) {
state = !state; 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); uint32_t bit;
#ifdef STM32F1
IOConfigGPIO(IOGetByTag(pin), IOCFG_IPU); #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 #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 #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); softSerial->rxActive = true;
IOConfigGPIO(IOGetByTag(pin), IOCFG_OUT_PP); #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) static bool isTimerPeriodTooLarge(uint32_t timerPeriod)
@ -120,10 +192,12 @@ static bool isTimerPeriodTooLarge(uint32_t timerPeriod)
return timerPeriod > 0xFFFF; 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; uint32_t timerPeriod;
do { do {
timerPeriod = clock / baud; timerPeriod = clock / baud;
if (isTimerPeriodTooLarge(timerPeriod)) { if (isTimerPeriodTooLarge(timerPeriod)) {
@ -136,10 +210,9 @@ static void serialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t
} }
} while (isTimerPeriodTooLarge(timerPeriod)); } while (isTimerPeriodTooLarge(timerPeriod));
uint8_t mhz = SystemCoreClock / 1000000; uint8_t mhz = baseClock / 1000000;
timerConfigure(timerHardwarePtr, timerPeriod, mhz); 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) 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); 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) static void resetBuffers(softSerial_t *softSerial)
{ {
softSerial->port.rxBufferSize = SOFTSERIAL_BUFFER_SIZE; softSerial->port.rxBufferSize = SOFTSERIAL_BUFFER_SIZE;
@ -177,71 +242,131 @@ static void resetBuffers(softSerial_t *softSerial)
softSerial->port.txBufferHead = 0; 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]); softSerial_t *softSerial = &(softSerialPorts[portIndex]);
#ifdef USE_SOFTSERIAL1 int pinCfgIndex = portIndex + RESOURCE_SOFT_OFFSET;
if (portIndex == SOFTSERIAL1) {
softSerial->rxTimerHardware = &(timerHardware[SOFTSERIAL_1_TIMER_RX_HARDWARE]);
softSerial->txTimerHardware = &(timerHardware[SOFTSERIAL_1_TIMER_TX_HARDWARE]);
}
#endif
#ifdef USE_SOFTSERIAL2 ioTag_t tagRx = serialPinConfig()->ioTagRx[pinCfgIndex];
if (portIndex == SOFTSERIAL2) { ioTag_t tagTx = serialPinConfig()->ioTagTx[pinCfgIndex];
softSerial->rxTimerHardware = &(timerHardware[SOFTSERIAL_2_TIMER_RX_HARDWARE]);
softSerial->txTimerHardware = &(timerHardware[SOFTSERIAL_2_TIMER_TX_HARDWARE]);
}
#endif
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.baudRate = baud;
softSerial->port.mode = MODE_RXTX; softSerial->port.mode = mode;
softSerial->port.options = options; softSerial->port.options = options;
softSerial->port.rxCallback = rxCallback; softSerial->port.rxCallback = rxCallback;
resetBuffers(softSerial); resetBuffers(softSerial);
softSerial->isTransmittingData = false; softSerial->softSerialPortIndex = portIndex;
softSerial->isSearchingForStartBit = true;
softSerial->rxBitIndex = 0;
softSerial->transmissionErrors = 0; softSerial->transmissionErrors = 0;
softSerial->receiveErrors = 0; softSerial->receiveErrors = 0;
softSerial->softSerialPortIndex = portIndex; softSerial->rxActive = false;
softSerial->isTransmittingData = false;
softSerial->txIO = IOGetByTag(softSerial->txTimerHardware->tag); // Configure master timer (on RX); time base and input capture
serialOutputPortConfig(softSerial->txTimerHardware->tag, portIndex);
softSerial->rxIO = IOGetByTag(softSerial->rxTimerHardware->tag); serialTimerConfigureTimebase(softSerial->timerHardware, baud);
serialInputPortConfig(softSerial->rxTimerHardware->tag, portIndex); serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, (options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
setTxSignal(softSerial, ENABLE); // Initialize callbacks
delay(50); timerChCCHandlerInit(&softSerial->edgeCb, onSerialRxPinChange);
timerChOvrHandlerInit(&softSerial->overCb, onSerialTimerOverflow);
serialTimerTxConfig(softSerial->txTimerHardware, portIndex, baud); // Configure bit clock interrupt & handler.
serialTimerRxConfig(softSerial->rxTimerHardware, portIndex, options); // 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; return &softSerial->port;
} }
/*********************************************/ /*********************************************/
//
// Serial engines
//
void processTxState(softSerial_t *softSerial) void processTxState(softSerial_t *softSerial)
{ {
uint8_t mask; uint8_t mask;
if (!softSerial->isTransmittingData) { if (!softSerial->isTransmittingData) {
char byteToSend;
if (isSoftSerialTransmitBufferEmpty((serialPort_t *)softSerial)) { 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; return;
} }
// data to send // 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) { if (softSerial->port.txBufferTail >= softSerial->port.txBufferSize) {
softSerial->port.txBufferTail = 0; softSerial->port.txBufferTail = 0;
} }
@ -251,6 +376,12 @@ void processTxState(softSerial_t *softSerial)
softSerial->bitsLeftToTransmit = TX_TOTAL_BITS; softSerial->bitsLeftToTransmit = TX_TOTAL_BITS;
softSerial->isTransmittingData = true; softSerial->isTransmittingData = true;
if (softSerial->rxActive && (softSerial->port.options & SERIAL_BIDIR)) {
// Half-duplex: Deactivate receiver, activate transmitter
serialInputPortDeActivate(softSerial);
serialOutputPortActivate(softSerial);
}
return; return;
} }
@ -288,9 +419,7 @@ void prepareForNextRxByte(softSerial_t *softSerial)
softSerial->isSearchingForStartBit = true; softSerial->isSearchingForStartBit = true;
if (softSerial->rxEdge == LEADING) { if (softSerial->rxEdge == LEADING) {
softSerial->rxEdge = TRAILING; softSerial->rxEdge = TRAILING;
serialICConfig( serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel,
softSerial->rxTimerHardware->tim,
softSerial->rxTimerHardware->channel,
(softSerial->port.options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling (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); UNUSED(capture);
softSerial_t *softSerial = container_of(cbRec, softSerial_t, timerCb); //debug[0]++;
processTxState(softSerial); softSerial_t *softSerial = container_of(cbRec, softSerial_t, overCb);
processRxState(softSerial);
if (softSerial->port.mode & MODE_TX)
processTxState(softSerial);
if (softSerial->port.mode & MODE_RX)
processRxState(softSerial);
} }
void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture) void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
{ {
UNUSED(capture); UNUSED(capture);
//debug[1]++;
softSerial_t *softSerial = container_of(cbRec, softSerial_t, edgeCb); softSerial_t *softSerial = container_of(cbRec, softSerial_t, edgeCb);
bool inverted = softSerial->port.options & SERIAL_INVERTED; bool inverted = softSerial->port.options & SERIAL_INVERTED;
@ -371,12 +506,12 @@ void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
// synchronise bit counter // synchronise bit counter
// FIXME this reduces functionality somewhat as receiving breaks concurrent transmission on all ports because // 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. // the next callback to the onSerialTimer will happen too early causing transmission errors.
TIM_SetCounter(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->tim->ARR / 2); TIM_SetCounter(softSerial->timerHardware->tim, softSerial->timerHardware->tim->ARR / 2);
if (softSerial->isTransmittingData) { if ((softSerial->timerMode != TIMER_MODE_DUAL) && softSerial->isTransmittingData) {
softSerial->transmissionErrors++; 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->rxEdge = LEADING;
softSerial->rxBitIndex = 0; softSerial->rxBitIndex = 0;
@ -394,13 +529,17 @@ void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
if (softSerial->rxEdge == TRAILING) { if (softSerial->rxEdge == TRAILING) {
softSerial->rxEdge = LEADING; 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 { } else {
softSerial->rxEdge = TRAILING; 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) uint32_t softSerialRxBytesWaiting(const serialPort_t *instance)
{ {
if ((instance->mode & MODE_RX) == 0) { 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) void softSerialSetBaudRate(serialPort_t *s, uint32_t baudRate)
{ {
softSerial_t *softSerial = (softSerial_t *)s; 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) void softSerialSetMode(serialPort_t *instance, portMode_t mode)
@ -468,19 +610,17 @@ bool isSoftSerialTransmitBufferEmpty(const serialPort_t *instance)
return instance->txBufferHead == instance->txBufferTail; return instance->txBufferHead == instance->txBufferTail;
} }
const struct serialPortVTable softSerialVTable[] = { static const struct serialPortVTable softSerialVTable = {
{ .serialWrite = softSerialWriteByte,
.serialWrite = softSerialWriteByte, .serialTotalRxWaiting = softSerialRxBytesWaiting,
.serialTotalRxWaiting = softSerialRxBytesWaiting, .serialTotalTxFree = softSerialTxBytesFree,
.serialTotalTxFree = softSerialTxBytesFree, .serialRead = softSerialReadByte,
.serialRead = softSerialReadByte, .serialSetBaudRate = softSerialSetBaudRate,
.serialSetBaudRate = softSerialSetBaudRate, .isSerialTransmitBufferEmpty = isSoftSerialTransmitBufferEmpty,
.isSerialTransmitBufferEmpty = isSoftSerialTransmitBufferEmpty, .setMode = softSerialSetMode,
.setMode = softSerialSetMode, .writeBuf = NULL,
.writeBuf = NULL, .beginWrite = NULL,
.beginWrite = NULL, .endWrite = NULL
.endWrite = NULL
}
}; };
#endif #endif

View File

@ -24,7 +24,7 @@ typedef enum {
SOFTSERIAL2 SOFTSERIAL2
} softSerialPortIndex_e; } 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 // serialPort API
void softSerialWriteByte(serialPort_t *instance, uint8_t ch); void softSerialWriteByte(serialPort_t *instance, uint8_t ch);

View File

@ -3342,6 +3342,8 @@ const cliResourceValue_t resourceTable[] = {
#ifdef LED_STRIP #ifdef LED_STRIP
{ OWNER_LED_STRIP, &ledStripConfig()->ioTag, 0 }, { OWNER_LED_STRIP, &ledStripConfig()->ioTag, 0 },
#endif #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) static void printResource(uint8_t dumpMask, const master_t *defaultConfig)

View File

@ -428,6 +428,175 @@ void resetBatteryConfig(batteryConfig_t *batteryConfig)
batteryConfig->consumptionWarningPercentage = 10; 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 #ifdef SWAP_SERIAL_PORT_0_AND_1_DEFAULTS
#define FIRST_PORT_INDEX 1 #define FIRST_PORT_INDEX 1
#define SECOND_PORT_INDEX 0 #define SECOND_PORT_INDEX 0
@ -747,6 +916,8 @@ void createDefaultConfig(master_t *config)
config->gpsConfig.autoBaud = GPS_AUTOBAUD_OFF; config->gpsConfig.autoBaud = GPS_AUTOBAUD_OFF;
#endif #endif
resetSerialPinConfig(&config->serialPinConfig);
resetSerialConfig(&config->serialConfig); resetSerialConfig(&config->serialConfig);
resetProfile(&config->profile[0]); resetProfile(&config->profile[0]);

View File

@ -352,14 +352,12 @@ serialPort_t *openSerialPort(
#endif #endif
#ifdef USE_SOFTSERIAL1 #ifdef USE_SOFTSERIAL1
case SERIAL_PORT_SOFTSERIAL1: case SERIAL_PORT_SOFTSERIAL1:
serialPort = openSoftSerial(SOFTSERIAL1, rxCallback, baudRate, options); serialPort = openSoftSerial(SOFTSERIAL1, rxCallback, baudRate, mode, options);
serialSetMode(serialPort, mode);
break; break;
#endif #endif
#ifdef USE_SOFTSERIAL2 #ifdef USE_SOFTSERIAL2
case SERIAL_PORT_SOFTSERIAL2: case SERIAL_PORT_SOFTSERIAL2:
serialPort = openSoftSerial(SOFTSERIAL2, rxCallback, baudRate, options); serialPort = openSoftSerial(SOFTSERIAL2, rxCallback, baudRate, mode, options);
serialSetMode(serialPort, mode);
break; break;
#endif #endif
default: default:

View File

@ -81,6 +81,8 @@ typedef enum {
extern const serialPortIdentifier_e serialPortIdentifiers[SERIAL_PORT_COUNT]; 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 // runtime
// //

View File

@ -68,7 +68,8 @@
#define USE_UART1 #define USE_UART1
#define USE_UART2 #define USE_UART2
#define USE_UART3 #define USE_UART3
#define SERIAL_PORT_COUNT 4 #define USE_SOFTSERIAL1
#define SERIAL_PORT_COUNT 5
#define UART1_TX_PIN PA9 #define UART1_TX_PIN PA9
#define UART1_RX_PIN PA10 #define UART1_RX_PIN PA10
@ -79,8 +80,9 @@
#define UART3_TX_PIN PB10 // PB10 (AF7) #define UART3_TX_PIN PB10 // PB10 (AF7)
#define UART3_RX_PIN PB11 // PB11 (AF7) #define UART3_RX_PIN PB11 // PB11 (AF7)
#define USE_I2C #undef USE_I2C
#define I2C_DEVICE (I2CDEV_1) // PB6/SCL, PB7/SDA //#define USE_I2C
//#define I2C_DEVICE (I2CDEV_1) // PB6/SCL, PB7/SDA
#define USE_ESCSERIAL #define USE_ESCSERIAL
#define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1 #define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1

View File

@ -125,11 +125,23 @@
#define UART6_RX_PIN PC7 #define UART6_RX_PIN PC7
#define UART6_TX_PIN PC6 #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 USE_ESCSERIAL
#define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1 #define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1
#define SERIAL_PORT_COUNT 4 //VCP, USART1, USART3, USART6
#define USE_SPI #define USE_SPI
#define USE_SPI_DEVICE_1 #define USE_SPI_DEVICE_1

View File

@ -157,7 +157,10 @@
#define UART6_RX_PIN PC7 #define UART6_RX_PIN PC7
#define UART6_TX_PIN PC6 #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 USE_ESCSERIAL
#define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1 #define ESCSERIAL_TIMER_TX_HARDWARE 0 // PWM 1