Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Разный результат чтения АЦП AD7799
Форум разработчиков электроники ELECTRONIX.ru > Аналоговая и цифровая техника, прикладная электроника > Метрология, датчики, измерительная техника
alux
24-битное АЦП AD7799 меряет сигнал мостового датчика давления. Вывод MISO AT90USB1287 (DOUT AD7799) соединен с INT7 на AT90USB1287. Привожу код, чтобы было понятно о чем речь. Если читать АЦП через опрос вывода RDY, то все в порядке - вывожу на ЖКИ в виде кодов АЦП (0х000000 соответствует максимальному отрицательному давлению, 0х800000 соответствует отсутствию давления, 0хffffff соответствует максимальному положительному давлению). А если вместо
Код
while(!ad7799_data_ready());
написать
Код
Int7.Wait();
(это OS::TEventFlag - флаг события из ОС scmRTOS. В данном случае сигнал сообщения возникает из прерывания Int7.SignalISR(); ) , то вместо 0х800000 выводится 0хС00000, т.е. появляется "лишняя" единица в старшем предпоследнем разряде. Почему так происходит, - не пойму никак.
Код
void ad7799_Init(void)
{  
  ad7799_reset();
  delay_ms(500);
  ad7799_init_status = ad7799_status();
  
  // Enable external interrupt INT7
  ENABLE_INT7;      // Enable external interrupt INT7  falling edge
}


//============================================================
// Запуск непрерывного преобразования на AIN1
//______________________________________________________________________________
void start_Measure(void)
{
  ad7799_write_config(1, 0, AD7799_32_GAIN, 1, 1, AD7799_AIN1_CHAN);        //burnout, bipolar, gain, ref_det, buf, chan
  ad7799_set_mode(AD7799_CONTINUOUS_CONVERSION_MODE, 0, AD7799_470_HZ+rate);  //mode, psw=0(OFF), rate    

  while(!ad7799_data_ready());
  ad7799_request_data(1);           // 1 -> Continuous Read
  PORTB &= ~(1<<DIN);               // Held Low in Continuous-Read mode
}


/*** External interrupt handler ***/
#pragma vector=INT7_vect
OS_INTERRUPT void INT7_ISR()
{
  OS::TISRW_SS ISRW;
  
//  DISABLE_INT7;          // Prevent further external interrupts
  
  Int7.SignalISR();  
}

//////////////////////////////////////////////
//-------------------------------------------------------------------------------
OS_PROCESS void TMeasure::Exec()    //TProc2
{
    for(;;)
    {
        for(unsigned char volatile i=0; i < nmax; i++)
        {
          //Int7.Wait();                   // Ждем окончания преобразования АЦП (RDY => 0)
          while(!ad7799_data_ready());
          accumulator += ad7799_read_data();  // Накапливаем результат в аккумуляторе
        }        

        m.data[mux] = accumulator/nmax;     // Усреднение результата
        accumulator=0;

        //Int7.Wait();                   // Ждем окончания преобразования АЦП (RDY => 0)
        while(!ad7799_data_ready());
        ad7799_request_data(0);     // 0 -> Not Continuous Read  
        
         // Maintain multiplexing of input channels
          if(++mux > 1)  mux=0;      
          ad7799_write_config(1, 0, AD7799_32_GAIN, 1, 1, AD7799_AIN1_CHAN+mux); //burnout, bipolar, gain, ref_det, buf, chan  

//        ad7799_set_mode(AD7799_CONTINUOUS_CONVERSION_MODE, 0, AD7799_16_7_1_HZ); //mode, psw=0(OFF), rate

        //Int7.Wait();                   // Ждем окончания преобразования АЦП (RDY => 0)  
        while(!ad7799_data_ready());
        ad7799_request_data(1);     // 1 -> Continuous Read    
        PORTB &= ~(1<<DIN);         // Held Low in Continuous-Read mode

        if(!mux)
        {
          m.src = TValueADC::AD7799_SRC;
          ValueMsg = m;       // put the content to the OS::message object
          ValueMsg.send();    // send the message
        }
        Sleep(100);
      }
}

