Автономный программатор для AVR

Сделал автономный программатор для AVR с блекджеком и девочками, т.е. с экраном и SD картой. Пока для затравочки закидываю часть кода. Если тема будет интересна, продолжу )

#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 (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 (unsigned int 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;

void Serial_print_HEX(uint8_t n) {
  if (n <= 0x0F) Serial.print("0");
  Serial.print(n, HEX);
}

void reset_target(bool reset) {
  digitalWrite(ARDUINOISP_PIN_RESET, reset ? LOW : HIGH);
}

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);
}

uint8_t spi_enable_prog_mode() {
  uint8_t res;
  SPI_BB.transfer(0xAC);
  SPI_BB.transfer(0x53);
  res = SPI_BB.transfer(0x00);
  SPI_BB.transfer(0x00);
  if (res == 0x53) return 0;
  else return 1;
}

uint8_t start_pmode() {
  Serial.println("start programm mode");
  reset_target(true);
  pinMode(ARDUINOISP_PIN_RESET, OUTPUT);
  SPI_BB.begin();
  SPI_BB.beginTransaction(SPI_CLOCK);
  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() {
  Serial.println("end programm mode");
  SPI_BB.end();
  pinMode(ARDUINOISP_PIN_MOSI, INPUT);
  pinMode(ARDUINOISP_PIN_SCK, INPUT);
  reset_target(false);
  pinMode(ARDUINOISP_PIN_RESET, INPUT);
}

void spi_transaction_test(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  Serial_print_HEX(SPI_BB.transfer(a));
  Serial_print_HEX(SPI_BB.transfer(b));
  Serial_print_HEX(SPI_BB.transfer(c));
  Serial_print_HEX(SPI_BB.transfer(d));
  Serial.println();
}

uint8_t flash_read(uint8_t hilo, unsigned int addr) {
  return spi_transaction(0x20 + hilo * 8, (addr >> 8) & 0xFF, addr & 0xFF, 0);
}

void flash_read_page(unsigned int start, int length) {
  unsigned int 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 flash_read_page_buffer(uint8_t *buff, unsigned int start, int length) {
  unsigned int here = start / 2;
  for (int x = 0; x < length; x += 2) {
    buff[x] = flash_read(LOW, here);
    buff[x + 1] = flash_read(HIGH, here);
    here++;
  }
}

void eeprom_read_page(unsigned int 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 write_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) {
  spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
}

void write_flash_page(uint8_t *buff, unsigned int start, unsigned int length) {
  unsigned int here = start / 2;
  int x = 0;
  unsigned int page = here & 0xFFFFFFF0;
  // Serial.println(page);
  while (x < length) {
    if (page != here & 0xFFFFFFF0) {
      commit(page);
      page = here & 0xFFFFFFF0;
      delay(20);
    }
    write_flash(LOW, here, buff[x++]);
    write_flash(HIGH, here, buff[x++]);
    here++;
  }
  commit(page);
  delay(20);
}

void write_eeprom_page(uint8_t *buff, unsigned int start, unsigned int length) {
  for (unsigned int x = 0; x < length; x++) {
    unsigned int addr = start + x;
    spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);
    delay(20);
  }
}

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();
}

void chip_erase() {
  Serial.println("erase flash");
  spi_transaction(0xAC, 0x80, 0x00, 0x00);
  delay(20);
};

#endif

Уже неинтересно

С какой целью?

Чтобы остальную часть продать по дороже)))

Кому эта автономность в авр нужна, интересно?
У меня PICkit умеет так (правда без дисплея он), но ни разу еще не понадобилось )))

назначение не понятно
а так похвально
фотки будут?

1 лайк

Похожая тема вроде.

Да тема похожая. К сожалению ничем она там не закончилась. Эту штуку я делаю, что бы на производстве передать прошивки на производственный участок. ПК там поставить проблематично, от сюда и подобное решение.
остатки файлов, если кому интересно обсудить, поискать проблемы \ ошибки \ что то предложить…

#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"));
  }
}

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");
      str = "/" + String(folder_name) + "/fuse.hex";
      if (writing_fuse_from_file(str)) u8x8.println(F("........SKIP"));
      else u8x8.println(F("..........OK"));

      u8x8.print("eeprom");
      str = "/" + String(folder_name) + "/eeprom.hex";
      if (writing_eeprom_from_file(str)) u8x8.println(F("......SKIP"));
      else u8x8.println(F("........OK"));

      u8x8.print("flash");
      str = "/" + String(folder_name) + "/prog.hex";
      if (writing_flash_from_file(str)) u8x8.println(F(".......SKIP"));
      else u8x8.println(F(".........OK"));

      u8x8.print("check");
      str = "/" + String(folder_name) + "/prog.hex";
      switch (verification_flash_from_file(str)) {
        case 0x13:
          u8x8.println(F("......ERROR"));
          error = 1;
          break;
        case 0:
          u8x8.println(F(".........OK"));
          break;
        default:
          u8x8.println(F(".......SKIP"));
      }
    } else {
      u8x8.println("....ERROR");
      error = 1;
    }

    if (error) {
      leds[0] = CRGB::Red;
      leds[1] = CRGB::Red;
      leds[2] = CRGB::Red;
      FastLED.show();

      u8x8.setCursor(5, 7);
      u8x8.println(F("-ERROR-"));
    } else {
      leds[0] = CRGB::White;
      leds[1] = CRGB::Green;
      leds[2] = CRGB::Green;
      FastLED.show();

      u8x8.setCursor(3, 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();
}

#ifndef ARDUINOISP_FILE_H
#define ARDUINOISP_FILE_H

#include "ARDUINOISP.h"
#include <SdFat.h>

uint8_t buff[32];  // global block storage
extern File myFile;
extern SdFat SD;

uint8_t char_to_byte(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 *f) {
  return char_to_byte(myFile.read()) * 16 + char_to_byte(myFile.read());
}

uint8_t check_file(String file_name) {
  uint8_t error = 0;
  uint8_t checksum = 0;
  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();
      if (ch == ':') {
        uint8_t RECLEN = read_byte(&myFile);
        checksum += RECLEN;
        checksum += read_byte(&myFile);
        checksum += read_byte(&myFile);
        checksum += read_byte(&myFile);
        for (int i = 0; i < RECLEN; ++i) {
          checksum += read_byte(&myFile);
        }
        checksum += read_byte(&myFile);
      }
      if (checksum) {
        Serial.println(F("checksum file error"));
        error = 0x22;
        break;
      }
    }
    myFile.close();
  } else {
    Serial.println(F("error open file"));
    error = 0x21;
  }
  return error;
}

uint8_t writing_flash_from_file(String file_name) {
  Serial.println(F("---writing flash---"));
  uint8_t error = 0;
  error = check_file(file_name);
  if (error == 0) {
    myFile = SD.open(file_name);
    Serial.println(F("writing flash"));
    while (myFile.available()) {
      char ch = myFile.read();
      if (ch == ':') {
        uint8_t RECLEN = read_byte(&myFile);
        uint16_t LOAD_OFFSET = read_byte(&myFile);
        LOAD_OFFSET = LOAD_OFFSET * 256 + read_byte(&myFile);
        uint8_t RECTYP = read_byte(&myFile);
        if (RECTYP == 0x00) {
          for (int i = 0; i < RECLEN; ++i) {
            uint8_t DATA = read_byte(&myFile);
            buff[i] = DATA;
          }
          write_flash_page(buff, LOAD_OFFSET, RECLEN);
        }
      }
    }
    myFile.close();
  }
  Serial.println(F("-end writing flash-"));
  return error;
}

uint8_t writing_eeprom_from_file(String file_name) {
  Serial.println(F("---writing eeprom---"));
  uint8_t error = 0;
  error = check_file(file_name);
  if (error == 0) {
    myFile = SD.open(file_name);
    Serial.println(F("writing eeprom"));
    while (myFile.available()) {
      char ch = myFile.read();
      if (ch == ':') {
        uint8_t RECLEN = read_byte(&myFile);
        uint16_t LOAD_OFFSET = read_byte(&myFile);
        LOAD_OFFSET = LOAD_OFFSET * 256 + read_byte(&myFile);
        uint8_t RECTYP = read_byte(&myFile);
        if (RECTYP == 0x00) {
          for (int i = 0; i < RECLEN; ++i) {
            uint8_t DATA = read_byte(&myFile);
            buff[i] = DATA;
          }
          write_eeprom_page(buff, LOAD_OFFSET, RECLEN);
        }
      }
    }
  }
  Serial.println(F("-end writing eeprom-"));
  return error;
}

uint8_t verification_flash_from_file(String file_name) {
  Serial.println(F("---verification flash---"));
  uint8_t error = 0;
  error = check_file(file_name);
  if (error == 0) {
    myFile = SD.open(file_name);
    Serial.println(F("verification flash"));
    while (myFile.available()) {
      char ch = myFile.read();
      if (ch == ':') {
        uint8_t RECLEN = read_byte(&myFile);
        uint16_t LOAD_OFFSET = read_byte(&myFile);
        LOAD_OFFSET = LOAD_OFFSET * 256 + read_byte(&myFile);
        uint8_t RECTYP = read_byte(&myFile);
        // RECLEN Если считали больше размера буфера ?
        flash_read_page_buffer(buff, LOAD_OFFSET, RECLEN);
        if (RECTYP == 0x00) {
          for (int i = 0; i < RECLEN; ++i) {
            uint8_t DATA = read_byte(&myFile);
            if (DATA != buff[i]) {
              Serial.println("verification flash error");
              error = 0x13;
              break;
            }
          }
        }
      }
    }
    myFile.close();
  }
  Serial.println(F("-end verification flash-"));
  return error;
}

uint8_t writing_fuse_from_file(String file_name) {
  Serial.println(F("---writing fuse---"));
  uint8_t error = 0;
  error = check_file(file_name);
  if (error == 0) {
    myFile = SD.open(file_name);
    Serial.println(F("writing fuse"));
    while (myFile.available()) {
      char ch = myFile.read();
      if (ch == ':') {
        uint8_t RECLEN = read_byte(&myFile);
        uint16_t LOAD_OFFSET = read_byte(&myFile);
        LOAD_OFFSET = LOAD_OFFSET * 256 + read_byte(&myFile);
        uint8_t RECTYP = read_byte(&myFile);

        if (RECTYP == 0x00) {
          uint8_t low_fuse = read_byte(&myFile);
          uint8_t high_fuse = read_byte(&myFile);
          uint8_t extended_fuse = read_byte(&myFile);
          uint8_t lock_fuse = read_byte(&myFile);
          //low
          spi_transaction(0xAC, 0xA0, 0x00, low_fuse);
          delay(20);
          //high
          spi_transaction(0xAC, 0xA8, 0x00, high_fuse);
          delay(20);
          //extend
          spi_transaction(0xAC, 0xA4, 0x00, extended_fuse);
          delay(20);
          //lock
          spi_transaction(0xAC, 0xE0, 0x00, lock_fuse);
          delay(20);
        }
      }
    }
    myFile.close();
  }
  Serial.println(F("-end writing fuse-"));
  return error;
}

#endif

А фото готового устройства?

прототип + Fysetc Mini12864 2.1

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

2 лайка

Мельком глянул файл, начинающийся с

интересно, это .h или .cpp ? Если это хидер, то зачем вы в 4-й строке включаете его сам в себя? А если исходник, то нафига он обрамлен дефайнами #ifndef ARDUINOISP_FILE_H?

Далее, функция

uint8_t char_to_byte(char n) {

как минимум неправильно названа, ее результат не байт, а нибл

Ну и функции

uint8_t writing_flash_from_file(String file_name) 

uint8_t writing_eeprom_from_file(String file_name)

uint8_t verification_flash_from_file(String file_name)

и в меньшей степени


uint8_t writing_fuse_from_file(String file_name) 

содержат на 70% повторяющийся код чтения ХЕКС из файла. Было бы правильнее этот кусок вынести в отдельную функцию и вызывать из остальных

Добавлю свои 5 копеек

при каждом вызове создают новую копию строки-аргумента. Зачем? ХЗ!

если будет интересно есть плата esp… и на нее можно передавать прошивку дистанционно… через интернет… своими заготовками не поделюсь, но в сети может что то и выкладывали…

ну тут на все есть свои причины…

это .h, в который сейчас запихнут и .сpp.
Знаю, не кошено, ну лень мне на прототипе раскидку по фалам делать, глаза в основной программе не мозолит и ладно :slight_smile: )

с ниблом согласен, тут действительно char_to_nible

c writing_flash_from_file копипаста не просто так, там еще допилить стоит. У меня там затык, как сделать красиво чтение строки из файла и запись его в МК, если строка больше буфера. Пока оставил как есть, так как для используемых контроллеров этого достаточно.

ESP смотрел, в принципе даже хотел взять плату с дисплеем. Но просто не люблю wifi для таких целей. Я тут больше в сторону stm с имитацией флешки.

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

А в чем вообще проблема? Строка, например, 80 символов, буфер 10 символов - читаете строку в 8 приемов и все…

Почему для имени файла надо использовать String?

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

нет. не так все просто. было-бы так, так и сделал… там intel HEX. в котором в начале строки прописаны сервисные вещи (размер строки, смещение в памяти, тип данных…) а в конце контрольная сумма. если строка выходит за размер буфера, то промежуточную инфу надо придержать в памяти, искать начало строки, обрабатывать ситуацию с контрольной суммой. Да это красиво, с точки зрения кода, однако сейчас в приоритете сделать быстро и что бы работало. по сути MVP…

потому, что проще, коли платформа предоставляет. имя формируется просто путем суммирования строк, без заморочки на буфер… грязно, но вполне себе решения на этапе MVP. Можете предложить решение лучше, предложите… обсудим и по использованию памяти и оптимальности подхода. Учтите, только момент с формирование строки.

делают. Еще как делают. Вы удивитесь сколько либ мне уже попадалось когда .h и .сpp или .c фалы сливали в один .h. и как в объявлении класса сразу методы прописываю (обычно для небольших методов так делают). Не то что это хорошо, но мир не белый и черный. В мире серого много…

Предлагаю формат “критикуешь - покажи как бы сделал сам” :slight_smile:

со стрингом и ссылкой в функцию в принципе все просто

String str;

void f(const char *s) {
  Serial.println(s);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  str = "test";

  f(str.c_str());
}

void loop() {
  // put your main code here, to run repeatedly:
}

тут кстати вопрос, а сколько мы на стеке выиграем от этого преобразование взамен передачи просто по String. Если уж совсем правильно спросить, сколько стека съест передача по String и передача с преобразованием с const char при вызове данной функции.

отвечу

1 лайк

я предлагаю к сути вернуться, а то холивар надолго может затянуться…