Merge pull request #422 from andreika-git/uart_dma2

Working UART-DMA v2.0
This commit is contained in:
rusefi 2017-05-23 15:15:19 -04:00 committed by GitHub
commit 0db60bf425
9 changed files with 184 additions and 69 deletions

@ -1 +1 @@
Subproject commit fa141e270361bc75da809abe3c6d44c4dc22c46b
Subproject commit 5746069508d98a2ac94a2e0d9bdc46a532f46edf

View File

@ -243,8 +243,16 @@
#define EFI_CONSOLE_UART_DEVICE (&SD3)
#endif
#ifndef TS_SERIAL_UART_DEVICE
// Use 'UART' DMA-mode driver instead of 'SERIAL'
#define TS_UART_DMA_MODE FALSE
#define TS_DMA_UART_DEVICE (&UARTD3)
#define TS_SERIAL_UART_DEVICE (&SD3)
// todo: add DMA-mode for Console & GPS?
#if TS_UART_DMA_MODE
#define EFI_UART_GPS FALSE
#undef EFI_CONSOLE_UART_DEVICE
#endif
// todo: start using consoleSerialTxPin? Not sure

View File

@ -132,8 +132,13 @@
* @brief Enables the SERIAL subsystem.
*/
#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
/* Configured in efifeatures.h */
#if TS_UART_DMA_MODE
#define HAL_USE_SERIAL FALSE
#else
#define HAL_USE_SERIAL TRUE
#endif
#endif
/**
* @brief Enables the SERIAL over USB subsystem.
@ -153,8 +158,13 @@
* @brief Enables the UART subsystem.
*/
#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
/* Configured in efifeatures.h */
#if TS_UART_DMA_MODE
#define HAL_USE_UART TRUE
#else
#define HAL_USE_UART FALSE
#endif
#endif
/**
* @brief Enables the USB subsystem.
@ -353,8 +363,13 @@
* @note Disabling this option saves both code and data space.
*/
#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
/* Configured in efifeatures.h */
#if TS_UART_DMA_MODE
#define UART_USE_WAIT TRUE
#else
#define UART_USE_WAIT FALSE
#endif
#endif
/**
* @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.

View File

@ -34,6 +34,11 @@
*/
#define ICU_PRIORITY 3
/**
* UART DMA-mode byte capture (low latency)
*/
#define UART_DMA_IRQ_PRIORITY (PRECISE_SCHEDULING_TIMER_PRIORITY + 2)
/*
* SysTick driver system settings.
*/
@ -332,12 +337,12 @@
#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#define STM32_UART_USART1_IRQ_PRIORITY 12
#define STM32_UART_USART2_IRQ_PRIORITY 12
#define STM32_UART_USART3_IRQ_PRIORITY 12
#define STM32_UART_UART4_IRQ_PRIORITY 12
#define STM32_UART_UART5_IRQ_PRIORITY 12
#define STM32_UART_USART6_IRQ_PRIORITY 12
#define STM32_UART_USART1_IRQ_PRIORITY UART_DMA_IRQ_PRIORITY
#define STM32_UART_USART2_IRQ_PRIORITY UART_DMA_IRQ_PRIORITY
#define STM32_UART_USART3_IRQ_PRIORITY UART_DMA_IRQ_PRIORITY
#define STM32_UART_UART4_IRQ_PRIORITY UART_DMA_IRQ_PRIORITY
#define STM32_UART_UART5_IRQ_PRIORITY UART_DMA_IRQ_PRIORITY
#define STM32_UART_USART6_IRQ_PRIORITY UART_DMA_IRQ_PRIORITY
#define STM32_UART_USART1_DMA_PRIORITY 0
#define STM32_UART_USART2_DMA_PRIORITY 0
#define STM32_UART_USART3_DMA_PRIORITY 0

View File

