Skip to content

chip select issue with multiple screens #95

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
kmtm opened this issue Jul 14, 2021 · 13 comments
Closed

chip select issue with multiple screens #95

kmtm opened this issue Jul 14, 2021 · 13 comments

Comments

@kmtm
Copy link

kmtm commented Jul 14, 2021

Hi, I'm trying to control two 2.2 TFT screens, both on SPI 0 using the two chip selects (CE0 and CE1).

Whenever I display to the first screen on CE0, it's fine (i.e. only displays on the first screen), but displaying to the second screen (CE1) pushes the same image to both screens. I can't seem to figure out why. Trying to manually throw CE0 high hasn't appeared to work.

Here's the implementation (adjusted from the sample code):

import digitalio
import board
from PIL import Image, ImageDraw, ImageFont
import adafruit_rgb_display.ili9341 as ili9341
import time

# First define some constants to allow easy resizing of shapes.
BORDER = 0
FONTSIZE = 24

# Configuration for CS and DC pins (these are PiTFT defaults):
cs_pin = digitalio.DigitalInOut(board.CE0)
cs2_pin = digitalio.DigitalInOut(board.CE1)
dc_pin = digitalio.DigitalInOut(board.D25)
dc2_pin = digitalio.DigitalInOut(board.D25)
reset_pin = digitalio.DigitalInOut(board.D24)
reset_pin2 = digitalio.DigitalInOut(board.D24)

# Config for display baudrate (default max is 24mhz):
BAUDRATE = 24000000

# Setup SPI bus using hardware SPI:
spi = board.SPI()
print('spi set up')

# pylint: disable=line-too-long
# Create the display:
disp = ili9341.ILI9341(
    spi,
    rotation=90,  # 2.2", 2.4", 2.8", 3.2" ILI9341
    cs=cs_pin,
    dc=dc_pin,
    rst=reset_pin,
    baudrate=BAUDRATE,
)

disp2 = ili9341.ILI9341(
    spi,
    rotation=90,  # 2.2", 2.4", 2.8", 3.2" ILI9341
    cs=cs2_pin,
    dc=dc2_pin,
    rst=reset_pin2,
    baudrate=BAUDRATE,
)
# pylint: enable=line-too-long

# Create blank image for drawing.
# Make sure to create image with mode 'RGB' for full color.
if disp.rotation % 180 == 90:
    height = disp.width  # we swap height/width to rotate it to landscape!
    width = disp.height
else:
    width = disp.width  # we swap height/width to rotate it to landscape!
    height = disp.height

image = Image.new("RGB", (width, height))

if disp2.rotation % 180 == 90:
    height2 = disp2.width  # we swap height/width to rotate it to landscape!
    width2 = disp2.height
else:
    width2 = disp2.width # we swap height/width to rotate it to landscape!
    height2 = disp2.height 

image2 = Image.new("RGB", (width2, height2))
print('width2:', width2, 'height2:', height2)

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
draw2 = ImageDraw.Draw(image2)

# Draw a white filled box as the background
draw.rectangle((00, 0, disp.width+100, disp.height+100), fill=(225, 225, 225))
disp.image(image)

input('draw blue box on second screen only')

#Draw a blue box only on the second screen
draw2.rectangle((0, 0, disp2.width+100, disp2.height+100), fill=(0, 225, 225))
disp2.image(image2)

Essentially the blue box appears on both screens instead of just the second one!

I'm not sure if I'm doing something wrong with the chip selects/setup, or if this library just can't support multiple SPI devices.

@TrevorFSmith
Copy link

TrevorFSmith commented Nov 15, 2021

I have exactly this same issue! I've checked everything that I can think of. A single board works fine but when I try to use both board.CE0 and board.CE1 as CS lines the display using CE0 responds to both drawing commands. In the code below, the CE0 display draws "Left" and then redraws to "Right" while the display using CE1 only draws "Right".

I've been working on this for a few hours and I'm a pretty stumped.

@kmtm Did you find a solution?

I'm using today's Blinka on a Raspberry Pi 4 running bullseye and I followed the directions in this learn guide.

