|
|
@ -21,8 +21,6 @@ |
|
|
|
#define F_CPU 8000000 |
|
|
|
#include <util/delay.h> |
|
|
|
|
|
|
|
#define USE_HEX 0 |
|
|
|
|
|
|
|
/* |
|
|
|
* attiny2313 |
|
|
|
* lfuse: 0xe4 (int rc osc, max startup time) |
|
|
@ -50,15 +48,65 @@ |
|
|
|
#define nWRITE PORTD5 |
|
|
|
#define nREAD PORTD6 |
|
|
|
|
|
|
|
#define PAGE_SIZE 64 |
|
|
|
|
|
|
|
#define BAUDRATE 115200 |
|
|
|
|
|
|
|
#define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1) |
|
|
|
|
|
|
|
#define NOP asm volatile ("nop") |
|
|
|
|
|
|
|
static uint16_t g_address; |
|
|
|
/* ************************************************************************* */ |
|
|
|
|
|
|
|
#define MSGTYPE_VERSION_REQ 0x01 /* no payload */ |
|
|
|
#define MSGTYPE_PAGESIZE_REQ 0x02 /* no payload */ |
|
|
|
#define MSGTYPE_CONFIG_REQ 0x03 /* eprom_type(1), pagesize(1), reset_polarity(1) */ |
|
|
|
#define MSGTYPE_PROGMODE_REQ 0x04 /* progmode(1) */ |
|
|
|
#define MSGTYPE_SETADDRESS_REQ 0x05 /* address(3) msb first */ |
|
|
|
#define MSGTYPE_WRITE_REQ 0x06 /* data(0-pagesize) */ |
|
|
|
#define MSGTYPE_READ_REQ 0x07 /* length(1) */ |
|
|
|
|
|
|
|
#define MSGTYPE_ERROR_RSP 0x80 /* error_code(1) */ |
|
|
|
#define MSGTYPE_VERSION_RSP 0x81 /* version(?) */ |
|
|
|
#define MSGTYPE_PAGESIZE_RSP 0x82 /* pagesize(1) */ |
|
|
|
#define MSGTYPE_CONFIG_RSP 0x83 /* no payload */ |
|
|
|
#define MSGTYPE_PROGMODE_RSP 0x84 /* no payload */ |
|
|
|
#define MSGTYPE_SETADDRESS_RSP 0x85 /* no payload */ |
|
|
|
#define MSGTYPE_WRITE_RSP 0x86 /* no payload */ |
|
|
|
#define MSGTYPE_READ_RSP 0x87 /* data(0-pagesize) */ |
|
|
|
|
|
|
|
#define SUCCESS 0x00 |
|
|
|
#define ERROR_UNKNOWN_COMMAND 0x01 /* unknown message type */ |
|
|
|
#define ERROR_NOT_SUPPORTED 0x02 /* command not supported */ |
|
|
|
#define ERROR_INVALID_MODE 0x03 /* invalid progmode */ |
|
|
|
#define ERROR_INVALID_PARAMETER 0x04 /* invalid parameter in request */ |
|
|
|
#define ERROR_INVALID_ADDRESS 0x05 /* write outside of configured region */ |
|
|
|
|
|
|
|
#define RESET_POLARITY_LOW 0x00 /* low active reset */ |
|
|
|
#define RESET_POLARITY_HIGH 0x01 /* high active reset */ |
|
|
|
|
|
|
|
#define EPROM_TYPE_2K 0x02 /* 2716 */ |
|
|
|
#define EPROM_TYPE_4K 0x04 /* 2732 */ |
|
|
|
#define EPROM_TYPE_8K 0x08 /* 2764 */ |
|
|
|
#define EPROM_TYPE_16K 0x10 /* 27128 */ |
|
|
|
#define EPROM_TYPE_32K 0x20 /* 27256 */ |
|
|
|
#define EPROM_TYPE_64K 0x40 /* 27512 */ |
|
|
|
#define EPROM_TYPE_128K 0x80 /* 27010 */ |
|
|
|
|
|
|
|
#define PROGMODE_DISABLED 0x00 /* target running, no write access to RAM */ |
|
|
|
#define PROGMODE_ENABLED 0x01 /* target reset, write access to RAM */ |
|
|
|
|
|
|
|
#define PAGESIZE_MAX 64 |
|
|
|
|
|
|
|
/* ************************************************************************* */ |
|
|
|
|
|
|
|
struct _globdata { |
|
|
|
uint32_t address_max; |
|
|
|
uint32_t address; |
|
|
|
uint8_t progmode; |
|
|
|
uint8_t pagesize; |
|
|
|
}; |
|
|
|
|
|
|
|
static const uint8_t version_str[] = "e2prog v1.00"; |
|
|
|
static struct _globdata gdata = { 0 }; |
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* send one byte to UART |
|
|
@ -80,71 +128,6 @@ static uint8_t ser_recv(void) |
|
|
|
} /* ser_recv */ |
|
|
|
|
|
|
|
|
|
|
|
#if (USE_HEX) |
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
|
static void ser_send_hexnibble(uint8_t value) |
|
|
|
{ |
|
|
|
value += (value < 0x0A) ? '0' : ('A' - 0x0A); |
|
|
|
|
|
|
|
ser_send(value); |
|
|
|
} /* ser_send_hexnibble */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
|
static void ser_send_hex(uint8_t value) |
|
|
|
{ |
|
|
|
ser_send_hexnibble(value >> 4); |
|
|
|
ser_send_hexnibble(value & 0x0F); |
|
|
|
} /* ser_send_hex */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
|
static uint8_t ascii2hexnibble(uint8_t value) |
|
|
|
{ |
|
|
|
if (value >= '0' && value <= '9') |
|
|
|
{ |
|
|
|
return (value - '0'); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
value &= ~(0x20); |
|
|
|
if (value >= 'A' && value <= 'F') |
|
|
|
{ |
|
|
|
return (value - 'A' + 0x0A); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} /* ascii2hexnibble */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
|
static uint8_t ser_recv_hex(void) |
|
|
|
{ |
|
|
|
uint8_t result; |
|
|
|
|
|
|
|
result = ascii2hexnibble(ser_recv()) << 4; |
|
|
|
result |= ascii2hexnibble(ser_recv()); |
|
|
|
|
|
|
|
return result; |
|
|
|
} /* ser_recv_hex */ |
|
|
|
|
|
|
|
#define ser_send_comm(x) ser_send_hex(x) |
|
|
|
#define ser_recv_comm() ser_recv_hex() |
|
|
|
#else |
|
|
|
#define ser_send_comm(x) ser_send(x) |
|
|
|
#define ser_recv_comm() ser_recv() |
|
|
|
#endif /* (USE_HEX) */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
@ -160,23 +143,19 @@ static void address_clear(void) |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<REGCLK); |
|
|
|
|
|
|
|
g_address = 0; |
|
|
|
gdata.address = 0; |
|
|
|
} /* address_clear */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* set address counter to value |
|
|
|
* ************************************************************************* */ |
|
|
|
static void address_set(void) |
|
|
|
static void address_set(uint16_t address) |
|
|
|
{ |
|
|
|
uint16_t count; |
|
|
|
uint16_t address; |
|
|
|
|
|
|
|
address = ser_recv_comm() << 8; |
|
|
|
address |= ser_recv_comm(); |
|
|
|
|
|
|
|
/* address already higher then target */ |
|
|
|
if (g_address > address) |
|
|
|
if (gdata.address > address) |
|
|
|
{ |
|
|
|
/* reset address counter */ |
|
|
|
PORTA &= ~(1<<nCNTRES); |
|
|
@ -187,7 +166,7 @@ static void address_set(void) |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
count = (address - g_address); |
|
|
|
count = (address - gdata.address); |
|
|
|
} |
|
|
|
|
|
|
|
/* increase address counter */ |
|
|
@ -203,10 +182,7 @@ static void address_set(void) |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<REGCLK); |
|
|
|
|
|
|
|
g_address = address; |
|
|
|
|
|
|
|
// ser_send_hex(address >> 8); |
|
|
|
// ser_send_hex(address & 0xFF); |
|
|
|
gdata.address = address; |
|
|
|
} /* address_set */ |
|
|
|
|
|
|
|
|
|
|
@ -225,25 +201,61 @@ static void address_inc(void) |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<REGCLK); |
|
|
|
|
|
|
|
g_address++; |
|
|
|
gdata.address++; |
|
|
|
} /* address_inc */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* configures max. address |
|
|
|
* ************************************************************************* */ |
|
|
|
static uint8_t set_eprom_type(uint8_t type) |
|
|
|
{ |
|
|
|
switch (type) |
|
|
|
{ |
|
|
|
case EPROM_TYPE_2K: |
|
|
|
gdata.address_max = 0x0800; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_4K: |
|
|
|
gdata.address_max = 0x1000; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_8K: |
|
|
|
gdata.address_max = 0x2000; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_16K: |
|
|
|
gdata.address_max = 0x4000; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_32K: |
|
|
|
gdata.address_max = 0x8000; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_64K: |
|
|
|
gdata.address_max = 0x10000; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return ERROR_INVALID_PARAMETER; |
|
|
|
} |
|
|
|
|
|
|
|
return SUCCESS; |
|
|
|
} /* set_eprom_type */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* read data from eeprom |
|
|
|
* ************************************************************************* */ |
|
|
|
static void data_read(void) |
|
|
|
static void data_read(uint8_t length) |
|
|
|
{ |
|
|
|
uint8_t i; |
|
|
|
uint8_t data; |
|
|
|
uint8_t count; |
|
|
|
|
|
|
|
count = ser_recv_comm(); |
|
|
|
|
|
|
|
DDRB = 0x00; |
|
|
|
PORTB = 0x00; |
|
|
|
|
|
|
|
for (i = 0; i < count; i++) |
|
|
|
for (i = 0; i < length; i++) |
|
|
|
{ |
|
|
|
PORTD &= ~((1<<nCHIPSELECT) | (1<<nREAD)); |
|
|
|
NOP; |
|
|
@ -251,8 +263,7 @@ static void data_read(void) |
|
|
|
PORTD |= (1<<nCHIPSELECT) | (1<<nREAD); |
|
|
|
|
|
|
|
address_inc(); |
|
|
|
|
|
|
|
ser_send_comm(data); |
|
|
|
ser_send(data); |
|
|
|
} |
|
|
|
} /* data_read */ |
|
|
|
|
|
|
@ -280,27 +291,20 @@ static void data_poll(uint8_t value) |
|
|
|
/* ************************************************************************* |
|
|
|
* read data to eeprom |
|
|
|
* ************************************************************************* */ |
|
|
|
static void data_write(void) |
|
|
|
static void data_write(uint8_t length) |
|
|
|
{ |
|
|
|
static uint8_t buffer[PAGE_SIZE]; |
|
|
|
static uint8_t buffer[PAGESIZE_MAX]; |
|
|
|
|
|
|
|
uint8_t i; |
|
|
|
uint8_t count; |
|
|
|
|
|
|
|
count = ser_recv_comm(); |
|
|
|
if (count > PAGE_SIZE) |
|
|
|
for (i = 0; i < length; i++) |
|
|
|
{ |
|
|
|
count = PAGE_SIZE; |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
buffer[i] = ser_recv_comm(); |
|
|
|
buffer[i] = ser_recv(); |
|
|
|
} |
|
|
|
|
|
|
|
DDRB = 0xFF; |
|
|
|
|
|
|
|
for (i = 0; i < count; i++) |
|
|
|
for (i = 0; i < length; i++) |
|
|
|
{ |
|
|
|
PORTB = buffer[i]; |
|
|
|
|
|
|
@ -309,7 +313,7 @@ static void data_write(void) |
|
|
|
PORTD |= (1<<nCHIPSELECT) | (1<<nWRITE); |
|
|
|
|
|
|
|
/* last address of page -> start polling */ |
|
|
|
if ((g_address & (sizeof(buffer) -1)) == (sizeof(buffer) -1)) |
|
|
|
if ((gdata.address & (gdata.pagesize -1)) == (gdata.pagesize -1)) |
|
|
|
{ |
|
|
|
data_poll(buffer[i]); |
|
|
|
DDRB = 0xFF; |
|
|
@ -318,6 +322,8 @@ static void data_write(void) |
|
|
|
address_inc(); |
|
|
|
} |
|
|
|
|
|
|
|
data_poll(buffer[length -1]); |
|
|
|
|
|
|
|
DDRB = 0x00; |
|
|
|
PORTB = 0x00; |
|
|
|
} /* data_write */ |
|
|
@ -351,37 +357,180 @@ int main(void) |
|
|
|
|
|
|
|
while (1) |
|
|
|
{ |
|
|
|
switch (ser_recv()) |
|
|
|
uint8_t msgtype = ser_recv(); |
|
|
|
uint8_t length = ser_recv(); |
|
|
|
uint8_t error_code = ERROR_INVALID_PARAMETER; |
|
|
|
|
|
|
|
switch (msgtype) |
|
|
|
{ |
|
|
|
case 'a': |
|
|
|
address_set(); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
case MSGTYPE_VERSION_REQ: |
|
|
|
if (length == 0x00) |
|
|
|
{ |
|
|
|
ser_send(MSGTYPE_VERSION_RSP); |
|
|
|
ser_send(sizeof(version_str) -1); |
|
|
|
|
|
|
|
const uint8_t * p_data = version_str; |
|
|
|
while (*p_data) |
|
|
|
{ |
|
|
|
ser_send(*p_data++); |
|
|
|
} |
|
|
|
|
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case MSGTYPE_PAGESIZE_REQ: |
|
|
|
if (length == 0x00) |
|
|
|
{ |
|
|
|
ser_send(MSGTYPE_PAGESIZE_RSP); |
|
|
|
ser_send(0x01); |
|
|
|
ser_send(PAGESIZE_MAX); |
|
|
|
|
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 'b': |
|
|
|
ser_send_comm(PAGE_SIZE); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
case MSGTYPE_CONFIG_REQ: |
|
|
|
if (length == 0x03) |
|
|
|
{ |
|
|
|
uint8_t eprom_type = ser_recv(); |
|
|
|
uint8_t pagesize = ser_recv(); |
|
|
|
|
|
|
|
/* reset polarity not used on this target */ |
|
|
|
ser_recv(); |
|
|
|
|
|
|
|
if (gdata.progmode == PROGMODE_ENABLED) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_MODE; |
|
|
|
} |
|
|
|
else if ((pagesize <= PAGESIZE_MAX) && |
|
|
|
(set_eprom_type(eprom_type) == SUCCESS) |
|
|
|
) |
|
|
|
{ |
|
|
|
gdata.pagesize = pagesize; |
|
|
|
|
|
|
|
ser_send(MSGTYPE_CONFIG_RSP); |
|
|
|
ser_send(0x00); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 'r': |
|
|
|
data_read(); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
case MSGTYPE_PROGMODE_REQ: |
|
|
|
if (length == 0x01) |
|
|
|
{ |
|
|
|
uint8_t progmode = ser_recv(); |
|
|
|
|
|
|
|
if (progmode <= PROGMODE_ENABLED) |
|
|
|
{ |
|
|
|
gdata.progmode = progmode; |
|
|
|
|
|
|
|
ser_send(MSGTYPE_PROGMODE_RSP); |
|
|
|
ser_send(0x00); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 'w': |
|
|
|
data_write(); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
case MSGTYPE_SETADDRESS_REQ: |
|
|
|
if (length == 0x03) |
|
|
|
{ |
|
|
|
uint32_t address; |
|
|
|
|
|
|
|
address = ser_recv(); |
|
|
|
address = (address<<8) | ser_recv(); |
|
|
|
address = (address<<8) | ser_recv(); |
|
|
|
|
|
|
|
if (address < gdata.address_max) |
|
|
|
{ |
|
|
|
if (gdata.progmode == PROGMODE_DISABLED) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_MODE; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
address_set(address); |
|
|
|
|
|
|
|
ser_send(MSGTYPE_SETADDRESS_RSP); |
|
|
|
ser_send(0x00); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case MSGTYPE_WRITE_REQ: |
|
|
|
if ((length > 0) && |
|
|
|
(length <= gdata.pagesize) |
|
|
|
) |
|
|
|
{ |
|
|
|
if ((gdata.address >= gdata.address_max) || |
|
|
|
((gdata.address + length) > gdata.address_max) |
|
|
|
) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_ADDRESS; |
|
|
|
} |
|
|
|
else if (gdata.progmode == PROGMODE_DISABLED) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_MODE; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
data_write(length); |
|
|
|
|
|
|
|
ser_send(MSGTYPE_WRITE_RSP); |
|
|
|
ser_send(0x00); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case MSGTYPE_READ_REQ: |
|
|
|
if (length == 0x01) |
|
|
|
{ |
|
|
|
uint8_t size = ser_recv(); |
|
|
|
|
|
|
|
if (size <= PAGESIZE_MAX) |
|
|
|
{ |
|
|
|
if ((gdata.address >= gdata.address_max) || |
|
|
|
((gdata.address + size) > gdata.address_max) |
|
|
|
) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_ADDRESS; |
|
|
|
} |
|
|
|
else if (gdata.progmode == PROGMODE_DISABLED) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_MODE; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
ser_send(MSGTYPE_READ_RSP); |
|
|
|
ser_send(size); |
|
|
|
|
|
|
|
data_read(size); |
|
|
|
|
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
ser_send('?'); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
error_code = ERROR_UNKNOWN_COMMAND; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (error_code != SUCCESS) |
|
|
|
{ |
|
|
|
/* read remaining request */ |
|
|
|
while (length--) |
|
|
|
{ |
|
|
|
(void)ser_recv(); |
|
|
|
} |
|
|
|
|
|
|
|
ser_send(MSGTYPE_ERROR_RSP); |
|
|
|
ser_send(0x01); |
|
|
|
ser_send(error_code); |
|
|
|
} |
|
|
|
} |
|
|
|
} /* main */ |