Портативный автономный программатор.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Портативный автономный программатор.
В какой-то момент заинтересовала меня тема автономного программатора, то есть устройства, которое позволяет прошить микроконтроллер без участия компьютера. По большому счёту необходимость в нём может возникнуть довольно редко, но тем не менее хотелось бы такой иметь "шоб был". Тем более, что ISP-программатор можно сделать на любой Arduino, значит это не должно составить особого труда. Поиск по сети выдаёт практически единственный вариант, перепечатанный на многих сайтах. Очень хорошо он описан здесь: http://www.tehnari.ru/f115/t104559/ Программатор очень хорош и лёгок в повторении, но не устраивает по некоторым параметрам. А так как исходники автор не предоставил (что вовсе не мешает народу его производить и продавать), изменить что-то практически нереально.
Что меня не устраивает в авторском варианте?
1. Хотелось бы иметь возможность сделать его на других дисплеях, дешевле, с большим разрешением, возможно, компактнее, у меня минимум два варианта.
2. Авторский вариант поддерживает только керты памяти MicroSD старого формата до 2 Гб, которые сейчас трудно достать. Библиотеки SD позволяют использовать современные карты памяти.
3. Без карты памяти программатор "превращается в тыкву", даже надпись об ошибке на экране отображается некорректно. Хочется, чтоб основные возможности были доступны без карты памяти.
4*. Бонусная хотелка. Обойтись вообще без карты памяти. Для этого нужна микросхема памяти, которая стоит сущие копейки, софтовая реализация USB интерфейса для загрузки прошивки с компа, и терминальная программа для преобразования НЕХ-файла и отправки с компа в память программатора. Последнее для меня вообще тёмный лес, надежда на специалистов.
5*. Исходя из предыдущего пункта, напрашивается ещё один вариант. Если нужно в 100500 контроллеров залить одинаковую прошивку, которая влезает в программную память контроллера программатора, достаточно преобразовать НЕХ-файл в массив байтов с помощью скрипта на компьютере (здесь для меня опять тёмный лес), и вставить в код программатора. А так как дисплей в данном случае необязателен, то можно просто закинуть созданный скетч в первую попавшуюся плату Arduino, и с повербанком отправиться в горы прошивать 100500 контроллеров (а где ещё может быть недоступен компьютер?). Вот как раз для последнего варианта в сети нашёлся ещё один вариант программатора: сверхмобильная прошивалка http://we.easyelectronics.ru/AVR/sverhmobilnaya-proshivalka-avr-po-jtag.html  Запустить её я смог только переписав код почти полностью, но за идею спасибо.
6*. В связи с этим вспомнил про ещё важную хотелку: возможность выбора в меню программатора интерфейса программирования- ISP (по умолчанию), JTAG, TPI (Attiny10).

Сама последовательность прошивки контроллеров очень хорошо описана в статье Прошиваем AVR вручную https://habr.com/ru/post/152052/  Думаю, без этой статьи у меня бы вообще ничего не получилось.
Ниже тестовый скетч для прошивки Attiny13 при помощи Arduino, заливаем в Arduino, подсоединяем к Attiny13, и просто подаём питание на Arduino, можно даже с повербанка.
Если включить Монитор порта (при питании Arduino от USB компьютера), то в мониторе будет отображаться сигнатура прошиваемого контроллера и ход записи и чтения прошивки. Внимание! Каждый раз при запуске Монитора порта Arduino перезагружается и выполняет скетч заново, соответственно по-новой перезаписывая Attiny. Это не страшно, но если в неподходящий момент вынуть из USB, можно испортить Attiny. Я так в процессе экспериментов запорол Atmega64. Прошивка происходит в течение пары секунд после подачи питания, далее можно проверять Attiny в действии: при низком уровне на входе 3 (это нога 2 тини13) светится светодиод на выходе 2 (это нога 7 тини13), его роль выполняет светодиод Arduino, и не светится при высоком, просто подсоединяем ножку 2 тини13 к ножке 4 (GND) или к ножке 8 (VCC).

#include "Arduino.h"
// Подключение
//Arduino   ->  tiny13
// GND      ->  4 (GND)
// 2        ->  8 (VCC)
// 10       ->  1 (reset)
// 11(MOSI) ->  5 (MOSI)
// 12(MISO) ->  6 (MISO)
// 13(SCK)  ->  7 (SCK)

#define VCC     2 // Питание на прошиваемый контроллер подаётся с ноги 2 прошивающего
#define RESET     10 // reset прошиваемого контроллера еодключается к ноге 10 прошивающего
#define SPI_CLOCK     (128000/6) // скорость прошивки

#include "SPI.h"

//Здесь НЕХ файл, который нужно прошить
const byte PROGMEM store[16*2*32] = { // 32 страницы по 16 слов по 2 байта
  0x09, 0xC0, 0x0E, 0xC0, 0x0D, 0xC0, 0x0C, 0xC0,
  0x0B, 0xC0, 0x0A, 0xC0, 0x09, 0xC0, 0x08, 0xC0,
  0x07, 0xC0, 0x06, 0xC0, 0x11, 0x24, 0x1F, 0xBE,
  0xCF, 0xE9, 0xCD, 0xBF, 0x02, 0xD0, 0x08, 0xC0,
  0xEF, 0xCF, 0xBA, 0x9A, 0xB3, 0x99, 0x02, 0xC0,
  0xC2, 0x9A, 0xFC, 0xCF, 0xC2, 0x98, 0xFA, 0xCF,
  0xF8, 0x94 , 0xFF, 0xCF
};
static bool rst_active_high;

