#include "jtag.h"
#include "uart.h"
#include "time.h"
#include "crc.h"
#include "larvorProtocol.h"
static uint16_t addrBegin;
static uint16_t addrEnd;
static uint8_t pageSize;
static void nop()
{
__asm__ __volatile__ ("nop");
}
#define JTAG_UART_TIMEOUT 1000 // 1000 ms = 1s
static unsigned char
getAddrs()
{
addrBegin = uartRead16();
addrEnd = uartRead16();
pageSize = uartRead8();
unsigned char crc = uartRead8(); unsigned char crcData = 0;
crcData = CRC16(addrBegin, crcData);
crcData = CRC16(addrEnd, crcData);
crcData = CRC8(pageSize, crcData);
if (crcData == crc) {
uartWrite(PROG_CRC_OK);
} else {
uartWrite(PROG_CRC_ERROR);
}
return (crcData == crc)?1:0;
}void
jtagWriteInstruction(uint8_t instruction)
{
jtagShiftIR();
jtagWriteIR(instruction & 0x0F);
jtagRunTestIdle();
}uint32_t
jtagWriteData(uint32_t cmd, uint8_t length)
{
uint8_t shift = 0;
uint32_t result = 0;
jtagShiftDR();
while (length > 0) {
if (length <= 8) {
result += jtagWriteDR(((cmd>>shift)&0xFF), length, 1) << shift;
break;
} else {
result += jtagWriteDR(((cmd>>shift)&0xFF), 8, 0) << shift;
}
length -= 8;
shift += 8;
}
jtagRunTestIdle();
return result;
}uint16_t
jtagWriteProgCmd(uint8_t cmdH, uint8_t cmdL)
{
return jtagWriteData((cmdH<<8) + cmdL, 15) & 0xFFFF;
}void
jtagEnteringProgramming()
{
jtagTestLogicReset();
jtagWriteInstruction(JTAG_AVR_RESET);
jtagWriteData(0x01, 1);
jtagWriteInstruction(JTAG_PROG_ENABLE);
jtagWriteData(0xA370, 16);
}void
jtagLeavingProgramming()
{
jtagWriteInstruction(JTAG_PROG_COMMANDS);
jtagWriteProgCmd(0x23, 0x00);
jtagWriteProgCmd(0x33, 0x00);
jtagWriteInstruction(JTAG_PROG_ENABLE);
jtagWriteData(0x0000, 16);
jtagWriteInstruction(JTAG_AVR_RESET);
jtagWriteData(0x00, 1);
}uint32_t
avrJtagGetDeviceId()
{
uint32_t data=0, data2;
jtagTestLogicReset();
jtagShiftIR();
jtagWriteIR(JTAG_IDCODE);
jtagRunTestIdle();
jtagShiftDR();
data = (jtagWriteDR(0, 8, 0)) & 0xFF;
data += (jtagWriteDR(0, 8, 0) << 8) & 0xFF00;
data2 = (jtagWriteDR(0, 8, 0)) & 0xFF;
data2 += (jtagWriteDR(0, 8, 1) << 8) & 0xFF00;
data += data2 << 16;
jtagTestLogicReset();
return data;
}uint32_t
avrJtagReadSignature()
{
uint32_t data=0, data2;
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x08); jtagWriteProgCmd(0x03, 0x00); jtagWriteProgCmd(0x32, 0x00);
data2 = jtagWriteProgCmd(0x33, 0x00) & 0xFF;
data += data2 << 0; jtagWriteProgCmd(0x03, 0x01); jtagWriteProgCmd(0x32, 0x00);
data2 = jtagWriteProgCmd(0x33, 0x00) & 0xFF;
data += data2 << 8; jtagWriteProgCmd(0x03, 0x02); jtagWriteProgCmd(0x32, 0x00);
data2 = jtagWriteProgCmd(0x33, 0x00) & 0xFF;
data += data2 << 16;
jtagLeavingProgramming();
return data;
}uint8_t
avrJtagReadCalibration()
{
uint8_t data;
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x08); jtagWriteProgCmd(0x03, 0x00); jtagWriteProgCmd(0x32, 0x00);
data = (jtagWriteProgCmd(0x33, 0x00) & 0xFF);
jtagLeavingProgramming();
return data;
}uint8_t
avrJtagReadFuseExt()
{
uint8_t data;
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x04); jtagWriteProgCmd(0x3A, 0x00);
data = (jtagWriteProgCmd(0x3B, 0x00) & 0xFF);
jtagLeavingProgramming();
return data;
}uint8_t
avrJtagReadFuseHigh()
{
uint8_t data;
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x04); jtagWriteProgCmd(0x3E, 0x00);
data = (jtagWriteProgCmd(0x3F, 0x00) & 0xFF);
jtagLeavingProgramming();
return data;
}uint8_t
avrJtagReadFuseLow()
{
uint8_t data=0;
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x04); jtagWriteProgCmd(0x32, 0x00);
data = (jtagWriteProgCmd(0x33, 0x00) & 0xFF);
jtagLeavingProgramming();
return data;
}uint8_t
avrJtagReadLock()
{
uint8_t data;
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x04); jtagWriteProgCmd(0x36, 0x00);
data = (jtagWriteProgCmd(0x37, 0x00) & 0xFF);
jtagLeavingProgramming();
return data;
}void
avrJtagWriteFuseExt(uint8_t data)
{
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x40); jtagWriteProgCmd(0x13, data) ; jtagWriteProgCmd(0x3B, 0x00);
jtagWriteProgCmd(0x39, 0x00);
jtagWriteProgCmd(0x3B, 0x00);
jtagWriteProgCmd(0x3B, 0x00); while ((jtagWriteProgCmd(0x3B, 0x00)& 0x200) == 0);
jtagLeavingProgramming();
}void
avrJtagWriteFuseHigh(uint8_t data)
{
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x40); jtagWriteProgCmd(0x13, data ) ; jtagWriteProgCmd(0x37, 0x00);
jtagWriteProgCmd(0x35, 0x00);
jtagWriteProgCmd(0x37, 0x00);
jtagWriteProgCmd(0x37, 0x00); while ((jtagWriteProgCmd(0x37, 0x00)& 0x200) == 0);
jtagLeavingProgramming();
}void
avrJtagWriteFuseLow(uint8_t data)
{
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x40); jtagWriteProgCmd(0x13, data ); jtagWriteProgCmd(0x33, 0x00);
jtagWriteProgCmd(0x31, 0x00);
jtagWriteProgCmd(0x33, 0x00);
jtagWriteProgCmd(0x33, 0x00); while ((jtagWriteProgCmd(0x33, 0x00)& 0x200) == 0);
jtagLeavingProgramming();
}void
avrJtagWriteLock(uint8_t data)
{
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x20); jtagWriteProgCmd(0x13, 0xC0 + (data & 0x3F)); jtagWriteProgCmd(0x33, 0x00);
jtagWriteProgCmd(0x31, 0x00);
jtagWriteProgCmd(0x33, 0x00);
jtagWriteProgCmd(0x33, 0x00); while ((jtagWriteProgCmd(0x33, 0x00)& 0x200) == 0);
jtagLeavingProgramming();
}static unsigned char rxBuffer[140];
static unsigned char
avrGetWriteBuffer(unsigned char** writeBuffer,
unsigned char bufferSize)
{ timeReset();
while(1) {
if (uartReadNBytes(rxBuffer, bufferSize + 2) != 0) break;
if (timeGet() > JTAG_UART_TIMEOUT) { uartWrite(PROG_TIMEOUT);
return PROG_CANCEL;
}
} if (rxBuffer[0] == PROG_CANCEL) { uartWrite(PROG_CANCEL);
return PROG_CANCEL;
} *writeBuffer = rxBuffer + 1; unsigned char i = 0;
unsigned char crc=0;
while(i < bufferSize) {
crc = CRC8((*writeBuffer)[i++], crc);
} uint8_t crcExpected = rxBuffer[1 + bufferSize];
if (crc != crcExpected) {
uartWrite(PROG_CRC_ERROR);
return PROG_CRC_ERROR;
} else {
uartWrite(PROG_CRC_OK);
return PROG_CRC_OK;
}
}static void
avrUartResync()
{
timeReset();
while(uartRead(UART_DONT_WAIT_RECEIVE) != PROG_SYNC1 && timeGet() < JTAG_UART_TIMEOUT);
while(uartRead(UART_DONT_WAIT_RECEIVE) != PROG_SYNC2 && timeGet() < JTAG_UART_TIMEOUT);
}static uint8_t
avrJtagGetWriteBufferData(uint8_t** buffer, uint8_t size)
{
uint8_t rcvStatus = PROG_CRC_ERROR;
do {
rcvStatus = avrGetWriteBuffer(buffer, size);
if (rcvStatus == PROG_CRC_ERROR) {
avrUartResync();
}
} while (rcvStatus == PROG_CRC_ERROR);
return rcvStatus;
}void
avrJtagChipErase()
{
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS); jtagWriteProgCmd(0x23, 0x80);
jtagWriteProgCmd(0x31, 0x80);
jtagWriteProgCmd(0x33, 0x80);
jtagWriteProgCmd(0x33, 0x80); while ((jtagWriteProgCmd(0x33, 0x80) & 0x200) == 0) nop();
jtagLeavingProgramming();
}static uint8_t
avrJtagEEpromRead(uint16_t begin,
uint16_t size,
uint8_t* compareBuffer,
uint8_t* crc)
{ jtagWriteProgCmd(0x23, 0x03);
uint16_t i=0, index=0;
for(index=0; index < size; ++index) {
uint16_t addr= begin + index;
uint8_t addrL = ((addr) & 0xFF);
uint8_t addrH = ((addr >> 8) & 0xFF); jtagWriteProgCmd(0x07, addrH); jtagWriteProgCmd(0x03, addrL); jtagWriteProgCmd(0x33, 0x00); jtagWriteProgCmd(0x32, 0x00); uint8_t data, lastData = jtagWriteProgCmd(0x33, 0x00) & 0xFF;
while(1) {
jtagWriteProgCmd(0x33, 0x00);
jtagWriteProgCmd(0x32, 0x00);
data = jtagWriteProgCmd(0x33, 0x00) & 0xFF;
if (data == lastData) {
break;
} else {
lastData = data;
}
}
if (compareBuffer != 0) { if (compareBuffer[i] != data) {
return PROG_ERROR;
}
i++;
} else { uartWrite8(data); *crc = CRC8(data, *crc);
}
}
return PROG_OK;
}
#define avrJtagCompareEEpromBlock(addr, size, buffer) avrJtagEEpromRead(addr, size, buffer, 0)
#define avrJtagSendEEpromBlock(addr, size, crc) avrJtagEEpromRead(addr, size, 0, crc)
static void
avrJtagWriteEEpromPage(uint16_t addr,
uint8_t pageSize,
uint8_t* buffer)
{
uint8_t addrH = ((addr >> 8) & 0xFF); jtagWriteProgCmd(0x23, 0x11); jtagWriteProgCmd(0x07, addrH); uint8_t indexInPage = 0;
for(indexInPage=0; indexInPage < pageSize; ++indexInPage) {
uint8_t addrL = ((addr+indexInPage) & 0xFF); jtagWriteProgCmd(0x03, addrL); jtagWriteProgCmd(0x13, buffer[indexInPage]); jtagWriteProgCmd(0x37, 0x00);
jtagWriteProgCmd(0x77, 0x00);
jtagWriteProgCmd(0x37, 0x00);
} jtagWriteProgCmd(0x33, 0x00);
jtagWriteProgCmd(0x31, 0x00);
jtagWriteProgCmd(0x33, 0x00);
jtagWriteProgCmd(0x33, 0x00); while((jtagWriteProgCmd(0x33, 0x00) & 0x200) == 0) nop();
}void
avrJtagReadEEprom()
{
if (!getAddrs()) {
return;
}
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS);
uint16_t addr;
for (addr = addrBegin; addr <= addrEnd;) {
uint8_t crc=0; avrJtagSendEEpromBlock(addr, PROG_CRC_CHECK_SIZE, &crc); uartWrite8(crc); uint8_t answer = uartRead8();
if (answer == PROG_CANCEL) {
break;
} else if (answer == PROG_CRC_OK) { addr = addr + PROG_CRC_CHECK_SIZE;
} else { }
}
jtagLeavingProgramming();
uartWrite(PROG_OK);
}void
avrJtagWriteEEprom()
{
if (!getAddrs()) {
return;
}
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS);
uint8_t status = PROG_OK;
uint16_t addr=0;
for(addr=addrBegin; addr <= addrEnd; addr += pageSize) { uint8_t* buffer=0;
if (avrJtagGetWriteBufferData(&buffer, pageSize) != PROG_CRC_OK) {
break;
}
uint8_t retry;
for(retry = 0; retry < 5; retry++) { avrJtagWriteEEpromPage(addr, pageSize, buffer); if (avrJtagCompareEEpromBlock(addr, pageSize, buffer) == PROG_OK)
break;
}
if (retry >= 5) {
status = PROG_ERROR;
break;
}
}
jtagLeavingProgramming();
uartWrite(status);
}static uint8_t
avrJtagFlashRead(uint16_t begin,
uint16_t size,
uint8_t* compareBuffer,
uint8_t* crc)
{ jtagWriteProgCmd(0x23, 0x02);
uint16_t i=0, index=0;
for(index=0; index < size; ++index) {
uint16_t addr= begin + index;
uint8_t addrH = ((addr >> 8) & 0xFF);
uint8_t addrL = (addr & 0xFF); jtagWriteProgCmd(0x07, addrH); jtagWriteProgCmd(0x03, addrL); uint8_t data1, data2, lastData1, lastData2; jtagWriteProgCmd(0x32, 0x00);
lastData1 = jtagWriteProgCmd(0x36, 0x00) & 0xFF;
lastData2 = jtagWriteProgCmd(0x37, 0x00) & 0xFF;
while(1) {
jtagWriteProgCmd(0x32, 0x00);
data1 = jtagWriteProgCmd(0x36, 0x00) & 0xFF;
data2 = jtagWriteProgCmd(0x37, 0x00) & 0xFF;
if ((data1 == lastData1) && (data2 == lastData2)) {
break;
} else {
lastData1 = data1;
lastData2 = data2;
}
}
if (compareBuffer != 0) { if ((compareBuffer[i] != data1)
|| (compareBuffer[i+1] != data2))
{
return PROG_ERROR;
}
i+=2;
} else { uartWrite8(data1);
uartWrite8(data2); *crc = CRC8(data1, *crc);
*crc = CRC8(data2, *crc);
}
}
return PROG_OK;
}
#define avrJtagCompareFlashBlock(addr, size, buffer) avrJtagFlashRead(addr, size, buffer, 0)
#define avrJtagSendFlashBlock(addr, size, crc) avrJtagFlashRead(addr, size, 0, crc)
static void
avrJtagWriteFlashPage(uint16_t addr,
uint8_t pageSize,
uint8_t* buffer)
{
uint8_t addrE = 0; uint8_t addrH = ((addr >> 8) & 0xFF); jtagWriteProgCmd(0x23, 0x10); jtagWriteProgCmd(0x0B, addrE); jtagWriteProgCmd(0x07, addrH); uint8_t indexInPage = 0;
for(indexInPage=0; indexInPage < pageSize; ++indexInPage) {
uint8_t addrL = ((addr+indexInPage) & 0xFF); jtagWriteProgCmd(0x03, addrL);
uint8_t dataL = buffer[indexInPage*2];
uint8_t dataH = buffer[indexInPage*2+1]; jtagWriteProgCmd(0x13, dataL); jtagWriteProgCmd(0x17, dataH); jtagWriteProgCmd(0x37, 0x00);
jtagWriteProgCmd(0x77, 0x00);
jtagWriteProgCmd(0x37, 0x00);
} jtagWriteProgCmd(0x37, 0x00);
jtagWriteProgCmd(0x35, 0x00);
jtagWriteProgCmd(0x37, 0x00);
jtagWriteProgCmd(0x37, 0x00); while((jtagWriteProgCmd(0x37, 0x00) & 0x200) == 0) nop();
}void
avrJtagReadFlash()
{
if (!getAddrs()) {
return;
}
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS);
uint16_t addr;
for (addr = addrBegin; addr <= addrEnd;) {
uint8_t crc=0; avrJtagSendFlashBlock(addr, PROG_CRC_CHECK_SIZE, &crc); uartWrite8(crc); uint8_t answer = uartRead8();
if (answer == PROG_CANCEL) {
break;
} else if (answer == PROG_CRC_OK) { addr = addr + PROG_CRC_CHECK_SIZE;
} else { }
}
jtagLeavingProgramming();
uartWrite(PROG_OK);
}void
avrJtagWriteFlash()
{
if (!getAddrs()) {
return;
}
jtagEnteringProgramming();
jtagWriteInstruction(JTAG_PROG_COMMANDS);
uint8_t status = PROG_OK;
uint16_t addr=0;
for(addr=addrBegin; addr <= addrEnd; addr += pageSize) { uint8_t* buffer=0;
if (avrJtagGetWriteBufferData(&buffer, pageSize*2) != PROG_CRC_OK) {
break;
}
uint8_t retry;
for(retry = 0; retry < 5; retry++) { avrJtagWriteFlashPage(addr, pageSize, buffer); if (avrJtagCompareFlashBlock(addr, pageSize, buffer) == PROG_OK)
break;
}
if (retry >= 5) {
status = PROG_ERROR;
break;
}
}
jtagLeavingProgramming();
uartWrite(status);
}