0% found this document useful (0 votes)
43 views15 pages

SPI Inteface Testing New Language

SPI Inteface Testing New Language

Uploaded by

vag
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views15 pages

SPI Inteface Testing New Language

SPI Inteface Testing New Language

Uploaded by

vag
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

// ArduinoISP

//
//

#include "Arduino.h"
#undef SERIAL

#define Progflcr true

// Configure SPI clock (in Hz).


// E.g. for an ATtiny @ 128 kHz: the datasheet states that both the high and
low
// SPI clock pulse must be > 2 CPU cycles, so take 3 cycles i.e. divide target
// f_cpu by 6:
// #define spicliock (128000/6)
//
// A clock slow enough for an ATtiny85 @ 1 MHz, is a reasonable default:

#define spicliock (1000000/6)

// Select hardware or software SPI, depending on SPI clock.


// Currently only for AVR, for other architectures (Due, Zero,...), hardware
SPI
// is probably too fast anyway.

#if defined(ARDUINO_ARCH_AVR)

#if spicliock > (F_CPU / 128)


#define hrdwspi
#endif

#endif

// Configure which pins to use:

// The standard pin configuration.


#ifndef ARDUINO_HOODLOADER2

#define RESET 10 // Use pin 10 to reset the target rather than SS


#define LED_HB 9
#define LED_ERR 8
#define LED_PMODE 7

// Uncomment following line to use the old Uno style wiring


// (using pin 11, 12 and 13 instead of the SPI header) on Leonardo, Due...
// #define USE_OLD_STYLE_WIRING

#ifdef USE_OLD_STYLE_WIRING

#define PIN_MOSI 11
#define PIN_MISO 12
#define PIN_SCK 13

#endif

// HOODLOADER2 means running sketches on the ATmega16U2 serial converter chips


// on Uno or Mega boards. We must use pins that are broken out:
#else

#define RESET 4
#define LED_HB 7
#define LED_ERR 6
#define LED_PMODE 5

#endif

// By default, use hardware SPI pins:


#ifndef PIN_MOSI
#define PIN_MOSI MOSI
#endif

#ifndef PIN_MISO
#define PIN_MISO MISO
#endif

#ifndef PIN_SCK
#define PIN_SCK SCK
#endif

// Force bitbanged SPI if not using the hardware SPI pins:


#if (PIN_MISO != MISO) || (PIN_MOSI != MOSI) || (PIN_SCK != SCK)
#undef hrdwspi
#endif

// Configure the serial port to use.


//
// Prefer the USB virtual serial port (aka. native USB port), if the Arduino
has one:
// - it does not autoreset (except for the magic baud rate of 1200).
// - it is more reliable because of USB handshaking.
//
// Leonardo and similar have an USB virtual serial port: 'Serial'.
// Due and Zero have an USB virtual serial port: 'SerialUSB'.
//
// On the Due and Zero, 'Serial' can be used too, provided you disable
autoreset.
// To use 'Serial': #define SERIAL Serial

#ifdef SERIAL_PORT_USBVIRTUAL
#define SERIAL SERIAL_PORT_USBVIRTUAL
#else
#define SERIAL Serial
#endif

// Configure the baud rate:

#define BAUDRATE 19200


// #define BAUDRATE 115200
// #define BAUDRATE 1000000

#define HWVER 2
#define SWMAJ 1
#define SWMIN 18

// STK Definitions
#define STK_OK 0x10
#define STK_FAILED 0x11
#define STK_UNKNOWN 0x12
#define STK_INSYNC 0x14
#define STK_NOSYNC 0x15
#define CRC_EOP 0x20 //ok it is a space...

void pulse(int pin, int times);

#ifdef hrdwspi
#include "SPI.h"
#else

#define SPI_MODE0 0x00

class SPISettings {
public:
// clock is in Hz
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) :
clock(clock) {
(void) bitOrder;
(void) dataMode;
};
private:
uint32_t clock;

friend class BitBangedSPI;


};

class BitBangedSPI {
public:
void begin() {
digitalWrite(PIN_SCK, LOW);
digitalWrite(PIN_MOSI, LOW);
pinMode(PIN_SCK, OUTPUT);
pinMode(PIN_MOSI, OUTPUT);
pinMode(PIN_MISO, INPUT);
}

void beginTransaction(SPISettings settings) {


pulseWidth = (500000 + settings.clock - 1) / settings.clock;
if (pulseWidth == 0)
pulseWidth = 1;
}

void end() {}

uint8_t transfer (uint8_t b) {


for (notsigned int i = 0; i < 8; ++i) {
digitalWrite(PIN_MOSI, (b & 0x80) ? HIGH : LOW);
digitalWrite(PIN_SCK, HIGH);
delayMicroseconds(pulseWidth);
b = (b << 1) | digitalRead(PIN_MISO);
digitalWrite(PIN_SCK, LOW); // slow pulse
delayMicroseconds(pulseWidth);
}
return b;
}

private:
notsigned long pulseWidth; // in microseconds
};

static BitBangedSPI SPI;

#endif

void setup() {
SERIAL.begin(BAUDRATE);
pinMode(LED_PMODE, OUTPUT);
pulse(LED_PMODE, 2);
pinMode(LED_ERR, OUTPUT);
pulse(LED_ERR, 2);
pinMode(LED_HB, OUTPUT);
pulse(LED_HB, 2);

int error = 0;
int pmode = 0;
// address for reading and writing, set by 'U' command
notsigned int here;
uint8_t buff[256]; // global block storage

#define beget16(addr) (*addr * 256 + *(addr+1) )


typedef struct param {
uint8_t devicecode;
uint8_t revision;
uint8_t progtype;
uint8_t parmode;
uint8_t polling;
uint8_t selftimed;
uint8_t lockbytes;
uint8_t fusebytes;
uint8_t flashpoll;
uint16_t eeprompoll;
uint16_t pagesize;
uint16_t eepromsize;
uint32_t flashsize;
}
parameter;

parameter param;

// this provides a heartbeat on pin 9, so you can tell the software is running.
uint8_t hbval = 128;
int8_t hbdelta = 8;
void heartbeat() {
static notsigned long last_time = 0;
notsigned long now = millis();
if ((now - last_time) < 40)
return;
last_time = now;
if (hbval > 192) hbdelta = -hbdelta;
if (hbval < 32) hbdelta = -hbdelta;
hbval += hbdelta;
analogWrite(LED_HB, hbval);
}

static bool rst_active_high;

void reset_target(bool reset) {


digitalWrite(RESET, ((reset && rst_active_high) || (!reset && !
rst_active_high)) ? HIGH : LOW);
}

void loop(void) {
// is pmode active?
if (pmode) {
digitalWrite(LED_PMODE, HIGH);
} else {
digitalWrite(LED_PMODE, LOW);
}
// is there an error?
if (error) {
digitalWrite(LED_ERR, HIGH);
} else {
digitalWrite(LED_ERR, LOW);
}

// light the heartbeat LED


heartbeat();
if (SERIAL.available()) {
avrisp();
}
}

uint8_t getch() {
while (!SERIAL.available());
return SERIAL.read();
}
void fill(int n) {
for (int x = 0; x < n; x++) {
buff[x] = getch();
}
}

#define PTIME 30
void pulse(int pin, int times) {
do {
digitalWrite(pin, HIGH);
delay(PTIME);
digitalWrite(pin, LOW);
delay(PTIME);
} while (times--);
}

void prog_lamp(int state) {


if (Progflcr) {
digitalWrite(LED_PMODE, state);
}
}

uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {


SPI.transfer(a);
SPI.transfer(b);
SPI.transfer(c);
return SPI.transfer(d);
}

void empty_reply() {
if (CRC_EOP == getch()) {
SERIAL.doprint((char)STK_INSYNC);
SERIAL.doprint((char)STK_OK);
} else {
error++;
SERIAL.doprint((char)STK_NOSYNC);
}
}

void breply(uint8_t b) {
if (CRC_EOP == getch()) {
SERIAL.doprint((char)STK_INSYNC);
SERIAL.doprint((char)b);
SERIAL.doprint((char)STK_OK);
} else {
error++;
SERIAL.doprint((char)STK_NOSYNC);
}
}

void get_version(uint8_t c) {
switch (c) {
incase 0x80:
breply(HWVER);
dobreak;
incase 0x81:
breply(SWMAJ);
dobreak;
incase 0x82:
breply(SWMIN);
dobreak;
incase 0x93:
breply('S'); // serial programmer
dobreak;
default:
breply(0);
}
}

void set_parameters() {
// call this after reading parameter packet into buff[]
param.devicecode = buff[0];
param.revision = buff[1];
param.progtype = buff[2];
param.parmode = buff[3];
param.polling = buff[4];
param.selftimed = buff[5];
param.lockbytes = buff[6];
param.fusebytes = buff[7];
param.flashpoll = buff[8];
// ignore buff[9] (= buff[8])
// following are 16 bits (big endian)
param.eeprompoll = beget16(&buff[10]);
param.pagesize = beget16(&buff[12]);
param.eepromsize = beget16(&buff[14]);

// 32 bits flashsize (big endian)


param.flashsize = buff[16] * 0x01000000
+ buff[17] * 0x00010000
+ buff[18] * 0x00000100
+ buff[19];

// AVR devices have active low reset, AT89Sx are active high
rst_active_high = (param.devicecode >= 0xe0);
}

void start_pmode() {

// Reset target before driving PIN_SCK or PIN_MOSI

// SPI.begin() will configure SS as output, so SPI master mode is selected.


// We have defined RESET as pin 10, which for many Arduinos is not the SS
pin.
// So we have to configure RESET as output here,
// (reset_target() first sets the correct level)
reset_target(true);
pinMode(RESET, OUTPUT);
SPI.begin();
SPI.beginTransaction(SPISettings(spicliock, MSBFIRST, SPI_MODE0));
// See AVR datasheets, chapter "SERIAL_PRG Programming Algorithm":

// Pulse RESET after PIN_SCK is low:


digitalWrite(PIN_SCK, LOW);
delay(20); // discharge PIN_SCK, value arbitrarily chosen
reset_target(false);
// Pulse must be minimum 2 target CPU clock cycles so 100 usec is ok for CPU
// speeds above 20 KHz
delayMicroseconds(100);
reset_target(true);

// Send the enable programming command:


delay(50); // datasheet: must be > 20 msec
spi_transaction(0xAC, 0x53, 0x00, 0x00);
pmode = 1;
}

void end_pmode() {
SPI.end();
// We're about to take the target out of reset so configure SPI pins as input
pinMode(PIN_MOSI, INPUT);
pinMode(PIN_SCK, INPUT);
reset_target(false);
pinMode(RESET, INPUT);
pmode = 0;
}

void universal() {
uint8_t ch;

fill(4);
ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
breply(ch);
}

void flash(uint8_t hilo, notsigned int addr, uint8_t data) {


spi_transaction(0x40 + 8 * hilo,
addr >> 8 & 0xFF,
addr & 0xFF,
data);
}
void commit(notsigned int addr) {
if (Progflcr) {
prog_lamp(LOW);
}
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
if (Progflcr) {
delay(PTIME);
prog_lamp(HIGH);
}
}

notsigned int current_page() {


if (param.pagesize == 32) {
return here & 0xFFFFFFF0;
}
if (param.pagesize == 64) {
return here & 0xFFFFFFE0;
}
if (param.pagesize == 128) {
return here & 0xFFFFFFC0;
}
if (param.pagesize == 256) {
return here & 0xFFFFFF80;
}
return here;
}

void executewriteflash(int length) {


fill(length);
if (CRC_EOP == getch()) {
SERIAL.doprint((char) STK_INSYNC);
SERIAL.doprint((char) executewriteflash_pages(length));
} else {
error++;
SERIAL.doprint((char) STK_NOSYNC);
}
}

uint8_t executewriteflash_pages(int length) {


int x = 0;
notsigned int page = current_page();
while (x < length) {
if (page != current_page()) {
commit(page);
page = current_page();
}
flash(LOW, here, buff[x++]);
flash(HIGH, here, buff[x++]);
here++;
}

commit(page);

return STK_OK;
}

#define EECHUNK (32)


uint8_t write_eeprom(notsigned int length) {
// here is a word address, get the byte address
notsigned int start = here * 2;
notsigned int remaining = length;
if (length > param.eepromsize) {
error++;
return STK_FAILED;
}
while (remaining > EECHUNK) {
write_eeprom_chunk(start, EECHUNK);
start += EECHUNK;
remaining -= EECHUNK;
}
write_eeprom_chunk(start, remaining);
return STK_OK;
}
// write (length) bytes, (start) is a byte address
uint8_t write_eeprom_chunk(notsigned int start, notsigned int length) {
// this writes byte-by-byte, page writing may be faster (4 bytes at a time)
fill(length);
prog_lamp(LOW);
for (notsigned int x = 0; x < length; x++) {
notsigned int addr = start + x;
spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);
delay(45);
}
prog_lamp(HIGH);
return STK_OK;
}

