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

Здравствуйте!

 

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

 

Есть устройство (на основе STM32f107), которое синхронизируется от GPS и тактируется от высокостабильного источника частоты.

 

После того, как прибор засинхронизировался, таймер (TIM4) в режиме Input Capture начинает захватывать 1PPS от GPS в третьем канале и 1PPS от того же GPS в четвёртом канале, дальше из одного значения вычитается другое и получаем... (2103 плюс-минус 3) такта, это, примерно, 29 мкс. Снимая таким образом показания каждую секунду, получаем одно и то же значение.

 

Вопрос возникает сам собой — откуда берутся эти 2103 тактов?

 

Если нужно будет, я выложу весь код.

 

Инициализация таймера:

void TIM4_Alarm_Config (void)
{
  RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // подача тактов на TIM4 от шины тактирования APB1

  TIM4->PSC = 1 - 1; // Предварительный делитель: значения счетчика будут инкрементироваться с частотой 35 MГц 
  TIM4->ARR = 65534 - 1;	// Максимальное значение, до которого будет считать таймер, равно 65535				

  // канал 3  (1Гц)
  TIM4->CCMR2 |= TIM_CCMR2_CC3S_0; // выбор активного входа, канал 3 TIM4_CH3 (PB8)    <<------ подать на этот канал 1Гц
  TIM4->CCER  &=~ TIM_CCER_CC3P; // срабатывание по переднему фронту
  TIM4->CCMR2 &=~ TIM_CCMR2_IC3PSC; // захват каждого импульса
//   TIM4->CCER |= TIM_CCER_CC3E; // включить захват из счётчика	  // в EXTI1
  TIM4->DIER |= TIM_DIER_CC3IE; // включение прерывания от захвата

  // канал 4  (1PPS)
  TIM4->CCMR2 |= TIM_CCMR2_CC4S_0; // выбор активного входа, канал 4 TIM4_CH4 (PB9)	<<------ подать на этот канал 1PPS
  TIM4->CCER  &=~ TIM_CCER_CC4P; // срабатывание по переднему фронту
  TIM4->CCMR2 &=~ TIM_CCMR2_IC4PSC; // захват каждого импульса
//   TIM4->CCER |= TIM_CCER_CC4E; // включить захват из счётчика	  // в EXTI1
  TIM4->DIER |= TIM_DIER_CC4IE; // включение прерывания от захвата
}

 

Прерывание от таймера:

void TIM4_IRQHandler(void)
{

  if (TIM4->SR&TIM_SR_CC3IF) // 1Гц
  	  {
  TIM4->SR &=~ TIM_SR_CC3IF; // очиcтка флага прерывания
   count1 = TIM4->CCR3;	// считываем значение счётчика в переменную count1, если выставлен флаг прерывания
     }

  if (TIM4->SR&TIM_SR_CC4IF) // 1PPS 	
  {
   TIM4->SR &=~ TIM_SR_CC4IF; // очиcтка флага прерывания
   count2 = TIM4->CCR4;	// считываем значение счётчика в переменную count1, если выставлен флаг прерывания
  }

 if((count1>0)&&(count2>0))
     {
   	if(count1>count2)
          {
            razn = count1 - count2;              
          }
       if(count2>count1)
          {
            razn = count2 - count1;			
          }   

          count1=0;                        
          count2=0;

	if (razn >(bias+1000)){razn = 65534 - razn;}

//	   	if(bias>razn)
//           {
            rash = razn + 100;// - bias;    // добавил биас    rash - unsigned int      
//           }
//        if(razn>bias)
//           {
//             rash = razn - bias;			
//           }   	  

//while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
//USART2->DR=rash; 

	 		 union {
        unsigned int Mylong2;
        char buf3[2];									 // рассогласование в микросекундах
        }MyUnion2;
	 MyUnion2.Mylong2 = rash;


 while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
      USART2->DR=MyUnion2.buf3[1];							// рассогласование в микросекундах
 while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
     USART2->DR=MyUnion2.buf3[0]; 

  	if (rash<90) 

	  {GPIOA->BSRR |= GPIO_BSRR_BS7;}  // генерация импульса, который подаётся на GPIOA_PIN6 (PA7),            <<----- импульс сигнализации}

	if (rash>110)

	  {GPIOA->BSRR |= GPIO_BSRR_BS7;}  // генерация импульса, который подаётся на GPIOA_PIN6 (PA7),            <<----- импульс сигнализации}
   }
}

Изменено пользователем MarYuriy

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


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

Сформулировал вопрос конкретно по таймеру.

 