import digitalio
import board
import time
import busio
from PIL import Image, ImageDraw, ImageFont
from adafruit_rgb_display import ili9341
from adafruit_rgb_display import st7789  # pylint: disable=unused-import
from adafruit_rgb_display import hx8357  # pylint: disable=unused-import
from adafruit_rgb_display import st7735  # pylint: disable=unused-import
from adafruit_rgb_display import ssd1351  # pylint: disable=unused-import
from adafruit_rgb_display import ssd1331  # pylint: disable=unused-import

BORDER = 20
FONTSIZE = 24

left_cs_pin = digitalio.DigitalInOut(board.CE0)
right_cs_pin = digitalio.DigitalInOut(board.CE1)
dc_pin = digitalio.DigitalInOut(board.D25)
reset_pin = digitalio.DigitalInOut(board.D24)

BAUDRATE = 24000000

spi = board.SPI()

left_disp = ili9341.ILI9341(
    spi,
    rotation=0, 
    cs=left_cs_pin,
    dc=dc_pin,
    #rst=reset_pin,
    baudrate=BAUDRATE,
)

right_disp = ili9341.ILI9341(
    spi,
    rotation=0,
    cs=right_cs_pin,
    dc=dc_pin,
    #rst=reset_pin,
    baudrate=BAUDRATE,
        )

if left_disp.rotation % 180 == 90:
    height = left_disp.width
    width = left_disp.height
else:
    width = left_disp.width
    height = left_disp.height

left_image = Image.new("RGB", (width, height))
left_draw = ImageDraw.Draw(left_image)
left_text = "Left"

right_image = Image.new("RGB", (width, height))
right_draw = ImageDraw.Draw(right_image)
right_text = "Right"

font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FONTSIZE)
text_color = 128 

while True:
    right_draw.rectangle((0, 0, width, height), fill=(0,0,0))
    (font_width, font_height) = font.getsize(right_text)
    right_draw.text(
        (width // 2 - font_width // 2, height // 2 - font_height // 2),
        right_text,
        font=font,
        fill=(text_color, 255 - text_color, 255 - text_color),
    )
    right_disp.image(right_image)

    left_draw.rectangle((0, 0, width, height), fill=(0,0,0))
    (font_width, font_height) = font.getsize(left_text)
    left_draw.text(
            (width // 2 - font_width // 2, height // 2 - font_height // 2),
            left_text,
            font=font,
            fill=(text_color, 255 - text_color, 255 - text_color),
            )
    left_disp.image(left_image)
    
    text_color = (text_color + 10) % 255
    time.sleep(0.5)

@makermelissa
Copy link
Collaborator

It may be that Linux is messing with the Chip Enable lines. We have instruction on how to reassign them here: https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/spi-sensors-devices#reassigning-the-spi-chip-enable-lines-3097985-4.

@TrevorFSmith
Copy link

Hi, @makermelissa! Thank you for the suggestion.

I reassigned CE0 and CE1 to GPIO 5 and 6 using the method in the learning guide that you linked. It did change the CS lines over to those pins but sadly they behave the same as when it was using the original CE0 and CE1 pins.

@makermelissa
Copy link
Collaborator

Ok, it was worth a shot.

@TrevorFSmith
Copy link

So, I found a work-around by using both SPI0 and SPI1 on the RPi 4. They're separate SPI peripherals so it takes more wires and won't work for devices that don't have two SPI peripherals but it'll get the job done for my immediate use case.

Just in case anyone else needs this, to turn on SPI0 and SPI1 go to /boot/config.txt and make sure that dtparam=spi-on and dtoverlay=spi1-3cs are set. (you'll need to reboot after changing them)

Then hook each display up to the various SPI0 and SPI1 pin with completely separate wiring (no shared MOSI, MISO, DC, etc) and program them separately by using busio.SPI() and busio.SPI(board.SCK_1, MISO=board.MISO_1, MOSI=board.MOSI_1)

@kmtm
Copy link
Author

kmtm commented Nov 16, 2021 via email

@pastel137
Copy link

Hey, what about four screens? We need to make them work, but rpi has only two SPI interfaces. Is there any fix for CS pins behaviour?

@makermelissa
Copy link
Collaborator

I was able to get 2 displays working at the same time. First of all, please don't use CE0 and CE1. The reassignment of pins was only if you absolutely needed to use those because the hardware couldn't easily be reconfigured.

Additionally, this would easily let you use more than 2 displays.

In my test, I used D5 and D6 as the chip select lines and D24 as the DC line.
Here's the code I used:

import time
import random
import busio
import digitalio
import board

from adafruit_rgb_display.rgb import color565
from adafruit_rgb_display import ili9341

# Configuratoin for CS and DC pins (these are FeatherWing defaults on M0/M4):
cs_pin = digitalio.DigitalInOut(board.D5)
cs2_pin = digitalio.DigitalInOut(board.D6)
dc_pin = digitalio.DigitalInOut(board.D24)

# Config for display baudrate (default max is 24mhz):
BAUDRATE = 24000000

# Setup SPI bus using hardware SPI:
spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# Create the ILI9341 display:
display = ili9341.ILI9341(spi, cs=cs_pin, dc=dc_pin, baudrate=BAUDRATE)
display2 = ili9341.ILI9341(spi, cs=cs2_pin, dc=dc_pin, baudrate=BAUDRATE)

# Fill the screen red, green, blue, then black:
for color in ((255, 0, 0), (0, 255, 0), (0, 0, 255)):
    display.fill(color565(color))
    display2.fill(color565(color))
# Clear the display
display.fill(0)
# Draw a red pixel in the center.
display.pixel(display.width // 2, display.height // 2, color565(255, 0, 0))
# Pause 2 seconds.
time.sleep(2)
# Clear the screen a random color
display.fill(
    color565(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
)
display2.fill(
    color565(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
)

I'm closing this because no modifications to the library were necessary to get this working.

@TrevorFSmith
Copy link

Thank you for looking into this, @makermelissa! It'll be useful for future projects.

@BioRyajenka
Copy link

Hi @makermelissa !
Your code doesn't work for my ST7789 screens. I can draw on one or another but not on both at the same time (specifically, after I create another ST7789 object, previous one stops working).

Here is my code adapted from your example

import time
import busio
import digitalio
import board

from adafruit_rgb_display.rgb import color565
from adafruit_rgb_display.st7789 import ST7789

# Configuratoin for CS and DC pins (these are FeatherWing defaults on M0/M4):
cs_pin = digitalio.DigitalInOut(board.GP10)
cs2_pin = digitalio.DigitalInOut(board.GP11)
dc_pin = digitalio.DigitalInOut(board.GP12)
rs_pin = digitalio.DigitalInOut(board.GP13)

# Config for display baudrate (default max is 24mhz):
BAUDRATE = 24000000

# Setup SPI bus using hardware SPI:
spi = busio.SPI(clock=board.GP14, MOSI=board.GP15)

# Create the ILI9341 display:
display = ST7789(spi, rotation=0, width=240, height=240, x_offset=0, y_offset=80, baudrate=BAUDRATE,
                 cs=cs_pin,
                 dc=dc_pin,
                 rst=rs_pin)
display2 = ST7789(spi, rotation=0, width=240, height=240, x_offset=0, y_offset=80, baudrate=BAUDRATE,
                 cs=cs2_pin,
                 dc=dc_pin,
                 rst=rs_pin)

# Fill the screen red, green, blue, then black:
for color in ((255, 0, 0), (0, 255, 0), (0, 0, 255)):
    display.fill(color565(color))
    display2.fill(color565(color))
# Clear the display
display.fill(0)
# Draw a red pixel in the center.
display.pixel(display.width // 2, display.height // 2, color565(255, 0, 0))
# Pause 2 seconds.
time.sleep(2)
# Clear the screen a random color
display.fill(
    color565(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
)
display2.fill(
    color565(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
)

Moreover, If I put the following lines instead:

display2 = ST7789(...)
display2.fill(color565(255, 0, 0))
time.sleep(2)
display1 = initDisplay(...)
display1.fill(color565(0, 255, 0))

Then the behaviour is to display red (actually, yellow. I think its because both CS are enabled by default until I initialized driver?), then wait for 2 sec, they put the first screen to black and then display green on the second screen.
I would expect both screen to work at the same time?

@makermelissa
Copy link
Collaborator

@BioRyajenka please create a new issue referencing this issue. Thanks.

@BioRyajenka
Copy link

Hi @makermelissa , done (link).
I also fixed a bunch of grammar and code errors in this new issue compared to my last message here :) So I hope it will make more sense now

@makermelissa
Copy link
Collaborator

Thank you. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants