Артем, спасибо за помощь. Попытаюсь объяснить подробнее.
Цитата
Что у вас за обработчик такой? Что вы в нём делаете? Вызываете функции из других файлов? Почему вход такой долгий? Приведите код.
Задача МК записывать осциллограмму в массив и выполнять цифровую фильтрацию измеренного сигнала. Сначала идея была в использовании прерываний МК для цифровой фильтрации, которая заключается в нахождении разницы между текущим отсчетом АЦП и предыдущим 40 отсчетом АЦП. DMAС предполагалось использовать для записи осциллограммы. Однако, измеряя в дебаггере AVR Studio время перехода в функцию прерывания, решил внести изменения в алгоритм.
Теперь контролирую флаг завершения преобразования АЦП (CH0IF - флаг статуса, который говорит о завершенном преобразовании АЦП по даташиту от 11.2012). Как только вижу что флаг установился, сбрасываю его и считываю регистр результата преобразования АЦП. Выполняю преобразования над новым отсчетом и снова ожидаю установки флага завершения преобразования АЦП. При этом запись осциллограммы также возлагается на DMAC. DMAC фиксирует установку флага CH0IF (ранее я думал, что DMAC будет так делать) и копирует значение регистра результата преобразования АЦП в массив. Однако, не тут то было...
Ассемблер решил использовать для ускорения работы программы, т.к. надо укладываться в 1 мкс (т.е. успевать обрабатывать отсчет пока АЦП преобразует новый). В программе также используется прерывание от Компаратора, который контролирует напряжение питания. Если срабатывает компаратор, то происходит останов АЦП. Для этого контролирую 1 бит ADCB.CTRLA.
Код программы без использования прерываний следующий:
Код
unsigned char EEMEM C0_ctrl_E =3|(1<<2);//диф. режим АЦП с усилением 2x
unsigned char EEMEM C0_MUXpos_E =0; //PIN0
unsigned char EEMEM C0_MUXneg_E =0; //PIN4
unsigned char EEMEM ADC_ref_E =(1<<4);//опорное напряжение Vcc/1.6V
unsigned char EEMEM ADC_prescaler_E =(1<<1)|1;
register unsigned char t_i asm("r2");
register unsigned char t_eq asm("r3");
register unsigned char FLAG asm("r4");
register unsigned char t1 asm("r5");
register unsigned char Ustavka asm("r6");
register unsigned char ch0_iL asm("r7");
register unsigned char ch0_iH asm("r8");
register unsigned char ValueOfFlag asm("r9");
register unsigned char One asm("r10");
register unsigned char TempR asm("r11");
void ADC_B_init()
{
if (!RESET) asm("wdr");
unsigned char ADC_C0_ctrl =eeprom_read_byte((uint8_t *)0x02);
unsigned char C0_MUXpos =eeprom_read_byte((uint8_t *)0x03);
unsigned char C0_MUXneg =eeprom_read_byte((uint8_t *)0x04);
unsigned char ADC_ref =eeprom_read_byte((uint8_t *)0x05);
unsigned char ADC_prescaler=eeprom_read_byte((uint8_t *)0x06);
if (!RESET) asm("wdr");
ADCB.CTRLA=2;// очищаем настройки АЦП
ADCB.REFCTRL=ADC_ref;
ADCB.PRESCALER=ADC_prescaler;
ADCB.EVCTRL=0;//используем нулевой канал
ADCB.CH0.CTRL=ADC_C0_ctrl;//дифференциальный входной
//сигнал c усилением 1x ADCB.CH0.CTRL=3;
ADCB.CH0.MUXCTRL=(C0_MUXpos<<3)|(C0_MUXneg);
ADCB.CH0.INTCTRL=0;//MAX Level is OFF
ADCB.CH0.INTFLAGS=0x01; // сбрасываем флаги прерываний канала
ADCB.CALL=Production_Signature_Row_Read(0x24); // ADCBCAL0 = 0x44
ADCB.CALH=Production_Signature_Row_Read(0x25); // ADCBCAL1 = 0x04
PORTB.PIN0CTRL=7;
PORTB.PIN1CTRL=7;
PORTB.PIN2CTRL=7;
PORTB.PIN4CTRL=7;
PORTB.PIN5CTRL=7;
PORTB.PIN6CTRL=7;
}
void DMAC_init()
{
DMA.CTRL=0;
DMA.CH0.CTRLB=(1<<4)|(1<<5);//Отключаем прерывания от DMA и сбрасываем флаги TRNIF и ERRIF
DMA.CH0.ADDRCTRL|=(1<<3)|(1<<2);//Начальное значение перезагружается
// в регистр адреса получателя DMA в конце каждой транзакции
DMA.CH0.ADDRCTRL|=(1);//Инкрементное увеличение адреса получателя
DMA.CH0.TRIGSRC=0x20;//0x20;//Запуск оn ADCB
DMA.CH0.TRFCNT=10;//Количество байт в блоке
DMA.CH0.REPCNT=0;
DMA.CH0.SRCADDR0=0x64;//младший байт адреса RESL ADCB.CH0
DMA.CH0.SRCADDR1=0x02;//старший байт адреса RESL ADCB.CH0
DMA.CH0.SRCADDR2=0;
DMA.CH0.DESTADDR0=((int)&Ch0)&255;
DMA.CH0.DESTADDR1=((int)&Ch0)>>8;
DMA.CH0.DESTADDR2=0;
DMA.CH0.CTRLA|=(1<<7)|(1<<5)|(1<<2);//посылка из 1 байта
//REPEAT
//разрешение работы 0 канала DMA
//singleshot
}
void main ()
{
ADC_B_init();
DMAC_init();
DMA.CTRL|=(1<<7);
ADCB.CTRLB=(1<<4)|(1<<2);//знаковый режим и 8 битное разрешение АЦП
ADCB.CTRLA|=1;//Включаем АЦП
ADCB.CTRLB|=(1<<3); // Старт первого преобразования АЦП
[b]//-------Здесь идет запись сороковой точки в регистр r5, из которого далее будут вычитаться новый текущий отсчет (этот код не привожу т.к. он однотипный коду далее)
//При выполнения кода ниже DMA сюдя по дебаггеру ведет себя не так как задумано[/b]
asm("loopInt1:");
asm("wdr");
asm("LDS r18,0x0240");//ADCB.CTRLA - Bit 1 - Enable ADCB
asm("TST r18");//if (!(ADCB.CTRLA&1)) goto loopEx1;
asm("BRNE loopInt4");
asm("rjmp loopEx1");
asm("loopInt4:");
asm("LDS r18,0x0246");//INTFLAGS
asm("CPI r18,1");
asm("BRNE loopInt1");
asm("STS 0x0246,1");//Сбрасываем INTFLAG0
asm("LDS r18, 0264");
asm("INC r2");
asm("CP r2,r3");
asm("BRNE loopInt1");
asm("MOV r5,r18");//t1=ADCB.CH0.RES
asm("CLR r2");//t_i=0;
asm("CLR r4");//FLAG=0;
}
Теперь приведу код с обработчиком прерывания. Настройка параметров АЦП такая же как указано выше, только ADCB.CH0.INTCTRL=3;//MAX Level is on
Настройка DMA такая же как выше. Переход из основной функции main () в обработчик прерывания занимает много времени. Думаю это связано с тем, что компилятор преобразуя код си добавляет команды сохранения в стек адреса с которого произошло прерывание.
Код
ISR(ADCB_CH0_vect) [b]//Общее время выполнения команд в прерывании занимает не более 0,8 мкс[/b]
{
asm("wdr");
asm("LDS R18,0x0264");//0x0264 - адрес ADCB.CH0.RESL
asm("TST r4");//if (FLAG!=) тогда переход
asm("BRNE loop1");//Метка Аварии
//t_i - номер текущей точки - r2
//t_e - номер разностной точки - для частоты 1 МГц равна 40, для частоты 0,5 Мгц равна 20 - r3
asm("CP r2,r3");
asm("BRNE loop2");//Выход1
asm("SUB R18,r5");//t3=t2-t1; (разницы нет t1-t2 или t2-t1)
asm("TST R5");//if (t3>0)
asm("BRGE loop3");//Если R5 больше нуля или равно нулю, тогда переход
asm("NEG R5");//Если R5 меньше, тогда находим модуль
asm("loop3:");
asm("CP R5,R6");//if (t3>Ustavka)
asm("BRLO loop6");
asm("INC R4");
asm("STS 0x0689, R1");//PORTE.INTCTRL=0; Отключаем прерывание от часов
asm("RJMP loop5");
asm ("loop6:");
asm ("MOV r5,r18");//t1=r18
asm ("CLR r2");//t_i=0;
asm ("RJMP loop5");
asm("loop1:");
asm("CP R4,r9");
asm("BREQ loop5");
asm("ADD r7,1");
asm("ADC r8,0");
asm("MOV R19, R7");
asm("LDI R20, hi8(LEN)");
asm("CPI r19, lo8(LEN)");
asm("CPC r8,r20");
asm("BRNE loop5");
asm("STS 0x0241, R1");
asm("STS 0x0240, R1");
asm("LDI R18, 152");
asm("STS 0x0664, R18");//PORTD.OUT|=(1<<4);
asm ("loop2:");
asm("INC R2");//t_i++
asm("loop5:");
}
Цитата
Вы не пробовали использовать ДМА в ping-ping режиме(DMA_DBUFMODE_CH01_gc или DMA_DBUFMODE_CH23_gc и тп)? Если каналы есть, то попробуйте.
Каналы есть. Расскажите, пожалуйста, подробнее как могу использовать DMA в ping-ping режиме. (DMA_DBUFMODE_CH01_gc - если правильно понял - это ведь создание буфера DMA )