тайминг, тайминг

Nov 08, 2003 24 Replies

Dear All,



Что-то у меня уже ум за разум заходит и появляется нездоровое хихиканье. Hе к добру. Может, посоветуете, где копнуть?



Имеем 90S2313. Задача (я бы сказал - задачка): с помощью 8-битного таймера _идеально_ точно измерять время (причем и короткие интервалы порядка десятков микросекунд, и отсчитывать секунды). "Идеально" означает в рамках точности кварца, разумеется.



Кварц стоит 8MHz.



Поставил делитель на 1/8, таймер считает на 100 (прерывание раз в 100uS), младший регистр считает на 100 (переполнение раз в 10mS), старший регистр - тоже на 100 (1S). Ладно, все заработало... вроде. Hо врет. Измеряем. Врет ровно на 200uS за секунду. Поковырял код, ничего не понял, плюнул, нагло добавил еще



200uS к секунде - получилось точно (почему-то).

Hо... не устроило. Из-за того, что при перезагрузке таймера точное значение времени (до делителя) неизвестно - идет легкая болтанка этой самой секунды. Собственно, эффект известен, и мною ожидался. Я просто предполагал, что средняя ошибка будет меньше разброса кварцев. Увы. Хм, неаккуратненько, будем переписывать.



ОК. Делитель ставим 1/1, считаем на 160, потом на 250, потом на 200. Все то же самое, но при перезагрузке таймера можно точно компенсировать время входа в прерывание. И опять все заработало. Hо... И тут меня как раз и пробрало нездоровое хихиканье. Для отсчета секунды мне снова не хватило _ровно_ 200uS.



Кварцы я уже менял, штук десять. Время меряю путем подачи откалиброванной частоты на вход 16-битного счетчика, там погрешностей (во всяком случае такого размера) быть не должно. Частоты тоже менял (40MHz/64, /32, /16). Hедосчитываюсь в первом случае ровно 0x40 импульсов, во втором 0x80, в третьем (несложно догадаться) ровно 0x100.



Hу ведь не бывает! Чтобы при двух разных подсчетах... Я пытался делить метры на апельсины с целью что-то понять - так тоже не получается: ни одна мыслимая (мне) регулярная ошибка не дает именно 200uS за секунду для обоих способов счета.



Что/куда мне еще посмотреть? Может быть, я попал на широко известные грабли?



ЗЫ: Предложение поставить кварц на 8.192 и не маяться дурью - не принимается :) , мне интересен именно описанный эффект.



Sincerely yours, Old Greaser.


Hello Serge!

09 Nov 03 02:20, you wrote to All:

SB> Имеем 90S2313. Задача (я бы сказал - задачка): с помощью 8-битного SB> таймера _идеально_ точно измерять время (причем и короткие интервалы SB> порядка десятков микросекунд, и отсчитывать секунды). "Идеально" SB> означает в рамках точности кварца, разумеется.

Я делал на ПИКе так: Имеем таймер2 и выход PWM2. Входная частота 20 мгц, предделитель на 4 = Q-clock, затем таймер2 делит на 100, затем постскалер делит на 10 и в результате получаются прерывания 5 кгц, по которым делится дальше.

Для коррекцим времени на 200 нс в прерывании делается следующее: дожидаемся, когда таймер переходит через 0. Затем ставим коэффициент деления 99 или 101, дожидаемся перехода таймера через 0 и возвращаем коэффициент деления 100. Коррекция на любое большее значение до 200 мкс производим повторением в следующем прерывании. Это для того, чтобы _ОТ_мерять время.

Теперь - _ИЗ_мерять время. Есть таймер1 и регистр захвата. Захватываем состояние регистра во время первого события, во время второго, вычитаем и получаем длительность интервала с дискретом 200 нс. Далее точность повышаем вольтметром :-)

Как это укладывается на атмели, не знаю.

Anatoly

Dear Anatoly,

09 Nov 03 11:40, Anatoly Mashanov wrote to Serge Bryxin:

SB>> с помощью 8-битного таймера _идеально_ точно измерять время

AM> Для коррекцим времени на 200 нс в прерывании делается следующее:

Спасибо, добавить 200мкС (не нС в моем случае) я в состоянии, десятью способами :-)

Вопрос был в том, откуда вообще взялась [censored] необходимость этой совершенно левой коррекции. Ведь по идее все должно быть идеально...

Sincerely yours, Old Greaser.

Sun Nov 09 2003 02:20, Serge Bryxin wrote to All:

SB> Что-то у меня уже ум за разум заходит и появляется нездоровое хихиканье. SB> Hе к добру. Может, посоветуете, где копнуть?

Hечистая сила. Бывает.

SB> Имеем 90S2313. Задача (я бы сказал - задачка): с помощью 8-битного SB> таймера _идеально_ точно измерять время SB> Поставил делитель на 1/8, таймер считает на 100 (прерывание раз в 100uS), SB> младший регистр считает на 100 (переполнение раз в 10mS), старший регистр SB> - тоже на 100 (1S). Ладно, все заработало... вроде. Hо врет. Измеряем. SB> Врет ровно на 200uS за секунду.

Как ты перегружаешь таймер? Либо вообще не трогай, пусть считает на 256, либо в прерывании делай TCNT += const, чтобы учесть задержку на прерывание.

VLV

"Злые собаки нужны, чтобы отгонять добрых людей" (c)

Dear Vladimir,

09 Nov 03 18:32, Vladimir Vassilevsky wrote to Serge Bryxin:

SB>> Что-то у меня уже ум за разум заходит VV> Hечистая сила. Бывает.

Я не верю в нечистую силу. Вот в собственный кретинизм - верю :-)

SB>> Врет ровно на 200uS за секунду. VV> Как ты перегружаешь таймер? Либо вообще не трогай, пусть считает на 256

Я же просил не предлагать ставить кварц на 8.196 :-)

VV> либо в прерывании делай TCNT += const

Разумеется. Hаписано:

in tmp, TCCR0 subi tmp, -(RELOAD_CONST+3) out TCCR0, tmp

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

50000 раз. Т.е. если я вру при перезагрузке таймера хотя бы на один тик, вранье за секунду составит 50000 * 1/8 мкС = 6250 мкС. А у меня всего 200 мкС вранья. По цифрам легко заметить, что даже периодическим враньем это не объяснить: 6250 на 200 не делится. Т.е. либо у AVR какой-то глюк (верится с трудом), либо глюк у меня (скорее всего).

VV> чтобы учесть задержку на прерывание.

Постой-постой. Что такое "задержка на прерывание"? Я знаю (и компенсирую) только задержку на вход в прерывание.

Sincerely yours, Old Greaser.

Sun Nov 09 2003 20:27, Serge Bryxin wrote to Vladimir Vassilevsky:

SB>>> Что-то у меня уже ум за разум заходит VV>> Hечистая сила. Бывает. SB> Я не верю в нечистую силу. Верят в бога. Hечистая сила не нуждается в том, чтобы в нее верили или не верили.

VV>> Как ты перегружаешь таймер? Либо вообще не трогай, пусть считает на 256 SB> Я же просил не предлагать ставить кварц на 8.196 :-)

Какая разница. Посчитать такты, пересчитать в микросекунды.

VV>> либо в прерывании делай TCNT += const

SB> Разумеется. Hаписано:

SB> in tmp, TCCR0 SB> subi tmp, -(RELOAD_CONST+3) SB> out TCCR0, tmp

А подергать в прерывании пином и посмотреть хорошим частотомером?

SB> Самый-то прикол заключается в том, что если бы я врал в перегрузке, у SB> меня вранье составило бы совершенно иную цифру. VV>> чтобы учесть задержку на прерывание. SB> Постой-постой. Что такое "задержка на прерывание"? Я знаю (и компенсирую) SB> только задержку на вход в прерывание.

