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

[STM32] i Timery - generator

Aro_ 26 May 2009 14:54 9673 35
  • #1
    Aro_
    Level 15  
    Witam,
    Timery w tych prockach mają tyle opcji, że się w tym wszystkim pogubiłem. Jak można wygenerować na jakimś wyjściu przebieg prostokątny o programowo określonej częstotliwości? Pewnie będzie to tryb Compare z zerowaniem rejestru licznika i zmiany wyjścia na stan przeciwny. Nie mam jednak pojęcia co i gdzie poustawiać w rejestrach.
  • #3
    Freddie Chopin
    MCUs specialist
    Aby uruchomić coś takiego na timerze trzeba ustawic kilka rejestrow

    CCMR1 - wybierasz tryb pracy i kierunek portów OCx
    CCER - aktywujesz daną końcówkę OCx
    CR1 - kilka podstawowych parametrow pracy oraz wlasciwa aktywacja zliczania

    odczywiscie do tego dochodzi jeszcze ustawienie samego okresu [; przypuszczam ze dla twojego trybu pracy znajduje sie on w rejestrze ARR. W kręgu twoich zainteresowań znajduje się też rejestr PSC odpowiedzialny za preskaler.

    4\/3!!
  • #4
    Aro_
    Level 15  
    Dzięki za naprowadzenie na właściwy trop. Jeszcze trochę postudiuję notkę STMa, może coś stworzę.

    Dodano po 43 [minuty]:

    Przejrzałem pobieżnie notę STMa "RM0008 Reference manual" i nie zauważyłem możliwości ustawienia aby timer zerował się po porównaniu. Natomiast moją uwagę przykuło takie zdanie: "16-bit programmable prescaler used to divide (also “on the fly”) the counter clock frequency by any factor between 1 and 65535". Czyli można użyć dowolnej liczby do podziału? Druga sprawa to okres, czy może wynosić np. 2? Jeżeli tak to mógłbym zrealizować ten generator inaczej. Timer liczy sobie dwa stany i zmienia wyjście OC1, natomiast częstotliwość będzie regulowana preskalerem. Da radę coś takiego zrobić? Głównie zależy mi na częstotliwościach generowania 18MHz, 9MHz, oraz 3,6MHz.
  • #5
    Freddie Chopin
    MCUs specialist
    Aro_ wrote:
    Przejrzałem pobieżnie notę STMa "RM0008 Reference manual" i nie zauważyłem możliwości ustawienia aby timer zerował się po porównaniu.

    Na następny raz nie przeglądaj manuali tak pobieżnie, bo:

    Quote:

    13.3.2 Counter modes
    upcounting mode
    In upcounting mode, the counter counts from 0 to the auto-reload value (content of the
    TIMx_ARR register), then restarts from 0 and generates a counter overflow event.


    Ustawiasz sobie potem albo PWMa albo Toggle'a. Przy Toggle ustawiasz porównanie na dowolną wartość z zakresu 0-ARR, a podstawowy okres równy jest ARR*2 (+ ewentualny preskaler oczywiście). Przy PWM ustawiasz porównanie na wartość ARR/2 (jeśli chcesz mieć wypełnienie 50%), natomiast okres odpowiada ARR (oraz ewentualny preskaler).

    4\/3!!
  • #6
    Aro_
    Level 15  
    No tak, tylko jakbym dokładnie czytał, to do dzisiaj bym nie skończył:P Ale może przynajmniej był to uruchomił:|
    Więc sprawa ma się tak: zrobiłem kilka wpisów do rejestrów o których mówiłeś
    TIM3->CR1|=1<<7 |01<<5 | 1<<0; //ARPE, CMS, CEN
      TIM3->CCMR1|=011<<4; //OC1M=011
      TIM3->CCER|=1<<9 | 1<<0; //CC3P,  CC1
      TIM3->PSC|=0;
      TIM3->ARR|=100;

    Oczywiście standardowo uaktywniony zegar oraz pin jako AF. Niestety licznik wciąż milczy. Czy czegoś tu brakuje?
  • #8
    Aro_
    Level 15  
    Nie pomogło ustawienie bitu CEN na końcu:(
    Jak stwierdziłem? Na GPIOB.0 nic się nie zmienia.
  • #9
    markosik20
    Level 33  
    Aro_ wrote:
    Jak stwierdziłem? Na GPIOB.0 nic się nie zmienia.


    Miernikiem częstotliwości czy oscyloskopem sprawdzałeś ?
  • #10
    Aro_
    Level 15  
    Miernikiem f i sondą logiczną. Cały czas jest stan niski.
  • #12
    Aro_
    Level 15  
    Tak, mam włączony timer w RCC, oraz wyjście w trybie AF_PP. AFIO tu się raczej nie przyda (aczkolwiek sprawdziłem tak na wszelki wypadek...).
  • #14
    Aro_
    Level 15  
    Tak, jest wszystko włączone, pytanie czy wszystko w rejestrach timera jest jak trzeba. Chciałbym wykorzystać funkcje API dostarczone przez STMa, sprawdziły się dla innych peryferii (SPI, USART, GPIO, DMA...) jednak nie ma nigdzie przykładu konfiguracji timera w trybie compare.
  • #15
    Freddie Chopin
    MCUs specialist
    No dobra. Przedewszystkim weź wywal te wszystkie ORy ( |= ) bo nie mają najmniejszego sensu, a mogą powodować problemy. Wartość do rejestrów wpisujesz od razu, a nie ORujesz z poprzednią zawartością.

    Następnie - ustawiasz ARR, ale gdzie ustawiasz rejestr CCR1? Przecież z czymś trzeba porównywać.

    Idąc dalej - ustawiłeś w CR1 "Center Aligned Moder (1<<5) - ustaw lepiej "Edge ..." czyli 0<<5.

    Do tego spróbuj wyciągnąć ustawianie bitu CEN zupełnie poza te instrukcje które masz. Ustaw go (CR1|=1) dopiero gdy wszystko inne będzie już ustawione, koniecznie na samym końcu.

    4\/3!!
  • #16
    Aro_
    Level 15  
    Dalej nic:( Czegoś musi brakować.
  • #19
    Freddie Chopin
    MCUs specialist
    No więc tak, po kolei:

    1. Pisałem już ze 3x, żebyś nie włączał (CEN) timera przed ustawieniem całej reszty. Timer włączasz na samym początku, a potem poprawiasz jeszcze na końcu... Nie o to mi chodziło... Usuń ustawienie CEN z początku!

    2. Nie wiem jakiego dokładnie masz STMa, ale w datasheecie do F103x8 i F103xB, na porcie PB0 jest TIM3_CH3. Ty natomiast w swoim kodzie ustawiasz troszkę CH3 i resztę dla CH1!

    TIM3->CCMR1=011<<4; //OC1M=011
    W rejestrze CCMR1 są bity dla CH1 i CH2!

    TIM3->CCER=1<<9 | 1<<0; //CC3P, CC3E, CC1
    Ustawiasz polaryzację dla CH3, ale aktywujesz CH1!

    TIM3->CCR1=50;
    CCR1 odpowiada za CH1!

    4\/3!!
  • #20
    Aro_
    Level 15  
    No, tak teraz to rozumiem:) Przerobiłem wpisy na takie:
    /* Time base configuration */
      TIM3->CR1=1<<7 |00<<5; //ARPE, CMS=00
      TIM3->CCMR2=011<<4; //OC3M=011
      TIM3->CCER=1<<8; //CC3E
      TIM3->PSC=0;
      TIM3->ARR=1;
      TIM3->CCR3=200;
      
      TIM3->CR1|= 1<<0; //CEN
      while (1)
      {}

    I nie rozumiem czemu wciąż nie działa:(
  • Helpful post
    #21
    Freddie Chopin
    MCUs specialist
    011<<4

    Wiesz co w C oznacza zapis 011? Podpowiem, że odpowiada on liczbie 9, co binarnie odpowiada liczbie 1001. Proponowałbym napisać tam cyfrę 3.

    Pozatym każdy twój przykład kodu ma chyba więcej błędów. W tym momencie ustawiłeś, że timer liczy do 1, a zmianę pinu będziesz miał przy wartości 200. No to jakim cudem chcesz jakąkolwiek zaobserwować, skoro timer nigdy nie doliczy do tej wartości?

    4\/3!!
  • #22
    Aro_
    Level 15  
    Chyba zrobię sobie jakąś dłuższą przerwę w programowaniu bo już głupoty wypisuję... Na szczęście po zmianie tej nieszczęsnej "trójki" i wartości ARR na wyjściu pojawił się sygnał. Dalej sobie już poradzę.
    Freddie Chopin nie wiem jak Ci dziękować, potrafisz nie tylko pokazać, ale co bardzo ważne, także wytłumaczyć! Za co jestem Ci bardzo wdzięczny:D
  • #23
    Freddie Chopin
    MCUs specialist
    Aro_ wrote:
    Freddie Chopin nie wiem jak Ci dziękować, potrafisz nie tylko pokazać, ale co bardzo ważne, także wytłumaczyć! Za co jestem Ci bardzo wdzięczny:D

    To wystarczy za podziękowanie [;

    powodzenia w dalszej walce.

    4\/3!!
  • #24
    Talib84po
    Level 10  
    Żeby nie zakładać oddzielnego wątku - mam problem z włączeniem przerwania na TIM4. Wszystko niby skonfigurowane - GPIOB.9 jako wyłapanie przerwania:
       /* TIM 4 intetrupt pin  PB.7 channel 4 */
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      GPIO_Init(GPIOB, &GPIO_InitStructure);


    RCC_APB1 dla TIM4 włączone, RCC_APB2 dla GPIOB również, wektor zainicjowany
    /* Timer 4 vector configuration */
      NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    Sam Timer również :


    /* Timer 4 configuration
         Time base configuration */
      TIM_TimeBaseStructure.TIM_Period = 65535;
      TIM_TimeBaseStructure.TIM_Prescaler = 1024;
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    
      TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    
    
      // TIM4 Input Capture configuration 
      TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
      TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //TIM Input Capture Rising Edge.
      TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
      TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;  // TIM Capture performed each time an edge is detected on the capture input.
      TIM_ICInitStructure.TIM_ICFilter = 0;
    
      TIM_ICInit(TIM4, &TIM_ICInitStructure);
     
      TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE); 
      TIM_Cmd(TIM4, ENABLE);


    Jak również zadeklarowany jest TIM4_IRQHandler w .h i sama funkcja też jest. Gdy podam sygnał na powyższy pin pojawia się zmiana w TIM4_CCR4, natomiast powyższy handler nie startuje. Może ktoś pomóc ?
  • #25
    Aro_
    Level 15  
    Przerwanie powinno być w porządku, ale co do inicjacji samego Timera to nie jestem pewny. Po prostu nie mam zaufania do funkcji API dla Timerów. Czy udało Ci się uruchomić cokolwiek związanego z licznikami na tych funkcjach?
  • #26
    Talib84po
    Level 10  
    Problem rozwiązałem - okazało się, że przy przenoszeniu kodu zniknęła inicjalizacja NVIC_InitStructure...
    Puki co interesowało mnie samo wyliczanie czasu pomiędzy kolejnymi przerwaniami, i to działa mi ładnie - dostosowałem sobie przykład z 32 bitowego timera ze strony stm i wszystko ładnie działa.
  • #27
    Aro_
    Level 15  
    O to świetnie:) Teraz jeszcze muszę popatrzeć co zniknęło u mnie, że timery nie działają na API...
  • #28
    ciastek4
    Level 14  
    Witajcie ja z kolei mam inny problem z tymi timerami. Chce generować przerwanie co określony czas ( włączone przerwanie UPDATE ) i problem polega na tym, że co pewien czas jedno przerwanie jest gubione. Co ewentualnie robię źle kod poniżej:
    inicjalizacja:
     
    	TIM_TimeBaseInitTypeDef TIM_InitStruct;
    	TIM_InitStruct.TIM_ClockDivision = 0;
    	TIM_InitStruct.TIM_Prescaler = 71;		//fclk = 72MHz/72 = 1MHz
    	TIM_InitStruct.TIM_Period = 1000;
    	TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Down;
    	TIM_TimeBaseInit(TIM2,&TIM_InitStruct);
    	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
    	TIM_Cmd(TIM2,ENABLE);			//wlaczenie timera
    


    przerwanie:
    
    void TIM2_Handler(void)
    {
    	if (TIM2->SR & (TIM_SR_UIF))
    	{
    		TIM2->SR = (uint16_t)~TIM_SR_UIF;	//kasuj bit 
    		GPIOE->ODR ^= (1<<15); // toggle led
    	}
    }
    
  • #29
    Freddie Chopin
    MCUs specialist
    przerwanie powinno być z atrybutem ((interrupt)), a próby wpisywania wartości 0xFFFE do rejestru SR nie wydają mi się szczególnie mądre. W końcu rejestr ten ma kilka pól które są "reserved" więc nikt nie wie co robią, a poza tym ST pewnie zapomniało napisać, że jakieś tam bity można jednak pomieszać wpisując do rejestru jedynkę - nic nowego, w produktach ST zawsze trzeba brać na to poprawkę.

    Poza tym przyczyna może być bardziej prozaiczna - jeśli masz jakieś inne przerwania które są kiepsko napisane, to blokują Ci to przerwanie i czasem jest po prostu gubisz. Ale tego nie wiemy, bo nie ma całości kodu.

    4\/3!!
  • #30
    ciastek4
    Level 14  
    Freddie Chopin wrote:
    przerwanie powinno być z atrybutem ((interrupt))

    oczywiście jest ten atrybut (i tylko ten), jednak nie w definicji tylko deklaracji. Wszystko w Twoim pliku vectors.c.
    Freddie Chopin wrote:

    a próby wpisywania wartości 0xFFFE do rejestru SR nie wydają mi się szczególnie mądre. W końcu rejestr ten ma kilka pól które są "reserved" więc nikt nie wie co robią, a poza tym ST pewnie zapomniało napisać, że jakieś tam bity można jednak pomieszać wpisując do rejestru jedynkę

    Ten przyklad jest zabrany/ przekopiowany z bliblioteki ST. Tą flagę kasuje się poprzez wpisanie 0. W pozostałych polach wpis 1 nie robi nic :). Trzeba zatem coś wpisać w ten rejestr i te pola reserved. Nota nic nie wspomina o tym co tam ma być wpisane.
    Freddie Chopin wrote:

    Poza tym przyczyna może być bardziej prozaiczna - jeśli masz jakieś inne przerwania które są kiepsko napisane, to blokują Ci to przerwanie i czasem jest po prostu gubisz. Ale tego nie wiemy, bo nie ma całości kodu.


    Owszem mam odblokowane jeszcze inne przerwanie. Od odbioru danych z UARTA4. Lecz nie ma tam niczego nadzwyczajnego co by blokowało przerwanie. Zwłaszcza, że w chwili gdy nie odbieram danych problem ten nadal występuje.
    Oba przerwania mają ten sam priorytet.