
#006 - LIB01 - Biblioteka I2C - STHAL
Pierwsza biblioteka opisana/udostępniona na tym blogu - bardzo prosta, wręcz banalna, ale praktyczna.
Biblioteka udostępniona na GitLabie: I2C.
Przeznaczenie biblioteki
Jest to “wrapper” na bibliotekę STHAL ułatwiający pracę z I2C w przypadku kiedy jedna magistrala jest używana przez kilka bibliotek. Zawiera wbudowany mutex dzięki czemu mamy pewność, że tylko jeden task w danej chwili będzie miał dostęp do zasobu I2C.
Najważniejsze wymaganie biblioteki - FreeRTOS w projekcie - biblioteka nie ma żadnej dodatkowej abstrakcji nad funckjami FreeRTOSa.
Użycie - teoria
Konfiguracja biblioteki do wykorzystania w projekcie sprowadza się do uruchomienia funkcji inicjalizacyjnej do której jako prarametr należy przekazać adres wcześniej skonfigurowanego handlera do “I2C_HandleTypeDef”.
Dzięki temu I2C można skonfigurować w CubeMX/CubeIDE - “wyklikać” potrzebną konfigurację, a bibliotekę to totalnie nie interesuje.
I2C_Init(&hi2c1);
Jeśli potrzebne jest dostosowanie timeoutu dla przesyłania pojedynczego znaku - biblioteka oczekuje, że konfiguracja znajdzie się w pliku “board.h”, który będzie znajdował się w ścieżkach includów projektu.
Tak naprawdę moduł udostępnia 5 funkcji (fragment z pliku I2C.h):
bool I2C_Init(I2C_HandleTypeDef *handler);
bool I2C_ReadByte(uint8_t devAddress, uint8_t regAddress, uint8_t *value);
bool I2C_ReadBytes(uint8_t devAddress, uint8_t regAddress, uint8_t *value, uint8_t bytes);
bool I2C_WriteByte(uint8_t devAddress, uint8_t regAddress, uint8_t value);
bool I2C_WriteBytes(uint8_t devAddress, uint8_t regAddress, const uint8_t *values, uint16_t size);
Użycie - w praktyce
Biblioteka została przetestowana w aplikacji, gdzie na jednej magistrali I2C znalazło się 6 urządzeń:
- OLED 128x64
- ADP5585
- LPS331
- HTS221
- STMLM75
- TSL25721
Z punktu projektowania takiego urządzenia należy mieć świadomość mechanizmu “priority inversion” związanego z użyciem mutexów do kontroli dostępu do zasobu i odpowiednio przeliczyć krytyczne czasy wykonania tasków z jego uwzględnieniem.
Jeśli biblioteki do poszczególnych układów są zbudowane tak, że należy im przekazać callbacki do funkcji dostępu do I2C (zasada Dependency Inversion z SOLIDa) - wygląda to mniej więcej tak:
ADP5585_init_s ADP5585_init =
{
.readI2CBuff = I2C_readBytes,
.sendI2CBuff = I2C_writeBytes,
};
A - biblioteka jest oczywiście zgodna z punktami z poprzedniego postu: reużywalne biblioteki - jedyny sporny punkt to “zalezność od platformy” - ale ta biblioteka to właśnie wrapper dla STHAL - i dzięki temu, że można ją wykorzystać jak w przykładzie ze strukturą konfiguracją dla ADP5585 można uzyskać niezależność od platformy na wyższych poziomach architektury oprogramowania projektu.