Skocz do zawartości

I2C - sprawdzenie czy interfejs zakończył poprzedni pomiar


radek04

Pomocna odpowiedź

Cześć,
używam w projekcie 4 modułów GY-91. Odczytuję z nich 500 razy na sekundę wartości z akcelerometru, żyroskopu i barometru. O ile osobno IMU i BAR działają dobrze, o tyle mam problem z "symultanicznym" odczytem wszystkich danych.
Korzystam z 4 linii I2C (każdy moduł podłączony do innej) oraz odczytu w trybach DMA oraz IT. Problem w tym, że zarówno IMU (akcelerometr i żyroskop), jak i barometr korzystają ze wspólnego interfejsu I2C. Poprawnie mogę odczytać tylko te dane, które w programie są jako pierwsze (reszta zostaje zerami).
Podejrzewam, że kolejny pomiar próbuję zrobić, zanim poprzedni się zakończył. Jak sprawdzić, czy operacja HAL_I2C_Mem_Read_DMA() została już zakończona i mogę wykonać kolejny pomiar po tej samej linii I2C? Jest jakaś flaga do tego?

Na razie roboczo wstawiłem opóźnienie, ale to rozwiązanie nie do końca mnie zadowala, ponieważ ważna dla mnie jest każda mikrosekuda. Poza tym to niezbyt eleganckie rozwiązanie.

Używam STM32H743ZII, STM32CubeIDE.

HAL_I2C_Mem_Read_DMA(&hi2c1, BMP280_ADDRESS_A, BMP280_REG_BAR_MSB, 1, BMP280_Data_A, 3); // 3 registers (MSB, LSB, XLSB)
HAL_I2C_Mem_Read_DMA(&hi2c2, BMP280_ADDRESS_B, BMP280_REG_BAR_MSB, 1, BMP280_Data_B, 3); // 3 registers (MSB, LSB, XLSB)
HAL_I2C_Mem_Read_DMA(&hi2c3, BMP280_ADDRESS_C, BMP280_REG_BAR_MSB, 1, BMP280_Data_C, 3); // 3 registers (MSB, LSB, XLSB)
HAL_I2C_Mem_Read_IT (&hi2c4, BMP280_ADDRESS_D, BMP280_REG_BAR_MSB, 1, BMP280_Data_D, 3); // 3 registers (MSB, LSB, XLSB)

Hal_Delay(1);
				
HAL_I2C_Mem_Read_DMA(&hi2c1, MPU9250_ACC_ADDRESS_A,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_A, 14); //14 registers measurement
HAL_I2C_Mem_Read_DMA(&hi2c2, MPU9250_ACC_ADDRESS_B,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_B, 14); //14 registers measurement
HAL_I2C_Mem_Read_DMA(&hi2c3, MPU9250_ACC_ADDRESS_C,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_C, 14); //14 registers measurement
HAL_I2C_Mem_Read_IT (&hi2c4, MPU9250_ACC_ADDRESS_D,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_D, 14); //14 registers measurement

 

Link do komentarza
Share on other sites

(edytowany)

Wybaczcie moją niefrasobliwość. Okazało się,że już wcześniej to robiłem funkcją

while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){}

Tylko teraz nasuwa mi się pytanie, czy lepiej sprawdzać każdą linię I2C osobno

