kil00 0 19 сентября, 2012 Опубликовано 19 сентября, 2012 (изменено) · Жалоба Здравствуйте! У меня есть, на мой взгляд, интересная задачка (хотя я новичок в МК, может быть, преувеличиваю), над которой я изрядно поломал мозг, но так и не решил. Есть устройство (на основе 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), <<----- импульс сигнализации} } } Изменено 19 сентября, 2012 пользователем MarYuriy Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба Сформулировал вопрос конкретно по таймеру. Подаю один сигнал параллельно на 2 канала таймера TIM4 (на 2 ноги). Я думаю, что таймер должен защёлкнуть их одновременно, и значения регистров Capture/Compare должны быть одинаковыми. В реальности получается между ними разница в 2103 (плюс минус 3, от включения к включеию) такта шины таймера (35 МГц), которая сохраняется постоянной при приходе этого сигнала, например, раз в секунду. Откуда берутся эти 2103 тактов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 21 сентября, 2012 Опубликовано 21 сентября, 2012 · Жалоба А Вы в прерывании таймера еще что-то отправлять в USART пытаетесь? :blink: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 22 сентября, 2012 Опубликовано 22 сентября, 2012 · Жалоба А Вы в прерывании таймера еще что-то отправлять в USART пытаетесь? :blink: Да, но это для отладки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 1 22 сентября, 2012 Опубликовано 22 сентября, 2012 · Жалоба а вот еще момент с вычислением разницы. Есть потенциальная возможность глюков. Я бы как-то так написал: if (count1>count2) { razn = count1 - count2; } else { razn = count2 - count1; } Да, но это для отладки. а уверены, что именно это не приводит к непонятным глюкам? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 23 сентября, 2012 Опубликовано 23 сентября, 2012 · Жалоба а вот еще момент с вычислением разницы. Есть потенциальная возможность глюков. Я бы как-то так написал: if (count1>count2) { razn = count1 - count2; } else { razn = count2 - count1; } а уверены, что именно это не приводит к непонятным глюкам? Не уверен. Буду ещё разбираться.. Напишу, как что-нибудь получится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 25 сентября, 2012 Опубликовано 25 сентября, 2012 · Жалоба Опять всё напутал. Извиняюсь! В общем теперь задача точно описывается так (всё проверил несколько раз!): 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тка флага прерывания } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 25 сентября, 2012 Опубликовано 25 сентября, 2012 · Жалоба Вопрос всё тот же: откуда берутся эти постоянные 2103 тактов? 2103/35000000 = 0,000060086. Видимо, это погрешность вашего кварца, помноженная на PLL. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 26 сентября, 2012 Опубликовано 26 сентября, 2012 · Жалоба 2103/35000000 = 0,000060086. Видимо, это погрешность вашего кварца, помноженная на PLL. Если бы это была погрешность, то она распространилась и на пункты 1 и 2 моего предыдущего сообщения. Плюс 10Мгц у меня от рубидиевого стандарта. Поэтому я грешу на код... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 26 сентября, 2012 Опубликовано 26 сентября, 2012 · Жалоба Если бы это была погрешность, то она распространилась и на пункты 1 и 2 моего предыдущего сообщения. Почему? В первом и втором случае вы засекаете секунду, которую формирует GPS. А в третьем - секунду, которая формируется из вашего кварца. Сформируйте не секунду, а полсекунды, и разница между ней и GPS будет ещё более заметной:) Что касаемо кода, то после записи в TIM2->PSC нужно делать TIM2->EGR = TIM_EGR_UG; чтобы новое значение PSC вступило в действие. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 27 сентября, 2012 Опубликовано 27 сентября, 2012 · Жалоба Почему? В первом и втором случае вы засекаете секунду, которую формирует GPS. А в третьем - секунду, которая формируется из вашего кварца. Я использую вместо кварца внешнюю частоту (рубидиевый стандарт) для тактирования МК (значит и таймеры тактируются от этой частоты), поэтому такой погрешности быть не может. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 27 сентября, 2012 Опубликовано 27 сентября, 2012 · Жалоба В формировании секундного импульса участвует не только рубидиевый стандарт. Возможно, вы ошиблись при настройке PLL? Как вы получили из 10МГц 35МГц? И почему TIM2->PSC = 35000 у вас даёт 2000Гц? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 27 сентября, 2012 Опубликовано 27 сентября, 2012 · Жалоба В формировании секундного импульса участвует не только рубидиевый стандарт. По схемам (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 готов к работе } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 27 сентября, 2012 Опубликовано 27 сентября, 2012 · Жалоба По схемам (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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kil00 0 28 сентября, 2012 Опубликовано 28 сентября, 2012 · Жалоба Как минимум ещё 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 КГц, и измерьте осциллоскопом, какая частота получится. В общем, если что-то получится, то отпишусь. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться