This tutorial shows you how to display string, color and dynamic value on LCD with STM32-Nucleo development board from ground up. It will also show you how to read the technical datasheet of LCD. If you are interested in more advance topic of RTOS from scratch, please go to Real-Time Operating Systems tutorial.
- What is the Goal and what you need to have
- Basic Knowledge
- Configure Pins and Code
- 3.1 Configure Pins on CubeMX
- 3.2 Start Coding
- Connect Hardware and Download the Code to the Nucleo-64
- Let's talk about the code
- 5.1 Initialization
- 5.2 Sending data (color)
- Reference
- The End
Let's first take a look what are we going to achieve after this tutorial.
1.1 Hardware
- STM32F411RE Nucleo 64
- ST7735s 1.8" TFT LCD 128 X 160 (SKU:MAR1801)
- Jumper wires (Male-Male, Male-Female, Female-Female)
- Potentiometer (optional, only affect the dynamic value displaying)
- USB Cable-A to Mini-B
- Breadboard
1.2 Documents
You are ready to go!!
A series of Youtube tutorial on STM32-Nucleo is a good start if you never use this link
You can think of it as a tiny and simplify PC without monitor(output), keyboard(input), and mouse(input). The LCD acts as output and the Potentiometer acts as input in our tutorial. There is a big problem, how can this tiny PC communicate with the outside world (such as monitor or keyboard)? Some use wired or wireless.
Wired/Wireless | Example |
---|---|
Wired | SPI, I2C, UART, Ethernet |
Wireless | Wi-Fi, Bluetooth, Cellular |
In this tutorial, we will use SPI (Serial Peripheral Interface) to communicate with the output device ~ LCD. We call our Nucleo board as master and the LCD as slave because we are sending order and command to the LCD. Sparkfun has a great tutorial website about SPI (link). The image in the following shows the relationship and connection between master and slave.(image from Sparkfun with some modification to fit our case)
Terminology | Function |
---|---|
MOSI | Master out Slave in. Master sends command or data to Slave. |
MISO | Master in Slave out. Slave sends command or data to Master. We don't use this in our case. We don't need to get data from the LCD. (If you use touchscreen, you would need this function) |
SS (CS) | Slave select (or Chip select). If you have multiple slaves connectes to one master, you can use SS to communicate with the specified slave. Eventhough we only have one slave (LCD), we still need to use this Slave select to let the LCD knows we want to talk to him now. |
SCK (CLK) | Clock. Because SPI is synchronous, it requires clock for sampling. |
We want to display some string or color on the specific location of the LCD. We can achieve this by sending data to the specific address of RAM (Memory) in the LCD board. This is call Memory to Display Address Mapping. Take the image below for example. We want to make the top left corner of the LCD display a yellow square. First, you need to let the LCD knows at where of the RAM are you going to write the data to (using X_start, X_end, Y_start, Y_end value). Then you can start writing the data (color information) to those address of the RAM. Then, the specified portion of LCD will change it's color according to the value you wirte into the address in the RAM. (Please refer to the ST7735s datasheet page 59 ~ 72)
Let's take a look the back side of the LCD board in the following image. You only need to focus on the left side.
The following table shows each pinout of the LCD board and its function.
Pinout on LCD | Function |
---|---|
VCC | Power 3.3V ~ 5V |
GND | Connect to ground |
NC | No need to connect |
CLK | Clock. Also call SCK |
SDA | MOSI for receiving data from the master |
RS | Data/Command selection. (some LCD board calls it DC or D/C). When applying high voltage meaning sending data while applying low voltage meaning sending command. |
RST | Reset (reset at low level) |
CS | Chip selection (some LCD calls it SS) |
We will talk about how to connect these two devices by wires later. Let's see the protocol when communicating to the LCD board. First look at the graphic explanation below.
Connection Pin | Explanation |
---|---|
CS | Only at the falling edge on CS (voltage become low) enables the SPI and indicates the start of data or command transmission. When the CS is high (voltage is high), the clock is ignored. |
Data or Command | Data: You use the high voltage from the GPIO pin to tell the LCD board that you are transmitting the data. Command: You use the low voltage from the GPIO pin to tell the LCD board that you are transmitting the command. (Please refer to the ST7735s datasheet page 36 ~ 51) |
MOSI | While sending a command, it's not necessary to send data. How many data right after the command is defined by the command. (Please refer to the ST7735s datasheet page 104 ~ 186) In our code, our SPI transmit 8-bit data at a time, however, the color in our case is defined in 16-bit, so you need to transfer the first 8 bit of the color and then the rest 8 bit. (Please refer to the ST7735s datasheet page 44 ~ 58) |
Clock | MOSI data is sampled at the rising edge of clock |
In the following, we will first use CubeMX (link) to configure SPI and ADC (optional) on the STM32-Nucleo board and then generate code for keil µVision IDE v5 (link). Secondly, copy paste the code from the program we provided. Finally, we will test the code on the hardware.
Click File --> New Project --> In the search, key in your board model (STM32f411RE in our case) --> Click on the NUCLEO-F411RE --> Double click the item --> Click Yes to initialize all peripherals with their default Mode. --> Clear all Pinout.
Categories | Configure |
---|---|
SPI | On the left panel, click Connectivity --> SPI1 --> Select Mode : Transmit Only Master --> Prescaler(for Baud Rate): 32. On the Pinout view, we will change the pin. Click on PB5 --> Select SPI1_MOSI. Click on PB3 --> Select SPI1_SCK. |
ADC (Optional) | On the left panel, click Analog --> ADC1 --> Select Mode: IN4. |
GPIO | The following will set the pins in Pinout view to GPIO_Output CS: Click PB15 --> Select GPIO_Output --> Right click to enter user label: LCD_CS RS: Click PB14 --> Select GPIO_Output --> Right click to enter user label: LCD_RS RST: Click PB12 --> Select GPIO_Output --> Right click to enter user label: LCD_RST |
The configuration process and the result view will be the following. On the top of the panel, click on Project Manager.
- Enter Project Name.
- Create a folder and set the Project Location to this folder.
For the Toolchain/IDE, select MDK-ARM --> Min Version select V5. - In the Code Generator (left panel), click Generate peripheral initialization as a pair of c/h files per peripheral.
- On the top of the panel, click on GENERATE CODE.
- Click Open Project
Now the keil uvision IDE would open up itself with you project in it.
You may wonder what pin of SPI should I use (you see we change the pin from the default PA5~7). Actually, ARM Cortex-M4 defined the combination of pins with SPI, I2C, UART. You can check the table from the STM32F411RE User Manual page 47 ~ 52. In the table, you can see we are using the combination of PB3/PB5, that combination also legit.
Before we get started, we need to configure the package. Make sure all the package are installed and up to date shown in the following image
Then, we will configure the dubgger. Nucleo-64 board uses ST-LINK (the upper part of the board which you connect the mini usb to).
Click Flash tab --> Configure flash tools
- C/C++ tab: check C99 Mode
- C/C++ tab: Include Paths --> New (Insert) --> click the MDK-ARM folder --> OK
- Debug tab: On the upper right side --> Use: --> Select ST-Link Debugger --> Settings --> Flash Download tab --> Check Reset and Run
let's check whether the generated code are correct by clicking Project tab --> Rebuild all target files. It should be 0 Error and 0 Warning. In the Project, you should see all the file in the following image.
Now we are going to add the code so that we can communicate with the ST7735 LCD. Right click the Application/User
- Add new item.... --> Select C File (.c) --> Name: st7735 --> Copy paste the code (st7735.c) we provided in ST7735 folder.
- Add new item.... --> Select Header File (.h) --> Name: st7735 --> Copy paste the code (st7735.h) we provided in ST7735 folder.
- Add new item.... --> Select C File (.c) --> Name: fonts --> Copy paste the code (fonts.c) we provided in ST7735 folder.
- Add new item.... --> Select Header File (.h) --> Name: fonts --> Copy paste the code (fonts.h) we provided in ST7735 folder.
Now we add something in the main.c file so that we can use st7735.c and st7735.h for our project.
- Open main.c in Application/User folder --> add the following code highlight with red square. These code will be enough for testing.
Please refer to the following image to connect those devices.
After you connect these devices, connect USB with the PC and Nucleo-64 board. Your PC should be able to detect the Nucleo board and the LED light near the Mini usb port should be steady red ligh. The LCD should be power on with white screen.
- Click Project tab --> Rebuild all target files. It should be 0 Error and some Warning (it's fine).
- Click Flash tab --> Download.
- Do you see the LCD light become black and a string shows up. Cool !!!
If everything is working good, we can keep going on.
- Add the following 3 functions in main.c after the main function
void plotData(void)
{
ST7735_PlotPoint(sensorValue,ST7735_GREEN);
ST7735_PlotIncrement();
}
void drawInfoBar(void)
{
ST7735_DrawString(1, 0, "CPU =", ST7735_GREEN);
ST7735_DrawString(7, 0, "75%", ST7735_BLUE );
ST7735_DrawString(11, 0, "Temp =", ST7735_GREEN);
ST7735_DrawString(18, 0, "30", ST7735_BLUE );
}
void drawaxes(void){
ST7735_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "ADC", LIGHTCOLOR, "", 0, YMAX, YMIN);
}
Add the three header on the top of the main.c file
void drawInfoBar(void);
void drawaxes(void);
void plotData(void);
- In the main function will be like the following. We read the value from the ADC (Analog to Digital Conversion) and this value would change if you tune the potentiometer. The plotData function will take this value and plot it on the LCD.
int main(void)
{
HAL_Init();
//SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_SPI1_Init();
ST7735_Init();
ST7735_FillScreen(ST7735_BLACK);
drawaxes();
drawInfoBar();
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,1);
sensorValue = HAL_ADC_GetValue(&hadc1);
plotData();
}
}
- Rebuild the code and download to the board. Try to tune the Potentiometer, and then you will see the green line moving up and down.
Before starting to display anything on the LCD, we need to initialize and configure the LCD by sending some command and parameters (data) to the LCD board. This initialization only need to be processed once. After that, we can send data to the LCD with correct protocol.
-
- Chip Select (CS): Make CS pin low.
-
- Reset (RST): Reset pin low --> delay 5~9 ms --> Reset pin high (Please refer to the ST7735s datasheet page 85)
-
- Send command and parameter(data): Command such as Frame rate, inversion, color bit, memory reading order, ....(Please refer to the ST7735s datasheet page 104 ~ 186).
-
- Chip un-select (CS): Make CS pin high.
Let's make the uper left corner of the LCD become green. In the following sending command as well as sending data, we all communicate via SPI. Remember that before sending data, we need to set the RS (Data or command) pin high. We set the RS pin low before sending command.
-
- Chip Select (CS): Make CS pin low.
-
- Memory to Display Address Mapping:
- Send command to perform Column address set
- Send data: X_start (first 8 bit start from the most significant bit)
- Send data: X_start (rest of the bit)
- Send data: X_end (first 8 bit start from the most significant bit)
- Send data: X_end (rest of the bit)
- Send command to perform Row address set
- Send data: Y_start (first 8 bit start from the most significant bit)
- Send data: Y_start (rest of the bit)
- Send data: Y_end (first 8 bit start from the most significant bit)
- Send data: Y_end (rest of the bit)
- Send command to perform writting to RAM
-
- Send the color data (16-bit data for each color)
- Send data: color (first 8 bit start from the most significant bit)
- Send data: color (rest of the bit)
-
- Chip un-select (CS): Make CS pin high.
- Udemy course: Build Your Own RealTime OS (RTOS) From Ground Up on ARM 1. Instructor: Israel Gbati
- Github code: https://github.com/afiskon/stm32-st7735
The reason of making this tutorial is that the code provided from instructor of the Udemy course is not working at all and the instructor didn't reply to any student at all. I start from knowing nothing about SPI no need to say the LCD board. After 5 days of research, reading documentation, and trial and error, I finally make it works. This tutorial is to guide those people who want to get a deep knowledge of making a driver to display on LCD.