Skip to content

Instantly share code, notes, and snippets.

@yurapyon
Created November 29, 2018 07:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yurapyon/4b5915822763284fa6321dd8018b3bfd to your computer and use it in GitHub Desktop.
Save yurapyon/4b5915822763284fa6321dd8018b3bfd to your computer and use it in GitHub Desktop.
arduino uno uploader
#include <Arduino.h>
#include <SPI.h>
#define P_MOSI 11
#define P_MISO 12
#define P_SCK 13
#define P_RESET 8
#define P_ERR 9
// spi has to be 2x slower than slowest device clock
uint8_t hr_nibble_to_uint(char nibble) {
if (nibble >= '0' && nibble <= '9') {
return nibble - 0x30;
} else if (nibble >= 'A' && nibble <= 'F') {
return 0xA + (nibble - 0x41);
} else if (nibble >= 'a' && nibble <= 'f') {
return 0xA + (nibble - 0x61);
} else {
return 0;
}
}
// converts 2 humanreadable hexchars from str to a uint8
uint8_t hr_byte_to_uint(const char *byte) {
uint8_t buf[2];
buf[0] = hr_nibble_to_uint(byte[0]);
buf[1] = hr_nibble_to_uint(byte[1]);
return buf[0] * 16 + buf[1];
}
//
#define RECV_BUF_SZ 256
uint8_t recv_buf[RECV_BUF_SZ + 1];
uint8_t recv_buf_len = 0;
int receive_from_pc() {
uint8_t msg_sz;
for (;;) {
if (Serial.available() > 0) {
msg_sz = Serial.read();
break;
}
delay(5);
}
recv_buf_len = 0;
for (;;) {
if (Serial.available() > 0) {
recv_buf[recv_buf_len] = Serial.read();
recv_buf_len++;
if (recv_buf_len >= msg_sz) {
break;
}
}
delay(5);
}
recv_buf[recv_buf_len] = '\0';
return msg_sz;
}
void transmit_to_pc(const char *buf, unsigned int sz) {
Serial.write(sz);
Serial.flush();
Serial.write(buf, sz);
Serial.flush();
}
const uint8_t msg_ok = 0;
const uint8_t msg_begin = 1;
//
uint8_t spi_transfer(uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4) {
SPI.transfer(a1);
SPI.transfer(a2);
SPI.transfer(a3);
return SPI.transfer(a4);
}
void begin_programming() {
digitalWrite(P_RESET, HIGH);
pinMode(P_MOSI, OUTPUT);
pinMode(P_MISO, INPUT);
pinMode(P_SCK, OUTPUT);
pinMode(P_RESET, OUTPUT);
digitalWrite(P_SCK, LOW);
delay(20);
digitalWrite(P_RESET, HIGH);
delayMicroseconds(200);
digitalWrite(P_RESET, LOW);
delay(40);
SPI.begin();
SPI.beginTransaction(SPISettings(1000000/6, MSBFIRST, SPI_MODE0));
SPI.transfer(0xAC);
SPI.transfer(0x53);
uint8_t sync = SPI.transfer(0x00);
SPI.transfer(0x00);
uint8_t sig_bytes[4];
sig_bytes[0] = spi_transfer(0x30, 0x00, 0x00, 0x00);
sig_bytes[1] = spi_transfer(0x30, 0x00, 0x01, 0x00);
sig_bytes[2] = spi_transfer(0x30, 0x00, 0x02, 0x00);
sig_bytes[3] = spi_transfer(0x30, 0x00, 0x03, 0x00);
transmit_to_pc(sig_bytes, 4);
uint8_t fuses[3];
fuses[0] = spi_transfer(0x50, 0x00, 0x00, 0x00);
fuses[1] = spi_transfer(0x58, 0x08, 0x00, 0x00);
fuses[2] = spi_transfer(0x50, 0x08, 0x00, 0x00);
transmit_to_pc(fuses, 3);
spi_transfer(0xAC, 0x80, 0x00, 0x00);
delay(25);
}
void end_programming() {
SPI.endTransaction();
SPI.end();
digitalWrite(P_RESET, HIGH);
}
void load_flash_word(uint16_t addr, uint16_t word) {
// write low first
spi_transfer(0x40, addr >> 8, addr, word);
// write high
spi_transfer(0x48, addr >> 8, addr, word >> 8);
}
void write_flash_page(uint16_t addr) {
spi_transfer(0x4c, addr >> 8, addr, 0x00);
// wait 2.6 ms
delay(10);
}
uint16_t read_flash_word(uint16_t addr) {
uint8_t low = spi_transfer(0x20, addr >> 8, addr, 0x00);
uint16_t high = spi_transfer(0x28, addr >> 8, addr, 0x00);
return (high << 8) | low;
}
// adresses are 16 or less bits long
#define PAGE_SZ 64
uint16_t page_of(uint16_t addr) {
if (PAGE_SZ == 64) {
return addr & 0xffc0;
}
return addr;
}
uint16_t curr_addr;
uint16_t curr_page;
//
// when writing to 8bit location from 16bit hex file
// msB is ignored
// adresses >= x8000 are eeprom // 32kW flash
// adresses >= x9000 are fuse // 4kB eeprom
// x9000 high low fuses
// x9001 extended fuses
// todo check checksum
unsigned int write_hex_line(const char *line) {
// assume lines look like this
// :szaddrtpdatadatadatacs
uint8_t checksum_acc = 0;
const char *temp = line;
// TODO error check starts with ':'
temp++;
uint8_t sz = hr_byte_to_uint(temp) / 2;
temp += 2;
uint16_t addr_high = hr_byte_to_uint(temp);
temp += 2;
uint8_t addr_low = hr_byte_to_uint(temp);
temp += 2;
uint8_t type = hr_byte_to_uint(temp);
temp += 2;
if (type == 1) {
return 1;
}
uint16_t addr = (addr_high << 8) | addr_low;
// todo handle if sz is 0
curr_addr = addr;
curr_page = page_of(curr_addr);
if (curr_addr < 0x8000) {
// TODO clean up
// use a buffer to hold data thats been converted to u16
for (int i = 0; i < sz; ++i) {
uint16_t data_high = hr_byte_to_uint(temp);
temp += 2;
uint8_t data_low = hr_byte_to_uint(temp);
temp += 2;
load_flash_word(curr_addr, (data_high << 8) | data_low);
curr_addr++;
if(curr_page != page_of(curr_addr)) {
write_flash_page(curr_addr - 1);
curr_page = page_of(curr_addr);
}
}
write_flash_page(curr_addr - 1);
temp = line + 9;
curr_addr = addr;
for (int i = 0; i < sz; ++i) {
uint16_t data_high = hr_byte_to_uint(temp);
temp += 2;
uint8_t data_low = hr_byte_to_uint(temp);
temp += 2;
data_high = (data_high << 8) | data_low;
uint16_t from_chip = read_flash_word(curr_addr);
if (data_high != from_chip) {
digitalWrite(P_ERR, HIGH);
}
// transmit_to_pc((char *)&data_high, 2);
// transmit_to_pc((char *)&from_chip, 2);
curr_addr++;
}
} else if (curr_addr == 0x9000) {
if (sz > 0) {
uint8_t high = hr_byte_to_uint(temp);
temp += 2;
uint8_t low = hr_byte_to_uint(temp);
temp += 2;
spi_transfer(0xAC, 0xA0, 0x00, low);
delay(10);
spi_transfer(0xAC, 0xA8, 0x00, high);
delay(10);
}
}
return 0;
}
#define HEX_BUF_SZ 256
char hex_buf[HEX_BUF_SZ];
uint8_t hex_buf_at = 0;
bool programming = false;
void setup() {
pinMode(P_ERR, OUTPUT);
digitalWrite(P_ERR, LOW);
Serial.begin(19200);
transmit_to_pc(&msg_ok, 1);
}
void loop() {
int sz = receive_from_pc();
if (!programming) {
if (sz == 1 && recv_buf[0] == msg_begin) {
begin_programming();
programming = true;
hex_buf_at = 0;
transmit_to_pc(&msg_ok, 1);
}
} else {
// every transmission is part of a hex file
memcpy(hex_buf + hex_buf_at, recv_buf, sz);
hex_buf_at += sz;
for (int i = 0; i < hex_buf_at; ++i) {
if (hex_buf[i] == '\n') {
if (write_hex_line(hex_buf)) {
end_programming();
programming = false;
break;
}
memmove(hex_buf, hex_buf + i + 1, hex_buf_at - i - 1);
hex_buf_at = hex_buf_at - i - 1;
i = 0;
}
}
transmit_to_pc(&msg_ok, 1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment