Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[STM32F4][C] - Synchronizacja równoległa PWM

qaz88 31 Lip 2015 04:30 1290 9
  • #1 31 Lip 2015 04:30
    qaz88
    Poziom 12  

    Witam, mam taki problem.
    Potrzebuje mieć 7 zsynchronizowanych ze sobą wyjść PWM. Użyłem timerów TIM1 i TIM3 i zsynchronizowałem je timerem TIM2 ustawionym na 21MHz. Synchronizacja wyzwalania działa tylko że wyjścia PWM są przesunięte w fazie. Zaczynam mieć poważne wątpliwości czy takie coś da się poprawnie zrobić używając timerów sprzętowych, jeśli tak to jak?

    Oto mój kod:

    Code:

    void tim2_config(void) {

      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
       
      TIM_TimeBaseStructure.TIM_Prescaler = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;
      TIM_TimeBaseStructure.TIM_Period = 1;
      TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
       
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_Pulse = 1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC1Init(TIM2, &TIM_OCInitStructure);
       
       /* Master Mode selection */
      TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);
      TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
       
      TIM_Cmd(TIM2, ENABLE);
    }


    void tim1_config(void) {

          TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
            TIM_OCInitTypeDef  TIM_OCInitStructure;

            TIM_TimeBaseStructure.TIM_Prescaler = 1;
            TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned2;
            TIM_TimeBaseStructure.TIM_Period = 999;
            TIM_TimeBaseStructure.TIM_ClockDivision = 0;
            TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
            TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

            TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
               TIM_OCInitStructure.TIM_Pulse = 0;
            TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
            TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
          TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
            TIM_OC1Init(TIM1, &TIM_OCInitStructure);
               TIM_OC2Init(TIM1, &TIM_OCInitStructure);
            TIM_OC3Init(TIM1, &TIM_OCInitStructure);   




          TIM_OC4Init(TIM1, &TIM_OCInitStructure);
       
          TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Gated);
                    TIM_SelectInputTrigger(TIM1, TIM_TS_ITR1);

                    TIM_CtrlPWMOutputs(TIM1,ENABLE);// bez tego nie dziala

          TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
          TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_OC4Ref);
             
          TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Gated);
                    TIM_SelectInputTrigger(TIM1, TIM_TS_ITR1);
               TIM_Cmd(TIM1, ENABLE);
    }

    void tim3_config(void) {

     
            TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
              TIM_OCInitTypeDef  TIM_OCInitStructure;

              TIM_TimeBaseStructure.TIM_Prescaler = 0;
              TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned2;
              TIM_TimeBaseStructure.TIM_Period = 999;
              TIM_TimeBaseStructure.TIM_ClockDivision = 0;
              TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
              TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

              TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
                 TIM_OCInitStructure.TIM_Pulse = 0;
              TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
              TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
                TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
              TIM_OC1Init(TIM3, &TIM_OCInitStructure);
            TIM_OC4Init(TIM3, &TIM_OCInitStructure);
            TIM_OC2Init(TIM3, &TIM_OCInitStructure);
            TIM_OC3Init(TIM3, &TIM_OCInitStructure);
             
            TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated);
                      TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);
            TIM_Cmd(TIM3, ENABLE);
    }

    0 9
  • #2 11 Sie 2015 08:39
    qaz88
    Poziom 12  

    Tyle wyświetleń i zero odpowiedzi więc domyślam się że nikt nie zna rozwiązania. Do kitu jest ten STM. Jeśli nie da się zsynchronizować PWMów to nie można na nim zbudować podstawowego falownika. Przecież to jakaś porażka..

    0
  • Pomocny post
    #3 11 Sie 2015 09:17
    Marek_Skalski
    Moderator Projektowanie

    Do budowy falowników to ja używam dsPIC33EPxxxMUxxx. Tam właśnie masz do dyspozycji moduł 7 komplementarnych, szybkich PWM ze wspólną, podwójną podstawą czasu. Każdy kanał może być w pełni synchroniczny z pozostałymi, lub zupełnie niezależny, a trybów pracy jest kilka. A jak chcesz, to możesz mieć 14 osobnych kanałów, ale bez kontroli dead-time.
    Nie jest demonem prędkości, a Microchip nie jest najlepszą firmą, ale do tej pory nie spotkałem lepszych układów do takich zadań.
    Link do wyszukiwarki.
    Link do strony domowej.

    Z drugiej strony, na STM32F4xx też da się zrobić taki układ, jednak będzie to trochę trudniejsze. Twojego programu nie rozumiem, ponieważ używałeś SPLa.
    1. Skonfiguruj pierwszy licznik PWM (4 wyjścia?)
    2. Skonfiguruj drugi licznik PWM (3 wyjścia?)
    3. Skonfiguruj licznik nadrzędny, który odpowiada za cykliczny reset liczników podrzędnych (synchronizacja).
    4. Włącz liczniki podrzędne. Jeszcze nie będą pracować synchronicznie.
    5. Włącz licznik nadrzędny i poczekaj na synchronizację.
    6. Uaktywnij wyjścia liczników podrzędnych. Teraz sygnał na wyjściu będzie prawidłowy.

    1
  • #4 11 Sie 2015 10:05
    qaz88
    Poziom 12  

    Robie właśnie dokładnie jak to opisujesz. Timery są ze sobą zsynchronizowane czasowo ale sygnały z dwóch podrzędnych timerów są przesunięte w fazie o wartość zależną od częstotliwości timera nadrzędnego. Uniemożliwia to implementacje trójpoziomowego SVPWM gdzie wszystkie sygnały muszą być central oriented.
    Ten PIC jest faktycznie fajny ale niestety za wolny do tego co potrzebuje, docelowo chciałem się przesiąść na F7 bo ten stm32f4 też może nie wystarczyć ale taka mi właśnie niespodzianka wyskoczyła.

    0
  • #5 11 Sie 2015 10:12
    BlueDraco
    Specjalista - Mikrokontrolery

    Tak na oko to potrzebujesz synchronicznego startu, a nie timera nadrzędnego. Poczytaj dokładnie w RefMan - zapewne da się to zrobić, chociaż niekoniecznie przy użyciu SPL - zresztą na rejestrach będzie dużo łatwiej i krócej, no i kod będzie łatwiejszy do przeanalizowania i sprawdzenia z RefMan.

    0
  • #6 11 Sie 2015 10:52
    qaz88
    Poziom 12  

    Synchroniczny start raczej nic nie da, Gdy ustawie oba timery na identyczne czestotliwości (wyzwalane z głównego zegara) i puszczam ich PWM na oscyloskop to i tak widze że ich wartości "pływają" między sobą. Dopiero wyzwalanie ich timerem nadrzędnym powoduje że sygnały te są stabilne i stoją w miejscu względem siebie. Będe jeszcze z tym walczyć ale przeglądając note to widze informacje tylko odnośnie synchronizacji timerów a nie wartości wypełnień. Pokombinuje też jeszcze z innymi timerami bo może tim1 (advanced puszczane z APB2) z tim3 (general puszczane z APB1) mają jakieś różnice i nie należy ich łączyć.

    0
  • #7 11 Sie 2015 11:45
    BlueDraco
    Specjalista - Mikrokontrolery

    Jeśli timery startują synchronicznie i mają równy okres, to o ile nie wyłączyłeś buforowania wypełnień i modyfikujesz wartości wypełnień w przerwaniu Update (końca okresu) - wszystko musi działać poprawnie. Oczywiście powinieneś używać przerwania tylko z jednego timera.

    0
  • #8 11 Sie 2015 18:27
    SeerKaza
    Poziom 20  

    Tylko do sterowania wyjściami użyj dwóch timerów tego samego typu i znajdujących się na tej samej magistrali.

    0
  • #9 09 Wrz 2015 10:40
    qaz88
    Poziom 12  

    SeerKaza niestety nie masz racji. Wybór timerów róznego lub tego samego typu daje takie same rezultaty. Zadziałała natomiast metoda opisana przez Marek_Skalski za co bardzo dziękuje, jedyne co zmieniłem aby to wszystko zaczeło poprawnie działać to zamiana miejscami punktu 5-tego z 6-stym. Inne kolejności aktywowania timerów dają już przesunięte wyniki.
    Temat do zamknięcia

    0
  • #10 09 Wrz 2015 23:44
    Marek_Skalski
    Moderator Projektowanie

    qaz88 napisał:
    Ten PIC jest faktycznie fajny ale niestety za wolny do tego co potrzebuje

    dsPIC33EPxxxMUxxx oferują 16-bitowe PWM z rozdzielczością rzędu 7ns. A to wcale nie jest gorsze od tego co dają STM32F4xx.
    dsPIC33EPxxxGSxxx oferują 16-bitowe PWM z rozdzielczością rzędu 1,042ns. Na razie nie znalazłem lepszych układów do przetwarzania DC/DC czy DC/AC. PGA+ADC+komparatory sprzężone z PWM są jedyne w swoim rodzaju. Ten rdzeń taktowany na 70MHz jest całkiem wydajny. Pętla kontroli z typowym PID na 3 próbkach i przetwarzaniem ADC trwa około 1,4us.
    Ja też próbowałem z STM32L151, później 32F405, próbowałem też z SAM V71, ale MCP jest najbardziej efektywny dzięki synchronicznym ADC, komparatorom sprzężonym z PWM i bardzo dobrym układem Hi-Speed PWM. Spróbuj.

    0