alux 0 27 августа, 2008 Опубликовано 27 августа, 2008 · Жалоба 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 0 28 августа, 2008 Опубликовано 28 августа, 2008 · Жалоба Может быть некорректное формирование импульсов SCLK. Уровень на входе SCLK перед операциями с AD7799 всегда высокий? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 28 августа, 2008 Опубликовано 28 августа, 2008 · Жалоба Уровень на входе SCLK перед операциями с AD7799 всегда высокий?Да, как положено по даташиту. Если бы в этом проблема была, то не работало бы по опросу пина. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GPP 0 28 августа, 2008 Опубликовано 28 августа, 2008 · Жалоба Нужно читать данные в прерывании и только после этого сигналить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sensor_ua 0 28 августа, 2008 Опубликовано 28 августа, 2008 · Жалоба Стоит посмотреть, не перенастраивается ли пин CS при разрешениях/запрещениях источника прерываний. Ну и какое чтение - аппаратный SPI (тогда он может с неподключенным MISO начинать читать, хотя был бы скорее лишний ноль) или ручками? А то куча текста, а ключевые моменты зачем-то отсутствуют. И не знаю, и не развернут у меня фриртос - как там (или у Вас) этот обработчик прописан и обрамление - не видел. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 28 августа, 2008 Опубликовано 28 августа, 2008 · Жалоба не перенастраивается ли пин 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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sensor_ua 0 28 августа, 2008 Опубликовано 28 августа, 2008 · Жалоба CS используется? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 29 августа, 2008 Опубликовано 29 августа, 2008 · Жалоба 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 0 29 августа, 2008 Опубликовано 29 августа, 2008 · Жалоба Вот это // DISABLE_INT7; // Prevent further external interrupts что такое? Ведь после первого бита, 0х800000 ещё до того, как закончилось чтение первого байта, опять появится флаг. И чего там for(unsigned char volatile i=0; i < nmax; i++) насобирает своим accumulator += ad7799_read_data(); // Накапливаем результат в аккумуляторе это очень веселый вопрос. Будет регулярное суммирование 0х800000 с холостым 0xFFFFFF. Рулить этим запрещением/разрешением, думаю, стОит очень внимательно;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alux 0 29 августа, 2008 Опубликовано 29 августа, 2008 · Жалоба Рулить этим запрещением/разрешением, думаю, стОит очень внимательно;)Да, это я тормознул :) Прерывание 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 и очищать флаг, то возникает проблема? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sensor_ua 0 29 августа, 2008 Опубликовано 29 августа, 2008 · Жалоба А все-таки, почему если читать данные в обработчике прерывания INT7 и очищать флаг, то возникает проблема? Не ясно. Может, прерывания вложенные разрешены (см. как оно в этой архитектуре/сборке ОС) и чегой-то интересное получается. Да и как там с событиями?- они ж наверно в очередь событий укладываются и garbage collector для неё врядли предусмотрен, ну и какие-то куски кода, цепляющиеся за события могли остаться при тесте Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Layer 0 28 апреля, 2011 Опубликовано 28 апреля, 2011 · Жалоба alux, хотел в личку написать, но функция не доступна, поэтому в теме. работаю с ad7799, драйвер взял, тот что у вас, конфигурацию выставил.. однако почему-то при выполнении ad7799_read_data() получаю только значение 0xFFFF8000 хотя датчик, который идет на АЦП выдает разное напряжение как и должно быть.. не могли бы вы привести полный код с драйвером, может я че-то где то упустил.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться