FB_ILI9341 80fps up to 100fps | memcpy(); 387 fps minimal
-
I'm using a ILI9341 display ("2.8 TFT SPI 240x320"). I've tried loading your modules on a newly upgraded b192 firmware but encounter missing references.
root@Omega-C465:~/modules# ./display_init.sh failed to insert /root/modules/fb.ko failed to insert /root/modules/fbtft.ko failed to insert /root/modules/fb_ili9341.ko failed to insert /root/modules/fbtft_device.ko
[ 340.557995] fb: Unknown symbol fb_find_logo (err 0) [ 340.563270] fb: Unknown symbol fb_mode_option (err 0) [ 340.654413] fbtft: Unknown symbol unregister_framebuffer (err 0) [ 340.660810] fbtft: Unknown symbol fb_deferred_io_init (err 0) [ 340.666885] fbtft: Unknown symbol fb_deferred_io_cleanup (err 0) [ 340.673171] fbtft: Unknown symbol framebuffer_alloc (err 0) [ 340.679135] fbtft: Unknown symbol register_framebuffer (err 0) [ 340.685397] fbtft: Unknown symbol framebuffer_release (err 0) [ 340.704371] fb_ili9341: Unknown symbol fbtft_remove_common (err 0) [ 340.710879] fb_ili9341: Unknown symbol fbtft_probe_common (err 0) [ 340.738748] fbtft_device: Unknown symbol fbtft_write_gpio16_wr_latched (err 0) [ 340.746528] fbtft_device: Unknown symbol fbtft_dbg_hex (err 0)
fb_find_logo
seems to from the video module (https://elixir.bootlin.com/linux/latest/ident/fb_find_logo). Did you also encounter this error? Is a kernel module file missing maybe? Or did is my current firwmare just bad?(PS: Sorry to spam this thread, but there's no private messaging possibility on this forum :()
-
@Maximilian-Gerhardt said in FB_ILI9341 80fps up to 100fps:
unregister_framebuffer
It's in not a spam and I'll gladly help for this
I could not generate same error but it generated by fb.ko
Would you try to load modules in this order
insmod /root/modules/fb_sys_fops.ko insmod /root/modules/fb.ko insmod /root/modules/backlight.ko insmod /root/modules/sysfillrect.ko insmod /root/modules/syscopyarea.ko insmod /root/modules/sysimgblt.ko insmod /root/modules/fbtft.ko insmod /root/modules/fb_ili9341.ko
I am reverting to b192, and feed back to you.
-
@unique1984 said in FB_ILI9341 80fps up to 100fps:
I am reverting to b192, and feed back to you.
B192 is the already newest, the same firmware you mentioned in the first post
I reflashed the firmware from web and from USB onto a Omega2 using http://repo.onion.io/omega2/images/ (
omega2p-v0.2.0-b192.bin
) https://docs.onion.io/omega2-docs/updating-the-omega.html and https://docs.onion.io/omega2-docs/Firmware-Flashing-from-USB-storage.html, I still get the same errors.Either my Omega2's flash is doing weird stuf (file corruption) or something else. Can anyone else test this? It obviously works from your video but I can't reproduce :(.
-
@Maximilian-Gerhardt I am getting same errors there are 2 possibilities,
- I mixed the my image with the stock image b192
- I am missing a step of mine.
both of them are my stupidity.
here is my custom image file, and it works(just flashed) 1st possibilty is higher, but i sure of it i was using the b192 (#!) i'll inspect this further but right now time is 22:00 here and i dont want to miss bloody moon.
custom lede images omega2 and omega2p
ps. in the display_init.sh file there is a line
cat rgb565_0degree.bmp > /dev/fb0
you can comment that line it was there for the test purpose.
-
Yep, this works like a charm!
[ 254.231106] m25p80 spi32766.0: spi-nor spi32766.0 40000kHz 8 bits mode=0x00 [ 254.238192] spidev spi32766.1: spidev spi32766.1 40000kHz 8 bits mode=0x00 [ 254.245322] spidev spi32766.1: Deleting spi32766.1 [ 254.274384] fb_ili9341 spi32766.1: fbtft_request_gpios: 'reset' = GPIO2 [ 254.281148] fb_ili9341 spi32766.1: fbtft_request_gpios: 'dc' = GPIO3 [ 254.581036] fb_ili9341 spi32766.1: Display update: 3100 kB/s, fps=0 [ 254.587786] graphics fb0: fb_ili9341 frame buffer, 320x240, 150 KiB video memory, 3072 KiB DMA buffer memory, fps=100, spi 32766.1 at 96 MHz [ 254.600541] fbtft_device: GPIOS used by 'fb_ili9341': [ 254.605665] fbtft_device: 'reset' = GPIO2 [ 254.609742] fbtft_device: 'dc' = GPIO3 [ 254.613560] m25p80 spi32766.0: spi-nor spi32766.0 40000kHz 8 bits mode=0x00 [ 254.620643] fb_ili9341 spi32766.1: fb_ili9341 spi32766.1 96666kHz 8 bits mode=0x06
I modified this program to work with the 16 bit framebuffer and elimate some checks
/* fbgrad: draw gradient using framebuffer. run in console, X11 would overwrite everything immediatelly. (c) Lev, 2018, MIT licence */ #include <stdint.h> #include <stdlib.h> typedef uint_fast16_t uint; typedef struct { char *buffer; size_t size, bytes_per_pixel, bytes_per_line, width, height; uint red, green, blue; } Screen; #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <linux/kd.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <unistd.h> #include <time.h> #define fbdev "/dev/fb0" #define ttydev "/dev/tty" typedef struct { uint_fast8_t r, g, b, a; } Color; #define Die(Msg, ...) { \ fprintf (stderr, "fbgrad: " Msg ".\n", __VA_ARGS__); \ exit(1); \ }\ #define Assumption(Cond, Msg) \ if (!(Cond)) { \ fprintf (stderr, "fbgrad: failed assumption: %s\n", Msg);\ exit(2);\ } int main (int argc, char **argv) { //int ttyfd = open (ttydev, O_RDWR); //if (ttyfd < 0) // Die ("cannot open \"%s\"", ttydev); //if (ioctl (ttyfd, KDSETMODE, KD_GRAPHICS) == -1) // Die ("cannot set tty into graphics mode on \"%s\"", ttydev); int fbfd = open (fbdev, O_RDWR); if (fbfd < 0) Die ("cannot open \"%s\"", fbdev); struct fb_var_screeninfo vinf; struct fb_fix_screeninfo finf; if (ioctl (fbfd, FBIOGET_FSCREENINFO, &finf) == -1) Die ("cannot open fixed screen info for \"%s\"", fbdev); if (ioctl (fbfd, FBIOGET_VSCREENINFO, &vinf) == -1) Die ("cannot open variable screen info for \"%s\"", fbdev); /*Assumption ((vinf.red.offset%8) == 0 && (vinf.red.length == 8) && (vinf.green.offset%8) == 0 && (vinf.green.length == 8) && (vinf.blue.offset%8) == 0 && (vinf.blue.length == 8) && (vinf.transp.offset) == 0 && (vinf.transp.length == 0) && vinf.xoffset == 0 && vinf.yoffset == 0 && vinf.red.msb_right == 0 && vinf.green.msb_right == 0 && vinf.blue.msb_right == 0, "Color masks are 8bit, byte aligned, little endian, no transparency." );*/ Screen s = { .size = finf.line_length * vinf.yres, .bytes_per_pixel = vinf.bits_per_pixel / 8, .bytes_per_line = finf.line_length, .red = vinf.red.offset/8, .green = vinf.green.offset/8, .blue = vinf.blue.offset/8, .width = vinf.xres, .height = vinf.yres }; s.buffer = mmap (0, s.size, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if (s.buffer == MAP_FAILED) Die ("cannot map frame buffer \"%s\"", fbdev); int time_start = time (NULL); uint border = vinf.xres/2; for (uint t = 0; t < 255*1; t++) { for (uint y = 0; y < vinf.yres; y++) { for (uint x = 0; x < vinf.xres; x++) { uint pix_offset = x * s.bytes_per_pixel + y * s.bytes_per_line; // PIXEL FORMAT IS RGB565, in BGR format if(/*t < 255*10/2*/ x < border) { s.buffer[pix_offset] = 0B00000000; s.buffer[pix_offset+ 1] = 0B11111000; } else { s.buffer[pix_offset+ 1] = 0B00000000; s.buffer[pix_offset] = 0B11111000; } //s.buffer[pix_offset + s.red] = x * 255 / s.width; //s.buffer[pix_offset + s.green] = y * 255 / s.height; //s.buffer[pix_offset + s.blue] = t; } } } int time_end = time(NULL); munmap (s.buffer, s.size); /*if (ioctl (ttyfd, KDSETMODE, KD_TEXT) == -1) Die ("cannot set tty into text mode on \"%s\"", ttydev); */ close (fbfd); //close (ttyfd); printf ("FPS: %.2f.\n", 255.0 / (time_end - time_start)); return EXIT_SUCCESS; }
This access method (memory-mapped buffer, byte-wise writes) gives circa 255FPS [TIMING NOT ACCURATE, USES
time()
in seconds). There are probably fast access ways than this (write whole image in one go). I need to look into the DirectFB layer for that maybe.But this is extremely cool.
/dev/fb0
works on a custom firmware image. Wondering what prevented it from running on the stock image.For anyone wondering what the pin connections are:
- VCC -> 3.3V
- GND -> GND
- CS -> CS1 (GPIO pin 6)
- RESET -> GPIO 2
- DC -> GPIO 3
- MOSI -> GPIO 8
- SCLK -> GPIO 7
- LED -> to 5V over 50 Ohms resistor or over 10 Ohms to 3.3V (power LED backlight, needs small current limiting)
- MISO -> GPIO 9
When you're back, could you tell us how you converted the BMP images (e.g.
logo.bmp
) to the needed 16-bit format so that they are displayed correctly? I could not get this to work directly, I can only save it in 8 or 24 bit format, and the image looks garbeled on the display.EDIT: Tool reports 85 FPS when using different pixel computation.
unsigned short ConvertRGB888toRGB565(unsigned int sourceColor) { unsigned int red = (sourceColor & 0x00FF0000) >> 16; unsigned int green = (sourceColor & 0x0000FF00) >> 8; unsigned int blue = sourceColor & 0x000000FF; return (red >> 3 << 11) + (green >> 2 << 5) + (blue >> 3); }
unsigned int targetCol = ((uint8_t)( x * 255 / s.width) << 16) | ((uint8_t)(y * 255 / s.height) << 8) | (uint8_t) t; unsigned short targetColor16 = ConvertRGB888toRGB565(targetCol); s.buffer[pix_offset] = targetColor16 & 0xff; s.buffer[pix_offset + 1] = targetColor16 >> 8;
-
@Maximilian-Gerhardt In this topic ffmpeg side you can find BMP image conversion, i am using ffmpeg, gimp, imagemagic(convert) all the image job, quick tip:
mkdir ~/sequence # basically we have 2 steps for conversion in ffmpeg # 1. convert the video to resolotion of display, in my case 320x240(4:3 ratio) ffmpeg -i the-prey-video.xyz -vf scale=320:240 scaled.mp4 # 2. create the sequence files from given video ffmpeg -i scaled.mp4 -pix_fmt rgb565 -r 25/1 ~/sequence/seq%0001d.bmp # if you want to convert one image file(png,jpeg,bmp) to rgb565 bmp ffmpeg -i some-image-file.png -vf scale=320:240 -pix_fmt rgb565 exported-image.bmp
thats it.
Tested right now, when the files located in ram (/tmp) on omega it gives stable 100fps. In here 100fps notro's wiki says "Thus above fps=20 we only have 4 distinct values: 100/25=4, 100/26=3, 100/34=2, 100/51=1 (integer division)" in here so i think it can go further. Simple math says we have 96Mhz spi frequency hardware limit.
on the other hand -> mt7688 datasheet says:
27:16 rs_clk_sel Register Space SPI clock frequency select.
0: SPI clock frequency is hclk/2. (50% duty cycle, duty cycle is the ratio of the output high time to the total cycle time)
1: SPI clock frequency is hclk/3. (33.33% or 66.67% duty cycle)
2: SPI clock frequency is hclk/4. (50% duty cycle)
3: SPI clock frequency is hclk/5. (40% or 60% duty cycle)
4095: SPI clock frequency is hclk/4097
page 143
I think we could'nt get the max freq... i do'nt know that, ok then i will prepare a document "how to fbtft supported image" today, see you soon.
-
@Maximilian-Gerhardt I think activated kernel_menuconfig items are triggers some packages in the image, Build process step by step it works!
-
Nice work!
Can we run some number just to validate my understanding is correct...If it's 320x240 ( @ 16 bit/pixel) per image frame
and such individual (different) frames are transfer 80 times per second, thus
320x240x16x80 = 98.304 Megabits per second, not considering SPI overhead (and I am thinking the SPI protocol engine is hardware based fetching directly from RAM space.)Later post stated 12 fps, which will be
320x240x16x12 = 14.8 MHz pixel clock (not padded with SPI and frame fetching overhead), while SPI is clocked at 48MHz.
<-- here I am assuming MT7688 SoC is doing something else (such as running other code, e.g., build new frames, housekeeping, application code, etc.)In my view, the usability would be how much of the CPU time is left over for Omega2+ to perform its regular job (other than screen refreshing)? Do you have a guesstimate?
ccshello
-
@ccs-hello said in FB_ILI9341 80fps up to 100fps:
I am thinking the SPI protocol engine is hardware based fetching directly from RAM space
Yes, that's exactly what it is. The other question " how much of the CPU time is left over for Omega2+ to perform its regular job " i2ve just test it, it seems to be ok, but i did'nt test it for durability, just push the work load to omega2 and its just fine;
- 25fps ram loaded bmp sequence push to /dev/fb0 using sleep microseconds
- 3 ssh connection + serial console,
- working top application,
- shiftOut application that drives 7 segment lcd using 8bit shiftregister on omega
- web site download using wget in to omega2
bmp push to /dev/fb0
#!/usr/bin/env sh echo "mkdir /tmp/kizu" echo "cp -v /tmp/mounts/USB-A1/kizuwa/* /tmp/kizu" if [ -d /tmp/kizu ]; then while : # infinite loop do for i in `ls -v /tmp/kizu/*.bmp` do $(cat $i > /dev/fb0) > /dev/null # opkg install coreutils-sleep (microsecond sleep) # this way this script will work 25 times in a second # human eyes can't grab above this value so this is ok. echo $i sleep 0.04 done done fi
website download
wget -mkEpnp --no-check-certificate https://docs.onion.io/omega2-docs/
workload test video : https://www.youtube.com/watch?v=IFDwKkcWwDg
screen record video : https://www.youtube.com/watch?v=RJgqwcGm7vQ
-
I am currently working on getting DirectFB (https://github.com/deniskropp/DirectFB) to work with the Omega2. DirectFB is an abstraction layer above fbdev (which provides
/dev/fb0
).Based on DirectFB, one can build SDL, with which games can be built. DirectFB also includes a C++ wrapper and example programs which implement a image viewer and video player (
dfbplay
) with lots of formats (MPEG, AVI, ...)I am so close to getting DirectFB running on this thing. So close.
Basically I get DirectFB to compile. But during startup, it just hangs. I have debug output available, but since I haven't yet worked with DirectFB (or have a working reference system), it's hard for me to find the error. Especially since I had to patch DirectFB to get it compile under the gcc-musl toolchain at all..
If anyone is willing to help or test this, I have more info at the original OpenWRT/LEDE forum post at https://forum.openwrt.org/t/need-debugging-help-with-directfb-lede/19985. The responses there: Zero.
This is a stepping stone to getting a multimedia experience running directly on the Omega2, and possible more complicated games / emulators.
-
Thank you for your hard work, @Maximilian-Gerhardt . I am willing to help or test this, actually i cloned directfb, and lvgl_project, but i couldn't create time for the full scale display manager because of my project.
I've nearly finished a prototype device for education purpose using fbtft on omega, plus atmel328 that drives touch screen and rc522 rfid R/W, display on/off, some digital controls ...
After this project i will take my time, firstly chrooted debian i am thinking of, this way i can find a way out or might be see a workaround. After than that, not for just prototype, from top to toe openwrt lede specialist, I am aiming for. I am lack of knowledge for the full scale solution but all of us together is another thing. If this thing works Omega2 will be a fullscale computer
In a month or so i will be dive deeper i think.
-
Any updates on this?
-
@brolly759 Sorry for the late reply, i saw the post now.
Actually there are but that is not a finished code(even beta).
My work partner and I parted ways, and the project was canceled so i don't code it further.
In the code there are lots of comment lines with Turkish language, when i create a free time i can change the comment lines and push the "unfinished code" to github. If it'll work for someone i will be glad.
Some of the functions.
/* Color conversion */ typedef struct hex2rgb { unsigned int hexValue; unsigned short int r, g, b; } hex2rgb; hex2rgb parseRgb888( hex2rgb hexValue ); hex2rgb parseRgb565( hex2rgb hexValue ); hex2rgb color565( char *hexVal ); hex2rgb color888( char *hexVal ); --- /* Color conversion */ hex2rgb parseRgb565 ( hex2rgb hexParse ) { hex2rgb hexParsed888, parsed; hexParsed888 = parseRgb888( hexParse ); parsed.hexValue = ( ( hexParsed888.r >> 3 ) << 11 ) | ( ( hexParsed888.g >> 2 ) << 5 ) | ( hexParsed888.b >> 3 ); parsed.r = ( ( parsed.hexValue >> 11 ) & 0x1F ); parsed.g = ( ( parsed.hexValue >> 5 ) & 0x3F ); parsed.b = ( parsed.hexValue & 0x1F ); //printf( "Output\nHex 565: #%04X\n", parsed.hexValue ); return parsed; } --- hex2rgb parseRgb888( hex2rgb hexParse ) { hex2rgb parsed; parsed.r = ( ( hexParse.hexValue >> 16 ) & 0xff ); parsed.g = ( ( hexParse.hexValue >> 8 ) & 0xff ); parsed.b = ( ( hexParse.hexValue >> 0 ) & 0xff ); //printf( "Output\nHex 888: #%06X\n", hexParse.hexValue ); //printf( "RGB (%d, %d, %d)\n", parsed.r, parsed.g, parsed.b ); return parsed; } --- hex2rgb color565( char *hexVal ) { hex2rgb hex24, hexParsed565; sscanf( hexVal , "%06x", &hex24.hexValue ); //~ hexParsed888 = parseRgb888( hex24 ); hexParsed565 = parseRgb565( hex24 ); //~ printf ( "Hex24\t#%06X\nRGB888 (%d, %d, %d)\n\n", hex24.hexValue ,hexParsed888.r, hexParsed888.g, hexParsed888.b ); //~ printf ( "Hex16\t#%04X\nRGB565 (%d, %d, %d)\n", hexParsed565.hexValue, hexParsed565.r, hexParsed565.g, hexParsed565.b ); return hexParsed565; } --- hex2rgb color888( char *hexVal ) { hex2rgb hex24, hexParsed888; sscanf( hexVal , "%06x", &hex24.hexValue ); hexParsed888 = parseRgb888( hex24 ); //~ hexParsed565 = parseRgb565( hex24 ); //~ printf ( "Hex24\t#%06X\nRGB888 (%d, %d, %d)\n\n", hex24.hexValue ,hexParsed888.r, hexParsed888.g, hexParsed888.b ); //~ printf ( "Hex16\t#%04X\nRGB565 (%d, %d, %d)\n", hexParsed565.hexValue, hexParsed565.r, hexParsed565.g, hexParsed565.b ); return hexParsed888; } --- void drawEmbedBmp ( struct fb_info *fb_info, char *bmpFile, unsigned int bmpFile_len ) { memcpy( fb_info->ptr, &bmpFile[0], bmpFile_len ); }
-
Well fingers crossed you get this working
-
Hello, great work you can, it would help us a lot to have a vagrant file. Do you have the firmware compiled? Could you provide it?