Spickzettel für ESP32
Installation in der Arduino-IDE
- Menü Datei->Voreinstellungen->Zusätzliche Boardverwalter-URLs anfügen
(mehrere durch Kommas getrennt):
[Quelle]
Hardware ESP32 Dev Module
GPIO-Belegung zum ESP32-WROOM
- IO0 - interner Pull-Up, BOOT-Taster, low durch DTR=0 und RTS=1
- IO1 - TxD der USB-UART
- IO2 - Pull-down, blaue LED, muss beim Reset low sein
- IO3 - RxD der USB-UART
- IO5 - Pull-Up: SDIO Timing
- IO6...IO11 - SPI-Flash-Interface
- IO12 (MTDI) muss beim Reset low (bzw. offen) sein, da sonst die Spannung für den Flash auf
1,8V umgeschaltet wird und so nicht gebootet werden kann
kann durch eFuses "befreit" werden: XPD_SDIO_FORCE=1 (VDD_SDIO wird durch
eFuse bestimmt), XPD_SDIO_REG=1 (enable regulator), XPD_SDIO_TIEH=1 (3,3V)
- IO15 (MTDO) steuert die Boot-Debug-Ausgabe: high (offen, PullUp während
Reset) über
die serielle Schnittstelle wird der Bootprozess protokolliert (115200 8N1), low
erfolgt keine Ausgabe
- der EN-Eingang (Reset) kann durch den Taster "EN" oder die USB-UART
aktiviert werden (DTR=1 und RTS=0)

Pins
30-Pin-Variante (schwarze Pinleiste)
- GPIO 1(TX0 mit blauer LED nach 3V3),2(blaue
LED),3(RX0),4,5,12-15,16(RX2),17(TX2),18-19,21,22,25-27,32-33, IN-only:
34,35,36(VP), 39(VN)
- VIN (5V Eingang)
- 3V3 (3,3V Ausgang, oder Eingang statt 5V)
- GND (2x)

