diff options
-rw-r--r-- | avr/Tupfile | 10 | ||||
-rw-r--r-- | avr/cmd_boot.c | 35 | ||||
-rw-r--r-- | avr/cmd_mem.c | 11 | ||||
-rw-r--r-- | avr/cmd_pin.c | 329 | ||||
-rw-r--r-- | avr/command.c | 17 | ||||
-rw-r--r-- | avr/command_tbl.c | 42 | ||||
-rw-r--r-- | avr/getopt-min.c | 76 | ||||
-rw-r--r-- | avr/main.c | 17 | ||||
-rw-r--r-- | avr/pin.c | 372 | ||||
-rw-r--r-- | avr/print-utils.c | 10 | ||||
-rw-r--r-- | avr/serial.c | 2 | ||||
-rw-r--r-- | avr/timer.c | 4 | ||||
-rw-r--r-- | avr/z80-if.c | 103 | ||||
-rw-r--r-- | include/config.h | 7 | ||||
-rw-r--r-- | include/getopt-min.h | 12 | ||||
-rw-r--r-- | include/pin.h | 17 | ||||
-rw-r--r-- | include/print-utils.h | 2 | ||||
-rw-r--r-- | include/z80-if.h | 2 |
18 files changed, 898 insertions, 170 deletions
diff --git a/avr/Tupfile b/avr/Tupfile index 9227f2b..91562b4 100644 --- a/avr/Tupfile +++ b/avr/Tupfile @@ -1,12 +1,12 @@ include_rules -PROG = stamp-test +PROG = stamp-monitor SRC = main.c SRC += cli.c cli_readline.c command.c command_tbl.c -SRC += cmd_help.c cmd_echo.c cmd_date.c cmd_mem.c cmd_boot.c -SRC += env.c xmalloc.c date.c -SRC += timer.c con-utils.c serial.c i2c.c pcf8583.c -SRC += background.c z180-serv.c z80-if.c +SRC += cmd_help.c cmd_echo.c cmd_date.c cmd_mem.c cmd_boot.c cmd_pin.c +SRC += env.c xmalloc.c date.c con-utils.c print-utils.c getopt-min.c +SRC += timer.c serial.c i2c.c pcf8583.c +SRC += background.c z180-serv.c z80-if.c pin.c SRC_Z = ../z180/hdrom.c diff --git a/avr/cmd_boot.c b/avr/cmd_boot.c index 58c4f56..17ed746 100644 --- a/avr/cmd_boot.c +++ b/avr/cmd_boot.c @@ -4,11 +4,11 @@ */ #include "common.h" #include <stdlib.h> -#include <util/delay.h> #include <avr/pgmspace.h> #include "command.h" #include "z80-if.h" +//#include "debug.h" /* ugly hack to get Z180 loadfile into flash memory */ #define const const FLASH @@ -32,7 +32,7 @@ static void z80_load_mem(void) z80_bus_cmd(Request); z80_write_block((const FLASH unsigned char *) &hdrom[sec_base], /* src */ - hdrom_address[sec], /* dest */ + hdrom_address[sec], /* dest */ hdrom_length_of_sections[sec]); /* len */ z80_bus_cmd(Release); sec_base+=hdrom_length_of_sections[sec]; @@ -143,34 +143,3 @@ command_ret_t do_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv return CMD_RET_SUCCESS; } - -command_ret_t do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) -{ - uint32_t freq; - - (void) cmdtp; (void) flag; - - if (argc == 2) { - freq = strtoul(argv[1], NULL, 10); - if (freq == 0) { - printf_P(PSTR("CPU clock cannot be 0\n")); - return CMD_RET_USAGE; - } - - if (freq > F_CPU / 2) { - printf_P(PSTR("Max CPU clock freq. is: %luHz\n"), F_CPU/2); - return CMD_RET_USAGE; - } - - if (z80_clock_set(freq) < 0) { - printf_P(PSTR("Setting CPU clock freq. to %luHz failed.\n"), - freq); - } - } - - printf_P(PSTR("CPU clock: %luHz\n"), z80_clock_get()); - - - return CMD_RET_SUCCESS; -} - diff --git a/avr/cmd_mem.c b/avr/cmd_mem.c index f1f34c0..66dc88f 100644 --- a/avr/cmd_mem.c +++ b/avr/cmd_mem.c @@ -14,13 +14,14 @@ #include "common.h" #include <stdlib.h> #include <ctype.h> +#include <avr/pgmspace.h> -#include "config.h" -#include "debug.h" #include "command.h" #include "cli_readline.h" +#include "print-utils.h" #include "con-utils.h" #include "z80-if.h" +//#include "debug.h" #ifndef CONFIG_SYS_MEMTEST_SCRATCH @@ -38,12 +39,6 @@ static uint32_t base_address = 0; /*--------------------------------------------------------------------------*/ -static void print_blanks(uint_fast8_t count) -{ - while(count--) - putchar(' '); -} - int z180_dump_mem(uint32_t startaddr, uint32_t len, const char *title) { uint8_t buf[16]; diff --git a/avr/cmd_pin.c b/avr/cmd_pin.c new file mode 100644 index 0000000..b46b853 --- /dev/null +++ b/avr/cmd_pin.c @@ -0,0 +1,329 @@ +#include "common.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <avr/pgmspace.h> + +#include "command.h" +#include "print-utils.h" +#include "getopt-min.h" +#include "env.h" +#include "pin.h" +//#include "debug.h" + + + +static const int namestr = PIN_MAX; +static char *pin_names[PIN_MAX+1]; +static uint_least8_t pin_names_width; + +static void pinnames_get(void) +{ + static const FLASH char delim1[] = {":= "}; + static const FLASH char delim2[] = {", "}; + char *lp; + char *ptr; + uint_fast8_t i; + + if (pin_names[namestr] != NULL) + free(pin_names[namestr]); + memset(pin_names, 0, sizeof(pin_names)); + pin_names_width = 0; + + if ((lp = getenv(PSTR(ENV_PINALIAS))) != NULL) { + pin_names[namestr] = strdup(lp); + ptr = strtok_P(pin_names[namestr], delim1); + while (ptr != NULL) { + if (((i = strtoul(ptr, &lp, 10)) < PIN_MAX) && + lp != ptr && + (ptr = strtok_P(NULL, delim2)) != NULL ) { + pin_names[i] = ptr; + ptr = strtok_P(NULL, delim1); + } + } + + for (i = 0; i < PIN_MAX; i++) + if (strlen(pin_names[i]) > pin_names_width) + pin_names_width = strlen(pin_names[i]); + } +} + + +static size_t xstrlen(char *s) +{ + if (s == NULL) + return 0; + else + return strlen(s); +} + +static const FLASH char * const FLASH pinconf_str[] = { + FSTR("?"), + FSTR("Input"), + FSTR("Pullup"), + FSTR("Output"), + FSTR("Clock"), + }; + +static const FLASH char * const FLASH pinlevel_str[] = { + FSTR("Low"), + FSTR("High"), + FSTR(""), + }; + +static int print_pin(int pin, int multi) +{ + int pinconf; + const FLASH char *levelp; + long div; + + pinconf = pin_config_get(pin); + if (pinconf == OUTPUT_TIMER) { + div = pin_clockdiv_get(pin); + levelp = pinlevel_str[2]; + } else + levelp = pinlevel_str[pin_read(pin)]; + + if (multi) { + printf_P(PSTR("%3d "), pin); + if (pin_names_width) { + printf_P(PSTR("%s "), pin_names[pin]); + print_blanks(pin_names_width - xstrlen(pin_names[pin])); + } + my_puts_P(pinconf_str[pinconf]); + print_blanks(7 - strlen_P(pinconf_str[pinconf])); + my_puts_P(levelp); + print_blanks(5 - strlen_P(levelp)); + if (pinconf == OUTPUT_TIMER) + printf_P(PSTR("%8ld %8ld"), + div, F_CPU/div); + } else { + printf_P(PSTR("%d: \"%s\", "), pin, pin_names[pin] ? pin_names[pin] : 0); + my_puts_P(pinconf_str[pinconf]); + printf_P(PSTR(", ")); + my_puts_P(levelp); + + if (pinconf == OUTPUT_TIMER) + printf_P(PSTR("divide by %ld (%ldHz)"), + div, F_CPU/div); + } + printf_P(PSTR("\n")); + + return 0; +} + +static int_fast8_t pinarg_insert(int pin, uint_fast8_t count, uint_fast8_t pinarg[]) +{ + uint_fast8_t pos; + + if (pin < 0 || pin >= PIN_MAX) + return -1; + + for (pos = 0; pos < count; pos++) { + if (pin == pinarg[pos]) + return 0; + if (pin < pinarg[pos]) + break; + } + for (uint_fast8_t i = count-1; i == pos ; i--) + pinarg[i+1] = pinarg[i]; + pinarg[pos] = pin; + + return 1; +} + +static uint_fast8_t pinarg_get(char * arg, uint_fast8_t pinarg[]) +{ + char *endp; + uint_fast8_t pin1; + int_fast8_t rc; + uint_fast8_t count = 0; + + while (1) { + pin1 = strtoul(arg, &endp, 10); + if (endp != arg && *endp == '-') { + arg = endp+1; + uint_fast8_t pin2 = (int) strtoul(arg, &endp, 10); + if (pin1 < pin2) + for (; pin1 < pin2; pin1++) + if ((rc = pinarg_insert(pin1, count, pinarg)) >= 0) + count += rc; + else + return 0; + else + return 0; + } + if (endp != arg) { + if ((*endp == ',' || *endp == '\0') && + (rc = pinarg_insert(pin1, count, pinarg)) >= 0) { + count += rc; + if (*endp == '\0') + return count; + } else + return 0; + } else + return 0; + + arg = endp+1; + } +} + + +command_ret_t do_pin(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + char printheader = 1; + uint_fast8_t pinarg[PIN_MAX]; + uint_fast8_t pinargc; + + (void) cmdtp; (void) flag; + + /* reset getopt() */ + optind = 1; + + int opt; + while ((opt = getopt(argc, argv, PSTR("s"))) != -1) { + switch (opt) { + case 's': + printheader = 0; + break; + default: /* '?' */ + return CMD_RET_USAGE; + } + } + + /* remaining arguments */ + argc -= optind; + + pinnames_get(); + + if (argc == 0) { + /* print cofig of all pins */ + for (pinargc = 0; pinargc < PIN_MAX; pinargc++) + pinarg[pinargc] = pinargc; + } else { + /* get first arg */ + pinargc = pinarg_get(argv[optind++], pinarg); + if (pinargc == 0) + return CMD_RET_USAGE; + else + argc--; + } + + if (argc == 0) { + /* no more args, print config */ + if (pinargc == 1) + print_pin(pinarg[0], 0); + else { + if (printheader) { + if (pin_names_width > 0) { + if ( strlen("Name") > pin_names_width) + pin_names_width = strlen("Name"); + char s[pin_names_width+1]; + memset(s, ' ', pin_names_width); + s[pin_names_width] = '\0'; + strncpy_P(s, PSTR("Name"), 4); + printf_P(PSTR("Pin %s Config Level Divider Frequency/Hz\n"),s); + memset(s, '-', pin_names_width); + printf_P(PSTR("----%s-----------------------------------\n"), s); + } else + printf_P(PSTR("Pin Config Level Divider Frequency/Hz\n" + "--------------------------------------\n")); + } + for (uint_fast8_t i = 0; i < pinargc; i++) + print_pin(pinarg[i], 1); + } + return CMD_RET_SUCCESS; + } + + /* arguments must be in pairs: pins conf */ + if (argc % 2 != 1) + return CMD_RET_USAGE; + + while (argc > 0) { + char *endp; + pinmode_t mode = NONE; + int level = 0; + unsigned long value = 0; + uint8_t hz_flag = 0; + + switch (toupper(argv[optind][0])) { + case 'H': + level = 1; + case 'L': + mode = OUTPUT; + break; + case 'P': + mode = INPUT_PULLUP; + break; + case 'I': + case 'T': + mode = INPUT; + break; + + default: + value = strtoul(argv[optind], &endp, 10); + switch (*endp) { + case 'M': + value *= 1000; + case 'K': + value *= 1000; + endp++; + } + + if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) { + hz_flag = 1; + endp += 2; + } + + if (*endp != '\0') { + printf_P(PSTR("invalid parameter: '%s'\n"), argv[optind]); + return CMD_RET_USAGE; + } + + if (value == 0) { + printf_P(PSTR("invalid value: %lu \n")); + return CMD_RET_USAGE; + } + + if (hz_flag) { + if (value > F_CPU / 2) { + printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2); + return CMD_RET_USAGE; + } + value = F_CPU/value; + } + mode = OUTPUT_TIMER; + + } + + if (mode == NONE) + return CMD_RET_USAGE; + + for (uint_fast8_t i = 0; i < pinargc; i++) { + switch (mode) { + case OUTPUT: + pin_write(pinarg[i], level); + /* fall thru */ + case INPUT: + case INPUT_PULLUP: + pin_config(pinarg[i], mode); + break; + case OUTPUT_TIMER: + if (pin_clockdiv_set(pinarg[i], value) < 0) { + printf_P(PSTR("Setting pin %d to %lu failed.\n"), + pinarg[i], value); + } + break; + default: + break; + } + } + + optind++; + pinargc = pinarg_get(argv[optind++], pinarg); + argc -= 2; + } + + return CMD_RET_SUCCESS; +} + diff --git a/avr/command.c b/avr/command.c index f1e184a..2b53adf 100644 --- a/avr/command.c +++ b/avr/command.c @@ -1,29 +1,24 @@ - /* * Command Processor Table */ #include "common.h" - +#include <stdlib.h> #include <string.h> #include <ctype.h> -#include <stdlib.h> #include <stdio.h> +#include <avr/pgmspace.h> #include "config.h" -#include "debug.h" +#include "print-utils.h" #include "con-utils.h" +#ifdef CONFIG_AUTO_COMPLETE #include "env.h" -#include "timer.h" +#endif +#include "debug.h" #include "command.h" -static void print_blanks(int_fast8_t count) -{ - while(count--) - my_puts_P(PSTR(" ")); -} - static void print_usage_line(const FLASH char *name, int width, const FLASH char *usage) { diff --git a/avr/command_tbl.c b/avr/command_tbl.c index c721d53..e8af931 100644 --- a/avr/command_tbl.c +++ b/avr/command_tbl.c @@ -18,7 +18,9 @@ extern command_ret_t do_dump_mem(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_eep_cp(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_busreq_pulse(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_date(cmd_tbl_t *, int, int, char * const []); -extern command_ret_t do_clock(cmd_tbl_t *, int, int, char * const []); +//extern command_ret_t do_clock(cmd_tbl_t *, int, int, char * const []); +//extern command_ret_t do_clock2(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_pin(cmd_tbl_t *, int, int, char * const []); cmd_tbl_t cmd_tbl[] = { @@ -120,10 +122,46 @@ CMD_TBL_ITEM( "Perform RESET of the CPU", "" ), + +#if 0 CMD_TBL_ITEM( clock, 2, 0, do_clock, "Set or get CPU frequency", - "" + "\n" + " - print frequency or state of clock pin\n" + "clock value[K|M]\n" + " - set frequency of clock pin to value\n" + "clock [high|low]\n" + " - set clock pin level high or low" +), +CMD_TBL_ITEM( + clk2, 3, 0, do_clock2, + "Set or get clk2 frequency", + "\n" + " - print frequency or state of clk2 pin\n" + "clk2 [-d] value[K|M]\n" + " - set frequency of clk2 pin to value\n" + "clk2 [high|low]\n" + " - set clk2 pin level high or low" +), +#endif + +CMD_TBL_ITEM( + pin, CONFIG_SYS_MAXARGS, 0, do_pin, + "Set or query pin state", + "[-s] [<pins>]\n" + " - print cofiguration and state or frequency of pins\n" + " print all pins, if argument is omitted\n" + "pin <pins> h[igh]|l[ow]\n" + " - config pins as output and set to level high or low\n" + "pin <pins> ts|i[n]|p[ullup]\n" + " - config pins as input/tristate or input with pullup\n" + "pin <pins> value[K|M][Hz]\n" + " - output a clock on pins\n" + " value is system clock divider or frequency, if 'Hz' is appended\n" + " divider is rounded down to next possible value (depends on pin)\n" + "\n" + "<pins> is a comma separated list of numbers or ranges, i.e. \"0,9,3-6\"\n" ), CMD_TBL_ITEM( diff --git a/avr/getopt-min.c b/avr/getopt-min.c new file mode 100644 index 0000000..571c14f --- /dev/null +++ b/avr/getopt-min.c @@ -0,0 +1,76 @@ +#include "common.h" +#include <avr/pgmspace.h> + + +/* + * Minimum getopt, original version was: + */ + +/* + getopt -- public domain version of standard System V routine + + Strictly enforces the System V Command Syntax Standard; + provided by D A Gwyn of BRL for generic ANSI C implementations +*/ +/* $Id: getopt.c,v 1.2 1992/12/07 11:12:52 nickc Exp $ */ + +#include <string.h> + +int optind = 1; /* next argv[] index */ +char *optarg; /* option parameter if any */ + + +int +getopt( /* returns letter, '?', EOF */ + int argc, /* argument count from main */ + char *const argv[], /* argument vector from main */ + const FLASH char *optstring ) /* allowed args, e.g. "ab:c" */ +{ + static int sp = 1; /* position within argument */ + int osp; /* saved `sp' for param test */ + int c; /* option letter */ + const FLASH char *cp; /* -> option in `optstring' */ + + optarg = NULL; + + if ( sp == 1 ) /* fresh argument */ + { + if ( optind >= argc /* no more arguments */ + || argv[optind][0] != '-' /* no more options */ + || argv[optind][1] == '\0' /* not option; stdin */ + ) + return -1; + } + + c = argv[optind][sp]; /* option letter */ + osp = sp++; /* get ready for next letter */ + + if ( argv[optind][sp] == '\0' ) /* end of argument */ + { + ++optind; /* get ready for next try */ + sp = 1; /* beginning of next argument */ + } + + if ( c == ':' /* optstring syntax conflict */ + || (cp = strchr_P( optstring, c )) == NULL /* not found */ + ) + return '?'; + + if ( cp[1] == ':' ) /* option takes parameter */ + { + if ( osp != 1 ) + return '?'; + + if ( sp != 1 ) /* reset by end of argument */ + return '?'; + + if ( optind >= argc ) + return '?'; + + optarg = argv[optind]; /* make parameter available */ + ++optind; /* skip over parameter */ + } + + return c; +} + @@ -95,11 +95,10 @@ void setup_avr(void) CLKPR = 0; /* Timer */ - PRR0 &= ~_BV(PRTIM2); - OCR2A = F_CPU / 256 / 1000 - 1; /* Timer2: 1000Hz interval (OC2A) */ - TCCR2A = (0b10 << WGM20); /* CTC Mode */ - TCCR2B = (0b110 << CS20); /* Prescaler 256 */ - TIMSK2 = _BV(OCIE2A); /* Enable TC2.oca interrupt */ + PRR1 &= ~_BV(PRTIM3); + OCR3A = F_CPU / 1000 - 1; /* Timer3: 1000Hz interval (OC3A) */ + TCCR3B = (0b01<<WGM32)|(0b001<<CS30); /* CTC Mode, Prescaler 1 */ + TIMSK3 = _BV(OCIE3A); /* Enable TC2.oca interrupt */ } static @@ -169,13 +168,13 @@ const char *bootdelay_process(void) char *s; int bootdelay; - bootdelay = (int) getenv_ulong(PSTR("bootdelay"), 10, CONFIG_BOOTDELAY); + bootdelay = (int) getenv_ulong(PSTR(ENV_BOOTDELAY), 10, CONFIG_BOOTDELAY); debug("### main_loop entered: bootdelay=%d\n\n", bootdelay); _delay_ms(20); - s = getenv(PSTR("bootcmd")); + s = getenv(PSTR(ENV_BOOTCMD)); stored_bootdelay = bootdelay; return s; } @@ -213,7 +212,7 @@ int main(void) if (reset_reason_is_power_on()) _delay_ms(CONFIG_PWRON_DELAY); - serial_setup(getenv_ulong(PSTR("baudrate"), 10, CONFIG_BAUDRATE)); + serial_setup(getenv_ulong(PSTR(ENV_BAUDRATE), 10, CONFIG_BAUDRATE)); sei(); #if DEBUG @@ -229,7 +228,7 @@ int main(void) i2c_init(CONFIG_SYS_I2C_CLOCK); #endif - printf_P(PSTR("\n(ATMEGA1281+HD64180)_stamp Tester\n")); + printf_P(PSTR("\nATMEGA1281+Z8S180 Stamp Monitor\n\n")); main_loop(); diff --git a/avr/pin.c b/avr/pin.c new file mode 100644 index 0000000..14896b3 --- /dev/null +++ b/avr/pin.c @@ -0,0 +1,372 @@ +#include "common.h" +#include <util/atomic.h> +#include <limits.h> +#include "debug.h" +#include "pin.h" + + +/* + +Pin Name Port Timer Mode max div max div min f [Hz] +---------------------------------------------------------------------------------- +0 PG5 OC0B PWM (2**8)*1024 262144 70.31 +1 PG4 +2 CLK2 PB4 OC2A Toggle (2**8)*1024*2 524288 35.16 +3 ZCLK PB5 OC1A PWM (2**16)*1024 67108864 0.2746 +4 PB6 OC1B PWM (2**16)*1024 67108864 0.2746 +5 PB7 OC0A Toggle (2**8)*1024*2 524288 35.16 +6 PG3 +7 PG2 +8 PG1 +9 PG0 +10 CLKO PE7 + + +pre Timer0 Timer1 Timer2 +-------------------------------------------------- +0 0 0 0 +1 1 1 1 +2 8 x8 8 x8 8 x8 +3 64 x8 64 x8 32 x4 +4 256 x4 256 x4 64 x2 +5 1024 x4 1024 x4 128 x2 +6 256 x2 +7 1024 x4 +-------------------------------------------------- + +*/ + + +#define PWMTOGGLE 0b01 +#define PWMPOS 0b10 +#define PWMNEG 0b11 + + +const FLASH uint8_t prescale_factors_01[] = + { 8, 8, 4, 4, 0 }; + +const FLASH uint8_t prescale_factors_2[] = + { 8, 4, 2, 2, 2, 4, 0 }; + +typedef volatile struct { + uint8_t pin; + uint8_t ddr; + uint8_t pout; +} port_t ; + +struct pindef_s { + port_t * const adr; + const uint8_t mask; +#define NO_TIMER 0 +#define TIMER0 (1 << 0) +#define TIMER1 (2 << 0) +#define TIMER2 (3 << 0) +#define TIMER (3 << 0) +#define T_16BIT (1 << 3) +#define CHANA (1 << 4) +#define CHANB (0 << 4) + const uint8_t timer; +}; + + +const FLASH struct pindef_s pinlist[PIN_MAX] = { + { (port_t *) &PING, _BV(5), TIMER0 | CHANB }, + { (port_t *) &PING, _BV(4), NO_TIMER }, + { (port_t *) &PINB, _BV(4), TIMER2 | CHANA }, + { (port_t *) &PINB, _BV(5), TIMER1 | CHANA | T_16BIT }, + { (port_t *) &PINB, _BV(6), TIMER1 | CHANB | T_16BIT }, + { (port_t *) &PINB, _BV(7), TIMER0 | CHANA }, + { (port_t *) &PING, _BV(3), NO_TIMER }, + { (port_t *) &PING, _BV(2), NO_TIMER }, + { (port_t *) &PING, _BV(1), NO_TIMER }, + { (port_t *) &PING, _BV(0), NO_TIMER }, + { (port_t *) &PINE, _BV(7), NO_TIMER }, +}; + +void pin_timer_off(uint8_t timertype) +{ + uint8_t chan_mask; + + if (timertype & CHANA) + chan_mask = 0xc0; + else + chan_mask = 0x30; + + switch (timertype & TIMER) { + case TIMER0: + if (TCCR0A & chan_mask) { + TCCR0B = 0; + TCCR0A = 0; + PRR0 |= _BV(PRTIM0); + } + break; + case TIMER1: + if (TCCR1A & chan_mask) { + TCCR1B = 0; + TCCR1A = 0; + PRR0 |= _BV(PRTIM1); + } + break; + case TIMER2: + if (TCCR2A & chan_mask) { + TCCR2B = 0; + TCCR2A = 0; + PRR0 |= _BV(PRTIM2); + } + break; + } +} + +int pin_config(int pin, pinmode_t mode) +{ + if ((unsigned) pin >= ARRAY_SIZE(pinlist)) { + /* Invalid pin number */ + return -1; + } else { + + port_t *p = pinlist[pin].adr; + uint8_t bit = pinlist[pin].mask; + + switch (mode) { + case INPUT: + pin_timer_off(pinlist[pin].timer); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + p->ddr &= ~bit; + p->pout &= ~bit; + } + break; + case INPUT_PULLUP: + pin_timer_off(pinlist[pin].timer); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + p->ddr &= ~bit; + p->pout |= bit; + } + break; + case OUTPUT: + pin_timer_off(pinlist[pin].timer); + case OUTPUT_TIMER: + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + p->ddr |= bit; + } + break; + default: + /* Invalid pin mode */ + return -1; + } + } + return 0; +} + +void pin_write(int pin, uint8_t val) +{ + port_t *p = pinlist[pin].adr; + uint8_t bit = pinlist[pin].mask; + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if (val) + p->pout |= bit; + else + p->pout &= ~bit; + } +} + +int pin_read(int pin) +{ + port_t *p = pinlist[pin].adr; + uint8_t bit = pinlist[pin].mask; + + return (p->pin & bit) != 0; +} + +pinmode_t pin_config_get(int pin) +{ + uint8_t timertype = pinlist[pin].timer; + + if (timertype & TIMER) { + + uint8_t chan_mask; + if (timertype & CHANA) + chan_mask = 0xc0; + else + chan_mask = 0x30; + + switch (timertype & TIMER) { + case TIMER0: + if (TCCR0A & chan_mask) + return OUTPUT_TIMER; + break; + case TIMER1: + if (TCCR1A & chan_mask) + return OUTPUT_TIMER; + break; + case TIMER2: + if (TCCR2A & chan_mask) + return OUTPUT_TIMER; + break; + } + } + + port_t *p = pinlist[pin].adr; + uint8_t bit = pinlist[pin].mask; + + if (p->ddr & bit) + return OUTPUT; + + if (p->pout & bit) + return INPUT_PULLUP; + + return INPUT; +} + +/* + * return -1: pin has no timer output + * 0: pin is not configured for timer output + * > 0: divider + */ + +long pin_clockdiv_get(int pin) +{ + long divider; + uint8_t prescale; + const FLASH uint8_t *pstab; + + uint8_t timertype = pinlist[pin].timer; + if ((timertype & TIMER) == 0) + return -1; + + if (pin_config_get(pin) != OUTPUT_TIMER) + return 0; + + switch (timertype & TIMER) { + case TIMER0: + prescale = TCCR0B; + divider = OCR0A; + break; + + case TIMER1: + prescale = TCCR1B; + divider = ICR1; + break; + + case TIMER2: + prescale = TCCR2B; + divider = OCR2A; + break; + } + + prescale = (prescale & 0x07) - 1; + divider += 1; + + pstab = (timertype & TIMER) == TIMER2 ? + prescale_factors_2 : prescale_factors_01; + + while (prescale--) + divider *= pstab[prescale]; + + if ((timertype & (CHANA|T_16BIT)) == CHANA) + divider *= 2; + + return divider; +} + +int pin_clockdiv_set(int pin, unsigned long divider) +{ + unsigned long ltop; + uint16_t top; + uint8_t prescale; + const FLASH uint8_t *pstab; + + uint8_t timertype = pinlist[pin].timer; + if ((timertype & TIMER) == 0) + return 0; + + if (divider < 2) + return -1; + + ltop = divider; + if ((timertype & (CHANA|T_16BIT)) == CHANA) + ltop /= 2; + + if (ltop > 1024 * ((timertype & T_16BIT) ? (1L<<16) : (1L<<8))) + return -1; + + prescale = 1; + pstab = (timertype & TIMER) == TIMER2 ? + prescale_factors_2 : prescale_factors_01; + +// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d\n", +// pin, ltop, prescale); + + while (ltop > ((timertype & T_16BIT) ? (1L<<16) : (1L<<8))) { +// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d, *pstab %d\n", +// pin, ltop, prescale, *pstab); + + if (*pstab == 0) + return -1; + ltop /= *pstab++; + prescale++; + } + + if (ltop == 0) + return -1; + + top = ltop - 1; + + PING |= _BV(0); /* Debug */ + + switch (timertype & TIMER) { + case TIMER0: + PRR0 &= ~_BV(PRTIM0); + TCCR0B = (1 << WGM02); + TCNT0 = 0; + OCR0A = top; + if (timertype & CHANA) { + TCCR0A = (PWMTOGGLE << COM0A0) | (0b11 << WGM00); + } else { + OCR0B = top/2; + TCCR0A = (PWMPOS << COM0B0) | (0b11 << WGM10); + } + TCCR0B = (1 << WGM02) | (prescale << CS10); + break; + + case TIMER1: + PRR0 &= ~_BV(PRTIM1); + TCCR1B = (0b11 << WGM12); + TCNT1 = 0; + ICR1 = top; + if (timertype & CHANA) { + OCR1A = top/2; + TCCR1A = (PWMPOS << COM1A0) | (0b10 << WGM10); + } else { + OCR1B = top/2; + TCCR1A = (PWMPOS << COM1B0) | (0b10 << WGM10); + } +// debug("pin: %d, top: %u," +// " ICR1: %u, OCR1A: %u, OCR1B: %u\n", +// pin, top, ICR1, OCR1A, OCR1B); + + TCCR1B = (0b11 << WGM12) | (prescale << CS10); + break; + + case TIMER2: + PRR0 &= ~_BV(PRTIM2); + TCCR2B = (1 << WGM22); + TCNT2 = 0; + OCR2A = top; + if (timertype & CHANA) { + TCCR2A = (PWMTOGGLE << COM2A0) | (0b11 << WGM20); + } else { + OCR2B = top/2; + TCCR2A = (PWMPOS << COM2B0) | (0b11 << WGM10); + } + TCCR2B = (1 << WGM22) | (prescale << CS10); + break; + } + + PING |= _BV(0); /* Debug */ + + pin_config(pin, OUTPUT_TIMER); + + return 0; +} + diff --git a/avr/print-utils.c b/avr/print-utils.c new file mode 100644 index 0000000..b814d97 --- /dev/null +++ b/avr/print-utils.c @@ -0,0 +1,10 @@ +#include <stdio.h> +#include "print-utils.h" + +void print_blanks(uint_fast8_t count) +{ + while(count--) + putchar(' '); +} + + diff --git a/avr/serial.c b/avr/serial.c index a5e2846..e897c84 100644 --- a/avr/serial.c +++ b/avr/serial.c @@ -17,7 +17,7 @@ static FILE mystdout = FDEV_SETUP_STREAM(_write, -#define BUFFER_SIZE 64 +#define BUFFER_SIZE 128 #if ((BUFFER_SIZE-1) & BUFFER_SIZE) # error: BUFFER_SIZE not power of 2 diff --git a/avr/timer.c b/avr/timer.c index 56c7bed..e15a55b 100644 --- a/avr/timer.c +++ b/avr/timer.c @@ -19,10 +19,10 @@ volatile uint32_t timestamp; /*---------------------------------------------------------*/ -/* 1000Hz timer interrupt generated by OC2A */ +/* 1000Hz timer interrupt generated by OC3A */ /*---------------------------------------------------------*/ -ISR(TIMER2_COMPA_vect) +ISR(TIMER3_COMPA_vect) { static int_fast8_t tick_10ms; int_fast8_t i; diff --git a/avr/z80-if.c b/avr/z80-if.c index 25a71b0..3a2c184 100644 --- a/avr/z80-if.c +++ b/avr/z80-if.c @@ -64,12 +64,6 @@ /* Number of array elements */ #define NELEMS(x) (sizeof x/sizeof *x) - -#define CONCAT(x,y) x ## y -#define EVALUATOR(x,y) CONCAT(x,y) - -#define GPIO_(X) CONCAT(GPIO, X) - struct bits { uint8_t b0:1; uint8_t b1:1; @@ -81,12 +75,14 @@ struct bits { uint8_t b7:1; } __attribute__((__packed__)); +typedef struct bits pbit_t; + #define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin) -#define P_ZCLK PORTB -#define ZCLK 7 -#define DDR_ZCLK DDRB +//#define P_ZCLK PORTB +//#define ZCLK 5 +//#define DDR_ZCLK DDRB #define P_MREQ PORTD #define MREQ 4 #define DDR_MREQ DDRD @@ -130,7 +126,7 @@ struct bits { //#define ADB_PORT PORTE -#define Z80_O_ZCLK SBIT(P_ZCLK, 7) +//#define Z80_O_ZCLK SBIT(P_ZCLK, 5) #define Z80_O_MREQ SBIT(P_MREQ, 4) #define Z80_O_RD SBIT(P_RD, 3) #define Z80_O_WR SBIT(P_WR, 2) @@ -144,8 +140,6 @@ struct bits { #define MASK(n) ((1<<(n))-1) #define SMASK(w,s) (MASK(w) << (s)) -#define LOWSPEED 50000 - typedef union { uint32_t l; @@ -158,89 +152,6 @@ static zstate_t zstate; /*--------------------------------------------------------------------------*/ -static -uint8_t is_lowspeed() -{ - return (TCCR1B & 7) < 2 && - OCR1A > (F_CPU / 2 / LOWSPEED); -} - -static -void z80_setup_clock(void) -{ - /* ZCLK: Output and low */ - DDR_ZCLK |= _BV(ZCLK); - Z80_O_ZCLK = 0; - - DDRB |= _BV(6); /* Debug */ - PORTB |= _BV(6); /* Debug */ - - PRR0 &= ~_BV(PRTIM1); - - /* Timer1: CTC: Toggle OC1C on compare match */ - OCR1A = 0; - OCR1C = 0; - TCCR1A = (0b01 << COM1C0) | (0b00 << WGM10); - TCCR1B = (0b01 << WGM12) | (0b001 << CS10); -} - - -int z80_clock_set(unsigned long freq) -{ - unsigned long ocrval = F_CPU / freq / 2; - uint8_t prescale = 0; - - while (ocrval > (1L<<16)) { - prescale++; - if (prescale < 3) - ocrval = ocrval / 8; - else - ocrval = ocrval / 4; - } - - if ((ocrval == 0) || (prescale > 4)) - return -1; - - ocrval -= 1; - - PINB |= _BV(6); /* Debug */ - - /* Stop Timer */ - TCCR1B = (0b01 << WGM12) | (0b000 << CS10); - TCNT1 = 0; - - OCR1A = ocrval; - OCR1CL = ocrval; - TCCR1A = (0b01 << COM1C0) | (0b00 << WGM10); - TCCR1B = (0b01 << WGM12) | ((prescale+1) << CS10); - - if (ocrval == 0) - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - TCNT1 = 0xFFFF; - } - - PINB |= _BV(6); /* Debug */ - - return 0; -} - -uint32_t z80_clock_get(void) -{ - uint32_t count = (OCR1A + 1L) * 2; - uint8_t pre = (TCCR1B & 7) - 1; - - while (pre) { - if (pre > 2) - count *= 4; - else - count *= 8; - pre--; - } - - return F_CPU/count; -} - - static void z80_addrbus_set_tristate(void) { @@ -296,8 +207,6 @@ static void z80_reset_pulse(void) void z80_setup_bus(void) { - z80_setup_clock(); - /* /ZRESET: Output and low */ Z80_O_RST = 0; DDR_RST |= _BV(RST); diff --git a/include/config.h b/include/config.h index 4093a67..c0777a8 100644 --- a/include/config.h +++ b/include/config.h @@ -1,6 +1,13 @@ #ifndef CONFIG_H #define CONFIG_H +/* Environment variables */ + +#define ENV_BAUDRATE "baudrate" +#define ENV_BOOTDELAY "bootdelay" +#define ENV_BOOTCMD "bootcmd" +#define ENV_PINALIAS "pin_alias" + #define CONFIG_ENV_SIZE 1600 #define CONFIG_ENV_OFFSET 0 #define CONFIG_ENVVAR_MAX 20 diff --git a/include/getopt-min.h b/include/getopt-min.h new file mode 100644 index 0000000..9f7729e --- /dev/null +++ b/include/getopt-min.h @@ -0,0 +1,12 @@ +#ifndef GETOPT_MIN_H +#define GETOPT_MIN_H + +int getopt( /* returns letter, '?', EOF */ + int argc, /* argument count from main */ + char *const argv[], /* argument vector from main */ + const FLASH char * optstring ); /* allowed args, e.g. "ab:c" */ + +extern int optind; + +#endif /* GETOPT_MIN_H */ + diff --git a/include/pin.h b/include/pin.h new file mode 100644 index 0000000..5b37587 --- /dev/null +++ b/include/pin.h @@ -0,0 +1,17 @@ +#ifndef PIN_H +#define PIN_H + +/* Number of user configurable I/O pins */ +#define PIN_MAX 11 + +typedef enum {NONE, INPUT, INPUT_PULLUP, OUTPUT, OUTPUT_TIMER} pinmode_t; + +int pin_config(int pin, pinmode_t mode); +pinmode_t pin_config_get(int pin); +int pin_read(int pin); +void pin_write(int pin, uint8_t val); +int pin_clockdiv_set(int pin, unsigned long divider); +long pin_clockdiv_get(int pin); + +#endif /* PIN_H */ + diff --git a/include/print-utils.h b/include/print-utils.h new file mode 100644 index 0000000..bcd9505 --- /dev/null +++ b/include/print-utils.h @@ -0,0 +1,2 @@ +void print_blanks(uint_fast8_t count); + diff --git a/include/z80-if.h b/include/z80-if.h index 5153f37..6f6f6fa 100644 --- a/include/z80-if.h +++ b/include/z80-if.h @@ -26,8 +26,6 @@ void z80_setup_bus(void); int z80_stat_reset(void); //void z80_busreq(level_t level); int z80_stat_halt(void); -uint32_t z80_clock_get(void); -int z80_clock_set(unsigned long freq); void z80_write(uint32_t addr, uint8_t data); |