haki 0 28 февраля, 2014 Опубликовано 28 февраля, 2014 · Жалоба Получалось ли у кого либо менять значение 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 14 28 февраля, 2014 Опубликовано 28 февраля, 2014 · Жалоба Вот так у меня работает: 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 0 28 февраля, 2014 Опубликовано 28 февраля, 2014 · Жалоба Вот так у меня работает: 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 14 28 февраля, 2014 Опубликовано 28 февраля, 2014 · Жалоба Код правильный, комментарий - нет:) если я правильно понял документацию, то прелоад надо разрешать, чтоб он в теневой регистр писал только по Update Event а не на середине пути, т.е. теневой регистр не должен влиять на то что из регистра предзагрузки данные скопируются в теневой при событии. Вам же не нужно чтоб по событию, вам нужно сразу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haki 0 28 февраля, 2014 Опубликовано 28 февраля, 2014 · Жалоба И по событию, и сразу, я пробовал все возможные варианты, даже те которые по логике не должны работать. и естественно ничего не работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 28 февраля, 2014 Опубликовано 28 февраля, 2014 · Жалоба Почему "естественно"? У меня всё работает:) Вот код инициализации: // 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 0 28 февраля, 2014 Опубликовано 28 февраля, 2014 · Жалоба Почему "естественно"? У меня всё работает :) естественно, потому что пишу на форум, если бы заработало, я бы не тревожил форум. вот в чём разница: у вас С++ у меня Си; у вас похоже win у меня linux; у вас среда разработки и компилятор от производителя, у меня "почти самодельный" gcc arm none eabi; библиотека у меня libopencm3, которой похоже никто не пользуется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 1 марта, 2014 Опубликовано 1 марта, 2014 · Жалоба С чего вы взяли, что у меня 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 сразу после записи. Поэтому я сразу вам посоветовал: Попробуйте убрать timer_enable_oc_preload( TIMER, TIM_OC1 ); А вы, вместо того, чтобы попробовать, начали придираться к комментариям в моём примере:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haki 0 2 марта, 2014 Опубликовано 2 марта, 2014 · Жалоба я не придираюсь, а пытаюсь найти причину, и пишу больше инфы, которая на мой взгляд может иметь значение. я пробовал убирать timer_enable_oc_preload, я даже пробовал использовать timer_disable_oc_preload. но МК ведёт себя не так как я хочу. >> а потому что вы не читаете документацию я эту документацию уже вдоль и поперёк прочитал, и очень удивляюсь не работоспособности примера. а какую вы библиотеку используете ? про С++ я подумал из-за конструкции TIM3->CR1 = 0; не помню чтоб в Си было ->, это вроде только у С++. >> то новое значение в CCR1 запишется только при переполнении таймера или при вызове "события обновления" из проги. что в общем то тоже должно работать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться