From b8335062ae7d19bd27e6131fadcd7d3a116c4992 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Fri, 11 Mar 2011 01:28:00 +0000 Subject: DimOS RT --- Makefile | 5 + bootloader/Makefile | 5 + bootloader/Makefile.inc | 6 + bootloader/bootloader.c | 94 +++++++++++++ bootloader/bootloader.h | 39 ++++++ bootloader/bootloader/Makefile | 7 + bootloader/dump.c | 60 +++++++++ bootloader/hexdump/Makefile | 7 + bootloader/ihex.c | 93 +++++++++++++ bootloader/mem.c | 69 ++++++++++ bootloader/memdump/Makefile | 7 + bootloader/tty.c | 80 +++++++++++ firmware/Makefile | 61 +++++++++ firmware/firmware.c | 104 +++++++++++++++ kernel/Makefile | 64 +++++++++ kernel/heartbeat.c | 53 ++++++++ kernel/hsv.c | 25 ++++ kernel/kernel.c | 297 +++++++++++++++++++++++++++++++++++++++++ kernel/kernel.h | 80 +++++++++++ kernel/lcd3.c | 184 +++++++++++++++++++++++++ kernel/main.c | 52 ++++++++ kernel/rgb.c | 79 +++++++++++ kernel/stack.h | 99 ++++++++++++++ kernel/tasks.h | 39 ++++++ kernel/uart.c | 80 +++++++++++ 25 files changed, 1689 insertions(+) create mode 100644 Makefile create mode 100644 bootloader/Makefile create mode 100644 bootloader/Makefile.inc create mode 100644 bootloader/bootloader.c create mode 100644 bootloader/bootloader.h create mode 100644 bootloader/bootloader/Makefile create mode 100644 bootloader/dump.c create mode 100644 bootloader/hexdump/Makefile create mode 100644 bootloader/ihex.c create mode 100644 bootloader/mem.c create mode 100644 bootloader/memdump/Makefile create mode 100644 bootloader/tty.c create mode 100644 firmware/Makefile create mode 100644 firmware/firmware.c create mode 100644 kernel/Makefile create mode 100644 kernel/heartbeat.c create mode 100644 kernel/hsv.c create mode 100644 kernel/kernel.c create mode 100644 kernel/kernel.h create mode 100644 kernel/lcd3.c create mode 100644 kernel/main.c create mode 100644 kernel/rgb.c create mode 100644 kernel/stack.h create mode 100644 kernel/tasks.h create mode 100644 kernel/uart.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0bbec38 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +# $Id$ + +SUBDIR = bootloader firmware kernel + +.include diff --git a/bootloader/Makefile b/bootloader/Makefile new file mode 100644 index 0000000..ddf36a5 --- /dev/null +++ b/bootloader/Makefile @@ -0,0 +1,5 @@ +# $Id$ + +SUBDIR= bootloader hexdump memdump + +.include diff --git a/bootloader/Makefile.inc b/bootloader/Makefile.inc new file mode 100644 index 0000000..772968c --- /dev/null +++ b/bootloader/Makefile.inc @@ -0,0 +1,6 @@ +# $Id$ + +.PATH: ${.CURDIR}/.. +CFLAGS+=-I${.CURDIR}/.. +DEBUG+= -Wall -ggdb +NOMAN= diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c new file mode 100644 index 0000000..d83db57 --- /dev/null +++ b/bootloader/bootloader.c @@ -0,0 +1,94 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "bootloader.h" + +int +transfer(int fd, struct page *p, int pages, int pagesize) +{ + int n, off; + + fprintf(stderr, "trying to reboot device\n"); + usleep(500); + put('R', fd); /* try to reboot */ + usleep(500); + + fprintf(stderr, "waiting for bootloader "); + do { + put('P', fd); + twiddle(); + } while (get(fd) != 'p'); + + fprintf(stderr, "\nwriting: "); + + for (n = 0; n < pages; n++) { + fprintf(stderr, "%c", ".o"[p[n].dirty]); + if (p[n].dirty) { + put('D', fd); + put(n, fd); + for (off = 0; off < pagesize; off++) + put(p[n].data[off], fd); + assert (get(fd) == 'd'); + } + } + fprintf(stderr, "\nrebooting\n"); + put('R', fd); + + return 0; +} + +int +main(int argc, char **argv) +{ + struct page *p; + char *dev = "/dev/ttyU0"; + int c, fd; + + while ((c = getopt(argc, argv, "f:")) != -1) + switch (c) { + case 'f': + dev = strdup(optarg); + break; + default: + break; + } + + argc -= optind; + argv += optind; + + if (argc != 1) + return -1; + + p = rdhex(argv[0], PAGENUM, PAGESIZE); + assert(p); + assert(p[120].dirty == 0); /* protect firmware */ + + fd = open_tty(dev); + if (fd == -1) + perror(dev); + transfer(fd, p, PAGENUM, PAGESIZE); + close(fd); + + freehex(p, PAGENUM); + + return 0; +} diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h new file mode 100644 index 0000000..1af5364 --- /dev/null +++ b/bootloader/bootloader.h @@ -0,0 +1,39 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __BOOTLOADER_H +#define __BOOTLOADER_H + +#define PAGESIZE 64 +#define PAGENUM 128 +#define RAMEND 0x45F + +struct page { + unsigned char *data; + int dirty; +}; + +struct page *rdhex(char *, int, int); +void freehex(struct page *, int); + +void put(unsigned char c, int fd); +unsigned char get(int fd); +void twiddle(void); +int open_tty(char *dev); +void close_tty(int fd); + +#endif diff --git a/bootloader/bootloader/Makefile b/bootloader/bootloader/Makefile new file mode 100644 index 0000000..d12e9fb --- /dev/null +++ b/bootloader/bootloader/Makefile @@ -0,0 +1,7 @@ +# $Id$ + +PROG= bootloader +SRCS= bootloader.c ihex.c tty.c +NOMAN= + +.include diff --git a/bootloader/dump.c b/bootloader/dump.c new file mode 100644 index 0000000..3d675f4 --- /dev/null +++ b/bootloader/dump.c @@ -0,0 +1,60 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include "bootloader.h" + +void +dumphex(struct page *p, int pages, int pagesize) +{ + int n, off, used = 0; + + for (n = 0; n < pages; n++) { + if (p[n].dirty) { + ++used; + printf("page %3d (%.4x)", n, n * pagesize); + for (off = 0; off < pagesize; off++) { + if (off % 16 == 0) + printf("\n"); + printf("%3.2x", p[n].data[off]); + } + printf("\n"); + } + } + + printf("used: %3d/%3d (%5.2f%%)\n", used, pages, + 100 * used / (float)pages); +} + +int +main(int argc, char **argv) +{ + struct page *p; + + if (argc != 2) + return -1; + + p = rdhex(argv[1], PAGENUM, PAGESIZE); + assert(p); + dumphex(p, PAGENUM, PAGESIZE); + freehex(p, PAGENUM); + + return 0; +} diff --git a/bootloader/hexdump/Makefile b/bootloader/hexdump/Makefile new file mode 100644 index 0000000..c72213a --- /dev/null +++ b/bootloader/hexdump/Makefile @@ -0,0 +1,7 @@ +# $Id$ + +PROG= dump +SRCS= dump.c ihex.c +NOMAN= + +.include diff --git a/bootloader/ihex.c b/bootloader/ihex.c new file mode 100644 index 0000000..4348910 --- /dev/null +++ b/bootloader/ihex.c @@ -0,0 +1,93 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "bootloader.h" + +int +rdbyte(char **s, int *sum) +{ + int x; + + sscanf(*s, "%2x", &x); + + *s += 2; + *sum += x; + + return x; +} + +struct page * +rdhex(char *fname, int pages, int pagesize) +{ + struct page *p; + FILE *fd; + uint i, length, addr, addrh, addrl, cksum, page, off; + char *s, buf[80]; + + fd = fopen(fname, "r"); + if (!fd) + return NULL; + + p = calloc(pages, sizeof(struct page)); + + while ((s = fgets(buf, sizeof(buf), fd)) != NULL) { + if (*s++ != ':') + continue; + + cksum = 0; + length = rdbyte(&s, &cksum); + addrh = rdbyte(&s, &cksum); + addrl = rdbyte(&s, &cksum); + if (rdbyte(&s, &cksum)) /* type, has to be 0 (DATA) */ + continue; + + addr = (addrh << 8) | addrl; + for (i = 0; i < length; i++) { + page = (addr + i) / pagesize; + off = (addr + i) % pagesize; + if (!p[page].dirty) { + p[page].data = malloc(pagesize); + memset(p[page].data, 0xff, pagesize); + } + p[page].data[off] = rdbyte(&s, &cksum); + p[page].dirty = 1; + } + + rdbyte(&s, &cksum); /* checksum, last byte */ + if (cksum & 0xff) + return NULL; + } + + fclose(fd); + + return p; +} + +void +freehex(struct page *p, int pages) +{ + int i; + + for (i = 0; i < pages; i++) + if (p[i].dirty) + free(p[i].data); + + free(p); +} diff --git a/bootloader/mem.c b/bootloader/mem.c new file mode 100644 index 0000000..3f6e564 --- /dev/null +++ b/bootloader/mem.c @@ -0,0 +1,69 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include "bootloader.h" + +int +transfer(int fd, FILE *dump, int ramend) +{ + int n; + + put('D', fd); + + printf("reading mem: "); + + for (n = 0; n <= ramend; n++) { + twiddle(); + fputc(get(fd), dump); + } + printf("\n"); + + return 0; +} + +int +main(int argc, char **argv) +{ + char *dev = "/dev/ttyU0"; + int c, fd; + FILE *dump; + + while ((c = getopt(argc, argv, "f:")) != -1) + switch (c) { + case 'f': + dev = strdup(optarg); + break; + default: + break; + } + + argc -= optind; + argv += optind; + + dump = fopen("memdump", "w"); + fd = open_tty(dev); + transfer(fd, dump, RAMEND); + close(fd); + fclose(dump); + + return 0; +} diff --git a/bootloader/memdump/Makefile b/bootloader/memdump/Makefile new file mode 100644 index 0000000..f958b94 --- /dev/null +++ b/bootloader/memdump/Makefile @@ -0,0 +1,7 @@ +# $Id$ + +PROG= mem +SRCS= mem.c tty.c +NOMAN= + +.include diff --git a/bootloader/tty.c b/bootloader/tty.c new file mode 100644 index 0000000..8cf20fb --- /dev/null +++ b/bootloader/tty.c @@ -0,0 +1,80 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootloader.h" + +void +put(unsigned char c, int fd) +{ + while (write(fd, &c, 1) == -1) + ; +} + +unsigned char +get(int fd) +{ + unsigned char c; + + while (read(fd, &c, 1) == -1) + ; + + return c; +} + +void +twiddle(void) +{ + static int pos; + + putchar("|/-\\"[pos++ & 3]); + putchar('\b'); +} + + +int +open_tty(char *dev) +{ + struct termios tio; + int fd; + + fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) + return -1; + + fprintf(stderr, "open done, trying to set raw\n"); + + bzero(&tio, sizeof(tio)); + tio.c_cflag = CS8 | CREAD | CLOCAL; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 10; + cfsetspeed(&tio, B9600); + cfmakeraw(&tio); + if (tcsetattr(fd, TCSANOW, &tio) < 0) + fprintf(stderr, "cannot set raw mode\n"); + + usleep(500); + + return fd; +} diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..a65993e --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,61 @@ +# $Id$ + +PROG = firmware +SRCS = firmware.c +HEADERS = +MCU_TARGET = atmega8 +F_CPU = 16000000 +PRESCALE = 8 +BAUD = 9600 +ORG = 0x1e00 + +# You should not have to change anything below here. + +OBJS = ${SRCS:.c=.o} +CC = avr-gcc +CFLAGS = -Wall -Os -mmcu=${MCU_TARGET} \ + -DF_CPU=${F_CPU} -DPRESCALE=${PRESCALE} -DBAUD=${BAUD} +LDFLAGS = -Wl,-Map,${PROG}.map,--section-start=.text=${ORG} +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size + +.SUFFIXES: .elf .lst .hex .bin .srec .ehex .ebin .esrec + +all: ${PROG}.elf ${PROG}.lst ${PROG}.hex ${PROG}.ehex size + +${SRCS}: ${HEADERS} Makefile + +${PROG}.elf: ${OBJS} + ${CC} ${CFLAGS} ${LDFLAGS} -o ${.TARGET} ${.ALLSRC} + +size: ${PROG}.elf + ${SIZE} -C --mcu=${MCU_TARGET} ${.ALLSRC} + +clean: + rm -f *.o ${PROG}.elf *.bak *.lst *.map *.hex *.bin *srec *.ehex *.ebin *.esrec + +.elf.lst: + ${OBJDUMP} -h -S ${.ALLSRC} > ${.TARGET} + +# Rules for building the .text rom images + +.elf.hex: + ${OBJCOPY} -j .text -j .data -O ihex ${.ALLSRC} ${.TARGET} + +.elf.bin: + ${OBJCOPY} -j .text -j .data -O binary ${.ALLSRC} ${.TARGET} + +.elf.srec: + ${OBJCOPY} -j .text -j .data -O srec ${.ALLSRC} ${.TARGET} + +# Rules for building the .eeprom rom images + +.elf.ehex: + ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O ihex ${.ALLSRC} ${.TARGET} + +.elf.ebin: + ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O binary ${.ALLSRC} ${.TARGET} + +.elf.esrec: + ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O srec ${.ALLSRC} ${.TARGET} diff --git a/firmware/firmware.c b/firmware/firmware.c new file mode 100644 index 0000000..a0a649b --- /dev/null +++ b/firmware/firmware.c @@ -0,0 +1,104 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include /* depends on BAUD & F_CPU env vars */ +#include + +#define TIMEOUT (F_CPU >> 3) /* ca. 2 sec */ + +union { + uint16_t word; + uint8_t byte[2]; +} data; + +void +reboot() +{ + boot_rww_enable(); + ((void(*)(void))0)(); /* jump to app */ +} + +void +putch(char c) +{ + if (c == '\n') + putch('\r'); /* be unix polite */ + + loop_until_bit_is_set(UCSRA, UDRE); + + UDR = c; +} + +uint8_t +getch(void) +{ + uint32_t counter = 0; + + do { + if (++counter > TIMEOUT) + reboot(); + } while (bit_is_clear(UCSRA, RXC)); + + return UDR; +} + +int +main(void) +{ + uint8_t i; + uint16_t off; + + UCSRB = _BV(RXEN) | _BV(TXEN); + UBRRH = UBRRH_VALUE; + UBRRL = UBRRL_VALUE; + UCSRA &= ~_BV(U2X); + + putch('+'); /* say hallo */ + + if (getch() != 'P') /* wait a while for program request */ + reboot(); + putch('p'); /* confirm */ + + for (;;) { + switch (getch()) { + case 'D': /* data request */ + off = (uint16_t)getch() * SPM_PAGESIZE; + for (i = 0; i < SPM_PAGESIZE; i += 2) { + data.byte[0] = getch(); + data.byte[1] = getch(); + boot_page_fill(off + i, data.word); + } + + boot_page_erase(off); + boot_spm_busy_wait(); + + boot_page_write(off); + boot_spm_busy_wait(); + + putch('d'); /* confirm */ + break; + case 'R': /* reboot request */ + reboot(); + break; + default: + break; + } + } + + return 0; +} diff --git a/kernel/Makefile b/kernel/Makefile new file mode 100644 index 0000000..1d5be25 --- /dev/null +++ b/kernel/Makefile @@ -0,0 +1,64 @@ +# $Id$ + +PROG = kernel +SRCS = kernel.c main.c uart.c heartbeat.c rgb.c hsv.c lcd3.c +HEADERS = kernel.h stack.h +MCU_TARGET = atmega8 +F_CPU = 16000000 +PRESCALE = 8 +STACK = 64 +TASKS = 8 +SEMAPHORES = 8 +BAUD = 9600 + +# You should not have to change anything below here. + +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +OBJS = ${SRCS:.c=.o} +CFLAGS = -Wall -Os -mmcu=${MCU_TARGET} \ + -DF_CPU=${F_CPU} -DPRESCALE=${PRESCALE} -DBAUD=${BAUD} \ + -DSTACK=${STACK} -DTASKS=${TASKS} -DSEMAPHORES=${SEMAPHORES} +LDFLAGS = -Wl,-Map,${PROG}.map + +.SUFFIXES: .elf .lst .hex .bin .srec .ehex .ebin .esrec + +all: ${PROG}.elf ${PROG}.lst ${PROG}.hex ${PROG}.ehex size + +${SRCS}: ${HEADERS} Makefile + +${PROG}.elf: ${OBJS} + ${CC} ${LDFLAGS} -o ${.TARGET} ${.ALLSRC} + +size: ${PROG}.elf + ${SIZE} -C --mcu=${MCU_TARGET} ${.ALLSRC} + +clean: + rm -f *.o ${PROG}.elf *.bak *.lst *.map *.hex *.bin *srec *.ehex *.ebin *.esrec + +.elf.lst: + ${OBJDUMP} -h -S ${.IMPSRC} > ${.TARGET} + +# Rules for building the .text rom images + +.elf.hex: + ${OBJCOPY} -j .text -j .data -O ihex ${.IMPSRC} ${.TARGET} + +.elf.bin: + ${OBJCOPY} -j .text -j .data -O binary ${.IMPSRC} ${.TARGET} + +.elf.srec: + ${OBJCOPY} -j .text -j .data -O srec ${.IMPSRC} ${.TARGET} + +# Rules for building the .eeprom rom images + +.elf.ehex: + ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O ihex ${.IMPSRC} ${.TARGET} + +.elf.ebin: + ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O binary ${.IMPSRC} ${.TARGET} + +.elf.esrec: + ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O srec ${.IMPSRC} ${.TARGET} diff --git a/kernel/heartbeat.c b/kernel/heartbeat.c new file mode 100644 index 0000000..6960e63 --- /dev/null +++ b/kernel/heartbeat.c @@ -0,0 +1,53 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "kernel.h" +#include "tasks.h" + +#define PIN PB0 + +void +heartbeat(void *arg) +{ + /* 80bpm: 100ms on, 50ms off, 100ms on, 500ms off */ + uint32_t d = deadline(); + uint32_t r = release(); + + DDRB |= _BV(PIN); + PORTB &= ~_BV(PIN); + + for (;;) { + PORTB ^= _BV(PIN); + r += MSEC(100); + update(r, d); + + PORTB ^= _BV(PIN); + r += MSEC(50); + update(r, d); + + PORTB ^= _BV(PIN); + r += MSEC(100); + update(r, d); + + PORTB ^= _BV(PIN); + r += MSEC(500); + d = r + MSEC(750); + update(r, d); + } +} diff --git a/kernel/hsv.c b/kernel/hsv.c new file mode 100644 index 0000000..f41bf09 --- /dev/null +++ b/kernel/hsv.c @@ -0,0 +1,25 @@ +/* $Id$ */ +/* public domain */ + +#include + +void +hsv(uint8_t *r, uint8_t *g, uint8_t *b, uint16_t h, uint8_t s, uint8_t v) +{ + uint8_t i, f, p, q, t; + + i = h / 60; + f = h % 60; + p = v - ((uint16_t)v * s) / 255; + q = v - ((uint32_t)v * s * f) / (255 * 59); + t = v - ((uint32_t)v * s * (59 - f)) / (255 * 59); + + switch (i % 6) { + case 0: *r = v; *g = t; *b = p; break; + case 1: *r = q; *g = v; *b = p; break; + case 2: *r = p; *g = v; *b = t; break; + case 3: *r = p; *g = q; *b = v; break; + case 4: *r = t; *g = p; *b = v; break; + case 5: *r = v; *g = p; *b = q; break; + } +} diff --git a/kernel/kernel.c b/kernel/kernel.c new file mode 100644 index 0000000..1d37d97 --- /dev/null +++ b/kernel/kernel.c @@ -0,0 +1,297 @@ +/* $Id$ */ +/* + * Copyright (c) 2010 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * based on TinyRealTime by Dan Henriksson and Anton Cervin + * http://www.control.lth.se/Publication/hen+04t.html + */ + +#include +#include +#include +#include "kernel.h" +#include "stack.h" + +enum { TERMINATED, READYQ, TIMEQ, WAITQOFFSET }; + +#define LO8(x) ((uint8_t)((uint16_t)(x))) +#define HI8(x) ((uint8_t)((uint16_t)(x) >> 8)) +#define SCHEDULE TIMER1_COMPA_vect +#define DISTANCE(from, to) ((int32_t)((to) - (from))) +#define EPOCH 0x3FFFFFFFUL /* XXX */ +#define EPS (LATENCY / PRESCALE + 1) /* XXX */ +#define NOW(hi, lo) (((uint32_t)(hi) << 0x10) | (lo)) + +struct task { + uint8_t spl; + uint8_t sph; + uint32_t release; + uint32_t deadline; + uint8_t state; +}; + +struct kernel { + struct task *running; + struct task *prev; + struct task *idle; + struct task *first; + struct task *last; + struct task task[TASKS + 1]; + uint8_t semaphore[SEMAPHORES]; + uint8_t *freemem; + uint16_t cycles; +} kernel; + +ISR(SCHEDULE, ISR_NAKED) +{ + struct task *t; + struct task *rtr; + uint32_t now; + uint32_t nexthit; + int32_t timeleft; + + PUSH_ALL(); + + TIMSK &= ~_BV(OCIE1A); /* turn off output compare 1A */ + + if (TIFR & _BV(TOV1)) { + TIFR |= _BV(TOV1); /* reset flag */ + ++kernel.cycles; + } + + now = NOW(kernel.cycles, TCNT1); + nexthit = now + EPOCH; + + /* update idle task */ + kernel.idle->release = now; + kernel.idle->deadline = nexthit; + + rtr = kernel.idle; + + for (t = kernel.first; t <= kernel.last; t++) { + /* release tasks from time-wait-queue */ + if (t->state == TIMEQ) { + if (DISTANCE(now, t->release) < 0) + t->state = READYQ; + else if (DISTANCE(t->release, nexthit) > 0) + nexthit = t->release; + } + + /* find next task to run */ + if (t->state == READYQ && \ + DISTANCE(t->deadline, rtr->deadline) > 0) + rtr = t; + } + + if (kernel.running != rtr) { + /* switch task */ + kernel.running->spl = SPL; + kernel.running->sph = SPH; + SPL = rtr->spl; + SPH = rtr->sph; + kernel.prev = kernel.running; + kernel.running = rtr; + } + + now = NOW(kernel.cycles, TCNT1); + timeleft = DISTANCE(now, nexthit); + + if (timeleft < EPS) + timeleft = EPS; + + timeleft += TCNT1; + + if (timeleft < 0xFFFF) + OCR1A = timeleft; + else if (TCNT1 < 0xFFFF - EPS) + OCR1A = 0; + else + OCR1A = EPS; + + TIMSK |= _BV(OCIE1A); + + POP_ALL(); + + reti(); +} + +void +init(int idlestack) +{ + /* Set up timer 1 */ + TCNT1 = 0; /* reset counter 1 */ + TCCR1A = 0; /* normal operation */ + TCCR1B = TIMER_FLAGS; + TIMSK = _BV(OCIE1A); + + kernel.freemem = (void *)(RAMEND - idlestack); + kernel.idle = &kernel.task[0]; + kernel.first = &kernel.task[1]; + kernel.last = kernel.idle; + kernel.running = kernel.idle; + kernel.prev = kernel.idle; + kernel.cycles = 0; + + /* Initialize idle task (task 0) */ + kernel.running->release = 0; + kernel.running->deadline = EPOCH; + + sei(); +} + +void +task(void (*fun)(void *), uint16_t stack, uint32_t release, uint32_t deadline, void *args) +{ + struct task *t; + uint8_t *sp; + int i; + + cli(); + + sp = kernel.freemem; + kernel.freemem -= stack; + + /* + *sp-- = 'A'; + *sp-- = 'A'; + */ + + /* initialize stack */ + *sp-- = LO8(fun); /* store PC(lo) */ + *sp-- = HI8(fun); /* store PC(hi) */ + + for (i = 0; i < 25; i++) + *sp-- = 0; /* store r1-r0, SREG, r2-r23 */ + + /* Save args in r24-25 (input arguments stored in these registers) */ + *sp-- = LO8(args); + *sp-- = HI8(args); + + for (i = 0; i < 6; i++) + *sp-- = 0; /* store r26-r31 */ + + t = ++kernel.last; + + t->release = release; + t->deadline = deadline; + t->state = TIMEQ; + + t->spl = LO8(sp); /* store stack pointer */ + t->sph = HI8(sp); + + SCHEDULE(); +} + +void +semaphore(uint8_t sema, uint8_t val) +{ + cli(); + + kernel.semaphore[sema] = val; + + sei(); +} + +void +wait(uint8_t sema) +{ + cli(); + + if (kernel.semaphore[sema] == 0) { + kernel.running->state = WAITQOFFSET + sema; + SCHEDULE(); + } else + --kernel.semaphore[sema]; + + sei(); +} + +void +signal(uint8_t sema) +{ + struct task *t; + struct task *rtr; + + cli(); + + rtr = kernel.idle; + + for (t = kernel.first; t <= kernel.last; t++) { + if (t->state == WAITQOFFSET + sema && \ + DISTANCE(t->deadline, rtr->deadline) > 0) + rtr = t; + } + + if (rtr != kernel.idle) { + rtr->state = READYQ; + SCHEDULE(); + } else + ++kernel.semaphore[sema]; + + sei(); +} + +void +update(uint32_t release, uint32_t deadline) +{ + cli(); + + kernel.running->state = TIMEQ; + kernel.running->release = release; + kernel.running->deadline = deadline > release ? deadline : release; + + SCHEDULE(); +} + +uint32_t +deadline(void) +{ + return kernel.running->deadline; +} + +uint32_t +release(void) +{ + return kernel.running->release; +} + +uint32_t +now(void) +{ + return NOW(kernel.cycles, TCNT1); +} + +void +suspend(void) +{ + cli(); + + kernel.running->state = TERMINATED; + + SCHEDULE(); +} + +uint8_t +running(void) +{ + return kernel.running - kernel.idle; +} + +uint8_t +previous(void) +{ + return kernel.prev - kernel.idle; +} diff --git a/kernel/kernel.h b/kernel/kernel.h new file mode 100644 index 0000000..feab5b0 --- /dev/null +++ b/kernel/kernel.h @@ -0,0 +1,80 @@ +/* $Id$ */ +/* + * Copyright (c) 2010 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __KERNEL_H +#define __KERNEL_H + +#ifndef TASKS +#warning "TASKS not set, fallback to default" +#define TASKS 8 +#endif + +#ifndef SEMAPHORES +#warning "SEMAPHORES not set, fallback to default" +#define SEMAPHORES 8 +#endif + +#ifndef STACK +#warning "STACK not set, fallback to default" +#define STACK 64 +#endif + +#ifndef F_CPU +#warning "F_CPU not set, fallback to default" +#define F_CPU 1000000 +#endif + +#ifndef PRESCALE +#warning "PRESCALE not set, fallback to default" +#define PRESCALE 1 +#endif + +#if (PRESCALE == 1) +#define TIMER_FLAGS _BV(CS10) +#elif (PRESCALE == 8) +#define TIMER_FLAGS _BV(CS11) +#elif (PRESCALE == 64) +#define TIMER_FLAGS (_BV(CS11) | _BV(CS10)) +#elif (PRESCALE == 256) +#define TIMER_FLAGS _BV(CS12) +#elif (PRESCALE == 1024) +#define TIMER_FLAGS (_BV(CS12) | _BV(CS10)) +#else +#warning "invalid PRESCALE value" +#endif + +#define SEC(T) ((uint32_t)((T) * (F_CPU / PRESCALE))) +#define MSEC(T) ((uint32_t)(T) * ((F_CPU / 1000) / PRESCALE)) +#define USEC(T) ((uint32_t)(T) * ((F_CPU / 1000000) / PRESCALE)) + +void init(int idlestack); +void task(void (*fun)(void *), uint16_t stacksize, uint32_t release, uint32_t deadline, void *args); +void semaphore(uint8_t semnbr, uint8_t initVal); + +void wait(uint8_t semnbr); +void signal(uint8_t semnbr); + +void update(uint32_t release, uint32_t deadline); +void suspend(void); + +uint32_t now(void); +uint32_t release(void); +uint32_t deadline(void); +uint8_t running(void); +uint8_t previous(void); + +#endif diff --git a/kernel/lcd3.c b/kernel/lcd3.c new file mode 100644 index 0000000..7ad82aa --- /dev/null +++ b/kernel/lcd3.c @@ -0,0 +1,184 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "kernel.h" +#include "tasks.h" + +#define CLEAR_DISPLAY _BV(0) +#define RETURN_HOME _BV(1) + +#define ENTRY_MODE_SET _BV(2) +#define INC_DDRAM _BV(1) +#define SHIFT_ENTIRE_DISP _BV(0) + +#define ON_OFF_CONTROL _BV(3) +#define DISPLAY_ON _BV(2) +#define CURSOR _BV(1) +#define BLINK _BV(0) + +#define CURSOR_OR_DISPLAY_SHIFT _BV(4) +#define SHIFT_CURS_LEFT (0x00 << 2) +#define SHIFT_CURS_RIGHT (0x01 << 2) +#define SHIFT_DISP_LEFT (0x10 << 2) +#define SHIFT_DISP_RIGHT (0x11 << 2) + +#define FUNCTION_SET _BV(5) +#define DATA_LENGTH_8BIT _BV(4) /* on 8 / off 4 bit */ +#define TWO_LINES _BV(3) /* on 2 / off 1 line */ +#define BIG_FONT _BV(2) /* on 5x10 / off 5x7 */ + + +#define SET_CGRAM_ADDRESS _BV(6) +#define SET_DDRAM_ADDRESS _BV(7) +#define BUSY_FLAG _BV(7) + +/* 3-wire interface with 74HC164 */ +#define PORT PORTD +#define PORTDIR DDRD +#define DATA PD5 +#define CLOCK PD6 +#define E PD7 + +struct lcdargs { + uint32_t d; + uint32_t r; +} lcdargs; + +#define snooze(t) do { lcdargs.r += USEC(t); update(lcdargs.r, lcdargs.d); } while (0) +#define write_cmd(x, delay) do { write_byte((x), 0); snooze(delay); } while (0) +#define write_data(x) do { write_byte((x), 1); snooze(43); } while (0) +#define move(line, row) do { write_cmd(SET_DDRAM_ADDRESS | ((line) << 6) | (row), 39); } while (0) +#define clear() do { write_cmd(CLEAR_DISPLAY, 1530); } while (0) +#define home() do { write_cmd(RETURN_HOME, 1530); } while (0) + + +/* recomended cycle 1us: 450ns on, 450ns off. this is beyond our resolution */ +#define wait_short() do { asm volatile ("nop"); } while (0) +#define strobe(port, bit) do { port |= _BV(bit); wait_short(); port &= ~_BV(bit); } while (0) +#define setif(cond, port, bit) do { if (cond) port |= _BV(bit); else port &= ~_BV(bit); } while (0) + +static void +write_byte(uint8_t byte, uint8_t rs) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + setif(byte & (0b10000000 >> i), PORT, DATA); /* MSF */ + strobe(PORT, CLOCK); + } + setif(rs, PORT, DATA); + strobe(PORT, E); +} + +static void +mvputs(uint8_t line, uint8_t row, char *s) +{ + move(line, row); + while (*s) + write_data(*(s++)); +} + +static void +mvputch(uint8_t line, uint8_t row, char ch) +{ + move(line, row); + write_data(ch); +} + +static char * +itoa(int32_t n) +{ + static char buf[12]; + char *s = &buf[11]; + uint32_t sign, u = n; + + *s = '\0'; + + if ((sign = (n < 0))) + u = ~u + 1; + + do + *--s = '0' + (u % 10); + while ((u /= 10) > 0); + + if (sign) + *--s = '-'; + + while (s != buf) + *--s = ' '; + + return s; +} + +static char * +itohex(uint32_t x) +{ + static char hex[] = "0123456789ABCDEF"; + static char buf[9]; + char *s = &buf[8]; + uint8_t i; + + *s = '\0'; + + for (i = 0; i < 32; i += 4) + *--s = hex[(x >> i) & 0x0f]; + + return s; +} + +void +lcd(void *arg) +{ + uint8_t i, t; + + PORTDIR |= (_BV(DATA) | _BV(CLOCK) | _BV(E)); + + /* task init: wait >40ms */ + + lcdargs.d = deadline(); + lcdargs.r = release(); + + /* 8 bit, 2 line, 5x8 font */ + write_cmd(FUNCTION_SET | DATA_LENGTH_8BIT | TWO_LINES, 39); + /* no BUSY_FLAG until now */ + + /* display on, cursor off, cursor blink off */ + write_cmd(ON_OFF_CONTROL | DISPLAY_ON, 39); + + /* clear display */ + clear(); + + /* entry mode */ + write_cmd(ENTRY_MODE_SET | INC_DDRAM, 39); + + mvputs(0, 0, "Task"); + mvputs(1, 0, "Time"); + + for (;;) { + t = previous() - 1; /* 0 is idle */ + for (i = 0; i < TASKS; i++) + mvputch(0, 5 + i, t == i ? '1' + t : '-'); + + mvputs(1, 5, itohex(now())); + + lcdargs.r = lcdargs.d + MSEC(100); + lcdargs.d += MSEC(50); + update(lcdargs.r, lcdargs.d); + } +} diff --git a/kernel/main.c b/kernel/main.c new file mode 100644 index 0000000..3a1921c --- /dev/null +++ b/kernel/main.c @@ -0,0 +1,52 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "kernel.h" +#include "tasks.h" + +uint8_t red, green, blue; + +struct rgbarg rgbargs[] = { + { &red, &green, &blue } +}; + +struct pwmarg pwmargs[] = { + { &red, PB2, 0, 0 }, + { &green, PB3, 0, 0 }, + { &blue, PB4, 0, 0 }, +}; + +int +main() +{ + init(STACK); + + init_uart(); + + task(heartbeat, STACK, SEC(0), MSEC(10), 0); + task(rgb, STACK, SEC(0), MSEC(10), &rgbargs[0]); + task(pwm, STACK, SEC(0), MSEC(10), &pwmargs[0]); + task(pwm, STACK, SEC(0), MSEC(10), &pwmargs[1]); + task(pwm, STACK, SEC(0), MSEC(10), &pwmargs[2]); + task(lcd, STACK, MSEC(40), SEC(1), 0); + + for (;;); + + return 0; +} diff --git a/kernel/rgb.c b/kernel/rgb.c new file mode 100644 index 0000000..c1aefde --- /dev/null +++ b/kernel/rgb.c @@ -0,0 +1,79 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "kernel.h" +#include "tasks.h" + +void hsv(uint8_t *, uint8_t *, uint8_t *, uint16_t, uint8_t, uint8_t); + +/* +struct pwmarg pwmargs[] = { + { &red, PB2, 0, 0 }, + { &green, PB3, 0, 0 }, + { &blue, PB4, 0, 0 }, +}; + */ + +void +rgb(void *arg) +{ + struct rgbarg *a = (struct rgbarg *)arg; + uint32_t d = deadline(); + uint32_t r = release(); + uint16_t i = 0; + uint8_t v; + + for (;;) { + i = (i + 1) % 360; + v = i % 120; + v = (v < 60) ? 255 - 2 * v : 15 + 2 * v; + + hsv(a->r, a->g, a->b, i, 255, v); + + r = d + MSEC(28); + d = r + MSEC(2); + update(r, d); + } +} + +void +pwm(void *arg) +{ +#define SCALE 4 + struct pwmarg *a = (struct pwmarg *)arg; + a->d = deadline(); + a->r = release(); + + DDRB |= _BV(a->pin); + PORTB &= ~_BV(a->pin); + + for (;;) { + if (*a->value > 0) { + PORTB |= _BV(a->pin); + a->r = a->d += USEC(*a->value << SCALE); + update(a->r, a->d); + } + + if (*a->value < 255) { + PORTB &= ~_BV(a->pin); + a->r = a->d += USEC((255 - *a->value) << SCALE); + update(a->r, a->d); + } + } +} diff --git a/kernel/stack.h b/kernel/stack.h new file mode 100644 index 0000000..0f44954 --- /dev/null +++ b/kernel/stack.h @@ -0,0 +1,99 @@ +/* $Id$ */ +/* + * Copyright (c) 2010 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __STACK_H +#define __STACK_H + +/* average latency in cycles */ +#define LATENCY 72 + +/* 68 cycles */ +#define PUSH_ALL() asm volatile ( \ + "push r1 \n" \ + "push r0 \n" \ + "in r0, __SREG__ \n" \ + "push r0 \n" \ + "eor r1, r1 \n" \ + "push r2 \n" \ + "push r3 \n" \ + "push r4 \n" \ + "push r5 \n" \ + "push r6 \n" \ + "push r7 \n" \ + "push r8 \n" \ + "push r9 \n" \ + "push r10 \n" \ + "push r11 \n" \ + "push r12 \n" \ + "push r13 \n" \ + "push r14 \n" \ + "push r15 \n" \ + "push r16 \n" \ + "push r17 \n" \ + "push r18 \n" \ + "push r19 \n" \ + "push r20 \n" \ + "push r21 \n" \ + "push r22 \n" \ + "push r23 \n" \ + "push r24 \n" \ + "push r25 \n" \ + "push r26 \n" \ + "push r27 \n" \ + "push r28 \n" \ + "push r29 \n" \ + "push r30 \n" \ + "push r31 \n" ) + +/* 69 cycles */ +#define POP_ALL() asm volatile ( \ + "pop r31 \n" \ + "pop r30 \n" \ + "pop r29 \n" \ + "pop r28 \n" \ + "pop r27 \n" \ + "pop r26 \n" \ + "pop r25 \n" \ + "pop r24 \n" \ + "pop r23 \n" \ + "pop r22 \n" \ + "pop r21 \n" \ + "pop r20 \n" \ + "pop r19 \n" \ + "pop r18 \n" \ + "pop r17 \n" \ + "pop r16 \n" \ + "pop r15 \n" \ + "pop r14 \n" \ + "pop r13 \n" \ + "pop r12 \n" \ + "pop r11 \n" \ + "pop r10 \n" \ + "pop r9 \n" \ + "pop r8 \n" \ + "pop r7 \n" \ + "pop r6 \n" \ + "pop r5 \n" \ + "pop r4 \n" \ + "pop r3 \n" \ + "pop r2 \n" \ + "pop r0 \n" \ + "out __SREG__, r0 \n" \ + "pop r0 \n" \ + "pop r1 \n" ) + +#endif diff --git a/kernel/tasks.h b/kernel/tasks.h new file mode 100644 index 0000000..aa7f992 --- /dev/null +++ b/kernel/tasks.h @@ -0,0 +1,39 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __TASKS_H +#define __TASKS_H + +struct rgbarg { + uint8_t *r, *g, *b; +}; + +struct pwmarg { + uint8_t *value; + uint8_t pin; + uint32_t d; + uint32_t r; +}; + +void init_uart(void); + +void heartbeat(void *); +void rgb(void *); +void pwm(void *); +void lcd(void *); + +#endif diff --git a/kernel/uart.c b/kernel/uart.c new file mode 100644 index 0000000..63f5c11 --- /dev/null +++ b/kernel/uart.c @@ -0,0 +1,80 @@ +/* $Id$ */ +/* + * Copyright (c) 2011 Dimitri Sokolyuk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef BAUD +#warning "BAUD not set, fallback to default" +#define BAUD 9600 +#endif + +#include +#include +#include +#include +#include +#include "kernel.h" +#include "tasks.h" + +void +uart_putchar(char c) +{ + loop_until_bit_is_set(UCSRA, UDRE); + UDR = c; +} + +ISR(SIG_UART_RECV) +{ + uint8_t c = UDR; + uint8_t *p = 0; + + switch (c) { + case 'R': /* reboot */ + wdt_enable(WDTO_15MS); + break; + case 'D': /* dump */ + while (p <= (uint8_t *)RAMEND) + uart_putchar(*p++); + break; + case 'T': + UCSRB |= _BV(UDRIE); + break; + case 't': + UCSRB &= ~_BV(UDRIE); + break; + case '\r': + case '\n': + break; + default: + uart_putchar('?'); + break; + } +} + +ISR(SIG_UART_DATA) +{ + uint8_t r = running(); + + UDR = r ? '0' + r : '.'; +} + +void +init_uart(void) +{ + UCSRB = _BV(RXCIE) | _BV(RXEN) | _BV(TXEN); + UBRRH = UBRRH_VALUE; + UBRRL = UBRRL_VALUE; + UCSRA &= ~_BV(U2X); +} -- cgit v1.2.3