Skocz do zawartości

Kurs STM32L4 – #9 – przetworniki analogowo-cyfrowe (ADC)


Wiadomość dodana przez Treker,

Uwaga! Program STM Studio nie jest już rozwijany przez producenta, więc może nie działać poprawnie. Zamiennikiem może być znacznie bardziej rozbudowany program STM32Cube Monitor. Warto również sprawdzić aplikację, której autorem jest jeden z użytkowników Forbota: STMViewer.

Pomocna odpowiedź

Przy probie uruchomienia stm-studio, gdy otwieram DAC1.elf pokazuje się błąd:

GMD cmd [symbol-file "D:\STM\.........\DAC1.elf"] failed:

Error: wrong version in compilation unit header (is 5, should be 2, 3, or 4) [in module D:\STM32\STM32CubeIDE_workspace\DAC1\Debug\DAC1.elf]

Probowałem roznych rozwiązań, ale to nie pomoglo, ciągle ten sam błąd wyswietla.

Co robić ???

 

  • 5 miesiące później...
(edytowany)

Uczę się adc, dzięki za kurs bardzo pomocny.
Btw, wzór konwersji na wolty ma chyba pewną nieścisłość, zakres wartości odczytywany przez 12 bitowy adc to 4095 nie 4096?
(właściwą wartość można też otrzymać używająca makra biblioteki low level api __LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_12B))
 

Edytowano przez HansKloss
  • 2 tygodnie później...
  • 3 miesiące później...
(edytowany)

Dzień dobry.

Właśnie przerabiam odcinek ADC i mam problem z STM studio. Jak chcę zaimportować plik elf to wywala błąd:
obraz.thumb.png.9d588ce1e12f9e51cd409f924c596e15.png

Czyżby niezgodność wersji kompilatora z STM CUBE IDE z STM Studio? Może ktoś natknął się na taki błąd i zna rozwiązanie.
Sprawdziłem wszystkie projekty. Dająten sam błąd. Próbowałem zaaplikować rozwiązanie ze strony:
https://community.st.com/t5/stm32-vscode-extension-mcus/stm-studio-upload-error-wrong-version-in-compilation-unit-header/m-p/595498/highlight/true#M5278 , ale bezskutecznie. ręczne wpisanie nazwy kompilatora powoduje błąd w kompilacji. Pewnie dlatego, że kompilatora o takiej nazwie niema w systemie. Może trzeba zainstalować starszą wersję CUBE, tylko do z którą najnowszą do działało. Skoro narzędzie nie jest wspierane, to może jest nowe?
Jest nowe narzędzie - STM32Cube Monitor. Wspominał o tym wcześniej jeden z kolegów, ale filozofia zupełnie inna. Narazie ściągnąłem z linku https://www.st.com/en/development-tools/stm32cubemonitor.html#featured_resources-0 uruchomiłem i nie wiem jak z niego skorzystać. Ponoć pozwala na połączenie z projektem przez debugger, ale nie  wiem jak to skonfigurować. Może ktoś wie??

Znalazłem na YT video jak tego używać https://www.youtube.com/watch?v=eIrTYMl7fD0 , ale udało się tylko załadować elf i skonfigurować stlink / nucleo i potwierdzić działanie przez ikonę z żarówką, która daje mignięcie led na programatorze. Jednak nie udaje mi się wystartować zbierania danych. Prawdopodobnie dlatego, że nie daje się wkonfigurować już użytego st-linka do myprobeout, a to służy do wysyłania komend do debugera.
obraz.thumb.png.21c1be3ce4596360ff03052b98cd7125.png

Też nie rozumiem dlaczego linie komunikacji są przerywane.

Pozdrawiam.  M.

Edytowano przez aimeiz
Nowe informacje

Teoria mówi, że jeśli coś nie wychodzi, to zrób ponownie, ale w inny sposób.

No ja zrobiłem ponownie ale inny sposób polegał na tym, że wyciąłem wszystkie poprzednie błędne ruchy i zacząłem od początku. Udało się.
obraz.thumb.png.0bbfe922e2abc82a6197a8151b33775e.pngobraz.thumb.png.8d3b34a2bda2f66489a9e120f6b34d91.png

To są wykresy zmiennych joysticka. Tylko trzeba było zrobić je jako całkiem globalne, zdefiniowane jeszcze przed main(), bo takie symbole zawiera elf. Na razie nie umiem śledzić zmiennych lokalnych, jak to możliwe jest przy zatrzymaniu debugera w miejscu gdzie są dostępne. Tu można zdefiniować jakieś wykresy, ale jeszcze nie umiem.
Trzeba pamiętać, żeby zatrzymać debugowanie w CUBE IDE, inaczej Cube Monitor nie ma dostępu do stlinka.

Filozofia dosyć prosta:

1. użyć gotowego wzoru / czartu basic flow. Można go wgrać bo jest dostępny.
2. zbudować projekt w trybie debug, aby powstał elf z mapą symboli.

3. dwukliknąć bloczek wejścia my_probe_in.

4. Tam dodać probe funkcją add. Program wykryje podłączony stlink / nucleo

5. To samo powtórzyć dla myProbe_Out. Można dodać po nadanej własnej nazwie.

6. dwukliknąć blok my variables - u mnie już nazwany joystickXY

Tam wpisać ścieżkę do pliku debug/projekt.elf z naszego projektu i wybrać plik. Program wciągnie dystępne symbole zmiennych.

7. Wybrać i zaznaczyć zmienne, które chcemy monitorować. Zapamiętać i zamknąć.

8. Dwukliknąć dolny blok my variables i tam wybrać które z wybranych zmiennych mają być śledzone.
Można dodać post procesing np. na podstawie zmiennych ADC wyliczyć rzeczywiste napięcia.

9. Zapamietać, zamknąć i nacisnąć deploy.

10. kliknąć dashboard a w nim start acquisition. P5rogram będzia zbierał zawartości zmiennych i wyświetlał na wykresie.

Tyle narazie się nauczyłem. Widzę że są inne bloczki np. show notification, myChart, clear graphics....., poza tym to jest basic flow czyli najprostszy. Można tworzyć własne jak sięumie :).

Narzędzie wygląda na fajne i jednak działa.

Nie można przejść tego rozdziału kursu używając starego narzędzia. Najpierw trzeba odkryć nowe. Warto by było zaktualizować kurs do nowych wersji IDE i pobocznych narzędzi.

  • Lubię! 1

Daje się to konfigurować, ale nie wszystko jest na początku oczywiste. Wybrane zmienne można edytować w biegu, można też włączać i wyłączać w biegu zmienne, których przebieg jest rysowany. Wykres wtedy jest automatycznie skalowany do pozostałych. Na rysunku widać jak wyzerowałem zmienną counter i sinusy zaczęły się od początku. Zmienne muszą być globalne, zdefiniowane jeszcze przed funkcją main(), ale można dodać własne zmienne, podając ich adresy w pamięci, też rejestry procesora, liczników..., ale to wyższa szkoła jazdy. Narzędzie fajne, ale trzeba trochę popróbować żeby to opanować. Nie umiem usunąć tego Import data, choć jest niepotrzebne tutaj.

obraz.thumb.png.8a76922ef26854b534032e74eead2814.png

  • Lubię! 1
Dnia 28.02.2025 o 12:33, aimeiz napisał:

Czyżby niezgodność wersji kompilatora z STM CUBE IDE z STM Studio? Może ktoś natknął się na taki błąd i zna rozwiązanie.

Tak, niestety tak, jak pisałem wyżej STM Studio nie jest już rozwijanym programem. Było proste w użyciu, dlatego pokazaliśmy je w kursie. Nowe narzędzie, czyli STM32Cube Monitor daje dużo więcej możliwości, ale jest też dużo bardziej zaawansowane - wymagałoby praktycznie osobnego kursu tylko na jego temat. Dlatego nie dodawaliśmy tych informacji do kursu L4, który i tak był już obszerny. Zaraz dodam informację na blogu, że narzędzie te może już nie działać.

Przy okazji dodam jeszcze link do narzędzia, które opracował użytkownik @klonyyy:

 

