Я пишу acquisitioning данные программы, которая должнаC - выберите(), кажется, блок дольше, чем тайм-аут
засаде сериала с некоторыми()
считанных последовательных данных (RS232 в 115200 бод),
метка времени он (clock_gettime()),
чтения АЦП на SPI,
интерпретировать,
отправить новые данные поверх другого TTY устройства
петли и повторить
АЦП не имеет значения, на данный момент.
В конце цикла я снова использую select() с 0 таймаутом для опроса и посмотреть, доступны ли данные уже, если это означает, что у меня переполнение, I.e. Я ожидаю, что цикл завершится раньше, чем больше данных, и для select() в начале цикла заблокировать и получить его, как только он поступит.
Данные должны поступать каждые 5 мс, мой первый тайм-аут select() рассчитывается как (5,5 мс - время цикла) - это должно быть около 4 мс.
У меня нет таймаутов, но много перерасходов.
Рассмотрение временных меток показывает, что select() блокирует дольше, чем таймаут (но все же возвращает> 0). Похоже, что select() возвращает позже после получения данных до таймаута.
Это может случиться 20 раз в 1000 повторов. Что может быть причиной? Как это исправить?
EDIT: Вот урезанная версия кода (! Я гораздо больше контроля ошибок, чем это)
#include <bcm2835.h> /* for bcm2835_init(), bcm2835_close() */
int main(int argc, char **argv){
int err = 0;
/* Set real time priority SCHED_FIFO */
struct sched_param sp;
sp.sched_priority = 30;
if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)){
perror("pthread_setschedparam():");
err = 1;
}
/* 5ms between samples on /dev/ttyUSB0 */
int interval = 5;
/* Setup tty devices with termios, both totally uncooked, 8 bit, odd parity, 1 stop bit, 115200baud */
int fd_wc=setup_serial("/dev/ttyAMA0");
int fd_sc=setup_serial("/dev/ttyUSB0");
/* Setup GPIO for SPI, SPI mode, clock is ~1MHz which equates to more than 50ksps */
bcm2835_init();
setup_mcp3201spi();
int collecting = 1;
struct timespec starttime;
struct timespec time;
struct timespec ftime;
ftime.tv_nsec = 0;
fd_set readfds;
int countfd;
struct timeval interval_timeout;
struct timeval notime;
uint16_t p1;
float w1;
uint8_t *datap = malloc(8);
int data_size;
char output[25];
clock_gettime(CLOCK_MONOTONIC, &starttime);
while (!err && collecting){
/* Set timeout to (5*1.2)ms - (looptime)ms, or 0 if looptime was longer than (5*1.2)ms */
interval_timeout.tv_sec = 0;
interval_timeout.tv_usec = interval * 1200 - ftime.tv_nsec/1000;
interval_timeout.tv_usec = (interval_timeout.tv_usec < 0)? 0 : interval_timeout.tv_usec;
FD_ZERO(&readfds);
FD_SET(fd_wc, &readfds);
FD_SET(0, &readfds); /* so that we can quit, code not included */
if ((countfd=select(fd_wc+1, &readfds, NULL, NULL, &interval_timeout))<0){
perror("select()");
err = 1;
} else if (countfd == 0){
printf("Timeout on select()\n");
fflush(stdout);
err = 1;
} else if (FD_ISSET(fd_wc, &readfds)){
/* timestamp for when data is just available */
clock_gettime(CLOCK_MONOTONIC, &time)
if (starttime.tv_nsec > time.tv_nsec){
time.tv_nsec = 1000000000 + time.tv_nsec - starttime.tv_nsec;
time.tv_sec = time.tv_sec - starttime.tv_sec - 1;
} else {
time.tv_nsec = time.tv_nsec - starttime.tv_nsec;
time.tv_sec = time.tv_sec - starttime.tv_sec;
}
/* get ADC value, which is sampled fast so corresponds to timestamp */
p1 = getADCvalue();
/* receive_frame, receiving is slower so do it after getting ADC value. It is timestamped anyway */
/* This function consists of a loop that gets data from serial 1 byte at a time until a 'frame' is collected. */
/* it uses select() with a very short timeout (enough for 1 byte at baudrate) just to check comms are still going */
/* It never times out and behaves well */
/* The interval_timeout is passed because it is used as a timeout for responding an ACK to the device */
/* That select also never times out */
ireceive_frame(&datap, fd_wc, &data_size, interval_timeout.tv_sec, interval_timeout.tv_usec);
/* do stuff with it */
/* This takes most of the time in the loop, about 1.3ms at 115200 baud */
snprintf(output, 24, "%d.%04d,%d,%.2f\n", time.tv_sec, time.tv_nsec/100000, pressure, w1);
write(fd_sc, output, strnlen(output, 23));
/* Check how long the loop took (minus the polling select() that follows */
clock_gettime(CLOCK_MONOTONIC, &ftime);
if ((time.tv_nsec+starttime.tv_nsec) > ftime.tv_nsec){
ftime.tv_nsec = 1000000000 + ftime.tv_nsec - time.tv_nsec - starttime.tv_nsec;
ftime.tv_sec = ftime.tv_sec - time.tv_sec - starttime.tv_sec - 1;
} else {
ftime.tv_nsec = ftime.tv_nsec - time.tv_nsec - starttime.tv_nsec;
ftime.tv_sec = ftime.tv_sec - time.tv_sec - starttime.tv_sec;
}
/* Poll with 0 timeout to check that data hasn't arrived before we're ready yet */
FD_ZERO(&readfds);
FD_SET(fd_wc, &readfds);
notime.tv_sec = 0;
notime.tv_usec = 0;
if (!err && ((countfd=select(fd_wc+1, &readfds, NULL, NULL, ¬ime)) < 0)){
perror("select()");
err = 1;
} else if (countfd > 0){
printf("OVERRUN!\n");
snprintf(output, 25, ",,,%d.%04d\n\n", ftime.tv_sec, ftime.tv_nsec/100000);
write(fd_sc, output, strnlen(output, 24));
}
}
}
return 0;
}
Метки времени я вижу на последовательный поток, выход я довольно регулярно (отклонение обычно улавливается следующим циклом). Отрывок выхода:
6.1810,0,225.25
6.1867,0,225.25
6.1922,0,225.25
6,2063,0,225.25
,,,0.0010
Здесь, до 6.1922s, все в порядке. Следующий образец равен 6.2063 - 14.1ms после последнего, но он не ушел в прошлое, и предыдущий цикл от 6.1922-6.2063 не поймал переполнение с помощью select(). Мой вывод состоит в том, что в последнем цикле было время выборки, и выбор взял -10ms слишком долгое возвращение без тайм-аута.
The ,,, 0.0010 указывает время цикла (ftime) цикла после - я действительно должен проверять, какое время цикла было, когда оно пошло не так. Я попробую это завтра.
Как вы устанавливаете свои маски ?, и передаете нулевой указатель на аргумент времени или устанавливаете значения struct в ноль. Каждый из них приводит к собственному поведению. – ryyker
Возможно, вам придется включить _ [SSCCE] (http://sscce.org/) _, чтобы проиллюстрировать проблему. Очевидно, есть что-то другое, кроме проблемы с тайм-аутом, вызывающей вашу проблему. Это также привлечет более широкую аудиторию. – ryyker
Добавлена малина-пи к тегам. – ryyker