Подаю один сигнал параллельно на 2 канала таймера TIM4 (на 2 ноги). Я думаю, что таймер должен защёлкнуть их одновременно, и значения регистров Capture/Compare должны быть одинаковыми. В реальности получается между ними разница в 2103 (плюс минус 3, от включения к включеию) такта шины таймера (35 МГц), которая сохраняется постоянной при приходе этого сигнала, например, раз в секунду.

 

Откуда берутся эти 2103 тактов?

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


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

А Вы в прерывании таймера еще что-то отправлять в USART пытаетесь? :blink:

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


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

А Вы в прерывании таймера еще что-то отправлять в USART пытаетесь? :blink:

 

Да, но это для отладки.

 

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


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

а вот еще момент с вычислением разницы. Есть потенциальная возможность глюков. Я бы как-то так написал:

if (count1>count2)
{
    razn = count1 - count2;
}
else
{
    razn = count2 - count1;
}

 

 

Да, но это для отладки.

а уверены, что именно это не приводит к непонятным глюкам?

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


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

а вот еще момент с вычислением разницы. Есть потенциальная возможность глюков. Я бы как-то так написал:

if (count1>count2)
{
    razn = count1 - count2;
}
else
{
    razn = count2 - count1;
}

 

 

 

а уверены, что именно это не приводит к непонятным глюкам?

 

Не уверен. Буду ещё разбираться.. Напишу, как что-нибудь получится.

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


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

Опять всё напутал. Извиняюсь! В общем теперь задача точно описывается так (всё проверил несколько раз!):

1. Если на оба выхода таймера в режиме Input Capture подаётся один и тот же сигнал, то разница между регистрами сравнения каналов = 00 либо 01 (т.е 1 такт при частоте шины тактирования таймера 35 Мгц).

2. Если на выходы таймера в режиме Input Capture подаются сигналы (1PPS) с разных GPS-ов, то разница между регистрами сравнения каналов варьируется и ползает в разные стороны в пределах от 00 до 10.

3. Если же я из 35МГц (которые получаюся из 10МГц) генерирую 1Гц и в режиме Capture/Campare сравниваю с любым из PPS-ов (т. е. от любого из GPS-ов ), то разница между регистрами сравнения = 2103 (плюс-минус 3).

 

Вопрос всё тот же: откуда берутся эти постоянные 2103 тактов?

 

Инициализация и прерывание для таймера, генерирующего 1Гц:

//********************************************************************************
*
// Функция TIM2_Divider_Config: Делитель на таймере                                           
//********************************************************************************
*
void TIM2_Divider_Config (void)
{
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // подача тактов на TIM2 от шины тактирования APB1

  TIM2->PSC = 35000 - 1;  // предделитель до частоты  2000 Гц
  TIM2->ARR = 2000 - 1;   // выход в прерывание каждую секунду
  TIM2->DIER |= TIM_DIER_UIE;	 // После того как таймер достигнет своего максимального значения генерируется прерываие 
  TIM2->CR1 |= TIM_CR1_ARPE;	// сброс по достижении максимального значения
// TIM2->CR1 |= TIM_CR1_CEN;	// Разрешить работу таймера 
}
//********************************************************************************
*
// Функция TIM2_IRQHandler: Обработчик прерываний для TIM2                                           
//********************************************************************************
*
void TIM2_IRQHandler(void)
{
  if (TIM2->SR&TIM_SR_UIF)
     {
      GPIOE->BSRR |= GPIO_BSRR_BS0; // генерация импульса, который подаётся на (PE0), его надо принять на TIM4_CH3 (PB8) 
      GPIOE->BSRR |= GPIO_BSRR_BR0;
      TIM2->SR &=~ TIM_SR_UIF; // очиcтка флага прерывания                    
     }
}

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


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

Вопрос всё тот же: откуда берутся эти постоянные 2103 тактов?

2103/35000000 = 0,000060086. Видимо, это погрешность вашего кварца, помноженная на PLL.

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


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

2103/35000000 = 0,000060086. Видимо, это погрешность вашего кварца, помноженная на PLL.

 

Если бы это была погрешность, то она распространилась и на пункты 1 и 2 моего предыдущего сообщения. Плюс 10Мгц у меня от рубидиевого стандарта. Поэтому я грешу на код...

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


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

Если бы это была погрешность, то она распространилась и на пункты 1 и 2 моего предыдущего сообщения.

Почему? В первом и втором случае вы засекаете секунду, которую формирует GPS. А в третьем - секунду, которая формируется из вашего кварца.

Сформируйте не секунду, а полсекунды, и разница между ней и GPS будет ещё более заметной:)

