Дэнниф
Пн, 09 октября 2017 г. 12:03
Я написал быструю часть для цепочки двух 16-битных таймеров здесь: https: // dannyelectronics.WordPress.ком/ ... It-timers/
соответствующая часть кода здесь:
соответствующая часть кода здесь:
//initialize tim23 as a synchronized 32-bit timer
//tim2 as master / prescaler to tim3 / lsw of the 32-bit timer
//tim3 as slave / msw of the 32-bit timer
void tim23_init(uint16_t ps) {
//initialize tim2 as master
//enable clock to tim2
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN |
0x00;
//stop the timer to configure it
TIM2->CR1 &=~TIM_CR1_CEN; //clear cen. 0=disable the timer, 1=enable the timer
TIM2->CR1 &=~TIM_CR1_CKD; //clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
TIM2->CR1 &=~TIM_CR1_DIR; //clear DIR bit. 0=upcounter, 1=downcounter
TIM2->CR1 &=~TIM_CR1_OPM; //clear opm bit. 0=periodic timer, 1=one-shot timer
//or to simply zero the register
//TIMx->CR1 = 0; //much easier
TIM2->CR2 = 0x20; //MMS = 0b010->tim2 as prescaler
//source from internal clock -> disable slave mode
TIM2->SMCR &=~TIM_SMCR_SMS; //clear sms->master mode and use internal clock
//clear the status register bits for capture / compare flags
TIM2->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_UIF);
//disable the interrupt by clearing the enable bits
TIM2->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE | TIM_DIER_UIE);
//set the prescaler
TIM2->PSC = ps - 1; //set the prescaler to ps
TIM2->RCR = 0; //repetition counter = 0 (=no repetition)
//user can specify a prescaler here. otherwise use 0xffff
TIM2->ARR = 0xffff; //auto reload register / period = 0; - need to change for downcounters
TIM2->CNT = 0; //reset the counter
//enable the timer.
TIM2->CR1 |= TIM_CR1_CEN; //enable the timer
//initialize tim3 as slave
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN |
0x00;
//stop the timer to configure it
TIM3->CR1 &=~TIM_CR1_CEN; //clear cen. 0=disable the timer, 1=enable the timer
TIM3->CR1 &=~TIM_CR1_CKD; //clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
TIM3->CR1 &=~TIM_CR1_DIR; //clear DIR bit. 0=upcounter, 1=downcounter
TIM3->CR1 &=~TIM_CR1_OPM; //clear opm bit. 0=periodic timer, 1=one-shot timer
//or to simply zero the register
//TIMx->CR1 = 0; //much easier
//source from internal clock -> disable slave mode
TIM3->SMCR &=~TIM_SMCR_SMS; //clear sms->master mode and use internal clock
//clear the status register bits for capture / compare flags
TIM3->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_UIF);
//disable the interrupt by clearing the enable bits
TIM3->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE | TIM_DIER_UIE);
//set the prescaler
TIM3->PSC = 0; //set the prescaler to 1:1 - master timer acts as prescaler
TIM3->RCR = 0; //repetition counter = 0 (=no repetition)
TIM3->ARR = 0xffff; //auto reload register / period = 0; - need to change for downcounters
TIM3->CNT = 0; //reset the counter
//enable the timer.
TIM3->CR1 |= TIM_CR1_CEN; //enable the timer
//source from trgo -> enable slave mode and trigger on trgo
TIM3->SMCR = (TIM3->SMCR &~((0x07 << 4) | 0x07)) |
(0x01 << 4) | //tab 71: 0b001->//slave tim3 driven by tim2
(0x07 << 0) | //0b111->external trigger on trgo
0x00;
}
uint32_t tmr23_get(void) {
uint16_t msw, lsw; //timer's high/low words
//double read to maintain atomicity
do {
msw = TIM3->CNT; //read the msw
lsw = TIM2->CNT; //read the lsw
} while (msw != TIM3->CNT); //see if overflow has taken place
return (msw << 16) | lsw; //return 32-bit time
}
Стивестронг
Пн, 09 октября 2017 г. 12:15
[Дэнниф - Пн, 09 октября 2017 12:03] -
uint32_t tmr23_get(void) {
uint16_t msw, lsw; //timer's high/low words
//double read to maintain atomicity
do {
msw = TIM3->CNT; //read the msw
lsw = TIM2->CNT; //read the lsw
} while (msw == TIM3->CNT); //see if overflow has taken place
return (msw << 16) | lsw; //return 32-bit time
}
Дэнниф
Пн, 09 октября 2017 г. 12:59
Вы правы. мой плохой.
Стивестронг
Пн, 09 октября 2017 г. 13:23
Без проблем. Я исправил это в вашем первоначальном посте, если это хорошо для вас.
Дэнниф
Пн, 09 октября 2017 г. 13:33
не проблема. Спасибо.
Дэнниф
Пн, 09 октября 2017 г. 20:19
Вот другой подход: 32-битный входной захват с использованием одного 16-битного таймера.
https: // dannyelectronics.WordPress.ком/ ... бит-timer/
Протестировано на STM32F100, но также должен работать на 103.
https: // dannyelectronics.WordPress.ком/ ... бит-timer/
Протестировано на STM32F100, но также должен работать на 103.
Ddrown
Пн, 09 октября 2017 г. 20:36
У меня также есть немного другой способ сделать это (используя HAL):
uint32_t get_counters() {
uint16_t tim2_before, tim1, tim2_after;
tim2_before = __HAL_TIM_GET_COUNTER(&htim2);
tim1 = __HAL_TIM_GET_COUNTER(&htim1);
tim2_after = __HAL_TIM_GET_COUNTER(&htim2);
if(tim2_before != tim2_after) {
if(tim1 > 60000) { // allow for ~5000 cycles between tim2_before/tim2_after - beware of long interrupt handlers
tim2_after = tim2_before;
}
}
return ((uint32_t)tim2_after) << 16 | tim1;
}
Дэнниф
Пн, 09 октября 2017 г., 21:02
более чем один способ сделать то же самое,
Спасибо.
Спасибо.
Ddrown
Пн, 09 октября 2017 г., 22:45
[Дэнниф - Пн, 09 октября 2017 г. 9:02 вечера] - более чем один способ сделать то же самое,Это очень правда!
Дэнниф
Пн, 09 октября 2017 г. 11:58
Я реализовал ту же концепцию на Atmega8/8L "Ghetto Chrono": https: // github.com/dannyf00/ghetto-chro ... ER/ATMEGA8
это сработало хорошо.
это сработало хорошо.
vitor_boss
Пн 19 февраля 2018 г., 21:15
Я сделал 32 -битный таймер для картинки, используя флаг переполнения таймера, он используется только для того, чтобы захватить период импульса и ширину. Работает отлично.
Если у тебя есть идея не сложно. Но если захочу код, просто процитируйте это
Если у тебя есть идея не сложно. Но если захочу код, просто процитируйте это
Арпрос
Пт 23 февраля 2018 г., 18:37
Обычно я просто время с счетчиком цикла DWT. Это 32-битное, высокое разрешение (по одному циклу на счет; при 72 МГц он может рассчитывать примерно до 59 секунд до переполнения) и работает с включенными или отключенными прерываниями, что приятно для точного битового графика. Стоимость состоит в том, что это немного замедляет (10-15%?) Когда вы включите это.
Пример:
Пример:
#include // https://github.com/arpruss/gamecube-usb-adapter/blob/master/dwt.h
void setup() {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= 1;
}
void pulsePinForCycles(unsigned pin, unsigned value, unsigned cycles) {
nvic_globalirq_disable(); // for greater precision
unsigned reversedValue = !value;
digitalWrite(pin,value); // use direct register manipulation for greater precision
DWT->CYCCNT = 0;
while (DWT->CYCCNT < cycles) ;
digitalWrite(pin,reversedValue);
nvic_globalirq_enable();
}
fpistm
Сб 24 февраля 2018 г. 8:14
[Арпрос - Пт. 23 февраля 2018 г. 18:37] - Стоимость состоит в том, что это немного замедляет (10-15%?) Когда вы включите это.Это кажется немного высоким, как замедление для аппаратного счетчика
Дэнниф
Сб 24 февраля 2018 12:17
Стоимость состоит в том, что это немного замедляет (10-15%?) Когда вы включите это.
Я никогда не испытывал этого замедления. Это аппаратный счетчик, который всегда есть, без участия процессора в его операциях. Так сложно представить причину, что это замедлит оставшуюся часть чипа.
fpistm
Сб 24 февраля 2018 г. 15:34
Я согласен с Дэннифом.
Арпрос
Солнце 25 февраля 2018 г., 3:48
Я думал, что видел небольшое замедление в тесте. Но я не вижу этого сейчас. Я был неправ.
Я также замечаю, что счетчик CYCCNT активен по умолчанию в ядре. Можно отключить, но это не имеет разницы в скорости.
Я также замечаю, что счетчик CYCCNT активен по умолчанию в ядре. Можно отключить, но это не имеет разницы в скорости.
Дэнниф
Ср. 04 июля 2018 г. 13:00
Та же самая логика может быть применена к цепочке других таймеров, таких как TIM15/16/17.
//initialize TIM1615 as a synchronized 32-bit timer
//tim16 as master / lsw (including prescaler) to tim15 / msw of the 32-bit timer
//tim15 as slave / msw of the 32-bit timer
void tim1615_init(uint16_t ps) {
//initialize TIM16 as master
//enable clock to TIM16
RCC->APB2ENR |= RCC_APB2ENR_TIM16EN |
0x00;
//stop the timer to configure it
TIM16->CR1 &=~TIM_CR1_CEN; //clear cen. 0=disable the timer, 1=enable the timer
TIM16->CR1 &=~TIM_CR1_CKD; //clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
TIM16->CR1 &=~TIM_CR1_DIR; //clear DIR bit. 0=upcounter, 1=downcounter
TIM16->CR1 &=~TIM_CR1_OPM; //clear opm bit. 0=periodic timer, 1=one-shot timer
//or to simply zero the register
//TIMx->CR1 = 0; //much easier
//CR2 on TIM16/17 doesn't exist -> the following statement has no effect
//thus it doesn't work
TIM16->CR2 = 0x20; //MMS = 0b010->TIM16 as prescaler
//alternative: set up OC1 as the TRGO signal
TIM16->CCER&=~TIM_CCER_CC1E; //0->disable cc1, 1->enable cc1
//disable cc1e to change ccmr1
//TIM16->CCMR1&=~(0x03<<0); //0->CC1 as output
TIM16->CCMR1= 0x06<<4; //1->oc1ref high on match, 3->oc1ref flip on match, 6->pwm mode 1(
TIM16->CCER|= TIM_CCER_CC1E; //0->disable cc1, 1->enable cc1
//TIM16->EGR = TIM_EGR_UG | TIM_EGR_CC1G; //force an update
TIM16->CCR1= 0xffff; //set the match point: anything but 0
TIM16->BDTR|= TIM_BDTR_MOE; //1->set MOE
//source from internal clock -> disable slave mode
TIM16->SMCR &=~TIM_SMCR_SMS; //clear sms->master mode and use internal clock
//clear the status register bits for capture / compare flags
TIM16->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_UIF);
//disable the interrupt by clearing the enable bits
TIM16->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE | TIM_DIER_UIE);
//set the prescaler
TIM16->PSC = ps - 1; //set the prescaler to ps
TIM16->RCR = 0; //repetition counter = 0 (=no repetition)
//user can specify a prescaler here. otherwise use 0xffff
TIM16->ARR = 0xffff; //auto reload register / period = 0; - need to change for downcounters
TIM16->CNT = 0; //reset the counter
//enable the timer.
//TIM16->CR1 |= TIM_CR1_CEN; //enable the timer
//initialize TIM15 as slave
RCC->APB2ENR |= RCC_APB2ENR_TIM15EN |
0x00;
//stop the timer to configure it
TIM15->CR1 &=~TIM_CR1_CEN; //clear cen. 0=disable the timer, 1=enable the timer
TIM15->CR1 &=~TIM_CR1_CKD; //clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
TIM15->CR1 &=~TIM_CR1_DIR; //clear DIR bit. 0=upcounter, 1=downcounter
TIM15->CR1 &=~TIM_CR1_OPM; //clear opm bit. 0=periodic timer, 1=one-shot timer
//or to simply zero the register
//TIMx->CR1 = 0; //much easier
//source from internal clock -> disable slave mode
TIM15->SMCR &=~TIM_SMCR_SMS; //clear sms->master mode and use internal clock
//clear the status register bits for capture / compare flags
TIM15->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_UIF);
//disable the interrupt by clearing the enable bits
TIM15->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE | TIM_DIER_UIE);
//set the prescaler
TIM15->PSC = 0; //set the prescaler to 1:1 - master timer acts as prescaler
TIM15->RCR = 0; //repetition counter = 0 (=no repetition)
TIM15->ARR = 0xffff; //auto reload register / period = 0; - need to change for downcounters
TIM15->CNT = 0; //reset the counter
TIM15->EGR = TIM_EGR_UG; //force an update
//source from trgo -> enable slave mode and trigger on trgo
TIM15->SMCR = (TIM15->SMCR &~((0x07 << 4) | (0x07 << 0))) |
(0x02 << 4) | //tab 74: 0b010->//slave TIM15 driven by TIM16
(0x07 << 0) | //0b111->external trigger on trgo
(1<<7) | //set sms
0x00;
//enable the timer.
TIM15->CR1 |= TIM_CR1_CEN; //enable the timer
//enable the timer.
TIM16->CR1 |= TIM_CR1_CEN; //enable the timer
}
Дэнниф
Ср. 04 июля 2018 г. 13:04
Во многих чипах STM32 некоторые таймеры могут действовать как мастер, так и рабыни. Таким образом, можно объединить более 2 таймеров, чтобы сформировать 48-битные композитные таймеры (3 x 16-битные таймеры) или 64-битные композитные таймеры (4 x 16-битные таймеры). или даже больше.
Не уверен в их приложениях, но это довольно аккуратно.
Не уверен в их приложениях, но это довольно аккуратно.
Дэнниф
Ср. 04 июля 2018 г. 20:17
Вот пример реализации 48-битных таймеров путем цепочки TIM2->Тим3->TIM4:
//initialize tim2/3/4 as a synchronized 32-bit timer
//tim2 as master / lsw (including prescaler) to tim3 / msw of the 48-bit timer
//tim3 as slave/master / middle word of the 48-bit timer
//tim4 as slave / msw word of the 48-bit timer
void tim234_init(uint16_t ps) {
//initialize tim2 as master
//enable clock to tim2
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN |
0x00;
//stop the timer to configure it
TIM2->CR1 &=~TIM_CR1_CEN; //clear cen. 0=disable the timer, 1=enable the timer
TIM2->CR1 &=~TIM_CR1_CKD; //clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
TIM2->CR1 &=~TIM_CR1_DIR; //clear DIR bit. 0=upcounter, 1=downcounter
TIM2->CR1 &=~TIM_CR1_OPM; //clear opm bit. 0=periodic timer, 1=one-shot timer
//or to simply zero the register
//TIMx->CR1 = 0; //much easier
TIM2->CR2 = 0x20; //MMS = 0b010->tim2 as prescaler
//source from internal clock -> disable slave mode
TIM2->SMCR &=~TIM_SMCR_SMS; //clear sms->master mode and use internal clock
//clear the status register bits for capture / compare flags
TIM2->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_UIF);
//disable the interrupt by clearing the enable bits
TIM2->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE | TIM_DIER_UIE);
//set the prescaler
TIM2->PSC = ps - 1; //set the prescaler to ps
TIM2->RCR = 0; //repetition counter = 0 (=no repetition)
//user can specify a prescaler here. otherwise use 0xffff
TIM2->ARR = 0xffff; //auto reload register / period = 0; - need to change for downcounters
TIM2->CNT = 0; //reset the counter
//enable the timer.
//TIM2->CR1 |= TIM_CR1_CEN; //enable the timer
//enable clock to tim3
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN |
0x00;
//stop the timer to configure it
TIM3->CR1 &=~TIM_CR1_CEN; //clear cen. 0=disable the timer, 1=enable the timer
TIM3->CR1 &=~TIM_CR1_CKD; //clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
TIM3->CR1 &=~TIM_CR1_DIR; //clear DIR bit. 0=upcounter, 1=downcounter
TIM3->CR1 &=~TIM_CR1_OPM; //clear opm bit. 0=periodic timer, 1=one-shot timer
//or to simply zero the register
//TIMx->CR1 = 0; //much easier
TIM3->CR2 = 0x20; //MMS = 0b010->tim2 as prescaler
//source from internal clock -> disable slave mode
TIM3->SMCR &=~TIM_SMCR_SMS; //clear sms->master mode and use internal clock
//clear the status register bits for capture / compare flags
TIM3->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_UIF);
//disable the interrupt by clearing the enable bits
TIM3->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE | TIM_DIER_UIE);
//set the prescaler
TIM3->PSC = 0; //set the prescaler to ps
TIM3->RCR = 0; //repetition counter = 0 (=no repetition)
//user can specify a prescaler here. otherwise use 0xffff
TIM3->ARR = 0xffff; //auto reload register / period = 0; - need to change for downcounters
TIM3->CNT = 0; //reset the counter
//source from trgo -> enable slave mode and trigger on trgo
TIM3->SMCR = (TIM3->SMCR &~((0x07 << 4) | (0x07 << 0))) |
(0x01 << 4) | //tab 71: 0b001->//slave tim3 driven by tim2
(0x07 << 0) | //0b111->external trigger on trgo
0x00;
//enable the timer.
//TIM2->CR1 |= TIM_CR1_CEN; //enable the timer
//initialize tim4 as slave
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN |
0x00;
//stop the timer to configure it
TIM4->CR1 &=~TIM_CR1_CEN; //clear cen. 0=disable the timer, 1=enable the timer
TIM4->CR1 &=~TIM_CR1_CKD; //clear CKD0..1. 0b00->1x clock; 0b01->2:1 clock, 0b10->4:1 clk; 0b11->reserved
TIM4->CR1 &=~TIM_CR1_DIR; //clear DIR bit. 0=upcounter, 1=downcounter
TIM4->CR1 &=~TIM_CR1_OPM; //clear opm bit. 0=periodic timer, 1=one-shot timer
//or to simply zero the register
//TIMx->CR1 = 0; //much easier
//source from internal clock -> disable slave mode
TIM4->SMCR &=~TIM_SMCR_SMS; //clear sms->master mode and use internal clock
//clear the status register bits for capture / compare flags
TIM4->SR &=~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF | TIM_SR_UIF);
//disable the interrupt by clearing the enable bits
TIM4->DIER &=~(TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE | TIM_DIER_UIE);
//set the prescaler
TIM4->PSC = 0; //set the prescaler to 1:1 - master timer acts as prescaler
TIM4->RCR = 0; //repetition counter = 0 (=no repetition)
TIM4->ARR = 0xffff; //auto reload register / period = 0; - need to change for downcounters
TIM4->CNT = 0; //reset the counter
//enable the timer.
//TIM4->CR1 |= TIM_CR1_CEN; //enable the timer
//source from trgo -> enable slave mode and trigger on trgo
TIM4->SMCR = (TIM4->SMCR &~((0x07 << 4) | (0x07 << 0))) |
(0x02 << 4) | //tab 71: 0b010->//slave tim4 driven by tim3
(0x07 << 0) | //0b111->external trigger on trgo
0x00;
//enable the timer: MSW first, and LSW last
TIM4->CR1 |= TIM_CR1_CEN; //enable the timer
TIM3->CR1 |= TIM_CR1_CEN; //enable the timer
TIM2->CR1 |= TIM_CR1_CEN; //enable the timer
}