|
|
@ -0,0 +1,387 @@ |
|
|
|
/*************************************************************************** |
|
|
|
* Copyright (C) 02/2017 by Olaf Rempel * |
|
|
|
* razzor@kopf-tisch.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> |
|
|
|
|
|
|
|
#define F_CPU 8000000 |
|
|
|
#include <util/delay.h> |
|
|
|
|
|
|
|
#define USE_HEX 0 |
|
|
|
|
|
|
|
/* |
|
|
|
* attiny2313 |
|
|
|
* lfuse: 0xe4 (int rc osc, max startup time) |
|
|
|
* hfuse: 0xdf (no BOD) |
|
|
|
* efuse: 0xff (no self programming) |
|
|
|
* |
|
|
|
* PA0 -> HC590 /MRC (Counter Reset) |
|
|
|
* PB0:7 <-> D0:7 |
|
|
|
* PD0 <- RXD |
|
|
|
* PD1 -> TXD |
|
|
|
* PD2 -> HC590 CPC (Counter Clock) |
|
|
|
* PD3 -> HC590 CPR (Register Clock) |
|
|
|
* PD4 -> EEPROM /CS |
|
|
|
* PD5 -> EEPROM /WR |
|
|
|
* PD6 -> EEPROM /OE |
|
|
|
*/ |
|
|
|
|
|
|
|
#define nCNTRES PORTA0 |
|
|
|
|
|
|
|
#define RXD PORTD0 |
|
|
|
#define TXD PORTD1 |
|
|
|
#define CNTCLK PORTD2 |
|
|
|
#define REGCLK PORTD3 |
|
|
|
#define nCHIPSELECT PORTD4 |
|
|
|
#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; |
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* send one byte to UART |
|
|
|
* ************************************************************************* */ |
|
|
|
static void ser_send(uint8_t data) |
|
|
|
{ |
|
|
|
loop_until_bit_is_set(UCSRA, UDRIE); |
|
|
|
UDR = data; |
|
|
|
} /* ser_send */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* receive one byte from UART |
|
|
|
* ************************************************************************* */ |
|
|
|
static uint8_t ser_recv(void) |
|
|
|
{ |
|
|
|
loop_until_bit_is_set(UCSRA, RXC); |
|
|
|
return UDR; |
|
|
|
} /* 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) */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
|
static void address_clear(void) |
|
|
|
{ |
|
|
|
/* reset address counter */ |
|
|
|
PORTA &= ~(1<<nCNTRES); |
|
|
|
NOP; |
|
|
|
PORTA |= (1<<nCNTRES); |
|
|
|
|
|
|
|
/* clock address into register */ |
|
|
|
PORTD |= (1<<REGCLK); |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<REGCLK); |
|
|
|
|
|
|
|
g_address = 0; |
|
|
|
} /* address_clear */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* set address counter to value |
|
|
|
* ************************************************************************* */ |
|
|
|
static void address_set(void) |
|
|
|
{ |
|
|
|
uint16_t count; |
|
|
|
uint16_t address; |
|
|
|
|
|
|
|
address = ser_recv_comm() << 8; |
|
|
|
address |= ser_recv_comm(); |
|
|
|
|
|
|
|
/* address already higher then target */ |
|
|
|
if (g_address > address) |
|
|
|
{ |
|
|
|
/* reset address counter */ |
|
|
|
PORTA &= ~(1<<nCNTRES); |
|
|
|
NOP; |
|
|
|
PORTA |= (1<<nCNTRES); |
|
|
|
|
|
|
|
count = address; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
count = (address - g_address); |
|
|
|
} |
|
|
|
|
|
|
|
/* increase address counter */ |
|
|
|
while (count--) |
|
|
|
{ |
|
|
|
PORTD |= (1<<CNTCLK); |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<CNTCLK); |
|
|
|
} |
|
|
|
|
|
|
|
/* clock address into register */ |
|
|
|
PORTD |= (1<<REGCLK); |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<REGCLK); |
|
|
|
|
|
|
|
g_address = address; |
|
|
|
|
|
|
|
// ser_send_hex(address >> 8); |
|
|
|
// ser_send_hex(address & 0xFF); |
|
|
|
} /* address_set */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* increase address by one |
|
|
|
* ************************************************************************* */ |
|
|
|
static void address_inc(void) |
|
|
|
{ |
|
|
|
/* increase address counter */ |
|
|
|
PORTD |= (1<<CNTCLK); |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<CNTCLK); |
|
|
|
|
|
|
|
/* clock address into register */ |
|
|
|
PORTD |= (1<<REGCLK); |
|
|
|
NOP; |
|
|
|
PORTD &= ~(1<<REGCLK); |
|
|
|
|
|
|
|
g_address++; |
|
|
|
} /* address_inc */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* read data from eeprom |
|
|
|
* ************************************************************************* */ |
|
|
|
static void data_read(void) |
|
|
|
{ |
|
|
|
uint8_t i; |
|
|
|
uint8_t data; |
|
|
|
uint8_t count; |
|
|
|
|
|
|
|
count = ser_recv_comm(); |
|
|
|
|
|
|
|
DDRB = 0x00; |
|
|
|
PORTB = 0x00; |
|
|
|
|
|
|
|
for (i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
PORTD &= ~((1<<nCHIPSELECT) | (1<<nREAD)); |
|
|
|
NOP; |
|
|
|
data = PINB; |
|
|
|
PORTD |= (1<<nCHIPSELECT) | (1<<nREAD); |
|
|
|
|
|
|
|
address_inc(); |
|
|
|
|
|
|
|
ser_send_comm(data); |
|
|
|
} |
|
|
|
} /* data_read */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
|
static void data_poll(uint8_t value) |
|
|
|
{ |
|
|
|
uint16_t retry = 2000; |
|
|
|
uint8_t data; |
|
|
|
|
|
|
|
DDRB = 0x00; |
|
|
|
PORTB = 0x00; |
|
|
|
|
|
|
|
do { |
|
|
|
PORTD &= ~((1<<nCHIPSELECT) | (1<<nREAD)); |
|
|
|
NOP; |
|
|
|
data = PINB; |
|
|
|
PORTD |= (1<<nCHIPSELECT) | (1<<nREAD); |
|
|
|
} while (retry-- && (data != value)); |
|
|
|
} /* data_poll */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* read data to eeprom |
|
|
|
* ************************************************************************* */ |
|
|
|
static void data_write(void) |
|
|
|
{ |
|
|
|
static uint8_t buffer[PAGE_SIZE]; |
|
|
|
|
|
|
|
uint8_t i; |
|
|
|
uint8_t count; |
|
|
|
|
|
|
|
count = ser_recv_comm(); |
|
|
|
if (count > PAGE_SIZE) |
|
|
|
{ |
|
|
|
count = PAGE_SIZE; |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
buffer[i] = ser_recv_comm(); |
|
|
|
} |
|
|
|
|
|
|
|
DDRB = 0xFF; |
|
|
|
|
|
|
|
for (i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
PORTB = buffer[i]; |
|
|
|
|
|
|
|
PORTD &= ~((1<<nCHIPSELECT) | (1<<nWRITE)); |
|
|
|
NOP; |
|
|
|
PORTD |= (1<<nCHIPSELECT) | (1<<nWRITE); |
|
|
|
|
|
|
|
/* last address of page -> start polling */ |
|
|
|
if ((g_address & (sizeof(buffer) -1)) == (sizeof(buffer) -1)) |
|
|
|
{ |
|
|
|
data_poll(buffer[i]); |
|
|
|
DDRB = 0xFF; |
|
|
|
} |
|
|
|
|
|
|
|
address_inc(); |
|
|
|
} |
|
|
|
|
|
|
|
DDRB = 0x00; |
|
|
|
PORTB = 0x00; |
|
|
|
} /* data_write */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* |
|
|
|
* ************************************************************************* */ |
|
|
|
int main(void) __attribute__ ((noreturn)); |
|
|
|
int main(void) |
|
|
|
{ |
|
|
|
PORTA = (1<<nCNTRES); |
|
|
|
DDRA = (1<<nCNTRES); |
|
|
|
|
|
|
|
PORTB = 0x00; |
|
|
|
DDRB = 0x00; |
|
|
|
|
|
|
|
PORTD = (1<<RXD) | (1<<TXD) | (1<<nCHIPSELECT) | (1<<nWRITE) | (1<<nREAD); |
|
|
|
DDRD = ~(1<<RXD); |
|
|
|
|
|
|
|
/* increase rc osc frequency to reach 115200 baud */ |
|
|
|
OSCCAL = 0xCC; |
|
|
|
|
|
|
|
/* enable UART 8n1 */ |
|
|
|
UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF; |
|
|
|
UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); |
|
|
|
UCSRC = (1<<UCSZ1) | (1<<UCSZ0); |
|
|
|
UCSRB = (1<<RXEN) | (1<<TXEN); |
|
|
|
|
|
|
|
address_clear(); |
|
|
|
|
|
|
|
while (1) |
|
|
|
{ |
|
|
|
switch (ser_recv()) |
|
|
|
{ |
|
|
|
case 'a': |
|
|
|
address_set(); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
break; |
|
|
|
|
|
|
|
case 'b': |
|
|
|
ser_send_comm(PAGE_SIZE); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
break; |
|
|
|
|
|
|
|
case 'r': |
|
|
|
data_read(); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
break; |
|
|
|
|
|
|
|
case 'w': |
|
|
|
data_write(); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
ser_send('?'); |
|
|
|
ser_send('\r'); |
|
|
|
ser_send('\n'); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} /* main */ |