• Using a KXTJ3-1057 2x2mm accelerometer using Grok 3 in Micropython

    shane.snipe21 小時前 0 comments

    I 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...
    Read more »

  • Littlefs saving files with Thonny MicroPython and ESP32-C6

    shane.snipe7 天前 0 comments

    Most 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...

    Read more »

  • Getting to Blinky with Thonny MicroPython and the ESP32-C6

    shane.snipe7 天前 0 comments

    I 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.