Skocz do zawartości

I2C - sprawdzenie czy interfejs zakończył poprzedni pomiar


Pomocna odpowiedź

Napisano

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

 

(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
(edytowany)
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

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

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