Skocz do zawartości

[STM32f4] sonar srf02 na I2C, gdzie popełniłem błąd? (HAL i Cube)


intercooler

Pomocna odpowiedź

Witam!

Forbota przeglądam od dawna, ale dopiero teraz przyszedł czas na pierwszy post, więc proszę o wyrozumiałość.

Mam problem z STM32f4 DISCOVERY. Chcę podłączyć sonar srf02 i komunikować się z nim za pomocą I2C. Korzystam z Cube oraz bibliotek HAL, dokładnie tak, jak w kursie dostępnym tutaj na Forbocie. I właśnie wg części o I2C, próbowałem ogarnąć srf02, użyłem takich samych komend (mem_write oraz read) no i niestety czujnik nie działa (mam również drugi taki sam i z nim jest to samo, więc nie jest to wina mechanicznego uszkodzenia).

Poniżej zamieszczam screeny potrzebnych fragmentów z datasheeta sonara srf02.

Adresy czujników:

Mój zamrugał 3 razy (short flash), czyli adres 0xE6.

Komendy:

Chcę wynik w centymetrach, czyli 0x51.

Rejestry:

Wychodzi na to, że wyższy bajt to 0x02, niższy 0x03, a rejestr ustawień to 0x00.

Oto cały kod programu:

/**
 ******************************************************************************
 * File Name          : main.c
 * Description        : Main program body
 ******************************************************************************
 *
 * COPYRIGHT(c) 2016 STMicroelectronics
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c3;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

#define ADDRESS (0xE6) //adres czujnika
#define REGISTER_ADDRESS (0x00) //adres rejestru ustawien
#define H_BYTE (0x02) //wyzszy bajt danych odczytu - 2
#define L_BYTE (0x03) //nizszy bajt - 3

#define SET_CM (0x51) //ustawienie pomiaru w centymetrach

uint8_t data1 = 0;
uint8_t data2 = 0;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_I2C3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void)
{

 /* USER CODE BEGIN 1 */

 /* USER CODE END 1 */

 /* MCU Configuration----------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 HAL_Init();

 /* Configure the system clock */
 SystemClock_Config();

 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_I2C3_Init();

 /* USER CODE BEGIN 2 */
 uint8_t settings = SET_CM;
 HAL_I2C_Mem_Write(&hi2c3, ADDRESS, REGISTER_ADDRESS, 1, &settings, 1, 100);
 HAL_Delay(100);


 /* USER CODE END 2 */

 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
  HAL_I2C_Mem_Read(&hi2c3, ADDRESS, H_BYTE, 1, &data1, 1, 100);
  HAL_Delay(100);
  HAL_I2C_Mem_Read(&hi2c3, ADDRESS, L_BYTE, 1, &data2, 1, 100);
  HAL_Delay(100);

 /* USER CODE END WHILE */

 /* USER CODE BEGIN 3 */

 }
 /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

 RCC_OscInitTypeDef RCC_OscInitStruct;
 RCC_ClkInitTypeDef RCC_ClkInitStruct;

 __HAL_RCC_PWR_CLK_ENABLE();

 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
 RCC_OscInitStruct.PLL.PLLM = 12;
 RCC_OscInitStruct.PLL.PLLN = 96;
 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
 RCC_OscInitStruct.PLL.PLLQ = 4;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
   Error_Handler();
 }

 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                             |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
 {
   Error_Handler();
 }

 HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

 HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

 /* SysTick_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* I2C3 init function */
static void MX_I2C3_Init(void)
{

 hi2c3.Instance = I2C3;
 hi2c3.Init.ClockSpeed = 400000;
 hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
 hi2c3.Init.OwnAddress1 = 0;
 hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
 hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
 hi2c3.Init.OwnAddress2 = 0;
 hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
 hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
 if (HAL_I2C_Init(&hi2c3) != HAL_OK)
 {
   Error_Handler();
 }

}

/** Configure pins as 
       * Analog 
       * Input 
       * Output
       * EVENT_OUT
       * EXTI
*/
static void MX_GPIO_Init(void)
{

 GPIO_InitTypeDef GPIO_InitStruct;

 /* GPIO Ports Clock Enable */
 __HAL_RCC_GPIOH_CLK_ENABLE();
 __HAL_RCC_GPIOD_CLK_ENABLE();
 __HAL_RCC_GPIOC_CLK_ENABLE();
 __HAL_RCC_GPIOA_CLK_ENABLE();

 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);

 /*Configure GPIO pin : LED_Pin */
 GPIO_InitStruct.Pin = LED_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @param  None
 * @retval None
 */
void Error_Handler(void)
{
 /* USER CODE BEGIN Error_Handler */
 /* User can add his own implementation to report the HAL error return state */
 while(1) 
 {
 }
 /* USER CODE END Error_Handler */ 
}

#ifdef USE_FULL_ASSERT

/**
  * @brief Reports the name of the source file and the source line number
  * where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
 /* USER CODE BEGIN 6 */
 /* User can add his own implementation to report the file name and line number,
   ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
 /* USER CODE END 6 */

}

#endif

/**
 * @}
 */ 

/**
 * @}
*/ 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

No i niestety podczas podglądu zmiennych w STM Studio, zmienne data1 oraz data2 mają ciągle wartość 0 (taką, jaką ustawiłem na początku).

Uprzedzając pytania, odczytuję najpierw data1 (wyższy bajt), a później data2 (niższy), żeby zobaczyć czy w ogóle cokolwiek działa, prawidłowy wynik jest na razie nieistotny.

Tutaj screeny z analizatora:

Ustawienie:

Odczyt wyższego bajtu:

Odczyt niższego bajtu:

Co w takim razie zrobiłem nie tak, że czujnik nie działa?

Ogarnął ktoś w ogóle I2C na bibliotekach HAL? Niestety nie ma do nich zbyt wielu przykładów.

Z góry dziękuję za pomoc.

W załączniku jest pełny datasheet czujnika srf02.

srf02 sensor datasheet.pdf

Link do komentarza
Share on other sites

Po pierwsze dostajesz NAK podczas adresowania czujnika - przecież to wypisał nawet analizator na pierwszym rysunku. Czujnik nie rozpoznaje swojego adresu i wszystko dalsze nie ma sensu.

Podejrzewam, że problem leży w dwuznacznym rozumieniu adresów w specyfikacjach różnych implementacji I2C. Spróbuj a) zmniejszyć adres dwukrotnie (zamiast 0xE6 użyć 0x73) a jeśli to nie pomoże, b) napisać funkcję która przeskanuje całe I2C w poszukiwaniu adresu na który czujnik odpowie.

Musisz w fazie adresowania dostać ACK - to jedyny znak, że czujnik zobaczył swój adres. Bez tego jest on po prostu odpięty od szyny. Oczywiście może być źle podłączony (np, zamienione SDA z SCL) lub mieć inny problem sprzętowy (np. z zasilaniem).

Swoją drogą to oznacza, że nie obsługujesz błędów oddawanych z funkcji tylko zakładasz, że wszystko poszło dobrze. To bardzo optymistyczne i naiwne podejście. Jestem pewien, że funkcja HAL adresująca moduł I2C oddaje jakiś kod błędu w razie niepowodzenia.

EDIT: Hm, coś jest nie tak. Następny obrazek pokazuje prawidłową próbę odczytu bajtu z adresu 02. Rzeczywiście czujnik widzi swój adres, potwierdza go, poprawnie zachodzi ustawienie licznika adresów na 0x02 i odczyt bajtu o wartości 0x00. Ale już na ostatnim obrazku mamy poprawne adresowanie, ustawienie licznika adresów na 0x03 a potem nagle próba "dobrania się" do modułu 0xB9 🤯 która oczywiście kończy się NAK-iem w fazie adresowania.

EDIT2: Nie, to jednak ten analizator I2C głupieje. Wygląda to jednak na poprawne wybranie modułu 0xB6 do odczytu (czyli adres 0xB7) i odczyt bajtu 0x00 zakończony (prawidłowo) NAK-iem ze strony procesora. Adres jest OK, czujnik rzeczywiście oddaje 0x0000. W opisie czujnika napisali tak:

"The are three commands to initiate a ranging (80 to 82), to produce the result in inches, centimeters or microseconds. These three commands don't Tx the result back to your controller. You should wait 70mS and then use command 94 to get the result of the ranging"

Czy tak działa Twój program? Wysyłasz komendę pomiaru (80-82), czekasz te min. 70ms i czytasz wynik poleceniem 94?

Link do komentarza
Share on other sites

Właśnie to mnie zastanawia, że straszne głupoty pokazują się na analizatorze. Właśnie tak jak piszesz, najpierw NAK, potem niby okej, na końcu jakiś głupoty.

Fragment, który zacytowałeś, tyczy się komunikacji przez Serial. Wszystko co do I2C jest wyżej, a tam:

To initiate a ranging, write one of the above commands to the command register and wait the required

amount of time for completion and read the result. The echo buffer is cleared at the start of each ranging.

The ranging lasts up to 66mS, after this the range can be read from locations 2 and 3.

Czyli ustawiamy najpierw jedną z trzech komend jednostkę pomiaru (u mnie 0x51, centymetry), czekamy te 66ms (u mnie aż 100ms) i odczytujemy dane z lokacji 2 oraz 3, czyli wyższego oraz niższego bajtu.

U mnie jest tak:

W mainie:

-ustawienie pomiaru w centymetrach

-dla pewności odczekanie 100ms

W pętli nieskończonej:

-odczytanie wyższego bajtu

-odczekanie 100ms

-odczytanie niższego bajtu

-odczekanie 100ms

Wiem, że to bez sensu, ale chodzi o to, aby otrzymać jakikolwiek wynik. Gdy będę odbierał już cokolwiek, wtedy zbiorę do kupy te dwa bajty.

Link do komentarza
Share on other sites

No dobrze, a czy czujnik widzi jakąś solidną przeszkodę? Bo komunikacja działa. Analizator coś bredzi, ale spróbuj (jeśli możesz) zwiększyć mu częstotliwość próbkowania. Ostateczną wyrocznią byłby oscyloskop, bo przebiegi "cyfrowo" mogą być oszukane. Długie zbocza (za duże pojemności linii I2C, za duże oporniki podciągające - jakiś schemat?) mogą powodować bardzo pochylone, "analogowe" zbocza czego analizator nie widzi. Za to widzi dziwne przesuwania czasów, bo jego komparatory mają jakieś progi zadziałania. Być może inne niż wejścia czujnika i procesora. U nich więc działa o ten pokazuje śmieci.

Nie widzę wysłania komendy startu pomiaru. Możesz podesłać? Na pierwszym obrazku mamy tylko adresowanie modułu bez zapisu bajtu komendy.

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

Czujnik nie widzi nic, mimo, że próbowałem z przeróżnymi przeszkodami na różnych odległościach, nie widzi nawet ściany w odległości 30 cm.

Częstotliwość próbkowania niestety jest najwyższa.

Do linii I2C podłączony jest tylko ten czujnik i nic więcej. Rezystory podciągające ustawione są programowo, wartość mają narzuconą.

Komenda startu pomiaru wygląda w programie tak (przynajmniej wg mnie powinna tak wyglądać):

HAL_I2C_Mem_Write(&hi2c3, ADDRESS, REGISTER_ADDRESS, 1, &settings, 1, 100);

&hi2c3 - struktura i2c

ADDRESS - adres czujnika

REGISTER_ADDRESS - adres rejestru

&settings = SET_CM = 0x51, czyli komenda dla pomiaru w centymetrach

Inna sprawa, że płytka bardzo grzeje mi się w okolicach wejścia usb, mniejszego procesora stm32f103. Główny procesor bez zarzutów, wszystko z nim okej.

Napięcie na wyjściowym pinie zasilania 5V waha się w okolicach 4,4V, a na pinie 3V w okolicach 4V. Grzanie zauważyłem już dawno temu, ale dopiero teraz sprawdziłem napięcia. Może czujnikowi za mało te 4,4V i po prostu nie wysyła żadnych sygnałów. Chyba trzeba będzie sprawdzić na innej płytce.

Link do komentarza
Share on other sites

To jeśli analizator nie wyrabia, to zwolnij I2C. Spróbuj na 50 czy 10kHz. Po pierwsze lepiej będzie działało próbkowanie analizatora a po drugie odsuniesz się od problemów z liniami I2C. Nie powinieneś polegać na wbudowanych w porty opornikach (bo one nie są do tego) tylko podłączyć swoje o znanych wartościach. Prędkość 400kHz wymaga naprawdę małych rezystancji podciągających. I drąż tematy aż się dokopiesz, nie zwalaj na płytkę. Grzanie się jest dziwne i może niebezpieczne - dowiedz się co jest tego powodem.

Widziałeś na analizatorze poprawne i potwierdzone ACK-iem wysyłanie komendy pomiaru? Nie pokazuj mi tego w programie, bo widzę gdzie wołasz funkcję tylko chcę zobaczyć wykresy czasowe.

Napięcia wyglądają na zwieranie 3.3V z 5V przez jakąś diodę/scalak. O ile 4.4V nie popsuje niczego na 5V, o tyle 4V na szynie 3.3V już może zrobić krzywdę. Pokaż schemat, bo coś mi tu przestaje się podobać. Napisałeś, że sprzęt jest OK, to uwierzyłem głupi..

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

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