The main reason that I got the STM32F407VET was to learn how to write to a LCD screen in parallel. I have a 320×240 screen that has 8 bit parallel pins broken out along with RST, CS, RS, WR, RD so I assume a standard 8 bit 8080 interface.
I am a noob but am always a fast learner at this sort of stuff. Can anyone point me to any links on blogs or tutorials of setting up and using FSMC to write to a LCD on a STM32F4xx
First I can’t seem to find any docs that tells me what pins are capable of FSMC, The board that I have is using pins on port D and E but where’s the docs from ST that tells you this?? Can I wire my LCD to any pins and set them in mode AF12??
I am not sure where to report this but there is a slight typo on the docs here http://wiki.stm32duino.com/images/a/a8/ … AG-TFT.pdf
Where it shows the pin out of the LCD header 1 of the pins is listed as PD2 when in fact it is PD0.
My next step is to make it work with the screen. I think the screen I have uses a ST7781 driver chip. If I am reading the data sheet properly it seems it doesn’t use the the memory address part of the FSMC transmission and only uses the data part of the FSMC transmission. This leads me to wonder if faster LCD updates can be achieved by bit bang as you could cut out the address part and just send the data, you could use 1 whole port (16 pins) and just write the data the ODR of the port then pulse the WR pin low then high to send data as the screen just seems to read the data on the rising edge of the WR line as long as the pulse is more than 50ns.
When I try hooking my scope to different pins and sending different data my scope shows the the pins doing what I would expect but when I wire it to a screen tried both ST7781 in 8 bit and now a HX8357 in 16 bit. but nothing shows on my screen.
I have used and programmed a few different types of SPI screens(ili9341, st7735) using Python very successfully and these parallel screens have many of the same registers just use parallel instead of SPI.
Can someone correct me if I am in wrong in understanding it works like this. You pull RS pin low then send the command via FSMC then you let RS high then send the data via FSMC. Fist you need to send all the commands to setup the screen then you send RAMWR command then sedn off the pixel data and it should appear on the screen.
I switched to eclipse to write the code and compile then flash with st-link.
#include "stm32f4xx.h"
//used for coutn down in Delay
__IO uint32_t TimmingDelay;
void SysTick_Handler(void)
{
if(TimmingDelay !=0)
{
TimmingDelay --;
}
}
void Delay(__IO uint32_t time)
{
TimmingDelay = time;
while(TimmingDelay !=0);
}
//pointer used to write to start address of FSMC
volatile uint16_t* fsmc = (uint16_t*)0x60000000;
void FSMC_setup(void){
//enable RCC for FSMC and both GPIO ports
RCC->AHB3ENR |= RCC_AHB3ENR_FSMCEN;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOEEN;
//setup RS (PD13) and RST (PD12) pin as output
GPIOD->MODER |= GPIO_MODER_MODER13_0 | GPIO_MODER_MODER12_0;
//setup other pins as AF
GPIOD->MODER |= GPIO_MODER_MODER0_1 | GPIO_MODER_MODER1_1 | GPIO_MODER_MODER4_1 | GPIO_MODER_MODER5_1 | GPIO_MODER_MODER7_1 | GPIO_MODER_MODER8_1 | GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1 | GPIO_MODER_MODER14_1 | GPIO_MODER_MODER15_1;
GPIOE->MODER |= GPIO_MODER_MODER7_1 | GPIO_MODER_MODER8_1 | GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1 | GPIO_MODER_MODER11_1 | GPIO_MODER_MODER12_1 | GPIO_MODER_MODER13_1 | GPIO_MODER_MODER14_1 | GPIO_MODER_MODER15_1;
//setup pins as PP
GPIOD->OTYPER = 0x00000000;
GPIOE->OTYPER = 0x00000000;
//set speed to 100MHz
GPIOD->OSPEEDR = 0xFFFFFFFF;
GPIOE->OSPEEDR = 0xFFFFFFFF;
//set NO pull-up or pull-down
GPIOD->PUPDR = 0x00000000;
GPIOE->PUPDR = 0x00000000;
//set other pins to AF12 i.e as FSMC pins
GPIOD->AFR[0] |= (GPIO_AF12_FSMC << (0 * 4)) | (GPIO_AF12_FSMC << (1 * 4)) | (GPIO_AF12_FSMC << (4 * 4)) | (GPIO_AF12_FSMC << (5 * 4)) | (GPIO_AF12_FSMC << (7 * 4));
GPIOD->AFR[1] |= (GPIO_AF12_FSMC << ((8 - 8) * 4)) | (GPIO_AF12_FSMC << ((9 - 8) * 4)) | (GPIO_AF12_FSMC << ((10 - 8) * 4)) | (GPIO_AF12_FSMC << ((14 - 8) * 4)) | (GPIO_AF12_FSMC << ((15 - 8) * 4));
GPIOE->AFR[0] |= (GPIO_AF12_FSMC << (7 * 4));
GPIOE->AFR[1] |= (GPIO_AF12_FSMC << ((8 - 8) * 4)) | (GPIO_AF12_FSMC << ((9 - 8) * 4)) | (GPIO_AF12_FSMC << ((10 - 8) * 4)) | (GPIO_AF12_FSMC << ((11 - 8) * 4)) | (GPIO_AF12_FSMC << ((12 - 8) * 4)) | (GPIO_AF12_FSMC << ((13 - 8) * 4)) | (GPIO_AF12_FSMC << ((14 - 8) * 4)) | (GPIO_AF12_FSMC << ((15 - 8) * 4));
//setup FSMC on Bank1 NORSRAM1
//disable ASYNCWAIT:
FSMC_Bank1->BTCR[0] &= ~FSMC_BCR1_ASYNCWAIT;
//disable Extended mode
FSMC_Bank1->BTCR[0] &= ~FSMC_BCR1_EXTMOD;
//disable the wait for NWAIT signal
FSMC_Bank1->BTCR[0] &= ~FSMC_BCR1_WAITEN;
//write enable
FSMC_Bank1->BTCR[0] |= FSMC_BCR1_WREN;
//disable wrap mode
FSMC_Bank1->BTCR[0] &= ~FSMC_BCR1_WRAPMOD;
//disable Burst mode
FSMC_Bank1->BTCR[0] &= ~FSMC_BCR1_BURSTEN;
//enable Flash access
FSMC_Bank1->BTCR[0] |= FSMC_BCR1_FACCEN;
//set data bus width to 16 bit
FSMC_Bank1->BTCR[0] |= FSMC_BCR1_MWID_0;
//set to SRAM type
FSMC_Bank1->BTCR[0] &= ~FSMC_BCR1_MTYP;
//disable Address/data multiplexing
FSMC_Bank1->BTCR[0] &= ~FSMC_BCR1_MUXEN;
//enable Memory bank
FSMC_Bank1->BTCR[0] |= FSMC_BCR1_MBKEN;
//setup timings
//set access mode A
FSMC_Bank1->BTCR[1] &= ~FSMC_BTR1_ACCMOD;
//set short bus turn around
FSMC_Bank1->BTCR[1] &= ~(FSMC_BTR1_BUSTURN_0 | FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_2 |FSMC_BTR1_BUSTURN_3);
}
void TFT_write_cmd(uint16_t command){
//set RS pin low
GPIOD->ODR &= ~GPIO_ODR_ODR_13;
Delay(10);
*fsmc = command;
//set RS pin high
GPIOD->ODR |= GPIO_ODR_ODR_13;
Delay(10);
}
//sets up a HX8357B TFT
void TFT_setup(void){
//hardware reset
GPIOD->ODR &= ~GPIO_ODR_ODR_12;
Delay(200);
GPIOD->ODR |= GPIO_ODR_ODR_12;
Delay(120);
//software reset
TFT_write_cmd(0x01);
Delay(120);
//sleep out
TFT_write_cmd(0x11);
Delay(120);
//Normal Display Mode On)
TFT_write_cmd(0x13);
//Display On
TFT_write_cmd(0x29);
//CASET (Column Address Set)
TFT_write_cmd(0x2A);
*fsmc = 0000;
*fsmc = 320;
//PASET (Page Address Set)
TFT_write_cmd(0x2B);
*fsmc = 0000;
*fsmc = 320;
//Exit_idle_mode
TFT_write_cmd(0x38);
//Set_pixel_format RGR565 16 bit
TFT_write_cmd(0x3A);
*fsmc = 0b01010101;
//RAMWR (Memory Write)
TFT_write_cmd(0x2C);
}
void main(void){
// At this stage the system clock should have already been configured
// at high speed.
//set systick for 1 MS used in Delay interrupt
SysTick_Config(SystemCoreClock/1000);
FSMC_setup();
TFT_setup();
for (uint32_t i = 0; i < 102400; ++i ){
*fsmc = 0xff00;
fsmc += 2;
}
// Infinite loop
while (1){
// Add your code here.
}
}
[flyboy74 – Mon Jul 09, 2018 6:44 am] –
Can someone correct me if I am in wrong in understanding it works like this. You pull RS pin low then send the command via FSMC then you let RS high then send the data via FSMC. Fist you need to send all the commands to setup the screen then you send RAMWR command then sedn off the pixel data and it should appear on the screen.
That is right.
In order to check your wiring you can use this sketch: https://github.com/prenticedavid/MCUFRI … eadreg.ino. Just adapt the pins.
Alternatively, you may have a look on my implementation here: https://github.com/stevstrong/Adafruit_ … it_STM32.h, in conjunction with FSMC base file: https://github.com/stevstrong/Arduino_S … ple/fsmc.c
Thanks for your reply.
The goal is to be able to use the screen with FSMC and DMA but since I am unable to get anything yet to show on the screen I am going to use bit bang and get that to work then go back to FSMC.
I wrote a simple bit bang but got the same out come: screen just stayed white like it wasn’t starting up. The back light of course always comes on with power up. When playing with SPI screen even if the data isn’t writing to the GRAM, when the screen starts up you don’t get white you get random coloured pixels. The SPI screens only give blank white screen if the it hasn’t started up.
This thread is about FSCM so I have started another thread on general discussion to ask about using the screen with bit bang. @stevestrong can you look at the simple code I posted on that thread and see if you notice anything of why it isn’t working viewtopic.php?f=3&t=3841
So 1 thing that seems to have me confused looking at your code is that you setup the RS pin(FSMC_A18) as a AF pin same as the rest of the pins. I setup it as a normal output pin and drive it manually.
How does someone using your code issue a command and how to write data???
Is the FSMC peripheral smart enough to be able to drive the LCD RS pin??
[flyboy74 – Tue Jul 10, 2018 7:11 am] –
How does someone using your code issue a command and how to write data???
Have a look at the header file I posted above.
[flyboy74 – Tue Jul 10, 2018 7:11 am] –
Is the FSMC peripheral smart enough to be able to drive the LCD RS pin??
Yes.
fsmc_nor_psram_bank_enable(FSMC_NOR_PSRAM1_BASE);See https://github.com/stevstrong/Arduino_S … #L303-L305
static inline void fsmc_nor_psram_bank_enable(fsmc_nor_psram_reg_map *regs) {
regs->BCR |= FSMC_BCR_MBKEN;
}
I followed the above link to another thread then followed that link to a stack overflow and got this FSMC setup
int FSMC_Bank = 0;
FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_1 | FSMC_BTR1_DATAST_1;
// Bank1 NOR/SRAM control register configuration
FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN;


