summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--lib/cm4.h2
-rw-r--r--setup.c2
-rw-r--r--uart/uart.c213
-rw-r--r--uart/uart.h4
-rw-r--r--usb/usb.c1
-rw-r--r--vectors.s2
7 files changed, 225 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index d663578..ce66787 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,8 @@ CFLAGS = -std=c11 $(WARNINGS) -O2 -flto -MMD -MP -ffreestanding -nostdlib
LDFLAGS = -T layout.ld -O2 -flto -ffreestanding -nostdlib
ASFLAGS = $(TARGET_ARCH)
-OBJ := crt0.o vectors.o flashconf.o setup.o fmk.o lib/le.o usb/usb.o usb/endpt0.o usb/endpt1.o
+OBJ := crt0.o vectors.o flashconf.o setup.o fmk.o lib/le.o usb/usb.o \
+ usb/endpt0.o usb/endpt1.o uart/uart.o
include $(MK20DX256)/mk20dx256.mk
CPPFLAGS += $(mk20dx256_CPPFLAGS)
diff --git a/lib/cm4.h b/lib/cm4.h
index 7c1c774..27c02da 100644
--- a/lib/cm4.h
+++ b/lib/cm4.h
@@ -7,4 +7,6 @@
#define SETENA(n) REG_32(0xE000E100 + 4 * (n))
#define ISR_SETENA(i) SETENA((i) / 32) = BV((i) % 32);
+#define INTPRI(n) REG_8(0xE000E400 + (n))
+
#endif /* LIB_CM4_H */
diff --git a/setup.c b/setup.c
index e024844..71d7d73 100644
--- a/setup.c
+++ b/setup.c
@@ -4,6 +4,7 @@
#include "asm.h"
#include "usb/usb.h"
+#include "uart/uart.h"
extern unsigned char _ldata[], _sdata[], _edata[];
extern unsigned char _sbss[], _ebss[];
@@ -88,6 +89,7 @@ void setup(void)
PORTC_PCR(5) = 1 << PCR_MUX | BV(PCR_DSE);
GPIOC_PDDR = BV(5);
+ uart_setup();
usb_setup();
/* Enable interrupts for setup */
diff --git a/uart/uart.c b/uart/uart.c
index 031cf74..2e5d68d 100644
--- a/uart/uart.c
+++ b/uart/uart.c
@@ -1,5 +1,218 @@
+#include <cm4.h>
+#include <reg/gpio.h>
+#include <reg/port.h>
+#include <reg/sim.h>
+#include <reg/uart.h>
+#include <stddef.h>
+#include <stdarg.h>
+
#include "uart.h"
+#include "../asm.h"
+
+enum {
+ SBR_VAL = 39,
+ BRFA_VAL = 2,
+ SRBSZ = 1024,
+ FIFOSZ = 8,
+};
+
+static struct {
+ unsigned char buf[SRBSZ];
+ int start, end;
+} send_rb = { .start = 0, .end = 0 };
+
+static inline size_t rb_store(void *_data, size_t size)
+{
+ unsigned char *data = _data;
+ size_t avail;
+ int start, end;
+
+ start = send_rb.start;
+ end = send_rb.end;
+ avail = (start + sizeof send_rb.buf - end) % sizeof send_rb.buf - 1;
+
+ if (size > avail)
+ size = avail;
+
+ for (int i = 0; i < size; i++)
+ send_rb.buf[(end + i) % sizeof send_rb.buf] = data[i];
+ send_rb.end = (end + size) % sizeof send_rb.buf;
+
+ /* Enable Transmission Interrupt */
+ CLI();
+ SET_BIT(UART0_C2, C2_TIE);
+ STI();
+
+ return size;
+}
void uart_setup(void)
{
+ /* Clock gating for UART0 */
+ SET_BIT(SIM_SCGC4, SCGC4_UART0);
+ /* Disable TX and RX */
+ SET_MASKED(UART0_C2, BV(C2_TE) | BV(C2_RE), 0);
+ /* Default settings */
+ UART0_C1 = 0;
+ /* SBR and BRFA for baud rate */
+ SET_MASKED(UART0_BDH, BDH_SBR_M, ((SBR_VAL & 0x1f00) >> 8) << BDH_SBR);
+ SET_MASKED(UART0_BDL, BDL_SBR_M, (SBR_VAL & 0xff) << BDL_SBR);
+ SET_MASKED(UART0_C4, C4_BRFA_M, BRFA_VAL << C4_BRFA);
+ /* flush and enable TX FIFO */
+ UART0_CFIFO |= BV(CFIFO_TXFLUSH);
+ UART0_PFIFO |= BV(PFIFO_TXFE);
+ /* set watermark at 1 entry */
+ SET_MASKED(UART0_TWFIFO, TWFIFO_TXWATER_M, 1 << TWFIFO_TXWATER);
+ /* NVIC enable interrupt */
+ ISR_CLRPEND(45);
+ INTPRI(45) = 0xf0;
+ ISR_SETENA(45);
+ /* enable correct ALT MUX on TX pin */
+ PORTB_PCR(17) = 3 << PCR_MUX;
+ /* enable TX */
+ SET_MASKED(UART0_C2, BV(C2_TE), BV(C2_TE));
+}
+
+void uart_putchar(int c)
+{
+ static unsigned char buf[128];
+ static size_t size = 0;
+
+ if (c == '\n')
+ uart_putchar('\r');
+
+ buf[size++] = c;
+
+ if (size >= sizeof buf || c == '\n') {
+ rb_store(buf, size);
+ size = 0;
+ }
+}
+
+void uart_puts(const char *s)
+{
+ for (size_t i = 0; s[i]; i++)
+ uart_putchar(s[i]);
+ uart_putchar('\n');
+}
+
+static inline void putul(unsigned long n, int base)
+{
+ static const char *digits = "0123456789abcdef";
+ int i;
+ char tmp[64];
+
+ if (base < 2 || base > 16)
+ return;
+
+ if (n == 0) {
+ uart_putchar('0');
+ return;
+ }
+ for (i = 0; n; i++) {
+ int res = n % base;
+ n = n / base;
+ tmp[i] = digits[res];
+ }
+
+ for (i -= 1; i >= 0; i--)
+ uart_putchar(tmp[i]);
+}
+
+static inline void putl(long n)
+{
+ int i;
+ char tmp[64];
+
+ if (n < 0) {
+ uart_putchar('-');
+ n *= -1;
+ }
+
+ if (n == 0) {
+ uart_putchar('0');
+ return;
+ }
+
+ for (i = 0; n; i++) {
+ int res = n % 10;
+ n = n / 10;
+ tmp[i] = '0' + res;
+ }
+
+ for (i -= 1; i >= 0; i--)
+ uart_putchar(tmp[i]);
+}
+
+void uart_printf(const char *fmt, ...)
+{
+ va_list ap;
+ const char *p;
+ int ival;
+ unsigned uival;
+ long lival;
+ unsigned long ulival;
+
+ va_start(ap, fmt);
+ for (p = fmt; *p; p++) {
+ if (*p != '%') {
+ uart_putchar(*p);
+ continue;
+ }
+ switch (*++p) {
+ case 'd': case 'i':
+ ival = va_arg(ap, int);
+ putl(ival);
+ break;
+ case 'o': case 'u': case 'x':
+ uival = va_arg(ap, unsigned);
+ switch (*p) {
+ case 'o': putul(uival, 8); break;
+ case 'u': putul(uival, 10); break;
+ case 'x': putul(uival, 16); break;
+ }
+ break;
+ case 'l':
+ switch (*++p) {
+ case 'd': case 'i':
+ lival = va_arg(ap, long);
+ putl(lival);
+ break;
+ case 'o': case 'u': case 'x':
+ ulival = va_arg(ap, unsigned long);
+ switch (*p) {
+ case 'o': putul(ulival, 8); break;
+ case 'u': putul(ulival, 10); break;
+ case 'x': putul(ulival, 16); break;
+ }
+ break;
+ }
+ }
+ }
+ va_end(ap);
+}
+
+void uart0_isr(void)
+{
+ int avail, start, end, tosend;
+
+ if (!GET_BIT(UART0_S1, S1_TDRE))
+ return;
+
+ avail = FIFOSZ - UART0_TCFIFO;
+ CLI();
+ start = send_rb.start;
+ end = send_rb.end;
+ tosend = (end + sizeof send_rb.buf - start) % sizeof send_rb.buf;
+ if (tosend == 0)
+ UNSET_BIT(UART0_C2, C2_TIE);
+ STI();
+
+ if (tosend > avail)
+ tosend = avail;
+
+ for (int i = 0; i < tosend; i++)
+ UART0_D = send_rb.buf[(start + i) % sizeof send_rb.buf];
+
+ send_rb.start = (start + tosend) % sizeof send_rb.buf;
}
diff --git a/uart/uart.h b/uart/uart.h
index 984d704..2733bb7 100644
--- a/uart/uart.h
+++ b/uart/uart.h
@@ -2,5 +2,9 @@
#define UART_UART_H
void uart_setup(void);
+void uart_putchar(int c);
+void uart_printf(const char *fmt, ...);
+void uart_puts(const char *s);
+void uart0_isr(void);
#endif /* UART_UART_H */
diff --git a/usb/usb.c b/usb/usb.c
index 59519fc..8b78f3b 100644
--- a/usb/usb.c
+++ b/usb/usb.c
@@ -44,6 +44,7 @@ void usb_setup(void)
/* NVIC Enable interrupt */
ISR_CLRPEND(73);
ISR_SETENA(73);
+ INTPRI(73) = 0x00;
/* Enable USB */
USB0_CTL = BV(CTL_USBENSOFEN);
diff --git a/vectors.s b/vectors.s
index 1981eb5..ae53c35 100644
--- a/vectors.s
+++ b/vectors.s
@@ -56,7 +56,7 @@
.long 0 // 52 I2S0: Receive
.fill 7,4,0 // 53..59 -
.long 0 // 60 UART0: Single interrupt vector for UART LON sources
-.long 0 // 61 UART0: Single interrupt vector for UART status sources
+.long uart0_isr // 61 UART0: Single interrupt vector for UART status sources
.long 0 // 62 UART0: Single interrupt vector for UART error sources
.long 0 // 63 UART1: Single interrupt vector for UART status sources
.long 0 // 64 UART1: Single interrupt vector for UART error sources