Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: STM32 - частотомер.

Пн мар 17, 2014 13:01:40

Не знаю расчехлится ли кто-то после 2 с лишним лет. Вот код для STM32F0-Discovery. Яркий пример прямого счета (насколько я понял).
Прерывание срабатывает, когда на 1 из 4ёх входов таймера приходит передний фронт. И считается [частота сигнала] = [частота таймера] / [сколько натикало за 1 период]
Примитивно, но работает. Так же работает пример от ST Timer_PWM_Input_mode
Спойлер
Код:
// STM32 TIM2 4 Channel Input Capture STM32F0-Discovery - sourcer32@gmail.com
 
#include "stm32f0xx.h"
#include "stm32f0_discovery.h"
 
//**************************************************************************************
 
void TIM2_Config(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_ICInitTypeDef        TIM_ICInitStructure;
 
  /* TIM2 Periph clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
 
  /* TIM2 Configuration */
  TIM_DeInit(TIM2);
 
  /* Time base configuration */
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz
  TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // Maximal, TIM2 is 32-bit counter
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
 
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // Rising/Falling/BothEdge
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
 
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
 
  /* TIM1 enable counter */
  TIM_Cmd(TIM2, ENABLE);
 
  /* Enable the CCx Interrupt Request */
  TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
}
 
//**************************************************************************************
 
volatile uint32_t Freq[4];
 
void TIM2_IRQHandler(void)
{
    uint32_t Current, Delta;
    static uint32_t Last[4];
     
  if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
    {
        /* Clear TIM2_CH1 Capture compare interrupt pending bit */
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
 
        Current = TIM_GetCapture1(TIM2);
        Delta = Current - Last[0];
        Last[0] = Current;
        if (Delta)
            Freq[0] = 1000000 / Delta; // 1MHz clock
         
        // ..
    }
     
  if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
    {
        /* Clear TIM2_CH2 Capture compare interrupt pending bit */
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
 
        Current = TIM_GetCapture2(TIM2);
        Delta = Current - Last[1];
        Last[1] = Current;
        if (Delta)
            Freq[1] = 1000000 / Delta; // 1MHz clock
         
        // ..
    }
     
  if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)
    {
        /* Clear TIM2_CH3 Capture compare interrupt pending bit */
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
 
        Current = TIM_GetCapture3(TIM2);
        Delta = Current - Last[2];
        Last[2] = Current;
        if (Delta)
            Freq[2] = 1000000 / Delta; // 1MHz clock
         
        // ..
    }
     
  if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)
    {
        /* Clear TIM2_CH4 Capture compare interrupt pending bit */
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
 
        Current = TIM_GetCapture4(TIM2);
        Delta = Current - Last[3];
        Last[3] = Current;
        if (Delta)
            Freq[3] = 1000000 / Delta; // 1MHz clock
         
        // ..
    }
}
 
//**************************************************************************************
 
void NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
 
  /* Enable and set TIM2 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
 
//**************************************************************************************
 
void GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
 
  /* GPIOA Periph clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
 
  /* Configure TIM2 input */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
  /* Connect TIM pins to AF2 */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_2); // TIM2_CH1 PA5
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_2); // TIM2_CH2 PA1
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_2); // TIM2_CH3 PA2
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_2); // TIM2_CH4 PA3
}
 
//**************************************************************************************
 
int main(void)
{
  NVIC_Config();
 
  GPIO_Config();
 
  TIM2_Config();
 
  while(1); /* Infinite loop */
}
взято тут

и вот еще очень хорошая статья
Последний раз редактировалось kybin Пн мар 17, 2014 14:21:19, всего редактировалось 2 раз(а).

Re: STM32 - частотомер.

Пн мар 17, 2014 13:05:10

У STM32F407 есть "3×12-bit, 2.4 MSPS A/D converters: up to 24 channels and 7.2 MSPS in triple interleaved mode", то есть скорости более чем достаточно для того, чтобы считывать сигнал частотой 100КГц. Тактовой частоты тоже более чем достаточно, чтобы обрабатывать этот сигнал в реальном времени.

Re: STM32 - частотомер.

Пн мар 17, 2014 13:15:00

по-моему АЦП тут ни к чему. У датчика меандр на выходе с переменной частотой.

Re: STM32 - частотомер.

Пн мар 17, 2014 15:02:33

Да, тогда вообще халява. Настроил таймер и снимай время от времени показания. :)

Re: STM32 - частотомер.

Ср мар 19, 2014 12:01:18

Какая там халява - если задача требует точного измерения частоты за короткий интервал времени, то здесь как раз место для Reciprocal Counting, но его для STM32 пока никто красиво не написал.

Re: STM32 - частотомер.

Ср мар 19, 2014 12:26:29

И шо танцору так мешает??? Холст, краски и вперёд!!!
Назови причины невозможности "красивого" написания... слушаем...

Re: STM32 - частотомер.

Ср мар 19, 2014 12:36:04

HHIMERA писал(а):Назови причины невозможности "красивого" написания... слушаем...


Дык , причина то одна - в SPL этого нету. :)))
Слизать то не у кого ...

Re: STM32 - частотомер.

Ср мар 19, 2014 12:44:32

Дык... хочется услышать... "как танцор картины пишет"... чтобы от "красивого" сразу перейти к "прекрасному"...

Re: STM32 - частотомер.

Ср мар 19, 2014 14:30:43