Это делается для того, чтобы не тратить время процессора на опрос бита RDY. Во время Int7.Wait(); ОС передает управление другим процессам. Но почему-то вылазит лишняя единица.
Какие будут предположения по этому поводу?
akl
Может быть некорректное формирование импульсов SCLK. Уровень на входе SCLK перед операциями с AD7799 всегда высокий?
alux
Цитата(akl @ Aug 28 2008, 09:12) *
Уровень на входе SCLK перед операциями с AD7799 всегда высокий?
Да, как положено по даташиту. Если бы в этом проблема была, то не работало бы по опросу пина.
GPP
Нужно читать данные в прерывании и только после этого сигналить.
sensor_ua
Стоит посмотреть, не перенастраивается ли пин CS при разрешениях/запрещениях источника прерываний. Ну и какое чтение - аппаратный SPI (тогда он может с неподключенным MISO начинать читать, хотя был бы скорее лишний ноль) или ручками? А то куча текста, а ключевые моменты зачем-то отсутствуют. И не знаю, и не развернут у меня фриртос - как там (или у Вас) этот обработчик прописан и обрамление - не видел.
alux
Цитата(sensor_ua @ Aug 28 2008, 19:38) *
не перенастраивается ли пин CS при разрешениях/запрещениях источника прерываний.

Нет, не перестраивается. В данном случае по SPI работает только AD7799.
Цитата(sensor_ua @ Aug 28 2008, 19:38) *
Ну и какое чтение - аппаратный SPI (тогда он может с неподключенным MISO начинать читать, хотя был бы скорее лишний ноль) или ручками?

SPI в данном случае аппаратный без использования прерывания:
Код
//------------------------------------------------------------------------------
unsigned char spiTransferByte(unsigned char data)
{
  unsigned char temp;
  
#ifdef SPI_USEINT
    spiTransferComplete = false;
    SPDR = data;                    // send the given data
    while(!spiTransferComplete);    // wait for transfer to complete
#else
    SPDR = data;                    // send the given data
    while(!(SPSR & (1<<SPIF)));    // wait for transfer to complete
#endif
        temp = SPDR;            // read value in SPI data reg.
    return temp;                    // return the received data                
}


Цитата(sensor_ua @ Aug 28 2008, 19:38) *
А то куча текста, а ключевые моменты зачем-то отсутствуют.
Какие еще ключевые моменты нужны? Я не вижу смысла расписывать мелкие функции драйвера АЦП. На мой взгляд проблема в том, что после готовности данных АЦП и моментом чтения проходит время, и портится результат следующего преобразования.
Цитата(GPP @ Aug 28 2008, 16:39) *
Нужно читать данные в прерывании и только после этого сигналить.
Попробовал так:
Код
#pragma vector=INT7_vect
OS_INTERRUPT void INT7_ISR()
{
  OS::TISRW_SS ISRW;

  accumulator += ad7799_read_data();  // Накапливаем результат в аккумуляторе
  
  if(++count > nmax)
  {
    count = 0;
    m.data[mux] = accumulator/nmax;   // Усреднение результата
    accumulator = 0;
    Int7.SignalISR();
  }
}
стало еще хуже - вместо 0х800000 выводит 0хffffff.
sensor_ua
CS используется?
alux
Цитата(sensor_ua @ Aug 28 2008, 22:06) *
CS используется?

