Skip to content

Commit

Permalink
UART driver for ezr32 now uses DMA for TX. Console implementation dum…
Browse files Browse the repository at this point in the history
…ps the whole fifo is the HAL support UART TX using DMA, otherwise it resort to ending small chunks at once (as before)
  • Loading branch information
glennergeerts committed Mar 17, 2017
1 parent 1375bd8 commit 31e1a7e
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 12 deletions.
16 changes: 12 additions & 4 deletions stack/framework/components/console/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "fifo.h"
#include "scheduler.h"
#include "console.h"
#include "hal_defs.h"

#ifdef FRAMEWORK_CONSOLE_ENABLED

Expand All @@ -21,20 +22,27 @@ static uint8_t console_tx_buffer[CONSOLE_TX_FIFO_SIZE];
static fifo_t console_tx_fifo;

static void flush_console_tx_fifo() {
uint8_t len = fifo_get_size(&console_tx_fifo);
#ifdef HAL_UART_USE_DMA_TX
// when using DMA we transmit the whole FIFO at once
uint8_t buffer[CONSOLE_TX_FIFO_SIZE];
fifo_pop(&console_tx_fifo, buffer, len);
uart_send_bytes(uart, buffer, len);
#else
// only send small chunks over uart each invocation, to make sure
// we don't interfer with critical stack timings.
// When there is still data left in the fifo this will be rescheduled
// with lowest prio
uint8_t chunk[TX_FIFO_FLUSH_CHUNK_SIZE];
uint8_t depth = fifo_get_size(&console_tx_fifo);
if(depth < 10) {
fifo_pop(&console_tx_fifo, chunk, depth);
uart_send_bytes(uart, chunk, depth);
if(len < 10) {
fifo_pop(&console_tx_fifo, chunk, len);
uart_send_bytes(uart, chunk, len);
} else {
fifo_pop(&console_tx_fifo, chunk, TX_FIFO_FLUSH_CHUNK_SIZE);
uart_send_bytes(uart, chunk, TX_FIFO_FLUSH_CHUNK_SIZE);
sched_post_task_prio(&flush_console_tx_fifo, MIN_PRIORITY);
}
#endif
}

void console_init(void) {
Expand Down
2 changes: 2 additions & 0 deletions stack/framework/hal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ include(${PROJECT_SOURCE_DIR}/cmake/hal_macros.cmake)

# HAL parameters (might be forcefully overruled by chip, which is why HAL_HEADER_DEFINE() is only called after adding chips)
SET(HAL_RADIO_USE_HW_CRC "FALSE" CACHE BOOL "Enable/Disable the use of HW CRC")
SET(HAL_UART_USE_DMA_TX "FALSE" CACHE BOOL "Enable/Disable the use of DMA for UART TX")

#note: this does not include any chip code.
#see note in 'chips' directory in the CMakeLists.txt in the 'chips' directory
Expand All @@ -40,6 +41,7 @@ ADD_SUBDIRECTORY("platforms")
#Generate the 'hal_defs.h'
HAL_HEADER_DEFINE(BOOL HAL_RADIO_INCLUDE_TIMESTAMP)
HAL_HEADER_DEFINE(BOOL HAL_RADIO_USE_HW_CRC)
HAL_HEADER_DEFINE(BOOL HAL_UART_USE_DMA_TX)
HAL_BUILD_SETTINGS_FILE()


5 changes: 4 additions & 1 deletion stack/framework/hal/chips/ezr32lg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ ENDIF()

SET(LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/CMSIS/device/linker/ezr32lg.ld" CACHE FILEPATH "")

SET(HAL_UART_USE_DMA_TX "TRUE" CACHE BOOL "Enable/Disable the use of DMA for UART TX" FORCE)

IF(${PLATFORM_BUILD_BOOTLOADABLE_VERSION})
SET(LINKER_SCRIPT_BOOTLOADABLE "${CMAKE_CURRENT_SOURCE_DIR}/CMSIS/device/linker/ezr32lg_bootloader.ld" CACHE FILEPATH "")
ENDIF()
Expand Down Expand Up @@ -132,5 +134,6 @@ ADD_LIBRARY (${CHIP_LIBRARY_NAME} OBJECT
usb/src/em_usbtimer.c
emdrv/gpiointerrupt/src/gpiointerrupt.c
emdrv/spidrv/src/spidrv.c
emdrv/dmadrv/src/dmadrv.c
emdrv/dmadrv/src/dmadrv.c
emdrv/dmadrv/inc/dmadrv.h
)
54 changes: 47 additions & 7 deletions stack/framework/hal/chips/ezr32lg/ezr32lg_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <em_cmu.h>
#include <em_gpio.h>
#include <em_usbd.h>
#include <dmadrv.h>
#include "hwgpio.h"
#include "hwuart.h"
#include <assert.h>
Expand All @@ -37,6 +38,7 @@
#include "ezr32lg_pins.h"

#include "platform.h"
#include "hal_defs.h"


#define UARTS 4 // 2 UARTs + 3 USARTs
Expand Down Expand Up @@ -149,6 +151,10 @@ struct uart_handle {
CMU_Clock_TypeDef clock;
uart_irq_t irq;
uart_pins_t* pins;
#ifdef HAL_UART_USE_DMA_TX
unsigned int dma_channel_tx;
DMADRV_PeripheralSignal_t dma_req_signal_tx;
#endif
};

// private storage of handles, pointers to these records are passed around
Expand All @@ -157,25 +163,37 @@ static uart_handle_t handle[UARTS] = {
.idx = 0,
.channel = UART0,
.clock = cmuClock_UART0,
.irq = { .tx = UART0_TX_IRQn, .rx = UART0_RX_IRQn }
.irq = { .tx = UART0_TX_IRQn, .rx = UART0_RX_IRQn },
#ifdef HAL_UART_USE_DMA_TX
.dma_req_signal_tx = DMAREQ_UART0_TXBL
#endif
},
{
.idx = 1,
.channel = UART1,
.clock = cmuClock_UART1,
.irq = { .tx = UART1_TX_IRQn, .rx = UART1_RX_IRQn }
.irq = { .tx = UART1_TX_IRQn, .rx = UART1_RX_IRQn },
#ifdef HAL_UART_USE_DMA_TX
.dma_req_signal_tx = DMAREQ_UART1_TXBL
#endif
},
{
.idx = 2,
.channel = USART1,
.clock = cmuClock_USART1,
.irq = { .tx = USART1_TX_IRQn, .rx = USART1_RX_IRQn }
.irq = { .tx = USART1_TX_IRQn, .rx = USART1_RX_IRQn },
#ifdef HAL_UART_USE_DMA_TX
.dma_req_signal_tx = DMAREQ_USART1_TXBL
#endif
},
{
.idx = 3,
.channel = USART2,
.clock = cmuClock_USART2,
.irq = { .tx = USART2_TX_IRQn, .rx = USART2_RX_IRQn }
.irq = { .tx = USART2_TX_IRQn, .rx = USART2_RX_IRQn },
#ifdef HAL_UART_USE_DMA_TX
.dma_req_signal_tx = DMAREQ_USART2_TXBL
#endif
}
};

Expand Down Expand Up @@ -216,6 +234,14 @@ uart_handle_t* uart_init(uint8_t idx, uint32_t baudrate, uint8_t pins) {

USART_Enable(handle[idx].channel, usartEnable);

#ifdef HAL_UART_USE_DMA_TX
// DMADRV is used for allocating a channel. We need to use DMADRV for housekeeping, since ezradio driver also uses this for allocating a channel.
Ecode_t e = DMADRV_Init();
assert(e == ECODE_EMDRV_DMADRV_OK || e == ECODE_EMDRV_DMADRV_ALREADY_INITIALIZED); // can be already initialized for example by EZRDRV

e = DMADRV_AllocateChannel(&(handle[idx].dma_channel_tx), NULL); assert(e == ECODE_EMDRV_DMADRV_OK);
#endif

return &handle[idx];
}

Expand Down Expand Up @@ -278,11 +304,24 @@ void uart_send_bytes(uart_handle_t* uart, void const *data, size_t length) {
};
int ret = USBD_Write( 0x81, (void*) tempData, length, NULL);
}
#else
#ifdef HAL_UART_USE_DMA_TX
DMADRV_MemoryPeripheral(
uart->dma_channel_tx,
uart->dma_req_signal_tx,
(void*)&uart->channel->TXDATA,
data,
true,
length,
dmadrvDataSize1,
NULL,
NULL);
#else
for(size_t i=0; i<length; i++) {
uart_send_byte(uart, ((uint8_t const*)data)[i]);
}
#endif
uart_send_byte(uart, ((uint8_t const*)data)[i]);
}
#endif // HAL_UART_USE_DMA_TX
#endif // PLATFORM_USE_USB_CDC
}

void uart_send_string(uart_handle_t* uart, const char *string) {
Expand Down Expand Up @@ -312,6 +351,7 @@ void uart_rx_interrupt_disable(uart_handle_t* uart) {

void UART0_RX_IRQHandler(void) {
if(handle[0].channel->STATUS & UART_STATUS_RXDATAV) {
assert((USART_IntGet(handle[0].channel) & UART_IF_RXOF) == 0);
handler[0](USART_Rx(handle[0].channel));
USART_IntClear(handle[0].channel, UART_IF_RXDATAV);
}
Expand Down

0 comments on commit 31e1a7e

Please sign in to comment.