Nordic nRF54L15-DK와 LSM6DSO 센서를 Zephyr RTOS 기반 I²C 연동하기

이 글을 계속 읽기에 앞서, 리눅스 환경에서 Nordic nRF54L15-DK 개발 키트에 Zephyr RTOS를 설치하는 과정을 설명한 이전 글을 참고하시기 바랍니다. 여기에서는 SparkFun 6자유도 센서 LSM6DSO 평가 기판을 이 nRF54L15-DK 개발 키트와 연동하는 과정에 대해 설명하겠습니다. 다음 그림은 두 장치가 어떻게 연결되어 있는지를 보여줍니다.

첫 번째 단계는 다음과 같은 디렉터리 구조를 만들고 Zephyr OS 개발용 파일들을 생성합니다.

|-- CMakeLists.txt
|-- nrf54l15dk_nrf54l15.overlay
|-- prj.conf
`-- src
    `-- main.c

CMakeLists.txt 파일은 다음과 같습니다.

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(blinky)

target_sources(app PRIVATE src/main.c)

proj.conf 파일은 아래와 같습니다 (부동소수점 출력을 지원할 수 있도록 CONFIG_CBPRINTF_FP_SUPPORT를 사용하였습니다).

CONFIG_GPIO=y

CONFIG_I2C=y

CONFIG_CBPRINTF_FP_SUPPORT=y

그리고 가장 중요한 부분은 다음의 오버레이 파일로, I²C 인터페이스를 통해 LSM6DSO 센서를 nRF54L15-DK 개발 키트에서 실행 중인 Zephyr “RTOS” 애플리케이션 (main.c)에 연결해 줍니다. 오버레이 파일에서 I²C 마스터 클록 주파수는 100 kHz 그리고 I²C 슬레이브 주소는 0x6B로 설정되었습니다.

&i2c22 {
    status = "okay";
    pinctrl-0 = <&i2c22_default>;
	pinctrl-1 = <&i2c22_sleep>;
    clock-frequency = <100000>;
    pinctrl-names = "default", "sleep";
    mysensor: mysensor@6b{
        compatible = "i2c-device";
        status = "okay";
        reg = < 0x6b >;
    };
};

&pinctrl {
	/omit-if-no-ref/ i2c22_default: i2c22_default {
		group1  {
			psels = <NRF_PSEL(TWIM_SCL, 1, 11)>,
					<NRF_PSEL(TWIM_SDA, 1, 12)>;
		};
	};

	/omit-if-no-ref/ i2c22_sleep: i2c22_sleep {
		group1  {
			psels = <NRF_PSEL(TWIM_SCL, 1, 11)>,
					<NRF_PSEL(TWIM_SDA, 1, 12)>;
			low-power-enable;
		};
	};
};

main.c 파일은 다음과 같습니다.

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/printk.h>


#define I2C_NODE DT_NODELABEL(mysensor)
static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C_NODE);
#define WHOAMI  0x0F

/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS   1000

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)


static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int main(void)
{


    if (!device_is_ready(dev_i2c.bus)) {
	    printk("I2C bus %s is not ready!\n\r",dev_i2c.bus->name);
	    return -1;
    }

	int ret;
	bool led_state = true;

	if (!gpio_is_ready_dt(&led)) {
		return 0;
	}

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		return 0;
	}

	while (1) {

        uint8_t id = 0;
	    uint8_t regs[] = {WHOAMI};
    
        int ret = i2c_write_read_dt(&dev_i2c, regs, 1, &id, 1);

	    if (ret != 0) {
		    printk("Failed to read register %x \n", regs[0]);
		    return -1;
	    }

	    if (id != 0x6C) {
		    printk("Invalid chip id! %x \n", id);
		    return -1;
	    }
        else {
            printk("Found WHOAMI = %x\n", id);
        }

		ret = gpio_pin_toggle_dt(&led);
		if (ret < 0) {
			return 0;
		}

		led_state = !led_state;
		printf("LED state: %s\n", led_state ? "ON" : "OFF");
		k_msleep(SLEEP_TIME_MS);


        //Read and print values
        uint8_t values[65];
	    ret = i2c_burst_read_dt(&dev_i2c, 0x00, values, 64);
	    if (ret != 0) {
		    printk("Failed to read registers %x \n", 0x00);
		    return;
	    }
        int i = 0;
        while(i < 64)
        {
            printk("Register %x = %x\n", i, values[i]);
            i = i + 1;
        }

	}

	return 0;
}

main.c 코드는 LED를 점멸시키는 동시에 WHOAMI 레지스터를 읽고, 센서 내부 ASIC에 있는 65개의 레지스터 주소를 자동 증가 (버스트) 방식으로 읽어옵니다. 이러한 I²C 트랜잭션은 아래와 같으며, Zephyr OS API와 적절한 매크로 기법을 통해 이루어집니다.

int ret = i2c_write_read_dt(&dev_i2c, regs, 1, &id, 1);
 ret = i2c_burst_read_dt(&dev_i2c, 0x00, values, 64);

이를 컴파일 (빌드)하기 위해 다음 단계를 실행합니다.

(venv) $ west build -p always -b nrf54l15dk/nrf54l15/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=nrf54l15dk_nrf54l15.overlay

그 다음, nRF54L15-DK를 다음과 같이 프로그래밍합니다.

(venv) $ west flash

프로그래밍이 완료되면, 아래와 같이 구성하여 LSM6DSO 평가 기판의 I²C 통신 기능을 시연합니다.

이 영상은 I²C 인터페이스가 LSM6DSO 센서와 통신을 하면 LED가 점멸하는 모습과 함께, 이전 게시글에서 설명한 SparkFun 8채널 USB 로직 분석기로 I²C 통신을 캡처하는 모습을 보여줍니다.

IoT용 nRF54L15-DK 개발 키트는 USB를 통해 호스트 PC에 연결되어 있습니다. SparkFun 로직 분석기가 캡처한 I²C 트랜잭션을 보면 아래와 같이 정상적으로 동작하고 있습니다.

이제 다음 명령으로 minicom 터미널을 열어 nRF54L15-DK가 수신하는 데이터를 모니터링합니다.

minicom -D /dev/ttyACM1

LSM6DSO 평가 기판의 WHO_AM_I (0x0F) 레지스터를 읽으면 아래와 같습니다.

Found WHOAMI = 6c
LED state: ON
Register 0 = 0
Register 1 = 0
Register 2 = 3f
Register 3 = 0
Register 4 = 0
Register 5 = 0
Register 6 = 0
Register 7 = 0
Register 8 = 0
Register 9 = 0
Register a = 0
Register b = 0
Register c = 0
Register d = 0
Register e = 0
Register f = 6c
Register 10 = 0
Register 11 = 0                                                                                                                     
Register 12 = 4                                                                                                                     
Register 13 = 0                                                                                                                     
Register 14 = 0                                                                                                                     
Register 15 = 0
Register 16 = 0
Register 17 = 0
Register 18 = e0
Register 19 = 0
Register 1a = 0
Register 1b = 0
Register 1c = 0
Register 1d = 0
Register 1e = 0
Register 1f = 28
Register 20 = 0
Register 21 = 0
Register 22 = 0
Register 23 = 0
Register 24 = 0
Register 25 = 0
Register 26 = 0
Register 27 = 0
Register 28 = 0
Register 29 = 0
Register 2a = 0
Register 2b = 0
Register 2c = 0
Register 2d = 0
Register 2e = 0
Register 2f = 0
Register 30 = 0
Register 31 = 0
Register 32 = 0
Register 33 = 0
Register 34 = 0
Register 35 = 0
Register 36 = 0
Register 37 = 0
Register 38 = 0
Register 39 = 0
Register 3a = 0
Register 3b = 0
Register 3c = 0
Register 3d = 0
Register 3e = 0
Register 3f = 0
Found WHOAMI = 6c
LED state: OFF

이 글에서는 Nordic nRF54L15-DK 개발 키트에 I²C를 통해 센서를 연결하는 방법을 설명하였습니다. 디지키에서는 여러 IoT 프로젝트에 적용할 수 있는 다양한 I²C 센서를 취급하고 있으며, 이 글에서 설명한 절차를 사용하여 이러한 센서들을 Nordic nRF54L15-DK 개발 키트에 연결할 수 있습니다.

좋은 하루 되세요!



영문 원본: Nordic nRF54L15-DK Zephyr Linux I2C interface to LSM6DSO sensor