summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo C2014-10-16 11:08:47 +0200
committerLeo C2014-10-16 11:08:47 +0200
commit6dc26e92c20eedcfcba9e0b75a015a5b160748c5 (patch)
treea2a7c5a22b3353b4d26b8eb1b3a8caef7f6411ac
parent349c01b10d1f6e223f963c6cbdf6a94d0b618895 (diff)
parent8f23e84c6a08a384d25582f9cf79c4f5549bc852 (diff)
downloadz180-stamp-6dc26e92c20eedcfcba9e0b75a015a5b160748c5.zip
Merge branch 'master' into hostcomm_avr
-rw-r--r--avr/Tupfile10
-rw-r--r--avr/cmd_boot.c35
-rw-r--r--avr/cmd_mem.c11
-rw-r--r--avr/cmd_pin.c329
-rw-r--r--avr/command.c17
-rw-r--r--avr/command_tbl.c42
-rw-r--r--avr/getopt-min.c76
-rw-r--r--avr/main.c17
-rw-r--r--avr/pin.c372
-rw-r--r--avr/print-utils.c10
-rw-r--r--avr/serial.c2
-rw-r--r--avr/timer.c4
-rw-r--r--avr/z80-if.c103
-rw-r--r--include/config.h7
-rw-r--r--include/getopt-min.h12
-rw-r--r--include/pin.h17
-rw-r--r--include/print-utils.h2
-rw-r--r--include/z80-if.h2
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;
+}
+
diff --git a/avr/main.c b/avr/main.c
index 9d7c89f..ba8a672 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<<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);