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

[STM32] Przerwania, timery

onicram 04 Dec 2009 15:56 6447 10
  • #1
    onicram
    Level 10  
    Witam,

    Zacząłem niedawno zabawę z STM32 i mam problem z przerwaniami oraz timerami.

    Chciałem uruchomić przerwanie zewnętrzne, a dalej przerwanie od timera co np 1sek. Jednak nie działa ani jedno ani drugie, czy ktoś mógłby nakierować mnie na dobrą drogę i powiedzieć co robię źle? Przeglądałem przykładowe aplikacje jednak dalej nie potrafię tego uruchomić. Układ na jakim się bawię to STM32 Primer I.

    Przykładowy kod do uruchomienia przerwania zewnętrznego:
    
    /* Includes ------------------------------------------------------------------*/
    #include "stm32f10x_conf.h"
    
    
    /* Private typedef -----------------------------------------------------------*/
    /* Private define ------------------------------------------------------------*/
    /* Private macro -------------------------------------------------------------*/
    /* Private variables ---------------------------------------------------------*/
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStruct;
    EXTI_InitTypeDef EXTI_InitStruct;
    /* Private function prototypes -----------------------------------------------*/
    void RCC_Configuration(void);
    void NVIC_Configuration(void);
    
    
    /* Private functions ---------------------------------------------------------*/
    /*******************************************************************************
    * Function Name  : main
    * Description    : Main program.
    * Input          : None
    * Output         : None
    * Return         : None
    *******************************************************************************/
    int main(void)
    {
    #ifdef DEBUG
      debug();
    #endif
    
    /* System Clocks Configuration */
      RCC_Configuration();
    
      /* NVIC Configuration */
      NVIC_Configuration();
    
      /* Enable GPIOB clock */
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
      /* Configure PE.12, PE.11, PE.10 and PE.09 i PE.08 as INPUT FLOATING */
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_0;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
    
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
      /* Configure PE.14, PE.15 as output push-pull */
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
     
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
      
      NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
      NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStruct);
      
      GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
      
      EXTI_InitStruct.EXTI_Line = EXTI_Line0;
      EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
      EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
      EXTI_InitStruct.EXTI_LineCmd = ENABLE;
      EXTI_Init(&EXTI_InitStruct);
      
      
      while(1)
       {
    
       }   
    }
    
    /*******************************************************************************
    * Function Name  : RCC_Configuration
    * Description    : Configures the different system clocks.
    * Input          : None
    * Output         : None
    * Return         : None
    *******************************************************************************/
    void RCC_Configuration(void)
       {
       /* RCC system reset(for debug purpose) */
       RCC_DeInit();
    
       /* Enable HSE */
       RCC_HSEConfig(RCC_HSE_ON);
    
       /* Wait till HSE is ready */
      while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
    
             {;}  
    
       /* Enable Prefetch Buffer */
       FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
       /* Flash 2 wait state */
       FLASH_SetLatency(FLASH_Latency_2);
    
       /* HCLK = SYSCLK */
       RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    
       /* PCLK2 = HCLK */
       RCC_PCLK2Config(RCC_HCLK_Div1); 
    
       /* PCLK1 = HCLK */
       RCC_PCLK1Config(RCC_HCLK_Div1);
    
       /* Select HSE as system clock source */
       RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
    
       /* Wait till HSE is used as system clock source */
       while(RCC_GetSYSCLKSource() != 0x04)
          {;}  
       }
    
    /*******************************************************************************
    * Function Name  : NVIC_Configuration
    * Description    : Configures Vector Table base location.
    * Input          : None
    * Output         : None
    * Return         : None
    *******************************************************************************/
    void NVIC_Configuration(void)
    {
    #ifdef  VECT_TAB_RAM  
      /* Set the Vector Table base location at 0x20000000 */ 
      NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
    #else  /* VECT_TAB_FLASH  */
      /* Set the Vector Table base location at 0x08000000 */ 
      NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    #endif
    }
    
    
    /*******************************************************************************
    * Function Name  : assert_failed
    * Description    : Reports the name of the source file and the source line number
    *                  where the assert error has occurred.
    * Input          : - file: pointer to the source file name
    *                  - line: assert error line source number
    * Output         : None
    * Return         : None
    *******************************************************************************/
    void assert_failed(u8* file, u32 line)
    { 
      /* User can add his own implementation to report the file name and line number,
         ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    
      /* Infinite loop */
      while (1)
      {
      }
    }
    
    


    Podprogram obsługi przerwania:
    
    void EXTI0_IRQHandler(void)
    {
      if(EXTI_GetITStatus(EXTI_Line0) != RESET)
         {
          GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction) ((1- GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0))));
          EXTI_ClearITPendingBit(EXTI_Line0);
         }
    }



    Gdy próbuje uruchomić przerwanie od jakiegoś timera również nie ma reakcji, rejestry ustawiają się poprawnie jednak licznik timera nic nie zlicza - kodu dotyczącego timera narazie nie podaje bo może sprawa się wyjaśni kiedy uruchomie przerwanie od zdarzenia zewnętrznego.

    W czym tkwi problem?
    Dzięki z góry za pomoc!
    Pozdrawiam
    Marcin
  • Helpful post
    #2
    Krauser
    Level 26  
    Trzeba dodatkowo włączyć taktowanie bloku przerwań. Wstaw np. zaraz przed while(1)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    Jak dojdziesz do timera to też dodatkowo trzeba włączyć taktowanie
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
  • #4
    onicram
    Level 10  
    Krauser wrote:
    Trzeba dodatkowo włączyć taktowanie bloku przerwań. Wstaw np. zaraz przed while(1)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    Jak dojdziesz do timera to też dodatkowo trzeba włączyć taktowanie
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);


    No wreszcie udało mi się uruchomić te przerwania zewnętrzne, brakowało właśnie tego taktowania. Domyślałem się że to może coś z taktowaniem, ale myślałem że przerwanie zewnętrzne nie dotyczy tego taktowania wyprowadzeń alternatywnych. Dzięki za pomoc!

    Co do Timerów to wiedziałem że trzeba dodatkowo uruchomić taktowanie, jednak mimo tego nie działało coś, ale jeszcze z tym po walczę.

    Jeszcze jedno małe pytanie, czy jeśli nie było uruchomione to taktowanie czy próba uruchomienia programowo funkcji obsługi przerwania tez nie bedzie działać?

    Pozdrawiam
    Marcin

    Dzięki i pozdrawiam!
  • #6
    onicram
    Level 10  
    Freddie Chopin wrote:
    Bez taktowania nic nie będzie działać. Funkcja zapisuje dane pod adresy które są wyłączone, więc możesz tam wpisywać co chcesz.!


    No to już wszystko jasne, dzięki za pomoc.

    Co do uruchomienia TIMERA to tez mi się udało, jednak mam jeszcze jeden problem z nim... mianowicie chciałbym uruchomić go w trybie porównywania, gdy chce zmienić opóźnienie wystąpienia przerwania (parametr: TIM_OCInitStructure.TIM_Pulse = 1000;) to nic sie nie dzieje, częstotliwość występowania przerwania się nie zmienia. Kiedy za to zmienie: TIM_TimeBaseStructure.TIM_Period = 65535; to częstotliwość występowania przerwania się zmienia.
    Nie wiem czy moje rozumowanie jest błędne czy mam złe ustawienia samego timera.

    Poniżej kod:

     
      NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
      NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStruct);
      
       /* TIM2 clock enable */
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
     /* Time base configuration */
      TIM_TimeBaseStructure.TIM_Period = 65535;
      TIM_TimeBaseStructure.TIM_Prescaler = 800;
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
      TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    
      /* Output Compare Toggle Mode configuration: Channel1 */
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 1000;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC1Init(TIM2, &TIM_OCInitStructure);
    
      TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
      TIM_ARRPreloadConfig(TIM2, ENABLE);
    
      TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
    
      TIM_Cmd(TIM2, ENABLE);
    


    Obsługa przerwania:
    
    void TIM2_IRQHandler(void)
    {
        if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
      {
       GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction) ((1- GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_8))));
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC1 );
      }
    }
    



    Czym różnią się tryby pracy kanałów porównywania opisane jako: Inactive, Active, Timing oraz Toggle?

    Dzieki za pomoc
    Pozdrawiam
  • #8
    onicram
    Level 10  
    Freddie Chopin wrote:
    Nie łaska poczytać datasheeta? Przecież tam to wszystko jest opisane...



    Dzięki kolego za pomoc, oczywiście poczytałem datasheeta zanim napisałem tego posta (niestety nie każdy umie perfekcyjnie język angielski), przeglądałem również przykładowe programy jakie udostępnia ST, poczytałem również książkę Krzysztofa Paprockiego, ale widocznie coś musiałem pomylić skoro coś nie działało. Dlatego poprosiłem o pomoc. Każdy kiedyś zaczyna...

    Pozdrawiam
    Marcin
  • #9
    onicram
    Level 10  
    Witam

    Nie chciałem zakładać nowego tematu więc dopiszę w tym. "Bawiłem" się trochę STM-em - aktualnie uruchamiam przetwornik ADC i mam pytanie do bardziej obeznanych ode mnie kolegów.

    Mianowicie udało mi się uruchomić jeden kanał przetwornika, tutaj nie było problemu. Kanał uruchomiłem w trybie ciągłego przetwarzania i tutaj odczyt wartości przetworzonej nie był problemem.

    Chciałem uruchomić teraz dwa kanały również w trybie ciągłym, włączyłem skanowanie uruchomiłem przetwornik i nie bardzo potrafię poradzić sobie z odczytem danych. W grupie regularnej przetwarzane są kanały jeden po drugim a dane w rejestrze są nadpisywane. Jak więc mam odczytać dane z kolejnych kanałów i by mieć pewność, że odczytana wartość to dany kanał. Oczywiście ustalana jest kolejność konwersji jednak jak odczytać dane. W dokumentacji nie wiem czy dobrze zrozumiałem, po każdej konwersji ustawiana jest flaga zakończenia konwersji, czy zatem sprawdzanie flagi zakończenia konwersji a następnie odczytanie wartości i tak z każdym kanałem to dobra metoda? niestety nie udało mi się w ten sposób odczytać danych.

    Mam przykłady gdzie wykonywane jest to za pomocą DMA, jednak ja chciałbym zrobić bez tego.


          ADC_SoftwareStartConvCmd(ADC1, ENABLE);
           while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
            ADCVal[0]=ADC_GetConversionValue(ADC1);
    
           while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
            ADCVal[1]=ADC_GetConversionValue(ADC1);


    Z góry dziękuje za pomoc.
    Pozdrawiam
    Marcin
  • #10
    cool_kuba
    Level 12  
    Mam pytanie w związku z zewnętrznymi przerwaniami.
    Czy można wykryć czy przerwanie zostało wywołane przez PA0 czy PB0 bo widzę że zostały tu one wrzucone do jednego "worka" w EXTI trochę to dziwne jako, że wcześniej bawiłem się atmegami. Jeśli się da to proszę o jakąś wskazówkę.
  • #11
    pawel_rad
    Level 11  
    jeśli flaga jest ustawiana po zakończeniu konwersji, to w trakcie pomiaru nie jest ona ustawiona, więc powinno być:

    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == 0);   // czekaj na koniec konwersji


    następnie odczyt, i tak w kółko…