реклама на сайте
подробности

 
 
> ADC в ATtiny461, калибровка
ivainc1789
сообщение Jul 2 2010, 19:24
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 175
Регистрация: 5-01-05
Пользователь №: 1 807



Только что закончил небольшшой заказ в 10 устройств на ATtiny461. В каждом устройстве необходимо было мерить как униполярные, так
и дифф сигналы. Так как прослеживалась тенденция к повторным заказам, решил приложить определенные усилия к написанию программы
калибровки внутреннего ADC. Попытки сделать это чуть не сорвали сроки проекта - оказалось, что ADC ATtiny461 имеют существенные
разбросы по параметрам от экз к экз и др. тонкости:
1. Обычное униполярное измерение в 4 экземплярах из 10 показало ошибку в 20 LSB при напряжениях на входе около 2.2 вольт при
опоре 2.56 вольт. Вроде требования даташита выполнены - для униполярных сигналов все напряжения в доп пределах. Измерения низких
напряжений (в районе 100 mV) были практически идеальны. Насколько я понимаю, ADC в этих 4 экз. имеют слишком большой INL. Как с
этим бороться просто не представляю. А если бы устройств было не 10, а 100? Что, делать стенд для отбраковки кристаллов?
2. ADC в AVR по скорости работы и так аутсайдер, но определенные тонкости выявились и при переключениях каналов. Особенно когда
есть и униполярные и дифф. (у меня было по 2 сигнала каждого типа). Засада в том, что униполярные мерялись стабильно, но дифф
колбасило конкретно, сэмплы отличались почти в два раза. Сначала подумал, что PCB неправильно разведена, но вроде не первый раз
развожу, решил искать причину дальше. По-моему, из AVR аппликух была в свое время выдрана некая функция AdcStable():
Код
void AdcStable(void){
       signed int Vmax,Vmin,V[4];
       unsigned char i;
       //Loop until the ADC value is stable. (Vmax <= (Vmin+1))
       for (Vmax=10,Vmin=0;Vmax > (Vmin+1);){    
         V[3] = V[2];V[2] = V[1];V[1] = V[0];// сдвиг в буфере
         SETBIT(ADCSRA,ADSC);while(CHKBIT(ADCSRA,ADSC));// получить результат
         V[0] = ADC;
         Vmin = V[0];  // Vmin is the lower VOLTAGE
         Vmax = V[0];  // Vmax is the higher VOLTAGE
         for (i=0;i<=3;i++){//Save the max and min voltage
           if (V[i] > Vmax) Vmax=V[i];
           if (V[i] < Vmin) Vmin=V[i];    
         }          
       }        
     }

C ней дифф сигналы стали измеряться нормально, но косяк проявился в том, что компилятор IAR v5.50 при оптимизации по скорости
сделал так, что цикл в этой функции становился вечным и я не смог разобраться в чем дело. При оптимизации по коду все работало
нормально. Однако это наблюдение покоя так и не дало, поэтому данную функцию пришлось выкинуть. В даташите на ATmega324 написано,
что при измер дифф сигналов схеме нужно время чтобы прошли переходные процессы переключения и это время указано - 125us. Как
только поставил паузу 200us после смены мультиплексора (измерения шли группой, но single conversions) - сразу все начало измеряться нормально. Но горький осадок остался: ADC и так не быстр, скорость выборок падает с увеличением кол-ва сигналов, дак еще и переходные задерживают... Что же делать? Кто как выкручивается?
Мне особенно интересно, как все это хозяйство калибруется в серию? Это же все серьезный риск получить приключений на собственное то самое место...
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
defunct
сообщение Jul 9 2010, 22:27
Сообщение #2


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата
По-моему, из AVR аппликух была в свое время выдрана некая функция AdcStable()

такого говнокода не могло быть в AVR аппликухах. Программистов такого уровня в Atmel не держат.

Цитата
Как только поставил паузу 200us после смены мультиплексора

Многократно обсуждалось...
При смене канала просто делайте два измерения. Первое выбрасывайте, второе оставляйте.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jul 9 2010, 23:47
Сообщение #3


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(defunct @ Jul 10 2010, 04:27) *
такого говнокода не могло быть в AVR аппликухах. Программистов такого уровня в Atmel не держат.

Высокого же вы мнения о программистах атмеляsmile.gif. Однако этот код именно из их аппноты ( avr450 smile.gif )


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
defunct
сообщение Jul 10 2010, 00:44
Сообщение #4


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(AHTOXA @ Jul 10 2010, 02:47) *
Высокого же вы мнения о программистах атмеляsmile.gif.

Да, высокого, вот оригинал по ссылке:

