Jednostka 3 / 9

Systemy wbudowane i generowanie kodu mikrokontrolera

Zyski:

  • Możliwość generowania osadzonego kodu na podstawie rejestru i kontekstu sprzętowego dla Arduino/STM32/ESP32 z AI
  • Możliwość rozpoznawania i korygowania osadzonych wzorców, takich jak przerwania, liczniki czasu i nieblokujące pętle w wynikach AI
  • Możliwość przeglądu wygenerowanego kodu pod kątem pamięci, czasu rzeczywistego i bezpieczeństwa przed wgraniem go na sprzęt

W mechatronice mikrokontroler jest miejscem, w którym pomysły spotykają się ze światem fizycznym. Karty takie jak Arduino, STM32, ESP32; odczytuje czujniki, steruje urządzeniami wykonawczymi, komunikuje się i robi to wszystko przy ograniczonej pamięci, ograniczonej mocy obliczeniowej i rygorystycznych wymaganiach czasowych. Sztuczna inteligencja jest na tym polu bardzo przydatna: potrafi wyodrębnić ustawienia rejestrów na podstawie karty katalogowej czujnika, zakodować protokół komunikacyjny, ustawić przerwanie czasowe. Jednak systemy wbudowane to jeden z obszarów, w których sztuczna inteligencja produkuje najbardziej „przekonujące kłamstwa”; ponieważ adresy rejestrów, maski bitowe i zachowanie taktowania są specyficzne dla płytki i jeden błąd bitowy zakłóca całe zachowanie. W tej części omówimy, jak wygenerować osadzony kod za pomocą sztucznej inteligencji i jak go sprawdzić przed załadowaniem go na sprzęt.

Różnica kodu osadzonego od czystego oprogramowania

Program komputerowy ma dużo pamięci, system operacyjny i łatwość debugowania. W kodzie osadzonym brakuje większości z nich:

Rozmiar

pulpit

system wbudowany

pamięć

Poziom GB

Poziom KB (np. 2 KB RAM)

czas

Generalnie elastyczny

Napięty, w czasie rzeczywistym

debugowanie

Łatwe (debuger, dziennik)

Twardy (JTAG, szeregowy, LED)

Wynik błędu

Program ulega awarii

Siłownik/osprzęt może zostać uszkodzony

dostęp do zasobów

Streszczenia systemu operacyjnego

Bezpośredni dostęp do Rejestru

Te różnice określają kryteria oceny wyników AI: wykorzystanie pamięci, dokładność w czasie rzeczywistym (bez blokowania) i dokładność rejestrów sprzętowych są zawsze na górze listy kontrolnej.

Kod blokujący a kod nieblokujący

Najczęstszym błędem popełnianym przez początkujących (i często popełnianym przez sztuczną inteligencję) jest użycie opóźnienia(). opóźnienie(1000) blokuje procesor na 1 sekundę; W tym czasie nie można odczytywać żadnych innych czujników, nie można sterować żadnymi przyciskami. Jest to niedopuszczalne w mechatronice. Zamiast tego używany jest nieblokujący wzorzec oparty na millis().

// ZŁY: blocker -- procesor nie może wykonywać żadnej innej pracy przez 1 sekundę void pętli() { digitalWrite(LED, HIGH); opóźnienie (1000); // wszystko zatrzymuje się digitalWrite(LED, LOW); opóźnienie (1000); // W tej chwili nie można odczytać przycisku awaryjnego!}// DOBRY: nieblokuje -- pętla nie jest blokowana, inne zadania są uruchamiane if (nowMs - poprzedniMs >= interwał) { poprzedniaMs = terazMs; stan diody = !stan diody; digitalWrite(LED, stan diody); } przyciskSprawdź(); // może działać w każdym cyklu sensorRead(); //można uruchomić w dowolnej pętli}

Wzór nieblokujący jest podstawą wbudowanej mechatroniki: pętla sterowania przebiega w sposób ciągły, żadne zadanie nie blokuje innego. Nakazanie sztucznej inteligencji „nie używaj opóźnienia, pisz nieblokowanie oparte na millis” podczas pisania kodu bezpośrednio poprawia jakość wyników.