Леонид Иванович писал(а):Какая там халява - если задача требует точного измерения частоты за короткий интервал времени, то здесь как раз место для Reciprocal Counting
Я тоже так подумал.
Леонид Иванович писал(а):, но его для STM32 пока никто красиво не написал.
himera хвастал(а)сь.

Леонид Иванович, поделитесь методикой расчета точности.

В общем в процессе. Да, ничего особенно сложного, если почитать Ref.manual. И уже считает.
Кварц у контроллера 8 МГц (нестабильность +-50ppm). Внутри частота умножается до 168 МГц. Там свои ppm'ы. Вопрос: может стоит использовать внешнее тактирование для таймера? Там есть такая возможность (ETR).

Re: STM32 - частотомер.

Ср мар 19, 2014 14:56:46

kybin, HHIMERA не хвастался - он сделал ... :)))

Re: STM32 - частотомер.

Ср мар 19, 2014 15:00:17

dosikus писал(а):kybin, HHIMERA не хвастался - он сделал и работает...

Где? Ты видел?

Re: STM32 - частотомер.

Ср мар 19, 2014 15:10:40

И не только видел . :)))
Сам частотомер на 103 , выхлоп 130МГц с F4 дискавери с MCO ...

Изображение

Re: STM32 - частотомер.

Ср мар 19, 2014 15:28:31

молодцы. И какая у вас точность получилась?
Вы могли бы выложить код.

upd: вижу точность=2E-5. или 0,002% Круто! Даже очень. Это если генератор брать за чистую монету

Re: STM32 - частотомер.

Чт мар 20, 2014 13:08:32

HHIMERA писал(а):Назови причины невозможности "красивого" написания... слушаем...


Причина проста. У меня не хватает мозгов такое написать.

kybin писал(а):Да, ничего особенно сложного, если почитать Ref.manual. И уже считает.


Вы уже реализовали Reciprocal Counting? Как Вам это удалось?

kybin писал(а):Кварц у контроллера 8 МГц (нестабильность +-50ppm). Внутри частота умножается до 168 МГц. Там свои ppm'ы. Вопрос: может стоит использовать внешнее тактирование для таймера? Там есть такая возможность (ETR).


PLL дает повышенный фазовый шум, но среднее значение частоты погрешности практически не имеет. Чувствительность частотомера к фазовому шуму обратно пропорциональна интервалу измерения. В общем случае, конечно, лучше обойтись без PLL. Но можно работать и с ней. Другое дело, что обычный кварц в качестве опорного генератора подходит плохо. Нужно взять хотя бы TCXO для тактирования процессора. Внешнее тактирование таймеров не знаю, получится ли применить в таком алгоритме счета. Что касается погрешности, то для метода Reciprocal Counting относительная погрешность не зависит от частоты и равна 1 / (Tизм * Fref), плюс погрешность опорного генератора. Если нужен хороший частотомер, то вряд ли стоит тратить силы по натягиванию этой задачи на STM32, проще взять ПЛИС и на ней сделать всё как надо.

Re: STM32 - частотомер.

Чт мар 20, 2014 17:00:06

Вы уже реализовали Reciprocal Counting? Как Вам это удалось?

В процессе. Технически это возможно. Будет результат отпишусь. А Ххимера сделал. Точный? - достаточно. Жаль делиться не хочет.

Меня беспокоит маленькое время измерения. Но мои первые опыты более-менее. Наверняка ПЛИС будет лучше... Лучше обойтись.

Re: STM32 - частотомер.

Чт мар 20, 2014 18:44:18

Если измерительный интервал равен 100 мкс, то при опорной частоте 168 МГц получается относительная погрешность измерения около 0.006%. Конечно, при условии, что удастся реализовать на STM32 метод Reciprocal Counting.

Re: STM32 - частотомер.

Чт мар 20, 2014 20:50:58

kybin писал(а):Жаль делиться не хочет.

Да чем там делиться... чем??? Там инит двух таймеров... в теме всё расписано... дальше чисто формула...
Ну лень мне рыться в своей "помойке"... проверять в железе... править что-то... неинтересно уже...
Всё работает... чтобы там ЛИ не говорил... Работает и на STM32 и на STM8L... и даже на STM8S903...
Я не делал частотомер... я просто проверил идею, возможность... суть Reciprocal Counting... и просто развеял миф что "сделать нельзя"...

Re: STM32 - частотомер.

Чт мар 27, 2014 10:44:07

Леонид Иванович писал(а):Вы уже реализовали Reciprocal Counting? Как Вам это удалось?.
Да. :music:
И мне не лень будет это выложить и расписать по полочкам. Чтоб и ламеру ясно было :)
Кстати считает хорошо. Хотя возможно баги еще вылезут..

Re: STM32 - частотомер.

Чт мар 27, 2014 12:20:43

Дальнейшее обсуждение переношу в новую тему.

Re: STM32 - частотомер.

Пт фев 16, 2018 21:53:15

TIM1 в режиме Master выдавал секундные импульсы на TIM2, который был настроен как Slave mode: External Clock mode 2 + gated mode... TIM2 осуществлял подсчёт импульсов по входу ETR...
В принципе... и всё... Ничего сложного там нет...

А для меня вот непонятно - как настроить одновременно ETR и gate mode? Бит SMS регистра SMCR сделать этого не даст, как я понял это тупо мультиплексор:
Изображение
Автору топика черкнул, но боюсь он уже здесь не появится.
Ответить