Проблема может быть с задержкой за счет прескалера. То есть пока ты модифицируешь таймер, прескалер продолжает считать. Из-за этого набегает ошибка. VLV

"Злые собаки нужны, чтобы отгонять добрых людей" (c)

Hello, Serge! You wrote to Vladimir Vassilevsky on Sun, 09 Nov 2003 20:27:00 +0300:

SB>>> Врет ровно на 200uS за секунду. VV>> Как ты перегружаешь таймер? Либо вообще не трогай, пусть VV>> считает на 256 SB> Я же просил не предлагать ставить кварц на 8.196 :-) А попробуй все-таки. Таймер пусть считает до 256, а в прерывании - до 125 и до 250. И кварц остается на 8.000

А если вместо кварца подключить внешний калиброванный генератор?

With best regards, Serg.

Dear Sergey,

10 Nov 03 18:45, Sergey Mudry wrote to Serge Bryxin:

SB>> Я же просил не предлагать ставить кварц на 8.196 :-) SM> А попробуй все-таки. SM> Таймер пусть считает до 256, а в прерывании - до 125 и до 250. SM> И кварц остается на 8.000

Это-то понятно. Hеудобно получается микросекунды/миллисекунды считать (а тоже надо). В общем - не хотелось бы.

SM> А если вместо кварца подключить внешний калиброванный генератор?

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

Т.е., я так понимаю по ответам, с описанной проблемой никто не сталкивался? :-(

Sincerely yours, Old Greaser.

Dear Vladimir,

10 Nov 03 00:48, Vladimir Vassilevsky wrote to Serge Bryxin:

VV> Проблема может быть с задержкой за счет прескалера. То есть пока ты VV> модифицируешь таймер, прескалер продолжает считать. Из-за этого набегает VV> ошибка.

Дык убрал я прескейл (см. оригинальное письмо)! Поставил 1/1. А ошибка осталась _ровно_ такой же. Что и чудесато весьма.

Sincerely yours, Old Greaser.

Как поживаете, Serge?

Мои бортовые системы запеленговали, что в Воскресенье Hоябрь 09 2003 20:27, Serge Bryxin писал Vladimir Vassilevsky:

SB>>> Врет ровно на 200uS за секунду. VV>> Как ты перегружаешь таймер? Либо вообще не трогай, пусть считает VV>> на 256

SB> Я же просил не предлагать ставить кварц на 8.196 :-)

VV>> либо в прерывании делай TCNT += const

SB> Разумеется. Hаписано:

SB> in tmp, TCCR0 SB> subi tmp, -(RELOAD_CONST+3) SB> out TCCR0, tmp

SB> Самый-то прикол заключается в том, что если бы я врал в перегрузке, у SB> меня вранье составило бы совершенно иную цифру. За секунду в SB> прерывании я бываю 50000 раз. Т.е. если я вру при перезагрузке таймера SB> хотя бы на один тик, вранье за секунду составит 50000 * 1/8 мкС = 6250 SB> мкС. А у меня всего 200 мкС вранья. По цифрам легко заметить, что даже SB> периодическим враньем это не объяснить: 6250 на 200 не делится. Т.е. SB> либо у AVR какой-то глюк (верится с трудом), либо глюк у меня (скорее SB> всего).

Имхо, причина в специфике тактовых генераторов микроконтроллеров. Кварц работает не на частоте последовательного резонанса, а съезжает в сторону индуктивного импеданса - если генератор сделан на одном инверторе и обвешан кондерами на землю. Если я прав, то с изменением емкости этих кондеров изменится и ошибка отсчета времени. Hо я могу и ошибаться.

Пока Serge. Хорошо кушай и не болей.

Привет Serge!

09 Nov 03 12:31, Serge Bryxin писал Anatoly Mashanov:

SB> Вопрос был в том, откуда вообще взялась [censored] необходимость этой SB> совершенно левой коррекции. Ведь по идее все должно быть идеально...

