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

Устройство должно измерять три аналоговых сигнала: AS1, AS2, AS3. Таймер 1 переполняется каждые 32 мкс. К факту переполнения привязан ADC с общими настройками:

 

  

  ADCSRA = BIN(10111101); // ADC 250kHz при Fbq=8MHz, включен

  ADCSRB = BIN(00000110);

 

Конечно, таймер 1 переполняется чаще, чем ADC успевает выполнить одно преобразование, но это пока представляется не важным.

 

Обработчик прерывания по завершению преобразования выполнен так:

 

// ADC Conversion Complete
#pragma vector = ADC_vect
__interrupt void ADC_COMPLITE(void) {
  unsigned int tmp = ADC;
  if(ADMUX == BIN(10010010)){AS1 = tmp;ADMUX = BIN(10000010);return;}
  if(ADMUX == BIN(10000010)){AS2 = tmp;ADMUX = BIN(10000011);return;}
  if(ADMUX == BIN(10000011)){AS3 = tmp;ADMUX = BIN(10010010);return;}
}

 

Казалось бы, все правильно: закончили одно преобразование, забрали результат, посмотрели от какого MUX оно произошло и записали в соотв глобалную переменную. Но не работает. Причина установлена, заключается в том, что ADMUX некорректно менять в данный момент в данном прерывании. Если читать только одну величину преобразования (не меняя ADMUX) ее значение получается правильным и устройство работает.

 

В даташите по поводу работы с мультиплексором написано на стр.147-148:

 

 

 

If Auto Triggering is used, the exact time of the triggering event can be indeterministic. Special

 

care must be taken when updating the ADMUX Register, in order to control which conversion

will be affected by the new settings.

If both ADATE and ADEN is written to one, an interrupt event can occur at any time. If the

ADMUX Register is changed in this period, the user cannot tell if the next conversion is based

on the old or the new settings. ADMUX can be safely updated in the following ways:

a. When ADATE or ADEN is cleared.

b. During conversion, minimum one ADC clock cycle after the trigger event.

c. After a conversion, before the Interrupt Flag used as trigger source is cleared.

When updating ADMUX in one of these conditions, the new settings will affect the next ADC

conversion.

 

 

Использовать вариант (a) как-то не хочется, вкл/выкл ADC на такой частоте чреват переходными процессами... Хотелось бы все же менять ADMUX в прерывании по окончанию преобразования, но как это лучше сделать и можно ли понять пока не смог...

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


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

....

Использовать вариант (a) как-то не хочется, вкл/выкл ADC на такой частоте чреват переходными процессами... Хотелось бы все же менять ADMUX в прерывании по окончанию преобразования, но как это лучше сделать и можно ли понять пока не смог...

Может измерять каждый канал по два раза подряд, и использовать только результат второго преобразования? Насколько критична скорость оцифровки?

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


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

Может измерять каждый канал по два раза подряд, и использовать только результат второго преобразования? Насколько критична скорость оцифровки?

 

Скорость оцифровки желательно иметь максимальную. Вопрос по сути: как правильно менять настройки ADMUX для трех AS1,AS2,AS3 при триггерировании ADC от TOV1, если период триггерного сигнала меньше, чем время преобразования ADC?

 

Варианты (B) и (с) даташита сложно использовать для обеспеч. макс скорости оцифровки...

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


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

Если ADC работает в режиме одиночного преобразоания, то в прерывании от него можно изменить ADMUX и запустить следующее преобразование- получится псевдо автоматический режим.

Или по другому - ADC молотит непрерывно, в прерывании мы сохраняем результат преобразования в зависимости от ADMUX, т.е. если второй канал в ADMUX, то результат отностися к первому каналу :), третий - результат от второго. Далее ADMUX меняется.

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


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

Если ADC работает в режиме одиночного преобразоания, то в прерывании от него можно изменить ADMUX и запустить следующее преобразование- получится псевдо автоматический режим.

