/*************************************************************************** * C based avr910 / avr109 ISP Adapter * * * * Copyright (C) 2006 - 20011 by Olaf Rempel * * razzor AT kopf MINUS tisch DOT de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License, * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) /* * using ATmega16 @7.3728MHz: * Fuse H: 0xDA (512 words bootloader, jtag disabled) * Fuse L: 0xFF (ext. Crystal) */ #define F_CPU 7372800 #define BAUDRATE 115200 #define TIMER_RELOAD (0xFF - 72) /* 10ms @7.3728MHz */ #define ISP_RESET PORTB1 /* to target */ #define ISP_LED PORTB3 /* low active */ #define ISP_MOSI PORTB5 /* to target */ #define ISP_MISO PORTB6 /* to target */ #define ISP_SCK PORTB7 /* to target */ #define RESET_IN PORTD3 /* high active */ #include #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1) /* F_CPU /4 (1.8432MHz) */ #define SPI_MODE4 ((1<> 8); spi_rxtx(addr & 0xFF); spi_rxtx(val); /* remember values for polling */ last_cmd = cmd; last_addr = addr; last_val = val; } /* read a byte from target flash/eeprom */ static uint8_t mem_read(uint8_t cmd, uint16_t addr) { spi_rxtx(cmd); spi_rxtx(addr >> 8); spi_rxtx(addr & 0xFF); return spi_rxtx(0x00); } /* wait until byte/page is written to target memory */ static void poll(void) { uint8_t cmd, val, poll = 0xFF; if (((last_val == 0x00) && (device.flags & POLL_00)) || ((last_val == 0x7F) && (device.flags & POLL_7F)) || ((last_val == 0x80) && (device.flags & POLL_80)) || ((last_val == 0xFF) && (device.flags & POLL_FF)) ) { /* wait default time */ _delay_ms(15); return; } if (last_cmd == CMD_WRITE_EEPROM) { cmd = CMD_READ_EEPROM; } else { /* CMD_WRITE_FLASH -> CMD_READ_FLASH */ cmd = (last_cmd & 0x08) | 0x20; } /* poll until we get correct value */ do { val = mem_read(cmd, last_addr); } while ((val != last_val) && poll--); } static void mem_pagewrite(uint16_t addr) { spi_rxtx(CMD_WRITE_FLASH_PAGE); spi_rxtx(addr >> 8); spi_rxtx(addr & 0xFF); spi_rxtx(0x00); poll(); } static void cmdloop(void) __attribute__ ((noreturn)); static void cmdloop(void) { static uint8_t page_buf[256]; uint16_t addr = 0; /* disable ISP_RESET */ set_reset(1); while (1) { switch (ser_recv()) { /* Enter programming mode */ case 'P': { uint8_t sync, count = 0x20; led_mode = LED_ON; do { set_reset(1); _delay_ms(50); set_reset(0); _delay_ms(50); spi_rxtx(CMD_PROG_ENABLE_1); spi_rxtx(CMD_PROG_ENABLE_2); sync = spi_rxtx(0x00); spi_rxtx(0x00); } while (sync != CMD_PROG_ENABLE_2 && count--); memset(&device, 0x00, sizeof(struct _device)); if (sync == CMD_PROG_ENABLE_2) { uint8_t i; for (i = 0; i < 3; i++) { device.sig[i] = mem_read(CMD_READ_SIG_1, (CMD_READ_SIG_2 << 8) | i); } for (i = 0; i < ARRAY_SIZE(devices); i++) { if (memcmp_P(device.sig, devices[i].sig, sizeof(device.sig)) == 0) { memcpy_P(&device, &devices[i], sizeof(struct _device)); break; } } } ser_send('\r'); break; } /* Autoincrement address */ case 'a': ser_send('Y'); break; /* Set address */ case 'A': addr = (ser_recv() << 8); addr |= ser_recv(); ser_send('\r'); break; /* Write program memory, low byte */ case 'c': led_mode = LED_FAST; mem_write(CMD_LOAD_FLASH_LO, addr, ser_recv()); /* poll on byte addressed targets */ if (device.pagemask == 0x00) { poll(); } ser_send('\r'); break; /* Write program memory, high byte */ case 'C': led_mode = LED_FAST; mem_write(CMD_LOAD_FLASH_HI, addr, ser_recv()); /* poll on byte addressed targets */ if (device.pagemask == 0x00) { poll(); } addr++; ser_send('\r'); break; /* Issue Page Write */ case 'm': led_mode = LED_FAST; mem_pagewrite(last_addr); ser_send('\r'); break; /* Read Lock Bits */ case 'r': ser_send(mem_read(CMD_READ_LOCK_1, CMD_READ_LOCK_2 << 8)); ser_send('\r'); break; /* Read program memory */ case 'R': led_mode = LED_SLOW; ser_send(mem_read(CMD_READ_FLASH_HI, addr)); ser_send(mem_read(CMD_READ_FLASH_LO, addr)); addr++; break; /* Read data memory */ case 'd': led_mode = LED_SLOW; ser_send(mem_read(CMD_READ_EEPROM, addr)); addr++; break; /* Write data memory */ case 'D': led_mode = LED_FAST; mem_write(CMD_WRITE_EEPROM, addr, ser_recv()); poll(); addr++; ser_send('\r'); break; /* Chip erase */ case 'e': spi_rxtx(CMD_CHIP_ERASE_1); spi_rxtx(CMD_CHIP_ERASE_2); spi_rxtx(0x00); spi_rxtx(0x00); _delay_ms(10); ser_send('\r'); break; /* Write lock bits */ case 'l': { uint8_t val = ser_recv(); spi_rxtx(CMD_WRITE_LOCK_1); spi_rxtx(CMD_WRITE_LOCK_2); spi_rxtx(0x00); spi_rxtx(val); _delay_ms(10); ser_send('\r'); break; } /* Read fusebits */ case 'F': ser_send(mem_read(CMD_READ_FUSE_1, CMD_READ_FUSE_2 << 8)); break; /* Read high fusebits */ case 'N': ser_send(mem_read(CMD_READ_FUSE_H_1, CMD_READ_FUSE_H_2 << 8)); break; /* Read extended fusebits */ case 'Q': ser_send(mem_read(CMD_READ_FUSE_E_1, CMD_READ_FUSE_E_2 << 8)); break; /* Leave programming mode */ case 'L': /* Exit Bootloader */ case 'E': set_reset(1); led_mode = LED_OFF; ser_send('\r'); break; /* Select device type */ case 'T': { ser_recv(); // ignore ser_send('\r'); break; } /* Read signature bytes */ case 's': { uint8_t i = 2; do { ser_send(device.sig[i]); } while (i--); break; } /* Return supported device codes */ case 't': { uint8_t limit = 0x00; while (1) { uint8_t i; uint8_t search = 0xFF; for (i = 0; i < ARRAY_SIZE(devices); i++) { uint8_t devcode = pgm_read_byte(&devices[i].devcode); if ((devcode > limit) && (devcode < search)) { search = devcode; } } if (search == 0xFF) break; ser_send(search); limit = search; } ser_send(0x00); break; } /* Return software identifier */ case 'S': ser_send('A'); ser_send('V'); ser_send('R'); ser_send('-'); ser_send('I'); ser_send('S'); ser_send('P'); break; /* Return software version */ case 'V': ser_send('3'); ser_send('8'); break; /* Return hardware version */ case 'v': ser_send('1'); ser_send('2'); break; /* Return programmer type */ case 'p': ser_send('S'); break; /* Set LED */ case 'x': ser_recv(); led_mode = LED_ON; break; /* Clear LED */ case 'y': ser_recv(); led_mode = LED_OFF; break; /* Report Block write Mode */ case 'b': { ser_send('Y'); ser_send(sizeof(page_buf) >> 8); ser_send(sizeof(page_buf) & 0xFF); break; } /* Block Write */ case 'B': { uint16_t size, i; uint8_t type; led_mode = LED_FAST; size = ser_recv() << 8; size |= ser_recv(); type = ser_recv(); for (i = 0; i < size; i++) page_buf[i] = ser_recv(); if (type == 'F') { for (i = 0; i < size; i += 2) { mem_write(CMD_LOAD_FLASH_LO, addr, page_buf[i]); mem_write(CMD_LOAD_FLASH_HI, addr, page_buf[i+1]); addr++; if ((addr & device.pagemask) == 0x00) { mem_pagewrite(last_addr); } } if (size != sizeof(page_buf)) { mem_pagewrite(last_addr); } } else if (type == 'E') { for (i = 0; i < size; i++) { mem_write(CMD_WRITE_EEPROM, addr, page_buf[i]); poll(); addr++; } } ser_send('\r'); break; } /* Block Read */ case 'g': { uint16_t size, i; uint8_t type; led_mode = LED_SLOW; size = ser_recv() << 8; size |= ser_recv(); type = ser_recv(); if (type == 'F') { for (i = 0; i < size; i += 2) { ser_send(mem_read(CMD_READ_FLASH_LO, addr)); ser_send(mem_read(CMD_READ_FLASH_HI, addr)); addr++; } } else if (type == 'E') { for (i = 0; i < size; i++) { ser_send(mem_read(CMD_READ_EEPROM, addr)); addr++; } } break; } /* Write fusebits */ case 'f': { uint8_t val = ser_recv(); spi_rxtx(CMD_WRITE_FUSE_1); spi_rxtx(CMD_WRITE_FUSE_2); spi_rxtx(0x00); spi_rxtx(val); _delay_ms(10); ser_send('\r'); break; } /* Universial command */ case ':': { uint8_t val[3]; val[0] = ser_recv(); val[1] = ser_recv(); val[2] = ser_recv(); spi_rxtx(val[0]); spi_rxtx(val[1]); ser_send(spi_rxtx(val[2])); _delay_ms(10); ser_send('\r'); break; } /* New universal command */ case '.': { uint8_t val[4]; val[0] = ser_recv(); val[1] = ser_recv(); val[2] = ser_recv(); val[3] = ser_recv(); spi_rxtx(val[0]); spi_rxtx(val[1]); spi_rxtx(val[2]); ser_send(spi_rxtx(val[3])); _delay_ms(10); ser_send('\r'); break; } /* ESC */ case 0x1B: break; default: ser_send('?'); break; } } } static uint16_t button_statemachine(uint8_t event) { static uint8_t oldstate; uint8_t state = oldstate; uint16_t timer; do { if (state != oldstate) { event = EV_STATE_ENTER; } switch (state) { case STATE_IDLE: if (event == EV_STATE_ENTER) { led_mode = LED_OFF; timer = 0xFFFF; /* stop timer */ } else if (event == EV_BUTTON_PRESSED) { state = STATE_PRESSED; set_reset(0); } break; case STATE_PRESSED: if (event == EV_STATE_ENTER) { led_mode = LED_ON; timer = 5; /* timeout 50ms (== reset length) */ } else if (event == EV_BUTTON_RELEASED) { state = STATE_IDLE; set_reset(1); } else if (event == EV_TIMEOUT) { state = STATE_PRESSED2; set_reset(1); } break; case STATE_PRESSED2: if (event == EV_STATE_ENTER) { led_mode = LED_OFF; timer = 500; /* timeout in 5s */ } else if (event == EV_BUTTON_RELEASED) { state = STATE_IDLE; } else if (event == EV_TIMEOUT) { switch (SPCR) { case SPI_MODE1: state = STATE_SPEED1; break; case SPI_MODE2: state = STATE_SPEED2; break; case SPI_MODE3: state = STATE_SPEED3; break; default: case SPI_MODE4: state = STATE_SPEED4; break; } } break; case STATE_SPEED1: if (event == EV_STATE_ENTER) { led_mode = LED_SPEED1; timer = 500; /* timeout in 5s */ } else if (event == EV_BUTTON_PRESSED) { state = STATE_SPEED2; } else if (event == EV_TIMEOUT) { state = STATE_NVRAM_STORE; SPCR = SPI_MODE1; } break; case STATE_SPEED2: if (event == EV_STATE_ENTER) { led_mode = LED_SPEED2; timer = 500; /* timeout in 5s */ } else if (event == EV_BUTTON_PRESSED) { state = STATE_SPEED3; } else if (event == EV_TIMEOUT) { state = STATE_NVRAM_STORE; SPCR = SPI_MODE2; } break; case STATE_SPEED3: if (event == EV_STATE_ENTER) { led_mode = LED_SPEED3; timer = 500; /* timeout in 5s */ } else if (event == EV_BUTTON_PRESSED) { state = STATE_SPEED4; } else if (event == EV_TIMEOUT) { state = STATE_NVRAM_STORE; SPCR = SPI_MODE3; } break; case STATE_SPEED4: if (event == EV_STATE_ENTER) { led_mode = LED_SPEED4; timer = 500; /* timeout in 5s */ } else if (event == EV_BUTTON_PRESSED) { state = STATE_SPEED1; } else if (event == EV_TIMEOUT) { state = STATE_NVRAM_STORE; SPCR = SPI_MODE4; } break; default: state = STATE_IDLE; break; } if (state == STATE_NVRAM_STORE) { state = STATE_IDLE; nvram_data.spi_mode = SPCR; nvram_start_write(); } if (event == EV_STATE_ENTER) { oldstate = state; } } while (state != oldstate); return timer; } /* time keeping */ ISR(TIMER0_OVF_vect) { uint8_t event = EV_NONE; /* restart timer */ TCNT0 = TIMER_RELOAD; static uint8_t prev_pressed; if (PIND & (1< 0) { timer = new_timer; } } /* update LED */ static uint8_t led_timer; if (led_mode & ((led_timer++ & 0xFF) | 0x80)) { PORTB &= ~(1<>8) & 0xFF; UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); /* enable usart with 8n1 */ UCSRB = (1<