2015-08-25 03:41:49 +00:00
|
|
|
#include <avr/io.h>
|
|
|
|
#include <avr/wdt.h>
|
|
|
|
#include <avr/power.h>
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <LUFA/Drivers/USB/USB.h>
|
|
|
|
#include "Descriptors.h"
|
|
|
|
#include "Macros.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define BUFF_SIZE 512
|
|
|
|
#define LEDPIN 6
|
|
|
|
#define PREFIXBYTE 0x42
|
|
|
|
#define ROMSIZE 32768
|
2015-09-20 16:32:58 +00:00
|
|
|
#define EEPROM_PAGE_SIZE 64
|
|
|
|
#define EEPROM_PAGE_MASK 0xffc0
|
2015-08-25 03:41:49 +00:00
|
|
|
|
|
|
|
void SetupHardware(void);
|
|
|
|
void FatalError(void);
|
|
|
|
void ClearCommand(void);
|
|
|
|
void Echo(const char* string);
|
2015-09-20 16:32:58 +00:00
|
|
|
void WriteBlock(uint16_t startAddr, uint16_t length);
|
2015-08-25 03:41:49 +00:00
|
|
|
void ReadBlock(uint16_t startAddr, uint16_t length, bool maskROM);
|
|
|
|
void SetAddressMSB(uint8_t addr, bool maskROM);
|
2015-09-05 18:45:57 +00:00
|
|
|
uint32_t CRC32(uint8_t *buf, size_t size);
|
2015-08-25 03:41:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
void EVENT_USB_Device_Connect(void);
|
|
|
|
void EVENT_USB_Device_Disconnect(void);
|
|
|
|
void EVENT_USB_Device_ConfigurationChanged(void);
|
|
|
|
void EVENT_USB_Device_ControlRequest(void);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// LUFA CDC Class driver interface configuration and state information.
|
|
|
|
USB_ClassInfo_CDC_Device_t EETool_CDC_Interface =
|
|
|
|
{
|
|
|
|
.Config =
|
|
|
|
{
|
|
|
|
.ControlInterfaceNumber = INTERFACE_ID_CDC_CCI,
|
|
|
|
.DataINEndpoint =
|
|
|
|
{
|
|
|
|
.Address = CDC_TX_EPADDR,
|
|
|
|
.Size = CDC_TXRX_EPSIZE,
|
|
|
|
.Banks = 1,
|
|
|
|
},
|
|
|
|
.DataOUTEndpoint =
|
|
|
|
{
|
|
|
|
.Address = CDC_RX_EPADDR,
|
|
|
|
.Size = CDC_TXRX_EPSIZE,
|
|
|
|
.Banks = 1,
|
|
|
|
},
|
|
|
|
.NotificationEndpoint =
|
|
|
|
{
|
|
|
|
.Address = CDC_NOTIFICATION_EPADDR,
|
|
|
|
.Size = CDC_NOTIFICATION_EPSIZE,
|
|
|
|
.Banks = 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
CMD_NONE,
|
|
|
|
CMD_PING,
|
|
|
|
CMD_STARTRW,
|
|
|
|
CMD_READBLOCK,
|
2015-09-06 17:18:48 +00:00
|
|
|
CMD_READBLOCK_MASK,
|
2015-08-25 03:41:49 +00:00
|
|
|
CMD_WRITEBLOCK
|
|
|
|
} Command;
|
|
|
|
|
|
|
|
|
|
|
|
Command gCurrentCommand = CMD_NONE;
|
|
|
|
uint8_t gCommBuffer[BUFF_SIZE] = "";
|
|
|
|
uint16_t gCurrentAddress = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
SetupHardware();
|
|
|
|
GlobalInterruptEnable();
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
// Check for host data
|
|
|
|
uint16_t byteCount = CDC_Device_BytesReceived(&EETool_CDC_Interface);
|
|
|
|
byteCount = MIN(byteCount,BUFF_SIZE-1);
|
|
|
|
|
|
|
|
if (byteCount>BUFF_SIZE)
|
|
|
|
{
|
|
|
|
FatalError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (byteCount>0)
|
|
|
|
{
|
|
|
|
// Read all data from host
|
|
|
|
int i;
|
|
|
|
for (i=0; i<byteCount; i++)
|
|
|
|
{
|
|
|
|
int16_t value = CDC_Device_ReceiveByte(&EETool_CDC_Interface);
|
|
|
|
if (value>=0)
|
|
|
|
{
|
|
|
|
gCommBuffer[i] = (uint8_t)value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for new command
|
|
|
|
if (gCurrentCommand==CMD_NONE && gCommBuffer[0]==PREFIXBYTE)
|
|
|
|
{
|
|
|
|
gCurrentCommand = gCommBuffer[1];
|
|
|
|
|
|
|
|
// New command
|
|
|
|
switch (gCurrentCommand)
|
|
|
|
{
|
|
|
|
case CMD_PING:
|
|
|
|
{
|
|
|
|
Echo("PONG");
|
|
|
|
ClearCommand();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CMD_STARTRW:
|
|
|
|
{
|
|
|
|
gCurrentAddress = 0;
|
|
|
|
PULSEC(LEDPIN);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CMD_READBLOCK:
|
|
|
|
{
|
|
|
|
ReadBlock(gCurrentAddress,BUFF_SIZE,false);
|
|
|
|
gCurrentAddress += BUFF_SIZE;
|
2015-09-06 17:18:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CMD_READBLOCK_MASK:
|
|
|
|
{
|
|
|
|
ReadBlock(gCurrentAddress,BUFF_SIZE,true);
|
|
|
|
gCurrentAddress += BUFF_SIZE;
|
2015-08-25 03:41:49 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-09-20 16:32:58 +00:00
|
|
|
|
|
|
|
case CMD_WRITEBLOCK:
|
|
|
|
{
|
|
|
|
WriteBlock(gCurrentAddress,BUFF_SIZE);
|
|
|
|
gCurrentAddress += BUFF_SIZE;
|
|
|
|
break;
|
|
|
|
}
|
2015-08-25 03:41:49 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
FatalError();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ClearCommand();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CDC_Device_USBTask(&EETool_CDC_Interface);
|
|
|
|
USB_USBTask();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetupHardware(void)
|
|
|
|
{
|
|
|
|
// Disable watchdog if enabled by bootloader/fuses
|
|
|
|
MCUSR &= ~(1 << WDRF);
|
|
|
|
wdt_disable();
|
|
|
|
|
|
|
|
// Disable clock division
|
|
|
|
clock_prescale_set(clock_div_1);
|
|
|
|
|
|
|
|
// Configure IO pins
|
|
|
|
|
|
|
|
// Address bus, LSB
|
|
|
|
DDRB = QDDRB(0) | QDDRB(1) | QDDRB(2) | QDDRB(3) | QDDRB(4) | QDDRB(5) | QDDRB(6) | QDDRB(7);
|
|
|
|
|
|
|
|
// Address bus, MSB
|
|
|
|
DDRF = QDDRF(0) | QDDRF(1) | QDDRF(4) | QDDRF(5) | QDDRF(6) | QDDRF(7);
|
|
|
|
DDRC = QDDRC(6) | QDDRC(7); // Also LED output
|
|
|
|
|
|
|
|
// Control bits
|
|
|
|
DDRE = QDDRE(2) | QDDRE(6); // Output enable , Write Enable / Mask ROM high bit
|
|
|
|
|
|
|
|
// Initialize control signals
|
|
|
|
SETE_HI(6);
|
|
|
|
SETE_HI(2);
|
|
|
|
SETC_LO(LEDPIN);
|
|
|
|
|
|
|
|
USB_Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FatalError(void)
|
|
|
|
{
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
SETC_LO(LEDPIN);
|
|
|
|
_delay_ms(50);
|
|
|
|
SETC_HI(LEDPIN);
|
|
|
|
_delay_ms(50);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ClearCommand(void)
|
|
|
|
{
|
|
|
|
gCommBuffer[0] = 0;
|
|
|
|
gCurrentCommand = CMD_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Echo(const char* string)
|
|
|
|
{
|
|
|
|
PULSEC(LEDPIN);
|
|
|
|
|
|
|
|
CDC_Device_SendString(&EETool_CDC_Interface, string);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetAddressMSB(uint8_t addr, bool maskROM)
|
|
|
|
{
|
|
|
|
// Drives the high address lines to the specified value. These lines
|
|
|
|
// are all mixed up to get around the holes in the AVR's IO space
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETF_HI(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETF_LO(0);
|
|
|
|
}
|
|
|
|
addr>>=1;
|
|
|
|
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETF_HI(1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETF_LO(1);
|
|
|
|
}
|
|
|
|
addr>>=1;
|
|
|
|
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETF_HI(4);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETF_LO(4);
|
|
|
|
}
|
|
|
|
addr>>=1;
|
|
|
|
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETF_HI(5);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETF_LO(5);
|
|
|
|
}
|
|
|
|
addr>>=1;
|
|
|
|
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETF_HI(6);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETF_LO(6);
|
|
|
|
}
|
|
|
|
addr>>=1;
|
|
|
|
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETF_HI(7);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETF_LO(7);
|
|
|
|
}
|
|
|
|
addr>>=1;
|
|
|
|
|
|
|
|
if (maskROM)
|
|
|
|
{
|
|
|
|
SETC_HI(7); // For Mask ROM, this provides extra Vcc
|
|
|
|
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETE_HI(6);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETE_LO(6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (addr & 0x1)
|
|
|
|
{
|
|
|
|
SETC_HI(7);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SETC_LO(7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ReadBlock(uint16_t startAddr, uint16_t length, bool maskROM)
|
|
|
|
{
|
|
|
|
if (startAddr >= ROMSIZE)
|
|
|
|
{
|
|
|
|
FatalError();
|
|
|
|
}
|
|
|
|
|
|
|
|
_delay_ms(10); // Give the host a moment to set up before we flood them with data
|
|
|
|
|
|
|
|
DDRD = 0; // Data bus for input
|
|
|
|
SETE_HI(2); // Initialize Output Enable
|
|
|
|
|
|
|
|
if (!maskROM)
|
|
|
|
{
|
|
|
|
SETE_HI(6); // Write Enable to disable
|
2015-09-20 16:32:58 +00:00
|
|
|
FatalError();
|
2015-08-25 03:41:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (uint16_t i=startAddr; i<startAddr+length; i++)
|
|
|
|
{
|
|
|
|
// Drive address lines
|
|
|
|
PORTB = (uint8_t)(i & 0xff); // LSB
|
|
|
|
SetAddressMSB((uint8_t)(i>>8),maskROM);
|
|
|
|
|
|
|
|
// Show falling edge to Output Enable
|
|
|
|
SETE_LO(2);
|
|
|
|
|
|
|
|
_delay_us(1);
|
|
|
|
|
|
|
|
// Read the data byte
|
|
|
|
uint8_t data = PIND;
|
|
|
|
|
|
|
|
SETE_HI(2);
|
|
|
|
uint16_t index = i-startAddr;
|
|
|
|
if (index>=BUFF_SIZE)
|
|
|
|
{
|
|
|
|
FatalError();
|
|
|
|
}
|
|
|
|
|
|
|
|
gCommBuffer[index] = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send data to host
|
|
|
|
CDC_Device_SendData(&EETool_CDC_Interface, gCommBuffer, length);
|
2015-09-05 18:45:57 +00:00
|
|
|
|
|
|
|
// Compute a 32 bit CRC and send it
|
|
|
|
uint32_t crc = CRC32(gCommBuffer,length);
|
|
|
|
for (int i=0; i<4; i++)
|
|
|
|
{
|
|
|
|
CDC_Device_SendByte(&EETool_CDC_Interface, (uint8_t)(crc & 0xff));
|
|
|
|
crc>>=8;
|
|
|
|
}
|
2015-08-25 03:41:49 +00:00
|
|
|
_delay_ms(10);
|
|
|
|
|
|
|
|
PULSEC(LEDPIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-20 16:32:58 +00:00
|
|
|
void WriteBlock(uint16_t startAddr, uint16_t length)
|
2015-08-25 03:41:49 +00:00
|
|
|
{
|
2015-09-20 16:32:58 +00:00
|
|
|
// Configure data bus for output
|
2015-08-25 03:41:49 +00:00
|
|
|
DDRD = QDDRD(0) | QDDRD(1) | QDDRD(2) | QDDRD(3) | QDDRD(4) | QDDRD(5) | QDDRD(6) | QDDRD(7);
|
|
|
|
|
2015-09-20 16:32:58 +00:00
|
|
|
if (startAddr+length > ROMSIZE)
|
|
|
|
{
|
|
|
|
FatalError();
|
|
|
|
}
|
|
|
|
|
|
|
|
SETE_HI(2); // Force Output Enable high for writing
|
|
|
|
SETE_HI(6); // Initialize Write Enable to disabled
|
|
|
|
|
|
|
|
uint16_t pageNum = startAddr & EEPROM_PAGE_MASK;
|
|
|
|
uint16_t pageByte = 0;
|
|
|
|
|
|
|
|
// Wait for entire block from host
|
|
|
|
uint16_t byteCount = 0;
|
|
|
|
while (byteCount<BUFF_SIZE)
|
|
|
|
{
|
|
|
|
uint16_t numBytes = CDC_Device_BytesReceived(&EETool_CDC_Interface);
|
|
|
|
|
|
|
|
uint16_t i;
|
|
|
|
for (i=0; i<numBytes; i++)
|
|
|
|
{
|
|
|
|
int16_t value = CDC_Device_ReceiveByte(&EETool_CDC_Interface);
|
|
|
|
if (value>=0)
|
|
|
|
{
|
|
|
|
gCommBuffer[byteCount] = (uint8_t)value;
|
|
|
|
}
|
|
|
|
byteCount++;
|
|
|
|
if (byteCount>=BUFF_SIZE)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (byteCount>BUFF_SIZE)
|
|
|
|
{
|
|
|
|
FatalError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read all data from host
|
|
|
|
|
|
|
|
// Write data to the EEPROM
|
|
|
|
for (uint16_t i=startAddr; i<startAddr+length; i++)
|
|
|
|
{
|
|
|
|
// Drive address lines
|
|
|
|
PORTB = (uint8_t)(i & 0xff); // LSB
|
|
|
|
SetAddressMSB((uint8_t)(i>>8),false);
|
|
|
|
|
|
|
|
// Prepare read buffer
|
|
|
|
uint16_t index = i-startAddr;
|
|
|
|
if (index>=BUFF_SIZE)
|
|
|
|
{
|
|
|
|
FatalError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Drive data lines
|
|
|
|
PORTD = gCommBuffer[index];
|
|
|
|
|
|
|
|
// Show falling edge to Write Enable
|
|
|
|
SETE_LO(6);
|
|
|
|
SETE_HI(6);
|
|
|
|
|
|
|
|
_delay_ms(8); // For now, just doing "byte write" mode. Easier than page write (see below), but glacially slow
|
|
|
|
|
|
|
|
// After each EEPROM page, wait for the write to complete
|
|
|
|
// uint16_t nextPageNum = i & EEPROM_PAGE_MASK;
|
|
|
|
|
|
|
|
// pageByte++;
|
|
|
|
// if (pageByte >= EEPROM_PAGE_SIZE || pageNum != nextPageNum)
|
|
|
|
// {
|
|
|
|
// pageByte = 0;
|
|
|
|
// pageNum = nextPageNum;
|
|
|
|
// _delay_ms(8);
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
// Confirm with host that we're done
|
|
|
|
uint8_t ackByte = PREFIXBYTE;
|
|
|
|
CDC_Device_SendData(&EETool_CDC_Interface, &ackByte, 1);
|
|
|
|
|
|
|
|
PULSEC(LEDPIN);
|
2015-08-25 03:41:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-05 18:45:57 +00:00
|
|
|
uint32_t CRC32(uint8_t *buf, size_t size)
|
|
|
|
{
|
|
|
|
// This could be made faster with a table lookup, but it's plenty fast enough for our purposes
|
|
|
|
int i, j;
|
|
|
|
uint32_t byte, crc, mask;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
crc = 0xFFFFFFFF;
|
|
|
|
while (size--)
|
|
|
|
{
|
|
|
|
byte = buf[i];
|
|
|
|
crc = crc ^ byte;
|
|
|
|
for (j = 7; j >= 0; j--)
|
|
|
|
{
|
|
|
|
mask = -(crc & 1);
|
|
|
|
crc = (crc >> 1) ^ (0xEDB88320 & mask);
|
|
|
|
}
|
|
|
|
i = i + 1;
|
|
|
|
}
|
|
|
|
return ~crc;
|
|
|
|
}
|
|
|
|
|
2015-08-25 03:41:49 +00:00
|
|
|
// USB Event Handlers
|
|
|
|
void EVENT_USB_Device_Connect(void)
|
|
|
|
{
|
|
|
|
SETC_HI(LEDPIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EVENT_USB_Device_Disconnect(void)
|
|
|
|
{
|
|
|
|
SETC_LO(LEDPIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EVENT_USB_Device_ConfigurationChanged(void)
|
|
|
|
{
|
|
|
|
bool ConfigSuccess = true;
|
|
|
|
|
|
|
|
ConfigSuccess &= CDC_Device_ConfigureEndpoints(&EETool_CDC_Interface);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EVENT_USB_Device_ControlRequest(void)
|
|
|
|
{
|
|
|
|
CDC_Device_ProcessControlRequest(&EETool_CDC_Interface);
|
|
|
|
}
|