diff options
| author | Tomasz Kramkowski <tk@the-tk.com> | 2017-03-26 21:45:42 +0100 | 
|---|---|---|
| committer | Tomasz Kramkowski <tk@the-tk.com> | 2017-03-26 21:45:42 +0100 | 
| commit | 03f33481c42954ec118d5dd92703b2b2208f4a3a (patch) | |
| tree | 61ff51b02413e2a7441bf340f9afd8510af29890 | |
| parent | 6f2090ae7fca871512258623d2bbd5484716a706 (diff) | |
| download | fmk-03f33481c42954ec118d5dd92703b2b2208f4a3a.tar.gz fmk-03f33481c42954ec118d5dd92703b2b2208f4a3a.tar.xz fmk-03f33481c42954ec118d5dd92703b2b2208f4a3a.zip | |
uart support
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | lib/cm4.h | 2 | ||||
| -rw-r--r-- | setup.c | 2 | ||||
| -rw-r--r-- | uart/uart.c | 213 | ||||
| -rw-r--r-- | uart/uart.h | 4 | ||||
| -rw-r--r-- | usb/usb.c | 1 | ||||
| -rw-r--r-- | vectors.s | 2 | 
7 files changed, 225 insertions, 2 deletions
| @@ -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) @@ -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 */ @@ -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 */ @@ -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); @@ -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 | 
