From 3ef4d6385d8b39cfd7b50d557d51118eff5a4dab Mon Sep 17 00:00:00 2001 From: kisslorand Date: Sun, 17 Sep 2023 21:13:22 +0300 Subject: [PATCH] DMA TX --- TFT/src/User/API/RRFSendCmd.c | 64 ++---- TFT/src/User/API/SerialConnection.c | 33 +-- TFT/src/User/API/SerialConnection.h | 3 +- TFT/src/User/Hal/gd32f20x/Serial.c | 197 ++++++++++------ TFT/src/User/Hal/gd32f20x/Serial.h | 5 +- TFT/src/User/Hal/stm32f10x/Serial.c | 153 +++++++++---- TFT/src/User/Hal/stm32f10x/Serial.h | 5 +- TFT/src/User/Hal/stm32f10x/uart.h | 2 +- TFT/src/User/Hal/stm32f2_f4xx/Serial.c | 306 ++++++++++++++++++------- TFT/src/User/Hal/stm32f2_f4xx/Serial.h | 10 +- 10 files changed, 503 insertions(+), 275 deletions(-) diff --git a/TFT/src/User/API/RRFSendCmd.c b/TFT/src/User/API/RRFSendCmd.c index e753cdcae7..b0ed58a8cd 100644 --- a/TFT/src/User/API/RRFSendCmd.c +++ b/TFT/src/User/API/RRFSendCmd.c @@ -1,58 +1,24 @@ -#include "RRFSendCmd.h" -#include "Serial.h" -#include +#include "includes.h" -static uint8_t n_sent = 0; static uint32_t line_number = 0; -static uint8_t checksum = 0; -void sendCharAndChecksum(const char c) +void rrfSendCmd(const char * cmd_ptr) { - checksum ^= c; - Serial_PutChar(SERIAL_PORT, c); - n_sent++; -} + char rrfCmd[CMD_MAX_SIZE]; + char * rrfCmd_ptr = rrfCmd; + uint8_t checksum = 0; -void sendChar(const char c) -{ - if (c == '\n') - { - if (n_sent != 0) - { - Serial_PutChar(SERIAL_PORT, '*'); - char digit0 = checksum % 10 + '0'; - checksum /= 10; - char digit1 = checksum % 10 + '0'; - checksum /= 10; - if (checksum != 0) - { - Serial_PutChar(SERIAL_PORT, checksum + '0'); - } - Serial_PutChar(SERIAL_PORT, digit1); - Serial_PutChar(SERIAL_PORT, digit0); - } - Serial_PutChar(SERIAL_PORT, c); - n_sent = 0; - } - else - { - if (n_sent == 0) - { - char number[11]; - checksum = 0; - sendCharAndChecksum('N'); - snprintf(number, 11, "%lu", line_number++); - rrfSendCmd(number); - sendCharAndChecksum(' '); - } - sendCharAndChecksum(c); - } -} + sprintf(rrfCmd, "N%lu %s", line_number++, cmd_ptr); -void rrfSendCmd(const char* cmd_ptr) -{ - while (*cmd_ptr != 0) + // calculate checksum + while (*rrfCmd_ptr != '\n') { - sendChar(*cmd_ptr++); + checksum ^= *rrfCmd_ptr++; } + + // add checksum and finalize formatting the RRF command + sprintf(rrfCmd_ptr, "*%u\n", checksum); + + // send the command to the serial port + Serial_Put(SERIAL_PORT, rrfCmd); } diff --git a/TFT/src/User/API/SerialConnection.c b/TFT/src/User/API/SerialConnection.c index 558548f9bc..96d3e3465b 100644 --- a/TFT/src/User/API/SerialConnection.c +++ b/TFT/src/User/API/SerialConnection.c @@ -1,21 +1,26 @@ #include "SerialConnection.h" #include "includes.h" -#define SERIAL_PORT_QUEUE_SIZE NOBEYOND(512, RAM_SIZE * 64, 4096) -#define SERIAL_PORT_2_QUEUE_SIZE 512 -#define SERIAL_PORT_3_QUEUE_SIZE 512 -#define SERIAL_PORT_4_QUEUE_SIZE 512 +#define SERIAL_PORT_RX_QUEUE_SIZE NOBEYOND(512, RAM_SIZE * 64, 4096) +#define SERIAL_PORT_2_RX_QUEUE_SIZE 512 +#define SERIAL_PORT_3_RX_QUEUE_SIZE 512 +#define SERIAL_PORT_4_RX_QUEUE_SIZE 512 + +#define SERIAL_PORT_TX_QUEUE_SIZE CMD_MAX_SIZE +#define SERIAL_PORT_2_TX_QUEUE_SIZE CMD_MAX_SIZE +#define SERIAL_PORT_3_TX_QUEUE_SIZE CMD_MAX_SIZE +#define SERIAL_PORT_4_TX_QUEUE_SIZE CMD_MAX_SIZE const SERIAL_PORT_INFO serialPort[SERIAL_PORT_COUNT] = { - {SERIAL_PORT, SERIAL_PORT_QUEUE_SIZE, "", "1 - Printer"}, + {SERIAL_PORT , SERIAL_PORT_RX_QUEUE_SIZE , SERIAL_PORT_TX_QUEUE_SIZE , "" , "1 - Printer"}, #ifdef SERIAL_PORT_2 - {SERIAL_PORT_2, SERIAL_PORT_2_QUEUE_SIZE, "2", "2 - WIFI"}, + {SERIAL_PORT_2, SERIAL_PORT_2_RX_QUEUE_SIZE, SERIAL_PORT_2_TX_QUEUE_SIZE, "2", "2 - WiFi"}, #endif #ifdef SERIAL_PORT_3 - {SERIAL_PORT_3, SERIAL_PORT_3_QUEUE_SIZE, "3", "3 - UART3"}, + {SERIAL_PORT_3, SERIAL_PORT_3_RX_QUEUE_SIZE, SERIAL_PORT_3_TX_QUEUE_SIZE, "3", "3 - UART3"}, #endif #ifdef SERIAL_PORT_4 - {SERIAL_PORT_4, SERIAL_PORT_4_QUEUE_SIZE, "4", "4 - UART4"} + {SERIAL_PORT_4, SERIAL_PORT_4_RX_QUEUE_SIZE, SERIAL_PORT_4_TX_QUEUE_SIZE, "4", "4 - UART4"} #endif }; @@ -26,7 +31,7 @@ static inline void Serial_InitPrimary(void) { InfoHost_Init(false); // initialize infoHost when disconnected - Serial_Config(serialPort[PORT_1].port, serialPort[PORT_1].cacheSize, baudrateValues[infoSettings.serial_port[PORT_1]]); + Serial_Config(serialPort[PORT_1].port, serialPort[PORT_1].cacheSizeRX, serialPort[PORT_1].cacheSizeTX, baudrateValues[infoSettings.serial_port[PORT_1]]); } static inline void Serial_DeInitPrimary(void) @@ -53,7 +58,7 @@ void Serial_Init(SERIAL_PORT_INDEX portIndex) // Disable the serial port when it is not in use and/or not connected to a device (floating) to // avoid to receive and process wrong data due to possible electromagnetic interference (EMI). if (infoSettings.serial_port[portIndex] > 0) // if serial port is enabled - Serial_Config(serialPort[portIndex].port, serialPort[portIndex].cacheSize, + Serial_Config(serialPort[portIndex].port, serialPort[portIndex].cacheSizeRX, serialPort[portIndex].cacheSizeTX, baudrateValues[infoSettings.serial_port[portIndex]]); } } @@ -64,7 +69,7 @@ void Serial_Init(SERIAL_PORT_INDEX portIndex) { if (infoSettings.serial_port[portIndex] > 0) // if serial port is enabled { - Serial_Config(serialPort[portIndex].port, serialPort[portIndex].cacheSize, + Serial_Config(serialPort[portIndex].port, serialPort[portIndex].cacheSizeRX, serialPort[portIndex].cacheSizeTX, baudrateValues[infoSettings.serial_port[portIndex]]); } } @@ -138,16 +143,16 @@ uint16_t Serial_GetReadingIndex(SERIAL_PORT_INDEX portIndex) if (!WITHIN(portIndex, PORT_1, SERIAL_PORT_COUNT - 1)) return 0; - return dmaL1Data[portIndex].rIndex; + return dmaL1DataRX[portIndex].rIndex; } uint16_t Serial_Get(SERIAL_PORT_INDEX portIndex, char * buf, uint16_t bufSize) { // if port index is out of range or no data to read from L1 cache - if (!WITHIN(portIndex, PORT_1, SERIAL_PORT_COUNT - 1) || dmaL1Data[portIndex].flag == dmaL1Data[portIndex].wIndex) + if (!WITHIN(portIndex, PORT_1, SERIAL_PORT_COUNT - 1) || dmaL1DataRX[portIndex].flag == dmaL1DataRX[portIndex].wIndex) return 0; - DMA_CIRCULAR_BUFFER * dmaL1Data_ptr = &dmaL1Data[portIndex]; + DMA_CIRCULAR_BUFFER * dmaL1Data_ptr = &dmaL1DataRX[portIndex]; // make a static access to dynamically changed (by L1 cache's interrupt handler) variables/attributes uint16_t wIndex = dmaL1Data_ptr->wIndex; diff --git a/TFT/src/User/API/SerialConnection.h b/TFT/src/User/API/SerialConnection.h index 820a0a198e..c931fdbb4d 100644 --- a/TFT/src/User/API/SerialConnection.h +++ b/TFT/src/User/API/SerialConnection.h @@ -32,7 +32,8 @@ typedef enum typedef struct { uint8_t port; // physical port (e.g. _USART1) related to serial port (e.g. 0 for SERIAL_PORT, 1 for SERIAL_PORT_2 etc...) - uint16_t cacheSize; // queue size for sending/receiving data to/from the port + uint16_t cacheSizeRX; // buffer size for receiving data from the serial port + uint16_t cacheSizeTX; // buffer size for sending data to the serial port const char * const id; // serial port ID (e.g. "" for SERIAL_PORT, "2" for SERIAL_PORT_2 etc...) const char * const desc; // serial port description (e.g. "1 - Printer" for SERIAL_PORT, "2 - WIFI" for SERIAL_PORT_2 etc...) } SERIAL_PORT_INFO; // serial port info diff --git a/TFT/src/User/Hal/gd32f20x/Serial.c b/TFT/src/User/Hal/gd32f20x/Serial.c index 2b9badedcb..acfe123918 100644 --- a/TFT/src/User/Hal/gd32f20x/Serial.c +++ b/TFT/src/User/Hal/gd32f20x/Serial.c @@ -1,90 +1,140 @@ #include "Serial.h" #include "includes.h" // for infoHost -// dma rx buffer -DMA_CIRCULAR_BUFFER dmaL1Data[_UART_CNT] = {0}; -// Config for USART Channel -//USART1 RX DMA2 Channel4 Steam2/5 -//USART2 RX DMA1 Channel4 Steam5 -//USART3 RX DMA1 Channel4 Steam1 -//UART4 RX DMA1 Channel4 Steam2 -//UART5 RX DMA1 Channel4 Steam0 -//USART6 RX DMA2 Channel5 Steam1/2 +DMA_CIRCULAR_BUFFER dmaL1DataRX[_UART_CNT] = {0}; // DMA RX buffer +char * dmaL1DataTX[_UART_CNT] = {NULL}; // DMA TX buffer // Config for USART Channel typedef struct { uint32_t uart; rcu_periph_enum dma_rcc; - uint8_t dma_channel; uint32_t dma_stream; + uint8_t dma_channelRX; + uint8_t dma_channelTX; } SERIAL_CFG; static const SERIAL_CFG Serial[_UART_CNT] = { - {USART0, RCU_DMA0, 4, DMA0}, - {USART1, RCU_DMA0, 5, DMA0}, - {USART2, RCU_DMA0, 2, DMA0}, - {UART3, RCU_DMA1, 2, DMA1}, - {UART4, RCU_DMA1, 1, DMA1}, - {USART5, RCU_DMA1, 5, DMA1}, + {USART0, RCU_DMA0, DMA0, 4, 3}, + {USART1, RCU_DMA0, DMA0, 5, 6}, + {USART2, RCU_DMA0, DMA0, 2, 1}, + {UART3, RCU_DMA1, DMA1, 2, 4}, + //{UART4, RCU_DMA1, DMA1, 1, 0}, + //{USART5, RCU_DMA1, DMA1, 5, 6}, }; +// Clear all DMA RX interrupt flags for a serial port +void Serial_DMAClearFlagRX(uint8_t port) +{ + DMA_INTC(Serial[port].dma_stream) = 0x0F << (4 * Serial[port].dma_channelRX); +} + +// Clear all DMA TX interrupt flags for a serial port +void Serial_DMAClearFlagTX(uint8_t port) +{ + DMA_INTC(Serial[port].dma_stream) = 0x0F << (4 * Serial[port].dma_channelTX); +} + +// Clear all DMA RX and TX interrupt flags for a serial port void Serial_DMAClearFlag(uint8_t port) { - switch(port) - { - case _USART1: DMA_INTC(DMA0) = (0x0F << 12); break; - case _USART2: DMA_INTC(DMA0) = (0x0F << 20); break; - case _USART3: DMA_INTC(DMA0) = (0x0F << 8); break; - case _UART4: DMA_INTC(DMA1) = (0x0F << 8); break; - case _UART5: DMA_INTC(DMA1) = (0x0F << 4); break; - case _USART6: DMA_INTC(DMA1) = (0x0F << 20); break; - } + DMA_INTC(Serial[port].dma_stream) = (0x0F << (4 * Serial[port].dma_channelRX)) | (0x0F << (4 * Serial[port].dma_channelTX)); } void Serial_DMA_Config(uint8_t port) { - const SERIAL_CFG * cfg = &Serial[port]; - rcu_periph_clock_enable(cfg->dma_rcc); + const SERIAL_CFG * serial = &Serial[port]; + rcu_periph_clock_enable(serial->dma_rcc); + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(1<<0); // Disable DMA RX + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(1<<0); // Disable DMA TX - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) &= ~(1<<0); // Disable DMA Serial_DMAClearFlag(port); - USART_CTL2(cfg->uart) |= 1<<6; // DMA enable receiver - - DMA_CHPADDR(cfg->dma_stream, cfg->dma_channel) = (uint32_t)(&USART_DATA(cfg->uart)); - DMA_CHMADDR(cfg->dma_stream, cfg->dma_channel) = (uint32_t)(dmaL1Data[port].cache); - DMA_CHCNT(cfg->dma_stream, cfg->dma_channel) = dmaL1Data[port].cacheSize; - - // DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) = cfg->dma_channel << 25; - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 3<<12; // Priority level: Very high - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 0<<10; // Memory data size: 8 - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 0<<8; // Peripheral data size: 8 - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 1<<7; // Memory increment mode - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 0<<6; // Peripheral not increment mode - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 1<<5; // Circular mode enabled - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 0<<4; // Data transfer direction: Peripheral-to-memory - DMA_CHCTL(cfg->dma_stream, cfg->dma_channel) |= 1<<0; // Enable DMA + USART_CTL2(serial->uart) |= 3<<6; // enable uart DMA RX-TX + + DMA_CHPADDR(serial->dma_stream, serial->dma_channelRX) = (uint32_t)(&USART_DATA(serial->uart)); // DMA RX peripheral address + DMA_CHPADDR(serial->dma_stream, serial->dma_channelTX) = (uint32_t)(&USART_DATA(serial->uart)); // DMA TX peripheral address + + DMA_CHMADDR(serial->dma_stream, serial->dma_channelRX) = (uint32_t)(dmaL1DataRX[port].cache); // DMA RX memory address + DMA_CHMADDR(serial->dma_stream, serial->dma_channelTX) = (uint32_t)(dmaL1DataTX[port]); // DMA TX memory address + + DMA_CHCNT(serial->dma_stream, serial->dma_channelRX) = dmaL1DataRX[port].cacheSize; // DMA RX data count + DMA_CHCNT(serial->dma_stream, serial->dma_channelTX) = 0; // DMA TX data count + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) = 0x00; // reset DMA RX control register + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) = 0x00; // reset DMA TX control register + + if (port == SERIAL_PORT) + { // primary serial port priority at highest level (TX higher than RX) + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) |= DMA_PRIORITY_HIGH; // Priority level: High + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) |= DMA_PRIORITY_ULTRA_HIGH; // Priority level: Ultra high + } + else + { // secondary serial ports priority at medium level + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) |= DMA_PRIORITY_MEDIUM; // Priority level: Medium + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) |= DMA_PRIORITY_MEDIUM; // Priority level: Medium + } + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(3<<10); // Memory data size: 8 + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(3<<10); // Memory data size: 8 + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(3<<8); // Peripheral data size: 8 + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(3<<8); // Peripheral data size: 8 + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) |= 1<<7; // Memory increment mode + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) |= 1<<7; // Memory increment mode + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(1<<6); // Peripheral not increment mode + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(1<<6); // Peripheral not increment mode + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) |= 1<<5; // Circular mode enabled + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(1<<5); // Circular mode disabled + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(1<<4); // Data transfer direction: Peripheral-to-memory + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) |= 1<<4; // Data transfer direction: Memory-to-peripheral + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(1<<3); // Channel error interrupt disabled + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(1<<3); // Channel error interrupt disabled + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(1<<2); // Channel half transfer finish interrupt disabled + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(1<<2); // Channel half transfer finish interrupt disabled + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) &= ~(1<<1); // Channel full transfer finish interrupt disabled + DMA_CHCTL(serial->dma_stream, serial->dma_channelTX) &= ~(1<<1); // Channel full transfer finish interrupt disabled + + DMA_CHCTL(serial->dma_stream, serial->dma_channelRX) |= 1<<0; // Re-enable DMA RX } void Serial_ClearData(uint8_t port) { - dmaL1Data[port].wIndex = dmaL1Data[port].rIndex = dmaL1Data[port].flag = dmaL1Data[port].cacheSize = 0; + dmaL1DataRX[port].wIndex = dmaL1DataRX[port].rIndex = dmaL1DataRX[port].flag = dmaL1DataRX[port].cacheSize = 0; + + if (dmaL1DataRX[port].cache != NULL) + { + free(dmaL1DataRX[port].cache); + dmaL1DataRX[port].cache = NULL; + } - if (dmaL1Data[port].cache != NULL) + if (dmaL1DataTX[port] != NULL) { - free(dmaL1Data[port].cache); - dmaL1Data[port].cache = NULL; + free(dmaL1DataTX[port]); + dmaL1DataTX[port] = NULL; } } -void Serial_Config(uint8_t port, uint16_t cacheSize, uint32_t baudrate) +void Serial_Config(uint8_t port, uint16_t cacheSizeRX, uint16_t cacheSizeTX, uint32_t baudrate) { Serial_ClearData(port); - dmaL1Data[port].cacheSize = cacheSize; - dmaL1Data[port].cache = malloc(cacheSize); - while (!dmaL1Data[port].cache); // malloc failed + dmaL1DataRX[port].cacheSize = cacheSizeRX; + dmaL1DataRX[port].cache = malloc(cacheSizeRX); + while (!dmaL1DataRX[port].cache); // malloc failed + dmaL1DataRX[port].rIndex = 0; + dmaL1DataRX[port].wIndex = 0; + + dmaL1DataTX[port] = malloc(cacheSizeTX); + while (!dmaL1DataTX[port]); // malloc failed UART_Config(port, baudrate, USART_INT_IDLE); // IDLE interrupt Serial_DMA_Config(port); @@ -94,19 +144,34 @@ void Serial_DeConfig(uint8_t port) { Serial_ClearData(port); - DMA_CHCTL(Serial[port].dma_stream, Serial[port].dma_channel) &= ~(1<<0); // Disable DMA + DMA_CHCTL(Serial[port].dma_stream, Serial[port].dma_channelRX) &= ~(1<<0); // Disable DMA RX + DMA_CHCTL(Serial[port].dma_stream, Serial[port].dma_channelTX) &= ~(1<<0); // Disable DMA TX + Serial_DMAClearFlag(port); UART_DeConfig(port); } + +void Serial_Put(uint8_t port, const char *s) // send a zero terminated string to uart port by DMA +{ + // Waiting for previous TX to end, it is a blocking operation but + // it gets effective usually only when emergency commands are sent. + while(DMA_CHCNT(Serial[port].dma_stream, Serial[port].dma_channelTX) != 0); + + DMA_CHCTL(Serial[port].dma_stream, Serial[port].dma_channelTX) &= ~(1<<0); // disable DMA TX + strncpy_no_pad(dmaL1DataTX[port], s, serialPort[port].cacheSizeTX); // prepare TX data + DMA_CHCNT(Serial[port].dma_stream, Serial[port].dma_channelTX) = strlen(dmaL1DataTX[port]); // set the number of bytes to be sent + DMA_CHCTL(Serial[port].dma_stream, Serial[port].dma_channelTX) |= 1<<0; // enable DMA TX (this will start the DMA TX process) +} + void USART_IRQHandler(uint8_t port) { - if ((USART_STAT0(Serial[port].uart) & (1<<4)) != 0) + if ((USART_STAT0(Serial[port].uart) & USART_STAT0_IDLEF) != RESET) // RX: check for serial Idle interrupt { - USART_STAT0(Serial[port].uart); // Clear interrupt flag - USART_DATA(Serial[port].uart); + USART_STAT0(Serial[port].uart); // Clear idle line interrupt flag + USART_DATA(Serial[port].uart); // Clear RXNE pending bit - dmaL1Data[port].wIndex = dmaL1Data[port].cacheSize - DMA_CHCNT(Serial[port].dma_stream, Serial[port].dma_channel); + dmaL1DataRX[port].wIndex = dmaL1DataRX[port].cacheSize - DMA_CHCNT(Serial[port].dma_stream, Serial[port].dma_channelRX); } } @@ -134,23 +199,3 @@ void UART4_IRQHandler(void) { USART_IRQHandler(_UART5); } - -void USART5_IRQHandler(void) -{ - USART_IRQHandler(_USART6); -} - -void Serial_Put(uint8_t port, const char *s) -{ - while (*s) - { - while ((USART_STAT0(Serial[port].uart) & (1 << USART_FLAG_TC)) == (uint16_t)RESET); - USART_DATA(Serial[port].uart) = ((uint16_t)*s++ & (uint16_t)0x01FF); - } -} - -void Serial_PutChar(uint8_t port, const char ch) -{ - while ((USART_STAT0(Serial[port].uart) & (1 << USART_FLAG_TC)) == (uint16_t)RESET); - USART_DATA(Serial[port].uart) = (uint8_t) ch; -} diff --git a/TFT/src/User/Hal/gd32f20x/Serial.h b/TFT/src/User/Hal/gd32f20x/Serial.h index ca48a22082..ef0f781d53 100644 --- a/TFT/src/User/Hal/gd32f20x/Serial.h +++ b/TFT/src/User/Hal/gd32f20x/Serial.h @@ -14,9 +14,10 @@ typedef volatile struct // precautionally declared as volatile due to access fr uint16_t cacheSize; } DMA_CIRCULAR_BUFFER; -extern DMA_CIRCULAR_BUFFER dmaL1Data[_UART_CNT]; +extern DMA_CIRCULAR_BUFFER dmaL1DataRX[_UART_CNT]; // DMA RX buffer +extern char * dmaL1DataTX[_UART_CNT]; // DMA TX buffer -void Serial_Config(uint8_t port, uint16_t cacheSize, uint32_t baudrate); +void Serial_Config(uint8_t port, uint16_t cacheSizeRX, uint16_t cacheSizeTX, uint32_t baudrate); void Serial_DeConfig(uint8_t port); void Serial_Put(uint8_t port, const char *s); void Serial_PutChar(uint8_t port, const char ch); diff --git a/TFT/src/User/Hal/stm32f10x/Serial.c b/TFT/src/User/Hal/stm32f10x/Serial.c index bbe60e14c8..1d055ca783 100644 --- a/TFT/src/User/Hal/stm32f10x/Serial.c +++ b/TFT/src/User/Hal/stm32f10x/Serial.c @@ -1,23 +1,24 @@ #include "Serial.h" #include "includes.h" // for infoHost -// dma rx buffer -DMA_CIRCULAR_BUFFER dmaL1Data[_UART_CNT] = {0}; +DMA_CIRCULAR_BUFFER dmaL1DataRX[_UART_CNT] = {0}; // DMA RX buffer +char * dmaL1DataTX[_UART_CNT] = {NULL}; // DMA TX buffer // Config for USART Channel typedef struct { USART_TypeDef *uart; uint32_t dma_rcc; - DMA_Channel_TypeDef *dma_chanel; + DMA_Channel_TypeDef *dma_channelRX; + DMA_Channel_TypeDef *dma_channelTX; } SERIAL_CFG; static const SERIAL_CFG Serial[_UART_CNT] = { - {USART1, RCC_AHBPeriph_DMA1, DMA1_Channel5}, - {USART2, RCC_AHBPeriph_DMA1, DMA1_Channel6}, - {USART3, RCC_AHBPeriph_DMA1, DMA1_Channel3}, - {UART4, RCC_AHBPeriph_DMA2, DMA2_Channel3}, - //{UART5, -1, -1}, // UART5 don't support DMA + {USART1, RCC_AHBPeriph_DMA1, DMA1_Channel5, DMA1_Channel4}, + {USART2, RCC_AHBPeriph_DMA1, DMA1_Channel6, DMA1_Channel7}, + {USART3, RCC_AHBPeriph_DMA1, DMA1_Channel3, DMA1_Channel2}, + {UART4, RCC_AHBPeriph_DMA2, DMA2_Channel3, DMA2_Channel5}, + //{UART5, -1, -1, -1}, // UART5 don't support DMA }; void Serial_DMA_Config(uint8_t port) @@ -26,37 +27,96 @@ void Serial_DMA_Config(uint8_t port) RCC_AHBPeriphClockCmd(cfg->dma_rcc, ENABLE); // DMA RCC EN - cfg->dma_chanel->CCR &= ~(1<<0); // DMA disable - cfg->uart->CR3 |= 1<<6; // DMA enable receiver - - cfg->dma_chanel->CPAR = (uint32_t)(&cfg->uart->DR); - cfg->dma_chanel->CMAR = (uint32_t)(dmaL1Data[port].cache); - cfg->dma_chanel->CNDTR = dmaL1Data[port].cacheSize; - cfg->dma_chanel->CCR = 0X00000000; - cfg->dma_chanel->CCR |= 3<<12; // Channel priority level - cfg->dma_chanel->CCR |= 1<<7; // Memory increment mode - cfg->dma_chanel->CCR |= 1<<5; // Circular mode enabled - cfg->dma_chanel->CCR |= 1<<0; // DMA EN + cfg->dma_channelRX->CCR &= ~(1<<0); // disable RX DMA + cfg->dma_channelTX->CCR &= ~(1<<0); // disable TX DMA + + cfg->uart->CR3 |= 3<<6; // enable DMA RX-TX + + cfg->dma_channelRX->CPAR = (uint32_t)(&cfg->uart->DR); // peripheral address RX (usart) + cfg->dma_channelTX->CPAR = (uint32_t)(&cfg->uart->DR); // peripheral address TX (usart) + + cfg->dma_channelRX->CMAR = (uint32_t)(dmaL1DataRX[port].cache); // RX destination data (sram) + cfg->dma_channelTX->CMAR = (uint32_t)(dmaL1DataTX[port]); // TX source data (sram) + + cfg->dma_channelRX->CNDTR = dmaL1DataRX[port].cacheSize; // RX buffer size + cfg->dma_channelTX->CNDTR = 0; // TX buffer size + + cfg->dma_channelRX->CCR = 0x00000000; // reset DMA RX CCR + cfg->dma_channelTX->CCR = 0x00000000; // reset DMA TX CCR + + if (port == SERIAL_PORT) + { // primary serial port priority at highest level (TX higher than RX) + cfg->dma_channelRX->CCR |= DMA_Priority_High; // RX priority level: High + cfg->dma_channelTX->CCR |= DMA_Priority_VeryHigh; // TX priority level: Very high + } + else + { // secondary serial ports priority at medium level + cfg->dma_channelRX->CCR |= DMA_Priority_Medium; // RX priority level: Medium + cfg->dma_channelTX->CCR |= DMA_Priority_Medium; // TX priority level: Medium + } + + cfg->dma_channelRX->CCR &= ~(DMA_M2M_Enable); // RX MEM2MEM disabled + cfg->dma_channelTX->CCR &= ~(DMA_M2M_Enable); // TX MEM2MEM disabled + + cfg->dma_channelRX->CCR &= ~(1<<4); // data transfer direction: Peripheral-to-memory + cfg->dma_channelTX->CCR |= 1<<4; // data transfer direction: Memory-to-Peripheral + + cfg->dma_channelRX->CCR |= DMA_Mode_Circular; // RX circular mode enabled + cfg->dma_channelTX->CCR &= ~(DMA_Mode_Circular); // TX circular mode disabled + + cfg->dma_channelRX->CCR &= ~(DMA_PeripheralInc_Enable); // RX peripheral no increment mode + cfg->dma_channelTX->CCR &= ~(DMA_PeripheralInc_Enable); // TX peripheral no increment mode + + cfg->dma_channelRX->CCR |= DMA_MemoryInc_Enable; // RX memory increment mode + cfg->dma_channelTX->CCR |= DMA_MemoryInc_Enable; // TX memory increment mode + + cfg->dma_channelRX->CCR &= ~(3<<10); // RX memory data size: 8 bit + cfg->dma_channelTX->CCR &= ~(3<<10); // TX memory data size: 8 bit + + cfg->dma_channelRX->CCR &= ~(3<<8); // RX peripheral data size: 8 bit + cfg->dma_channelTX->CCR &= ~(3<<8); // TX peripheral data size: 8 bit + + cfg->dma_channelRX->CCR &= ~(DMA_IT_TE); // RX transfer error interrupt disable + cfg->dma_channelTX->CCR &= ~(DMA_IT_TE); // TX transfer error interrupt disable + + cfg->dma_channelRX->CCR &= ~(DMA_IT_HT); // RX half transfer interrupt disable + cfg->dma_channelTX->CCR &= ~(DMA_IT_HT); // TX half transfer interrupt disable + + cfg->dma_channelRX->CCR &= ~(DMA_IT_TC); // RX transfer complete interrupt disable + cfg->dma_channelTX->CCR &= ~(DMA_IT_TC); // TX transfer complete interrupt disable + + cfg->dma_channelRX->CCR |= 1<<0; // re-enable DMA RX } void Serial_ClearData(uint8_t port) { - dmaL1Data[port].wIndex = dmaL1Data[port].rIndex = dmaL1Data[port].flag = dmaL1Data[port].cacheSize = 0; + dmaL1DataRX[port].wIndex = dmaL1DataRX[port].rIndex = dmaL1DataRX[port].flag = dmaL1DataRX[port].cacheSize = 0; - if (dmaL1Data[port].cache != NULL) + if (dmaL1DataRX[port].cache != NULL) { - free(dmaL1Data[port].cache); - dmaL1Data[port].cache = NULL; + free(dmaL1DataRX[port].cache); + dmaL1DataRX[port].cache = NULL; + } + + if (dmaL1DataTX[port] != NULL) + { + free(dmaL1DataTX[port]); + dmaL1DataTX[port] = NULL; } } -void Serial_Config(uint8_t port, uint16_t cacheSize, uint32_t baudrate) +void Serial_Config(uint8_t port, uint16_t cacheSizeRX, uint16_t cacheSizeTX, uint32_t baudrate) { Serial_ClearData(port); - dmaL1Data[port].cacheSize = cacheSize; - dmaL1Data[port].cache = malloc(cacheSize); - while (!dmaL1Data[port].cache); // malloc failed + dmaL1DataRX[port].cacheSize = cacheSizeRX; + dmaL1DataRX[port].cache = malloc(cacheSizeRX); + while (!dmaL1DataRX[port].cache); // malloc failed + dmaL1DataRX[port].rIndex = 0; + dmaL1DataRX[port].wIndex = 0; + + dmaL1DataTX[port] = malloc(cacheSizeTX); + while (!dmaL1DataTX[port]); // malloc failed, blocking! UART_Config(port, baudrate, USART_IT_IDLE); // IDLE interrupt Serial_DMA_Config(port); @@ -66,18 +126,32 @@ void Serial_DeConfig(uint8_t port) { Serial_ClearData(port); - Serial[port].dma_chanel->CCR &= ~(1<<0); // Disable DMA + Serial[port].dma_channelRX->CCR &= ~(1<<0); // Disable DMA RX + Serial[port].dma_channelTX->CCR &= ~(1<<0); // Disable DMA TX + UART_DeConfig(port); } +void Serial_Put(uint8_t port, const char *s) // send a zero terminated string to uart port by DMA +{ + // Waiting for previous TX to end, it is a blocking operation but + // it gets effective usually only when emergency commands are sent. + while(Serial[port].dma_channelTX->CNDTR != 0); + + Serial[port].dma_channelTX->CCR &= ~(1<<0); // disable TX DMA + strncpy_no_pad(dmaL1DataTX[port], s, serialPort[port].cacheSizeTX); // prepare TX data + Serial[port].dma_channelTX->CNDTR = strlen(dmaL1DataTX[port]); // set the number of bytes to be sent + Serial[port].dma_channelTX->CCR |= 1<<0; // enable TX DMA (this will start the DMA TX process) +} + void USART_IRQHandler(uint8_t port) { - if ((Serial[port].uart->SR & (1<<4)) != 0) + if ((Serial[port].uart->SR & USART_SR_IDLE) != RESET) { - Serial[port].uart->SR; - Serial[port].uart->DR; + Serial[port].uart->SR; // Clear idle line interrupt flag + Serial[port].uart->DR; // Clear RXNE pending bit - dmaL1Data[port].wIndex = dmaL1Data[port].cacheSize - Serial[port].dma_chanel->CNDTR; + dmaL1DataRX[port].wIndex = dmaL1DataRX[port].cacheSize - Serial[port].dma_channelRX->CNDTR; } } @@ -105,18 +179,3 @@ void UART5_IRQHandler(void) { USART_IRQHandler(_UART5); } - -void Serial_Put(uint8_t port, const char *s) -{ - while (*s) - { - while ((Serial[port].uart->SR & USART_FLAG_TC) == (uint16_t)RESET); - Serial[port].uart->DR = ((uint16_t)*s++ & (uint16_t)0x01FF); - } -} - -void Serial_PutChar(uint8_t port, const char ch) -{ - while ((Serial[port].uart->SR & USART_FLAG_TC) == (uint16_t)RESET); - Serial[port].uart->DR = (uint8_t) ch; -} diff --git a/TFT/src/User/Hal/stm32f10x/Serial.h b/TFT/src/User/Hal/stm32f10x/Serial.h index ca48a22082..ef0f781d53 100644 --- a/TFT/src/User/Hal/stm32f10x/Serial.h +++ b/TFT/src/User/Hal/stm32f10x/Serial.h @@ -14,9 +14,10 @@ typedef volatile struct // precautionally declared as volatile due to access fr uint16_t cacheSize; } DMA_CIRCULAR_BUFFER; -extern DMA_CIRCULAR_BUFFER dmaL1Data[_UART_CNT]; +extern DMA_CIRCULAR_BUFFER dmaL1DataRX[_UART_CNT]; // DMA RX buffer +extern char * dmaL1DataTX[_UART_CNT]; // DMA TX buffer -void Serial_Config(uint8_t port, uint16_t cacheSize, uint32_t baudrate); +void Serial_Config(uint8_t port, uint16_t cacheSizeRX, uint16_t cacheSizeTX, uint32_t baudrate); void Serial_DeConfig(uint8_t port); void Serial_Put(uint8_t port, const char *s); void Serial_PutChar(uint8_t port, const char ch); diff --git a/TFT/src/User/Hal/stm32f10x/uart.h b/TFT/src/User/Hal/stm32f10x/uart.h index b51881a306..aa140e1774 100644 --- a/TFT/src/User/Hal/stm32f10x/uart.h +++ b/TFT/src/User/Hal/stm32f10x/uart.h @@ -8,7 +8,7 @@ #define _USART3 2 #define _UART4 3 #define _UART5 4 // UART5 don't support DMA -#define _UART_CNT 6 +#define _UART_CNT 5 void UART_Config(uint8_t port, uint32_t baud, uint16_t usart_it); void UART_DeConfig(uint8_t port); diff --git a/TFT/src/User/Hal/stm32f2_f4xx/Serial.c b/TFT/src/User/Hal/stm32f2_f4xx/Serial.c index fe931f69c2..fbc8284d87 100644 --- a/TFT/src/User/Hal/stm32f2_f4xx/Serial.c +++ b/TFT/src/User/Hal/stm32f2_f4xx/Serial.c @@ -1,45 +1,133 @@ #include "Serial.h" #include "includes.h" // for infoHost -// dma rx buffer -DMA_CIRCULAR_BUFFER dmaL1Data[_UART_CNT] = {0}; - -// Config for USART Channel -//USART1 RX DMA2 Channel4 Steam2/5 -//USART2 RX DMA1 Channel4 Steam5 -//USART3 RX DMA1 Channel4 Steam1 -//UART4 RX DMA1 Channel4 Steam2 -//UART5 RX DMA1 Channel4 Steam0 -//USART6 RX DMA2 Channel5 Steam1/2 +DMA_CIRCULAR_BUFFER dmaL1DataRX[_UART_CNT] = {0}; // DMA RX buffer +char * dmaL1DataTX[_UART_CNT] = {NULL}; // DMA TX buffer // Config for USART Channel typedef struct { - USART_TypeDef *uart; - uint32_t dma_rcc; - uint8_t dma_channel; - DMA_Stream_TypeDef *dma_stream; + USART_TypeDef *uart; + uint32_t dma_rcc; + uint8_t dma_channel; + DMA_Stream_TypeDef *dma_streamRX; + DMA_Stream_TypeDef *dma_streamTX; } SERIAL_CFG; -static const SERIAL_CFG Serial[_UART_CNT] = { - {USART1, RCC_AHB1Periph_DMA2, 4, DMA2_Stream2}, - {USART2, RCC_AHB1Periph_DMA1, 4, DMA1_Stream5}, - {USART3, RCC_AHB1Periph_DMA1, 4, DMA1_Stream1}, - {UART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2}, - {UART5, RCC_AHB1Periph_DMA1, 4, DMA1_Stream0}, - {USART6, RCC_AHB1Periph_DMA2, 5, DMA2_Stream1}, +static SERIAL_CFG Serial[_UART_CNT] = { +// USART DMA1 or DMA2 Channel RX_STREAM TX_STREAM + {USART1, RCC_AHB1Periph_DMA2, 4, DMA2_Stream2, DMA2_Stream7}, + {USART2, RCC_AHB1Periph_DMA1, 4, DMA1_Stream5, DMA1_Stream6}, + {USART3, RCC_AHB1Periph_DMA1, 4, DMA1_Stream1, DMA1_Stream3}, + {UART4, RCC_AHB1Periph_DMA1, 4, DMA1_Stream2, DMA1_Stream4}, + {UART5, RCC_AHB1Periph_DMA1, 4, DMA1_Stream0, DMA1_Stream7}, + {USART6, RCC_AHB1Periph_DMA2, 5, DMA2_Stream1, DMA2_Stream6}, }; -void Serial_DMAClearFlag(uint8_t port) +// Clear all DMA RX and TX interrupt flags for a serial port +void Serial_DMAClearITflags(uint8_t port) { - switch(port) +// Channel to bits: Low 0: 0-5, 1: 6-11, 2: 16-21, 3: 22-27 +// Channel to bits: High 4: 0-5, 5: 6-11, 6: 16-21, 7: 22-27 + + switch(port) // DMA low/high interrupt Control Register (DMA_LIFCR/DMA_HIFCR) { - case _USART1: DMA2->LIFCR = (0x3F << 16); break; // DMA2_Stream2 low bits:16-21 - case _USART2: DMA1->HIFCR = (0xFC << 4); break; // DMA1_Stream5 high bits: 6-11 - case _USART3: DMA1->LIFCR = (0xFC << 4); break; // DMA1_Stream1 low bits: 6-11 - case _UART4: DMA1->LIFCR = (0x3F << 16); break; // DMA1_Stream2 low bits:16-21 - case _UART5: DMA1->LIFCR = (0x3F << 0); break; // DMA1_Stream0 low bits: 0-5 - case _USART6: DMA2->LIFCR = (0xFC << 4); break; // DMA2_Stream1 low bits: 6-11 + case _USART1: + DMA2->LIFCR = (0x3F << 16); // DMA2_Stream2 low bits:16-21 Channel 4 + DMA2->HIFCR = (0x3F << 22); // DMA2_Stream7 high bits:22-27 Channel 4 + break; + + case _USART2: + DMA1->HIFCR = (0x3F << 6) | // DMA1_Stream5 high bits: 6-11 Channel 4 + (0x3F << 16); // DMA1_Stream6 high bits:16-21 Channel 4 + break; + + case _USART3: + DMA1->LIFCR = (0x3F << 6) | // DMA1_Stream1 low bits: 6-11 Channel 4 + (0x3F << 22); // DMA1_Stream3 low bits:22-27 Channel 4 + break; + + case _UART4: + DMA1->LIFCR = (0x3F << 16); // DMA1_Stream2 low bits:16-21 Channel 4 + DMA1->HIFCR = (0x3F << 0); // DMA1_Stream4 high bits: 0- 5 Channel 4 + break; + + case _UART5: + DMA1->LIFCR = (0x3F << 0); // DMA1_Stream0 low bits: 0- 5 Channel 4 + DMA1->HIFCR = (0x3F << 22); // DMA1_Stream7 high bits:22-27 Channel 4 + break; + + case _USART6: + DMA2->LIFCR = (0x3F << 6); // DMA2_Stream1 low bits: 6-11 Channel 5 + DMA2->HIFCR = (0x3F << 16); // DMA2_Stream6 high bits:16-21 Channel 5 + break; + } +} + +// clear all DMA RX interrupt flags for a given serial port +void Serial_DMAClearITflagsRX(uint8_t port) +{ +// Channel to bits: Low 0: 0-5, 1: 6-11, 2: 16-21, 3: 22-27 +// Channel to bits: High 4: 0-5, 5: 6-11, 6: 16-21, 7: 22-27 + + switch(port) // DMA low/high interrupt Control Register (DMA_LIFCR/DMA_HIFCR) + { + case _USART1: + DMA2->LIFCR = (0x3F << 16); // DMA2_Stream2 low bits:16-21 Channel 4 + break; + + case _USART2: + DMA1->HIFCR = (0x3F << 6); // DMA1_Stream5 high bits: 6-11 Channel 4 + break; + + case _USART3: + DMA1->LIFCR = (0x3F << 6); // DMA1_Stream1 low bits: 6-11 Channel 4 + break; + + case _UART4: + DMA1->LIFCR = (0x3F << 16); // DMA1_Stream2 low bits:16-21 Channel 4 + break; + + case _UART5: + DMA1->LIFCR = (0x3F << 0); // DMA1_Stream0 low bits: 0-5 Channel 4 + break; + + case _USART6: + DMA2->LIFCR = (0x3F << 6); // DMA2_Stream1 low bits: 6-11 Channel 5 + break; + } +} + +// clear all DMA TX interrupt flags for a given serial port +void Serial_DMAClearITflagsTX(uint8_t port) +{ +// Channel to bits: Low 0: 0-5, 1: 6-11, 2: 16-21, 3: 22-27 +// Channel to bits: High 4: 0-5, 5: 6-11, 6: 16-21, 7: 22-27 + switch(port) // DMA low/high interrupt Control Register (DMA_LIFCR/DMA_HIFCR) + { + case _USART1: + DMA2->HIFCR = (0x3F << 22); // DMA2_Stream7 high bits:22-27 Channel 4 + break; + + case _USART2: + DMA1->HIFCR = (0x3F << 16); // DMA1_Stream6 high bits:16-21 Channel 4 + break; + + case _USART3: + DMA1->LIFCR = (0x3F << 22); // DMA1_Stream3 low bits:22-27 Channel 4 + break; + + case _UART4: + DMA1->HIFCR = (0x3F << 0); // DMA1_Stream4 high bits: 0- 5 Channel 4 + break; + + case _UART5: + DMA1->HIFCR = (0x3F << 22); // DMA1_Stream7 high bits:22-27 Channel 4 + break; + + case _USART6: + DMA2->HIFCR = (0x3F << 16); // DMA2_Stream6 high bits:16-21 Channel 5 + break; } } @@ -47,47 +135,107 @@ void Serial_DMA_Config(uint8_t port) { const SERIAL_CFG * cfg = &Serial[port]; - RCC_AHB1PeriphClockCmd(cfg->dma_rcc, ENABLE); // DMA RCC EN - - cfg->dma_stream->CR &= ~(1<<0); // Disable DMA - Serial_DMAClearFlag(port); - cfg->uart->CR3 |= 1<<6; // DMA enable receiver - - cfg->dma_stream->PAR = (uint32_t)(&cfg->uart->DR); - cfg->dma_stream->M0AR = (uint32_t)(dmaL1Data[port].cache); - cfg->dma_stream->NDTR = dmaL1Data[port].cacheSize; - - cfg->dma_stream->CR = cfg->dma_channel << 25; - cfg->dma_stream->CR |= 3<<16; // Priority level: Very high - cfg->dma_stream->CR |= 0<<13; // Memory data size: 8 - cfg->dma_stream->CR |= 0<<11; // Peripheral data size: 8 - cfg->dma_stream->CR |= 1<<10; // Memory increment mode - cfg->dma_stream->CR |= 0<<9; // Peripheral not increment mode - cfg->dma_stream->CR |= 1<<8; // Circular mode enabled - cfg->dma_stream->CR |= 0<<6; // Data transfer direction: Peripheral-to-memory - cfg->dma_stream->CR |= 1<<0; // Enable DMA + RCC_AHB1PeriphClockCmd(cfg->dma_rcc, ENABLE); // DMA RCC enable + + cfg->dma_streamRX->CR &= ~(1<<0); // disable RX DMA + cfg->dma_streamTX->CR &= ~(1<<0); // disable TX DMA + + Serial_DMAClearITflags(port); // clear DMA RX-TX interrupt flags + + cfg->uart->CR3 |= 3<<6; // DMA enable transmitter(DMAT) and receiver(DMAR) + + cfg->dma_streamRX->PAR = (uint32_t)(&cfg->uart->DR); // peripheral address RX (usart) + cfg->dma_streamTX->PAR = (uint32_t)(&cfg->uart->DR); // peripheral address TX (usart) + + cfg->dma_streamRX->M0AR = (uint32_t)(dmaL1DataRX[port].cache); // RX destination data (sram) + cfg->dma_streamTX->M0AR = (uint32_t)(dmaL1DataTX[port]); // TX source data (sram) + + cfg->dma_streamRX->NDTR = dmaL1DataRX[port].cacheSize; // RX buffer size + cfg->dma_streamTX->NDTR = 0; // TX buffer size + + cfg->dma_streamRX->CR = cfg->dma_channel << 25; // RX channel selection, set to 0 all the other CR bits + cfg->dma_streamTX->CR = cfg->dma_channel << 25; // TX channel selection, set to 0 all the other CR bits + + if (port == SERIAL_PORT) + { // primary serial port priority at highest level (TX higher than RX) + cfg->dma_streamRX->CR |= DMA_Priority_High; // RX priority level: High + cfg->dma_streamTX->CR |= DMA_Priority_VeryHigh; // TX priority level: Very high + } + else + { // secondary serial ports priority at medium level + cfg->dma_streamRX->CR &= DMA_Priority_Medium; // RX priority level: Medium + cfg->dma_streamTX->CR |= DMA_Priority_Medium; // TX priority level: Medium + } + + cfg->dma_streamRX->FCR &= ~(DMA_FIFOMode_Enable); // enable DMA RX direct mode (no FIFO) + cfg->dma_streamTX->FCR &= ~(DMA_FIFOMode_Enable); // enable DMA TX direct mode (no FIFO) + + cfg->dma_streamRX->FCR &= ~(1<<7); // enable DMA RX FIFO error interrupt disable + cfg->dma_streamTX->FCR &= ~(1<<7); // enable DMA TX FIFO error interrupt disable + + cfg->dma_streamRX->CR &= ~(1<<6); // data transfer direction: Peripheral-to-memory + cfg->dma_streamTX->CR |= 1<<6; // data transfer direction: Memory-to-Peripheral + + cfg->dma_streamRX->CR &= ~(3<<13); // memory data size: 8 bit + cfg->dma_streamTX->CR &= ~(3<<13); // memory data size: 8 bit + + cfg->dma_streamRX->CR &= ~(3<<11); // peripheral data size: 8 bit + cfg->dma_streamTX->CR &= ~(3<<11); // peripheral data size: 8 bit + + cfg->dma_streamRX->CR |= DMA_MemoryInc_Enable; // memory increment mode + cfg->dma_streamTX->CR |= DMA_MemoryInc_Enable; // memory increment mode + + cfg->dma_streamRX->CR &= ~(DMA_PeripheralInc_Enable); // peripheral no increment mode + cfg->dma_streamTX->CR &= ~(DMA_PeripheralInc_Enable); // peripheral no increment mode + + cfg->dma_streamRX->CR |= DMA_Mode_Circular; // RX circular mode enabled + cfg->dma_streamTX->CR &= ~(DMA_Mode_Circular); // TX circular mode disabled + + cfg->dma_streamRX->CR &= ~(DMA_IT_TC); // disable RX DMA Transfer Complete interrupt + cfg->dma_streamTX->CR &= ~(DMA_IT_TC); // disable TX DMA Transfer Complete interrupt + + cfg->dma_streamRX->CR &= ~(DMA_IT_HT); // disable RX DMA Half Transfer interrupt + cfg->dma_streamTX->CR &= ~(DMA_IT_HT); // disable TX DMA Half Transfer interrupt + + cfg->dma_streamRX->CR &= ~(DMA_IT_TE); // disable RX DMA transfer error interrupt + cfg->dma_streamTX->CR &= ~(DMA_IT_TE); // disable TX DMA transfer error interrupt + + cfg->dma_streamRX->CR &= ~(DMA_IT_DME); // disable RX DMA direct mode error interrupt + cfg->dma_streamTX->CR &= ~(DMA_IT_DME); // disable TX DMA direct mode error interrupt + + cfg->dma_streamRX->CR |= 1<<0; // re-enable RX DMA } void Serial_ClearData(uint8_t port) { - dmaL1Data[port].wIndex = dmaL1Data[port].rIndex = dmaL1Data[port].flag = dmaL1Data[port].cacheSize = 0; + dmaL1DataRX[port].rIndex = dmaL1DataRX[port].wIndex = dmaL1DataRX[port].cacheSize = 0; + if (dmaL1DataRX[port].cache != NULL) + { + free(dmaL1DataRX[port].cache); + dmaL1DataRX[port].cache = NULL; + } - if (dmaL1Data[port].cache != NULL) + if (dmaL1DataTX[port] != NULL) { - free(dmaL1Data[port].cache); - dmaL1Data[port].cache = NULL; + free(dmaL1DataTX[port]); + dmaL1DataTX[port] = NULL; } } -void Serial_Config(uint8_t port, uint16_t cacheSize, uint32_t baudrate) +void Serial_Config(uint8_t port, uint16_t cacheSizeRX, uint16_t cacheSizeTX, uint32_t baudrate) { Serial_ClearData(port); - dmaL1Data[port].cacheSize = cacheSize; - dmaL1Data[port].cache = malloc(cacheSize); - while (!dmaL1Data[port].cache); // malloc failed + dmaL1DataRX[port].cacheSize = cacheSizeRX; + dmaL1DataRX[port].cache = malloc(cacheSizeRX); + while (!dmaL1DataRX[port].cache); // malloc failed, blocking! + dmaL1DataRX[port].rIndex = 0; + dmaL1DataRX[port].wIndex = 0; + + dmaL1DataTX[port] = malloc(cacheSizeTX); + while (!dmaL1DataTX[port]); // malloc failed, blocking! - UART_Config(port, baudrate, USART_IT_IDLE); // IDLE interrupt + UART_Config(port, baudrate, USART_IT_IDLE); // enable serial line IDLE interrupt Serial_DMA_Config(port); } @@ -95,19 +243,36 @@ void Serial_DeConfig(uint8_t port) { Serial_ClearData(port); - Serial[port].dma_stream->CR &= ~(1<<0); // Disable DMA - Serial_DMAClearFlag(port); + Serial[port].dma_streamRX->CR &= ~(1<<0); // disable RX DMA + Serial[port].dma_streamTX->CR &= ~(1<<0); // disable TX DMA + + Serial_DMAClearITflags(port); UART_DeConfig(port); } +void Serial_Put(uint8_t port, const char *s) // send a zero terminated string to uart port by DMA +{ + // Waiting for previous TX to end, it is a blocking operation but + // it gets effective usually only when emergency commands are sent. + while(Serial[port].dma_streamTX->NDTR != 0); + + strncpy_no_pad(dmaL1DataTX[port], s, serialPort[port].cacheSizeTX); // prepare TX data + Serial[port].dma_streamTX->NDTR = strlen(dmaL1DataTX[port]); // set the number of bytes to be sent + + // Before setting EN bit to '1' to start a new transfer, the event flags which + // corresponds to the stream in DMA_LISR or DMA_HISR register must be cleared. + Serial_DMAClearITflagsTX(port); // clear DMA TX interrupt flags + Serial[port].dma_streamTX->CR |= 1<<0; // enable TX DMA (this will start the DMA TX process) +} + void USART_IRQHandler(uint8_t port) { - if ((Serial[port].uart->SR & (1<<4)) != 0) + if ((Serial[port].uart->SR & USART_SR_IDLE) != RESET) // RX: check for serial Idle interrupt { - Serial[port].uart->SR; - Serial[port].uart->DR; + Serial[port].uart->SR; // Clear idle line interrupt flag + Serial[port].uart->DR; // Clear RXNE pending bit - dmaL1Data[port].wIndex = dmaL1Data[port].cacheSize - Serial[port].dma_stream->NDTR; + dmaL1DataRX[port].wIndex = dmaL1DataRX[port].cacheSize - Serial[port].dma_streamRX->NDTR; } } @@ -140,18 +305,3 @@ void USART6_IRQHandler(void) { USART_IRQHandler(_USART6); } - -void Serial_Put(uint8_t port, const char *s) -{ - while (*s) - { - while ((Serial[port].uart->SR & USART_FLAG_TC) == (uint16_t)RESET); - Serial[port].uart->DR = ((uint16_t)*s++ & (uint16_t)0x01FF); - } -} - -void Serial_PutChar(uint8_t port, const char ch) -{ - while ((Serial[port].uart->SR & USART_FLAG_TC) == (uint16_t)RESET); - Serial[port].uart->DR = (uint8_t) ch; -} diff --git a/TFT/src/User/Hal/stm32f2_f4xx/Serial.h b/TFT/src/User/Hal/stm32f2_f4xx/Serial.h index ca48a22082..09fec30d98 100644 --- a/TFT/src/User/Hal/stm32f2_f4xx/Serial.h +++ b/TFT/src/User/Hal/stm32f2_f4xx/Serial.h @@ -8,17 +8,17 @@ typedef volatile struct // precautionally declared as volatile due to access from interrupt handler and main thread { char *cache; - uint16_t wIndex; // writing index - uint16_t rIndex; // reading index + volatile uint16_t wIndex; // writing index + volatile uint16_t rIndex; // reading index uint16_t flag; // custom flag (for custom usage by the application) uint16_t cacheSize; } DMA_CIRCULAR_BUFFER; -extern DMA_CIRCULAR_BUFFER dmaL1Data[_UART_CNT]; +extern DMA_CIRCULAR_BUFFER dmaL1DataRX[_UART_CNT]; // DMA RX buffer +extern char * dmaL1DataTX[_UART_CNT]; // DMA TX buffer -void Serial_Config(uint8_t port, uint16_t cacheSize, uint32_t baudrate); +void Serial_Config(uint8_t port, uint16_t cacheSizeRX, uint16_t cacheSizeTX, uint32_t baudrate); void Serial_DeConfig(uint8_t port); void Serial_Put(uint8_t port, const char *s); -void Serial_PutChar(uint8_t port, const char ch); #endif