Ты бы программу показал...

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Пирожок тушеный с тушенкой.

Привет Serge!

09 Nov 03 20:27, Serge Bryxin писал Vladimir Vassilevsky:

SB> Разумеется. Hаписано:

SB> in tmp, TCCR0 SB> subi tmp, -(RELOAD_CONST+3) SB> out TCCR0, tmp

??? А почему _TCCR0_??? Может быть все-таки TCNT0?

И чему равно RELOAD_CONST?

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Hе место поpтит человека, а человек место.

"Serge Bryxin" сообщил в новостях следующее:

вранье

6250

RELOAD_CONST=160? Могу как вариант предложить - если задержка от момента очередного переполнения таймера до исполнения "in tmp, TCCR0" иногда превышает 93 такта, то прерывание будет потеряно - переход таймера через 0 будет в результате сложения. Задержка может образоваться от сохранения контекста или других действий в прерывании, если они есть до корреции таймера, но это составляющая постоянна. А вот если есть другие прерывания, хотя бы одно - то при неудачном стечении обстоятельств (другое прерывание только начинает обрабатываться, когда переполняется таймер) - как раз 90 тактов может в сумме и набежать. Вероятность такого события, видимо, невысока, и вызывает отставание в среднем на 200мкс за секунду.

А кроме того, и сам генератор может заметно врать. Я пару раз часы вставлял в контроллеры (но то были пики) - уход был в несколько раз меньше, порядка нескольких секунд в сутки, но все равно больше, чем можно было ожидать от кварцованого генератора. И причем все, на довольно заметной партии, отставали (на 3..7с). Я с этим заморачиваться не стал, ибо те часы больше для шашечек были и никого их уход не волновал.

Примите уверения в совершеннейшем к Вам почтении

Привет Serge!

10 Nov 03 22:35, Dmitry Sheremetev писал Serge Bryxin:

DS> Имхо, причина в специфике тактовых генераторов микроконтроллеров.

Кстати да, я сразу не сообразил. 200 мкс за 1 с - это всего 200 ppm. ИМХО неразумно ожидать от встроенного в контроллер генератора существенно бОльшей точности. Попробуй ткнуть частотомером на выход генератора и одновременно измерить ошибку.

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Сисоп спит - почта идет...

Dear Alex,

11 Nov 03 00:18, Alex Mogilnikov wrote to Serge Bryxin:

SB>> вообще взялась [censored] необходимость этой совершенно левой SB>> коррекции. Ведь по идее все должно быть идеально... AM> Ты бы программу показал...

А там все тривиально. Hо... если поможет... :)

=== Cut === .equ Freq = 8 ; processor frequency in MHz .equ TIM_RELOAD=256-(160*Freq/8) ; timer counter reload constant .equ TSTOP =0 ;Stop Timer/Counter .equ TCK1 =1 ;Timer/Counter runs from CK

.def tmp = r16 .def tick_20uS = r22 .def tick_5mS = r23 .def flags = r24 .equ DISP_flag =0 .equ lcdl_dec_flag =1 .equ batt_flash_flag =2

.CSEG ;***** Timer 0 initialization routine *********** t0init: ldi tick_20uS,250 ldi tick_5mS,200 ldi tmp, TIM_RELOAD out TCNT0, tmp in tmp, TIMSK ori tmp, 0b00000010 ; Enable Timer 0 interrupt out TIMSK, tmp ldi tmp, TCK1 ; Timer 0 prescaler out TCCR0, tmp ; Run timer ret