Или по другому - ADC молотит непрерывно, в прерывании мы сохраняем результат преобразования в зависимости от ADMUX, т.е. если второй канал в ADMUX, то результат отностися к первому каналу :) , третий - результат от второго. Далее ADMUX меняется.

 

Да, это все понятно. Я так и сделал: ADC молотит по кругу:

 

#define AS1set      BIN(10000011)// mux const for AS1
#define AS2set      BIN(10010010)// mux const for AS2-AS1
#define AS3set      BIN(10000010)// mux const for AS3

__C_task void main (void) {
  // settings for ADC
  ADMUX = AS2set;         
  ADCSRA = BIN(10011101); 
  ADCSRB = BIN(00000000);  
  DIDR0 = BIN(11111111);
  DIDR1 = BIN(11110000);
  __enable_interrupt();
  
  SETBIT(ADCSRA,ADSC);// first ADC conversion start

  while(1);
}



// ADC Conversion Complete
#pragma vector = ADC_vect
__interrupt void ADC_COMPLITE(void) {
  //AS2value = ADC;
  switch(ADMUX){
    case AS1set: ADMUX = AS2set;AS1value = ADC;break;
    case AS2set: ADMUX = AS3set;AS2value = ADC;break;
    case AS3set: ADMUX = AS1set;AS3value = ADC;break; 
  }
  SETBIT(ADCSRA,ADSC);
}

 

Проверил: сигналы AS1 и AS3 измеряются нормально. А вот AS2 - это дифференциальный сигнал, пропущенный через внутр. инструментальный усилитель. Вот с ним-то и возникают проблемы:

 

1. Если обработчик использовать как приведено выше (мультиплексор периодически переключается), то ADC = 0 для сигнала AS2.

 

2. Если в обработчике убрать весь оператор SWITCH и раскомментировать строку //AS2value = ADC;, т.е. мультиплексор остается ПОСТОЯННО настроенным для сигнала AS2, то данный сигнал измеряется нормально.

 

Никак не могу понять, почему так???

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


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

И, наконец, окончательно установлено: в ATtiny461 переключение мультиплексора ADC с single ended input на differential input приведет к последующему ошибочному преобразованию, которое необходимо пропустить. Что-то в даташите на данную тему никаких notes не обнаружено. Для моего случая обработчик должен выглядеть так:

 

unsigned char ADMUXval=0;
// ADC Conversion Complete
#pragma vector = ADC_vect
__interrupt void ADC_COMPLITE(void) {
  //AS2value = ADC;
switch(ADMUXval){
    case 0: break;// холостое измерение для AS2
    case 1: ADMUX = AS1set;AS2value = ADC;break;
    case 2: ADMUX = AS3set;AS1value = ADC;break;
    case 3: ADMUX = AS2set;AS3value = ADC;ADMUXval=0xFF;break;    
  }  
  ADMUXval++;
  SETBIT(ADCSRA,ADSC);// начать очередное преобразование
}

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


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

И, наконец, окончательно установлено:

............................

Покажите наконец весь код ....:)

Ваша проблема скорее всего заключается в использовании 2 прерываний для работы с ADC,

в итоге Вы и имеете то что переключение каналов происходит в момент когда его нельзя

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

Вы выставили флаг начать преобразование и НЕ начинается синхронно от таймера в случае

если частота преобразования ADC не кратна частоте таймера.

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


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

Покажите наконец весь код .... :)

Ваша проблема скорее всего заключается в использовании 2 прерываний для работы с ADC,

в итоге Вы и имеете то что переключение каналов происходит в момент когда его нельзя

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

Вы выставили флаг начать преобразование и НЕ начинается синхронно от таймера в случае

если частота преобразования ADC не кратна частоте таймера.

 

Весь код я привел выше. Единственное, о чем умолчал - как я определял правильно измеряется величина ADC или нет. Так как Дракона под рукой все еще пока нет использовались два метода:

 

1. Значение AS2value (по сути значение ADC для сигнала AS2) записывалось в EEPROM с периодом 5 сек. В некоторый момент EEPROM считывалась программатором. Если мультиплексор переключался в прерывании по оконч преобр., то считывалось из EEPROM AS2value == 0;

 

2. Так как программатор самопал, в истинности считывания я усомнился и для контроля инициализировал таймер1 в режим inverted fastPWM, далее значение ADC записывалось в регистр сравнения. Контроль скважности проводился на пине OC1D. При увеличении значения ADC ширина импульсов должна была уменьшаться - так и было для всех трех сигналов, если mux не переключать в прерывании по оконч. преобразования...

 

Заметьте, что флаг ADATE в исправленном коде не установлен. То есть ADC работает в режиме единичного преобразования но с разрешенным прерыванием по оконч. преобраз. В обработчике стартует новое преобраз. Так организовано зацикливание. Согласно даташиту, если ADATE не установлен, то ADMUX можно безопасно записывать. Но даже в этом случае, если не пропускалось "битое" измерение от AS2, AS2value == 0, а на выводе OC1D присутствовал высокий уровень...

 

Далее я пробовал менять записи в ADMUX в прерывании, т. е. измерял сигналы в разной последовательности. И опять: только дифференциальный сигнал AS2 всегда возвращал некорректное (нулевое) значение...

 

 

"Двойственность" прерываний легко проверить. Для этого устанавливаем в единицу какой-либо тестовый пин в начале обработчика и сбрасываем его в ноль в конце. В моем случае на осцилле наблюдались короткие прямоуголные импульсы с периодом 62 мкс.

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


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

a. When ADATE or ADEN is cleared.

b. During conversion, minimum one ADC clock cycle after the trigger event.

c. After a conversion, before the Interrupt Flag used as trigger source is cleared.

When updating ADMUX in one of these conditions, the new settings will affect the next ADC conversion.

 

 

 

Использовать вариант (a) как-то не хочется,...

А придется... Выключаешь ADEN по влету в прерывание и включаешь по выходу (при запуске следующего преобразования). При этом длительность каждого преобразования удваивается...

 

Или попробуй убрать из своей программы использование SLEEP-а. На Мегах48 это мне помогло...

Изменено пользователем ArtemKAD

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


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

Весь код я привел выше.....

"Двойственность" прерываний легко проверить. Для этого устанавливаем в единицу какой-либо тестовый пин в начале обработчика и сбрасываем его в ноль в конце......

Вопрос не в "двойственности" прерываний, вопрос в том вовремя

ли Вы меняете ADMUX или нет ?

Приведите весь код, и настройку таймером в том числе, да, Вы вроде еще и результаты

тестов в EEPROM писали ? , тоже укажите как Вы это делали.

 

 

А придется... Выключаешь ADEN по влету в прерывание и включаешь по выходу (при запуске следующего преобразования). При этом длительность каждого преобразования удваивается...
Так нужно ? Правда ?

Что я не так делаю, что у меня и без этого преобразования на разных каналах правильно работают ?

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


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

Что я не так делаю, что у меня и без этого преобразования на разных каналах правильно работают ?

Наткнулся на эту особенность на мегах. Особенность - "перетекание" сигнала с другого канала при переключении ADMUX-ов.

Наблюдалась только при использовании SLEEP-а. Без SLEEP-а "перетекание" не обнаружил.

 

Решения проблемы у меня получилось два - оба с почти одинаковым результатом. Или включение/выключение АЦП (что заставляло ее принудительно запустить холостое преобразование - те самые 25 тактов) или убиранием команды SLEEP.

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


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

Привожу полный код. Оказывается, в прерывании от ADC важна последовательность измерения сигналов. Один из трех измеренных измеряется неверно. Теперь это AS3.

 

