diff options
Diffstat (limited to 'avr/main.c')
-rw-r--r-- | avr/main.c | 252 |
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(); +} |