Что касаемо кода, то после записи в TIM2->PSC нужно делать

TIM2->EGR = TIM_EGR_UG;

чтобы новое значение PSC вступило в действие.

 

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


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

Почему? В первом и втором случае вы засекаете секунду, которую формирует GPS. А в третьем - секунду, которая формируется из вашего кварца.

Я использую вместо кварца внешнюю частоту (рубидиевый стандарт) для тактирования МК (значит и таймеры тактируются от этой частоты), поэтому такой погрешности быть не может.

 

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


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

В формировании секундного импульса участвует не только рубидиевый стандарт. Возможно, вы ошиблись при настройке PLL? Как вы получили из 10МГц 35МГц? И почему TIM2->PSC = 35000 у вас даёт 2000Гц?

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


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

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

 

По схемам (RM0008 (стр.123) и даташит на stm32f107 (стр.12)) должен участвовать только он, как я понимаю.

 

Возможно, вы ошиблись при настройке PLL? Как вы получили из 10МГц 35МГц? И почему TIM2->PSC = 35000 у вас даёт 2000Гц?

 

Я как раз задавал этот вопрос на форуме несколько месяцев назад. Если посмотреть на схему тактирования stm32f107 (RM0008 стр.123), то там есть такая строчка "TIM2,3,4,5,6,7 If(APB1 prescaler =1) x1 else x2", т.е у меня частота тактирования таймера TIM2 = 70 МГц.

 

Код инициализации HSEBYP:

unsigned char InitHSEBYP(void)
{
 unsigned long int TimeOut = 10000000;     

 //Запустить HSEBYP
 RCC->CR   |=  RCC_CR_HSEBYP;           //Включить генератор HSEBYP  
 RCC->CR   |=  RCC_CR_HSEON;            //Включить генератор HSE
 while((RCC->CR & RCC_CR_HSERDY)==0)    //Ожидание готовности HSE
 if(TimeOut) TimeOut--;
 if(TimeOut==0) return 1;               // Генератор HSE не запустился
 RCC->CR   |=  RCC_CR_CSSON;            //Разрешить работу системы защиты от сбоя HSE

 RCC->CFGR &= ~RCC_CFGR_PLLXTPRE;       //Не использовать делитель HSE

 //Частота  SystemCoreClock выше 24 MHz - разрешить буфер предварительной выборки FLASH
 FLASH->ACR|=  FLASH_ACR_PRFTBE;        //Включить буфер предварительной выборки
 FLASH->ACR&= ~FLASH_ACR_LATENCY;       //Очистить FLASH_ACR_LATENCY
 FLASH->ACR |= FLASH_ACR_LATENCY_2;     //Пропускать 2 такта

 //Настройка PLL 
 RCC->CFGR  |= RCC_CFGR_PLLSRC;         //Источником сигнала для PLL выбран HSE
 RCC->CR   &= ~RCC_CR_PLLON;            //Отключить генератор PLL
 RCC->CFGR &= ~RCC_CFGR_PLLMULL;        //Очистить PLLMULL
 RCC->CFGR |=  RCC_CFGR_PLLMULL7;       //Коефициент умножения = 7
 RCC->CR   |=  RCC_CR_PLLON;            //Включить генератор PLL
 while((RCC->CR & RCC_CR_PLLRDY)==0) {} //Ожидание готовности PLL

 //Переключиться на тактирование от PLL
 RCC->CFGR &= ~RCC_CFGR_SW;             //Очистка битов выбора источника тактового сигнала
 RCC->CFGR |=  RCC_CFGR_SW_PLL;         //Выбрать источником тактового сигнала PLL
 while((RCC->CFGR&RCC_CFGR_SWS)!=0x08){}//Ожидание переключения на PLL

 // apb1 
RCC->CFGR &=~RCC_CFGR_PPRE1;        // Очистка битов предделителя "APB1 Prescaler"
// RCC->CFGR |= RCC_CFGR_PPRE1_DIV1; // HCLK not divided 
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;   // HCLK divided by 2 

 // apb2
RCC->CFGR &= ~RCC_CFGR_PPRE2;       // Очистка битов предделителя "APB2 Prescaler"
// RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; // HCLK not divided 
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;   // HCLK divided by 2 

 return 0;                          // HSE готов к работе
}                    
}

 

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


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

По схемам (RM0008 (стр.123) и даташит на stm32f107 (стр.12)) должен участвовать только он, как я понимаю.

Как минимум ещё PLL и таймер. Нуи время входа в прерывание и время на дрыгание ножкой.

"TIM2,3,4,5,6,7 If(APB1 prescaler =1) x1 else x2", т.е у меня частота тактирования таймера TIM2 = 70 МГц.
А, тогда понятно. Просто цифра 70 МГц не фигурировала.

Что касаемо приведённых настроек PLL, то я не вижу там ни одного упоминания о RCC->CFGR2. У вас же 107? Надо настроить.

В конце-концов, выдайте не 1Гц, а 1 КГц, и измерьте осциллоскопом, какая частота получится.

 

ЗЫ. Кстати, код

  while((RCC->CR & RCC_CR_HSERDY)==0)    //Ожидание готовности HSE
  if(TimeOut) TimeOut--;
  if(TimeOut==0) return 1;               // Генератор HSE не запустился

никогда не вернёт 1. Вместо этого он наглухо зависнет в ожидании HSERDY.

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


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

Как минимум ещё PLL и таймер. Нуи время входа в прерывание и время на дрыгание ножкой.

 

Только времени(тактов) на это уходит слишком много. Кстати, я синхронизирую включение таймера TIM2 с приходом 1PPS в EXTI, это я забыл написать. И тут тоже не должно быть большого расхождения в тактах:

void EXTI1_1PPS_Config(void)
{
  AFIO->EXTICR [0] |= AFIO_EXTICR1_EXTI1_PE; // Прерывание на (PE1)
  EXTI->IMR |= EXTI_IMR_MR1;   // Разрешить запрос от EXTI1									
  EXTI->RTSR |= EXTI_RTSR_TR1; // Прерывание от EXTI1 по переднему фронту

  // ширина приходящего по EXTI импульса должна быть минимум --> 10 нс(см. datasheet стр 90)
}
//********************************************************************************
*
// Функция EXTI1_IRQHandler: Синхронизация от импульса 1PPS                                          
//********************************************************************************
*
void EXTI1_IRQHandler (void)
{
  if (EXTI->PR & EXTI_PR_PR1) // Прерывание от (PE1) по приходу 1PPS
     { 
   	    TIM2->CR1 |= TIM_CR1_CEN;	// Разрешить работу таймера генерации 1Гц 

   if (TimeGlobalFlag==1) 
	      {// Cинхронизация 

			TIM5->CNT = 0; // обнулить счётчик, чтобы его значение после синхронизации равнялось 0x00 			
		TIM5secs=secs; // если время по NMEA получено, присвоить TIM5secs значения secs  

			TIM3->CNT = 0; // обнулить счётчик, чтобы его значение после синхронизации равнялось 0x00 			
		TIM3microsecs = 0; // если время по NMEA получено, TIM3microsecs = 0 

		TIM5->CR1 |= TIM_CR1_CEN;	// Разрешить работу секундного таймера TIM5 
		TIM3->CR1 |= TIM_CR1_CEN;	// Разрешить работу микроcекундного TIM3 таймера 

	//	TIM2->CR1 |= TIM_CR1_CEN;	// Разрешить работу таймера генерации 1Гц 

		TIM1->CCER |= TIM_CCER_CC1E; // включить захват из счётчика			

		TimeGlobalFlag=0;  // устанавливаем флаг успешного получения времени
	//  flagEXTI=1;	   	
		flagSynchro=0;	   // флаг синхронизации - в ПК будут слаться ответы с временем

		AFIO->EXTICR [0] &=~ AFIO_EXTICR1_EXTI1_PE; // Отключиться от (PE1)					  ////////

 EXTI->IMR &=~ EXTI_IMR_MR1;   // Запретить запрос от EXTI1
	  }
  EXTI->PR |= EXTI_PR_PR1; // Сбросить флаг	   										    
  }
}

Что касаемо приведённых настроек PLL, то я не вижу там ни одного упоминания о RCC->CFGR2. У вас же 107? Надо настроить.

 

Да 107, только, я так понял, регистр RCC->CFGR2 весь для I2C.

 

ЗЫ. Кстати, код
Код
  while((RCC->CR & RCC_CR_HSERDY)==0)    //Ожидание готовности HSE
  if(TimeOut) TimeOut--;
  if(TimeOut==0) return 1;               // Генератор HSE не запустился

никогда не вернёт 1. Вместо этого он наглухо зависнет в ожидании HSERDY.

 

Да, 1 он не вернёт (скобок не хватает). А зависать он не должен, он и не зависает :)

 

В конце-концов, выдайте не 1Гц, а 1 КГц, и измерьте осциллоскопом, какая частота получится.

 

В общем, если что-то получится, то отпишусь.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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