V
V
veydlin2015-05-01 20:20:24
Microcontrollers
veydlin, 2015-05-01 20:20:24

Why is the servo buggy in FreeRTOS?

I'm just starting to switch to STM after AVR
. Also, my first experience with preemptive RTOS, before that I used only cooperative ones.
Example from here
When trying to build a servo into an RTOS, the servo starts to go crazy

#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "misc.h"

#include "FreeRTOS.h" // Подключаем FreeRTOS
#include "task.h" // Переключение задач



// Функция устанавливает позицию вала (в градусах)
#define SERVO_180 8200
#define SERVO_0 1800
void set_pos(uint8_t pos) {
  uint32_t tmp = (SERVO_180 - SERVO_0) / 180;
  TIM2->CCR2 = SERVO_0 + tmp * pos;
}



// Крутим сервопривод
void servo_task(void *pvParameters) {
  uint8_t i;
  while(1) {
    for(i = 0; i <= 180; i += 10) {
      vTaskDelay(10);
      set_pos(i);
    }
  }
}


// Мигаем светодиодом
void led_task(void *pvParameters) {
  while(1) {
    GPIOC->ODR |= (GPIO_Pin_8);
    vTaskDelay(1000);
    GPIOC->ODR &= ~(GPIO_Pin_8);
    vTaskDelay(1000);
  }

}


int main(void) {

  // Настраиваем порт A
  GPIO_InitTypeDef PORT_A;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Тактируем
  PORT_A.GPIO_Pin = (GPIO_Pin_1);
  PORT_A.GPIO_Mode = GPIO_Mode_AF_PP; // Будем использовать альтернативный режим, а не обычный GPIO
  PORT_A.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOA, &PORT_A);


  // Настраиваем порт С
  GPIO_InitTypeDef PORT_C;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  PORT_C.GPIO_Pin = (GPIO_Pin_9 | GPIO_Pin_8);
  PORT_C.GPIO_Mode = GPIO_Mode_Out_PP;
  PORT_C.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOC, &PORT_C);


  // Настраиваем таймер таймер 2
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // Тактируем
  TIM2->CCER |= (TIM_CCER_CC2E); // Разрешаем таймеру использовать ногу PA1 для ШИМа
  TIM2->CCMR1 |= (TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2);
  TIM2->PSC = 6; // Настраиваем предделитель, чтобы частота ШИМа была в районе 50 Гц
  TIM2->CR1 |= TIM_CR1_CEN; // Запускаем


  // Создаем задачи для ОС
  xTaskCreate(servo_task, (signed char*)"servo", configMINIMAL_STACK_SIZE, NULL, 2, (xTaskHandle*)NULL);
  xTaskCreate(led_task, (signed char*)"led", configMINIMAL_STACK_SIZE, NULL, 2, (xTaskHandle*)NULL);


  // Пинаем планировщик
  vTaskStartScheduler();
};

Answer the question

In order to leave comments, you need to log in

1 answer(s)
J
jcmvbkbc, 2015-05-02
@veydlin

#define SERVO_180 8200
#define SERVO_0 1800
void set_pos(uint8_t pos) {
  uint32_t tmp = (SERVO_180 - SERVO_0) / 180;
  TIM2->CCR2 = SERVO_0 + tmp * pos;
}

Fufufu, first multiply, then divide, otherwise you will lose accuracy and get a big shortfall at large angles.
In addition, it seems to me that this formula should look like this:
uint32_t tmp = ((SERVO_180 - SERVO_0) * pos) / 180 + SERVO_0;
  TIM2->CCR2 = tmp;

not?
Would you describe exactly how.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question