summaryrefslogtreecommitdiff
path: root/avr/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'avr/main.c')
-rw-r--r--avr/main.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/avr/main.c b/avr/main.c
new file mode 100644
index 0000000..2f9a62f
--- /dev/null
+++ b/avr/main.c
@@ -0,0 +1,252 @@
+/*
+ */
+
+
+#include "common.h"
+
+#include <avr/interrupt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "debug.h"
+#include "z80-if.h"
+#include "i2c.h"
+#include "con-utils.h"
+#include "serial.h"
+#include "timer.h"
+#include "cli.h"
+#include "env.h"
+#include "z180-serv.h"
+
+static uint8_t mcusr;
+
+/*--------------------------------------------------------------------------*/
+#if DEBUG
+
+__attribute__ ((naked)) __attribute__ ((section (".init3")))
+void preset_ram (void)
+{
+ for (uint8_t *p = RAMSTART; p <= (uint8_t *) RAMEND; p++)
+ *p = 0xdd;
+
+}
+
+static const FLASH char * const FLASH rreasons[] = {
+ FSTR("Power on"),
+ FSTR("External"),
+ FSTR("Brown out"),
+ FSTR("Watchdog"),
+ FSTR("JTAG"),
+ };
+
+static
+void print_reset_reason(void)
+{
+ uint8_t r = mcusr & 0x1f;
+ const FLASH char * const FLASH *p = rreasons;
+
+ printf_P(PSTR("### Reset reason(s): %s"), r ? "" : "none");
+ for ( ; r; p++, r >>= 1) {
+ if (r & 1) {
+ my_puts_P(*p);
+ if (r & ~1)
+ printf_P(PSTR(", "));
+ }
+ }
+ printf_P(PSTR(".\n"));
+}
+
+#endif
+
+ISR(INT5_vect)
+{
+ Stat |= S_MSG_PENDING;
+}
+
+ISR(INT6_vect)
+{
+ Stat |= S_CON_PENDING;
+}
+
+static
+void setup_avr(void)
+{
+ /* save and clear reset reason(s) */
+ /* TODO: move to init section? */
+ mcusr = MCUSR;
+ MCUSR = 0;
+
+ /* WD */
+
+ /* CPU */
+
+ /* Disable JTAG Interface regardless of the JTAGEN fuse setting. */
+ MCUCR = _BV(JTD);
+ MCUCR = _BV(JTD);
+
+ /* Disable peripherals. Enable individually in respective init function. */
+ PRR0 = _BV(PRTWI) |
+ _BV(PRTIM2) | _BV(PRTIM0) | _BV(PRTIM1) |
+ _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC);
+
+ PRR1 = _BV(PRTIM5) | _BV(PRTIM4) | _BV(PRTIM3) |
+ _BV(PRUSART3) | _BV(PRUSART2) | _BV(PRUSART1);
+
+
+ /* disable analog comparator */
+ ACSR = _BV(ACD);
+ /* Ports */
+
+ /* Clock */
+ CLKPR = _BV(CLKPCE);
+ CLKPR = 0;
+
+ /* Timer */
+ 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 */
+
+ /* INT5, INT6: falling edge */
+ EICRB = (EICRB & ~((0b11 << ISC50) | (0b11 << ISC60))) |
+ (0b10 << ISC50) | (0b10 << ISC60);
+ /* Reset pending ints */
+ EIFR |= _BV(INTF5) | _BV(INTF6);
+ /* Enable INT5, and INT6 */
+ EIMSK |= _BV(INT5) | _BV(INT6);
+}
+
+static
+int reset_reason_is_power_on(void)
+{
+ return (mcusr & _BV(PORF)) != 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Stored value of bootdelay, used by autoboot_command() */
+static int stored_bootdelay;
+
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop.
+ * returns: 0 - no key, allow autoboot
+ * 1 - got key, abort
+ */
+
+static int abortboot(int bootdelay)
+{
+ int abort = 0;
+ uint32_t ts;
+
+ if (bootdelay >= 0)
+ printf_P(PSTR("Hit any key to stop autoboot: %2d "), bootdelay);
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+ /*
+ * Check if key already pressed
+ * Don't check if bootdelay < 0
+ */
+ if (bootdelay >= 0) {
+ if (tstc()) { /* we got a key press */
+ (void) my_getchar(1); /* consume input */
+ my_puts_P(PSTR("\b\b\b 0"));
+ abort = 1; /* don't auto boot */
+ }
+ }
+#endif
+
+ while ((bootdelay > 0) && (!abort)) {
+ --bootdelay;
+ /* delay 1000 ms */
+ ts = get_timer(0);
+ do {
+ if (tstc()) { /* we got a key press */
+ abort = 1; /* don't auto boot */
+ bootdelay = 0; /* no more delay */
+ break;
+ }
+ udelay(10000);
+ } while (!abort && get_timer(ts) < 1000);
+
+ printf_P(PSTR("\b\b\b%2d "), bootdelay);
+ }
+
+ putchar('\n');
+
+ return abort;
+}
+
+static
+const char *bootdelay_process(void)
+{
+ char *s;
+ int 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(ENV_BOOTCMD));
+ stored_bootdelay = bootdelay;
+ return s;
+}
+
+static
+void autoboot_command(const char *s)
+{
+ debug("### main_loop: bootcmd=\"%s\"\n", s ? s : PSTR("<UNDEFINED>"));
+ _delay_ms(20);
+
+ if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
+ run_command_list(s, -1);
+ }
+}
+
+
+static
+void main_loop(void)
+{
+ const char *s;
+
+ s = bootdelay_process();
+ autoboot_command(s);
+ cli_loop();
+}
+
+int main(void)
+{
+
+ setup_avr();
+ z80_setup_bus();
+
+ env_init();
+
+ if (reset_reason_is_power_on())
+ _delay_ms(CONFIG_PWRON_DELAY);
+
+ serial_setup(getenv_ulong(PSTR(ENV_BAUDRATE), 10, CONFIG_BAUDRATE));
+ sei();
+
+#if DEBUG
+ debug("\n=========================< (RE)START DEBUG >=========================\n");
+ print_reset_reason();
+#endif
+
+#if DEBUG
+ unsigned long i_speed = getenv_ulong(PSTR("i2c_clock"), 10, CONFIG_SYS_I2C_CLOCK);
+ debug("### Setting I2C clock Frequency to %lu Hz.\n", i_speed);
+ i2c_init(i_speed);
+#else
+ i2c_init(CONFIG_SYS_I2C_CLOCK);
+#endif
+
+ printf_P(PSTR("\nATMEGA1281+Z8S180 Stamp Monitor\n\n"));
+
+ setup_z180_serv();
+
+ main_loop();
+}