notro / fbtft

Linux Framebuffer drivers for small TFT LCD display modules. Development has moved to https://git.kernel.org/cgit/linux/kernel/git/gregkh/staging.git/tree/drivers/staging/fbtft?h=staging-testing
1.84k stars 495 forks source link

newbie here with fb and fbtft, need help with touchscreen (ili9341) #583

Closed ciobania closed 2 years ago

ciobania commented 2 years ago

Hi there,

I'm new to TFT and FB integration. The display I'm using is a Display Module, 2.8" 240x320 SPI TFT LCD Touch Panel Serial Port Module +PCB ILI9341 5V/3.3V

I've been struggling for the past months in understanding how to drive my display, and touchscreen at the same time;

Currently I'm using a very clunky(?!) python written driver that builds a PIL Image and buffers it to the display directly via the SPI. SPI0 for display, and SPI1 for touchscreen.

The issue with it is the fact that I cannot calibrate the touchscreen, and have to manually create the hotspots, and polygons for where the buttons will go. After couple of hours of updating the screen and interacting with it, the screen just goes white, nothing else is displayed, but the touchscreen still receives the events; I'm assuming at this point the display buffer is full, and have no idea how to clean it up;

I have started looking into FB, and was able to get something sent to the display using following overlays:

  1. dtoverlay=fbtft,spi0-0,rpi-display,bgr,reset_pin=25,dc_pin=24,led_pin=5,rotate=270,debug=7

  2. dtoverlay=fbtft,spi0-0,rpi-display,bgr,reset_pin=25,dc_pin=24,led_pin=5,rotate=270,pendown_gpios=26,debug=7

  3. dtoverlay=rpi-display

The issue I'm having right now is the fact that I cannot seem to be able to pass in the pen_irq pin number for the fbtft overlays. As such, it does not create a /dev/input/event0. On the other hand if I use the rpi-display overlay, I'm able to send something useful to the screen, but I cannot seem to be able to use /dev/input/event0.

I've tried different configs, messing around with the overlays and to no avail. Do you have a wiki page that describes how to create a new overlay, or perhaps how I can pass in the touchscreen pins?

I don't need a desktop environment setup, or just to be able to calibrate the touchscreen, and built my thermostat GUI.

Could you please help me out, in any way shape or form with it?

Thank you.

notro commented 2 years ago

The fbtft overlay only deals with the display controller and not the touch controller. Looking at the datasheets in the rar file, the touch controller should be supported by the ads7846 driver. But it behaves differently depending on the model, so you need to know exactly which one it is. If it is an ads7846 there's a DT overlay for it: https://github.com/raspberrypi/linux/blob/rpi-5.15.y/arch/arm/boot/dts/overlays/ads7846-overlay.dts.

If you're not getting touch events you can look at /proc/interrupts to see if the gpio interrupt is firing.

As a sidenote, it was refreshing to see a seller that is so frank about the difficulty in getting this to work. From the description:

Note:
This kit requires professional knowledge and ability, please make sure you know how to use it.
ciobania commented 2 years ago

Hey, thanks for replying!

Can you please confirm if I need to enable 2 overlays in order to be able to drive my TFT display with touch screen? I think I did try this at one point, with the ADS7486, and FBTFT, but wasn't receiving anything with evtest /dev/input/event0.

Fair point with the note from the seller. :D Initially I read that note to be about knowing how to wire it, now I think it's meant to be about having real skills to pull this off :))

Do you know of any resource on the internet or some books that kind of describe how FB and overlays work with these displays? Most of the knowledge I have currently on them is through trial and error, and reading blogs for the past 6 months.

The PENIRQ is 26, in my case, and the touchscreen is configured on SPI1.1 - it looks like I may have to fiddle with the overlay, in order to tell it which SPI interface to use. Am I wrong assuming that?

Would you be able to tell me what dtoverlays to use, based on above config, and my initial comment?

I read somwhere that overlays can be merged, is that something doable in my particular case, and how I'm meant to be using these overlays?

Thank you kindly for any kind of support!

notro commented 2 years ago

Yes you need both, one for the display controller and one for the touch controller.

I just did a test on a display I have which uses gpio25 for penirq:

dtoverlay=ads7846,penirq=25,penirq_pull=2,xohms=60,pmax=255

My display doesn't have a pullup resistor on PENIRQ that's why I had to use penirq_pull, but the schematics in the rar file shows there's a 10k pullup on yours so you shouldn't need it.

If evtest doesn't show any events make sure interrupts are firing:

$ cat /proc/interrupts | grep ads7846
 84:         15          0          0          0  pinctrl-bcm2835  25 Edge      ads7846
# one touch generating 4 interrupts
$ cat /proc/interrupts | grep ads7846
 84:         19          0          0          0  pinctrl-bcm2835  25 Edge      ads7846
ciobania commented 2 years ago

Yes, I am getting something from interrupts, when I press the touchscreen.

Depending on how I press, the counter increases: 199: 1228 0 0 0 pinctrl-bcm2835 26 Edge ads7846

