piTFT adafruit tft+touchscreen

#3

I have done some digging and here is what I got so far. Linux has things called framebuffers for controlling the displays. It uses fb0 for the hdmi port, and fb1 for the touch screen. It seems that openFrameworks writes to fb0 and there isnt much you can do about it (something about opengl and the hardware acceleration, yada yada)

My fix is set openFrameworks window size to 720x480 in main.cpp and then use this handy framebuffer mirroring utility: https://github.com/notro/fbtft/wiki/Framebuffer-use

This thread was helpful in understanding (partially) the nature of the problem
http://www.raspberrypi.org/forum/viewtopic.php?f=67&t=58952

2 Likes
#4

thanks for the info!! that just what i need to know

so you use this https://github.com/tasanakorn/rpi-fbcp to mirror the content of fb1 to fb0

#5

My previous post used a separate app to copy the contents of one frame buffer over to another so that you can see your openFrameworks stuff on the touch screen. There are a few problems with this approach. One is that you have to run it separately from your OF app, which is lame. Another problem is that it simple runs on a timer and duplicates the frame buffer every so often. This means that the frame rate is slower than it needs to be. It also means that it is not synced with your display so there is no telling when it will begin the copy. It might start copying while you are still writing the buffer. Though, in practice I never saw this happen, it seems possible for tearing to occur.

To address those problems I have ported the original c based framebuffer copying code into a c++ for use inside OF directly.

Here is how you can use it

Copy and paste this code into testApp.cpp just under the #include statement

#define USE_FRAMEBUFFER
#ifdef USE_FRAMEBUFFER
#include <stdio.h>
#include <syslog.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <bcm_host.h>

class FrameBufferCopier
{
	private:
		//DISPMANX_DISPLAY_HANDLE_T display;
		int display;
		DISPMANX_MODEINFO_T display_info;
		//DISPMANX_RESOURCE_HANDLE_T screen_resource;
		int screen_resource;
		VC_IMAGE_TRANSFORM_T transform;
		uint32_t image_prt;
		VC_RECT_T rect1;
		int ret;
		int fbfd;
		char *fbp;

		struct fb_var_screeninfo vinfo;
		struct fb_fix_screeninfo finfo;
	public:
		FrameBufferCopier()
		{
			Initialize();
		}
		
		int Initialize()
		{
			fbfd = 0;
			fbp = 0;

			setlogmask(LOG_UPTO(LOG_DEBUG));
			openlog("fbcp", LOG_NDELAY | LOG_PID, LOG_USER);
			
			bcm_host_init();

			display = vc_dispmanx_display_open(0);
			if (!display) {
				syslog(LOG_ERR, "Unable to open primary display");
				return -1;
			}
			ret = vc_dispmanx_display_get_info(display, &display_info);
			if (ret) {
				syslog(LOG_ERR, "Unable to get primary display information");
				return -1;
			}
			syslog(LOG_INFO, "Primary display is %d x %d", display_info.width, display_info.height);


			fbfd = open("/dev/fb1", O_RDWR);
			if (!fbfd) {
				syslog(LOG_ERR, "Unable to open secondary display");
				return -1;
			}
			if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
				syslog(LOG_ERR, "Unable to get secondary display information");
				return -1;
			}
			if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
				syslog(LOG_ERR, "Unable to get secondary display information");
				return -1;
			}

			syslog(LOG_INFO, "Second display is %d x %d %dbps\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

			screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt);
			if (!screen_resource) {
				syslog(LOG_ERR, "Unable to create screen buffer");
				close(fbfd);
				vc_dispmanx_display_close(display);
				return -1;
			}

			fbp = (char*) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
			if (fbp <= 0) {
				syslog(LOG_ERR, "Unable to create mamory mapping");
				close(fbfd);
				ret = vc_dispmanx_resource_delete(screen_resource);
				vc_dispmanx_display_close(display);
				return -1;
			}

			vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres);			
			return 1;
		}
		
		void Dispose()
		{
			munmap(fbp, finfo.smem_len);
			close(fbfd);
			ret = vc_dispmanx_resource_delete(screen_resource);
			vc_dispmanx_display_close(display);
		}

		void Copy()
		{
			vc_dispmanx_snapshot(display, screen_resource, (DISPMANX_TRANSFORM_T)0);
			vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8);
		}
};
FrameBufferCopier fbcp;
#endif

Then in your draw method add this code after all drawing commands have been completed

#ifdef USE_FRAMEBUFFER
fbcp.Copy();	
#endif

I included the #ifdef’s so that you can commit out the #define USE_FRAMEBUFFER line if you want to work with the project on your computer and not get all the compiler errors. There is probably a more elegant way to achieve this, but I don’t know about it.

#6

@greengiant831 thanks for that! Works like a charm.

What about the touchscreen? I have the event register on the OS… anybody have a clue about how to read mouse events from that?

#7

igual this helps
http://marks-space.com/2013/09/07/programming-a-touchscreen-on-the-raspberry-pi/

#8

grande nacho!

#9

Hi all, I’m putting together both the framebuffer copy and the touch events in an addon.

Let me know if you want to help

#10

I’m stock porting this code from https://github.com/mwilliams03/Pi-Touchscreen-basic/blob/master/touch.h that seams not to compile under linux. Any idea?

char *events[EV_MAX + 1] = {
	[0 ... EV_MAX] = NULL,
	[EV_SYN] = "Sync",			[EV_KEY] = "Key",
	[EV_REL] = "Relative",			[EV_ABS] = "Absolute",
	[EV_MSC] = "Misc",			[EV_LED] = "LED",
	[EV_SND] = "Sound",			[EV_REP] = "Repeat",
	[EV_FF] = "ForceFeedback",		[EV_PWR] = "Power",
	[EV_FF_STATUS] = "ForceFeedbackStatus",
}; 
#11

@patricio you doing this?

extern "C" {
#include "touch.h"
}
1 Like
#12

also from the readme it looks like it requires wiringPi so make sure you are linking that - here is how I did it

#13

I’m still getting:

../../../addons/ofxPiTFT/src/touch.h: In lambda function:
../../../addons/ofxPiTFT/src/touch.h:343:30: error: expected ‘{’ before ‘=’ token
../../../addons/ofxPiTFT/src/touch.h: At global scope:
../../../addons/ofxPiTFT/src/touch.h:343:30: warning: lambda expressions only available with -std=c++0x or -std=gnu++0x [enabled by default]
../../../addons/ofxPiTFT/src/touch.h:343:32: error: no match for ‘operator=’ in ‘{} = leds’
../../../addons/ofxPiTFT/src/touch.h:343:32: note: candidate is:
../../../addons/ofxPiTFT/src/touch.h:343:28: note: <lambda()>&<lambda()>::operator=(const<lambda()>&)
../../../addons/ofxPiTFT/src/touch.h:343:28: note:   no known conversion for argument 1 from ‘char* [16]’ to ‘const<lambda()>&’
../../../addons/ofxPiTFT/src/touch.h:344:3: error: expected identifier before numeric constant
../../../addons/ofxPiTFT/src/touch.h:344:9: error: type ‘<lambda>’ with no linkage used to declare function ‘void<lambda>::operator()() const’ with linkage [-fpermissive]
#14

It looks odd to me because of the extra commas at the end of each array but I guess gcc is fine with this but g++ is not

For instance if you try and compile his project with

$ g++ -g -o buttonExample buttonExample.c -l wiringPi

instead of

$ gcc -g -o buttonExample buttonExample.c -l wiringPi

you will get the same errors

#15

Hello! I have managed to have my animation program run on the PiTFT screen as a copy of the HDMI output as described here. But the framerate is very low, 30fps instead of 60fps. It doesn’t look good. Is it possible to run an openframeworks program on the PiTFT only, to get higher framerate? Maybe make the PiTFT the main display for the entire operating system?

#16

I think that its not possible, maybe you can use an small hdmi display

#17

It looks like the reason it isn’t possible is because the PiTFT is not connected to the GPU like the HDMI and RCA connectors are. And openGL works on the GPU. I have decided to use this screen instead: https://www.adafruit.com/products/913 which uses the RCA connection. A little bit blurry on text and thin lines, but smooth and fast and very easy to use. I haven’t found this small screens with HDMI connection. Probably expensive to make, since the pixels then have to be very tiny.

#18

Have anyone tested this screen:

https://www.sparkfun.com/products/13051

Says it operates as primary display. Maybe it utilizes the GPU?

#19

I just received that sparkfun screen, and sadly it does not work with openFrameworks out of the box. At first glance it looks like it does the alternative framebuffer thing too.

#20

im not an expert but any screen that uses the gpio to connect with the rpi its going to use the framebuffer way. Only a hdmi or composite its going to work as you expected

#21

Just for reference, I got touch events working with ofxPiTFT. I’ll push changes soon. Sooner if it’s urgent for anyone :smile:

1 Like
#22

That´s super!!! Im curious to see how did you do it