Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[MSP430][C] Timer_A i 3 sprzętowe PWMy - Da radę?

ZbeeGin 02 May 2009 08:32 3270 9
  • #1
    ZbeeGin
    Level 39  
    Projektuję takie małe urządzonko, w którym najpierw był ATTiny861, potem ATMega16 i teraz z powodu prądożerności AVRów z serii Mega, Mój Boss uparł się na migrację do MSP430 bo można go będzie zasilić z klasycznego układu beztransformatorowego z malutkim kondensatorem szeregowym. W tym celu na początek dostałem zakupiony tydzień temu eZ430-RF2500 i całą "laskę" MSP430F2274 by móc już czegoś się nauczyć, przetestować i na szybko zaprojektować nową wersję.

    Program dla AVRa jest już prawie cały napisany więc migracja głównego algorytmu tego urządzenia będzie łatwa i być może przyjemna. W skrócie: w urządzeniu potrzebuję 3 PWMy pracujące z częstotliwością ok. 120Hz, jeden timer odliczający podstawę czasu 200us do innych celów, dwa przerwania z zewnątrz, przetwornik ADC 2 kanały i port do 2 cyfrowego wyświetlacza.



    Pierwsze próby z Code Composerem i programem mrugającym diodą przebiegły w miarę sprawnie, więc zabrałem się napisania najwaważniejszego modułu jakim sa te nieszczęsne PWMy. Po paru godzinach bojów z konfiguracją i debuggerem efekt był... żaden. Na wyjściach albo była stale jedynka albo zero w zależności od konfiguracji bitów Output Mode, a Timer_A zmianę w rejestrach TACCRx nazwyklej w świecie miał [cenzura], choć licznik inkrementował się normalnie. Ponowna lektura dokumentacji w temacie licznika nasunęła właściwe w tym miejscu pytanie(-a):

    • Czy wogóle jest możliwe, by Timer_A stał się sprzętowym generatorem PWM z trzema wyjściami na końcówkach TA 0, TA 1, TA 2?
    • Czy rzeczywiście nawet jak licznik pracuje w trybie Continuos Up, TACCR0 nadal jest używany jako wartość przy której następuje zmiana stanu wyjścia i tym samym kanał TA 0 jest "niedostępny"?
    • Czy jednak mariage sprzętu (wyjścia porównania w trybie Reset) i przerwanie z przepełnienia (ponowne ustawianie stanu portów) jest tu nieunikniony, albo wogóle PWM w całości programowy?



    I przy okazji druga kwestia, czy jest możliwe przeznaczenie jakiegoś sektora pamięci Flash na pamięć nieulotną, bo ten F2274 nie ma EEPROMa, a gdzieś muszę zapisać parę bajtów konfiguracji, które później użyszkodnik może z poziomu klawiatury zmienić? Zewnętrzną szeregową "flaszkę" Boss będzie miał ciężko przełknąć.
  • Helpful post
    #2
    Dr_DEAD
    Level 28  
    ZbeeGin wrote:

    • Czy wogóle jest możliwe, by Timer_A stał się sprzętowym generatorem PWM z trzema wyjściami na końcówkach TA 0, TA 1, TA 2?
    • Czy rzeczywiście nawet jak licznik pracuje w trybie Continuos Up, TACCR0 nadal jest używany jako wartość przy której następuje zmiana stanu wyjścia i tym samym kanał TA 0 jest "niedostępny"?
    • Czy jednak mariage sprzętu (wyjścia porównania w trybie Reset) i przerwanie z przepełnienia (ponowne ustawianie stanu portów) jest tu nieunikniony, albo wogóle PWM w całości programowy?



    I przy okazji druga kwestia, czy jest możliwe przeznaczenie jakiegoś sektora pamięci Flash na pamięć nieulotną, bo ten F2274 nie ma EEPROMa, a gdzieś muszę zapisać parę bajtów konfiguracji, które później użyszkodnik może z poziomu klawiatury zmienić? Zewnętrzną szeregową "flaszkę" Boss będzie miał ciężko przełknąć.

    • Na pewno da radę, po to są modułu Caputer/Compare.
    • Nie bardzo rozumiem pytanie, w każdym razie do PWM'a dużo lepiej nadaje się tryb Up-Down niż Continuos Up
    • Sciągnij ze strony Texasa przykładowy kod do PWM'a i wszystko będzie jasne.


    Możesz sobie wybrać dowolny segment Flasha na trzymanie danych, ale jeżeli będzie ich niewiele to polecam do tego celu wykorzystać segmenty INFO bo są mniejsze i są trochę inaczej traktowana.
  • #3
    ZbeeGin
    Level 39  
    Dr_DEAD wrote:
    Na pewno da radę, po to są modułu Caputer/Compare.
    Nie bardzo rozumiem pytanie (...)

    W nocie katalogowej jest to tak narysowane, że trzy moduły Compare są takie same - zatem 3 wyjścia mogą niby pracować jako trzy niezależne generatory impulsów. Niestety przy rysunku opisującym tryby wyjściowe zawsze występuje wartość brana z TACCR0, która to jest tą wartością przy której zgodność z licznikiem powoduje powrót do stanu początkowego. Patrz na rusunek, zaznaczyłem to na czerwono.

    [MSP430][C] Timer_A i 3 sprzętowe PWMy - Da radę?

    A Ja potrzebuję TACCR0/TA 0 jako kolejnego kanału PWM, a nie jako logiczną wartość TOP dla pozostałych kanałów. Dlatego zastanawiam się czy by nie połączyć sprzęt z przerwaniem TAI i ustawić tryby wyjściowe na Mode 5: Reset, a w przerwaniu wymuszać ponownie stan wysoki na wyjściach przez resetowanie licznika (ustawianie TAR). Niestety MSP430 zajmuję się dopiero od 3 dni, zatem będzie to droga przez mękę. A jeśli rzeczywiście Ti tak fatalnie zrobiło obsługę PWM, to jakiś inżynierek powinien dostać po uszach.

    Dr_DEAD wrote:
    (...), w każdym razie do PWM'a dużo lepiej nadaje się tryb Up-Down niż Continuos Up

    I tu znów na przeszkodzie stoii TACCR0 - powód jak wyżej, gdyż w tym trybie definiuje on rozdzielczość licznika. :cry: A tryb FastPWM z licznikiem liczącym tylko w górę byłby wystarczający. To tylko steruje dimmerami.

    Dr_DEAD wrote:
    Sciągnij ze strony Texasa przykładowy kod do PWM'a i wszystko będzie jasne.

    Paczka z Ti zawiera owszem programy przykładowe, ale we wszystkich jest tylko dwukanałowy PWM:
    Quote:
    msp430x22x4_ta_16.c Timer_A, PWM TA1-2, Up Mode, DCO SMCLK
    msp430x22x4_ta_17.c Timer_A, PWM TA1-2, Up Mode, 32kHz ACLK
    msp430x22x4_ta_18.c Timer_A, PWM TA1-2, Up Mode, HF XTAL ACLK
    msp430x22x4_ta_19.c Timer_A, PWM TA1-2, Up/Down Mode, DCO SMCLK
    msp430x22x4_ta_20.c Timer_A, PWM TA1-2, Up/Down Mode, 32kHz ACLK
    msp430x22x4_ta_21.c Timer_A, PWM TA1-2, Up/Down Mode, HF XTAL ACLK

    Zatem pomysł z sprzętowo-programowym trzykanałowym PWMem będzie się musiał zrealizować. Chyba, że ktoś ma jeszcze jakieś inne pomysły...?

    [Dodano o 19:04]

    Próba z kasowaniem licznika w przerwaniu też jakoś nie wyszła. :cry:
    Code:
    #include <msp430x22x4.h>
    

    unsigned int pwm;
    //---------------------------------------------------
    void pwmtimerA_conf(void)
    {
       // TA jako PWMy, taktowany z cpu, preskaler 8, liczy w górę/stale
       // przerwania włączone
       TACCTL0 = CM_0 | CCIS_0 | OUTMOD_1;
       TACCTL1 = CM_0 | CCIS_0 | OUTMOD_1;
       TACCTL2 = CM_0 | CCIS_0 | OUTMOD_1;
       TACTL = MC_2 | ID_3 | TASSEL_2 | TAIE; 
    }
    //---------------------------------------------------
    void port_conf(void)
    {
       P1SEL |= BIT1 | BIT2 | BIT3;    //włącz funkcję tajmerów
       P1DIR |= BIT1 | BIT2 | BIT3;    //porty jako wyjście
    }
    //---------------------------------------------------
    void delay(unsigned int period)
    {
       unsigned int iperiod;
       // jakieś tam opóźnienie - nie liczone
       while(period>1)
          {
             for(iperiod=0; iperiod<8000; iperiod++);
             period--;
          }
    }
    // ===================================================
    int main()
    {
       WDTCTL = WDTPW | WDTHOLD;   // stop watchdoga
       __enable_interrupt();       // włącz przerwania
       port_conf();
       pwmtimerA_conf();
       while(1)
          for(pwm=0; pwm<65534; pwm++)
          {
             TACCR0 = pwm;
             TACCR1 = pwm;
             TACCR2 = pwm;
             delay(15);
          }
    }
    // ===================================================
    #pragma vector=TIMERA1_VECTOR
    __interrupt void Timer_A(void)
    {
      if(TAIV==TAIV_TAIFG)  // jak przerwanie z przepełnienia
         TACTL |= TACLR;    // to kasujemy licznik
    }
  • #4
    Dr_DEAD
    Level 28  
    Masz rację, Timer A do 3 PWMow się nie nadaje.
    Najprosztrze rozwiązanie jakie mi przyszło do glowy to puszczenie Timera w Continous Mode a modułów Compare na SET. Wtedy w obsłudze przerwania od Overflow Timera kasujesz piny a moduły Compare je ustawiają w zależności od wpisanej do nich wartości. Software sprowadza się do obsługi jednego przerwania czyli jednego AND'a.
  • #5
    ZbeeGin
    Level 39  
    Tylko, że konfiguracja końcówek wyjściowych IMHO na to nie pozwoli, gdyż moduły I/O przecież wyłączam, by do tych końcówek dopiął się układ Compare licznika. Z kasowaniem licznika, który to powinien stan spoczynkowy przywracać po tej operacji jakoś nie wyszło (patrz kod wyżej).

    Spróbuję to jednak dziś napisać (jakoś).
  • #6
    Dr_DEAD
    Level 28  
    A próbowałeś przełączyć się na OUTMOD = 0 przy OUT = 0, to powinno zresetować pina. Następnie znowu wracasz na OUTMOD = 1.
  • #7
    ZbeeGin
    Level 39  
    Tego nie próbowałem, ale zauważyłem, że ten if w przerwaniu się wogóle nie spełnia :( Po zgłoszeniu przerwania TAIV ma wartość 0x000a zatem jest równy tej stałej lecz rejestr TAIV zostaje dziwnym trafem szybko wyzerowany właśnie przez tą instrukcję:

    Quote:
    0x815c: CMP.W #0x000a,&Timer_A3_TAIV
    0x8162: JNE (C$L7)
    0x8164: BIS.W #4,&Timer_A3_TACTL
    C$L7:
    0x8168: RETI


    Doprowadza to do tego, że TACTL |= TACLR; czyli BIS.W się wogóle nie wykonuje.
  • Helpful post
    #8
    Dr_DEAD
    Level 28  
    ZbeeGin wrote:
    Tego nie próbowałem, ale zauważyłem, że ten if w przerwaniu się wogóle nie spełnia :( Po zgłoszeniu przerwania TAIV ma wartość 0x000a zatem jest równy tej stałej lecz rejestr TAIV zostaje dziwnym trafem szybko wyzerowany właśnie przez tą instrukcję:

    Quote:
    0x815c: CMP.W #0x000a,&Timer_A3_TAIV
    0x8162: JNE (C$L7)
    0x8164: BIS.W #4,&Timer_A3_TACTL
    C$L7:
    0x8168: RETI


    Doprowadza to do tego, że TACTL |= TACLR; czyli BIS.W się wogóle nie wykonuje.

    No to by się zgadzało. Każdy odczyt rejestru TAIV powoduje reset flagi o najwyższym priorytecie.
  • #9
    ZbeeGin
    Level 39  
    Zmieniłem ISRa na taki:
    Code:
    #pragma vector=TIMERA1_VECTOR
    
    __interrupt void Timer_A(void)
    {
       switch  (TAIV)                         // które źródło zgłosiło
      {
        case 0x0002: break;
        case 0x0004: break;
        case 0x000a: TACTL |= TACLR;         // to kasujemy licznik
                     break;
      }
    }

    Licznik się resetuje (o ile debugger nie kłamie), ale dalej LEDa podpięta pod TA 0 nie chce się ściemnić ani na trochę. Jutro sobie podepnę oscyloskop w pracy i zobaczymy jak to tam wygląda. No i zaaplikuję też Twoje rozwiązanie.
  • #10
    ZbeeGin
    Level 39  
    No, cóż. Temat z MSP upadł gdyż niedługo po przegranej :( walce z PWM-em założenia się zmieniły i musiał powstać malutki zasilacz impulsowy ~10W - a temu to już ATMega mogła bez przeszkód podkraść te paręnaście miliamper.
    Na dziś urządzenie już gotowe, próbki poszły. Zatem zamykam temat.

    Dziękuję koledze Dr_DEAD za pomoc.