Wracając do kursu i tematu ADC. Chciałem zobaczyć jak ADC1 poradzi sobie z odczytem 4 kanałów. W MX dołożyłem do joystika kanały 3 na fotorezystor i kanał 4 na potencjometr. Pozostawiłem użycie DMA i oversampling. MX tak przyporządkował porty do kanałów:

obraz.thumb.png.17d456621058c310418623415dacdda6.png

Tylko w rzeczywistości okazało się że kanał 3 czyta z PC3 a kanał 4 niewiadomo skąd, bo wynik jest niezależny od ustawienia potencjometru i waha się odczyt 750 +/- 50. Poniżej  fragmenty kodu dotyczące ADC1

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <math.h>
#include <stdio.h>
/* USER CODE END Includes */

/* USER CODE BEGIN 0 */
int __io_putchar(int ch)
{
  if (ch == '\n') {
    __io_putchar('\r');
  }
  HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
  return 1;
}

volatile static uint16_t joystickX;
volatile static uint16_t joystickY;
volatile static uint16_t photoResistor;
volatile static uint16_t potentiometer;

/* USER CODE END 0 */
..............
/* USER CODE BEGIN WHILE */
  volatile static uint16_t adc1[4];
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc1, 4);
  joystickX = adc1[0];
  joystickY = adc1[1];
  photoResistor = adc1[2];
  potentiometer = adc1[3];
  while (1)
  {
	  if(abs(joystickX-adc1[0]) > 10 || abs(joystickY-adc1[1])>10 || abs(photoResistor - adc1[2])>10 || abs(potentiometer - adc1[3])>10){
	  joystickX=adc1[0];
	  joystickY=adc1[1];
	  photoResistor=adc1[2];
	  potentiometer=adc1[3];
	  printf("VRx=%u, VRy=%u, VPhoto=%u, VPot=%u\n", joystickX, joystickY, photoResistor, potentiometer);
	  }
	  HAL_Delay(100);
    /* USER CODE END WHILE */
.........
//Konfiguracja ADC1 utworzona przez MX
   hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 4;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.OversamplingMode = ENABLE;
  hadc1.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_16;
  hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_4;
  hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
  hadc1.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_REGULAR_RANK_4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

Dodatkowe zmienne globalne joystickX, joystickY, photoResistor, potentiometr zastosowałem, aby móc łatwo skonfigurować CUBEMonitor. Tam widać tylko globalne zmienne.

Debuger pokazuje tablicę adc1[4] i już w tablicy odczyt adc1[3] pokazuje "smieci" a adc1[2] pokazuje odczyt z portu PC3 zamiast PC2.

Podłączenia zrobiłem według tej rozpiski portów:

obraz.thumb.png.d7c21ceaccbf52c4716618ba3c04b553.png

Na moje oko wszystko jest dobrze a działa źle.

(edytowany)
15 godzin temu, Treker napisał:

Tak, niestety tak, jak pisałem wyżej STM Studio nie jest już rozwijanym programem. .............

 

Bawiłem się nieco CUBE Monitorem. Narzędzie bardzo obszerne, niestety mało intuicyjne i dokumentacja szczątkowa. Poza tym co pokazane jest w kilku przykładach: Wykres, zmiany zmiennych w biegu, filtr na pojedynczą zmienną, waga, nie udało mi się doprowadzić do działania innych bardzo podstawowych funkcji np. tabela. Chciałem mieć wypisy zmiennych w tabelce, ale wyświetlają się tylko nagłówki. Próbowałem też radar z myślą o przedstawieniu zależności jednej zmiennej od drugiej, ale nic się nie wyświetla poza rysunkiem radaru. Trudno powiedzieć czy narzędzie nie działa czy są jakieś subtelności w tworzeniu flow, których opisów nie znalazłem.

Dziś pojawiło siękolejne uaktualnienie CUBE IDE. Teraz jest wersja:

Version: 1.18.0

Build: 24413_20250227_1633 (UTC)

 

Edytowano przez aimeiz
  • Lubię! 1

siemanko , mam problem z pierwszym zadaniem z DMA kod mam dokładnie taki jak w kursie wszystkie ustawienia też, tylko jedna wartość która zmienia się tylko jeśli kliknie się reset a druga jest równa zero. widziałem że ktoś już w komentarzach miał taki problem i rozwiązaniem była zmiana kolejności /* Initialize all configured peripherals */ tak aby MX_DMA_Init(); było przed MX_ADC1_Init(); jednak jeśli tak zrobię kompletnie nic nie jest wysyłane. ktoś ma pomysł dlaczego tak się dzieje ?

@Osk1 przetestowaliśmy raz jeszcze przykład na najnowszej wersji oprogramowania i wszystko zadziałało. Czy korzystasz z płytki, na której bazuje ten kurs? Jaką wersję środowiska posiadasz?

  • 3 miesiące później...

Cześć, przerobiłem cały dział natomiast utknąłem na pierwszym zadaniu domowym. Mam podany kod, z potencjometru odczytuje wartość, którą następnie przerabiam na okres i duty cycle tak aby otrzymać 50% wypełnienia okresu. Podglądając zmienne w debugerze wszystko gra, zmienne są aktualizowane natomiast potem dzieje się czarna magia. Początkowo diody migają w równych odstępach, natomiast po chwili (czasem kilka mignięć czasem kilkanaście) cały program się rozjeżdża. Diody migają 2-3 razy potem dłuższa przerwa i od początku. Zwiększanie częstotliwości czasem działa a czasem nie, dla niektórych położeń potencjometra diody się świecą cały czas a dla innego w ogóle. Mógłbym prosić o naprowadzenie co sprawdzić? Myślałem o tym czy nie inicjalizować licznika od początku na zmianach natomiast nie daje to efektu.

 

/* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim3);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_ADC_Start(&hadc1);
	  HAL_ADC_PollForConversion(&hadc1, 100);
	  uint32_t value = HAL_ADC_GetValue(&hadc1);
	  uint32_t period = value * 2;
	  uint32_t duty = period / 2;
	  __HAL_TIM_SET_AUTORELOAD(&htim3, period);
	  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty);
	  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, duty);

    /* USER CODE END WHILE */
  }