// мультиплексор ADC
#define AS1set      BIN(10000011)// для сигнала AS1
#define AS2set      BIN(10010010)// для сигнала AS2-AS1
#define AS3set      BIN(10000010)// для сигнала AS3
/********************************************************************************/
unsigned int AS3value,AS2value,AS1value;
unsigned int __eeprom A;
/********************************************************************************/
__C_task void main (void) {
  SETUP(SWUP,OUT0);SETUP(SWBAT,OUT0);SETUP(SWPWR,OUT0);
  SETUP(AS1GND,OUT0);SETUP(AS2GND,OUT0);SETUP(AS4GND,OUT0);// подключить делители 
  
  // общие настройки компаратора
  CLRBIT(ACSRA,ACIE);
  ACSRA = BIN(01010000);  // компаратор с AIN+ = BANDGAP_REF включен
  ACSRB = BIN(00000100);
  //SETBIT(ACSRA,ACIE);
  
  // общие настройки ADC
  ADMUX = AS2set;         // опора компаратора и ADC = 1.1 вольт
  ADCSRA = BIN(10011101); // ADC 250kHz при Fbq=8MHz,включен,прерывание по оконч.
  ADCSRB = BIN(00000000);  
  DIDR0 = BIN(11111111);// отключить входные буферы ADC(нет вх цифровых сигналов)
  DIDR1 = BIN(11110000);
  
  Tmr1Ini();
  __enable_interrupt();
  
  SETBIT(ADCSRA,ADSC);// начать первое преобразование
  Tmr1Start;
Work:
   {
    unsigned int tmp;
    __disable_interrupt();
    tmp = AS3value;// !!!!!!!!!!!!!значение AS3 наблюдаем неверное!!!!!!!!!!!!
    __enable_interrupt();
   A = tmp;
   }
  goto Work; 
}
/********************************************************************************/
// Timer/Counter1 Overflow 
#pragma vector = TIM1_OVF_vect
__interrupt void TIM1_OVF(void) {
  unsigned char tmp2;
  tmp2 = AS3value;// !!!!!!!!!!!!!значение AS3 наблюдаем неверное!!!!!!!!!!!!
  TC1H = ((tmp2 >> 8) & 0x0003);
  OCR1D = (tmp2 & 0x00FF);// загрузка величины сравнения для след. цикла   
}

// ADC Conversion Complete
#pragma vector = ADC_vect
__interrupt void ADC_COMPLITE(void) {
  SETBIT(ADCSRA,ADSC);// начать преобразование по текущему ADMUX  
  switch(ADMUX){// установить следующий ADMUX
    case AS1set: ADMUX = AS2set;AS1value = ADC;break;
    case AS2set: ADMUX = AS3set;AS2value = ADC;break;
    case AS3set: ADMUX = AS1set;AS3value = ADC;break;    
  }
}
/********************************************************************************/
// ини таймера1 для stepDown и stepUp регуляторов
void Tmr1Ini(void){
  Tmr1Stop;
  CLRBIT(PRR,PRTIM1);   // включить модуль таймера 1
  SETBIT(PLLCSR,LSM);   // PLL = 32MHz    
  SETBIT(PLLCSR,PLLE);Delay(200*us);do{}while(!CHKBIT(PLLCSR,PLOCK));// запуск PLL    
  SETBIT(PLLCSR,PCKE);  // разрешить тактирование таймера от PLL
  TCCR1A = BIN(00110001);
  TCCR1B = BIN(01000000);do{}while(CHKBIT(TCCR1B,PSR1));// сброс прескалера  
  TCCR1C = BIN(00111101);
  TCCR1D = BIN(00000000);
  TCCR1E = BIN(00000000);
  DT1 = 0x00;
  Reg10write(TCNT1reg,0x000);
  Reg10write(OCR1Areg,0x3FF);
  Reg10write(OCR1Breg,0x3FF);
  Reg10write(OCR1Creg,0x3FF);
  Reg10write(OCR1Dreg,0x3FF);  
  SETBIT(TIFR,TOV1);
  SETBIT(TIMSK,TOIE1);    
}
/********************************************************************************/

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


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