void setup() {
  Serial.begin(115200);
  Serial.println("Wait..."); delay(10);
  unsigned int addr = 0;
  unsigned int _word;  // счетчик байтов внутре страничек
  unsigned char k;  // байт для записи
  unsigned char kk;  // байт для чтения
  start_pmode();
  read_signature();
  Serial.println("chip erase"); delay(10);
  spi_transaction(0xAC, 0x80, 0xFF, 0xFF); // ОЧИСТКА ! // chip erase
  delay(20);
  /*flash(0, 0, 0x09);
  flash(1, 0, 0xC0 );
  flash(0, 1, 0x0E);
  flash(1, 1, 0xC0 );
  flash(0, 2, 0x0D);
  flash(1, 2, 0xC0 );
  flash(0, 3, 0x0C);
  flash(1, 3, 0xC0 );
  flash(0, 4, 0x0B);
  flash(1, 4, 0xC0 );
  flash(0, 5, 0x0A);
  flash(1, 5, 0xC0 );
  flash(0, 6, 0x09);
  flash(1, 6, 0xC0 );
  flash(0, 7, 0x08);
  flash(1, 7, 0xC0 );
  flash(0, 8, 0x07);
  flash(1, 8, 0xC0 );
  flash(0, 9, 0x06);
  flash(1, 9, 0xC0 );
  flash(0, 10, 0x11);
  flash(1, 10, 0x24 );
  flash(0, 11, 0x1F);
  flash(1, 11, 0xBE );
  flash(0, 12, 0xCF);
  flash(1, 12, 0xE9 );
  flash(0, 13, 0xCD);
  flash(1, 13, 0xBF );
  flash(0, 14, 0x02);
  flash(1, 14, 0xD0 );
  flash(0, 15, 0x08);
  flash(1, 15, 0xC0 );
  delay(5);
  spi_transaction(0x4C, 0x00, 0x00, 0x00);// write page00
  delay(5);
  flash(0, 0, 0xEF);
  flash(1, 0, 0xCF );
  flash(0, 1, 0xBA);
  flash(1, 1, 0x9A );
  flash(0, 2, 0xB3);
  flash(1, 2, 0x99 );
  flash(0, 3, 0x02);
  flash(1, 3, 0xC0 );
  flash(0, 4, 0xC2);
  flash(1, 4, 0x9A );
  flash(0, 5, 0xFC);
  flash(1, 5, 0xCF );
  flash(0, 6, 0xC2);
  flash(1, 6, 0x98 );
  flash(0, 7, 0xFA);
  flash(1, 7, 0xCF );
  flash(0, 8, 0xF8);
  flash(1, 8, 0x94 );
  flash(0, 9, 0xFF);
  flash(1, 9, 0xCF );
  delay(5);
  spi_transaction(0x4C, 0x00, 0x10, 0x00);// write page01
  delay(50);*/

  Serial.println("Flash"); delay(10);
  for (int _page = 0; _page < 32; _page++) //
  {
    // прочитали страницу из хранилища (16*2=32 байт)
    // положили побайтно во FlashPage
    for (_word = 0; _word < 16; _word++)
    {
      k = pgm_read_byte(&(store[_page * 32 + _word * 2]));
      // загрузка младшего байта слова;
      spi_transaction(0x40, 0x00, _word, k);//
      k = pgm_read_byte(&(store[_page * 32 + _word * 2 + 1]));
      // загрузка старшего байта слова;
      spi_transaction(0x48, 0x00, _word, k);//
    }
    // прошиваем
    spi_transaction(0x4C, _page >> 4, _page << 4, 0x00); // write page
    // ожидание записи странички не менее 4,5 милисекунд
    delay(5);
  }
  delay(10);
  // Проверяем, прочитав записанное
  Serial.println("+++Verify+++");
  for (int addr = 0; addr < (16 * 32); addr++)
  {
    k = pgm_read_byte(&(store[addr * 2]));
    kk = spi_transaction(0x20, 0x1F & (addr >> 8), addr & 0xFF, 0xFF); //Lbyte
    Serial.println(kk, HEX);
    if (k != kk) end_pmode();
    k = pgm_read_byte(&(store[addr * 2 + 1]));
    kk = spi_transaction(0x28, 0x1F & (addr >> 8), addr & 0xFF, 0xFF); //Hbyte
    Serial.println(kk, HEX);
    if (k != kk) end_pmode();
  }
  Serial.println("Verify OK!");

  end_pmode();
}

void loop() { // пустой ыикл, всё сделано в void setup
}

// Чтение сигнатуры прошиваемого контроллера
void read_signature() { 
  Serial.println("read_signature"); delay(10);
  uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
  Serial.println(high + 0, HEX);
  uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
  Serial.println(middle + 0, HEX);
  uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
  Serial.println(low + 0, HEX);
  Serial.println("*****");
}

void start_pmode() {
  Serial.println("start_pmode"); delay(10);
  reset_target(true);
  pinMode(RESET, OUTPUT); // сначала сброс
  digitalWrite(VCC, LOW);
  pinMode(VCC, OUTPUT);
  SPI.begin();
  SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0));
  digitalWrite(SCK, LOW);
  delay(20); 
  reset_target(false);
  delayMicroseconds(100);
  reset_target(true);
  delay(50);
  digitalWrite(VCC, 1); // только потом подаём питание на прошиваемый контроллер
  delay(50); // datasheet: must be > 20 msec
  spi_transaction(0xAC, 0x53, 0x00, 0x00); // команда не включение режима программирования
}

void end_pmode() {
  SPI.end();
  // все ноги прошивающего делаем входами, не мешаем прошитому контроллеру выполнять работу
  pinMode(MOSI, INPUT);
  pinMode(SCK, INPUT);
  reset_target(false);
  pinMode(RESET, INPUT);
}

uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  Serial.print(a, HEX); // печать в порт для контроля
  Serial.print('-');
  Serial.print(b, HEX);
  Serial.print('-');
  Serial.print(c, HEX);
  Serial.print('-');
  Serial.println(d, HEX);
  SPI.transfer(a);
  SPI.transfer(b);
  SPI.transfer(c);
  return SPI.transfer(d);
}

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


void flash(uint8_t hilo, unsigned int addr, uint8_t data) {
  spi_transaction(0x40 + 8 * hilo,
                  addr >> 8 & 0xFF,
                  addr & 0xFF,
                  data);
}

// Такой код скомпилирован для Attiny13
/*
// attiny13

#include <avr/io.h>

int main (void) {
   bitWrite(DDRB, 2, 1);
  while (1) {
    bitWrite(PORTB, 2, !bitRead(PINB, 3));
  }
}

// HEX file
:1000000009C00EC00DC00CC00BC00AC009C008C09A
:1000100007C006C011241FBECFE9CDBF02D008C063
:10002000EFCFBA9AB39902C0C29AFCCFC298FACF66
:04003000F894FFCF72
:00000001FF

// HEX file. разобранный на байты:

09C0 0EC0 0DC0 0CC0 0BC0 0AC0 09C0 08C0
07C0 06C0 1124 1FBE CFE9 CDBF 02D0 08C0

EFCF BA9A B399 02C0 C29A FCCF C298 FACF
F894 FFCF
*/

Есть ещё заготовка кода для чтения НЕХ файла с карты памяти и расшифровки его, я над этим корпел целую неделю, выложу позже.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Жаль, ни одного ответа пока, неужели тема интересна только мне?
Я всё же надеюсь на помощь коллективного разума, поэтому информацию буду выкладывать пошагово и с подробными комментариями, чтоб в любом месте меня могли поправить, подсказать или оптимизировать.
 Для следующего шага нужен Модуль SD карты и Arduino, у меня такой, как на картинке, и подключение такое же.

На карту памяти закидываем несколько НЕХ файлов. И далее при помощи Arduino раскладываем их на составляющие и "виртуально прошиваем микроконтроллер", то есть на самом деле отправляем всё в Монитор порта и сверяем с тем, что хотелось бы получить.
 Я не буду комментировать ту часть скетча, где SD карта инициализируется и выводится в монитор список файлов с карты. Далее в монитор вводим в зависимости от выбранного номера файла символ от 1 до 9 (далее a, b, c, d, и т.д) и нажимаем Enter, и видим на мониторе результат обработки файла.
 Далее в скетче:

Читаем содержимое файла до окончания файла

while (dataFile.available()) { 

Так как первая строка любого НЕХ файла выглядит примерно так:
   :100000000C94A6000C94B8000C94B8000C94B800A2
То первым под обработку попадает символ ":" , вот от него и будем отталкиваться

if (dataFile.read() == ':') {

Дальше обнуляем байт контрольной суммы, он понадобится позже

byte sum = 0;

 После двоеточия читаем два символа- один байт

char char_1 = (dataFile.read());       
char char_2 = (dataFile.read());  

В строке выше это "1" и "0", то есть 10 в шестнадцатеричной или 16 в десятичной- это количество байтов данных в записи, нам нужно преобразовать два символа в число

byte length_str = convertCharToHex(char_1) << 4 | convertCharToHex(char_2);

Здесь приходится обратиться к подпрограмме преобразования, пришлось слелать очень примитивно, но пока это нас устраивает

char convertCharToHex(char ch)
{
  char returnType;
  switch (ch)
  {
    case '0':
      returnType = 0;
      break;
    case  '1' :
      returnType = 1;
      break;
    . . . . . . .

Я искал способ сделать это правильно, но пока не нашёл. Поехали дальше. Прибавляем полученное число к контрольной сумме и печатаем его же в монитор, в шестнадцатеричном виде

sum = sum + length_str;
Serial.print(length_str, HEX);

Печатаем "а" в монитор, чтобы не запутаться в цифрах на мониторе, дальше будет адрес загрузки данных

Serial.print('a');

Читаем из файла ещё 4 символа- адрес

      char char_3 = (dataFile.read());
      char char_4 = (dataFile.read());
      char char_5 = (dataFile.read());
      char char_6 = (dataFile.read());

 Преобразуем их  в четырёхзначное число

addr_data = convertCharToHex(char_3) << 12 | convertCharToHex(char_4) << 8 | convertCharToHex(char_5) << 4 | convertCharToHex(char_6);

Снова прибавляем полученное число к контрольной сумме, но здесь засада- у нас число четырёхзначное, а прибавлять нужно два двухзначных

sum = sum + (convertCharToHex(char_3) << 4 | convertCharToHex(char_4));
sum = sum + (convertCharToHex(char_5) << 4 | convertCharToHex(char_6));

Печатаем число адреса в монитор

Serial.print(addr_data, HEX);

Ещё два символа или один байт- тип записи (00- данные, 01- конец файла, ещё бывает 02 или 03, об этом позже). Не забываем о контрольной сумме.

      Serial.print('t');
      char char_7 = (dataFile.read());
      char char_8 = (dataFile.read());
      byte tipe_ = convertCharToHex(char_7) << 4 | convertCharToHex(char_8);
      sum = sum + tipe_;
      Serial.print(tipe_, HEX);

Ну и дальше читаем кучу символов данных, каждые два символа- это один байт. Читаем по паре символов N-ное количество раз, а именно количество байтов данных length_str, полученное в начале

Serial.print(" data ");
      for (int i = 0; i < length_str; i++) {
        char char_01 = (dataFile.read());
        char char_02 = (dataFile.read());
        data_ = convertCharToHex(char_01) << 4 | convertCharToHex(char_02);

Каждый из полученных файлов данных сохраняем в ранее созданный массив, размер массива должен быть не менее длины страницы для записи во FLASH

buf_data_byte[num_data_byte] = data_;

 После каждого записанного в массив байта прибавляем счётчик байтов, чтоб следующий байт попал в следующую ячейку массива

num_data_byte++;

 Ну и контрольную сумму продолжаем считать, и печатаем каждый байт, а после каждого байта печатаем пробел для разделения

        sum = sum + data_;
        Serial.print(data_, HEX);
        Serial.print(' ');
      }

Закончили упражнение. Все 16 байтов выведены на экран
Читаем ещё два символа- они должны быть последние в строке, это контрольная сумма

      char char_9 = (dataFile.read());
      char char_10 = (dataFile.read());
      byte summa = convertCharToHex(char_9) << 4 | convertCharToHex(char_10);

Это была сумма, прописанная в файле, а мы заканчиваем считать нашу

sum = 0 - sum;

Так как это байтовая переменная, получается то же число, что и в файле.Можем убедиться на экране монитора

      Serial.print('s');
      Serial.print(sum, HEX);
      Serial.print('-');
      Serial.println(summa, HEX);

Итак,исходная строка, и полученная в мониторе:
:100000000C94A6000C94B8000C94B8000C94B800A2
10a0t0 data C 94 A6 0 C 94 B8 0 C 94 B8 0 C 94 B8 0 sA2-A2
 То же самое для другой строки:
:1000E0000810204080048040201008040201010212
10aE0t0 data 8 10 20 40 80 4 80 40 20 10 8 4 2 1 1 2 s12-12
 Закрываем цикл, начавшийся с поиска символа двоеточия
 Дальше программа возвращается е началу цикла, то есть снова ищет символ двоеточия
 И расшифровывает следующую строку

 Но в каждой строке только 16 байт данных. А для записи страницы во FLASH нужно сохранить в  массив от 32 байт (для Аttiny13 это 16 слов по 2 байта) до 256 байт (для ATmega128 это 128 слов по 2 байта). Казалось бы, что проще? Досчитываем num_data_byte до нужной цифры, и даём команду на запись страницы. Но как вам такой фрагмент файла:
:04FE8000019608954A
:02FFFE000206F9

Здесь 4 байта нужно прошить по адресу FE80, и 2 байта по адресу FFFE, а это совсем на разных страницах. Поэтому после загрузки в массив первых 4 байтов (и возможно данных перед ними) нужно записать страницу, далее загрузить следущие данные, и записать следующую страницу.
После прочтения адреса в записи добавляем следующие проверки:

      if (num_data_byte == 0)ADDR_data = addr_data;
      if (addr_data - ADDR_data > Words_ * 2) {
        Write_Page();
        ADDR_data = addr_data;
        _page = ADDR_data / (Words_ * 2);
        ADDR_data = _page * Words_ * 2;
        num_data_byte = addr_data - ADDR_data; //........
      }

Здесь трудно объяснить, кто захочет, разберётся (Words_ - это количество слов на странице для заданного контроллера).

Ну и результирующий скетч.


#include <SPI.h>
#include <SD.h>
byte num;
byte data_;
int _page = 0;
int num_data_byte = 0;   
uint16_t ADDR_data; // uint16_t
uint16_t addr_data; // uint16_t
String Name_[15];
File dataFile;
File root;
boolean SDfound;
byte buf_data_byte[256];//буфер для загрузкм страницы с карты памяти
int Words_;
//int Pages_ = 64;

void setup()
{
  pinMode(10, OUTPUT);
  pinMode(9, OUTPUT);
  Serial.begin(115200);
  Serial.print("Initializing SD card...");

  if (!SD.begin(10)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  root = SD.open("/");
  printDirectory(root, 0);
  Serial.println("done!");
}

void loop()
{ //Serial.println(num);
  for (uint8_t i = 1; i < (num + 1); i++) {
    Serial.print(i);
    Serial.print("-> ");
    Serial.println(Name_[i]);
  }
  Serial.print( F( "NumFile 1,2,3,4,5,6,7,8,9,0,a,b,c,d,e,f_" ) );

  for ( ;; ) {
    switch ( serial_read() ) {
// значения Words_   соответствуют файлам на моей карте памяти, для проверки вам подойдут
      case '1':    Words_ = 16; READ(1);    break;
      case '2':    Words_ = 16; READ(2);    break;
      case '3':    Words_ = 64; READ(3);    break;
      case '4':    Words_ = 64; READ(4);    break;
      case '5':    Words_ = 64; READ(5);    break;
      case '6':    Words_ = 128; READ(6);   break;
      case '7':    Words_ = 64; READ(7);    break;
      case '8':    READ(8);    break;
      case '9':    READ(9);    break;
      case 'a': case 'A':   READ(10);    break;
      case 'b': case 'B':   Words_ = 64; READ(11);    break;
      case 'c': case 'C':   READ(12);    break;
      case 'd': case 'D':   READ(13);    break;
      case 'e': case 'E':   READ(14);    break;
      case 'f': case 'F':   READ(15);    break;

      case ' ': case '\t': case '\r': case '\n':      continue;

      default: {
        } break;
    }
    break;
  }
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    else num = num + 1;
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(num);
    Serial.print("-> ");
    Name_[num] = entry.name();
    Serial.print(Name_[num]);
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void READ(byte num) {
  Serial.println("Initializing SD card..."); // Инициализация SD-карты...
  Serial.print("num file ");
  Serial.println(num);
  Serial.println(Name_[num]);
  dataFile = SD.open(Name_[num]);//Откроем файл
  Serial.println("SD card ok.");

  if (!dataFile)
  {
    Serial.print("text fail eror"); // Текстовый файл не открывается
    while (1);
  }
  num_data_byte = 0;
  for (int i = 0; i < Words_ * 2; i++) { //очистка буфера страницы
    buf_data_byte[i] = 255;
  }
  while (dataFile.available()) //Читаем содержимое файла до окончания файла
  { if (dataFile.read() == ':') {
      byte sum = 0;
      char char_1 = (dataFile.read());       
      char char_2 = (dataFile.read());       
      byte length_str = convertCharToHex(char_1) << 4 | convertCharToHex(char_2);
      sum = sum + length_str;
      Serial.print(length_str, HEX);
      Serial.print('a');     
      char char_3 = (dataFile.read());
      char char_4 = (dataFile.read());
      char char_5 = (dataFile.read());
      char char_6 = (dataFile.read());
      int addr_data1 = convertCharToHex(char_3) << 4 | convertCharToHex(char_4);
      int addr_data2 = convertCharToHex(char_5) << 4 | convertCharToHex(char_6);
      addr_data = addr_data1*256+addr_data2;   
      //addr_data = convertCharToHex(char_3) << 12 | convertCharToHex(char_4) << 8 | convertCharToHex(char_5) << 4 | convertCharToHex(char_6);
      if (num_data_byte == 0)ADDR_data = addr_data;
      if (addr_data - ADDR_data > Words_ * 2) {
        Write_Page();
        ADDR_data = addr_data;
        _page = ADDR_data / (Words_ * 2);
        ADDR_data = _page * Words_ * 2;
        num_data_byte = addr_data - ADDR_data; //........
      }
      sum = sum + (convertCharToHex(char_3) << 4 | convertCharToHex(char_4));
      sum = sum + (convertCharToHex(char_5) << 4 | convertCharToHex(char_6));
      Serial.print(addr_data, HEX);
      Serial.print('t');
      char char_7 = (dataFile.read());
      char char_8 = (dataFile.read());
      byte tipe_ = convertCharToHex(char_7) << 4 | convertCharToHex(char_8);
      sum = sum + tipe_;
      Serial.print(tipe_, HEX);
      //if (tipe_ == 1 || tipe_ == 3)goto label; // переходим к метке label
      //if (tipe_ == 2)..........; // здесь должен быть переход к следующему сектору flash для Атмега128, 256
      Serial.print(" data ");
      for (int i = 0; i < length_str; i++) {
        char char_01 = (dataFile.read());
        char char_02 = (dataFile.read());
        data_ = convertCharToHex(char_01) << 4 | convertCharToHex(char_02);

        if (i == 0) {
        //ADDR_data = addr_data;
        //_page = ADDR_data / (Words_ * 2);
        //ADDR_data = _page * Words_ * 2;
        num_data_byte = addr_data - ADDR_data; //........
      }
      buf_data_byte[num_data_byte] = data_;
        num_data_byte++;
        sum = sum + data_;
        Serial.print(data_, HEX);
        Serial.print(' ');

        if (num_data_byte == (Words_ * 2)) Write_Page();
      }
      char char_9 = (dataFile.read());
      char char_10 = (dataFile.read());
      byte summa = convertCharToHex(char_9) << 4 | convertCharToHex(char_10);
      sum = 0 - sum;
      Serial.print('s');
      Serial.print(sum, HEX);
      Serial.print('-');
      Serial.println(summa, HEX);
    }
  }
label:
  dataFile.close(); //закроем файл
}

uint8_t serial_read() {
  while ( Serial.available() < 1 ) ;
  return Serial.read();
}

char convertCharToHex(char ch)
{
  char returnType;
  switch (ch)
  {
    case '0':
      returnType = 0;
      break;
    case  '1' :
      returnType = 1;
      break;
    case  '2':
      returnType = 2;
      break;
    case  '3':
      returnType = 3;
      break;
    case  '4' :
      returnType = 4;
      break;
    case  '5':
      returnType = 5;
      break;
    case  '6':
      returnType = 6;
      break;
    case  '7':
      returnType = 7;
      break;
    case  '8':
      returnType = 8;
      break;
    case  '9':
      returnType = 9;
      break;
    case  'A':
      returnType = 10;
      break;
    case  'B':
      returnType = 11;
      break;
    case  'C':
      returnType = 12;
      break;
    case  'D':
      returnType = 13;
      break;
    case  'E':
      returnType = 14;
      break;
    case  'F' :
      returnType = 15;
      break;
    default:
      returnType = 0;
      break;
  }
  return returnType;
}


void Write_Page() {
  digitalWrite(10, 0);
  digitalWrite(9, 1);
  Serial.println('/');
  _page = ADDR_data / (Words_ * 2);
  Serial.print("PAGE ");
  Serial.print(ADDR_data, HEX);
  Serial.print('/');
  Serial.print(addr_data, HEX);
  Serial.print('/');
  Serial.print(_page, HEX);
  Serial.print("-> ");

  for (int _data = 0; _data < Words_ * 2; _data++) {
    Serial.print(buf_data_byte[_data], HEX);
    Serial.print('-');
  }
  Serial.println('/');
  digitalWrite(9, 0);
  digitalWrite(10, 1);
  num_data_byte = 0;
  for (int i = 0; i < Words_ * 2; i++) { //очистка буфера страницы
    buf_data_byte[i] = 255;
  }
}

b707
Offline
Зарегистрирован: 26.05.2017

Код преобразования CharToHex записывается в одну строчку:
hex = char - '0';

Что касается остального - поражаюсь смелости людей, которые берутся за программатор, хотя для них работа с hex файлом "темный лес":)

подпишусь, пожалуй, это должно быть забавно

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

b707 пишет:
подпишусь, пожалуй, это должно быть забавно

Если "чисто поржать", то не надо. Я сюда за помощью пришёл, а не стать посмешищем. И не писал я, что для меня работа с hex файлом "темный лес", а имел ввиду "темный лес"- создание терминальной программы.

Ваш вариант преобразования я пробовал одним из первых, он мне не понравился. Если предложите рабочий вариант подпрограммы char convertCharToHex(char ch), которым я смогу заменить тот, что сейчас в скетче, и он будет корректно работать во всех ситуациях, я буду благодарен. Сейчас ваш вариант часть НЕХ файлов "переводит" неправильно, в отличие от моего деревянного.

Кстати, забыл вчера привести результаты обработки. Закидываем на карту памяти в качестве примера НЕХ файл из первого поста

:1000000009C00EC00DC00CC00BC00AC009C008C09A
:1000100007C006C011241FBECFE9CDBF02D008C063
:10002000EFCFBA9AB39902C0C29AFCCFC298FACF66
:04003000F894FFCF72
:00000001FF

Получаем в Мониторе результат

10a0t0 data 9 C0 E C0 D C0 C C0 B C0 A C0 9 C0 8 C0 s9A-9A
10a10t0 data 7 C0 6 C0 11 24 1F BE CF E9 CD BF 2 D0 8 C0 /
PAGE 0/10/0-> 9-C0-E-C0-D-C0-C-C0-B-C0-A-C0-9-C0-8-C0-7-C0-6-C0-11-24-1F-BE-CF-E9-CD-BF-2-D0-8-C0-/
s63-63
10a20t0 data EF CF BA 9A B3 99 2 C0 C2 9A FC CF C2 98 FA CF s66-66
4a30t0 data F8 94 FF CF s72-72
0a/
PAGE 20/0/1-> EF-CF-BA-9A-B3-99-2-C0-C2-9A-FC-CF-C2-98-FA-CF-F8-94-FF-CF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-/
0t1 data sFF-FF

Две самые длинные строки (PAGE 0/10/0-> и PAGE 20/0/1->) - это как раз то, что должно записаться в первые две страницы FLASH памяти.

Само-собой, я проверял и другие НЕХ файлы, около 15 штук с разным размером строки и под разные контроллеры (что выражается в разных размерах страницы записи), объёмом до 128 килобайт, проверял от корки до корки, всё декодируется правильно.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Сейчас мне нужна информация о формате отображения номера страницы при записи страницы в память контроллера. Для Attiny13 формат такой

01001100 0000000a bbbbxxxx xxxxxxxx

Где abbbb - это номер записываемой страницы.

Для Atmega64 формат вроде такой

01001100  xaaaaaaa  bxxxxxxx  xxxxxxxx

Где aaaaaaab - это номер записываемой страницы.

Для Atmega128 формат такой

01001100  aaaaaaaa  bxxxxxxx  xxxxxxxx

Где aaaaaaaab - это номер записываемой страницы.

Это информация из даташитов. Но, во-первых, непонятно почему формат записи для Attiny13 не вписывается в общие правила, а во-вторых, где взять даные для всего списка возможных контроллеров?

Ну ещё меня интересует количество страниц и слов на странице для разных контроллеров, потому что непросто перерыть  шесть десятков даташитов.

<добавлено позже>

Раскусил! В третьем байте после номера страницы должен поместиться номер последнего слова страницы, то есть для тини13 это 1111 (15-е слово), соответственно 4 символа. Всё равно требуется информация про количество страниц и слов на странице для разных контроллеров. Где найти?

 

rkit
Онлайн
Зарегистрирован: 23.11.2016

Это делается телефоном и обычным юсбаспом. Нафиг не нужно паять и таскать с собой лишнюю железку, трахаться с картой, и так далее.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Можете назвать конкретное приложение для Андроид?

b707
Offline
Зарегистрирован: 26.05.2017

seri0shka пишет:

Ваш вариант преобразования я пробовал одним из первых, он мне не понравился. Если предложите рабочий вариант подпрограммы char convertCharToHex(char ch), которым я смогу заменить тот, что сейчас в скетче, и он будет корректно работать во всех ситуациях, я буду благодарен. Сейчас ваш вариант часть НЕХ файлов "переводит" неправильно, в отличие от моего деревянного.

простите, но вы пишете бред. Примерно как "я попробовал проверить , равно ли 2*2 =4 и выяснил, что это верно не всегда "

Ваш код

char convertCharToHex(char ch)
{
  char returnType;
  switch (ch)
  {
    case '0':
      returnType = 0;
      break;
    case  '1' :
      returnType = 1;
      break;
    case  '2':
      returnType = 2;
      break;
    case  '3':
      returnType = 3;
      break;
    case  '4' :
      returnType = 4;
      break;
    case  '5':
      returnType = 5;
      break;
    case  '6':
      returnType = 6;
      break;
    case  '7':
      returnType = 7;
      break;
    case  '8':
      returnType = 8;
      break;
    case  '9':
      returnType = 9;
      break;
    case  'A':
      returnType = 10;
      break;
    case  'B':
      returnType = 11;
      break;
    case  'C':
      returnType = 12;
      break;
    case  'D':
      returnType = 13;
      break;
    case  'E':
      returnType = 14;
      break;
    case  'F' :
      returnType = 15;
      break;
    default:
      returnType = 0;
      break;
  }
  return returnType;
}

полностью заменяется вот этим:

char convertCharToHex(char ch)
{
char returnType;
if (( ch >= '0') && (ch <= 'F'))    returnType = ch - '0';
else  returnType = 0;

return returnType;
}

если захотите поспорить на тему "2*2" - приведите пример, при котором эти два кода дают разный результат

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Привожу.

:200000000C9464000C9476000C9476000C9476000C9476000C9476000C9476000C94760042

Мой результат

20a0t0 data C 94 64 0 C 94 76 0 C 94 76 0 C 94 76 0 C 94 76 0 C 94 76 0 C 94 76 0 C 94 76 0 s42-42

Ваш результат

20a0t0 data 13 94 64 0 13 94 76 0 13 94 76 0 13 94 76 0 13 94 76 0 13 94 76 0 13 94 76 0 13 94 76 0 sA-42

И так весь третий файл. На всякий случай: Words_ = 64

С первыми двумя файлами всё в порядке, но там Words_ = 16

 

 

b707
Offline
Зарегистрирован: 26.05.2017

да сорри, забыл что в ASCII цифры и буквы идут не подряд

вот так попробуйте

char convertCharToHex(char ch)
{
char returnType;
if (( ch >= '0') && (ch <= '9'))    returnType = ch - '0';
else if (( ch >= 'A') && (ch <= 'F'))   returnType = (ch - 'A') +10;
else  returnType = 0;

return returnType;
}

 

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Теперь другое дело! Вообще я надеялся, что для ардуино существует стандартная функция перевода char в число

b707
Offline
Зарегистрирован: 26.05.2017

seri0shka пишет:

 Вообще я надеялся, что для ардуино существует стандартная функция перевода char в число

для десятичных чисел есть atoi(), для hex - stoi . но на ардуине оно не пойдет.

Поэтому проще написать самому - как видите, меньше 10 строчек

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ну и от меня тебе дедокода в ленту.  Преобразует байт в два HEX символа

static const char hexDigits[] PROGMEM = "0123456789ABCDEF";


char* ByteToHex(const uint8_t abyte) {
	static char result[3];
	memset(result, 0, 3);
	result[1] = pgm_read_byte(&hexDigits[abyte & 0x0F]);
	abyte >>= 4;
	result[0] = pgm_read_byte(&hexDigits[abyte]);
	return result;
}

 

mixail844
Offline
Зарегистрирован: 30.04.2012
как насчет библиотеки которая парсит Intel Hex ? 
seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

DetSimen, спасибо, но меня вполне устраивает Serial.print(data_, HEX);

Тем более, что нужно это только для отладки, в рабочем варианте не нужно.

mixail844,  я нашёл на Гитхабе 39 библиотек только для Ардуино, ещё бы понять, как ими пользоваться.

Green
Offline
Зарегистрирован: 01.10.2015

DetSimen пишет:

ну и от меня тебе дедокода в ленту.  Преобразует байт в два HEX символа


Не у всех есть Ардуина.

#define HI_NIBBLE_TO_HEX(x) (x>>4 > 9 ? (x>>4) + 'A' - 10 : (x>>4) + '0')
#define LO_NIBBLE_TO_HEX(x) ((x & 15) > 9 ? (x & 15) + 'A' - 10 : (x & 15) + '0')

 

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Проект продвигается, но медленно.

Дальнейшие планы:

Подключение LCD к аппаратному USART в режиме SPI (проверено с двумя типами дисплеев- LCD NOKIA5110 и такой: http://arduino.ru/forum/apparatnye-voprosy/st7567-plyus-nabor-polufabrik... )

Установка передачи данных с компа на контроллер через софтовый USB без использования моста UART (частично решено: http://arduino.ru/forum/programmirovanie/arduino-ide-v-usb-biblioteka   )

Создать навигационное меню (частично решено).

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

seri0shka пишет:

Можете назвать конкретное приложение для Андроид?

ZFlasher  

QuickWitted
Offline
Зарегистрирован: 30.08.2020

seri0shka пишет:
неужели тема интересна только мне?

Нет не только Вам.
А причина того что ажиотажа нет, в том, что вы предлагаете что то паять на индивидуально разработанной плате - а всем лень.

seri0shka пишет:
напрашивается ещё один вариант. Если нужно в 100500 контроллеров залить одинаковую прошивку, которая влезает в программную память контроллера программатора, достаточно преобразовать НЕХ-файл в массив байтов с помощью скрипта на компьютере (здесь для меня опять тёмный лес), и вставить в код программатора.

Подход не для ленивых.

Перефразирую для массовости.

Нужно взять стандартную плату для прошивки стандартных плат.
В некоторых модификациях с внешним модулем памяти типа AT24C512
и с помощью уже дано разработанного софта залить в нее прошивку для массовой заливки с компа.

при этом прошивка в области программ, а ваш код в области загрузчика.

Для NanoV3 софт
AVRprog version 1,40

из минусов - нужно ставить драйвер 232
а не всегда есть доступ администратора для этого.

Для самостоятельной сборки
Project: AVR bootloader HID
Author: Christian Starkjohann
он работает без прав админа.

и далее имея два светодиода кнопку и переключатель
и массово повторять алгоритм

0 переключатель замкнут - ждем 3 сек - сверили тип проца - пошли далее.
1 стирание + сброс фусе
2 прошивка
3 верификация
4 еепром
5 установка фусе
6 верификация установки

Почему я не собрал себе uProg ?
А потому, что алгоритм выше программатор AVRISP mkII под гуедудкой проходит в 1 клик мыша. А в uProg сколько кнопки топтать надо?

в чем плюс решения описанного выше?

лежит перед вами 100 девайсов, в каждом из которых торчит ардуино нано в3
комп (или андроид телефон) 1 в каждый втыкать ждать кликать... брр...

или требуется гальваническая развязка так как девайс может быть воткнут в сеть
и запитать его отдельно и все обесточить...

а так просто воткнул программатор - подождал вынул.
можно параллельно воткнуть в 5 шт программировать параллельно - независимо и автономно.
можно монтажнику дать и он сам поедет в дыру и обновит софт сам.

Еще направление для развития вышедшие недавно LGT8F328P
для них пока нет программатора в одну кнопку...

А если освоить в качестве программатора STM32F103C8T6
то у них 64кб флэш и можно наныv3 прошивать полностью...

ПС: Если сделаете для заливки в  LGT8F328P то у вашего девайса будет море повторений, так как для массовости LGT8F328P намного интереснее той же ATMega328. но шить его пока не совсем есть чем и что там с фусе битами...

ПС: Если по каким то причинам у вас не открывается гугля и вы не можете загуглить исходники - пишите - кинем ссылки сюда.

QuickWitted
Offline
Зарегистрирован: 30.08.2020

dimax пишет:

seri0shka пишет:

Можете назвать конкретное приложение для Андроид?

ZFlasher  

Поиск подсказывает что уважаемый dimax как раз и ведет ветку форума про LGT8F328P
но нормального программатора с отдельным интерфейсом у них пока не появилось.
ни автономного, ни привязанного к той же дудке.

b707
Offline
Зарегистрирован: 26.05.2017

seri0shka пишет:

Дальнейшие планы:

Подключение LCD к аппаратному USART в режиме SPI


стоя в гамаке? Нафига SPI эмулировать через USART, а USART заменять софтовым? Почему SPI не подключить к SPI?

QuickWitted
Offline
Зарегистрирован: 30.08.2020

b707 пишет:
Нафига SPI эмулировать через USART, а USART заменять софтовым?

Вопрос более глобален - а нафиг там дисплей?

Для себя - Захочу дисплей с тачем подключу готовый программатор к готовому андройд телефону.

b707
Offline
Зарегистрирован: 26.05.2017

QuickWitted пишет:

ПС: Если сделаете для заливки в  LGT8F328P то у вашего девайса будет море повторений, так как для массовости LGT8F328P намного интереснее той же ATMega328. но шить его пока не совсем есть чем и что там с фусе битами..


для массовости есть куда более интересные чипы, чем эта кривая китайская подделка под атмегу.... например стм ... а это недоразумение через пару лет и не вспомнит никто

QuickWitted
Offline
Зарегистрирован: 30.08.2020

b707 пишет:
для массовости есть куда более интересные чипы. например стм ...

Учитывая что я пишу на ассемблере и помню все АВР команды
то мне вот прям сейчас гораздо проще залить прошивку в другой АВР чем переходить под СТМ и учить си.

b707 пишет:
а это недоразумение через пару лет и не вспомнит никто

Ему уже 3,5 года.
и пока только развивается

b707
Offline
Зарегистрирован: 26.05.2017

"Массово" и " на асме" давно уже взаимоисключающие понятия, время программистов, пишущих на асме и не знающих Си - прошло лет 30 назад. Сейчас это единичные пенсионеры, о какой массовости речь...

QuickWitted
Offline
Зарегистрирован: 30.08.2020

b707 пишет:
"Массово" и " на асме" давно уже взаимоисключающие понятия, время программистов, пишущих на асме и не знающих Си - прошло лет 30 назад. Сейчас это единичные пенсионеры, о какой массовости речь...

Угу которые выпускают 80% мелкосерийных устройств собранных в кустарных условиях, так как они еще 15 лет назад заняли эту нишу имеют портфолио и опыт, в том числе и поддержки этих самых устройств.

В отличии от школоты, у которых ни заказов ни опыта... одни проектики на макетке.

А так как на асме получается быстрее и код меньше, то можно ставить более дешовые процессоры, в которые школота не влезет. Соответственно не скопипастит - дороже получится. А при серийности в 100 и более шт цена железа становится существенным плюсом.

Я автор проектов IgorPlug2 и PaintPack
А у вас хоть один проект с серийностью более 200шт и поддержкой есть? что бы вы могли опытом поделиться?

Кстати ровно по этим причинам - школоте массовая заливка и не нужна (они тут и не отписываются) - заливать массово просто им нечего.

Я тему массовой заливки начинаю гуглить, когда от БОЛЬШОЙ кучи процов и тырканья мышкой на кнопку "залить все" становится тоскливо и хочется как то убыстрить процесс.

b707
Offline
Зарегистрирован: 26.05.2017

Погуглил быренько проект Игор-четатам. Очень показательно . Древний, как гавно мамонта, проект, устаревший еще в прошлом веке - иначе и быть не могло, раз он на асме написан. И такой же древний программист, который это старье решил осовременить... Нашли друг друга.
Для стареньких сообщаю - современные компиляторы Си обеспечивают почти такую же эффективность кода, как и асм, написанный средним программистом.
Я не против ваших заслуг, но право, полные прошивки на голом асме не пишут уже лет 20, только небольшие кусочки, критичные по скорости и ресурсам

А что касается более дешевых мк, которые якобы вы используете благодаря компактному коду на асме - то это тоже сомнительно. Stm8s003 стоит в 2 раза дешевле атмеги8, при этом бьет ее по всем характеристикам в 2-4 раза.
Собственно атмега8 живет лишь благодаря спросу таких динозавров как вы, китайцы давным давно отказались от авр в своих дешевых поделках сначала в пользу указанных выше стм8, а потом в пользу разных нувотонов

QuickWitted
Offline
Зарегистрирован: 30.08.2020

b707 пишет:
атмеги8, при этом бьет ее по всем характеристикам в 2-4 раза.

1) где у нас модератор? оскарбление участников форума
2) а кто говорил про мегу8 - только вы, я писал про нанов3 на 328
3) а за слова отвечать не в вашем тоне?
я писал про "нанов3 на ATmega328P", STM32F103C8T6 на ардуино плате и LGT8F328P
вы подменяете понятия приписываете мне ... мегу8
и далее сравниваете мной написанное с
16-MHz STM8S 8-bit MCU, 8-Kbyte Flash memory, 128-byte data EEPROM
и утверждаете "при этом бьет ее по всем характеристикам в 2-4 раза."
сравнивая их с приведенными мной процессорами.
Если вас не затруднит - ответьте за слова!!!

Green
Offline
Зарегистрирован: 01.10.2015

ТС, у вас стрёмный SD модуль в #1. Он не преобразует уровни 5 в 3 вольта, только питание(.

b707
Offline
Зарегистрирован: 26.05.2017

Мега8 используется в вашем проекте igor... который вы сами привели как пример своего эффективного кода на асме

QuickWitted
Offline
Зарегистрирован: 30.08.2020

b707 пишет:
Мега8 используется в вашем проекте igor... который вы сами привели как пример своего эффективного кода на асме

Опять подмена понятий.
Где я говорил что игорьплаг2 эффективен?
в 2004 году на чем я ещё мог собрать?

Вы всегда выдаете желаемое - не существующее за действительное?

В районе 2012г IR прошивки были пересобраны под AT90USB162 из паинтпака и атмега328
вот они эффективны так как рассчитаны по тактам.

тот вариант давал в 2 раза выше частоту обновления кадров - по сравнению с "эффективным" СИ вариантом
И был ИК канал, на который у СИ варианта производительности не хватило.
Си вариант это то что у нас скопипастили... А потом продали с кикстартера и запустили выпуск в китае.

 

b707
Offline
Зарегистрирован: 26.05.2017

Вы 32к флеша атмеги328 на асме заполнили? Оно, конечно, подвиг, типа из москвы в саратов пешком...но для практики было бы полезнее за это время С выучить

Чтото я увлекся. Нет смысла спорить с фанатиками, особенно престарелыми

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Green пишет:

ТС, у вас стрёмный SD модуль в #1. Он не преобразует уровни 5 в 3 вольта, только питание(.

Я в курсе. Проект думаю питать от аккума 3.6 в, убиваем трёх зайцев- не нужно согласовывать уровни с SD и c USB, и можно прошивать контроллеры с питанием от 3 до 5 вольт.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

b707 пишет:
Нафига SPI эмулировать через USART, а USART заменять софтовым? Почему SPI не подключить к SPI?

Нафига SPI эмулировать через USART  Не эмулировать. Это аппаратный SPI.

а USART заменять софтовым  Не USART, а USB. Чтобы избавиться от посредника в виде USART to USB.

Green
Offline
Зарегистрирован: 01.10.2015

seri0shka пишет:

Проект думаю питать от аккума 3.6 в, убиваем трёх зайцев- не нужно согласовывать уровни с SD и c USB, и можно прошивать контроллеры с питанием от 3 до 5 вольт.


Ну тогда частоту МК Ардуино желательно понизить до 8, что бы всё по красивому было. Да и свежий акк выдаёт до 4.2. Вот и думайте.

QuickWitted
Offline
Зарегистрирован: 30.08.2020

Green пишет:
Ну тогда частоту МК Ардуино желательно понизить до 8, что бы всё по красивому было.

Из простого = взять ардуино плату которая нормально работает на 32х Мгц от 3в (LGT8F328P)
от 32х Мгц и видео быстрее, или подумать про STM32F103C8T6
(мое мнение - видео и дисплей излишек - повтор функций программатора на андройде)

Из красивого = сдуть микросхему конвертера с SD шильда.
В нашей местности шильды есть, а вот 74LVC125A дороже шильда и на заказ.
за одно решит проблему с +5толерант от 5в девайса в 3,3в программатор

Про питание = а не проще взять готовый балансир с защитой на два 18650 и готовую понижалку с высоким КПД ?
(мое мнение - некоторые мои девайсы питаются от +5В и током 0,5А - проще от них питать, чем их от внешнего акб качать)

seri0shka пишет:
Не USART, а USB. Чтобы избавиться от посредника в виде USART to USB.

И получить проблемы с драйверами, скоростью обмена в софтовом случае. А самое главное получить опыт написания своего софта (изобрести велосипед повторно вслед за автором HID бутлоадера. Он его сколько отлаживал?)

В том же STM32F103C8T6 аппаратный юсб и никаких проблем с посредником.

seri0shka пишет:
Не USART, а USB.

В общем и целом, а вы не пробовали делить проблему на участки, ставить цели по участкам и достигать их?
Пока вы накидали все в одну кучу, включая функционально излишние = юсб+сд карта +дисплей+интерфейс пользователя в которых вы плутать будите месяцами (8 часов в день, 7 дней в неделю) и пытаетесь все разгребсти.

Вы зашивалку отладили?
Вам ее кто нибудь протестировал?

Может в начале зашивалку отладить (фундамент) - просто взять ардуино НаноВ3, залепить к ней
Или AT24C512 для флэш + AT24C512 для фесе, настроек и еепрома
Или SD шильд с конвертером 74LVC125A
и отладить все используя имеющийся на плате посредник USART to USB, со штатным кварцем и +5В USB.

И только потом - отладив все на простых ГОТОВЫХ платах, с готовым отлаженным до нас софтом, проектировать печатную плату под ваш проект, приделывать бантики и рюшечки, костыли сносить и делать все красиво? (1,2,3 этаж и чердак = печатная плата, юсб, дисплей, интерфейс пользователя).

А то мы сейчас проектируем чердак не сделав не то что фундамента, не представляя ни плана ни последовательности работ.