์ข์ ์คํ์์ ์ฐ๋ฆฌ๋ ํ๋ก์ ํธ์ ์์ต๋๋ค
Qt๋ ๊ทธ๋ํฝ ๊ตฌ์ฑ์์๋ฟ๋ง ์๋๋ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์
์ ์ํ ํด๋์ค ์ธํธ์ธ QtNetwork, ์๋ํ์ฉ Qt(IoT ๊ตฌํ ํฌํจ) ๋ฑ์ ํฌํจํ๋ ํฌ๋ก์ค ํ๋ซํผ ํ๋ ์์ํฌ์
๋๋ค. Qt ํ์ ์๋ฒ ๋๋ ์์คํ
์์ Qt๋ฅผ ์ฌ์ฉํ๋ ๋ฐ ์ ๊ทน์ ์ผ๋ก ์ฐธ์ฌํด ์๊ธฐ ๋๋ฌธ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ตฌ์ฑ์ด ์๋นํ ๊ฐ๋ฅํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ต๊ทผ๊น์ง Qt๋ฅผ ๋ง์ดํฌ๋ก ์ปจํธ๋กค๋ฌ๋ก ํฌํ
ํ๋ ๊ฒ์ ๋ํด ์๊ฐํ ์ฌ๋์ ๊ฑฐ์ ์์์ต๋๋ค. ์๋ง๋ ๊ทธ๋ฌํ ์์
์ด ์ด๋ ค์ ๋ณด์๊ธฐ ๋๋ฌธ์ผ ๊ฒ์
๋๋ค. Qt๋ ํฌ๊ณ MCU๋ ์์ต๋๋ค.
๋ฐ๋ฉด์ ํ์ฌ ๋ฉํฐ๋ฏธ๋์ด์ ํจ๊ป ์๋ํ๋๋ก ์ค๊ณ๋๊ณ ์ต์ด์ ํํฐ์๋ณด๋ค ์ฐ์ํ ๋ง์ดํฌ๋ก ์ปจํธ๋กค๋ฌ๊ฐ ์์ต๋๋ค. ์ฝ XNUMX๋
์ , Qt ๋ธ๋ก๊ทธ๊ฐ ๋ฑ์ฅํ์ต๋๋ค.
Qt 4.8์ด ์ค๋ซ๋์ Embox๋ก ํฌํ ๋์ด ์๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ์ ์ฌ์ฉํด ๋ณด๊ธฐ๋ก ํ์ต๋๋ค. ์ฐ๋ฆฌ๋ ํ๋ ฅ ์๋ ์ ๋๋ฉ์ด์ ์ ์์ธ moveblocks ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํํ์ต๋๋ค.
QEMU์ Qt moveblocks
์ฐ์ ์ ๋๋ฉ์ด์
์ ์ง์ํ๋ ๋ฐ ํ์ํ ์ต์ํ์ ๊ตฌ์ฑ ์์ ์งํฉ์ผ๋ก Qt๋ฅผ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ฅผ ์ํด โ-qconfigminimal,small,medium...โ์ต์
์ด ์์ต๋๋ค. Qt์ ๊ตฌ์ฑ ํ์ผ์ ๋ง์ ๋งคํฌ๋ก(ํ์ฑํํ ํญ๋ชฉ/๋นํ์ฑํํ ํญ๋ชฉ)์ ์ฐ๊ฒฐํฉ๋๋ค. ์ด ์ต์
๋ค์ ๋ค๋ฅธ ๊ฒ์ ๋นํ์ฑํํ๋ ค๋ฉด ๊ตฌ์ฑ์ ๋ค๋ฅธ ํ๋๊ทธ๋ฅผ ์ถ๊ฐํฉ๋๋ค. ๋ค์์ ์ฐ๋ฆฌ์ ์์
๋๋ค.
Qt๊ฐ ์๋ํ๋ ค๋ฉด OS ํธํ์ฑ ๋ ์ด์ด๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ํ ๊ฐ์ง ๋ฐฉ๋ฒ์ QPA(Qt Platform Abstraction)๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๋ Linux์ฉ QPA๊ฐ ์๋ํ๋ ๊ธฐ๋ฐ์ผ๋ก Qt์ ํฌํจ๋ ๊ธฐ์ฑ fb_base ํ๋ฌ๊ทธ์ธ์ ๊ธฐ๋ฐ์ผ๋ก ์ผ์์ต๋๋ค. ๊ทธ ๊ฒฐ๊ณผ Qt์ Embox์ ํ๋ ์๋ฒํผ๋ฅผ ์ ๊ณตํ๊ณ ์ธ๋ถ ๋์ ์์ด ๊ฑฐ๊ธฐ์ ๊ทธ๋ฆผ์ ๊ทธ๋ฆฌ๋ emboxfb๋ผ๋ ์์ ํ๋ฌ๊ทธ์ธ์ด ํ์ํ์ต๋๋ค.
ํ๋ฌ๊ทธ์ธ์ ๋ง๋๋ ๋ชจ์ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
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();
}
๊ทธ๋ฆฌ๊ณ ๋ค์ ๊ทธ๋ฆฌ๋ ๋ชจ์ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค
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;
}
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ -Os์ ๋ํ ์ปดํ์ผ๋ฌ ์ต์ ํ๊ฐ ํ์ฑํ๋๋ฉด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ด๋ฏธ์ง๊ฐ 3.5MB๋ก ํ๋ช ๋์์ผ๋ฉฐ ์ด๋ ๋ฌผ๋ก STM32F746์ ๋ฉ์ธ ๋ฉ๋ชจ๋ฆฌ์ ๋ง์ง ์์ต๋๋ค. OpenCV์ ๋ํ ๋ค๋ฅธ ๊ธฐ์ฌ์์ ์ด๋ฏธ ์ผ๋ฏ์ด ์ด ๋ณด๋์๋ ๋ค์์ด ํฌํจ๋ฉ๋๋ค.
- 1MB ROM
- 320KB RAM
- 8MB SDRAM
- 16MB QSPI
QSPI์์ ์ฝ๋ ์คํ์ ๋ํ ์ง์์ด ์ด๋ฏธ OpenCV์ ์ถ๊ฐ๋์์ผ๋ฏ๋ก ์ ์ฒด Embox c Qt ์ด๋ฏธ์ง๋ฅผ QSPI์ ๋ก๋ํ๋ ๊ฒ๋ถํฐ ์์ํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. ๋ง์ธ, ๋ชจ๋ ๊ฒ์ด QSPI์์ ๊ฑฐ์ ์ฆ์ ์์๋์์ต๋๋ค! ํ์ง๋ง OpenCV์ ๊ฒฝ์ฐ์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋๋ฌด ๋๋ฆฌ๊ฒ ์๋ํ๋ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค.
๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ํํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. ๋จผ์ ์ด๋ฏธ์ง๋ฅผ QSPI์ ๋ณต์ฌํ ๋ค์ SDRAM์ ๋ก๋ํ๊ณ ๊ฑฐ๊ธฐ์์ ์คํํฉ๋๋ค. SDRAM์์๋ ์กฐ๊ธ ๋ ๋นจ๋ผ์ก์ง๋ง ์ฌ์ ํ QEMU์์๋ ๊ฑฐ๋ฆฌ๊ฐ ๋ฉ์ต๋๋ค.
๋ค์์ผ๋ก ๋ถ๋ ์์์ ์ ํฌํจ์ํค๋ ์์ด๋์ด๊ฐ ์์์ต๋๋ค. ๊ฒฐ๊ตญ Qt๋ ์ ๋๋ฉ์ด์
์์ ์ฌ๊ฐํ ์ขํ์ ๋ํ ์ผ๋ถ ๊ณ์ฐ์ ์ํํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์๋ํ์ง๋ง ์ฌ๊ธฐ์๋ ๋์ ๋๋ ๊ฐ์๋๋ฅผ ์ป์ง ๋ชปํ์ต๋๋ค.
๊ฐ์ฅ ํจ๊ณผ์ ์ธ ์์ด๋์ด๋ ํ๋ ์ ๋ฒํผ๋ฅผ SDRAM์์ ๋ด๋ถ ๋ฉ๋ชจ๋ฆฌ๋ก ์ฎ๊ธฐ๋ ๊ฒ์ด์์ต๋๋ค. ์ด๋ฅผ ์ํด ํ๋ฉด ํฌ๊ธฐ๋ฅผ 480x272๊ฐ ์๋ 272x272๋ก ๋ง๋ค์์ต๋๋ค. ๋ํ ์ ๋๋๋ฅผ A8R8G8B8์์ R5G6B5๋ก ๋ฎ์ถ์ด ํ ํฝ์ ์ ํฌ๊ธฐ๋ฅผ 4๋ฐ์ดํธ์์ 2๋ฐ์ดํธ๋ก ์ค์์ต๋๋ค. ๊ฒฐ๊ณผ ํ๋ ์ ๋ฒํผ ํฌ๊ธฐ๋ 272 * 272 * 2 = 147968๋ฐ์ดํธ์ ๋๋ค. ์ด๋ก ์ธํด ์๋นํ ๊ฐ์์ด ์ด๋ฃจ์ด์ก์ผ๋ฉฐ ์๋ง๋ ๊ฐ์ฅ ๋์ ๋๊ฒ ์ ๋๋ฉ์ด์ ์ด ๊ฑฐ์ ๋งค๋๋ฌ์์ก์ต๋๋ค.
์ต์ ์ต์ ํ๋ RAM์์ Embox ์ฝ๋๋ฅผ ์คํํ๊ณ SDRAM์์ Qt ์ฝ๋๋ฅผ ์คํํ๋ ๊ฒ์ด์์ต๋๋ค. ์ด๋ฅผ ์ํด ๋จผ์ ํ์์ ๊ฐ์ด Embox๋ฅผ Qt์ ์ ์ ์ผ๋ก ์ฐ๊ฒฐํ์ง๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ ์คํธ, rodata, ๋ฐ์ดํฐ ๋ฐ bss ์ธ๊ทธ๋จผํธ๋ฅผ QSPI์ ๋ฐฐ์นํ ๋ค์ ์ด๋ฅผ 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))
ROM์์ Embox ์ฝ๋๋ฅผ ์คํํจ์ผ๋ก์จ ์ฐ๋ฆฌ๋ ๋์ ๋๋ ๊ฐ์์ ์ป์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ ๋๋ฉ์ด์ ์ด ๋งค์ฐ ๋งค๋๋ฌ์์ก์ต๋๋ค.
๋ง์ง๋ง์ ๊ธฐ์ฌ๋ฅผ ์ค๋นํ๊ณ ๋ค์ํ Embox ๊ตฌ์ฑ์ ์๋ํ๋ ๋์ Qt moveblocks๋ SDRAM์ ํ๋ ์ ๋ฒํผ๋ฅผ ์ฌ์ฉํ๋ QSPI์์ ํ๋ฅญํ๊ฒ ์๋ํ๋ฉฐ ๋ณ๋ชฉ ํ์์ ์ ํํ ํ๋ ์ ๋ฒํผ์ ํฌ๊ธฐ๋ผ๋ ๊ฒ์ด ๋ฐํ์ก์ต๋๋ค! ๋ถ๋ช ํ ์ด๊ธฐ "์ฌ๋ผ์ด๋์ผ"๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด์๋ ํ๋ ์ ๋ฒํผ ํฌ๊ธฐ์ ์ง๋ถํ ๊ฐ์๋ก ์ธํด 2๋ฐฐ ๊ฐ์์ด๋ฉด ์ถฉ๋ถํ์ต๋๋ค. ํ์ง๋ง Embox ์ฝ๋๋ง์ ๋ค์ํ ๊ณ ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์กํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ด๋ฌํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์์ต๋๋ค(๊ฐ์๋ฅ ์ 2๋ฐฐ๊ฐ ์๋๊ณ 1.5๋ฐฐ ์ ๋์์ต๋๋ค).
์ง์ ์๋ํด ๋ณด๋ ๋ฐฉ๋ฒ
STM32F7-Discovery๊ฐ ์๋ ๊ฒฝ์ฐ Embox์์ Qt๋ฅผ ์ง์ ์คํํ ์ ์์ต๋๋ค. ์ด ์์
์ด ์ด๋ป๊ฒ ์ํ๋๋์ง๋ ๋น์ฌ์์ ์ฝ์ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
๊ทธ ๊ฒฐ๊ณผ, ์ฐ๋ฆฌ๋ Qt๋ฅผ ์ถ์ํ ์ ์์์ต๋๋ค! ์ฐ๋ฆฌ ์๊ฒฌ์ผ๋ก๋ ์์ ์ ๋ณต์ก์ฑ์ด ๋ค์ ๊ณผ์ฅ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋น์ฐํ ๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ์ ํน์ฑ์ ๊ณ ๋ คํ๊ณ ์ปดํจํฐ ์์คํ ์ ์ํคํ ์ฒ๋ฅผ ์ ๋ฐ์ ์ผ๋ก ์ดํดํด์ผ ํฉ๋๋ค. ์ต์ ํ ๊ฒฐ๊ณผ๋ ์ปดํจํ ์์คํ ์ ๋ณ๋ชฉ ํ์์ด ํ๋ก์ธ์๊ฐ ์๋๋ผ ๋ฉ๋ชจ๋ฆฌ์ ์๋ค๋ ์ฌ์ค์ ์ ๋ณด์ฌ์ค๋๋ค.
์ฌํด ์ฐ๋ฆฌ๋ ์ถ์ ์ ์ฐธ์ฌํ ๊ฒ์
๋๋ค
์ถ์ฒ : habr.com