This commit is contained in:
Olaf Rempel 2011-06-25 16:19:18 +02:00
parent e1c00dc403
commit 9205611c5a
2 changed files with 417 additions and 214 deletions

View File

@ -48,4 +48,4 @@ bin: $(PRG).bin
install: text install: text
# uisp -dprog=stk200 --erase --upload if=$(PRG).hex --verify # uisp -dprog=stk200 --erase --upload if=$(PRG).hex --verify
avrdude -p m16 -c butterfly -b 19200 -U flash:w:$(PRG).hex avrdude -p m16 -c butterfly -b 19200 -P /dev/ttyUSB0 -U flash:w:$(PRG).hex

629
ispprog.c
View File

@ -1,59 +1,129 @@
/* /***************************************************************************
* C based avr910 / avr109 ISP Adapter * C based avr910 / avr109 ISP Adapter *
* * *
* (c) 2006-2008 by Olaf Rempel * Copyright (C) 2006 - 20011 by Olaf Rempel *
* <razzor at kopf minus tisch dot de> * razzor AT kopf MINUS tisch DOT de *
* * *
* using ATmega16 @7.3728MHz: * This program is free software; you can redistribute it and/or modify *
* PB1 = /Reset (to target) * it under the terms of the GNU General Public License as published by *
* PB3 = /LED * the Free Software Foundation; version 2 of the License, *
* PB5 = MOSI (to target) * *
* PB6 = MISO (to target) * This program is distributed in the hope that it will be useful, *
* PB7 = SCK (to target) * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* PD3 = reset-in * 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 <avr/io.h> #include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <string.h>
#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 F_CPU 7372800
#define BAUDRATE 115200 #define BAUDRATE 115200
#define TIMER_RELOAD (0xFF - 72) /* 10ms @7.3728MHz */
/* SPI Clock: F_CPU /4 (1.8432MHz) or /128 (57.6kHz) */ #define ISP_RESET PORTB1 /* to target */
#define SPI_MODE ((1<<SPE) | (1<<MSTR)) #define ISP_LED PORTB3 /* low active */
//#define SPI_MODE ((1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0)) #define ISP_MOSI PORTB5 /* to target */
#define ISP_MISO PORTB6 /* to target */
#define ISP_RESET PORTB1 #define ISP_SCK PORTB7 /* to target */
#define ISP_LED PORTB3 #define RESET_IN PORTD3 /* high active */
#define ISP_MOSI PORTB5
#define ISP_MISO PORTB6
#define ISP_SCK PORTB7
#define RESET_IN PORTD3
struct {
uint8_t id; /* device id */
uint8_t pagemask; /* bitmask of one flash-page */
uint8_t pollcode; /* value of an empty flash-cell */
} devices[] = {
// { 0x20, 0x00, 0x7F }, /* at90s2313 (no paging, reads 0x7F back) */
{ 0x20, 0x0F, 0xFF }, /* tiny24 (16 words/page) */
{ 0x38, 0x00, 0x7F }, /* at90s8515 (no paging, reads 0x7F back) */
{ 0x43, 0x7F, 0xFF }, /* mega128 (128 words/page) */
{ 0x72, 0x3F, 0xFF }, /* mega32 (64 words/page) */
{ 0x74, 0x3F, 0xFF }, /* mega16 (64 words/page) */
{ 0x76, 0x1F, 0xFF }, /* mega8 (32 words/page) */
{ 0x00, 0x00, 0x00 },
};
#include <util/delay.h> #include <util/delay.h>
#define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1) #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1)
#define LED_OFF 0x00 /* F_CPU /4 (1.8432MHz) */
#define LED_ON 0x01 #define SPI_MODE4 ((1<<SPE) | (1<<MSTR))
#define LED_FAST 0x02 /* F_CPU /16 (460.8kHz) */
#define LED_SLOW 0x03 #define SPI_MODE3 ((1<<SPE) | (1<<MSTR) | (1<<SPR1))
/* F_CPU /64 (115.2kHz) */
#define SPI_MODE2 ((1<<SPE) | (1<<MSTR) | (1<<SPR0))
/* F_CPU /128 (57.6kHz) */
#define SPI_MODE1 ((1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0))
#define POLL_00 0x01 /* value 0x00 can not be polled from flash/eeprom */
#define POLL_7F 0x02 /* value 0x7F can not be polled from flash/eeprom */
#define POLL_80 0x04 /* value 0x80 can not be polled from flash/eeprom */
#define POLL_FF 0x08 /* value 0xFF can not be polled from flash/eeprom */
struct _device {
uint8_t sig[3]; /* device signature */
uint8_t devcode; /* avr910 device code */
uint16_t pagemask; /* pagemask */
uint16_t flags; /* quirks for this device */
};
static struct _device device;
static struct _device devices[] PROGMEM = {
{ { 0x1E, 0x90, 0x01 }, 0x13, 0x00, POLL_00 | POLL_FF }, /* at90s1200 */
{ { 0x1E, 0x91, 0x01 }, 0x20, 0x00, POLL_7F | POLL_80 | POLL_FF }, /* at90s2313 */
{ { 0x1E, 0x91, 0x08 }, 0x20, 0x0F, POLL_FF }, /* tiny25 (at90s2313 devcode) */
{ { 0x1E, 0x91, 0x09 }, 0x5E, 0x0F, POLL_FF }, /* tiny26 */
{ { 0x1E, 0x91, 0x0A }, 0x5E, 0x0F, POLL_FF }, /* tiny2313 (tiny26 devcode) */
{ { 0x1E, 0x91, 0x0B }, 0x20, 0x0F, POLL_FF }, /* tiny24 (at90s2313 devcode) */
{ { 0x1E, 0x92, 0x06 }, 0x20, 0x1F, POLL_FF }, /* tiny45 (at90s2313 devcode) */
{ { 0x1E, 0x92, 0x07 }, 0x20, 0x1F, POLL_FF }, /* tiny44 (at90s2313 devcode) */
{ { 0x1E, 0x93, 0x01 }, 0x38, 0x00, POLL_7F | POLL_80 | POLL_FF }, /* at90s8515 */
{ { 0x1E, 0x93, 0x07 }, 0x76, 0x1F, POLL_00 | POLL_FF }, /* mega8 */
{ { 0x1E, 0x93, 0x0A }, 0xFF, 0x1F, POLL_FF }, /* mega88 (no devcode) */
{ { 0x1E, 0x93, 0x0B }, 0x20, 0x1F, POLL_FF }, /* tiny85 (at90s2313 devcode) */
{ { 0x1E, 0x93, 0x0C }, 0x20, 0x1F, POLL_FF }, /* tiny84 (at90s2313 devcode) */
{ { 0x1E, 0x94, 0x03 }, 0x74, 0x3F, POLL_FF }, /* mega16 */
{ { 0x1E, 0x94, 0x06 }, 0xFF, 0x3F, POLL_FF }, /* mega168 (no devcode) */
{ { 0x1E, 0x95, 0x02 }, 0x72, 0x3F, POLL_FF }, /* mega32 */
{ { 0x1E, 0x96, 0x02 }, 0x45, 0x7F, POLL_FF }, /* mega64 */
{ { 0x1E, 0x96, 0x09 }, 0x74, 0x7F, POLL_FF }, /* mega644 (mega16 devcode) */
{ { 0x1E, 0x96, 0x0A }, 0x74, 0x7F, POLL_FF }, /* mega644p (mega16 devcode) */
{ { 0x1E, 0x97, 0x01 }, 0x41, 0x7F, POLL_7F | POLL_80 | POLL_FF }, /* mega103 */
{ { 0x1E, 0x97, 0x02 }, 0x43, 0x7F, POLL_FF }, /* mega128 */
};
/* sorted devcodes from devices[], terminated with 0x00 */
static uint8_t devcodes[] PROGMEM = { 0x13, 0x20, 0x38, 0x41, 0x43, 0x45, 0x5E, 0x72, 0x74, 0x76, 0x00 };
#define EV_NONE 0
#define EV_STATE_ENTER 1
#define EV_BUTTON_PRESSED 2
#define EV_BUTTON_RELEASED 3
#define EV_TIMEOUT 4
#define STATE_IDLE 0 /* nothing */
#define STATE_PRESSED 1 /* reset_in pressed, generating 50ms isp_reset pulse */
#define STATE_PRESSED2 2 /* reset_in still pressed, isp_reset pulse complete */
#define STATE_SPEED1 3 /* spi speed setting 1 */
#define STATE_SPEED2 4
#define STATE_SPEED3 5
#define STATE_SPEED4 6
#define LED_OFF 0x00
#define LED_SLOW 0x20
#define LED_FAST 0x08
#define LED_ON 0x80
#define LED_SPEED1 0x20
#define LED_SPEED2 0x10
#define LED_SPEED3 0x08
#define LED_SPEED4 0x04
#define CMD_PROG_ENABLE_1 0xAC #define CMD_PROG_ENABLE_1 0xAC
#define CMD_PROG_ENABLE_2 0x53 #define CMD_PROG_ENABLE_2 0x53
@ -95,16 +165,11 @@ struct {
#define CMD_WRITE_FUSE_E_1 0xAC /* not used */ #define CMD_WRITE_FUSE_E_1 0xAC /* not used */
#define CMD_WRITE_FUSE_E_2 0xA4 /* not used */ #define CMD_WRITE_FUSE_E_2 0xA4 /* not used */
static uint16_t lastaddr; static volatile uint8_t led_mode;
static uint8_t lastcmd;
static uint8_t lastval;
static uint8_t pollcode = 0xFF;
/* toggle LED */ static uint8_t last_cmd;
ISR(SIG_OUTPUT_COMPARE1A) static uint8_t last_val;
{ static uint16_t last_addr;
PORTB ^= (1<<ISP_LED);
}
/* Send one byte to PC */ /* Send one byte to PC */
static void ser_send(uint8_t data) static void ser_send(uint8_t data)
@ -120,12 +185,6 @@ static uint8_t ser_recv(void)
return UDR; return UDR;
} }
/* Check if receiver ready */
static uint8_t ser_recv_ready(void)
{
return bit_is_set(UCSRA, RXC);
}
/* Send one byte to target, and return received one */ /* Send one byte to target, and return received one */
static uint8_t spi_rxtx(uint8_t val) static uint8_t spi_rxtx(uint8_t val)
{ {
@ -134,35 +193,6 @@ static uint8_t spi_rxtx(uint8_t val)
return SPDR; return SPDR;
} }
/* Set LED mode */
static void led_mode(uint8_t mode)
{
static uint8_t oldmode = LED_OFF;
if (mode == oldmode) {
return;
} else if (mode == LED_ON) {
TCCR1B = 0x00;
PORTB &= ~(1<<ISP_LED);
} else if (mode == LED_OFF) {
TCCR1B = 0x00;
PORTB |= (1<<ISP_LED);
} else if (mode == LED_FAST) {
/* timer1: F_CPU /64, CTC mode via OutputCompare A, 10Hz */
OCR1A = (F_CPU / (64 * 10));
TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10);
} else if (mode == LED_SLOW) {
/* timer1: FCPU /64, CTC mode via OutputCompare A, 4Hz */
OCR1A = (F_CPU / (64 * 4));
TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10);
}
oldmode = mode;
}
/* Control reset and SPI lines */ /* Control reset and SPI lines */
static void set_reset(uint8_t mode) static void set_reset(uint8_t mode)
{ {
@ -176,9 +206,6 @@ static void set_reset(uint8_t mode)
DDRB |= ((1<<ISP_SCK) | (1<<ISP_MOSI) | (1<<ISP_RESET)); DDRB |= ((1<<ISP_SCK) | (1<<ISP_MOSI) | (1<<ISP_RESET));
PORTB &= ~(1<<ISP_RESET); PORTB &= ~(1<<ISP_RESET);
} }
_delay_ms(25);
_delay_ms(25);
} }
/* writes a byte to target flash/eeprom */ /* writes a byte to target flash/eeprom */
@ -190,9 +217,9 @@ static void mem_write(uint8_t cmd, uint16_t addr, uint8_t val)
spi_rxtx(val); spi_rxtx(val);
/* remember values for polling */ /* remember values for polling */
lastcmd = cmd; last_cmd = cmd;
lastaddr = addr; last_addr = addr;
lastval = val; last_val = val;
} }
/* read a byte from target flash/eeprom */ /* read a byte from target flash/eeprom */
@ -209,94 +236,84 @@ static void poll(void)
{ {
uint8_t cmd, val, poll = 0xFF; uint8_t cmd, val, poll = 0xFF;
if (lastcmd == CMD_WRITE_EEPROM) { if (((last_val == 0x00) && (device.flags & POLL_00)) ||
/* check if we can poll */ ((last_val == 0x7F) && (device.flags & POLL_7F)) ||
if (lastval == pollcode || lastval == 0x7F || lastval == 0x80) { ((last_val == 0x80) && (device.flags & POLL_80)) ||
/* wait default time */ ((last_val == 0xFF) && (device.flags & POLL_FF))
_delay_ms(10); ) {
return; /* wait default time */
} _delay_ms(15);
return;
}
if (last_cmd == CMD_WRITE_EEPROM) {
cmd = CMD_READ_EEPROM; cmd = CMD_READ_EEPROM;
} else { } else {
/* check if we can poll */
if (lastval == pollcode) {
/* wait default time */
_delay_ms(10);
return;
}
/* CMD_WRITE_FLASH -> CMD_READ_FLASH */ /* CMD_WRITE_FLASH -> CMD_READ_FLASH */
cmd = (lastcmd & 0x08) | 0x20; cmd = (last_cmd & 0x08) | 0x20;
} }
/* poll until we get correct value */ /* poll until we get correct value */
do { do {
val = mem_read(cmd, lastaddr); val = mem_read(cmd, last_addr);
} while ((val != lastval) && poll--); } while ((val != last_val) && poll--);
} }
int main(void)
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)
{ {
static uint8_t page_buf[256]; static uint8_t page_buf[256];
uint16_t addr = 0; uint16_t addr = 0;
uint8_t device = 0, pagemask = 0;
/* ISP_RESET and ISP_LED are outputs, pullup SlaveSelect */
PORTB = (1<<ISP_RESET) | (1<<ISP_LED) | (1<<PORTB4);
DDRB = (1<<ISP_RESET) | (1<<ISP_LED);
/* Set baud rate */
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
/* enable usart with 8n1 */
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
/* enable SPI master mode */
SPCR = SPI_MODE;
/* enable timer1 OutputCompare A interrupt (CTC hit) */
TIMSK = (1<<OCIE1A);
sei();
/* disable ISP_RESET */ /* disable ISP_RESET */
set_reset(1); set_reset(1);
while (1) { while (1) {
uint8_t pulse = 0;
while (!ser_recv_ready()) {
/* reset the target */
if (PIND & (1<<RESET_IN)) {
if (!pulse) {
led_mode(LED_ON);
set_reset(0);
set_reset(1);
led_mode(LED_OFF);
pulse = 1;
}
} else {
pulse = 0;
}
}
switch (ser_recv()) { switch (ser_recv()) {
/* Enter programming mode */ /* Enter programming mode */
case 'P': { case 'P': {
uint8_t sync, count = 0x20; uint8_t sync, count = 0x20;
led_mode(LED_ON); led_mode = LED_ON;
do { do {
set_reset(1); set_reset(1);
_delay_ms(50);
set_reset(0); set_reset(0);
_delay_ms(50);
spi_rxtx(CMD_PROG_ENABLE_1); spi_rxtx(CMD_PROG_ENABLE_1);
spi_rxtx(CMD_PROG_ENABLE_2); spi_rxtx(CMD_PROG_ENABLE_2);
sync = spi_rxtx(0x00); sync = spi_rxtx(0x00);
spi_rxtx(0x00); spi_rxtx(0x00);
} while (sync != 0x53 && count--); } while (sync != CMD_PROG_ENABLE_2 && count--);
memset(&device, 0x00, sizeof(struct _device));
if (sync == CMD_PROG_ENABLE_2) {
uint8_t i, sig[3];
for (i = 0; i < 3; i++) {
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(sig, devices[i].sig, sizeof(sig)) == 0) {
memcpy_P(&device, &devices[i], sizeof(struct _device));
break;
}
}
}
ser_send('\r'); ser_send('\r');
break; break;
@ -316,24 +333,26 @@ int main(void)
/* Write program memory, low byte */ /* Write program memory, low byte */
case 'c': case 'c':
led_mode(LED_FAST); led_mode = LED_FAST;
mem_write(CMD_LOAD_FLASH_LO, addr, ser_recv()); mem_write(CMD_LOAD_FLASH_LO, addr, ser_recv());
/* poll on byte addressed targets */ /* poll on byte addressed targets */
if (!pagemask) if (device.pagemask == 0x00) {
poll(); poll();
}
ser_send('\r'); ser_send('\r');
break; break;
/* Write program memory, high byte */ /* Write program memory, high byte */
case 'C': case 'C':
led_mode(LED_FAST); led_mode = LED_FAST;
mem_write(CMD_LOAD_FLASH_HI, addr, ser_recv()); mem_write(CMD_LOAD_FLASH_HI, addr, ser_recv());
/* poll on byte addressed targets */ /* poll on byte addressed targets */
if (!pagemask) if (device.pagemask == 0x00) {
poll(); poll();
}
addr++; addr++;
ser_send('\r'); ser_send('\r');
@ -341,14 +360,8 @@ int main(void)
/* Issue Page Write */ /* Issue Page Write */
case 'm': case 'm':
led_mode(LED_FAST); led_mode = LED_FAST;
spi_rxtx(CMD_WRITE_FLASH_PAGE); mem_pagewrite(last_addr);
spi_rxtx(lastaddr >> 8);
spi_rxtx(lastaddr & 0xFF);
spi_rxtx(0x00);
poll();
ser_send('\r'); ser_send('\r');
break; break;
@ -360,7 +373,7 @@ int main(void)
/* Read program memory */ /* Read program memory */
case 'R': case 'R':
led_mode(LED_SLOW); led_mode = LED_SLOW;
ser_send(mem_read(CMD_READ_FLASH_HI, addr)); ser_send(mem_read(CMD_READ_FLASH_HI, addr));
ser_send(mem_read(CMD_READ_FLASH_LO, addr)); ser_send(mem_read(CMD_READ_FLASH_LO, addr));
addr++; addr++;
@ -368,14 +381,14 @@ int main(void)
/* Read data memory */ /* Read data memory */
case 'd': case 'd':
led_mode(LED_SLOW); led_mode = LED_SLOW;
ser_send(mem_read(CMD_READ_EEPROM, addr)); ser_send(mem_read(CMD_READ_EEPROM, addr));
addr++; addr++;
break; break;
/* Write data memory */ /* Write data memory */
case 'D': case 'D':
led_mode(LED_FAST); led_mode = LED_FAST;
mem_write(CMD_WRITE_EEPROM, addr, ser_recv()); mem_write(CMD_WRITE_EEPROM, addr, ser_recv());
poll(); poll();
@ -390,7 +403,7 @@ int main(void)
spi_rxtx(0x00); spi_rxtx(0x00);
spi_rxtx(0x00); spi_rxtx(0x00);
_delay_ms(25); _delay_ms(10);
ser_send('\r'); ser_send('\r');
break; break;
@ -402,7 +415,7 @@ int main(void)
spi_rxtx(0x00); spi_rxtx(0x00);
spi_rxtx(val); spi_rxtx(val);
_delay_ms(25); _delay_ms(10);
ser_send('\r'); ser_send('\r');
break; break;
} }
@ -428,25 +441,13 @@ int main(void)
/* Exit Bootloader */ /* Exit Bootloader */
case 'E': case 'E':
set_reset(1); set_reset(1);
led_mode(LED_OFF); led_mode = LED_OFF;
ser_send('\r'); ser_send('\r');
break; break;
/* Select device type */ /* Select device type */
case 'T': { case 'T': {
uint8_t val, i = 0; ser_recv(); // ignore
val = ser_recv();
do {
if (val == devices[i].id) {
device = val;
pagemask = devices[i].pagemask;
pollcode = devices[i].pollcode;
break;
}
} while (devices[i++].id);
ser_send('\r'); ser_send('\r');
break; break;
} }
@ -455,18 +456,17 @@ int main(void)
case 's': { case 's': {
uint8_t i = 2; uint8_t i = 2;
do { do {
ser_send(mem_read(CMD_READ_SIG_1, (CMD_READ_SIG_2 << 8) | i)); ser_send(device.sig[i]);
} while (i--); } while (i--);
break; break;
} }
/* Return supported device codes */ /* Return supported device codes */
case 't': { case 't': {
uint8_t val, i = 0; uint8_t i;
do { for (i = 0; i < ARRAY_SIZE(devcodes); i++) {
val = devices[i++].id; ser_send(pgm_read_byte(&devcodes[i]));
ser_send(val); }
} while (val);
break; break;
} }
@ -501,28 +501,29 @@ int main(void)
/* Set LED */ /* Set LED */
case 'x': case 'x':
ser_recv(); ser_recv();
led_mode(LED_ON); led_mode = LED_ON;
break; break;
/* Clear LED */ /* Clear LED */
case 'y': case 'y':
ser_recv(); ser_recv();
led_mode(LED_OFF); led_mode = LED_OFF;
break; break;
/* Report Block write Mode */ /* Report Block write Mode */
case 'b': case 'b': {
ser_send('Y'); ser_send('Y');
ser_send(sizeof(page_buf) >> 8); ser_send(sizeof(page_buf) >> 8);
ser_send(sizeof(page_buf) & 0xFF); ser_send(sizeof(page_buf) & 0xFF);
break; break;
}
/* Block Write */ /* Block Write */
case 'B': { case 'B': {
uint16_t size, i; uint16_t size, i;
uint8_t type; uint8_t type;
led_mode(LED_FAST); led_mode = LED_FAST;
size = ser_recv() << 8; size = ser_recv() << 8;
size |= ser_recv(); size |= ser_recv();
@ -538,25 +539,13 @@ int main(void)
addr++; addr++;
/* page write on page-boundry */ if ((addr & device.pagemask) == 0x00) {
if ((addr & pagemask) == 0x00) { mem_pagewrite(last_addr);
spi_rxtx(CMD_WRITE_FLASH_PAGE);
spi_rxtx(lastaddr >> 8);
spi_rxtx(lastaddr & 0xFF);
spi_rxtx(0x00);
poll();
} }
} }
/* last page */
if (size != sizeof(page_buf)) { if (size != sizeof(page_buf)) {
spi_rxtx(CMD_WRITE_FLASH_PAGE); mem_pagewrite(last_addr);
spi_rxtx(lastaddr >> 8);
spi_rxtx(lastaddr & 0xFF);
spi_rxtx(0x00);
poll();
} }
} else if (type == 'E') { } else if (type == 'E') {
@ -575,7 +564,7 @@ int main(void)
uint16_t size, i; uint16_t size, i;
uint8_t type; uint8_t type;
led_mode(LED_SLOW); led_mode = LED_SLOW;
size = ser_recv() << 8; size = ser_recv() << 8;
size |= ser_recv(); size |= ser_recv();
@ -605,7 +594,7 @@ int main(void)
spi_rxtx(0x00); spi_rxtx(0x00);
spi_rxtx(val); spi_rxtx(val);
_delay_ms(25); _delay_ms(10);
ser_send('\r'); ser_send('\r');
break; break;
} }
@ -621,7 +610,7 @@ int main(void)
spi_rxtx(val[1]); spi_rxtx(val[1]);
ser_send(spi_rxtx(val[2])); ser_send(spi_rxtx(val[2]));
_delay_ms(25); _delay_ms(10);
ser_send('\r'); ser_send('\r');
break; break;
} }
@ -639,7 +628,7 @@ int main(void)
spi_rxtx(val[2]); spi_rxtx(val[2]);
ser_send(spi_rxtx(val[3])); ser_send(spi_rxtx(val[3]));
_delay_ms(25); _delay_ms(10);
ser_send('\r'); ser_send('\r');
break; break;
} }
@ -653,5 +642,219 @@ int main(void)
break; break;
} }
} }
}
static uint16_t 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_IDLE;
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_IDLE;
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_IDLE;
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_IDLE;
SPCR = SPI_MODE4;
}
break;
default:
state = STATE_IDLE;
break;
}
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<<RESET_IN)) {
if (!prev_pressed) {
event = EV_BUTTON_PRESSED;
prev_pressed = 1;
}
} else {
if (prev_pressed) {
event = EV_BUTTON_RELEASED;
prev_pressed = 0;
}
}
static uint16_t timer;
if (timer) {
timer--;
if (timer == 0) {
event = EV_TIMEOUT;
}
}
if (event != EV_NONE) {
uint16_t new_timer = statemachine(event);
if (new_timer == 0xFFFF) {
timer = 0;
} else if (new_timer > 0) {
timer = new_timer;
}
}
/* update LED */
static uint8_t led_timer;
if (led_mode & ((led_timer++ & 0xFF) | 0x80)) {
PORTB &= ~(1<<ISP_LED);
} else {
PORTB |= (1<<ISP_LED);
}
}
int main(void)
{
/* ISP_RESET and ISP_LED are outputs, pullup SlaveSelect */
PORTB = (1<<ISP_RESET) | (1<<ISP_LED) | (1<<PORTB4);
DDRB = (1<<ISP_RESET) | (1<<ISP_LED);
/* Set baud rate */
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
/* enable usart with 8n1 */
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
/* enable SPI master mode */
SPCR = SPI_MODE4;
/* timer0, FCPU/1024, overflow interrupt */
TCCR0 = (1<<CS02) | (1<<CS00);
TIMSK = (1<<TOIE0);
sei();
cmdloop();
return 0; return 0;
} }