Zephyr OS en Raspberry Pico 2 I2C interfaz al SPARKFUN 9DOF IMU (Linux) Parte 3

En el artículo anterior Zephyr OS en la Raspberry Pico 2 con interfaz I2C al SPARKFUN 9DOF IMU (Linux) Parte 2 - foro en español - DigiKey TechForum - An Electronic Component and Engineering Solution Forum, se demonstro como conectar al TDK ICM-2094 de Sparkfun para rastrear las direcciones de los artefactos esclavos conectados a la linea I2C desde el shell del sistema operativo Zephyr. En este artículo, el proceso de construcción del sistema operativo Zephyr, con los archivos esenciales y la estructura del directorio sera descrita para el Raspberry Pico 2. Primero, se abre un terminal minicom que se puede usar luego desde la salida del Raspberry Pico 2 that correr el sistema operativo Zephyr.

$ minicom -D /dev/ttyACM0

Welcome to minicom 2.8

OPTIONS: I18n 
Port /dev/ttyACM0, 12:41:43

Press CTRL-A Z for help on special keys

Desde el directorio Zephyr, se crea un directorio llamado myproject, entonces dentro de ese directorio se crean los siguientes archivos,

El archivo de CMake llamado CMakeLists.txt,

cmake_minimum_required(VERSION 3.25.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(i2c_scanner)
target_sources(app PRIVATE src/main.c)

El sistema operativo Zephyr llamado prj.conf,

CONFIG_I2C=y

El archivo del sistema operativo de Zephyr llamado “Overlay file” en este caso nombrado RP2350.overlay que define el puerto de I2C en este caso puerto 0 en el Raspberry Pico 2,

/ {
    aliases {
        scan-i2c = &i2c0;
    };
};

El programa main.c que reside dentro del subdirectorio llamado src.

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

#define CONFIG_I2C_SCAN_ADDR_START 0x00
#define CONFIG_I2C_SCAN_ADDR_STOP  0x99

static const struct device *scan_dev = DEVICE_DT_GET(DT_ALIAS(scan_i2c));

int main(void)
{
    k_sleep(K_SECONDS(5));
    if (!scan_dev) {
        printk("I2C: Device driver not found.\n");
        return -1;
    }

    printk("*** Digikey I2C scanner started ***\n");
    printk("Board:           %s\n", CONFIG_BOARD);
    printk("I2C device:      %s\n", scan_dev->name);

    /* Print pin information if available in devicetree */

    if (!device_is_ready(scan_dev)) {
        printk("I2C device not ready\n");
        return -1;
    }

    printk("Digikey Scanning on I2C bus...\n\n");

    printk("    | 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f |\n");
    printk("****|*********************************************************************************");

    uint8_t error = 0u;
    uint8_t dst;
    uint8_t i2c_dev_cnt = 0;
    struct i2c_msg msgs[1];
    msgs[0].buf = &dst;
    msgs[0].len = 1U;
    msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;
    uint16_t slave_addr = 0;

    /* Use the full range of I2C address for display purpose */
    for (uint16_t x = 0; x <= 0x7f; x++) {
        /* New line every 0x10 address */
        if (x % 0x10 == 0) {
            printk("|\n0x%02x| ",x);
        }
        /* Range the test with the start and stop value configured in the kconfig */
        if (x >= CONFIG_I2C_SCAN_ADDR_START && x <= CONFIG_I2C_SCAN_ADDR_STOP)	{
            /* Send the address to read from */
            error = i2c_transfer(scan_dev, &msgs[0], 1, x);
                /* I2C device found on current address */
                if (error == 0) {
                    printk("0x%02x ",x);
                    slave_addr = x;
                    ++i2c_dev_cnt;
                }
                else {
                    printk("#### ");
                }
        } else {
            /* Scan value out of range, not scanned */
            printk("     ");
        }
        k_sleep(K_MSEC(15));
    }
    printk("|\n");
    printk("\nI2C device(s) found on the bus by Digikey: %d\nScanning complete!\n\n", i2c_dev_cnt);
    
}

La estructura del directorio completo llamado myproject será como sigue,

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

Ahora en este punto, se construye la aplicación dentro de el sistema operativo Zephyr OS application for the Raspberry Pico 2 usando el archivo RP2350.overlay como se muestra a continuación,

(venv) $ west build -p always -b rpi_pico2/rp2350a/m33 -S cdc-acm-console -- -DCONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y -DEXTRA_DTC_OVERLAY_FILE=RP2350.overlay

El Sparkfun 8-channel USB Logic Analyzer previously descrito previamente en este Techforum article se confifguro como se muestra en la siguiente figura usando los cables Qwiic para monitorear la linea de I2C usando la fuente apropiada de voltaje, PIN6 (SDA), PIN7 (SCL) (I2C Port 0) and PIN 38 (GND) en el Raspberry Pico 2 como se muestra a continuación,

y el “Setup” establecido en la plataforma de evaluación "bread board " de Digikey,

El Sparkfun 8-channel USB Logic Analyzer fue conectado al SCL y SDA (Señales de la linea I2C) y el GND (Ground) como se muestra previamente (No la forma óptima de conectarlo debido al extenso largo de los cables, que aumenta la constante de tiempo Rc, etc, perturbando la linea de I2C. Ahora se procede a programar la aplicación dentro de la Raspberry Pico 2

(venv) $ west flash --runner uf2

En el terminal minicom la salida se muestra de la Raspberry Pico 2 como se muestra a continuación,

*** Booting Zephyr OS build v4.2.0-5176-ge5838ffc2176 ***
*** Digikey I2C scanner started ***
Board:           rpi_pico2
I2C device:      i2c@40090000
Digikey Scanning on I2C bus...

    | 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f |
****|*********************************************************************************|
0x00| #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### |
0x10| #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### |
0x20| #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### |
0x30| #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### |
0x40| #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### |
0x50| #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### |
0x60| #### #### #### #### #### #### #### #### #### 0x69 #### #### #### #### #### #### |
0x70| #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### |

I2C device(s) found on the bus by Digikey: 1
Scanning complete!

El sensor esclavo en la linea I2C se registro con una dirección de I2C de 0x69 por la aplicación corriendo el sistema operativo Zephyr en la Raspberry Pico 2.. También el artefacto de I2C: i2c@40090000 usado en el previo artículo. Para verificar esto, el Sparkfun 8-channel USB Logic Analyzer fue configurado para mostrar solamente 2 canales, con una frequencia de colección de 4 MHz, 100 millones de muestras usando el decodificador I2C. El siguiente conjunto de figuras fueron capturadas por el Sparkfun 8-channel USB Logic Analyzer mientras la aplicación de Zephyr OS fue “reset”. La primera captura de I2C muestra la secuencia de direcciones de I2C enviadas por el principal de I2C dentro de la aplicación de Zephyr lmain.c

Viendo de mas cerca el mensaje de I2C en la linea enviada por el Raspberry Pico 2 para el case de la dirección I2C de 0x80 de rastreo, muestra un NACK (In Red below) no “Acknowledgement” del sensor I2C que se encuentra en la linea.

Finalmente, para verifcar el caso donde el artefacto de I2C conectado en la linea en la dirección de 0x69 ha sido detectado, muestra claramente el “Acknowledgement” (Mostrado en violeta abajo) a la Raspberry Pico 2 corriendo el sistema operativo Zephyr,

Se ha descrito como se configura en la aplicación de Zephyr OS la interfaz I2C utilizando el Raspberry Pico 2 a el TDK ICM-20984 de Sparkfun. Que tenga un buen día!

Este artículo esta disponible en ingles aquí.

This articule is also available in english here.

1 Like