ESP32 D1 mini – problem z regulatorem napięcia

Moduł zakupiony na Aliexpress: D1 mini ESP32 ESP-32 WiFi+Bluetooth Internet of Things development board based ESP8266 Fully functional

Proste programy działały, aż do momentu użycia Bluetooth / Wifi – następował reset Brownout detector:

Po krótkich poszukiwaniach w internecie, okazało się że podejrzanym może być regulator napięcia: https://www.reddit.com/r/esp8266/comments/9itox8/survey_did_you_get_a_150ma_regulator_on_your/

Strona https://www.esp32.com/viewtopic.php?t=2662 podaje, jaki jest pobór prądu przez ESP32:

SCENARIO—————————CPU80MHz—-CPU160MHz—-CPU240MHz
– CPU + ELECTRONICS + BT———–113mA——-123mA——–141mA
– CPU + ELECTRONICS—————-38mA——–51mA ——–73mA
– CPU (deep sleep) + ELECTRONICS—3.5mA——-3.5mA——–3.5mA

Na płytce znajdował się układ w obudowie SOT23-5 i oznaczeniu 4B2X.

Jeżeli jego wydajność prądowa to 150mA, to można postawić tezę, iż nie daje on rady. Wykonany został zatem pomiar napięcia wyjściowego stabilizatora w układzie z ESP32, który próbował uruchomić Wifi:

Widać spadek napięcia z 3,3 V do ok. 2,4 V, czyli o 0, 7 V. Ponowny wzrost napięcia spowodowany jest resetem ESP32.

Stabilizator został wymieniony na MIC5504-3.3YM5, o gwarantowanej wydajności prądowej 300 mA. Układ wyprowadzeń zgadzał się.

Po wymianie układu resety nie następowały. Tak prezentuje się pomiar po:

Tutaj również widać spadki napięć, jednak nigdy nie są poniżej 2,8 V. Możliwe, że brakuje kondensatora na wejściu układu. Mimo wszystko, problem wydaje się być rozwiązany.

Zabawy z FFT na STM32F103C8T6 (bluepill)

Procesor STM32F103C8T6 z rdzeniem ARM®Cortex®-M3 mogącym pracować z taktowaniem do 72MHz. 20KB SRAM i 64KB FLASH są zaletami, ale brak FPU w tej serii poważnie zmniejsza wydajność obliczeniową dla FFT, które zwykle wykorzystują typ danych float.

Uwaga 1: W tych eksperymentach nie jest wykorzystywany ADC – sample są generowane przez zdefiniowaną funkcję.

Uwaga 2: Wykorzystałem bibliotekę https://github.com/leeshineSZ/fft_for_stm32 – w razie jakby zniknęła z sieci, załączam:

fft_for_stm32-master

Uwaga 3: Do pomiarów wydajności wykorzystuję timer TIM1 w roli zwykłego timera/licznika. Okres ustawiony na max, tj. 65535. Prescaler na 1000. Ponieważ zegar trafia z linii APB2, to w moim przypadku daje to 72MHz na wejściu, po prescalerze 72KHz. Daje to (1/72KHz) 13,89us na pojedynczą inkrementację licznika. Wystarczy zerować rejestr licznika TIM1->CNT przed pomiarem, i odczytać rejestr po zakończeniu pomiaru, a potem przemnożyć przez 13,89us, żeby otrzymać czas potrzebny na wykonanie obliczeń.

Najpierw sprawdzałem, ile zajmuje mnożenie liczb float, a dokładniej zmiennej przez stałą. Jest to ok 3,43us, wliczając obieg pętli for.

Obliczenia FFT dla tablicy 128 próbek zajmują 6,5ms. Do tego trzeba doliczyć wyliczanie modułów liczb zespolonych – kolejne 0,93ms. Łącznie 7,43ms.

Daje to ok. 134Hz częstotliwości aktualizacji widma. Jest to tylko 128 próbek, czyli realnie 64 wartości w widmie – może wystarczyć do spektrometru na led-ach, gdzie mamy kilkanaście pasków.

Dla 1024 próbek FFT 61ms + moduł 7,4ms = 68,5ms, co daje częstotliwość odświeżania 14,6Hz – dosyć mało jak na wizualizację “real time”.

Wniosek 1: Częstotliwość próbkowania jest niezależna od ilości próbek, jakie bierzemy do analizy.

Wniosek 2: Więcej próbek – znacznie więcej czasu na obliczenia. Warto tą kwestię najpierw przemyśleć, bo zmiana nie ogranicza nam pasma, jedynie rozdzielczość.

Wniosek 3: Nie zastosowałem tu okien, co powoduje, że np. w widmie fali prostokątnej ciężko się jest jej doszukać – kolejne prążki szybko gasną, zwłasza jak nie “trafimy” z częstotliwością.

Wniosek 4: Fajnie by było wyeliminować floaty i skorzystać z np obliczeń stałoprzecinkowych.

Wniosek 5: Żeby wartości modułów odpowiadały rzeczywistości, należy ich amplitudy podzielić przez [0,5 x ilość próbek].

Wizualizacja obliczeń dla fali prostokątnej, 128 próbek i dokładnie “trafionej” (jeden cały okres):

Widać niską wartość składowej stałej i szybko malejące prążki nieparzyste – parzyste są równe składowej stałej. Nie wiem skąd ta składowa stała – jest dokładnie 64 próbek o wartości -30 i 64 próbki o wartości 30. Takiego rezultatu spodziewałbym się, gdybym miał o jedną próbkę dodatnią na plusie. Chyba że chodzi o aliasing – w końcu nie ograniczałem pasma prostokątowi.

Kod pisany w STM32CubeIDE.

STM32 obsługa enkodera na przykładzie STM32F103C8T6 (bluepill)

Konfiguracja STM32CubeMX

W przykładzie: STM32F103C8T6, użycie TIMERA2, enkoder na pinach PA0, PA1

 

Zmiany w kodzie programu (main.c):

Przed główną pętlą

W pętli głównej, odczyt wartości enkodera:

Wartości uzyskiwane będą z przedziału 0 – [Counter Period] – w naszym przypadku 0 – 1000 włącznie. Po przekroczeniu wartości 1000 licznik zaczyna zliczać dalej od zera.

Nie trzeba uruchamiać przerwań, ani wykonywać dodatkowych konfiguracji.


Przykład uruchomienia na płytce Bluepill:

Enkoder podpięty pod wejścia PA0, PA1 – jak w konfiguracji.

Udostępniam projekt z kodami źródłowymi oraz binarnymi, które były używane do testów: encoder_test

W kodzie zaimplementowana jest obsługa wirtualnego portu szeregowego pod USB, oraz zmiana tempa błyskania LED PC13 w zależności od wartości licznika enkodera.

Powyższy opis w pliku PDF do wydruku: STM32 obsługa enkodera inkrementalnego

OLED-AG-L-12864-05-WHITE-1i3 – biblioteka Eagle

Wyświetlacz OLED 1.3″ z dystrybucji firmy Artronic – największy niewymagający zewnętrznej przetwornicy napięcia.
Dokumentacja:
Hardware: http://www.artronic.com.pl/o_produkcie.php?id=2075
Software: http://www.artronic.com.pl/pdf/pl/SH1106.pdf
Potencjalna biblioteka Arduino: https://github.com/wonho-maker/Adafruit_SH1106
Biblioteka Eagle 7.1.1:
oled_artronic
Footprint w 2 wersjach – “płaskiej”, oraz ze slotem w PCB i taśmą lutowaną od spodu płytki.
Uwaga: biblioteka (jeszcze) nie sprawdzona w praktyce!

STM32 pierwsze kroki

Najtańsza płytka: stm32f103c8t6 (72MHz, USB device, 2 kwarce 8MHz i 32KHz, 64KB Flash, 20KB RAM, 2xADC; nie ma: DAC, FPU, EEPROM, )

Programator : ST-Link V2

Wyświetlanie Float przez printf:

Bug w STM32CubeMX w wersji 4.20.0, przy ustawieniu HSE – zewnętrznego kwarcu

W pliku main.c jest:

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI |RCC_OSCILLATORTYPE_HSE |RCC_OSCILLATORTYPE_LSE;

Powinno być:

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE |RCC_OSCILLATORTYPE_LSE;

źródło: https://community.st.com/thread/39340-bug-cubemx-v420-rcc-initialization-fail-with-hse-selected
 

Atmel Studio – wgrywanie programu do Atxmega256A3BU poprzez Flip

źródło: http://www.avrfreaks.net/forum/atmel-studio-61-evk1100-dfu-usb-programming

Klikamy w Menu Tools -> External Tools i uzupełniamy pola:
Title:

FLIP

Command:

C:\Program Files (x86)\Atmel\Flip 3.4.7\bin\Batchisp.exe

Arguments:

-device atxmega256a3bu -hardware usb -operation erase f memory flash blankcheck loadbuffer "$(TargetPath)" program verify start reset 0

Initial directory:

$(TargetDir)

Zaznaczamy opcję “Use Output window”
Klikamy OK.

as6_flip

Najlepiej dodać sobie tak utworzony skrót do paska narzędzi. Menu View -> Toolbars -> Customize…
Przechodzimy na zakładkę Commands, wybieramy pole Toolbar, z listy rozwijanej preferowany przez nas pasek narzędzi.
Klikamy przycisk “Add Command…” i szukamy w kategorii Tools pozycji “External Command 1”

Trzeba pamiętać, że przed załadowaniem programu musimy ręcznie uruchomić bootloader poprzez zwarcie odpowiedniego pinu do masy i reset mikrokontrolera.

Niestety nie ma możliwości, aby Atmel Studio sam przekazywał w parametrach wywołania programu Flip typ mikroprocesora.

Sensor dotykowy na AVR, udało się bez Qtouch library

IMAG0328W końcu udało mi się zmusić AVR’ki do odczytu dotykowych przycisków. Biblioteka Atmel Qtouch kusiła, ale za nic nie byłem wstanie jej rozgryźć, a o rozmiarze nie wspomnę. Poczytałem trochę teorii, znalazłem jakieś przykłady i udało się. Pierwszym efektem jest ten moduł. Jak działa w praktyce:

Jak działa w teorii:
Płytki czujników dotyku działają jak kondensatory, ładowane przez rezystor. Mikroprocesor ładuje ten układ RC, mierząc czas. Ponieważ R jest stałe, czas ładowania jest zależny od pojemności. Pojemność zmienia się gdy przykładamy palec – staje się on dielektrykiem. Aby układ działał, należy zadbać o kilka elementów:
-Pojemność takiego “kondensatora” jest bardzo mała. Aby wydłużyć czas ładowania, stosuje się rezystory o dużej wartości (ja użyłem z braku innych 10M, lepsze byłyby około 2-5M om).
-Jeden sensor wymaga jednego pinu do odczytu, i jednego do ładowania, z tym że ten drugi może obsługiwać jednocześnie wiele czujników.
-Czasy są tu bardzo niewielkie; nie ma po co używać funkcji opóźniających; sam obrót pętli pomiarowej jest wystarczająco długi.
-Zmiany pojemności są także niewielkie, dlatego ważne jest aby ta zmiana po przyłożeniu palca była możliwie duża. Dlatego płytki mają powierzchnię w postaci siatki, aby zmniejszyć ich własną pojemność. Wbrew intuicji, im większe pola sensorów, tym niekoniecznie lepiej.
-W takich układach bardzo ważne jest zastosowanie jak najkrótszych ścieżek, aby zmniejszyć szkodliwe pojemności.
-Ważne jest też wylanie dookoła masy, która będzie ekranować zakłócenia i stanowić drugą elektrodę kondensatora.
-Jak wynika z powyższego opisu, pomiar nie polega na wykryciu pojemności ludzkiego ciała względem ziemi, ani niczego takiego. Palec człowieka jest dielektrykiem w polu elektrycznym kondensatora utworzonego z pola czujnika i pobliskiego pola masy.

