From: Leo C Date: Tue, 14 Oct 2014 10:53:48 +0000 (+0200) Subject: pin command, add user configurable i/o pins X-Git-Tag: hexrel-3~1 X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp.git/commitdiff_plain/41d36f28612cb6c49cf0260236f3b834549883be pin command, add user configurable i/o pins --- diff --git a/avr/Tupfile b/avr/Tupfile index 9227f2b..cbceff8 100644 --- a/avr/Tupfile +++ b/avr/Tupfile @@ -4,9 +4,9 @@ PROG = stamp-test 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 += env.c xmalloc.c date.c getopt-min.c SRC += timer.c con-utils.c serial.c i2c.c pcf8583.c -SRC += background.c z180-serv.c z80-if.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..285dd65 100644 --- a/avr/cmd_boot.c +++ b/avr/cmd_boot.c @@ -4,11 +4,16 @@ */ #include "common.h" #include +#include +#include #include #include #include "command.h" +#include "getopt-min.h" #include "z80-if.h" +#include "pin.h" +#include "debug.h" /* ugly hack to get Z180 loadfile into flash memory */ #define const const FLASH @@ -32,7 +37,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,25 +148,47 @@ command_ret_t do_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv return CMD_RET_SUCCESS; } - +#if 0 command_ret_t do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - uint32_t freq; + long freq; + char *endp; (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 (toupper(argv[1][0]) == 'L') + freq = 0; + else if (toupper(argv[1][0]) == 'H') + freq = LONG_MAX; + else { + freq = strtol(argv[1], &endp, 10); + switch (*endp) { + case 'M': + freq *= 1000; + case 'K': + freq *= 1000; + endp++; + case '\0': + if (*endp == '\0') + break; + default: + printf_P(PSTR("invalid value\n")); + return CMD_RET_USAGE; + } + + if (freq == 0) { + printf_P(PSTR("CPU clock cannot be 0\n")); + return CMD_RET_USAGE; + } + + +/* if (freq > (long) F_CPU / 2) { + printf_P(PSTR("Max CPU clock freq. is: %luHz\n"), F_CPU/2); + 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); @@ -174,3 +201,247 @@ command_ret_t do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_SUCCESS; } +command_ret_t do_clock2(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + long value; + char *endp; + uint8_t div_flag = 0; + + (void) cmdtp; (void) flag; + + if (argc >= 2) { + if (argv[1][0] == '-' && argv[1][1] == 'd') { + div_flag = 1; + argc--; + argv++; + } + } + + if (argc == 2) { + if (toupper(argv[1][0]) == 'L') + value = 0; + else if (toupper(argv[1][0]) == 'H') + value = LONG_MAX; + else { + value = strtol(argv[1], &endp, 10); + switch (*endp) { + case 'M': + value *= 1000; + case 'K': + value *= 1000; + endp++; + case '\0': + if (*endp == '\0') + break; + default: + printf_P(PSTR("invalid value\n")); + return CMD_RET_USAGE; + } + + if (value == 0) { + printf_P(PSTR("clk2 cannot be 0\n")); + return CMD_RET_USAGE; + } + + if (div_flag) { + if (value > 256*1024L) { + printf_P(PSTR("Max clk2 divider is: %lu\n"), 256*1024L); + return CMD_RET_USAGE; + } + } else { + if (value > (long) F_CPU / 2) { + printf_P(PSTR("Max clk2 freq. is: %luHz\n"), F_CPU/2); + return CMD_RET_USAGE; + } + } + } + if (div_flag ? z80_clock2_divset(value) : z80_clock2_set(value) < 0) { + printf_P(PSTR("Setting clk2 freq. to %luHz failed.\n"), + value); + } + } + + printf_P(PSTR("clk2: %luHz\n"), z80_clock2_get()); + + + return CMD_RET_SUCCESS; +} +#endif + +// {INPUT, INPUT_PULLUP, OUTPUT, OUTPUT_TIMER} pinmode_t; + + +static void print_blanks(uint_fast8_t count) +{ + while(count--) + putchar(' '); +} + +static const FLASH char * const FLASH pinconf_str[] = { + FSTR("Input"), + FSTR("Pullup"), + FSTR("Output"), + FSTR("Clock"), + }; + +static const FLASH char * const FLASH pinlevel_str[] = { + FSTR("Low"), + FSTR("High"), + FSTR(""), + }; + +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); + my_puts_P(pinconf_str[pinconf]); + print_blanks(8 - strlen_P(pinconf_str[pinconf])); + my_puts_P(levelp); + print_blanks(6 - strlen_P(levelp)); + if (pinconf == OUTPUT_TIMER) + printf_P(PSTR("%7ld %8ld"), + div, F_CPU/div); + } else { + printf_P(PSTR("Pin %d: "), pin); + 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; +} + + +/* + * TODO: - pin groups + * - error if pin "config clock" on pins without clock + * - stat for single pin (group) + */ + +command_ret_t do_pin(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int opt, pin; + unsigned long value; + char *endp; + char printheader = 1; + + (void) cmdtp; (void) flag; + + /* reset getopt() */ + optind = 1; + + while ((opt = getopt(argc, argv, PSTR("s"))) != -1) { + switch (opt) { + case 's': + printheader = 0; + break; + default: /* '?' */ + return CMD_RET_USAGE; + } + } + +// if ((argc - optind) % 2 != 0) +// return CMD_RET_USAGE; + + debug("argc: %d, optind: %d\n", argc, optind); + + switch (argc - optind) { + case 0: + if (printheader) + printf_P(PSTR("Pin Config Level Divider Frequency/Hz\n" + "-----------------------------------------\n")); + for (pin = 0; pin < PIN_MAX; pin++) + print_pin(pin, 1); + + return CMD_RET_SUCCESS; + break; + case 1: + pin = strtol(argv[optind], &endp, 10); + print_pin(pin, 0); + return CMD_RET_SUCCESS; + break; + } + + while (optind < argc ) { + uint8_t hz_flag = 0; + + pin = strtol(argv[optind++], &endp, 10); + + switch (toupper(argv[optind][0])) { + case 'L': + case 'H': + pin_write(pin, toupper(argv[optind][0]) == 'H'); + pin_config(pin, OUTPUT); + break; + case 'P': + pin_config(pin, INPUT_PULLUP); + break; + case 'I': + case 'T': + pin_config(pin, 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; + } + + + debug("** setting pin '%d' to '%lu'\n", pin, value); + if (pin_clockdiv_set(pin, value) < 0) { + printf_P(PSTR("Setting pin %d to %lu failed.\n"), + pin, value); + } + } + + optind++; + } + + + return CMD_RET_SUCCESS; +} + diff --git a/avr/command_tbl.c b/avr/command_tbl.c index c721d53..71e70ea 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 get 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..778258d --- /dev/null +++ b/avr/getopt-min.c @@ -0,0 +1,76 @@ +#include "common.h" +#include + + +/* + * 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 + +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 EOF; + } + + 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; +} + diff --git a/avr/main.c b/avr/main.c index 9d7c89f..0470fea 100644 --- a/avr/main.c +++ b/avr/main.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< +#include +#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 CLOCK 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/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 dd0dd96..a60a482 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/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..e673b56 --- /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 {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/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);