Not sure what I need to do now.

This is the output of dev/input:

crw-rw---- 1 root input 13, 64 Mar 21 15:12 event0
crw-rw---- 1 root input 13, 63 Mar 21 15:11 mice
crw-rw---- 1 root input 13, 32 Mar 21 15:12 mouse0

Neither of those is spitting out anything, with evtest.

Below are my dtoverlays, in the same order as they are declared in the config.txt:

dtoverlay=ads7846,cs=1,penirq=26,xohms=60,pmax=255
dtoverlay=fbtft,spi0-0,rpi-display,bgr,reset_pin=25,dc_pin=24,led_pin=5,rotate=270,debug=7
notro commented 2 years ago

I would have tried to see what the ads7846 driver does. This will show when the irq function is entered and the spi transfers the driver performs:

$ sudo trace-cmd start -e spi:spi_transfer_start -p function_graph -l ads7846_irq
$ sudo trace-cmd show
# tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
 2)               |  ads7846_irq [ads7846]() {
 2)               |  /* spi_transfer_start: spi0.1 6995c1fa len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-3f-30-00-57-30-00-1c-10-00-59-80-00-55-f8] */
 2)               |  /* spi_transfer_start: spi0.1 6995c1fa len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-2b-20-00-3e-80-00-13-80-00-42-48-00-3e-b8] */
 2)               |  /* spi_transfer_start: spi0.1 6995c1fa len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-2b-90-00-3e-c0-00-13-a8-00-41-f8-00-3e-70] */
 2)               |  /* spi_transfer_start: spi0.1 6995c1fa len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-2b-c8-00-3e-e0-00-13-40-00-43-00-00-3d-d0] */
 2)               |  /* spi_transfer_start: spi0.1 6995c1fa len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-2c-08-00-3e-f8-00-12-f0-00-44-c0-00-3e-18] */
 2)               |  /* spi_transfer_start: spi0.1 6995c1fa len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-2c-70-00-3f-60-00-12-b0-00-45-e8-00-3e-98] */
 2)               |  /* spi_transfer_start: spi0.1 6995c1fa len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-2c-50-00-3f-80-00-12-70-00-46-f8-00-3f-80] */
 2) @ 168968.4 us |  }

Unload the fbtft driver first to avoid cluttering the log.

ciobania commented 2 years ago

This is the output of it:

 2)               |  ads7846_irq [ads7846]() {
 2)               |  /* spi_transfer_start: spi0.1 706e2265 len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-00-00-00-00-00-00-00-00-00-00-00-00-00-00] */
 2) * 49014.68 us |  }
 2) * 30000.41 us |  ads7846_irq [ads7846]();

One thing that strikes me, looking at it, is the fact that you get 4 interrupts for one press, whereas I get 2. The counter increases by 2, with each press. Also it looks like RX is all 0s in my case, not sure if that means there is no receiver, or if that's a fluke because I disabled the display.

notro commented 2 years ago

The rx bytes being zero is the reason you don't get any events. It's strange really if you had this working using python. Does it still work under python?

The number of interrupts per touch isn't that important as long as it's not an interrupt storm. A wiggily finger will probably trigger multiple interrupts.

ciobania commented 2 years ago

Indeed it still works. In the sense that I have some logic to turn ON/OFF the display if I don't use it. I can also get (X, Y) positions, from it.

I will have a look again tomorrow at the overlay, to see if there's else anything I need to address, or pins to declare. I read about the ADS7846 being flaky and people having issues with it, recently, not sure if that's my case. I suspect that's one of the reasons ts_calibrate and evtest don't work either?

It sounds like what you are saying is that the touchscreen is sending those events, but they are not passed on further, that there's no receiver at the other end? (I'm inferring this from the convo above, and the fact that the IRQ events are triggered only when I touch the screen).

I will upload my framework tomorrow morning, and you can have a look on why it's working with Python. This "driver" is something glued together from multiple similar examples and lots of sources (for example: BLAVERY has an obsolete example, and it's similar to the Adafruit ili9341 driver.)

If this doesn't work, I wonder if you can give me some hints on how to calibrate the display, because right now it's very hard to work out the coordinates, since the screen is a bit offset from the touch, and very hard to keep track of the hotspots.

Would be nice if I can get to reuse some of the hotspots and coordinates from the buttons perhaps...

ciobania commented 2 years ago

I think I know what's wrong here. The logs that I pulled from the trace-cmd is reporting that the spi0.1 is used. However, the touchscreen is wired on spi1.1, at least that's the SPIDEV config I'm using in the Python code.

I've tried to enable the the spidev1, but I get an error: 002752.774: Unknown dtparam 'spidev1' - ignored I've looked over the internet, and I'm unable to find info on how to do this, and I've already changed the spidev1 to okay in the dtbo.

Any hints please - assuming that I've done the right thing so far, that I'm on the right path?

Thank you

notro commented 2 years ago

The ads7846 overlay doesn't support changing the spi bus, so you need edit the overlay itself. Copy, rename, edit and compile:

$ wget https://raw.githubusercontent.com/raspberrypi/linux/rpi-5.15.y/arch/arm/boot/dts/overlays/ads7846-overlay.dts
$ mv ads7846-overlay.dts ads7846-spi1-overlay.dts

# edit overlay: spi0 -> spi1

$ dtc -@ -I dts -O dtb -o ads7846-spi1.dtbo ads7846-spi1-overlay.dts
$ sudo cp ads7846-spi1.dtbo /boot/overlays/

Since you're not using spi0 you have to enable a spi1-Xcs overlay as well, but you already have that I guess since otherwise spi1 wouldn't be available. Just remember to drop the csX_spidev property as that will conflict with ads7846.

ciobania commented 2 years ago

SUCCESS!!

Bloody hell! I did change the spi0 to spi1 before you posted your comment, but changed the spidev1 to okay, as well. That didn't work;

Followed your steps and it did work:

irq/199-ads7846-304   [000]    87.929023: funcgraph_entry:                   |  ads7846_irq() {
 irq/199-ads7846-304   [000]    87.949396: spi_transfer_start:   spi1.1 0x84f79060 len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-39-50-00-4c-10-00-12-88-00-6c-a8-00-48-c0]
 irq/199-ads7846-304   [000]    87.969396: spi_transfer_start:   spi1.1 0x84f79060 len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-3f-f8-00-4c-90-00-2b-70-00-56-b0-00-4c-d0]
 irq/199-ads7846-304   [000]    87.989392: spi_transfer_start:   spi1.1 0x84f79060 len=15 tx=[d1-00-00-91-00-00-b1-00-00-c1-00-00-90-00-00] rx=[00-3e-78-00-4b-d8-00-1e-30-00-62-60-00-4b-e8]
 irq/199-ads7846-304   [000]    88.009380: funcgraph_exit:       # 80357.760 us |  }
 irq/199-ads7846-304   [000]    88.009387: funcgraph_entry:      # 29987.448 us |  ads7846_irq();

evtest works as well!

I don't have words to express the joy, and how grateful I am for your help in sorting this out, and allowing me to learn! Let me know if and where I can buy you a coffee :smile: :joy: :partying_face: :fireworks:

You kind sir, are a legend!!!!

PS: the only thing nagging me is the fact that ts_calibrate doesn't display anything, however it does record the touch, etc. I'll dig that out somehow on the internet.

notro commented 2 years ago

Glad you made it work 😄

Please close this issue if your problem is solved.

ciobania commented 2 years ago

Much appreciated!

ciobania commented 2 years ago

Hey,

can you help me out please with the same display. I'm running ts_calibrate and I'm not able to see the squares with the cross-hairs to calibrate the touchscreen.

When the raspberry starts, it displays some boot info, and then ends up on the console login. I have nothing in the console to tell it to display a tty on the fb1. When I run ts_calibrate via SSH, the screen on the display turns black and I am able to click on it randomly, and it registers the events, and says it calibrates it. However, I'm not able to see where I click so that means the display will mis-calibrate it?

There seems to be less info over the internet on this particular type of issue and I don't know what else can I do. Do I need to enable console over ttyAMA0 - though that is for uart?

this is my cmdline.txt -

console=serial0,115200 console=tty1 root=PARTUUID=613f8ab9-02 rootfstype=ext4 fsck.repair=yes rootwait

Following is my config.txt:

# Enable audio (loads snd_bcm2835)
dtparam=audio=on

[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
#dtoverlay=vc4-fkms-v3d
max_framebuffers=2

[all]
#dtoverlay=vc4-fkms-v3d
hdmi_force_hotplug=1
dtparam=i2c_arm=on
dtparam=spi=on
dtoverlay=spi1-3cs
enable_uart=1
#dtoverlay=tft9341:rotate=270
dtoverlay=fbtft,spi0-0,rpi-display,bgr,reset_pin=25,dc_pin=24,led_pin=5,rotate=270,debug=7
dtoverlay=ads7846-spi1,penirq=26,xohms=60,pmax=255
hdmi_group=2
hdmi_mode=1
hdmi_mode=87
hdmi_cvt 320 240 60 6 0 0 0
hdmi_drive=2

Thank you again, for any input, and for help so far!

ciobania commented 2 years ago

I managed to be able to get the crosshair displayed, and do the calibration.

I don't get it why it doesn't draw on the /dev/fb1. Command I was using was:

TSLIB_TSDEVICE=/dev/input/event0 TSLIB_FBDEVICE=/dev/fb1 TSLIB_CALIBFILE=/etc/pointercal TSLIB_CONFFILE=/etc/ts.conf ts_calibrate

After ditching the TSLIB_FBDEVICE=/dev/fb1 environment variable, the calibration screen came on correctly, and was able to calibrate it.

Boy, what a ride this was!

Thanks for all your input, feedback and help sorting this out!