Close

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

A project log for ESP32-C6 Exploration

Putting the ESP32-C6 Supermini though its paces. Is it worth using? How much does AI help me learn the chip quickly?

shanesnipeshane.snipe a day ago0 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 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.

Discussions