Skocz do zawartości

Kurs STM32 F4 - #8 - Zaawansowane funkcje liczników


Komentator

Pomocna odpowiedź

Cześć, korzystam z kursu i natrafiłem na zagwozdke. Według mnie wartość ARR licznika w encoder mode jest niepoprawna, ponieważ resetowanie licznika następuje przy kolejnej stabilnej pozycji względem poprawnej, każdy obrót przesuwa punkt zerowy o jeden. Przy 100 stabilnych pozycjach indeksując od zera impulsy to właśnie dojście do pozycji początkowej jest pełnym obrotem, a zatem czy maksymalna wartość ARR nie powinna wynosić 399?

Link do komentarza
Share on other sites

@dirrack dzięki za sygnał, wygląda na to, że masz rację 🙂 Sprawdzę to jeszcze później, ale dni tego kursu i tak są już policzone, bo zmierzamy w kierunku jego archiwizacji (za dużo zmieniło się w ekosystemie ST od czasu przygotowania tych materiałów).

Link do komentarza
Share on other sites

Ja korzystam obecnie, i poza tym, że programy mają troszkę inny interfejs to generalnie wszystko się zgadza. Chyba, że można zrobić to po prostu lepiej, ale to nie archiwizujcie zanim nie zrobicie nowego ;).

Ale mam też pytanie. Robiąc enkodery na timerach mając płytkę z 4 timerami z czego chcąc jeszcze jeden mieć dla połączenia po usb, to zostaje mi tylko miejsce na 3 enkodery. Co w przypadku gdybym chciał mieć ich więcej? Można zrobić enkodery bez pomocy timerów? Jeśli tak to w jaki sposób? 

Link do komentarza
Share on other sites

32 minuty temu, DraveS napisał:

Ja korzystam obecnie, i poza tym, że programy mają troszkę inny interfejs to generalnie wszystko się zgadza. Chyba, że można zrobić to po prostu lepiej, ale to nie archiwizujcie zanim nie zrobicie nowego ;).

@DraveS miło słyszeć, że jednak kurs nadal pomocny 🚀

34 minuty temu, DraveS napisał:

Ale mam też pytanie. Robiąc enkodery na timerach mając płytkę z 4 timerami z czego chcąc jeszcze jeden mieć dla połączenia po usb, to zostaje mi tylko miejsce na 3 enkodery. Co w przypadku gdybym chciał mieć ich więcej? Można zrobić enkodery bez pomocy timerów? Jeśli tak to w jaki sposób? 

Dedykowana opcja do obsługi enkoderów to miły dodatek, ale równie dobrze możesz obsłużyć enkodery samodzielnie korzystając np. z przerwań zewnętrznych 🙂 

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Mam pytanie odnośnie "Generowanie sygnału PWM z wykorzystaniem DMA".

Jak już wcześniej kilka osób zdążyło napisać funkcja HAL_TIM_PWM_Start_DMA() jako *pData oczekuje typu uint32_t, natomiast przy podaniu uint16_t funkcja nadal działa nawet bez rzutowania.
Teoretycznie da się zapisać 100 w zmiennej typu uint8_t jako 1100100 i tak początkowo próbowałem, jednak DMA nie pracuje wtedy poprawnie - rzutowanie (uint32_t*) &duty nie pomaga. Czy mógłbym ktoś spróbować wytłumaczyć mi dlaczego tak się dzieje? Pozdrawiam.
 

Podsyłam jeszcze ewentualne poprawki do kursu:
"Znamy naszą częstotliwość (FREQ) oraz rozdzielczość (ARR+1), z jaką chcemy zadawać wypełnienie PWM. Zaglądając na początek artykułu o zegarach dowiemy się, że timer 4 znajduje się na magistrali APB1, a więc będzie taktowany częstotliwością 50MHz (TIM_CLK). Do ustalenia zostają nam więc tylko dwa rejestry (PSC i CKD)." - Peryferia APB1 taktowane są z częstotliwością max 50MHz, jednak nie dotyczy to timerów znajdujących się na APB1, które osiągają 100Mhz niezależnie.

Link do komentarza
Share on other sites

@Emerid Typ zmiennej przekazywanej do HAL_TIM_PWM_Start_DMA nie ma praktycznie żadnego znaczenia, DMA i tak nie zna typów języka C. Napisz może trochę dokładniej, co chcesz uzyskać i jak skonfigurowałeś kanał DMA. Prawdopodobnie błąd jest w konfiguracji i nie ma nic wspólnego z rzutowaniem.

  • Lubię! 1
Link do komentarza
Share on other sites

@Elvis - Przepraszam za zwłokę z odpowiedzią.

Kiedy wgrywam poniższych kod do płytki, zmiana jasności diody nie działa poprawnie. 
Zmienienie typu zmiennej duty jak w linijce poniżej rozwiązuje natomiast problem i zmiana jasności diody przebiega poprawnie. Nie rozumiem dlaczego.


uint8_t duty = 0 na uint16_t duty = 0

 

Poniżej zdjęcie z inicjalizacji i kod źródłowy.

image.thumb.png.77a52dd8b280a9360ef26a09d2f687d3.png

/*main.c*/

#include "main.h"

uint8_t duty = 0;

TIM_HandleTypeDef htim4;
DMA_HandleTypeDef hdma_tim4_ch3;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM4_Init(void);

void HAL_SYSTICK_Callback(void);

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM4_Init();

  HAL_TIM_PWM_Start_DMA(&htim4,TIM_CHANNEL_3,(uint32_t*) &duty,1);

  while (1)
  {
  }
}

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_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_TIM4_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 9999;
  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_3) != HAL_OK)
  {
    Error_Handler();
  }
  
  HAL_TIM_MspPostInit(&htim4);

}