Да. К SPI подключен еще AT45D321. Но он деактивирован по CS:
Код
//------------------------------------------------------------------------------
void spi_Init(void)
{
    // setup SPI I/O pins
    PORTB |= (1<<P_SCK)|(1<<P_MISO);      // set SCK high, pull-up on P_MISO
        DF_CS_inactive;                                          // -> PORTB |= (1<<CS2)
        // SS must be output for Master mode to work
    DDRB |= (1<<P_SCK)|(1<<P_MOSI)|(1<<P_SS); // set SCK, MOSI, SS as output
    DDRB &= ~(1<<P_MISO);                      // set MISO as input
    
    // setup SPI interface :
    // master mode
    SPCR |= (1<<MSTR);
    // clock = f/16
    SPCR |= (1<<SPR0);
    SPCR &= ~(1<<SPR1);
    // select clock phase negative-going in middle of data
    SPCR |= (1<<CPOL);
        // data is sampled on the trailing (last) edge of SCK. SPI Mode - 3
        SPCR |= (1<<CPHA);
    // Data order MSB first
    SPCR &= ~(1<<DORD);
    // enable SPI
    SPCR |= (1<<SPE);
    
    // clear status
    SPSR = SPSR;
    spiTransferComplete = true;

    // enable SPI interrupt
    #ifdef SPI_USEINT
    SPCR |= (1<<SPIE);
    #endif
}
В начале функции инициализации АЦП устанавливаю соответствующий CS, и больше его не меняю:
Код
void ad7799_Init(void)
{
  DF_CS_inactive;
  ADC_CS_active;        // -> PORTB &= ~(1 << CS1)
...........
sensor_ua
Вот это
Цитата
// DISABLE_INT7; // Prevent further external interrupts

что такое? Ведь после первого бита, 0х800000 ещё до того, как закончилось чтение первого байта, опять появится флаг. И чего там
Цитата
for(unsigned char volatile i=0; i < nmax; i++)
насобирает своим
Цитата
accumulator += ad7799_read_data(); // Накапливаем результат в аккумуляторе

это очень веселый вопрос. Будет регулярное суммирование 0х800000 с холостым 0xFFFFFF. Рулить этим запрещением/разрешением, думаю, стОит очень внимательноwink.gif
alux
Цитата(sensor_ua @ Aug 29 2008, 08:08) *
Рулить этим запрещением/разрешением, думаю, стОит очень внимательноwink.gif
Да, это я тормознул smile.gif
Прерывание INT7 разрешено постоянно. Если очищать флаг внешнего прерывания после ad7799_read_data(), то все равно выводит не то, что надо.

Код
#pragma vector=INT7_vect
OS_INTERRUPT void INT7_ISR()
{
  OS::TISRW_SS ISRW;

  accumulator += ad7799_read_data();  // Накапливаем результат в аккумуляторе
  EIFR |= (1<<INTF7);             // Clear interrupt status flag
.....................
}

А почему?

PS. Проблема решилась запрещением прерывания INT7 в обработчике прерывания и разрешением его сразу после чтения данных АЦП в коде, приведенном в первом посте. Спасибо, sensor_ua, что направили на путь истинный wink.gif

PS2. А все-таки, почему если читать данные в обработчике прерывания INT7 и очищать флаг, то возникает проблема?
sensor_ua
Цитата
А все-таки, почему если читать данные в обработчике прерывания INT7 и очищать флаг, то возникает проблема?

Не ясно. Может, прерывания вложенные разрешены (см. как оно в этой архитектуре/сборке ОС) и чегой-то интересное получается. Да и как там с событиями?- они ж наверно в очередь событий укладываются и garbage collector для неё врядли предусмотрен, ну и какие-то куски кода, цепляющиеся за события могли остаться при тесте
Layer
alux, хотел в личку написать, но функция не доступна, поэтому в теме.
работаю с ad7799, драйвер взял, тот что у вас, конфигурацию выставил..

однако почему-то при выполнении ad7799_read_data() получаю только значение 0xFFFF8000
хотя датчик, который идет на АЦП выдает разное напряжение как и должно быть..

не могли бы вы привести полный код с драйвером, может я че-то где то упустил..
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.