Вопрос по сути: как правильно менять настройки ADMUX для трех AS1,AS2,AS3 при триггерировании ADC от TOV1, если период триггерного сигнала меньше, чем время преобразования ADC?

Вы хотите заставить АЦП мерять чаще чем он может? Нмкак нельзя, так как напряжение на накопительной емкости используется для сравнения в течение всего преобразования. Так же желательно не использовать первый результат преобразования при переключении входа АЦП.

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


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

// ADC Conversion Complete
#pragma vector = ADC_vect
__interrupt void ADC_COMPLITE(void) {
  SETBIT(ADCSRA,ADSC);// начать преобразование по текущему ADMUX  
  switch(ADMUX){// установить следующий ADMUX
    case AS1set: ADMUX = AS2set;AS1value = ADC;break;
    case AS2set: ADMUX = AS3set;AS2value = ADC;break;
    case AS3set: ADMUX = AS1set;AS3value = ADC;break;    
  }
}

Проблема в том что Вы сначала запускаете преобразование SETBIT(ADCSRA,ADSC);

и тут же меняете номер канала ADMUX = ....

SETBIT(ADCSRA,ADSC); НЕ запускает преобразование немедленно,

реально новое преобразование запустится только когда начнется очередной такт ADC клока.

Попробуйте так:

// ADC Conversion Complete
#pragma vector = ADC_vect
__interrupt void ADC_COMPLITE(void) {

  switch(ADMUX){// установить следующий ADMUX
    case AS1set: ADMUX = AS2set;AS1value = ADC;break;
    case AS2set: ADMUX = AS3set;AS2value = ADC;break;
    case AS3set: ADMUX = AS1set;AS3value = ADC;break;    
  }
  SETBIT(ADCSRA,ADSC); // запускаем новый канал
}

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


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

реально новое преобразование запустится только когда начнется очередной такт ADC клока.

Попробуйте так:

 

Честно сказать, много приходилось заниматься AVR кристаллами, но такого капризного как 461 я никогда не встречал... Слабое место тиней 461 - это безусловно мультиплексор. Может из-за того, что сильно уж наворочен. Уже два кристалла вышли из строя при долговременной (около часа) работе при штатном режиме! Причем в одном сдох мультиплексор компаратора, а в другом - АЦП. Перенапряжения исключены, программа не перепрошивалась: просто работала ИС работала и в какой-то момент - отказ. Выражается это в том, что входы мультиплексоров вдруг по неизвестной причине садятся на землю. Причем к этим входам подключены делители от 12 вольт 56к/2к7 - достаточно безопасное подключение... При всем этом ИС нормально прошивается, читается сигнатура и т. д. Насколько пока позволило время разобраться - отказ получается частичный. У меня ревизия А.

 

Что касается момента начала преобразования, то, конечно, я инструкцию изначально ставил и после установки мультиплексора в прерывании, однако это не спасало: дифф сигнал не измерялся, АЦП выдавал только 0... Вскоре после множества экспериментов созрела идея: так как аналоговые сигналы посупают на входы через делители а выход АЦП контролируется по ШИМу, то можно просто последовательно контролировать сигналы замыкая делители на входах через амперметр. Если именно НУЖНЫЙ сигнал измеряется, на выводе OCR1D должен установиться высокий уровень в момент замыкания делителя. Так вот, для single ended сигналов такой фокус сработал безотказно, а для дифф - стоял высокий уровень и на шаманство с делителями вообще не отзывался. При этом в прерывании инструкция начала преобразования стояла после выбора ADMUX. Короче, предполагаю, что мне попались не совсем исправные ИС, при условии, что в даташите нет опечаток в таблицах мультиплексоров...

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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