Adresowanie rejestrów za pomocą bibliotek HAL I2C STM32F0

12

Jestem bardzo nowy w używaniu CUBE STB i bibliotek HAL. Używam mikrokontrolera STM32F0 z 32 pinami. Schemat I2C jest poprawny. Potrzebuję więc trochę pomocy.

Mam czujnik pojemnościowy ( FDC1004 ), który wykorzystuje komunikację I2C. Muszę napisać te rejestry, aby odczytać dane.

Jak poprawnie wysłać żądanie START z mastera do slave (adres slave to A0)?

Jak ustawić wskaźnik na rejestr 0x0C?

  • Arkusz danych widzi (Zarejestruj 0x0C: bit [7: 4]) na 1.) Nie wiem, jak to zrobić? I wreszcie, jak CZYTAĆ z tego samego rejestru?
  • Plus muszę czekać pole DONE_x (Zarejestruj 0x0C: bity [3: 0]) zanim go przeczytam?

Ale nie wiem, czy zwracam się do właściwych rejestrów! Ponieważ nie otrzymuję żadnych danych z czujnika!

Oto mój kod:

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
źródło
Proszę zadać bardziej szczegółowe pytania. jak Jak poprawnie adresować rejestr X? To źle sformułowane pytanie. Dalsze wytyczne można znaleźć na stronie electronics.stackexchange.com/help/how-to-ask
Skok napięcia o
Czy zatem lepiej jest napisać nowe pytanie, czy po prostu je edytować?
wczoraj 11
Lepiej edytować, mniej pytań i nie będziemy musieli tego zamykać.
Skok napięcia

Odpowiedzi:

16

Zacznijmy od HAL_I2C_Master_Transmit()funkcji. Jeśli sprawdzisz jego deklarację:

 HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  1. Drobny problem z drugim parametrem, adresem urządzenia podrzędnego. Adres urządzenia podrzędnego to, b1010000jeśli uzupełnimy go do formatu 8-bitowego, będzie tak 0xA0, jak powiedziałeś. Teraz, gdy przekazujesz to do HAL_I2C_Master_Transmit()ciebie, nie musisz ręcznie ustawiać bitu R / W, HAL zrobi to za ciebie. Tak więc, kiedy wywołasz HAL_I2C_Master_Transmit()transmitowany bit R / W, automatycznie wyniesie 0, co oznacza operację zapisu, a kiedy wywołasz HAL_I2C_Master_Receive()transmitowany bit R / W, automatycznie wyniesie 1, wskazując operację zapisu . Zmieszałeś wartości R / W, ale myślę, że to nie obchodzi mnie funkcja, więc nie jest to prawdziwy błąd w kodzie.

  2. 3-ci parametrów ( uint8_t *pData) stanowi wskaźnik na bufor , który zawiera dane do wysłania . Teraz w rozmowie trzecim parametrem 0x0Cjest Twoje rzeczywiste dane, adres rejestru. Problem polega na tym, że zostanie zinterpretowany jako wskaźnik (do HAL_I2C_Master_Transmit()) w miejscu pamięci, w którym można znaleźć niektóre niezdefiniowane dane.

  3. 4-ci parametrem jest wielkość bufora , liczba bajtów do wysłania. Jeśli chcesz wysłać pojedynczy bajt, ten parametr powinien wynosić 1, a nie 10.

I2C

Napisz rejestry

Oto odpowiedni schemat z arkusza danych.

wprowadź opis zdjęcia tutaj

Więc po wysłaniu adresu slave do autobusu, trzy kolejne bajty powinny być przesyłane: zarejestruj wskaźnik , MSB bajt , LSB bajt . Ogólna implementacja z rejestrowaniem 16-bitowych rejestrów HAL:

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
}

Przykład z twoimi wartościami: write_register(0x0C, 0x0054);

Alternatywnie można również użyć funkcji zapisu rejestru zdefiniowanej w HAL, która ma dodatkowe parametry do przekazywania adresu rejestru i wielkości adresu.

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

Teraz HAL_I2C_Master_Receive()funkcja jest prawie taka sama jak druga.

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

Jedyną różnicą jest to, że trzeci parametr jest wskaźnikiem do bufora, w którym będą przechowywane odebrane dane . Jest 0x02w twoim kodzie i nie wiem, jaki był twój cel, ale będzie interpretowany jako wskaźnik (niestety do przypadkowej lokalizacji w pamięci).

Czytaj rejestry

wprowadź opis zdjęcia tutaj

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

Przykład:

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

read_register(reg_ptr, buffer);

// the register content available in the buffer

Istnieje również funkcja odczytu rejestru zdefiniowana przez HAL, która ma.

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

Zapoznaj się z częścią 8.5 dotyczącą programowania w arkuszu danych, aby uzyskać więcej informacji.

Bence Kaulics
źródło
Dziękuję za odpowiedź, teraz w końcu działa. Ale jeszcze jedno pytanie? Czy muszę czekać kilka miliardów sekund na przeczytanie, czy mogę czytać bez zwłoki?
wczoraj11
Nie sądzę, że jakiekolwiek opóźnienie jest konieczne, możesz spróbować bez żadnego wcześniejszego.
Bence Kaulics
1
Nie musisz czekać, I2C wymaga zapętlenia sygnału zegarowego, aż slave się zakończy.
Mahmoud Al-Qudsi,