Reverse RGB565 byte order for ILI9341 TFT Display

@ajacobs ok, now is clear !
This is the code adjusted,but I’m still in trouble with the image on tft as before.
I start thinking that I’ve an hw problem with the H7 hw.
As I said before, I’m surprised that before I start to see the output of FPS on the console I must wait more that 10 second, sound very strange that it takes soo much time to configure the TFT.
Do you see the same delay ?

#TFT screen demo to steam frame buffer to a external SPI screen

import sensor, image, time ,pyb
from machine import SPI,Pin
from TftILI9341 import TFT

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)

clock = time.clock()
rset =Pin("P7",Pin.OUT)
rset.value(0)
pyb.delay(200)
rset.value(1)

spi = SPI(2, baudrate=20000000) #create an SPI bus

#create an instance of the screen driver
#you mustr pass a SPI bus and type of screen (ili9341 or st7735
#optional can pass cs pin and dc pin default is cs='P3' and dc='P9'
screen = TFT(spi)


#set window on screen to write to (x_start, Y_start, width, height)
#the window needs to be inside the resolution of the screen and must match the exact size of fb
screen.set_window(0,0,320,240)


while(True):
    clock.tick()
    img = sensor.snapshot()

    # some image processing code goes here...

    screen.write_to_screen(img) #send the fb to the screen
    print(clock.fps())type or paste code here

@ajacobs - Did my firmware fix the issue?

@kwagyeman ,
Hi, I’ve tried to use your new firmware with this code, but I’ve not clear where pass the byte_reverse=True argument in the code .
At the moment what I obtain is a full image filling all the screen but with obviously the colors are wrong.
The code is :

import sensor, image, time
from MP_ili9341 import ili9341

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)

clock = time.clock()

screen = ili9341()
screen.set_window(0,0,320,240)

while(True):
    clock.tick()
    img = sensor.snapshot()
    screen.send_spi(img, True)
    print(clock.fps())

and this is the driver

from machine import Pin, SPI
import time
import ustruct


class ili9341():


  def send_spi(self,data, is_data):
    self.dc.value(is_data) #set data/command pin
    self.cs.value(0)
    self.hspi.write(data)
    self.cs.value(1)

  def __init__(self, cs='P3', dc='P9'):
    self.hspi = SPI(2, baudrate=54000000)
    self.cs = Pin(cs, Pin.OUT)
    self.dc = Pin(dc, Pin.OUT)

    for command, data in (
      (0xef, b'\x03\x80\x02'),
      (0xcf, b'\x00\xc1\x30'),
      (0xed, b'\x64\x03\x12\x81'),
      (0xe8, b'\x85\x00\x78'),
      (0xcb, b'\x39\x2c\x00\x34\x02'),
      (0xf7, b'\x20'),
      (0xea, b'\x00\x00'),
      (0xc0, b'\x23'),  # Power Control 1, VRH[5:0]
      (0xc1, b'\x10'),  # Power Control 2, SAP[2:0], BT[3:0]
      (0xc5, b'\x3e\x28'),  # VCM Control 1
      (0xc7, b'\x86'),  # VCM Control 2
      (0x36, b'\xF8'),  # Memory Access Control
      (0x3a, b'\x55'),  # Pixel Format
      (0xb1, b'\x00\x18'),  # FRMCTR1
      (0xb6, b'\x08\x82\x27'),  # Display Function Control
      (0xf2, b'\x00'),  # 3Gamma Function Disable
      (0x26, b'\x01'),  # Gamma Curve Selected
      (0xe0, b'\x0f\x31\x2b\x0c\x0e\x08\x4e\xf1\x37\x07\x10\x03\x0e\x09\x00'), # Set Gamma
      (0xe1, b'\x00\x0e\x14\x03\x11\x07\x31\xc1\x48\x08\x0f\x0c\x31\x36\x0f')):  # Set Gamma
      self.send_spi(bytearray([command]), False)
      self.send_spi(data, True)
    self.send_spi(bytearray([0x11]), False)
    #time.sleep(10)
    self.send_spi(bytearray([0x29]), False)


  def set_window(self, x0=0, y0=0, width=320, height=240):
    x1=x0+width-1
    y1=y0+height-1
    self.send_spi(bytearray([0x2A]),False)            # set Column addr command
    self.send_spi(ustruct.pack(">HH", x0, x1), True)  # x_end
    self.send_spi(bytearray([0x2B]),False)            # set Row addr command
    self.send_spi(ustruct.pack(">HH", y0, y1), True)  # y_end
    self.send_spi(bytearray([0x2C]),False)            # set to write to RAM

  #chuck size can be increased for faster wiring to the screen at cost of RAM
  def load_image(self, image_file, chunk_size=1024):
    BMP_file = open(image_file , "rb")
    data = BMP_file.read(54)              #seek position past header
    data = BMP_file.read(chunk_size)
    while len(data)>0 :                   #read data from file to SPI
      self.send_spi(data, True)
      data = BMP_file.read(chunk_size)
    BMP_file.close()