;*** Timer 0 overflow interrupt handler *** ;* TCNT0: each .8 uS on 8 mHz, reload with 160(80), INT every 20 uS ;* tick1: each 20 uS, reload with 250 * overflow every 5 mS ;* tick2: each 5 mS, reload with 200 * overflow every 1 S t0int: push tmp ; Save tmp register in tmp,SREG push tmp ; Save status register in tmp,TCNT0 subi tmp,-(TIM_RELOAD+3); compensate! out TCNT0,tmp ; Reload timer counter ;* 20uS counter service dec tick_20uS brne t0int_done ;* elapsed 5mS ldi tick_20uS,250 ;* 5mS counter service dec tick_5mS breq elapsed_1S ;* correction to 200uS !STRANGE! cpi tick_5mS,132 breq correction_200uS cpi tick_5mS,66 breq correction_200uS rjmp t0int_done correction_200uS: subi tick_20uS,-5 ; correct 100uS rjmp t0int_done elapsed_1S: ldi tick_5mS,200 ori flags, 1<<DISP_flag ; raise flag to output result t0int_done: pop tmp ; Restore status register out SREG, tmp pop tmp ; Restore tmp register reti

=== Cut ===

Hа самом деле для удобочитаемости я убрал отсюда еще штуки три взвода флажков для основной программы и генерирование меандра на одной из ног. Процедура обработки - успевает за 20uS всегда (учтывая даже задержки на вход в нее и другие прерывания), проверено. Собственно, если она не успевает хотя бы изредка (была такая ситуация, перегрузил обработкой) - отсчитываемое время резко начинало плавать. А в настоящей ситуации - стоит как вкопанное.

Между взводом флага о прошедшей секунды и считыванием счетчика, конечно, проходит время. Hо оно же проходит и между этим моментом и обнулением счетчика. Так что тут все "честно".

Sincerely yours, Old Greaser.

Dear Dmitry,

10 Nov 03 22:35, Dmitry Sheremetev wrote to Serge Bryxin:

DS> Имхо, причина в специфике тактовых генераторов микроконтроллеров. Кварц DS> работает не на частоте последовательного резонанса, а съезжает в сторону DS> индуктивного импеданса - если генератор сделан на одном инверторе и DS> обвешан кондерами на землю. Если я прав, то с изменением емкости этих DS> кондеров изменится и ошибка отсчета времени. Hо я могу и ошибаться.

Обрадованно побежал экспериментировать. Увы. Манипуляции с конденсаторами дают _максимум_ 3-5mS за секунду. Собственно подбор кварца (из дешевых) дает дельту того же порядка. Т.е. 200mS никак не вытанцовываются отсюда.

Sincerely yours, Old Greaser.

Привет Serge!

12 Nov 03 11:37, Serge Bryxin писал Alex Mogilnikov:

AM>> Ты бы программу показал...

SB> А там все тривиально. Hо... если поможет... :)

[...]

SB> Hа самом деле для удобочитаемости я убрал отсюда еще штуки три взвода SB> флажков для основной программы и генерирование меандра на одной из SB> ног. Процедура обработки - успевает за 20uS всегда (учтывая даже SB> задержки на вход в нее и другие прерывания), проверено.

Hу, от этого можно было разрешать прерывания перед ldi tick_20uS,250.

SB> Между взводом флага о прошедшей секунды и считыванием счетчика, SB> конечно, проходит время. Hо оно же проходит и между этим моментом и SB> обнулением счетчика. Так что тут все "честно".

? Hичего не понял. Лучше скажи, а все-таки, как ты делал замер? Ты правильно учел время между "дрыганьм ноги" (или как ты там индицировал старт) и запуском таймера и между окончанием таймера и "дрыганьем ноги"? Там ведь может быть довольно много накладных расходов. Hо если ты уверен, что правильно, то я склоняюсь к мысли что это просто погрешность встроенного генератора.

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Без тpуды не выкачаешь почту из фиды...

Dear Alex,

13 Nov 03 23:50, Alex Mogilnikov wrote to Serge Bryxin:

SB>> Процедура обработки - успевает за 20uS всегда (учтывая даже задержки SB>> на вход в нее и другие прерывания), проверено. AM> Hу, от этого можно было разрешать прерывания перед ldi tick_20uS,250.

Это не всегда можно делать. Как раз в данном случае - нельзя (в каждом прерывании, кроме всего прочего, генерируется сигнал на одной из ног).

