Перейти к содержанию
    

STM32F103; libopencm3; timer; compare registr

Получалось ли у кого либо менять значение 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 }

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот так у меня работает:

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 );

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот так у меня работает:

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 а не на середине пути, т.е. теневой регистр не должен влиять на то что из регистра предзагрузки данные скопируются в теневой при событии.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Код правильный, комментарий - нет:)

если я правильно понял документацию, то прелоад надо разрешать, чтоб он в теневой регистр писал только по Update Event а не на середине пути, т.е. теневой регистр не должен влиять на то что из регистра предзагрузки данные скопируются в теневой при событии.

Вам же не нужно чтоб по событию, вам нужно сразу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И по событию, и сразу, я пробовал все возможные варианты, даже те которые по логике не должны работать. и естественно ничего не работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему "естественно"? У меня всё работает:)

Вот код инициализации:

 

    // 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;

Код обработчика я уже привёл.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему "естественно"? У меня всё работает :)

 

естественно, потому что пишу на форум, если бы заработало, я бы не тревожил форум.

вот в чём разница:

у вас С++ у меня Си;

у вас похоже win у меня linux;

у вас среда разработки и компилятор от производителя, у меня "почти самодельный" gcc arm none eabi;

библиотека у меня libopencm3, которой похоже никто не пользуется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С чего вы взяли, что у меня 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 );

А вы, вместо того, чтобы попробовать, начали придираться к комментариям в моём примере:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

я не придираюсь, а пытаюсь найти причину, и пишу больше инфы, которая на мой взгляд может иметь значение.

я пробовал убирать timer_enable_oc_preload, я даже пробовал использовать timer_disable_oc_preload.

но МК ведёт себя не так как я хочу.

 

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

 

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

 

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

 

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

 

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

 

или при вызове "события обновления" из проги. что в общем то тоже должно работать.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...