Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'stm32'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino i ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - DIY
    • Projekty - DIY roboty
    • Projekty - DIY (mini)
    • Projekty - DIY (początkujący)
    • Projekty - DIY w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Zawody/Konkursy/Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie

Kategorie

  • Quizy o elektronice
  • Quizy do kursu elektroniki I
  • Quizy do kursu elektroniki II
  • Quizy do kursów Arduino
  • Quizy do kursu STM32L4
  • Quizy do pozostałych kursów

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Imię


Strona

  1. Dzień dobry, pacjent to stm32 H723VGT6, dodałem arm_math, deklarację użycia CM7 oraz bibliotekę dla mojego mikrokontrolera tj. M7lfsp. Dane odbieram przez DMA i mam je od razu skonwertowane do float, wysyłane są tak samo z zmiennej typu float przez rzutowanie na uint16_t. Problem jest taki, że przekazywanie parametrów na sucho aby sprawdzić czy same rzutowania stanowią problem działają jak najbardziej w porządku. Problem następuje gdy wykorzystuję funkcję od implementowania filtrów IIR, wówczas wartości wyjściowe zwracają wartość inf. Próbowałem przekazać parametry zarówno w formie wskazania od którego miejsca tablicy ma zacząć odczytywać wartości czyli &l_buf_in[0] jak i wskazać całą tablicę l_buf_in, przy późniejszej deklaracji rozmiaru bloku 256. W obu przypadkach wychodzi na to samo, zarówno nie działa jak i wskazuje na całą tablicę. arm_biquad_casd_df1_inst_f32 mam deklarację dwóch struktur, które później inicjuję. W init mam obie struktury, filtr będzie drugiego rzędu więc wykorzystuje 5 współczynników, stąd iir_coeffs[5], i będą 4 stany - wzorowane na grafice struktury filtru IIR czyli iir_l_state[4]. I numStages czyli drugi parametr inicjalizacji to liczba takich filtrów połączona szeregowo - w tym wypadku jest to pojedyncza filtracja, pojedynczy filtr. Później zapewne jak uda mi się to poprawić to zwiększę liczbę filtrów to będę miał analogicznie 10 współczynników, 8 stanów i numStages = 2, itd itd. Dodatkowo kalibracja i inicjalizacja ADC, mniejsza z nim bo tutaj nic nie robi oraz start DMA dla I2S z rzutowaniem aby otrzymać od razu upragnione wartości float. I potem cała magia - mam dwa stany - halfCplt oraz Cplt callback, i w zależności od tego rozpatruję zakres 0-511 oraz 512-1023 w zmiennej rxBuff. Rozdzielam 512 wartości na dwa bufory zawierające dane dla kanału lewego oraz prawego więc mam 2x 256 próbek w odpowiednich tablicach i próbuję to przefiltrować osobno dla obu kanałów. Wskazuję blok z danymi wejściowymi, blok gdzie mają zostać zapisane i rozmiar bloku. Z racji tego, że wartości l_buf_in oraz r_buf_in są nadpisywane to nie muszę podawać zakresów tak jak w głównej zmiennej rxBuf tylko to co jest w bloku jest gotowe do przetworzenia.Więc na jedno wyjdzie jak wcześniej wspomniałem czy napiszę &l_buf_in[0] czy l_buf_in. I problem jest taki, że na wyjściu dla l_buf_out[0] dostaję inf, tak samo jak wszystkie inne komórki tablicy. Potem obie tablice są sumowane aby utworzyć analogiczny przebieg jak przedtem, nie wiem tylko czy nie zamieniam kolejności dwóch kanałów, ale to wyjdzie w praniu jak zacznie działać normalnie kod. I tutaj moje pytanie, dlaczego arm_biquad_cascade_df1_f32 zwraca wartości inf. /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "arm_math.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; CORDIC_HandleTypeDef hcordic; FMAC_HandleTypeDef hfmac; I2S_HandleTypeDef hi2s1; DMA_HandleTypeDef hdma_spi1_rx; DMA_HandleTypeDef hdma_spi1_tx; /* USER CODE BEGIN PV */ volatile static uint16_t adc_val[2]; float rxBuf[1024]; float txBuf[1024]; float l_buf_in[256]; float r_buf_in[256]; float l_buf_out[256]; float r_buf_out[256]; float iir_coeffs[5] = { 1.0041645480379269, -1.9797515357244457, 0.9759879669583226, -1.9798515425143588, 0.9800525082063363 }; float iir_l_state[4]; float iir_r_state[4]; uint8_t callback_state = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_ADC1_Init(void); static void MX_I2S1_Init(void); static void MX_CORDIC_Init(void); static void MX_FMAC_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ 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(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_ADC1_Init(); MX_I2S1_Init(); MX_CORDIC_Init(); MX_FMAC_Init(); /* USER CODE BEGIN 2 */ arm_biquad_casd_df1_inst_f32 iirsettings_l, iirsettings_r; arm_biquad_cascade_df1_init_f32(&iirsettings_l, 1, iir_coeffs, iir_l_state); arm_biquad_cascade_df1_init_f32(&iirsettings_r, 1, iir_coeffs, iir_r_state); if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED) != HAL_OK) { Error_Handler(); } HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc_val, 2); HAL_I2SEx_TransmitReceive_DMA(&hi2s1, (uint16_t*) txBuf, (uint16_t*) rxBuf, 1024); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if (callback_state != 0) { if (callback_state == 1) { uint16_t x = 0; for (int i = 0; i < 511; i = i + 2) { l_buf_in[x] = rxBuf[i]; r_buf_in[x] = rxBuf[i + 1]; x++; } x = 0; arm_biquad_cascade_df1_f32(&iirsettings_l, l_buf_in, l_buf_out, 256); arm_biquad_cascade_df1_f32(&iirsettings_r, r_buf_in, r_buf_out, 256); for (int i = 0; i < 511; i = i + 2) { txBuf[i] = l_buf_out[x]; txBuf[i + 1] = r_buf_out[x]; x++; } x = 0; } else if (callback_state == 2) { uint16_t x = 0; for (int i = 512; i < 1023; i = i + 2) { l_buf_in[x] = rxBuf[i]; r_buf_in[x] = rxBuf[i + 1]; x++; } x = 0; arm_biquad_cascade_df1_f32(&iirsettings_l, l_buf_in, l_buf_out, 256); arm_biquad_cascade_df1_f32(&iirsettings_r, r_buf_in, r_buf_out, 256); for (int i = 512; i < 1023; i = i + 2) { txBuf[i] = l_buf_out[x]; txBuf[i + 1] = r_buf_out[x]; x++; } x = 0; } callback_state = 0; } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = { 0 }; RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 }; /** Supply configuration update enable */ HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); /** Configure the main internal regulator output voltage */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) { } /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_DIV1; RCC_OscInitStruct.HSICalibrationValue = 64; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 34; RCC_OscInitStruct.PLL.PLLP = 1; RCC_OscInitStruct.PLL.PLLQ = 3; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLFRACN = 3072; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) { Error_Handler(); } } /** * @brief ADC1 Initialization Function * @param None * @retval None */ static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_MultiModeTypeDef multimode = { 0 }; ADC_ChannelConfTypeDef sConfig = { 0 }; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Common config */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc1.Init.Resolution = ADC_RESOLUTION_16B; hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc1.Init.LowPowerAutoWait = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.NbrOfConversion = 2; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR; hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; hadc1.Init.OversamplingMode = ENABLE; hadc1.Init.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_10; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_810CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; sConfig.OffsetSignedSaturation = DISABLE; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_16; sConfig.Rank = ADC_REGULAR_RANK_2; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ } /** * @brief CORDIC Initialization Function * @param None * @retval None */ static void MX_CORDIC_Init(void) { /* USER CODE BEGIN CORDIC_Init 0 */ /* USER CODE END CORDIC_Init 0 */ /* USER CODE BEGIN CORDIC_Init 1 */ /* USER CODE END CORDIC_Init 1 */ hcordic.Instance = CORDIC; if (HAL_CORDIC_Init(&hcordic) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN CORDIC_Init 2 */ /* USER CODE END CORDIC_Init 2 */ } /** * @brief FMAC Initialization Function * @param None * @retval None */ static void MX_FMAC_Init(void) { /* USER CODE BEGIN FMAC_Init 0 */ /* USER CODE END FMAC_Init 0 */ /* USER CODE BEGIN FMAC_Init 1 */ /* USER CODE END FMAC_Init 1 */ hfmac.Instance = FMAC; if (HAL_FMAC_Init(&hfmac) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN FMAC_Init 2 */ /* USER CODE END FMAC_Init 2 */ } /** * @brief I2S1 Initialization Function * @param None * @retval None */ static void MX_I2S1_Init(void) { /* USER CODE BEGIN I2S1_Init 0 */ /* USER CODE END I2S1_Init 0 */ /* USER CODE BEGIN I2S1_Init 1 */ /* USER CODE END I2S1_Init 1 */ hi2s1.Instance = SPI1; hi2s1.Init.Mode = I2S_MODE_MASTER_FULLDUPLEX; hi2s1.Init.Standard = I2S_STANDARD_PHILIPS; hi2s1.Init.DataFormat = I2S_DATAFORMAT_24B; hi2s1.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; hi2s1.Init.AudioFreq = I2S_AUDIOFREQ_48K; hi2s1.Init.CPOL = I2S_CPOL_LOW; hi2s1.Init.FirstBit = I2S_FIRSTBIT_MSB; hi2s1.Init.WSInversion = I2S_WS_INVERSION_DISABLE; hi2s1.Init.Data24BitAlignment = I2S_DATA_24BIT_ALIGNMENT_RIGHT; hi2s1.Init.MasterKeepIOState = I2S_MASTER_KEEP_IO_STATE_DISABLE; if (HAL_I2S_Init(&hi2s1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN I2S1_Init 2 */ /* USER CODE END I2S1_Init 2 */ } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA interrupt init */ /* DMA1_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); /* DMA1_Stream1_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); /* DMA1_Stream2_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ void HAL_I2SEx_TxRxHalfCpltCallback(I2S_HandleTypeDef *hi2s) { callback_state = 1; } void HAL_I2SEx_TxRxCpltCallback(I2S_HandleTypeDef *hi2s) { callback_state = 2; } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #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 /* USE_FULL_ASSERT */ Dodaję też archiwum jak by ktoś chciał zobaczyć czy nie namieszałem nic w ustawieniach projektu. IIR_Biquad_ARM.zip
  2. Sprzedam płytkę dicovery B-U585I-IOT02A. Płytka w pełni sprawna, chciałbym za nią 350zł(możliwa jakaś negocjacja ceny). Optymalny byłby odbiór osobisty w Warszawie, ale możliwa wysyłka paczkomatem przy płatności z góry. Pełną specyfikacje płytki można znaleźć na stronie ST W razie pytań zapraszam na pw.
  3. Mam pewien problem. Zakupiłem analogiczny wyswietlacz LCD 2.4 inch module na sterowniku ILI9341. Lecz nie jestem w stanie go skofigurować tak aby jakkolwiek działał. Próbowałem go zrobić analogicznie do jego "mniejszej" wersji 1.8 cala z kursu STM32, lecz ten crushuje się cały czas. Nie wiem w czym tkwi problem i jak skonfigurować to prawidłowo bym mógł na nim pracować. Cięzko mi się dokopać do jakihś plików konkretnie z tym wyswietlaczem i jego podstawową konfiguracją, a jak coś znajdę to nic nie działa prawidłowo/nie jestem w stanie tego przenieść do siebie. Proszę o radę/pomoc albo jakieś przydatne proste linki które pomogą amatorowi stm32. Moja płytka to Nucleo L476RG, ta z kursu. Pozdrawiam PO.
  4. Witam. Realizuję projekt matrycy mikrofonów z wykorzystaniem mikrofonów MEMS ICS-52000 oraz mikrokontrolera, który służy do zbierania danych z mikrofonu w celu dalszej analizy dźwięku np. w MATLAB'ie. Mam problem z komunikacją z mikrofonami. Mikrofony ICS-52000 mają wyjście TDM i mam takich mikrofonów połączonych w łańcuch zgodnie z dokumentacją (zdjęcie poniżej). Celem jest pobranie danych z mikrofonów i zapisanie ich na dysku. Póki co mam gotową konstrukcję i próbuję pisać program, który pobierze dane z każdego mikrofonu. Moje pytanie brzmi: W jaki sposób zrealizować mogę komunikację TDM (Time Division Multiplexing)? Nie ma na ten temat za wiele materiałów. To co udało mi się znaleźć to zastosowanie interfejsu SAI (Serial Audio Interface) i próbowałem ten interfejs wykorzystać jednak podłączając tylko jeden mikrofon w celu jego stestowania nie działało to tak jak powinny. Próbowałem pobrać dane przez HAl_SAI_Receive_DMA() i w funkcji callback void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) przypisać wartość do zmiennej, jednak nie działało to. Szczerze to nie ma zbyt wielu przykładów zastosowania tego interfejsu do rejestracji dźwięku, a z dokumentacji co udało mi się wyczytać to SAI wspiera TDM. Konfiguracja interfejsu SAI Mode: Master Konfiguracja zegara: Po włączeniu SAI w tej konfiguracji mam 3 piny: SAI1_SD_A - wyjście danych SAI1_SCK_A - zegar SAI1_FS_A - frame select (word select) Czy zegar jaki podaje na wyjścia mikrofonów równy jest wartości zegara SAI1 (24MHz)? Czy częstotliwośc SAI1_FS_A równa jest częstotliwości audio (48kHz), czy musze ten pin obsługiwać w jakiś sposób? Według dokumentacji mikrofony są synchronizowane przez sygnał WS, więc mikrofony dzielące ten sam zegar będą samplowane synchronicznie.
  5. Enbio Technology - Potrzebujemy do pomocy średniodoświadczonego programistę embedded, najlepiej który ma doświadczenie w STM32 i ESP32 w rozwiązaniach komercyjnych, albo przynajmniej w projektach wykonanych profesjonalnie, przetestowanych, nieawaryjnych. Dobrze mieć wiedzę w temacie IoT, najlepiej z MQTT i Azure IoT Hub. Praca hybrydowa: zdalnie / biuro + warsztat R&D w Rumii (Pomorskie, tuż obok Gdynii). Zarobki: do 10k brutto. Projekty które robimy to autoklawy parowe z dostępem do internetu. Pracujemy nad nowymi technologiami, a urządzenia, po wdrożeniu będą pracować w krajach na całym świecie. Duża zaleta tej pracy - możliwość prześledzenia projektu od początku do końca i napisanie własnego programu - jest to świetna okazja do nauki. Praca nie ogranicza się do jednego projektu. W tym momencie jest jeden produkt wymagający utrzymania (STM32F4), drugi w trakcie realizacji i trzeci do którego szukamy programisty. Będą też kolejne. W przypadku zainteresowania podam szczegóły.
  6. Cześć, z uwagi na ograniczoną ilość pamięci w STM32H7, w celu pełnego wykorzystania jej zasobów, chciałbym współdzielić jeden duży bufor do dwóch zadań (gdy pierwsze zadanie się skończy, zaczyna się drugie, więc dane "nie kłócą się ze sobą"). Normalnie korzystam z tablic: uint32_t tab1[119256] w jednym programie oraz uint8_t tab2[278528] w drugim ( (round_No=4096)*(liczba_rejestrów=68) ). Przyszedł czas połączyć programy i okazało się, że pamięci brakuje. Stąd pomysł, by wykorzystać jeden bufor (tablicę) do obu celów. Mam jednak problem z poprawnym zapisem danych. Próbowałem bardzo różnych kombinacji, może nie będę ich wymieniał, by nie narzucać (złych) pomysłów. Proszę o pomoc, jak poprawnie skonstruować zapis do tablicy, a następnie zapis tablicy na kartę. Dobrze byłoby, gdybym w pełni wykorzystał tab1 i mógł użyć 2 razy więcej komórek 8-bitowych niż jest komórek 32-bitowych, ale jeśli zostanie mi do dyspozycji owe 119256, to też da radę. Poniżej krytyczne fragmenty programu, czyli akwizycja danych do tablicy oraz ich zapis na kartę pamięci. HAL_I2C_Mem_Read_DMA(&hi2c1, MPU9250_ACC_ADDRESS_A, MPU9250_ACCEL_XOUT_H, 1, &tab[round_No*68 + 0*14], 14); //14 registers measurement HAL_I2C_Mem_Read_DMA(&hi2c2, MPU9250_ACC_ADDRESS_B, MPU9250_ACCEL_XOUT_H, 1, &tab[round_No*68 + 1*14], 14); //14 registers measurement HAL_I2C_Mem_Read_DMA(&hi2c3, MPU9250_ACC_ADDRESS_C, MPU9250_ACCEL_XOUT_H, 1, &tab[round_No*68 + 2*14], 14); //14 registers measurement HAL_I2C_Mem_Read_IT (&hi2c4, MPU9250_ACC_ADDRESS_D, MPU9250_ACCEL_XOUT_H, 1, &tab[round_No*68 + 3*14], 14); //14 registers measurement HAL_I2C_Mem_Read_DMA(&hi2c1, BMP280_ADDRESS_A, BMP280_REG_BAR_MSB, 1, &tab[round_No*68 + 4*14+0*3], 3); //3 registers measurement HAL_I2C_Mem_Read_DMA(&hi2c2, BMP280_ADDRESS_B, BMP280_REG_BAR_MSB, 1, &tab[round_No*68 + 4*14+1*3], 3); //3 registers measurement HAL_I2C_Mem_Read_DMA(&hi2c3, BMP280_ADDRESS_C, BMP280_REG_BAR_MSB, 1, &tab[round_No*68 + 4*14+2*3], 3); //3 registers measurement HAL_I2C_Mem_Read_IT (&hi2c4, BMP280_ADDRESS_D, BMP280_REG_BAR_MSB, 1, &tab[round_No*68 + 4*14+3*3], 3); //3 registers measurement f_write(&fil, readings_from_registers, sizeof(tab), &numread); W tej drugiej części (BMP280) dane pobieram z 3 rejestrów 8-bitowych. Ponieważ może być to kłopotliwe, mogę ograniczyć się do 2 lub rozszerzyć do 4, w którym jeden będzie zawsze zerami. Każda konstruktywna uwaga będzie na dla mnie cenna.
  7. Hej, Chciałbym wam przedstawić mój ostatni popołudniowy projekt, którego używam w pracy i przy projektach z udziałem mikrokontrolerów STM32. Krótko mówiąc jest to opensourceow'a kopia niewspieranego już STMStudio. Dla tych, którzy nie słyszeli wcześniej o tym programie, był to realtime'owy logger wartości zmiennych, które były odczytywane przy pomocy programatora STlink bezpośrednio z mikrokontrolera przy użyciu interfejsu debugowego. Genialna sprawa do strojenia regulatorów PID, podglądu zmiennych procesowych, konfigów, czy nawet sterowania wykonaniem programu. Narzędzie o tyle fajne, że jest bezinwazyjne (nie zmienia zachowania softu zależnie od tego czy z niego korzystamy czy nie), pozwala na odczyt z częstotliwością dochodzącą nawet do 1kHz, przy niewielkiej ilości logowanych zmiennych, a także pozwala na zapisywanie wartości z poziomu GUI. Niestety od jakiegoś czasu jest niewspierane, a jego następca czyli Cube Monitor jest bardzo ograniczony i wydaje się również być obecnie porzucony. Dodatkowo STMStudio ma problem z dekorowanymi (manglowanymi) nazwami obiektów C++ - wbudowana wyszukiwarka ich po prostu nie widzi, a dodatkowo program działa tylko na Windowsie. Dochodzi do tego kilka wkurzających bugów i w efekcie program przestaje być już tak atrakcyjny. Nie mając innych alternatyw postanowiłem zrobić swoje narzędzie w oparciu o różne projekty dostępne na Githubie. Główne założenia to wsparcie dla Windowsa i Linuxa oraz obsługiwanie C++. W chwili obecnej projekt jest we wczesnym stadium, jest używalny ale nie ma jeszcze wszystkich ficzerów STMStudio. Postanowiłem o nim napisać teraz ze względu na to, że może akurat ktoś zdecyduje się spróbować nim pobawić i wrzuci mi jakiś feedback, a ja będę wiedział co trzeba dopracować/zmienić w pierwszej kolejności. Aktualnie sam projekt to nie są jakieś wyżyny programowania, nad refactorem pracuję w wolnych chwilach - z czasem powinno być lepiej. Zachęcam do uwag i sugestii 😉 Poniżej link do repa na Githubie: https://github.com/klonyyy/STMViewer Na razie testy przeprowadzałem tylko na maszynach wirtualnych i komputerze z Windowsem, ale założenie jest takie, że pobierając installera z strony z Releasami (po lewej stronie) i instalując program powinien on ruszyć 😉 W razie problemów jestem do dyspozycji, tutaj czy na Githubie. Jako, że softwareowe projekty zazwyczaj bywają nudne jeśli chodzi o opis, to wrzucam gifa z działania programu, tak na zachętę 😉 Postaram się wrzucać tutaj ważniejsze update'y jako posty, możecie także zajrzeć na bloga, tam pojawiać się będą posty w j. angielskim.
  8. Hej, zwracam się do Was z prośbą i radą jaki protokół do komunikacji miedzy różnymi mikrokontrolerami najlepiej użyć do mojego wymyślonego projektu. To zaczynając od pomysłu. Chciałem stworzyć kontroler główny, który będzie miał komunikację 2 kierunkową z urządzeniami podłączonymi do niego: mniej więcej tak ja na tym schemacie: Z Założenia chcę, aby urządzenia łączyły się ze sobą kablowo najprawdopodobniej skrętką 8 żyłową(2 lub 4 przewody chciałbym poświęcić na zasilania, reszta na komunikację) a odległość maksymalna to będzie 20m, Dane przesyłane miedzy nimi nie będą duże( najprawdopodobniej string o długości max 30 znaków lub char do identyfikacji typu wiadomości i int16) a częstotliwość komunikacji raz na 1s z każdym urządzeniem wystarczy. Chciałbym także aby te podłączenia można było robić w trakcie używania urządzenia a ich wykrywanie było na zasadzie "do portu 3 zostało coś podłączone" i po przez różnego rodzaju wiadomości urządzanie będzie rozpoznawało z czym konkretnie się połączył. Dodatkowo chciałbym aby można było podłączyć różne mikrokontrolery, takie jak STM32, ESP oraz Arduino. Jest Modbus, SPI, I2C, CAN, UART itd... Ale co najlepiej do takiego zastosowania by się nadało? Wiem, że każdy wybór ma swoje plusy i minusy i zdaję sobie sprawę, że muszę pójść na jakieś kompromisy. Moim wstępnym pomysłem było wykorzystanie do tego RS-485. Tylko nie miałem z nim nigdy styczności i nie jestem przekonany, że się sprawdzi. Dlatego chcę waszej opinii i porady, co byście do takiego zastosowania użyli, a może już ktoś robił coś podobnego i ma w tym doświadczenie.
  9. Cześć wszystkim. Chciałbym skonfigurować akcelerometr mc3479 do pomiaru położenia komunikując się z czujnikiem przy użyciu interfejsu spi. Do tej pory nie wykorzystywałem zbyt tego interfejsu i mam problem z funkcjami do zapisu oraz do odczytu rejestrów. Mianowicie po napisaniu funkcji nie jestem w stanie zapisać/odczytać wartości z czujnika. Próbowałem podać przykładową wartość, ale niestety nie zadziałało. Czy ktoś ma pomysł co mogłem przeoczyć? 🙂 void mc_reg_write(uint8_t reg, uint8_t value) { uint8_t tx[3] = { 0x40 | reg, value, 0x00 }; HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, tx, 3, HAL_MAX_DELAY); HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_SET); } uint8_t mc_reg_read(uint8_t reg) { uint8_t tx_data[2] = { reg | 0x80, 0x00 }; uint8_t rx_data[2] = { 0x00, 0x00 }; HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_RESET); HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, 2, HAL_MAX_DELAY); HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_SET); return rx_data[1]; } mc_reg_write(0x12, 0x01); printf("In register 0x%02X is: (0x%02X)\r\n",0x12, mc_reg_read(0x12));
  10. Kontynuacja tematu analizy widma audio. To już prawie 2 lata z przerwami 🙂 Niedawno nieco niepewnie wrzuciłem pierwszą wzmiankę o projekcie w wspólny worklog, ale temat się trzyma więc dorzucam osobny worklog. Jak ostatnio link na githuba z projektem PCB, programem, notatnikiem Jupyter z obliczeniami i pomiarami: https://github.com/Gieneq/FFTSlice W tej aktualizacji doszła całkiem dobra metoda generowania sinusoid z DAC. Po tym jak odpaliłem DAC, przypomniałem sobie dlaczego kiedyś odrzuciłem tę opcję. Wygenerowanie dowolnej częstotliwości nie jest takie oczywiste bo trzeba regulować częstotliwość timera i ewentualnie wybrać inną rozdzielczość spóbkowania sinusoidy. Dlatego uprościłem sytuację i pomyślałem że dla potrzeb analizatora widma audio potrzebuję tylko 100 częstotliwości pomiędzy 20Hz a 20kHz. Podzieliłem przedział logarytmicznie dla lepszej percepcji: Mikrokontroler STM32G081RBT nie ma za dużo pamięci, ale 6 spróbkowanych sinusoid zapisanych na uint16_t może być. Wartości narastają od 64 do 2048. Następnie trzeba przyporządkować próbki do częstotliwości jakie chcę wygenerować. Większe rozdzielczości lepiej nadają się dla niskich częstotliwości, a mniejsze rozdzielczości do szybszych przebiegów. Skrypt w Pythonie pomógł mi dokonać takiego przyporządkowania minimalizując czas w którym sygnał pozostaje na tym samym poziomie przy zachowaniu niezadużego odchylenia od oczekiwanej częstotliwości: Błąd poniżej 1% to całkiem dobry wynik. Przyporządkowanie jest dość proporcjonalne: W tabelce widać co by się działo gdyby skorzystać z tej samej rozdzielczości próbek - dla wysokich częstotliwości 1024 próbek ni jak nie pasuje: Pozostały testy, porównałem teoretycznie obliczoną częstotliwość z pomiarami picoscopem i wyniki są zgodne z oczekiwaniami. Tu wybrana wartość 1068Hz: Jestem trochę zaskoczony, że tak dobrze to działa 😅 w kolejnej aktualizacji chcę dodać opcję kolejkowania zmiany częstotliwości, żeby następowała po zakończeniu odtwarzania okresu sinusoidy - żeby nie było ucięcia w środku co wiązałoby się z trzaskiem od tak wygenerowanej wysokiej częstotliwości. Następnie pozostaje przetestowanie PGA i dodanie interfejsu SPI.
  11. Cześć, testuję ostatnio evalboard STM32U5A9J-DK, na pewno ktoś ma większe doświadczenie więc na starcie pytanie: czy -Ofast i 160MHz (max) 480x480 px RGB8888 10ms czyszczenie framebuffera na samym MCU to szybko? Na razie podejście nienajlepsze. Bez optymalizacji wyszło 36ms. void gfx_prepare() { int32_t ltdc_clear_sreen_start_us = microtimer_get_us(); /* Clear screen */ gfx_fillscreen(0xFFFF0000); // RED gfx_draw_fillrect(LCD_WIDTH/2 - 20, LCD_HEIGHT-40, 40, 40, 0xff0000ff); ltdc_clear_sreen_duriation_us = microtimer_get_us() - ltdc_clear_sreen_start_us; } void gfx_draw_fillrect(uint32_t x_pos, uint32_t y_pos, uint32_t width, uint32_t height, uint32_t color) { uint32_t px_address = 0; uint32_t i; uint32_t j; /* Get the rectangle start address */ uint32_t startaddress = (hltdc.LayerCfg[0].FBStartAdress + (4 * (y_pos * PIXEL_PERLINE + x_pos))); /* Fill the rectangle */ for (i = 0; i < height; i++) { px_address = startaddress + (3072 * i); //768 * 4 for (j = 0; j < width; j++) { *(__IO uint32_t *)(px_address) = color; px_address += 4; } } } void gfx_fillscreen(uint32_t color) { gfx_draw_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT, color); } Tu podgląd czasów: Jak można to poprawić? Używanie memset nie poprawiło, pewnie optymalizacja i tak sprowadza to do podobnych operacji. Widziałem że DMA2D ma tryb mem-register do wypełniania kolorem. A może transfer małych kawałów pamieci? Chcę teraz dodać doublebuffer z przerwania od LTDC Live Event, ale najpierw muszę mieć sposób żeby zmieścić się pomiędzy back i front Vporch 😕 To zajmuje te 10ms:
  12. Cześć piszę własną bibliotekę, trochę na bazie HAL ale uproszczoną i zoptymalizowaną, język: C++. W pliku serial.cpp zdefiniowałem klasę SerialInterface z podstawową obsługą portu, to jest OK - ślady kodu są widoczne w wynikowym kodzie (plik .list) /* USER CODE BEGIN WHILE */ SerialInterface tty0(USART2, 9600); 800022a: 463b mov r3, r7 800022c: f44f 5216 mov.w r2, #9600 ; 0x2580 8000230: 4904 ldr r1, [pc, #16] ; (8000244 <main+0x2c>) 8000232: 4618 mov r0, r3 8000234: f001 fa06 bl 8001644 <_ZN15SerialInterfaceC1EP13USART_TypeDefm> while (1){ // if (tty0.getReceived()>5) // tty0.sendByte('X'); // else if (tty0.getReceived()>0) // tty0.sendByte('L'); tty0.sendByte('-'); 8000238: 463b mov r3, r7 800023a: 212d movs r1, #45 ; 0x2d 800023c: 4618 mov r0, r3 800023e: f001 fa3f bl 80016c0 <_ZN15SerialInterface8sendByteEh> 8000242: e7f9 b.n 8000238 <main+0x20> Oprócz klasy, w pliku serial.cpp zdefiniowałem obsługę przerwania, funkcję USART2_IRQHandler jako: void USART2_IRQHandler(void){....} no i ta funkcja nie pojawia się już w listingu nie pojawia. Program testowy w pętli wysyła znaki, zgodnie z oczekiwaniem: (...) SerialInterface tty0(USART2, 9600); while (1){ tty0.sendByte('-'); } /* USER CODE END 3 */ } (...) jednak po odebraniu znaku "z zewnątrz" wysypuje się -> na debuggerze widzę, że następuje skok do obsługi nieznanego przerwania (👉Default_Handler), czyli faktycznie jakby linker połączył tylko część mojej biblioteki?? (plik startup_stm32g431kbtx.s w którym "ląduje" procesor, zawartość jest defaultowa, nie grzebane) : /** * @brief This is the code that gets called when the processor receives an * unexpected interrupt. This simply enters an infinite loop, preserving * the system state for examination by a debugger. * * @param None * @retval : None */ .section .text.Default_Handler,"ax",%progbits Default_Handler: Infinite_Loop: b Infinite_Loop <--- SKOK TUTAJ .size Default_Handler, .-Default_Handler Jak spowodować, aby linker dołączył moją obsługę IRQ? W CubeMX nie wyklikałem konfiguracji, żeby nie tworzył mi swoich "śmieci" z HAL, które są dalekie od optymalnych. Obsługa przerwania w oryginalnym HAL trwa wieki, a piszę aplikację wymagającą bardzo krótkich i sprawnych przerwań. Ktoś poradzi?
  13. Witam, Moje pytanie dotyczy pomiaru częstotliwości, który można (najlepiej programowo) włączać i przerywać po określonym czasie, jednocześnie nie tracąc zawartości zliczonej przez timer. Nie znalazłem takiego rozwiązania, jakie bym chciał, a rozwiązania jakie spotkałem (m.in. AVT5398) bramkowały timer za pomocą zewnętrznej logiki dołączonej do pinów procesora w postaci układu TTL. Ponadto użyty w tym mierniku procesor jest już dość archaiczny i rzadko spotykany. Co chcę uzyskać? Zmierzyć ilość impulsów (częstotliwość) na danym pinie napędzającym jakiś timer, w zadanym oknie czasowym na przykład 1s. Chodzi mi o to, żeby odbyło się to "automatycznie", czyli żeby włączyć rozpoczęcie zliczania zewnętrznych impulsów pędzących timer i po zaprogramowanym czasie zaprzestać zliczania tych impulsów, jednakże mieć możliwość odczytania ilości impulsów zliczonych w danym oknie czasowym. Tu pojawia się kolejny problem, ponieważ sygnał prostokątny jest w okolicach 1 MHz, co oznaczałoby, że "zwykłego" 16 bitowego timera do tego "nie wystarczy", więc przydałby się albo 24 bitowy timer, który można zaprogramować na bramkowanie, albo dwa timery 16 bitowe połączone kaskadowo. Oczywiście wiem, że można by ten problem rozwiązać półśrodkiem, który by wywoływał przerwanie po zadanym okresie zliczania i w tym przerwaniu można by odczytać zawartość rejestru timera, natomiast chodzi mi o rozwiązanie bardziej "automatyczne" i wygodne - godne tych new age procesorów.
  14. Miał ktoś może problem przy wykorzystaniu UART z wartością CRC i w konsekwecji błędny odczyt temperatury z czujnika(85 *C)? Dodatkowo zauważyłem błędy odczyt pierwszego bajtu w adresie czujnika...
  15. Cześć, zaczynam dopiero z STM32, mam teraz wstęp na studiach, ale postanowiłem nauczyć się czegoś więcej. Na razie jestem po #3 części kursu i zabrałem się za zadania domowe. Co do pierwszego (Wróć do przykładu, w którym dioda włączała się na 200 ms i gasła na 800 ms. Zastanów się, jak odwrócić działanie tego programu bez zmieniania jego kodu. ), HAL_GPIO_WritePin(LED[1].port, LED[0].pin, GPIO_PIN_SET); HAL_Delay(200); HAL_GPIO_WritePin(LED[1].port, LED[0].pin, GPIO_PIN_RESET); HAL_Delay(800); mam pomysł, żeby zmienić wyjście na aktywne stanem niskim, ale nie mogę znaleźć tej opcji. Zadanie 3. Dodaj do programu kolejny przycisk, który będzie resetował linijkę. Podpięcie przycisku bez problemów, dodanie go do pinu na płytkę też, ale prosiłbym o pomoc z samym kodem - gdzie szukać w jaki sposób napisać funkcję, która zresetuje. Dzięki za pomoc!
  16. Witam wszystkich użytkowników kursu, wielkie dzięki dla autorów za poświęcony czas. Jestem nowicjuszem w STM32 ale mam kilkunastoletnie doświadczenie z 8051 i AVR-ami Mam problem z pierwszym przykładem gdzie wykorzystywany jest SYSTICK. Po prostu SYSTICK nie generuje przerwania i nie jest wywoływana funkcja HAL_SYSTICK_Callback. Uruchomiłem przykład z wykorzystaniem kolejnego Timera zamiast SYSTICK. Aby się upewnić czy funkcja HAL_SYSTICK_Callback jest wywoływana skonfigurowałem PD15 jako wyjście i wstawiłem w pierwszej linijce funkcji HAL_SYSTICK_Callback polecenie HAL_GPIO_WritePin(dioda_GPIO_Port,dioda_Pin,GPIO_PIN_SET). Dioda się nie zapala. Co robię źle. W kursie nie ma ani słowa na temat skonfigurowania SYSTICK. Poże trzeba jakoś włączyć przerwania od SYSTICK.
  17. Witam, Ostatnio postanowiłem przetrenować sobie czytnik kart microSD pod mikrokontroler NUCLEO-L552ZE-Q. Mam problem z komunikacją z kartą. Generalnie udało mi się wykrywać włożenie bądź wyjęcie karty z czytnika, natomiast przy próbie wykonania testowych czynności tj. utworzenie nowego folderu czy zapis do pliku załącza mi się obsługa błędów. Generalnie komunikację nawiązałem po smmcsd1 z obsługą wbudowanej biblioteki dla plików FatFs. Mój problem polega na tym, że pomimo wykrycia karty w czytniku przy próbie wydania komend pojawiają mi się następujące błędy f_mount (FR_NOT_READY), f_open (FR_DISK_ERR), f_write (FR_INVALID_OBJECT), f_close (FR_INVALID_OBJECT). Podejrzewam, że błąd mogłem popełnić gdzieś przy konfiguracji, ale nigdy wcześniej nie obsługiwałem jeszcze kart microSD. Jeżeli chodzi o podłączenia pinów, to skonfigurowałem je następująco: SDMMC_D0 (PC8), SDMMC_D1 (PC9), SDMMC_D2 (PC10), SDMMC_D3 (PC11), SDMMC_CK (PC12), SDMMC_CMD (PD2), SDCDET (PF3) (ten pin poprawnie wykrywa umieszczenie karty w czytniku). Jest to program głównie do przetestowania karty microSD, do wykonywania nieskomplikowanych działań takich jak tworzenie folderów czy plików. Poniżej załączam plik programu oraz dane odczytywane z terminala. Z góry dziękuję za pomoc. test_microSD.zip
  18. Cześć, kontynuuję przygodę z zapisem danych sensorycznych na kartę pamięci. W przypadku czujników inercyjnych odczytywałem 8-bitowe rejestry, dzięki czemu w dość łatwy sposób mogłem przerobić te dane na char (fragment kodu poniżej). uint8_t my_string[(ASCII_char_No)*rounds]; uint8_t MPU9250_Data_A[14]; sprintf(&my_string[(ASCII_char_No)*(round_No-1)], "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", MPU9250_Data_A[0],MPU9250_Data_A[1],MPU9250_Data_A[2],MPU9250_Data_A[3],MPU9250_Data_A[4],MPU9250_Data_A[5],MPU9250_Data_A[8],MPU9250_Data_A[9],MPU9250_Data_A[10],MPU9250_Data_A[11],MPU9250_Data_A[12],MPU9250_Data_A[13]); Teraz do konwersji mam dane typu int16_t zapisane w tablicy o 16384 elementach i nie bardzo radzę sobie z nimi. W związku z rozmiarem nie wchodzi w grę ręczne wypisywanie elementów, jak poprzednim razem. Pomożecie, jak taką tablicę danych zapisać do tablicy char? W nowej tablicy dane mogą być stałej długości, ale nie muszą. Wystarczy mi ich oddzielenie przecinkiem. Każdy element muszę konwertować osobno w pętli, czy można to zrobić prościej?
  19. Cześć, ponownie wrócił u mnie temat wysyłania z uC danych z czujników MPU9250 do PC. Poprzednio robiłem to z użyciem funkcji printf i terminala CoolTerm i w przypadku 6 osi (akcelerometr + żyroskop) i szybkości próbkowania 20 Hz nie było problemu. Obecnie potrzebuję przesłać dane z 24 osi (4 akcelerometry i 4 żyroskopy na 4 IMU) z szybkością 500 Hz. No i tutaj printf nie wyrabia. Próbowałem też użyć sprintf oraz funkcję HAL_UART_Transmit, HAL_UART_Transmit_IT, HAL_UART_Transmit_DMA. (Z tą ostatnią mam problem, ponoć jest jakiś kłopot z CubeIDE i serią F7. Pierwsze testy pokazały mi jednak, że IT działa tak samo szybko jak DMA. Jeśli to prawda, to na razie ten problem pomijam. Jeśli jednak będzie potrzebne DMA, to tutaj też będę prosił o pomoc. W STM32F410RB Nucleo działa mi bez zarzutu.) Tutaj jednak przy przesyłaniu 24 wartości typu float czas przesłania danych jest zbyt duży i rzeczywista szybkość próbkowania mi spada. Wpadłem na pomysł, by zamiast danych typu float i funkcji (s)printf przesłać po prostu surowe wartości uint8_t z 2 rejestrów (lub jeszcze lepiej połączone od razu w uint16_t) dla każdej osi. Ale tutaj napotykam na problemy. Po pierwsze - jak wysłać te dane? Kolejno po sobie wartości z każdej osi? Czy jakoś je spakować "do kupy" i zrobić jedną transmisję w każdym przerwaniu zegarowym 500 Hz? Pierwszy pomysł wyglądałby mniej więcej tak (od razu proszę o korektę): int16_t MPU9250_aX_A, MPU9250_aY_A ... MPU9250_gZ_D); HAL_UART_Transmit_IT(&huart3, MPU9250_aX_A, sizeof(MPU9250_aX_A)); HAL_UART_Transmit_IT(&huart3, MPU9250_aY_A, sizeof(MPU9250_aY_A)); HAL_UART_Transmit_IT(&huart3, MPU9250_aZ_A, sizeof(MPU9250_aZ_A)); . . . HAL_UART_Transmit_IT(&huart3, MPU9250_gX_D, sizeof(MPU9250_gX_D)); HAL_UART_Transmit_IT(&huart3, MPU9250_gY_D, sizeof(MPU9250_gY_D)); HAL_UART_Transmit_IT(&huart3, MPU9250_gZ_D, sizeof(MPU9250_gZ_D)); Kolejny problem to odbiór tych danych i ich konwersja do postaci zrozumiałej dla człowieka. Na razie otrzymuję w terminalu coś w stylu: BĽR–ˇÍ.h)B*]+ ,Ş.A,Ş)B+ )BŐń."únôA-0Ŕ,."-0~,ŞˇÍÉČÚą.hŐńçÖ~´)Uź˝..áR–)BBĽŐńĺ.Ŕ,çÖ~..ú‰‡.˙,Ş`“+ á.}.ÉČ­mnô[`¦“.űëm.ś '—..˝.††`J.ĹV-0|<’ ĺ.D.›@úí.÷hú..^[.˝J„–÷h‰‡A+ .Š.‰‡~UźçÖ`“Ü÷˛h0`“JahUź©;BĽëmÉČÚą.˙á.ŠUź8\‰‡‰‡éjĺ.Aöš)B+ Korzystam z STM32F746ZG Nucleo, STM32CubeIDE 1.10.1, MCU Package 1.17.0. Na razie dane przesyłam z Nucleo poprzez USB, docelowo będzie to nowy układ z rdzeniem STM32F756VGT6 i komunikacja poprzez BT lub WiFi. 4 czujniki mam podłączone do 2 magistrali I2C. Proszę o wszelkie porady i pomysły, jak szybko przesłać wszystkie potrzebne dane i je poprawnie odczytać w PC.
  20. Zastanawiam się na ile dużym problemem jest używanie dynamicznej alokacji do np. std::string, std::vector w embedded. Podobno fragmentacja może namieszać ale w jeszcze nie widzę jej skutków. Zamierzam zrobić coś z profilerem ale na to przyjdzie czas. Jednym ze sposobów poradzenia sobie z tym jest memory pool ale nie mam z tym większego doświadczenia. Np w ThreadX do założenia wątku, albo kolejki potrzeba przydzielić ręcznie pamięć, tu statycznie: #if (USE_STATIC_ALLOCATION == 1) UINT status = TX_SUCCESS; VOID *memory_ptr; if (tx_byte_pool_create(&tx_app_byte_pool, "Tx App memory pool", tx_byte_pool_buffer, TX_APP_MEM_POOL_SIZE) != TX_SUCCESS) { /* USER CODE BEGIN TX_Byte_Pool_Error */ Error_Handler(); /* USER CODE END TX_Byte_Pool_Error */ } else { /* USER CODE BEGIN TX_Byte_Pool_Success */ /* USER CODE END TX_Byte_Pool_Success */ memory_ptr = (VOID *)&tx_app_byte_pool; status = App_ThreadX_Init(memory_ptr); if (status != TX_SUCCESS) { /* USER CODE BEGIN App_ThreadX_Init_Error */ Error_Handler(); /* USER CODE END App_ThreadX_Init_Error */ } /* USER CODE BEGIN App_ThreadX_Init_Success */ /* USER CODE END App_ThreadX_Init_Success */ } A jak to może wyglądać z alokacją wspomnianych stringów czy wektorów? W mojej aplikacji przetwarzam stringi JSON i dynamiczne struktury są niezbędne. Nie jestem też w stanie określić jak duże sądane wejściowe więc statyczna alokacja bufora może się nie udać.
  21. Cześć, niedawno zakupiłem Nucleo-H743ZI2 (MB1364) głównie w celu uzyskania dostępu jednocześnie do 4 linii I2C oraz interfejsu SDMMC. No i spotkała mnie pewna niespodzianka, ponieważ wyprowadzenia SDMMC_D0 oraz SDMMC_D1 są rozłączone od złącza morpho. Można je podłączyć poprzez 2 zworki (SB14 i SB15). Niby oczywiste, ale zastanawia mnie, dlaczego producent nie podłączył ich fabrycznie. W dokumencie UM2407 znajduje się informacja "These pins are disconnected from ST morpho connector CN12 to avoid stub of SDMMC data signals on PCB". Co to dokładnie oznacza. Czym "grozi" dodanie tych zworek i jak się uchronić przed ewentualnymi problemami. I drugie pytanie - rozumiem, że dotyczy to jedynie interfejsu SDMMC2, czyli pinów PB14 i PB15? Niestety nie znalazłem schematu do MB1364, a na schematach MB1137 zworki te odpowiadają za zupełnie inne piny. Czy możliwe jest w ogóle używanie obu interfejsów SDMMC jednocześnie? Jawnie nigdzie nie definiuję pinów, do których jest podłączony moduł SD, ani nie wskazuję, czy używam interfejsu nr 1 czy 2.
  22. Cześć, po długich wahaniach ponownie rozważam zakup oscyloskopu. Widziałem podobny post sprzed roku, ale postanowiłem założyć nowy temat. Sprzęt potrzebuję w zasadzie "na już", więc wolę się poradzić, by nie zrobić błędu. Budżet: 1000 - 3000 zł. Niekoniecznie chcę wydać aż 3k na bajery, których nigdy nie wykorzystam. Wymagania (do weryfikacji): - 4 kanały - pasmo 200 MHz - dekoder/analizator magistral szeregowych - wbudowany prosty generator - w miarę kompaktowy - dostępny bez długiego czekania. Chciałem przystawkę PC, bo cena fajna, miejsca nie zajmuje, a i tak używany będzie w zasadzie tylko na biurku z monitorem. Proszę o opinie, jakie są z nimi problemy, czy obsługa nie irytuje itp. Na razie zniechęca mnie brak dekoderów magistrali. Potrzebuję go głównie do projektów mikroprocesorowych i cyfrowego przetwarzania sygnałów. Na razie najszybszy testowany przeze mnie sygnał to zegar podawany na mikrofon PDM (ok. 3 MHz). Nie wiem, czy kiedykolwiek będę potrzebował szerszego pasma, ale korzystam z STM32H7 na zegarze 480 MHz. Przede wszystkim liczę na praktyczne recenzje, a nie suche parametry. Wygoda obsługi jest dla mnie ważna. Jestem mocno otwarty na wszelkie propozycje.
  23. Witam 😄 Chciałem zacząć przygode z płytką stm32l476RG. Postępowałem zgodnie z instrukcjami zawartymi w kursie zamieszczonym na tej stronie: https://forbot.pl/blog/kurs-stm32l4-wejscia-wyjscia-czyli-gpio-stm32-id46571 W odpowiednim miejscu w zakładce main.c w funkcji while(1) wpisałem komendy: HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); HAL_Delay(500); Korzystam z STM32CubeIDE 1.11.0. Zdebugowałem i uruchomiłem program klawiszem F8. Mimo wykonanych czynności, dioda nie załącza się. Nie wyskakują żadne błędy. Przy nowym projekcie w oknie wyboru płytki wybrałem stm32l476RGT3. Dlaczego dioda LD2 nie uruchamia się? Bardzo byłbym wdzięczny za pomoc 😄
  24. Dodając krok po kroku trochę automatyki w mieszkaniu powstał projekt i realizacja sterownika rolet zewnętrznych. Główne cechy urządzenia: obsługa 7 rolet zdalny dostęp z dowolnego miejsca na świecie sterowanie przez Wifi sterowanie przez Bluetooth sterowanie przez sieć CAN automatyczny pomiar czasu pracy poszczególnych rolet harmonogram otwierania/zamykania rolet sterowanie grupowe tworzenie scen pobieranie aktualnego czasu z serwera NTP Sterownik został podzielony na dwie części, pierwsza to płytka z przekaźnikami i zasilaniem, druga płytka to układ sterowania wraz z modułami komunikacyjnymi. Główne elementy wykorzystane w sterowniku to: STM32F103C8T6 jako moduł Bluepill Moduł Wifi ESP-12 Bluetooth HC-05 Największym wyzwanie okazało się wykrywanie zakończenia pracy rolety. Było to niezbędne do automatycznego pomiaru czasu pracy, które jest wykorzystywane do określania pozycji pośrednich. Na początku testowałem wykrywanie prądu z wykorzystaniem modułu ACS711, ale niewielki prąd pobierany przez roletę podczas pracy powodował niestabilne pomiary z układu ACS711. Drugim pomysłem było wykorzystanie przekładników prądowych. Pomiary były stabilne, ale to rozwiązanie odpadło ze względu na fizyczne rozmiary takich przekładników, potrzebowałem użyć ich aż siedem sztuk. Ostatecznie zastosowałem rozwiązanie polegające na spadku napięcia na diodach, które aktywuje transoptor PC814. Rolety które posiadam mają wewnętrzne zabezpieczenie przed podaniem napięcia na oba uzwojenia silnika (góra, dół), jednak tak zaprojektowałem układ, aby sprzętowo nie było to możliwe. Pokazane jest to na poniższym rysunku. Program został napisany w C++ z wykorzystanie Arduino Core. ESP-12 pełni rolę konwertera komunikacyjnego, od strony wifi oferuje RestApi, konwertuje otrzymane wiadomości/zapytania na komunikację uart i wysyła do głównego procesora STM32. Na drugim porcie uart w STM32 jest podobna komunikacja z wykorzystaniem modułu bluetooth. Moduł BT aktualnie służy do przeglądania bieżących logów. Ponadto moduł posiada opcję komunikacji z wykorzystaniem sieci CAN, jestem bardziej fanem rozwiązań przewodowych tam gdzie jest to możliwe. Jak w mieszkaniu pojawi się więcej elementów automatyki to będę chciał całość przepiąć na sieć CAN zamiast Wifi. Sterowanie modułem odbywa się jak wspomniałem wyżej zapytaniami REST, na Banana Pro posiadam domowy serwer www, dołożyłem do niego prostą stronę w PHP, która pozwala w wygodny sposób wysyłać zapytania do sterownika. Do połączenia się ze sterownikiem poza domową siecią wykorzystuje OpenVPNa.
  25. Witam Znudzony ręcznym ustawianiem napięć na przetwornicy, mierzeniem prądu miernikiem stwierdziłem że stworze urządzenie które będzie to robić za mnie. Właśnie projekt zbudowany pod tym pretekstem chciałbym przedstawić. Projekt ten jest w zasadzie zasilaczem laboratoryjnym, tylko że zasilacz AC DC może być dowolny, podłączany właśnie do tego modułu, a w środku modułu ochrona przeciw zbyt wysokimi napięciami, prądami jest zarządzana przez płytkę blue pill której interfejsy do programowania są wyprowadzone na zewnątrz, co umożliwia wiele, np: Nie wyłączenie przepływu prądu jeżeli prąd skoczył ponad limit na czas mniejszy niż ustawiony Wyrzucanie pomiarów przez UART do późniejszej analizy Podłączenie czegokolwiek dodatkowo przez interfejs I2C, np pomiaru temperatury, natężenia światła i dodatkowe warunki do działania urządzenia na podstawie tych danych ( Właśnie do tego jest "dziura" po prawej stronie, do montowania dodatkowych modułów w razie potrzeby ) IO na sterydach: podłączenie potężnych tranzystorów do IO mikrokontrolera i sterowanie nimi ( np, by włączyć drugie urządzenie parę sekund po pierwszym ) Samo urządzenie prezentuje się tak: W środku znajduje się przetwornica na układ LM2596 i to od niej zależą parametry prądowe całego urządzenia, druga przetwornica na 5V do zasilania mikrokontrolera, oraz do szybkiego dostępu do 5V, które można zmienić przełącznikiem który jest ukryty na lewo od ekranu. To właśnie ta przetwornica miała zintegrowany układ do pokazywania napięcia na wyświetlaczu 7 segmentowy który wykorzystałem. Oczywiście odpowiedni bezpiecznik, tranzystory o których już wspominałem, oraz układ INA219 który mierzy prąd poprzez I2C, bardzo fajny układ. Urządzenie ma wiele skutków wątpliwych decyzji, choć na pierwszy rzut oka nie mają sensu, postaram się wytłumaczyć: Złączki wago z przodu - moim zdaniem to najlepsze wielorazowe połączenia kabli, bardzo bym chciał by istniały moduły gdzie jeden kabel da się przylutować od tyłu do jakieś blaszki. potencjometr ukryty pod plastikowym zakryciem miał nie istnieć, ale moduł potencjometra cyfrowego albo dotarł do mnie zepsuty, albo sam go zepsułem. I tak ustawianie napięć teraz jest szybsze. Połączenia XT30 użyłem by można łatwo używać przetwornicy z akumulatorami dla dronów. Porty USB są ze sobą połączone liniamy zasilania, więc można użyć tej "przetwornicy" jako zewnetrznego zasilania dla urządzeń USB. Minusem jest to że na portach USB może pojawić się wyższe napięcie, ale jest to w praktyce niemożliwe - oprogramowanie pilnuje docelowego napięcia. Zworki, piny i przycisk na drugim planie służą do programowania mikro kontrolera w środku, jak już wspominałem. I może się już ktoś zastanawiał, ale istnieje powód dla którego nie pokazałem jeszcze środka urządzenia... Więc jak można zauważyć, masa rzeczy na suficie urządzenia, a ich źródło na dole może się źle skończyć dla wyglądu wewnętrznego. Może kogoś zainteresuję jak zwykły mikro kontroler jest w stanie włączać i wyłączać przetwornicę na tym typowym układzie. Rozwiązaniem było podniesienie pinu 5 o dosłownej nazwie ON/OFF, i podłączenie go do pinu IO mikrokontrolera. Niestety pełne oprogramowanie jeszcze nie jest gotowe, a chciałbym choćby snake'a zagrać. Choć dodałem już pewną funkcję - do oscylowania silnikami z różnych śmieci, testowania ich. Rezultat był nieoczekiwany - Ekran OLED z sterownikiem SSD1306 jest wrażliwy na tyle, że czasami krzaczki pojawiały się na ekranie. Najczęściej jednak cała komunikacja I2C padała, ekran albo nic nie wyświetlał, albo wyświetlał zerowe pomiary napięć, które także były pobierane przez I2C jak już wcześniej wspominałem. Obudowę także sam zaprojektowałem i wydrukowałem na drukarce 3D, oto przecięcie modelu: Oto obecne główne menu, zabezpieczenie przeciw prądowe i okablowanie w środku 😉 Zapraszam do zadawania pytań, gdyby takie się znalazły.
×
×
  • 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.