реклама на сайте
подробности

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> Временные интервалы
=GM=
сообщение Jun 24 2010, 22:35
Сообщение #31


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(xemul @ Jun 22 2010, 15:18) *
Завести таймер на 5 мкс, в его прерывании делать только
Код
PORTC = tmpC;
Flag_5us = 1;

В основном цикле
Код
uint24_t ch1_cnt, ..., ch8_cnt; // uint24_t придумать, для счётчиков при 0.1 Гц и 5 мкс нужен 21 бит
                                // с uint32_t будут лишние считания
if(Flag_5us)
{
   if(!--ch1_cnt) { tmpC ^= 1; ch1_cnt = (tmpC & 1)? ch1_high_time: ch1_low_time; }
   if(!--ch2_cnt) { tmpC ^= 2; ch2_cnt = (tmpC & 2)? ch2_high_time: ch2_low_time; }
...
   if(!--ch8_cnt) { tmpC ^= 128; ch8_cnt = (tmpC & 128)? ch8_high_time: ch8_low_time; }
   Flag_5us = 0;
}

Но в 5 мкс (100 тактов на 20 МГц) if(Flag_5us) {...} всё равно не уложится, так что урезайте осетра по разрешению.

Тогда уж лучше весь if(Flag_5us) {...} вставить в прерывание, по крайней мере, флаг не придётся проверять. Но прерывание для данной задачи - зло, поэтому лучше делать без прерываний вообще, не будет потерь времени на сохранение контекста в прерывании.

Конструкция if(!--ch1_cnt) ... выглядит компактно, но только на бумаге, здесь 8 раз вычитается то, что в предыдущем решении таймер1 делает аппаратно.

По моим грубым прикидкам, если писать на асме, то можно уложиться в максимальный джиттер 8 мкс.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
Палыч
сообщение Jun 25 2010, 05:57
Сообщение #32


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(singlskv @ Jun 25 2010, 01:04) *
Кстати, задачка на самом деле очень интересная, и вполне решаемая...
Не забываем что Ton+Toff >= 100 тиков для каждого канал и такта 5мкс,
а всего смен значения порта за 100тиков не более 16
Вот и давайте посчитаем: сколько отводиться на смену выходного сигнала? Сто делим на 16 = 6 (четыре такта отдадим на смену Ton/Toff rolleyes.gif ). Не все команды выполняются за один такт. Следовательно, нужно определить прошедшее время удержания сигнала, сравнить с некой константой, при необходимости изменить выходной сигнал и проделать некие действия по новому отсчету времени, и всё это улолжить максимум в шесть команд (точнее в несколько команд, которые выполняются за шесть тактов). Сможите? Пусть даже на ассемблере.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 25 2010, 06:07
Сообщение #33


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



В общем, если отбросить чисто академические изыски, не имеющие практического значения, нужно поставить снаружи ЦПЛД за 30р и упаковать туда 8-канальный таймер-счётчик.
Либо применить готовые программируемые интервальные таймеры

Либо заменить контроллер на более подходящий для таких целей


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
singlskv
сообщение Jun 25 2010, 07:08
Сообщение #34


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Палыч @ Jun 25 2010, 09:57) *
Вот и давайте посчитаем: сколько отводиться на смену выходного сигнала? Сто делим на 16 = 6 (четыре такта отдадим на смену Ton/Toff rolleyes.gif ). Не все команды выполняются за один такт. Следовательно, нужно определить прошедшее время удержания сигнала, сравнить с некой константой, при необходимости изменить выходной сигнал и проделать некие действия по новому отсчету времени, и всё это улолжить максимум в шесть команд (точнее в несколько команд, которые выполняются за шесть тактов). Сможите? Пусть даже на ассемблере.
Вы чего-то совсем не то насчитали, 16смен значения порта будет в самом худшем случае за
100*5мкс=500мкс (если на всех выходах нужно 2КГц и никакие фронты не совпадают)

Цитата(=GM= @ Jun 25 2010, 02:35) *
Тогда уж лучше весь if(Flag_5us) {...} вставить в прерывание, по крайней мере, флаг не придётся проверять.
Почти так, только не совсем
Цитата
Но прерывание для данной задачи - зло, поэтому лучше делать без прерываний вообще, не будет потерь времени на сохранение контекста в прерывании.
Прерывания позволят освободить основной цикл проги для приема обновленных значений Ton/Toff
извне, например по уарту или с кнопочек.
Большую часть сохранения контекста можно делать после вывода значения в порт перед вычислениями(это конечно только на АСМ).

Видимо Вы не до конца поняли суть предлагаемого алгоритма.
За 500мкс сменить значение порта нужно не более 16 раз.
Если эти 16смен забуферировать и приделать к ним счетчики сколько времени не менять значение на порту,
то у нас будет куча времени на рассчеты следующих значений.
Вопрос только в правильной организации рассчетов в прерывании и одновременный вывод из буфера уже сохраненных.
Так вот здесь очень красиво можно вписать вложенные прерывания, причем прерывание то будет одно,
только оно может вызываться из уже работающего того же самого обработчика.

Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 25 2010, 07:18
Сообщение #35


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(singlskv @ Jun 25 2010, 11:08) *
Видимо Вы не до конца поняли суть предлагаемого алгоритма.
За 500мкс сменить значение порта нужно не более 16 раз.

Вы видимо, тоже не до конца.
Эти смены не равномерно распределены по интервалу, а могут вплотную друг за другом идти, либо вообще накладываться.
Вот в эти моменты и возникает джиттер. И требование в 5мкс накладывает очень жёсткие требования...


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
singlskv
сообщение Jun 25 2010, 07:24
Сообщение #36


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(MrYuran @ Jun 25 2010, 11:18) *
Вы видимо, тоже не до конца.
Эти смены не равномерно распределены по интервалу, а могут вплотную друг за другом идти, либо вообще накладываться.
Вот в эти моменты и возникает джиттер. И требование в 5мкс накладывает очень жёсткие требования...
Как раз для случаев когда они идут с интервалом в 5мкс и вводится буферирование,
и вывод в порт при смене значения всегда из буфера в самом начале прерывания,
а после этого дальнейший рассчет нового значения на освободившееся место в буфере.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Jun 25 2010, 09:12
Сообщение #37


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(MrYuran @ Jun 25 2010, 05:07) *
-В общем, если отбросить чисто академические изыски, не имеющие практического значения, нужно поставить снаружи ЦПЛД за 30р и упаковать туда 8-канальный таймер-счётчик.
-Либо применить готовые программируемые интервальные таймеры
-Либо заменить контроллер на более подходящий для таких целей

На самом деле в CPLD нужно ставить шестнадцать 24-битных счётчиков ПЛЮС 16 регистров хранения длительностей полупериодов ПЛЮС схема управления ПЛЮС интерфейс связи с МК...придётся осетра за 30 рубчиков урезать :-).

Ещё вариант - поставить четыре 8-ногие тиньки, у которых есть два аппаратных ШИМА...Но можно и чисто программно, те же 6-ногие АТмега10 подойдут. У меня получается где-то 18 тактов на обработку одного канала, т.е. для софтового генератора джиттер не превосходит 1 мкс/канал.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
xemul
сообщение Jun 25 2010, 10:07
Сообщение #38



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(=GM= @ Jun 25 2010, 02:35) *
Тогда уж лучше весь if(Flag_5us) {...} вставить в прерывание, по крайней мере, флаг не придётся проверять. Но прерывание для данной задачи - зло, поэтому лучше делать без прерываний вообще, не будет потерь времени на сохранение контекста в прерывании.

Я затруднюсь сказать, что лучше, не видя остальной части загадки. Потери на общение с волатильными счетчиками могут оказаться больше и непредсказуемей.
Цитата
Конструкция if(!--ch1_cnt) ... выглядит компактно, но только на бумаге, здесь 8 раз вычитается то, что в предыдущем решении таймер1 делает аппаратно.

Я предложил "рыбу" решения на С - так короче. имхо, исходно было понятно, что отдавать оптимизацию компилятору в этой задаче ... неразумно.
Извините, не понял, какое из предыдущих решений Вы имели в виду.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Jun 25 2010, 11:30
Сообщение #39


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Из поста #26.

1) Ну смотрите, объясняю конструкцию if(!--ch1_cnt) на пальцах. Надо загрузить 4-х байтный счётчик из памяти в регистры, вычесть 1 и сохранить обратно в памяти. И так 8 раз!

2) В прерывании вы выставляете флаг5мкс, а в фоне ждёте его. Если поместить тело if в прерывание, то ждать флага не надо, наступило прерывание - выполняем тело if. Всяко быстрее будет.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
xemul
сообщение Jun 25 2010, 12:46
Сообщение #40



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(=GM= @ Jun 25 2010, 15:30) *
Из поста #26.

1) Ну смотрите, объясняю конструкцию if(!--ch1_cnt) на пальцах. Надо загрузить 4-х байтный счётчик из памяти в регистры, вычесть 1 и сохранить обратно в памяти. И так 8 раз!

За объяснение спасибо. Я об этом смутно догадывался, Вы подтвердили мои опасения.smile.gif
В посте #26 в любой ветке выполняется 3 бинарные (!) операции с uint32_t (две из них - с загрузкой и сохранением). И так 8 раз!
Изначально (мной) было сказано, что достаточно 3 байтов на счётчик, с соответствующими умолчательными предположениями о реализации и оптимизации.
Декремент 3-х (или 4-х) байтового числа с проверкой на 0, имхо, не сложнее if(sysTime>endTime[i]), которая выполняется через вычитание двух uint32_t и проверку знака результата.
Цитата
2) В прерывании вы выставляете флаг5мкс, а в фоне ждёте его. Если поместить тело if в прерывание, то ждать флага не надо, наступило прерывание - выполняем тело if. Всяко быстрее будет.

