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

Отключение выгрузки регистров в стек (CVAVR)

Камень: 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+

Уважаемые знатоки, подскажите, пожалуйста- есть ли иной вариант, как заставить компилятор запускать вложенные прерывания пораньше?

И если нет - насколько правильно написан мой костыль?

 

Спасибо!

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сразу после входа в обработчик ... идёт задумчивый код с 32-битной арифметикой

Задумчивый код в прерывании!?

Не думаю что это правильно.

 

Разбавлять её опросом флага ADSC - кощунство.

либо джиттер либо кощунство

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы можете вынести меделнную обработку в другое прерывание, скажем, в прерывание по SPM. Тогда ваш основной обработчик будет в начале брать результаты предыдущего вычисления, а конце будет разрешать прерывание SPM. После выхода из основного обработчика будет запускаться обработчик SPM, в котором в самом начале нужно запретить прерывание SPM и разрешить глобальные прерывания. Этот обработчик SPM будет готовить данные для следующего основного прерывания и будет как бы фоновой задачей между остальными прерываниями и основным циклом. Возможно, еще стоит подумать о переходе от плавучки к арифметике с фиксированной точкой.

 

Добавлено: а, ну да - этот обработчик будет давать точно такую же задержку. Тогда вы можете проверять флаг АЦП и разрешать его прерывание, если флаг взведен, в конце прерывания ШИМ. Тогда ваш обработчик АЦП будег вызван после обработчика ШИМ и мешать ему не будет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавлено: Тогда вы можете проверять флаг АЦП и разрешать его прерывание, если флаг взведен, в конце прерывания ШИМ. Тогда ваш обработчик АЦП будег вызван после обработчика ШИМ и мешать ему не будет.

 

Увы, проверять в конце прерывания ШИМ - бессмысленно, следующее ШИМ-прерывание может наступить уже через 8 тактов, а запустившийся до него обработчик АЦП занимает до 3000.

 

Возможно, еще стоит подумать о переходе от плавучки к арифметике с фиксированной точкой.

 

Арифметика вся с фиксированной точкой беззнаковая. Я пробовал ужать до 16-битной арифметики, но набор регистров, которые используется в обработчике остаётся почти таким же большим, а точность генерируемого сигнала падает, вылезая за пределы техзадания.

 

Весь обработчик писать на ассемблере я не готов.

 

Господа, а что по поводу костыля - насколько он кривой и опасный?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

следующее ШИМ-прерывание может наступить уже через 8 тактов
Тогда любое другое прерывание даст вам дрожание. Может стоит уйти от ШИМа к чему-то более другому?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

насколько он кривой и опасный?

дык вроде ничего ни кривого ни опасного

разрешайте прерывания первой командой обработчика а в конце простой RET.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сразу после входа в обработчик разрешаются вложенные прерывания (чтоб не глох ШИМ)
Внутри прерывания ШИМ не глохнет.

ШИМ генерируется таймером аппаратно, независимо от того, чем занимается процессор. Или вы вручную ногами дергаете?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...