Wskazówka: Poszukaj opóźnienia (w osadzonym kodzie AI. Jeśli zauważysz opóźnienie w głównej pętli sterującej, najczęściej ten kod nie jest odpowiedni dla systemu czasu rzeczywistego i powinien zostać przepisany.

Przerwania i timery

Przechwytujemy zdarzenia krytyczne czasowo (impuls enkodera, przycisk, próbkowanie okresowe) z przerwaniami, zamiast czekać w głównej pętli. Procedura przerwania (ISR) powinna być napisana krótko i ostrożnie: bez opóźnień, Serial.print i długich obliczeń; Zmienne współdzielone są oznaczone jako zmienne.

lotny długi licznik enkodera = 0; // ISR i pętla są współdzielone -> stan lotny void enkoderISR() { // Krótki ISR: po prostu policz, nie wykonuj żadnej innej pracy if (digitalRead(ENC_B)) enkoderCounter++; else encoderCounter--;}void setup() { pinMode(ENC_A, INPUT_PULLUP); tryb pin(ENC_B, INPUT_PULLUP); dołączyćInterrupt(digitalPinToInterrupt(ENC_A), enkoderISR, RISING);}void pętli() { długi licznik; noPrzerwania(); //krótkie przerwania dla atomowego odczytu licznika = encoderCounter; przerywa(); //dokonuj bezpiecznej transakcji przy kasie...}

Sztuczna inteligencja często pomija trzy punkty krytyczne w tym przykładzie: (1) współdzielony licznik kodera musi być „lotny” lub optymalizacja kompilatora nie będzie uwzględniać aktualizacji; (2) ISR powinien być krótki; (3) Podczas odczytu zmiennej wielobajtowej w pętli głównej przerwania odczytu atomowego muszą zostać zamknięte na krótki czas, w przeciwnym razie podczas odczytu może zainterweniować ISR i odczytana może być połowa/uszkodzona wartość (warunek wyścigu). Koniecznie sprawdź, czy te trzy są obecne w kodzie AI.

Dokładność rejestru i arkusz danych

Sztuczna inteligencja może wiarygodnie błędnie przedstawić adres rejestru czujnika lub bit konfiguracyjny MCU. Na przykład rejestr zarządzania energią jednostki IMU MPU6050 to 0x6B; Jeśli AI podaje to jako 0x6A, kod jest kompilowany, wydaje się działać, ale czujnik się nie budzi. Takie błędy są wykrywane tylko w porównaniu z arkuszem danych.

// Wybudzenie MPU6050: zgodnie z arkuszem danych PWR_MGMT_1 = 0x6B, wartość 0x00#define MPU_ADDR 0x68#define PWR_MGMT_1 0x6B // <-- WERYFIKUJ z arkusz danychWire.beginTransmission(MPU_ADDR);Wire.write(PWR_MGMT_1);Wire.write(0x00); // wybudzenie z trybu uśpieniaWire.endTransmission(true);

Uwaga: Sprawdź każdy adres rejestru, maskę bitową i adres I2C/SPI podane przez AI z arkusza danych. Wartości te są specyficzne dla karty i chipa; Wartość, którą AI „zapamiętuje”, może pochodzić z innej wersji chipa. Nieprawidłowy rejestr po cichu prowadzi do nieprawidłowego zachowania.

Słaba podpowiedź/silna podpowiedź

SŁABY: „Odczytaj czujnik temperatury na ESP32.” (Który czujnik? Który protokół? Który pin? Ogólny, prawdopodobnie błędny kod.) SILNY: „Odczytaj czujnik temperatury DS18B20 na ESP32 (framework Arduino) z GPIO4 za pomocą OneWire. Zapis bez blokowania, próbkowanie co 1 sekundę (z opóźnieniem, w oparciu o milis). Ustaw flagę błędu w przypadku błędu odczytu (stała wartość -127 lub 85). Proszę określić każdą bibliotekę i połączenie pinowe, które chcesz zastosować użyj w pierwszym komentarzu ze względu na pamięć, użyj bufora znaków zamiast ciągu.

Potężny monit; Podaje chip, strukturę, czujnik, protokół, pin, wzór próbkowania, status błędu i ograniczenia pamięci. W ten sposób wyniki są zarówno weryfikowalne, jak i realistyczne.

Przejrzyj listę kontrolną dla kodu osadzonego

Przed załadowaniem wyjścia AI przekaż je przez tę listę:

  1. Blokowanie: Czy w pętli głównej występuje opóźnienie lub długie blokowanie?
  2. volatile: Czy zmienne współdzielone z ISR są niestabilne?
  3. Dostęp atomowy: czy wielobajtowa zmienna współdzielona jest bezpieczna do odczytania?
  4. Rejestracja: Czy adresy i maski bitowe są zgodne z arkuszem danych?
  5. Pamięć: ciąg znaków, duże tablice, czy rekurencja powoduje przepełnienie poziomu KB?
  6. Obsługa błędów: Czy obsługiwane są błędy odczytu czujnika i przekroczenia limitu czasu komunikacji?
  7. Bezpieczny start: Czy podczas uruchamiania wyjścia siłownika znajdują się w stanie bezpiecznym (pasywnym)?

Mini etui

Inżynier systemów wbudowanych Baran każe sztucznej inteligencji napisać kod odczytujący IMU drona. Kod się kompiluje i wydaje się działać, ale wartości kąta są bez znaczenia. Baran stosuje listę kontrolną: porównuje adresy rejestrów z arkuszem danych i stwierdza, że ​​sztuczna inteligencja błędnie wyprowadza rejestr konfiguracji żyroskopu (0x1A zamiast 0x1B), więc skala czułości jest błędna. Po skorygowaniu wartości się ustalają. Następnie opóźnienia (10) powiadamiają w głównej pętli; konwersja tego na strukturę opartą na millisach, ponieważ blokowanie pętli sterowania lotem jest niedopuszczalne. Na koniec widzi, że współdzielona zmienna licznika nie jest zmienna i dodaje ją. AI szybko dała szkielet; Jednak na liście przeglądowej wykryto trzy oddzielne błędy: rejestr, blokowanie i lotność, a sprzęt nie był w ogóle zagrożony.

Typowe błędy

  • Zabijanie odpowiedzi w czasie rzeczywistym za pomocą funkcji opóźnienia() w głównej pętli sterującej.
  • Unikaj sprawiania, że ​​zmienna współdzielona z ISR będzie niestabilna i doświadczać cichego uszkodzenia danych.
  • Odczyt wielobajtowej zmiennej współdzielonej w sposób nieatomowy i generowanie warunku wyścigu.
  • Brak weryfikacji rejestrów/masek bitowych podanych przez sztuczną inteligencję w arkuszu danych.
  • Tworzenie przepełnienia pamięci przy użyciu ciągów i dużych tablic w ograniczonej pamięci RAM.
  • Zapominając o wstępnym zabezpieczeniu wyjść siłowników.

Podsumowując

  • Wbudowany kod; Działa z ograniczoną pamięcią, krótkim czasem i bezpośrednim dostępem do rejestrów.
  • W głównej pętli zamiast opóźnienia używany jest wzór nieblokujący oparty na millis.
  • ISR jest krótki; zmienne współdzielone muszą być zmienne i mieć dostęp atomowy.
  • Adresy rejestrów i maski bitowe są zawsze sprawdzane w oparciu o arkusz danych; AI może się mylić.
  • Zawsze sprawdzana jest pamięć, obsługa błędów i stan bezpiecznego uruchamiania.
  • Potężny monit; Obejmuje chip, strukturę, czujnik, protokół, pin i ograniczenia.

Zadanie aplikacji

Wybierz czujnik (np. DS18B20, MPU6050 lub HC-SR04) i mikrokontroler (Arduino/ESP32/STM32). Niech sztuczna inteligencja wygeneruje nieblokujący kod odczytu za pomocą potężnego szablonu podpowiedzi w tym urządzeniu. Następnie wykonaj jeden po drugim siedem elementów listy kontrolnej przeglądu: porównaj co najmniej jedną wartość rejestru/pinu z arkuszem danych, sprawdź opóźnienia pętli, sprawdź stan zmienności wspólnych zmiennych. Ile elementów „zaliczyło” za pierwszym podejściem, a ile wymagało korekty? Zanotuj każdy znaleziony problem i jego rozwiązanie.