mirror of
https://github.com/iNavFlight/inav.git
synced 2025-07-21 15:25:29 +03:00
git-svn-id: https://afrodevices.googlecode.com/svn/trunk/baseflight@435 7c89a4a9-59b9-e629-4cfe-3a2d53b20e61
323 lines
9.5 KiB
C
323 lines
9.5 KiB
C
#include "board.h"
|
|
|
|
// There needs to be a table of timerMhz per baud rate so the system can set the timer correctly.
|
|
// See http://www.wormfood.net/avrbaudcalc.php?postbitrate=19200&postclock=72
|
|
// Currently defaulting to 3Mhz to support 19200.
|
|
#define SOFT_SERIAL_TIMER_MHZ 3
|
|
#define SOFT_SERIAL_1_TIMER_RX_HARDWARE 4
|
|
#define SOFT_SERIAL_1_TIMER_TX_HARDWARE 5
|
|
|
|
#define RX_TOTAL_BITS 8
|
|
#define TX_TOTAL_BITS 10
|
|
|
|
#define MAX_SOFTSERIAL_PORTS 2
|
|
softSerial_t softSerialPorts[MAX_SOFTSERIAL_PORTS];
|
|
|
|
void onSerialTimer(uint8_t portIndex, uint16_t capture);
|
|
|
|
uint8_t readRxSignal(softSerial_t *softSerial)
|
|
{
|
|
uint8_t invertedSignal = (digitalIn(softSerial->rxTimerHardware->gpio, softSerial->rxTimerHardware->pin) == 0);
|
|
if (softSerial->isInverted) {
|
|
return invertedSignal;
|
|
}
|
|
return !invertedSignal;
|
|
}
|
|
|
|
void setTxSignal(softSerial_t *softSerial, uint8_t state)
|
|
{
|
|
if ((state == 1 && softSerial->isInverted == false) || (state == 0 && softSerial->isInverted == true)) {
|
|
digitalHi(softSerial->txTimerHardware->gpio, softSerial->txTimerHardware->pin);
|
|
} else {
|
|
digitalLo(softSerial->txTimerHardware->gpio, softSerial->txTimerHardware->pin);
|
|
}
|
|
}
|
|
|
|
softSerial_t* lookupSoftSerial(uint8_t reference)
|
|
{
|
|
assert_param(reference >= 0 && reference <= MAX_SOFTSERIAL_PORTS);
|
|
|
|
return &(softSerialPorts[reference]);
|
|
}
|
|
|
|
void resetSerialTimer(softSerial_t *softSerial)
|
|
{
|
|
//uint16_t counter = TIM_GetCounter(softSerial->rxTimerHardware->tim);
|
|
TIM_SetCounter(softSerial->rxTimerHardware->tim, 0);
|
|
//counter = TIM_GetCounter(softSerial->rxTimerHardware->tim);
|
|
}
|
|
|
|
void stopSerialTimer(softSerial_t *softSerial)
|
|
{
|
|
TIM_Cmd(softSerial->rxTimerHardware->tim, DISABLE);
|
|
}
|
|
|
|
void startSerialTimer(softSerial_t *softSerial)
|
|
{
|
|
TIM_Cmd(softSerial->rxTimerHardware->tim, ENABLE);
|
|
}
|
|
|
|
static void softSerialGPIOConfig(GPIO_TypeDef *gpio, uint16_t pin, GPIO_Mode mode)
|
|
{
|
|
gpio_config_t cfg;
|
|
|
|
cfg.pin = pin;
|
|
cfg.mode = mode;
|
|
cfg.speed = Speed_2MHz;
|
|
gpioInit(gpio, &cfg);
|
|
}
|
|
|
|
void serialInputPortConfig(const timerHardware_t *timerHardwarePtr)
|
|
{
|
|
softSerialGPIOConfig(timerHardwarePtr->gpio, timerHardwarePtr->pin, Mode_IPU);
|
|
}
|
|
|
|
#define TICKS_PER_BIT 3
|
|
|
|
void serialTimerConfig(const timerHardware_t *timerHardwarePtr, uint32_t baud, uint8_t reference, timerCCCallbackPtr callback)
|
|
{
|
|
uint16_t timerPeriod = (SOFT_SERIAL_TIMER_MHZ * 1000000) / (baud * TICKS_PER_BIT);
|
|
timerInConfig(timerHardwarePtr, timerPeriod, SOFT_SERIAL_TIMER_MHZ);
|
|
configureTimerCaptureCompareInterrupt(timerHardwarePtr, reference, callback);
|
|
}
|
|
|
|
void serialOutputPortConfig(const timerHardware_t *timerHardwarePtr)
|
|
{
|
|
softSerialGPIOConfig(timerHardwarePtr->gpio, timerHardwarePtr->pin, Mode_Out_PP);
|
|
}
|
|
|
|
void setupSoftSerial1(uint32_t baud, uint8_t inverted)
|
|
{
|
|
int portIndex = 0;
|
|
softSerial_t *softSerial = &(softSerialPorts[portIndex]);
|
|
|
|
softSerial->port.vTable = softSerialVTable;
|
|
softSerial->port.mode = MODE_RXTX;
|
|
softSerial->port.baudRate = baud;
|
|
softSerial->isInverted = inverted;
|
|
|
|
softSerial->rxTimerHardware = &(timerHardware[SOFT_SERIAL_1_TIMER_RX_HARDWARE]);
|
|
softSerial->txTimerHardware = &(timerHardware[SOFT_SERIAL_1_TIMER_TX_HARDWARE]);
|
|
|
|
softSerial->port.rxBufferSize = SOFT_SERIAL_BUFFER_SIZE;
|
|
softSerial->port.rxBuffer = softSerial->rxBuffer;
|
|
softSerial->port.rxBufferTail = 0;
|
|
softSerial->port.rxBufferHead = 0;
|
|
|
|
softSerial->port.txBuffer = softSerial->txBuffer;
|
|
softSerial->port.txBufferSize = SOFT_SERIAL_BUFFER_SIZE,
|
|
softSerial->port.txBufferTail = 0;
|
|
softSerial->port.txBufferHead = 0;
|
|
|
|
softSerial->isTransmittingData = false;
|
|
softSerial->isSearchingForStartBit = true;
|
|
softSerial->isSearchingForStopBit = false;
|
|
|
|
softSerial->timerRxCounter = 1;
|
|
|
|
serialInputPortConfig(softSerial->rxTimerHardware);
|
|
serialOutputPortConfig(softSerial->txTimerHardware);
|
|
|
|
setTxSignal(softSerial, 1);
|
|
delay(50);
|
|
|
|
serialTimerConfig(softSerial->rxTimerHardware, baud, portIndex, onSerialTimer);
|
|
}
|
|
|
|
void updateBufferIndex(softSerial_t *softSerial)
|
|
{
|
|
if (softSerial->port.rxBufferTail >= softSerial->port.rxBufferSize - 1) {
|
|
softSerial->port.rxBufferTail = 0; //cycling the buffer
|
|
} else {
|
|
softSerial->port.rxBufferTail++;
|
|
}
|
|
}
|
|
|
|
/*********************************************/
|
|
|
|
void searchForStartBit(softSerial_t *softSerial)
|
|
{
|
|
char rxSignal = readRxSignal(softSerial);
|
|
if (rxSignal == 1) {
|
|
// start bit not found
|
|
softSerial->timerRxCounter = 1; // process on next timer event
|
|
return;
|
|
}
|
|
|
|
// timer is aligned to falling signal of start bit.
|
|
// three ticks per bit.
|
|
|
|
softSerial->isSearchingForStartBit = false;
|
|
softSerial->internalRxBuffer = 0;
|
|
softSerial->timerRxCounter = TICKS_PER_BIT + 1; // align to middle of next bit
|
|
softSerial->bitsLeftToReceive = RX_TOTAL_BITS;
|
|
softSerial->rxBitSelectionMask = 1;
|
|
}
|
|
|
|
void searchForStopBit(softSerial_t *softSerial)
|
|
{
|
|
char rxSignal;
|
|
softSerial->timerRxCounter = 1;
|
|
|
|
rxSignal = readRxSignal(softSerial);
|
|
if (rxSignal != 1) {
|
|
// not found
|
|
return;
|
|
}
|
|
|
|
softSerial->isSearchingForStopBit = false;
|
|
softSerial->isSearchingForStartBit = true;
|
|
softSerial->internalRxBuffer &= 0xFF;
|
|
|
|
softSerial->port.rxBuffer[softSerial->port.rxBufferTail] = softSerial->internalRxBuffer;
|
|
updateBufferIndex(softSerial);
|
|
}
|
|
|
|
void readDataBit(softSerial_t *softSerial)
|
|
{
|
|
softSerial->timerRxCounter = TICKS_PER_BIT; // keep aligned to middle of bit
|
|
|
|
char rxSignal = readRxSignal(softSerial);
|
|
if (rxSignal) {
|
|
softSerial->internalRxBuffer |= softSerial->rxBitSelectionMask;
|
|
}
|
|
softSerial->rxBitSelectionMask <<= 1;
|
|
if (--softSerial->bitsLeftToReceive <= 0) {
|
|
softSerial->isSearchingForStopBit = true;
|
|
softSerial->timerRxCounter = 2;
|
|
}
|
|
}
|
|
|
|
void processRxState(softSerial_t *softSerial)
|
|
{
|
|
//digitalToggle(softSerial->txTimerHardware->gpio, softSerial->txTimerHardware->pin);
|
|
|
|
if (--softSerial->timerRxCounter > 0) {
|
|
return;
|
|
}
|
|
|
|
if (softSerial->isSearchingForStartBit) {
|
|
searchForStartBit(softSerial);
|
|
return;
|
|
}
|
|
|
|
if (softSerial->isSearchingForStopBit) {
|
|
searchForStopBit(softSerial);
|
|
return;
|
|
}
|
|
|
|
readDataBit(softSerial);
|
|
}
|
|
|
|
|
|
void processTxState(softSerial_t *softSerial)
|
|
{
|
|
char mask;
|
|
|
|
if (!softSerial->isTransmittingData) {
|
|
char byteToSend;
|
|
if (isSoftSerialTransmitBufferEmpty((serialPort_t *)softSerial)) {
|
|
return;
|
|
}
|
|
|
|
// data to send
|
|
byteToSend = softSerial->port.txBuffer[softSerial->port.txBufferTail++];
|
|
if (softSerial->port.txBufferTail >= softSerial->port.txBufferSize) {
|
|
softSerial->port.txBufferTail = 0;
|
|
}
|
|
|
|
// build internal buffer, start bit(1) + data bits + stop bit(0)
|
|
softSerial->internalTxBuffer = (1 << (TX_TOTAL_BITS - 1)) | (byteToSend << 1);
|
|
softSerial->bitsLeftToTransmit = TX_TOTAL_BITS;
|
|
|
|
// start immediately
|
|
softSerial->timerTxCounter = 1;
|
|
softSerial->isTransmittingData = true;
|
|
return;
|
|
}
|
|
|
|
if (--softSerial->timerTxCounter <= 0) {
|
|
mask = softSerial->internalTxBuffer & 1;
|
|
softSerial->internalTxBuffer >>= 1;
|
|
|
|
setTxSignal(softSerial, mask);
|
|
|
|
softSerial->timerTxCounter = TICKS_PER_BIT;
|
|
if (--softSerial->bitsLeftToTransmit <= 0) {
|
|
softSerial->isTransmittingData = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void onSerialTimer(uint8_t portIndex, uint16_t capture)
|
|
{
|
|
softSerial_t *softSerial = &(softSerialPorts[portIndex]);
|
|
|
|
processTxState(softSerial);
|
|
processRxState(softSerial);
|
|
}
|
|
|
|
|
|
uint8_t softSerialTotalBytesWaiting(serialPort_t *instance)
|
|
{
|
|
int availableBytes;
|
|
softSerial_t *softSerial = (softSerial_t *)instance;
|
|
if (softSerial->port.rxBufferTail == softSerial->port.rxBufferHead) {
|
|
return 0;
|
|
}
|
|
|
|
if (softSerial->port.rxBufferTail > softSerial->port.rxBufferHead) {
|
|
availableBytes = softSerial->port.rxBufferTail - softSerial->port.rxBufferHead;
|
|
} else {
|
|
availableBytes = softSerial->port.rxBufferTail + softSerial->port.rxBufferSize - softSerial->port.rxBufferHead;
|
|
}
|
|
return availableBytes;
|
|
}
|
|
|
|
static void moveHeadToNextByte(softSerial_t *softSerial)
|
|
{
|
|
if (softSerial->port.rxBufferHead < softSerial->port.rxBufferSize - 1) {
|
|
softSerial->port.rxBufferHead++;
|
|
} else {
|
|
softSerial->port.rxBufferHead = 0;
|
|
}
|
|
}
|
|
|
|
uint8_t softSerialReadByte(serialPort_t *instance)
|
|
{
|
|
char b;
|
|
if (softSerialTotalBytesWaiting(instance) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
b = instance->rxBuffer[instance->rxBufferHead];
|
|
|
|
moveHeadToNextByte((softSerial_t *)instance);
|
|
return b;
|
|
}
|
|
|
|
void softSerialWriteByte(serialPort_t *s, uint8_t ch)
|
|
{
|
|
s->txBuffer[s->txBufferHead] = ch;
|
|
s->txBufferHead = (s->txBufferHead + 1) % s->txBufferSize;
|
|
}
|
|
|
|
void softSerialSetBaudRate(serialPort_t *s, uint32_t baudRate)
|
|
{
|
|
// not implemented.
|
|
}
|
|
|
|
bool isSoftSerialTransmitBufferEmpty(serialPort_t *instance)
|
|
{
|
|
return instance->txBufferHead == instance->txBufferTail;
|
|
}
|
|
|
|
const struct serialPortVTable softSerialVTable[] = {
|
|
{
|
|
softSerialWriteByte,
|
|
softSerialTotalBytesWaiting,
|
|
softSerialReadByte,
|
|
softSerialSetBaudRate,
|
|
isSoftSerialTransmitBufferEmpty
|
|
}
|
|
};
|