Download:

Tiny13_2x_touch_sources_firmware

tiny13_2x_touch

Mini stacja czujników online

Spakowany sketch Arduino: Pobierz sketch Mini stacja czujników online

Wymagana biblioteka (z odpowiednimi przeróbkami): EtherCard

Podłączenie:

  • Moduł Ethernet pod złącze ICSP na Arduino (MOSI – SI, MISO – SO, SCK – SCK, GND-GND), pin CS do pinu 8, VCC do 3,3V
  • DHT11 wyjście pod pin 12
  • MQ7 wyjście analogowe pod pin A0
  • Fotorezystor pomiędzy VCC a pin A1, który ściągamy do masy rezystorem 1KΩ
  • Moduł Ethernet podpięty do routera

Aby odnaleźć IP, pod którym widnieje nasz układ proponuję zalogować się do panelu administracyjnego routera, u mnie była to zakładka/okienko “DHCP Client List”. Odczyt z czujnika tlenku węgla w normalnych warunkach wynosi poniżej 50 (<250mV). Potraktowanie go jakimikolwiek oparami powoduje szybką reakcję i skok napięcia powyżej 1V (przy bliskim rozpyleniu).

 

Mój pierwszy robot Arduino

Kod źródłowy:

//ROBOT jeżdżący
//LCD I2C; 2x silniki, sonarr HC-SR04, tsop4836 RC5
//Piny:
/*
12: Silnik prawy kierunek;
11: Silnik prawy PWM;
4: Silnik lewy kierunek;
5: Silnik lewy PWM;
8: Sonar Echo;
9: Sonar trig;
10: TSOP4836;
SDA/SCL:  LCD 16x2;

*/
#include <Wire.h>  // Comes with Arduino IDE
#include <FastIO.h>
#include <I2CIO.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <LiquidCrystal_SR.h>
#include <LiquidCrystal_SR2W.h>
#include <LiquidCrystal_SR3W.h>



LiquidCrystal_I2C lcd(0x20, 4, 5, 6, 0, 1, 2, 3, 7, POSITIVE);  // Set the LCD I2C address
const int echo = 8;
const int trig = 9;
long duration, cm;

void setup(){
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(8, INPUT);
  pinMode(9, OUTPUT);
  pinMode(10, INPUT);

  analogWrite(6,0);
  analogWrite(5,0);
  digitalWrite(7,LOW);
  digitalWrite(4,LOW);
  digitalWrite(9,LOW);
  
  lcd.begin(16,2);         // initialize the lcd for 20 chars 4 lines]
  lcd.setBacklightPin(7, NEGATIVE);
  lcd.setBacklight(0);
// NOTE: Cursor Position: CHAR, LINE) start at 0  
  lcd.setCursor(0,0); //Start at character 4 on line 0
  lcd.print("ROBOT! 4");


}
void loop(){
int wynik;
lcd.setCursor(0,1);
lcd.print("L:           ");
lcd.setCursor(3,1);
wynik = pomiar();
if(wynik<3000){
  lcd.print(wynik);
  
    if(wynik<30)
    {
      digitalWrite(7,LOW);
      digitalWrite(4,LOW);
      analogWrite(6,255);
      analogWrite(5,255);
    }
    if((wynik>30) && (wynik<80))
    {
      digitalWrite(7,LOW);
      digitalWrite(4,LOW);
      analogWrite(6,0);
      analogWrite(5,0);
    }

    if(wynik>50)
    {
      digitalWrite(7,HIGH);
      digitalWrite(4,HIGH);
      analogWrite(6,0);
      analogWrite(5,0);
    }


}
delay(10);


}
int pomiar(void)
{
  pinMode(trig, OUTPUT);
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
   
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echo, INPUT);
  duration = pulseIn(echo, HIGH);
  return microsecondsToCentimeters(duration);
}

int microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}