Код
void Stable_ADC(void)                     // loop until you have a stable value
{
  int V[4];
  char i;
  int Vmax, Vmin;
  
    //Loop until the ADC value is stable. (Vmax <= (Vmin+1))
    for (Vmax=10,Vmin= 0;Vmax > (Vmin+1);)
    {
        V[3] = V[2];
        V[2] = V[1];
        V[1] = V[0];
        ADCSR |= 0x40;                      // Start a new A/D conversion
        while (!(ADCSR & (1<<ADIF)))        // wait until ADC is ready      
;
        V[0] = ADC;
        Vmin = V[0];                          // Vmin is the lower VOLTAGE
        Vmax = V[0];                          // Vmax is the higher VOLTAGE  
        /*Save the max and min voltage*/
        for (i=0;i<=3;i++)
        {
            if (V[i] > Vmax)
                Vmax=V[i];
            if (V[i] < Vmin)
              Vmin=V[i];  
        }
    }
}

функция написана и отформатирована читаемо по крайней мере.

Цитата(singlskv @ Jul 10 2010, 02:44) *
Это Вы ерунду "сморозили"...
при смене на дифф. каналах нужна просто пауза на 125мкс:
Alternatively, conversion results obtained within this period should be discarded.

Отнюдь не ерунду, а то самое "alternatively" из ДШ.
Только не уточнил что АЦП не разгонять выше 8KSPS (125 мкс --> 8Khz).
Вот например как оно делается у меня для дифф каналов:

Код
#pragma vector=TIMER1_COMPA_vect
__interrupt void T1OCAISRHandler(void)
{
    // 1ms timer event (Fd = 1kHz)
    if (!adcContext.lock)
    {
        adcContext.CurrentChan = 0;
        adcContext.DummyCycle = TRUE;   // notify to discard this result as mux channel changes
        adcContext.SampleSequence += 1; // inc sample id
        adcStartConversion( adc_GetMuxIndex( adcContext.CurrentChan ) );
        adcContext.lock = 1;
    }
    else
    {
        // overload.... skip current sample on all channels.
        adcContext.nSampleOffsetErrors += 1;
    }
}


#pragma vector=ADC_vect
__interrupt void AdcISRHandler(void)
{
    U16 Val = ADC;
    if (adcContext.DummyCycle)
    { // restart current channel
        adcStartConversion( adc_GetMuxIndex( adcContext.CurrentChan ) );
        adcContext.DummyCycle = FALSE;
    }
    else
    {

        // handle current conversion result
        adcUpdateChannel( &adcContext.Channels[ adcContext.CurrentChan ], Val );

        // switch to the next channel and launch it
        adcContext.CurrentChan++;
        if (adcContext.CurrentChan > MUX_LAST_INDEX)
        {
            adcContext.lock = 0;
            adcContext.CurrentChan = 0;
        }
        else
        {
            adcStartConversion( adc_GetMuxIndex( adcContext.CurrentChan ) );
            adcContext.DummyCycle = TRUE; // mux changes - need to discard the next result
        }

    }
}

Куда приятнее в прерывании от АЦП просто забирать 100% верный результат, чем натыкивать delay_us() в основном цикле программы убивая при этом ее портируемость и способность к расширению.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jul 10 2010, 08:55
Сообщение #5


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(defunct @ Jul 10 2010, 06:44) *
Да, высокого, вот оригинал по ссылке:
функция написана и отформатирована читаемо по крайней мере.

biggrin.gif То есть, по-вашему, отформатированный говнокод перестаёт быть говнокодом?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- ivainc1789   ADC в ATtiny461   Jul 2 2010, 19:24
- - sigmaN   А на каком именно цикле он зацикливается? Может с...   Jul 3 2010, 07:57
|- - ivainc1789   ЦитатаА если на этом виснет Кодwhile(CHKBIT...   Jul 3 2010, 18:23
- - Duhas   вообще для поточнее и побыстрее ставится внешний А...   Jul 4 2010, 09:48
|- - singlskv   Цитата(defunct @ Jul 10 2010, 02:27) Мног...   Jul 9 2010, 23:44
||- - defunct   Цитата(AHTOXA @ Jul 10 2010, 11:55) То ес...   Jul 10 2010, 19:45
||- - AHTOXA   Цитата(defunct @ Jul 11 2010, 01:45) крит...   Jul 10 2010, 20:27
||- - defunct   Цитата(AHTOXA @ Jul 10 2010, 23:27) Вы не...   Jul 10 2010, 21:26
||- - AHTOXA   Цитата(defunct @ Jul 11 2010, 03:26) В пе...   Jul 10 2010, 22:02
||- - defunct   Цитата(AHTOXA @ Jul 11 2010, 01:02) Обычн...   Jul 11 2010, 04:04
|- - singlskv   Цитата(defunct @ Jul 10 2010, 04:44) Отню...   Jul 10 2010, 21:42
|- - defunct   Цитата(singlskv @ Jul 11 2010, 00:42) - В...   Jul 10 2010, 21:57
- - xemul   Цитата(ivainc1789 @ Jul 2 2010, 23:24) .....   Jul 10 2010, 09:57
- - sigmaN   Ееее. Моя любимая тема - говнокод! Хоть п...   Jul 10 2010, 23:56


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 10:25
Рейтинг@Mail.ru


Страница сгенерированна за 0.01435 секунд с 7
ELECTRONIX ©2004-2016