I am trying to interface with an SPI ILI9341 screen using an STM32 microcontroller. I know there are a whole lot of things that can go wrong with these interfaces, and I've spent an awful lot of time searching and solving problems. But I'm kind of at a loss as to why my display seems to succeed in its initialization, but refuses to display any colors.
What I'm seeing is that the screens 'turn on' to a flickering grey color, after which they ignore the 'set address window / send data' commands which should draw colors to the screen.
Here are the commands that I'm sending – the 'spi_write_[command|data]' methods just set D/C low or high respectively and then send a byte over the peripheral, and the commands/data are from several other libraries, mostly Adafruit's. I've reviewed them several times and tried tweaking a few commands, including the SPI timing, but nothing seems to help.
ILI9341 Initialization commands:
LDR r1, =0x000000EF
BL spi_write_command
LDR r1, =0x00000003
BL spi_write_data
LDR r1, =0x00000080
BL spi_write_data
LDR r1, =0x00000002
BL spi_write_data
LDR r1, =0x000000CF
BL spi_write_command
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x000000C1
BL spi_write_data
LDR r1, =0x00000030
BL spi_write_data
LDR r1, =0x000000ED
BL spi_write_command
LDR r1, =0x00000064
BL spi_write_data
LDR r1, =0x00000003
BL spi_write_data
LDR r1, =0x00000012
BL spi_write_data
LDR r1, =0x00000081
BL spi_write_data
LDR r1, =0x000000E8
BL spi_write_command
LDR r1, =0x00000085
BL spi_write_data
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x00000078
BL spi_write_data
LDR r1, =0x000000CB
BL spi_write_command
LDR r1, =0x00000039
BL spi_write_data
LDR r1, =0x0000002C
BL spi_write_data
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x00000034
BL spi_write_data
LDR r1, =0x00000002
BL spi_write_data
LDR r1, =0x000000F7
BL spi_write_command
LDR r1, =0x00000020
BL spi_write_data
LDR r1, =0x000000EA
BL spi_write_command
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x000000C0 // (Power control 1)
BL spi_write_command
LDR r1, =0x00000023
BL spi_write_data
LDR r1, =0x000000C1 // (Power control 2)
BL spi_write_command
LDR r1, =0x00000010
BL spi_write_data
LDR r1, =0x000000C5 // (VCOM control 1)
BL spi_write_command
LDR r1, =0x0000002B
BL spi_write_data
LDR r1, =0x0000002B
BL spi_write_data
LDR r1, =0x000000C7 // (VCOM offset)
BL spi_write_command
LDR r1, =0x000000C0
BL spi_write_data
LDR r1, =0x00000036 // (Memory access type)
BL spi_write_command
LDR r1, =0x00000048
BL spi_write_data
LDR r1, =0x0000003A // (Pixel format)
BL spi_write_command
LDR r1, =0x00000055
BL spi_write_data
LDR r1, =0x000000B1 // (Framerate control)
BL spi_write_command
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x0000001B
BL spi_write_data
LDR r1, =0x000000B6 // (Display function)
BL spi_write_command
LDR r1, =0x00000008
BL spi_write_data
LDR r1, =0x00000082
BL spi_write_data
LDR r1, =0x00000027
BL spi_write_data
LDR r1, =0x000000F2 // (Gamma select)
BL spi_write_command
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x00000026 // (Gamma set)
BL spi_write_command
LDR r1, =0x00000001
BL spi_write_data
LDR r1, =0x000000E0 // (Gamma curve)
BL spi_write_command
LDR r1, =0x0000000F
BL spi_write_data
LDR r1, =0x00000031
BL spi_write_data
LDR r1, =0x0000002B
BL spi_write_data
LDR r1, =0x0000000C
BL spi_write_data
LDR r1, =0x0000000E
BL spi_write_data
LDR r1, =0x00000008
BL spi_write_data
LDR r1, =0x0000004E
BL spi_write_data
LDR r1, =0x000000F1
BL spi_write_data
LDR r1, =0x00000037
BL spi_write_data
LDR r1, =0x00000007
BL spi_write_data
LDR r1, =0x00000010
BL spi_write_data
LDR r1, =0x00000003
BL spi_write_data
LDR r1, =0x0000000E
BL spi_write_data
LDR r1, =0x00000009
BL spi_write_data
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x000000E1 // (Gamma curve)
BL spi_write_command
LDR r1, =0x00000000
BL spi_write_data
LDR r1, =0x0000000E
BL spi_write_data
LDR r1, =0x00000014
BL spi_write_data
LDR r1, =0x00000003
BL spi_write_data
LDR r1, =0x00000011
BL spi_write_data
LDR r1, =0x00000007
BL spi_write_data
LDR r1, =0x00000031
BL spi_write_data
LDR r1, =0x000000C1
BL spi_write_data
LDR r1, =0x00000048
BL spi_write_data
LDR r1, =0x00000008
BL spi_write_data
LDR r1, =0x0000000F
BL spi_write_data
LDR r1, =0x0000000C
BL spi_write_data
LDR r1, =0x00000031
BL spi_write_data
LDR r1, =0x00000036
BL spi_write_data
LDR r1, =0x0000000F
BL spi_write_data
LDR r1, =0x00000020 // No display inversion.
BL spi_write_command
// (Delay >=120ms)
MOVS r3, #120
BL delay_ms
LDR r1, =0x00000011 // Exit sleep mode
BL spi_write_command
// (Delay >=120ms)
MOVS r3, #120
BL delay_ms
LDR r1, =0x00000029 // Display on
BL spi_write_command
Fill screen with color – this simply sets the 'address window' to the whole screen, and then writes a single color 240*320 times:
// Set address window; r4-r7 hold x/y values, for whole screen:
// X = [0:239], Y = [0:319]
// Set the 'display addressing' window to the whole screen.
MOVS r4, #0
MOVS r5, #239
MOVS r6, #0
LDR r7, =0x0000013F // (319)
LDR r2, =0x000000FF
// Column-set
LDR r1, =0x0000002A
BL spi_write_command
// Min-X
MOVS r1, r4
LSRS r1, r1, #8
BL spi_write_data
MOVS r1, r4
ANDS r1, r1, r2
BL spi_write_data
// Max-X
MOVS r1, r5
LSRS r1, r1, #8
BL spi_write_data
MOVS r1, r5
ANDS r1, r1, r2
BL spi_write_data
// Row-set
LDR r1, =0x0000002B
BL spi_write_command
// Min-Y
MOVS r1, r6
LSRS r1, r1, #8
BL spi_write_data
MOVS r1, r6
ANDS r1, r1, r2
BL spi_write_data
// Max-Y
MOVS r1, r7
LSRS r1, r1, #8
BL spi_write_data
MOVS r1, r7
ANDS r1, r1, r2
BL spi_write_data
// RAM-Write command.
LDR r1, =0x0000002C
BL spi_write_command
// Write the given color (16-bit) 240*320 times, 1 for each pixel.
LDR r7, =0x00000140
MOVS r4, #240
MULS r4, r4, r7
MOVS r5, r3
LDR r6, =0x000000FF
ANDS r5, r5, r6
MOVS r6, r3
LSRS r6, r6, #8
ili9341_fill_screen_write_px:
MOVS r1, r6
BL spi_write_data
MOVS r1, r5
BL spi_write_data
SUBS r4, r4, #1
BNE ili9341_fill_screen_write_px
Thanks for any help! I've verified that each pin's signals are making it to the displays with an oscilloscope – even the Data/Command and CS pins – so I'm really out of ideas as to what could be going wrong.
Best Answer
Okay, it didn't take me long to abandon the idea of using assembly language to introduce people to microcontrollers, and I did eventually figure this out.
The flickering gray screen that I observed looks like it is a normal 'startup' state for the display when a hardware reset has been performed by pulling the reset pin low, then high.
But the STM32's SPI peripheral sends the full contents of its 16-bit 'Data Register' unless you use some specific conventions. It's easiest to cast the register to a pointer to an 8-bit integer.
SPI settings (using ST's device header files):
'Write byte' function:
With those settings, it seems to work.