Chào buổi chiều Chúng tôi đang ở trong dự án
Qt là một framework đa nền tảng không chỉ bao gồm các thành phần đồ họa mà còn bao gồm những thứ như QtNetwork, một tập hợp các lớp để làm việc với cơ sở dữ liệu, Qt cho Tự động hóa (bao gồm cả việc triển khai IoT) và hơn thế nữa. Nhóm Qt đã chủ động sử dụng Qt trong các hệ thống nhúng, vì vậy các thư viện có thể cấu hình khá dễ dàng. Tuy nhiên, cho đến gần đây, ít người nghĩ đến việc chuyển Qt sang vi điều khiển, có lẽ vì nhiệm vụ như vậy có vẻ khó khăn - Qt thì lớn, MCU thì nhỏ.
Mặt khác, hiện tại có những bộ vi điều khiển được thiết kế để hoạt động với đa phương tiện và vượt trội hơn những chiếc Pentium đầu tiên. Khoảng một năm trước, blog Qt xuất hiện
Qt 4.8 đã được chuyển sang Embox từ lâu nên chúng tôi quyết định dùng thử. Chúng tôi đã chọn ứng dụng Moveblocks - một ví dụ về hoạt ảnh có độ đàn hồi.
Khối di chuyển Qt trên QEMU
Để bắt đầu, chúng tôi định cấu hình Qt, nếu có thể, với bộ thành phần tối thiểu cần thiết để hỗ trợ hoạt ảnh. Đối với điều này, có một tùy chọn “-qconfig tối thiểu, nhỏ, trung bình…”. Nó kết nối một tệp cấu hình từ Qt với nhiều macro - nên bật/tắt cái gì. Sau tùy chọn này, chúng tôi thêm các cờ khác vào cấu hình nếu chúng tôi muốn tắt một thứ khác. Đây là một ví dụ của chúng tôi
Để Qt hoạt động, bạn cần thêm lớp tương thích với hệ điều hành. Một cách là triển khai QPA (Tóm tắt nền tảng Qt). Chúng tôi lấy plugin fb_base làm sẵn có trong Qt làm cơ sở, trên cơ sở đó QPA dành cho Linux hoạt động. Kết quả là một plugin nhỏ có tên emboxfb, cung cấp Qt với bộ đệm khung của Embox và sau đó nó vẽ ở đó mà không cần bất kỳ sự trợ giúp nào từ bên ngoài.
Đây là giao diện tạo một plugin
QEmboxFbIntegration::QEmboxFbIntegration()
: fontDb(new QGenericUnixFontDatabase())
{
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
const char *fbPath = "/dev/fb0";
fbFd = open(fbPath, O_RDWR);
if (fbPath < 0) {
qFatal("QEmboxFbIntegration: Error open framebuffer %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) == -1) {
qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
}
fbWidth = vinfo.xres;
fbHeight = vinfo.yres;
fbBytesPerLine = finfo.line_length;
fbSize = fbBytesPerLine * fbHeight;
fbFormat = vinfo.fmt;
fbData = (uint8_t *)mmap(0, fbSize, PROT_READ | PROT_WRITE,
MAP_SHARED, fbFd, 0);
if (fbData == MAP_FAILED) {
qFatal("QEmboxFbIntegration: Error mmap framebuffer %s", fbPath);
}
if (!fbData || !fbSize) {
qFatal("QEmboxFbIntegration: Wrong framebuffer: base = %p,"
"size=%d", fbData, fbSize);
}
mPrimaryScreen = new QEmboxFbScreen(fbData, fbWidth,
fbHeight, fbBytesPerLine,
emboxFbFormatToQImageFormat(fbFormat));
mPrimaryScreen->setPhysicalSize(QSize(fbWidth, fbHeight));
mScreens.append(mPrimaryScreen);
this->printFbInfo();
}
Và bản vẽ lại sẽ trông như thế này
QRegion QEmboxFbScreen::doRedraw()
{
QVector<QRect> rects;
QRegion touched = QFbScreen::doRedraw();
DPRINTF("QEmboxFbScreen::doRedrawn");
if (!compositePainter) {
compositePainter = new QPainter(mFbScreenImage);
}
rects = touched.rects();
for (int i = 0; i < rects.size(); i++) {
compositePainter->drawImage(rects[i], *mScreenImage, rects[i]);
}
return touched;
}
Kết quả là, khi bật tính năng tối ưu hóa trình biên dịch cho kích thước bộ nhớ -Os, hình ảnh thư viện hóa ra là 3.5 MB, tất nhiên là không vừa với bộ nhớ chính của STM32F746. Như chúng tôi đã viết trong bài viết khác về OpenCV, bảng này có:
- 1 MB bộ nhớ
- RAM 320 KB
- SDRAM 8 MB
- QSPI 16 MB
Vì hỗ trợ thực thi mã từ QSPI đã được thêm vào OpenCV nên chúng tôi quyết định bắt đầu bằng cách tải toàn bộ hình ảnh Embox c Qt vào QSPI. Và hoan hô, mọi thứ gần như bắt đầu ngay lập tức từ QSPI! Nhưng như trường hợp của OpenCV, hóa ra nó hoạt động quá chậm.
Do đó, chúng tôi quyết định thực hiện theo cách này - đầu tiên chúng tôi sao chép hình ảnh sang QSPI, sau đó tải nó vào SDRAM và thực thi từ đó. Từ SDRAM nó trở nên nhanh hơn một chút nhưng vẫn kém xa QEMU.
Tiếp theo, có một ý tưởng bao gồm một dấu phẩy động - xét cho cùng, Qt thực hiện một số phép tính về tọa độ của các hình vuông trong hoạt ảnh. Chúng tôi đã cố gắng, nhưng ở đây chúng tôi không nhận được bất kỳ khả năng tăng tốc rõ ràng nào, mặc dù ở
Ý tưởng hiệu quả nhất là chuyển bộ đệm khung từ SDRAM sang bộ nhớ trong. Để làm điều này, chúng tôi đã tạo kích thước màn hình không phải 480x272 mà là 272x272. Chúng tôi cũng giảm độ sâu màu từ A8R8G8B8 xuống R5G6B5, do đó giảm kích thước của một pixel từ 4 xuống 2 byte. Kích thước bộ đệm khung kết quả là 272 * 272 * 2 = 147968 byte. Điều này mang lại khả năng tăng tốc đáng kể, có lẽ đáng chú ý nhất là hoạt ảnh trở nên gần như mượt mà.
Tối ưu hóa mới nhất là chạy mã Embox từ RAM và mã Qt từ SDRAM. Để thực hiện điều này, trước tiên, như thường lệ, chúng tôi liên kết tĩnh Embox với Qt, nhưng chúng tôi đặt các phân đoạn văn bản, rodata, dữ liệu và bss của thư viện trong QSPI để sau đó sao chép nó vào SDRAM.
section (qt_text, SDRAM, QSPI)
phdr (qt_text, PT_LOAD, FLAGS(5))
section (qt_rodata, SDRAM, QSPI)
phdr (qt_rodata, PT_LOAD, FLAGS(5))
section (qt_data, SDRAM, QSPI)
phdr (qt_data, PT_LOAD, FLAGS(6))
section (qt_bss, SDRAM, QSPI)
phdr (qt_bss, PT_LOAD, FLAGS(6))
Bằng cách thực thi mã Embox từ ROM, chúng tôi cũng nhận được khả năng tăng tốc đáng chú ý. Kết quả là hoạt ảnh trở nên khá mượt mà:
Cuối cùng, trong khi chuẩn bị bài viết và thử các cấu hình Embox khác nhau, hóa ra các khối di chuyển Qt hoạt động rất tốt từ QSPI với bộ đệm khung trong SDRAM và nút cổ chai chính xác là kích thước của bộ đệm khung! Rõ ràng, để vượt qua "trình chiếu" ban đầu, khả năng tăng tốc gấp 2 lần là đủ do kích thước của bộ đệm khung giảm đi một cách tầm thường. Nhưng không thể đạt được kết quả như vậy nếu chỉ chuyển mã Embox sang nhiều bộ nhớ nhanh khác nhau (gia tốc không phải là 2 mà là khoảng 1.5 lần).
Làm thế nào để tự mình thử nó
Nếu bạn có STM32F7-Discovery, bạn có thể tự chạy Qt trong Embox. Bạn có thể đọc cách thực hiện điều này trên
Kết luận
Kết quả là chúng tôi đã khởi chạy được Qt! Theo chúng tôi, sự phức tạp của nhiệm vụ có phần bị cường điệu hóa. Đương nhiên, bạn cần phải tính đến các chi tiết cụ thể của bộ vi điều khiển và hiểu chung về kiến trúc của hệ thống máy tính. Các kết quả tối ưu hóa chỉ ra một thực tế rõ ràng rằng nút cổ chai trong hệ thống máy tính không phải là bộ xử lý mà là bộ nhớ.
Năm nay chúng tôi sẽ tham gia lễ hội
Nguồn: www.habr.com