Thank you for your reply, I did not use MCU Ram for the TFT. Just some small bytearray for a 5x8 font,OutoftheBOTS_ wrote: ↑Fri Apr 24, 2020 8:26 amLow RAM is the big factor in using this MCU for graphic. The work around is that you have very fast access to the TFT RAM so you need to program in a way that makes use of the TFT RAM and only having super minimal stuff in MCU RAMholberg wrote: ↑Thu Apr 23, 2020 9:51 amI got it running. ILIDriver now in micropython.OutoftheBOTS_ wrote: ↑Tue Apr 21, 2020 11:43 pmI wrote the code quite a while ago so without sitting down and reading the reference manual and looking at the code to remember what I did I couldn't be certain but that looks about right
But when I want to implement a ILI9341 grafic class, I' run out of RAM. If I check the availabel Memory
MicroPython v1.12-387-g1b1ceb67b on 2020-04-19; MCUDEV STM32F407VE with STM32F407VE
Type "help()" for more information.
>>> import gc
>>> gc.collect()
>>> gc.mem_free()
33280
its not this much, any Idea ?
My code (as of my experimental design), working but not yet as class, and yes I'm a "C" Programmer
Code: Select all
import stm
import time
import machine
from math import trunc
import glcdfont
def FSMC_Init():
#constants of register
RCC_AHB3ENR_FSMCEN = 0x1 #bit to enable FSMC clock
RCC_AHB1ENR_GPIODEN = 0x00000008 #bit to enable D port clock
RCC_AHB1ENR_GPIOEEN = 0x00000010 #bit to enable E port clock
FSMC_Bank1_base = 0xA0000000 # 0xA0000000 FSMC registers base address
FSMC_BCR_bank1_offset = 0x0
FSMC_BTR_bank1_offset = 0x4
FSMC_BTR1_ADDSET_0 = 0x00000001
FSMC_BTR1_ADDSET_1 = 0x00000002
FSMC_BTR1_ADDSET_2 = 0x00000004
FSMC_BTR1_ADDSET_3 = 0x00000008
FSMC_BTR1_ADDSET_T = 0x0000000F # ILI9341, this is equivalent to RD high duration, 90ns, we set ADDSET to 15,is 15*6=90ns
FSMC_BTR1_DATAST = 0x0000FF00 #<DATAST [3:0] bits (Data-phase duration) */
FSMC_BTR1_DATAST_0 = 0x00000100
FSMC_BTR1_DATAST_1 = 0x00000200
FSMC_BTR1_DATAST_2 = 0x00000400
FSMC_BTR1_DATAST_3 = 0x00000800
FSMC_BTR1_DATAST_T = 0x00003C00 # DATAST to 60, which is 60 HCLK cycles, and the time is approximately 360ns.
FSMC_BTR1_BUSTURN = 0x000F0000 #<BUSTURN[3:0] bits (Bus turnaround phase duration) */
FSMC_BTR1_BUSTURN_0 = 0x00010000
FSMC_BTR1_BUSTURN_1 = 0x00020000
FSMC_BTR1_BUSTURN_2 = 0x00040000
FSMC_BTR1_BUSTURN_3 = 0x00080000
FSMC_BTR1_ACCMOD = 0x03000000
#FSMC_BTR1_ADDSET_1 = 0x2
#FSMC_BTR1_DATAST_1 = 0x00000200
FSMC_BCR1_MWID_0 = 0x00000010
FSMC_BCR1_WREN = 0x00001000
FSMC_BCR1_MBKEN = 0x1
machine.mem32[stm.RCC + stm.RCC_AHB3ENR] |= RCC_AHB3ENR_FSMCEN
machine.mem32[stm.RCC + stm.RCC_AHB1ENR] |= RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOEEN
# MODER allows a programmer to define the functionality of a GPIO pin
# Each pin has2 bitsthat permits the following configurations:
# 00: Input
# 01: Output
# 10: Alternate Function
# 11: Analog
# MODER15(1:0)... MODER0(1:0)
machine.mem32[stm.GPIOD + stm.GPIO_MODER] = 0b10101000001010101000101000101010 #10 10 10 00 00 10 10 10 10 00 10 10 00 10 10 10
machine.mem32[stm.GPIOE + stm.GPIO_MODER] = 0xAAAA8000
# OTYPER allows a programmer to configure the output stage of anoutput GPIO pin
# Each pin has1 bits that permits the following configurations:
# 0: Push-pull
# 1: Open Drain
machine.mem32[stm.GPIOD + stm.GPIO_OSPEEDR] = 0xFFFFFFFF #0x54154525
machine.mem32[stm.GPIOE + stm.GPIO_OSPEEDR] = 0xFFFFFFFF #0x55554000
machine.mem32[stm.GPIOD + stm.GPIO_AFR0] = ( (0b1100<<(4*0)) | (0b1100<<(4*1)) | (0b1100<<(4*2)) | (0b1100<<(4*4)) | (0b1100<<(4*5)) | (0b1100<<(4*7)) )
machine.mem32[stm.GPIOD + stm.GPIO_AFR1] = ( (0b1100<<(4*(8-8))) | (0b1100<<(4*(9-8))) | (0b1100<<(4*(10-8))) | (0b1100<<(4*(13-8))) | (0b1100<<(4*(14-8))) | (0b1100<<(4*(15-8))))
machine.mem32[stm.GPIOE + stm.GPIO_AFR0] = 0b1100<<(4*7)
machine.mem32[stm.GPIOE + stm.GPIO_AFR1] = 0xCCCCCCCC
FSMC_BTR1_ADDHLD_0 = 0x00000010 #<Bit 0 */
FSMC_BTR1_CLKDIV_0 = 0x00100000 # <Bit 0 */
FSMC_BTR1_CLKDIV_1 = 0x00200000 #<Bit 1 */
FSMC_BCR1_FACCEN = 0x00000040 #<Flash access enable
machine.mem32[FSMC_Bank1_base + FSMC_BTR_bank1_offset] = FSMC_BTR1_ADDSET_T | FSMC_BTR1_DATAST_T | FSMC_BTR1_ADDHLD_0 # | FSMC_BTR1_CLKDIV_1 | FSMC_BTR1_ACCMOD
machine.mem32[FSMC_Bank1_base + FSMC_BCR_bank1_offset] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN
def TFT_Init():
#SOFTWARE RESET
machine.mem8[LCD_REG] = 0x01
time.sleep_ms(1000)
machine.mem8[LCD_REG] = 0x01
time.sleep_ms(1000)
#POWER CONTROL A
machine.mem8[LCD_REG] = 0xCB
machine.mem8[LCD_RAM] = 0x39
machine.mem8[LCD_RAM] = 0x2C
machine.mem8[LCD_RAM] = 0x00
machine.mem8[LCD_RAM] = 0x34
machine.mem8[LCD_RAM] = 0x02
#POWER CONTROL B
machine.mem8[LCD_REG] = 0xCF
machine.mem8[LCD_RAM] = 0x00
machine.mem8[LCD_RAM] = 0xC1
machine.mem8[LCD_RAM] = 0x30
#DRIVER TIMING CONTROL A
machine.mem8[LCD_REG] = 0xE8
machine.mem8[LCD_RAM] = 0x85
machine.mem8[LCD_RAM] = 0x00
machine.mem8[LCD_RAM] = 0x78
#DRIVER TIMING CONTROL B
machine.mem8[LCD_REG] = 0xEA
machine.mem8[LCD_RAM] = 0x00
machine.mem8[LCD_RAM] = 0x00
#POWER ON SEQUENCE CONTROL
machine.mem8[LCD_REG] = 0xED
machine.mem8[LCD_RAM] = 0x64
machine.mem8[LCD_RAM] = 0x03
machine.mem8[LCD_RAM] = 0x12
machine.mem8[LCD_RAM] = 0x81
#PUMP RATIO CONTROL
machine.mem8[LCD_REG] = 0xF7
machine.mem8[LCD_RAM] = 0x20
#POWER CONTROL,VRH[5:0]
machine.mem8[LCD_REG] = 0xC0
machine.mem8[LCD_RAM] = 0x23
#POWER CONTROL,SAP[2:0]BT[3:0]
machine.mem8[LCD_REG] = 0xC1
machine.mem8[LCD_RAM] = 0x10
#VCM CONTROL
machine.mem8[LCD_REG] = 0xC5
machine.mem8[LCD_RAM] = 0x3E
machine.mem8[LCD_RAM] = 0x28
#VCM CONTROL 2
machine.mem8[LCD_REG] = 0xC7
machine.mem8[LCD_RAM] = 0x86
#MEMORY ACCESS CONTROL
machine.mem8[LCD_REG] = 0x36
machine.mem8[LCD_RAM] = 0x48
#PIXEL FORMAT 16bit
machine.mem8[LCD_REG] = 0x3A
machine.mem8[LCD_RAM] = 0x55
#FRAME RATIO CONTROL, STANDARD RGB COLOR
machine.mem8[LCD_REG] = 0xB1
machine.mem8[LCD_RAM] = 0x00
machine.mem8[LCD_RAM] = 0x18
#DISPLAY FUNCTION CONTROL
machine.mem8[LCD_REG] = 0xB6
machine.mem8[LCD_RAM] = 0x08
machine.mem8[LCD_RAM] = 0x82
machine.mem8[LCD_RAM] = 0x27
#3GAMMA FUNCTION DISABLE
#machine.mem8[LCD_REG] = 0xF2
#machine.mem8[LCD_RAM] = 0x00
#GAMMA CURVE SELECTED
#machine.mem8[LCD_REG] = 0x26
#machine.mem8[LCD_RAM] = 0x01
#POSITIVE GAMMA CORRECTION
#machine.mem8[LCD_REG] = 0xE0
#machine.mem8[LCD_RAM] = 0x0F
#machine.mem8[LCD_RAM] = 0x31
#machine.mem8[LCD_RAM] = 0x2B
#machine.mem8[LCD_RAM] = 0x0C
#machine.mem8[LCD_RAM] = 0x0E
#machine.mem8[LCD_RAM] = 0x08
#machine.mem8[LCD_RAM] = 0x4E
#machine.mem8[LCD_RAM] = 0xF1
#machine.mem8[LCD_RAM] = 0x37
#machine.mem8[LCD_RAM] = 0x07
#machine.mem8[LCD_RAM] = 0x10
#machine.mem8[LCD_RAM] = 0x03
#machine.mem8[LCD_RAM] = 0x0E
#machine.mem8[LCD_RAM] = 0x09
#machine.mem8[LCD_RAM] = 0x00
#NEGATIVE GAMMA CORRECTION
#machine.mem8[LCD_REG] = 0xE1
#machine.mem8[LCD_RAM] = 0x00
#machine.mem8[LCD_RAM] = 0x0E
#machine.mem8[LCD_RAM] = 0x14
#machine.mem8[LCD_RAM] = 0x03
#machine.mem8[LCD_RAM] = 0x11
#machine.mem8[LCD_RAM] = 0x07
#machine.mem8[LCD_RAM] = 0x31
#machine.mem8[LCD_RAM] = 0xC1
#machine.mem8[LCD_RAM] = 0x48
#machine.mem8[LCD_RAM] = 0x08
#machine.mem8[LCD_RAM] = 0x0F
#machine.mem8[LCD_RAM] = 0x0C
#machine.mem8[LCD_RAM] = 0x31
#machine.mem8[LCD_RAM] = 0x36
#machine.mem8[LCD_RAM] = 0x0F
#EXIT SLEEP
machine.mem8[LCD_REG] = 0x11
time.sleep_ms(1200)
#TURN ON DISPLAY
machine.mem8[LCD_REG] = 0x29
#display inversion
#machine.mem8[LCD_REG] = 0x21
#setup Memory Access Control
machine.mem8[LCD_REG] = 0x36
machine.mem8[LCD_RAM] = 0b00111111
def ILI9341_Set_Address(X1, Y1, X2, Y2):
#set X min and max
machine.mem8[LCD_REG] = 0x2A
machine.mem16[LCD_RAM] = X1>>8
machine.mem16[LCD_RAM] = X1
machine.mem16[LCD_RAM] = X2>>8
machine.mem16[LCD_RAM] = X2
#set y min and max
machine.mem8[LCD_REG] = 0x2B
machine.mem16[LCD_RAM] = Y1>>8
machine.mem16[LCD_RAM] = Y1
machine.mem16[LCD_RAM] = Y2>>8
machine.mem16[LCD_RAM] = Y2
#write data command
machine.mem8[LCD_REG] = 0x2C
def drawPixel(X, Y, color):
ILI9341_Set_Address(X, Y, X, Y)
machine.mem16[LCD_RAM] = color
def fill(x = 0, y = 0, width = 320, height = 240, color = 0):
ILI9341_Set_Address(x, y, x + width, x + height)
for x in range(width):
for y in range(height):
machine.mem16[LCD_RAM] = color
def _set_ortho_line(width, length, color):
pixels = width * (length + 1)
for i in range(pixels):
machine.mem16[LCD_RAM] = color
curWidth = 240 # Current TFT width
curHeight = 320 # Current TFT height
def drawVline(x, y, length, color, width = 1):
if length > curHeight: length = curHeight
if width > 10: width = 10
ILI9341_Set_Address(x, y, x + (width - 1), y + length - 1)
_set_ortho_line(width, length, color)
def drawHline(x, y, length, color, width = 1):
if length > curWidth: length = curWidth
if width > 10: width = 10
ILI9341_Set_Address(x, y, x + length - 1, y + (width - 1))
_set_ortho_line(width, length, color)
def drawLine(x, y, x1, y1, color):
if x == x1:
drawVline( x, y if y <= y1 else y1, abs(y1 - y), color )
elif y==y1:
drawHline( x if x <= x1 else x1, y, abs(x-x1), color )
else:
# keep positive range for x
if x1 < x:
x, x1 = x1, x
y, y1 = y1, y
r = (y1 - y) / (x1 - x)
# select ratio > 1 for fast drawing (and thin line)
if abs(r) >= 1:
for i in range(x1 - x + 1):
drawPixel(x + i, trunc(y + (r * i)), color)
else:
# keep positive range for y
if y1 < y:
x, x1 = x1, x
y, y1 = y1, y
# invert the ratio (should be close of r = 1/r)
r = (x1 - x) / (y1 - y)
for i in range(y1 - y + 1):
drawPixel(trunc(x + (r * i)), y + i, color)
def drawRect(x, y, width, height, color, border = 1, infill = None):
if border is None:
border = 0
border = 10 if border > 10 else border
if width > curWidth:
width = curWidth
if height > curHeight:
height = curHeight
#height = 2 if height < 2 else height
#width = 2 if width < 2 else width
#self._graph_orientation()
if border > 0:
if border > width // 2:
border = width // 2 - 1
X, Y = x, y
for i in range(2):
if i == 1:
Y = y + height - (border - 1)
else:
Y = y
drawHline(X, Y, width, color, border)
print(X, Y, width)
if border > 1:
Y = y + 1
H = height
else:
Y = y
H = height + 1
if i == 1:
X = x + width - (border - 1)
else:
X = x
drawVline(X, Y, H, color, border)
print(X, Y, H)
else:
infill = color
if infill:
fill(x, y, width, height, infill)
def char(x, y, color):
cb, l = glcdfont.get_ch('0')
new = 0
# rotate pixel by 90 degree
buf = bytearray(8)
for j in range(8):
for i in range(l):
c = cb[i] # erste Reihe
c = c >> j
if (c & 0x01) == 0x01:
new |= 1 << i
#print (hex(new))
buf[j] = new
new = 0
# print pixel of char
ILI9341_Set_Address(x, y, x + 5, y + 8)
for i in range(8):
c = buf[i]
for j in range(l):
#print(j, (c & 0x01))
if (c & 0x01) == 0x01:
machine.mem16[LCD_RAM] = color
else:
machine.mem16[LCD_RAM] = 0
c = c >> 1
def show_bits(first, second, len = 8):
out =""
for i in range(len):
f = (first << i) & 0x80
#print(hex(f))
if f:
out = out + "1"
else:
out = out + "0"
for i in range(len):
f = (second << i) & 0x80
if f:
out = out + "1"
else:
out = out + "0"
print (out)
def big_char(x, y, char, fgcolor=0xffff, bgcolor=0):
k = 0
cb, l = glcdfont.get_ch(char)
pix = bytearray(24)
for i in range(6):
# first Byte
a = cb[i]
pix[k] = 0
if (a&0x10): pix[k]|=0x03
if (a&0x20): pix[k]|=0x0c
if (a&0x40): pix[k]|=0x30
if (a&0x80): pix[k]|=0xc0
k += 1
pix[k] = 0
if (a&0x01): pix[k]|=0x03 # die vier doppelten punkte setzen
if (a&0x02): pix[k]|=0x0c
if (a&0x04): pix[k]|=0x30
if (a&0x08): pix[k]|=0xc0
k += 1
pix[k] = 0
if (a&0x10): pix[k]|=0x03
if (a&0x20): pix[k]|=0x0c
if (a&0x40): pix[k]|=0x30
if (a&0x80): pix[k]|=0xc0
k += 1
pix[k] = 0
if (a&0x01): pix[k]|=0x03 # die vier doppelten punkte setzen
if (a&0x02): pix[k]|=0x0c
if (a&0x04): pix[k]|=0x30
if (a&0x08): pix[k]|=0xc0
k += 1
new = 0
# rotate pixel by 90 degree
buf = bytearray(32)
for j in range(8):
for i in range(8):
c = pix[(i * 2) + 1] # (High) Low
c = c >> j
if (c & 0x01) == 0x01:
new |= 0x80 >> i
buf[(j * 2)] = new
new = 0
for i in range(4):
c = pix[(i * 2) + 17] # zweite Reihe
c = c >> j
if (c & 0x01) == 0x01:
new |= 0x80 >> i
buf[(j * 2)+1] = new
#show_bits(buf[j*2], buf[(j*2)+1])
new = 0
for j in range(8):
for i in range(8):
c = pix[i * 2] # erste Reihe
c = c >> j
if (c & 0x01) == 0x01:
new |= 0x80 >> i
buf[(j * 2) + 16] = new
new = 0
for i in range(4):
c = pix[(i * 2) + 16] # zweite Reihe
c = c >> j
if (c & 0x01) == 0x01:
new |= 0x80 >> i
buf[(j * 2) + 17] = new
new = 0
#show_bits(buf[(j*2) + 16], buf[(j*2)+17])
# print pixel of char
ILI9341_Set_Address(x, y, x + 11, y + 15)
for i in range(16):
#show_bits(buf[i*2], buf[(i*2)+1])
c = buf[i * 2]
for j in range(8):
if (c & 0x80) == 0x80:
machine.mem16[LCD_RAM] = fgcolor
else:
machine.mem16[LCD_RAM] = bgcolor
c = c << 1
c = buf[(i * 2) + 1]
for j in range(4):
if (c & 0x80) == 0x80:
machine.mem16[LCD_RAM] = fgcolor
else:
machine.mem16[LCD_RAM] = bgcolor
c = c << 1
def string_big(x, y, string, fgcolor=0xffff, bgcolor=0):
for i in range(len(string)):
big_char(x + (i*11), y, string[i], fgcolor, bgcolor)
LCD_REG = const(0x60000002)
LCD_RAM = const(0x60080002)