Системи управління та автоматика
Як написати портативний код для пристроїв Iot
Table of Contents
Письмовий портативний код для пристроїв Інтернету речей є фундаментальною майстерністю для вбудованих розробників, які потребують розгортання додатків на різних апаратних платформах. екосистема IoT поєднує мікроконтролери з ARM Cortex-M, RISC-V, AVR та власні архітектури, кожен з унікальних карт пам'яті, периферичних реєстрів та компіляторних кіл. Без навмисного дизайну для портабельності, коду, який працює на одній цілі часто розбиває на інший, веде до дорогих резитів та технічного обслуговування кошмарів. Ця стаття забезпечує розширений посібник для досягнення істинної переносності в вбудованому C, охоплює як стратегічні підходи та практичні тактики.
Розуміння портабельності в IoT
Портабельність – це вихідний код, який може бути складений та працювати на різних апаратних архітектурах з невеликою або без модифікації. У світі Інтернету речей, переносимість не просто зручність — це бізнес-питома вимога. Терміни життєвих циклів продукту – довга, зміна ланцюжків, а також з’являється новий кремній. Портативна база коду дозволяє використовувати існуючу мікропрограму по генераціях продуктів, швидко пікточити на альтернативні компоненти при нестачі, а також зменшити часовий ринок для похідних продуктів.
Портованість існує на спектрі. В одному кінці код, який повністю відповідає залежним (наприклад, алгоритмам сортування генних сортів), що містяться в будь-якій точці світу. На іншому кінці код, який безпосередньо маніпулює апаратні реєстри, властиво незрівнянним. Мета портативного C для IoT полягає в тому, щоб ізолювати незрівняні деталі за шарами абстрагії, щоб основний логічний і алгоритм залишається багаторазовим.
Загальні виклики для портабельності коду
Кілька низьких рівнянь чуми вбудованої C портабельності:
- Endianness ARM Cortex‐M і AVR є малотерпентійським; деякі старі архітектури (наприклад, Freescale HC12) є великим ‐endian. Безпосередньо відливні тостери або союзи через байтові замовлення призводить до безшумної корупції даних.
- Word Size and type Definitions може бути 16 біт на 8-bit AVR, 32 біт на Cortex‐M0, 64 біти на RISC‐V 64-розрядному процесорі. Код, який приймає , точно 32 біти будуть розірватися.
- Регістрна різниця карт Навіть два МКУ з того ж постачальника часто мають різні периферичні адреси бази, бітові поля та послідовності конфігурації.
- Поповнення розширення та прагми] GCC, IAR, ARM Compiler 6, і Кіль кожен має свої власні синтаксису та інлайн збірка діалектів.
- Memory макет і вирівнювання Деякі платформи вимагають суворого вирівнювання для 32-розрядних доступу; інші ручки незрівнянний доступ з обробником несправностей.
- // Вектори інтер’єру та використання стека // Вектори інтеррептів, моделі пріоритетів та поведінка в цілому.
Ключові стратегії для написання портативного коду
Апаратні шари абстракції (HAL)
Найпотужніший інструмент в портативному керсеналі-коду є , що має тверде ставлення до анотації ]. Добре розроблений HAL виводить єдиний API для загального перифери (GPIO, UART, I2C, SPI, таймери) при захованні основного реєстру-розміщення. Інтерфейс повинен бути визначений в заголовку (наприклад, ), який заявляє функції, такі як і . Окремі вихідні файли реалізують функції для кожної цільової платформи. Код програми [[Fiter[Fit:2[Fit][Fit:2[Fit:2[Fit:2[Fit:2[Fit:2]
Типовий шаблон HAL виглядає так:
// hal_gpio.h (common)
typedef uint8_t gpio_pin_t;
typedef uint8_t gpio_port_t;
void hal_gpio_set_output(gpio_port_t port, gpio_pin_t pin);
void hal_gpio_set_high(gpio_port_t port, gpio_pin_t pin);
void hal_gpio_set_low(gpio_port_t port, gpio_pin_t pin);
Платформа – специфічні файли (наприклад, ) містять фактичні записи реєстрів. При переході на новий MCU потрібні тільки джерела низького рівня HAL, а всі вищі шари залишаються доручені.
Прийняти стандартні бібліотеки
Бібліотека C забезпечує портативний фундамент для багатьох поширених операцій. Функції, такі як , , рядові утиліти та математичні функції доступні на кожному конформуванні C компілятора. Уникнення припущення щодо внутрішніх бібліотек є критичним—never rewrite ] для виконання, якщо ви перевірили, що реалізація компілера є недостатньою.
Для IoT-систем з обмеженою пам'яттю, розглянемо за допомогою підмножини стандартної бібліотеки (наприклад, newlib‐nano] в екосистемі GCC), а не прокат власних рядових руйнувань. Аналогічно макрос і є універсально доступні. Посилання: GNU C Бібліотека документації] є відмінним посиланням для розуміння того, що гарантовано портативний.
Використання виправлених типів даних
Завжди використовуйте типи з і , щоб вказати цілі змінні з явними широтами: , , , ], і т.д. Уникайте рівнини , , або для будь-якого, що повинно мати відомий розмір. Для петля лічильників і малих індексів, де розмір не критичний, використання (який визначається виконанням) замість . Ця практика усуває ambiguity 64
Коли потрібно послідовно виконувати дані через те, що вони мають бути на курсі, об'єднайте типи фіксованих ширм з функціями перетворення байтів (, , або їх портативні еквіваленти). Ніколи не просто відкидте ] до і надішлемо її через мережу—ендіантство буде укусити вас.
Кондиціонер
Передпроцесорними напрямами є законний інструмент для платформи-специфічний код, але вони повинні бути використані належним чином. Визначте невеликий набір конфігураційних макросів в одному центральному заголовку (наприклад, ), а не розсіювання ] через кожен файл. Приклад:
// platform_config.h
#if defined(STM32L4)
#define PLATFORM_STM32L4
#elif defined(EFM32GG)
#define PLATFORM_EFM32GG
#else
#error "Unsupported platform"
#endif
Потім в коді використовується загальний тільки при абсолютно необхідному. Зробіть на увазі, що надмірна робить код важко читати і підтримувати. Захищайте HAL анотації за умовною компіляцією, де можливо.
Мінімізація зовнішніх залежностей
Кожна бібліотека сторонніх сторін, яку ви включає, є потенційним небезпекою для портів. Перед додаванням залежності, перевірте, що вона підтримує всі ваші цільові архітектури і що вона не тягнеться в незрівнянних припущеннях. Біблії, написані повністю в портативному C (наприклад, FatFS] або FreeRTOS) безпечні, ніж ті, що спираються на вбудовану збірку або компілеромоспецифічні прагми. Навіть тоді, розгляньте обгортання бібліотеки з власною тонкою абстракцією, щоб ви могли перетати її пізніше без дотикуючого коду.
Посилання: Embedded.com стаття on real‐world переносний C code пропонує додаткову перспективу на управління залежностями.
Практичні поради щодо підвищення переносності
Написати модульний код
Перервувати прошивку в автономні модулі з добре визначеними інтерфейсами. Кожен модуль повинен піддавати свою функціональність через файл заголовка і приховати його внутрішні деталі. Цей розділ стосується дозволяє легко замінити модуль портативною версією при перевезенні на нову платформу. Наприклад, модуль керування двигуном повинен говорити про HAL для виходу PWM, не безпосередньо до таймера периферичний реєстр.
Залежність до документів
Очистити будь-який код, який передбачає конкретну поведінку обладнання. Використовуйте коментарі, щоб пояснити, чому вибрано конкретний незрівняний підхід, які платформи, які він працює, і що потрібно буде змінити для іншої мети. Ця документація нездійснена, коли оригінальний розробник недоступний, і новий інженер повинен перевозити код.
Використовуйте інструменти для побудови Cross‐Platform
Створіть системи, такі як CMake або Meson] може керувати декількома цільовими конфігураціями з єдиної структури проекту. CMake, наприклад, дозволяє вказати файли інструментів для кожної платформи і встановити визначення компіляції на основі цілі. Це виключає необхідність в ручному збереженні окремих файлів проекту для IAR, Keil і GCC. Посилання: CMCake документація забезпечує широкі приклади налаштування крос-компіляції.
Використання портативних методів біт-менеджменту
При встановленні або очищенні біт в реєстрах, не вписуючи абсолютні маски, які припускають бітомні ділянки. Замість використання символічних констанцій, визначених в HAL, і використання макросів або інлайн функцій для безпечного бітообміну:
#define BIT_SET(reg, bit) ((reg) |= (1u << (bit)))
#define BIT_CLEAR(reg, bit) ((reg) &= ~(1u << (bit)))
Дефін як абстрактний параметр, а не літералізоване ціле. Таким чином, якщо зміни позиції біта на різних MCU, то тільки постійне визначення повинно змінитися, а не використання всієї бази коду.
Тестування та визначення платформи Across
Заяви про переносимість повинні бути дійсними. Використовуйте безперервну інтеграцію (CI), яка будує ваш проект для всіх підтримуваних платформ. У CI, запустіть статичні інструменти аналізу, такі як PC‐lint або Coverity], щоб виявити неправильне використання непортативних конструкцій. Для функціонального тестування використовуйте емулятори (наприклад, QEMU для ARM або Renode для RISC‐V) для імітації виконання без фізичного обладнання. При наявності фізичного обладнання, підтримують невеликі «важке землеробство» представниць для регулярних випробувань диму.
Рефресційні тести повинні здійснювати всі HAL API на кожній платформі, щоб зловити нерівності рано. Тест, як «писати байт в UART, читати його назад в петлюбека», викреслювати часові або конфігураційні відмінності між впровадженнями UART.
Висновок
Письмовий портативний C-код для пристроїв Інтернету речей не є післясумою, є дисципліною, яка повинна бути випіканий в архітектуру з дня. Вкладати в апаратний абстракційний шар, що сприяє стандартним типам і бібліотекам, використовуючи умовну компіляцію, що швидко та легко перевіряти по цілі, ви створюєте прошивку, яка може вижити неминучі зміни в апаратному ландшафті. Довгий зусилля сплачує дивіденди в зниженому технічному обслуговуванні, швидше переображуючи новий кремній, і більша стійкість до подачі-похилого збої. Почати ці стратегії сьогодні, щоб майбутнім'єднати ваші вбудовані C-проекти.