Pins
36-Pin-Variante (gelbe Pinleiste)
- EN mit 12k PullUp, C nach Masse und 470Ω mit Reset-Taste nach
Masse
- G0/IO0 mit 5k1 PullUp
- GPIO 1(TX0),2,3(RX0),4,5,12-15,16(RX2),17(TX2),18-19,21,22,25-27,32-33,
IN-only: 34,35,36(VP), 39(VN)
- zusätzlich zur 30er Variante: GPIO 6-11 reserviert für SPI-Flash
- VIN (5V Eingang)
- 3V3 (3,3V Ausgang, oder Eingang statt 5V)
- GND
Standard-Belegung ESP32
- UART0: IO1 (TxD), IO3 (RxD)
- UART2: IO17 (TxD), IO16 (RxD)
- I2C: IO21 (SDA), IO22 (SCL)
- VSPI: IO23 (MOSI), IO19 (MISO), IO18 (CLK), IO5 (CS0)
- HSPI: IO13 (MOSI), IO12 (MISO), IO14 (CLK), IO15 (CS0)
LOLIN32 mit LiIon
- Chip: ESP32-D0WDQ6
- 25C32STIG
ESP32-CAM
- AI Thinker: Modul ESP32-S mit ESP32-D0WDQ5
- DiyMore: Modul ESP32-S mit ESP32-D0WDQ6
- rote LED an GPIO33 - leuchtet bei '0'
- PSRAM IPUS IPS6404 - 64MBit / 8MB : über ESP32 sind 4MB (ohne große
Umstände) adressierbar
- IO16 - CS#
- IO17 - PSRAM_CLK
- IO7 - SD0 (SPI_Q Flash-/RAM-SPI)
- IO8 - SD1 (SPI_D Flash-/RAM-SPI)
- IO9 - SD2 (SPI_HD Flash-/RAM-SPI)
- IO10 - SD3 (SPI_WP Flash-/RAM-SPI)
- OV2460 mit SCCB-Interface auf I2C-Adresse 0x30 zur Steuerung
- IO5 - CSI_D0
- IO18 - CSI_D1
- IO19 - CSI_D2
- IO21 - CSI_D3
- IO36 - CSI_D4
- IO39 - CSI_D5
- IO34 - CSI_D6
- IO35 - CSI_D7
- IO0 - CSI_MCLK
- IO22 - CSI_PCLK
- IO23 - CSI_HSYNC
- IO25 - CSI_VSYNC
- IO26 - TWI_SDA mit 4k7 PullUp
- IO27 - TWI_SCK mit 4k7 PullUp
- IO32 - CAM_PWR: bei '0' schaltet ein FET Spannung auf die
Spannungsregler für das Kameramodul
- MicroSD-Slot
- IO2 - HS2_DATA0
- IO4 - HS2_DATA1
- IO12 - HS2_DATA2
- IO13 - HS2_DATA3
- IO14 - HS2_CLK
- IO15 - HS2_CMD
- Pins
- IO0 - CSI_MCLK mit 10k PullUp
- IO1 / U0TXD
- IO3 / U0RXD
- IO2 - HS2_DATA0
- IO4 - HS2_DATA1 - steuert bei '1' auch den Treibertransistor der
Flash-LED an
- IO12 - HS2_DATA2 - muss beim Reset low (bzw. offen) sein
- IO13 - HS2_DATA3
- IO14 - HS2_CLK
- IO15 - HS2_CMD
- IO16 - PSRAM_CLK
Wemos S2 Mini
- Chip: ESP32-S2 Rev 0
- Probleme mit Arduino V2! (sporadischer Neustart ohne Fehlerangabe)
- Arduino-Board "LOLIN S2 MINI"
- ESP32-S2FH32 Single-Core mit 4MB Flash, 2MB PSRAM; "ESP32-S2F N4R2..."
- ESP32-S2FH32 Single-Core mit 4MB Flash, ohne PSRAM; "ESP32-S2F H4..."
- ESP32-S2FH32 Single-Core mit 2MB Flash, ohne PSRAM; "ESP32-S2F H2..."
- Boot-Strap-Pins
- GPIO0 (PullUp) Boot-Mode: 1=SPI-Boot, 0=Download (wenn auch
GPIO46=0)
- GPIO45 (PullDown) VDD-SPI-Voltage: 0=3,3V, 1=1,8V
- GPIO46 (PullDown) Boot-Printout: 0=enabled, 1=disabled
- Link
- GPIO15 über 2k an LED
- GPIO18 mit 10k PullUp (Workaround Errata "Random flash download failure"
für Chip Rev. 0)
- Serielles USB-Gerät (COMx) : VID_303A PID_0002 REV_0723 MI_00
-
https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32s2/api-guides/dfu.html
- use version 2.8 (or newer) of the
ESP-IDF Tools Installer and select the driver "Espressif - WinUSB
support for JTAG (ESP32-C3/S3)"
- https://github.com/Adam-U/ESP32_VSCode_Debug
-
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/configure-ft2232h-jtag.html
- https://github.com/espressif/arduino-esp32/issues/5994
- U0TXD liegt auf GPIO43, darüber erfolgt auch das Boot-Up-Output, wenn
nicht durch eFuse EFUSE_UART_PRINT_CHANNEL auf GPIO17/U1TXD gesetzt:
- espefuse.py --chip esp32s2 --baud 921600 --port COM8 summary
- espefuse.py --chip esp32s2 --baud 921600 --port COM8 burn_efuse UART_PRINT_CHANNEL
- wenn man auf den bootup-log verzichten kann, könnte U0TXD auf einen beliebigen anderen Pin geroutet werden
- #include "hal/gpio_hal.h"
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[17], PIN_FUNC_GPIO);
pinMatrixOutAttach(17, U0TXD_OUT_IDX, false, false);
- Serial0.begin(115200,SERIAL_8N1,18,17);
- mit 115200 baud: ESP-ROM:esp32s2-rc4-20191025 Build:Oct 25 2019 rst:0x1
(POWERON),boot:0xa (SPI_FAST_FLASH_BOOT) SPIWP:0xee mode:DIO, clock div:1
load:0x3ffe6100,len:0x524 load:0x4004c000,
- mit 460800 baud: load:0x40050000,len:0x2914
entry 0x4004c18c
- boot (GPIO_STRAP_REG): 0x10=GPIO45, 0x8=GPIO0, 0x4=GPIO46
- IOs, neben IO15=LED, IO0=Taster
- EN
- IO1 bis IO18 (IO1 bis IO10 können als Analogeingänge von ADC1 verwendet
werden, 17/18=UART1TX/RX)
- IO21
- IO33 bis IO40
- Reboot / "Crash" bei WiFi.begin : EN / CHIP_PU bekommt einen Low-Spike -
die 100nF an EN reichen nicht aus: wie in den Hardware Design Guidelines
funktioniert es mit 1µF (mit einem zweiten 100nF hat es auch nicht
funktioniert)
ESP-Chips
HC2v1: ESP32 Chip model = ESP32-D0WDQ5 Rev 1
HC2v2: ESP32 Chip model = ESP32-D0WD Rev 1
RAM im ESP32
- die 520kB dyn. RAM im ESP32 sind so aufgeteilt:
- 64kB SRAM-0 als Instr-RAM oder Cache für externen Speicher
- 128kB SRAM-0 als Instr-RAM
- 8kB RTC_FAST-RAM als Instr-RAM
- 128kB SRAM-1 als Data-RAM, das auch als Instr-RAM nutzbar ist
- 200kB SRAM-2 als Data-RAM
- \cores\esp32\Esp.cpp
- ESP.getHeapSize() = heap_caps_get_info(&info, MALLOC_CAP_INTERNAL)
info.total_free_bytes + info.total_allocated_bytes
- ESP.getFreeHeap() = heap_caps_get_free_size(MALLOC_CAP_INTERNAL)
- ESP.getMaxAllocHeap() =
heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)
- MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL
- MALLOC_CAP_SPIRAM
PSRAM
- ESP32 rev. 0: kein PSRAM-Support wegen Hardware-Bugs
- ESP32 rev. 1: Workaround muss aktiviert werden:
-mfix-esp32-psram-cache-issue / CONFIG_SPIRAM_CACHE_WORKAROUND
- ESP32 rev. 3: keine Workarounds notwendig, CONFIG_ESP32_REV_MIN option
sollte auf rev. 3 gesetzt werden, damit die Workarounds deaktiviert werden
- weitere sdkconfig: CONFIG_SPIRAM_SUPPORT, CONFIG_SPIRAM
- wenn PSRAM vorhanden ist, so wird dieser mit in die Memory-List
integriert, sodass ein malloc auch PSRAM zurückgibt. Soll DRAM erzwungen
werden muss heap_caps_malloc(size, MALLOC_CAP_INTERNAL) oder
heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL, MALLOC_CAP_SPIRAM)
benutzt werden.
Bootup-Messages
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:9720
ho 0 tail 12 room 4
load:0x40080400,len:6352
entry 0x400806b8
Der Wert "boot" (GPIO_STRAP_REG) gibt den Zustand der Pins GPIO12, GPIO0, GPIO2, GPIO4,
GPIO15, GPIO5 beim Reset an.
Bei normalem Start (mit 1,8V-Flash) ist boot=0x13.
Bei Upload-Mode (IO0=0) ist boot=0x03.
|
GPIO12
0=3,3V
1=1,8V |
GPIO0
1=App
0=Upload |
GPIO2 |
GPIO4 |
GPIO15 |
GPIO5
SDIO Timing
0
1 |
0x13 |
0 |
1 |
0 |
0 |
1 |
1 |
0x03 |
0 |
0 |
0 |
0 |
1 |
1 |
0x17 |
0 |
1 |
0 |
1 |
1 |
1 |
0x07 |
0 |
0 |
0 |
1 |
1 |
1 |
|
|
|
|
|
|
|
Programmierung des ESP32 Dev Module
Bootloader
Der Bootloader im ESP32 fragt nach einem Reset den Zustand von GPIO0 ab. Ist
dieses Low startet der serielle Flashloader. IO0 muss dazu mind. 1ms nach EN=1
auf 0 gehalten werden. Die auf dem Eval-Board verwendete RTS/DTR-Logik
verhindert ein gleichzeitiges Low an EN und IO0. Das esp32load.py schaltet RTS
und DTR zu langsam um, sodass IO0 zu spät 0 ist. Abhilfe wäre die Vergrößerung
der Reset-Zeitkonstante durch eine größere Kapazität.
[Quelle]
Pin lesen
digitalRead(switchPin);
Z.B. ist der BOOT-Switch mit IO0 verbunden (um nach dem Reset vom Bootloader
in den Flash-Loader zu wechseln) und kann sofort als Taster im Programm genutzt
werden (switchPin=0).
Pin schreiben
#define ledPin 2
digitalWrite(ledPin, HIGH);
Auf dem ESP32 Dev Module V1 ist an IO2 eine blaue LED angeschlossen.
A/D-Wandler
Das Lesen erfolgt wie üblich über
analogRead(34); // read analog GPIO34
Der ESP32 hat zwei ADCs: ADC1 und ADC2.
CH |
ADC1
GPIO |
ADC2*
GPIO |
CH# |
0 |
36* |
4 |
10 |
1 |
37* |
0 |
11 |
2 |
38* |
2 |
12 |
3 |
39* |
15 |
13 |
4 |
32 |
13 |
14 |
5 |
33 |
12 |
15 |
6 |
34 |
14 |
16 |
7 |
35 |
27 |
17 |
8 |
|
25 |
18 |
9 |
|
26 |
19 |
|
Hall |
vdd33 |
|
*GPIO36 und GPIO39 dürfen bei Verwendung des Halls nicht beschaltet sein.
*GPIO37 und GPIO38 sind beim ESP32-WROOM-32 nicht herausgeführt
*ADC2 ist bei Verwendung von WiFi nicht verfügbar.
Wenn der volle Spannungsbereich gewählt ist (atten=3, d.h. 0..3,3V), dann ist
ab einer Spannung von ca. 2450mV (3000 ADC) das ADC-Ergebnis nicht mehr linear.
Siehe Datasheet 4.1.2. Der genauere Spannungsbereich wäre dann 150mV..2450mV bei
0dB, bzw. 0mV..2500mV beim ESP32-S2
- analogReadMilliVolts(ADC_PIN) : ADC-Wert in mV nach Korrektur durch
eFuse
- analogSetPinAttenuation(pin, attenuation) : attenuation=[0db, 2_5db,
6db, 11db] für die ESP32-Bereiche 0,15V..2,45V / 0,15V..1,75V /
0,1V..1,25V / 0,1V..0,95V und die ESP32-S2 0V..2,5V / 1,3V / 1,05V / 0,75V
- analogSetWidth(bits) : bits=[9,10,11,12]
Der ESP32-S2 hat zwei ADCs: ADC1 und ADC2.
CH |
ADC1
GPIO |
ADC2*
GPIO |
0 |
1 |
11 |
1 |
2 |
12 |
2 |
3 |
13 |
3 |
4 |
14 |
4 |
5 |
15 |
5 |
6 |
16 |
6 |
7 |
17 |
7 |
8 |
18 |
8 |
9 |
19 |
9 |
10 |
20 |
|
|
pa_pkdet1 |
|
|
pa_pkdet2 |
|
|
vdd33 |
ADC2 kann zwar parallel zu WiFi verwendet werden, eine Wandlung kann aber
durch die höhere Prio des WiFi abgebrochen werden.
Serielle Schnittstelle
Der ESP32 hat 3 UARTs.
Die erste UART, die auf dem Dev-Modul mit dem CP2102 verbunden ist (über IO1
und IO3), wird wie üblich initialisiert mit
Serial.begin(115200);
Die zwei anderen UARTs werden durch den Konstruktor definiert und mit Angabe der Pin-Nummern
in begin()
initialisiert:
//Definition der beiden Schnittstellen
HardwareSerial Serial1(1);
HardwareSerial Serial2(2);
void setup()
{ //Starten der Schnittstellen
Serial.begin(115200);
//Serial1 auf Pin 12 und 13
Serial1.begin(9600,SERIAL_8N1,12,13); //Serial2 auf Pin 22 und 23
Serial2.begin(9600,SERIAL_8N1,22,23); //Startmeldung ausgeben
Serial.println();
Serial.println("Bitte eine Eingabe:");
}
[Quelle]
CAN-Schnittstelle
ESP32-CAN-Bibliothek "miwagner": [Quelle]
als .zip herunterladen und nach "Arduino\libraries" entpacken oder mittels
Sketch > Include Library > Add .ZIP Library importieren
weitere Bibliotheken für MCP2515 [3/2024]:
Self-Test-Mode
Im Self-Test-Mode wird kein ACK benötigt, was sich zum Testen bzw. am Bus mit
nur einem, nicht immer aktiven Teilnehmer eignet. Um diesen zu aktivieren habe
ich folgende Änderungen der ESP32CAN-Lib vorgenommen:
Datei |
Änderung/Erweiterung |
ESP32CAN.cpp |
int ESP32CAN::CANSTM() {
return CAN_STM();
}
|
ESP32CAN.h |
class ESP32CAN {
public:
int CANSTM();
};
|
CAN.c |
int CAN_STM() {
// enter reset mode
MODULE_CAN->MOD.B.RM = 1;
MODULE_CAN->MOD.B.STM = 1;
MODULE_CAN->MOD.B.RM = 0;
return 0;
} |
Vergleich "ESP32CAN" ESP32-Arduino-CAN <> acan-esp32
|
ESP32CAN |
ACAN_ESP32 |
Methoden |
CANInit()
CANConfigFilter()
CANWriteFrame()
CANStop()
CANSTM()
CANLOM() |
available()
receive()
getReceivedMessage()
tryToSend()
|
Konfig |
CAN_device_t CAN_cfg [Global]
CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t)) |
ACAN_ESP32_Settings settings (DESIRED_BIT_RATE) |
Filter |
ESP32Can.CANConfigFilter(&p_filter) |
ACAN_ESP32_Filter filter = ACAN_ESP32_Filter::singleStandardFilter
(ACAN_ESP32_Filter::data, 0x123, 0x404) |
Init |
ESP32Can.CANInit() |
ACAN_ESP32::can.begin (settings, filter) |
|
|
ACAN_ESP32::can.tryToSend (frame) |
|
xQueueReceive(CAN_cfg.rx_queue, &rx_frame, timeout) |
ACAN_ESP32::can.receive (frame) |
Tx |
ISR: Tx => xSemaphoreGiveFromISR(sem_tx_complete) |
|
Rx |
ISR: Rx => xQueueSendToBackFromISR() |
|
I2C-Schnittstelle
#include <Wire.h> // I2C
Wire.begin(21,22);
Wire.setClock(400000); // choose 400 kHz I2C rate
Wire.beginTransmission(0x3B); // Initialize the Tx buffer
Wire.write(0x0F); // Put WHO_AM_I address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(0x3B, 1); // Read two bytes from slave PROM address
while (Wire.available()) {
data = Wire.read(); } // Put read results in the Rx buffer
#include <Wire.h>
#define SDA1 21
#define SCL1 22
#define SDA2 17
#define SCL2 16
TwoWire I2Cone = TwoWire(0);
TwoWire I2Ctwo = TwoWire(1);
SPI-Schnittstelle
siehe Arduino->Beispiele->SPI
Preferences / NVS
#include <Preferences.h>
Preferences prefs;
prefs.begin("nvs", false);
prefs.putUChar("addr", 65);
byte b = prefs.getUChar("addr", 0);
prefs.remove("nvs");
[Quelle]
EEPROM
#include <EEPROM.h>
EEPROM.begin(EEPROM_SIZE);
EEPROM.write(address, value);
EEPROM.commit();
EEPROM.read(address);
[Quelle]
OLED-Display
SSD1306 128x64 I2C monochrom
SSD1351 128x160 SPI monochrom
SSD1353 128x160 SPI RGB15
Adafruit SSD1351 RGB
Pinout:
- GND
- Vin - 5V
- Vio - 3,3V
- CD
- MISO (out) - nur bei SD-Karte: mit MISO (IO19) verbunden
- SDCS - CS der SD-Karte
- OLEDCS - CS des OLED
- RESET - optional
- DC - Data/Command
- SCK - mit SCLK (IO18) verbunden
- MOSI (in) - mit MOSI (IO23) verbunden
Ucglib
- sclk = SCK
- data = MOSI
- cd = DC
- cs = CS
U8glib
#include "U8glib.h"
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0); // I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_NO_ACK|U8G_I2C_OPT_FAST); // Fast I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); // Display which does not send AC
void setup()
{
// assign default color value
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255); // white
}
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
u8g.setColorIndex(3); // max intensity
}
else if ( u8g.getMode() == U8G_MODE_BW ) {
u8g.setColorIndex(1); // pixel on
}
else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
u8g.setHiColorByRGB(255,255,255);
}
void loop(void)
{
// picture loop
u8g.firstPage();
do
{
draw();
} while( u8g.nextPage() );
}
// Page-Mode (_1_) oder FullyBuffered (_F_)
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R2, /* clock=*/ 16, /* data=*/ 17, /* reset=*/ U8X8_PIN_NONE); // ESP32 Thing, pure SW emulated I2C
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17); // ESP32 Thing, HW I2C with pin remapping
void setup()
{
u8g2.begin();
}
void loop(void)
{
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
// im Fully Buffered Mode wird nur eine große Page benötigt
u8g2.clearBuffer(); // clear the internal memory
u8g2.drawStr(0,10,"Hello World!"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
// im Page-Mode müssen die Befehle für jede Page wiederholt werden
do
{
u8g2.drawStr( 0, 0, "drawLine");
} while( u8g2.nextPage() );}
SSD1353 mit u8glib
Die u8glib enthält nur teilweise die Unterstützung für den SSD1353.
Hinzugefügt habe ich:
Datei |
Änderung/Erweiterung |
u8glib.h |
class U8GLIB_SSD1353_160X128_HICOLOR : public U8GLIB
{
public:
U8GLIB_SSD1353_160X128_HICOLOR(uint8_t sck, uint8_t mosi, uint8_t cs, uint8_t a0, uint8_t reset = U8G_PIN_NONE)
: U8GLIB(&u8g_dev_ssd1353_160x128_hicolor_sw_spi, sck, mosi, cs, a0, reset) { }
U8GLIB_SSD1353_160X128_HICOLOR(uint8_t cs, uint8_t a0, uint8_t reset = U8G_PIN_NONE)
: U8GLIB(&u8g_dev_ssd1353_160x128_hicolor_hw_spi, cs, a0, reset) { }
};
class U8GLIB_SSD1353_160X128_332 : public U8GLIB
{
public:
U8GLIB_SSD1353_160X128_332(uint8_t sck, uint8_t mosi, uint8_t cs, uint8_t a0, uint8_t reset = U8G_PIN_NONE)
: U8GLIB(&u8g_dev_ssd1353_160x128_332_sw_spi, sck, mosi, cs, a0, reset) { }
U8GLIB_SSD1353_160X128_HICOLOR(uint8_t cs, uint8_t a0, uint8_t reset = U8G_PIN_NONE)
: U8GLIB(&u8g_dev_ssd1353_160x128_332_hw_spi, cs, a0, reset) { }
}; |
clib\u8g.h |
/* SSD1353 OLED Palmtronics */
extern u8g_dev_t u8g_dev_ssd1353_160x128_332_hw_spi;
extern u8g_dev_t u8g_dev_ssd1353_160x128_hicolor_hw_spi;
extern u8g_dev_t u8g_dev_ssd1353_160x128_332_sw_spi;
extern u8g_dev_t u8g_dev_ssd1353_160x128_hicolor_sw_spi; |
|
|
|
|
|
|
SSD1351 vs. SSD1353
|
SSD1351 |
SSD1353 |
ucglib |
Set Column Address |
0x15 Start End |
x |
Set Row Address |
0x75 Start End |
x |
Write RAM Command |
0x5C |
x |
Read RAM Command |
0x5D |
|
Set Second Precharge speed |
N/A |
0x8A AA |
|
Set Re-map / Color Depth
(Display RAM to Panel) |
0xA0 Bits
leicht unterschiedliche Reset-Werte, Bit 3 unterschiedlich |
|
Set Display Start Line / vertical scroll by RAM |
0xA1 Start |
|
Set Display Offset |
0xA2 Offset |
|
Set Display Mode - All OFF |
0xA4 |
0xA6 |
|
Set Display Mode - All ON, GS63 |
0xA5 |
|
Set Display Mode - Reset to normal |
0xA6 |
0xA4 |
|
Set Display Mode - Inverse |
0xA7 |
|
Function Selection (Vdd, Interface Width) |
0xAB Bits |
N/A |
|
Dim Mode setting |
N/A |
0xAB AA BB CC DD EE |
|
Display ON in dim mode |
N/A |
0xAC |
|
NOP |
0xAD
0xB0
0xD1 |
N/A |
|
Sleep Mode On (Display OFF) |
0xAE |
x |
Sleep Mode Off (Display ON) |
0xAF |
|
Set Reset (Phase 1) /
Pre-charge (Phase 2) period |
0xB1 AB; vorwärtskompatibel |
|
Display Enhancement |
0xB2 AA BB CC |
N/A |
|
Front Clock Divider (DivSet)/
Oscillator Frequency |
0xB3 AB - unterschiedliche
Wertezuordnung |
|
Set Segment Low Voltage (VSL) |
0xB4 AA BB CC |
N/A |
|
Set GPIO |
0xB5 Bits |
N/A |
|
Set Second Precharge Period |
0xB6 AA |
0xB4 AA gleicher Wertebereicch |
|
Look Up Table for Gray Scale Pulse width |
0xB8 AA[63], aber
unterschiedlicher Wertebereich |
|
Use Built-in Linear LUT [reset= linear] |
0xB9 |
|
Set Pre-charge voltage |
0xBB AA, aber unterschiedlicher
Wertebereich |
|
Set VCOMH Voltage |
0xBE AA, aber unterschiedlicher
Wertebereich |
|
OTP Write |
N/A |
0xC0 AA BB |
|
Set Contrast Current for Color A,B,C |
0xC1 AA BB CC |
0x81 AA
0x82 BB
0x83 CC |
|
Master Contrast Current Control |
0xC7 AA |
0x87 AA, gleicher Wertebereich |
x |
Set Multiplex Ratio |
0xCA AA |
0xA8 AA |
|
Software Reset |
N/A |
0xE2 |
|
NOP |
0xE3 |
|
Set Command Lock |
0xFD AA, aber unterschiedlicher
Wertebereich [AA.2] |
|
Graphic Acceleration |
|
Horizontal Scroll |
0x96 AA BB CC DD EE |
0x27 AA BB CC DD EE, dazu 0xA3 |
|
Stop Moving |
0x9E |
0x2E |
|
Start Moving |
0x9F |
0x2F |
|
Set Vertical Scroll Area |
N/A |
0xA3 AA BB |
|
Draw Line |
N/A |
0x21 D[7] |
|
Drawing Rectangle |
N/A |
0x22 D[10] |
|
Copy |
N/A |
0x23 D[6] |
|
Dim Window |
N/A |
0x24 D[4] |
|
Clear Window |
N/A |
0x25 D[4] |
|
Fill Enable / Disable |
N/A |
0x26 AA |
|
Ucglib
Datei |
|
|
ucglib.h |
class Ucglib_SSD1353_18x160x128_HWSPI : public Ucglib4WireHWSPI
{
public:
Ucglib_SSD1353_18x160x128_HWSPI( uint8_t cd, uint8_t cs =
UCG_PIN_VAL_NONE, uint8_t reset = UCG_PIN_VAL_NONE) :
Ucglib4WireHWSPI(ucg_dev_ssd1353_18x160x128_ilsoft, ucg_ext_ssd1353_18,
/*cd=*/ cd , /*cs=*/ cs, /*reset=*/ reset)
{ }
}; |
|
clib\ucg.h |
ucg_int_t ucg_dev_ssd1353_18x160x128_dep(ucg_t *ucg, ucg_int_t msg,
void *data); // ucg_dev_oled_160x128_dep.c
ucg_int_t ucg_ext_ssd1353_18(ucg_t *ucg, ucg_int_t msg, void *data); //
ucg_dev_ic_ssd1353.c
ucg_int_t ucg_dev_ic_ssd1353_18(ucg_t *ucg, ucg_int_t msg, void *data);
// ucg_dev_ic_ssd1353.c |
|
|
|
|
Fonts
In der Fontbezeichnung sind verschiedene Dinge kodiert [Quelle]:
- 't' - transparenter Font, mit UCG_FONT_MODE_TRANSPARENT zu benutzen
- 'h' - mit UCG_FONT_MODE_TRANSPARENT und UCG_FONT_MODE_SOLID zu benutzen
- 'm' - Monospace mit UCG_FONT_MODE_TRANSPARENT und UCG_FONT_MODE_SOLID zu
benutzen
- '8' - Monospace mit Größe aus Vielfachem von 8 mit
UCG_FONT_MODE_TRANSPARENT und UCG_FONT_MODE_SOLID zu benutzen
- 'f' - 256 Zeichen
- 'r' - ASCII 32 bis 127
- 'n' - nur Zahlen und Zeichen für Datum und Uhrzeit
Web-Update
[Quelle]
Das Beispiel "OTAWebUpdater" nutzt jQuery, sodass ein Update nicht möglich
ist, wenn der ESP32 als AccessPoint läuft, weil die jquery.min.js nicht aus dem
Internet geladen werden kann. Stattdessen kann das AJAX auch direkt ins
Javascript der firmwareUploadHTML geschrieben werden - einfach dieses firmwareUploadHTML
benutzen:
/*
* HTML-Seite Firmware-Upload: "/firmwareUpload"
*/
//#define HTMLCrLf "\n"
#define HTMLCrLf
const char* firmwareUploadHTML =
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form' onsubmit='return uploadFile(this);'>" HTMLCrLf
"<input type='file' name='update'>" HTMLCrLf
"<input type='submit' value='Update'>" HTMLCrLf
"</form>" HTMLCrLf
"<div id='prg'>progress: 0%</div>" HTMLCrLf
"<script>" HTMLCrLf
"function uploadFile(form)" HTMLCrLf
"{" HTMLCrLf
"var xhr = new window.XMLHttpRequest();" HTMLCrLf
"xhr.upload.addEventListener('progress', function (evt)" HTMLCrLf
"{" HTMLCrLf
"if (evt.lengthComputable)" HTMLCrLf
"{" HTMLCrLf
"var per = evt.loaded / evt.total;" HTMLCrLf
"document.getElementById('prg').innerHTML = 'progress: ' + Math.round(per*100) + '%';" HTMLCrLf
"}" HTMLCrLf
"}, false);" HTMLCrLf
"xhr.open('POST', '/update', true);" HTMLCrLf // true für async
"var data = new FormData(form);" HTMLCrLf
"xhr.onload = function()" HTMLCrLf
"{" HTMLCrLf
"if (xhr.status === 200)" HTMLCrLf
"{" HTMLCrLf
"console.log('success!');" HTMLCrLf
"document.getElementById('prg').innerHTML = 'Success!';" HTMLCrLf
"}" HTMLCrLf
"else document.getElementById('prg').innerHTML = 'Upload error!';" HTMLCrLf
"};" HTMLCrLf
"xhr.send(data);" HTMLCrLf
"return false;" HTMLCrLf
"}" HTMLCrLf
"</script>";
RMT
- der RMT-Puffer ist 512x32 Bits groß und ist in 8 Blöcke aufgeteilt:
- ein Block besteht aus 64 Items je 32 Bit
- pro Item sind zwei Zeit-Pegel-Paare abgelegt (Pegel im MSB)
- das Low-Word eines Items wird zuerst gesendet
- das Ende wird durch eine Dauer von 0 angezeigt
- den 8 Kanälen können eine bestimmte Anzahl Puffer-Blöcke zugewiesen
werden, wobei der erste Block eines Kanals immer der Kanalnummer entspricht:
- Channel 0: Startblock 0
- ...
- Channel 7: Startblock 7
- d.h. wenn Channel 0 zwei Blöcke belegt, kann Channel 1 nicht genutzt
werden
UNI/O
Nach einem POR/BOR muss VOR dem ersten Standby-Pulse ein L-H-Übergang erfolgt
sein!
- Standby-Pulse: High für TSTBY=600µs min.
- wird kein Standby-Pulse benutzt (weil das Device noch aktiv ist), muss TSS=10µs
min. gewartet werden, bevor ein neuer Startheader gesendet wird.
- '0' wird als H+L, '1' als L+H-Pulse gesendet
- Startheader: L für THDR=5µs min., dann 01010101, dann MAK
('1') und noSAK (H+H)
- es folgt die Device-Address, z.B. 10100000 + MAK + SAK
- nach dem SAK ist der Bus High, d.h. nach TSTBY würde der Standby
aktiviert sein - d.h.
- optional: um die Kommunikation anzuhalten, kann statt des nächsten MAK
der Bus für mind. eine Bitdauer auf Low gehalten werden,
- Zum Lesen von 32 Bits inkl. Header werden 2+10*(1+1+2)+3*3=54 RMT-Items
benötigt
- 4 Bytes lesen: bis zu 84 [2+10*(1+1+2+4)+2]
- 6 Bytes lesen: bis zu 104 [2+10*(1+1+2+6)+2]
- 8 Bytes lesen: bis zu 124 [2+10*(1+1+2+8)+2]
- 10 Bytes lesen: bis zu 144 [2+10*(1+1+2+10)+2]
- 16 Bytes lesen: bis zu 204 [2+10*(1+1+2+16)+2]
- genauer: 22 + 9*len
- 1 Tss+Thdr
- 13 Start+Device
- 9 pro Byte
- (1 für internes Ende)
- 64er-Puffer: 4 Byte
- 128er-Puffer: 11 Byte
- 192er-Puffer: 18 Byte
WiFi
Zum Debugging bietet es sich an, die WiFi-Events zu beobachten:
void WiFiEvent(WiFiEvent_t event, system_event_info_t info){...}
WiFi.onEvent(WiFiEvent);
WiFi.mode() - WiFiGeneric.cpp
- wenn der zu setzende Mode != 0 und vorher 0 (nicht initialisiert) war,
dann wifiLowLevelInit(_persistent) ansonsten espWiFiStop()=esp_wifi_stop()+wifiLowLevelDeinit()
- wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t err = esp_wifi_init(&cfg);
- esp_wifi_set_storage(WIFI_STORAGE_RAM);
- esp_wifi_set_mode(m);
- esp_wifi_set_protocol(...);
- espWiFiStart();
- wenn noch nicht gestartet:
- esp_wifi_start()
WiFi.begin() - WiFiSTA.cpp
Verbindet die Station mit DHCP.
- WiFi.begin(ssid, psk) => WiFi.begin(ssid, psk, int32_t channel = 0,
const uint8_t* bssid = NULL, bool connect = true);
- WiFi.enableSTA(true)
- wifi_sta_config(wifi_config_t &conf, ssid, psk, bssid, channel, _minSecurity,
_scanMethod, _sortMethod);
- wenn conf <> esp_wifi_get_config(ESP_IF_WIFI_STA, wifi_config_t ¤t_conf):
- esp_wifi_disconnect()
- esp_wifi_set_config(ESP_IF_WIFI_STA, &conf)
- wenn nicht status()==WL_CONNECTED dann
esp_wifi_set_config(ESP_IF_WIFI_STA, &conf)
- set_esp_interface_ip(ESP_IF_WIFI_STA)
- wenn "connect" dann esp_wifi_connect()
auch interessant:
- byte mac[6]; WiFi.macAddress(mac);
- WiFi.setHostname("ESP32-WiFi-Station");
WiFi.scanNetworks()
- int16_t WiFi.scanNetworks(
- bool async = false,
- bool show_hidden = false,
- bool passive = false,
- uint32_t max_ms_per_chan = 300,
- uint8_t channel = 0,
- const char * ssid=nullptr,
- const uint8_t * bssid=nullptr)
- int16_t scanComplete();
- void scanDelete();
- static void _scanDone();
WiFi.setAutoReconnect() in WiFiGenericClass::_eventCallback()
- funktioniert nur wenn reason =
event->event_info.wifi_sta_disconnected.reason
- _isReconnectableReason(reason)==true
- wenn also event->event_id == ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
- wenn dabei kein WiFi.disconnect()/WiFi.begin() ausgeführt wurde
- oder AutoReconnect wird deaktiviert und es wird alles selbst im CB
übernommen, if(status() != WL_CONNECTED)
Normaler-Connect:
- WiFi.mode(WIFI_STA);
- WiFiEvent 0: WiFi ready
- WiFiEvent 2: Station Mode Started
- protocols: 11B 11G 11N, bw=WIFI_BW_HT40
- esp_wifi_get_ps(0)=0
- conf: SSID='', PSK=''
- WiFi.begin(ssid, password);
- WiFiEvent 4: station connected to AP Skynet auth=3 (WPA2_PSK)
- get_country: >DE <, chan=1-14, txpwr=20, policy=WIFI_COUNTRY_POLICY_AUTO
- bw=WIFI_BW_HT40
- WiFiEvent 7: got IP 53b2a8c0
oder auch:
- WiFi.mode(WIFI_STA);
- WiFiEvent 0: WiFi ready
- WiFiEvent 2: Station Mode Started
- protocols: 11B 11G 11N, bw=WIFI_BW_HT40
- esp_wifi_get_ps(0)=0
- conf: SSID='', PSK=''
- WiFi.begin(ssid, password);
- WiFiEvent 5: station disconnected, attempting reconnection
Reason: 202 - AUTH_FAIL
Status: 6 - DISCONNECTED
- WiFiEvent 4: station connected to AP Skynet auth=3 (WPA2_PSK)
- get_country: >DE <, chan=1-14, txpwr=20, policy=WIFI_COUNTRY_POLICY_AUTO
- bw=WIFI_BW_HT40
- WiFiEvent 7: got IP 53b2a8c0
Wenn WLAN ausgeschaltet wird:
Reason: 3 - AUTH_LEAVE
Status: 6 - DISCONNECTED
Wenn kein WLAN verfügbar:
- 11:54:12.212 -> WiFiEvent 5: station disconnected, attempting
reconnection
Reason: 201 - NO_AP_FOUND
Status: 1 - NO_SSID_AVAIL
- 11:54:14.623 -> WiFiEvent 5: station disconnected, attempting
reconnection
Reason: 201 - NO_AP_FOUND
Status: 1 - NO_SSID_AVAIL
- wenn AutoReconnect==true wird weiter versucht
ESP-NOW
- WiFi.mode(...)
- esp_now_init()
- ...
- esp_now_deinit()
Bluetooth Classic
ESP-IDF
- const uint8_t *esp_bt_dev_get_address(void); - Get bluetooth device
address. Must use after "esp_bluedroid_enable". also nach .begin()
Arduino
- disconnect()
- _spp_client wird bei Vorhandensein abgekoppelt esp_spp_disconnect()
- unpairDevice(uint8_t remoteAddress[])
- "removing bonded device" esp_bt_gap_remove_bond_device(remoteAddress)
- connected(int timeout)
- isReady(bool checkMaster, int timeout)
- xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, ...
- enableSSP()
- Simple Secure Pairing _enableSSP = true
- register_callback(esp_spp_cb_t * callback)
- custom_spp_callback = callback;
- esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
- onAuthComplete(AuthCompleteCb cb)
- auth_complete_callback = cb;
- auth_complete_callback(bool "authentication success")
- onConfirmRequest(ConfirmRequestCb cb)
- confirm_request_callback = cb;
- confirm_request_callback(param->cfm_req.num_val) : case
ESP_BT_GAP_CFM_REQ_EVT
- onData(BluetoothSerialDataCb cb)
- custom_data_callback = cb;
- custom_data_callback(param->data_ind.data, param->data_ind.len);
- confirmReply(boolean confirm)
- esp_bt_gap_ssp_confirm_reply(current_bd_addr, confirm);
- write(const uint8_t *buffer, size_t size)
- hasClient(void)
Bluetooth LE
Der Server bietet unter der UUID_RX einen Write an, unter UUID_TX einen
Notify.
Der Client kann auf den UUID_RX schreiben, und bekommt einen Notify-Callback
vom UUID_TX.
Der Server schreibt auf den UUID_TX (dazu wird der Zeiger auf die
TxCharacteristic benötigt), und bekommt einen Write-Callback vom UUID_RX.
PIN:
https://github.com/choichangjun/ESP32_arduino/blob/master/ESP32_Arduino_paring_Key.ino
https://esp32-server.de/hm-10-esp32/
|
BLE Server |
BLE Client |
|
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" |
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART
service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" |
Init |
BLEDevice::init("UART Service For ESP32");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
***Beispiel eine gemeinsame Variable ***
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setValue("Hi,other ESP32 here is your data");
***Beispiel bidirektionaler Austausch ***
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic =
pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMinPreferred(0x12);
BLEDevice::startAdvertising();
// bzw. pServer->getAdvertising()->start(); |
BLEDevice::init("");
|
Connect:
Server |
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
}; |
|
Kommunikation:
Server <> Client |
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i]);
Serial.println();
Serial.println("*********");
}
}
};
...
pTxCharacteristic->setValue(&txValue, 1);
pTxCharacteristic->notify(); |
|
Scan for Server |
|
// Retrieve a Scanner and set the callback we want to use to be
informed when we
// have detected a new device. Specify that we want active scanning and
start the
// scan to run for 5 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false); |
CallBack:
Find Server |
|
/**
* Scan for BLE servers and find the first one that advertises the
service we are looking for.
*/
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
/**
* Called for each advertising BLE server.
*/
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// We have found a device, let us now see if it contains the service
we are looking for.
if (advertisedDevice.haveServiceUUID() &&
advertisedDevice.isAdvertisingService(serviceUUID)) {
BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
doScan = true;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks |
Main:
Connect to Server |
|
if (doConnect == true) {
if (connectToServer()) {
Serial.println("We are now connected to the BLE Server.");
} else {
Serial.println("We have failed to connect to the server; there is nothin
more we will do.");
}
doConnect = false;
} |
Kommunikation
Client > Server |
|
if (connected) {
String newValue = "Time since boot: " + String(millis()/1000);
Serial.println("Setting new characteristic value to \"" + newValue +
"\"");
// Set the characteristic's value to be the array of bytes that is
actually a string.
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
}else if(doScan){
BLEDevice::getScan()->start(0); // this is just example to start scan
after disconnect, most likely there is better way to do it in arduino
} |
esptool
https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html
Flash-Erase: esptool.py --chip esp32 p com7 erase_flash
Flash-Program: %LOCALAPPDATA%\Arduino15\packages\esp32\tools\esptool_py\3.0.0/esptool.exe
--chip esp32 --port COM7 --baud 921600 --before default_reset --after hard_reset
write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 %LOCALAPPDATA%\Arduino15\packages\esp32\hardware\esp32\1.0.6/tools/partitions/boot_app0.bin
0x1000 %LOCALAPPDATA%\Arduino15\packages\esp32\hardware\esp32\1.0.6/tools/sdk/bin/bootloader_qio_80m.bin
0x10000 CAN-Remote-ESP32.ino.bin 0x8000 CAN-Remote-ESP32.ino.partitions.bin
Flash-Read: esptool.exe --chip esp32-s2 --port COM8 --baud 921600 --before
no_reset --after no_reset read_flash 0 0x400000 flash_contents.bin
"%LOCALAPPDATA%\Arduino15\packages\esp32\tools\esptool_py\4.2.1/esptool.exe"
--chip esp32s2 --port "COM8" --baud 921600 --before default_reset --after
hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB
0x1000 "C:\Users\Christian\AppData\Local\Temp\arduino-sketch-BA776B339A5A10F512B565EB85152DEF/SmartCoffee.ino.bootloader.bin"
0x8000 "C:\Users\Christian\AppData\Local\Temp\arduino-sketch-BA776B339A5A10F512B565EB85152DEF/SmartCoffee.ino.partitions.bin"
0xe000 "C:\Users\Christian\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.6/tools/partitions/boot_app0.bin"
0x10000 "C:\Users\Christian\AppData\Local\Temp\arduino-sketch-BA776B339A5A10F512B565EB85152DEF/SmartCoffee.ino.bin"
"%LOCALAPPDATA%\Arduino15\packages\esp32\tools\esptool_py\4.5.1/esptool.exe"
--chip esp32 --port COM5 --baud 921600 --before default_reset --after hard_reset
write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x1000 "%TEMP%\Temp\arduino_build_843164/ACANLoopBack.ino.bootloader.bin"
0x8000 "%TEMP%\arduino_build_843164/ACANLoopBack.ino.partitions.bin" 0xe000 "%LOCALAPPDATA%\Arduino15\packages\esp32\hardware\esp32\2.0.9/tools/partitions/boot_app0.bin"
0x10000 "%TEMP%\arduino_build_843164/ACANLoopBack.ino.bin"
Assembler-Code erzeugen
AppData\Local\Arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\esp-2021r2-patch5-8.4.0\bin\xtensa-esp32-elf-objdump.exe
-d Sketch.ino.cpp.o >disasm.s
Aufbau des Firmware-Images
https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/firmware-image-format.html
- sichert mit Prüfbyte und SHA256
Partitionsaufbau bei Arduino
Die Partitionierung ergibt sich z.T. aus der partitions.csv (im temp):
# Name |
Type |
SubType |
Offset |
Size |
Flags |
Flashvorgang über ISP per esptool.exe |
Erklärung |
|
|
|
0x1000 |
[0x7000] |
|
sdk/bin/bootloader_qio_80m.bin [0x48E0] |
Bootloader, max. 28.672 Bytes |
|
|
|
0x8000 |
[0x1000] |
|
arduino_build_956369/WiFiClientPSK.ino.partitions.bin [0x1000] |
Partition Tables |
nvs |
data |
nvs |
0x9000 |
0x5000 |
|
|
|
otadata |
data |
ota |
0xe000 |
0x2000 |
|
partitions/boot_app0.bin [0x2000] |
|
app0 |
app |
ota_0 |
0x10000 |
0x140000 |
|
arduino_build_956369/WiFiClientPSK.ino.bin |
|
app1 |
app |
ota_1 |
0x150000 |
0x140000 |
|
|
|
spiffs |
data |
spiffs |
0x290000 |
0x170000 |
|
|
|
CSV to Binary: C:\Espressif\frameworks\esp-idf-v5.1\components\partition_table\python gen_esp32part.py input_partitions.csv
binary_partitions.bin
Die ino.partitions.bin wird aus der partitions.csv erzeugt durch
gen_esp32part.exe" -q "arduino_build_956369/partitions.csv"
"arduino_build_956369/WiFiClientPSK.ino.partitions.bin"
Binary to CSV: python gen_esp32part.py binary_partitions.bin
input_partitions.csv
Display partition table: python gen_esp32part.py binary_partitions.bin
Image einer Partition speichern: C:\Espressif\frameworks\esp-idf-v5.1\components\partition_table\parttool.py
-p COM7 read_partition --partition-type=data --partition-subtype=nvs --output "nvs.bin"
Image der Partitions-Partition speichern: esptool.py --chip esp32 -p COM7 -b
921600 --before no_reset --after no_reset read_flash 0x8000 0x1000
..\HC2v1_part.bin
Bootloader
Der Platz für den Bootloader ist bei den Standard-Arduino-Libraries
beschränkt auf 0x7000 Bytes. Bei unverschlüsseltem Flash kann ein
Bootloader-Debug-Level von bis zu 'Info' verwendet werden, beim verschlüsselten
Flash ist nur 'No output' möglich.
Ein Bootloader, der ohne "Enable flash encryption on boot" erstellt wurde,
also z.B. der von Arduino, funktioniert auch mit aktiver Flash-Encryption.
Der First-Stage-Bootloader im ROM kann bei nicht-durchgebrannter eFuse
DISABLE_DL_ENCRYPT ("bootloader encryption enabled") ein Plaintext-Image beim
Flashen encrypten (esptool mit --encrypt). D.h. im Development-Mode kann
beliebig oft Plaintext geflasht werden, ohne dass es pre-encryptet ist.
NVS-Partition lesen
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_partition_parse.html
C:\Espressif\frameworks\esp-idf-v5.1\components\nvs_flash\nvs_partition_tool\nvs_tool.py
-i -d minimal --color never d:\esp32\NVS.bin
NVS verschlüsseln
- es muss die Partition 'nvs_key' (data/nvs_keys) existieren
- 'nvs_key' muss entweder gelöscht sein, oder gültige Schlüssel enthalten:
- parttool.py -p COM7 --partition-table-file partitions.csv
--partition-table-offset 0x8000 erase_partition --partition-type=data
--partition-subtype=nvs_keys
ODER
- esptool.py -p COM7 erase_region --force 0x3FF000 0x1000 [Inhalt
0xff]
ODER
- nvs_partition_gen.py generate-key --keyfile mynvskey.bin [es wird
keys\my_nvs_key.bin erstellt]
esptool.py -p COM7 write_flash --encrypt 0x3FF000 keys\my_nvs_key.bin
- die App muss mit aktiviertem Flash- und NVS-Encryption kompiliert worden
sein
- falls nicht vorher festgelegt, erstellt die Funktion nvs_flash_init()
neue Schlüssel auf der nvs_keys
Selbstverschlüsselung der IDF
In die 'nvs_keys' wird raw geschrieben, also als ob es hardware-encrypted
wäre, sodass die Schlüssel beim Lesen durch die Hardware-Flash-Decryption
entstehen:
- eky: 16x 0xFF, 16x 0x09
- tky: 16x 0xEE, 16x 0x88
NVS entschlüsseln
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_partition_gen.html
Die (entschlüsselte) 'nvs_keys'-Partition ist der Schlüssel, um die
verschlüsselte 'nvs'-Partition zu entschlüsseln:
- esptool.py --chip esp32 -p COM7 -b 921600 --before no_reset --after
no_reset read_flash 0x9000 0x5000 nvs_enc.bin
- esptool.py --chip esp32 -p COM7 -b 921600 --before no_reset --after
no_reset read_flash 0x3ff000 0x1000 nvs_keys_enc.bin
- espsecure.py decrypt_flash_data --keyfile
flash_key.bin --address 0x3ff000 -o
nvs_key.bin nvs_key_enc.bin
- C:\Espressif\frameworks\esp-idf-v5.1\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py
decrypt nvs_enc.bin
nvs_key.bin nvs_dec.bin
Mit nvs_partition_gen.py lassen sich NVS-Partitionen aus CSV erstellen, oder
NVS-Schlüssel (nvs_keys) erstellen.
ESPFUSE.py
https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html
Flash-Verschlüsselung
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/flash-encryption.html
Folgende Teile des Flashs können verschlüsselt sein [Quelle]:
Standard sind 'app'-Type verschlüsselt, 'nvs' ist nicht mit
Hardware-Verschlüsselung kompatibel, kann aber mittels "NVS
Encryption" verschlüsselt werden: dazu wird die Partition "nvs_keys"
benötigt, die Hardware-verschlüsselt ist.
- Bootloader
- Secure boot bootloader digest (if secure boot is enabled)
- Partition Table
- All "app" type partitions
- Any partition marked with the "encrypted" flag in the partition table
Einschränkungen nach Verschlüsselung
https://docs.espressif.com/projects/espressif-esp-idf/en/latest/security/flash-encryption.html#using-encrypted-flash
Nur in den Adressbereich gemappter Flash wird ver-/entschlüsselt.
Daten über spi_flash_read() werden nicht entschlüsselt! Das betrifft z.B.
SketchMD5()
Daten über esp_partition_read() werden je nach Partitionstabelle
entschlüsselt oder nicht.
In Arduino sind diese Funktionen nicht Encryption-fähig:
- getSketchMD5() wegen flashRead()->spi_flash_read()
- getFlashChipSpeed(), getFlashChipSize(), getFlashChipMode() wegen
flashRead()->spi_flash_read()
- HTTPUpdate::handleUpdate() { ESP.getFlashChipSize() }
Verschlüsselung einrichten
Für verschlüsselten Flash ist ein anderer Bootloader nötig. Dieser richtet
die Verschlüsselung ein, wenn sie nicht aktiviert ist (FLASH_CRYPT_CNT hat
geradzahlige Anzahl von gesetzten Bits). Aktiviert wird dies durch "Enable flash
encryption". Im Development kann zum Schutz vor unbeabsichtigter Verschlüsselung
"Require flash encryption to be already enabled" gesetzt werden (SECURE_FLASH_REQUIRE_ALREADY_ENABLED).
- FLASH_CRYPT_CONFIG <= 0xF (Controls the AES encryption process)
- wenn in der eFuse 'flash_encryption' vorher kein Schlüssel mittels des
espefuse-Tools abgelegt wurde, wird einer aus Zufallszahlen erzeugt und
reingeschrieben.
Der automatisch erzeugte Schlüssel kann nicht gelesen werden, damit ist es
also später nicht möglich, eine Firmware im Voraus zu verschlüsseln!
- verschlüsselt dann auch beim ersten Start den Flash, der vorher also
Plaintext enthielt.
- die als zu verschlüsseln markierten Partitionen des Flashs werden
In-Place verschlüsselt, was bis zu 60 Sekunden dauern kann
- in FLASH_CRYPT_CNT wird das erste verfügbare Bit gesetzt, was also in
einer ungeraden Anzahl gesetzter Bits resultiert
- im Development-Mode: nur DISABLE_DL_DECRYPT und DISABLE_DL_CACHE werden
gesetzt; über die UART kann neue Firmware geladen werden: vorverschlüsselt
oder unverschlüsselt mit --encrypt; FLASH_CRYPT_CNT wird nicht "schreibgeschützt",
also nur um 1 Bit erweitert
- im Release-Mode: DISABLE_DL_ENCRYPT, DISABLE_DL_DECRYPT und
DISABLE_DL_CACHE werden gesetzt, FLASH_CRYPT_CNT wird
"schreibgeschützt" = 0x7f; über UART kann vorverschlüsselte Firmware geladen
werden kann mit --force
- ist DISABLE_DL_ENCRYPT gesetzt, ist esptool write_flash nur mit --force möglich
DISABLE_DL_DECRYPT: im Bootloader wird der Flash nicht
entschlüsselt, d.h. der Code wird nicht als Plain gelesen.
DISABLE_DL_ENCRYPT: im Bootloader wird die Möglichkeit deaktiviert während des
Uploads verschlüsselt zu schreiben (--encrypt)
Für den Bootloader ist Platz für 0x7000 Bytes. Durch Verschlüsselung oder Debuglevel kann dieser Platz ggfs. nicht ausreichen.
Ein Key kann erzeugt werden durch espsecure.py generate_flash_encryption_key
my_flash_encryption_key.bin - die Qualität wird durch das OS bestimmt.
Der Key wird im ESP32 gespeichert durch espefuse.py --port COM7 burn_key
flash_encryption my_flash_encryption_key.bin
Der Lese-/Schreibschutz für den Kay kann mit --no-protect-key verhindert werden.
Reflash mit verschlüsselter Firmware-Datei (Development- und Release-Mode)
Vor dem Flash muss die Firmware verschlüsselt werden, im Release-Mode muss
zusätzlich mit --force geflasht werden:
- espsecure.py encrypt_flash_data --keyfile my_flash_encryption_key.bin
--address 0x10000 -o build/my-app-encrypted.bin build/my-app.bin
- esptool.py --port PORT --baud 921600 write_flash 0x10000 build/my-app-encrypted.bin
Ggfs. sollte auch die ota-Partition mitgeflasht werden, um sicherzustellen,
dass app0 ausgeführt wird.
Reflash mit unverschlüsselter Firmware-Datei (Development-Mode)
ACHTUNG: Ist FLASH_CRYPT_CNT nicht gesperrt, kann eine unverschlüsselte
Firmware zum Auslesen aufgespielt werden.
ACHTUNG: Ist DISABLE_DL_ENCRYPT nicht aktiv, kann eine unverschlüsselte
Firmware zum Auslesen aufgespielt werden.
- esptool.py -p COM7 -b 921600 --before no_reset --after no_reset write_flash
-u --encrypt 0x10000 build/my-app-encrypted.bin
Deaktivieren der Verschlüsselung
geht nur 3mal, solange noch freie Bits in FLASH_CRYPT_CNT sind: FLASH_CRYPT_CNT
(7Bit) auf geradzahlige Bitanzahl setzen (0x00, 0x03, 0xF, 0x3F)
Vorgehen beim manuellen Einrichten der Verschlüsselung für Release
Vorgehen:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/host-based-security-workflows.html#enable-flash-encryption-externally
- Key erzeugen: espsecure.py generate_flash_encryption_key
my_flash_encryption_key.bin
- alle nötigen Images vorverschlüsseln
- verschlüsselte Images hochladen, app1 löschen
- Key und Fuses brennen: espefuse.py --chip esp32 -p COM7 -b 115200
--before no_reset
- burn_key flash_encryption my_flash_encryption_key.bin [wird
automatisch read- und write-protected]
- burn_efuse FLASH_CRYPT_CONFIG 0xF FLASH_CRYPT_CNT 0x7F [enable
flash encryption]
- burn_efuse DISABLE_DL_CACHE 1 DISABLE_DL_ENCRYPT 1
DISABLE_DL_DECRYPT 1 JTAG_DISABLE 1 [security flags]
- write_protect_efuse MAC
alternativ ohne Vorverschlüsselung: (NVS bleibt unverschlüsselt erhalten)
- ggfs. Löschen und alle unverschlüsselten Partitionen schreiben:
esptool.py -p COM7 -b 921600 --before
no_reset --after no_reset --chip esp32 erase_flash
- Key erzeugen: espsecure.py generate_flash_encryption_key
my_flash_encryption_key.bin
- Key brennen und Verschlüsselung aktivieren: espefuse.py --chip esp32 -p
COM7 -b 115200 --before no_reset
- burn_key flash_encryption my_flash_encryption_key.bin
- burn_efuse FLASH_CRYPT_CONFIG 0xF FLASH_CRYPT_CNT 0x7F
- write_protect_efuse MAC
- Plain-Images der zu verschlüsselnden Partitionen hochladen: esptool.py -p
COM7 -b 921600 --before no_reset --after no_reset write_flash -u
--encrypt 0x10000 build/my-app-encrypted.bin
- Fuses brennen: espefuse.py --chip esp32 -p COM7 -b 115200
--before no_reset
- burn_efuse DISABLE_DL_CACHE 1 DISABLE_DL_ENCRYPT 1
DISABLE_DL_DECRYPT 1 JTAG_DISABLE 1 [security flags]
Vorgehen bei Dev
- Fuses mal lesen (muss 115200 sein!): espefuse.py --chip esp32 -b 115200 -p
COM7 --before no_reset summary
- Key erzeugen: espsecure.py generate_flash_encryption_key
my_flash_encryption_key.bin
- Key brennen: espefuse.py --chip esp32 -p COM7 -b 115200 --before
no_reset burn_key flash_encryption [--no-protect-key] my_flash_encryption_key.bin
mit --no-protect-key kann der Lese-/Schreibschutz des Keys verhindert werden
- die bestehende Partitionstabelle kann/muss beibehalten werden:
Bootloader (0x1000-0x7FFF) und Partitionstabelle (0x8000-0x8FFF) müssen
bleiben, die partitions.csv muss übereinstimmen
ggfs. die nvs_keys anlegen für zukünftige Nutzung
- der Bootloader muss mit der esp-idf erstellt werden:
- idf.py menuconfig
- Custom Partition Table: partitions.csv @ 0x8000
- Bootloader config / "Enable app rollback support"
- ggfs. "Check Flash Encryption enabled on app startup"
deaktivieren
- "Enable flash encryption on boot" in Developer bzw. Release
- Component config / Log output / "Use ANSI terminal colors"
deaktivieren
- Component config / NVS / "Enable NVS encryption" deaktivieren
[CONFIG_NVS_ENCRYPTION]
- idf.py build
- Test Plain (ohne Bootloader): esptool.py -p COM7 -b 460800 --before
no_reset --after no_reset --chip esp32 write_flash --flash_mode dio
--flash_size 4MB --flash_freq 80m 0xe000 build\ota_data_initial.bin 0x10000
build\hello_world.bin
- Do It: esptool.py -p COM7 -b 460800 --before no_reset --after no_reset
--chip esp32 write_flash --flash_mode dio --flash_size 4MB --flash_freq 80m
0x1000 build\bootloader\bootloader.bin 0xe000 build\ota_data_initial.bin
0x10000 build\hello_world.bin
Für Debug muss die Partitionstabelle wegen des größeren Bootloaders geändert
werden, und auch in der menuconfig/partition-offset angegeben werden:
# Name |
Type |
SubType |
Offset |
Size |
Flags |
Flashvorgang über ISP per esptool.exe |
Erklärung |
|
|
|
0x001000 |
0x00C000 |
|
|
Bootloader |
|
|
|
0x00D000 |
0x001000 |
|
|
Partition Tables |
otadata |
data |
ota |
0x00E000 |
0x002000 |
|
|
|
app0 |
app |
ota_0 |
0x010000 |
0x140000 |
|
|
|
app1 |
app |
ota_1 |
0x150000 |
0x140000 |
|
|
|
spiffs |
data |
spiffs |
0x290000 |
0x16B000 |
|
|
|
nvs |
data |
nvs |
0x3FB000 |
0x005000 |
|
|
|
ACHTUNG: Die ESP-IDF verwendet für die Adresse der Partitionstabelle eine
feste Größe (ESP_PARTITION_TABLE_OFFSET), die in den Arduino-Libraries
"eingebrannt" ist (CONFIG_PARTITION_TABLE_OFFSET = 0x8000). Liegt sie woanders,
wird z.B. die NVS-Partition nicht gefunden. Siehe load_partitions()/partition.c
(initArduino()/esp32-hal-misc.c > nvs_flash_init()/nvs_api.cpp >
esp_partition_find_first()>load_partitions()/partition.c), in der
ESP_PARTITION_TABLE_OFFSET verwendet wird.
Fehlermeldung bei Arduino v1.0.6, mit Partitionstabelle auf 0xD000:
[E][esp32-hal-misc.c:298] initArduino(): Failed to initialize NVS! Error:
261 (ESP_ERR_NOT_FOUND 0x105)
Fehlermeldung bei ESP-IDF v5.1 mit Partitionstabelle kompiliert auf 0x8000,
tatsächlich auf 0xD000:
E (755) partition: No MD5 found in partition table
E (756) partition: load_partitions returned 0x105
Fehlermeldung wenn CONFIG_NVS_ENCRYPTION gesetzt ist und die
nvs_keys-Partition fehlt:
E (815) nvs: CONFIG_NVS_ENCRYPTION is enabled, but no partition with
subtype nvs_keys found in the partition table.
Verschlüsseltes NVS
Die 'data'/'nvs'-Partition kann nur "software"-verschlüsselt werden (CONFIG_NVS_ENCRYPTION=y),
die Schlüssel dazu werden in der "hardware"-verschlüsselten Partition 'data'/'nvs_keys'
aufbewahrt. Der Bootloader-Code ist davon nicht betroffen, nur die NVS-Routinen
der App:
C:\Espressif\frameworks\esp-idf-v5.1\components\nvs_flash\src\nvs_api.cpp :
nvs_flash_init()
- esp_partition_find_first()
- nvs_flash_read_security_cfg()
- nvs_flash_generate_keys()
- nvs_flash_secure_init_partition(), secure_init_partition() ODER
nvs_flash_init_partition()
Arduino-Library v1.0.6 (esp-idf v3.3.5) unterstützt kein verschlüsseltes NVS
(libnvs_flash.a).
Arduino-Bibliotheken vs. ESP-IDF
https://github.com/espressif/arduino-esp32/issues/6012 Ganz unten ist der
Download der Win32-Version von esptool
Win10x86 mit Arduino v1.8.9
- https://dl.espressif.com/dl/package_esp32_index.json
- "esp32" v1.0.6 installiert, v1.0.0...v1.0.6 , v2.0.10...v2.0.11 möglich
- 1.0.6:
Win10x64 mit Arduino v1.8.12
-
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- "esp32" v2.0.9 installiert, v1.0.0...v1.0.6 , v2.0.0...v2.0.11 möglich
-
https://github.com/espressif/arduino-esp32/releases
- Arduino Release v2.0.14 based on ESP-IDF v4.4.6-dirty
- Serial0 funktioniert nicht; in v2.0.9 geht sie
- Arduino Release v2.0.11 based on ESP-IDF v4.4.5:
https://github.com/espressif/esp-idf/blob/v4.4.5/components/driver/rmt.c
- Arduino Release v2.0.10 based on ESP-IDF v4.4.5
- Arduino Release v2.0.9 based on ESP-IDF v4.4.4 based on Vanilla FreeRTOS
v10.4.3
- ESP32 Arduino 2.0.6 based on ESP-IDF 4.4.3
- ESP32 Arduino 2.0.1 based on ESP-IDF 4.4
- ESP32 Arduino 2.0.3 based on ESP-IDF 4.4.1
- ESP32 Arduino Release 1.0.6 based on ESP-IDF v3.3.5
Arduino-Library Builder
https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/lib_builder.html
ESPTOOL erstellen
https://www.esp32.com/viewtopic.php?t=1029
- [Admin-Konsole] pip install pyinstaller
- pyinstaller --onefile --specpath build_tmp --workpath build_tmp\build
--distpath build_tmp\dist C:\Espressif\frameworks\esp-idf-v5.1\components\esptool_py\esptool\esptool.py
- pyinstaller --onefile --specpath build_tmp --workpath build_tmp\build
--distpath build_tmp\dist C:\Espressif\frameworks\esp-idf-v5.1\components\esptool_py\esptool\espsecure.py
- pyinstaller --onefile --specpath build_tmp --workpath build_tmp\build
--distpath build_tmp\dist C:\Espressif\frameworks\esp-idf-v5.1\components\esptool_py\esptool\espefuse.py
- pyinstaller --onefile --specpath build_tmp --workpath build_tmp\build
--distpath build_tmp\dist
C:\Espressif\frameworks\esp-idf-v5.1\components\partition_table\parttool.py
- pyinstaller --onefile --specpath build_tmp --workpath build_tmp\build
--distpath build_tmp\dist
C:\Espressif\frameworks\esp-idf-v5.1\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py
GY-SGP mit Sensirion SGP30
- VCC kann durch den LDO 2,1..6,0V betragen (1,8V / 300mA / 250mW
65K5)
- SGP30 arbeitet mit 1,8V / 49mA
- Dual MOSFET 2N7002DW (Panjit '702' SOT-363) als Level-Translator
- mangelhaftes Schaltverhalten von 1,8V-Low-Pegeln: manchmal werden
Low-Pegel des SGP30 nicht zum µC übertragen, da die G-S-Spannung nicht
ausreicht
- SGP30 VOC
Sensor I2C Issues: BSS138 sollen durch BSS806 getauscht werden, oder
besser TI TXS-Typen
- NX6008NBKSX soll auch gehen
- gemessen wird Ethanol und H2, daraus wird TVOC und CO2eq berechnet
- I²C 400kHz addr 0x58
- best performance at 1Hz sampling rate
- TVOC: 0 ppb to 60000 ppb
- CO2eq: 400 ppm to 60000 ppm
- For the first 15s after the "sgp30_iaq_init" command the sensor is in an
initialization phase during which a "sgp30_measure_iaq" command returns
fixed values of 400 ppm CO2eq and 0 ppb TVOC.
-
embedded-sgp/sgp30/sgp30_example_usage.c at master · Sensirion/embedded-sgp
· GitHub
-
Technischer Download (sensirion.com)
- Beobachtungen
- Baseline CO2 wird bei Bedarf ca. alle 40s um 1 verändert (lineare Rampe)
- Baseline TVOC wird bei Bedarf ca. alle 4s oder 40s um 1 verändert
(lineare Rampe)
- Adafruit:
- sgp.begin()
- i2c_dev->begin()
- _wire->begin();
- _wire->beginTransmission(_addr);
- _wire->endTransmission()
- readWordFromCommand(0x3682, 2, 10, serialnumber, 3) "Get Serial ID"
- i2c_dev->write(command, commandLength)
- _wire->beginTransmission(_addr);
- _wire->write(buffer, len)
- _wire->endTransmission(stop=true)
- delay(delayms);
- i2c_dev->read(replybuffer, replylen)
- _read(buffer + pos, read_len, read_stop)
- _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
- _wire->read();
- readWordFromCommand(0x202F, 2, 10, &featureset, 1)
- IAQinit()
- readWordFromCommand(0x2003, 2, 10);
- sgp.IAQmeasure()
- readWordFromCommand(0x2008, 2, 12, reply, 2)
- sgp.IAQmeasureRaw()
- readWordFromCommand(0x2050, 2, 25, reply, 2)
- sgp.getIAQBaseline(&eCO2_base, &TVOC_base)
- Tillard
- SGP.begin()
- isConnected()
- _wire->beginTransmission(_address);
- _wire->endTransmission()
- _init();
- _command(0x2003);
- _wire->beginTransmission(_address);
- _wire->write(cmd >> 8);
- _wire->write(cmd & 0xFF);
- _wire->endTransmission();
- SGP.measureTest() * is intended for production line testing and
verification only. !should not be used after having issued an
sgp30_iaq_init! After the command, the sensor is in sleep mode.
- _command(0x2032);
- delay(220);
- _wire->requestFrom(_address, (uint8_t)3)
- _wire->read();
- SGP.getFeatureSet()
- _command(0x202F);
- delay(10);
- _wire->requestFrom(_address, (uint8_t)3)
- _wire->read();
- SGP.getID()
- _command(0x3682);
- delay(1);
- _wire->requestFrom(_address, (uint8_t)9);
- _wire->read();
- SGP.measure(true);
- request();
- delay(12);
- read();
- _wire->requestFrom(_address, (uint8_t)6)
- _wire->read();
- requestRaw();
- delay(25);
- readRaw();
- _wire->requestFrom(_address, (uint8_t)6)
- _wire->read();
LAN8720 Eth Board mit SMSC LAN8720A (Microchip)
- VCC muss 3,0..3,6V betragen
- MDIO ist mit 4k7 gepullt und geht an MDIO
- TXD0/TXD1/TXEN/MDC gehen direkt an TX0/TX1/TX-EN/MDC
- RXD0/RXD1/CRS_DV gehen über 10Ω an RX0/RX1/CRS
- der Board-Pin nINT/RETCK ist über 33Ω mit dem 50MHz-Oszillatorausgang
verbunden, kann umgelötet werden nach nINT
- RXER ist mit 10k gepullt aber nicht herausgeführt; als Bootstrap ist
damit PHYAD0=H und die SMI-Adresse ist 0x01 (solange das Softwareregister
PHYAD[4:2]=0 ist)
- nRST ist mit R=1k5/C realisiert
- LEDs über 330Ω
- SMI über MDC/MDIO mit max. 2,5MHz
Erstellt 14.04.2019, zuletzt geändert
02.12.2024 21:54:16,
Besuche. © Christian Enders
Home | Nach oben | D-Link DUB-C2 | TechSolo TN-270 | Hama PCI-USB 2.0 18882 | Promise FastTrak100 TX2 | Mustek 1200 CP | Plustek OpticFilm 7200 | Canon MX925 | HP P1110 | Digitus DN-7003GT | Digitus DN-7003GS | Digitus DN-7006GR | Option Fusion | WLAN-Adapter | USB RS232 Wandler | ESP32 | BlackMagic DeckLink | KNC DVB-C+ | MD-9717