Перейти к содержанию
    

ProMetei

Новичок
  • Постов

    2
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный
  1. Увы, проверять в конце прерывания ШИМ - бессмысленно, следующее ШИМ-прерывание может наступить уже через 8 тактов, а запустившийся до него обработчик АЦП занимает до 3000. Арифметика вся с фиксированной точкой беззнаковая. Я пробовал ужать до 16-битной арифметики, но набор регистров, которые используется в обработчике остаётся почти таким же большим, а точность генерируемого сигнала падает, вылезая за пределы техзадания. Весь обработчик писать на ассемблере я не готов. Господа, а что по поводу костыля - насколько он кривой и опасный?
  2. Камень: 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+ Уважаемые знатоки, подскажите, пожалуйста- есть ли иной вариант, как заставить компилятор запускать вложенные прерывания пораньше? И если нет - насколько правильно написан мой костыль? Спасибо!
×
×
  • Создать...