From 03f33481c42954ec118d5dd92703b2b2208f4a3a Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Sun, 26 Mar 2017 21:45:42 +0100 Subject: uart support --- Makefile | 3 +- lib/cm4.h | 2 + setup.c | 2 + uart/uart.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ uart/uart.h | 4 ++ usb/usb.c | 1 + vectors.s | 2 +- 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 +#include +#include +#include +#include +#include +#include + #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 -- cgit v1.2.3-54-g00ecf