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

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.


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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.