Jump to content

    
Sign in to follow this  
alux

Разный результат чтения АЦП AD7799

Recommended Posts

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(); ОС передает управление другим процессам. Но почему-то вылазит лишняя единица.

Какие будут предположения по этому поводу?

Share this post


Link to post
Share on other sites
Уровень на входе SCLK перед операциями с AD7799 всегда высокий?
Да, как положено по даташиту. Если бы в этом проблема была, то не работало бы по опросу пина.

Share this post


Link to post
Share on other sites

Стоит посмотреть, не перенастраивается ли пин CS при разрешениях/запрещениях источника прерываний. Ну и какое чтение - аппаратный SPI (тогда он может с неподключенным MISO начинать читать, хотя был бы скорее лишний ноль) или ручками? А то куча текста, а ключевые моменты зачем-то отсутствуют. И не знаю, и не развернут у меня фриртос - как там (или у Вас) этот обработчик прописан и обрамление - не видел.

Share this post


Link to post
Share on other sites
не перенастраивается ли пин CS при разрешениях/запрещениях источника прерываний.

Нет, не перестраивается. В данном случае по SPI работает только AD7799.

Ну и какое чтение - аппаратный 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                
}

 

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

Нужно читать данные в прерывании и только после этого сигналить.
Попробовал так:

#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.

Share this post


Link to post
Share on other sites
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)
...........

Share this post


Link to post
Share on other sites

Вот это

// DISABLE_INT7; // Prevent further external interrupts

что такое? Ведь после первого бита, 0х800000 ещё до того, как закончилось чтение первого байта, опять появится флаг. И чего там

for(unsigned char volatile i=0; i < nmax; i++)
насобирает своим

accumulator += ad7799_read_data(); // Накапливаем результат в аккумуляторе

это очень веселый вопрос. Будет регулярное суммирование 0х800000 с холостым 0xFFFFFF. Рулить этим запрещением/разрешением, думаю, стОит очень внимательно;)

Share this post


Link to post
Share on other sites
Рулить этим запрещением/разрешением, думаю, стОит очень внимательно;)
Да, это я тормознул :)

Прерывание 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, что направили на путь истинный ;)

 

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

Share this post


Link to post
Share on other sites
А все-таки, почему если читать данные в обработчике прерывания INT7 и очищать флаг, то возникает проблема?

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

Share this post


Link to post
Share on other sites

alux, хотел в личку написать, но функция не доступна, поэтому в теме.

работаю с ad7799, драйвер взял, тот что у вас, конфигурацию выставил..

 

однако почему-то при выполнении ad7799_read_data() получаю только значение 0xFFFF8000

хотя датчик, который идет на АЦП выдает разное напряжение как и должно быть..

 

не могли бы вы привести полный код с драйвером, может я че-то где то упустил..

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this