Вряд ли - только на сохранении/восстановлении регистровой пары в прерывании будет потеряно столько же. В качестве же бесплатного довеска - некоторое количество volatile uint32_t с сопутствующим оверхедом.
Ну и скорость в данном месте как-то сбоку - на джиттер не влияет, а если у контроллера не хватит скорострельности, то абсолютно фиолетово, где не хватит - в прерывании или в фоне.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Jun 25 2010, 15:56
Сообщение #41


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Немного повергло в шок, как компилятор WinAVR транслирует вашу конструкцию
Код
//HEMUL VERSION
  if(!--endTime0)
19c:    8d 81           ldd    r24, Y+5; 0x05
19e:    9e 81           ldd    r25, Y+6; 0x06
1a0:    af 81           ldd    r26, Y+7; 0x07
1a2:    b8 85           ldd    r27, Y+8; 0x08
1a4:    01 97           sbiw    r24, 0x01; 1
1a6:    a1 09           sbc    r26, r1
1a8:    b1 09           sbc    r27, r1
1aa:    8d 83           std    Y+5, r24; 0x05
1ac:    9e 83           std    Y+6, r25; 0x06
1ae:    af 83           std    Y+7, r26; 0x07
1b0:    b8 87           std    Y+8, r27; 0x08
1b2:    8d 81           ldd    r24, Y+5; 0x05
1b4:    9e 81           ldd    r25, Y+6; 0x06
1b6:    af 81           ldd    r26, Y+7; 0x07
1b8:    b8 85           ldd    r27, Y+8; 0x08
1ba:    00 97           sbiw    r24, 0x00; 0
1bc:    a1 05           cpc    r26, r1
1be:    b1 05           cpc    r27, r1
1c0:    81 f4           brne    .+32    ; 0x1e2 <main+0x166>
  {
   PINC =_BV(0);
1c2:    73 bb           out    0x13, r23; 19
   endTime0 =(PORTC & _BV(0))? tLow0 : tHigh0;
1c4:    a8 9b           sbis    0x15, 0; 21
1c6:    05 c0           rjmp    .+10    ; 0x1d2 <main+0x156>
1c8:    8d 85           ldd    r24, Y+13; 0x0d
1ca:    9e 85           ldd    r25, Y+14; 0x0e
1cc:    af 85           ldd    r26, Y+15; 0x0f
1ce:    b8 89           ldd    r27, Y+16; 0x10
1d0:    04 c0           rjmp    .+8     ; 0x1da <main+0x15e>
1d2:    89 89           ldd    r24, Y+17; 0x11
1d4:    9a 89           ldd    r25, Y+18; 0x12
1d6:    ab 89           ldd    r26, Y+19; 0x13
1d8:    bc 89           ldd    r27, Y+20; 0x14
1da:    8d 83           std    Y+5, r24; 0x05
1dc:    9e 83           std    Y+6, r25; 0x06
1de:    af 83           std    Y+7, r26; 0x07
1e0:    b8 87           std    Y+8, r27; 0x08
  }

Но по зрелому размышлению понял, что лучше и не сделаешь.

Странно, но вот так: if(!endTime0--) получается фрагмент на 4 такта быстрее.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
xemul
сообщение Jun 25 2010, 16:26
Сообщение #42



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(=GM= @ Jun 25 2010, 19:56) *
Но по зрелому размышлению понял, что лучше и не сделаешь.

Вторая загрузка лишняя - достаточно про-OR'ить r24-r27 и сразу brne.

Сообщение отредактировал rezident - Jun 26 2010, 00:51
Причина редактирования: Нарушение п.3.4 Правил форума.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Jun 25 2010, 21:05
Сообщение #43


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



А зачем орить? После std сразу brne ... Но это не мне надо объяснять, а компилятору.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
=GM=
сообщение Jun 28 2010, 12:12
Сообщение #44


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Вот, немного переделал алгоритм

if(sysTime>endTime0)
{
PINC =_BV(0);
if(PORTC & _BV(0)) endTime0 +=tLow0; //новое время завершения 0 канала
else endTime0 +=tHigh0;
}
. . .
if(sysTime>endTime7)
{
PINC =_BV(7);
if(PORTC & _BV(7)) endTime7 +=tLow7; //новое время завершения 7 канала
else endTime7 +=tHigh7;
}

На асме укладывается в 18 тактов для одного канала при 24-битном времени. Но есть нюанс с системным временем, который пока не преодолел.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jun 28 2010, 17:14
Сообщение #45


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(=GM= @ Jun 25 2010, 19:56) *
Немного повергло в шок, как компилятор WinAVR транслирует вашу конструкцию
endTime0 волатильный? Если да то нормально скомпилировал...


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post

4 страниц V  < 1 2 3 4 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 21:47
Рейтинг@Mail.ru


Страница сгенерированна за 0.015 секунд с 7
ELECTRONIX ©2004-2016