Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: задержка в отправке пакета из буфера uart
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Linux
andybeg
странная картина наблюдается - из уарта делаем RS485, соответственно при посылке пакета в порт на конвертер 485го на одной ноге выставляю строб начала передачи
Цитата
stat = write( ttyfd, query, length );
setP01(0,24, 1);
delay(20);

но посмотрев по осцилографу вижу что delay отрабатывается ровно, а посылка гуляет на протяжении 200милисекунд от начала строба, но не случайно, а по какой то линейной зависимости. пробовал следить за U3LSR, но толи что не так делал, толи этот регистр тут не помошник
etoja
Линукс не является системой реального времени и вы наблюдаете его штатное поведение.
Для синхронизации в вашем случае надо править функцию putchar(), которая физически выдаёт байт в uart, и перекомпилировать ядро.
sasamy
Цитата(etoja @ Jul 1 2010, 11:35) *
Для синхронизации в вашем случае надо править функцию putchar(), которая физически выдаёт байт в uart, и перекомпилировать ядро.


putchar все еще в userspace к тому же понятия не имеет - сколько байт в посылке, смысла править ее честно говоря не вижу. Нужно править драйвер uart - после передачи байта смотреть в прерывании есть ли новые данные в буфере для передачи и если нет переключаться на прием аналогично если там используется dma (я не знаком с этим soc) тогда все еще проще - там и так ясно сколько байт передается.

PS "putchar все еще в userspace" - это я к тому что задержки в linux гарантируют что время выдержки будет не меньше того что запрошено, поэтому никто не гарантирует что задержка может оказаться раз в 5 больше что может привести к потере данных которые подчиненное устройство за это время уже может начать передавать а мы все еще не переключились на прием.
etoja
согласен
andybeg
Цитата
Нужно править драйвер uart - после передачи байта
понятно, носом не ткнёте где найти уарт драйвер? конечно предполагаю что в директории drivers
etoja
A driver for 8250/16550 compatible serial ports are integrated in the kernel source tree. That
driver is possible to use without modification for the LPC24xx. The source code is available
in the uClinux-dist/linux-2.6.x/drivers/serial/8250.c file.


Документ "Getting_started_with_uClinux_A.pdf" (4Мбайта) находится здесь: http://slil.ru/29418617

andybeg
спасибо, ценный документ smile.gif
andybeg
интересно, а флаг O_DIRECT для записи в порт в uClinux работает? компилятор ругается на него, хотя <fcntl.h> прописан
andybeg
проблему не решил, но обуздал фронт посылки. сначала, посмотрел в сторону регистра U3LSR в итоге имеем - ставим строб отправки пакета, отправляем пакет данных и ждём пока этот регистр сообщит нам , что данные сначала поступили на отправку, а затем , что они ушли из буфера , затем ставим строб на приём ответа и слушаем ...
Цитата
int write_stat,fd;
unsigned char *U3LSR,data,res;
fd = open("/dev/mem", O_RDWR);
U3LSR = mmap(0, 0x100, PROT_READ, MAP_SHARED, fd, 0xE007C000);
if (U3LSR == MAP_FAILED)
{
printf("Error mmapping the file");
return 0;
}
#ifdef DEBUG
int i;
#endif
modbus_query( query, string_length );
string_length += 2;
#ifdef DEBUG
fprintf( stderr, "\n" );
for( i = 0; i < string_length; i++ )
{
fprintf( stderr, "[%0.2X]", query[ i ] );
} fprintf( stderr, "\n" );
#endif
tcflush( ttyfd, TCIOFLUSH );
setP01(1,13, 1);

write_stat = write( ttyfd, query, string_length );
data = 1; //ждём захода данных в буфер отправки
while(data) { data = *(U3LSR+0x14)&(1<<6); res = *(U3LSR+0x14); printf("\ndata =%x",res); }
printf("\n"); //ждём когда они покинут буфер
while(!data) { data = *(U3LSR+0x14)&(1<<6); res = *(U3LSR+0x14); printf("\nres =%x",res); }
printf("\n");
//delay(220);
setP01(1,13, 0); if (munmap(U3LSR, 0x100) == -1) { perror("Error un-mmapping the file");

} close(fd); return( write_stat );


завтра наверное надо будет добавить таймаутов, а в целом код рабочий, правда по большому счёту не устраивает и надо будет искать другое решение
etoja
Есть очевидное решение: запретить прерывания и работать напрямую с регистрами UARTa и регистрами ножки ввода-вывода.
Как уже говорилось, uCLinux это позволяет.
Тут уж либо реальное время, либо многозадачность.
andybeg
лучше время smile.gif будем копать
LeshaL
Цитата(andybeg @ Jul 8 2010, 15:30) *
лучше время smile.gif будем копать


Если что откопаете, пожалуйста сообщите, галерка тоже интересуется...
andybeg
откопаю, ибо деваться некуда, с понедельнка начну
andybeg
ооооо ееее нииигааа ... нашёл регистр для отправки посылки путём прямого доступа в память
Цитата
4.2 UARTn Transmit Holding Register (U0THR - 0xE000 C000, U2THR -
0xE007 8000, U3THR - 0xE007 C000 when DLAB = 0, Write Only)
The UnTHR is the top byte of the UARTn TX FIFO. The top byte is the newest character in
the TX FIFO and can be written via the bus interface. The LSB represents the first bit to
transmit.
The Divisor Latch Access Bit (DLAB) in UnLCR must be zero in order to access the
UnTHR. The UnTHR is always Write Only.
Table 379. UART0 Transmit Holding Register (U0THR - address 0xE000 C000,
U2THR - 0xE007 8000, U3THR - 0xE007 C000 when DLAB = 0, Write Only) bit
description
Bit Symbol Description Reset Value
7:0 THR Writing to the UARTn Transmit Holding Register causes the data NA
to be stored in the UARTn transmit FIFO. The byte will be sent
when it reaches the bottom of the FIFO and the transmitter is
available.


