#1 2022-08-01 18:11:06

Honey
Учасник
З Київ
Зареєстрований: 2020-09-26
Повідомлень: 213

Лайфхак. Віддалена перепрошивка

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

Виникла потреба віддалено керувати (додавати/видаляти) списком радіо-брелоків, які можуть відчиняти ворота. Керуванням воріт займається одна плата, а для подачі їй сигналу на відкривання використовувався китайський приймач 433МГц, який замикав своїм реле два контакти з цієї плати. Все це розташовано поряд з воротами в ящику. Додатково під землею/асфальтом вже давно був проведений кабель до пульту охорони, щоб кнопкою можна було також вручну відкрити ворота. Проблема в тому, що китайський приймач дозволяє лише додавати в свою память коди брелоків, для чого потрібно натиснути кнопку безпосередьо на його платі (а для цього потрібно до неї добратись).
184046247.png

Перш за все я перевірив, чи працюватиме 1-wire по двом проводам, які призначені для кнопки відкривання воріт на пульті охорони. 1-wire працює чудово за винятком періодів часу, коли працює мотор, який відкриває/закриває ворота (мабуть він в цей час створює завади через кабель живлення, який десь там під землею проходить поряд).

Спочатку була ідея віддалено модифікувати память китайського приймача (память в ньому 24LC16B з I2C інтерфейсом, формат збереження даних стає зрозумілим з першого разу після додавання нового брелоку і зчитування памяті). Модифікувати память можна було б по 1-wire за допомогою pro-mini, включеної за такою схемою:
spi.jpg
До того ж за цією схемою можна віддалено оновлювати прошивку pro-mini, не відкриваючи ящик, в якому вона знаходиться.

Коли я почав придумувати протокол для додавання/видалення кодів брелоків по 1-wire, прийшла друга ідея.
По-перше відмовитися від китайського приймача, а написати його реалізацію на pro-mini.
По-друге не витрачати зусилля і час на придумування протоколу додавання/видалення кодів.

Ідея полягає в тому, щоб коди всіх брелоків помістити в програму (в PGM/EEPROM) і віддалено прошивати в pro-mini щоразу, коли потрібно якийсь брелок додати/видалити. Тобто редагуємо програму (додаємо/видаляємо код брелока в масиві), компілюємо і прошиваємо по 1-wire в pro-mini.

Отже, якщо стоїть задача розробки протоколу для віддаленого керування якоюсь базою даних на ардуіно і немає вимог до доступності до цієї ардуіни 100% часу, то можна не витрачати зусилля на розробку такого протоколу. Для цього можна щоразу зчитувати з віддаленої ардуіни її память, модифікувати і записувати назад.

Неактивний

#2 2022-08-11 23:04:03

Honey
Учасник
З Київ
Зареєстрований: 2020-09-26
Повідомлень: 213

Re: Лайфхак. Віддалена перепрошивка

До заголовку можна ще додати ... та віддалений монітор порта.

Оскільки знадобилося якось бачити те, що виводить Serial.print() на віддаленій pro-mini, то написав бібліотеку OWSerial, яка дозволяє по 1-wire емулювати послідовний порт для програми.

В скетчі знадобиться замінити всі Serial. на OWSerial. додати #include <OWSerial.h> та замінити Serial.begin(9600); на OWSerial.begin();
Наприклад, скетч HCS301.ino, який я постив у сусідній темі, віглядатиме так:

#include <OWSerial.h>

#define HCS301_TE    400
#define HCS301_BITS  66

typedef struct {
  uint32_t SerialNum;
  uint32_t Encrypted;
  uint8_t Btn1   :1;
  uint8_t Btn2   :1;
  uint8_t Btn3   :1;
  uint8_t Btn4   :1;
  uint8_t BatLow :1;
  uint8_t Repeat :1;
} hcs301_t;

void hcs301_msg(hcs301_t *msg, uint8_t *a) {
  msg->SerialNum = ((uint32_t)(a[7] & 0xf) << 24) | ((uint32_t)a[6] << 16) |
                   ((uint32_t)a[4] <<  8) | a[5];
  msg->Encrypted = ((uint32_t)a[0] << 24) | ((uint32_t)a[1] << 16) |
                   ((uint32_t)a[2] <<  8) | a[3];
  msg->Btn1 = (a[7] >> 5) & 1;
  msg->Btn2 = (a[7] >> 6) & 1;
  msg->Btn3 = (a[7] >> 7) & 1;
  msg->Btn4 = (a[7] >> 4) & 1;
  msg->BatLow = (a[8] >> 6) & 1;
  msg->Repeat = (a[8] >> 7) & 1;
}

#define RF_RECV_PIN       2
#define is_roughly(d,t)   ((d) > (t)-(t)/4 && (d) < (t)+(t)/4)
#define RF_TE             HCS301_TE
#define RF_BITS           HCS301_BITS
uint32_t                  RF_last_change = 0;
uint8_t                   RF_byte, RF_array[(RF_BITS+7)>>3];
uint8_t                   RF_mode = 0;
volatile boolean          RF_catched = false;

