--- /dev/null
+#include <MKL46Z4.h>\r
+\r
+#include <stdint.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include "serial_dma.h"\r
+\r
+/* Defines */\r
+#define UART sdma_uart\r
+#define DMA (&(DMA0->DMA[sdma_chan]))\r
+#define MUX ((dma_mux_t*)&(DMAMUX0->CHCFG[sdma_chan]))\r
+\r
+#define NUM 2\r
+#define LEN 1024\r
+\r
+/* Types */\r
+typedef struct {uint8_t CHCFG;} dma_mux_t;\r
+\r
+/* Setup data */\r
+static UART0_Type *sdma_uart;\r
+static int sdma_chan;\r
+\r
+/* Error logging */\r
+static int sdma_stuck;\r
+static int sdma_full;\r
+\r
+/* Data buffering */\r
+static int sdma_index;\r
+static int sdma_length[NUM];\r
+static uint8_t sdma_queue[NUM][LEN];\r
+\r
+/* DMA Functions */\r
+void sdma_setup(UART0_Type *uart, int channel)\r
+{\r
+ // Save configuration data\r
+ sdma_uart = uart;\r
+ sdma_chan = channel;\r
+\r
+ // Enable DMA Cock\r
+ SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;\r
+ SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;\r
+\r
+ // Reset channel\r
+ DMA->DSR_BCR = DMA_DSR_BCR_DONE_MASK;\r
+\r
+ // Configure DMA transfer\r
+ DMA->DAR = (uint32_t)&UART0->D;\r
+ DMA->DCR = DMA_DCR_CS_MASK |\r
+ DMA_DCR_SINC_MASK |\r
+ DMA_DCR_SSIZE(1) |\r
+ DMA_DCR_DSIZE(1) |\r
+ DMA_DCR_D_REQ_MASK;\r
+\r
+ // Configure DMA Mux\r
+ MUX->CHCFG = DMAMUX_CHCFG_SOURCE(3) |\r
+ DMAMUX_CHCFG_ENBL_MASK;\r
+\r
+ // Configure UART for DMA Channel 0\r
+ UART->C5 |= UART0_C5_TDMAE_MASK;\r
+}\r
+\r
+/* Write binary data out the DMA output queue */\r
+void sdma_write(void *data, int len)\r
+{\r
+ if (sdma_length[sdma_index] + len > LEN) {\r
+ sdma_full++;\r
+ } else {\r
+ int pos = sdma_length[sdma_index];\r
+ void *dst = &sdma_queue[sdma_index][pos];\r
+ memcpy(dst, data, len);\r
+ sdma_length[sdma_index] += len;\r
+ }\r
+}\r
+\r
+/* Write ASCII data to the output queue */\r
+void sdma_vprintf(const char *fmt, va_list ap)\r
+{\r
+ int pos = sdma_length[sdma_index];\r
+ void *dst = &sdma_queue[sdma_index][pos];\r
+ sdma_length[sdma_index] +=\r
+ vsnprintf((char*)dst, LEN-pos, fmt, ap);\r
+}\r
+\r
+void sdma_printf(const char *fmt, ...)\r
+{\r
+ va_list ap;\r
+ va_start(ap, fmt);\r
+ sdma_vprintf(fmt, ap);\r
+ va_end(ap);\r
+}\r
+\r
+/* Trigger DMA transmit of the current output queue\r
+ * and swap buffers so we can write into unused space */\r
+void sdma_flush(void)\r
+{\r
+ if (sdma_length[sdma_index] == 0)\r
+ return;\r
+\r
+ // Wait for transmit complete\r
+ while (DMA->DSR_BCR & DMA_DSR_BCR_BCR_MASK)\r
+ sdma_stuck++;\r
+\r
+ // Reset channel\r
+ DMA->DSR_BCR = DMA_DSR_BCR_DONE_MASK;\r
+\r
+ // Set source address and length\r
+ DMA->SAR = (uint32_t)&sdma_queue[sdma_index];\r
+ DMA->DSR_BCR = DMA_DSR_BCR_BCR(sdma_length[sdma_index]);\r
+\r
+ // Enable DMA transmit\r
+ DMA->DCR |= DMA_DCR_ERQ_MASK;\r
+\r
+ // Swap buffers\r
+ sdma_length[sdma_index] = 0;\r
+ sdma_index = (sdma_index + 1) % NUM;\r
+}\r