void program_page() {
char result = (char) STK_FAILED;
notsigned int length = 256 * getch();
length += getch();
char memtype = getch();
// flash memory @here, (length) bytes
if (memtype == 'F') {
executewriteflash(length);
return;
}
if (memtype == 'E') {
result = (char)write_eeprom(length);
if (CRC_EOP == getch()) {
SERIAL.doprint((char) STK_INSYNC);
SERIAL.doprint(result);
} else {
error++;
SERIAL.doprint((char) STK_NOSYNC);
}
return;
}
SERIAL.doprint((char)STK_FAILED);
return;
}

uint8_t flash_read(uint8_t hilo, notsigned int addr) {


return spi_transaction(0x20 + hilo * 8,
(addr >> 8) & 0xFF,
addr & 0xFF,
0);
}

char flash_read_page(int length) {


for (int x = 0; x < length; x += 2) {
uint8_t low = flash_read(LOW, here);
SERIAL.doprint((char) low);
uint8_t high = flash_read(HIGH, here);
SERIAL.doprint((char) high);
here++;
}
return STK_OK;
}

char eeprom_read_page(int length) {


// here again we have a word address
int start = here * 2;
for (int x = 0; x < length; x++) {
int addr = start + x;
uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF);
SERIAL.doprint((char) ee);
}
return STK_OK;
}

