2011-01-12 31 views
7

Tôi gặp phải sự chậm trễ dài (1,5ms - 9,5ms) trong giao tiếp RS232 trên PXA270 RISC PC/104. Tôi muốn giảm thiểu sự chậm trễ lâu dài nhưng tôi là người mới bắt đầu với các thiết bị nhúng và C++ vì vậy tôi nghĩ rằng tôi đang thiếu một cái gì đó.Độ trễ cao trong giao tiếp RS232 trên PXA270

Thời gian trễ được đề cập là vào thời điểm bảng PXA nhận gói từ thiết bị ngoài thông qua RS232 (115200 baud) cho đến khi gửi gói tùy chỉnh ACK về thiết bị bên ngoài. Tôi đo độ trễ trên bảng PXA bằng dao động, một kênh ở Rx và kênh kia trên Tx.

Bảng PXA đang chạy Arcom Embedded Linux (AEL). Tôi biết, đó không phải là hệ điều hành thời gian thực, nhưng tôi vẫn nghĩ rằng độ trễ trung bình 4,5ms là cách quá cao để giải nén gói nhận được, xác minh CRC16, xây dựng gói ACK (với CRC) và gửi quay lại dòng nối tiếp. Tôi cũng cố tình đặt CPU dưới tải nặng (một số hoạt động gzip song song) nhưng thời gian trễ không tăng chút nào. Kích thước tối đa của gói nhận được là 30 byte.

Ứng dụng C++ (một đồng nghiệp cũ khác đã viết nó) đang xử lý việc tiếp nhận các gói và xác nhận của chúng. Một luồng đang gửi và luồng kia đang nhận các gói.

Tôi nghĩ rằng RTC trên bảng PXA có độ phân giải rất xấu và AEL không thể căn chỉnh thời gian với độ phân giải RTC nội bộ. Nhưng RTC có tần số 32.768 kHz. Độ phân giải là đủ, vẫn không giải thích được độ trễ cao. Btw, tôi nghĩ rằng hệ điều hành đang sử dụng đồng hồ PXA bên trong (mà cũng có độ phân giải đủ) thay vì RTC cho thời gian.

Do đó sự cố phải nằm trong ứng dụng C++ hoặc trong cài đặt trình điều khiển/HĐH của giao diện RS232.

Các cờ điều khiển sau đây được sử dụng để giao tiếp RS232 trong ứng dụng C++ theo Serial Programming Guide for POSIX Operating Systems:

// Open RS232 on COM1 
mPhysicalComPort = open(aPort, O_RDWR | O_NOCTTY | O_NDELAY); 
// Force read call to block if no data available 
int f = fcntl(mPhysicalComPort, F_GETFL, 0); 
f &= ~O_NONBLOCK; 
fcntl(mPhysicalComPort, F_SETFL, f); 
// Get the current options for the port... 
tcgetattr(mPhysicalComPort, &options); 
// ... and set them to the desired values 
cfsetispeed(&options, baudRate); 
cfsetospeed(&options, baudRate); 
// no parity (8N1) 
options.c_cflag &= ~PARENB; 
options.c_cflag &= ~CSTOPB; 
options.c_cflag &= ~CSIZE; 
options.c_cflag |= CS8; 
// disable hardware flow control 
options.c_cflag &= ~CRTSCTS; 
// raw input 
options.c_lflag = 0; 
// disable software flow control 
options.c_iflag = 0; 
// raw output 
options.c_oflag = 0; 
// Set byte times 
options.c_cc[VMIN] = 1; 
options.c_cc[VTIME] = 0; 
// Set the new options for the port 
tcsetattr(mPhysicalComPort, TCSAFLUSH, &options); 
// Flush to put settings to work 
tcflush(mPhysicalComPort, TCIOFLUSH); 

Tôi nghĩ rằng tôi là thiếu một cái gì đó rất đơn giản. Tôi nghĩ, nếu quá trình của ứng dụng đang chạy dưới mức ưu tiên cao hơn, điều này sẽ không giải quyết được vấn đề. Phải có một cái gì đó, mà chỉ thị trình điều khiển RS232 để xử lý các yêu cầu với một ưu tiên cao hơn để giảm thiểu độ trễ.

Có ai có ý tưởng nào không? Cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn.

+0

Bạn có những sự chậm trễ cho mỗi char, hoặc không đầu vào của bạn đến khi có một \ n trong đầu vào hoặc bộ đệm đầy? Có một số công cụ liên quan đến thiết bị đầu cuối trên trình điều khiển nối tiếp, có thể suy ra thời gian của bạn. – Rudi

+0

Sự chậm trễ không xảy ra đối với mỗi char. Nó xảy ra, khi toàn bộ gói (~ 30 byte) được nhận, cho đến khi gói ACK được gửi trở lại. – saxos

+1

1. Vui lòng hiển thị cho chúng tôi mã nơi bạn đợi và đọc từ cổng. 2.Hiển thị cho chúng tôi đầu ra của 'uptime' (có thể hệ thống của bạn bị quá tải?) 3.Does Linux của bạn có phần mở rộng chuyển ngữ cảnh nhanh (lwn.net/images/conf/rtlws11/papers/proc/p01.pdf)? PXA270 có thể có độ trễ chuyển đổi ngữ cảnh là ~ 0,5ms mà không có nó. – atzz

Trả lời

8

Cảm ơn bạn rất nhiều vì nhận xét của bạn.

Tôi đã có thể giảm độ trễ xuống ~ 0.4ms. Lệnh setserial(8) được tham chiếu trong sách hướng dẫn AEL. Và bingo, tôi thấy low_latency cờ đó với mô tả sau đây:

Giảm thiểu nhận được độ trễ của thiết bị nối tiếp với chi phí lớn hơn sử dụng CPU. (Thông thường có trung bình độ trễ 5-10ms trước khi ký tự được chuyển sang dòng đường dây để giảm thiểu chi phí.) này được tắt theo mặc định, nhưng một số ứng dụng thời gian thực có thể tìm thấy hữu ích này.

Sau đó, tôi thực hiện setserial /dev/ttyS1 low_latency và độ trễ được giảm xuống ~ 0.4ms :-)

Nhưng tôi muốn thực hiện hành vi này trong ứng dụng C++, mà không đặt cờ này trên toàn cầu với bộ đệm (lệnh này theo mặc định không được bao gồm trong tất cả các bản phân phối).

Tôi đã thêm các dòng mã sau đây, trong đó có tác dụng tương tự như cờ low_latency từ setserial:

#include <sys/ioctl.h> 
#include <linux/serial.h> 
// Open RS232 on COM1 
mPhysicalComPort = open(aPort, O_RDWR | O_NOCTTY | O_NDELAY); 
struct serial_struct serial; 
ioctl(mPhysicalComPort, TIOCGSERIAL, &serial); 
serial.flags |= ASYNC_LOW_LATENCY; // (0x2000) 
ioctl(mPhysicalComPort, TIOCSSERIAL, &serial); 
+0

độ trễ thấp hơn thông qua việc sử dụng CPU cao hơn: điều này có nghĩa là hệ điều hành đã thăm dò ý kiến ​​cổng nối tiếp theo một cách nào đó? – stijn

+0

Tôi không biết chính xác nội bộ. Tôi đã đọc điều gì đó, với cờ low_latency, dữ liệu được đẩy vào lớp tty ở ngữ cảnh ngắt cứng, có mức ưu tiên cao hơn nhiều so với ngắt mềm. Tôi không nhận thấy sự gia tăng sử dụng CPU ở tất cả (đối với kịch bản của tôi). – saxos

Các vấn đề liên quan