You pass it to the lcd init function.

You have to use the OpenMV library BTW. E.g. the OpenMV lcd module. You are bypassing that with a custom driver.

Also If I want use a TFT screen with ili9341 Driver ?
Now is clear my misunderstanding , I was thinking that new firmware was fissing the problem rised originally by jacon with ili9341.
Anyway now I’ve solved using the byteswap function develope by jacob and the TFT 2,8 inc works ok .
This is the code

import sensor, image, time
from MP_ili9341 import ili9341

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)

clock = time.clock()

screen = ili9341()
screen.set_window(0,0,320,240)
#screen.load_image('bots16_320x240.bmp')


while(True):
    clock.tick()
    img_byte_array = sensor.snapshot().bytearray()

    ili9341.byteswap(img_byte_array,len(img_byte_array))
    screen.send_spi(img_byte_array, True)
    print(clock.fps())

and this the drive

from machine import Pin, SPI
import time
import ustruct


class ili9341():

  @micropython.asm_thumb
  def byteswap(r0, r1):               # bytearray, len(bytearray)
    mov(r3, 1)
    lsr(r1, r3) # divide len by 2
    mov(r4, r0)
    add(r4, 1) # dest address
    label(LOOP)
    ldrb(r5, [r0, 0])
    ldrb(r6, [r4, 0])
    strb(r6, [r0, 0])
    strb(r5, [r4, 0])
    add(r0, 2)
    add(r4, 2)
    sub(r1, 1)
    bpl(LOOP)

  def send_spi(self,data, is_data):
    self.dc.value(is_data) #set data/command pin
    self.cs.value(0)
    self.hspi.write(data)
    self.cs.value(1)

  def __init__(self, cs='P3', dc='P9'):
    self.hspi = SPI(2, baudrate=54000000)
    self.cs = Pin(cs, Pin.OUT)
    self.dc = Pin(dc, Pin.OUT)

    for command, data in (
      (0xef, b'\x03\x80\x02'),
      (0xcf, b'\x00\xc1\x30'),
      (0xed, b'\x64\x03\x12\x81'),
      (0xe8, b'\x85\x00\x78'),
      (0xcb, b'\x39\x2c\x00\x34\x02'),
      (0xf7, b'\x20'),
      (0xea, b'\x00\x00'),
      (0xc0, b'\x23'),  # Power Control 1, VRH[5:0]
      (0xc1, b'\x10'),  # Power Control 2, SAP[2:0], BT[3:0]
      (0xc5, b'\x3e\x28'),  # VCM Control 1
      (0xc7, b'\x86'),  # VCM Control 2
      (0x36, b'\xF8'),  # Memory Access Control
      (0x3a, b'\x55'),  # Pixel Format
      (0xb1, b'\x00\x18'),  # FRMCTR1
      (0xb6, b'\x08\x82\x27'),  # Display Function Control
      (0xf2, b'\x00'),  # 3Gamma Function Disable
      (0x26, b'\x01'),  # Gamma Curve Selected
      (0xe0, b'\x0f\x31\x2b\x0c\x0e\x08\x4e\xf1\x37\x07\x10\x03\x0e\x09\x00'), # Set Gamma
      (0xe1, b'\x00\x0e\x14\x03\x11\x07\x31\xc1\x48\x08\x0f\x0c\x31\x36\x0f')):  # Set Gamma
      self.send_spi(bytearray([command]), False)
      self.send_spi(data, True)
    self.send_spi(bytearray([0x11]), False)
    #time.sleep(10)
    self.send_spi(bytearray([0x29]), False)


  def set_window(self, x0=0, y0=0, width=320, height=240):
    x1=x0+width-1
    y1=y0+height-1
    self.send_spi(bytearray([0x2A]),False)            # set Column addr command
    self.send_spi(ustruct.pack(">HH", x0, x1), True)  # x_end
    self.send_spi(bytearray([0x2B]),False)            # set Row addr command
    self.send_spi(ustruct.pack(">HH", y0, y1), True)  # y_end
    self.send_spi(bytearray([0x2C]),False)            # set to write to RAM

  #chuck size can be increased for faster wiring to the screen at cost of RAM
  def load_image(self, image_file, chunk_size=1024):
    BMP_file = open(image_file , "rb")
    data = BMP_file.read(54)              #seek position past header
    data = BMP_file.read(chunk_size)
    while len(data)>0 :                   #read data from file to SPI
      self.send_spi(data, True)
      data = BMP_file.read(chunk_size)
    BMP_file.close()

Yeah, I’m saying the driver in the firmware will do all this and won’t have any performance impacts and be much faster than the pure Python code.