Dodałem też sprawdzanie czy nowa wartość jest różna od poprzedniej i wtedy aktualizowałem timer, natomiast to nie przyniosło poprawy.

(edytowany)

Po długich przebojach udało mi się coś wykombinować, nadal czasami mają miejsce dziwne mignięcia ale chyba wrócę do tego za jakiś czas

while (1)
  {

	  HAL_ADC_Start(&hadc1);
	  HAL_ADC_PollForConversion(&hadc1, 100);
	  uint32_t value = HAL_ADC_GetValue(&hadc1);


	  if (value < 250){
		  period = 1000;
	  } else {
		  period = value * 4;
	  };

	   float difference = old_value - value;

	   if(abs(difference) > 100){
		  if (old_period != period){
		  duty = period / 2;
		  __HAL_TIM_SET_AUTORELOAD(&htim3, period);
		  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty);
		  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, duty);
		  htim3.Instance->EGR |= TIM_EGR_UG;
		  old_period = period;
		  HAL_Delay(1000);
		  printf("value = %lu\n", value);
		  }

	   }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

Edytowano przez Unique
  • Lubię! 1
  • 8 miesiące później...

W schemacie do komparatora jest błąd - podmienione są R2 i Rfot, poza tym inny rezystor jest użyty na zdjęciu oraz obrazku z płytką niż w schemacie do R2 (1k vs 10k).

Z innej beki nagłowiłem się trochę, bo mi nie działało (dioda się paliła cały czas). Całe szczęście, że miałem drugi fotorezystor z kursu z elektroniki i z nim działało poprawnie. Niby oba fotorezystory są takie same, 5-10k, ale jednak ten z kursu STM32 ma większe spadki napięcia (inną "czułość"?). Dopiero jak zaświecę na niego latarką, to wtedy dioda gaśnie. 

Czy to znaczy, że ten fotorezystor jest walnięty, czy że aż tak mocno odbiegają jego parametry między egzemplarzami???

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