-
Power to the people.
03/29/2025 at 13:20 • 0 commentsI noticed an annoying characteristic of the device. The device will not run on battery unless the battery has been charged a little bit. Even then, it will shut off after about 30 seconds due to the low power inactivity shut off function in the IP-5306. This is why power banks shut off on makers trying to run microcontrollers from them.
In my conversations with Grok, it suggested two ways to deal with this. One was to run a 1K resistor from Pin 5 (Key) of the IP-5306 to a GPIO pin and pull the pin down every 20 seconds or so to simulate a button press.
Bodge resistor #1
Well I ran a 1.2K resistor to GPIO3 resistor and with the following code, my board will start working after plugging in the Supermini board and then unplugging it. It pulled battery power and ran. It also did not shut off. Ran it for about an hour and saw a 0.2V drop in the battery.
from machine import Pin import time # GPIO pin to control the KEY pin of the IP5306 (GPIO 3) key_pin = Pin(3, Pin.OUT) # Function to simulate a short press on the KEY pin (50ms to 2s) def simulate_short_press(): print("Simulating short press on KEY pin to enable/keep boost output on...") key_pin.value(0) # Pull KEY pin low time.sleep(0.1) # Hold for 100ms key_pin.value(1) # Release the KEY pin print("Short press completed.") # Initialize the KEY pin to high (inactive) key_pin.value(1) # Wait a moment to ensure the ESP32C6 is fully powered time.sleep(1) # Simulate an initial short press to enable the boost output simulate_short_press() # Main loop to periodically simulate short presses and keep the system running while True: # Simulate a short press every 20 seconds to ensure the boost output stays on simulate_short_press() print("System is running...") time.sleep(20) # Repeat every 20 seconds
I also tried the I2C pins input that should have worked. However, the only I2C device that came up when I did a sweep was the accelerometer. I tried swapping the SCL and SDA pins to see if I got the order reversed by to no avail.
Well I got some learnings! Chat GPT suggested that the I2C part might have to be turned on. It wrote a little skit to simulated the button press on the Key pin and then scanned for I2C addresses and all of a sudden we got an 0x75 address. Here was the code.
import machine, time # Simulate a button press on the KEY pin via GPIO3. key_pin = machine.Pin(3, machine.Pin.OUT) # Ensure KEY is high by default (if not, adjust logic accordingly) key_pin.value(1) time.sleep_ms(10) # a brief pause # Pull KEY low to simulate a short press (active low assumed) key_pin.value(0) time.sleep_ms(2000) # hold low for 50ms (adjust as needed) key_pin.value(1) time.sleep_ms(50) # Optionally, set the pin back to input mode key_pin.init(machine.Pin.IN) i2c = machine.I2C(0, scl=machine.Pin(19), sda=machine.Pin(20), freq=400000) devices = i2c.scan() print("I2C freaky devices found:", devices)
So the next job was to manipulate some registers to limit the current to 200 mA for charging because I am using a 200 mAh battery and to remove the low current shut off "feature". This is called Boost always on. I needed to modify the time to pull the Key low from 50ms to 500ms to make it work.
import machine import time # --- 1. Simulate KEY press on GPIO3 to enable I2C mode on the IP5306 --- key_pin = machine.Pin(3, machine.Pin.OUT) key_pin.value(1) # Ensure KEY is high by default. time.sleep_ms(10) # Brief pause. key_pin.value(0) # Pull KEY low to simulate a press. time.sleep_ms(500) # Hold low for 50ms (adjust if needed). key_pin.value(1) # Release KEY. time.sleep_ms(50) key_pin.init(machine.Pin.IN) # Return KEY pin to input. # --- 2. Initialize I2C on GPIO19 (SCL) and GPIO20 (SDA) at 400KHz --- i2c = machine.I2C(0, scl=machine.Pin(19), sda=machine.Pin(20), freq=400000) print("I2C devices found:", i2c.scan()) # Expect: [14, 117] # --- 3. Define the IP5306 class with helper methods --- # (We use address 0x75 for the IP5306, as discovered.) IP5306_I2C_ADDR = 0x75 class IP5306: def __init__(self, i2c, addr=IP5306_I2C_ADDR): self.i2c = i2c self.addr = addr def read_reg(self, reg): """Read one byte from register 'reg'.""" return self.i2c.readfrom_mem(self.addr, reg, 1)[0] def write_reg(self, reg, val): """Write one byte 'val' to register 'reg'.""" self.i2c.writeto_mem(self.addr, reg, bytes([val])) def update_reg(self, reg, mask, value): """ Read-modify-write: update only the bits specified by mask. """ cur = self.read_reg(reg) new_val = (cur & ~mask) | (value & mask) self.write_reg(reg, new_val) def dump_registers(self, start=0x00, end=0x30): """Dump registers for debugging.""" print("IP5306 Register Dump:") for reg in range(start, end): val = self.read_reg(reg) print(" Reg 0x{:02X} = 0x{:02X}".format(reg, val)) def enable_boost_always_on(self): """ Enable BOOST always-on by setting SYS_CTL0 (0x00) bit1. """ self.update_reg(0x00, 0x02, 0x02) print("BOOST always-on enabled.") def get_charging_status(self): """ Read charging status: - REG_READ0 (0x70) bit3: charging enable flag. - REG_READ1 (0x71) bit3: full-charge flag. """ reg70 = self.read_reg(0x70) reg71 = self.read_reg(0x71) charging = bool(reg70 & (1 << 3)) full = bool(reg71 & (1 << 3)) return {"charging": charging, "full": full} def set_charge_current_detection(self, current_setting): """ Adjust charging current detection via Charger_CTL1 (0x21), bits [7:6]: 0 -> 200mA, 1 -> 400mA, 2 -> 500mA, 3 -> 600mA. For a 200 mA battery, use setting 0. """ if current_setting not in (0, 1, 2, 3): print("Invalid current setting!") return self.update_reg(0x21, 0xC0, current_setting << 6) print("Charge current detection set to", current_setting, "(0=200mA)") def disable_low_power_shutdown(self): """ Disable the low power shutdown by clearing bit0 in SYS_CTL1 (0x01). """ self.update_reg(0x01, 0x01, 0x00) print("Low power shutdown disabled.") # --- 4. Create an IP5306 instance and adjust parameters --- ip5306 = IP5306(i2c) print("Dumping registers for debugging:") ip5306.dump_registers() ip5306.enable_boost_always_on() ip5306.set_charge_current_detection(0) # Set for 200 mA. ip5306.disable_low_power_shutdown() status = ip5306.get_charging_status() print("Initial charging status:", status) print("IP5306 setup complete.") # --- 5. Blink an external LED --- # Since the built-in LED pins (6 or 7) are controlled by the IP5306, # use a free GPIO pin for an external LED. Here, we use GPIO12. external_led = machine.Pin(15, machine.Pin.OUT) external_led.value(0) # Start with LED off. print("Blinking external LED on GPIO15...") while True: external_led.value(1) time.sleep(0.5) external_led.value(0) time.sleep(0.5)
The output to this is
MPY: soft reboot
I2C devices found: [14, 117]
Dumping registers for debugging:
IP5306 Register Dump:
Reg 0x00 = 0x37
Reg 0x01 = 0x1C
Reg 0x02 = 0x64
Reg 0x03 = 0x63
Reg 0x04 = 0x68
Reg 0x05 = 0x00
Reg 0x06 = 0x02
Reg 0x07 = 0xB0
Reg 0x08 = 0xA2
Reg 0x09 = 0xDE
Reg 0x0A = 0x2C
Reg 0x0B = 0x1B
Reg 0x0C = 0x64
Reg 0x0D = 0xAC
Reg 0x0E = 0x00
Reg 0x0F = 0x06
Reg 0x10 = 0xBD
Reg 0x11 = 0x7E
Reg 0x12 = 0xD8
Reg 0x13 = 0x92
Reg 0x14 = 0x80
Reg 0x15 = 0x78
Reg 0x16 = 0x00
Reg 0x17 = 0x00
Reg 0x18 = 0x00
Reg 0x19 = 0x00
Reg 0x1A = 0x00
Reg 0x1B = 0x00
Reg 0x1C = 0x00
Reg 0x1D = 0x00
Reg 0x1E = 0x00
Reg 0x1F = 0x00
Reg 0x20 = 0x01
Reg 0x21 = 0x09
Reg 0x22 = 0x02
Reg 0x23 = 0xBF
Reg 0x24 = 0xD6
Reg 0x25 = 0x00
Reg 0x26 = 0x00
Reg 0x27 = 0x00
Reg 0x28 = 0x00
Reg 0x29 = 0x00
Reg 0x2A = 0x00
Reg 0x2B = 0x00
Reg 0x2C = 0x00
Reg 0x2D = 0x00
Reg 0x2E = 0x00
Reg 0x2F = 0x00
BOOST always-on enabled.
Charge current detection set to 0 (0=200mA)
Low power shutdown disabled.
Initial charging status: {'charging': False, 'full': False}
IP5306 setup complete.
Blinking external LED on GPIO15...After running this, I can remove the USB from the ESP32C6 and the blue led on board the ESP32 will keep blinking.
So what did I learn.
1) Link the Key pin (5) with a GPIO via a 1.2K resistor.
2) Bring this pin LOW for 500ms to turn on the I2C part of the IP-5306I2C.
3) Once we got past the messiness of turning on the I2C, ChatGPT did real
well to work with the registers.
Here is a Chat GPT translation of the I2C portion of the IP5306 12C datasheet.
14. IP5306 I²C Register Documentation
The datasheet includes a section titled “IP5306 寄存器文档” which details the register map and describes the function of each register. Key points include:
14.1 I²C Protocol
- Data Format:
- I²C operates at up to 400 kbps.
- Uses 8-bit addressing and 8-bit data.
- Data is transmitted MSB first.
- Write Operation Example:
- To write 0x5A to register 0x05 at slave address 0xEA (8-bit), the master sends:
- Start → Slave address (0xEA) → ACK from slave → Register address (0x05) → ACK → Data (0x5A) → ACK → Stop.
- To write 0x5A to register 0x05 at slave address 0xEA (8-bit), the master sends:
- Read Operation Example:
- To read from register 0x05, the master first writes the register address then sends a repeated start and reads the data.
14.2 I²C Application Considerations
- The I²C interface must be enabled (by default, the standard IP5306 does not support I²C unless it is the I²C-enabled version).
- When modifying a register, always use a read–modify–write approach to change only the desired bits.
- It is recommended to use the IRQ (interrupt) signal to determine whether the IP5306 is in working or standby mode:
- IRQ = High: Working
- IRQ = High-Impedance: Standby
- Specific register bits:
- Register 0x70 (REG_READ0): Bit 3 indicates whether charging is enabled (1 = charging on).
- Register 0x71 (REG_READ1): Bit 3 indicates battery full status (1 = battery full).
14.3 Register Addresses and Descriptions
- SYS_CTL0 (Address 0x00):
- Bit 5: Boost enable (0 = disable, 1 = enable)
- Bit 4: Charger enable (0 = disable, 1 = enable)
- Bit 2: Enables automatic power-on when a load is inserted (0 = disable, 1 = enable)
- Bit 1: BOOST output always-on function (0 = disable, 1 = enable)
- Bit 0: Key shutdown function (0 = disable, 1 = enable)
- SYS_CTL1 (Address 0x01):
- Bit 7: Controls the selection of the boost control signal (1 = long press, 0 = double short press)
- Bit 6: Controls the selection of the WLED (flashlight) signal (1 = double short press, 0 = long press)
- Bit 5: Short press to switch boost (0 = disable, 1 = enable)
- Bits 4–3: Reserved
- Bit 2: Determines whether boost output is enabled when VIN is disconnected (0 = off, 1 = on)
- Bit 0: Batlow 3.0V low-power shutdown enable (0 = disable, 1 = enable)
- SYS_CTL2 (Address 0x02):
- Bits 3–2: Light-load shutdown time settings (with values corresponding to 8, 16, 32, or 64 seconds)
- Bits 1–0: Reserved
- Charger_CTL0 (Address 0x20):
- Bits 1–0: Charging termination voltage setting (with values corresponding to different cutoff voltages, e.g., 4.2V, 4.3V, 4.35V, 4.4V)
- Charger_CTL1 (Address 0x21):
- Bits 7–6: Battery-side charging current detection setting (e.g., 11 for 600 mA, 10 for 500 mA, 01 for 400 mA, 00 for 200 mA)
- Bits 4–2: Charging undervoltage threshold setting during charging (affecting the output voltage during charging)
- Bit 1–0: Charging constant voltage step-up setting
- Additional registers (REG_READ0, REG_READ1, REG_READ2, REG_READ3):
- Provide status information such as charging enable flag, full-charge flag, light-load flag, and key press flags (double click, long press, short press).
- Data Format:
-
Using a KXTJ3-1057 2x2mm accelerometer using Grok 3 in Micropython
03/08/2025 at 16:24 • 0 commentsI created a board that had 3 functions:
1) Charge a lipo battery and boost the output to 5V with a IP5306 chip.
2) Provide an Audio amp to allow the ESP32-C6 to place files through I2S and out 3V of sound on a single channel.
3) Receive the accelerometer input to moderate the sound being played. The accelerometer is the KXTJ3-1057 3 axis accelerometer.
Here is a 3D rendering of the board.
And the backside with the ESP32-C6 Super Mini.
This was the first time I used the castellated connections to surface mount the board by hand. I am finding the soldering is much quicker than the 40 solder connections needed if I used headers and the package is much sleeker. It also makes the rounding of the connections on the top easier. Lastly, as you can see this is version 5. I finally decided to be more disciplined about my through holes and I made this version breadboard compatible. It is a little wide so it barely fits, but proving out the board is easier than spaghetti wiring.
So I got the board and within an hour I had the LED's going and I also got the accelerometer responding. On my last version I had used attached a ESP32-C3 Supermini and the SDA and SCL pins were overlapping with the internal SPI pins. The accelerometer function was very inconsistent. This time is was smooth as butter. I fired up Grok 3 and got the following code that worked on the first time. I just put a screen shot of the schematic in and this is the code that was output.
import machine import time import struct # Define I2C pins for the KXTJ3-1057 sda_pin = machine.Pin(20) # SDA on GPIO20 scl_pin = machine.Pin(19) # SCL on GPIO19 i2c = machine.I2C(0, scl=scl_pin, sda=sda_pin, freq=400000) # Use I2C0, 400kHz frequency # Define the KXTJ3-1057 I2C address (default is 0x0F, but verify with datasheet or scan) KXTJ3_ADDR = 0x0E # Register addresses (approximate, adjust based on KXTJ3-1057 datasheet) # Common registers for accelerometers like KXTJ3-1057: XOUT_L = 0x06 # Low byte of X-axis data XOUT_H = 0x07 # High byte of X-axis data YOUT_L = 0x08 # Low byte of Y-axis data YOUT_H = 0x09 # High byte of Y-axis data ZOUT_L = 0x0A # Low byte of Z-axis data ZOUT_H = 0x0B # High byte of Z-axis data CTRL_REG1 = 0x1B # Control register 1 (to enable measurement mode) # Function to initialize the KXTJ3-1057 def init_kxtj3(): try: # Scan I2C bus to verify the device is present devices = i2c.scan() if len(devices) == 0: print("No I2C devices found!") return False print("I2C devices found at addresses:", [hex(addr) for addr in devices]) # Check if KXTJ3-1057 is at the expected address if KXTJ3_ADDR not in devices: print(f"KXTJ3-1057 not found at address 0x{KXTJ3_ADDR:02X}") return False # Configure the KXTJ3-1057 (enable measurement mode, set range, etc.) # Example: Enable 2g range and 50Hz output data rate (adjust based on datasheet) i2c.writeto_mem(KXTJ3_ADDR, CTRL_REG1, bytes([0xC0])) # Example value, adjust as needed print("KXTJ3-1057 initialized successfully") return True except Exception as e: print("Error initializing KXTJ3-1057:", e) return False # Function to read acceleration data (X, Y, Z axes) def read_acceleration(): try: # Read 6 bytes (2 bytes each for X, Y, Z) data = i2c.readfrom_mem(KXTJ3_ADDR, XOUT_L, 6) # Unpack 16-bit values (little-endian, signed) x = struct.unpack('<h', data[0:2])[0] # X-axis y = struct.unpack('<h', data[2:4])[0] # Y-axis z = struct.unpack('<h', data[4:6])[0] # Z-axis return x, y, z except Exception as e: print("Error reading acceleration data:", e) return None, None, None # Main loop to read and print accelerometer data if init_kxtj3(): while True: x, y, z = read_acceleration() if x is not None and y is not None and z is not None: print(f"Acceleration - X: {x}, Y: {y}, Z: {z}") else: print("Failed to read acceleration data") time.sleep(0.1) # Read every 100ms (adjust as needed) else: print("Initialization failed. Check connections and I2C address.")
The output of the three axes was super smooth.
Z axis is up and down when the board is flat. Positive when the accelerometer is facing up. +16,800 to -16,800 when stationary.
X axis is highest when the switch is facing down and most negative when the switch is facing up.
Y axis is most positive on the batter connector side and most negative of the right side when looking at the button.
Needless to say, I was stoked to be able to bring up my JLCPCB boards so quickly. The one mistake I made is that I connected the button to the GPIO8 pin. That pin is also used for the WS2812 multicolored LED on the Supermini. That means if you want to play with it, you need to do it before it is put on the PCB. It still works fine as a button though so thank God for small mercies.
-
Littlefs saving files with Thonny MicroPython and ESP32-C6
03/02/2025 at 16:50 • 0 commentsMost Esp32 modules have SPIFFS. This is is usually achieved with and EEPROM that is external to the ESP32 chip. However, some of the smaller packages like the 32 pin C3 or C6 have the flash built into the chip. That is why when you look at the chip there is no shield over it, or at least that is my understanding of it.
The problem with the ESP32-C3 supermini was that the SPI memory had dedicated GPIO for it that were actually broken out on the board. The ESP32-C6 has more pins, so even though the SuperMini has 20 pins broken out to the headers the internal SPI pins are not exposed and overlapping.
I tried to go straight for the Micropython sound creation using I2C. I was able to do this with the ESP32-C3 and a previous version of this board. In fact, I was able to get ChatGPT to write code to play Happy Birthday. However, both ChatGPT and Grok failed me on this one. Looks like the ESP32-C6 driver for Micropython is not updated to run I2S. Grok offer to take me through recompiling the driver to include it but I will try some other options first.Lets first confirm that the LittleFS (Little file system) is working. The ESP32-C6 uses the ESP32-C6H4 chip. It is the 32 pin version that has the memory on board, instead of in a separate flash chip. I asked Grok to write some code to provide that it is working and this is what I go.
import machine import os import time import uos # Define pins for the onboard switch and red LED button_pin = machine.Pin(8, machine.Pin.IN, machine.Pin.PULL_UP) # Onboard switch on GPIO8, with pull-up led_pin = machine.Pin(7, machine.Pin.OUT) # Red LED on GPIO7 # Function to initialize and mount LittleFS def init_littlefs(): try: # Check if LittleFS is already formatted vfs = uos.VfsLfs2 block_size = 4096 # Typical block size for ESP32-C6 flash block_count = 32 # Number of blocks (adjust based on flash size, e.g., 128KB) # Format and mount LittleFS print("Formatting LittleFS...") uos.VfsLfs2.mkfs(block_size, block_count) uos.mount(uos.VfsLfs2(block_size, block_count), "/") print("LittleFS mounted successfully") except Exception as e: print("Error initializing LittleFS:", e) try: # If already formatted, just mount uos.mount(uos.VfsLfs2(block_size, block_count), "/") print("LittleFS mounted successfully (already formatted)") except Exception as e: print("Failed to mount LittleFS:", e) return False return True # Function to write data to a file def write_file(filename, data): try: with open(filename, "w") as f: f.write(data) print(f"Wrote data to {filename}") except Exception as e: print(f"Error writing to {filename}:", e) # Function to read data from a file def read_file(filename): try: with open(filename, "r") as f: data = f.read() print(f"Read from {filename}: {data}") return data except Exception as e: print(f"Error reading from {filename}:", e) return None # Main demo function def littlefs_demo(): # Initialize LittleFS if not init_littlefs(): print("Cannot proceed with demo due to LittleFS failure.") return # Sample data to write sample_data = "Hello, ESP32-C6 LittleFS Demo!\n" filename = "/demo.txt" # Write to file write_file(filename, sample_data) # Read from file read_file(filename) # List directory contents print("Directory contents:", os.listdir("/")) # Main loop to trigger the demo using the onboard switch print("Press the onboard switch (GPIO8) to run the LittleFS demo...") while True: if button_pin.value() == 0: # Button pressed (low when using pull-up) print("Button pressed - Running LittleFS demo") led_pin.value(1) # Turn red LED ON (HIGH) littlefs_demo() led_pin.value(0) # Turn red LED OFF (LOW) time.sleep(1) # Debounce delay to avoid multiple triggers time.sleep(0.01) # Small delay to prevent excessive CPU usage
We got an error this time.
MPY: soft reboot
Press the onboard switch (GPIO8) to run the LittleFS demo...
Button pressed - Running LittleFS demo
Formatting LittleFS...
Error initializing LittleFS: extra positional arguments given
Failed to mount LittleFS: extra positional arguments given
Cannot proceed with demo due to LittleFS failure.Well dropped that into Grok and told it to fix it.
Here was the output.
import machine import os import uos import time # Define pins for the onboard switch and red LED button_pin = machine.Pin(8, machine.Pin.IN, machine.Pin.PULL_UP) # Onboard switch on GPIO8, with pull-up led_pin = machine.Pin(7, machine.Pin.OUT) # Red LED on GPIO7 # Function to initialize and mount LittleFS def init_littlefs(): try: # Check if LittleFS is already mounted try: uos.listdir('/') print("LittleFS is already mounted") return True except OSError: print("LittleFS not mounted, attempting to mount...") # Mount the default LittleFS partition (ESP32-C6 uses a pre-defined partition) try: uos.mount(uos.VfsLfs2(), "/") print("LittleFS mounted successfully") return True except OSError as e: print("Mount failed, attempting to format and mount...") # If no partition exists, format a new LittleFS (use with caution, erases data) # Note: On ESP32, this requires a pre-defined partition in the firmware # For now, we'll assume the partition is set up during firmware build uos.VfsLfs2.mkfs(uos.VfsLfs2()) uos.mount(uos.VfsLfs2(), "/") print("LittleFS formatted and mounted successfully") return True except Exception as e: print("Error initializing LittleFS:", e) return False # Function to write data to a file def write_file(filename, data): try: with open(filename, "w") as f: f.write(data) print(f"Wrote data to {filename}") except Exception as e: print(f"Error writing to {filename}:", e) # Function to read data from a file def read_file(filename): try: with open(filename, "r") as f: data = f.read() print(f"Read from {filename}: {data}") return data except Exception as e: print(f"Error reading from {filename}:", e) return None # Main demo function def littlefs_demo(): # Initialize LittleFS if not init_littlefs(): print("Cannot proceed with demo due to LittleFS failure.") return # Sample data to write sample_data = "Hello, ESP32-C6 LittleFS Demo!\n" filename = "/demo.txt" # Write to file write_file(filename, sample_data) # Read from file read_file(filename) # List directory contents print("Directory contents:", os.listdir("/")) # Main loop to trigger the demo using the onboard switch print("Press the onboard switch (GPIO8) to run the LittleFS demo...") while True: if button_pin.value() == 0: # Button pressed (low when using pull-up) print("Button pressed - Running LittleFS demo") led_pin.value(1) # Turn red LED ON (HIGH) littlefs_demo() led_pin.value(0) # Turn red LED OFF (LOW) time.sleep(1) # Debounce delay to avoid multiple triggers time.sleep(0.01) # Small delay to prevent excessive CPU usage
And yes, success!
Here is the output from the terminal.
Press the onboard switch (GPIO8) to run the LittleFS demo...
Button pressed - Running LittleFS demo
LittleFS is already mounted
Wrote data to /demo.txt
Read from /demo.txt: Hello, ESP32-C6 LittleFS Demo!Directory contents: ['boot.py', 'demo.txt', 'main.py']
Next step, playing some music.
-
Getting to Blinky with Thonny MicroPython and the ESP32-C6
03/02/2025 at 16:19 • 0 commentsI have made the choice to start with Micropython because the burn and learn cycle is so much shorter than ESP-IDF or Arduino. I was concerned that the ESP32-C6 support would not be there yet in Micropython but it is looking good so far.
I started with wanting to blink the LED. The latest ChatGPT and GROK models allow you to attach a picture and they are pretty good an pulling information from it. I have been attaching schematics and with good success and I save on the prompting I have to do. I wanted to try it with this round and attached the Pinout and asked for a blinking LED Micropython script.
I have been using Thonny for my Micropython. I connected the ESP32-C6 and under Tools->Options it recognized the USB port..
Clicking on the install link, I had the ESP32-C6 option. I picked the Espressif version and it installed.
I find Thonny a little cludgy to program. You may have to do some combination of pressing the stop program and the reset on the board. If a program is running it will not allow you to overwrite the main.py script.
ChatGPT provided working code but did not recognize the right pin for the LED. It suggested the builtin LED was on GPIO2 but it was on 15.
So I copied the LED code from ChaptGPT as follows:
from machine import Pin import time # Create a Pin object for the onboard LED (usually GPIO 2 for ESP32 boards) led = Pin(15, Pin.OUT) while True: led.value(1) # Turn the LED on time.sleep(1) # Wait for 1 second led.value(0) # Turn the LED off time.sleep(1) # Wait for 1 second
Saved it to MicroPython Device as main.py and pressed the play button. Blue light is blinking in less then 5 minutes.
I noticed there was another LED on the module with 4 pads and a 8 designator.
The pinout shows this LED to be a WS2812 (Neopixel) and I asked GROK to write me the code to run it.
import machine import neopixel import time # Define the pin for the WS2812 LED (GPIO8) led_pin = machine.Pin(8) # Define the number of NeoPixels (in this case, 1 for the onboard LED) num_pixels = 1 # Create a NeoPixel object np = neopixel.NeoPixel(led_pin, num_pixels) # Function to set the LED to a specific color (RGB values, 0-255 each) def set_color(red, green, blue): np[0] = (red, green, blue) # Set the color for the first (and only) pixel np.write() # Update the LED # Function to cycle through colors (example animation) def cycle_colors(): while True: # Red set_color(255, 0, 0) print("Red") time.sleep(1) # Green set_color(0, 255, 0) print("Green") time.sleep(1) # Blue set_color(0, 0, 255) print("Blue") time.sleep(1) # White set_color(255, 255, 255) print("White") time.sleep(1) # Off (black) set_color(0, 0, 0) print("Off") time.sleep(1) # Run the color cycle cycle_colors()
30 seconds later I have updated the code in the main.py file on the ESP32-C6 and my board lights up like a Christmas tree.
So, if the LLM knows what pin and what type of LED, this is all super smooth.
I unplugged in and connected it to a Voltaic power bank and it blinks away happily.
Note some power banks will shut down because the MCU does not drawing enough power.
The Voltaic will continue to work.