¿Cómo leer los datos de este sensor?

Estoy usando el Magnetómetro IC MLX90393 de Melexis. Más específicamente, estoy usando la placa de ruptura de Sparkfun . Todavía soy un principiante en lo que respecta a la programación, y esta es la primera vez que intento leer datos a través de I2C. Me aseguré de progresar lentamente (comencé cambiando los LED, luego escribiendo en los LCD, etc.) y ahora quiero probar la detección. Sin embargo, estoy realmente luchando con esto. He leído el protocolo I2C muchas veces para tratar de entenderlo y creo que estoy empezando a hacerlo.

Estoy usando una placa Nucleo STM32F303K8 para comunicarme con el IC. Estoy usando un LDC serial estándar de 16x2 para mostrar información. El IDE que estoy usando es mbed (es gratis y lo he usado antes, y no es complicado, y no requiere nada más que una PC, placa Nucleo y cable USB)

Por ahora, todo lo que quiero hacer es poder leer los datos. Busqué en el sitio web de mbed códigos de ejemplo para comenzar y no encontré ninguno. Ni siquiera puedo encontrar una biblioteca, aunque su guía de inicio rápido (no puede encontrar un enlace, solo descarga automáticamente un PDF) afirma que hay uno en el sitio de mbed. He podido encontrar 2 en otros lugares, uno AQUÍ de GitHub y otro AQUÍ para ESP32. El problema es que ambos son ejemplos del uso de diferentes equipos. El ESP32 está escrito para Arduino, y no quiero quedarme atrapado haciendo Arduino para siempre, así que prefiero no usarlo. He intentado convertirlo para usarlo con mbed pero obviamente no he tenido éxito. Intenté lo mismo con el código de GitHub, pero tampoco tuve éxito con eso.

Al revisar estos dos ejemplos, intenté descifrarlos y convertirlos para usarlos en mbed y obtuve el siguiente código:

CÓDIGO ACTUALIZADO A LA VERSIÓN ACTUAL USO.

#include "mbed.h"

int addr = 0x0C <<1; // 8bit I2C address

I2C i2c(PB_7 , PB_6);   //sda, scl

Serial pc(PA_9, PA_10); //Tx/Rx

int main()
{
    char config [4];
    char data[7] = {0};

    config[0] = 0x60;
    config[1] = 0x00;
    config[2] = 0x5C;
    config[3] = 0x00;

    i2c.write(addr, config, 4, false);

    i2c.read(addr, data, 1);

    config[0] = 0x60;
    config[1] = 0x02;
    config[2] = 0xB4;
    config[3] = 0x02;

    i2c.write(addr, config, 4, false);

    i2c.read(addr, data, 1);

    wait(0.25);

    while (1) {

        config[0] = 0x3E; // Single measurement mode, ZYX enabled

        i2c.write(addr, config, 1, false);
        i2c.read(addr, data, 1);

        wait(0.1);

        config[0] = 0x4E;

        i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set
        i2c.read(addr, data, 7); 

        if(i2c.read(addr, data, 7) == !7) {
            printf("ERROR \n");
        } else {
            int xMag = i2c.read(data[1] * 256 + data[2]);
            int yMag = i2c.read(data[3] * 256 + data[4]);
            int zMag = i2c.read(data[5] * 256 + data[6]);

            printf("X Axis = %d \n", xMag);
            printf("Y Axis = %d \n", yMag);
            printf("Z Axis = %d \n", zMag);
        }
        wait(5);
    }
}

Ejecuté el código Arduino en el hardware STM32 y logré mostrar los datos en un monitor en serie. Cuando ejecuto mi código, obtengo -1 lectura en los 3 ejes.

He analizado las líneas de datos y puedo confirmar que las líneas SDA y SCL coinciden con las del código Arduino en funcionamiento, por lo que la mayoría de esto funciona. Parece que estoy descifrando los datos incorrectamente o mostrándolos incorrectamente. Uno de esos 2 como el monitor serial muestra algo incorrecto. Esto significa que todo es correcto hasta aquí:

if(i2c.read(addr, data, 7) == !7) {
                printf("ERROR \n");
            } else {
                int xMag = i2c.read(data[1] * 256 + data[2]);
                int yMag = i2c.read(data[3] * 256 + data[4]);
                int zMag = i2c.read(data[5] * 256 + data[6]);

                printf("X Axis = %d \n", xMag);
                printf("Y Axis = %d \n", yMag);
                printf("Z Axis = %d \n", zMag);
            }

Este bit no parece estar haciendo lo que debería. Todo lo demás funciona como debería, se leen y escriben los registros correctos y se devuelven los datos. Lo he confirmado comparando las señales con la versión del código Arduino que funciona .

Antes de preguntar '¿Puede medir este bit?' o '¿Puede medir eso?', lea los registros completos del chat AQUÍ y AQUÍ , que mostrarán todo lo que he hecho hasta ahora para llegar a este punto.

Solo necesito saber cómo hacer que funcione ese último bit para mostrar la información correctamente.

Los comentarios no son para una discusión extensa; esta conversación se ha movido a chat .
Inserte el cableado y el esquema de su hardware
@MKS el cableado no es el problema. Lea la pregunta. El mismo hardware funcionó bien cuando se usó el IDE de arduino, estaba usando el código mbed para ejecutarlo que no funcionó. La razón por la que usé el lenguaje arduino y el IDE fue para verificar esto. Puede usar placas STM nucleo con arduino si importa algunos archivos al IDE de arduino. Eso es lo que hice para verificar. Por favor, lea toda la pregunta detenidamente.
Ponga un alcance en el reloj I2C y las líneas de datos para obtener una idea de lo que está haciendo su código.
@EE_social como es mi primera vez con I2C, no estoy 100% seguro de qué es lo correcto. Lo analicé y vi que las líneas SDA y SCL hacían cosas, ¡si fue correcto o no es una historia diferente! ¿Puedes ver algo malo con la traducción del código?
¿Puede publicar una captura de alcance de SCL, SDA?
@EE_socal si desea consultar la página de chat sobre mi otra pregunta, hay una discusión en curso que también se refiere a esto, siéntase libre de unirse
Allí tengo mucha más información, es un tema similar, pero centrado en el código del escáner i2c, que probablemente contenga pistas sobre cómo responder a esto. También tengo lecturas de osciloscopio, lecturas de monitores en serie y otras cosas similares.
Hola, un punto que acabo de notar (y comentaré aquí en lugar de dejarlo solo en el registro de chat) es sobre la dirección I2C del sensor. Su dirección I2C predeterminada de 7 bits es 0x0C. Eso significa que su dirección de 8 bits es 0x0C << 1 = 0x18. Eso significa que la línea de código fuente: const int addr = 0x0C; // 8bit I2C addresses incorrecta, ya que la variable addrse pasa directamente en las llamadas de función I2C (varias) como i2c.write(addr, config, 4);Como sabemos por el chat, puede haber otros problemas (por ejemplo, la necesidad de usar una llamada API I2C mbed diferente) pero obtener esa dirección correcta será parte de cualquier solución :-)
@SamGibson Estoy seguro de que lo intenté en algún momento ... ¡Pero no recuerdo cómo fue! Lo intentaré de nuevo mañana, pero estoy seguro de que leí en alguna parte que puedes darle la dirección 0x0C... Sin embargo, podría estar equivocado. Gracias por eso, te dejaré saber cómo me va mañana cuando lo pruebo!
@Curious - ¿Quizás eso fue antes de quitar los puentes de soldadura? Sospecho que has tenido varios problemas. Esos puentes de soldadura (deliberados) en el Nucleo se conectaron a pines que el mbed s/w no desactivó, lo que llevó a ese divertido nivel de 2V. Luego está la preocupación actual sobre las llamadas I2C de mbed (todavía en discusión). Luego está la dirección (¡con el error tipográfico de Sparkfun!). Observe cómo el código en esta pregunta pasa el valor de addrdirectamente. Eso significa que addrdebe ser 0x18. Alternativamente, podría usar addr << 1en las llamadas a i2c.write()y luego addrdebe ser 0x0C. Te veo mañana.
@SamGibson sí, ¡habría sido antes de quitar los enlaces de soldadura! Buen punto. Te dejare saber como me va.
@SamGibson Bueno, lo intenté... Todavía obtengo un error en las lecturas :( ¡Probablemente un poco más entonces! ¡Supongo que te veré de nuevo en el chat sobre la otra pregunta entonces!

Respuestas (2)

Trabajando con el OP y sobre la base de la investigación explicada en mi respuesta a esta pregunta relacionada " El escáner I2C no funciona correctamente ", los mismos dos problemas debían solucionarse primero:

  • Desuelde los puentes de soldadura de la placa STM32F303K8 Nucleo-32 (NUCLEO-F303K8) SB16 y SB18 cuando se utilizan las funciones Mbed I2C.
  • Utilice la llamada Mbed de 4 parámetros "extendida" i2c.write()con la placa STM32F303K8 Nucleo-32.

Como se señaló en otra respuesta, un analizador lógico sería útil en esta situación (y debe usarse, si es posible), se encontraron y solucionaron los siguientes problemas sin usar uno, dentro del tiempo limitado disponible:

  • La dirección I2C de 7 bits correcta del sensor es 0x0C, pero las llamadas I2C de Mbed quieren la versión de 8 bits.

    Las versiones anteriores del código fueron engañadas por un error tipográfico en los documentos de SparkFun para su placa de conexión que usaba este sensor, donde decían que la dirección era 0xC0.

    Además, algunas versiones de código no desplazaron a la izquierda ese valor de dirección I2C, sin embargo, las funciones Mbed I2C quieren que se les pase la dirección como una versión de 8 bits (por ejemplo, 0x18 en este caso). Entonces, la solución fue pasarlo como 0x0C << 1o 0x18(lo mismo) a las llamadas Mbed I2C.

  • Como se señaló en esa otra pregunta vinculada, el acceso I2C con esta placa Nucleo STM32F303K8 solo es exitoso cuando se usa el Mbed i2c.write()y i2c.read()las funciones, con (hasta) 4 parámetros (3 requeridos, 4to opcional) y no usando el parámetro único de nivel inferior i2c.write()y i2c.read()las llamadas en su lugar .

  • En este punto, al comparar la actividad del bus I2C en el alcance entre el código Arduino y el código Mbed, el OP pudo ver que la actividad del bus I2C ahora era idéntica, hasta el punto de activar la medición por parte del sensor. Eso dejó el problema final en la lectura y visualización de los valores del sensor en el código Mbed.

    Mirando esa parte del código, eliminé la parte que estaba leyendo del sensor varias veces y comprobé si había un código de retorno incorrecto. Por lo tanto, cambié parte del código original de:

config[0] = 0x4E;

i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set
i2c.read(addr, data, 7); 

if(i2c.read(addr, data, 7) == !7) {
printf("ERROR \n"); 
} else { 
int xMag = i2c.read(data[1] * 256 + data[2]); 
int yMag = i2c.read(data[3] * 256 + data[4]); 
int zMag = i2c.read(data[5] * 256 + data[6]); 

printf("X Axis = %d \n", xMag); 
printf("Y Axis = %d \n", yMag); 
printf("Z Axis = %d \n", zMag); 
}

a

config[0] = 0x4E; 

i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set 
i2c.read(addr, data, 7); 

int xMag = ((data[1] * 256) + data[2]); 
int yMag = ((data[3] * 256) + data[4]); 
int zMag = ((data[5] * 256) + data[6]); 

printf("X Axis = %d \n", xMag); 
printf("Y Axis = %d \n", yMag); 
printf("Z Axis = %d \n", zMag);

Así que la versión completa del código de trabajo es:

#include "mbed.h" 

int addr = 0x0C <<1; // 8bit I2C address 

I2C i2c(PB_9 , PB_8); //sda, scl 

Serial pc(PA_2, PA_3); //Tx/Rx 

int main() 
{ 
char config [4]; 
char data[7] = {0}; 

config[0] = 0x60; 
config[1] = 0x00; 
config[2] = 0x5C; 
config[3] = 0x00; 

i2c.write(addr, config, 4, false); 

i2c.read(addr, data, 1); 

config[0] = 0x60; 
config[1] = 0x02; 
config[2] = 0xB4; 
config[3] = 0x02; 

i2c.write(addr, config, 4, false); 

i2c.read(addr, data, 1); 

wait(0.25); 

while (1) { 

config[0] = 0x3E; // Single measurement mode, ZYX enabled 

i2c.write(addr, config, 1, false); 
i2c.read(addr, data, 1); 

wait(0.1); 

config[0] = 0x4E; 

i2c.write(addr, config, 1, false); // Read command, followed by ZYX bits set 
i2c.read(addr, data, 7); 

int xMag = ((data[1] * 256) + data[2]); 
int yMag = ((data[3] * 256) + data[4]); 
int zMag = ((data[5] * 256) + data[6]); 

printf("X Axis = %d \n", xMag); 
printf("Y Axis = %d \n", yMag); 
printf("Z Axis = %d \n", zMag); 

wait(5); 
} 
}

Con este código Mbed, el sensor produce una salida correcta, similar al código Arduino en funcionamiento, y el objetivo de la pregunta era llegar a esa etapa. Luego, el código puede usarse como punto de partida y mejorarse con verificación de errores e informes de estado, etc.

Una vez más, las investigaciones adicionales del comportamiento I2C de las bibliotecas Mbed y el sensor se pueden realizar con un analizador lógico, cuando se dispone de un analizador (y más tiempo).

En lugar de adivinar y hacer modificaciones convulsivas aleatorias a su código, debe obtener un analizador lógico económico ($ 7) de eBay, para el cual descarga software gratuito y un decodificador I2C, y obtiene rastros I2C de su bus de hardware.

ingrese la descripción de la imagen aquí

Inmediatamente verá si su dirección es correcta o no, y cómo responde (o no) el dispositivo.

Hoy en día, muchos osciloscopios digitales de uso general más caros tienen decodificadores I2C, pero el dispositivo de $ 7 hace bien su trabajo.

Usted se está embarcando en un diseño integrado, que pretendía producir señalización de hardware. El uso de herramientas de hardware para observar las señales resultantes es imprescindible. Este debería ser tu punto de partida, todo lo demás es secundario. Buscar unos minutos en el rastro capturado le ahorrará días de "ingeniería aleatoria".

Gracias por la respuesta. Puedo invertir en algo como esto. Hubo varios problemas con esto al final, pero logré ejecutar un escáner I2C para obtener la dirección correcta eventualmente, y examiné todas las señales de un lado a otro, comparándolas con las señales de Arduino (que funcionaron) para finalmente llegar a esto punto. No todo fueron conjeturas y cambios aleatorios en el código. Si hubiera leído los registros de chat, habría visto que se ha dedicado bastante esfuerzo a la depuración. No solo conjeturas
@Curious, sí, hizo un gran esfuerzo para portar el código y depurarlo. Mi punto es que un simple analizador lógico I2C de dos hilos, que muestra instantáneamente los paquetes decodificados y todos los errores asociados (falta de paradas de inicio, ACK/NAK), reduciría sus esfuerzos de depuración en órdenes de magnitud.
Sí, estoy de acuerdo. También hubiera ayudado tener un IDE con puntos de interrupción. Mbed es bastante inútil para la depuración. Terminé revisando todos los bytes enviados hacia y desde para encontrar los símbolos ACK y NACK, verificar qué direcciones se estaban escribiendo/leyendo hacia/desde, etc. en un osciloscopio. Estoy de acuerdo, uno de esos sería una buena inversión, así que +1 por esa sugerencia.