пишем функцию отсылки чара

Цитата
int putC(unsigned char ch)
{
int write_stat,fd;
unsigned char *map,data,res;

fd = open("/dev/mem", O_RDWR);
map = mmap(0, 0x100, PROT_READ, MAP_SHARED, fd, UnLCR_BASE_ADDR);
if (map == MAP_FAILED)
{
printf("Error mmapping the file");
return 0;
}

while(!(U0LCR && 0x20));

if (munmap(map, 0x100) == -1)
{
perror("Error un-mmapping the file");
}
close(fd);

fd = open("/dev/mem", O_RDWR);
map = mmap(0, 0x100, PROT_READ, MAP_SHARED, fd, UnTHR_BASE_ADDR);
if (map == MAP_FAILED)
{
printf("Error mmapping the file");
return 0;
}
U3THR = ch;
if (munmap(map, 0x100) == -1)
{
perror("Error un-mmapping the file");
}
close(fd);
return 0;
}


модернизируем отправку
Цитата
tcflush( ttyfd, TCIOFLUSH ); /* flush the input & output streams */
setP01(1,13, 1);

//write_stat = write( ttyfd, query, string_length );
for( i = 0; i < string_length; i++ )
putC(query[i]);

fd = open("/dev/mem", O_RDWR);
map = mmap(0, 0x100, PROT_READ, MAP_SHARED, fd, UnLCR_BASE_ADDR);
if (map == MAP_FAILED)
{
printf("Error mmapping the file");
return 0;
}

while(!(U0LCR && 0x20));

if (munmap(map, 0x100) == -1)
{
perror("Error un-mmapping the file");
}
close(fd);

printf("\n");


setP01(1,13, 0);

и получаем посылку почти чётко вписанную в строб, за качество кода прошу не ругать, ибо делал енто на коленях, по наитию и не успел ещё отредактировать, опять же почему то не получаю ответа от дочернего устройства где то есть косяк, вобщем объективная критика принимается
andybeg
насчёт дочернего устройства я ошибся - оно мою посылку принимает и отвечает, это я где то при приёме дал косяка, короче код рабочий, его только надо оптимизировать и сделать красивым
andybeg
возвращаясь к вопросу о подчинённом устройстве - модифицированная отправка работает исправно, устройство получает команду, реагирует соответствующе, но приём который работал раньше не отрабатывает
Цитата
fd_set rfds;

struct timeval tv;

tv.tv_sec = 1;
tv.tv_usec = 0;

FD_ZERO( &rfds );
FD_SET( ttyfd, &rfds );


#ifdef DEBUG
fprintf( stderr, "Waiting for response.\n");
#endif

/* wait for a response */
data_avail = select( FD_SETSIZE, &rfds, NULL, NULL, &tv );

if( !data_avail )
{
bytes_received = 0;
fprintf( stderr, "Comms time out\n" ); <---------- вылетает сюда
}
andybeg
товарищ столкнулся с сабжевой проблемой, покопался в драйвере компорта и нашёл неплохое решение - в коде в 8250.с есть строчки:
Цитата
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/5);
и
poll_timeout(up->port.timeout) + HZ/5);


я моём случае меняем на

Цитата
mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/200);
и
poll_timeout(up->port.timeout) + HZ/200);

и получаем строб в 20 мс, который накрывает посылку длящуюся 9-10мс, с такими показателями можно жить.
товарищ поставил отключение строба прямо в драйвере ... я пока что отключаю после отправки write
Цитата
fd = open("/dev/mem", O_RDWR);
map = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, UnLSR_BASE_ADDR);
if (map == MAP_FAILED)
{
#ifdef DEBUG
printf("Error mmapping the file");
setP01(1,13, 0);
#endif
return 0;
}
data = 1;

//ждём когда в отправляющем буфере появятся данные
goal = 10 * CLOCKS_PER_SEC / 1000 + clock();
while(data)
{
data = (U3LSR)&(1<<6);
res = (U3LSR);
#ifdef DEBUG
printf("\ndata =%x",res);
#endif
if(goal < clock())
{
#ifdef DEBUG
printf("outbuf timeout");
#endif
setP01(1,13, 0);
return 1;
}
}
//------------------------------------------------
#ifdef DEBUG
printf("\n");
#endif
//ждём когда из отправляющего буфера данные уйдут
goal = 10 * CLOCKS_PER_SEC / 1000 + clock();
while(!data)
{
data = (U3LSR)&(1<<6);
res = (U3LSR);
#ifdef DEBUG
printf("\nres =%x",res);
#endif
if(goal < clock())
{
#ifdef DEBUG
printf("sendbuf timeout");
#endif
setP01(1,13, 0);
return 1;
}
}
setP01(1,13, 0);
//------------------------------------------------
if (munmap(map, getpagesize()) == -1)
{
#ifdef DEBUG
perror("Error un-mmapping the file");
#endif
}
close(fd);
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.