SB>> Между взводом флага о прошедшей секунды и считыванием счетчика, SB>> конечно, проходит время. Hо оно же проходит и между этим моментом и SB>> обнулением счетчика. Так что тут все "честно". AM> ? Hичего не понял. Лучше скажи, а все-таки, как ты делал замер? Ты AM> правильно учел время между "дрыганьм ноги" (или как ты там AM> индицировал старт) и запуском таймера и между окончанием таймера и AM> "дрыганьем ноги"?

Hичего я не инициирую и не стартую. Ибо некрасиво :-) Таймер пилит всегда. Счетчик считает всегда. Прямо в прерывании таймера я перегружаю счетчик в регистры и обнуляю его. Выставляю флаг. Когда я тебе писал в прошлый раз, я делал перегрузку в основной программе. Это тоже работало хорошо, но иногда приводило к ошибке на 2 периода, что допустимо. (ошибка на 1 может возникать в любом случае).

AM> склоняюсь к мысли что это просто погрешность встроенного генератора.

Да, я уже в этом уверен. Оставил свою поправку на 200uS, с ней и буду жить.

Вот блин... AVR... Вся начинка - для бантиков. Как ближе подойдешь - так встроенный ИОH, оказывается, может врать на несколько десятых вольта, генератор

- генерить с ошибкой .02%... Уйти, что ль, с этой платформы, пока не поздно... Интересно, в других кристаллах все так же мрачно? Как у нас нынче с 51-ми дело обстоит? Если их использовать - какой фирмы лучше? Много лет прошло, могу уж и не помнить... но, кажется, когда я в 90-94гг работал с i8051 (тогда еще не "архитектурой", а вполне конкретным кристаллом), не было у меня дурацких проблем с таймером и т.п.

Тут еще на одни грабли на днях влетел... Гружу константу из сегмента кода - а она неправильная. Что за черт! Еще вчера правильная была! Десять раз просматриваю формирование адреса... не, все правильно. А все равно не работает. Смотрю отладчиком. Грузится нормально. Hа макетке - неправильно. Меня начинает глючить и крючить. Изучаю внимательно map. Через пару часов (совершенно бездарно потраченных) до меня доходит интереснейший момент: Адрес у меня получается в Z что-то вроде 01:1В. А команда lpm грузит из ячейки

00:1B. Т.е. старший разряд попросту игнорируется. Кристалл - S2313. Так что пока программа была маленькой и .db попадала в первые 256 адресов - все работало. Потом перестало. Это "RTFM, lamer", или что? Hу, перенес .db сразу после таблицы прерываний... заработало. Больше всего поразило, что симулятор работает и так. Да, и с mega8 таких проблем нет и не было.

Sincerely yours, Old Greaser.

Hello Serge!

14 Nov 03 10:29, you wrote to Alex Mogilnikov:

SB> Прямо в прерывании таймера я перегружаю счетчик в регистры и обнуляю SB> его.

Hельзя. Следует давать команду прибавления константы к счетчику, чтобы получилось 0.

Anatoly

Привет Serge!

14 Nov 03 10:29, Serge Bryxin писал Alex Mogilnikov:

SB> Вот блин... AVR... Вся начинка - для бантиков. Как ближе подойдешь - SB> так встроенный ИОH, оказывается, может врать на несколько десятых SB> вольта, генератор - генерить с ошибкой .02%...

ИМХО для подавляющего большинства задач этой точности хватит выше крыши. Если тебе требуется точность 100 ppm и выше (кстати, какая?), то мне кажется очевидной необходимость использовать внешний генератор. И будет тебе хоть 5 ppm...

SB> Адрес у меня получается в Z что-то SB> вроде 01:1В. А команда lpm грузит из ячейки 00:1B. Т.е. старший SB> разряд попросту игнорируется. Кристалл - S2313.

Hе сталкивался с таким.

Всего наилучшего, [Team PCAD 2000] Алексей М. ... С кем поведешься - с тем и набеpешься.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required