void RF_interrupt() {
  if (RF_catched)
    return;

  uint32_t duration = micros() - RF_last_change;
  uint8_t  pin = digitalRead(RF_RECV_PIN);
  RF_last_change += duration;

  if (!(RF_mode & 0x80)) {
    if (RF_mode > 20 && pin == HIGH && is_roughly(duration, 10*RF_TE))
      RF_mode = 0x80;
    else if (!is_roughly(duration, RF_TE))
      RF_mode = 0;
    else if (!(RF_mode & 0x40))
      RF_mode++;
  } else {
    uint8_t bit = 0;
    if (is_roughly(duration, RF_TE))
      bit = 0x80;
    else if (!is_roughly(duration, 2*RF_TE))
      RF_mode = 0;
    if (RF_mode) {
      if (pin == HIGH) {
        if ((bit ^= RF_byte) & 0x80)
          RF_mode++;
        else
          RF_mode = 0;
        RF_byte >>= 1;
      } else {
        RF_byte |= bit;
        RF_array[(RF_mode >> 3) & 0xf] = RF_byte;
        if (RF_mode >= 0x80 + RF_BITS - 1) {
          RF_catched = true;
          RF_mode = 0;
        }
      }
    }
  }
}

void setup() {
  OWSerial.begin();
  attachInterrupt(digitalPinToInterrupt(RF_RECV_PIN), RF_interrupt, CHANGE);
  OWSerial.println("Listening RF");
}

void loop() {
  if (RF_catched) {
    hcs301_t msg;
    hcs301_msg(&msg, RF_array);
    RF_catched = false;
    OWSerial.print("#");
    OWSerial.print(msg.SerialNum, HEX);
    OWSerial.print(" ");
    OWSerial.print(msg.Encrypted, HEX);
    OWSerial.print(" ");
    if (msg.Btn1) OWSerial.print("1");
    if (msg.Btn2) OWSerial.print("2");
    if (msg.Btn3) OWSerial.print("3");
    if (msg.Btn4) OWSerial.print("4");
    if (msg.BatLow) OWSerial.print(" BatLow");
    if (msg.Repeat) OWSerial.print(" R");
    OWSerial.println();
  }
}

Щоб залити цей скетч на віддалену pro-mini, спочатку перетворюєм локальну nano (див. схему в першому повідомленні) в програматор ArduinoOWISP (перед компіляцією цього скетчу замінюєм в ньому адресу модуля розширення портів на свою в цій стрічці: byte addr[] = {0x20,0x41,0x42,0x0F,0x48,0x4E,0x59,0x49};).
Заливаєм ArduinoOWISP.hex в nano:

avrdude -P /dev/ttyUSB0 -c arduino -p m328p -U flash:w:ArduinoOWISP.hex

Тепер nano стала повноцінним програматором по 1-wire для pro-mini - можна не лише заливати і читати прошивку і EEPROM, а й змінювати ф'юзи. При цьому на pro-mini не потрібен ніякий бутлоадер, і можемо не боятися, що прошивка на віддаленій pro-mini зависне і ми втратим до неї доступ.

Заливаєм HCS301.hex в pro-mini:

avrdude -P /dev/ttyUSB0 -b 9600 -c avrisp -p m328p -U flash:w:HCS301.hex

Програма на pro-mini починає працювати, щось виводить в OWSerial і нам тепер треба побачити, що там виводиться. Для цього в nano заливаєм скетч-ретранслятор (перед компіляцією цього скетчу замінюєм в ньому адресу модуля розширення портів на свою в цій стрічці: byte addr[] = {0x20,0x41,0x42,0x0F,0x48,0x4E,0x59,0x49};).

Заливаєм OWSerialMaster.hex в nano:

avrdude -P /dev/ttyUSB0 -c arduino -p m328p -U flash:w:OWSerialMaster.hex

Цей скетч через модуль розширення портів забирає з буферу OWSerial дані і виводить в свій Serial (в зворотньому напрямку дані також будуть передаватися).

Дивимось, що в нас виводиться в Serial на nano:

minicom -D /dev/ttyUSB0 -b 9600
Listening RF
#12345 1B6A46A2 1
#12345 1B6A46A2 1 R
#12345 9F204069 2
#12345 9F204069 2 R
#12345 D6A5816C 1234 BatLow
#12345 D6A5816C 1234 BatLow R

На брелоку я послідовно натискав кнопки 1, 2 і 1+2. Приймач 433МГц підключений до піна 2 на pro-mini.

Неактивний

#3 2022-08-12 10:45:05

akapulko
Гість

Re: Лайфхак. Віддалена перепрошивка

Лайк за спробу відняти шматок хліба у розробників UPDI. Взяли б контроллер з нової лінійки Attiny 0-,1-,2- series і не мучались.

#4 2022-08-12 14:21:24

Honey
Учасник
З Київ
Зареєстрований: 2020-09-26
Повідомлень: 213

Re: Лайфхак. Віддалена перепрошивка

akapulko пише:

Лайк за спробу відняти шматок хліба у розробників UPDI. Взяли б контроллер з нової лінійки Attiny 0-,1-,2- series і не мучались.

Це вийшло випадково))) Перша версія розширювача портів просто повторювала DS2450 (АЦП і gpio) плюс зовсім прості додаткові фішки, але залишалось ще трохи місця в памяті програм, тому придумував, що ще цікавого додати. Памяті вистачило лише на SPI, щоб можна було підключити датчик з SPI інтерфейсом (в планах є окремий пристій 1wire_slave -> I2C_master, типу DS28E17). Те, що можна дистанційно прошивати AVR, я вже збагнув трохи пізніше. А в OWSerial потреба виникла в процесі вирішення іншої задачі.

Якщо порівнювати це рішення з UPDI:
* дозволяє створити канал комунікації з програмою на м/к і писати на ньому свої датчики і пристрої (UPDI лише для прошивки)
* дозволяє використовувати одну шину для багатьох таких пристроїв ще й одночасно з іншими датчиками (UPDI - лише точка-точка)
* що у UPDI з відстанню роботи? 1-wire працює на 100-300м

Ще раз. Я ні на що не претендую, те що вийшло - вийшло випадково і на мою думку цікаво. Якщо підходить/подобається - користуйтесь.

Неактивний

#5 2022-08-14 21:12:46

Honey
Учасник
З Київ
Зареєстрований: 2020-09-26
Повідомлень: 213

Re: Лайфхак. Віддалена перепрошивка

Оскільки на практиці виявилось не зручно заливати в nano по черзі то ArduinoOWISP.hex то OWSerialMaster.hex (до того ж і кількість перезаписів не безмежна), то вбудував функціонал OWSerialMaster в код ArduinoOWISP. Тепер достатньо залити в nano один раз ArduinoOWISP і можна про неї (nano) забути - для заливки прошивки в pro-mini і для монітора порта достатньо лише двох команд:

avrdude -P /dev/ttyUSB0 -b 19200 -c avrisp -p m328p -U flash:w:HelloWorld.hex
minicom -D /dev/ttyUSB0 -b 19200

Після запуску мінікома чекаєм пару секунд, натискаєм клавішу Enter (або Ctrl+M) і ще через пару секунд бачимо наш вивід з pro-mini.

UPD: змінив швидкість з 9600 на 19200, щоб в Arduino IDE не доводилось виправляти ніякі системні файли.

Інструкція для тих, хто користується Arduino IDE

1. В Arduino IDE створити новий скетч, додати в нього код ArduinoOWISP.ino, вибрати: Інструменти->Плата: "Arduino Nano" і натиснути "Вивантажити". Цей скетч нам більше не знадобиться, можна закрити.

2. Зібрати схему, як на малюнку в першому пості.

3. Створити новий скетч, написати свій код з використанням OWSerial (звичайно встановити бібліотеки OWSerial, DS2450, OneWire).

4. Вибрати: Інструменти->Плата: "Arduino Pro or Pro Mini", вибрати: Інструменти->Програматор: "Arduino as ISP" і натиснути Скетч->"Вивантажити за допомогою програматора". Скетч буде завантажуватися в pro-mini по 1-wire.

5. Вибрати: Інструменти->Монітор послідовного порту, у новомі вікні внизу вибрати "Повернення каретки (CR)", "19200 бод" і натиснути "Надіслати", через пару секунд почнеться вивід.

Тепер щоразу після редагування скетчу просто натискаєм Скетч->"Вивантажити за допомогою програматора", після закінчення вивантаження у вікні монітора порта натискаєм "Надіслати" і через пару секунд знову бачимо вивід.

UPD: для тих, хто використовує майстер шини на DS2480B, у пункті 1 перед вивантаженням треба знайти в скетчі ArduinoOWISP.ino стрічку "#define HAVE_DS2480B 0" і замінити 0 на 1. Необхідні бібліотеки завантажити звідси.

Якщо при вивантаженні свого скетчу отримуєм помилку:

avrdude: Yikes! Invalid device signature.

То, скоріш за все, забули в ArduinoOWISP.ino замінити адресу модуля розширення портів на свою, шукаєм таку стрічку і міняєм:

byte addr[] = {0x20,0x41,0x42,0x0F,0x48,0x4E,0x59,0x49};

Просканувати шину 1-wire і дізнатися адреси всіх пристроїв на ній можна за допомогою простого скетчу (завантажувати його потрібно в nano):

#include <OneWire.h>
OneWire ow(10);

void setup(void) {
  Serial.begin(9600);
}

void loop(void) {
  byte i, addr[8];
  if (!ow.search(addr)) {
    Serial.println("No more addresses.");
    ow.reset_search();
    delay(5000);
    return;
  }
  Serial.print("ROM =");
  for (i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }
  Serial.println();
}

Описана вище технологія віддаленої прошивки і монітора порта дозволяє мати на одній шині 1-wire багато плат розширювача портів + pro-mini і працювати з кожною індивідуально.

Остання редакція Honey (Сьогодні 00:23:04)

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму