Adressage des registres avec les bibliothèques HAL I2C STM32F0

12

Je suis très nouveau dans l'utilisation de CUBE et HAL_libraries de STM. J'utilise un microcontrôleur STM32F0 avec 32 broches. Le schéma pour I2C est correct. J'ai donc besoin d'un peu d'aide ici.

J'ai un capteur capacitif ( FDC1004 ) qui utilise la communication I2C. Je dois écrire ces registres pour lire les données.

Comment pourrais-je envoyer correctement le maître de formulaire de demande START à l'esclave (l'adresse de l'esclave est A0)?

Comment définir le pointeur sur le registre 0x0C?

  • La fiche technique voit (Registre 0x0C: bit [7: 4]) à 1.) Je ne sais pas, comment faire? Et enfin comment lire à partir du même registre?
  • De plus, je dois attendre le champ DONE_x (Registre 0x0C: bits [3: 0]) avant de le lire?

Mais je ne sais pas si je m'adresse aux bons registres! Parce que je ne récupère aucune donnée du capteur!

Voici mon code:

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];
}
yest111
la source
Veuillez poser une ou des questions plus spécifiques. comme Comment puis-je adresser X s'inscrire correctement? C'est une question mal formulée. Pour plus d'informations, consultez electronics.stackexchange.com/help/how-to-ask
Voltage Spike
Alors est-il préférable d'écrire une nouvelle question ou simplement de la modifier?
yest111
Mieux vaut éditer, moins de questions et nous n'aurons pas à fermer celui-ci.
Voltage Spike

Réponses:

16

Commençons par la HAL_I2C_Master_Transmit()fonction. Si vous vérifiez sa déclaration:

 HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  1. Problème mineur avec le 2ème paramètre, l'adresse du périphérique esclave. L'adresse du périphérique esclave est que b1010000si nous la complétons au format 8 bits, elle le sera 0xA0, comme vous l'avez dit. Maintenant, lorsque HAL_I2C_Master_Transmit()vous passez cela, vous n'avez pas à définir le bit R / W manuellement, HAL le fera pour vous. Ainsi, lorsque vous appelez HAL_I2C_Master_Transmit()le bit R / W transmis sera automatiquement 0 indiquant l'opération d'écriture et lorsque vous appelez HAL_I2C_Master_Receive()le bit R / W transmis sera automatiquement 1 indiquant l'opération d'écriture . Vous avez mélangé les valeurs R / W mais je pense que c'est un peu pour la fonction, donc ce n'est pas une erreur réelle dans votre code.

  2. Le 3ème paramètre ( uint8_t *pData) est un pointeur vers un tampon qui contient les données à envoyer . Maintenant, dans votre appel, le troisième paramètre est 0x0Ccelui de vos données réelles, l'adresse du registre. Le problème est qu'il sera interprété comme un pointeur (par le HAL_I2C_Master_Transmit()) vers un emplacement mémoire, où des données non définies peuvent être trouvées.

  3. Le 4ème paramètre est la taille du tampon , le nombre d'octets à envoyer. Si vous souhaitez envoyer un seul octet, ce paramètre doit être 1 et non 10.

I2C

Écrire des registres

Voici le schéma correspondant de la fiche technique.

entrez la description de l'image ici

Ainsi , après l' envoi de l'adresse esclave au bus, trois autres octets doivent être transmis: registre de pointeur , octet MSB , LSB octet . Une implémentation générale avec l'écriture HAL de registres 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
}

Exemple avec vos valeurs: write_register(0x0C, 0x0054);

Alternativement, la fonction d'écriture de registre définie par HAL peut également être utilisée, qui a des paramètres supplémentaires pour transmettre l'adresse de registre et la taille d'adresse.

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

Maintenant, la HAL_I2C_Master_Receive()fonction est presque la même que l'autre.

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

La seule différence est que le troisième paramètre est un pointeur vers le tampon où les données reçues seront stockées. C'est 0x02dans votre code et je ne sais pas quel était votre but, mais il sera interprété comme un pointeur (malheureusement vers un emplacement mémoire aléatoire).

Lire les registres

entrez la description de l'image ici

I2CI2C

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

Exemple:

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

read_register(reg_ptr, buffer);

// the register content available in the buffer

Il existe également une fonction de lecture de registre définie par HAL, qui a.

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

Lisez la section 8.5 Programmation de la fiche technique pour plus de détails.

Bence Kaulics
la source
Merci pour votre réponse, maintenant ça marche enfin. Mais encore une question? Dois-je attendre quelques mili secondes pour lire ou pourrais-je lire sans délai?
yest111
Je ne pense pas qu'un délai soit nécessaire, vous pouvez essayer sans aucun préalable.
Bence Kaulics
1
Vous n'avez pas besoin d'attendre, I2C implique une boucle sur le signal d'horloge jusqu'à ce que l'esclave soit terminé.
Mahmoud Al-Qudsi