// Предделитель тактовой частоты - 8
// CLKPR=0x80;
asm ("push r20"); // Предварительно сохраняем регистр. Но обычно студия его не использует
asm ("ldi r20, 0x80");
asm ("sts 0x60, r20");
//CLKPR=0x03;
asm ("ldi r20, 3");
asm ("sts 0x60, r20");
asm ("pop r20"); // Загружаем обратно в регистр его исходное значение
Смотрим спецификацию на m2560
Да посчитайте же вы такты и разберитесь как оно работает!
ИС-пытатель, учите мат.часть!
Удачи.
Добавил спустя несколько минут:
Хоть оно и заработало в сокращённом варианте, но время между выборками будет много больше того, что "зашито" в таймере.
Время будет ещё и немного разное от раза-к-разу.
Последний раз редактировалось Kavka Чт мар 13, 2014 22:09:59, всего редактировалось 1 раз.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
// Предделитель тактовой частоты - 8
// CLKPR=0x80;
asm ("push r20"); // Предварительно сохраняем регистр. Но обычно студия его не использует
asm ("ldi r20, 0x80");
asm ("sts 0x60, r20");
//CLKPR=0x03;
asm ("ldi r20, 3");
asm ("sts 0x60, r20");
asm ("pop r20"); // Загружаем обратно в регистр его исходное значение
Смотрим спецификацию на m2560
Да посчитайте же вы такты и разберитесь как оно работает!
ИС-пытатель, учите мат.часть!
Удачи.
Прошу прощения. CLKPR = 0x61. Сейчас поправлю. ) Но это опять не принципиально! ) Эта ошибка появилась сейчас. потому что я переписывал программу с нуля, по памяти, впопыхах и под пиво. )) Сейчас поправлю. К тому же, в моей изначальной программе предделитель процессора устанавливался именно СИшными командами (а это исключает ошибку). И время срабатывания таймера проверялось по изменяющемуся выводу осциллографом. Все было правильно.
Последний раз редактировалось ИС-пытатель Чт мар 13, 2014 22:16:32, всего редактировалось 3 раза.
Kavka писал(а):
Хоть оно и заработало в сокращённом варианте, но время между выборками будет много больше того, что "зашито" в таймере.
Время будет ещё и немного разное от раза-к-разу.
А как Вы проверяли соотношение времени выборок и времени срабатывания таймера? В симуляторе?
Смотрел в симуляторе в 6й студии. В железе нет ни одного из упомянутых МК.
Соотношение времени проверять и не требуется зная как работают прерывания в этом МК.
С исправлением про CLKPR ассемблерный вариант работает?
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Кстати, факт входа в прерывание АЦП также можно отследить по какому-либо порту (грубо говоря, помигать светодиодами). И я это делал. И контроллер входил.
Последний раз редактировалось ИС-пытатель Чт мар 13, 2014 22:33:00, всего редактировалось 1 раз.
Kavka писал(а): С исправлением про CLKPR ассемблерный вариант работает?
Так я еще раз говорю, вариант на сайте - дубликат восстановленный по памяти. В первой версии инициализация предделителя была командами СИ. Ошибка исключена. Ассемблерный вариант работает без инструкций PUSH/POP. С любой из них вылет.
И проверить сейчас на железе не могу. все железо осталось на работе. Я Вас прекрасно понимаю в стремлении найти МОЮ ошибку. сам неделю бился головой об стену, думал, что где-то накосячил. Раз 100 перечитал даташит и евстифеева, перепроверил код. Пересчитал такты срабатывания прерываний и выполнения инструкций. Все в пустую. А потом просто в ассемблерном варианте выкинул все лишнее и начал экспериментировать. И нашел условия появления бага.
В железе будете проверять - отключите делитель тактовой CPU...
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Смотрите. Еще раз железо.
Меняем все команды push/pop в обработчике таймера на команды nop. (по два nop вместо каждой, т.к. длительность команд push/pop 2 такта). Все заработало.
Убираем по две команды nop с пролога и эпилога. и вместо них пихаем Push и Pop регистра r1. Перестало работать.
Далее. Изменение предделителя CPU на работу также не повлияло. (контроллер не работает).
А по поводу тактов. Я подсчитал, действительно прерывание таймера (учитывая пролог обработчика) накладывается на прерывание АЦП. НО!! Таймер срабатывает раз в 16*8=128 тактов контроллера. А сам обработчик таймера "весит" приблизительно 50 тактов. т.е. так как прерывания от таймера и от АЦП возникли в одно время, то первым обрабатывается прерывание от Таймера. (порядка 50 тактов) потом выполняется один jmp основного цикла и остается еще порядка 75 тактов до нового срабатывания таймера, чтобы обработать прерывание от АЦП (А оно тоже около 50 тактов). Принцип очередности прерываний. Пофиг, что наложились, прерывание от АЦП обработается просто позже. И при таком раскладе мы можем получить только не правильный результат АЦП (т.к. запустили его вновь не успев забрать результат), а внутренний счетчик в обработчике АЦП должен нормально работать.
Kavka писал(а):
Загнал Си-шный код в симулятор.
ISR(TIMER0_COMPA_vect) получилась около 45 тактов.
ISR(ADC_vect) получилась около 50 тактов.
Т.е. чаще 90-100 тактов у вас измерять не получиться!
Более того, "таймерный" флаг на прерывание будет уже стоят снова к моменту последующему выходу из ISR(TIMER0_COMPA_vect).
Первый раз попали в прерывание по таймеру - запустили АЦП. Выходим - уже стоит флаг на "таймерное" прерывание. Ну, одна команда CPU выполнилась и снова в обработчик прерывания таймера.
А что же с прерыванием АЦП?! А ничего! Он не будет выполняться вообще!
Укоротив код в ассемблерном представлении вы "впихнули" код во временнЫе рамки и оно заработало.
Здесь Вы не правильно посчитали. Таймер срабатывает раз в 128 тактов контроллера. как раз укладываюсь с измерениями.
Последний раз редактировалось ИС-пытатель Пт мар 14, 2014 09:13:25, всего редактировалось 2 раза.
ИС-пытатель писал(а):Таймер срабатывает раз в 16*8=128 тактов контроллера.
Вы же поделили тактовую контроллера на 8.
Т.е, повторюсь, такт АЦП == такту таймера == такту CPU и, следовательно, 16 тактов таймера == 16 тактам CPU, а не 128-ми.
ИС-пытатель писал(а):Меняем все команды push/pop в обработчике таймера на команды nop. (по два nop вместо каждой, т.к. длительность команд push/pop 2 такта). Все заработало.
Попробуйте оставить push/pop для r24.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
ИС-пытатель писал(а):Таймер срабатывает раз в 16*8=128 тактов контроллера.
Вы же поделили тактовую контроллера на 8.
Т.е, повторюсь, такт АЦП == такту таймера == такту CPU и, следовательно, 16 тактов таймера == 16 тактам CPU, а не 128-ми.
да, я поделил тактовую частоту контроллера на 8. А потом для таймера и АЦП поделил ее еще раз на 8. Предделитель таймера и АЦП делят тактовую чатоту после предделителя CPU, а не ту, которая приходит на него. 128 там тактов.
К тому же это проверено осциллографом по частоте срабатывания таймера. Все совпадает.
На EEPROM только всегда приходит частота до предделителя CPU
Последний раз редактировалось ИС-пытатель Пт мар 14, 2014 10:09:07, всего редактировалось 2 раза.
А еще в 2560 при баге бывает фича, когда в обработчике от АЦП после инкремента переменной добавляешь nop и она начинает считать. Но она как-то через раз работает. Бывает ресанешь - работает. второй раз ресанешь - нет.
ИС-пытатель писал(а):да, я поделил тактовую частоту контроллера на 8. А потом для таймера и АЦП поделил ее еще раз на 8. Предделитель таймера и АЦП делят тактовую чатоту после предделителя CPU, а не ту, которая приходит на него. 128 там тактов.
Да, тут я дал маху, извините. Не использовал этот делитель (CLKPR) ни разу.
ИС-пытатель писал(а):А еще в 2560 при баге бывает фича, когда в обработчике от АЦП после инкремента переменной добавляешь nop и она начинает считать. Но она как-то через раз работает. Бывает ресанешь - работает. второй раз ресанешь - нет.
Что, IMHO, говорит о ситуации типа "race condition" - проблемы с последовательностью событий, с последовательностью доступа/модификации данных. В случае с МК это связано с прерываниями и независимой работой периферии. Чего-то не учли.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Kavka писал(а): Да, тут я дал маху, извините. Не использовал этот делитель (CLKPR) ни разу.
Учите мат.часть!
P.S. А вообще, с Вами приятно было пообщаться. ) Вы действительно хорошо проанализировали код (даже нашли несколько помарок )и не выдавали версий наугад. ) Спасибо Вам! )
Ну, собственно, что и сделал. Смотри подпись.
Вам бы отладку через JTAG погонять - может что-нибудь удастся поймать.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Так заработало или пока решили оставить эту проблему?
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
ADCSRA – ADC Control and Status Register A
...
Bit 4 – ADIF: ADC Interrupt Flag
This bit is set when an ADC conversion completes and the Data Registers are updated. The
ADC Conversion Complete Interrupt is executed if the ADIE bit and the I-bit in SREG are set.
ADIF is cleared by hardware when executing the corresponding interrupt handling vector. Alter-
natively, ADIF is cleared by writing a logical one to the flag. Beware that if doing a Read-Modify-
Write on ADCSRA, a pending interrupt can be disabled. This also applies if the SBI and CBI
instructions are used.
То всё работает.
Вот и развеян ещё один баг контроллера.
ИС-пытатель писал(а):
P.S. А вообще, с Вами приятно было пообщаться. ) Вы действительно хорошо проанализировали код (даже нашли несколько помарок )и не выдавали версий наугад. ) Спасибо Вам! )
Взаимно (про CLKPR)
PS: Ставим плюсы, кому не жалко.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)