Direccionamiento de registros con bibliotecas I2C STM32F0 HAL

Soy muy nuevo en el uso de CUBE y HAL_libraries de STM. Estoy usando un microcontrolador STM32F0 con 32 pines. El esquema para I2C es correcto. Así que necesito un poco de ayuda aquí.

Tengo un sensor capacitivo ( FDC1004 ) que usa comunicación I2C. Tengo que escribir estos registros para leer los datos.

¿Cómo podría enviar correctamente el formulario de solicitud de INICIO del maestro al esclavo (la dirección del esclavo es A0)?

¿Cómo establecer el puntero en el registro 0x0C?

  • La hoja de datos ve (Registro 0x0C: bit [7: 4]) a 1.) No sé, ¿cómo hacer eso? Y finalmente ¿cómo LEER desde el mismo registro?
  • Además, tengo que esperar el campo DONE_x (Registrar 0x0C:bits[3:0]) antes de leerlo.

¡Pero no sé si me dirijo a los registros correctos! ¡Porque no obtengo ningún dato del sensor!

Aquí está mi código:

int I2Ccomm ()
{

    HAL_I2C_Master_Transmit(&hi2c1,0xA1,0x0C, 10, 100); //start bit and pointer to register
    HAL_Delay(50);
    HAL_I2C_Master_Transmit(&hi2c1,0xA1,0x054, 10, 100); // setting the register
    HAL_Delay(50);

    HAL_I2C_Master_Receive(&hi2c1, 0xA0, 0x0C, 10, 100); //read from this register
    HAL_Delay(50);
    HAL_I2C_Master_Receive(&hi2c1, 0xA0, 0x02, 10, 100); //read data from register

    return ReadREG[1];
}
Por favor, haga una pregunta más específica. como ¿Cómo dirijo el registro X correctamente? Esta es una pregunta mal formulada. Para obtener más pautas, consulte electronics.stackexchange.com/help/how-to-ask
Entonces, ¿es mejor escribir una nueva pregunta o simplemente editar esta?
Mejor editar, menos preguntas y no tendremos que cerrar este.

Respuestas (1)

Comencemos con la HAL_I2C_Master_Transmit()función. Si comprueba su declaración:

 HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  1. Problema menor con el segundo parámetro, la dirección del dispositivo esclavo. La dirección del dispositivo esclavo es b1010000si la completamos en formato de 8 bits, será 0xA0, tal como dijiste. Ahora, al pasar esto a HAL_I2C_Master_Transmit()usted, no tiene que configurar el bit R/W manualmente, HAL lo hará por usted. Entonces, cuando llame, HAL_I2C_Master_Transmit()el bit R/W transmitido será automáticamente 0, lo que indica una operación de escritura, y cuando llame, HAL_I2C_Master_Receive()el bit R/W transmitido será automáticamente 1, lo que indica una operación de escritura . Ha mezclado los valores R/W, pero creo que no le importa un poco la función, por lo que no es un error real en su código.

  2. El tercer parámetro ( uint8_t *pData) es un puntero a un búfer que contiene los datos a enviar . Ahora, en su llamada, el tercer parámetro es 0x0Ccuál es su información real, la dirección de registro. El problema es que se interpretará como un puntero (por el HAL_I2C_Master_Transmit()) a una ubicación de memoria, donde se pueden encontrar algunos datos no definidos.

  3. El cuarto parámetro es el tamaño del búfer , el número de bytes a enviar. Si desea enviar un solo byte, este parámetro debe ser 1 y no 10.

al trabajar con yo 2 C lo mejor que puede hacer es obtener la hoja de datos del dispositivo esclavo y buscar la documentación de las operaciones de escritura y lectura.

Escribir registros

Aquí está el diagrama correspondiente de la hoja de datos.

ingrese la descripción de la imagen aquí

Entonces, después de enviar la dirección del esclavo al bus, se deben transmitir tres bytes más: puntero de registro , byte MSB , byte LSB . Una implementación general con HAL escribiendo registros de 16 bits:

void write_register(uint8_t register_pointer, uint16_t register_value)
{
    uint8_t data[3];

    data[0] = register_pointer;     // 0x0C in your example
    data[1] = register_value>>8;    // MSB byte of 16bit data
    data[2] = register_value;       // LSB byte of 16bit data

    HAL_I2C_Master_Transmit(&hi2c1, 0xA0, data, 3, 100);  // data is the start pointer of our array
}

Ejemplo con tus valores:write_register(0x0C, 0x0054);

Alternativamente, también se puede usar la función de escritura de registro definida por HAL, que tiene parámetros adicionales para pasar la dirección del registro y el tamaño de la dirección.

void write_register(uint8_t register_pointer, uint16_t register_value)
{
    HAL_StatusTypeDef status = HAL_OK;

    status = HAL_I2C_Mem_Write(&hi2c1, 0xA0, (uint16_t)register_pointer, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&register_value), 2, 100); 

    /* Check the communication status */
    if(status != HAL_OK)
    {
        // Error handling, for example re-initialization of the I2C peripheral
    }
}

Ahora, la HAL_I2C_Master_Receive()función es casi la misma que la otra.

HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

La única diferencia es que el tercer parámetro es un puntero al búfer donde se almacenarán los datos recibidos . Está 0x02en su código y no sé cuál fue su propósito con él, pero se interpretará como un puntero (desafortunadamente a una ubicación de memoria aleatoria).

Leer registros

ingrese la descripción de la imagen aquí

Para leer un registro, se debe seleccionar con un yo 2 C operación de escritura enviando el puntero de registro apropiado (tenga en cuenta que si ha escrito este registro justo antes de la lectura, entonces no tiene que enviar nuevamente su dirección al registro de puntero, ya que ya lo configuró durante la escritura). Entonces con un yo 2 C operación de lectura, lea de nuevo los datos de 16 bits.

void read_register(uint8_t register_pointer, uint8_t* receive_buffer)
{
    // first set the register pointer to the register wanted to be read
    HAL_I2C_Master_Transmit(&hi2c1, 0xA0, &register_pointer, 1, 100);  // note the & operator which gives us the address of the register_pointer variable

    // receive the 2 x 8bit data into the receive buffer
    HAL_I2C_Master_Receive(&hi2c1, 0xA0, receive_buffer, 2, 100);   
}

Ejemplo:

uint8_t reg_ptr = 0x0C;
uint8_t buffer[2];

read_register(reg_ptr, buffer);

// the register content available in the buffer

También hay una función de lectura de registro definida por HAL, que tiene.

uint16_t read_register(uint8_t register_pointer)
{
    HAL_StatusTypeDef status = HAL_OK;
    uint16_t return_value = 0;

    status = HAL_I2C_Mem_Read(&hi2c1, 0xA0, (uint16_t)register_pointer, I2C_MEMADD_SIZE_8BIT, &return_value, 2, 100);

    /* Check the communication status */
    if(status != HAL_OK)
    {

    }

    return return_value;
}

Lea la sección de programación 8.5 de la hoja de datos para obtener más detalles.

Gracias por su respuesta, ahora finalmente está funcionando. Pero una pregunta más? ¿Tengo que esperar unos milisegundos para leer o puedo leer sin demora?
No creo que sea necesaria ninguna demora, podrías probar sin ninguna antes.
No necesita esperar, I2C implica hacer un bucle en la señal del reloj hasta que el esclavo se haya completado.