Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

STM32F100 ШИМ 5кГц с постоянно меняющейся скважностью

Чт апр 18, 2019 17:11:15

Всем привет!

Пытаюсь выжать аппаратно ШИМ сигнал из STM32F100C8T6, частота 4800Гц, фишка в том что скважность меняется каждый такт, импульсы повторяются в таком порядке: 30%, 70%, 95%, 95%, 70%, 30%, это значения скважности в %.
Использую TIM1 и каналы 2й и 4й, это ноги РА9 и РА11.
Скважность меняю в прерывании по сравнению, регистр таймера и регистр сравнения буферизованы, то есть их значения меняются после Update Event, который происходит после переполнения таймера.
На частоте 400Гц или чуть больше всё получается, но при увеличении частоты что-то ломается и пара импульсов идет не с той скважностью, причём у каждого канала это своя пара, но порядок чёткий и не меняется например при увеличении частоты на порядок.

Добавлено after 2 minutes 23 seconds:
Мне кажется проблема в аппаратных возможностях F100, поправьте если ошибаюсь :)

Код инициализации и обработчика прерывания:

Спойлер
Код:
void GPIO_init(void)
{
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
   GPIO_InitTypeDef temp_GPIO_Init;
   
   //PWM
   temp_GPIO_Init.GPIO_Pin = PH1sig|PH2sig;
   temp_GPIO_Init.GPIO_Speed = GPIO_Speed_10MHz;
   temp_GPIO_Init.GPIO_Mode = GPIO_Mode_AF_PP;
   GPIO_Init(GPIOA, &temp_GPIO_Init);
}

void PWM_init(void)
{
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

      TIM1->CCMR1  = 0x0000;
      TIM1->CR1     = 0x0000;
      TIM1->CCER   = 0x0000;
      TIM1->DIER   = 0x0000;
      TIM1->BDTR   = 0x0000;
      TIM1->CCMR1 |= 0x6000;         //PWM1 mode CH2
      TIM1->CCMR2 |= 0x6000;         //PWM1 mode CH4
      TIM1->ARR = 20000;
      TIM1->CCR2   = 1000;   
      TIM1->CCR4   = 1000;   
      //TIM1->PSC    = 0x0009;
      TIM1->CCMR1 |= 0x0800;         //OC2 preload enable
      TIM1->CCMR2 |= 0x0800;         //OC4 preload enable
      TIM1->CR1    |= 0x0080;         //ARR preload enable
      TIM1->CCER  |= 0x0010;         //CC2E = 1
      TIM1->CCER  |= 0x1000;         //CC4E = 1
      TIM1->BDTR  |= 0x8000;         //MOE = 1
      TIM1->EGR   |= 0x0001;         //generate update event
      TIM1->CR1   |= 0x0001;         //counter enable
     
      TIM1->DIER  |= 0x0004;         //compare CH2 interrupt enable
      NVIC_EnableIRQ(TIM1_CC_IRQn);
      __enable_irq();     //вроде не нужно, на всякий случай
     
}

#define         PULSE_A         30
#define         PULSE_B         70
#define         PULSE_C         95

void TIM1_CC_IRQHandler(void)
{
      TIM1->SR &= 0xFFE0;            //5 flags reset
   
      period  = (float)TIM1->ARR;
   
      switch(pulse)
      {
         case 1:
            TIM1->CCR2 = (period/100)*PULSE_A;
            TIM1->CCR4 = (period/100)*PULSE_C;
            pulse += 1;
            break;
         case 2:
            TIM1->CCR2 = (period/100)*PULSE_B;
            TIM1->CCR4 = (period/100)*PULSE_B;
            pulse += 1;
            break;
         case 3:
            TIM1->CCR2 = (period/100)*PULSE_C;
            TIM1->CCR4 = (period/100)*PULSE_A;
            pulse += 1;
            break;
         case 4:
            TIM1->CCR2 = (period/100)*PULSE_C;
            pulse += 1;
            break;
         case 5:
            TIM1->CCR2 = (period/100)*PULSE_B;
            TIM1->CCR4 = (period/100)*PULSE_B;
            pulse += 1;
            break;
         case 6:
            TIM1->CCR2 = (period/100)*PULSE_A;
            TIM1->CCR4 = (period/100)*PULSE_C;
            pulse += 1;
            break;
         case 7:
            TIM1->CCR2 = (period/100)*PULSE_A;
            pulse += 1;
            break;
         case 8:
            TIM1->CCR2 = (period/100)*PULSE_B;
            TIM1->CCR4 = (period/100)*PULSE_B;
            pulse += 1;
            break;
         case 9:
            TIM1->CCR2 = (period/100)*PULSE_C;
            TIM1->CCR4 = (period/100)*PULSE_A;
            pulse += 1;
            break;
         case 10:
            TIM1->CCR2 = (period/100)*PULSE_C;
            pulse += 1;
            break;
         case 11:
            TIM1->CCR2 = (period/100)*PULSE_B;
            TIM1->CCR4 = (period/100)*PULSE_B;
            pulse += 1;
            break;
         case 12:
            TIM1->CCR2 = (period/100)*PULSE_A;
            TIM1->CCR4 = (period/100)*PULSE_C;
            pulse = 1;
            break;
         default:
            break;
      }
   
}


Добавлено after 4 hours 51 minute 7 seconds:
В общем проблема была из-за использования float в прерывании.
Вложения
4800.PNG
4800Гц - сигнал портится
(18.14 KiB) Скачиваний: 306
400.PNG
400Гц - нормальный сигнал
(10.27 KiB) Скачиваний: 326
Последний раз редактировалось Millyvolt Чт апр 18, 2019 20:58:10, всего редактировалось 1 раз.

Re: F100 ШИМ 5кГц с постоянно меняющейся скважностью

Чт апр 18, 2019 20:16:16

Судя по описанию и коду, можно заранее вычислить значения для регистров сравнения и загружать их через DMA.

Re: F100 ШИМ 5кГц с постоянно меняющейся скважностью

Чт апр 18, 2019 20:56:59

Судя по описанию и коду, можно заранее вычислить значения для регистров сравнения и загружать их через DMA.


Через DMA и надо, но это сигнал для двигателя и у него должен быть разгон в течение нескольких секунд, и тут как быть? :)
Ответить