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

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

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

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

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


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

Может быть некорректное формирование импульсов SCLK. Уровень на входе SCLK перед операциями с AD7799 всегда высокий?

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


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

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

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


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

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

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


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

не перенастраивается ли пин 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.

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


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

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

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


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

Вот это

// DISABLE_INT7; // Prevent further external interrupts

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

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

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

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

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


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

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

Прерывание 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 и очищать флаг, то возникает проблема?

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


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

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

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

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


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

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

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

 

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

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

 

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

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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