No se puede cambiar el dtc del reloj I2C

No se puede cambiar el dtc del reloj I2C

Buenas tardes queridos amigos,

El objetivo: -> Cambiar la frecuencia del reloj i2c a 400kHz

La motivación: -> Intento usar Adafruit BNO085 a través de i2c y hay problemas conocidos con el estiramiento del reloj rpi i2c. (Este es un error conocido, ha estado presente desde 2012. ¡Sí!)

Qué he probado: Pasé dos días leyendo este tema e intentando varias veces cambiar la frecuencia del reloj i2c en mi raspberry pi 4b con Ubuntu 22.04 Server (sin cabeza).

Como no uso rasbian, NO puedo simplemente editar una línea en mi archivo de configuración de arranque. Más bien tengo que desmontar, modificar y recompilar un archivo de árbol de dispositivos.

Seguí este tutorial: Habilite SPI e I2C en Ubuntu 20.04 Raspberry Pi

Aplicado a este archivo:

/boot/dtbs/5.15.0-1033-raspi/bcm2711-rpi-4-b.dtb

Usé este comando para desmontar:

dtc -I dtb -O dts -o bcm2711-rpi-4-b.dts /boot/dtbs/5.15.0-1033-raspi/bcm2711-rpi-4-b.dtb

Luego modifiqué estas áreas en ese .dts (device-tree-source)

en los siguientes dos fragmentos de código reemplacé

clock-frequency = <0x186a0>; // 100000

con

clock-frequency = <0x61a80>; // 400000

Bloque 1

i2c@7e205000 {
compatible = "brcm,bcm2711-i2c\0brcm,bcm2835-i2c";
reg = <0x7e205000 0x200>;
interrupts = <0x00 0x75 0x04>;
clocks = <0x08 0x14>;
#address-cells = <0x01>;
#size-cells = <0x00>;
status = "disabled";
#clock-frequency = <0x186a0>; // 100000
clock-frequency = <0x61a80>; // 400000
phandle = <0x10>;
};

y también el Bloque 2

i2c@7e804000 {
compatible = "brcm,bcm2711-i2c\0brcm,bcm2835-i2c";
reg = <0x7e804000 0x1000>;
interrupts = <0x00 0x75 0x04>;
clocks = <0x08 0x14>;
#address-cells = <0x01>;
#size-cells = <0x00>;
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <0x18>;
#clock-frequency = <0x186a0>; // 100000
clock-frequency = <0x61a80>; // 400000
phandle = <0x36>;
};

Más abajo modifiqué el siguiente bloque de código:

#i2c1_baudrate = "\0\0\06clock-frequency:0"; // modified this
i2c1_baudrate = "\0\0\06clock-frequency:400000"; // modified this

Aquí todoanulaBloquear

__overrides__ {
cam0-pwdn-ctrl;
cam0-pwdn;
cam0-led-ctrl;
cam0-led;
krnbt = "\0\0\00status";
krnbt_baudrate = "\0\0\00max-speed:0";
cache_line_size;
uart0 = "\0\0\01status";
uart1 = "\0\0\02status";
i2s = "\0\0\03status";
spi = "\0\0\04status";
i2c0 = [00 00 00 10 73 74 61 74 75 73 00 00 00 00 35 73 74 61 74 75 73 00];
i2c1 = "\0\0\06status";
i2c0_baudrate = [00 00 00 10 63 6c 6f 63 6b 2d 66 72 65 71 75 65 6e 63 79 3a 30 00];  // left this alone
#i2c1_baudrate = "\0\0\06clock-frequency:0"; // modified this
i2c1_baudrate = "\0\0\06clock-frequency:400000"; // modified this
audio = "\0\0\07status";
watchdog = "\0\0\08status";
random = "\0\0\09status";
sd_overclock = "\0\0\0:brcm,overclock-50:0";
sd_force_pio = "\0\0\0:brcm,force-pio?";
sd_pio_limit = "\0\0\0:brcm,pio-limit:0";
sd_debug = "\0\0\0:brcm,debug";
sdio_overclock = "\0\0\0;brcm,overclock-50:0\0\0\0\0<brcm,overclock-50:0";
axiperf = "\0\0\0=status";
arm_freq;
act_led_gpio = "\0\0\0>gpios:4";
act_led_activelow = "\0\0\0>gpios:8";
act_led_trigger = "\0\0\0>linux,default-trigger";
pwr_led_gpio = "\0\0\0?gpios:4";
pwr_led_activelow = "\0\0\0?gpios:8";
pwr_led_trigger = "\0\0\0?linux,default-trigger";
eth_led0 = "\0\0\0/led-modes:0";
eth_led1 = "\0\0\0/led-modes:4";
sd_poll_once = "\0\0\0@non-removable?";
spi_dma4 = <0x34 0x646d6173 0x3a303d00 0x41 0x34 0x646d6173 0x3a383d00 0x41>;
};

después de eso volví a compilar el archivo .dts en .dtb usando este comando:

dtc -I dts -O dtb -o bcm2711-rpi-4-b.dtb bcm2711-rpi-4-b.dts

y luego copió el archivo nuevamente en el directorio donde se encontró originalmente y sobrescribió el archivo existente. Por supuesto que tengo una copia de seguridad.

sudo cp bcm2711-rpi-4-b.dtb /boot/dtbs/5.15.0-1033-raspi/bcm2711-rpi-4-b.dtb

Pero todavía no funciona. Al ejecutar el archivo de prueba de Python desde Adafruit aparece el siguiente error:

python3 imu_v2.py 

        ********** Packet *************
DBG::        HEADER:
DBG::        Data Len: 17
DBG::        Channel: CONTROL (2)
DBG::           ** UNKNOWN Report Type **: 0x7c
DBG::        Sequence number: 19

DBG::        Data:
DBG::       [0x04] 0x7C 0x05 0x00 0x00 
DBG::       [0x08] 0x00 0x50 0xC3 0x00 
DBG::       [0x0C] 0x00 0x00 0x00 0x00 
DBG::       [0x10] 0x00 0x00 0x00 0x00 
DBG::       [0x14] 0x00 
        *******************************

Traceback (most recent call last):
  File "/home/administrator/Documents/raspberrypi_software/python/src/imu_v2.py", line 19, in <module>
    bno.enable_feature(BNO_REPORT_ROTATION_VECTOR)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 999, in enable_feature
    self._process_available_packets(max_packets=10)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 803, in _process_available_packets
    self._handle_packet(new_packet)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 863, in _handle_packet
    raise error
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 858, in _handle_packet
    _separate_batch(packet, self._packet_slices)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 373, in _separate_batch
    required_bytes = _report_length(report_id)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 362, in _report_length
    return _AVAIL_SENSOR_REPORTS[report_id][2]
KeyError: 124

Este es el programa que estoy intentando ejecutar, que según la documentación de adafruit requerirá que la frecuencia del reloj i2c esté a 400 kHz.

import time
import board
import busio
from adafruit_bno08x import (
    BNO_REPORT_ACCELEROMETER,
    BNO_REPORT_GYROSCOPE,
    BNO_REPORT_MAGNETOMETER,
    BNO_REPORT_ROTATION_VECTOR,
)
from adafruit_bno08x.i2c import BNO08X_I2C

i2c = busio.I2C(board.SCL, board.SDA, frequency=400000)
#i2c = busio.I2C(board.SCL, board.SDA, frequency=100000)
bno = BNO08X_I2C(i2c)

bno.enable_feature(BNO_REPORT_ACCELEROMETER)
bno.enable_feature(BNO_REPORT_GYROSCOPE)
bno.enable_feature(BNO_REPORT_MAGNETOMETER)
bno.enable_feature(BNO_REPORT_ROTATION_VECTOR)

while True:
    time.sleep(0.5)

    imu_data = {}

    accel_x, accel_y, accel_z = bno.acceleration  # pylint:disable=no-member
    imu_data["linear_acceleration"] = {"x": accel_x, "y": accel_y, "z": accel_z}

    gyro_x, gyro_y, gyro_z = bno.gyro  # pylint:disable=no-member
    imu_data["angular_velocity"] = {"x": gyro_x, "y": gyro_y, "z": gyro_z}

    mag_x, mag_y, mag_z = bno.magnetic  # pylint:disable=no-member
    imu_data["magnetic_field"] = {"x": mag_x, "y": mag_y, "z": mag_z}

    quat_i, quat_j, quat_k, quat_real = bno.quaternion  # pylint:disable=no-member
    imu_data["orientation"] = {"x": quat_i, "y": quat_j, "z": quat_k, "w": quat_real}

    # Populate the 3x3 covariance matrices with zeros (assuming no covariance)
    imu_data["orientation_covariance"] = [0.0] * 9
    imu_data["angular_velocity_covariance"] = [0.0] * 9
    imu_data["linear_acceleration_covariance"] = [0.0] * 9

    print(imu_data)
    print("")

Y sí, lo intenté con 100000 y 400000 como puedes ver en el script.

Y aquí el resultado que produce, antes de que falle y produzca un seguimiento de error, que se puede encontrar más abajo. Tenga en cuenta que el resultado está muy redactado debido a la información repetitiva. Por lo general, dura entre 10 y 15 segundos antes de fallar. ¿Podría estar llenándose algún buffer?

administrator@hostname:~/Documents/raspberrypi_software/python/src$ python3 imu_v2.py 
{'linear_acceleration': {'x': 0.3046875, 'y': -0.11328125, 'z': 9.578125}, 'angular_velocity': {'x': 0.001953125, 'y': 0.0, 'z': 0.0}, 'magnetic_field': {'x': -4.0, 'y': -9.5625, 'z': 54.4375}, 'orientation': {'x': -0.005615234375, 'y': -0.01409912109375, 'z': 0.0001220703125, 'w': 0.9998779296875}, 'orientation_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'angular_velocity_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'linear_acceleration_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}

{'linear_acceleration': {'x': 0.26953125, 'y': -0.11328125, 'z': 9.58203125}, 'angular_velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0}, 'magnetic_field': {'x': -4.75, 'y': -11.375, 'z': 49.75}, 'orientation': {'x': -0.00567626953125, 'y': -0.01416015625, 'z': 6.103515625e-05, 'w': 0.9998779296875}, 'orientation_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'angular_velocity_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'linear_acceleration_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}

<data ommited>
    Large chunk of data ommited due to character limit
</data ommited>

{'linear_acceleration': {'x': 0.3046875, 'y': -0.15234375, 'z': 9.578125}, 'angular_velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0}, 'magnetic_field': {'x': -4.0, 'y': -9.9375, 'z': 54.1875}, 'orientation': {'x': -0.0064697265625, 'y': -0.015380859375, 'z': -6.103515625e-05, 'w': 0.9998779296875}, 'orientation_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'angular_velocity_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'linear_acceleration_covariance': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}

Y finalmente, el seguimiento del error que aparece después de 10 a 15 segundos del resultado anterior:

        ********** Packet *************
DBG::        HEADER:
DBG::        Data Len: 191
DBG::        Channel: INPUT_SENSOR_REPORTS (3)
DBG::           Report Type: BASE_TIMESTAMP (0xfb)
DBG::           Sensor Report Type: ACCELEROMETER(0x1)
DBG::        Sequence number: 87

DBG::        Data:
DBG::       [0x04] 0xFB 0xFB 0x12 0x00 
DBG::       [0x08] 0x00 0x01 0xE1 0x02 
DBG::       [0x0C] 0x00 0x45 0x00 0xE3 
DBG::       [0x10] 0xFF 0x95 0x09 0x03 
DBG::       [0x14] 0xD1 0x00 0x16 0xB4 
DBG::       [0x18] 0xFF 0x56 0xFF 0x44 
DBG::       [0x1C] 0x03 0x05 0xD0 0x00 
DBG::       [0x20] 0x7A 0x99 0xFF 0x00 
DBG::       [0x24] 0xFF 0x00 0x00 0x7E 
DBG::       [0x28] 0xBF 0x44 0x32 0x01 
DBG::       [0x2C] 0xE2 0x06 0x3D 0x4E 
DBG::       [0x30] 0x00 0xE3 0xFF 0x94 
DBG::       [0x34] 0x09 0x02 0xD2 0x04 
DBG::       [0x38] 0x3F 0x00 0x00 0x00 
DBG::       [0x3C] 0x00 0x00 0x00 0x03 
DBG::       [0x40] 0xD2 0x08 0x0B 0xBA 
DBG::       [0x44] 0xFF 0x56 0xFF 0x2B 
DBG::       [0x48] 0x03 0x05 0xD1 0x08 
DBG::       [0x4C] 0x6F 0x98 0xFF 0x00 
DBG::       [0x50] 0xFF 0x00 0x00 0xFE 
DBG::       [0x54] 0x3F 0x44 0x32 0x01 
DBG::       [0x58] 0xE3 0x0A 0x78 0x4E 
DBG::       [0x5C] 0x00 0xD9 0xFF 0x94 
DBG::       [0x60] 0x09 0x02 0xD3 0x0C 
DBG::       [0x64] 0x37 0x00 0x00 0x00 
DBG::       [0x68] 0x00 0x00 0x00 0x01 
DBG::       [0x6C] 0xE4 0x0E 0xB6 0x45 
DBG::       [0x70] 0x00 0xE3 0xFF 0x95 
DBG::       [0x74] 0x09 0x03 0xD3 0x10 
DBG::       [0x78] 0x00 0xBA 0xFF 0x5B 
DBG::       [0x7C] 0xFF 0x38 0x03 0x05 
DBG::       [0x80] 0xD2 0x10 0x63 0x98 
DBG::       [0x84] 0xFF 0x00 0xFF 0x00 
DBG::       [0x88] 0x00 0xFE 0x3F 0x44 
DBG::       [0x8C] 0x32 0x01 0xE5 0x12 
DBG::       [0x90] 0xF7 0x4E 0x00 0xE3 
DBG::       [0x94] 0xFF 0x8A 0x09 0x02 
DBG::       [0x98] 0xD4 0x14 0x2C 0x00 
DBG::       [0x9C] 0x00 0x00 0x00 0x00 
DBG::       [0xA0] 0x00 0x03 0xD4 0x14 
DBG::       [0xA4] 0xF4 0xB4 0xFF 0x5B 
DBG::       [0xA8] 0xFF 0xB1 0x03 0x01 
DBG::       [0xAC] 0xE6 0x1A 0x36 0x4E 
DBG::       [0xB0] 0x00 0xE3 0xFF 0x94 
DBG::       [0xB4] 0x04 0xFF 0xFF 0xFF 
DBG::       [0xB8] 0xFF 0xFF 0xFF 0xFF 
DBG::       [0xBC] 0xFF 0xFF 0xFF 0xFF 
DBG::       [0xC0] 0xFF 0xFF 0xFF 
        *******************************
        
Traceback (most recent call last):
  File "/home/administrator/Documents/raspberrypi_software/python/src/imu_v2.py", line 26, in <module>
    accel_x, accel_y, accel_z = bno.acceleration  # pylint:disable=no-member
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 598, in acceleration
    self._process_available_packets()
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 803, in _process_available_packets
    self._handle_packet(new_packet)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 863, in _handle_packet
    raise error
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 858, in _handle_packet
    _separate_batch(packet, self._packet_slices)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 373, in _separate_batch
    required_bytes = _report_length(report_id)
  File "/home/administrator/.local/lib/python3.10/site-packages/adafruit_bno08x/__init__.py", line 364, in _report_length
    return _REPORT_LENGTHS[report_id]
KeyError: 255

No estoy seguro de lo que me estoy perdiendo. En este punto, todavía no estoy seguro de si mi autobús realmente cambió la frecuencia del reloj. Alguien sabe:

  1. cómo verificar la frecuencia del reloj de i2c en rpi 4b ejecutando Ubuntu 22.04 (NO raspbian)
  2. lo que me falta, ¿qué pasa aquí?

Respuesta1

Pude resolver este problema y quería publicar la solución para cualquiera que:

  1. tiene una raspberry pi ejecutando Ubuntu
  2. necesita cambiar la velocidad del reloj i2c (de 100000 a 400000)

Después de esta incursión en dts y dtb, se decidió simplemente utilizar dt-overlays.

Primero creé un nuevo archivo "i2c1-frequency-overlay.dts"

// i2c1-frequency-overlay.dts
/dts-v1/;
/plugin/;
/ {
    compatible = "brcm,bcm2711";
    fragment@0 {
        target = <&i2c1>;
        __overlay__ {
            clock-frequency = <400000>; // Set your desired frequency here (e.g., 400 kHz)
        };
    };
};

Segundo, compilé este archivo usando:

dtc -I dts -O dtb -o i2c1-frequency-overlay.dtbo i2c1-frequency-overlay.dts

Esto creó el archivo dtb.

i2c1-frequency-overlay.dtbo

que luego se copió en /boot/firmware/overlays/

sudo cp i2c1-frequency-overlay.dtbo /boot/firmware/overlays/

Luego modifiqué /boot/firmware/config.txt

sudo nano /boot/firmware/config.txt

y añadió lo siguiente:

# Added below to change i2c frequency from 100kHz [default] to 400kHz [fast mode]
dtparam=i2c_arm_baudrate=400000
dtoverlay=i2c1-frequency-overlay

Reinicio del último paso

sudo reboot

Sólo para verificar la frecuencia del reloj i2c actualizada:

// this did not work:
cat /sys/class/i2c-adapter/i2c-1/of_node/clock-frequency

Investigué un poco más y encontré lo siguiente

// but this worked
echo 0x$(xxd /sys/class/i2c-adapter/i2c-1/of_node/clock-frequency | cut -f 2,3 -d ' ' --output-delimiter='') | xargs printf "%d\n"
-bash: warning: command substitution: ignored null byte in input
400000

-> esto confirma que el bus está a 400kHz :-)

información relacionada