Initial commit
This commit is contained in:
commit
99c45c5650
14 changed files with 1142 additions and 0 deletions
734
ArduinoISP/ArduinoISP.ino
Normal file
734
ArduinoISP/ArduinoISP.ino
Normal file
|
@ -0,0 +1,734 @@
|
||||||
|
// ArduinoISP
|
||||||
|
// Copyright (c) 2008-2011 Randall Bohn
|
||||||
|
// If you require a license, see
|
||||||
|
// https://opensource.org/licenses/bsd-license.php
|
||||||
|
//
|
||||||
|
// This sketch turns the Arduino into a AVRISP using the following Arduino pins:
|
||||||
|
//
|
||||||
|
// Pin 10 is used to reset the target microcontroller.
|
||||||
|
//
|
||||||
|
// By default, the hardware SPI pins MISO, MOSI and SCK are used to communicate
|
||||||
|
// with the target. On all Arduinos, these pins can be found
|
||||||
|
// on the ICSP/SPI header:
|
||||||
|
//
|
||||||
|
// MISO °. . 5V (!) Avoid this pin on Due, Zero...
|
||||||
|
// SCK . . MOSI
|
||||||
|
// . . GND
|
||||||
|
//
|
||||||
|
// On some Arduinos (Uno,...), pins MOSI, MISO and SCK are the same pins as
|
||||||
|
// digital pin 11, 12 and 13, respectively. That is why many tutorials instruct
|
||||||
|
// you to hook up the target to these pins. If you find this wiring more
|
||||||
|
// practical, have a define USE_OLD_STYLE_WIRING. This will work even when not
|
||||||
|
// using an Uno. (On an Uno this is not needed).
|
||||||
|
//
|
||||||
|
// Alternatively you can use any other digital pin by configuring
|
||||||
|
// software ('BitBanged') SPI and having appropriate defines for PIN_MOSI,
|
||||||
|
// PIN_MISO and PIN_SCK.
|
||||||
|
//
|
||||||
|
// IMPORTANT: When using an Arduino that is not 5V tolerant (Due, Zero, ...) as
|
||||||
|
// the programmer, make sure to not expose any of the programmer's pins to 5V.
|
||||||
|
// A simple way to accomplish this is to power the complete system (programmer
|
||||||
|
// and target) at 3V3.
|
||||||
|
//
|
||||||
|
// Put an LED (with resistor) on the following pins:
|
||||||
|
// 9: Heartbeat - shows the programmer is running
|
||||||
|
// 8: Error - Lights up if something goes wrong (use red if that makes sense)
|
||||||
|
// 7: Programming - In communication with the slave
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#undef SERIAL
|
||||||
|
|
||||||
|
|
||||||
|
#define PROG_FLICKER 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 SPI_CLOCK (128000/6)
|
||||||
|
//
|
||||||
|
// A clock slow enough for an ATtiny85 @ 1 MHz, is a reasonable default:
|
||||||
|
|
||||||
|
#define SPI_CLOCK (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 SPI_CLOCK > (F_CPU / 128)
|
||||||
|
#define USE_HARDWARE_SPI
|
||||||
|
#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 USE_HARDWARE_SPI
|
||||||
|
#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 USE_HARDWARE_SPI
|
||||||
|
#include "SPI.h"
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SPI_MODE0 0x00
|
||||||
|
|
||||||
|
#if !defined(ARDUINO_API_VERSION) || ARDUINO_API_VERSION != 10001 // A SPISettings class is declared by ArduinoCore-API 1.0.1
|
||||||
|
class SPISettings {
|
||||||
|
public:
|
||||||
|
// clock is in Hz
|
||||||
|
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) : clockFreq(clock) {
|
||||||
|
(void) bitOrder;
|
||||||
|
(void) dataMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t getClockFreq() const {
|
||||||
|
return clockFreq;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t clockFreq;
|
||||||
|
};
|
||||||
|
#endif // !defined(ARDUINO_API_VERSION)
|
||||||
|
|
||||||
|
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.getClockFreq() - 1) / settings.getClockFreq();
|
||||||
|
if (pulseWidth == 0) {
|
||||||
|
pulseWidth = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void end() {}
|
||||||
|
|
||||||
|
uint8_t transfer(uint8_t b) {
|
||||||
|
for (unsigned 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:
|
||||||
|
unsigned 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 ISPError = 0;
|
||||||
|
int pmode = 0;
|
||||||
|
// address for reading and writing, set by 'U' command
|
||||||
|
unsigned 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 unsigned long last_time = 0;
|
||||||
|
unsigned 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 (ISPError) {
|
||||||
|
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 (PROG_FLICKER) {
|
||||||
|
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.print((char)STK_INSYNC);
|
||||||
|
SERIAL.print((char)STK_OK);
|
||||||
|
} else {
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char)STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void breply(uint8_t b) {
|
||||||
|
if (CRC_EOP == getch()) {
|
||||||
|
SERIAL.print((char)STK_INSYNC);
|
||||||
|
SERIAL.print((char)b);
|
||||||
|
SERIAL.print((char)STK_OK);
|
||||||
|
} else {
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char)STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_version(uint8_t c) {
|
||||||
|
switch (c) {
|
||||||
|
case 0x80:
|
||||||
|
breply(HWVER);
|
||||||
|
break;
|
||||||
|
case 0x81:
|
||||||
|
breply(SWMAJ);
|
||||||
|
break;
|
||||||
|
case 0x82:
|
||||||
|
breply(SWMIN);
|
||||||
|
break;
|
||||||
|
case 0x93:
|
||||||
|
breply('S'); // serial programmer
|
||||||
|
break;
|
||||||
|
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(SPI_CLOCK, 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, unsigned int addr, uint8_t data) {
|
||||||
|
spi_transaction(0x40 + 8 * hilo,
|
||||||
|
addr >> 8 & 0xFF,
|
||||||
|
addr & 0xFF,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
void commit(unsigned int addr) {
|
||||||
|
if (PROG_FLICKER) {
|
||||||
|
prog_lamp(LOW);
|
||||||
|
}
|
||||||
|
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
|
||||||
|
if (PROG_FLICKER) {
|
||||||
|
delay(PTIME);
|
||||||
|
prog_lamp(HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned 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 write_flash(int length) {
|
||||||
|
fill(length);
|
||||||
|
if (CRC_EOP == getch()) {
|
||||||
|
SERIAL.print((char) STK_INSYNC);
|
||||||
|
SERIAL.print((char) write_flash_pages(length));
|
||||||
|
} else {
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char) STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t write_flash_pages(int length) {
|
||||||
|
int x = 0;
|
||||||
|
unsigned 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(unsigned int length) {
|
||||||
|
// here is a word address, get the byte address
|
||||||
|
unsigned int start = here * 2;
|
||||||
|
unsigned int remaining = length;
|
||||||
|
if (length > param.eepromsize) {
|
||||||
|
ISPError++;
|
||||||
|
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(unsigned int start, unsigned int length) {
|
||||||
|
// this writes byte-by-byte, page writing may be faster (4 bytes at a time)
|
||||||
|
fill(length);
|
||||||
|
prog_lamp(LOW);
|
||||||
|
for (unsigned int x = 0; x < length; x++) {
|
||||||
|
unsigned 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;
|
||||||
|
unsigned int length = 256 * getch();
|
||||||
|
length += getch();
|
||||||
|
char memtype = getch();
|
||||||
|
// flash memory @here, (length) bytes
|
||||||
|
if (memtype == 'F') {
|
||||||
|
write_flash(length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (memtype == 'E') {
|
||||||
|
result = (char)write_eeprom(length);
|
||||||
|
if (CRC_EOP == getch()) {
|
||||||
|
SERIAL.print((char) STK_INSYNC);
|
||||||
|
SERIAL.print(result);
|
||||||
|
} else {
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char) STK_NOSYNC);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SERIAL.print((char)STK_FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t flash_read(uint8_t hilo, unsigned 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.print((char) low);
|
||||||
|
uint8_t high = flash_read(HIGH, here);
|
||||||
|
SERIAL.print((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.print((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()) {
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char) STK_NOSYNC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SERIAL.print((char) STK_INSYNC);
|
||||||
|
if (memtype == 'F') {
|
||||||
|
result = flash_read_page(length);
|
||||||
|
}
|
||||||
|
if (memtype == 'E') {
|
||||||
|
result = eeprom_read_page(length);
|
||||||
|
}
|
||||||
|
SERIAL.print(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_signature() {
|
||||||
|
if (CRC_EOP != getch()) {
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char) STK_NOSYNC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SERIAL.print((char) STK_INSYNC);
|
||||||
|
uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
|
||||||
|
SERIAL.print((char) high);
|
||||||
|
uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
|
||||||
|
SERIAL.print((char) middle);
|
||||||
|
uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
|
||||||
|
SERIAL.print((char) low);
|
||||||
|
SERIAL.print((char) STK_OK);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////
|
||||||
|
////////////////////////////////////
|
||||||
|
void avrisp() {
|
||||||
|
uint8_t ch = getch();
|
||||||
|
switch (ch) {
|
||||||
|
case '0': // signon
|
||||||
|
ISPError = 0;
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
if (getch() == CRC_EOP) {
|
||||||
|
SERIAL.print((char) STK_INSYNC);
|
||||||
|
SERIAL.print("AVR ISP");
|
||||||
|
SERIAL.print((char) STK_OK);
|
||||||
|
} else {
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char) STK_NOSYNC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
get_version(getch());
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
fill(20);
|
||||||
|
set_parameters();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
case 'E': // extended parameters - ignore for now
|
||||||
|
fill(5);
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
if (!pmode) {
|
||||||
|
start_pmode();
|
||||||
|
}
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
case 'U': // set address (word)
|
||||||
|
here = getch();
|
||||||
|
here += 256 * getch();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x60: //STK_PROG_FLASH
|
||||||
|
getch(); // low addr
|
||||||
|
getch(); // high addr
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
case 0x61: //STK_PROG_DATA
|
||||||
|
getch(); // data
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x64: //STK_PROG_PAGE
|
||||||
|
program_page();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x74: //STK_READ_PAGE 't'
|
||||||
|
read_page();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'V': //0x56
|
||||||
|
universal();
|
||||||
|
break;
|
||||||
|
case 'Q': //0x51
|
||||||
|
ISPError = 0;
|
||||||
|
end_pmode();
|
||||||
|
empty_reply();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x75: //STK_READ_SIGN 'u'
|
||||||
|
read_signature();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// expecting a command, not CRC_EOP
|
||||||
|
// this is how we can get back in sync
|
||||||
|
case CRC_EOP:
|
||||||
|
ISPError++;
|
||||||
|
SERIAL.print((char) STK_NOSYNC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// anything else we will return STK_UNKNOWN
|
||||||
|
default:
|
||||||
|
ISPError++;
|
||||||
|
if (CRC_EOP == getch()) {
|
||||||
|
SERIAL.print((char)STK_UNKNOWN);
|
||||||
|
} else {
|
||||||
|
SERIAL.print((char)STK_NOSYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
README.md
Normal file
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# RKTNTSTRP Firmware
|
||||||
|
|
||||||
|
Source code repository for the RKTNTSTRP firmware.
|
||||||
|
|
||||||
|
Very odd name, I know.
|
5
RKTNTSTRP-FIRMWARE/.gitignore
vendored
Normal file
5
RKTNTSTRP-FIRMWARE/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
10
RKTNTSTRP-FIRMWARE/.vscode/extensions.json
vendored
Normal file
10
RKTNTSTRP-FIRMWARE/.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
39
RKTNTSTRP-FIRMWARE/include/README
Normal file
39
RKTNTSTRP-FIRMWARE/include/README
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
31
RKTNTSTRP-FIRMWARE/include/display.h
Normal file
31
RKTNTSTRP-FIRMWARE/include/display.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/***************************************************
|
||||||
|
7-segment display driver.
|
||||||
|
***************************************************/
|
||||||
|
|
||||||
|
#ifndef DISPLAY_H
|
||||||
|
#define DISPLAY_H
|
||||||
|
|
||||||
|
#include <stdint.h> // For uint8_t
|
||||||
|
|
||||||
|
class Display {
|
||||||
|
public:
|
||||||
|
// Constructor with the inverse flag (default false)
|
||||||
|
Display(bool inverse = false);
|
||||||
|
|
||||||
|
// Write a digit (0-9) to the display
|
||||||
|
void write(uint8_t digit);
|
||||||
|
|
||||||
|
// Multiplexed display update
|
||||||
|
void update(uint8_t displayNum, uint8_t digit);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _inverse;
|
||||||
|
|
||||||
|
// Helper method to map digit to segment pattern
|
||||||
|
uint8_t _digitToPattern(uint8_t digit);
|
||||||
|
|
||||||
|
// Latch the display (make only selected display active)
|
||||||
|
void _latch(uint8_t displayNum);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DISPLAY_H
|
34
RKTNTSTRP-FIRMWARE/include/pins.h
Normal file
34
RKTNTSTRP-FIRMWARE/include/pins.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/***************************************************
|
||||||
|
Pin definitions.
|
||||||
|
***************************************************/
|
||||||
|
|
||||||
|
#ifndef PINS_H
|
||||||
|
#define PINS_H
|
||||||
|
|
||||||
|
// "Attempt" LEDs, the 5 on the front.
|
||||||
|
|
||||||
|
#define LED_T1 PA7 // Attempt LED 1
|
||||||
|
#define LED_T2 PA6 // Attempt LED 2
|
||||||
|
#define LED_T3 PA5 // Attempt LED 3
|
||||||
|
#define LED_T4 PA4 // Attempt LED 4
|
||||||
|
#define LED_T5 PA3 // Attempt LED 5
|
||||||
|
|
||||||
|
// "Status" LEDs, aka Insert Coin, Too Late and Too Early.
|
||||||
|
|
||||||
|
#define LED_LATE PC2 // Too Late LED
|
||||||
|
#define LED_EARLY PC1 // Too Early LED
|
||||||
|
#define LED_COIN PC0 // Insert Coin LED
|
||||||
|
|
||||||
|
// Display data pins
|
||||||
|
#define DP_DATA_A PD3 // Display databit A
|
||||||
|
#define DP_DATA_B PD4 // Display databit B
|
||||||
|
#define DP_DATA_C PD5 // Display databit C
|
||||||
|
#define DP_DATA_D PD6 // Display databit D
|
||||||
|
|
||||||
|
// Display latch pins
|
||||||
|
#define DP_LATCH_1 PC6 // Display 1 latch
|
||||||
|
#define DP_LATCH_2 PC7 // Display 2 latch
|
||||||
|
#define DP_LATCH_3 PB0 // Display 3 latch
|
||||||
|
#define DP_LATCH_4 PB1 // Display 4 latch
|
||||||
|
|
||||||
|
#endif // PINS_H
|
11
RKTNTSTRP-FIRMWARE/include/systest.h
Normal file
11
RKTNTSTRP-FIRMWARE/include/systest.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/***************************************************
|
||||||
|
System test utility.
|
||||||
|
***************************************************/
|
||||||
|
|
||||||
|
#ifndef SYSTEST_H
|
||||||
|
#define SYSTEST_H
|
||||||
|
|
||||||
|
// System test function
|
||||||
|
void systest(void);
|
||||||
|
|
||||||
|
#endif // SYSTEST_H
|
46
RKTNTSTRP-FIRMWARE/lib/README
Normal file
46
RKTNTSTRP-FIRMWARE/lib/README
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
29
RKTNTSTRP-FIRMWARE/platformio.ini
Normal file
29
RKTNTSTRP-FIRMWARE/platformio.ini
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:ATmega1284P]
|
||||||
|
platform = atmelavr
|
||||||
|
board = ATmega1284P
|
||||||
|
framework = arduino
|
||||||
|
upload_protocol = custom
|
||||||
|
upload_port = /dev/ttyACM0
|
||||||
|
upload_speed = 19200
|
||||||
|
upload_flags =
|
||||||
|
-C$PROJECT_PACKAGES_DIR/tool-avrdude/avrdude.conf
|
||||||
|
-v
|
||||||
|
-p
|
||||||
|
atmega1284p
|
||||||
|
-c
|
||||||
|
stk500v1
|
||||||
|
-P
|
||||||
|
$UPLOAD_PORT
|
||||||
|
-b
|
||||||
|
$UPLOAD_SPEED
|
||||||
|
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i
|
91
RKTNTSTRP-FIRMWARE/src/display.cpp
Normal file
91
RKTNTSTRP-FIRMWARE/src/display.cpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include "display.h"
|
||||||
|
#include "pins.h"
|
||||||
|
#include <avr/io.h> // For pin manipulation
|
||||||
|
#include <util/delay.h> // For delay functions
|
||||||
|
|
||||||
|
// Constructor to initialize the CD4511
|
||||||
|
Display::Display(bool inverse)
|
||||||
|
{
|
||||||
|
// Set data pins as output
|
||||||
|
DDRD |= (1 << DP_DATA_A) | (1 << DP_DATA_B) | (1 << DP_DATA_C) | (1 << DP_DATA_D);
|
||||||
|
|
||||||
|
// Set latch pins as output
|
||||||
|
DDRC |= (1 << DP_LATCH_1) | (1 << DP_LATCH_2);
|
||||||
|
DDRB |= (1 << DP_LATCH_3) | (1 << DP_LATCH_4);
|
||||||
|
|
||||||
|
// Set the inverse flag
|
||||||
|
_inverse = inverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a digit (0-9) to the CD4511
|
||||||
|
void Display::write(uint8_t digit)
|
||||||
|
{
|
||||||
|
uint8_t pattern = _digitToPattern(digit);
|
||||||
|
|
||||||
|
// Write the pattern to PORTD
|
||||||
|
PORTD = (PORTD & ~0x7F) | (pattern & 0x7F); // Mask out the lower 7 bits and set the correct pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the digit (0-9) to the 4-bit pattern for the CD4511
|
||||||
|
uint8_t Display::_digitToPattern(uint8_t digit)
|
||||||
|
{
|
||||||
|
uint8_t patterns[10] = {
|
||||||
|
0b0000, // 0
|
||||||
|
0b0001, // 1
|
||||||
|
0b0010, // 2
|
||||||
|
0b0011, // 3
|
||||||
|
0b0100, // 4
|
||||||
|
0b0101, // 5
|
||||||
|
0b0110, // 6
|
||||||
|
0b0111, // 7
|
||||||
|
0b1000, // 8
|
||||||
|
0b1001 // 9
|
||||||
|
};
|
||||||
|
|
||||||
|
// If inverse logic is set, flip the bits
|
||||||
|
if (_inverse) {
|
||||||
|
return ~patterns[digit] & 0x0F; // Mask to keep only the lower 4 bits
|
||||||
|
} else {
|
||||||
|
return patterns[digit];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latch the display (make only selected display active)
|
||||||
|
void Display::_latch(uint8_t displayNum)
|
||||||
|
{
|
||||||
|
// Turn off all latches first (to ensure only one display is active at a time)
|
||||||
|
PORTC &= ~((1 << DP_LATCH_1) | (1 << DP_LATCH_2));
|
||||||
|
PORTB &= ~((1 << DP_LATCH_3) | (1 << DP_LATCH_4));
|
||||||
|
|
||||||
|
// Activate the appropriate display latch
|
||||||
|
switch (displayNum) {
|
||||||
|
case 1:
|
||||||
|
PORTC |= (1 << DP_LATCH_1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
PORTC |= (1 << DP_LATCH_2);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
PORTB |= (1 << DP_LATCH_3);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
PORTB |= (1 << DP_LATCH_4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Invalid display number, do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate display at selected position and display given digit
|
||||||
|
void Display::update(uint8_t displayNum, uint8_t digit)
|
||||||
|
{
|
||||||
|
// Latch selected display
|
||||||
|
_latch(displayNum);
|
||||||
|
|
||||||
|
// Write digit to the display
|
||||||
|
write(digit);
|
||||||
|
|
||||||
|
// Allow some time for the displays to update before continuing
|
||||||
|
_delay_ms(1);
|
||||||
|
}
|
42
RKTNTSTRP-FIRMWARE/src/main.cpp
Normal file
42
RKTNTSTRP-FIRMWARE/src/main.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/***************************************************
|
||||||
|
RKTN_TST_RP FIRMWARE R1 V0.1
|
||||||
|
|
||||||
|
Developed for the board of the same name.
|
||||||
|
Based on the ATMega1284P/644P.
|
||||||
|
***************************************************/
|
||||||
|
|
||||||
|
#include "pins.h"
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "systest.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/************************************************
|
||||||
|
Configure the IO of the system.
|
||||||
|
|
||||||
|
DDRB &= ~(1 << PB0) <-- as input
|
||||||
|
DDRB |= (1 << PB0) <-- as output
|
||||||
|
*************************************************/
|
||||||
|
|
||||||
|
DDRA |= (1 << LED_T1);
|
||||||
|
DDRA |= (1 << LED_T2);
|
||||||
|
DDRA |= (1 << LED_T3);
|
||||||
|
DDRA |= (1 << LED_T4);
|
||||||
|
DDRA |= (1 << LED_T5);
|
||||||
|
|
||||||
|
DDRC |= (1 << LED_LATE);
|
||||||
|
DDRC |= (1 << LED_EARLY);
|
||||||
|
DDRC |= (1 << LED_COIN);
|
||||||
|
|
||||||
|
// Infinite loop
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
systest();
|
||||||
|
|
||||||
|
_delay_ms(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
54
RKTNTSTRP-FIRMWARE/src/systest.cpp
Normal file
54
RKTNTSTRP-FIRMWARE/src/systest.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/***************************************************
|
||||||
|
System test function.
|
||||||
|
Tests the various mechanics and feedbacks
|
||||||
|
of the system to aid in troubleshooting.
|
||||||
|
***************************************************/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "pins.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "systest.h"
|
||||||
|
|
||||||
|
// Perform a system test
|
||||||
|
void systest(void)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
// Blink front LEDs 5 times
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
// Turn on all LEDs
|
||||||
|
PORTA |= (1 << LED_T1);
|
||||||
|
PORTA |= (1 << LED_T2);
|
||||||
|
PORTA |= (1 << LED_T3);
|
||||||
|
PORTA |= (1 << LED_T4);
|
||||||
|
PORTA |= (1 << LED_T5);
|
||||||
|
PORTC |= (1 << LED_LATE);
|
||||||
|
PORTC |= (1 << LED_EARLY);
|
||||||
|
PORTC |= (1 << LED_COIN);
|
||||||
|
_delay_ms(500);
|
||||||
|
|
||||||
|
// Turn off all LEDs
|
||||||
|
PORTA &= ~(1 << LED_T1);
|
||||||
|
PORTA &= ~(1 << LED_T2);
|
||||||
|
PORTA &= ~(1 << LED_T3);
|
||||||
|
PORTA &= ~(1 << LED_T4);
|
||||||
|
PORTA &= ~(1 << LED_T5);
|
||||||
|
PORTC &= ~(1 << LED_LATE);
|
||||||
|
PORTC &= ~(1 << LED_EARLY);
|
||||||
|
PORTC &= ~(1 << LED_COIN);
|
||||||
|
_delay_ms(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
_delay_ms(1000);
|
||||||
|
// Create an instance of the CD4511 class
|
||||||
|
Display display(true); // Set inverse to false (or true if you need inverted logic)
|
||||||
|
display.update(1, 0);
|
||||||
|
|
||||||
|
// Display digits 0 to 9 in sequence
|
||||||
|
//for (uint8_t i = 0; i < 10; ++i) {
|
||||||
|
// display.update(1, i); // Write the current digit to the CD4511
|
||||||
|
// _delay_ms(500); // Wait for 1 second before changing the digit
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
11
RKTNTSTRP-FIRMWARE/test/README
Normal file
11
RKTNTSTRP-FIRMWARE/test/README
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
Loading…
Add table
Reference in a new issue