|
Разный результат чтения АЦП AD7799, методом опроса RDY или по прерыванию от RDY. |
|
|
|
Aug 27 2008, 14:00
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
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(); ОС передает управление другим процессам. Но почему-то вылазит лишняя единица. Какие будут предположения по этому поводу?
|
|
|
|
|
 |
Ответов
(1 - 11)
|
Aug 28 2008, 13:39
|
Участник

Группа: Новичок
Сообщений: 38
Регистрация: 22-06-04
Из: г.Киев
Пользователь №: 101

|
Нужно читать данные в прерывании и только после этого сигналить.
|
|
|
|
|
Aug 28 2008, 18:34
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(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.
|
|
|
|
|
Aug 29 2008, 03:09
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(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) ...........
|
|
|
|
|
Aug 29 2008, 05:08
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Вот это Цитата // DISABLE_INT7; // Prevent further external interrupts что такое? Ведь после первого бита, 0х800000 ещё до того, как закончилось чтение первого байта, опять появится флаг. И чего там Цитата for(unsigned char volatile i=0; i < nmax; i++) насобирает своим Цитата accumulator += ad7799_read_data(); // Накапливаем результат в аккумуляторе это очень веселый вопрос. Будет регулярное суммирование 0х800000 с холостым 0xFFFFFF. Рулить этим запрещением/разрешением, думаю, стОит очень внимательно
--------------------
aka Vit
|
|
|
|
|
Aug 29 2008, 17:57
|
Знающий
   
Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447

|
Цитата(sensor_ua @ Aug 29 2008, 08:08)  Рулить этим запрещением/разрешением, думаю, стОит очень внимательно  Да, это я тормознул Прерывание 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 и очищать флаг, то возникает проблема?
|
|
|
|
|
Aug 29 2008, 19:53
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата А все-таки, почему если читать данные в обработчике прерывания INT7 и очищать флаг, то возникает проблема? Не ясно. Может, прерывания вложенные разрешены (см. как оно в этой архитектуре/сборке ОС) и чегой-то интересное получается. Да и как там с событиями?- они ж наверно в очередь событий укладываются и garbage collector для неё врядли предусмотрен, ну и какие-то куски кода, цепляющиеся за события могли остаться при тесте
--------------------
aka Vit
|
|
|
|
|
Apr 28 2011, 07:17
|
Группа: Новичок
Сообщений: 3
Регистрация: 11-11-10
Пользователь №: 60 799

|
alux, хотел в личку написать, но функция не доступна, поэтому в теме. работаю с ad7799, драйвер взял, тот что у вас, конфигурацию выставил..
однако почему-то при выполнении ad7799_read_data() получаю только значение 0xFFFF8000 хотя датчик, который идет на АЦП выдает разное напряжение как и должно быть..
не могли бы вы привести полный код с драйвером, может я че-то где то упустил..
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|