Оживим дискуссию.
Переписал в соответствии с рекомендации от сообщества.
Интересно что еще скажут…
(на .h и .c не делю осознано. это мой выбор. зачем и почему знаю, просто пока это не принципиально)
arduino_isf_flasher.ino
#include <Arduino.h>
#include <U8g2lib.h>
#include <FastLED.h>
#include <Versatile_RotaryEncoder.h>
#include <SPI.h>
#include "ARDUINOISP.h"
#include "ARDUINOISP_FILE.h"
#include <key.h>
#include <avr/wdt.h>
#include <SdFat.h>
SdFat SD;
File myFile;
#define NUM_LEDS 3
#define BRIGHTNESS 128
CRGB leds[NUM_LEDS];
digitalKey SD_CD(5);
digitalKey kill_key(6);
U8X8_ST7567_OS12864_4W_HW_SPI u8x8(/* cs=*/7, /* dc=*/9, /* reset=*/8);
// Set here your encoder reading pins
#define clk 2
#define dt 3
#define sw 4
// global variables for menu redraw and input event handling
uint8_t rotate_event = 0; // 0 = not turning, 1 = CW, 2 = CCW
uint8_t press_event = 0; // 0 = not pushed, 1 = pushed
uint8_t long_press_event = 0; // 0 = not pushed, 1 = pushed
Versatile_RotaryEncoder versatile_encoder(clk, dt, sw);
int folder_name = 1;
uint8_t status = 0;
String str;
// Functions prototyping to be handled on each Encoder Event
void handleRotate(int8_t rotation) {
if (rotation > 0)
rotate_event = 2; // CW
else
rotate_event = 1; // CCW
}
void handlePressRelease() {
press_event = 1;
}
void handleLongPress() {
long_press_event = 1;
}
void open_info_file(String file_name) {
u8x8.clear();
Serial.print(F("open file "));
Serial.print(file_name);
Serial.println();
myFile = SD.open(file_name);
if (myFile) {
while (myFile.available()) {
char ch = myFile.read();
u8x8.print(ch);
Serial.print(ch);
}
u8x8.println();
myFile.close();
Serial.println();
Serial.println(F("close readme.txt file"));
} else {
u8x8.println(F("error opening"));
}
}
// Serial.println(F("---writing file---"));
// myFile.getName(buff, 32);
// for (int i = 0; i < 32; ++i) {
// Serial.write(buff[i]);
// }
// Serial.println();
// Serial.println(F("checksum file error"));
// Serial.println(F("function write error"));
// Serial.println(F("open file error"));
void print_proress_bar(uint32_t current_line, uint32_t number_lines) {
uint8_t n = (float(current_line) / float(number_lines)) * 13;
u8x8.setCursor(0, 7);
u8x8.print(" ");
u8x8.setCursor(0, 7);
for (int i = 0; i < 13; ++i) {
if (i < n) u8x8.setInverseFont(1);
else u8x8.setInverseFont(0);
u8x8.print(F(" "));
}
u8x8.setInverseFont(0);
u8x8.setCursor(13, 7);
if (current_line * 100 / number_lines < 10) u8x8.print(F("0"));
u8x8.print(current_line * 100 / number_lines);
u8x8.print(F("%"));
}
void handle_events(void) {
if (long_press_event == 1) {
u8x8.clear();
u8x8.println("-PROGRAMMING MC-");
uint8_t error = 0;
u8x8.print("connect");
if (!start_pmode()) {
u8x8.println(".......OK");
u8x8.print("erase");
chip_erase();
u8x8.println(".........OK");
u8x8.print("fuse");
myFile = SD.open("/" + String(folder_name) + "/fuse.hex");
if (writing_from_file(myFile, write_fuse_page)) u8x8.println(F("........SKIP"));
else u8x8.println(F("..........OK"));
myFile.close();
u8x8.print("eeprom");
myFile = SD.open("/" + String(folder_name) + "/eeprom.hex");
if (writing_from_file(myFile, write_eeprom_page, print_proress_bar)) {
u8x8.setCursor(6, 4);
u8x8.println(F("......SKIP"));
} else {
u8x8.setCursor(6, 4);
u8x8.println(F("........OK"));
}
myFile.close();
u8x8.setCursor(0, 5);
u8x8.print("flash");
myFile = SD.open("/" + String(folder_name) + "/prog.hex");
if (writing_from_file(myFile, write_flash_page, print_proress_bar)) {
u8x8.setCursor(5, 5);
u8x8.println(F(".......SKIP"));
} else {
u8x8.setCursor(5, 5);
u8x8.println(F(".........OK"));
}
myFile.close();
u8x8.print("check");
myFile = SD.open("/" + String(folder_name) + "/prog.hex");
switch (writing_from_file(myFile, verification_flash_page, print_proress_bar)) {
case 0x13:
u8x8.setCursor(5, 6);
u8x8.println(F("......ERROR"));
error = 1;
break;
case 0:
u8x8.setCursor(5, 6);
u8x8.println(F(".........OK"));
break;
default:
u8x8.setCursor(5, 6);
u8x8.println(F(".......SKIP"));
}
} else {
u8x8.println("....ERROR");
error = 1;
}
myFile.close();
if (error) {
leds[0] = CRGB::Red;
leds[1] = CRGB::Red;
leds[2] = CRGB::Red;
FastLED.show();
u8x8.setCursor(0, 7);
u8x8.println(F(" -ERROR- "));
} else {
leds[0] = CRGB::White;
leds[1] = CRGB::Green;
leds[2] = CRGB::Green;
FastLED.show();
u8x8.setCursor(0, 7);
u8x8.println(F(" -COMPLITE- "));
}
end_pmode();
status = 1;
long_press_event = 0;
}
// 0 = not pushed, 1 = pushed
if (press_event == 1) {
str = "/" + String(folder_name) + "/readme.txt";
if (SD.exists(str)) {
open_info_file(str);
}
press_event = 0;
leds[0] = CRGB::White;
leds[1] = CRGB::Green;
leds[2] = CRGB::Green;
FastLED.show();
status = 0;
}
// 0 = not turning, 1 = CW, 2 = CCW
if (rotate_event == 1) {
if (status == 0) {
str = "/" + String(folder_name + 1) + "/readme.txt";
if (SD.exists(str)) {
++folder_name;
open_info_file(str);
}
}
rotate_event = 0;
}
if (rotate_event == 2) {
if (status == 0) {
str = "/" + String(folder_name - 1) + "/readme.txt";
if (SD.exists(str)) {
--folder_name;
open_info_file(str);
}
}
rotate_event = 0;
}
}
void yield() {
wdt_reset();
}
void setup(void) {
Serial.begin(115200);
Serial.println(F("START"));
u8x8.begin();
u8x8.setFlipMode(1);
u8x8.setFont(u8x8_font_amstrad_cpc_extended_f);
FastLED.addLeds<WS2811, A5, RGB>(leds, 3).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
leds[0] = CRGB::White;
leds[1] = CRGB::Green;
leds[2] = CRGB::Green;
FastLED.show();
versatile_encoder.setHandleRotate(handleRotate);
versatile_encoder.setHandlePressRelease(handlePressRelease);
versatile_encoder.setHandleLongPress(handleLongPress);
Serial.print(F("Initializing SD card..."));
u8x8.setCursor(2, 3);
u8x8.println("Initializing");
u8x8.setCursor(3, 4);
u8x8.println("SD card...");
if (SD_CD.readPin()) {
if (!SD.begin(10)) {
Serial.println(F("initialization failed!"));
u8x8.clear();
u8x8.setCursor(1, 3);
u8x8.println(F("error SD card!"));
leds[0] = CRGB::Red;
leds[1] = CRGB::Red;
leds[2] = CRGB::Red;
FastLED.show();
wdt_enable(WDTO_120MS);
while (!SD_CD.readPush()) {
wdt_reset();
}
while (1)
;
}
Serial.println(F("initialization done."));
u8x8.println("done.");
} else {
Serial.println(F("no SD card!"));
u8x8.clear();
u8x8.setCursor(2, 3);
u8x8.println(F("no SD card!"));
leds[0] = CRGB::Red;
leds[1] = CRGB::Red;
leds[2] = CRGB::Red;
FastLED.show();
wdt_enable(WDTO_120MS);
while (!SD_CD.readPush()) {
wdt_reset();
}
while (1)
;
}
str = "/" + String(folder_name) + "/readme.txt";
open_info_file(str);
}
void loop(void) {
if (SD_CD.readPop(100)) {
wdt_enable(WDTO_120MS);
while (1)
;
}
if (kill_key.readPin()) {
Serial.println(F("reset target"));
pinMode(ARDUINOISP_PIN_RESET, OUTPUT);
reset_target(true);
delay(50);
reset_target(false);
pinMode(ARDUINOISP_PIN_RESET, INPUT);
}
versatile_encoder.ReadEncoder(); // Do the encoder reading and processing
handle_events();
wdt_reset();
}
ARDUINOISP_FILE.h
#ifndef ARDUINOISP_FILE_H
#define ARDUINOISP_FILE_H
#include "ARDUINOISP.h"
#include <SdFat.h>
uint8_t buff[32];
uint8_t char_to_nible(char n) {
if (('0' <= n) && (n <= '9')) return uint8_t(n) - 48;
else if (('A' <= n) && (n <= 'F')) return uint8_t(n) - 55;
else return 0;
}
uint8_t read_byte(File &myFile) {
return char_to_nible(myFile.read()) * 16 + char_to_nible(myFile.read());
}
uint8_t writing_from_file(File &myFile, uint8_t (*write_page)(uint8_t *, uint16_t, uint16_t), void (*callback_progress_file)(uint32_t, uint32_t) = nullptr) {
uint8_t error = 0;
uint8_t checksum = 0;
if (myFile) {
uint32_t file_position = 0;
uint32_t file_size = myFile.size();
while (myFile.available()) {
char ch = myFile.read();
if (ch == ':') {
//читаем данные
uint8_t RECLEN = read_byte(myFile);
checksum += RECLEN;
uint8_t LOAD_OFFSET_HIGH = read_byte(myFile);
checksum += LOAD_OFFSET_HIGH;
uint8_t LOAD_OFFSET_LOW = read_byte(myFile);
checksum += LOAD_OFFSET_LOW;
uint16_t LOAD_OFFSET = LOAD_OFFSET_HIGH * 256 + LOAD_OFFSET_LOW;
uint8_t RECTYP = read_byte(myFile);
checksum += RECTYP;
for (int i = 0; i < RECLEN; ++i) {
uint8_t DATA = read_byte(myFile);
buff[i] = DATA;
checksum += DATA;
}
uint8_t CHKSUM = read_byte(myFile);
checksum += CHKSUM;
//проверяем контрольную сумму строки
if (checksum) {
error = 0x22;
break;
}
//пишем в МК
if (RECTYP == 0x00) {
error = write_page(buff, LOAD_OFFSET, RECLEN);
if (error) {
break;
}
}
}
file_position = myFile.position();
if (callback_progress_file) callback_progress_file(file_position, file_size);
}
} else {
error = 0x21;
}
return error;
}
#endif
ARDUINOISP.h
#ifndef ARDUINOISP_H
#define ARDUINOISP_H
#define ARDUINOISP_PIN_RESET A3
#define ARDUINOISP_PIN_MOSI A2
#define ARDUINOISP_PIN_MISO A1
#define ARDUINOISP_PIN_SCK A0
#define SPI_CLOCK_BB (1000000 / 6)
class BitBangedSPI {
public:
void begin() {
digitalWrite(ARDUINOISP_PIN_SCK, LOW);
digitalWrite(ARDUINOISP_PIN_MOSI, LOW);
pinMode(ARDUINOISP_PIN_SCK, OUTPUT);
pinMode(ARDUINOISP_PIN_MOSI, OUTPUT);
pinMode(ARDUINOISP_PIN_MISO, INPUT);
}
void beginTransaction(uint32_t clock) {
pulseWidth = (500000 + clock - 1) / clock;
if (pulseWidth == 0) {
pulseWidth = 1;
}
}
void end() {}
uint8_t transfer(uint8_t b) {
for (uint16_t i = 0; i < 8; ++i) {
digitalWrite(ARDUINOISP_PIN_MOSI, (b & 0x80) ? HIGH : LOW);
digitalWrite(ARDUINOISP_PIN_SCK, HIGH);
delayMicroseconds(pulseWidth);
b = (b << 1) | digitalRead(ARDUINOISP_PIN_MISO);
digitalWrite(ARDUINOISP_PIN_SCK, LOW); // slow pulse
delayMicroseconds(pulseWidth);
}
return b;
}
private:
unsigned long pulseWidth; // in microseconds
};
static BitBangedSPI SPI_BB;
uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
SPI_BB.transfer(a);
SPI_BB.transfer(b);
SPI_BB.transfer(c);
return SPI_BB.transfer(d);
}
void isp_wait() {
while (spi_transaction(0xF0, 0x00, 0x00, 0x00) & 0x01) {
delay(1);
}
}
void reset_target(bool reset) {
digitalWrite(ARDUINOISP_PIN_RESET, reset ? LOW : HIGH);
}
uint8_t spi_enable_prog_mode() {
SPI_BB.transfer(0xAC);
SPI_BB.transfer(0x53);
uint8_t result = !(SPI_BB.transfer(0x00) == 0x53);
SPI_BB.transfer(0x00);
return result;
}
uint8_t start_pmode() {
reset_target(true);
pinMode(ARDUINOISP_PIN_RESET, OUTPUT);
SPI_BB.begin();
SPI_BB.beginTransaction(SPI_CLOCK_BB);
digitalWrite(ARDUINOISP_PIN_SCK, LOW);
delay(20);
reset_target(false);
delayMicroseconds(100);
reset_target(true);
delay(50);
return spi_enable_prog_mode();
}
void end_pmode() {
SPI_BB.end();
pinMode(ARDUINOISP_PIN_MOSI, INPUT);
pinMode(ARDUINOISP_PIN_SCK, INPUT);
reset_target(false);
pinMode(ARDUINOISP_PIN_RESET, INPUT);
}
void write_flash(uint8_t hilo, uint16_t addr, uint8_t data) {
spi_transaction(0x40 + 8 * hilo, addr >> 8 & 0xFF, addr & 0xFF, data);
}
void commit(uint16_t addr) {
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
}
uint8_t write_flash_page(uint8_t *buff, uint16_t start, uint16_t length) {
uint16_t here = start / 2;
int x = 0;
uint16_t page = here & 0xFFFFFFF0;
while (x < length) {
if (page != here & 0xFFFFFFF0) {
commit(page);
page = here & 0xFFFFFFF0;
isp_wait();
}
write_flash(LOW, here, buff[x++]);
write_flash(HIGH, here, buff[x++]);
here++;
}
commit(page);
isp_wait();
return 0;
}
uint8_t flash_read(uint8_t hilo, uint16_t addr) {
return spi_transaction(0x20 + hilo * 8, (addr >> 8) & 0xFF, addr & 0xFF, 0);
}
uint8_t verification_flash_page(uint8_t *buff, uint16_t start, uint16_t length) {
uint16_t here = start / 2;
int x = 0;
while (x < length) {
uint8_t low = flash_read(LOW, here);
uint8_t high = flash_read(HIGH, here);
here++;
if (!((buff[x++] == low) && (buff[x++] == high))) return 0x13;
}
return 0;
}
uint8_t write_eeprom_page(uint8_t *buff, uint16_t start, uint16_t length) {
for (uint16_t x = 0; x < length; x++) {
uint16_t addr = start + x;
spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);
isp_wait();
}
return 0;
}
uint8_t write_fuse_page(uint8_t *buff, uint16_t start, uint16_t length) {
//low
spi_transaction(0xAC, 0xA0, 0x00, buff[0]);
isp_wait();
//high
spi_transaction(0xAC, 0xA8, 0x00, buff[1]);
isp_wait();
//extend
spi_transaction(0xAC, 0xA4, 0x00, buff[2]);
isp_wait();
//lock
spi_transaction(0xAC, 0xE0, 0x00, buff[3]);
isp_wait();
return 0;
}
void chip_erase() {
spi_transaction(0xAC, 0x80, 0x00, 0x00);
isp_wait();
};
//отладочные функции
void Serial_print_HEX(uint8_t n) {
if (n <= 0x0F) Serial.print("0");
Serial.print(n, HEX);
}
void flash_read_page(uint16_t start, int length) {
uint16_t here = start / 2;
for (int x = 0; x < length; x += 2) {
uint8_t low = flash_read(LOW, here);
Serial_print_HEX(low);
Serial.print(" ");
uint8_t high = flash_read(HIGH, here);
Serial_print_HEX(high);
Serial.print(" ");
here++;
}
Serial.println();
}
void eeprom_read_page(uint16_t start, int length) {
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_HEX(ee);
Serial.print(" ");
}
}
void read_signature() {
Serial.print("signature: ");
uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
Serial_print_HEX(high);
Serial.print(" ");
uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
Serial_print_HEX(middle);
Serial.print(" ");
uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
Serial_print_HEX(low);
Serial.println(" ");
}
void read_fuse() {
Serial.print("fuse high: ");
Serial_print_HEX(spi_transaction(0x58, 0x08, 0x00, 0x00));
Serial.println();
Serial.print("fuse low: ");
Serial_print_HEX(spi_transaction(0x50, 0x00, 0x00, 0x00));
Serial.println();
Serial.print("extend: ");
Serial_print_HEX(spi_transaction(0x50, 0x08, 0x00, 0x00));
Serial.println();
Serial.print("lock: ");
Serial_print_HEX(spi_transaction(0x58, 0x00, 0x00, 0x00));
Serial.println();
}
#endif