[SOLVED] FSMC LCD on STM32F407VET

flyboy74
Fri Jul 06, 2018 6:52 am
After playing the the blue pill STM32F103 I decided to take the next step and progress to the STM32F4xx and I found the Black STM32F407VET board really cheap on Aliexpress so am now playing with it. Have just done some basic blink an LED stuff by writing to the registers to setup the clock and pins then toggle the pin.

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


Pito
Fri Jul 06, 2018 9:48 am
Put “fsmc” into the “Search” – top right on this page..

flyboy74
Fri Jul 06, 2018 2:40 pm
Ok that’s somewhere to start but it mainly leaves me more confused hahaha.

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??


stevestrong
Fri Jul 06, 2018 3:03 pm
viewtopic.php?f=39&t=2298

flyboy74
Sat Jul 07, 2018 9:59 am
Ok I think that I have got FSMC working on my board and my scope is showing all the correct outputs on all the pins. At the moment I am using the slowest timing and it is giving 615KHz. Will experiment later to see how fast iT can go.

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.


flyboy74
Mon Jul 09, 2018 6:44 am
I haven’t been able to write anything to a screen.

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.
}
}


stevestrong
Mon Jul 09, 2018 9:49 am
[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


flyboy74
Tue Jul 10, 2018 4:12 am
@stevestrong

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


flyboy74
Tue Jul 10, 2018 7:11 am
Ok so I have now got the screen to work using bit bang so this means the pin out that I am using is correct and the screen does work and I am using the correct commands to drive it. So it is defiantly a problem with how I am using FSMC

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??


stevestrong
Tue Jul 10, 2018 7:36 am
[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.


flyboy74
Tue Jul 10, 2018 8:34 am
You also have the line of code
fsmc_nor_psram_bank_enable(FSMC_NOR_PSRAM1_BASE);

stevestrong
Tue Jul 10, 2018 8:42 am
Is it really so hard to perform a search in source files?

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;
}


flyboy74
Tue Jul 10, 2018 9:40 am
Ok that everyone for their patience I have it working now not sure why it now works but it does :)

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;


Leave a Reply

Your email address will not be published. Required fields are marked *