@ -110,21 +110,7 @@ extern persistent_config_container_s persistentState;
static efitimems_t previousWriteReportMs = 0;
ts_channel_s tsChannel;
static int ts_serial_ready(bool isConsoleRedirect) {
#if EFI_PROD_CODE || defined(__DOXYGEN__)
if (isCommandLineConsoleOverTTL() ^ isConsoleRedirect) {
// TS uses USB when console uses serial
return is_usb_serial_ready();
} else {
// TS uses serial when console uses USB
return true;
}
#else
return true;
#endif
}
static ts_channel_s tsChannel;
static uint16_t BINARY_RESPONSE = (uint16_t) SWAP_UINT16(BINARY_SWITCH_TAG);
@ -240,6 +226,7 @@ void handlePageSelectCommand(ts_channel_s *tsChannel, ts_response_format_e mode,
}
static void onlineTuneBytes(int currentPageId, uint32_t offset, int count) {
UNUSED(currentPageId);
if (offset > sizeof(engine_configuration_s)) {
int maxSize = sizeof(persistent_config_s) - offset;
if (count > maxSize) {
@ -313,6 +300,8 @@ void handleCrc32Check(ts_channel_s *tsChannel, ts_response_format_e mode, uint16
*/
void handleWriteValueCommand(ts_channel_s *tsChannel, ts_response_format_e mode, uint16_t page, uint16_t offset,
uint8_t value) {
UNUSED(tsChannel);
UNUSED(mode);
tsState.writeValueCommandCounter++;
currentPageId = page;
@ -439,7 +428,7 @@ void runBinaryProtocolLoop(ts_channel_s *tsChannel, bool isConsoleRedirect) {
bool isFirstByte = true;
while (true) {
int isReady = ts_serial_ready(isConsoleRedirect);
int isReady = sr5IsReady(isConsoleRedirect);
if (!isReady) {
chThdSleepMilliseconds(10);
wasReady = false;
@ -562,9 +551,7 @@ static THD_FUNCTION(tsThreadEntryPoint, arg) {
(void) arg;
chRegSetThreadName("tunerstudio thread");
#if EFI_PROD_CODE || defined(__DOXYGEN__)
startTsPort();
#endif
startTsPort(&tsChannel);
runBinaryProtocolLoop(&tsChannel, false);
}
@ -824,8 +811,6 @@ void startTunerStudioConnectivity(void) {
addConsoleAction("reset_ts", resetTs);
addConsoleActionI("set_ts_speed", setTsSpeed);
tsChannel.channel = getTsSerialDevice();
chThdCreateStatic(tsThreadStack, sizeof(tsThreadStack), NORMALPRIO, (tfunc_t)tsThreadEntryPoint, NULL);
}

View File

@ -24,14 +24,61 @@ extern LoggingWithStorage tsLogger;
#if HAL_USE_SERIAL_USB || defined(__DOXYGEN__)
extern SerialUSBDriver SDU1;
#define CONSOLE_DEVICE &SDU1
#else
#define CONSOLE_DEVICE TS_SERIAL_UART_DEVICE
#define CONSOLE_USB_DEVICE &SDU1
#endif
static SerialConfig tsSerialConfig = { 0, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 };
#if TS_UART_DMA_MODE
// Async. FIFO buffer takes some RAM...
static uart_dma_s tsUartDma;
void startTsPort(void) {
/* Common function for all DMA-UART IRQ handlers. */
static void tsCopyDataFromDMA() {
chSysLockFromISR();
// get 0-based DMA buffer position
int dmaPos = TS_DMA_BUFFER_SIZE - dmaStreamGetTransactionSize(TS_DMA_UART_DEVICE->dmarx);
// if the position is wrapped (circular DMA-mode enabled)
if (dmaPos < tsUartDma.readPos)
dmaPos += TS_DMA_BUFFER_SIZE;
// we need to update the current readPos
int newReadPos = tsUartDma.readPos;
for (int i = newReadPos; i < dmaPos; ) {
if (chIQPutI(&tsUartDma.fifoRxQueue, tsUartDma.dmaBuffer[newReadPos]) != Q_OK) {
break; // todo: ignore overflow?
}
// the read position should always stay inside the buffer range
newReadPos = (++i) & (TS_DMA_BUFFER_SIZE - 1);
}
tsUartDma.readPos = newReadPos;
chSysUnlockFromISR();
}
/* We use the same handler code for both halves. */
static void tsRxIRQHalfHandler(UARTDriver *uartp, uartflags_t full) {
UNUSED(uartp);
UNUSED(full);
tsCopyDataFromDMA();
}
/* This handler is called right after the UART receiver has finished its work. */
static void tsRxIRQIdleHandler(UARTDriver *uartp) {
UNUSED(uartp);
tsCopyDataFromDMA();
}
/* Note: This structure is modified from the default ChibiOS layout! */
static UARTConfig tsDmaUartConfig = {
NULL, NULL, NULL, NULL, NULL,
0, 0, 0/*USART_CR2_STOP1_BITS*/ | USART_CR2_LINEN, 0,
/*timeout_cb*/tsRxIRQIdleHandler, /*rxhalf_cb*/tsRxIRQHalfHandler
};
#else
static SerialConfig tsSerialConfig = { 0, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 };
#endif /* TS_UART_DMA_MODE */
#endif /* EFI_PROD_CODE */
void startTsPort(ts_channel_s *tsChannel) {
#if EFI_PROD_CODE || defined(__DOXYGEN__)
#if EFI_USB_SERIAL || defined(__DOXYGEN__)
if (isCommandLineConsoleOverTTL()) {
print("TunerStudio over USB serial");
@ -39,6 +86,8 @@ void startTsPort(void) {
* This method contains a long delay, that's the reason why this is not done on the main thread
*/
usb_serial_start();
// if console uses UART then TS uses USB
tsChannel->channel = (BaseChannel *) CONSOLE_USB_DEVICE;
} else
#endif
{
@ -48,29 +97,32 @@ void startTsPort(void) {
efiSetPadMode("tunerstudio rx", engineConfiguration->binarySerialRxPin, PAL_MODE_ALTERNATE(TS_SERIAL_AF));
efiSetPadMode("tunerstudio tx", engineConfiguration->binarySerialTxPin, PAL_MODE_ALTERNATE(TS_SERIAL_AF));
#if TS_UART_DMA_MODE
print("Using UART-DMA mode");
// init FIFO queue
chIQObjectInit(&tsUartDma.fifoRxQueue, tsUartDma.buffer, sizeof(tsUartDma.buffer), NULL, NULL);
// start DMA driver
tsDmaUartConfig.speed = boardConfiguration->tunerStudioSerialSpeed;
uartStart(TS_DMA_UART_DEVICE, &tsDmaUartConfig);
// start continuous DMA transfer using our circular buffer
tsUartDma.readPos = 0;
uartStartReceive(TS_DMA_UART_DEVICE, sizeof(tsUartDma.dmaBuffer), tsUartDma.dmaBuffer);
#else
print("Using Serial mode");
tsSerialConfig.speed = boardConfiguration->tunerStudioSerialSpeed;
sdStart(TS_SERIAL_UART_DEVICE, &tsSerialConfig);
}
tsChannel->channel = (BaseChannel *) TS_SERIAL_UART_DEVICE;
#endif /* TS_UART_DMA_MODE */
} else
tsChannel->channel = (BaseChannel *) NULL; // actually not used
}
}
#else /* EFI_PROD_CODE */
tsChannel->channel = (BaseChannel *) TS_SIMULATOR_PORT;
#endif /* EFI_PROD_CODE */
BaseChannel * getTsSerialDevice(void) {
#if EFI_PROD_CODE || defined(__DOXYGEN__)
#if EFI_USB_SERIAL || defined(__DOXYGEN__)
if (isCommandLineConsoleOverTTL()) {
// if console uses UART then TS uses USB
return (BaseChannel *) CONSOLE_DEVICE;
} else
#endif
{
return (BaseChannel *) TS_SERIAL_UART_DEVICE;
}
#else
return (BaseChannel *) TS_SIMULATOR_PORT;
#endif
}
void sr5WriteData(ts_channel_s *tsChannel, const uint8_t * buffer, int size) {
@ -78,7 +130,17 @@ void sr5WriteData(ts_channel_s *tsChannel, const uint8_t * buffer, int size) {
#if EFI_SIMULATOR || defined(__DOXYGEN__)
logMsg("chSequentialStreamWrite [%d]\r\n", size);
#endif
#if TS_UART_DMA_MODE && EFI_PROD_CODE
UNUSED(tsChannel);
int transferred = size;
uartSendTimeout(TS_DMA_UART_DEVICE, (size_t *)&transferred, buffer, BINARY_IO_TIMEOUT);
#else
if (tsChannel->channel == NULL)
return;
int transferred = chnWriteTimeout(tsChannel->channel, buffer, size, BINARY_IO_TIMEOUT);
#endif
#if EFI_SIMULATOR || defined(__DOXYGEN__)
logMsg("transferred [%d]\r\n", transferred);
#endif
@ -90,6 +152,18 @@ void sr5WriteData(ts_channel_s *tsChannel, const uint8_t * buffer, int size) {
}
}
int sr5ReadData(ts_channel_s *tsChannel, const uint8_t * buffer, int size) {
#if TS_UART_DMA_MODE && EFI_PROD_CODE
UNUSED(tsChannel);
return (int)chIQReadTimeout(&tsUartDma.fifoRxQueue, (uint8_t * )buffer, (size_t)size, SR5_READ_TIMEOUT);
#else
if (tsChannel->channel == NULL)
return 0;
return chnReadTimeout(tsChannel->channel, (uint8_t * )buffer, size, SR5_READ_TIMEOUT);
#endif
}
/**
* Adds size to the beginning of a packet and a crc32 at the end. Then send the packet.
*/
@ -122,7 +196,17 @@ void sr5SendResponse(ts_channel_s *tsChannel, ts_response_format_e mode, const u
}
}
int sr5ReadData(ts_channel_s *tsChannel, uint8_t * buffer, int size) {
return chnReadTimeout(tsChannel->channel, buffer, size, SR5_READ_TIMEOUT);
bool sr5IsReady(bool isConsoleRedirect) {
#if EFI_PROD_CODE || defined(__DOXYGEN__)
if (isCommandLineConsoleOverTTL() ^ isConsoleRedirect) {
// TS uses USB when console uses serial
return is_usb_serial_ready();
} else {
// TS uses serial when console uses USB
return true;
}
#else
return true;
#endif
}

View File

@ -39,7 +39,7 @@ typedef enum {
typedef struct {
BaseChannel * channel;
uint8_t writeBuffer[4];
uint8_t writeBuffer[7]; // size(2 bytes) + response(1 byte) + crc32 (4 bytes)
/**
* we use 'blockingFactor = 320' in rusefi.ini
* todo: should we just do (320 + CRC_WRAPPING_SIZE) ?
@ -47,6 +47,23 @@ typedef struct {
char crcReadBuffer[BLOCKING_FACTOR + 30];
} ts_channel_s;
// See uart_dma_s
#define TS_FIFO_BUFFER_SIZE (BLOCKING_FACTOR + 30)
// This must be a power of 2!
#define TS_DMA_BUFFER_SIZE 32
// struct needed for async DMA transfer mode (see TS_UART_DMA_MODE)
typedef struct {
// circular DMA buffer
uint8_t dmaBuffer[TS_DMA_BUFFER_SIZE];
// current read position for the DMA buffer
volatile int readPos;
// secondary FIFO buffer for async. transfer
uint8_t buffer[TS_FIFO_BUFFER_SIZE];
// input FIFO Rx queue
input_queue_t fifoRxQueue;
} uart_dma_s;
#define TS_HELLO_COMMAND_DEPRECATED 'H' // 0x48
#define TS_HELLO_COMMAND 'S' // 0x53
#define TS_TEST_COMMAND 't' // 0x74
@ -71,18 +88,19 @@ typedef struct {
// todo: double-check this
#define CRC_WRAPPING_SIZE (CRC_VALUE_SIZE + 3)
BaseChannel * getTsSerialDevice(void);
void startTsPort(void);
// that's 3 seconds
#define BINARY_IO_TIMEOUT MS2ST(3000)
void startTsPort(ts_channel_s *tsChannel);
// that's 3 seconds
#define SR5_READ_TIMEOUT MS2ST(3000)
// that's 1 second
#define BINARY_IO_TIMEOUT MS2ST(1000)
// that's 1 second
#define SR5_READ_TIMEOUT MS2ST(1000)
void sr5WriteData(ts_channel_s *tsChannel, const uint8_t * buffer, int size);
void sr5WriteCrcPacket(ts_channel_s *tsChannel, const uint8_t responseCode, const void *buf, const uint16_t size);
void sr5SendResponse(ts_channel_s *tsChannel, ts_response_format_e mode, const uint8_t * buffer, int size);
int sr5ReadData(ts_channel_s *tsChannel, uint8_t * buffer, int size);
bool sr55IsReady(bool isConsoleRedirect);
#endif /* CONSOLE_TUNERSTUDIO_TUNERSTUDIO_IO_H_ */

View File

@ -72,6 +72,7 @@ static bool getConsoleLine(BaseSequentialStream *chp, char *line, unsigned size)
short c = (short) chSequentialStreamGet(chp);
onDataArrived();
#if defined(EFI_CONSOLE_UART_DEVICE) || defined(__DOXYGEN__)
if (isCommandLineConsoleOverTTL()) {
uint32_t flags;
chSysLock()
@ -80,12 +81,11 @@ static bool getConsoleLine(BaseSequentialStream *chp, char *line, unsigned size)
flags = chEvtGetAndClearFlagsI(&consoleEventListener);
chSysUnlock()
;
if (flags & SD_OVERRUN_ERROR) {
// firmwareError(OBD_PCM_Processor_Fault, "serial overrun");
}
}
#endif
#if EFI_UART_ECHO_TEST_MODE
/**
@ -176,15 +176,15 @@ void runConsoleLoop(ts_channel_s *console) {
#if EFI_PROD_CODE || EFI_EGT || defined(__DOXYGEN__)
SerialDriver * getConsoleChannel(void) {
BaseChannel * getConsoleChannel(void) {
#if defined(EFI_CONSOLE_UART_DEVICE) || defined(__DOXYGEN__)
if (isCommandLineConsoleOverTTL()) {
return (SerialDriver *) EFI_CONSOLE_UART_DEVICE;
return (BaseChannel *) EFI_CONSOLE_UART_DEVICE;
}
#endif /* EFI_CONSOLE_UART_DEVICE */
#if HAL_USE_SERIAL_USB || defined(__DOXYGEN__)
return (SerialDriver *) &SDU1;
return (BaseChannel *) &SDU1;
#else
return NULL;
#endif /* HAL_USE_SERIAL_USB */
@ -217,8 +217,8 @@ static THD_FUNCTION(consoleThreadThreadEntryPoint, arg) {
binaryConsole.channel = (BaseChannel *) getConsoleChannel();
runConsoleLoop(&binaryConsole);
if (binaryConsole.channel != NULL)
runConsoleLoop(&binaryConsole);
}
// 10 seconds

View File

@ -29,7 +29,7 @@ typedef void (*CommandHandler)(char *);
#define GET_CONSOLE_MODE_VALUE() palReadPad(CONSOLE_MODE_SWITCH_PORT, CONSOLE_MODE_SWITCH_PIN)
#define SHOULD_INGORE_FLASH() (palReadPad(CONFIG_RESET_SWITCH_PORT, CONFIG_RESET_SWITCH_PIN) == 0)
SerialDriver * getConsoleChannel(void);
BaseChannel * getConsoleChannel(void);
void consolePutChar(int x);
void consoleOutputBuffer(const uint8_t *buf, int size);