# Changelog
Source: https://docs.kode.diy/en/changelog
News and updates from kode team.
* Introduced the v1.0 of kode docs in English and Spanish.
# Camera
Source: https://docs.kode.diy/en/external-modules/camera
Give vision to your Kode Dot with the Camera module
**Módulo:** Standard
# Features
With this module you can **learn to capture images and record video.** It integrates a camera with an OV5640 sensor with a resolution of 5MP.
## Connection with the Kode Dot
## Connection scheme
The camera is connected to the ESP32-S3 as follows:
| Camera | ESP32-S3 |
| ------ | -------- |
| nRESET | GPIO44 |
| SCL | GPIO47 |
| SDA | GPIO48 |
| PCLK | GPIO13 |
| HREF | GPIO43 |
| VSYNC | GPIO42 |
| D2 | GPIO12 |
| D3 | GPIO11 |
| D4 | GPIO1 |
| D5 | GPIO2 |
| D6 | GPIO3 |
| D7 | GPIO39 |
| D8 | GPIO40 |
| D9 | GPIO41 |
## Example code
To test the camera we will use the example that includes **Espressif in Arduino IDE**. You can open it in File > Examples > ESP32 > Camera > CameraWebServer.
This example allows you to configure the camera and see in real time what it is capturing through a web page.
Change all the code of CameraWebServer.ino by the following and change the WiFi credentials to yours:
```cpp CameraWebServer.ino lines icon="microchip" theme={null}
/**
* ESP32-S3 Camera Web Server Example.
* Configures the camera, connects to WiFi, and serves an MJPEG stream.
* Access URL after connection: http://
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "esp_camera.h"
#include
/* ===========================
WiFi credentials
=========================== */
const char *ssid = "**********"; /* WiFi network name */
const char *password = "**********"; /* WiFi network password */
/* External function declarations (implemented elsewhere) */
void startCameraServer();
void setupLedFlash();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true); /* Enable debug output on Serial */
Serial.println();
/* ─── Camera pin mapping and parameters ─── */
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = 12;
config.pin_d1 = 11;
config.pin_d2 = 1;
config.pin_d3 = 2;
config.pin_d4 = 3;
config.pin_d5 = 39;
config.pin_d6 = 40;
config.pin_d7 = 41;
config.pin_xclk = -1;
config.pin_pclk = 13;
config.pin_vsync = 42;
config.pin_href = 43;
config.pin_sccb_sda = 48;
config.pin_sccb_scl = 47;
config.pin_pwdn = -1;
config.pin_reset = 44;
config.xclk_freq_hz = 20000000; /* XCLK frequency */
config.frame_size = FRAMESIZE_UXGA; /* Initial resolution */
config.pixel_format = PIXFORMAT_JPEG; /* Format for streaming */
//config.pixel_format = PIXFORMAT_RGB565; // Option for face detection
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12; /* JPEG quality (lower number = higher quality) */
config.fb_count = 1;
/* Adjust configuration if PSRAM is available */
if (config.pixel_format == PIXFORMAT_JPEG) {
if (psramFound()) {
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
/* If PSRAM is not available, reduce resolution to save RAM */
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
/* Best settings for face detection/recognition */
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
/* ─── Camera initialization ─── */
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
/* Access the camera sensor for extra configuration */
sensor_t *s = esp_camera_sensor_get();
/* Reduce frame size for higher initial frame rate */
if (config.pixel_format == PIXFORMAT_JPEG) {
s->set_framesize(s, FRAMESIZE_QVGA);
}
/* Flip image vertically */
s->set_vflip(s, 1);
/* ─── WiFi connection ─── */
WiFi.begin(ssid, password);
WiFi.setSleep(false); /* Prevent WiFi from entering sleep mode */
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
/* ─── Start the camera web server ─── */
startCameraServer();
Serial.print("Camera Ready! Access at: http://");
Serial.println(WiFi.localIP());
}
void loop() {
/* Web server handles streaming; main loop is idle */
delay(10000);
}
```
## Download examples
You can test the example codes through the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Example codes of the Camera module](https://drive.google.com/drive/folders/1wom3hU-bjWmbpT9DnZFzFtpL3cr-7Qzg)
# Inventor
Source: https://docs.kode.diy/en/external-modules/inventor
Connect motors DC, a servo motor and sensors to create your own robot.
**Module:** Basic
# Features
With this module you can connect **motors to your Kode Dot and make robots like a car following lines.**
You can connect the following:
* 2x DC motors or 1x stepper motor
* 1x servo motor
* 4x GPIOs for sensors
* 1x I2C bus
It is not necessary to use an external power supply because **everything is powered from the Kode Dot.**
The **DC motors have to be 5V and are limited by hardware to a current of 700mA per motor.** So, as the Kode Dot can supply up to 2A, there are **600mA left to connect a servo motor.**
The **DC motors are controlled by PWM** and you can measure the current that each motor is consuming to have an estimation of its torque.
## Connection scheme
The driver that controls the motors is connected as follows:
| Driver | ESP32-S3 |
| ------- | -------- |
| AIN1 | GPIO42 |
| AIN2 | GPIO41 |
| BIN1 | GPIO40 |
| BIN2 | GPIO39 |
| nFAULT | GPIO38 |
| AIPROPI | GPIO37 |
| BIPROPI | GPIO36 |
AIPROPI and BIPROPI are used to measure the current that each motor is consuming. For more information, consult the driver's datasheet.
## Example code
Connect **two DC motors to the connectors** and with this code you will see how they first accelerate, then maintain the maximum speed and finally decelerate.
```cpp motors_test.ino lines icon="microchip" theme={null}
/**
* DRV8411A + 2x DC + Servo + Current reading via IPROPI (ESP32-S3).
* Prints to Serial Plotter: IA(A) \t IB(A) \t ITRIP(A) while sequencing both motors and a servo.
* IPROPI math (datasheet): IPROPI(µA) = I_LS_total(A) * 200 µA/A; V_IPROPI = IPROPI * R_IPROPI;
* I_motor = V_IPROPI / (R_IPROPI * 200e-6); I_TRIP = VREF / (R_IPROPI * 200e-6).
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* DRV8411A pins */
constexpr int PIN_AIN1 = 42;
constexpr int PIN_AIN2 = 41;
constexpr int PIN_BIN1 = 39;
constexpr int PIN_BIN2 = 40;
constexpr int PIN_nFAULT = 3;
/* IPROPI -> ADC (A channel and B channel) */
constexpr int PIN_AIPROPI = 2; /* ADC input for A-IPROPI */
constexpr int PIN_BIPROPI = 1; /* ADC input for B-IPROPI */
/* Servo */
constexpr int PIN_SERVO = 13;
Servo servo;
/* Servo settings (microseconds and angles) */
constexpr int SERVO_MIN_US = 500;
constexpr int SERVO_MAX_US = 2500;
constexpr int SERVO_CENTER = 90;
constexpr int SERVO_LEFT = 0;
constexpr int SERVO_RIGHT = 180;
/* DRV8411A helpers */
inline void motorA_coast() { digitalWrite(PIN_AIN1, LOW); digitalWrite(PIN_AIN2, LOW); } /* Hi-Z both inputs */
inline void motorA_brake() { digitalWrite(PIN_AIN1, HIGH); digitalWrite(PIN_AIN2, HIGH); } /* Fast decay brake */
inline void motorA_fwd() { digitalWrite(PIN_AIN1, HIGH); digitalWrite(PIN_AIN2, LOW); } /* A forward */
inline void motorA_rev() { digitalWrite(PIN_AIN1, LOW); digitalWrite(PIN_AIN2, HIGH); } /* A reverse */
inline void motorB_coast() { digitalWrite(PIN_BIN1, LOW); digitalWrite(PIN_BIN2, LOW); } /* Hi-Z both inputs */
inline void motorB_brake() { digitalWrite(PIN_BIN1, HIGH); digitalWrite(PIN_BIN2, HIGH); } /* Fast decay brake */
inline void motorB_fwd() { digitalWrite(PIN_BIN1, HIGH); digitalWrite(PIN_BIN2, LOW); } /* B forward */
inline void motorB_rev() { digitalWrite(PIN_BIN1, LOW); digitalWrite(PIN_BIN2, HIGH); } /* B reverse */
/* Timings */
constexpr uint32_t T_MOTOR_DIR = 2000; /* 2 s per direction */
constexpr uint32_t T_SERVO_TRAMO = 1000; /* 1 s per segment */
/* IPROPI parameters (set R to your actual resistor!) */
constexpr float VREF_V = 3.3f; /* VREF (V) */
constexpr float RIPROPI_OHMS = 23700.0f; /* Change to 10000.0f if you use 10 kΩ */
constexpr float AIPROPI_GAIN = 200e-6f; /* 200 µA/A (IPROPI gain) */
/* ADC configuration */
constexpr int ADC_BITS = 12; /* ADC resolution */
constexpr float ADC_VFULL = 3.3f; /* With 11 dB attenuation, ~3.3 V full scale */
/* Concurrent state machines */
enum class Phase { FWD, REV, DONE };
struct MotorSeq {
bool enabled=false; Phase phase=Phase::FWD; uint32_t tEnd=0;
void start() { enabled=true; phase=Phase::FWD; tEnd=millis()+T_MOTOR_DIR; }
};
struct ServoSeq {
bool enabled=false; int step=0; uint32_t tEnd=0;
void start() { enabled=true; step=0; servo.write(SERVO_RIGHT); tEnd=millis()+T_SERVO_TRAMO; }
};
MotorSeq seqA, seqB; ServoSeq seqS;
/* ADC counts -> volts */
float adcVolts(int pin) {
uint16_t raw = analogRead(pin);
return (raw * ADC_VFULL) / ((1 << ADC_BITS) - 1);
}
/* IPROPI volts -> motor current (A) */
float ipropiToCurrentA(float v_ipropi) {
return v_ipropi / (RIPROPI_OHMS * AIPROPI_GAIN);
}
/* Periodic sampling to Serial Plotter: IA, IB, and ITRIP */
void sampleAndPrintCurrents() {
float vA = adcVolts(PIN_AIPROPI);
float vB = adcVolts(PIN_BIPROPI);
float iA = ipropiToCurrentA(vA);
float iB = ipropiToCurrentA(vB);
float iTRIP = VREF_V / (RIPROPI_OHMS * AIPROPI_GAIN); /* Overcurrent trip threshold (A) */
/* Tab-separated columns for Arduino Serial Plotter */
Serial.print(iA, 4); Serial.print('\t');
Serial.print(iB, 4); Serial.print('\t');
Serial.println(iTRIP, 4);
}
/* Busy wait with periodic sampling (~every 20 ms) */
void waitWithSampling(uint32_t ms) {
uint32_t t0 = millis(), tNext = 0;
while ((uint32_t)(millis() - t0) < ms) {
uint32_t now = millis();
if ((int32_t)(now - tNext) >= 0) {
sampleAndPrintCurrents();
tNext = now + 20;
}
delay(1); /* Yield briefly */
}
}
/* Check /nFAULT low during a tagged section */
void checkFault(const char* tag) {
if (digitalRead(PIN_nFAULT) == LOW) {
Serial.print("[nFAULT] Fault detected during ");
Serial.println(tag);
}
}
void setup() {
Serial.begin(115200);
delay(100);
pinMode(PIN_AIN1, OUTPUT);
pinMode(PIN_AIN2, OUTPUT);
pinMode(PIN_BIN1, OUTPUT);
pinMode(PIN_BIN2, OUTPUT);
pinMode(PIN_nFAULT, INPUT_PULLUP);
motorA_coast();
motorB_coast();
/* ADC: 11 dB to cover up to ~3.3 V and 12-bit resolution */
analogReadResolution(ADC_BITS);
analogSetAttenuation(ADC_11db);
/* Optional header for Serial Plotter */
Serial.println("IA(A)\tIB(A)\tITRIP(A)");
/* Servo setup (50 Hz, constrained to given pulse widths) */
servo.setPeriodHertz(50);
servo.attach(PIN_SERVO, SERVO_MIN_US, SERVO_MAX_US);
servo.write(SERVO_CENTER);
/* 1) Motor A forward then reverse with sampling */
motorA_fwd(); waitWithSampling(T_MOTOR_DIR);
motorA_rev(); waitWithSampling(T_MOTOR_DIR);
motorA_brake(); delay(100); motorA_coast();
checkFault("Sequence 1 (Motor A)");
/* 2) Motor B forward then reverse with sampling */
motorB_fwd(); waitWithSampling(T_MOTOR_DIR);
motorB_rev(); waitWithSampling(T_MOTOR_DIR);
motorB_brake(); delay(100); motorB_coast();
checkFault("Sequence 2 (Motor B)");
/* 3) Servo sweep: +90°, -90° (1 s each segment) */
servo.write(SERVO_RIGHT); waitWithSampling(T_SERVO_TRAMO);
servo.write(SERVO_LEFT); waitWithSampling(T_SERVO_TRAMO);
servo.write(SERVO_CENTER);
/* 4) Concurrent sequences */
seqA.start(); seqB.start(); seqS.start();
}
void loop() {
/* Continuous sampling for the Plotter (~50 Hz) */
static uint32_t tNext = 0;
uint32_t now = millis();
if ((int32_t)(now - tNext) >= 0) {
sampleAndPrintCurrents();
tNext = now + 20;
}
/* Motor A concurrent sequence */
if (seqA.enabled) {
if (seqA.phase == Phase::FWD) {
motorA_fwd();
if ((int32_t)(now - seqA.tEnd) >= 0) {
seqA.phase = Phase::REV;
seqA.tEnd = now + T_MOTOR_DIR;
}
} else if (seqA.phase == Phase::REV) {
motorA_rev();
if ((int32_t)(now - seqA.tEnd) >= 0) {
seqA.phase = Phase::DONE; motorA_brake(); delay(50); motorA_coast();
}
}
}
/* Motor B concurrent sequence */
if (seqB.enabled) {
if (seqB.phase == Phase::FWD) {
motorB_fwd();
if ((int32_t)(now - seqB.tEnd) >= 0) {
seqB.phase = Phase::REV;
seqB.tEnd = now + T_MOTOR_DIR;
}
} else if (seqB.phase == Phase::REV) {
motorB_rev();
if ((int32_t)(now - seqB.tEnd) >= 0) {
seqB.phase = Phase::DONE; motorB_brake(); delay(50); motorB_coast();
}
}
}
/* Servo concurrent sequence (RIGHT -> LEFT -> CENTER) */
if (seqS.enabled) {
if (seqS.step == 0) {
if ((int32_t)(now - seqS.tEnd) >= 0) {
servo.write(SERVO_LEFT);
seqS.step = 1; seqS.tEnd = now + T_SERVO_TRAMO;
}
} else if (seqS.step == 1) {
if ((int32_t)(now - seqS.tEnd) >= 0) {
servo.write(SERVO_CENTER);
seqS.step = 2;
}
}
}
/* End condition: both motors done and servo centered */
if (seqA.phase == Phase::DONE && seqB.phase == Phase::DONE && seqS.step == 2) {
checkFault("Sequence 4 (concurrent)");
seqA.enabled = seqB.enabled = false; seqS.enabled = false;
motorA_coast(); motorB_coast();
while (true) { delay(1000); } /* Hold here after completion */
}
}
```
## Download examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Example codes of the Inventor module](https://drive.google.com/drive/folders/1wom3hU-bjWmbpT9DnZFzFtpL3cr-7Qzg)
# Maker
Source: https://docs.kode.diy/en/external-modules/maker
Create custom circuits, prototype your ideas and program with the GPIOs.
**Module:** Basic
# Features
With this module you can **create circuits and prototype your ideas using the integrated breadboard,** being able to program the circuit with the available pins of the Kode Dot.
In addition, you have the two power buses of the Kode Dot available:
| Voltage | Maximum current |
| ------- | --------------- |
| 5V | 2A |
| 3.3V | 2A |
## Available pins
You can use the following pins:
| Pin | Description |
| ------ | ------------------------------- |
| GPIO1 | RTC\_GPIO1, ADC1\_CH0, TOUCH1 |
| GPIO2 | RTC\_GPIO2, ADC1\_CH1, TOUCH2 |
| GPIO3 | RTC\_GPIO3, ADC1\_CH2, TOUCH3 |
| GPIO11 | RTC\_GPIO11, ADC2\_CH0, TOUCH11 |
| GPIO12 | RTC\_GPIO12, ADC2\_CH1, TOUCH12 |
| GPIO13 | RTC\_GPIO13, ADC2\_CH2, TOUCH13 |
| SCL | GPIO47 |
| SDA | GPIO46 |
| U0TXD | GPIO43 |
| U0RXD | GPIO44 |
| GPIO39 | JTAG-MTCK |
| GPIO40 | JTAG-MTCDO |
| GPIO41 | JTAG-MTCDI |
| GPIO42 | JTAG-MTMS |
The SCL and SDA pins are of the I2C bus of the Kode Dot, **only they can be used to connect other components to the I2C bus.**
# Radio
Source: https://docs.kode.diy/en/external-modules/radio
Give voice to your Kode Dot with the Radio module
**Module:** Pro
# Features
With this module you can **communicate with LoRa and locate yourself with GNSS.** It integrates a LoRa E80-900M2213S (LR1121) module from Ebyte and a GNSS MAX-M10S module from U-Blox.
We are working on the integration with **Meshtastic**.
## Connection with the Kode Dot
## Connection scheme
### LoRa module
The Ebyte E80-900M2213S module is connected to the ESP32-S3 as follows:
| E80-900M2213S | ESP32-S3 |
| ------------- | -------- |
| MISO | GPIO41 |
| MOSI | GPIO40 |
| SCK | GPIO39 |
| NSS (CS) | GPIO3 |
| BUSY | GPIO13 |
| LR\_NRESET | GPIO2 |
| DIO9 | GPIO12 |
| DIO8 | GPIO1 |
| DIO7 | GPIO11 |
### GNSS module
The GNSS MAX-M10S module is connected to the ESP32-S3 as follows:
| MAX-M10S | ESP32-S3 |
| -------- | -------- |
| TXD | GPIO44 |
| RXD | GPIO43 |
| SCL | GPIO47 |
| SDA | GPIO48 |
## Code examples
### Communication with LoRa
```cpp lora_test.ino lines icon="microchip" theme={null}
/**
* LR1121 Channel Scanner (RX only, no TX).
* Scans 868 MHz and 2.4 GHz bands with dynamic BW and SF changes.
* Measures RSSI (channel noise) and prints results in CSV format.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Pin configuration (based on your design) */
#define NSS_PIN 3 /* Chip Select */
#define DIO1_PIN 12 /* IRQ */
#define NRST_PIN 2 /* Reset */
#define BUSY_PIN 13 /* Busy */
#define MISO_PIN 41
#define MOSI_PIN 40
#define SCK_PIN 39
/* RF Switch mapping for E80-900M2213S */
static const uint32_t rfswitch_dio_pins[] = {
RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6,
RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC
};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{ LR11x0::MODE_STBY, { LOW, LOW } },
{ LR11x0::MODE_RX, { LOW, LOW } }, /* RX */
{ LR11x0::MODE_TX, { LOW, HIGH } }, /* TX Sub-1GHz LP */
{ LR11x0::MODE_TX_HP, { HIGH, LOW } }, /* TX Sub-1GHz HP */
{ LR11x0::MODE_TX_HF, { HIGH, HIGH } }, /* TX 2.4GHz */
{ LR11x0::MODE_GNSS, { LOW, LOW } },
{ LR11x0::MODE_WIFI, { LOW, LOW } },
END_OF_MODE_TABLE,
};
/* Instances */
SPIClass spi(HSPI);
LR1121 radio = new Module(NSS_PIN, DIO1_PIN, NRST_PIN, BUSY_PIN, spi);
/* Frequency sweep settings */
const float FREQS_868[] = { 863.0, 866.0, 868.0, 869.5 };
const float FREQS_24[] = { 2403.5, 2425.0, 2450.0, 2479.5 };
const size_t N_868 = sizeof(FREQS_868) / sizeof(FREQS_868[0]);
const size_t N_24 = sizeof(FREQS_24) / sizeof(FREQS_24[0]);
/* Dynamic parameters */
const float BWS_KHZ[] = { 125.0, 203.125 };
const int SFS[] = { 7, 9, 12 };
const int CR = 5;
const int PWR_DBM = 10;
const uint8_t PREAMBLE = 8;
const float TCXO_V = 1.8;
/* Listening time per measurement point */
const uint16_t DWELL_MS = 200;
/* Utilities */
/* Hardware reset for LR1121 */
static void hardResetModule() {
pinMode(NRST_PIN, OUTPUT);
digitalWrite(NRST_PIN, LOW);
delay(50);
digitalWrite(NRST_PIN, HIGH);
delay(50);
}
/* Configure LR1121 with given parameters */
static bool configRadio(float freqMHz, float bwkHz, int sf) {
int st = radio.begin(freqMHz, bwkHz, sf, CR, 0x12 /*sync*/, PWR_DBM, PREAMBLE, TCXO_V);
if (st != RADIOLIB_ERR_NONE) {
Serial.print("Config FAIL f="); Serial.print(freqMHz, 3);
Serial.print(" MHz BW="); Serial.print(bwkHz, 3);
Serial.print(" kHz SF="); Serial.print(sf);
Serial.print(" code="); Serial.println(st);
return false;
}
return true;
}
/* Measure RSSI once at given parameters and print CSV line */
static void measureOnce(float freqMHz, float bwkHz, int sf, const char* bandTag) {
if (!configRadio(freqMHz, bwkHz, sf)) return;
/* Start RX */
int st = radio.startReceive();
if (st != RADIOLIB_ERR_NONE) {
Serial.print("RX start FAIL code="); Serial.println(st);
return;
}
delay(DWELL_MS);
float rssi = radio.getRSSI();
/* CSV format output: BAND,FREQ_MHz,BW_kHz,SF,RSSI_dBm */
Serial.print(bandTag); Serial.print(",");
Serial.print(freqMHz, 3); Serial.print(",");
Serial.print(bwkHz, 3); Serial.print(",");
Serial.print(sf); Serial.print(",");
Serial.println(rssi, 1);
radio.standby();
}
/* Scan a full band across frequencies, BWs and SFs */
static void scanBand(const float* freqs, size_t nFreq, const char* bandTag) {
Serial.println();
Serial.println("BAND,FREQ_MHz,BW_kHz,SF,RSSI_dBm");
for (size_t i = 0; i < nFreq; i++) {
for (size_t b = 0; b < sizeof(BWS_KHZ)/sizeof(BWS_KHZ[0]); b++) {
for (size_t s = 0; s < sizeof(SFS)/sizeof(SFS[0]); s++) {
measureOnce(freqs[i], BWS_KHZ[b], SFS[s], bandTag);
}
}
}
}
/* Setup */
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); }
Serial.println("\n=== LR1121 Channel Scanner (RSSI only) ===");
Serial.println("RSSI = channel noise (closer to 0 => more noise)");
pinMode(BUSY_PIN, INPUT);
Serial.println("Resetting module...");
hardResetModule();
Serial.println("Initializing SPI...");
spi.begin(SCK_PIN, MISO_PIN, MOSI_PIN, NSS_PIN);
radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
Serial.println("\n--- Scanning: 868 MHz ---");
scanBand(FREQS_868, N_868, "868MHz");
Serial.println("\n--- Scanning: 2.4 GHz ---");
scanBand(FREQS_24, N_24, "2400MHz");
Serial.println("\nScan complete. Restart to repeat.");
}
/* Loop */
void loop() {
delay(1000);
}
```
### Location with GNSS
For using the GNSS module, we recommend using the library [SparkFun u-blox GNSS](https://github.com/sparkfun/SparkFun_u-blox_GNSS_v3)
#### Use by I2C
This code is an example of how to use the GNSS module via I2C.
```cpp gnss_test_I2C.ino lines icon="microchip" theme={null}
/**
* Example: Reading GNSS (GPS) data from a Kode Radio Module via I2C.
* Retrieves latitude, longitude, and altitude from the u-blox module.
* Uses the PVT (Position, Velocity, Time) message for data retrieval.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* GNSS module object */
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println("Kode Radio Module Example");
/* ─── Initialize I2C with SDA = GPIO48, SCL = GPIO47 ─── */
Wire.begin(48, 47);
/* Enable GNSS debug messages on Serial (optional) */
myGNSS.enableDebugging(); // Comment this line to disable debug messages
/* Try to connect to the u-blox GNSS module until successful */
while (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS not detected. Retrying..."));
delay(1000);
}
/* Set I2C output to UBX protocol only (disable NMEA messages) */
myGNSS.setI2COutput(COM_TYPE_UBX);
}
void loop()
{
/* If PVT data is available, read and display it */
if (myGNSS.getPVT() == true)
{
/* Get and print latitude */
int32_t latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
/* Get and print longitude */
int32_t longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (degrees * 10^-7)"));
/* Get and print altitude (MSL) */
int32_t altitude = myGNSS.getAltitudeMSL();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
Serial.println();
}
}
```
#### Use by UART
This code is an example of how to use the GNSS module via UART.
```cpp gnss_test_UART.ino lines icon="microchip" theme={null}
#include
/* GNSS object for serial communication */
SFE_UBLOX_GNSS_SERIAL myGNSS;
/* ─── GNSS UART pin mapping ───
* GNSS_RX_PIN → MCU pin that receives data from GNSS TX
* GNSS_TX_PIN → MCU pin that sends data to GNSS RX
*/
static const int GNSS_RX_PIN = 44; // MCU receives on GPIO44
static const int GNSS_TX_PIN = 43; // MCU transmits on GPIO43
/* Hardware serial instance (UART1) */
HardwareSerial GNSSSerial(1);
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println("u-blox GNSS via UART1 (GPIO44/43)");
/* ─── Initialize UART1 on the specified pins ───
* Baud rate: 38400
* Format: 8 data bits, no parity, 1 stop bit (SERIAL_8N1)
*/
GNSSSerial.begin(38400, SERIAL_8N1, GNSS_RX_PIN, GNSS_TX_PIN);
/* Enable GNSS debug messages on main Serial (optional) */
myGNSS.enableDebugging(Serial);
/* Configure UART1 output → UBX protocol only (disable NMEA messages) */
myGNSS.setUART1Output(COM_TYPE_UBX);
/* Attempt to connect to the GNSS module until successful */
while (!myGNSS.begin(GNSSSerial)) {
Serial.println(F("u-blox GNSS not detected. Retrying..."));
delay(1000);
}
}
void loop()
{
/* If PVT (Position, Velocity, Time) data is available, read and display it */
if (myGNSS.getPVT()) {
int32_t lat = myGNSS.getLatitude(); // Latitude in degrees * 10^-7
int32_t lon = myGNSS.getLongitude(); // Longitude in degrees * 10^-7
int32_t alt = myGNSS.getAltitudeMSL(); // Altitude MSL in millimeters
Serial.print(F("Lat: ")); Serial.print(lat);
Serial.print(F(" Long: ")); Serial.print(lon);
Serial.print(F(" (deg*1e-7) Alt: ")); Serial.print(alt);
Serial.println(F(" (mm)"));
}
}
```
## Download of examples
You can test the code examples using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Examples of code from the Radio module](https://drive.google.com/drive/folders/1wom3hU-bjWmbpT9DnZFzFtpL3cr-7Qzg)
# Frequently Asked Questions
Source: https://docs.kode.diy/en/faq
Frequently asked questions about kode, the Kode Dot and kodeOS.
## kode.
kode is your **open source community** to learn, build and create your ideas.
The pillars of the community are the **passion for technology, practical learning and collaboration.**
The kode community is in **constant growth** and we meet in [Discord](TBD). Joining and participating in the community is **totally free.**
## Kode Dot
The Kode Dot is a **one-in-all, pocket-sized device with AI capabilities,** designed to facilitate the **learning and prototyping** of electronics and embedded systems.
It integrates all the **hardware needed to create your projects** and is powered by **kodeOS**, our open source operating system, that allows you to **save your codes in applications and share them with the community.**
We are preparing the sale of the Kode Dot on **Kickstarter**. Prepare to buy yours on **September 1st.**
Connect the Kode Dot to your computer and program the code with your **favorite IDE**, as if it were any other board. Automatically **kodeOS** will give you the possibility of **running the code or creating an application.**
## kodeOS
**kodeOS is the operating system of the Kode Dot.** It is completely free and open source and allows you to **save your codes in applications and share them with the community.**
Additionally, you can upload applications created by the community to your Kode Dot to expand its functionalities.
**Yes! kodeOS is pre-installed on the Kode Dot**, so as soon as you take it out of the box you can use the applications that come with it.
If you delete kodeOS, you can recover it by re-programming it with the **kode desktop application.**
## Módulos Externos
Currently, in kode we have developed **four external modules** to make use of the upper 20-pin connector of the Kode Dot. All use a male pin connector of **2x10 with a 2.54mm pitch.**
Yes, the Kode Dot is designed so that you can **create your own external modules easily.** Currently we have a template developed for **KiCAD** with the correct connector and dimensions.
Via the rear magnetic connector, the Kode Dot can be charged and the i2c bus can be used. In the future it will make sense.
{/* TBD, in the future we will tell a little about us, the team and the kode philosophy. */}
# Welcome
Source: https://docs.kode.diy/en/introduction
kode is your open source community to learn, build and create your ideas.
# What do you want to learn today?
Discover the features of your Kode Dot and how you can use it to make your ideas a reality with our guides, documentation, examples and more.
Learn how to use your Kode Dot, configure it and run your first application.
Discover the ESP32-S3, the microcontroller of your Kode Dot, its features and how it is integrated.
Explore the use of the IO expander, the integrated circuit that adds programmable pins to your Kode Dot.
Learn how to use the display, its features and how you can use it to create incredible interfaces.
Add light to your projects with the RGB addressable LED. Learn about its features and how you can use it.
Understand the distribution of buttons and how you can use them to create your applications.
Discover the use of the microSD, its programming and why it is a key component in your Kode Dot.
Add audio to your projects and create applications with AI that interact with your voice.
Learn what an IMU is for and how to detect the position and movements of your Kode Dot.
Take control of time in your applications using the two RTCs of your Kode Dot.
Discover how the power system works and how to know the battery parameters.
Expand the capabilities of your Kode Dot, so the only limit is your imagination.
Meet Hammy, your learning companion that will evolve as you program.
Understand how applications work and how you can create your own or use those created by others.
Discover kodeOS, the operating system of your Kode Dot and how you can update it.
Create custom circuits, prototype your ideas using the breadboard and program the external GPIOs.
Connect DC motors, a servo motor and sensors to create and program your own robots.
Coming soon.
Coming soon.
# Addresable LED
Source: https://docs.kode.diy/en/kode-dot/addresable-led
Learn how the addresable LED works and give light to your projects.
# Features
The Kode Dot integrates an **addresable LED** on the top left of the pad, that you can light up with the **color and brightness you want.**
It is not a normal RGB LED, but an **addresable RGB LED WS2812B.** This means that inside the LED there is a **small integrated circuit** that can independently handle the color of the RGB LEDs and the brightness of each one.
| Feature | Description |
| ------- | ---------------- |
| Driver | WS2812B - 1-Wire |
| Size | 2mm x 2mm |
| Color | RGB |
## Connection diagram
The addresable LED works through a single pin connected to the ESP32-S3.
| WS2812B | ESP32-S3 |
| ------- | -------- |
| Data | GPIO4 |
1-Wire is a communication protocol that allows data communication through a single pin.
## Recommended libraries
### Arduino
* [Adafruit\_NeoPixel](https://github.com/adafruit/Adafruit_NeoPixel)
* [FastLED](https://github.com/FastLED/FastLED)
### ESP-IDF
* [led\_indicator](https://components.espressif.com/components/espressif/led_indicator)
* [led\_strip](https://components.espressif.com/components/espressif/led_strip)
## Example code
This code lights up the addresable LED by making a color cycle: first red, then green, and finally blue.
```cpp rgb_cycle.ino lines icon="microchip" theme={null}
/**
* Controls a single NeoPixel connected to GPIO 4, lighting it in red, green, and blue.
* Each color stays on for half a second, turning off between changes.
* Uses the Adafruit_NeoPixel library to control RGB LEDs.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Library to control NeoPixel strips and LEDs */
#define NEOPIXEL_PIN 4 /* GPIO pin where the NeoPixel is connected */
#define NUMPIXELS 1 /* Number of connected NeoPixels */
#define PIXEL_FORMAT (NEO_GRB + NEO_KHZ800) /* Color format and data speed */
Adafruit_NeoPixel *pixels; /* Pointer to the NeoPixel object */
#define DELAYVAL 500 /* Delay time between changes (ms) */
void setup() {
Serial.begin(115200); /* Start serial communication for debugging */
/* Create the NeoPixel object with the defined parameters */
pixels = new Adafruit_NeoPixel(NUMPIXELS, NEOPIXEL_PIN, PIXEL_FORMAT);
pixels->begin(); /* Initialize the NeoPixel */
pixels->clear(); /* Ensure the LED starts off */
pixels->show(); /* Apply the change */
}
void loop() {
/* Turn on red */
pixels->setPixelColor(0, pixels->Color(150, 0, 0));
pixels->show();
delay(DELAYVAL);
/* Turn off */
pixels->setPixelColor(0, pixels->Color(0, 0, 0));
pixels->show();
delay(DELAYVAL);
/* Turn on green */
pixels->setPixelColor(0, pixels->Color(0, 150, 0));
pixels->show();
delay(DELAYVAL);
/* Turn off */
pixels->setPixelColor(0, pixels->Color(0, 0, 0));
pixels->show();
delay(DELAYVAL);
/* Turn on blue */
pixels->setPixelColor(0, pixels->Color(0, 0, 150));
pixels->show();
delay(DELAYVAL);
/* Turn off */
pixels->setPixelColor(0, pixels->Color(0, 0, 0));
pixels->show();
delay(DELAYVAL);
}
```
## Download examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Addresable LED examples](https://drive.google.com/drive/folders/1f7pmw24Q7ikkvg6vVaRGUN63GGYj1NbC)
# Microphone
Source: https://docs.kode.diy/en/kode-dot/audio/microphone
# Features
The Kode Dot integrates a **digital MEMS microphone.** This type of microphones are very common in modern electronic devices and give a great reliability since **they do not depend on any analog part.**
## Connection diagram
The microphone is connected to the ESP32-S3 as follows:
| Microphone | ESP32-S3 |
| ---------- | -------- |
| SCK | GPIO38 |
| WS | GPIO45 |
| DIN | GPIO21 |
## Recommended libraries
### Arduino
* [ESP\_I2S](https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP_I2S)
### ESP-IDF
* [ESP-ADF](https://github.com/espressif/esp-adf)
The use of ESP-ADF is for advanced users. If you do not have experience in this framework, we recommend using the Arduino library.
## Example code
This code **records 5 seconds of audio** and saves it in the microSD in WAV format.
```cpp record_to_microsd.ino lines icon="microchip" theme={null}
/**
* Records 5 seconds of audio via I2S (48 kHz, 32-bit, mono) and saves it to /sdcard/test.wav.
* Uses the ESP32-S3 I2S bus and a microSD in SD_MMC 1-bit mode with custom pins.
* Prints initialization, recording, and write status over Serial.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "ESP_I2S.h"
#include "FS.h"
#include "SD_MMC.h"
/* I2S pin assignments */
const uint8_t I2S_SCK = 38; /* Serial clock pin (SCK) */
const uint8_t I2S_WS = 45; /* Word select pin (LRCLK) */
const uint8_t I2S_DIN = 21; /* Data input pin (SD) */
/* SD card pin assignments for SD_MMC in 1-bit mode */
const uint8_t SD_CMD = 5; /* Command pin (CMD) */
const uint8_t SD_CLK = 6; /* Clock pin (CLK) */
const uint8_t SD_DATA0 = 7; /* Data0 pin (D0) */
/* Create I2S interface instance */
I2SClass i2s;
/* Variables to store WAV data and its size */
uint8_t *wav_buffer;
size_t wav_size;
void setup() {
/* Initialize serial port for debugging */
Serial.begin(115200);
Serial.println("Starting setup...");
/* Configure I2S pins (MCLK not used: pass -1) */
i2s.setPins(I2S_SCK, I2S_WS, -1, I2S_DIN);
/* Initialize I2S in standard mode: 48 kHz, 32-bit data, mono, left-aligned slot */
Serial.println("Initializing I2S bus...");
if (!i2s.begin(
I2S_MODE_STD,
48000,
I2S_DATA_BIT_WIDTH_32BIT,
I2S_SLOT_MODE_MONO,
I2S_STD_SLOT_LEFT)) {
Serial.println("Failed to initialize I2S bus!");
return;
}
Serial.println("I2S bus initialized.");
/* Configure SD_MMC pins for 1-bit SD mode */
Serial.println("Configuring SD card pins...");
if (!SD_MMC.setPins(SD_CLK, SD_CMD, SD_DATA0)) {
Serial.println("Failed to configure SD pins!");
return;
}
/* Mount the SD card at "/sdcard" */
Serial.println("Mounting SD card...");
if (!SD_MMC.begin("/sdcard", true)) { /* true => 1-bit bus */
Serial.println("Failed to initialize SD card!");
return;
}
Serial.println("SD card mounted successfully.");
/* Notify that recording will start */
Serial.println("Recording 5 seconds of audio...");
/* Record WAV data for 5 seconds into wav_buffer */
wav_buffer = i2s.recordWAV(5, &wav_size);
/* Open a file on the SD card for writing */
File file = SD_MMC.open("/test.wav", FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing!");
return;
}
/* Write recorded data and verify complete write */
Serial.println("Writing audio data to file...");
if (file.write(wav_buffer, wav_size) != wav_size) {
Serial.println("Failed to write audio data to file!");
file.close();
return;
}
/* Close the file when done */
file.close();
Serial.println("Audio recording and save complete.");
}
void loop() {
delay(10000);
}
```
## Download examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Audio examples](https://drive.google.com/drive/folders/1rJPxfOXun4p1ijXyRdREydyOMEUJju0u)
# Overview
Source: https://docs.kode.diy/en/kode-dot/audio/overview
Understand how audio works in the Kode Dot and what is the I2S bus
# What is the I2S bus
**Inter-IC Sound (I2S)** is a digital communication protocol designed specifically to **transmit audio between electronic devices.**
Unlike other buses like I2C, which are used to transmit general data between chips, I2S is **optimized to send audio data of high quality in real time.**
## How does I2S work?
The I2S bus uses several lines to transmit the information:
* **Serial Data (SD):** Where the audio data travels.
* **Serial Clock (SCK):** Marks the rhythm at which the bits are sent.
* **Word Select (WS):** Indicates if the data corresponds to the left or right channel (in stereo audio).
The **SCK and WS lines are common** to all devices that are connected to the I2S bus. However, both the speaker and the microphone have their **own SD lines.**
This structure allows the audio to be transmitted in a **synchronized and lossless manner, ideal for applications where sound quality is important.**
## Why use I2S for digital audio?
* **Quality:** Allows digital audio transmission without interference or typical noise of analog signals.
* **Synchronization:** Ensures that the data arrives at the right time, avoiding phase shifts or distortions.
* **Compatibility:** It is the standard in most modern audio chips, facilitating the integration of microphones and digital speakers.
In the Kode Dot, both the **microphone and the speaker are connected via I2S,** which allows recording and reproducing sound with great fidelity and efficiency.
# Speaker
Source: https://docs.kode.diy/en/kode-dot/audio/speaker
# Features
The Kode Dot integrates a **1W speaker connected to an amplifier.** Thus, you only have to worry about giving sound to your projects through the I2S bus and the amplifier will take care of doing all the work.
## Connection diagram
The speaker is connected to the ESP32-S3 as follows:
| Speaker | ESP32-S3 |
| ------- | -------- |
| SCK | GPIO38 |
| WS | GPIO45 |
| DOUT | GPIO46 |
| SD | EXP3 |
The amplifier is off by default to not waste energy. To turn it on, set the EXP3 pin of the [IO expander](/en/kode-dot/io-expander) to HIGH.
## Recommended libraries
### Arduino
* [ESP\_I2S](https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP_I2S)
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [ESP-ADF](https://github.com/espressif/esp-adf)
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
The use of ESP-ADF is for advanced users. If you do not have experience in this framework, we recommend using the Arduino library.
## Example code
This code **reproduces the tone specified in the `frequency` variable.**
```cpp speaker_tone.ino lines icon="microchip" theme={null}
/**
* Generates a square-wave tone over I2S (48 kHz, 32-bit, mono) and enables the amplifier via an I/O expander.
* The tone streams continuously through I2S; the expander powers the audio stage.
* Uses custom pins for I2S and for the TCA95XX_16BIT expander.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Expander pin configuration */
#define I2C_SCL_PIN (47)
#define I2C_SDA_PIN (48)
#define I2C_ADDR (0x20)
/* I2S interface pins */
const uint8_t I2S_SCK = 38; // Serial clock (SCK)
const uint8_t I2S_WS = 45; // Word Select / LRCLK
const uint8_t I2S_DOUT = 46; // Data output (SD)
/* Audio signal parameters */
const int frequency = 300; // Square wave frequency in Hz
const int amplitude = 500; // Square wave amplitude
/* Signal generation state variables */
int32_t sample = amplitude; // Current sample value
int count = 0; // Sample counter
/* Global instances */
I2SClass i2s; // I2S interface object
esp_expander::Base *expander = nullptr; // Expander instance pointer
void setup() {
Serial.begin(115200);
Serial.println("Simple I2S tone");
/* Configure I2S pins (no MCLK: pass -1) */
i2s.setPins(I2S_SCK, I2S_WS, I2S_DOUT, -1);
/* Initialize I2S: standard mode, 48 kHz, 32-bit, mono, left slot */
if (!i2s.begin(I2S_MODE_STD, 48000, I2S_DATA_BIT_WIDTH_32BIT,
I2S_SLOT_MODE_MONO, I2S_STD_SLOT_LEFT)) {
Serial.println("Failed to initialize I2S!");
while (1); // Halt on failure
}
Serial.println("I2S bus initialized.");
/* Initialize the I/O expander */
expander = new esp_expander::TCA95XX_16BIT(I2C_SCL_PIN, I2C_SDA_PIN, I2C_ADDR);
expander->init();
expander->begin();
/* Set expander pin 3 as output to enable the amplifier */
expander->pinMode(3, OUTPUT);
expander->digitalWrite(3, HIGH); /* Enable amplifier */
}
void loop() {
/* Toggle sign every half wavelength to create a square wave */
if (count % (48000/(2*frequency)) == 0) {
sample = -sample;
}
/* Write the sample (mono) */
i2s.write(sample); // Left channel
/* Increment sample counter */
count++;
}
```
## Download examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Audio examples](https://drive.google.com/drive/folders/1rJPxfOXun4p1ijXyRdREydyOMEUJju0u)
# Buttons
Source: https://docs.kode.diy/en/kode-dot/buttons
Understand the distribution of buttons and how to use them in your projects.
# Features
The buttons of the Kode Dot are distributed between a **directional pad of four buttons and two independent buttons.**
With these buttons you can navigate through kodeOS, control the state of the ESP32-S3 and turn the device on or off.
## Connection diagram
All buttons are connected to the **IO expander**, except for the **top button** that is connected directly to the ESP32-S3. In addition, all have a physical **pull-up resistor.**
The connection of the buttons is as follows:
| Button | IO expander |
| ----------- | ----------- |
| Left pad | EXP7 |
| Up pad | EXP6 |
| Right pad | EXP11 |
| Down pad | EXP8 |
| Up button | GPIO0 |
| Down button | EXP9 |
See [IO expander](/en/kode-dot/io-expander) to learn how the IO expander works.
The top button is connected to GPIO0, to control the BOOT state of the ESP32-S3.
## Recommended libraries
### Arduino
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [button](https://components.espressif.com/components/espressif/button)
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
## Example code
With this code you can check the **functionality of the buttons.** Connect the Kode Dot to the **serial monitor** and depending on which button you press, you will see a message in the monitor.
```cpp buttons_check.ino lines icon="microchip" theme={null}
/**
* Detects button presses from a TCA95XX_16BIT I/O expander and a direct ESP32-S3 pin.
* Uses interrupts to respond to button events without constant polling.
* Prints the detected button to the serial monitor.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Library to control I/O expanders on ESP32 */
/* Expander configuration */
#define CHIP_NAME TCA95XX_16BIT
#define I2C_SCL_PIN (47) /* I2C bus SCL pin */
#define I2C_SDA_PIN (48) /* I2C bus SDA pin */
#define EXP_INT_PIN (18) /* Expander interrupt pin */
#define I2C_ADDR (0x20)/* Expander I2C address */
/* Button connections on expander */
#define PAD_UP 6
#define PAD_LEFT 7
#define PAD_DOWN 8
#define PAD_RIGHT 11
#define BUTTON_BOTTOM 9
/* Button connected directly to ESP32-S3 */
#define BUTTON_UP_PIN 0 /* GPIO0 */
/* Expander instance */
esp_expander::Base *expander = nullptr;
/* Flags for pending interrupts */
volatile bool expanderInterrupted = false;
volatile bool buttonUpInterrupted = false;
/* ISR for expander interrupt */
void IRAM_ATTR handleExpanderIRQ() {
expanderInterrupted = true;
}
/* ISR for button on GPIO0 */
void IRAM_ATTR handleButtonUpIRQ() {
buttonUpInterrupted = true;
}
void setup() {
Serial.begin(115200);
Serial.println("Button interrupt test start");
/* Initialize expander */
expander = new esp_expander::TCA95XX_16BIT(I2C_SCL_PIN, I2C_SDA_PIN, I2C_ADDR);
expander->init();
expander->begin();
/* Configure expander pins as inputs */
expander->pinMode(PAD_UP, INPUT);
expander->pinMode(PAD_LEFT, INPUT);
expander->pinMode(PAD_DOWN, INPUT);
expander->pinMode(PAD_RIGHT, INPUT);
expander->pinMode(BUTTON_BOTTOM, INPUT);
/* Configure expander interrupt pin */
pinMode(EXP_INT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EXP_INT_PIN),
handleExpanderIRQ, FALLING);
/* Configure direct button on GPIO0 */
pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_UP_PIN),
handleButtonUpIRQ, FALLING);
Serial.println("Setup complete. Waiting for button presses...");
}
void loop() {
/* If there are no pending interrupts, wait */
if (!expanderInterrupted && !buttonUpInterrupted) {
delay(10);
return;
}
/* Handle direct button */
if (buttonUpInterrupted) {
buttonUpInterrupted = false;
Serial.println("→ BUTTON_UP (GPIO0) pressed");
delay(50);
}
/* Handle expander buttons */
if (expanderInterrupted) {
expanderInterrupted = false;
if (expander->digitalRead(PAD_UP) == LOW) {
Serial.println("→ PAD_UP pressed");
}
if (expander->digitalRead(PAD_LEFT) == LOW) {
Serial.println("→ PAD_LEFT pressed");
}
if (expander->digitalRead(PAD_DOWN) == LOW) {
Serial.println("→ PAD_DOWN pressed");
}
if (expander->digitalRead(BUTTON_BOTTOM) == LOW) {
Serial.println("→ BUTTON_BOTTOM pressed");
}
if (expander->digitalRead(PAD_RIGHT) == LOW) {
Serial.println("→ PAD_RIGHT pressed");
}
delay(50);
}
}
```
## Download examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Examples using the buttons](https://drive.google.com/drive/folders/1-K3qP_pf7niBGDafzZQtoZ7c4Zyx9w1W)
# Connectors
Source: https://docs.kode.diy/en/kode-dot/connectors
Expand your Kode Dot capabilities to make your imagination the limit.
# Features
The Kode Dot has two connectors, one **20 pins on the top** and another **magnetic 4 pins on the back.**
## Top 20 pin connector
## Magnetic connector on the back
# Display
Source: https://docs.kode.diy/en/kode-dot/display
Learn to program it and create incredible interfaces with LVGL.
# Features
The Kode Dot has the **best screen in a maker device on the market.** It is a **2.13-inch AMOLED touch screen** with the following features:
| Feature | Description |
| ------------ | ---------------- |
| Size | 2.13 inches |
| Resolution | 410x502 pixels |
| Color depth | 16 bits (RGB565) |
| Driver | CO5300 - QSPI |
| Touch driver | CST820 - I2C |
The screen is completely programmable with **existing Arduino and ESP-IDF libraries** and compatible with **LVGL.**
## Connection diagram
### Screen driver
The screen driver is the **CO5300** and works using the **QuadSPI bus.** This driver is connected to the ESP32-S3 in the following way:
| CO5300 | ESP32-S3 |
| ----------- | -------- |
| Chip Select | GPIO9 |
| Clock | GPIO17 |
| Data 0 | GPIO15 |
| Data 1 | GPIO14 |
| Data 2 | GPIO16 |
| Data 3 | GPIO10 |
| Reset | GPIO8 |
The QuadSPI bus is of the same family as the SPI bus, but has double the bandwidth.
### Touch driver
The touch driver is the **CST820** and works using the **I2C bus.** This driver is connected to the ESP32-S3 in the following way:
| CST820 | ESP32-S3 |
| --------- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| Interrupt | EXP15 |
| Reset | GPIO8 |
The touch driver has the address 0x15 on the I2C bus.
The interrupt pin is connected to EXP15 of the IO expander. See [IO expander](/en/kode-dot/io-expander) for more information.
The reset pin of the touch driver and the screen driver are connected to the same pin of the ESP32-S3.
## Recommended libraries
### Arduino
* [Arduino\_GFX](https://github.com/moononournation/Arduino_GFX)
* [bb\_captouch](https://github.com/bitbank2/bb_captouch)
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [esp\_lcd\_co5300](https://components.espressif.com/components/kodediy/esp_lcd_co5300)
* [esp\_lcd\_touch\_cst820](https://components.espressif.com/components/kodediy/esp_lcd_touch_cst820)
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
## Example code
### Basic example
This is the most basic code to test the screen, only printing a **¡Hola mundo!** on the screen.
```cpp display_test.ino lines icon="microchip" theme={null}
/**
* Simple display demo with Arduino_GFX: initializes the panel and draws “Hello World!”.
* Uses ESP32-S3 QSPI bus, 410x502 resolution, and max brightness.
* Renders large text roughly centered on a blue background.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#define DSP_HOR_RES 410
#define DSP_VER_RES 502
#define DSP_SCLK 17
#define DSP_SDIO0 15
#define DSP_SDIO1 14
#define DSP_SDIO2 16
#define DSP_SDIO3 10
#define DSP_RST 8
#define DSP_CS 9
/* Objects to handle the graphics bus and display */
static Arduino_DataBus *gfxBus;
static Arduino_CO5300 *gfx;
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("Simple Display Demo");
/* ─── Display configuration ───
QSPI bus: CS, SCLK, D0, D1, D2, D3 */
gfxBus = new Arduino_ESP32QSPI(DSP_CS, DSP_SCLK, DSP_SDIO0, DSP_SDIO1, DSP_SDIO2, DSP_SDIO3);
/* Panel constructor: bus, RST, rotation offset (0), x/y offset (0,0),
width/height, backlight pin (22), options (0,0,0) */
gfx = new Arduino_CO5300(gfxBus, DSP_RST, 0, 0, DSP_HOR_RES, DSP_VER_RES, 22, 0, 0, 0);
if (!gfx->begin()) {
Serial.println("Error: display init failed");
while (true) /* halt on failure */ ;
}
gfx->setRotation(0);
gfx->setBrightness(255);
gfx->displayOn();
Serial.println("Display initialized");
/* Print Hello World! */
gfx->fillScreen(BLUE);
gfx->setTextSize(4);
gfx->setTextColor(ORANGE);
gfx->setCursor(65, 250);
gfx->print("Hello World!");
}
void loop() {
delay(1000);
}
```
### LVGL example
This code implements **LVGL 9.3** and allows you to test the screen **printing a text, using an example or using a demo.** By default, the **music demo of LVGL** is used.
```cpp lvgl_test.ino lines icon="microchip" theme={null}
/**
* Example of using LVGL with Arduino on Kode Dot.
* Sets up the display, touch panel, and draws a simple label.
* More info: https://docs.lvgl.io/master/integration/framework/arduino.html
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
#include
#include
/*To use the built-in examples and demos of LVGL uncomment the includes below respectively.
*You also need to copy lvgl/examples to lvgl/src/examples. Similarly for the demos lvgl/demos to lvgl/src/demos.
*Note that the lv_examples library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8)
*as the examples and demos are now part of the main LVGL library. */
// #include
// #include
/* Display resolution and rotation */
#define DSP_HOR_RES 410
#define DSP_VER_RES 502
#define DSP_ROTATION LV_DISPLAY_ROTATION_0
/* LVGL draw buffer size */
#define DRAW_BUF_SIZE (DSP_HOR_RES * DSP_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
static uint8_t *lv_buf1;
static uint8_t *lv_buf2;
/* Objects to handle display bus and panel */
static Arduino_DataBus *gfxBus;
static Arduino_CO5300 *gfx;
static BBCapTouch touch;
/* Callback for LVGL to push rendered image to the display */
void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
uint32_t w = lv_area_get_width(area);
uint32_t h = lv_area_get_height(area);
gfx->startWrite();
gfx->writeAddrWindow(area->x1, area->y1, w, h);
gfx->writePixels((uint16_t *)px_map, w * h);
gfx->endWrite();
/* Tell LVGL flushing is done */
lv_display_flush_ready(disp);
}
/* Read data from the touch panel */
void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) {
TOUCHINFO ti;
if (touch.getSamples(&ti) && ti.count > 0) {
data->state = LV_INDEV_STATE_PRESSED;
data->point.x = ti.x[0];
data->point.y = ti.y[0];
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
/* Use Arduino's millis() as LVGL tick source */
static uint32_t my_tick(void) {
return millis();
}
void setup() {
Serial.begin(115200);
Serial.println("LVGL with Arduino on Kode Dot");
/* ─── Display configuration ─── */
gfxBus = new Arduino_ESP32QSPI(9, 17, 15, 14, 16, 10);
gfx = new Arduino_CO5300(gfxBus, 8, 0, 0, DSP_HOR_RES, DSP_VER_RES, 22, 0, 0, 0);
if (!gfx->begin()) {
Serial.println("Display initialization failed");
while (true) delay(1000);
}
gfx->setRotation(0);
gfx->setBrightness(255);
gfx->fillScreen(BLACK);
Serial.println("Display initialized");
/* ─── Touch panel configuration ─── */
if (touch.init(48, 47, -1, -1, 400000) == CT_SUCCESS) {
touch.setOrientation(0, DSP_HOR_RES, DSP_VER_RES);
Serial.printf("Touch OK. Type=%d\n", touch.sensorType());
} else {
Serial.println("Touch initialization failed");
}
/* ─── Initialize LVGL ─── */
lv_init();
lv_tick_set_cb(my_tick); /* Set tick source */
lv_display_t *disp = lv_display_create(DSP_HOR_RES, DSP_VER_RES);
lv_display_set_flush_cb(disp, my_disp_flush);
/* Allocate buffers in PSRAM */
lv_buf1 = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
lv_buf2 = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
lv_display_set_buffers(disp, lv_buf1, lv_buf2, DRAW_BUF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);
/* Configure input device as a pointer (touch) */
lv_indev_t *indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, my_touchpad_read);
/* *******************
* Create a simple label
******************** */
lv_obj_t *label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Hello Arduino, I'm LVGL!");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
/* *******************
* Try an example. See all the examples
* - Online: https://docs.lvgl.io/master/examples.html
* - Source codes: https://github.com/lvgl/lvgl/tree/master/examples
******************** */
// lv_example_btn_1();
/* *******************
* Or try out a demo. Don't forget to enable the demos in lv_conf.h. E.g. LV_USE_DEMO_WIDGETS
******************** */
// lv_demo_music();
}
void loop() {
lv_timer_handler(); /* Let LVGL handle the GUI */
delay(5);
}
```
## Download of examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Examples of screen code](https://drive.google.com/drive/folders/1dw2ThNCUiHljMfDs-s67guQxr_ILJ5BL)
# ESP32-S3
Source: https://docs.kode.diy/en/kode-dot/esp32s3
Know the microcontroller that gives life to the Kode Dot and its state control.
# Features
The **ESP32-S3** is one of the best microcontrollers of **Espressif** that incorporates a **double core XTensa LX7,** capable of running up to **240MHz**. In addition, it integrates **2.4GHz** connectivity with support for **WiFi** and **Bluetooth LE**.
In the following image you can see the **functional diagram of the ESP32-S3** with all the peripherals it incorporates:
In addition to its power and versatility, we have integrated it into the Kode Dot expanding its capabilities with **32MB of flash** and **8MB of PSRAM.** Thus, it makes honor to its status as the **best maker device on the market** and executing programs much larger and more complex.
| Feature | Description |
| ------- | --------------------------------------- |
| Flash | External memory of **32MB by Octalbus** |
| PSRAM | Internal memory of **8MB by Octalbus** |
## Antenna
Inside the Kode Dot we have integrated a **2.4GHz antenna** in the PCB. With this antenna you will be able to use the **WiFi** and **Bluetooth LE** of the ESP32-S3, as well as **ESP-NOW** and other communication protocols that work in this frequency band.
## Programming
**Programming the Kode Dot is done like any other ESP32-S3-based board.** Connect it directly to your computer using the USB-C cable and start uploading your code.
In the [Applications](/en/kodeOS/apps) section it is explained in detail how to upload code and create applications.
Internally, the **USB-C data lines** are connected to the **GPIO19 and GPIO20** pins to use the internal USB-Serial peripheral.
With the USB-C, you also have the option to use the internal **USB Serial/JTAG** peripheral that the ESP32-S3 incorporates to **flash and debug the Kode Dot.**
For the most advanced, you can use the **GPIO39, GPIO40, GPIO41 and GPIO42** pins of the **top connector of the Kode Dot** to debug a program using an **external JTAG interface.**
## State control
The control of the **BOOT** and **RESET** states of the ESP32-S3 is performed using simple combinations with the **buttons of the Kode Dot.**
### RESET
To reset the Kode Dot, you must press the **left button of the pad** at the same time as you press the **bottom button.** This is useful in these cases:
* When a program has been **flashed** and the Kode Dot is **locked.**
* To **exit an application** and return to the main menu.
### BOOT
To enter the Kode Dot in BOOT mode, while holding the **top button,** the Kode Dot must be reset following the RESET combination.
It is likely that you will not have to use this process since if the code you upload to the Kode Dot blocks or makes the ESP32-S3 restart, the Kode Dot will return to the main menu automatically.
## Example code
With this code you can get the **MAC address** of the different interfaces of the ESP32-S3.
```cpp esp32s3_info.ino lines icon="microchip" theme={null}
/**
* Displays ESP32-S3 microcontroller information via serial port.
* Includes model, revision, number of cores, and Chip ID.
* Prints the data every 3 seconds.
*/
/* ───────── KODE | docs.kode.diy ───────── */
void setup() {
Serial.begin(115200); /* Starts serial communication at 115200 baud */
}
void loop() {
/* Prints ESP32 chip model and revision */
Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
/* Prints the number of cores in the chip */
Serial.printf("This chip has %d cores\n", ESP.getChipCores());
/* Prints the chip's unique identifier */
Serial.print("Chip ID: ");
Serial.println(ESP.getEfuseMac());
/* Waits 3 seconds before repeating */
delay(3000);
}
```
## Download ofexamples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[ESP32-S3 examples](https://drive.google.com/drive/folders/11FnC9pj8qADzXAlg8xAT0knNWh9bgYV6)
# IMU
Source: https://docs.kode.diy/en/kode-dot/imu
Learn what an IMU is for and how to use it in your Kode Dot
# Features
The Kode Dot integrates a **3-axis gyroscope, 3-axis accelerometer and 3-axis magnetometer.** Thus, you can know the relative position to itself and its absolute position relative to the Earth.
The gyroscope and accelerometer are in the **same integrated** and have the following characteristics:
| Feature | Description |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Accelerometer + gyroscope “always-on” | Total consumption of **0,55 mA** in high-performance mode for continuous operation. |
| Ranges | Accelerometer **±2/4/8/16 g** • Gyroscope **±125/250/500/1000/2000 dps**. |
| Smart FIFO | Data buffer of up to **9 KB** with compression and dynamic batching. |
| Embedded AI motor | **16 FSMs** programmable + **MLC** (up to 8 flows / 256 nodes). |
| Event recognition | Pedometer, step counter, significant motion, inclination, free-fall, wake-up, 6D/4D orientation, click and double click. |
| Temperature sensor | Internal thermometer to monitor the chip temperature. |
The magnetometer has the following characteristics:
| Feature | Detail |
| ------------------- | --------------------------------------------------------- |
| Dynamic range | **±50 gauss** (three axes) |
| Output resolution | **16 bits** |
| Typical consumption | 200 µA @ 20 Hz (high-resolution mode) / 50 µA (low-power) |
## Connection diagram
### 6-axis IMU
The IMU is connected to the ESP32-S3 through the I2C bus using these connections:
| IMU | ESP32-S3 |
| ---- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INT1 | EXP13 |
| INT2 | EXP12 |
The IMU has the address 0x6A on the I2C bus.
The interrupt pins are connected to the [IO expander](/en/kode-dot/io-expander).
### 3-axis magnetometer
The magnetometer is connected in the same way to the I2C bus using these connections:
| Magnetometer | ESP32-S3 |
| ------------ | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INT1 | EXP0 |
The magnetometer has the address 0x1E on the I2C bus.
The interrupt pin is connected to the [IO expander](/en/kode-dot/io-expander).
## Recommended libraries
### Arduino
* [Adafruit LSM6DS](https://github.com/adafruit/Adafruit_LSM6DS)
* [Adafruit LIS2MDL](https://github.com/adafruit/Adafruit_LIS2MDL)
### ESP-IDF
* [kode\_lsm6dsox](https://components.espressif.com/components/kodediy/kode_lsm6dsox)
* [kode\_lis2mdl](TBD)
## Example code
### 6-axis IMU
This code shows the measurement range of the sensors and the sampling frequency. It also shows the temperature, acceleration and angular velocity.
```cpp imu_test.ino lines icon="microchip" theme={null}
/**
* Initializes and reads an LSM6DSOX IMU over I2C on ESP32-S3, printing accel, gyro, and temperature.
* Prints configured ranges and data rates, then outputs readings every 1 second over Serial.
* Uses custom I2C pins (GPIO48/47) and the Adafruit_LSM6DSOX library.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Library for the LSM6DSOX sensor */
#include /* I2C communication library */
/* Configurable I2C pins */
#define I2C_SDA 48 /* SDA pin */
#define I2C_SCL 47 /* SCL pin */
/* IMU sensor instance and I2C bus object */
Adafruit_LSM6DSOX imu;
void setup(void) {
/* Initialize serial port for debugging */
Serial.begin(115200);
while (!Serial);
/* Initialize the I2C bus with the specified pins */
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("LSM6DSOX test");
/* Attempt to initialize the sensor at the default I2C address (0x6A).
Note: some boards use 0x6B depending on SA0. */
if (!imu.begin_I2C()) {
Serial.println("Failed to find LSM6DSOX chip");
while (1) {
delay(10); /* Infinite loop if initialization fails */
}
}
Serial.println("LSM6DSOX Found!");
/* Display configured accelerometer range */
Serial.print("Accelerometer range set to: ");
switch (imu.getAccelRange()) {
case LSM6DS_ACCEL_RANGE_2_G:
Serial.println("+-2G"); break;
case LSM6DS_ACCEL_RANGE_4_G:
Serial.println("+-4G"); break;
case LSM6DS_ACCEL_RANGE_8_G:
Serial.println("+-8G"); break;
case LSM6DS_ACCEL_RANGE_16_G:
Serial.println("+-16G"); break;
}
/* Display configured gyroscope range */
Serial.print("Gyro range set to: ");
switch (imu.getGyroRange()) {
case LSM6DS_GYRO_RANGE_125_DPS:
Serial.println("125 degrees/s"); break;
case LSM6DS_GYRO_RANGE_250_DPS:
Serial.println("250 degrees/s"); break;
case LSM6DS_GYRO_RANGE_500_DPS:
Serial.println("500 degrees/s"); break;
case LSM6DS_GYRO_RANGE_1000_DPS:
Serial.println("1000 degrees/s"); break;
case LSM6DS_GYRO_RANGE_2000_DPS:
Serial.println("2000 degrees/s"); break;
case ISM330DHCX_GYRO_RANGE_4000_DPS:
/* Unsupported range for the DSOX */
break;
}
/* Display accelerometer data rate */
Serial.print("Accelerometer data rate set to: ");
switch (imu.getAccelDataRate()) {
case LSM6DS_RATE_SHUTDOWN: Serial.println("0 Hz"); break;
case LSM6DS_RATE_12_5_HZ: Serial.println("12.5 Hz"); break;
case LSM6DS_RATE_26_HZ: Serial.println("26 Hz"); break;
case LSM6DS_RATE_52_HZ: Serial.println("52 Hz"); break;
case LSM6DS_RATE_104_HZ: Serial.println("104 Hz"); break;
case LSM6DS_RATE_208_HZ: Serial.println("208 Hz"); break;
case LSM6DS_RATE_416_HZ: Serial.println("416 Hz"); break;
case LSM6DS_RATE_833_HZ: Serial.println("833 Hz"); break;
case LSM6DS_RATE_1_66K_HZ: Serial.println("1.66 KHz"); break;
case LSM6DS_RATE_3_33K_HZ: Serial.println("3.33 KHz"); break;
case LSM6DS_RATE_6_66K_HZ: Serial.println("6.66 KHz"); break;
}
/* Display gyroscope data rate */
Serial.print("Gyro data rate set to: ");
switch (imu.getGyroDataRate()) {
case LSM6DS_RATE_SHUTDOWN: Serial.println("0 Hz"); break;
case LSM6DS_RATE_12_5_HZ: Serial.println("12.5 Hz"); break;
case LSM6DS_RATE_26_HZ: Serial.println("26 Hz"); break;
case LSM6DS_RATE_52_HZ: Serial.println("52 Hz"); break;
case LSM6DS_RATE_104_HZ: Serial.println("104 Hz"); break;
case LSM6DS_RATE_208_HZ: Serial.println("208 Hz"); break;
case LSM6DS_RATE_416_HZ: Serial.println("416 Hz"); break;
case LSM6DS_RATE_833_HZ: Serial.println("833 Hz"); break;
case LSM6DS_RATE_1_66K_HZ: Serial.println("1.66 KHz"); break;
case LSM6DS_RATE_3_33K_HZ: Serial.println("3.33 KHz"); break;
case LSM6DS_RATE_6_66K_HZ: Serial.println("6.66 KHz"); break;
}
}
void loop() {
/* Variables to hold sensor events */
sensors_event_t accel;
sensors_event_t gyro;
sensors_event_t temp;
/* Get accelerometer, gyroscope, and temperature events */
imu.getEvent(&accel, &gyro, &temp);
/* Print temperature in degrees Celsius */
Serial.print("\t\tTemperature: ");
Serial.print(temp.temperature);
Serial.println(" deg C");
/* Print acceleration in m/s^2 for each axis */
Serial.print("\t\tAccel X: ");
Serial.print(accel.acceleration.x);
Serial.print(" \tY: ");
Serial.print(accel.acceleration.y);
Serial.print(" \tZ: ");
Serial.print(accel.acceleration.z);
Serial.println(" m/s^2");
/* Print gyroscope rotation in rad/s for each axis */
Serial.print("\t\tGyro X: ");
Serial.print(gyro.gyro.x);
Serial.print(" \tY: ");
Serial.print(gyro.gyro.y);
Serial.print(" \tZ: ");
Serial.print(gyro.gyro.z);
Serial.println(" radians/s");
Serial.println();
delay(1000); /* Small delay between readings */
}
```
### 3-axis magnetometer
This code shows the magnetic vector in micro-Teslas (uT).
```cpp mag_test.ino lines icon="microchip" theme={null}
/**
* Initializes and reads the LIS2MDL magnetometer over I2C on an ESP32-S3.
* Prints sensor details on startup, then outputs the magnetic vector (uT) every second.
* Uses custom I2C pins (GPIO48/47) and the Adafruit_LIS2MDL library.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Configurable I2C pins */
#define I2C_SDA 48 /* SDA pin */
#define I2C_SCL 47 /* SCL pin */
/* Magnetometer instance with unique ID */
Adafruit_LIS2MDL mag = Adafruit_LIS2MDL(12345);
void setup(void) {
/* Initialize serial port for debug output */
Serial.begin(115200);
while (!Serial) {
/* wait for serial */
}
/* Initialize I2C bus with selected SDA, SCL pins */
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("Magnetometer Test");
Serial.println();
/* Attempt to initialize the LIS2MDL sensor at I2C address 0x1E */
if (!mag.begin()) {
/* Sensor not detected: print error and halt */
Serial.println("Ooops, no LIS2MDL detected ... Check your wiring!");
while (1) {
delay(10); /* Infinite loop on failure */
}
}
/* Display some basic information on this sensor */
mag.printSensorDetails();
}
void loop(void) {
/* Get a new sensor event */
sensors_event_t event;
mag.getEvent(&event);
/* Display the results (magnetic vector values are in micro-Tesla (uT)) */
Serial.print("X: ");
Serial.print(event.magnetic.x);
Serial.print(" ");
Serial.print("Y: ");
Serial.print(event.magnetic.y);
Serial.print(" ");
Serial.print("Z: ");
Serial.print(event.magnetic.z);
Serial.print(" ");
Serial.println("uT");
/* Delay before next reading */
delay(1000);
}
```
## Download examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[IMU and magnetometer examples](https://drive.google.com/drive/folders/1eAutUqjqenHA7lNoFHxKpBUXdwUa-6ZS)
# IO Expander
Source: https://docs.kode.diy/en/kode-dot/io-expander
Learn to control the programmable pins of the IO expander.
# Features
Although all the **important signals** of the components of the Kode Dot are connected to the **pins of the ESP32-S3,** there are some **less important signals** that do not fit.
The IO expander is a component that has **16 programmable pins** and to which the rest of the signals are connected that, or are of **low speed** or that **are not very relevant.**
## Connection diagram
The pins of the expander are controlled by the ESP32-S3 through the **I2C bus.** In addition, it has an **interrupt pin** that is connected to the ESP32-S3 to know when there has been a change in one of its pins.
The IO expander is connected to the ESP32-S3 in the following way:
| Expander | ESP32-S3 |
| --------- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| Interrupt | GPIO18 |
The expander has the address 0x20 on the I2C bus.
The signals of the different components of the Kode Dot that are connected to the expander are:
| Signal | Expander |
| ------------------------------ | -------- |
| Magnetometer - INT | EXP0 |
| RTC - INTB | EXP1 |
| RTC - INTA | EXP2 |
| Amplifier - SD | EXP3 |
| Power supply - 3V3 peripherals | EXP4 |
| Battery indicator - GPOUT | EXP5 |
| Pad - Up | EXP6 |
| Pad - Left | EXP7 |
| Pad - Down | EXP8 |
| Button - Down | EXP9 |
| PMIC - INT | EXP10 |
| Pad - Right | EXP11 |
| IMU - INT2 | EXP12 |
| IMU - INT1 | EXP13 |
| microSD - CD | EXP14 |
| Screen - TP INT | EXP15 |
Most of the signals are interrupt signals of the different integrated circuits or buttons and in the examples of the following sections it is implemented the reading of these signals.
## Recommended libraries
### Arduino
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
## Example code
With this code you can test the operation of the expander of pins. When you press the **down button,** a message will be printed on the **serial monitor.**
```cpp expander_test.ino lines icon="microchip" theme={null}
/**
* Reads and displays the status of signals connected to a TCA95XX_16BIT I/O expander via I2C.
* Configures pins as inputs or outputs and updates the reading every second.
* Shows each pin's name and state on the serial monitor.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Library to control I/O expanders on ESP32 */
#define I2C_SCL_PIN (47) /* I2C bus SCL pin */
#define I2C_SDA_PIN (48) /* I2C bus SDA pin */
#define I2C_ADDR (0x20) /* I2C address of the expander */
esp_expander::Base *expander = nullptr; /* Pointer to expander object */
/* Descriptive signal names */
const char* signalNames[14] = {
"Magnetometer - INT", // EXP0
"RTC - INTB", // EXP1
"RTC - INTA", // EXP2
"Battery Indicator - GPOUT", // EXP5
"Pad - Up", // EXP6
"Pad - Left", // EXP7
"Pad - Down", // EXP8
"Button - Down", // EXP9
"PMIC - INT", // EXP10
"Pad - Right", // EXP11
"IMU - INT2", // EXP12
"IMU - INT1", // EXP13
"microSD - CD", // EXP14
"Display - TP INT" // EXP15
};
void setup() {
Serial.begin(115200); /* Starts serial communication at 115200 baud */
Serial.println("Expander polling test start.");
/* Initializes the expander at the configured I2C address */
expander = new esp_expander::TCA95XX_16BIT(I2C_SCL_PIN, I2C_SDA_PIN, I2C_ADDR);
expander->init();
expander->begin();
/* Sets pins 3 and 4 as outputs */
expander->multiPinMode(IO_EXPANDER_PIN_NUM_3 | IO_EXPANDER_PIN_NUM_4, OUTPUT);
/* Sets all other pins as inputs */
expander->multiPinMode(IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_2 |
IO_EXPANDER_PIN_NUM_5 | IO_EXPANDER_PIN_NUM_6 | IO_EXPANDER_PIN_NUM_7 |
IO_EXPANDER_PIN_NUM_8 | IO_EXPANDER_PIN_NUM_9 | IO_EXPANDER_PIN_NUM_10 |
IO_EXPANDER_PIN_NUM_11 | IO_EXPANDER_PIN_NUM_12 | IO_EXPANDER_PIN_NUM_13 |
IO_EXPANDER_PIN_NUM_14 | IO_EXPANDER_PIN_NUM_15, INPUT);
/* Sets controlled outputs to LOW */
expander->digitalWrite(IO_EXPANDER_PIN_NUM_3, LOW); /* Amplifier - SD */
expander->digitalWrite(IO_EXPANDER_PIN_NUM_4, LOW); /* Power Supply - 3V3 peripherals */
}
int level[14] = {0}; /* Input states */
void loop() {
/* Reads the state of each input pin on the expander */
level[0] = expander->digitalRead(0);
level[1] = expander->digitalRead(1);
level[2] = expander->digitalRead(2);
level[3] = expander->digitalRead(5);
level[4] = expander->digitalRead(6);
level[5] = expander->digitalRead(7);
level[6] = expander->digitalRead(8);
level[7] = expander->digitalRead(9);
level[8] = expander->digitalRead(10);
level[9] = expander->digitalRead(11);
level[10] = expander->digitalRead(12);
level[11] = expander->digitalRead(13);
level[12] = expander->digitalRead(14);
level[13] = expander->digitalRead(15);
/* Displays the status of each signal on the serial monitor */
Serial.println("=== Pin Status ===");
for (int i = 0; i < 14; i++) {
Serial.printf("EXP%02d: %d - %s\n", i, level[i], signalNames[i]);
}
Serial.println();
delay(1000); /* Waits 1 second before the next read */
}
```
## Download of examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[IO expander examples](https://drive.google.com/drive/folders/1nJHAeJOtqmLtWnhrUvgWu9GuijLvPg9s)
# MicroSD
Source: https://docs.kode.diy/en/kode-dot/microsd
Discover the use of the microSD, its programming and why it is so important.
# Features
The microSD card is one of the **essential parts for the operation of the Kode Dot.** In it the applications, configuration data and user files are stored.
In addition, for **projects and applications** that are developed in kodeOS, it is the **easiest way to save the data that is generated.**
## Connection diagram
The microSD is connected to the ESP32-S3 via **SDIO, in 1-bit mode.** Thus, the **SD/MMC Host** peripheral that has the ESP32-S3 dedicated to read and write on the microSD is used.
The connection between the microSD and the ESP32-S3 is as follows:
| MicroSD | ESP32-S3 |
| ------------- | -------- |
| Command | GPIO5 |
| Clock | GPIO6 |
| Data | GPIO7 |
| Card Detected | EXP14 |
The Card Detected pin is connected to EXP14 of the IO expander. See [IO expander](/en/kode-dot/io-expander) for more information.
## Recommended libraries
### Arduino
* [SD\_MMC](https://github.com/espressif/arduino-esp32/tree/master/libraries/SD_MMC)
### ESP-IDF
* No requires additional libraries.
## Example code
This code will make a **test of the microSD in this order:**
1. List directories
2. Create a directory
3. List directories
4. Delete a directory
5. List directories
6. Write a file
7. Add a message to the end of a file
8. Read a file
9. Delete a file
10. Rename a file
11. Read a file
12. Test of reading and writing performance
```cpp microsd_test.ino lines icon="microchip" theme={null}
/**
* Manages an SD card in SD_MMC (1-bit) mode on ESP32-S3.
* Performs file operations (list, create, read, write, rename, delete) and measures performance.
* Uses custom pins and mounts the card at /sdcard.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "FS.h"
#include "SD_MMC.h"
/* Custom pins for SD_MMC (SD in 1-bit mode) */
int clk = 6; /* Clock pin (CLK) */
int cmd = 5; /* Command pin (CMD) */
int d0 = 7; /* Data0 pin (D0) */
/* Recursive function to list directories */
void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
Serial.printf("Listing directory: %s\n", dirname);
/* Open the directory */
File root = fs.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}
/* Iterate through files and subdirectories */
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
/* Recurse into subdirectories if levels > 0 */
if (levels) {
listDir(fs, file.path(), levels - 1);
}
} else {
/* It's a file: print name and size */
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
/* Function to create a directory */
void createDir(fs::FS &fs, const char *path) {
Serial.printf("Creating Dir: %s\n", path);
if (fs.mkdir(path)) {
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
/* Function to remove a directory */
void removeDir(fs::FS &fs, const char *path) {
Serial.printf("Removing Dir: %s\n", path);
if (fs.rmdir(path)) {
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
/* Function to read and display file contents */
void readFile(fs::FS &fs, const char *path) {
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
/* Read byte by byte and write to Serial */
while (file.available()) {
Serial.write(file.read());
}
}
/* Function to write a message to a file (overwrite) */
void writeFile(fs::FS &fs, const char *path, const char *message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
/* Write the message and check result */
if (file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
}
/* Function to append a message to a file */
void appendFile(fs::FS &fs, const char *path, const char *message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file) {
Serial.println("Failed to open file for appending");
return;
}
if (file.print(message)) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
}
/* Function to rename a file */
void renameFile(fs::FS &fs, const char *path1, const char *path2) {
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
/* Function to delete a file */
void deleteFile(fs::FS &fs, const char *path) {
Serial.printf("Deleting file: %s\n", path);
if (fs.remove(path)) {
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
/* File I/O performance test on a large file */
void testFileIO(fs::FS &fs, const char *path) {
File file = fs.open(path);
static uint8_t buf[512]; /* 512-byte buffer */
size_t len = 0;
uint32_t start = millis();
uint32_t elapsed;
if (file) {
/* Get file size */
len = file.size();
size_t originalLen = len;
start = millis();
/* Read file in chunks */
while (len) {
size_t toRead = (len > sizeof(buf)) ? sizeof(buf) : len;
file.read(buf, toRead);
len -= toRead;
}
elapsed = millis() - start;
Serial.printf("%u bytes read in %lu ms\n", originalLen, elapsed);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
/* Write performance measurement */
file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
start = millis();
/* Write 2048 blocks of 512 bytes (1 MiB) */
for (size_t i = 0; i < 2048; i++) {
file.write(buf, sizeof(buf));
}
elapsed = millis() - start;
Serial.printf("%u bytes written in %lu ms\n", 2048 * sizeof(buf), elapsed);
file.close();
}
void setup() {
Serial.begin(115200);
/* Assign custom pins for SD_MMC in 1-bit mode */
if (!SD_MMC.setPins(clk, cmd, d0)) {
Serial.println("Pin change failed!");
return;
}
/* Mount the SD card via SD_MMC (mount point and busWidth=1 for 1-bit) */
if (!SD_MMC.begin("/sdcard", 1)) {
Serial.println("Card Mount Failed");
return;
}
/* Check card type */
uint8_t cardType = SD_MMC.cardType();
if (cardType == CARD_NONE) {
Serial.println("No SD_MMC card attached");
return;
}
Serial.print("SD_MMC Card Type: ");
if (cardType == CARD_MMC) Serial.println("MMC");
else if (cardType == CARD_SD) Serial.println("SDSC");
else if (cardType == CARD_SDHC) Serial.println("SDHC");
else Serial.println("UNKNOWN");
/* Print card size in MB */
uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
/* Examples of file and directory operations */
listDir(SD_MMC, "/", 0);
createDir(SD_MMC, "/mydir");
listDir(SD_MMC, "/", 0);
removeDir(SD_MMC, "/mydir");
listDir(SD_MMC, "/", 2);
writeFile(SD_MMC, "/hello.txt", "Hello ");
appendFile(SD_MMC, "/hello.txt", "World!\n");
readFile(SD_MMC, "/hello.txt");
deleteFile(SD_MMC, "/foo.txt");
renameFile(SD_MMC, "/hello.txt", "/foo.txt");
readFile(SD_MMC, "/foo.txt");
testFileIO(SD_MMC, "/test.txt");
/* Print total and used space in MB */
Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));
}
void loop() {
/* Nothing to do in the main loop; brief delay to yield CPU */
delay(10);
}
```
## Download examples
You can test the example codes using the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[MicroSD examples](https://drive.google.com/drive/folders/1fMG1BzAr6a9Gi88daPVNe0bdkRSY8TKe)
# Power
Source: https://docs.kode.diy/en/kode-dot/power
The power system in electronics is the most important part because of the components that depend on it.
Read this section carefully to avoid damaging the Kode Dot.
## Features
The Kode Dot integrates a **complex and sophisticated power system, but at the same time robust, modular and easy to use.** It can be powered in three ways: from the 500mAh battery, from the USB-C or through the external connectors.
The system is formed by these components:
* Power Management Integrated Circuit (PMIC)
* Fuel Gauge
* 3V3 regulator for internal components
* 3V3 regulator for peripherals
* 3V3 regulator for the internal RTC of the ESP32-S3
### Power Management Integrated Circuit (PMIC)
The **central part of the power system is a PMIC** that is responsible for managing where the energy comes from, **whether from the battery, the USB-C or the external connectors.**
In addition, the PMIC is responsible for **the security and protection of the components**, ensuring protection against overcurrents, short circuits or overcurrents. In addition, it allows **to obtain data from the battery and the power supply.**
It also allows **to generate a 5V bus and up to 2A of current** that can be used to power external peripherals through the external connectors.
### Fuel Gauge
The fuel gauge is a component that **is responsible for measuring several battery data and giving us an analysis of its state.**
So we can know the following data from the battery:
* Remaining capacity
* Charge state
* Remaining usage time
* Battery voltage
* Battery temperature
* Health
* Output or input current
In addition, **it warns us about possible problems such as overcurrents, short circuits, overcurrents, etc.**
### 3V3 regulator for internal components
This is the **main voltage regulator of the Kode Dot** and supports up to **1A of current.** It is responsible for stabilizing the voltage to 3V3 and powering these components:
* ESP32-S3
* IO expander
* RTC
* Audio amplifier
* Microphone
* 6-axis IMU
* 3-axis magnetometer
So, when the Kode Dot enters **suspend mode**, this regulator is responsible for **maintaining the voltage on the ESP32-S3 and the internal components.**
### 3V3 regulator for peripherals
This regulator, which supports up to **2A of current**, can be **activated or deactivated** to power the following peripherals of the Kode Dot:
* Screen
* microSD
* 3V3 bus of the upper connector
When the Kode Dot is in **suspend mode**, this regulator is deactivated and disconnects the power to the peripherals.
### 3V3 regulator for the internal RTC of the ESP32-S3
This regulator is responsible for **powering the internal RTC of the ESP32-S3.**
## Connection diagram
### Power Management Integrated Circuit (PMIC)
The PMIC is connected to the I2C bus using these connections:
| PMIC | ESP32-S3 |
| ---- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INT | EXP10 |
The PMIC has the address 0x6B on the I2C bus.
The interrupt pin is connected to the [IO expander](/en/kode-dot/io-expander).
The **5V and 2A bus that the PMIC generates is connected to the upper connector and the back of the Kode Dot.** If the USB-C is connected, the power of the 5V bus comes from this. If not, the power of the 5V bus comes from the battery.
In addition, a **external 5V power supply** can be connected through one of the external connectors to charge the Kode Dot.
**Do not connect an external 5V power supply while the USB-C is connected.**
### Fuel Gauge
The fuel gauge is connected to the I2C bus using these connections:
| Fuel Gauge | ESP32-S3 |
| ---------- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| GPOUT | EXP5 |
The fuel gauge has the address 0x55 on the I2C bus.
The GPOUT pin is connected to the [IO expander](/en/kode-dot/io-expander).
### 3V3 regulator for peripherals
This regulator can be **activated or deactivated** to power the peripherals of the Kode Dot. By **default it is activated, to deactivate it set the following pin to LOW:**
| 3V3 regulator | ESP32-S3 |
| ------------- | -------- |
| EN | EXP4 |
The EN pin is connected to the [IO expander](/en/kode-dot/io-expander).
## Recommended libraries
### Arduino
#### Power Management Integrated Circuit (PMIC)
* [PMIC\_BQ25896](https://github.com/sqmsmu/PMIC_BQ25896)
#### Fuel Gauge
* [kode\_bq27220](https://github.com/kodediy/kode_bq27220)
### ESP-IDF
#### Power Management Integrated Circuit (PMIC)
* [kode\_bq25896](https://components.espressif.com/components/kodediy/kode_bq25896)
#### Fuel Gauge
* [kode\_bq27220](https://components.espressif.com/components/kodediy/kode_bq27220/versions/1.0.0)
## Example code
#### Power Management Integrated Circuit (PMIC)
With this code you can see the parameters that the PMIC returns from the battery and the power supply.
```cpp pmic_test.ino lines icon="microchip" theme={null}
/**
* Example usage of the PMIC BQ25896 on ESP32-S3 via I²C.
* Initializes the battery charger/power manager, displays system parameters,
* and updates readings and status every second.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "PMIC_BQ25896.h"
#include
/* I²C bus configuration: SDA, SCL pins */
#define I2C_SDA 48 /* SDA pin */
#define I2C_SCL 47 /* SCL pin */
/* BQ25896 driver instance */
PMIC_BQ25896 bq25896;
void setup() {
/* Initialize serial port for debugging */
Serial.begin(115200);
while (!Serial) {
/* Wait for serial connection */
}
/* Initialize I²C bus with specified pins */
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("BQ25896 Power Management and Battery Charger Example");
/* Initialize the BQ25896 over I²C */
bq25896.begin();
delay(500); /* Allow device to power up */
/* Check device connectivity */
if (!bq25896.isConnected()) {
Serial.println("BQ25896 not found! Check connection and power");
while (1) {
/* Halt execution if device is not found */
}
} else {
Serial.println("BQ25896 found successfully.");
}
}
void loop() {
Serial.println("BQ25896 System Parameters");
/* Input current limit pin status */
Serial.print("ILIM PIN : ");
Serial.println(String(bq25896.getILIM_reg().en_ilim));
/* System and charging parameters */
Serial.print("IINLIM : "); Serial.println(String(bq25896.getIINLIM()) + " mA");
Serial.print("VINDPM_OS : "); Serial.println(String(bq25896.getVINDPM_OS()) + " mV");
Serial.print("SYS_MIN : "); Serial.println(String(bq25896.getSYS_MIN()) + " mV");
Serial.print("ICHG : "); Serial.println(String(bq25896.getICHG()) + " mA");
Serial.print("IPRE : "); Serial.println(String(bq25896.getIPRECHG()) + " mA");
Serial.print("ITERM : "); Serial.println(String(bq25896.getITERM()) + " mA");
Serial.print("VREG : "); Serial.println(String(bq25896.getVREG()) + " mV");
Serial.print("BAT_COMP : "); Serial.println(String(bq25896.getBAT_COMP()) + " mΩ");
Serial.print("VCLAMP : "); Serial.println(String(bq25896.getVCLAMP()) + " mV");
Serial.print("BOOSTV : "); Serial.println(String(bq25896.getBOOSTV()) + " mV");
Serial.print("BOOST_LIM : "); Serial.println(String(bq25896.getBOOST_LIM()) + " mA");
Serial.print("VINDPM : "); Serial.println(String(bq25896.getVINDPM()) + " mV");
Serial.print("BATV : "); Serial.println(String(bq25896.getBATV()) + " mV");
Serial.print("SYSV : "); Serial.println(String(bq25896.getSYSV()) + " mV");
Serial.print("TSPCT : "); Serial.println(String(bq25896.getTSPCT()) + "%");
Serial.print("VBUSV : "); Serial.println(String(bq25896.getVBUSV()) + " mV");
Serial.print("ICHGR : "); Serial.println(String(bq25896.getICHGR()) + " mA");
/* Fault status */
Serial.print("Fault -> ");
Serial.print("NTC:" + String(bq25896.getFAULT_reg().ntc_fault));
Serial.print(" ,BAT:" + String(bq25896.getFAULT_reg().bat_fault));
Serial.print(" ,CHGR:" + String(bq25896.getFAULT_reg().chrg_fault));
Serial.print(" ,BOOST:" + String(bq25896.getFAULT_reg().boost_fault));
Serial.println(" ,WATCHDOG:" + String(bq25896.getFAULT_reg().watchdog_fault));
/* Charging status */
Serial.print("Charging Status -> ");
Serial.print("CHG_EN:" + String(bq25896.getSYS_CTRL_reg().chg_config));
Serial.print(" ,BATFET DIS:" + String(bq25896.getCTRL1_reg().batfet_dis));
Serial.print(" ,BATLOAD_EN:" + String(bq25896.getSYS_CTRL_reg().bat_loaden));
Serial.print(" ,PG STAT:" + String(bq25896.get_VBUS_STAT_reg().pg_stat));
Serial.print(" ,VBUS STAT:" + String(bq25896.get_VBUS_STAT_reg().vbus_stat));
Serial.print(" ,CHRG STAT:" + String(bq25896.get_VBUS_STAT_reg().chrg_stat));
Serial.println(",VSYS STAT:" + String(bq25896.get_VBUS_STAT_reg().vsys_stat));
/* Trigger a new ADC conversion */
bq25896.setCONV_START(true);
delay(1000); /* Update every second */
}
```
#### Fuel Gauge
With this code you can see the parameters that the fuel gauge returns from the battery.
```cpp bq27220_test.ino lines icon="microchip" theme={null}
/**
* Example usage of the Texas Instruments BQ27220 battery fuel gauge.
* Reads state of charge, voltage, current, and temperature over I²C.
* Displays charging status and estimated time to full when charging.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* I²C pin configuration for ESP32-S3 */
#define SDA_PIN 48 /* SDA line */
#define SCL_PIN 47 /* SCL line */
/* Battery fuel gauge driver instance */
BQ27220 gauge;
void setup() {
/* Initialize serial port for debug output */
Serial.begin(115200);
/* Start I²C bus with custom SDA/SCL pins */
Wire.begin(SDA_PIN, SCL_PIN);
/* Initialize the BQ27220 fuel gauge */
if (!gauge.begin()) {
Serial.println("BQ27220 not found!");
while (1) delay(1000); /* Halt execution if not found */
}
Serial.println("BQ27220 ready.");
}
void loop() {
/* Read battery parameters */
int soc = gauge.readStateOfChargePercent(); // State of charge (%)
int mv = gauge.readVoltageMillivolts(); // Voltage (mV)
int ma = gauge.readCurrentMilliamps(); // Current (mA), positive = charging
float tC = gauge.readTemperatureCelsius(); // Temperature (°C)
/* Print basic battery information */
Serial.print("SOC= "); Serial.print(soc); Serial.print("% ");
Serial.print("V= "); Serial.print(mv); Serial.print(" mV ");
Serial.print("I= "); Serial.print(ma); Serial.print(" mA ");
Serial.print("T= "); Serial.print(tC, 1); Serial.print(" °C");
/* If charging, show estimated time to full */
if (ma > 0) {
int ttf = gauge.readTimeToFullMinutes();
Serial.print(" TTF= "); Serial.print(ttf); Serial.print(" min");
}
Serial.println();
delay(1000); /* Update once per second */
}
```
## Download examples
You can test the example codes through the Arduino IDE or the ESP-IDF IDE or download the codes in our drive:
[Power codes](https://drive.google.com/drive/folders/1I5WI-snWixP8urmTfhuuEfvBaxEJhqmo)
# Quickstart
Source: https://docs.kode.diy/en/kode-dot/quickstart
Quick guide to understand the Kode Dot and start with the applications.
# What is the Kode Dot
The Kode Dot is the **best maker device on the market.** It is a **all-in-one, pocket-sized device with AI capabilities,** that allows you to learn to program electronics and embedded systems while **building and making your ideas a reality.**
It integrates the most advanced hardware and combines it with kodeOS, our open-source operating system, that allows you to **save your code in applications and share them with the community.**
The main technical features of the Kode Dot are:
| Feature | Description |
| --------------- | ----------------------------------------------- |
| Microcontroller | **ESP32-S3** - 32MB of flash and 8 MB of PSRAM |
| Screen | AMOLED 2.13" |
| Led | RGB Directional |
| Buttons | 4 buttons pad + 2 buttons |
| Audio | **Microphone and speaker** |
| Storage | microSD |
| IMU | **IMU** of 6 axes + **magnetometer** of 3 axes |
| Connectivity | WiFi - Bluetooth - ESP-NOW - **2.4GHz** |
| Connectors | **USB-C** - **Top 20 pins** - **Back magnetic** |
## What's in the box
When you buy the Kode Dot, you will receive:
* 1x **Kode Dot**
* 1x **charging and programming cable**
* 3x **stickers**
* 1x **quick start manual**
## How to turn on the Kode Dot
Just take the Kode Dot out of the box, **press the button on the bottom right for 2 seconds to turn it on.**
You don't have to worry about turning it off because it will automatically detect when you're not using it and enter **suspend mode.**
If you're not going to use your Kode Dot for a **long period of time**, you can press the button on the bottom right for **5 seconds** to turn it off completely.
## Launch your first application
Follow these steps to launch your first application:
Slide your finger **to the left** to enter the **applications menu.** Here, all the categories in which the applications are grouped will appear. Slide down and select the section of **"Games"**.
Here you will see all the applications in the section of "Games". Select the **application "Snake"** to launch it.
On this screen you will see the **title of the application and a small description.** Confirm that you want to launch the application by pressing **"YES".**
Your **Kode Dot will restart** and you can **start playing the famous Snake.**
To exit the application, press the button on the bottom right at the same time as the left pad.
## Create your first application
### Prepare the environment
Uploading your code and turning it into an application is very simple. Let's look at an example of how to do this with Arduino IDE.
Go to the following [link](https://www.arduino.cc/en/software/) and download and install the Arduino IDE.
Open Arduino IDE and in the *Board Manager* search for and install the **ESP32** boards.
Select the Kode Dot as the board in "Tools > Board > esp32 > Kode Dot".
### Upload your code and create the application
Copy this sample code into the Arduino IDE. This code prints information from the ESP32-S3 chip to the serial monitor every 3 seconds.
```cpp esp32s3_info.ino icon=microchip lines theme={null}
void setup() {
Serial.begin(115200); /* Start serial communication at 115200 baud */
}
void loop() {
/* Print model and revision of the ESP32 chip */
Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
/* Print the number of cores of the chip */
Serial.printf("This chip has %d cores\n", ESP.getChipCores());
/* Print the unique identifier of the chip */
Serial.print("Chip ID: ");
Serial.println(ESP.getEfuseMac());
/* Wait 3 seconds before repeating */
delay(3000);
}
```
Swipe your **finger to the right** on the Kode Dot to enter the **upload code menu.** When you connect your Kode Dot to your computer, it will appear in the **device list** in the Arduino IDE. Click the **Upload** button to upload the code.
Now in the **upload code menu of the Kode Dot**, you will see the option to **execute the code you just uploaded or create an application.** Select the option of **"Create App"** and save it in the category of **"General"**.
Go to the applications menu, enter the category of **"General"** and you will see your **newly created application** ready to be launched.
# Real Time Clock
Source: https://docs.kode.diy/en/kode-dot/rtc
Take control of time in your projects with the RTCs of your Kode Dot.
# Features
The Kode Dot integrates **two real time clocks**, the internal one of the ESP32-S3 and one external.
## Connection diagram
The internal ESP32-S3 clock can be used directly using the **Espressif documentation.**
The external clock is connected to the I2C of the ESP32-S3 using these connections:
| External RTC | ESP32-S3 |
| ------------ | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INTA | EXP2 |
| INTB | EXP1 |
The external clock has the address 0xD0 on the I2C bus.
The interrupt pins are connected to the [IO expander](/en/kode-dot/io-expander).
## Recommended libraries
### Arduino
* [kode\_MAX31329](https://github.com/kodediy/kode_MAX31329)
### ESP-IDF
* TBD
## Example code
This code configures the RTC with a specific date and time and then prints the current time every second.
```cpp rtc_test.ino lines icon="microchip" theme={null}
/**
* Demo básico de tiempo con RTC MAX31329: establece una hora inicial y lee/muestra la hora continuamente.
* Utiliza API fluida (rtc.t.year = 2024) para configurar la hora fácilmente en ESP32-S3.
* Imprime la hora formateada cada segundo en el monitor serie.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include "Wire.h"
MAX31329 rtc;
/* Función auxiliar para leer y mostrar la hora actual desde el RTC */
static void printTime()
{
/* Leer hora del RTC en la estructura rtc.t */
if (!rtc.readTime()) {
Serial.println("Error al leer la hora (readTime failed)");
return;
}
/* Formatear e imprimir la hora como YYYY-MM-DD HH:MM:SS */
Serial.printf("%04d-%02d-%02d %02d:%02d:%02d\n",
rtc.t.year, rtc.t.month, rtc.t.day,
rtc.t.hour, rtc.t.minute, rtc.t.second);
}
void setup()
{
Serial.begin(115200);
Serial.println("Ejemplo de hora con MAX31329");
Wire.begin(48,47);
/* Inicializar el RTC */
rtc.begin();
/* Establecer la hora inicial con la API fluida - 24 de noviembre de 2024 15:10:00 */
rtc.t.year = 2024;
rtc.t.month = 11;
rtc.t.day = 24;
rtc.t.hour = 15;
rtc.t.minute = 10;
rtc.t.second = 0;
rtc.t.dayOfWeek = 0; /* 0=Domingo, 1=Lunes, ..., 6=Sábado */
/* Escribir la hora configurada en el hardware del RTC */
if (!rtc.writeTime()) {
Serial.println("Error al escribir la hora (writeTime failed)");
}
}
void loop()
{
delay(1000); /* Esperar 1 segundo entre lecturas */
printTime(); /* Mostrar hora actual */
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos del RTC](https://drive.google.com/drive/folders/1EHoXhwTg31xQmAzV5kKiH4j0Wmi5bjY9)
# Applications
Source: https://docs.kode.diy/en/kodeOS/apps
Understand how applications work and how you can create yours.
# Applications of the Kode Dot
Open source communities are based on **sharing knowledge and resources.** That's why the main feature of the Kode Dot is that your **codes become applications** so you can **share them with other people and show your work.**
In addition, you can also **use applications created by other people and experiment with them.**
## How it works
If **no code is uploaded to the flash**, you will see the following screen:
When you program the code of your project in your favorite IDE, you can **upload it to your Kode Dot** as you do on any other platform.
Once uploaded, on the screen of your Kode Dot you will see two options, **run the code directly or transform the code into an application and save it on your Kode Dot.**
### Run
Depending on whether the **maker mode is activated or not**, the code you upload will run automatically or not.
If the maker mode is activated, you will see a **pop-up with a countdown of 3 seconds until the code runs.** You can **cancel the countdown and cancel the execution.**
If the maker mode is deactivated, the code **will not run automatically** and you can run it whenever you want by pressing the run button.
### Create an application
When you have the code validated and working, you can press the **create application** button. You can choose **if you want to change the name and select in which category you want to save it.**
## Application menu
By entering the **application menu, you will see all the available categories.** Although you can create your own categories, by default there are these:
* General
* Hacking
* GPIO
* USB
* Games
In each of them, you will see that there are already applications uploaded so you can **test them.**
## Add applications from other people
All **applications** of your Kode Dot are **stored on the microSD.** That's why, to add applications from other people, connect the **microSD to your computer** and copy the applications in the **category folder you want.**
In the future, you will be able to share applications between Kode Dots wirelessly or download them directly from the store.
# Firmware
Source: https://docs.kode.diy/en/kodeOS/firmware
Discover kodeOS and how you can update or repair it.
# kodeOS
kodeOS is the operating system that runs on a **partition of the flash** of your Kode Dot.
If for some reason **you erase the flash or program a code on top of the kodeOS partition**, you can reinstall it through the **kode desktop application.**
## Recover kodeOS
Open the application and connect the Kode Dot via USB cable. In the Serial Port section, you should see the port to which it is connected.
Download the kodeOS file in the downloads folder and select it in the program.
Press the Load button and wait for the load to complete. In the terminal you will see the load process and when it is finished you will see a pop-up with the message that it has been loaded correctly.
# Hammy
Source: https://docs.kode.diy/en/kodeOS/hammy
Meet Hammy, your learning companion that will accompany you on your journey.
# Meet Hammy
Hammy is your **learning companion.** As you use your Kode Dot, Hammy will **learn and evolve.**
In addition, he will give you **tips and suggestions of applications that you may be interested in programming.**
## Play with him and take care of him
If you give him a **touch on the head, you can start playing with him.** Don't forget to feed him and take care of him so he doesn't get upset and can continue evolving.
## Customize Hammy
Each person has a Hammy with a **unique name.** In addition, as each one uses their Kode Dot differently, you can **personalize their appearance and add accessories.**
## Add friends
When you are near another person with a Kode Dot, you will receive a notification that you can add them as a friend. Thus, your Hammies can **meet, share accessories and play together.**
## Talk to him
Soon you will be able to talk to him and ask him to help you program.
# Historial de cambios
Source: https://docs.kode.diy/es/changelog
Noticias y actualizaciones del equipo de kode.
* Presentamos la versión v1.0 de kode docs tanto en inglés como en español.
# Camera
Source: https://docs.kode.diy/es/external-modules/camera
Dale visión a tu Kode Dot con el módulo Camera
**Módulo:** Standard
# Características
Con este módulo puedes desde **aprender a capturar imágenes hasta grabar vídeo.** Integra una cámara con un sensor OV5640 con una resolución de 5MP.
## Conexión con el Kode Dot
## Esquema de conexión
La cámara está conectada al ESP32-S3 de la siguiente manera:
| Cámara | ESP32-S3 |
| ------ | -------- |
| nRESET | GPIO44 |
| SCL | GPIO47 |
| SDA | GPIO48 |
| PCLK | GPIO13 |
| HREF | GPIO43 |
| VSYNC | GPIO42 |
| D2 | GPIO12 |
| D3 | GPIO11 |
| D4 | GPIO1 |
| D5 | GPIO2 |
| D6 | GPIO3 |
| D7 | GPIO39 |
| D8 | GPIO40 |
| D9 | GPIO41 |
## Ejemplo de código
Para probar la cámara vamos a usar el ejemplo que incorpora **Espressif en Arduino IDE**. Puedes abrirlo en File > Examples > ESP32 > Camera > CameraWebServer.
Este ejemplo te permite configurar la cámara y ver en tiempo real lo que está capturando a través de una página web.
Cambia todo el código del CameraWebServer.ino por el siguiente y cambia las credenciales de la red WiFi por las tuyas:
```cpp CameraWebServer.ino lines icon="microchip" theme={null}
/**
* Ejemplo de servidor de cámara web con ESP32-S3 + módulo de cámara.
* Configura la cámara, se conecta a la red WiFi y sirve un stream MJPEG.
* URL de acceso: http:// tras la conexión.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "esp_camera.h"
#include
/* ===========================
Credenciales WiFi
=========================== */
const char *ssid = "**********"; /* Nombre de la red WiFi */
const char *password = "**********"; /* Contraseña de la red WiFi */
/* Declaración de funciones externas (implementadas en otros archivos) */
void startCameraServer();
void setupLedFlash();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
/* ─── Configuración de pines y parámetros de la cámara ─── */
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = 12;
config.pin_d1 = 11;
config.pin_d2 = 1;
config.pin_d3 = 2;
config.pin_d4 = 3;
config.pin_d5 = 39;
config.pin_d6 = 40;
config.pin_d7 = 41;
config.pin_xclk = -1;
config.pin_pclk = 13;
config.pin_vsync = 42;
config.pin_href = 43;
config.pin_sccb_sda = 48;
config.pin_sccb_scl = 47;
config.pin_pwdn = -1;
config.pin_reset = 44;
config.xclk_freq_hz = 20000000; /* Frecuencia XCLK */
config.frame_size = FRAMESIZE_UXGA; /* Resolución inicial */
config.pixel_format = PIXFORMAT_JPEG; /* Formato para streaming */
//config.pixel_format = PIXFORMAT_RGB565; // Opción para detección facial
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12; /* Calidad JPEG (menor número = mejor calidad) */
config.fb_count = 1;
/* Ajustar configuración si hay PSRAM disponible */
if (config.pixel_format == PIXFORMAT_JPEG) {
if (psramFound()) {
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
/* Si no hay PSRAM, reducir resolución para no agotar RAM */
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
/* Ajuste para detección/ reconocimiento facial */
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
/* ─── Inicialización de la cámara ─── */
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Error al iniciar la cámara: 0x%x", err);
return;
}
/* Obtener acceso al sensor para ajustes adicionales */
sensor_t *s = esp_camera_sensor_get();
/* Reducir tamaño de frame para aumentar la velocidad inicial */
if (config.pixel_format == PIXFORMAT_JPEG) {
s->set_framesize(s, FRAMESIZE_QVGA);
}
/* Voltear imagen verticalmente */
s->set_vflip(s, 1);
/* ─── Conexión WiFi ─── */
WiFi.begin(ssid, password);
WiFi.setSleep(false); /* Evitar suspensión de WiFi */
Serial.print("Conectando a WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi conectado");
/* ─── Iniciar servidor de cámara ─── */
startCameraServer();
Serial.print("Cámara lista. Accede a: http://");
Serial.println(WiFi.localIP());
}
void loop() {
/* El servidor web gestiona el streaming; bucle vacío */
delay(10000);
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de código del módulo Camera](https://drive.google.com/drive/folders/1wom3hU-bjWmbpT9DnZFzFtpL3cr-7Qzg)
# Inventor
Source: https://docs.kode.diy/es/external-modules/inventor
Conecta motores DC, un servomotor y sensores para crear tu propio robot.
**Módulo:** Basic
# Características
Con este módulo puedes conectar **motores a tu Kode Dot y hacer robots, como por ejemplo un coche siguelineas.**
Puedes conectar lo siguiente:
* 2x motores DC o 1x motor paso a paso
* 1x servomotor
* 4x GPIOs para sensores
* 1x bus de I2C
No es necesario usar una fuente externa de alimentación ya que **todo se alimenta desde el Kode Dot.**
Los **motores DC tienen que ser de 5V y están limitados por hardware a una corriente máxima de 700mA por motor.** Así, como el Kode Dot puede suministrar hasta 2A, quedan **600mA para conectar un servomotor.**
Los **motores DC se controlan por PWM** y se puede medir la corriente que esta consumiendo cada motor para tener una estimación de su torque.
## Conexión con el Kode Dot
## Esquema de conexión
El driver que controla los motores está conectado de la siguiente manera:
| Driver | ESP32-S3 |
| ------- | -------- |
| AIN1 | GPIO42 |
| AIN2 | GPIO41 |
| BIN1 | GPIO40 |
| BIN2 | GPIO39 |
| nFAULT | GPIO38 |
| AIPROPI | GPIO37 |
| BIPROPI | GPIO36 |
AIPROPI y BIPROPI sirven para medir la corriente que está consumiendo cada motor. Para más información consulta el datasheet del driver.
## Ejemplo de código
Conecta **dos motores DC a los conectores** y con este código verás como primero aceleran, luego mantienen la velocidad máxima y finalmente desaceleran.
```cpp motors_test.ino lines icon="microchip" theme={null}
/**
* DRV8411A + 2x DC + Servo + Lectura de corriente por IPROPI (ESP32-S3).
* Muestra en Serial Plotter: IA(A) \t IB(A) \t ITRIP(A) mientras ejecuta secuencias de ambos motores y un servo.
* Fórmulas IPROPI (datasheet): IPROPI(µA) = I_LS_total(A) * 200 µA/A; V_IPROPI = IPROPI * R_IPROPI;
* I_motor = V_IPROPI / (R_IPROPI * 200e-6); I_TRIP = VREF / (R_IPROPI * 200e-6).
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Pines DRV8411A */
constexpr int PIN_AIN1 = 42;
constexpr int PIN_AIN2 = 41;
constexpr int PIN_BIN1 = 39;
constexpr int PIN_BIN2 = 40;
constexpr int PIN_nFAULT = 3;
/* IPROPI -> ADC (canal A y canal B) */
constexpr int PIN_AIPROPI = 2; /* Entrada ADC para A-IPROPI */
constexpr int PIN_BIPROPI = 1; /* Entrada ADC para B-IPROPI */
/* Servo */
constexpr int PIN_SERVO = 13;
Servo servo;
/* Configuración del servo (microsegundos y ángulos) */
constexpr int SERVO_MIN_US = 500;
constexpr int SERVO_MAX_US = 2500;
constexpr int SERVO_CENTER = 90;
constexpr int SERVO_LEFT = 0;
constexpr int SERVO_RIGHT = 180;
/* Funciones auxiliares DRV8411A */
inline void motorA_coast() { digitalWrite(PIN_AIN1, LOW); digitalWrite(PIN_AIN2, LOW); } /* Alta impedancia en ambas entradas */
inline void motorA_brake() { digitalWrite(PIN_AIN1, HIGH); digitalWrite(PIN_AIN2, HIGH); } /* Freno por decaimiento rápido */
inline void motorA_fwd() { digitalWrite(PIN_AIN1, HIGH); digitalWrite(PIN_AIN2, LOW); } /* Motor A adelante */
inline void motorA_rev() { digitalWrite(PIN_AIN1, LOW); digitalWrite(PIN_AIN2, HIGH); } /* Motor A atrás */
inline void motorB_coast() { digitalWrite(PIN_BIN1, LOW); digitalWrite(PIN_BIN2, LOW); } /* Alta impedancia en ambas entradas */
inline void motorB_brake() { digitalWrite(PIN_BIN1, HIGH); digitalWrite(PIN_BIN2, HIGH); } /* Freno por decaimiento rápido */
inline void motorB_fwd() { digitalWrite(PIN_BIN1, HIGH); digitalWrite(PIN_BIN2, LOW); } /* Motor B adelante */
inline void motorB_rev() { digitalWrite(PIN_BIN1, LOW); digitalWrite(PIN_BIN2, HIGH); } /* Motor B atrás */
/* Tiempos */
constexpr uint32_t T_MOTOR_DIR = 2000; /* 2 s por sentido */
constexpr uint32_t T_SERVO_TRAMO = 1000; /* 1 s por tramo */
/* Parámetros IPROPI (ajustar R al valor real usado) */
constexpr float VREF_V = 3.3f; /* VREF (V) */
constexpr float RIPROPI_OHMS = 23700.0f; /* Cambiar a 10000.0f si se usa 10 kΩ */
constexpr float AIPROPI_GAIN = 200e-6f; /* 200 µA/A (ganancia IPROPI) */
/* Configuración del ADC */
constexpr int ADC_BITS = 12; /* Resolución ADC */
constexpr float ADC_VFULL = 3.3f; /* Con atenuación 11 dB, ~3.3 V de escala completa */
/* Máquinas de estado concurrentes */
enum class Phase { FWD, REV, DONE };
struct MotorSeq {
bool enabled=false; Phase phase=Phase::FWD; uint32_t tEnd=0;
void start() { enabled=true; phase=Phase::FWD; tEnd=millis()+T_MOTOR_DIR; }
};
struct ServoSeq {
bool enabled=false; int step=0; uint32_t tEnd=0;
void start() { enabled=true; step=0; servo.write(SERVO_RIGHT); tEnd=millis()+T_SERVO_TRAMO; }
};
MotorSeq seqA, seqB; ServoSeq seqS;
/* ADC -> voltios */
float adcVolts(int pin) {
uint16_t raw = analogRead(pin);
return (raw * ADC_VFULL) / ((1 << ADC_BITS) - 1);
}
/* Voltios IPROPI -> corriente del motor (A) */
float ipropiToCurrentA(float v_ipropi) {
return v_ipropi / (RIPROPI_OHMS * AIPROPI_GAIN);
}
/* Muestreo periódico para Serial Plotter: IA, IB e ITRIP */
void sampleAndPrintCurrents() {
float vA = adcVolts(PIN_AIPROPI);
float vB = adcVolts(PIN_BIPROPI);
float iA = ipropiToCurrentA(vA);
float iB = ipropiToCurrentA(vB);
float iTRIP = VREF_V / (RIPROPI_OHMS * AIPROPI_GAIN); /* Umbral de sobrecorriente (A) */
/* Columnas separadas por tabuladores para Arduino Serial Plotter */
Serial.print(iA, 4); Serial.print('\t');
Serial.print(iB, 4); Serial.print('\t');
Serial.println(iTRIP, 4);
}
/* Espera activa con muestreo periódico (~cada 20 ms) */
void waitWithSampling(uint32_t ms) {
uint32_t t0 = millis(), tNext = 0;
while ((uint32_t)(millis() - t0) < ms) {
uint32_t now = millis();
if ((int32_t)(now - tNext) >= 0) {
sampleAndPrintCurrents();
tNext = now + 20;
}
delay(1); /* Breve espera para ceder CPU */
}
}
/* Verifica si /nFAULT está en bajo durante la sección indicada */
void checkFault(const char* tag) {
if (digitalRead(PIN_nFAULT) == LOW) {
Serial.print("[nFAULT] Falla detectada durante ");
Serial.println(tag);
}
}
void setup() {
Serial.begin(115200);
delay(100);
pinMode(PIN_AIN1, OUTPUT);
pinMode(PIN_AIN2, OUTPUT);
pinMode(PIN_BIN1, OUTPUT);
pinMode(PIN_BIN2, OUTPUT);
pinMode(PIN_nFAULT, INPUT_PULLUP);
motorA_coast();
motorB_coast();
/* ADC: 11 dB para abarcar hasta ~3.3 V y resolución de 12 bits */
analogReadResolution(ADC_BITS);
analogSetAttenuation(ADC_11db);
/* Cabecera opcional para Serial Plotter */
Serial.println("IA(A)\tIB(A)\tITRIP(A)");
/* Configuración del servo (50 Hz, limitado a los pulsos definidos) */
servo.setPeriodHertz(50);
servo.attach(PIN_SERVO, SERVO_MIN_US, SERVO_MAX_US);
servo.write(SERVO_CENTER);
/* 1) Motor A adelante y atrás con muestreo */
motorA_fwd(); waitWithSampling(T_MOTOR_DIR);
motorA_rev(); waitWithSampling(T_MOTOR_DIR);
motorA_brake(); delay(100); motorA_coast();
checkFault("Secuencia 1 (Motor A)");
/* 2) Motor B adelante y atrás con muestreo */
motorB_fwd(); waitWithSampling(T_MOTOR_DIR);
motorB_rev(); waitWithSampling(T_MOTOR_DIR);
motorB_brake(); delay(100); motorB_coast();
checkFault("Secuencia 2 (Motor B)");
/* 3) Barrido del servo: +90°, -90° (1 s cada tramo) */
servo.write(SERVO_RIGHT); waitWithSampling(T_SERVO_TRAMO);
servo.write(SERVO_LEFT); waitWithSampling(T_SERVO_TRAMO);
servo.write(SERVO_CENTER);
/* 4) Ejecución concurrente */
seqA.start(); seqB.start(); seqS.start();
}
void loop() {
/* Muestreo continuo para el Plotter (~50 Hz) */
static uint32_t tNext = 0;
uint32_t now = millis();
if ((int32_t)(now - tNext) >= 0) {
sampleAndPrintCurrents();
tNext = now + 20;
}
/* Secuencia concurrente Motor A */
if (seqA.enabled) {
if (seqA.phase == Phase::FWD) {
motorA_fwd();
if ((int32_t)(now - seqA.tEnd) >= 0) {
seqA.phase = Phase::REV;
seqA.tEnd = now + T_MOTOR_DIR;
}
} else if (seqA.phase == Phase::REV) {
motorA_rev();
if ((int32_t)(now - seqA.tEnd) >= 0) {
seqA.phase = Phase::DONE; motorA_brake(); delay(50); motorA_coast();
}
}
}
/* Secuencia concurrente Motor B */
if (seqB.enabled) {
if (seqB.phase == Phase::FWD) {
motorB_fwd();
if ((int32_t)(now - seqB.tEnd) >= 0) {
seqB.phase = Phase::REV;
seqB.tEnd = now + T_MOTOR_DIR;
}
} else if (seqB.phase == Phase::REV) {
motorB_rev();
if ((int32_t)(now - seqB.tEnd) >= 0) {
seqB.phase = Phase::DONE; motorB_brake(); delay(50); motorB_coast();
}
}
}
/* Secuencia concurrente Servo (DERECHA -> IZQUIERDA -> CENTRO) */
if (seqS.enabled) {
if (seqS.step == 0) {
if ((int32_t)(now - seqS.tEnd) >= 0) {
servo.write(SERVO_LEFT);
seqS.step = 1; seqS.tEnd = now + T_SERVO_TRAMO;
}
} else if (seqS.step == 1) {
if ((int32_t)(now - seqS.tEnd) >= 0) {
servo.write(SERVO_CENTER);
seqS.step = 2;
}
}
}
/* Condición de fin: ambos motores terminados y servo centrado */
if (seqA.phase == Phase::DONE && seqB.phase == Phase::DONE && seqS.step == 2) {
checkFault("Secuencia 4 (concurrente)");
seqA.enabled = seqB.enabled = false; seqS.enabled = false;
motorA_coast(); motorB_coast();
while (true) { delay(1000); } /* Mantener aquí tras finalizar */
}
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de código del módulo Inventor](https://drive.google.com/drive/folders/1wom3hU-bjWmbpT9DnZFzFtpL3cr-7Qzg)
# Maker
Source: https://docs.kode.diy/es/external-modules/maker
Crea circuitos personalizados, prototipa tus ideas y programa con los GPIOs.
**Módulo:** Basic
# Características
Con este módulo puedes **crear circuitos y prototipar tus ideas usando la breadboard integrada** y usar los pines disponibles del Kode Dot.
Además, tienes disponible los dos buses de alimentación del Kode Dot: 5V y 3.3V, con una corriente máxima de 2A.
## Conexión con el Kode Dot
## Pines disponibles
Puedes usar los siguientes pines:
| Pin | Descripción |
| ------ | ------------------------------- |
| GPIO1 | RTC\_GPIO1, ADC1\_CH0, TOUCH1 |
| GPIO2 | RTC\_GPIO2, ADC1\_CH1, TOUCH2 |
| GPIO3 | RTC\_GPIO3, ADC1\_CH2, TOUCH3 |
| GPIO11 | RTC\_GPIO11, ADC2\_CH0, TOUCH11 |
| GPIO12 | RTC\_GPIO12, ADC2\_CH1, TOUCH12 |
| GPIO13 | RTC\_GPIO13, ADC2\_CH2, TOUCH13 |
| SCL | GPIO47 |
| SDA | GPIO46 |
| U0TXD | GPIO43 |
| U0RXD | GPIO44 |
| GPIO39 | JTAG-MTCK |
| GPIO40 | JTAG-MTCDO |
| GPIO41 | JTAG-MTCDI |
| GPIO42 | JTAG-MTMS |
Los pines SCL y SDA son del bus I2C del Kode Dot, **solo se pueden usar para conectar otros componentes al bus I2C.**
# Radio
Source: https://docs.kode.diy/es/external-modules/radio
Comunicate con LoRa y ubícate con GNSS
**Módulo:** Pro
# Características
Con este módulo puedes desde **comunicarte con LoRa hasta ubicarte con GNSS.** Integra un módulo LoRa E80-900M2213S (LR1121) de Ebyte y un módulo GNSS MAX-M10S de U-Blox.
Estamos trabajando en la integración con **Meshtastic**.
## Conexión con el Kode Dot
## Esquema de conexión
### Módulo LoRa
El módulo Ebyte E80-900M2213S está conectado al ESP32-S3 de la siguiente manera:
| E80-900M2213S | ESP32-S3 |
| ------------- | -------- |
| MISO | GPIO41 |
| MOSI | GPIO40 |
| SCK | GPIO39 |
| NSS (CS) | GPIO3 |
| BUSY | GPIO13 |
| LR\_NRESET | GPIO2 |
| DIO9 | GPIO12 |
| DIO8 | GPIO1 |
| DIO7 | GPIO11 |
### Módulo GNSS
El módulo GNSS MAX-M10S está conectado al ESP32-S3 de la siguiente manera:
| MAX-M10S | ESP32-S3 |
| -------- | -------- |
| TXD | GPIO44 |
| RXD | GPIO43 |
| SCL | GPIO47 |
| SDA | GPIO48 |
## Ejemplos de código
### Comunicación con LoRa
Para usar el módulo LoRa, recomendamos usar la librería [RadioLib](https://github.com/jgromes/RadioLib)
Este código es un ejemplo de cómo usar el módulo LoRa para escanear las bandas de 868 MHz y 2.4 GHz.
```cpp lora_test.ino lines icon="microchip" theme={null}
/**
* Escáner de canales LR1121 (solo RX, sin TX).
* Barre las bandas de 868 MHz y 2.4 GHz cambiando BW y SF dinámicamente.
* Mide el RSSI (ruido de canal) y muestra los resultados en formato CSV.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Configuración de pines (según tu diseño) */
#define NSS_PIN 3 /* Chip Select */
#define DIO1_PIN 12 /* IRQ */
#define NRST_PIN 2 /* Reset */
#define BUSY_PIN 13 /* Busy */
#define MISO_PIN 41
#define MOSI_PIN 40
#define SCK_PIN 39
/* Mapeo del RF Switch para E80-900M2213S */
static const uint32_t rfswitch_dio_pins[] = {
RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6,
RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC
};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{ LR11x0::MODE_STBY, { LOW, LOW } },
{ LR11x0::MODE_RX, { LOW, LOW } }, /* RX */
{ LR11x0::MODE_TX, { LOW, HIGH } }, /* TX Sub-1GHz LP */
{ LR11x0::MODE_TX_HP, { HIGH, LOW } }, /* TX Sub-1GHz HP */
{ LR11x0::MODE_TX_HF, { HIGH, HIGH } }, /* TX 2.4GHz */
{ LR11x0::MODE_GNSS, { LOW, LOW } },
{ LR11x0::MODE_WIFI, { LOW, LOW } },
END_OF_MODE_TABLE,
};
/* Instancias */
SPIClass spi(HSPI);
LR1121 radio = new Module(NSS_PIN, DIO1_PIN, NRST_PIN, BUSY_PIN, spi);
/* Configuración de barrido de frecuencias */
const float FREQS_868[] = { 863.0, 866.0, 868.0, 869.5 };
const float FREQS_24[] = { 2403.5, 2425.0, 2450.0, 2479.5 };
const size_t N_868 = sizeof(FREQS_868) / sizeof(FREQS_868[0]);
const size_t N_24 = sizeof(FREQS_24) / sizeof(FREQS_24[0]);
/* Parámetros dinámicos */
const float BWS_KHZ[] = { 125.0, 203.125 };
const int SFS[] = { 7, 9, 12 };
const int CR = 5;
const int PWR_DBM = 10;
const uint8_t PREAMBLE = 8;
const float TCXO_V = 1.8;
/* Tiempo de escucha por punto de medida */
const uint16_t DWELL_MS = 200;
/* Funciones auxiliares */
/* Reset físico del LR1121 */
static void hardResetModule() {
pinMode(NRST_PIN, OUTPUT);
digitalWrite(NRST_PIN, LOW);
delay(50);
digitalWrite(NRST_PIN, HIGH);
delay(50);
}
/* Configura el LR1121 con los parámetros indicados */
static bool configRadio(float freqMHz, float bwkHz, int sf) {
int st = radio.begin(freqMHz, bwkHz, sf, CR, 0x12 /*sync*/, PWR_DBM, PREAMBLE, TCXO_V);
if (st != RADIOLIB_ERR_NONE) {
Serial.print("Fallo de configuración f="); Serial.print(freqMHz, 3);
Serial.print(" MHz BW="); Serial.print(bwkHz, 3);
Serial.print(" kHz SF="); Serial.print(sf);
Serial.print(" código="); Serial.println(st);
return false;
}
return true;
}
/* Mide una vez el RSSI con los parámetros indicados y muestra línea CSV */
static void measureOnce(float freqMHz, float bwkHz, int sf, const char* bandTag) {
if (!configRadio(freqMHz, bwkHz, sf)) return;
/* Iniciar recepción */
int st = radio.startReceive();
if (st != RADIOLIB_ERR_NONE) {
Serial.print("Fallo al iniciar RX, código="); Serial.println(st);
return;
}
delay(DWELL_MS);
float rssi = radio.getRSSI();
/* Salida en formato CSV: BANDA,FREQ_MHz,BW_kHz,SF,RSSI_dBm */
Serial.print(bandTag); Serial.print(",");
Serial.print(freqMHz, 3); Serial.print(",");
Serial.print(bwkHz, 3); Serial.print(",");
Serial.print(sf); Serial.print(",");
Serial.println(rssi, 1);
radio.standby();
}
/* Escanea toda una banda de frecuencias variando BW y SF */
static void scanBand(const float* freqs, size_t nFreq, const char* bandTag) {
Serial.println();
Serial.println("BANDA,FREQ_MHz,BW_kHz,SF,RSSI_dBm");
for (size_t i = 0; i < nFreq; i++) {
for (size_t b = 0; b < sizeof(BWS_KHZ)/sizeof(BWS_KHZ[0]); b++) {
for (size_t s = 0; s < sizeof(SFS)/sizeof(SFS[0]); s++) {
measureOnce(freqs[i], BWS_KHZ[b], SFS[s], bandTag);
}
}
}
}
/* Setup */
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); }
Serial.println("\n=== Escáner de canales LR1121 (solo RSSI) ===");
Serial.println("RSSI = ruido de canal (más cerca de 0 => más ruido)");
pinMode(BUSY_PIN, INPUT);
Serial.println("Reseteando módulo...");
hardResetModule();
Serial.println("Inicializando SPI...");
spi.begin(SCK_PIN, MISO_PIN, MOSI_PIN, NSS_PIN);
radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
Serial.println("\n--- Escaneo: 868 MHz ---");
scanBand(FREQS_868, N_868, "868MHz");
Serial.println("\n--- Escaneo: 2.4 GHz ---");
scanBand(FREQS_24, N_24, "2400MHz");
Serial.println("\nFin del escaneo. Reinicia para repetir.");
}
/* Loop */
void loop() {
delay(1000);
}
```
### Ubicación con GNSS
Para usar el módulo GNSS, recomendamos usar la librería [SparkFun u-blox GNSS](https://github.com/sparkfun/SparkFun_u-blox_GNSS_v3)
#### Uso por I2C
Este código es un ejemplo de cómo usar el módulo GNSS por I2C.
```cpp gnss_test_I2C.ino lines icon="microchip" theme={null}
/**
* Ejemplo: Lectura de datos GNSS (GPS) desde un Módulo de Radio Kode vía I2C.
* Obtiene latitud, longitud y altitud del módulo u-blox.
* Utiliza el mensaje PVT (Posición, Velocidad, Tiempo) para la lectura de datos.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Objeto del módulo GNSS */
SFE_UBLOX_GNSS myGNSS;
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println("Ejemplo de Módulo de Radio Kode");
/* ─── Inicializar I2C con SDA = GPIO48, SCL = GPIO47 ─── */
Wire.begin(48, 47);
/* Habilitar mensajes de depuración GNSS por Serial (opcional) */
myGNSS.enableDebugging(); // Comenta esta línea para desactivar mensajes de depuración
/* Intentar conectar con el módulo GNSS u-blox hasta que tenga éxito */
while (myGNSS.begin() == false)
{
Serial.println(F("u-blox GNSS no detectado. Reintentando..."));
delay(1000);
}
/* Configurar salida I2C en protocolo UBX únicamente (desactiva mensajes NMEA) */
myGNSS.setI2COutput(COM_TYPE_UBX);
}
void loop()
{
/* Si hay datos PVT disponibles, leerlos y mostrarlos */
if (myGNSS.getPVT() == true)
{
/* Obtener e imprimir latitud */
int32_t latitude = myGNSS.getLatitude();
Serial.print(F("Lat: "));
Serial.print(latitude);
/* Obtener e imprimir longitud */
int32_t longitude = myGNSS.getLongitude();
Serial.print(F(" Long: "));
Serial.print(longitude);
Serial.print(F(" (grados * 10^-7)"));
/* Obtener e imprimir altitud (MSL) */
int32_t altitude = myGNSS.getAltitudeMSL();
Serial.print(F(" Alt: "));
Serial.print(altitude);
Serial.print(F(" (mm)"));
Serial.println();
}
}
```
#### Uso por UART
Este código es un ejemplo de cómo usar el módulo GNSS por UART.
```cpp gnss_test_UART.ino lines icon="microchip" theme={null}
#include
/* Objeto GNSS para comunicación vía puerto serie */
SFE_UBLOX_GNSS_SERIAL myGNSS;
/* ─── Mapeo de pines para UART GNSS ───
* GNSS_RX_PIN → pin del MCU que recibe datos desde TX del GNSS
* GNSS_TX_PIN → pin del MCU que envía datos hacia RX del GNSS
*/
static const int GNSS_RX_PIN = 44; // MCU recibe por GPIO44
static const int GNSS_TX_PIN = 43; // MCU transmite por GPIO43
/* Instancia de puerto serie hardware (UART1) */
HardwareSerial GNSSSerial(1);
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println("u-blox GNSS vía UART1 (GPIO44/43)");
/* ─── Inicializar UART1 en los pines indicados ───
* Velocidad: 38400 baudios
* Formato: 8 bits, sin paridad, 1 bit de stop (SERIAL_8N1)
*/
GNSSSerial.begin(38400, SERIAL_8N1, GNSS_RX_PIN, GNSS_TX_PIN);
/* Activar mensajes de depuración en el puerto serie principal (opcional) */
myGNSS.enableDebugging(Serial);
/* Configurar salida de datos por UART1 → Solo protocolo UBX, sin NMEA */
myGNSS.setUART1Output(COM_TYPE_UBX);
/* Intentar conectar con el módulo GNSS hasta que responda */
while (!myGNSS.begin(GNSSSerial)) {
Serial.println(F("u-blox GNSS no detectado. Reintentando..."));
delay(1000);
}
}
void loop()
{
/* Si hay datos PVT (Posición, Velocidad, Tiempo) disponibles, mostrarlos */
if (myGNSS.getPVT()) {
int32_t lat = myGNSS.getLatitude(); // Latitud en grados * 10^-7
int32_t lon = myGNSS.getLongitude(); // Longitud en grados * 10^-7
int32_t alt = myGNSS.getAltitudeMSL(); // Altitud MSL en milímetros
Serial.print(F("Lat: ")); Serial.print(lat);
Serial.print(F(" Long: ")); Serial.print(lon);
Serial.print(F(" (deg*1e-7) Alt: ")); Serial.print(alt);
Serial.println(F(" (mm)"));
}
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de código del módulo Inventor](https://drive.google.com/drive/folders/1wom3hU-bjWmbpT9DnZFzFtpL3cr-7Qzg)
# Preguntas frecuentes
Source: https://docs.kode.diy/es/faq
Preguntas frecuentes sobre kode, el Kode Dot y kodeOS.
## kode.
kode es tu **comunidad de código abierto** para aprender, construir y crear tus ideas.
Los pilares de la comunidad son la **pasión por la tecnología, el aprendizaje práctico y la colaboración.**
La comunidad de kode está en **constante crecimiento** y nos reunimos en [Discord](TBD). Entrar y participar en la comunidad es **totalmente gratuito.**
## Kode Dot
El Kode Dot es un dispositivo **todo en uno, de tamaño de bolsillo y con capacidad de IA,** diseñado para facilitar el **aprendizaje y prototipado** de la electrónica y los sistemas embebidos.
Integra todo el **hardware necesario para crear tus proyectos** y está impulsado por **kodeOS**, nuestro sistema operativo de código abierto, que te permite **guardar en aplicaciones tus códigos y compartirlos con la comunidad.**
Estámos preparando la venta del Kode Dot en **Kickstarter**. Preparate para comprar el tuyo el **1 de septiembre.**
Conecta el Kode Dot a tu ordenador y programa el código con tu **IDE favorito**, como si fuera cualquiera otra placa. Automáticamente **kodeOS** te dará la posibilidad de **correr el código o crear una aplicación.**
## kodeOS
**kodeOS es el sistema operativo del Kode Dot.** Es totalmente gratuito y de código abierto y te permite guardar en aplicaciones tus códigos y compartirlos con la comunidad.
Además, puedes **subir a tu Kode Dot aplicaciones creadas por la comunidad** para ampliar sus funcionalidades.
**¡Si! kodeOS viene programado en el Kode Dot**, por lo que nada más sacarlo de la caja ya podrás usar las aplicaciones que trae por defecto.
Si borras kodeOS, puedes recuperarlo volviéndolo a programar con la **aplicación de escritorio de kode.**
## Módulos Externos
Actualmente, en kode hemos desarrollado **cuatro módulos externos** para hacer uso del conector superior de **20 pines del Kode Dot.** Todos usan un conector de pines macho de **2x10 con una separación de 2.54mm.**
Si, el Kode Dot está diseñado para que puedas **crear tus propios módulos externos de forma sencilla.** Actualmente tenemos una plantilla desarrollada para **KiCAD** con el conector y las dimensiones correctas.
Mediante el conector trasero magnético se puede cargar el Kode Dot y usar el bus de i2c. En un futuro cobrará sentido.
{/* TBD, en el futuro contar un poco sobre nosotros, el equipo y la filosofía de kode. */}
# Bienvenido
Source: https://docs.kode.diy/es/introduction
kode es tu comunidad de código abierto para aprender, construir y crear tus ideas.
# ¿Qué quieres aprender hoy?
Descubre las características de tu Kode Dot y cómo puedes usarlo para hacer realidad tus ideas con nuestras guías, documentación, ejemplos y más.
Aprende a cómo usar tu Kode Dot, configurarlo y correr tu primera aplicación.
Descubre el microprocesador de tu Kode Dot, sus características y cómo esta integrado.
Explora el uso del expansor de pines, el integrado que añade pines programables a tu Kode Dot.
Aprende a usar la pantalla, sus características y cómo puedes usarla para crear increibles interfaces.
Dale luz a tus proyectos con el led direccionable RGB. Conoce sus características y cómo puedes usarlo.
Entiende la distribución de los botones y cómo puedes usarlos para crear tus aplicaciones.
Descubre el uso de la microSD, su programación y porqué es un componente clave en tu Kode Dot.
Añade audio a tus proyectos y crea aplicaciones con AI que interactúen con tu voz.
Aprende para qué sirve una IMU y cómo detectar la posición y los movimientos de tu Kode Dot.
Lleva el control del tiempo en tus aplicaciones haciendo uso de los dos RTCs de tu Kode Dot.
Descubre cómo funciona el sistema de alimentación y cómo conocer parámetros de la batería.
Amplia las capacidades de tu Kode Dot, para que el único límite sea tu imaginación.
Conoce a Hammy, tu compañero de aprendizaje que evolucionará a medida que vayas programando.
Entiende funcionan las aplicaciones y cómo puedes crear las tuyas o usar las de otras personas.
Descubre kodeOS, el sistema operativo de tu Kode Dot y cómo puedes actualizarlo.
Crea circuitos personalizados, prototipa tus ideas usando la breadboard y programa los GPIOs externos.
Conecta motores DC, un servomotor y sensores para crear y programar tus propios robots.
Próximamente.
Próximamente.
# LED direccionable
Source: https://docs.kode.diy/es/kode-dot/addresable-led
Conoce cómo funciona el led direccionable y dale luz a tus proyectos.
# Características
El Kode Dot integra un **led direccionable** arriba a la izquierda del pad, que podrás iluminar con el **color y brillo que quieras.**
No es un led RGB normal, sino que es un **led RGB direccionable WS2812B.** Esto significa que dentro del led hay un **pequeño integrado** que puede manejar independientemente el color de los leds RGB y el brillo de cada uno.
| Característica | Descripción |
| -------------- | ---------------- |
| Driver | WS2812B - 1-Wire |
| Tamaño | 2mm x 2mm |
| Color | RGB |
## Esquema de conexión
El led direccionable funciona mediante un sólo pin conectado al ESP32-S3.
| WS2812B | ESP32-S3 |
| ------- | -------- |
| Data | GPIO4 |
1-Wire es un protocolo de comunicación que permite la comunicación de datos por medio de un único pin.
## Librerías recomendadas
### Arduino
* [Adafruit\_NeoPixel](https://github.com/adafruit/Adafruit_NeoPixel)
* [FastLED](https://github.com/FastLED/FastLED)
### ESP-IDF
* [led\_indicator](https://components.espressif.com/components/espressif/led_indicator)
* [led\_strip](https://components.espressif.com/components/espressif/led_strip)
## Ejemplo de código
Este código ilumina el led direccionable haciendo un ciclo de colores: primero rojo, luego verde y por último azul.
```cpp rgb_cycle.ino lines icon="microchip" theme={null}
/**
* Controla un único NeoPixel conectado al GPIO 4, encendiéndolo en rojo, verde y azul.
* Cada color se mantiene encendido durante medio segundo y se apaga entre cambios.
* Usa la librería Adafruit_NeoPixel para el control de LEDs RGB.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Librería para controlar tiras y LEDs NeoPixel */
#define NEOPIXEL_PIN 4 /* Pin GPIO donde está conectado el NeoPixel */
#define NUMPIXELS 1 /* Número de NeoPixels conectados */
#define PIXEL_FORMAT (NEO_GRB + NEO_KHZ800) /* Formato de color y velocidad de datos */
Adafruit_NeoPixel *pixels; /* Puntero al objeto NeoPixel */
#define DELAYVAL 500 /* Tiempo de espera entre cambios (ms) */
void setup() {
Serial.begin(115200); /* Inicia la comunicación serie para depuración */
/* Crea el objeto NeoPixel con los parámetros definidos */
pixels = new Adafruit_NeoPixel(NUMPIXELS, NEOPIXEL_PIN, PIXEL_FORMAT);
pixels->begin(); /* Inicializa el NeoPixel */
pixels->clear(); /* Asegura que el LED empiece apagado */
pixels->show(); /* Aplica el cambio */
}
void loop() {
/* Enciende en rojo */
pixels->setPixelColor(0, pixels->Color(150, 0, 0));
pixels->show();
delay(DELAYVAL);
/* Apaga */
pixels->setPixelColor(0, pixels->Color(0, 0, 0));
pixels->show();
delay(DELAYVAL);
/* Enciende en verde */
pixels->setPixelColor(0, pixels->Color(0, 150, 0));
pixels->show();
delay(DELAYVAL);
/* Apaga */
pixels->setPixelColor(0, pixels->Color(0, 0, 0));
pixels->show();
delay(DELAYVAL);
/* Enciende en azul */
pixels->setPixelColor(0, pixels->Color(0, 0, 150));
pixels->show();
delay(DELAYVAL);
/* Apaga */
pixels->setPixelColor(0, pixels->Color(0, 0, 0));
pixels->show();
delay(DELAYVAL);
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos del led direccionable](https://drive.google.com/drive/folders/1f7pmw24Q7ikkvg6vVaRGUN63GGYj1NbC)
# Micrófono
Source: https://docs.kode.diy/es/kode-dot/audio/microphone
# Características
El Kode Dot integra un **micrófono MEMS digital.** Este tipo de micrófonos son muy comunes en dispositivos electrónicos modernos y dan una gran fiabilidad ya que **no dependen de ninguna parte analógica.**
## Esquema de conexión
El micrófono está conectado al ESP32-S3 de la siguiente manera:
| Micrófono | ESP32-S3 |
| --------- | -------- |
| SCK | GPIO38 |
| WS | GPIO45 |
| DIN | GPIO21 |
## Librerías recomendadas
### Arduino
* [ESP\_I2S](https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP_I2S)
### ESP-IDF
* [ESP-ADF](https://github.com/espressif/esp-adf)
El uso de ESP-ADF es para usuarios avanzados. Si no tienes experiencia en este framework, te recomendamos usar la librería de Arduino.
## Ejemplo de código
Este código **graba 5 segundos de audio** y lo guarda en la microSD en formato WAV.
```cpp record_to_microsd.ino lines icon="microchip" theme={null}
/**
* Graba 5 segundos de audio por I2S (48 kHz, 32-bit, mono) y los guarda en /sdcard/test.wav.
* Usa el bus I2S del ESP32-S3 y una microSD en modo SD_MMC de 1 bit con pines personalizados.
* Muestra por Serial el estado de inicialización, grabación y escritura en la tarjeta.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "ESP_I2S.h"
#include "FS.h"
#include "SD_MMC.h"
/* Asignación de pines I2S */
const uint8_t I2S_SCK = 38; /* Pin de reloj serie (SCK) */
const uint8_t I2S_WS = 45; /* Pin de selección de palabra (LRCLK) */
const uint8_t I2S_DIN = 21; /* Pin de entrada de datos (SD) */
/* Pines de la tarjeta SD para SD_MMC en modo 1 bit */
const uint8_t SD_CMD = 5; /* Pin de comando (CMD) */
const uint8_t SD_CLK = 6; /* Pin de reloj (CLK) */
const uint8_t SD_DATA0 = 7; /* Pin de datos 0 (D0) */
/* Instancia de la interfaz I2S */
I2SClass i2s;
/* Variables para almacenar el WAV y su tamaño */
uint8_t *wav_buffer;
size_t wav_size;
void setup() {
/* Inicializa el puerto serie para depuración */
Serial.begin(115200);
Serial.println("Starting setup...");
/* Configura los pines I2S (MCLK no usado: pasar -1) */
i2s.setPins(I2S_SCK, I2S_WS, -1, I2S_DIN);
/* Inicializa I2S en modo estándar: 48 kHz, 32 bits, mono, slot alineado a izquierda */
Serial.println("Initializing I2S bus...");
if (!i2s.begin(
I2S_MODE_STD,
48000,
I2S_DATA_BIT_WIDTH_32BIT,
I2S_SLOT_MODE_MONO,
I2S_STD_SLOT_LEFT)) {
Serial.println("Failed to initialize I2S bus!");
return;
}
Serial.println("I2S bus initialized.");
/* Configura los pines de SD_MMC para modo 1 bit */
Serial.println("Configuring SD card pins...");
if (!SD_MMC.setPins(SD_CLK, SD_CMD, SD_DATA0)) {
Serial.println("Failed to configure SD pins!");
return;
}
/* Monta la tarjeta SD en "/sdcard" */
Serial.println("Mounting SD card...");
if (!SD_MMC.begin("/sdcard", true)) { /* true => bus de 1 bit */
Serial.println("Failed to initialize SD card!");
return;
}
Serial.println("SD card mounted successfully.");
/* Aviso de inicio de grabación */
Serial.println("Recording 5 seconds of audio...");
/* Graba 5 s de audio WAV en wav_buffer */
wav_buffer = i2s.recordWAV(5, &wav_size);
/* Abre el archivo de salida en la SD */
File file = SD_MMC.open("/test.wav", FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing!");
return;
}
/* Escribe los datos grabados y verifica escritura completa */
Serial.println("Writing audio data to file...");
if (file.write(wav_buffer, wav_size) != wav_size) {
Serial.println("Failed to write audio data to file!");
file.close();
return;
}
/* Cierra el archivo al terminar */
file.close();
Serial.println("Audio recording and save complete.");
}
void loop() {
delay(10000);
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de audio](https://drive.google.com/drive/folders/1rJPxfOXun4p1ijXyRdREydyOMEUJju0u)
# Resumen
Source: https://docs.kode.diy/es/kode-dot/audio/overview
Entiende cómo funciona el audio en el Kode Dot y qué es el bus I2S
# Qué es el bus I2S
**Inter-IC Sound (I2S)** es un protocolo de comunicación digital diseñado específicamente para **transmitir audio entre dispositivos electrónicos.**
A diferencia de otros buses como I2C, que se usan para transmitir datos generales entre chips, I2S está **optimizado para enviar datos de audio de alta calidad en tiempo real.**
## ¿Cómo funciona I2S?
El bus I2S utiliza varias líneas para transmitir la información:
* **Serial Data (SD):** Por donde viajan los datos de audio.
* **Serial Clock (SCK):** Marca el ritmo al que se envían los bits.
* **Word Select (WS):** Indica si los datos corresponden al canal izquierdo o derecho (en audio estéreo).
Las **líneas de SCK y WS son comunes** a todos los dispositivos que se conecten al bus I2S. Sin embargo, tanto el altavoz como el micrófono tienen sus **propias líneas de SD.**
Esta estructura permite que el audio se transmita de forma **sincronizada y sin pérdidas, ideal para aplicaciones donde la calidad de sonido es importante.**
## ¿Por qué usar I2S para audio digital?
* **Calidad:** Permite transmitir audio digital sin interferencias ni ruidos típicos de las señales analógicas.
* **Sincronización:** Garantiza que los datos lleguen en el momento correcto, evitando desfases o distorsiones.
* **Compatibilidad:** Es el estándar en la mayoría de chips de audio modernos, facilitando la integración de micrófonos y altavoces digitales.
En el Kode Dot, tanto el **micrófono como el altavoz están conectados mediante I2S,** lo que permite grabar y reproducir sonido con gran fidelidad y eficiencia.
# Altavoz
Source: https://docs.kode.diy/es/kode-dot/audio/speaker
# Características
El Kode Dot integra un **altavoz de 1W conectado a un amplificador.** Así, solo te tienes que preocupar de darle sonido a tus proyectos a través del bus I2S y el amplificador se encargará de hacer todo el trabajo.
## Esquema de conexión
El altavoz está conectado al ESP32-S3 de la siguiente manera:
| Micrófono | ESP32-S3 |
| --------- | -------- |
| SCK | GPIO38 |
| WS | GPIO45 |
| DOUT | GPIO46 |
| SD | EXP3 |
El amplificador por defecto está apagado para no gastar energía. Para encenderlo, pon el pin EXP3 del [expansor de pines](/es/kode-dot/io-expander) en HIGH.
## Librerías recomendadas
### Arduino
* [ESP\_I2S](https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP_I2S)
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [ESP-ADF](https://github.com/espressif/esp-adf)
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
El uso de ESP-ADF es para usuarios avanzados. Si no tienes experiencia en este framework, te recomendamos usar la librería de Arduino.
## Ejemplo de código
Este código **reproduce el tono que especifiques en la variable `frequency`.**
```cpp speaker_tone.ino lines icon="microchip" theme={null}
/**
* Genera un tono cuadrado por I2S (48 kHz, 32-bit, mono) y habilita el amplificador vía expansor I/O.
* El tono se guarda en flujo I2S continuo; el expansor activa la etapa de audio.
* Usa pines personalizados para I2S y para el expansor TCA95XX_16BIT.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Configuración de pines del expansor */
#define I2C_SCL_PIN (47)
#define I2C_SDA_PIN (48)
#define I2C_ADDR (0x20)
/* Pines de la interfaz I2S */
const uint8_t I2S_SCK = 38; // Reloj serie (SCK)
const uint8_t I2S_WS = 45; // Word Select / LRCLK
const uint8_t I2S_DOUT = 46; // Salida de datos (SD)
/* Parámetros de la señal de audio */
const int frequency = 300; // Frecuencia de la onda cuadrada en Hz
const int amplitude = 500; // Amplitud de la onda cuadrada
/* Variables de estado para generación de señal */
int32_t sample = amplitude; // Muestra actual
int count = 0; // Contador de muestras
/* Instancias globales */
I2SClass i2s; // Objeto interfaz I2S
esp_expander::Base *expander = nullptr; // Puntero al expansor
void setup() {
Serial.begin(115200);
Serial.println("Simple I2S tone");
/* Configura los pines de I2S (sin MCLK: pasar -1) */
i2s.setPins(I2S_SCK, I2S_WS, I2S_DOUT, -1);
/* Inicializa I2S: modo estándar, 48 kHz, 32 bits, mono, ranura izquierda */
if (!i2s.begin(I2S_MODE_STD, 48000, I2S_DATA_BIT_WIDTH_32BIT,
I2S_SLOT_MODE_MONO, I2S_STD_SLOT_LEFT)) {
Serial.println("Failed to initialize I2S!");
while (1); // Detener en caso de fallo
}
Serial.println("I2S bus initialized.");
/* Inicializa el expansor de E/S */
expander = new esp_expander::TCA95XX_16BIT(I2C_SCL_PIN, I2C_SDA_PIN, I2C_ADDR);
expander->init();
expander->begin();
/* Configura el pin 3 del expansor como salida para habilitar el amplificador */
expander->pinMode(3, OUTPUT);
expander->digitalWrite(3, HIGH); /* Habilita el amplificador */
}
void loop() {
/* Conmuta el signo cada media longitud de onda para crear una cuadrada */
if (count % (48000 / frequency) == 0) {
sample = -sample;
}
/* Escribe la muestra (mono) */
i2s.write(sample); // Canal izquierdo
/* Incrementa el contador de muestras */
count++;
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de audio](https://drive.google.com/drive/folders/1rJPxfOXun4p1ijXyRdREydyOMEUJju0u)
# Botones
Source: https://docs.kode.diy/es/kode-dot/buttons
Entiende la distribución de los botones y cómo usarlos en tus proyectos.
# Características
Los botones del Kode Dot se distribuyen entre un **pad direccional de cuatro botones y dos botones independientes.**
Con estos botones se puede navegar por kodeOS, controlar el estado del ESP32-S3 y apagar o encender el dispositivo.
## Esquema de conexión
Todos los botones están conectados al **expansor de pines**, exceptuando el **botón de arriba** que está conectado directamente al ESP32-S3. Además, todos tienen conectada una **resistencia de pull-up física.**
La conexión de los botones es la siguiente:
| Botón | Expansor de pines |
| ------------- | ----------------- |
| Pad Izquierdo | EXP7 |
| Pad Arriba | EXP6 |
| Pad Derecha | EXP11 |
| Pad Abajo | EXP8 |
| Botón Arriba | GPIO0 |
| Botón Abajo | EXP9 |
Ve a [Expansor de pines](/es/kode-dot/io-expander) para conocer cómo funciona el expansor de pines.
El botón de arriba está conectado al pin GPIO0, para controlar el estado BOOT del ESP32-S3.
## Librerías recomendadas
### Arduino
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [button](https://components.espressif.com/components/espressif/button)
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
## Ejemplo de código
Con este código puedes comprobar el **funcionamiento de los botones.** Conecta el Kode Dot al **monitor serie** y según qué botón pulses, verás un mensaje en el monitor.
```cpp buttons_check.ino lines icon="microchip" theme={null}
/**
* Detecta pulsaciones de botones conectados a un expansor I/O TCA95XX_16BIT y a un pin directo del ESP32-S3.
* Usa interrupciones para responder a eventos de pulsación sin necesidad de sondeo constante.
* Muestra en el monitor serie el botón detectado.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Librería para controlar expansores de I/O en ESP32 */
/* Configuración del expansor */
#define CHIP_NAME TCA95XX_16BIT
#define I2C_SCL_PIN (47) /* Pin SCL del bus I2C */
#define I2C_SDA_PIN (48) /* Pin SDA del bus I2C */
#define EXP_INT_PIN (18) /* Pin de interrupción del expansor */
#define I2C_ADDR (0x20)/* Dirección I2C del expansor */
/* Conexiones de botones en el expansor */
#define PAD_UP 6
#define PAD_LEFT 7
#define PAD_DOWN 8
#define PAD_RIGHT 11
#define BUTTON_BOTTOM 9
/* Botón conectado directamente al ESP32-S3 */
#define BUTTON_UP_PIN 0 /* GPIO0 */
/* Instancia del expansor */
esp_expander::Base *expander = nullptr;
/* Banderas para interrupciones pendientes */
volatile bool expanderInterrupted = false;
volatile bool buttonUpInterrupted = false;
/* ISR para interrupción del expansor */
void IRAM_ATTR handleExpanderIRQ() {
expanderInterrupted = true;
}
/* ISR para el botón en GPIO0 */
void IRAM_ATTR handleButtonUpIRQ() {
buttonUpInterrupted = true;
}
void setup() {
Serial.begin(115200);
Serial.println("Button interrupt test start");
/* Inicializa el expansor */
expander = new esp_expander::TCA95XX_16BIT(I2C_SCL_PIN, I2C_SDA_PIN, I2C_ADDR);
expander->init();
expander->begin();
/* Configura pines del expansor como entradas */
expander->pinMode(PAD_UP, INPUT);
expander->pinMode(PAD_LEFT, INPUT);
expander->pinMode(PAD_DOWN, INPUT);
expander->pinMode(PAD_RIGHT, INPUT);
expander->pinMode(BUTTON_BOTTOM, INPUT);
/* Configura pin de interrupción del expansor */
pinMode(EXP_INT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(EXP_INT_PIN),
handleExpanderIRQ, FALLING);
/* Configura botón directo en GPIO0 */
pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_UP_PIN),
handleButtonUpIRQ, FALLING);
Serial.println("Setup complete. Waiting for button presses...");
}
void loop() {
/* Si no hay interrupciones pendientes, espera */
if (!expanderInterrupted && !buttonUpInterrupted) {
delay(10);
return;
}
/* Gestiona botón directo */
if (buttonUpInterrupted) {
buttonUpInterrupted = false;
Serial.println("→ BUTTON_UP (GPIO0) pressed");
delay(50);
}
/* Gestiona botones del expansor */
if (expanderInterrupted) {
expanderInterrupted = false;
if (expander->digitalRead(PAD_UP) == LOW) {
Serial.println("→ PAD_UP pressed");
}
if (expander->digitalRead(PAD_LEFT) == LOW) {
Serial.println("→ PAD_LEFT pressed");
}
if (expander->digitalRead(PAD_DOWN) == LOW) {
Serial.println("→ PAD_DOWN pressed");
}
if (expander->digitalRead(BUTTON_BOTTOM) == LOW) {
Serial.println("→ BUTTON_BOTTOM pressed");
}
if (expander->digitalRead(PAD_RIGHT) == LOW) {
Serial.println("→ PAD_RIGHT pressed");
}
delay(50);
}
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos usando los botones](https://drive.google.com/drive/folders/1-K3qP_pf7niBGDafzZQtoZ7c4Zyx9w1W)
# Conectores
Source: https://docs.kode.diy/es/kode-dot/connectors
Amplia las capacidades de tu Kode Dot para que el límite sea tu imaginación.
# Características
El Kode Dot tiene dos conectores, uno **20 pines en la parte superior** y otro **magnético de 4 pines en la parte posterior.**
## Conector superior de 20 pines
## Conector magnético trasero
# Pantalla
Source: https://docs.kode.diy/es/kode-dot/display
Aprende a programarla y a crear increibles interfaces con LVGL.
# Características
El Kode Dot tiene la **mejor pantalla en un dispositivo maker del mercado.** Se trata de una **pantalla táctil AMOLED de 2.13 pulgadas** con las siguientes características:
| Característica | Descripción |
| -------------------- | ---------------- |
| Tamaño | 2.13 pulgadas |
| Resolución | 410x502 píxeles |
| Profundidad de color | 16 bits (RGB565) |
| Driver | CO5300 - QSPI |
| Driver táctil | CST820 - I2C |
La pantalla es totalmente programable con **librerías de Arduino y ESP-IDF ya existentes** y compatible con **LVGL.**
## Esquema de conexión
### Driver de la pantalla
El driver de la pantalla es el **CO5300** y funciona usando bus **QuadSPI.** Este driver está conectado al ESP32-S3 de la siguiente manera:
| CO5300 | ESP32-S3 |
| ----------- | -------- |
| Chip Select | GPIO9 |
| Clock | GPIO17 |
| Data 0 | GPIO15 |
| Data 1 | GPIO14 |
| Data 2 | GPIO16 |
| Data 3 | GPIO10 |
| Reset | GPIO8 |
El bus QuadSPI es de la misma familia que el bus SPI, pero tiene el doble de ancho de banda.
### Driver del táctil
El driver del táctil es el **CST820** y funciona mediante **I2C.** Este driver está conectado al ESP32-S3 de la siguiente manera:
| CST820 | ESP32-S3 |
| --------- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| Interrupt | EXP15 |
| Reset | GPIO8 |
El driver del táctil tiene la dirección 0x15 en el bus I2C.
El pin de Interrupt está conectado al EXP15 del expansor de pines. Ve a [Expansor de pines](/es/kode-dot/io-expander) para más información.
Tanto el reset del driver del táctil como el de la pantalla están conectados al mismo pin del ESP32-S3.
## Librerías recomendadas
### Arduino
* [Arduino\_GFX](https://github.com/moononournation/Arduino_GFX)
* [bb\_captouch](https://github.com/bitbank2/bb_captouch)
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [esp\_lcd\_co5300](https://components.espressif.com/components/kodediy/esp_lcd_co5300)
* [esp\_lcd\_touch\_cst820](https://components.espressif.com/components/kodediy/esp_lcd_touch_cst820)
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
## Ejemplos de código
### Ejemplo básico
Este es el código más básico para probar la pantalla, únicamente imprime un **¡Hola mundo!** en la pantalla.
```cpp display_test.ino lines icon="microchip" theme={null}
/**
* Demo simple de pantalla con Arduino_GFX: inicializa el panel y dibuja “Hello World!”.
* Usa bus QSPI del ESP32-S3 con resolución 410x502 y brillo al máximo.
* Muestra texto grande centrado aproximadamente sobre un fondo azul.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#define DSP_HOR_RES 410
#define DSP_VER_RES 502
#define DSP_SCLK 17
#define DSP_SDIO0 15
#define DSP_SDIO1 14
#define DSP_SDIO2 16
#define DSP_SDIO3 10
#define DSP_RST 8
#define DSP_CS 9
/* Objetos para manejar el bus gráfico y la pantalla */
static Arduino_DataBus *gfxBus;
static Arduino_CO5300 *gfx;
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("Simple Display Demo");
/* ─── Configuración de la pantalla ───
Bus QSPI: CS, SCLK, D0, D1, D2, D3 */
gfxBus = new Arduino_ESP32QSPI(DSP_CS, DSP_SCLK, DSP_SDIO0, DSP_SDIO1, DSP_SDIO2, DSP_SDIO3);
/* Constructor del panel: bus, RST, rotation offset (0), x/y offset (0,0),
ancho/alto, pin de backlight (22), opciones (0,0,0) */
gfx = new Arduino_CO5300(gfxBus, DSP_RST, 0, 0, DSP_HOR_RES, DSP_VER_RES, 22, 0, 0, 0);
if (!gfx->begin()) {
Serial.println("Error: no se pudo iniciar el display");
while (true) /* bucle infinito si falla */ ;
}
gfx->setRotation(0);
gfx->setBrightness(255);
gfx->displayOn();
Serial.println("Pantalla inicializada");
/* Print Hello World! */
gfx->fillScreen(BLUE);
gfx->setTextSize(4);
gfx->setTextColor(ORANGE);
gfx->setCursor(65, 250);
gfx->print("Hello World!");
}
void loop() {
delay(1000);
}
```
### Ejemplo con LVGL
Este código implementa **LVGL 9.3** y te permite probar la pantalla **imprimiendo un texto, usando un ejemplo o usando una demo.** Por defecto se usa la **demo de musica de LVGL.**
```cpp lvgl_test.ino lines icon="microchip" theme={null}
/**
* Ejemplo de uso de LVGL con Arduino en Kode Dot.
* Configura la pantalla, el táctil y dibuja una etiqueta simple.
* Más info: https://docs.lvgl.io/master/integration/framework/arduino.html
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
#include
#include
/*Para usar los ejemplos y demos de LVGL descomenta los includes de abajo respectivamente.
*También necesitas copiar lvgl/examples a lvgl/src/examples. De la misma manera para las demos lvgl/demos a lvgl/src/demos.
*Ten en cuenta que la librería lv_examples es para LVGL v7 y no deberías instalarla para esta versión (ya que LVGL v8)
*ya que los ejemplos y demos ahora forman parte de la librería principal de LVGL. */
// #include
// #include
/* Resolución y rotación de la pantalla */
#define DSP_HOR_RES 410
#define DSP_VER_RES 502
#define DSP_ROTATION LV_DISPLAY_ROTATION_0
/* Tamaño del buffer de dibujo de LVGL */
#define DRAW_BUF_SIZE (DSP_HOR_RES * DSP_VER_RES / 10 * (LV_COLOR_DEPTH / 8))
static uint8_t *lv_buf1;
static uint8_t *lv_buf2;
/* Objetos para manejar el bus gráfico y la pantalla */
static Arduino_DataBus *gfxBus;
static Arduino_CO5300 *gfx;
static BBCapTouch touch;
/* Función de callback para que LVGL dibuje en la pantalla */
void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
uint32_t w = lv_area_get_width(area);
uint32_t h = lv_area_get_height(area);
gfx->startWrite();
gfx->writeAddrWindow(area->x1, area->y1, w, h);
gfx->writePixels((uint16_t *)px_map, w * h);
gfx->endWrite();
/* Avisar a LVGL que se ha terminado de refrescar */
lv_display_flush_ready(disp);
}
/* Lectura del panel táctil */
void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) {
TOUCHINFO ti;
if (touch.getSamples(&ti) && ti.count > 0) {
data->state = LV_INDEV_STATE_PRESSED;
data->point.x = ti.x[0];
data->point.y = ti.y[0];
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
/* Fuente de ticks para LVGL usando millis() */
static uint32_t my_tick(void) {
return millis();
}
void setup() {
Serial.begin(115200);
Serial.println("LVGL con Arduino en Kode Dot");
/* ─── Configuración de la pantalla ─── */
gfxBus = new Arduino_ESP32QSPI(9, 17, 15, 14, 16, 10);
gfx = new Arduino_CO5300(gfxBus, 8, 0, DSP_HOR_RES, DSP_VER_RES, 0, 22, 0, 0);
if (!gfx->begin()) {
Serial.println("Error al iniciar la pantalla");
while (true) delay(1000);
}
gfx->setRotation(0);
gfx->setBrightness(255);
gfx->fillScreen(BLACK);
Serial.println("Pantalla inicializada");
/* ─── Configuración del panel táctil ─── */
if (touch.init(48, 47, -1, -1, 400000) == CT_SUCCESS) {
touch.setOrientation(0, DSP_HOR_RES, DSP_VER_RES);
Serial.printf("Táctil OK. Tipo=%d\n", touch.sensorType());
} else {
Serial.println("No se pudo iniciar el táctil");
}
/* ─── Inicializar LVGL ─── */
lv_init();
lv_tick_set_cb(my_tick); /* Fuente de ticks */
lv_display_t *disp = lv_display_create(DSP_HOR_RES, DSP_VER_RES);
lv_display_set_flush_cb(disp, my_disp_flush);
/* Asignar buffers en PSRAM */
lv_buf1 = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
lv_buf2 = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
lv_display_set_buffers(disp, lv_buf1, lv_buf2, DRAW_BUF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);
/* Configurar entrada táctil como puntero */
lv_indev_t *indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, my_touchpad_read);
/* *******************
* Crear una etiqueta simple
******************** */
lv_obj_t *label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Hello Arduino, I'm LVGL!");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
/* *******************
* Probar un ejemplo. Ver todos los ejemplos
* - En línea: https://docs.lvgl.io/master/examples.html
* - Códigos fuente: https://github.com/lvgl/lvgl/tree/master/examples
******************** */
// lv_example_btn_1();
/* *******************
* O probar una demo. No olvides habilitar las demos en lv_conf.h. Por ejemplo, LV_USE_DEMO_WIDGETS
******************** */
// lv_demo_music();
Serial.println("Configuración finalizada");
}
void loop() {
lv_timer_handler(); /* Procesar eventos de LVGL */
delay(5);
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de código de la pantalla](https://drive.google.com/drive/folders/1dw2ThNCUiHljMfDs-s67guQxr_ILJ5BL)
# ESP32-S3
Source: https://docs.kode.diy/es/kode-dot/esp32s3
Conoce el microprocesador que le da vida al Kode Dot y su control de estados.
# Características
El **ESP32-S3** es uno de los mejores microprocesadores de **Espressif** que incorpora un **doble núcleo XTensa LX7,** capaces de correr hasta **240MHz**. Además, integra conectividad de **2.4GHz** con soporte **WiFi** y **Bluetooth LE**.
En la siguiente imagen se puede ver el **diagrama funcional del ESP32-S3** con todos los periféricos que incorpora:
Además de su potencia y versatilidad, lo hemos integrado en el Kode Dot ampliando sus capacidades con **32MB de flash** y **8MB de PSRAM.** Así, hace honor a su estatus de ser el **mejor dispositivo maker del mercado** y ejecutar programas mucho más grandes y complejos.
| Característica | Descripción |
| -------------- | ---------------------------------------- |
| Flash | Memoria externa de **32MB por Octalbus** |
| PSRAM | Memoria interna de **8MB por Octalbus** |
## Antena
Dentro del Kode Dot hemos incorporado una antena de **2.4GHz** en la PCB. Con esta antena vas a poder usar el **WiFi** y el **Bluetooth LE** del ESP32-S3, además de **ESP-NOW** y otros protocolos de comunicación que funcionen en esta banda de frecuencia.
## Programación
**Programar el Kode Dot se hace como cualquier otra placa basada en el ESP32-S3.** Conectalo diréctamente a tu ordenador mediante el cable USB-C y empieza a subir tus códigos.
En el apartado [Aplicaciones](/es/kodeOS/apps) se explica en detalle cómo subir código y crear aplicaciones.
Internamente, las **lineas de datos del USB-C** están conectadas a los pines **GPIO19 y GPIO20** para usar el periférico interno de **USB-Serial**.
Con el USB-C, también tienes la opción de usar el periférico **USB Serial/JTAG** interno que incorpora el ESP32-S3 para **flashear y debuggear el Kode Dot.**
Para los más avanzados, se pueden usar los pines **GPIO39, GPIO40, GPIO41 y GPIO42** del **conector superior del Kode Dot** para debuggear un programa usando una **interfaz externa de JTAG.**
## Control de estados
El control de los estados de **BOOT** y **RESET** del ESP32-S3 se realiza mediante unas sencillas combinaciones con los **botones del Kode Dot.**
### RESET
Para resetear el Kode Dot, se debe pulsar el **botón izquierdo del pad** a la vez que se pulsa el **botón de abajo.** Esto es útil para estos casos:
* Cuando se ha **flasheado** un programa y el Kode Dot se queda **bloqueado.**
* Para **salir de una aplicación** y volver al menú principal.
### BOOT
Para que el Kode Dot entre en modo BOOT, mientras se mantiene el **botón de arriba,** se debe resetear el Kode Dot siguiendo la combinación del RESET.
Es probable que no tengas que usar este proceso ya que si el código que subes al Kode Dot bloquea o hace reiniciar al ESP32-S3, el Kode Dot volverá al menú principal automáticamente.
## Ejemplo de código
Con este código puedes obtener la **dirección MAC** de las diferentes interfaces del ESP32-S3.
```cpp esp32s3_info.ino lines icon="microchip" theme={null}
/**
* Muestra información del microcontrolador ESP32-S3 por el puerto serie.
* Incluye modelo, revisión, número de núcleos y Chip ID.
* Imprime los datos cada 3 segundos.
*/
/* ───────── KODE | docs.kode.diy ───────── */
void setup() {
Serial.begin(115200); /* Inicia la comunicación serie a 115200 baudios */
}
void loop() {
/* Imprime modelo y revisión del chip ESP32 */
Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
/* Imprime la cantidad de núcleos del chip */
Serial.printf("This chip has %d cores\n", ESP.getChipCores());
/* Imprime el identificador único del chip */
Serial.print("Chip ID: ");
Serial.println(ESP.getEfuseMac());
/* Espera 3 segundos antes de repetir */
delay(3000);
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos del ESP32-S3](https://drive.google.com/drive/folders/11FnC9pj8qADzXAlg8xAT0knNWh9bgYV6)
# IMU
Source: https://docs.kode.diy/es/kode-dot/imu
Aprende para qué sirve una IMU y cómo usarla en tu Kode Dot
# Características
En el interior de tu Kode Dot tienes integrado un **giroscópio de 3 ejes, un acelerómetro de 3 ejes y un magnetómetro de 3 ejes.** Así, puedes conocer la posición relativa a si mismo y su posición absoluta respecto a la Tierra.
El giroscópio y el acelerómetro están en un **mismo integrado** y tienen las siguientes características:
| Característica | Descripción |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Acelerómetro + giroscopio “always-on” | Consumo total de **0,55 mA** en modo de alto rendimiento para operación continua. |
| Rangos de medida | Acelerómetro **±2/4/8/16 g** • Giroscopio **±125/250/500/1000/2000 dps**. |
| FIFO inteligente | Búfer de datos de hasta **9 KB** con compresión y batching dinámico. |
| Motor de IA embebido | **16 máquinas de estados (FSM)** programables + **núcleo MLC** (hasta 8 flujos / 256 nodos). |
| Reconocimiento de eventos | Podómetro, contador de pasos, significant motion, inclinación, free-fall, wake-up, orientación 6D/4D, clic y doble clic. |
| Sensor de temperatura | Termómetro interno para monitorizar la temperatura del chip. |
El magnetómetro tiene las siguientes características:
| Característica | Detalle |
| -------------------- | --------------------------------------------------------- |
| Rango dinámico | **±50 gauss** (tres ejes) |
| Resolución de salida | **16 bits** |
| Consumo típico | 200 µA @ 20 Hz (modo alta resolución) / 50 µA (low-power) |
## Esquema de conexión
### IMU de 6 ejes
La IMU está conectado al ESP32-S3 a través del bus I2C usando estas conexiones:
| IMU | ESP32-S3 |
| ---- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INT1 | EXP13 |
| INT2 | EXP12 |
La IMU tiene la dirección 0x6A en el bus I2C.
Los pines de interrupción están conectados al [expansor de pines](/es/kode-dot/io-expander).
### Magnetómetro de 3 ejes
El magnetómetro está conectado de la misma manera al bus I2C usando estas conexiones:
| Magnetómetro | ESP32-S3 |
| ------------ | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INT1 | EXP0 |
El magnetómetro tiene la dirección 0x1E en el bus I2C.
El pin de interrupción está conectado al [expansor de pines](/es/kode-dot/io-expander).
## Librerías recomendadas
### Arduino
* [Adafruit LSM6DS](https://github.com/adafruit/Adafruit_LSM6DS)
* [Adafruit LIS2MDL](https://github.com/adafruit/Adafruit_LIS2MDL)
### ESP-IDF
* [kode\_lsm6dsox](https://components.espressif.com/components/kodediy/kode_lsm6dsox)
* [kode\_lis2mdl](TBD)
## Ejemplo de código
### IMU de 6 ejes
Este código muestra el rango de medida de los sensores y la frecuencia de muestreo. También muestra la temperatura, la aceleración y la velocidad angular.
```cpp imu_test.ino lines icon="microchip" theme={null}
/**
* Inicializa y lee una IMU LSM6DSOX por I2C en ESP32-S3, mostrando aceleración, giro y temperatura.
* Imprime rangos y data rates configurados y luego publica lecturas cada 1 segundo por el puerto serie.
* Usa pines I2C personalizados (GPIO48/47) y la librería Adafruit_LSM6DSOX.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Librería para el sensor LSM6DSOX */
#include /* Librería de comunicación I2C */
/* Pines I2C configurables */
#define I2C_SDA 48 /* Pin SDA */
#define I2C_SCL 47 /* Pin SCL */
/* Instancia del sensor IMU y del bus I2C */
Adafruit_LSM6DSOX imu;
void setup(void) {
/* Inicializa el puerto serie para depuración */
Serial.begin(115200);
while (!Serial);
/* Inicializa el bus I2C con los pines especificados */
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("LSM6DSOX test");
/* Intenta inicializar el sensor en la dirección I2C por defecto (0x6A).
Nota: algunas placas usan 0x6B según el estado del pin SA0. */
if (!imu.begin_I2C()) {
Serial.println("Failed to find LSM6DSOX chip");
while (1) {
delay(10); /* Bucle infinito si falla la inicialización */
}
}
Serial.println("LSM6DSOX Found!");
/* Muestra el rango configurado del acelerómetro */
Serial.print("Accelerometer range set to: ");
switch (imu.getAccelRange()) {
case LSM6DS_ACCEL_RANGE_2_G:
Serial.println("+-2G"); break;
case LSM6DS_ACCEL_RANGE_4_G:
Serial.println("+-4G"); break;
case LSM6DS_ACCEL_RANGE_8_G:
Serial.println("+-8G"); break;
case LSM6DS_ACCEL_RANGE_16_G:
Serial.println("+-16G"); break;
}
/* Muestra el rango configurado del giroscopio */
Serial.print("Gyro range set to: ");
switch (imu.getGyroRange()) {
case LSM6DS_GYRO_RANGE_125_DPS:
Serial.println("125 degrees/s"); break;
case LSM6DS_GYRO_RANGE_250_DPS:
Serial.println("250 degrees/s"); break;
case LSM6DS_GYRO_RANGE_500_DPS:
Serial.println("500 degrees/s"); break;
case LSM6DS_GYRO_RANGE_1000_DPS:
Serial.println("1000 degrees/s"); break;
case LSM6DS_GYRO_RANGE_2000_DPS:
Serial.println("2000 degrees/s"); break;
case ISM330DHCX_GYRO_RANGE_4000_DPS:
/* Rango no soportado por el DSOX */
break;
}
/* Muestra el data rate configurado del acelerómetro */
Serial.print("Accelerometer data rate set to: ");
switch (imu.getAccelDataRate()) {
case LSM6DS_RATE_SHUTDOWN: Serial.println("0 Hz"); break;
case LSM6DS_RATE_12_5_HZ: Serial.println("12.5 Hz"); break;
case LSM6DS_RATE_26_HZ: Serial.println("26 Hz"); break;
case LSM6DS_RATE_52_HZ: Serial.println("52 Hz"); break;
case LSM6DS_RATE_104_HZ: Serial.println("104 Hz"); break;
case LSM6DS_RATE_208_HZ: Serial.println("208 Hz"); break;
case LSM6DS_RATE_416_HZ: Serial.println("416 Hz"); break;
case LSM6DS_RATE_833_HZ: Serial.println("833 Hz"); break;
case LSM6DS_RATE_1_66K_HZ: Serial.println("1.66 KHz"); break;
case LSM6DS_RATE_3_33K_HZ: Serial.println("3.33 KHz"); break;
case LSM6DS_RATE_6_66K_HZ: Serial.println("6.66 KHz"); break;
}
/* Muestra el data rate configurado del giroscopio */
Serial.print("Gyro data rate set to: ");
switch (imu.getGyroDataRate()) {
case LSM6DS_RATE_SHUTDOWN: Serial.println("0 Hz"); break;
case LSM6DS_RATE_12_5_HZ: Serial.println("12.5 Hz"); break;
case LSM6DS_RATE_26_HZ: Serial.println("26 Hz"); break;
case LSM6DS_RATE_52_HZ: Serial.println("52 Hz"); break;
case LSM6DS_RATE_104_HZ: Serial.println("104 Hz"); break;
case LSM6DS_RATE_208_HZ: Serial.println("208 Hz"); break;
case LSM6DS_RATE_416_HZ: Serial.println("416 Hz"); break;
case LSM6DS_RATE_833_HZ: Serial.println("833 Hz"); break;
case LSM6DS_RATE_1_66K_HZ: Serial.println("1.66 KHz"); break;
case LSM6DS_RATE_3_33K_HZ: Serial.println("3.33 KHz"); break;
case LSM6DS_RATE_6_66K_HZ: Serial.println("6.66 KHz"); break;
}
}
void loop() {
/* Variables para los eventos del sensor */
sensors_event_t accel;
sensors_event_t gyro;
sensors_event_t temp;
/* Obtiene eventos de acelerómetro, giroscopio y temperatura */
imu.getEvent(&accel, &gyro, &temp);
/* Imprime temperatura en grados Celsius */
Serial.print("\t\tTemperature: ");
Serial.print(temp.temperature);
Serial.println(" deg C");
/* Imprime aceleración en m/s^2 por eje */
Serial.print("\t\tAccel X: ");
Serial.print(accel.acceleration.x);
Serial.print(" \tY: ");
Serial.print(accel.acceleration.y);
Serial.print(" \tZ: ");
Serial.print(accel.acceleration.z);
Serial.println(" m/s^2");
/* Imprime rotación del giroscopio en rad/s por eje */
Serial.print("\t\tGyro X: ");
Serial.print(gyro.gyro.x);
Serial.print(" \tY: ");
Serial.print(gyro.gyro.y);
Serial.print(" \tZ: ");
Serial.print(gyro.gyro.z);
Serial.println(" radians/s");
Serial.println();
delay(1000); /* Espera entre lecturas */
}
```
### Magnetómetro de 3 ejes
Este código muestra el vector magnético en micro-Teslas (uT).
```cpp mag_test.ino lines icon="microchip" theme={null}
/**
* Inicializa y lee el magnetómetro LIS2MDL por I2C en un ESP32-S3.
* Imprime detalles del sensor al inicio y luego muestra el vector magnético (uT) cada segundo.
* Usa pines I2C personalizados (GPIO48/47) y la librería Adafruit_LIS2MDL.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* Pines I2C configurables */
#define I2C_SDA 48 /* Pin SDA */
#define I2C_SCL 47 /* Pin SCL */
/* Instancia del magnetómetro con ID único */
Adafruit_LIS2MDL mag = Adafruit_LIS2MDL(12345);
void setup(void) {
/* Inicializa el puerto serie para depuración */
Serial.begin(115200);
while (!Serial) {
/* espera al puerto serie */
}
/* Inicializa el bus I2C con los pines seleccionados */
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("Magnetometer Test");
Serial.println();
/* Intenta inicializar el sensor LIS2MDL en la dirección I2C 0x1E */
if (!mag.begin()) {
/* Sensor no detectado: muestra error y se detiene */
Serial.println("Ooops, no LIS2MDL detected ... Check your wiring!");
while (1) {
delay(10); /* Bucle infinito si falla */
}
}
/* Muestra información básica del sensor */
mag.printSensorDetails();
}
void loop(void) {
/* Obtiene un nuevo evento del sensor */
sensors_event_t event;
mag.getEvent(&event);
/* Muestra los resultados (valores magnéticos en micro-Teslas, uT) */
Serial.print("X: ");
Serial.print(event.magnetic.x);
Serial.print(" ");
Serial.print("Y: ");
Serial.print(event.magnetic.y);
Serial.print(" ");
Serial.print("Z: ");
Serial.print(event.magnetic.z);
Serial.print(" ");
Serial.println("uT");
/* Espera entre lecturas */
delay(1000);
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de la IMU y el magnetómetro](https://drive.google.com/drive/folders/1eAutUqjqenHA7lNoFHxKpBUXdwUa-6ZS)
# Expansor de pines
Source: https://docs.kode.diy/es/kode-dot/io-expander
Aprende a controlar los pines programables del expansor de pines.
# Características
Aunque todas las **señales importantes** de los componentes del Kode Dot están conectadas a los **pines del ESP32-S3,** hay algunas señales **menos importantes** que no caben.
El expansor de pines es un componente que tiene **16 pines programables** y al que están conectadas el resto de señales que, o son de **baja velocidad** o que **no son muy relevantes.**
## Esquema de conexión
Los pines del expansor se controlan con el ESP32-S3 mediante el **bus I2C.** Además, tiene un pin de **interrupción** que está conectado al ESP32-S3 para saber cuándo ha habido un cambio en uno de sus pines.
El expansor de pines está conectado al ESP32-S3 de la siguiente manera:
| Expansor | ESP32-S3 |
| --------- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| Interrupt | GPIO18 |
El expansor tiene la dirección 0x20 en el bus I2C.
Las señales de los distintos componentes del Kode Dot que están conectadas al expansor son:
| Señal | Expansor |
| ------------------------------ | -------- |
| Magnetómetro - INT | EXP0 |
| RTC - INTB | EXP1 |
| RTC - INTA | EXP2 |
| Amplificador - SD | EXP3 |
| Alimentación - 3V3 periféricos | EXP4 |
| Indicador batería - GPOUT | EXP5 |
| Pad - Arriba | EXP6 |
| Pad - Izquierda | EXP7 |
| Pad - Abajo | EXP8 |
| Botón - Abajo | EXP9 |
| PMIC - INT | EXP10 |
| Pad - Derecha | EXP11 |
| IMU - INT2 | EXP12 |
| IMU - INT1 | EXP13 |
| microSD - CD | EXP14 |
| Pantalla - TP INT | EXP15 |
La mayoría de señales son de interrupción de los distintos integrados o de los botones y en los ejemplos de los siguientes apartados está implementado la lectura de estas señales.
## Librerías recomendadas
### Arduino
* [ESP32\_IO\_Expander](https://github.com/esp-arduino-libs/ESP32_IO_Expander)
### ESP-IDF
* [esp\_io\_expander\_tca95xx\_16bit](https://components.espressif.com/components/espressif/esp_io_expander_tca95xx_16bit)
## Ejemplo de código
Con este código puedes probar el funcionamiento del expansor de pines. Cuando pulses el **botón de abajo,** se imprimirá un mensaje en el **monitor serie.**
```cpp expander_test.ino lines icon="microchip" theme={null}
/**
* Lee y muestra el estado de las señales conectadas a un expansor I/O TCA95XX_16BIT por I2C.
* Configura pines como entrada o salida, y actualiza la lectura de cada señal cada segundo.
* Muestra el nombre y estado de cada pin en el monitor serie.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include /* Librería para controlar expansores I/O en ESP32 */
#define I2C_SCL_PIN (47) /* Pin SCL del bus I2C */
#define I2C_SDA_PIN (48) /* Pin SDA del bus I2C */
#define I2C_ADDR (0x20) /* Dirección I2C del expansor */
esp_expander::Base *expander = nullptr; /* Puntero al objeto expansor */
/* Nombres descriptivos de las señales */
const char* signalNames[14] = {
"Magnetometer - INT", // EXP0
"RTC - INTB", // EXP1
"RTC - INTA", // EXP2
"Battery Indicator - GPOUT", // EXP5
"Pad - Up", // EXP6
"Pad - Left", // EXP7
"Pad - Down", // EXP8
"Button - Down", // EXP9
"PMIC - INT", // EXP10
"Pad - Right", // EXP11
"IMU - INT2", // EXP12
"IMU - INT1", // EXP13
"microSD - CD", // EXP14
"Display - TP INT" // EXP15
};
void setup() {
Serial.begin(115200); /* Inicia comunicación serie a 115200 baudios */
Serial.println("Expander polling test start.");
/* Inicializa el expansor en la dirección I2C configurada */
expander = new esp_expander::TCA95XX_16BIT(I2C_SCL_PIN, I2C_SDA_PIN, I2C_ADDR);
expander->init();
expander->begin();
/* Configura pines 3 y 4 como salida */
expander->multiPinMode(IO_EXPANDER_PIN_NUM_3 | IO_EXPANDER_PIN_NUM_4, OUTPUT);
/* Configura el resto de pines como entrada */
expander->multiPinMode(IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_2 |
IO_EXPANDER_PIN_NUM_5 | IO_EXPANDER_PIN_NUM_6 | IO_EXPANDER_PIN_NUM_7 |
IO_EXPANDER_PIN_NUM_8 | IO_EXPANDER_PIN_NUM_9 | IO_EXPANDER_PIN_NUM_10 |
IO_EXPANDER_PIN_NUM_11 | IO_EXPANDER_PIN_NUM_12 | IO_EXPANDER_PIN_NUM_13 |
IO_EXPANDER_PIN_NUM_14 | IO_EXPANDER_PIN_NUM_15, INPUT);
/* Pone en bajo las salidas controladas */
expander->digitalWrite(IO_EXPANDER_PIN_NUM_3, LOW); /* Amplifier - SD */
expander->digitalWrite(IO_EXPANDER_PIN_NUM_4, LOW); /* Power Supply - 3V3 peripherals */
}
int level[14] = {0}; /* Estados de las entradas */
void loop() {
/* Lee el estado de cada pin de entrada del expansor */
level[0] = expander->digitalRead(0);
level[1] = expander->digitalRead(1);
level[2] = expander->digitalRead(2);
level[3] = expander->digitalRead(5);
level[4] = expander->digitalRead(6);
level[5] = expander->digitalRead(7);
level[6] = expander->digitalRead(8);
level[7] = expander->digitalRead(9);
level[8] = expander->digitalRead(10);
level[9] = expander->digitalRead(11);
level[10] = expander->digitalRead(12);
level[11] = expander->digitalRead(13);
level[12] = expander->digitalRead(14);
level[13] = expander->digitalRead(15);
/* Muestra el estado de cada señal en el monitor serie */
Serial.println("=== Pin Status ===");
for (int i = 0; i < 14; i++) {
Serial.printf("EXP%02d: %d - %s\n", i, level[i], signalNames[i]);
}
Serial.println();
delay(1000); /* Espera 1 segundo antes de la siguiente lectura */
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos del expansor de pines](https://drive.google.com/drive/folders/1nJHAeJOtqmLtWnhrUvgWu9GuijLvPg9s)
# MicroSD
Source: https://docs.kode.diy/es/kode-dot/microsd
Descubre el uso de la microSD, su programación y porqué es tan importante.
# Características
La tarjeta microSD es una de las **partes esenciales para el funcionamiento del Kode Dot.** En ella se guardan las aplicaciones, los datos de configuración y los archivos de usuario.
Además, para los **proyectos y aplicaciones** que se desarrollen en kodeOS, es la **forma más sencilla de guardar los datos que se generen.**
## Esquema de conexión
La microSD se conecta al ESP32-S3 mediante **SDIO, en modo 1-bit.** Así, se usa el periférico **SD/MMC Host** que tiene el ESP32-S3 **dedicado para leer y escribir en la microSD.**
La conexión entre la microSD y el ESP32-S3 es la siguiente:
| MicroSD | ESP32-S3 |
| ------------- | -------- |
| Command | GPIO5 |
| Clock | GPIO6 |
| Data | GPIO7 |
| Card Detected | EXP14 |
El pin de Card Detected está conectado al EXP14 del expansor de pines. Ve a [Expansor de pines](/es/kode-dot/io-expander) para más información.
## Librerías recomendadas
### Arduino
* [SD\_MMC](https://github.com/espressif/arduino-esp32/tree/master/libraries/SD_MMC)
### ESP-IDF
No requiere librerías adicionales.
## Ejemplo de código
Este código hará un **test de la microSD en este orden:**
1. Listar directorios
2. Crear un directorio
3. Listar directorios
4. Eliminar un directorio
5. Listar directorios
6. Escribir un archivo
7. Añadir un mensaje al final de un archivo
8. Leer un archivo
9. Eliminar un archivo
10. Renombrar un archivo
11. Leer un archivo
12. Test de rendimiento de lectura y escritura
```cpp microsd_test.ino lines icon="microchip" theme={null}
/**
* Gestiona una tarjeta SD en modo SD_MMC (1-bit) en ESP32-S3.
* Realiza operaciones de archivos (listar, crear, leer, escribir, renombrar, borrar) y mide rendimiento.
* Usa pines personalizados y monta la tarjeta en /sdcard.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "FS.h"
#include "SD_MMC.h"
/* Pines personalizados para SD_MMC (SD en modo 1-bit) */
int clk = 6; /* Pin de reloj (CLK) */
int cmd = 5; /* Pin de comando (CMD) */
int d0 = 7; /* Pin de datos 0 (D0) */
/* Función recursiva para listar directorios */
void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
Serial.printf("Listing directory: %s\n", dirname);
/* Abre el directorio */
File root = fs.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}
/* Itera por archivos y subdirectorios */
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
/* Recurre en subdirectorios si levels > 0 */
if (levels) {
listDir(fs, file.path(), levels - 1);
}
} else {
/* Es un archivo: imprime nombre y tamaño */
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
/* Crea un directorio */
void createDir(fs::FS &fs, const char *path) {
Serial.printf("Creating Dir: %s\n", path);
if (fs.mkdir(path)) {
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
/* Elimina un directorio */
void removeDir(fs::FS &fs, const char *path) {
Serial.printf("Removing Dir: %s\n", path);
if (fs.rmdir(path)) {
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
/* Lee y muestra el contenido de un archivo */
void readFile(fs::FS &fs, const char *path) {
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
/* Lee byte a byte y escribe por Serial */
while (file.available()) {
Serial.write(file.read());
}
}
/* Escribe un mensaje en un archivo (sobrescribe) */
void writeFile(fs::FS &fs, const char *path, const char *message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
/* Escribe el mensaje y verifica el resultado */
if (file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
}
/* Añade un mensaje a un archivo */
void appendFile(fs::FS &fs, const char *path, const char *message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file) {
Serial.println("Failed to open file for appending");
return;
}
if (file.print(message)) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
}
/* Renombra un archivo */
void renameFile(fs::FS &fs, const char *path1, const char *path2) {
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
/* Elimina un archivo */
void deleteFile(fs::FS &fs, const char *path) {
Serial.printf("Deleting file: %s\n", path);
if (fs.remove(path)) {
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
/* Prueba de rendimiento de E/S de archivos sobre un archivo grande */
void testFileIO(fs::FS &fs, const char *path) {
File file = fs.open(path);
static uint8_t buf[512]; /* Búfer de 512 bytes */
size_t len = 0;
uint32_t start = millis();
uint32_t elapsed;
if (file) {
/* Obtiene tamaño de archivo */
len = file.size();
size_t originalLen = len;
start = millis();
/* Lee el archivo por bloques */
while (len) {
size_t toRead = (len > sizeof(buf)) ? sizeof(buf) : len;
file.read(buf, toRead);
len -= toRead;
}
elapsed = millis() - start;
Serial.printf("%u bytes read in %lu ms\n", originalLen, elapsed);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
/* Medición de rendimiento de escritura */
file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
start = millis();
/* Escribe 2048 bloques de 512 bytes (1 MiB) */
for (size_t i = 0; i < 2048; i++) {
file.write(buf, sizeof(buf));
}
elapsed = millis() - start;
Serial.printf("%u bytes written in %lu ms\n", 2048 * sizeof(buf), elapsed);
file.close();
}
void setup() {
Serial.begin(115200);
/* Asigna pines personalizados para SD_MMC en modo 1-bit */
if (!SD_MMC.setPins(clk, cmd, d0)) {
Serial.println("Pin change failed!");
return;
}
/* Monta la tarjeta SD vía SD_MMC (path y busWidth=1 para 1-bit) */
if (!SD_MMC.begin("/sdcard", 1)) {
Serial.println("Card Mount Failed");
return;
}
/* Revisa el tipo de tarjeta */
uint8_t cardType = SD_MMC.cardType();
if (cardType == CARD_NONE) {
Serial.println("No SD_MMC card attached");
return;
}
Serial.print("SD_MMC Card Type: ");
if (cardType == CARD_MMC) Serial.println("MMC");
else if (cardType == CARD_SD) Serial.println("SDSC");
else if (cardType == CARD_SDHC) Serial.println("SDHC");
else Serial.println("UNKNOWN");
/* Tamaño de la tarjeta en MB */
uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
/* Ejemplos de operaciones con archivos y directorios */
listDir(SD_MMC, "/", 0);
createDir(SD_MMC, "/mydir");
listDir(SD_MMC, "/", 0);
removeDir(SD_MMC, "/mydir");
listDir(SD_MMC, "/", 2);
writeFile(SD_MMC, "/hello.txt", "Hello ");
appendFile(SD_MMC, "/hello.txt", "World!\n");
readFile(SD_MMC, "/hello.txt");
deleteFile(SD_MMC, "/foo.txt");
renameFile(SD_MMC, "/hello.txt", "/foo.txt");
readFile(SD_MMC, "/foo.txt");
testFileIO(SD_MMC, "/test.txt");
/* Imprime espacio total y usado en MB */
Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));
}
void loop() {
/* Bucle principal sin trabajo: breve retardo para ceder CPU */
delay(10);
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos de microSD](https://drive.google.com/drive/folders/1fMG1BzAr6a9Gi88daPVNe0bdkRSY8TKe)
# Alimentación
Source: https://docs.kode.diy/es/kode-dot/power
El sistema de alimentación en electrónica es la parte más importante porque de ella dependen los componentes.
Lee detenidamente esta sección para no dañar el Kode Dot.
## Características
El Kode Dot integra un **sistema de alimentación complejo y sofisticado, pero a la vez robusto, modular y fácil de usar.** Se puede alimentar de tres maneras: de la batería de 500mAh, del USB-C o a través de los conectores externos.
El sistema está formado por estos componentes:
* Power Management Integrated Circuit (PMIC)
* Indicador de combustible (Fuel Gauge, en español no tiene mucho sentido la traducción)
* Regulador de 3V3 para los integrados internos
* Regulador de 3V3 para los periféricos
* Regulador para el RTC interno del ESP32-S3
### Power Management Integrated Circuit (PMIC)
La **parte central del sistema de alimentación es un PMIC** que se encarga de gestionar de dónde se obtiene la energía, **si de la batería, del USB-C o de los conectores externos.**
Además, el PMIC se encarga de **la seguridad y la protección de los componentes**, asegurando la protección contra sobrecargas, cortocircuitos o sobrecorrientes. Además,nos permite **obtener datos de la batería y de la alimentación.**
También permite **generar desde la batería un bus de 5V y hasta 2A de corriente** que se puede usar para alimentar periféricos externos a través de los conectores externos.
### Fuel Gauge
El fuel gauge es un componente que **se encarga de medir varios datos de la batería y darnos un análisis de su estado.**
Así podemos conocer los siguientes datos de la batería:
* Capacidad restante
* Estado de carga
* Tiempo restante de uso
* Voltaje de la batería
* Temperatura de la batería
* Salud
* Corriente de salida o entrada
Además, **nos avisa ante posibles problemas como sobrecargas, cortocircuitos, sobrecorrientes, etc.**
### Regulador de 3V3 para los integrados internos
Este es el **principal regulador de tensión del Kode Dot** y soporta hasta **1A de corriente.** Se encarga de estabilizar la tensión a 3V3 y alimenta estos integrados:
* ESP32-S3
* Expansor de pines
* Reloj de tiempo real
* Amplificador de audio
* Micrófono
* IMU de 6 ejes
* Magnetómetro de 3 ejes
Así, cuando el Kode Dot entre en **estado de suspensión**, este regulador se encarga de **mantener la tensión en el ESP32-S3 y a los integrados internos.**
### Regulador de 3V3 para los periféricos
Este regulador, que soporta hasta **2A de corriente**, se puede **activar o desactivar** para darle alimentación a los siguientes periféricos del Kode Dot:
* Pantalla
* microSD
* Bus 3V3 del conector superior
Cuando el Kode Dot está en **modo suspensión**, este regulador se desactiva y desconecta la alimentación de los periféricos.
### Regulador para el RTC interno del ESP32-S3
Este regulador se encarga de darle **alimentación al RTC interno del ESP32-S3.**
## Esquema de conexión
### Power Management Integrated Circuit (PMIC)
El PMIC está conectado al bus I2C usando estas conexiones:
| PMIC | ESP32-S3 |
| ---- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INT | EXP10 |
El PMIC tiene la dirección 0x6B en el bus I2C.
El pin de interrupción está conectado al [expansor de pines](/es/kode-dot/io-expander).
El **bus de 5V y 2A que genera el PMIC está conectado al conector superior y al trasero del Kode Dot.** Si el USB-C está conectado, la potencia del bus de 5V proviene de este. Si no está conectado, la potencia del bus de 5V proviene de la batería.
Además, se puede conectar por uno de los conectores externos una **fuente externa de alimentación de 5V** para cargar el Kode Dot.
**No conectes una fuente externa de 5V a la vez que está conectado el USB-C.**
### Fuel Gauge
El fuel gauge está conectado al bus I2C usando estas conexiones:
| Fuel Gauge | ESP32-S3 |
| ---------- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| GPOUT | EXP5 |
El fuel gauge tiene la dirección 0x55 en el bus I2C.
El pin de GPOUT está conectado al [expansor de pines](/es/kode-dot/io-expander).
### Regulador de 3V3 para los periféricos
Este regulador se puede **activar o desactivar** para darle alimentación a los periféricos del Kode Dot. Por **defecto está activado, para desactivarlo pon el siguiente pin en LOW:**
| Regulador 3V3 | ESP32-S3 |
| ------------- | -------- |
| EN | EXP4 |
El pin EN está conectado al [expansor de pines](/es/kode-dot/io-expander).
## Librerías recomendadas
### Arduino
#### Power Management Integrated Circuit (PMIC)
* [PMIC\_BQ25896](https://github.com/sqmsmu/PMIC_BQ25896)
#### Fuel Gauge
* [kode\_BQ27220](https://github.com/kodediy/kode_bq27220)
### ESP-IDF
#### Power Management Integrated Circuit (PMIC)
* [kode\_bq25896](https://components.espressif.com/components/kodediy/kode_bq25896)
#### Fuel Gauge
* [kode\_bq27220](https://components.espressif.com/components/kodediy/kode_bq27220/versions/1.0.0)
## Ejemplo de código
#### Power Management Integrated Circuit (PMIC)
Con este código puedes ver los parámetros que devuelven el PMIC de la batería y la alimentación.
```cpp pmic_test.ino lines icon="microchip" theme={null}
/**
* Ejemplo de uso del PMIC BQ25896 en ESP32-S3 vía I²C.
* Inicializa el cargador/gestor de batería, muestra parámetros del sistema,
* y actualiza lecturas y estados cada segundo.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include "PMIC_BQ25896.h"
#include
/* Configuración del bus I²C: pines SDA, SCL */
#define I2C_SDA 48 /* Pin SDA */
#define I2C_SCL 47 /* Pin SCL */
/* Instancia del driver BQ25896 */
PMIC_BQ25896 bq25896;
void setup() {
/* Inicializa puerto serie para depuración */
Serial.begin(115200);
while (!Serial) {
/* Espera la conexión serie */
}
/* Inicializa el bus I²C con los pines especificados */
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("BQ25896 Power Management and Battery Charger Example");
/* Inicializa el BQ25896 por I²C */
bq25896.begin();
delay(500); /* Espera para que el dispositivo se estabilice */
/* Comprueba la conectividad del dispositivo */
if (!bq25896.isConnected()) {
Serial.println("BQ25896 not found! Check connection and power");
while (1) {
/* Se detiene si no se detecta */
}
} else {
Serial.println("BQ25896 found successfully.");
}
}
void loop() {
Serial.println("BQ25896 System Parameters");
/* Estado del pin de límite de corriente de entrada */
Serial.print("ILIM PIN : ");
Serial.println(String(bq25896.getILIM_reg().en_ilim));
/* Parámetros de sistema y carga */
Serial.print("IINLIM : "); Serial.println(String(bq25896.getIINLIM()) + " mA");
Serial.print("VINDPM_OS : "); Serial.println(String(bq25896.getVINDPM_OS()) + " mV");
Serial.print("SYS_MIN : "); Serial.println(String(bq25896.getSYS_MIN()) + " mV");
Serial.print("ICHG : "); Serial.println(String(bq25896.getICHG()) + " mA");
Serial.print("IPRE : "); Serial.println(String(bq25896.getIPRECHG()) + " mA");
Serial.print("ITERM : "); Serial.println(String(bq25896.getITERM()) + " mA");
Serial.print("VREG : "); Serial.println(String(bq25896.getVREG()) + " mV");
Serial.print("BAT_COMP : "); Serial.println(String(bq25896.getBAT_COMP()) + " mΩ");
Serial.print("VCLAMP : "); Serial.println(String(bq25896.getVCLAMP()) + " mV");
Serial.print("BOOSTV : "); Serial.println(String(bq25896.getBOOSTV()) + " mV");
Serial.print("BOOST_LIM : "); Serial.println(String(bq25896.getBOOST_LIM()) + " mA");
Serial.print("VINDPM : "); Serial.println(String(bq25896.getVINDPM()) + " mV");
Serial.print("BATV : "); Serial.println(String(bq25896.getBATV()) + " mV");
Serial.print("SYSV : "); Serial.println(String(bq25896.getSYSV()) + " mV");
Serial.print("TSPCT : "); Serial.println(String(bq25896.getTSPCT()) + "%");
Serial.print("VBUSV : "); Serial.println(String(bq25896.getVBUSV()) + " mV");
Serial.print("ICHGR : "); Serial.println(String(bq25896.getICHGR()) + " mA");
/* Estado de fallos */
Serial.print("Fault -> ");
Serial.print("NTC:" + String(bq25896.getFAULT_reg().ntc_fault));
Serial.print(" ,BAT:" + String(bq25896.getFAULT_reg().bat_fault));
Serial.print(" ,CHGR:" + String(bq25896.getFAULT_reg().chrg_fault));
Serial.print(" ,BOOST:" + String(bq25896.getFAULT_reg().boost_fault));
Serial.println(" ,WATCHDOG:" + String(bq25896.getFAULT_reg().watchdog_fault));
/* Estado de carga */
Serial.print("Charging Status -> ");
Serial.print("CHG_EN:" + String(bq25896.getSYS_CTRL_reg().chg_config));
Serial.print(" ,BATFET DIS:" + String(bq25896.getCTRL1_reg().batfet_dis));
Serial.print(" ,BATLOAD_EN:" + String(bq25896.getSYS_CTRL_reg().bat_loaden));
Serial.print(" ,PG STAT:" + String(bq25896.get_VBUS_STAT_reg().pg_stat));
Serial.print(" ,VBUS STAT:" + String(bq25896.get_VBUS_STAT_reg().vbus_stat));
Serial.print(" ,CHRG STAT:" + String(bq25896.get_VBUS_STAT_reg().chrg_stat));
Serial.println(",VSYS STAT:" + String(bq25896.get_VBUS_STAT_reg().vsys_stat));
/* Inicia nueva conversión ADC */
bq25896.setCONV_START(true);
delay(1000); /* Actualiza cada segundo */
}
```
#### Fuel Gauge
Con este código puedes ver los parámetros que devuelve el fuel gauge de la batería.
```cpp bq27220_test.ino lines icon="microchip" theme={null}
/**
* Example usage of the Texas Instruments BQ27220 battery fuel gauge.
* Reads state of charge, voltage, current, and temperature over I²C.
* Displays charging status and estimated time to full when charging.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include
/* I²C pin configuration for ESP32-S3 */
#define SDA_PIN 48 /* SDA line */
#define SCL_PIN 47 /* SCL line */
/* Battery fuel gauge driver instance */
BQ27220 gauge;
void setup() {
/* Initialize serial port for debug output */
Serial.begin(115200);
/* Start I²C bus with custom SDA/SCL pins */
Wire.begin(SDA_PIN, SCL_PIN);
/* Initialize the BQ27220 fuel gauge */
if (!gauge.begin()) {
Serial.println("BQ27220 not found!");
while (1) delay(1000); /* Halt execution if not found */
}
Serial.println("BQ27220 ready.");
}
void loop() {
/* Read battery parameters */
int soc = gauge.readStateOfChargePercent(); // State of charge (%)
int mv = gauge.readVoltageMillivolts(); // Voltage (mV)
int ma = gauge.readCurrentMilliamps(); // Current (mA), positive = charging
float tC = gauge.readTemperatureCelsius(); // Temperature (°C)
/* Print basic battery information */
Serial.print("SOC= "); Serial.print(soc); Serial.print("% ");
Serial.print("V= "); Serial.print(mv); Serial.print(" mV ");
Serial.print("I= "); Serial.print(ma); Serial.print(" mA ");
Serial.print("T= "); Serial.print(tC, 1); Serial.print(" °C");
/* If charging, show estimated time to full */
if (ma > 0) {
int ttf = gauge.readTimeToFullMinutes();
Serial.print(" TTF= "); Serial.print(ttf); Serial.print(" min");
}
Serial.println();
delay(1000); /* Update once per second */
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Códigos de la alimentación](https://drive.google.com/drive/folders/1I5WI-snWixP8urmTfhuuEfvBaxEJhqmo)
# Inicio rápido
Source: https://docs.kode.diy/es/kode-dot/quickstart
Guía rápida para comprender el Kode Dot y empezar con las aplicaciones.
# Qué es el Kode Dot
El Kode Dot es el **mejor dispositivo maker del mercado.** Se trata de un dispositivo **todo en uno, de tamaño de bolsillo y con capacidad de IA,** que te permite aprender a programar electrónica y sistemas embebidos mientras **construyes y haces realidad tus ideas.**
Integra el **hardware más avanzado y lo combina con kodeOS**, nuestro sistema operativo de código abierto, que te permite **guardar tu código en aplicaciones y compartirlas con la comunidad.**
Las principales características técnicas del Kode Dot son:
| Característica | Descripción |
| ---------------- | ------------------------------------------------------------ |
| Microcontrolador | **ESP32-S3** - 32MB de flash y 8 MB de PSRAM |
| Pantalla | AMOLED 2.13" |
| Led | RGB Direccionable |
| Botones | Pad de 4 botones + 2 botones |
| Audio | **Micrófono y altavoz** |
| Almacenamiento | microSD |
| IMU | **IMU** de 6 ejes + **magnetómetro** de 3 ejes |
| Conectividad | WiFi - Bluetooth - ESP-NOW - **2.4GHz** |
| Conectores | **USB-C** - **Superior de 20 pines** - **Trasero magnético** |
## Qué hay en la caja
Cuando compres el Kode Dot, en la caja te llegarán:
* 1x **Kode Dot**
* 1x **cable de carga y programación**
* 3x **pegatinas**
* 1x **manual de inicio rápido**
## Cómo encender el Kode Dot
Nada más sacar el Kode Dot de la caja, **pulsa el botón de abajo a la derecha durante 2 segundos para encenderlo.**
No tienes que preocuparte de apagarlo ya que **automáticamente** detectará cuando no lo estás usando y entrará en **modo suspensión.**
Si no vas a usar tu Kode Dot durante un **largo peridodo de tiempo**, puedes pulsar el botón de abajo a la derecha durante **5 segundos** para apagarlo por completo.
## Lanza tu primera aplicación
Prueba a lanzar tu primera aplicación siguiendo estos pasos:
Desliza el dedo **hacia la izquierda** para entrar en el **menú de aplicaciones.** Aquí, aparecerán todas las categorías en las que se agrupan las aplicaciones. Desliza hacia abajo y selecciona el apartado de **"Games"**.
Aqui te aparecerán todas las aplicaciones que hay en el apartado de "Games". Selecciona la **aplicación "Snake"** para lanzarla.
En esta pantalla verás el **título de la aplicación y una pequeña descripción.** Confirma que quieres lanzar la aplicación **pulsando "YES".**
Tu **Kode Dot se reiniciará** y ya podrás **empezar a jugar al mítico Snake.**
Para salir de la aplicación, pulsa el botón de abajo a la derecha a la vez que el pad izquierdo.
## Crea tu primera aplicación
### Preparar Entorno
Subir tu código y convertirlo en una aplicación es muy sencillo, vamos a poner de ejemplo cómo se hace con Arduino IDE.
Entra en el siguiente [enlace](https://www.arduino.cc/en/software/) y descarga e instala el IDE de Arduino.
Abre Arduino IDE y en el *Administrador de placas* busca e instala las placas de **ESP32**.
Selecciona el Kode Dot como placa en "Tools > Board > esp32 > Kode Dot".
### Sube tu código y crea la aplicación
Copia este código de ejemplo en el Arduino IDE. Este código imprime información del chip ESP32-S3 en el monitor serie cada 3 segundos.
```cpp esp32s3_info.ino lines icon="microchip" theme={null}
void setup() {
Serial.begin(115200); /* Inicia la comunicación serie a 115200 baudios */
}
void loop() {
/* Imprime modelo y revisión del chip ESP32 */
Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
/* Imprime la cantidad de núcleos del chip */
Serial.printf("This chip has %d cores\n", ESP.getChipCores());
/* Imprime el identificador único del chip */
Serial.print("Chip ID: ");
Serial.println(ESP.getEfuseMac());
/* Espera 3 segundos antes de repetir */
delay(3000);
}
```
Desliza el **dedo hacia la derecha** en el Kode Dot para entrar en el **menú de subir código**. Al conectar tu Kode Dot al ordenador, en el Arduino IDE te saldrá en la **lista de dispositivos** y dándole al botón de **"Upload"** se subirá el código.
Ahora en el **menú de subir código del Kode Dot**, te saldrá la opción de **ejecutar el código que acabas de subir o crear una aplicación.** Selecciona la opción de **"Create App"**. Por defecto, se guardará en la categoría de **"General"**.
Ve al menú de aplicaciones, entra en la categoría de **"General"** y ya te **aparecerá tu aplicación recién creada** lista para ser lanzada.
# Reloj de tiempo real
Source: https://docs.kode.diy/es/kode-dot/rtc
Lleva el control del tiempo en tus proyectos con los RTCs de tu Kode Dot.
# Características
El Kode Dot integra **dos relojes de tiempo real**, el interno del ESP32-S3 y uno externo.
## Esquema de conexión
El reloj interno del ESP32-S3 se puede usar directamente usando la **documentación de Espressif.**
El reloj externo está conectado al I2C del ESP32-S3 usando estas conexiones:
| RTC externo | ESP32-S3 |
| ----------- | -------- |
| SDA | GPIO48 |
| SCL | GPIO47 |
| INTA | EXP2 |
| INTB | EXP1 |
El reloj externo tiene la dirección 0xD0 en el bus I2C.
Los pines de interrupción están conectados al [expansor de pines](/es/kode-dot/io-expander).
## Librerías recomendadas
### Arduino
* [kode\_MAX31329](https://github.com/kodediy/kode_MAX31329)
### ESP-IDF
* TBD
## Ejemplo de código
Este código configura el RTC con una fecha y hora específica y luego imprime la hora actual cada segundo.
```cpp rtc_test.ino lines icon="microchip" theme={null}
/**
* Basic MAX31329 RTC time demo: sets initial time and continuously reads/displays current time.
* Uses fluent API (rtc.t.year = 2024) for easy time configuration on ESP32-S3.
* Prints formatted time every second to Serial monitor.
*/
/* ───────── KODE | docs.kode.diy ───────── */
#include
#include "Wire.h"
MAX31329 rtc;
/* Helper function to read and display current time from RTC */
static void printTime()
{
/* Read time from RTC into rtc.t structure */
if (!rtc.readTime()) {
Serial.println("readTime failed");
return;
}
/* Format and print time as YYYY-MM-DD HH:MM:SS */
Serial.printf("%04d-%02d-%02d %02d:%02d:%02d\n",
rtc.t.year, rtc.t.month, rtc.t.day,
rtc.t.hour, rtc.t.minute, rtc.t.second);
}
void setup()
{
Serial.begin(115200);
Serial.println("MAX31329 Time example");
Wire.begin(48,47);
/* Initialize RTC */
rtc.begin();
/* Set initial time using fluent API - November 24, 2024 15:10:00 */
rtc.t.year = 2024;
rtc.t.month = 11;
rtc.t.day = 24;
rtc.t.hour = 15;
rtc.t.minute = 10;
rtc.t.second = 0;
rtc.t.dayOfWeek = 0; /* 0=Sunday, 1=Monday, ..., 6=Saturday */
/* Write configured time to RTC hardware */
if (!rtc.writeTime()) {
Serial.println("writeTime failed");
}
}
void loop()
{
delay(1000); /* Wait 1 second between readings */
printTime(); /* Display current time */
}
```
## Descarga de ejemplos
Puedes probar los códigos de ejemplo mediante el IDE de Arduino o el IDE de ESP-IDF o descargar los códigos en nuestro drive:
[Ejemplos del RTC](https://drive.google.com/drive/folders/1EHoXhwTg31xQmAzV5kKiH4j0Wmi5bjY9)
# Aplicaciones
Source: https://docs.kode.diy/es/kodeOS/apps
Entiende cómo funcionan las aplicaciones y cómo puedes crear las tuyas.
# Aplicaciones del Kode Dot
Las comunidades open source se basan en **compartir conocimientos y recursos.** Por eso, la principal característica del Kode Dot es que tus **códigos se conviertan en aplicaciones** para
que puedas **compartirlos con otras personas y dar a conocer tu trabajo.**
Además, tu también podrás **usar aplicaciones creadas por otras personas y experimentar con ellas.**
## Funcionamiento
Si **no hay ningún código subido en la flash**, te aparecerá la siguiente pantalla:
Cuando programes el código de tu proyecto en tu IDE favorito, podrás **subirlo a tu Kode Dot** como se hace en cualquier otra plataforma.
Una vez subido, en la pantalla de tu Kode Dot te aparecerán dos opciones, **correr directamente el código o transformar el código en una aplicación y guardarla en tu Kode Dot.**
### Correr el código
Dependiendo si el **modo maker está activado o no**, el código que subas se ejecutará automáticamente o no.
Si el modo maker está activado, te saldrá un **pop-up con una cuenta atrás de 3 segundos hasta que se ejecute el código.** Puedes **cancelar la cuenta atrás y cancelar la ejecución.**
Si el modo maker está desactivado, el código **no se ejecutará automáticamente** y podrás ejecutarlo cuando quieras dandole al botón de ejecutar.
### Crear una aplicación
Cuando tengas el código validado y funcionando, podrás darle al botón de **crear aplicación.** Puedes elegir **si quieres cambiarle el nombre y seleccionar en qué categoría quieres guardarla.**
## Menú de aplicaciones
Entrando en el **menú de las aplicaciones, te saldrán todas las categorías disponibles.** Aunque puedes crear tus propias categorías, por defecto hay estas:
* General
* Hacking
* GPIO
* USB
* Games
En cada una de ellas, podrás ver que ya hay aplicaciones subidas para que puedas **probarlas.**
## Añade aplicaciones de otras personas
Todas las **aplicaciones** de tu Kode Dot se **guardan en la microSD.** Por eso, para añadir aplicaciones de otras personas, conecta la **microSD a tu ordenador** y copia las aplicaciones en la **carpeta de la categoría que quieras.**
En un futuro, podrás compartir aplicaciones entre Kode Dots inalámbricamente o descargarlas directamente desde la store.
# Firmware
Source: https://docs.kode.diy/es/kodeOS/firmware
Descubre kodeOS y cómo puedes actualizarlo o repararlo.
# kodeOS
kodeOS es el sistema operativo que corre en una **partición de la flash** de tu Kode Dot.
Si por algún motivo **borras la flash o programas un código encima de la partición de kodeOS**, puedes volver a instalarlo mediante la **aplicación de escritorio de kode.**
## Recupera kodeOS
Abre la aplicación y conecta el Kode Dot mediante el cable USB. En el apartado de Serial Port te tendrá que salir el puerto al que está conectado.
Descarga el archivo de kodeOS en la carpeta de descargas y seleccionalo en el programa.
Dale al botón de Load y espera a que se complete la carga. En la terminal te saldrá el proceso de carga y cuando termine te saldrá un pop-up con el mensaje de que se ha cargado correctamente.
# Hammy
Source: https://docs.kode.diy/es/kodeOS/hammy
Conoce a Hammy, tu compañero de aprendizaje que te acompañará en tu viaje.
# Conoce a Hammy
Hammy es tu **compañero de aprendizaje.** Según vayas usando tu Kode Dot, Hammy irá **aprendiendo y evolucionando.**
Además, te va a ir dando **consejos y sugerencias de aplicaciones que te pueden interesar programar.**
## Juega con él y cuidalo
Si le das un **toque en la cabeza, podrás empezar a jugar con él.** No te olvides de darle comida y cuidarlo para que no se enfade y pueda
seguir evolucionando.
## Personaliza a Hammy
Cada persona tiene un Hammy con un **nombre único.** Además, como cada uno va a usar su Kode Dot de manera diferente, puedes **personalizar su aspecto y añadirle accesorios.**
## Añade amigos
Cuando estés cerca de otra persona con un Kode Dot, te saldrá una notificación de que puedes añadirlo como amigo. Así, vuestros Hammies podrán **conocerse, compartir accesorios y jugar juntos.**
## Háblale
Próximamente podrás hablarle y pedirle que te ayude a programar.