]> cloudbase.mooo.com Git - z180-stamp.git/commitdiff
pin command, add user configurable i/o pins
authorLeo C <erbl259-lmu@yahoo.de>
Tue, 14 Oct 2014 10:53:48 +0000 (12:53 +0200)
committerLeo C <erbl259-lmu@yahoo.de>
Tue, 14 Oct 2014 10:53:48 +0000 (12:53 +0200)
12 files changed:
avr/Tupfile
avr/cmd_boot.c
avr/command_tbl.c
avr/getopt-min.c [new file with mode: 0644]
avr/main.c
avr/pin.c [new file with mode: 0644]
avr/serial.c
avr/timer.c
avr/z80-if.c
include/getopt-min.h [new file with mode: 0644]
include/pin.h [new file with mode: 0644]
include/z80-if.h

index 9227f2b769040e887a7e07ec26654958e2b1fee7..cbceff8f9482f93dd3fb82f3541abe9a857a1feb 100644 (file)
@@ -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
 
index 58c4f569e276199ed0a1dc7240f61d654972c0f2..285dd6520088b6f596e8fdd2d9bf60b628dd0a2d 100644 (file)
@@ -4,11 +4,16 @@
  */
 #include "common.h"
 #include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
 #include <util/delay.h>
 #include <avr/pgmspace.h>
 
 #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;
+}
+
index c721d536e9febe1fac0534bb28be87c3ad937965..71e70eaccafcfcd4060f5c55171422b380e26263 100644 (file)
@@ -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 (file)
index 0000000..778258d
--- /dev/null
@@ -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 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;
+}
+
index 9d7c89feaa9c2412147bed0def0511ecb4ac881c..0470feaba1a967dfae761f03c7f1c0c7a569454e 100644 (file)
@@ -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
diff --git a/avr/pin.c b/avr/pin.c
new file mode 100644 (file)
index 0000000..8a9f000
--- /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      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;
+}
+
index a5e28468e6018e489042c779c9ff390cf0e00fc9..e897c84b41077088025dc1204984f0420923f543 100644 (file)
@@ -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
index 56c7bedd5d0609f548c762cdff549e19e8046e2b..e15a55bde51648b5aac2ec85296a130fa0b0dc88 100644 (file)
@@ -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;
index dd0dd96414e2a91a1494987c8b6e703f2f57a954..a60a48280bbe03d73cf132ec6d260e5e8dbcc1c8 100644 (file)
 /* 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 (file)
index 0000000..9f7729e
--- /dev/null
@@ -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 (file)
index 0000000..e673b56
--- /dev/null
@@ -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 */
+
index 5153f37974c412e1102477da5a8626ae52c91d99..6f6f6fadf77338bd6a3b4838d52d60200f1dd057 100644 (file)
@@ -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);