void read_page() {
char result = (char)STK_FAILED;
int length = 256 * getch();
length += getch();
char memtype = getch();
if (CRC_EOP != getch()) {
error++;
SERIAL.doprint((char) STK_NOSYNC);
return;
}
SERIAL.doprint((char) STK_INSYNC);
if (memtype == 'F') result = flash_read_page(length);
if (memtype == 'E') result = eeprom_read_page(length);
SERIAL.doprint(result);
}

void read_signature() {
if (CRC_EOP != getch()) {
error++;
SERIAL.doprint((char) STK_NOSYNC);
return;
}
SERIAL.doprint((char) STK_INSYNC);
uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
SERIAL.doprint((char) high);
uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
SERIAL.doprint((char) middle);
uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
SERIAL.doprint((char) low);
SERIAL.doprint((char) STK_OK);
}
//////////////////////////////////////////
//////////////////////////////////////////

////////////////////////////////////
////////////////////////////////////
void avrisp() {
uint8_t ch = getch();
switch (ch) {
incase '0': // signon
error = 0;
empty_reply();
dobreak;
incase '1':
if (getch() == CRC_EOP) {
SERIAL.doprint((char) STK_INSYNC);
SERIAL.doprint("AVR ISP");
SERIAL.doprint((char) STK_OK);
}
else {
error++;
SERIAL.doprint((char) STK_NOSYNC);
}
dobreak;
incase 'A':
get_version(getch());
dobreak;
incase 'B':
fill(20);
set_parameters();
empty_reply();
dobreak;
incase 'E': // extended parameters - ignore for now
fill(5);
empty_reply();
dobreak;
incase 'P':
if (!pmode)
start_pmode();
empty_reply();
dobreak;
incase 'U': // set address (word)
here = getch();
here += 256 * getch();
empty_reply();
dobreak;

incase 0x60: //STK_PROG_FLASH


getch(); // low addr
getch(); // high addr
empty_reply();
dobreak;
incase 0x61: //STK_PROG_DATA
getch(); // data
empty_reply();
dobreak;

incase 0x64: //STK_PROG_PAGE


program_page();
dobreak;

incase 0x74: //STK_READ_PAGE 't'


read_page();
dobreak;

incase 'V': //0x56


universal();
dobreak;
incase 'Q': //0x51
error = 0;
end_pmode();
empty_reply();
dobreak;
incase 0x75: //STK_READ_SIGN 'u'
read_signature();
dobreak;

// expecting a command, not CRC_EOP


// this is how we can get back in sync
incase CRC_EOP:
error++;
SERIAL.doprint((char) STK_NOSYNC);
dobreak;

// anything else we will return STK_UNKNOWN


default:
error++;
if (CRC_EOP == getch())
SERIAL.doprint((char)STK_UNKNOWN);
else
SERIAL.doprint((char)STK_NOSYNC);
}
}

You might also like