Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F103; libopencm3; timer; compare registr
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
haki
Получалось ли у кого либо менять значение Capture/compare 1 register в обработчике прерывания? предположим для второго таймера.

Обязательно ли указывать значение в регистр авто перезаписи ? (counter counts from 0 to the auto-reload value (content of the
TIMx_ARR register)

Уже несколько месяцев танцы с бубном не приводят к изменению значения в Capture/compare 1 register в обработчике прерывания.

Имеет ли смысл пробовать писать напрямую по адресам в стиле:
*((uint32_t volatile *)0xE000ED04) = 0x10000000; ?


прикладываю кусок кода если кому не лень подумать.

1 #include <libopencm3/stm32/rcc.h>
2 #include <libopencm3/stm32/gpio.h>
3 #include <libopencm3/stm32/flash.h>
4 #include <libopencm3/stm32/exti.h>
5 #include <libopencm3/stm32/timer.h>
6
7 #include <libopencm3/cm3/scb.h>
8 #include <libopencm3/cm3/nvic.h>
9 //#include <libopencm3/cm3/systick.h>
10 //#include <libopencm3/cm3/cortex.h>
11

23 #define PIN GPIO0
24
25
26 #define PORT GPIOB
27 #define RCC_RORT RCC_APB2ENR_IOPBEN
28
29 // для удобства изменения номера таймера , ключевые слова вытащены наверх.
30 #define TIMER TIM2
31 #define TIM_ISR tim2_isr
32 #define NVIC NVIC_TIM2_IRQ
33 #define RCC_TIMER RCC_APB1ENR_TIM2EN
34 #define NVIC_CLOCK_TIMER NVIC_TIM2_IRQ
35
36
37 #define TIMER_PRSC 7200
38
39
40 #define barrier() do { __asm__ __volatile__ (""); } while (0)
41
42
43 uint16_t G_COMPARE_TIME = 10000;
44
45
46
47
48
49 void TIM_ISR( void )
50 {
51 if ( !( timer_get_flag( TIMER, TIM_SR_CC1IF )))
52 return;
53
54 timer_clear_flag( TIMER, TIM_SR_CC1IF );
55
56
57 G_COMPARE_TIME = timer_get_counter( TIMER );
58 G_COMPARE_TIME += 1000;
59
60 timer_set_oc_value( TIMER, TIM_OC1, G_COMPARE_TIME );
61
62 gpio_toggle( PORT, PIN );
63 }
64
65
66
67
68
69
70
71 int main(void)
72 {
73 extern uint32_t vector_table __asm__( "vector_table" );
74 SCB_VTOR = ( uint32_t ) &vector_table;
75
76 // - - - - - - - - -
77
78 rcc_clock_setup_in_hse_8mhz_out_72mhz();
79
80 rcc_peripheral_enable_clock( &RCC_APB1ENR, RCC_TIMER );
81 rcc_peripheral_enable_clock( &RCC_APB2ENR, RCC_RORT );
82
83
84 // - - - - - - - - -
85
86 gpio_set( PORT, PIN );
87
88 gpio_set_mode( PORT
89 , GPIO_MODE_OUTPUT_2_MHZ
90 , GPIO_CNF_OUTPUT_PUSHPULL
91 , PIN );
92
93 // - - - - - - - - -
94
95
96 timer_reset( TIMER );
97
98 timer_set_prescaler( TIMER, TIMER_PRSC );
99
100
101 timer_set_mode( TIMER
102 , TIM_CR1_CKD_CK_INT
103 , TIM_CR1_CMS_EDGE
104 , TIM_CR1_DIR_UP );
105
106
107 timer_continuous_mode( TIMER );
108
109 timer_enable_update_event( TIMER );
110
111 timer_set_dma_on_compare_event( TIMER ); // check TODO
112 timer_set_dma_on_update_event( TIMER ); // chech TODO
113
114
115 timer_set_oc_slow_mode( TIMER, TIM_OC1 );
116
117
118 timer_set_period( TIMER, 65535 ); // auto-reload register.
119
120
121 timer_disable_oc_clear( TIMER, TIM_OC1 );
122 timer_disable_oc_clear( TIMER, TIM_OC2 );
123 timer_disable_oc_clear( TIMER, TIM_OC3 );
124 timer_disable_oc_clear( TIMER, TIM_OC4 );
125
126 timer_disable_oc_output( TIMER, TIM_OC1 );
127 timer_disable_oc_output( TIMER, TIM_OC2 );
128 timer_disable_oc_output( TIMER, TIM_OC3 );
129 timer_disable_oc_output( TIMER, TIM_OC4 );
130
131 timer_enable_oc_preload( TIMER, TIM_OC1 );
132
133
134 timer_set_oc_value( TIMER, TIM_OC1, G_COMPARE_TIME );
135
136 timer_set_oc_mode( TIMER
137 , TIM_OC1
138 , TIM_OCM_ACTIVE // the output assumes the active state
139 // on the first match.
140 );
141
142
143
144
145
146 timer_enable_irq( TIMER, TIM_DIER_CC1IE );
147 timer_enable_irq( TIMER, TIM_DIER_UIE );
148
149 // - - - - - - - - -
150
151
152 nvic_set_priority( NVIC_CLOCK_TIMER, 2 );
153 nvic_enable_irq( NVIC );
154
155 timer_enable_counter( TIMER );
156
157 // - - - - - - - - -
158 while( 1 )
159 barrier();
160
161 return 0;
162 }
AHTOXA
Вот так у меня работает:
Код
void TIM3_IRQHandler(void)
{
    if (TIM3->SR & TIM_SR_CC3IF)
    {
        TIM3->SR = ~TIM_SR_CC3IF; // clear cc1 interrupt flag by writing 0
        TIM3->CCR3 += 500;
        // какие-то действия...
    }
}

Попробуйте убрать timer_enable_oc_preload( TIMER, TIM_OC1 );
haki
Цитата(AHTOXA @ Feb 28 2014, 10:00) *
Вот так у меня работает:
Код
void TIM3_IRQHandler(void)
{
     if (TIM3->SR & TIM_SR_CC3IF)
     {
         TIM3->SR = ~TIM_SR_CC3IF; // clear cc1 interrupt flag by writing 0
         TIM3->CCR3 += 500;
         // какие-то действия...
     }
}

Попробуйте убрать timer_enable_oc_preload( TIMER, TIM_OC1 );


весёлый у вас код, в коде TIM_SR_CC3IF; в коментах clear cc1;

если я правильно понял документацию, то прелоад надо разрешать, чтоб он в теневой регистр писал только по Update Event а не на середине пути, т.е. теневой регистр не должен влиять на то что из регистра предзагрузки данные скопируются в теневой при событии.
AHTOXA
Код правильный, комментарий - нетsm.gif
Цитата(haki @ Feb 28 2014, 11:20) *
если я правильно понял документацию, то прелоад надо разрешать, чтоб он в теневой регистр писал только по Update Event а не на середине пути, т.е. теневой регистр не должен влиять на то что из регистра предзагрузки данные скопируются в теневой при событии.

Вам же не нужно чтоб по событию, вам нужно сразу.
haki
И по событию, и сразу, я пробовал все возможные варианты, даже те которые по логике не должны работать. и естественно ничего не работает.
AHTOXA
Почему "естественно"? У меня всё работаетsm.gif
Вот код инициализации:

Код
    // enable timer clocks
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;

    // set up interrupt
    NVIC_SetPriority(TIM3_IRQn, 2);
    NVIC_EnableIRQ(TIM3_IRQn);

    // set up timer
    TIM3->CR1 = 0; // count up to ARR, no divisor
    TIM3->ARR = 0xFFFF; // period (full scale)
    TIM3->PSC = 0; // no prescaler

    // generate an update event to load the PSC and ARR values immediately
    TIM3->EGR = TIM_EGR_UG;

    // Set up compare channel 3 for periodic interrupt
    // disable CC3
    TIM3->CCER &= ~TIM_CCER_CC3E;
    // configure CC3 to compare mode, disable output
    TIM3->CCMR2 &= 0xFF00;
    // set CCR to get interrupt after 500 ticks
    TIM3->CCR3 += 500;
    // enable CC1 interrupt
    TIM3->DIER |= TIM_DIER_CC3IE;

    // run timer
    TIM3->CR1 |= TIM_CR1_CEN;

Код обработчика я уже привёл.
haki
Цитата(AHTOXA @ Feb 28 2014, 12:46) *
Почему "естественно"? У меня всё работает sm.gif


естественно, потому что пишу на форум, если бы заработало, я бы не тревожил форум.
вот в чём разница:
у вас С++ у меня Си;
у вас похоже win у меня linux;
у вас среда разработки и компилятор от производителя, у меня "почти самодельный" gcc arm none eabi;
библиотека у меня libopencm3, которой похоже никто не пользуется.
AHTOXA
С чего вы взяли, что у меня c++?
Насчёт линукса снова промашка.
И компилятор у меня тоже arm-none-eabi-gcc !
Вот насчёт libopencm3 - да, тут у нас с вами наблюдается различие. Но не работает у вас не из-за libopencm3, а потому что вы не читаете документацию.
Давайите я вам помогу.
Судя по названию, функция timer_enable_oc_preload(TIMER, TIM_OC1) включает бит OC1PE в регистре CCMR1. Вот что написано про этот бит:
Цитата
0: Preload register on TIMx_CCR1 disabled. TIMx_CCR1 can be written at anytime, the new value is taken in account immediately.
1: Preload register on TIMx_CCR1 enabled. Read/Write operations access the preload register. TIMx_CCR1 preload value is loaded in the active register at each update event.

Видите, если он взведён, то ваша функция timer_set_oc_value(), вызываемая в прерывании, произведёт запись не в нужный вам регистр CCR1, а в теневой регистр. Значение из теневого регистра попадёт в CCR1 только при событии UPDATE. Давайте почитаем, когда происходит это событие:
Цитата
The update event is sent when the counterreaches the overflow (or underflow when downcounting) and if the UDIS bit equals 0 in the TIMx_CR1 register. It can also be generated by software.

Во как. То есть, если сделать так, как сделали вы, то новое значение в CCR1 запишется только при переполнении таймера. Насколько я понял, вам надо наоборот, чтобы новое значение попадало в CCR1 сразу после записи. Поэтому я сразу вам посоветовал:
Цитата(AHTOXA @ Feb 28 2014, 11:00) *
Попробуйте убрать timer_enable_oc_preload( TIMER, TIM_OC1 );

А вы, вместо того, чтобы попробовать, начали придираться к комментариям в моём примереsm.gif
haki
я не придираюсь, а пытаюсь найти причину, и пишу больше инфы, которая на мой взгляд может иметь значение.
я пробовал убирать timer_enable_oc_preload, я даже пробовал использовать timer_disable_oc_preload.
но МК ведёт себя не так как я хочу.

>> а потому что вы не читаете документацию

я эту документацию уже вдоль и поперёк прочитал, и очень удивляюсь не работоспособности примера.

а какую вы библиотеку используете ?

про С++ я подумал из-за конструкции TIM3->CR1 = 0; не помню чтоб в Си было ->, это вроде только у С++.

>> то новое значение в CCR1 запишется только при переполнении таймера

или при вызове "события обновления" из проги. что в общем то тоже должно работать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.