while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_DMA(&hi2c1, BMP280_ADDRESS_A, BMP280_REG_BAR_MSB, 1, BMP280_Data_A, 3);
while(HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_DMA(&hi2c2, BMP280_ADDRESS_B, BMP280_REG_BAR_MSB, 1, BMP280_Data_B, 3);
while(HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_DMA(&hi2c3, BMP280_ADDRESS_C, BMP280_REG_BAR_MSB, 1, BMP280_Data_C, 3); 
while(HAL_I2C_GetState(&hi2c4) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_IT (&hi2c4, BMP280_ADDRESS_D, BMP280_REG_BAR_MSB, 1, BMP280_Data_D, 3); 

while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_DMA(&hi2c1, MPU9250_ACC_ADDRESS_A,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_A, 14); 
while(HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_DMA(&hi2c2, MPU9250_ACC_ADDRESS_B,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_B, 14); 
while(HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_DMA(&hi2c3, MPU9250_ACC_ADDRESS_C,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_C, 14); 
while(HAL_I2C_GetState(&hi2c4) != HAL_I2C_STATE_READY){} HAL_I2C_Mem_Read_IT (&hi2c4, MPU9250_ACC_ADDRESS_D,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_D, 14);

czy wystarczy wszystkie jednocześnie?

while(
	HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY ||
	HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY	||
	HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY	||
	HAL_I2C_GetState(&hi2c4) != HAL_I2C_STATE_READY){}
HAL_I2C_Mem_Read_DMA(&hi2c1, BMP280_ADDRESS_A, BMP280_REG_BAR_MSB, 1, BMP280_Data_A, 3);
HAL_I2C_Mem_Read_DMA(&hi2c2, BMP280_ADDRESS_B, BMP280_REG_BAR_MSB, 1, BMP280_Data_B, 3); 
HAL_I2C_Mem_Read_DMA(&hi2c3, BMP280_ADDRESS_C, BMP280_REG_BAR_MSB, 1, BMP280_Data_C, 3); 
HAL_I2C_Mem_Read_IT (&hi2c4, BMP280_ADDRESS_D, BMP280_REG_BAR_MSB, 1, BMP280_Data_D, 3);

while(
	HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY ||
	HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY	||
	HAL_I2C_GetState(&hi2c3) != HAL_I2C_STATE_READY	||
	HAL_I2C_GetState(&hi2c4) != HAL_I2C_STATE_READY){}
HAL_I2C_Mem_Read_DMA(&hi2c1, MPU9250_ACC_ADDRESS_A,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_A, 14);
HAL_I2C_Mem_Read_DMA(&hi2c2, MPU9250_ACC_ADDRESS_B,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_B, 14);
HAL_I2C_Mem_Read_DMA(&hi2c3, MPU9250_ACC_ADDRESS_C,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_C, 14);
HAL_I2C_Mem_Read_IT (&hi2c4, MPU9250_ACC_ADDRESS_D,	MPU9250_ACCEL_XOUT_H, 1, MPU9250_Data_D, 14);

Chodzi mi o to, który sposób będzie szybszy, jeśli przy trybach DMA i IT to w ogóle ma jakieś znaczenie.

Edytowano przez radek04
  • Lubię! 1
Link do komentarza
Share on other sites

Dnia 28.08.2023 o 05:07, radek04 napisał:

Jak sprawdzić, czy operacja HAL_I2C_Mem_Read_DMA() została już zakończona i mogę wykonać kolejny pomiar po tej samej linii I2C? Jest jakaś flaga do tego?

A czy nie trzeba by do tego celu zaużyć przerwania?

Warto zapoznać się z sekwencją programowania w HAL protokołu I2C w trybie DMA i przerwaniowym, przy czym nie mogę namierzyć odpowiednika poniższego dokumentu dla innych wersji boardów STM32 (tu jest link do dokumentacji HALa dla STM32F4 - może być co najmniej dobrą inspiracją)...
https://www.st.com/resource/en/user_manual/um1725-description-of-stm32f4-hal-and-lowlayer-drivers-stmicroelectronics.pdf

Edytowano przez ReniferRudolf
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dane pobieram 500 razy na sekundę i tak szybko też (w przerwaniu timera) odczytuję je. Dane wyglądają dobrze i za każdym razem delikatnie inne, więc zdaje się, że działa to dobrze. Roboczo przyjmuję, że odczytuję nowe dane po tym, jak się zmieniły i zanim nastąpi kolejna zmiana. W instrukcji BMP280 jest informacja, że jeśli odczyt wykonywany jest seryjnie po kolejnych rejestrach, to dane są zawsze spójne. W MPU9250 podobnej informacji nie znalazłem i przyznaję, że nie sprawdzam tego. Nie bardzo nawet umiem takie rzeczy robić.

  • Lubię! 1
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.