Skocz do zawartości

STM32F407VG DISCO - problem z PWMem przez DMA


Pomocna odpowiedź

Napisano (edytowany)

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

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...