diff options
Diffstat (limited to 'stm32/z180-stamp-stm32.c')
-rw-r--r-- | stm32/z180-stamp-stm32.c | 778 |
1 files changed, 778 insertions, 0 deletions
diff --git a/stm32/z180-stamp-stm32.c b/stm32/z180-stamp-stm32.c new file mode 100644 index 0000000..6751fe1 --- /dev/null +++ b/stm32/z180-stamp-stm32.c @@ -0,0 +1,778 @@ +/* + */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +#include <libopencmsis/core_cm3.h> +#include <libopencm3/cm3/nvic.h> +#include <libopencm3/cm3/systick.h> +#include <libopencm3/stm32/rtc.h> +#include <libopencm3/stm32/usart.h> +#include <libopencm3/stm32/rcc.h> +#include <libopencm3/stm32/gpio.h> +#include <libopencm3/stm32/timer.h> + +#define ODR 0x0c +#define IDR 0x08 + + +/* +#define __ASM __asm +#define __STATIC_INLINE static inline + +__attribute__((always_inline)) __STATIC_INLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i"); +} + +__attribute__((always_inline)) __STATIC_INLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i"); +} +*/ + + + +#include "z80-if.h" +#include "hdrom.h" + +#define USART_CONSOLE USART1 + +int _write(int fd, char *ptr, int len) __attribute__((used)); + +#define S_10MS_TO (1<<0) + +/* + * LED Connections + */ + +#define LED_PORT GPIOC +#define LED_BLUE_PIN GPIO8 +#define BLUE 8 +#define LED_GREEN_PIN GPIO9 +#define GREEN 9 + + +#define LED_BLUE_ON() BBIO_PERIPH(LED_PORT+ODR, BLUE) = 1 +#define LED_BLUE_OFF() BBIO_PERIPH(LED_PORT+ODR, BLUE) = 0 +#define LED_BLUE_TOGGLE() BBIO_PERIPH(LED_PORT+ODR, BLUE) = !BBIO_PERIPH(LED_PORT+ODR, BLUE) + +#define LED_GREEN_ON() BBIO_PERIPH(LED_PORT+ODR, GREEN) = 1 +#define LED_GREEN_OFF() BBIO_PERIPH(LED_PORT+ODR, GREEN) = 0 +#define LED_GREEN_TOGGLE() BBIO_PERIPH(LED_PORT+ODR, GREEN) = !BBIO_PERIPH(LED_PORT+ODR, GREEN) + + +/* + * Button connections + */ + +//BBIO_PERIPH(GPIOA+IDR, 0); + +#define KEY_PORT GPIOA_IDR +#define KEY0 GPIO0 +//#define KEY1 GPIO1 +//#define KEY2 GPIO2 + +#define REPEAT_MASK KEY0 // repeat: key0 +#define REPEAT_START 100 // after 1s +#define REPEAT_NEXT 20 // every 200ms + + +typedef enum { + NOTHING, PULSE, BLINK1, BLINK2 +} LED_MODE; + +typedef struct { + uint8_t mode; + uint8_t ontime, offtime; +} led_stat_t; + +volatile uint8_t led_timer[2]; +led_stat_t led_stat[2]; + +volatile int timeout_1s; +volatile uint32_t Stat; + + +/*--------------------------------------------------------------------------*/ + + +static void clock_setup(void) +{ + rcc_clock_setup_in_hse_8mhz_out_24mhz(); + + /* Enable clocks for: + GPIO port A (for GPIO_USART1_TX and Button) + GPIO port C (LEDs) + USART1 + TIM16 (RST-Pin) + TIM1 (IOE) + TODO: USART1 --> USART_CONSOLE + */ + rcc_peripheral_enable_clock(&RCC_APB2ENR, + RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN + | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN + | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN + | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN); + /* Enable clocks for: + TIM3 + */ + rcc_peripheral_enable_clock(&RCC_APB1ENR, + RCC_APB1ENR_TIM3EN); + + /* Enable clocks for: + TIM3 + */ + rcc_peripheral_enable_clock(&RCC_AHBENR, + RCC_AHBENR_DMA1EN); +} + +static void systick_setup(void) +{ + /* SysTick interrupt every N clock pulses: set reload to N-1 */ + STK_RVR = 24000000/1000 - 1; + + /* Set source to core clock, enable int and start counting. */ + STK_CSR = STK_CSR_CLKSOURCE_AHB | STK_CSR_TICKINT | STK_CSR_ENABLE; +} + +#if 0 +static void nvic_setup(void) +{ +// nvic_enable_irq(NVIC_RTC_IRQ); +// nvic_set_priority(NVIC_RTC_IRQ, 1); +} +#endif + +static void tim3_setup(void) +{ + TIM3_CR1 = TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP; + + TIM3_CCMR2 = 0 + | TIM_CCMR2_OC4M_FORCE_LOW + /* | TIM_CCMR2_OC4M_FORCE_HIGH */ + /* | TIM_CCMR2_OC4M_PWM2 */ + + /* | TIM_CCMR2_OC4PE */ + /* | TIM_CCMR2_OC4FE */ + | TIM_CCMR2_CC4S_OUT; + + TIM3_CCER = TIM_CCER_CC4E + | TIM_CCER_CC4P; + + TIM3_ARR = 48; /* default */ + TIM3_CCR4 = 1; /* */ +} + +static void gpio_setup(void) +{ + + /* Disable JTAG-DP, but leave SW-DP Enabled. (free PA15, PB3, PB4) + Remap SPI1 to PB3, PB4, PB5 and PA15. + Remap TIM3 (CH1/PC6, CH2/PC7, CH3/PC8, CH4/PC9) + */ + gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, + AFIO_MAPR_SPI1_REMAP | AFIO_MAPR_TIM3_REMAP_FULL_REMAP); + + /* LEDs and User Button. */ + gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, LED_BLUE_PIN); + gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, LED_GREEN_PIN); + gpio_set_mode(GPIOA, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_FLOAT, GPIO0); +} + + +static void usart_setup(void) +{ + /* Setup GPIO pin GPIO_USART1_TX/LED_GREEN_PIN on GPIO port A for transmit. */ + /* TODO: USART1 --> USART_CONSOLE */ + + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); + + /* Setup UART parameters. */ +// usart_set_baudrate(USART_CONSOLE, 38400); + usart_set_baudrate(USART_CONSOLE, 115200); + usart_set_databits(USART_CONSOLE, 8); + usart_set_stopbits(USART_CONSOLE, USART_STOPBITS_1); + usart_set_mode(USART_CONSOLE, USART_MODE_TX_RX); + usart_set_parity(USART_CONSOLE, USART_PARITY_NONE); + usart_set_flow_control(USART_CONSOLE, USART_FLOWCONTROL_NONE); + + /* Finally enable the USART. */ + usart_enable(USART_CONSOLE); +} + +/*--------------------------------------------------------------------------*/ + +/** + * Use USART_CONSOLE as a console. + * This is a syscall for newlib + * @param fd + * @param ptr + * @param len + * @return + */ +int _write(int fd, char *ptr, int len) +{ + int i; + + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { + for (i = 0; i < len; i++) { + if (ptr[i] == '\n') { + usart_send_blocking(USART_CONSOLE, '\r'); + } + usart_send_blocking(USART_CONSOLE, ptr[i]); + } + return i; + } + errno = EIO; + return -1; +} + + +/*--------------------------------------------------------------------------*/ + +void delay_systicks(int ticks) +{ + int start, stop, now; + + start = STK_CVR; + stop = start - ticks; + if (stop < 0) { + stop += STK_RVR; + do { + now = STK_CVR; + } while ((now > stop) || (now <= start)); + } else { + do { + now = STK_CVR; + } while ((now > stop) && (now <= start)); + } +} + + +/*--------------------------------------------------------------------------*/ + +static void led_toggle(uint8_t lednr) { + if (lednr == 0) + LED_BLUE_TOGGLE(); + else if (lednr == 1) + LED_GREEN_TOGGLE(); +} + +static void led_on(uint8_t lednr) { + if (lednr == 0) + LED_BLUE_ON(); + else if (lednr == 1) + LED_GREEN_ON(); +} + +static void led_off(uint8_t lednr) { + if (lednr == 0) + LED_BLUE_OFF(); + else if (lednr == 1) + LED_GREEN_OFF(); +} + +static uint8_t led_is_on(uint8_t lednr) { + if (lednr == 0) + return BBIO_PERIPH(LED_PORT+ODR, BLUE); + else if (lednr == 1) + return BBIO_PERIPH(LED_PORT+ODR, GREEN); + else + return 0; +} + +static void ledset(uint8_t lednr, uint8_t what, uint8_t len) { + + led_stat[lednr].mode = what; + switch (what) { + case PULSE: + led_stat[lednr].ontime = len; + led_stat[lednr].offtime = 0; + led_timer[lednr] = len; + led_on(lednr); + break; + case BLINK1: + case BLINK2: + if (what == BLINK1) + led_stat[lednr].offtime = 100 - len; + else + led_stat[lednr].offtime = 200 - len; + led_stat[lednr].ontime = len; + led_timer[lednr] = len; + led_on(lednr); + break; + default: + break; + } +} + +/*--------------------------------------------------------------------------*/ + +static volatile uint16_t key_state, + key_press, // key press detect + key_rpt; // key long press and repeat + + +static uint16_t get_key_press(uint16_t key_mask) { + __disable_irq(); + // read and clear atomic ! + key_mask &= key_press; // read key(s) + key_press ^= key_mask; // clear key(s) + __enable_irq(); + return key_mask; +} + +static uint16_t get_key_rpt(uint16_t key_mask) { + __disable_irq(); + // read and clear atomic ! + key_mask &= key_rpt; // read key(s) + key_rpt ^= key_mask; // clear key(s) + __enable_irq(); + return key_mask; +} + +static uint16_t get_key_short(uint16_t key_mask) { + __disable_irq(); + // read key state and key press atomic ! + return get_key_press(key_state & key_mask); +} + +/* +static uint16_t get_key_long(uint16_t key_mask) { + return get_key_press(get_key_rpt(key_mask)); +} +*/ + +static void key_timerproc() { + static uint16_t key_in_last, rpt; + uint16_t key_in, c; + + key_in = KEY_PORT; + + c = key_in_last & key_in & ~key_state; + +// key_state = key_state & key_in_last | (key_state | key_in_last) & key_in; +// key_state = key_state & key_in | (key_state | key_in) & key_in_last; + + key_state = c | ((key_in_last | key_in) & key_state); + +// key_state = (key_state&key_in_last) | (key_state&key_in) | (key_in_last&key_in); + + key_press |= c; + + key_in_last = key_in; + + + if ((key_state & REPEAT_MASK) == 0) // check repeat function + rpt = REPEAT_START; + if (--rpt == 0) { + rpt = REPEAT_NEXT; // repeat delay + key_rpt |= key_state & REPEAT_MASK; + } + + +#if 0 + +static char ds[30]; +int dsi = 0; + +ds[dsi++] = key_state & 1 ? '1' : '0'; +ds[dsi++] = key_in_last & 1 ? '1' : '0'; +ds[dsi++] = key_in & 1 ? '1' : '0'; +ds[dsi++] = ' '; + +//ds[dsi++] = key_state & 1 ? '1' : '0'; +//ds[dsi++] = key_in_last & 1 ? '1' : '0'; + +//ds[dsi++] = ' '; +//ds[dsi++] = ' '; +ds[dsi++] = 0; +puts(ds); +#endif + +} + +/*--------------------------------------------------------------------------*/ + +void sys_tick_handler(void) +{ + static int tick_10ms = 0; + static int count_ms = 0; + + int i; + + ++tick_10ms; + if (tick_10ms == 10) + { + Stat |= S_10MS_TO; + + tick_10ms = 0; + + i = led_timer[0]; + if (i) + led_timer[0] = i - 1; + i = led_timer[1]; + if (i) + led_timer[1] = i - 1; + + key_timerproc(); + + /* Drive timer procedure of low level disk I/O module */ + //disk_timerproc(); + } + + count_ms++; + if (count_ms == 1000) { + count_ms = 0; + + if (timeout_1s) + --timeout_1s; + } +} + +void rtc_isr(void) +{ + /* The interrupt flag isn't cleared by hardware, we have to do it. */ + rtc_clear_flag(RTC_SEC); + +} + +/*--------------------------------------------------------------------------*/ + +void tim3_set(int mode) +{ + uint16_t cc_mode; + + cc_mode = TIM_CCMR2_CC4S_OUT; + + TIM3_CR1 = TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP | TIM_CR1_OPM; + + if (mode < 0) + cc_mode |= TIM_CCMR2_OC4M_FORCE_LOW; + else if (mode == 0) + cc_mode |= TIM_CCMR2_OC4M_FORCE_HIGH; + else { + TIM3_ARR = mode; + cc_mode |= TIM_CCMR2_OC4M_PWM2; + } + + TIM3_CCMR2 = cc_mode; + + if (mode > 0) + TIM3_CR1 |= TIM_CR1_CEN; +} + +/*--------------------------------------------------------------------------*/ + +static uint32_t z80_sram_cmp(uint32_t addr, int length, uint8_t wval, int inc) +{ + uint8_t rval; + int errors = 0; + + printf("SRAM: Check %#.5x byte... ", length); //fflush(stdout); + while (length--) { + if ((rval = z80_read(addr)) != wval) { + if (errors == 0) { + printf("\nSRAM: Address W R\n" \ + " -------------\n"); +// 12345 00 11 + } + printf(" %.5lx %.2x %.2x\n", addr, wval, rval); + + if (++errors > 16 ) + break; + } + addr++; + wval += inc; + } + printf("Done.\n"); + + return addr; +} + +#if 0 +static void z80_sram_fill(uint32_t addr, int length, uint8_t startval, int inc) +{ + printf("SRAM: Write %#.5x byte... ", length); //fflush(stdout); + while (length--) { + z80_write(addr, startval); + ++addr; + startval += inc; + } + printf("Done.\n"); +} + + +void z80_sram_fill_string(uint32_t addr, int length, const char *text) +{ + char c; + const char *p = text; + + while (length--) { + z80_write(addr++, c = *p++); + if (c == 0) + p = text; + } +} + + +uint32_t z80_sram_cmp_string(uint32_t addr, int length, const char *text) +{ + char c; + const char *p = text; + + while (length--) { + c = *p++; + if (z80_read(addr) != c) + break; + ++addr; + if (c == 0) + p = text; + } + return addr; +} + +const char * const qbfox = "Zhe quick brown fox jumps over the lazy dog!"; +const char * const qbcat = "Zhe quick brown fox jumps over the lazy cat!"; + +#endif + +uint8_t z80_get_byte(uint32_t adr) +{ + uint8_t data; + + z80_get_bus(); + data = z80_read(adr), + z80_release_bus(); + + return data; +} + + +/*--------------------------------------------------------------------------*/ + +static void do_10ms(void) +{ + for (uint8_t i = 0; i < 2; i++) { + switch (led_stat[i].mode) { + case PULSE: + if (led_timer[i] == 0) { + led_off(i); + led_stat[i].mode = NOTHING; + } + break; + case BLINK1: + case BLINK2: + if (led_timer[i] == 0) { + if (led_is_on(i)) + led_timer[i] = led_stat[i].offtime; + else + led_timer[i] = led_stat[i].ontime; + led_toggle(i); + } + break; + default: + break; + } + } +} + +/*--------------------------------------------------------------------------*/ + +int main(void) +{ + //uint32_t led_state = LED_BLUE_PIN; + //uint32_t rc; + //uint8_t startval = 0; + //int count; + int stat, ch; + uint8_t c; + + clock_setup(); + gpio_setup(); + tim3_setup(); + setvbuf(stdout, NULL, _IONBF, 0); + usart_setup(); + printf("Hello World!\n"); + + z80_setup_bus(); + printf("z80_setup_bus done.\n"); + + /* + * If the RTC is pre-configured just allow access, don't reconfigure. + * Otherwise enable it with the LSE as clock source and 0x7fff as + * prescale value. + */ + rtc_auto_awake(LSE, 0x7fff); + + systick_setup(); + ///* Setup the RTC interrupt. */ + //nvic_setup(); + + /* Enable the RTC interrupt to occur off the SEC flag. */ + //rtc_interrupt_enable(RTC_SEC); + + printf("get bus..."); + z80_busreq(LOW); + z80_reset(HIGH); + z80_get_bus(); + printf(" got it!\n"); + + z80_memset(0, 0x76, 0x80000); + //z80_sram_fill(0, 512 * 1024, 0x76, 0); + z80_sram_cmp(0, 512 * 1024, 0x76, 0); + + z80_write_block((unsigned char *) hdrom, 0, hdrom_length); + z80_reset(LOW); + printf("bus released! "); + z80_release_bus(); + z80_reset(HIGH); + printf(" reset released!\n"); + + timeout_1s = 6; + while (timeout_1s) { + static int to=0; + uint8_t b, rc, tc, m; + if (to != timeout_1s) { + b = z80_get_byte(tx_fifo-0), + rc = z80_get_byte(tx_fifo-1), + tc = z80_get_byte(tx_fifo-2), + m =z80_get_byte(tx_fifo-3); + printf(" %.2x %.2x %.2x %.2x\n", + b, rc, tc, m); + to = timeout_1s; + + if ((rc==0) && (m==0x7f)) + break; + } + } + + z80_fifo_init(); + + ledset(0, BLINK1, 50); + + while (1) { +// static int tickstat = 0; + + if (Stat & S_10MS_TO) { + Stat &= ~S_10MS_TO; + do_10ms(); + } + + +// if (get_key_long(KEY0)) +// ledset(1, PULSE, 100); + + if (get_key_short(KEY0)) + z80_reset_pulse(); + + +/* + switch (tickstat) { + + case 0: + if (BBIO_PERIPH(GPIOA+IDR, 0)) + { + tickstat = 1; + + LED_GREEN_ON(); + LED_GREEN_OFF(); + LED_GREEN_ON(); + delay_systicks(12); + LED_GREEN_OFF(); + } + break; + default: + if (!BBIO_PERIPH(GPIOA+IDR, 0)) + tickstat = 0; + } +*/ + + //BBIO_PERIPH(LED_PORT+0x0C, 9) = BBIO_PERIPH(GPIOA+0x08, 0); + + //BBIO_PERIPH(LED_PORT+0x0C, 9) = !z80_stat_halt(); + + //BBIO_PERIPH(LED_PORT+0x0C, 9) = (~key_state & KEY0) != 0; + + +/* + stat = z80_fifo_is_not_full(rx_fifo); + if(stat) { + z80_fifo_putc(rx_fifo, 'y'); + if (++count == 154) { + putchar('\n'); + putchar('\r'); + count = 0; + } + + } +*/ + + stat = usart_get_flag(USART_CONSOLE, USART_SR_RXNE); + if (stat) { + c = usart_recv(USART_CONSOLE) & 0xff; + switch (c) { + case 'H': + tim3_set(-1); + break; + case 'L': + tim3_set(0); + break; + case 'P': + tim3_set(24000000/1000000 * 5); /* 5 us */ + break; + default: + z80_fifo_putc(fifo_out, c); + } + } + + if (timeout_1s == 0) { + + while (z80_fifo_is_not_empty(fifo_in)) { +// LED_GREEN_ON(); + c = z80_fifo_getc(fifo_in); + putchar(c); +// LED_GREEN_OFF(); + } + + timeout_1s = 1; + } + + while ((ch = z80_inbuf_getc()) >= 0) + printf(" 0x%.2X ", ch); + } + + return 0; +} + +#if 0 + +static char ds[30]; +int dsi = 0; + +ds[dsi++] = key_state1 & 1 ? '1' : '0'; +ds[dsi++] = key_in_last & 1 ? '1' : '0'; +ds[dsi++] = key_in & 1 ? '1' : '0'; +ds[dsi++] = ' '; +ds[dsi++] = key_state1 & 1 ? '1' : '0'; +ds[dsi++] = key_in_last & 1 ? '1' : '0'; + +ds[dsi++] = ' '; +ds[dsi++] = ' '; +ds[dsi++] = key_state & 1 ? '1' : '0'; +ds[dsi++] = ct1 & 1 ? '0' : '1'; +ds[dsi++] = ct0 & 1 ? '0' : '1'; +ds[dsi++] = ' '; +ds[dsi++] = key_state & 1 ? '1' : '0'; +//ds[dsi++] = '\r'; +//ds[dsi++] = '\n'; +ds[dsi++] = 0; +puts(ds); +#endif |