2011-06-25 16:19:18 +02:00
|
|
|
/***************************************************************************
|
|
|
|
* C based avr910 / avr109 ISP Adapter *
|
|
|
|
* *
|
2019-12-31 17:12:58 +01:00
|
|
|
* Copyright (C) 2006 - 2020 by Olaf Rempel *
|
2011-06-25 16:19:18 +02:00
|
|
|
* 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 <avr/io.h>
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2019-12-30 20:26:58 +01:00
|
|
|
#include "avrdevice.h"
|
2020-01-08 22:55:25 +01:00
|
|
|
#include "display.h"
|
2020-01-08 23:34:44 +01:00
|
|
|
#include "spi_isp.h"
|
2020-01-12 18:12:49 +01:00
|
|
|
#include "target.h"
|
2020-01-13 22:18:33 +01:00
|
|
|
#include "twi_master.h"
|
2019-12-30 21:27:47 +01:00
|
|
|
#include "uart.h"
|
2020-01-12 18:12:49 +01:00
|
|
|
|
2020-01-13 22:18:33 +01:00
|
|
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
|
|
|
|
2020-01-12 19:16:07 +01:00
|
|
|
#define TIMER_IRQFREQ_MS 10
|
|
|
|
|
|
|
|
/* convert milliseconds to timer ticks */
|
|
|
|
#define TIMER_MSEC2TICKS(x) ((x * F_CPU) / (TIMER_DIVISOR * 1000ULL))
|
|
|
|
#define TIMER_MSEC2IRQCNT(x) (x / TIMER_IRQFREQ_MS)
|
|
|
|
|
2014-10-14 21:56:16 +02:00
|
|
|
#define EV_NONE 0x00
|
|
|
|
#define EV_STATE_ENTER 0x01
|
|
|
|
#define EV_BUTTON_PRESSED 0x02
|
2020-01-08 23:46:19 +01:00
|
|
|
#define EV_BUTTON_RELEASED 0x04
|
|
|
|
#define EV_TIMEOUT 0x08
|
|
|
|
#define EV_PROG_ENTER 0x10
|
|
|
|
#define EV_PROG_LEAVE 0x20
|
2020-01-13 22:18:33 +01:00
|
|
|
#define EV_PROG_ENTER_TWI 0x40
|
2014-10-14 21:56:16 +02:00
|
|
|
|
|
|
|
#define STATE_IDLE 0x00 /* nothing */
|
|
|
|
#define STATE_RESET_SYNC 0x01
|
|
|
|
#define STATE_RESET_RETRY 0x02
|
|
|
|
#define STATE_RESET_PROGMODE 0x03
|
2020-01-13 22:18:33 +01:00
|
|
|
#define STATE_TWI_CHECK_BL 0x04
|
|
|
|
#define STATE_TWI_PROGMODE 0x05
|
2012-11-18 13:12:27 +01:00
|
|
|
|
|
|
|
#define LED_OFF 0x00
|
|
|
|
#define LED_SLOW 0x20
|
|
|
|
#define LED_FAST 0x08
|
|
|
|
#define LED_ON 0x80
|
2008-03-27 20:06:02 +01:00
|
|
|
|
2012-02-19 12:54:54 +01:00
|
|
|
|
2020-01-08 23:46:19 +01:00
|
|
|
static volatile uint8_t m_led_mode = LED_OFF;
|
|
|
|
static volatile uint8_t m_reset_timer;
|
|
|
|
static volatile uint8_t m_events;
|
|
|
|
static uint8_t m_state;
|
2008-03-27 20:06:02 +01:00
|
|
|
|
2020-01-08 23:34:44 +01:00
|
|
|
static uint8_t m_page_buf[256];
|
2019-12-30 20:26:58 +01:00
|
|
|
static avr_device_t m_device;
|
2020-01-08 23:34:44 +01:00
|
|
|
static uint16_t m_address = 0x0000;
|
2014-10-16 21:29:43 +02:00
|
|
|
|
2020-01-13 22:18:33 +01:00
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
static twi_chipinfo_t m_twi_chipinfo;
|
|
|
|
static uint8_t m_twi_address;
|
|
|
|
#endif /* (USE_TWI_SUPPORT) */
|
|
|
|
|
2006-05-06 22:55:42 +02:00
|
|
|
|
2020-01-08 23:46:19 +01:00
|
|
|
static void reset_statemachine(uint8_t events)
|
|
|
|
{
|
|
|
|
static uint8_t reset_retries;
|
|
|
|
static uint8_t reset_cause;
|
|
|
|
|
|
|
|
uint8_t oldstate;
|
|
|
|
uint8_t timer;
|
|
|
|
|
|
|
|
/* shortcut: there is nothing to do */
|
|
|
|
if ((events == EV_NONE) &&
|
|
|
|
(m_events == EV_NONE)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cli();
|
|
|
|
/* get button/timer events */
|
|
|
|
events |= m_events;
|
|
|
|
m_events = 0x00;
|
|
|
|
|
|
|
|
/* disable timer */
|
|
|
|
timer = m_reset_timer;
|
|
|
|
m_reset_timer = 0x0000;
|
|
|
|
sei();
|
|
|
|
|
|
|
|
do {
|
|
|
|
oldstate = m_state;
|
|
|
|
|
|
|
|
switch (m_state)
|
|
|
|
{
|
|
|
|
case STATE_IDLE:
|
|
|
|
if (events & EV_STATE_ENTER)
|
|
|
|
{
|
|
|
|
/* remove all events */
|
|
|
|
events = EV_NONE;
|
|
|
|
|
2020-01-12 19:16:07 +01:00
|
|
|
/* stop timer */
|
|
|
|
timer = TIMER_MSEC2IRQCNT(0);
|
2020-01-08 23:46:19 +01:00
|
|
|
|
|
|
|
spi_init(0);
|
2020-01-13 22:18:33 +01:00
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
twi_init(0);
|
|
|
|
#endif
|
2020-01-08 23:46:19 +01:00
|
|
|
/* put device in RUN mode */
|
|
|
|
RESET_INACTIVE();
|
|
|
|
m_led_mode = LED_OFF;
|
|
|
|
}
|
2020-01-13 22:18:33 +01:00
|
|
|
else if ((events & EV_PROG_ENTER) ||
|
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
((events & EV_BUTTON_PRESSED) && (m_twi_address == 0x00))
|
|
|
|
#else
|
|
|
|
(events & EV_BUTTON_PRESSED)
|
|
|
|
#endif /* (USE_TWI_SUPPORT) */
|
|
|
|
)
|
2020-01-08 23:46:19 +01:00
|
|
|
{
|
|
|
|
reset_cause = events;
|
|
|
|
events &= ~(EV_BUTTON_PRESSED | EV_PROG_ENTER);
|
|
|
|
|
|
|
|
reset_retries = 5;
|
|
|
|
|
|
|
|
/* enable SPI interface */
|
|
|
|
spi_init(1);
|
|
|
|
|
|
|
|
m_state = STATE_RESET_SYNC;
|
|
|
|
}
|
2020-01-13 22:18:33 +01:00
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
else if ((events & EV_PROG_ENTER_TWI) ||
|
|
|
|
((events & EV_BUTTON_PRESSED) && (m_twi_address != 0x00))
|
|
|
|
)
|
|
|
|
{
|
|
|
|
uint8_t result;
|
|
|
|
|
|
|
|
reset_cause = events;
|
|
|
|
events &= ~(EV_BUTTON_PRESSED | EV_PROG_ENTER_TWI);
|
|
|
|
|
|
|
|
reset_retries = 5;
|
|
|
|
|
|
|
|
twi_init(1);
|
|
|
|
result = twi_switch_application(m_twi_address, BOOTTYPE_BOOTLOADER);
|
2020-01-26 00:24:20 +01:00
|
|
|
if (result == TWI_NACK_ADDR)
|
2020-01-13 22:18:33 +01:00
|
|
|
{
|
|
|
|
/* no response from target, do normal reset */
|
|
|
|
RESET_ACTIVE();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_state = STATE_TWI_CHECK_BL;
|
|
|
|
}
|
|
|
|
#endif /* (USE_TWI_SUPPORT) */
|
2020-01-08 23:46:19 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case STATE_RESET_SYNC:
|
|
|
|
if (events & EV_STATE_ENTER)
|
|
|
|
{
|
|
|
|
events &= ~(EV_STATE_ENTER);
|
|
|
|
|
2020-01-12 19:16:07 +01:00
|
|
|
timer = TIMER_MSEC2IRQCNT(10);
|
2020-01-08 23:46:19 +01:00
|
|
|
|
|
|
|
/* put device in ISP mode */
|
|
|
|
RESET_ACTIVE();
|
|
|
|
m_led_mode = LED_ON;
|
|
|
|
}
|
|
|
|
else if (events & EV_TIMEOUT)
|
|
|
|
{
|
|
|
|
events &= ~(EV_TIMEOUT);
|
|
|
|
|
|
|
|
memset(&m_device, 0x00, sizeof(avr_device_t));
|
|
|
|
|
|
|
|
if (isp_enter_progmode())
|
|
|
|
{
|
|
|
|
isp_read_signature(m_device.sig);
|
|
|
|
avrdevice_get_by_signature(&m_device, m_device.sig);
|
|
|
|
|
|
|
|
m_state = STATE_RESET_PROGMODE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_state = STATE_RESET_RETRY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STATE_RESET_RETRY:
|
|
|
|
if (events & EV_STATE_ENTER)
|
|
|
|
{
|
|
|
|
events &= ~(EV_STATE_ENTER);
|
|
|
|
|
2020-01-12 19:16:07 +01:00
|
|
|
timer = TIMER_MSEC2IRQCNT(50);
|
2020-01-08 23:46:19 +01:00
|
|
|
|
|
|
|
/* put device in RUN mode */
|
|
|
|
RESET_INACTIVE();
|
|
|
|
m_led_mode = LED_OFF;
|
|
|
|
}
|
|
|
|
else if (events & EV_TIMEOUT)
|
|
|
|
{
|
|
|
|
events &= ~(EV_TIMEOUT);
|
|
|
|
|
|
|
|
reset_retries--;
|
|
|
|
if (reset_retries > 0)
|
|
|
|
{
|
|
|
|
/* try lower frequency */
|
|
|
|
spi_set_clk(SPI_SET_CLK_DEC);
|
|
|
|
|
|
|
|
m_state = STATE_RESET_SYNC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* got no sync */
|
|
|
|
m_state = STATE_IDLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STATE_RESET_PROGMODE:
|
|
|
|
if (events & EV_STATE_ENTER)
|
|
|
|
{
|
|
|
|
events &= ~(EV_STATE_ENTER);
|
|
|
|
|
2020-01-12 22:46:30 +01:00
|
|
|
if (reset_cause == EV_BUTTON_PRESSED)
|
2020-01-08 23:46:19 +01:00
|
|
|
{
|
|
|
|
m_state = STATE_IDLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (events & (EV_PROG_LEAVE | EV_BUTTON_PRESSED))
|
|
|
|
{
|
|
|
|
events &= ~(EV_PROG_LEAVE | EV_BUTTON_PRESSED);
|
|
|
|
|
|
|
|
m_state = STATE_IDLE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-01-13 22:18:33 +01:00
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
case STATE_TWI_CHECK_BL:
|
|
|
|
if (events & EV_STATE_ENTER)
|
|
|
|
{
|
|
|
|
events &= ~(EV_STATE_ENTER);
|
|
|
|
|
|
|
|
timer = TIMER_MSEC2IRQCNT(10);
|
|
|
|
}
|
|
|
|
else if (events & EV_TIMEOUT)
|
|
|
|
{
|
|
|
|
uint8_t result;
|
|
|
|
|
|
|
|
events &= ~(EV_TIMEOUT);
|
|
|
|
|
|
|
|
/* put target in RUN mode */
|
|
|
|
RESET_INACTIVE();
|
|
|
|
m_led_mode = LED_ON;
|
|
|
|
|
|
|
|
result = twi_read_chipinfo(m_twi_address, &m_twi_chipinfo);
|
|
|
|
if (result == TWI_SUCCESS)
|
|
|
|
{
|
|
|
|
#if (USE_DISPLAY)
|
|
|
|
char twi_version[16 +1];
|
|
|
|
|
|
|
|
twi_read_version(m_twi_address, twi_version,
|
|
|
|
sizeof(twi_version) -1);
|
|
|
|
twi_version[16] = '\0';
|
|
|
|
|
|
|
|
display_show_string(twi_version, 0);
|
|
|
|
|
|
|
|
avrdevice_get_by_signature(&m_device, m_twi_chipinfo.sig);
|
|
|
|
if (m_device.name[0] != '\0')
|
|
|
|
{
|
|
|
|
display_show_string(" ", 1);
|
|
|
|
display_show_string(m_device.name, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
display_show_string(" 0X", 1);
|
|
|
|
display_show_hex(m_twi_chipinfo.sig[0], 1);
|
|
|
|
display_show_hex(m_twi_chipinfo.sig[1], 1);
|
|
|
|
display_show_hex(m_twi_chipinfo.sig[2], 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
display_set_mode(DISPLAY_MODE_SCROLL_ONCE);
|
|
|
|
#endif /* (USE_DISPLAY) */
|
|
|
|
|
|
|
|
m_state = STATE_TWI_PROGMODE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reset_retries--;
|
|
|
|
if (reset_retries > 0)
|
|
|
|
{
|
|
|
|
timer = TIMER_MSEC2IRQCNT(10);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if (USE_DISPLAY)
|
|
|
|
display_show_string("0x", 0);
|
|
|
|
display_show_hex(m_twi_address, 1);
|
|
|
|
display_show_string(":NAK", 1);
|
|
|
|
display_set_mode(DISPLAY_MODE_SCROLL_ONCE);
|
|
|
|
#endif /* (USE_DISPLAY) */
|
|
|
|
|
|
|
|
m_state = STATE_IDLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case STATE_TWI_PROGMODE:
|
|
|
|
if (events & EV_STATE_ENTER)
|
|
|
|
{
|
|
|
|
events &= ~(EV_STATE_ENTER);
|
|
|
|
|
|
|
|
if (reset_cause == EV_BUTTON_PRESSED)
|
|
|
|
{
|
|
|
|
m_state = STATE_IDLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (events & EV_PROG_LEAVE)
|
|
|
|
{
|
|
|
|
events &= ~(EV_PROG_LEAVE);
|
|
|
|
|
|
|
|
m_state = STATE_IDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_state == STATE_IDLE)
|
|
|
|
{
|
|
|
|
twi_switch_application(m_twi_address, BOOTTYPE_APPLICATION);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif /* (USE_TWI_SUPPORT) */
|
|
|
|
|
2020-01-08 23:46:19 +01:00
|
|
|
default:
|
|
|
|
m_state = STATE_IDLE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if (USE_DISPLAY)
|
|
|
|
if ((m_state == STATE_IDLE) &&
|
|
|
|
((oldstate == STATE_RESET_RETRY) ||
|
|
|
|
(oldstate == STATE_RESET_PROGMODE)
|
|
|
|
))
|
|
|
|
{
|
|
|
|
if (m_device.name[0] != '\0')
|
|
|
|
{
|
|
|
|
display_show_string(m_device.name, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
display_show_string("unknown 0X", 0);
|
|
|
|
display_show_hex(m_device.sig[0], 1);
|
|
|
|
display_show_hex(m_device.sig[1], 1);
|
|
|
|
display_show_hex(m_device.sig[2], 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
display_set_mode(DISPLAY_MODE_SCROLL_ONCE);
|
|
|
|
}
|
|
|
|
#endif /* (USE_DISPLAY) */
|
|
|
|
|
|
|
|
if (oldstate != m_state)
|
|
|
|
{
|
|
|
|
events |= EV_STATE_ENTER;
|
|
|
|
}
|
|
|
|
} while (oldstate != m_state);
|
|
|
|
|
|
|
|
cli();
|
|
|
|
/* start timer again */
|
|
|
|
m_reset_timer = timer;
|
|
|
|
sei();
|
|
|
|
} /* reset_statemachine */
|
|
|
|
|
|
|
|
|
|
|
|
static void reset_statemachine_wait(uint8_t events)
|
|
|
|
{
|
|
|
|
reset_statemachine(events);
|
|
|
|
|
|
|
|
/* wait while timer is running or timer elapsed */
|
|
|
|
while (m_reset_timer || m_events)
|
|
|
|
{
|
|
|
|
reset_statemachine(EV_NONE);
|
|
|
|
}
|
|
|
|
} /* reset_statemachine_wait */
|
2014-10-14 21:56:16 +02:00
|
|
|
|
2014-10-16 21:29:43 +02:00
|
|
|
|
2020-01-09 00:06:29 +01:00
|
|
|
static void cmd_handler_isp(uint8_t cmd)
|
2011-06-25 16:19:18 +02:00
|
|
|
{
|
2020-01-09 00:06:29 +01:00
|
|
|
switch (cmd)
|
2020-01-08 23:46:19 +01:00
|
|
|
{
|
2012-11-18 13:12:27 +01:00
|
|
|
/* Write program memory, low byte */
|
|
|
|
case 'c':
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_FAST;
|
2020-01-08 23:34:44 +01:00
|
|
|
isp_mem_write(CMD_LOAD_FLASH_LO, m_address, uart_recv());
|
2012-11-18 13:12:27 +01:00
|
|
|
|
|
|
|
/* poll on byte addressed targets */
|
2020-01-08 23:34:44 +01:00
|
|
|
if (m_device.pagemask == 0x00)
|
|
|
|
{
|
|
|
|
isp_mem_poll(&m_device);
|
2012-11-18 13:12:27 +01:00
|
|
|
}
|
|
|
|
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Write program memory, high byte */
|
|
|
|
case 'C':
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_FAST;
|
2020-01-08 23:34:44 +01:00
|
|
|
isp_mem_write(CMD_LOAD_FLASH_HI, m_address, uart_recv());
|
2012-11-18 13:12:27 +01:00
|
|
|
|
|
|
|
/* poll on byte addressed targets */
|
2020-01-08 23:34:44 +01:00
|
|
|
if (m_device.pagemask == 0x00)
|
|
|
|
{
|
|
|
|
isp_mem_poll(&m_device);
|
2012-11-18 13:12:27 +01:00
|
|
|
}
|
|
|
|
|
2020-01-08 23:34:44 +01:00
|
|
|
m_address++;
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Issue Page Write */
|
|
|
|
case 'm':
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_FAST;
|
2020-01-08 23:34:44 +01:00
|
|
|
isp_mem_pagewrite();
|
|
|
|
isp_mem_poll(&m_device);
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read Lock Bits */
|
|
|
|
case 'r':
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_mem_read(CMD_READ_LOCK_1, CMD_READ_LOCK_2 << 8));
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read program memory */
|
|
|
|
case 'R':
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_SLOW;
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_mem_read(CMD_READ_FLASH_HI, m_address));
|
|
|
|
uart_send(isp_mem_read(CMD_READ_FLASH_LO, m_address));
|
|
|
|
m_address++;
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read data memory */
|
|
|
|
case 'd':
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_SLOW;
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_mem_read(CMD_READ_EEPROM, m_address));
|
|
|
|
m_address++;
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Write data memory */
|
|
|
|
case 'D':
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_FAST;
|
2020-01-08 23:34:44 +01:00
|
|
|
isp_mem_write(CMD_WRITE_EEPROM, m_address, uart_recv());
|
|
|
|
isp_mem_poll(&m_device);
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2020-01-08 23:34:44 +01:00
|
|
|
m_address++;
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Chip erase */
|
|
|
|
case 'e':
|
2020-01-08 23:34:44 +01:00
|
|
|
isp_cmd4(CMD_CHIP_ERASE_1, CMD_CHIP_ERASE_2, 0x00, 0x00);
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Write lock bits */
|
2020-01-08 23:34:44 +01:00
|
|
|
case 'l':
|
|
|
|
isp_cmd4(CMD_WRITE_LOCK_1, CMD_WRITE_LOCK_2, 0x00, uart_recv());
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read fusebits */
|
|
|
|
case 'F':
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_mem_read(CMD_READ_FUSE_1, CMD_READ_FUSE_2 << 8));
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read high fusebits */
|
|
|
|
case 'N':
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_mem_read(CMD_READ_FUSE_H_1, CMD_READ_FUSE_H_2 << 8));
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read extended fusebits */
|
|
|
|
case 'Q':
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_mem_read(CMD_READ_FUSE_E_1, CMD_READ_FUSE_E_2 << 8));
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read signature bytes */
|
2019-12-30 21:27:47 +01:00
|
|
|
case 's':
|
|
|
|
uart_send(m_device.sig[2]);
|
|
|
|
uart_send(m_device.sig[1]);
|
|
|
|
uart_send(m_device.sig[0]);
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Block Write */
|
2020-01-08 23:34:44 +01:00
|
|
|
case 'B':
|
|
|
|
{
|
2012-11-18 13:12:27 +01:00
|
|
|
uint16_t size, i;
|
|
|
|
uint8_t type;
|
|
|
|
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_FAST;
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2019-12-30 21:27:47 +01:00
|
|
|
size = uart_recv() << 8;
|
|
|
|
size |= uart_recv();
|
|
|
|
type = uart_recv();
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2020-01-13 22:18:33 +01:00
|
|
|
size = MIN(size, sizeof(m_page_buf));
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_recv_buf(m_page_buf, size);
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2020-01-08 23:34:44 +01:00
|
|
|
if (type == 'F')
|
|
|
|
{
|
|
|
|
for (i = 0; i < size; i += 2)
|
|
|
|
{
|
|
|
|
isp_mem_write(CMD_LOAD_FLASH_LO, m_address, m_page_buf[i]);
|
|
|
|
isp_mem_write(CMD_LOAD_FLASH_HI, m_address, m_page_buf[i+1]);
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2020-01-08 23:34:44 +01:00
|
|
|
m_address++;
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2020-01-08 23:34:44 +01:00
|
|
|
if ((m_address & m_device.pagemask) == 0x00)
|
|
|
|
{
|
|
|
|
isp_mem_pagewrite();
|
|
|
|
isp_mem_poll(&m_device);
|
2012-11-18 13:12:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-30 20:26:58 +01:00
|
|
|
if ((m_device.pagemask != 0x00) &&
|
|
|
|
(size != ((m_device.pagemask +1) << 1))
|
2020-01-08 23:34:44 +01:00
|
|
|
)
|
|
|
|
{
|
|
|
|
isp_mem_pagewrite();
|
|
|
|
isp_mem_poll(&m_device);
|
2012-11-18 13:12:27 +01:00
|
|
|
}
|
2020-01-08 23:34:44 +01:00
|
|
|
}
|
|
|
|
else if (type == 'E')
|
|
|
|
{
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
isp_mem_write(CMD_WRITE_EEPROM, m_address, m_page_buf[i]);
|
|
|
|
isp_mem_poll(&m_device);
|
|
|
|
m_address++;
|
2012-11-18 13:12:27 +01:00
|
|
|
}
|
|
|
|
}
|
2020-01-08 23:34:44 +01:00
|
|
|
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Block Read */
|
2020-01-08 23:34:44 +01:00
|
|
|
case 'g':
|
|
|
|
{
|
2012-11-18 13:12:27 +01:00
|
|
|
uint16_t size, i;
|
|
|
|
uint8_t type;
|
|
|
|
|
2020-01-08 23:46:19 +01:00
|
|
|
m_led_mode = LED_SLOW;
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2019-12-30 21:27:47 +01:00
|
|
|
size = uart_recv() << 8;
|
|
|
|
size |= uart_recv();
|
|
|
|
type = uart_recv();
|
2012-11-18 13:12:27 +01:00
|
|
|
|
2020-01-08 23:34:44 +01:00
|
|
|
if (type == 'F')
|
|
|
|
{
|
|
|
|
for (i = 0; i < size; i += 2)
|
|
|
|
{
|
|
|
|
uart_send(isp_mem_read(CMD_READ_FLASH_LO, m_address));
|
|
|
|
uart_send(isp_mem_read(CMD_READ_FLASH_HI, m_address));
|
|
|
|
m_address++;
|
2012-11-18 13:12:27 +01:00
|
|
|
}
|
2020-01-08 23:34:44 +01:00
|
|
|
}
|
|
|
|
else if (type == 'E')
|
|
|
|
{
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
uart_send(isp_mem_read(CMD_READ_EEPROM, m_address));
|
|
|
|
m_address++;
|
2012-11-18 13:12:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write fusebits */
|
2020-01-08 23:34:44 +01:00
|
|
|
case 'f':
|
|
|
|
isp_cmd4(CMD_WRITE_FUSE_1, CMD_WRITE_FUSE_2, 0x00, uart_recv());
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Universial command */
|
2020-01-08 23:34:44 +01:00
|
|
|
case ':':
|
|
|
|
{
|
2012-11-18 13:12:27 +01:00
|
|
|
uint8_t val[3];
|
2019-12-30 21:27:47 +01:00
|
|
|
|
|
|
|
uart_recv_buf(val, sizeof(val));
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_cmd3(val[0], val[1], val[2]));
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* New universal command */
|
2020-01-08 23:34:44 +01:00
|
|
|
case '.':
|
|
|
|
{
|
2012-11-18 13:12:27 +01:00
|
|
|
uint8_t val[4];
|
2019-12-30 21:27:47 +01:00
|
|
|
|
|
|
|
uart_recv_buf(val, sizeof(val));
|
2020-01-08 23:34:44 +01:00
|
|
|
uart_send(isp_cmd4(val[0], val[1], val[2], val[3]));
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('\r');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2019-12-30 21:27:47 +01:00
|
|
|
uart_send('?');
|
2012-11-18 13:12:27 +01:00
|
|
|
break;
|
2020-01-09 00:06:29 +01:00
|
|
|
}
|
|
|
|
} /* cmd_handler_isp */
|
|
|
|
|
|
|
|
|
2020-01-13 22:18:33 +01:00
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
static void cmd_handler_twi(uint8_t cmd)
|
|
|
|
{
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
/* Chip erase */
|
|
|
|
case 'e':
|
|
|
|
uart_send('\r');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read signature bytes */
|
|
|
|
case 's':
|
|
|
|
uart_send(m_twi_chipinfo.sig[2]);
|
|
|
|
uart_send(m_twi_chipinfo.sig[1]);
|
|
|
|
uart_send(m_twi_chipinfo.sig[0]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Block Write */
|
|
|
|
case 'B':
|
|
|
|
{
|
|
|
|
uint16_t write_pos = 0;
|
|
|
|
uint16_t size;
|
|
|
|
uint8_t type;
|
2020-01-26 00:24:20 +01:00
|
|
|
uint8_t result = TWI_SUCCESS;
|
2020-01-13 22:18:33 +01:00
|
|
|
|
|
|
|
m_led_mode = LED_FAST;
|
|
|
|
|
|
|
|
size = uart_recv() << 8;
|
|
|
|
size |= uart_recv();
|
|
|
|
type = uart_recv();
|
|
|
|
|
|
|
|
size = MIN(size, sizeof(m_page_buf));
|
|
|
|
uart_recv_buf(m_page_buf, size);
|
|
|
|
|
|
|
|
memset(m_page_buf + size, 0xFF, sizeof(m_page_buf) - size);
|
|
|
|
|
2020-01-26 00:24:20 +01:00
|
|
|
while ((write_pos < size) &&
|
|
|
|
(result == TWI_SUCCESS)
|
|
|
|
)
|
2020-01-13 22:18:33 +01:00
|
|
|
{
|
|
|
|
if (type == 'F')
|
|
|
|
{
|
2020-01-26 00:24:20 +01:00
|
|
|
result = twi_write_memory(m_twi_address, MEMTYPE_FLASH,
|
|
|
|
(m_address << 1),
|
|
|
|
m_page_buf + write_pos,
|
|
|
|
m_twi_chipinfo.page_size);
|
2020-01-13 22:18:33 +01:00
|
|
|
|
|
|
|
/* when accessing flash, m_address is a word address */
|
|
|
|
m_address += (m_twi_chipinfo.page_size >> 1);
|
|
|
|
write_pos += m_twi_chipinfo.page_size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint8_t write_size;
|
|
|
|
|
2020-01-26 00:24:20 +01:00
|
|
|
/* one eeprom byte takes 3.5ms to programm */
|
|
|
|
write_size = MIN(size, 4);
|
2020-01-13 22:18:33 +01:00
|
|
|
|
2020-01-26 00:24:20 +01:00
|
|
|
result = twi_write_memory(m_twi_address, MEMTYPE_EEPROM,
|
|
|
|
m_address,
|
|
|
|
m_page_buf + write_pos,
|
|
|
|
write_size);
|
2020-01-13 22:18:33 +01:00
|
|
|
|
|
|
|
/* when accessing eeprom, m_address is a byte address */
|
|
|
|
m_address += write_size;
|
|
|
|
write_pos += write_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-26 00:24:20 +01:00
|
|
|
uart_send((result == TWI_SUCCESS) ? '\r' : '!');
|
2020-01-13 22:18:33 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Block Read */
|
|
|
|
case 'g':
|
|
|
|
{
|
|
|
|
uint16_t size;
|
|
|
|
uint8_t type;
|
|
|
|
|
|
|
|
m_led_mode = LED_SLOW;
|
|
|
|
|
|
|
|
size = uart_recv() << 8;
|
|
|
|
size |= uart_recv();
|
|
|
|
type = uart_recv();
|
|
|
|
|
|
|
|
size = MIN(size, sizeof(m_page_buf));
|
|
|
|
|
|
|
|
if (type == 'F')
|
|
|
|
{
|
|
|
|
twi_read_memory(m_twi_address, MEMTYPE_FLASH,
|
|
|
|
(m_address << 1),
|
|
|
|
m_page_buf, size);
|
|
|
|
|
|
|
|
m_address += (size >> 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
twi_read_memory(m_twi_address, MEMTYPE_EEPROM,
|
|
|
|
m_address,
|
|
|
|
m_page_buf, size);
|
|
|
|
|
|
|
|
m_address += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
uart_send_buf(m_page_buf, size);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
uart_send('?');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} /* cmd_handler_twi */
|
|
|
|
#endif /* (USE_TWI_SUPPORT) */
|
|
|
|
|
|
|
|
|
2020-01-09 00:06:29 +01:00
|
|
|
static void cmdloop(void) __attribute__ ((noreturn));
|
|
|
|
static void cmdloop(void)
|
|
|
|
{
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
uint8_t cmd;
|
|
|
|
|
|
|
|
if (!uart_rx_ready())
|
|
|
|
{
|
|
|
|
reset_statemachine(EV_NONE);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if (USE_DISPLAY)
|
|
|
|
if (m_state == STATE_RESET_PROGMODE)
|
|
|
|
{
|
|
|
|
uint16_t byte_address;
|
|
|
|
|
|
|
|
byte_address = (m_address << 1);
|
|
|
|
display_show_hex(byte_address >> 8, 0);
|
|
|
|
display_show_hex(byte_address & 0xFF, 1);
|
|
|
|
|
|
|
|
display_set_mode(DISPLAY_MODE_STATIC);
|
|
|
|
}
|
|
|
|
#endif /* (USE_DISPLAY) */
|
|
|
|
|
|
|
|
cmd = uart_recv();
|
|
|
|
switch (cmd)
|
|
|
|
{
|
2020-01-26 00:15:12 +01:00
|
|
|
/* Enter programming mode */
|
|
|
|
case 'P':
|
|
|
|
reset_statemachine_wait(EV_PROG_ENTER);
|
|
|
|
uart_send((m_state == STATE_RESET_PROGMODE) ? '\r' : '!');
|
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
m_twi_address = 0x00;
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
2020-01-09 00:06:29 +01:00
|
|
|
/* Autoincrement address */
|
|
|
|
case 'a':
|
|
|
|
uart_send('Y');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Set address */
|
|
|
|
case 'A':
|
|
|
|
m_address = (uart_recv() << 8);
|
|
|
|
m_address |= uart_recv();
|
|
|
|
uart_send('\r');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Leave programming mode */
|
|
|
|
case 'L':
|
|
|
|
|
|
|
|
/* Exit Bootloader */
|
|
|
|
case 'E':
|
|
|
|
reset_statemachine_wait(EV_PROG_LEAVE);
|
|
|
|
uart_send('\r');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Select device type */
|
|
|
|
case 'T':
|
|
|
|
uart_recv(); // ignore
|
|
|
|
uart_send('\r');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Return supported device codes */
|
|
|
|
case 't':
|
|
|
|
avrdevice_iterate_devcodes(uart_send);
|
|
|
|
uart_send(0x00);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Return software identifier */
|
|
|
|
case 'S':
|
|
|
|
uart_send('A');
|
|
|
|
uart_send('V');
|
|
|
|
uart_send('R');
|
|
|
|
uart_send('-');
|
|
|
|
uart_send('I');
|
|
|
|
uart_send('S');
|
|
|
|
uart_send('P');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Return software version */
|
|
|
|
case 'V':
|
|
|
|
uart_send('3');
|
|
|
|
uart_send('8');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Return hardware version */
|
|
|
|
case 'v':
|
|
|
|
uart_send('1');
|
|
|
|
uart_send('2');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Return programmer type */
|
|
|
|
case 'p':
|
|
|
|
uart_send('S');
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Set LED */
|
|
|
|
case 'x':
|
|
|
|
uart_recv();
|
|
|
|
m_led_mode = LED_ON;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Clear LED */
|
|
|
|
case 'y':
|
|
|
|
uart_recv();
|
|
|
|
m_led_mode = LED_OFF;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Report Block write Mode */
|
|
|
|
case 'b':
|
|
|
|
uart_send('Y');
|
|
|
|
uart_send(sizeof(m_page_buf) >> 8);
|
|
|
|
uart_send(sizeof(m_page_buf) & 0xFF);
|
|
|
|
break;
|
|
|
|
|
2020-01-13 22:18:33 +01:00
|
|
|
#if (USE_TWI_SUPPORT)
|
|
|
|
case 'I':
|
|
|
|
m_twi_address = uart_recv() & 0x7F;
|
|
|
|
|
|
|
|
if (m_twi_address != 0x00)
|
|
|
|
{
|
|
|
|
reset_statemachine_wait(EV_PROG_ENTER_TWI);
|
|
|
|
if (m_state == STATE_TWI_PROGMODE)
|
|
|
|
{
|
|
|
|
uart_send('\r');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uart_send('!');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uart_send('\r');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'i':
|
|
|
|
{
|
|
|
|
uint8_t twi_addr;
|
|
|
|
uint8_t write_size;
|
|
|
|
uint8_t read_size;
|
|
|
|
uint8_t result;
|
|
|
|
|
|
|
|
twi_addr = uart_recv();
|
|
|
|
write_size = uart_recv();
|
|
|
|
read_size = uart_recv();
|
|
|
|
|
|
|
|
uart_recv_buf(m_page_buf, write_size);
|
|
|
|
|
|
|
|
result = twi_generic(twi_addr,
|
|
|
|
m_page_buf, write_size,
|
|
|
|
m_page_buf, read_size);
|
|
|
|
|
|
|
|
uart_send_buf(m_page_buf, read_size);
|
|
|
|
|
|
|
|
uart_send((result == TWI_SUCCESS) ? '\r' : '!');
|
2020-01-26 00:24:20 +01:00
|
|
|
break;
|
2020-01-13 22:18:33 +01:00
|
|
|
}
|
|
|
|
#endif /* (USE_TWI_SUPPORT) */
|
|
|
|
|
2020-01-09 00:06:29 +01:00
|
|
|
/* ESC */
|
|
|
|
case 0x1B:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|