Skocz do zawartości
PrimeSoul

STM32F407VG DISCO - problem z PWMem przez DMA

Pomocna odpowiedź

Cześć wszystkim,

Walczę co nieco z serwonapędami na płytce Discovery z STM32F407VG na pokładzie (stary model, z programatorem poprzedniej generacji). Sprawa wygląda tak, że mam serwo wieloobrotowe z enkoderem w postaci czujnika szczelinowego i tarczy (sygnał dubluję 3 razy, na razie tylko do testów, później każdy kanał sterowany będzie oddzielnie). Dokładność pozycjonowania taka sobie, ale do potrzeb projektu wystarcza. Kwestia jest taka, że serwo poruszać się ma wg wyliczonej prędkości z regulatora (jeszcze nie zaimplementowany, dopiero w planach) w przerwaniu od timera systemowego. Wartość aktualnego sterowania serwem będzie zapisywana do zmiennej globalnej.

No i teraz kluczowa sprawa - chciałbym, żeby timer, na którym jest sterowane to serwo, samoczynnie zmieniał swoje wypełnienie na wartość zmiennej globalnej z obliczonym sterowaniem. Idealnym rozwiązaniem moim skromnym zdaniem byłoby użycie DMA w kierunku Memory -> Peripheral w trybie kołowym (half-word). Niestety, całość nie chce zadziałać - startuje tylko pierwszy kanał timera i w dodatku z ustawieniem domyślnym, nie zmienia swojego wypełnienia przy zmianach zmiennej przypisanej do kanału w DMA, a pozostałe nawet nie startują z domyślnymi wartościami.

W załączniku wrzuciłem okrojony tylko do tej kwestii projekt testowy i projekt z CubeMXa. Poniżej kod main'a:

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim4;
DMA_HandleTypeDef hdma_tim4_ch2;
DMA_HandleTypeDef hdma_tim4_ch1;
DMA_HandleTypeDef hdma_tim4_ch3;

/* USER CODE BEGIN PV */
volatile uint16_t PwmPulse = 199;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM4_Init(void);
static void MX_DMA_Init(void);
/* USER CODE BEGIN PFP */

(...)

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();
  MX_DMA_Init();
  /* USER CODE BEGIN 2 */
//  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
//  TIM4->CCR1 = PwmPulse;
//  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
//  TIM4->CCR2 = PwmPulse;
//  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
//  TIM4->CCR3 = PwmPulse;
//  HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
//  TIM4->CCR4 = PwmPulse;
  HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_1, (uint32_t*)&PwmPulse, 1);
  HAL_Delay(100);
  HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_2, (uint32_t*)&PwmPulse, 1);
  HAL_Delay(100);
  HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_3, (uint32_t*)&PwmPulse, 1);
  HAL_Delay(100);
  //HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_2, (uint32_t*)&PwmPulse, sizeof(PwmPulse)/2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
//	  TIM4->CCR2 = PwmPulse;
//	  HAL_Delay(100);
    /* USER CODE END WHILE */

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

Zakomentowana frakcja kodu bez DMA działa bez problemu i generalnie jest to awaryjna opcja, której użyję, jeśli nic z DMA nie uda mi się sensownego wypracować.

No i jeszcze wygenerowane z CubeMXa funkcje konfiguracyjne dla timera i DMA:

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 = 839;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 1999;
  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 = 99;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.Pulse = 189;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.Pulse = 199;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.Pulse = 0;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */

  /* USER CODE END TIM4_Init 2 */
  HAL_TIM_MspPostInit(&htim4);

}

/** 
  * 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_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
  /* DMA1_Stream7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);

}

Podobny problem miałem też wcześniej, gdy rozwiązywałem zadania z kursu STM32, ale tam była to kwestia złej kierunkowości w DMA, tutaj ją sprawdziłem w Cube'ie chyba z 3 razy.

Będę baaaardzo wdzięczny za wszelką pomoc w tym zakresie, przejrzenie kodu / projektu.

Środowisko: SW4STM32 + STM32CubeMX

Pozdrawiam

 

 

Wrk_03_SERVO_LIB.zip

Edytowano przez PrimeSoul

Udostępnij ten post


Link to post
Share on other sites

W załącznikach nie ma żadnych plików źródłowych. W treści nie ma wypełnionej struktury dla timerów.

W ten sposób nie da się nic wymyślić

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

@Zealota Oj sorki, mój błąd przy spakowaniu plików. Zaraz poprawię.
UPDATE: Teraz załącznik powinien już zawierać wszystkie pliki projektowe.

Edytowano przez PrimeSoul

Udostępnij ten post


Link to post
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!

Gość
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...