ProMetei 0 8 декабря, 2016 Опубликовано 8 декабря, 2016 · Жалоба Камень: atmega88pa Компилятор: CVAVR Главная часть проекта - 8-канальный аппаратно-программный генератор ШИМа на 6 прерываниях таймеров 0 и 2 (Fclk=2MHz, Fpwm=7,8kHz). Расчёт значений для ШИМ производится в прерывании от ADC. Сразу после входа в обработчик разрешаются вложенные прерывания (чтоб не глох ШИМ), затем идёт задумчивый код с 32-битной арифметикой и лишь перед выходом из обработчика- запускается новый отсчёт АЦП. Проблема в том, что компилятор абсолютно верно и предсказуемо сохраняет регистры при входе в обработчик, и лишь затем добирается до SEI, вот упрощенная выдержка из листинга: _ADC_isr: ST -Y,R0 ST -Y,R1 ST -Y,R22 ST -Y,R23 ST -Y,R24 ST -Y,R25 ST -Y,R26 ST -Y,R27 ST -Y,R30 ST -Y,R31 IN R30,SREG ST -Y,R30 sei ; тут живёт медленный код D R30,Y+ OUT SREG,R30 LD R31,Y+ LD R30,Y+ LD R27,Y+ LD R26,Y+ LD R25,Y+ LD R24,Y+ LD R23,Y+ LD R22,Y+ LD R1,Y+ LD R0,Y+ RETI Эта пауза в 23/20 (вход/выход) дополнительных тактов даёт джиттер ШИМ до 3 единиц. Джиттер не особо напрягает, но хотелось бы от него избавиться. Переносить медленный код в основной цикл - не вариант, там крутится основная логика программы, абстрагированная от железа. Разбавлять её опросом флага ADSC - кощунство. Попробовал покататься на вот таком костыле- помогает, но не уверен что он правильный. #pragma savereg- interrupt [ADC_INT] void ADC_isr(void) // замер входов АЦП, плавный разгон { static unsigned int soft_rpm=0; // внутренняя переменная плавной скорости static unsigned int addition; // компенсация ограничения unsigned char temp; // вспомогательная переменная для ускорения расчётов unsigned long L; // для точных расчётов #asm ST -Y,R0 ; выгрузили R0 IN R0,SREG ; в R0 положили SREG (с I-bit=0) SEI ; разрешили прерывания ST -Y,R0 ; выгрузили R0 ( реально - там SREG) ST -Y,R1 ; выгрузили R1 ST -Y,R15 ; выгрузили R15 ST -Y,R22 ; выгрузили R22 ST -Y,R23 ; выгрузили R23 ST -Y,R24 ; выгрузили R24 ST -Y,R25 ; выгрузили R25 ST -Y,R26 ; выгрузили R26 ST -Y,R27 ; выгрузили R27 ST -Y,R30 ; выгрузили R30 ST -Y,R31 ; выгрузили R31 #endasm {} // тут живёт медленный код ADCSRA=(1<<ADEN) | (1<<ADSC) |(1<<ADIE) | (1<<ADIF) | 0x06; // перезапуск прерывания #asm LD R31,Y+ ; восстановили R31 LD R30,Y+ ; восстановили R30 LD R27,Y+ ; восстановили R27 LD R26,Y+ ; восстановили R26 LD R25,Y+ ; восстановили R25 LD R24,Y+ ; восстановили R24 LD R23,Y+ ; восстановили R23 LD R22,Y+ ; восстановили R22 LD R15,Y+ ; восстановили R15 LD R1,Y+ ; восстановили R1 LD R0,Y+ ; восстановили R0 ( реально - там SREG) OUT SREG,R0 ; из R0 восстановить SREG (с I-bit=0, запретив прерывания) LD R0,Y+ ; восстановили R0 #endasm } #pragma savereg+ Уважаемые знатоки, подскажите, пожалуйста- есть ли иной вариант, как заставить компилятор запускать вложенные прерывания пораньше? И если нет - насколько правильно написан мой костыль? Спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zombi 0 8 декабря, 2016 Опубликовано 8 декабря, 2016 · Жалоба Сразу после входа в обработчик ... идёт задумчивый код с 32-битной арифметикой Задумчивый код в прерывании!? Не думаю что это правильно. Разбавлять её опросом флага ADSC - кощунство. либо джиттер либо кощунство Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 8 декабря, 2016 Опубликовано 8 декабря, 2016 · Жалоба Вы можете вынести меделнную обработку в другое прерывание, скажем, в прерывание по SPM. Тогда ваш основной обработчик будет в начале брать результаты предыдущего вычисления, а конце будет разрешать прерывание SPM. После выхода из основного обработчика будет запускаться обработчик SPM, в котором в самом начале нужно запретить прерывание SPM и разрешить глобальные прерывания. Этот обработчик SPM будет готовить данные для следующего основного прерывания и будет как бы фоновой задачей между остальными прерываниями и основным циклом. Возможно, еще стоит подумать о переходе от плавучки к арифметике с фиксированной точкой. Добавлено: а, ну да - этот обработчик будет давать точно такую же задержку. Тогда вы можете проверять флаг АЦП и разрешать его прерывание, если флаг взведен, в конце прерывания ШИМ. Тогда ваш обработчик АЦП будег вызван после обработчика ШИМ и мешать ему не будет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ProMetei 0 8 декабря, 2016 Опубликовано 8 декабря, 2016 · Жалоба Добавлено: Тогда вы можете проверять флаг АЦП и разрешать его прерывание, если флаг взведен, в конце прерывания ШИМ. Тогда ваш обработчик АЦП будег вызван после обработчика ШИМ и мешать ему не будет. Увы, проверять в конце прерывания ШИМ - бессмысленно, следующее ШИМ-прерывание может наступить уже через 8 тактов, а запустившийся до него обработчик АЦП занимает до 3000. Возможно, еще стоит подумать о переходе от плавучки к арифметике с фиксированной точкой. Арифметика вся с фиксированной точкой беззнаковая. Я пробовал ужать до 16-битной арифметики, но набор регистров, которые используется в обработчике остаётся почти таким же большим, а точность генерируемого сигнала падает, вылезая за пределы техзадания. Весь обработчик писать на ассемблере я не готов. Господа, а что по поводу костыля - насколько он кривой и опасный? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 8 декабря, 2016 Опубликовано 8 декабря, 2016 · Жалоба следующее ШИМ-прерывание может наступить уже через 8 тактовТогда любое другое прерывание даст вам дрожание. Может стоит уйти от ШИМа к чему-то более другому? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zombi 0 8 декабря, 2016 Опубликовано 8 декабря, 2016 · Жалоба насколько он кривой и опасный? дык вроде ничего ни кривого ни опасного разрешайте прерывания первой командой обработчика а в конце простой RET. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Zlumd 0 14 декабря, 2016 Опубликовано 14 декабря, 2016 · Жалоба Сразу после входа в обработчик разрешаются вложенные прерывания (чтоб не глох ШИМ)Внутри прерывания ШИМ не глохнет. ШИМ генерируется таймером аппаратно, независимо от того, чем занимается процессор. Или вы вручную ногами дергаете? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться