I2C 클럭 dtc를 변경할 수 없습니다.

I2C 클럭 dtc를 변경할 수 없습니다.

안녕하세요, 친애하는 친구 여러분,

목표: -> i2c 클럭 주파수를 400kHz로 변경

동기: -> i2c를 통해 Adafruit BNO085를 사용하려고 하는데 rpi i2c 클럭 스트레칭과 관련된 알려진 문제가 있습니다. (이것은 알려진 버그로 2012년부터 계속 돌아다니고 있습니다. 예!)

내가 시도한 것: 나는 이 주제를 읽고 Ubuntu 22.04 서버(헤드리스)를 실행하는 라즈베리 파이 4b에서 i2c 클럭 주파수를 변경하려고 여러 번 시도하는 데 이틀 동안 좋은 시간을 보냈습니다.

저는 rasbian을 사용하지 않기 때문에 boot-config 파일의 한 줄만 편집할 수는 없습니다. 하지만 오히려 장치 트리 파일을 분해하고 수정하고 다시 컴파일해야 합니다.

이 튜토리얼을 따랐습니다. Ubuntu 20.04 Raspberry Pi에서 SPI 및 I2C 활성화

이 파일에 적용됩니다:

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

이 명령을 사용하여 분해했습니다.

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

그런 다음 해당 .dts(device-tree-source)에서 이러한 영역을 수정했습니다.

다음 두 코드 청크에서 교체했습니다.

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

~와 함께

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

블록 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>;
};

그리고 블록 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>;
};

더 아래로 다음 코드 블록을 수정했습니다.

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

여기서는 전체재정의차단하다

__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>;
};

그 후 다음 명령을 사용하여 .dts 파일을 다시 .dtb로 다시 컴파일했습니다.

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

그런 다음 파일을 원래 있던 디렉터리에 다시 복사하고 기존 파일을 덮어썼습니다. 물론 백업이 있습니다.

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

하지만 여전히 작동하지 않습니다. Adafruit에서 Python 테스트 파일을 실행할 때 다음 오류가 발생합니다.

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

이것은 제가 실행하려는 프로그램입니다. adafruit 문서에 따르면 i2c-clock-주파수가 400kHz여야 합니다.

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("")

그리고 예, 스크립트에서 볼 수 있듯이 100000과 400000을 모두 사용해 보았습니다.

그리고 여기에 충돌이 발생하고 오류 추적이 생성되기 전에 생성되는 출력이 있습니다. 이는 더 아래에서 찾을 수 있습니다. 반복되는 정보로 인해 출력이 크게 편집되었습니다. 일반적으로 충돌이 발생하기 전 약 10~15초 동안 실행됩니다. 버퍼가 가득 차있을 수 있습니까?

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]}

마지막으로 위 출력의 10~15초 후에 나타나는 오류 추적은 다음과 같습니다.

        ********** 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

내가 무엇을 놓치고 있는지 잘 모르겠습니다. 이 시점에서는 내 버스가 실제로 클럭 주파수를 변경했는지 확실하지 않습니다. 아는 사람 있나요:

  1. Ubuntu 22.04(raspbian 아님)를 실행하는 rpi 4b에서 i2c의 클럭 주파수를 확인하는 방법
  2. 내가 무엇을 놓치고 있는지, 여기서 무엇이 문제인가요?

답변1

나는 이 문제를 해결할 수 있었고 다음과 같은 다른 사람을 위해 솔루션을 게시하고 싶었습니다.

  1. 우분투를 실행하는 라즈베리 파이가 있습니다
  2. i2c 클럭 속도를 100000에서 400000으로 변경해야 합니다.

dts와 dtb를 살펴본 후 단순히 dt-overlay를 사용하기로 결정했습니다.

먼저 "i2c1-주파수-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)
        };
    };
};

두 번째로 다음을 사용하여 이 파일을 컴파일했습니다.

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

이렇게 하면 dtb 파일이 생성됩니다.

i2c1-frequency-overlay.dtbo

그런 다음 /boot/firmware/overlays/에 복사되었습니다.

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

다음으로 /boot/firmware/config.txt를 수정했습니다.

sudo nano /boot/firmware/config.txt

그리고 다음을 추가했습니다.

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

마지막 단계 재부팅

sudo reboot

업데이트된 i2c 클럭 주파수를 확인하려면 다음을 수행하세요.

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

좀 더 조사한 결과 다음을 발견했습니다.

// 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

-> 이는 버스가 400kHz임을 확인합니다 :-)

관련 정보