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, 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 - roboty
    • Projekty - DIY
    • Projekty - DIY (początkujący)
    • Projekty - 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
    • Kosz

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


Znaleziono 54 wyników

  1. Cześć, to już któryś z kolei kurs na forbocie, który mi przypadł do gustu - przyjemny i wytłumaczony od deski do deski. Ja jednak używam płytki blue pill i mam problem z STM Studio - nie mogę nawiązać połączenia. Otrzymuję dwa komunikaty, jeden za drugim: "Error opening target connection" oraz "Failure opening connection with target". Zarówno ST-Link Utility jak i żaden debugger nie ma nawiązanego połączenia z płytką a jednak problem z połączeniem występuje. Używam ST-Link v2 i już w ST-Link utility miałem problem. O ile na początku wszystko działało bez problemu - połączenie z płytką i jej zaprogramowanie, tak już na drugi dzień wystąpił problem z połączeniem. Teraz po wybraniu Target -> Connect, muszę przez około 3 sekundy trzymać wciśnięty przycisk RESET na płytce i dopiero po jego zwolnieniu następuję połączenie, natomiast po zaprogramowaniu połączenie zostaje zerwane, mimo że program został poprawnie wgrany. Próbowałem powyższej metody w STM Studio, jednak wtedy, po zwolnieniu przycisku RESET, wyrzuca komunikat: "Acquisition stopped after 10 consecutive communication errors.". Dodam, że próbuję wgrać program odczytujący temperaturę z wbudowanego czujnika temperatury a konfiguracja w Cube odbyła się oczywiście pod mój mikrokontroler. Wszystkie narzędzia są zaktualizowane do najnowszej wersji, firmware w ST-Linku też. Ktoś się spotkał z podobnym problemem?
  2. Mam takie zapytanie bo uwaliłem stm i potrzebuje wymienić na nowy, które adresy pamięci są ważne żeby zrobić kopie 1:1? 0x0000 0000 - 0x0001 0000 i 0x0800 0000 - 0x0801 0000 czy coś jeszcze??
  3. Witam. Tworzę prostą aplikację pod Stm32CubeIDE z użycie kontrolera STM32F303 (z wbudowanym FPU). Trafiłem na dziwne problemy kiedy próbowałem użyć sprintf z włączonym wsparciem dla %f. Za każdym razem zamiast poprawnie sformatowanej liczby dostawałem bardzo długi ciąg cyfr. Znalazłem nawet na githubie jakąś inną implementację sprintf i to znowu często zamiast poprawnej wartości zwracało mi 0.00. W końcu okazało się, że problem jest z va_arg: void test(const char* format, ...) { va_list va; va_start(va, format); double arg1 = va_arg(va, double); char buf[102]; sprintf(buf, "a %.2f", arg1); va_end(va); } test("format", 0.1234); Zatrzymuje kod na linii z va_arg i widzę, że to zwraca głupoty. Obszedłem to przy pomocy takiego dziwnego rozwiązania: uint64_t doubleBinary = va_arg(va, uint32_t) | ((uint64_t)va_arg(va, uint32_t) << 32); double arg = *(double*)&doubleBinary; I tu dostaje poprawną wartość. Ale potem mam taki fragment (to z tego sprintf): static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) { {... tu jakiś kod...} } //i wywołanie: uint64_t doubleAsInt = va_arg(va, uint32_t) | ((uint64_t)va_arg(va, uint32_t) << 32); double doubleAsDouble = *(double*)&doubleAsInt; idx = _ftoa(out, buffer, idx, maxlen, doubleAsDouble, precision, width, flags); format++; No i na tym _ftoa znowu jest problem bo zamiast wejść do procedury to kod wpada mi do: Default_Handler: Infinite_Loop: b Infinite_Loop Próbowałem wyłączyć FPU i skompilować wszystko na software. va_arg nadal nie działa ale nie ma tego crasha przy _ftoa. Potem uruchomiłem ten sam program pod starym EmBitz (GCC w wersji 5) i tam wszystko wydaje się działać bezbłędnie (na tyle na ile udało mi się sprawdzić). Przy czym te projekty nie są identycznie (mój kod jest taki sam ale to co jest generowane przez środowisko już na pewno nie). Ma ktoś pomysł jak to debugować i o co może chodzić? Nie jestem w tym specjalnie zaawansowany i skończyły mi się już pomysły. W internecie znalazłem jakieś szczątkowe informacje, że double ma 8 bajtów i z tym jest jakiś problem (niestety bez konkretów więc nic mi to nie dało).
  4. Dzień dobry wszystkim. Po około miesiącu używania STM32L053R8 postanowiłem ułatwić sobie życie za pomocą STM32CubeMX i migrować z SW4STM32 na TrueSTUDIO. Niestety TrueSTUDIO nie chciało ze mną współpracować, a co gorsza projekty, które pierwotnie działały w SW4STM32 po całej tej operacji odmówiły posłuszeństwa. Magistrala USART zaczęła działać w niezrozumiały dla mnie sposób, tj aby terminal odczytał dane poprawnie musiał mieć ustawiony baud_rate_term ~= baud_rate_uC/2. np(uC 115200 - term 57600 lub 56000) Dwie rzeczy, które zmieniałem w międzyczasie to: a) aktualizacja ST Link v2 do V2.J34.M25 b) konfiguracja PLL w STM32CubeMX Załączam screeny z konfiguracji oraz fragmenty kodu. Jeżeli był już taki post to przepraszam , ale nawet nie wiedziałem jakimi słowami klucz go szukać, i dziękuję z góry za każdą pomoc. Inicjalizacja UARTu: void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } } void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART2) { /* USER CODE BEGIN USART2_MspInit 0 */ /* USER CODE END USART2_MspInit 0 */ /* USART2 clock enable */ __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART2 GPIO Configuration PA2 ------> USART2_TX PA3 ------> USART2_RX */ GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; GPIO_InitStruct.Alternate = GPIO_AF4_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN USART2_MspInit 1 */ /* USER CODE END USART2_MspInit 1 */ } } Transmisja: void uart_write_line(UART_HandleTypeDef *huart, char *str) { HAL_UART_Transmit(huart, str, strlen(str), 1000); HAL_UART_Transmit(huart, "\r\n", 2, 1000); }
  5. Witam, moze odrazu do rzeczy. Chcial bym podlaczyc termistor ktory bedzie zasilany napieciem 5V. Czytalem ze STM32 dzialaja na logice 3,3V. Wiec tu moje pytanie czy nie spale uC przez to ze dam napiecie bliskie 5V na ADC tego kontrolera. Mysle tez nad konwerterem logicznym lub prostym dzielnikiem napiecie by wrazie potrzeby zmniejszyc napiecie. Moze ktos ma inne pomysly, jakies rady co to ADC STM32? Z gory dzieki. Pozdrawiam
  6. Dzień dobry Dokładnie postępując jak to jest pokazane w kursie napotkałem pewien problem. Jak wyżej ktoś pisał, można wgrywać plik .hex, więc tak też uczyniłem. Nie zauważyłem po drodze żadnych błędów, jednak nie zauważyłem aby jakakolwiek dioda zaświeciła się na niebiesko. Nie mam pojęcia gdzie może być błąd, spróbować postąpić z tym co pisali inni wyżej - zainstalować starszą wersję Cuba i wtedy spróbować?
  7. Witam wszystkich, Realizuje właśnie projekt, którego celem jest generowanie tonu o zadanej częstotliwości i określonym poziomie głośności. Do tego wykorzystuje przetwornik dac CS43L22 znajdujący się na płytce a jako wyjście złącze jack. Poniżej mój kod odpowiadający za stworzenie dyskretnego sinusa: void Build_sin(float F_Out) { float sample_dt = F_Out/F_SAMPLE; uint16_t sample_N = F_SAMPLE/F_Out; float sin_val; for(uint16_t i=0; i<sample_N; i++) { sin_val = sinf(2*PI*sample_dt*i); dataI2S[i*2] = (sin_val ); //prawy tor dataI2S[i*2 + 1] =(sin_val ); //lewy tor } Na wyjście przekazuję go za pomocą HAL_I2S_Transmit_DMA w następujący sposób: HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t *)dataI2S, sample_N*2); Regulację głośności realizuję za pomocą funkcji SetVolume która wygląda w następujący sposób: void CS43_SetVolume(uint8_t volume) { int8_t tempVol = volume - 50; tempVol = tempVol*(127/50); uint8_t myVolume = (uint8_t )tempVol; DataReg[1] = myVolume; write_register(PASSTHROUGH_VOLUME_A,&DataReg[1]); write_register(PASSTHROUGH_VOLUME_B,&DataReg[1]); DataReg[1] = VOLUME_CONVERT_D(volume); write_register(CS43L22_REG_MASTER_A_VOL,&DataReg[1]); write_register(CS43L22_REG_MASTER_B_VOL,&DataReg[1]); } Macro VOLUME_CONVERT_D(vol) wygląda tak: (((volume) > 100)? 24:((uint8_t)((((volume) * 48) / 100) - 24))) Moje pytania są następujące: 1) W jaki sposób przekłada się poziom sygnału, stworzonego w funkcji Build_sin(), podawany na wyjście przetwornika na poziom głośności uzyskany w słuchawkach? 2) Czy w przypadku zmiany Master volume z powiedzmy 0 dB na -3 dB otrzymam na wyjściu sygnał audio pomniejszony o 3 dB względem wcześniejszego? Z góry dziękuje za odpowiedź i pozdrawiam
  8. Witam, Posiadam STM32 f429, nucleo 144. Chciałbym zrealizować program, który będzie wykonywał odczyt zmiennej (napięcia, stosując przetwornik ADC) cyklicznie, np co 2 sekundy. Poniżej wrzucam mój kod, w którym wywoływane jest przerwanie po każdym zakończeniu konwersji ADC. /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* 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; ADC_HandleTypeDef hadc2; uint16_t adc1 = 0; //zmienna nieprzekonwertowana uint16_t adc2 = 0; //zmienna nieprzekonwertowanan float v1 = 0; //zmienna przekonwertowana dla 3,3 V float a1 = 0; //do pomiaru pradu TIM_HandleTypeDef htim4; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); static void MX_ADC2_Init(void); static void MX_TIM4_Init(void); static void MX_GFXSIMULATOR_Init(void); /* USER CODE BEGIN PFP */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){ // przerwanie adc1 = HAL_ADC_GetValue(&hadc1); v1 = (float)adc1 * 3.3f / 4096.0f; TIM4->CCR2 = adc1; // przypisanie wartosci adc1 do rejestru timera PWM adc2 = HAL_ADC_GetValue(&hadc2); a1 = ((float)adc2 * 3.3f / 4096.0f)/0.47; //0,47 taka rezystancja rezystora, prad z prawa Ohma if (v1 > 3.1) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); } /* 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_ADC1_Init(); MX_ADC2_Init(); MX_TIM4_Init(); MX_GFXSIMULATOR_Init(); /* USER CODE BEGIN 2 */ HAL_ADC_Start_IT(&hadc1); // wystartowanie przetworników ADC HAL_ADC_Start_IT(&hadc2); HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2); //wystartowanie PWMa TIM4->CCR2 = 65535; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* 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}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 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_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DMAContinuousRequests = DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_10; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ } /** * @brief ADC2 Initialization Function * @param None * @retval None */ static void MX_ADC2_Init(void) { /* USER CODE BEGIN ADC2_Init 0 */ /* USER CODE END ADC2_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC2_Init 1 */ /* USER CODE END ADC2_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc2.Instance = ADC2; hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; hadc2.Init.Resolution = ADC_RESOLUTION_12B; hadc2.Init.ScanConvMode = DISABLE; hadc2.Init.ContinuousConvMode = ENABLE; hadc2.Init.DiscontinuousConvMode = DISABLE; hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc2.Init.NbrOfConversion = 1; hadc2.Init.DMAContinuousRequests = DISABLE; hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc2) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_11; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC2_Init 2 */ /* USER CODE END ADC2_Init 2 */ } /** * @brief GFXSIMULATOR Initialization Function * @param None * @retval None */ static void MX_GFXSIMULATOR_Init(void) { /* USER CODE BEGIN GFXSIMULATOR_Init 0 */ /* USER CODE END GFXSIMULATOR_Init 0 */ /* USER CODE BEGIN GFXSIMULATOR_Init 1 */ /* USER CODE END GFXSIMULATOR_Init 1 */ /* USER CODE BEGIN GFXSIMULATOR_Init 2 */ /* USER CODE END GFXSIMULATOR_Init 2 */ } /** * @brief TIM4 Initialization Function * @param None * @retval None */ static void MX_TIM4_Init(void) { /* USER CODE BEGIN TIM4_Init 0 */ /* USER CODE END TIM4_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM4_Init 1 */ /* USER CODE END TIM4_Init 1 */ htim4.Instance = TIM4; htim4.Init.Prescaler = 0; htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 65535; htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim4) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim4) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM4_Init 2 */ /* USER CODE END TIM4_Init 2 */ HAL_TIM_MspPostInit(&htim4); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_14, GPIO_PIN_RESET); /*Configure GPIO pins : PB0 PB14 */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ /* 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 */ /* 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, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  9. Hej, Praktycznie zawsze po kilkukrotnym wgraniu programu przez Utility następuje moment tak jakby "zawieszenia" możliwości wgrania programu z danego projektu. W sytuacji, gdy np chce sobie kilkukrotnie zmodyfikować program z kursu, tak +- za trzecim razem, gdy go wgrywam wyskakuje informacja (załączam screeny) i nie ma możliwości wgrania kodu. Do tej pory radziłem sobie z tym tak, że tworzyłem nowy projekt od początku, zaczynając od CUBE itd. (stary kasowałem) i wtedy znowu miałem kilka prób na wgrywanie programu. Dodam jeszcze, że wszystko poprawnie się kompilowało. Takie tworzenie projektu od nowa jest uciążliwe. Dlaczego tak się dzieje i jak temu zaradzić? Pozdrawiam
  10. Witam, Ostatnio zauważyłem problem podczas wgrywania programu dla mikrokontrolera STM32F429. Problem objawia się następująco: -Tworzę nowy projekt -> zapisuje, builduje, (nie ma błędów) -> wgrywam program poprzez Utility (wybierając plik z rozszerzeniem HEX) -> działa. - Biorę ten sam projekt i wprowadzam pewne modyfikacje (np. zmieniam częstotliwość w CUBE, wybieram inny pin itp, generalnie drobne zmiany) -> zapisuje, builduje (nie ma błędów) -> wgrywam, i niestety bez powodzenia. Załączam screena z Utility po nieudanej próbie wgrania kodu. Doszedłem do tego, że raczej wina leży po stronie Workbencha i niepoprawnie utworzonego pliku z rozszerzeniem HEX (plik ten jest praktycznie pusty, sprawdziałem go notatnikiem), ponieważ gdy chcę wgrać inny projekt wówczas wszystko działa poprawnie. Próbowałem odinstalować oprogramowanie i zainstalować od nowa. Nie pomogło. Czy ktoś spotkał się z czymś takim?
  11. Czy można wygenerować jeden impuls instrukcją HAL_TIM_OnePulse_Start_IT bez konieczności inicjowania impulsem zewnętrznym? Jak ewentualnie to ustawić w STM32CubeMX?
  12. Cześć, Zaczynam właśnie naukę programowania STM32 i chciałbym zrobić odtwarzacz audio. Posiadam płytkę STM32F411E-Disco, która jest wyposażona w DAC CS43L22. Planowałem wykorzystać interfejs I2C. Ze schematu układu odczytałem PB6 jako linie zegara i PB9 jako linie danych. Skonfigurowałem linie w programie STM32CubeMX. Znalazłem w dokumentacji adres urządzenia: 10010100 = 0x94(Write); 10010101 = 0x95(Read). Korzystam z bibliotek HAL, więc ustawiłem rejestr adresu CS43L22_ADDRESS (0x4A << 1). Następnie w pętli wykonuję: HAL_I2C_Mem_Write(&hi2c1, CS43L22_ADDRESS,CS43L22_REG_BEEP, 1, &beep,1,100); CS43L22_REG_BEEP to 0x1C na podstawie dokumentacji &beep jest wskaźnikiem na CS43L22_BEEP 0x74, które wg. dokumentacji powinno dawać na wyjściu dźwięk 1kHz trwający 1,5s. Niestety tak się nie dzieje. Bardzo proszę o pomoc. W którym miejscu popełniłem błąd? Z góry dziękuje za pomoc i wyrozumiałość. Pozdrawiam CS43L22_datasheet.pdf
  13. Dla użytkowników systemu Linux. Żeby sprawdzić gdzie montuje się wasze urządzenie możecie skorzystać z instrukcji https://askubuntu.com/a/408831/614907 U mnie była to ścieżka /dev/serial/by-id/usb-STMicroelectronics_STM32_STLink_066FFF494849887767072607-if02 Do czytania danych wysłanych przez mikrokontoler można użyć zarówno programu cat (zwykły tekst) jak i xdd (wygodny dla danych binarnych) Na przykład: cat /dev/serial/by-id/usb-STMicroelectronics_STM32_STLink_066FFF494849887767072607-if02 Znalezienie tego zajęło mi dużo czasu, być może ten komentarz go komuś oszczędzi. UPDATE: Do wysyłania danych można oczywiście używać przekierowań takich jak echo "a" > /dev/serial/... ale wygląda na to, że takie coś załącza jakiś dodatkowy znak końca strumienia danych, żeby tego uniknąć napisałem w node.js program który przechwytuje klawisze z klawiatury i wysyła na ten adres. W tym programie problem problem znaku kończącego zapis nie występuje, ale z chęcią dowiem się czy ktoś nie zna prostszego sposobu. /** * Script reads keys from keyboard and redirects them to usb device * We assume that device with usb communication is located in path * described in constant `file`. * * Usage: * connect STM32 with program from example "Data receiving" from Forbot Course * first conosle: cat /dev/serial/by-id/usb-STMicroelectronics_STM32_STLink_066FFF494849887767072607-if02 * second console: node app.js * Start typing in second console, you should see responses from microcontroller in first console * * It is possible that id of your device will be different, them use methods described on link: * https://askubuntu.com/a/408831/614907 * to detect youd device path * * Daniel Gustaw <gustaw.daniel@gmail.com> * * Sat Mar 16 20:54:45 CET 2019 * * Recommended tutorials: * https://forbot.pl/blog/kurs-stm32-5-komunikacja-z-komputerem-uart-id8439 * https://thisdavej.com/making-interactive-node-js-console-apps-that-listen-for-keypress-events/ * https://dustinpfister.github.io/2018/08/17/nodejs-filesystem-create-write-stream/ * https://askubuntu.com/a/408831/614907 */ const readline = require('readline'); const fs = require('fs'); const file = '/dev/serial/by-id/usb-STMicroelectronics_STM32_STLink_066FFF494849887767072607-if02'; let writer = fs.createWriteStream(file); // stream that allow redirect characters readline.emitKeypressEvents(process.stdin); // enable listening process.stdin.setRawMode(true); // listen for all keys (without confirming by enter) process.stdin.on('keypress', (str, key) => { // listen on pressing keys if (key.ctrl && key.name === 'c') { // allow for closing connection by ctrl+c process.exit(); // close process } else { console.log(`You pressed the "${str}" key`); // log info what you pressed writer.write(str); // send this key to stream } }); console.log('Press any key...');
  14. Witam serdecznie. Prosze wybaczyc, ze bez pisze bez polskich znakow, ale teraz do rzeczy. Chce nawiazac komunikacje pc - mcu przez Ethernet. Pracuje na Nucleo F746ZG. Stworzylem projekt z pomoca CubeMX (v4.27.0) w ktorym uruchomilem lwIP i podstawowe protokoly (w tym UDP), jako IDE uzywam Eclipse OpenSTM32. Ustalenie IP mikrokontrolera wykonywane jest przez DHCP. Ping oraz echo UDP dziala bez problemu (wyslanie pakietu UDP z dowolnego pc w sieci skutkuje odeslaniem wiadomosci na ten sam adres ip oraz port). Moj problem zaczyna sie wowczas, gdy zmodyfikowalem funkcje udpecho_raw_recv() i chce umiescic inne dane w odsylanym pakiecie. udp_sendto(pcb, p, addr, port); /* dziala jak echo */ udp_sendto(pcb, ethTxBuffer_p_x, addr, port); /* wysyla dane z bufora */ Po przeslaniu zwykle okolo 10 pakietow z pc i uzyskaniu odpowiedzi od mcu z pakietem o innej tresci nagle mikrokontroler przestaje odpowiadac (obrazek screenshot_udp.jpg). Wyglada mi to na problem z buforem pbuf w funkcji udpecho_raw_recv(), lecz nie wiem jak sie za to zabrac. Czy ktos z Was ma moze doswiadczenie z lwIP i moglby mi podpowiedziec co z tym zrobic? Przegladalem wiele stron z podobnymi problemami, ale jednak opisane tam rozwiazania lub rady mi nie pomogly. Z gory dziekuje! Kod wyglada nastepujaco: Zmienne globalne: /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ extern struct netif gnetif; static struct udp_pcb *udpPcb1_p; ip_addr_t ipaddress; static const char clientPacket_c[] = { 0x49, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x63, 0x61, 0x74, 0x73, 0x2e }; static const char reply[] = { 0x67, 0x6f, 0x74, 0x20, 0x69, 0x74, 0x20, 0x62, 0x72, 0x6f }; /* USER CODE END PV */ Funkcje: static void udpecho_raw_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) { static struct pbuf *ethTxBuffer_p_x; ethTxBuffer_p_x = pbuf_alloc(PBUF_TRANSPORT, sizeof(reply), PBUF_RAM); memcpy(ethTxBuffer_p_x->payload, reply, sizeof(reply)); udp_sendto(pcb, ethTxBuffer_p_x, addr, port); pbuf_free(ethTxBuffer_p_x); } /*-----------------------------------------------------------------------------------*/ void udpecho_raw_server_init(u16_t port) { struct udp_pcb *pcb; printf("%s() ..........\n", __func__); pcb = udp_new(); udp_bind(pcb, gnetif.ip_addr.addr, port); /* no need to loop forever */ udp_recv(pcb , udpecho_raw_recv, pcb); } W main() z rzeczy dodanych przeze mnie jest tylko: udpecho_raw_server_init(20); while(1) { MX_LWIP_Process(); }
  15. Hej, Realizuje ten kurs na stm32f429ZI (Nucleo 144). Jak do tej pory nie było problemów, czasem po prostu używałem innych portów i wszystko działało. Niestety nie tym razem. W moim przypadku chcę zaświecić diodą PB7 -> (w CUBE TIM4_CH2, pozostałe parametry zastosowałem tak jak jest opisane na kursie). Niestety po skompilowaniu wyskakiwał komunikat o niezadeklarowanej zmiennej Duty. Poniżej wklejam kod, tam też jest ta deklaracja zmiennej Duty, którą dodałem. Co jeszcze poprawić, żeby program zadziałał? /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* 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 ---------------------------------------------------------*/ TIM_HandleTypeDef htim4; /* USER CODE BEGIN PV */ uint16_t Duty = 0; //deklaracja zmiennej Duty /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM4_Init(void); /* USER CODE BEGIN PFP */ //Przerwanie wywolywane z czestotliwoscia 1KHz void HAL_SYSTICK_Callback(void) { static uint8_t InterruptPrescaler = 0; // licznik przerwan static uint8_t CzyRosnie = 1; // Flaga kierunku zliczania ++InterruptPrescaler; // Inkrementacja numeru przerwania // Jezeli wywolalo sie 40 przerwanie z rzedu if (InterruptPrescaler == 40) { InterruptPrescaler = 0; // wyzeruj licznik przerwan if (Duty == 100) // Jezeli wypelnienie jest rowne 100 CzyRosnie = 0; // Zmien kierunek zliczania w dol else if (Duty == 0) // Jezeli wypelnienie rowne 0 CzyRosnie = 1; // Zmien kierunek zliczania w gore if (CzyRosnie) // Jezeli zliczamy w gore ++Duty; // Inkrementuj wartosc wypelnienia else //Jezeli zliczamy w dol --Duty; // Dekrementuj wartosc wypelnienia } TIM4->CCR3 = Duty; // Wstawienie wyliczonej wartosci wypelnienia do // rejestru timera odpowiedzialnego za wypelnienie generowanego sygnalu PWM } /* 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_TIM4_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* 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}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 100; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ 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(); } } /** * @brief TIM4 Initialization Function * @param None * @retval None */ static void MX_TIM4_Init(void) { /* USER CODE BEGIN TIM4_Init 0 */ /* USER CODE END TIM4_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM4_Init 1 */ /* USER CODE END TIM4_Init 1 */ htim4.Instance = TIM4; htim4.Init.Prescaler = 4999; htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 99; htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim4) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim4) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM4_Init 2 */ /* USER CODE END TIM4_Init 2 */ HAL_TIM_MspPostInit(&htim4); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); } /* USER CODE BEGIN 4 */ /* 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 */ /* 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, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  16. Witam. Jestem początkujący więc z góry proszę o łagodne potraktowanie. Mam gotowy układ sterownika do z STM32 pracującym w sterowniku do drona Walkera Runner 250 Advance F3 SP Racing. Po zmianie konfiguracji w Betaflight Configurator układ zawiesił się i stracił komunikację z kompem. Proszę o informację w jaki sposób zresetować układ żeby wgrać firmware jeszcze raz. Próbowałem zewrzeć styk nRST do masy i na zwartym podłączyć ale nie przyniosło skutków. Czy macie jakieś pomysły? Proszę też o informację czy do aktualnego sterownika CP210x... jest konieczne wykonanie jeszcze jakiś operacji żeby chip STM32 stał się widoczny dla programu programującego. Próbowałem DfuSeDemo oraz UsbUpgradeTool. dzięki [ Dodano: 06-07-2018, 14:56 ] dodaje zdjęcie układu:
  17. Cześć, czy komuś udało się przerobić biblioteki dla tego wyświetlacza? https://botland.com.pl/pl/wyswietlacze-oled/4441-wyswietlacz-oled-niebieski-graficzny-13-b-128x64px-spii2c-proste-zlacza.html Próbowałam kilkakrotnie i pomimo wyeliminowania wszystkich warningów wyświetlacz nadal nie reaguje. W pliku SSD1306.h mam zdefiniowany SH1106. Nie wiem co robię źle
  18. Witam, próbuję uruchomić akcelerometr LIS3DHH ( https://www.st.com/en/mems-and-sensors/lis3dhh.html) na zestawie Nucleo F411RE (https://www.st.com/en/evaluation-tools/nucleo-f411re.html). Czujnik mam w postaci adaptera STEVAL-MKI180V1 (https://www.st.com/en/evaluation-tools/steval-mki180v1.html). Konfigurację dla mikrokontrolera generuję za pomocą CubeMX 5.0.1 z bibliotekami HAL dla rodziny STM32F4, w wersji 1.23.0. Próbę uruchomienia czujnika rozpocząłem od wykorzystania bibliotek: https://github.com/STMicroelectronics/STMems_Standard_C_drivers/tree/master/lis3dhh_STdC, a dokładnie od przykładu: read_data_simple.c. Po dużej liczbie nieudanych prób komunikacji, maksymalnie uprościłem przykład. Aktualnie próbuję odczytać wartość rejestru WHO_AM_I. Adres rejestru to: 0x0F. Podczas odczytu danych, bit SMB adresu powinien mieć wartość 1, więc modyfikuję adres rejestru do wartości 0x8F. Wartość rejestru WHO_AM_I powinna wynosić 0x11, a ja otrzymuję wartość 0x00. Wszystkie linie SPI są sprzętowo podciągnięte do plusa zasilania, za pomocą wewnętrznych rezystorów mikrokontrolera. Korzystam z SPI2. Jego konfiguracja to: CPOL = High, CPHA = 2 Edge, prędkość: 1.3125 Mbits/s. Sygnał CS jest generowany programowo. Poniżej przedstawiam fragment kodu źródłowego odpowiedzialnego za inicjalizację SPI oraz próbę odczytania rejestru WHO_AM_I. Inicjalizacja SPI: void MX_SPI2_Init(void) { hspi2.Instance = SPI2; hspi2.Init.Mode = SPI_MODE_MASTER; hspi2.Init.Direction = SPI_DIRECTION_2LINES; hspi2.Init.DataSize = SPI_DATASIZE_8BIT; hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH; hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; hspi2.Init.NSS = SPI_NSS_SOFT; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi2.Init.TIMode = SPI_TIMODE_DISABLE; hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi2.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi2) != HAL_OK) { Error_Handler(); } } [Próba odczytu zawartości rejestru WHO_AM_I (zawarte w funkcji main): MX_GPIO_Init(); MX_SPI2_Init(); HAL_Delay(10); HAL_StatusTypeDef status; uint8_t reg = 0x0F; // Adres rejestru WHO_AM_I uint8_t bufp[3]; uint16_t len = 1; reg |= 0x80; // Informacja, ze przeprowadzany bedzie odczyt danych HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET); // Aktywacja SPI status = HAL_SPI_Transmit(&LIS3DHH_HANDLE, ®, 1, 1000); // Wyslanie adresu do odczytu status = HAL_SPI_Receive(&LIS3DHH_HANDLE, bufp, len, 1000); // Odbior zawartosci adresu HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET); // Dezaktywacja SPI W załączniku przedstawiam przebiegi uzyskane z analizatora stanów logicznych, plik konfiguracyjny dla CubeMX oraz kod źródłowy programu testowego. Dodam, że testy przeprowadzałem na dwóch czujnikach, oraz dodatkowo na zestawie z mikrokontrolerem STM32F103 (blue PCB). Modyfikowałem na wiele sposobów konfigurację SPI oraz odczyt rejestrów. Efekt za każdym razem taki sam. Czy ktoś ma pomysł co robię nie tak, że za każdym razem otrzymuję wartość zero z rejestru WHO_AM_I? Test_LIS3DHH_F4.zip
  19. 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.
  20. mati1221

    [STM32f103] HC-SR04 HAL

    Witam wszystkich na forum. Od kilku dni posiłkując się starym i nowym kursem STM32F1 staram się przeportować z biblioteki StdPeriph na HAL program obsługujący czujnik HC-SR04, wykorzystujący przerwania i timery ( http://www.avislab.com/blog/stm32-exti/ ). Niestety program zawsze zwraca wartość pomiaru 0. Na 99% problem powoduje nieprawidłowa implementacja timera 3 lub błędnie napisane przerwanie służące do pomiaru długości sygnału Echo. Czy jest ktoś w stanie określić w którym miejscu jest błąd? Mój kod HAL: void sonar_init() { //Timer3 Echo __HAL_RCC_TIM3_CLK_ENABLE(); tim3.Instance = TIM3; tim3.Init.Prescaler = 64 - 1; tim3.Init.CounterMode = TIM_COUNTERMODE_UP; tim3.Init.ClockDivision = 0; tim3.Init.RepetitionCounter = 0; tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; HAL_TIM_Base_Init(&tim3); HAL_TIM_Base_Start_IT(&tim3); __HAL_RCC_GPIOC_CLK_ENABLE(); //Trigger Pin8 GPIO_InitTypeDef gpio; gpio.Pin = GPIO_PIN_8; gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &gpio); //Echo Pin9 GPIO_InitTypeDef GPIO_InitStruct; gpio.Pin = GPIO_PIN_9; gpio.Mode = GPIO_MODE_AF_PP; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); } void EXTI9_5_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if(GPIO_Pin == GPIO_PIN_9){ if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9) != 0) { // Rising __HAL_TIM_SET_COUNTER(&tim3, 0); } if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9) == 0) { // Falling SonarValue = __HAL_TIM_GET_COUNTER(&tim3); } } } void sonar_start() { //10us TRIG int i; HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET); //TRIG ON for(i=0;i<0x6400;i++); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET); //TRIG OFF } unsigned int sonar_get() { unsigned long Sonar; // 354 Sound speed (mm/sec), 64000 - F_CPU, Result = mm Sonar = (354/2) * (unsigned long)SonarValue / (64000 / 64); return (unsigned int)Sonar; }
  21. Czy ma ktoś działającą bibliotekę do obsługi wyświetlacza ST7565 działającą pod STM32F103 lub podobnym?
  22. Witam, Chcialem sie was zapytac, czy ta funkcja jest poprawna? Czy takie rozwiazanie nie bedzie powodowac wyciekow pamieci? Czy rozmiar tablicy jest dobrze alokowany? char * subarray; char buffor[30]; uint8_t bufforElementsNumber = 0; char * getSubArray(int size, char array[]) { subarray = NULL; subarray = malloc(sizeof(char) * size); for (int i = 0; i < size; i++) { subarray[i] = array[i]; } return subarray; }
  23. Cześć, mam problem z komunikacją USART na stm32L452RE, poniżej zamieszczam kody, które napisałem przy pomocy znalezionych przykładów. Nie mam pojęcia czego tu jeszcze brakuje. Kod inicjalizacji USART: static void MX_USART2_UART_Init(void) { LL_USART_InitTypeDef USART_InitStruct; LL_GPIO_InitTypeDef GPIO_InitStruct; /* Peripheral clock enable */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2); /**USART2 GPIO Configuration PA2 ------> USART2_TX PA3 ------> USART2_RX */ GPIO_InitStruct.Pin = USART_TX_Pin|USART_RX_Pin; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; GPIO_InitStruct.Alternate = LL_GPIO_AF_7; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART2 interrupt Init */ NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); NVIC_EnableIRQ(USART2_IRQn); USART_InitStruct.BaudRate = 115200; USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B; USART_InitStruct.StopBits = LL_USART_STOPBITS_1; USART_InitStruct.Parity = LL_USART_PARITY_NONE; USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX; USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE; USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16; LL_USART_Init(USART2, &USART_InitStruct); LL_USART_ConfigAsyncMode(USART2); LL_USART_Enable(USART2); } Kod ciała przerwania USARTA: void USART2_IRQHandler(void) { /* USER CODE BEGIN USART2_IRQn 0 */ if(LL_USART_IsEnabledIT_TXE(USARTx_INSTANCE) && LL_USART_IsActiveFlag_TXE(USARTx_INSTANCE)) { /* TXE flag will be automatically cleared when writing new data in TDR register */ /* Call function in charge of handling empty DR => will lead to transmission of next character */ USART_TXEmpty_Callback(); } if(LL_USART_IsEnabledIT_TC(USARTx_INSTANCE) && LL_USART_IsActiveFlag_TC(USARTx_INSTANCE)) { /* Clear TC flag */ LL_USART_ClearFlag_TC(USARTx_INSTANCE); /* Call function in charge of handling end of transmission of sent character and prepare next charcater transmission */ USART_CharTransmitComplete_Callback(); } if(LL_USART_IsEnabledIT_ERROR(USARTx_INSTANCE) && LL_USART_IsActiveFlag_NE(USARTx_INSTANCE)) { /* Call Error function */ Error_Callback(); } /* USER CODE END USART2_IRQn 0 */ /* USER CODE BEGIN USART2_IRQn 1 */ /* USER CODE END USART2_IRQn 1 */ } Funkcje wykorzystane w powyższym przerwaniu: void USART_TXEmpty_Callback(void) { if(ubSend == (ubSizeToSend - 1)) { /* Disable TXE interrupt */ LL_USART_DisableIT_TXE(USARTx_INSTANCE); /* Enable TC interrupt */ LL_USART_EnableIT_TC(USARTx_INSTANCE); } /* Fill TDR with a new char */ LL_USART_TransmitData8(USARTx_INSTANCE, aStringToSend[ubSend++]); } void USART_CharTransmitComplete_Callback(void) { if(ubSend == sizeof(aStringToSend)) { ubSend = 0; /* Disable TC interrupt */ LL_USART_DisableIT_TC(USARTx_INSTANCE); /* Turn LED1 On at end of transfer : Tx sequence completed successfully */ //LED_On(); } } void Error_Callback(void) { __IO uint32_t isr_reg; /* Disable USARTx_IRQn */ NVIC_DisableIRQ(USARTx_IRQn); /* Error handling example : - Read USART ISR register to identify flag that leads to IT raising - Perform corresponding error handling treatment according to flag */ isr_reg = LL_USART_ReadReg(USARTx_INSTANCE, ISR); if (isr_reg & LL_USART_ISR_NE) { /* case Noise Error flag is raised : ... */ //LED_Blinking(LED_BLINK_FAST); } else { /* Unexpected IT source : Set LED to Blinking mode to indicate error occurs */ //LED_Blinking(LED_BLINK_ERROR); } } Na koniec użycie funkcji do wysłania danych w przerwaniu o low power LPTIM: void LPTIM1_IRQHandler(void) { /* USER CODE BEGIN LPTIM1_IRQn 0 */ /* Start USART transmission : Will initiate TXE interrupt after TDR register is empty */ LL_USART_TransmitData8(USARTx_INSTANCE, aStringToSend[ubSend++]); /* Enable TXE interrupt */ LL_USART_EnableIT_TXE(USARTx_INSTANCE); LL_LPTIM_ClearFLAG_ARRM(LPTIM1); LL_LPTIM_ClearFLAG_CMPM(LPTIM1); LL_LPTIM_ClearFlag_ARROK(LPTIM1); /* USER CODE END LPTIM1_IRQn 0 */ /* USER CODE BEGIN LPTIM1_IRQn 1 */ /* USER CODE END LPTIM1_IRQn 1 */ } Uprzejmie proszę o pomoc, bo nie mam pojęcia co tu jest nie tak. Za wszystkie odpowiedzi serdeczne dzięki.
  24. Posiadam płytkę STM32F407G-DISC1 oraz ekspander MCP23S08. Na podstawie kursu STM32F4 oraz STM32F1 próbuję zapalić diodę na wyjściu ekspandera. Korzystam z CUBEMX do konfiguracji mikrokontrolera oraz eclipse'a do programowania. Mam wrażenie, że wszystko robię w poprawny sposób, konfiguracja SPI jest zgodna z tą pokazaną w 9 części kursu STM32F1 a mimo to wyjścia ekspandera pozostają nieaktywne. Oczekuję, że zapali się dioda podpięta do pinu GP0. Poniżej dołączam mój kod: /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f4xx_hal.h" /* USER CODE BEGIN Includes */ #define MCP_IODIR 0x00 #define MCP_OLAT 0x0a /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ SPI_HandleTypeDef hspi1; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_SPI1_Init(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ void mcp_write_reg(uint8_t addr, uint8_t value) { uint8_t tx_buff[]={0x40, addr, value}; HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, tx_buff, 3, HAL_MAX_DELAY); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); } /* 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(); /* 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_SPI1_Init(); /* USER CODE BEGIN 2 */ mcp_write_reg(MCP_IODIR, ~0x01); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ mcp_write_reg(MCP_OLAT, 0x01); while (1) { /* 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; /**Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 64; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ 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_DIV8; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* SPI1 init function */ static void MX_SPI1_Init(void) { /* SPI1 parameter configuration*/ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } /** 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_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : CS_Pin */ GPIO_InitStruct.Pin = CS_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(CS_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : DC_Pin */ GPIO_InitStruct.Pin = DC_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(DC_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : RESET_Pin */ GPIO_InitStruct.Pin = RESET_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(RESET_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(char * file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ 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 /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  25. Witam wszystkich, jakiś czas temu przeniosłem się na procki STM32F1, sporo korzystałem z kursów Forbot więc postaram się także w jakiś sposób odwdzięczyć za czyjąś robotę. Dziś prezentuję moją implementację UARTa wspomaganą buforami FIFO i przerwaniami. Zaletą takiego rozwiązania jest, pod warunkiem nie wysyłania danych więcej niż szybkość transmisji, natychmiastowe wyjście z procedury wysłania bajtu, zaś przy odczycie danych, braku gubienia przychodzących bajtów jeżeli czytamy w zbyt długich odstępach czasu. Temat ten wielokrotnie pojawiał się tutaj w przykładach ale nigdzie nie znalazłem kompleksowego, zadowalającego mnie rozwiązania, prezentuję więc własne, może się komuś przydać albo udoskonalić. Moje rozwiązanie bazuje na HAL, jako implementacji FIFO użyłem kodu z wyguglanej kwerendy"Steve Karg Interrupt Safe Ring Buffer Library", chociaż w moim rozwiązaniu bezpieczeństwo na przerwania nie jest wymagane. Pomijając trywialne sprawy typu inicjalizacja FIFO, pinów, UARTA itd, zakładamy: UART_HandleTypeDef g_uart1; // poprawnie zainicjowany UART: 1) Odbieranie danych, założenia: FIFO_BUFFER g_rxFifo; // Bufor odbiorczy uint8_t g_rxBuffer; // Pomocniczy bajt do odbierania danych Inicjalizacjia, konieczne jest zainicjowanie odbierania na przerwaniach, najlepiej zrobić to zaraz przy inicjalizacji UARTa: HAL_UART_Receive_IT(&g_uart1, &g_rxBuffer, 1); Inicjalizuje to odbiór danych, 1 bajtu do buforu g_rxBuffer. Funkcja ta wraca od razu, rezultatem będzie zawołanie callbacka HAL_UART_RxCpltCallback który należy przekierować do poniższej funkcji: void serial1_RxCpltCallback() { FIFO_Put(&g_rxFifo, g_rxBuffer); HAL_UART_Receive_IT(&g_uart1, &g_rxBuffer, 1); } Funkcja ta wpisuje odebraną wartość do FIFO i natychmiast inicjuje odbieranie kolejnego bajtu. Funkcja do odbierania wygląda następująco, zwraca status: 0 - nie odebrano bajtu, 1 - odebrano bajt, przypisano pod podany wskaźnik. Niestety nie ma tutaj kontroli gdy odbieranie przepełni FIFO i zacznie gubić odbierane bajty, implementacja musi zapewniać w miarę sprawne odbieranie danych. Sprawę wyłączania i włączania przerwań opiszę później. uint8_t serial1_receive(uint8_t* byte) { __disable_irq(); if( FIFO_Empty(&g_rxFifo)) { __enable_irq(); return 0; } *byte = FIFO_Get(&g_rxFifo); __enable_irq(); return 1; } 2) Wysyłanie danych: FIFO_BUFFER g_txFifo; // Bufor nadawczy uint8_t g_txBuffer; // Pomocniczy volatile uint8_t g_txPending = 0; // Flaga informująca o trwającej transmisji bajtu. Zasada działania, początkowo txPending = 0 co oznacza że nic nie jest wysyłane, w takim przypadku przestawiamy ją na 1 i bajt danych wysyłamy bezpośrednio wołając HAL_UART_Transmit_IT, nie korzystając z fifo. Jednak zawołamy funkcję drugi raz zanim transmisja się zakończy i wywoła przewanie końca transmisji to txPending będzie miało wartość 1 co oznacza, że bajtu wysłać nie można i wpisujemy go do FIFO. Tutaj jeszcze sprawdzamy czy FIFO nie jest pełne, jeśli pełne go czekamy aż się zwolni i to jest jedyna możliwość gdy funkcja może trwać niespodziewania długo, ale dzięki temu jest gwarancja braku dropowania bajtów przy zbyt szybkiej transmisji. Jeśli komuś na tym nie zależy może usunąć pętlę while, pozostawiająć wykonanie FIFO_Put. void serial1_send(uint8_t byte) { __disable_irq(); if( g_txPending ) { while(!FIFO_Put(&g_txFifo, byte)) { __enable_irq(); __disable_irq(); } } else { g_txPending = 1; g_txBuffer = byte; HAL_UART_Transmit_IT(&g_uart1, &g_txBuffer, 1); } __enable_irq(); } Callback HAL_UART_TxCpltCallback należy przekierować do poniższej funkcji która działa w następujący sposób, jeśli fifo nie jest puste to pobiera z niego kolejny bajt i ponownie inicjuje transmisję na przewaniach, pozostając w stanie trwającej transmisji (txPending jest i pozostaje 1), natomiast jeśli fifo jest puste to oznacza to że nie ma już nic do transmisji i przestawiamy stan na txPending = 0. void serial1_TxCpltCallback() { if( !FIFO_Empty(&g_txFifo)) { g_txBuffer = FIFO_Get(&g_txFifo); HAL_UART_Transmit_IT(&g_uart1, &g_txBuffer, 1); } else { g_txPending = 0; } } 3) Słowo o włączaniu/wyłączaniu przerwań i innych niuansach, zauważmy że przy odbiorze danych kod HAL (funkcja HAL_UART_Receive_IT) jest wołana tylko z przerwania, natomiast przy wysyłaniu (funkcja) HAL_UART_Transmit_IT z przerwania bądź z programu głównego. Pisząc tą implementację tymczasowo odbieranie miałem w przedstawionej tutaj wersji zaś nadawanie jako klasyczne, blokujące HAL_UART_Transmit z programu głównego. I niestety pojawia się problem, gdy przerwanie HAL_UART_RxCpltCallback pojawi się w czasie trwającego, blokującego HAL_UART_Transmit gdyż HAL zaznacza ten obiekt jako locked i cokolwiek będziemy chcieli zrobić w czasie przerwania to nam się nie uda, dostaniemy status HAL_BUSY z HAL_UART_Receive_IT i transmisja stanie. Żaden z tutoriali poruszających transmisję UART na przerwaniach nie podaje tego niuansu a jest to akurat niezwykle istotne dla prawidłowego działania w dłuższym czasie. Rozwiązanie które przedstawiłem jest bezpieczne pod tym względem, każda funkcja kliencka wyłącza tymczasowo przerwania aby zabezpieczyć się przed tym problemem. 4) Ulepszenia. "Ręczne" fifo można przerobić na DMA, wysyłanie wielu bajtów można usprawnić pobierając z FIFO więcej niż jeden bajt, czego z pewnością prędzej czy później dokonam. Pozdrawiam, Remigiusz
×