/** 
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void) 
{

  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Stream7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{

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

}

/* USER CODE BEGIN 4 */
void HAL_SYSTICK_Callback(void){
	static uint8_t interruptCounter = 0;
	static uint8_t countUp = 1;

	interruptCounter++;

	/* T_systick = 1/ 1kHz = 0.001 s
	 * T_incrementation = 40 * 0.001s = 0.04 s
	 * T_total = 0.04s *100 = 4s */

	if(interruptCounter == 40){
		interruptCounter = 0;

		if(duty == 100)
			countUp = 0;
		else if(duty == 0)
			countUp = 1;

		if(countUp)
			duty++;
		else
			duty--;
	}

}

void Error_Handler(void)
{

}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line)
{ 

}
#endif

 

/*stm32f4xx_hal_msp.c*/

#include "main.h"

extern DMA_HandleTypeDef hdma_tim4_ch3;
                        
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);

void HAL_MspInit(void)
{

  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_RCC_PWR_CLK_ENABLE();

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM4)
  {

    /* Peripheral clock enable */
    __HAL_RCC_TIM4_CLK_ENABLE();
  
    /* TIM4 DMA Init */
    /* TIM4_CH3 Init */
    hdma_tim4_ch3.Instance = DMA1_Stream7;
    hdma_tim4_ch3.Init.Channel = DMA_CHANNEL_2;
    hdma_tim4_ch3.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim4_ch3.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim4_ch3.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim4_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_tim4_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_tim4_ch3.Init.Mode = DMA_CIRCULAR;
    hdma_tim4_ch3.Init.Priority = DMA_PRIORITY_LOW;
    hdma_tim4_ch3.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_tim4_ch3) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_CC3],hdma_tim4_ch3);

  }

}

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim->Instance==TIM4)
  {
    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**TIM4 GPIO Configuration    
    PD14     ------> TIM4_CH3 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_14;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  }

}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM4)
  {
    /* Peripheral clock disable */
    __HAL_RCC_TIM4_CLK_DISABLE();

    /* TIM4 DMA DeInit */
    HAL_DMA_DeInit(htim_base->hdma[TIM_DMA_ID_CC3]);

  }

}


*/stm32f4xx_it.c*/

#include "main.h"
#include "stm32f4xx_it.h"

/* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_tim4_ch3;


/******************************************************************************/
/*           Cortex-M4 Processor Interruption and Exception Handlers          */ 
/******************************************************************************/
/**
  * @brief This function handles Non maskable interrupt.
  */
void NMI_Handler(void)
{

}

/**
  * @brief This function handles Hard fault interrupt.
  */
void HardFault_Handler(void)
{

  while (1)
  {

  }
}

/**
  * @brief This function handles Memory management fault.
  */
void MemManage_Handler(void)
{

  while (1)
  {

  }
}

/**
  * @brief This function handles Pre-fetch fault, memory access fault.
  */
void BusFault_Handler(void)
{

  while (1)
  {
  }
}

/**
  * @brief This function handles Undefined instruction or illegal state.
  */
void UsageFault_Handler(void)
{

  while (1)
  {

  }
}

/**
  * @brief This function handles System service call via SWI instruction.
  */
void SVC_Handler(void)
{

}

/**
  * @brief This function handles Debug monitor.
  */
void DebugMon_Handler(void)
{

}

/**
  * @brief This function handles Pendable request for system service.
  */
void PendSV_Handler(void)
{

}


void SysTick_Handler(void)
{
  HAL_IncTick();
  
  HAL_SYSTICK_IRQHandler();
}

void DMA1_Stream7_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_tim4_ch3);
}

 

 

 

 

Link do komentarza
Share on other sites

Cześć, chciałbym wyróżnić ten jeden komentarz, który moim zdaniem łatwo pominąć przeglądając komentarze, a rozwiązuje spory problem.

Jeżeli komuś zdarzyło się, że dioda się w ogóle nie świeci, warto sprawdzić obecność funkcji, o której mówi @gekon83.

Dnia 29.12.2019 o 12:19, gekon83 napisał:

@misklap dzięki za informacje! Od wczoraj próbowałem rozwiązać ten problem.

Z pomocą przychodzi tutaj Debugger. Po ustawieniu breakpointa w funkcji void HAL_SYSTICK_Callback(void) widać że program nigdy nie używa tego przerwania. Dlaczego? Ponieważ STM32CubeMX v5.x nie umieszcza funkcji obsługi tego przerwania HAL_SYSTICK_IRQHandler(); wewnątrz void SysTick_Handler(void) (w pliku stm32f4xx_it.c). Po dopisaniu brakującej linijki wszystko działa tak jak opisano w kursie.

PS. Wybaczcie jeżeli pogwałciłem jakiekolwiek normy w trakcie pisania tego (pierwszego) postu 😉

 

Lokalizacja pliku: Nasz_projekt/Core/Src/stm32f4xx_it.c

Jak funkcja wygląda u mnie, gdy działa:

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
  HAL_SYSTICK_IRQHandler(); // <---------------------- to polecenie trzeba dopisac jezeli nie ma (u mnie nie bylo)
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

Wiem, że trochę repostuję, ale niektórzy mogą nie skojarzyć, że problem z nieświecącą diodą tkwi w tym miejscu. Jak post nie na miejscu, to można usunąć, nie obrażę się 😛

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

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

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

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

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

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

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

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.