For my project I need a display for showing alphabets and related images. A bigger display is better and I choose a 2.8inch TFT Touch Shield from Waveshare Electronics. As the PSoC 62S4 Pioneer Kit has Arduino compatible headers this display can be easily connected to PSoC 62S4 board without any soldering and jumper wires. The display support SPI protocol and has a build-in SD Card slot which is required for my project.
After collecting the display I started searching for library and projects using the display. I found a zip file of the source code from official webpage of the display and downloaded the zip file. After unzipping the file I discover the library and some example code for Arduino and STM32 platform. So, again I started to search some example code or project for PSoC 6 MCU or ModusToolbox that use this 2.8inch TFT LCD but I was out of luck. So, I was mentally preparing to develop my own library for PSoC 6 MCU using HAL API. But before doing so, I wanted to be sure that this display works with the Arduino perfectly with the provided library. As I am experience in the Arduino environment it also helps me to understanding the library. Understanding the library is important for modifying it for another platform. It is much more easy to modify a library for another platform without developing from the scratch by reading the datasheet.
I added the library in the Arduino IDE and uploaded a sample code. It worked as expected. Then I did some experiment with the library by changing some instruction for better understanding. As now I know both the display and the Arduino library is working I started my job to make it compatible with ModusToolbox 3.0.
First I read the PSoC 6 HAL API documentation for GPIO and SPI. I also read the CY8CKIT-062S4 BSP documentation for understanding the pin mapping. I found the following information from the BSP documentation which is important for SPI driver and Arduino compatible pinout.
Using the following example code from HAL SPI documentation page and the Arduino library I wrote my first test code for testing the display in ModusToolbox 3.0.
Unfortunately my written code was not working. I took one sleepless night to trial and error the code to make it working but I was failed in every attempt. I again and again read the HAL API documentation, checked SPI Code example for the PSoC 62S4 board, checked with different SPI frequency but there was no success.
I was confused either the SPI communication is working or not. So, I configure a Arduino UNO board as SPI slave and connect it to the PSoC 62S4 Pioneer Kit through the SPI port. PSoC kit was working as a SPI master.
I used the following code for the Arduino SPI Slave. Here I am printing the received data from the master device.
#include<SPI.h>
volatile boolean received;
volatile byte receivedData;
ISR (SPI_STC_vect) //Inerrrput routine function
{
receivedData = SPDR; // Get the received data from SPDR register
received = true; // Sets received as True
}
void setup()
{
Serial.begin(115200);
pinMode(MISO,OUTPUT); //Sets MISO as OUTPUT
SPCR |= _BV(SPE); //Turn on SPI in Slave Mode
received = false;
SPI.attachInterrupt(); //Activate SPI Interuupt
Serial.println("SPI Slave Device");
}
void loop()
{
if(received) {
//SPDR = receivedData; // send back the received data, this is not necessary, only for demo purpose
received = false;
Serial.println(receivedData, HEX);
}
}
The slave device is receiving and printing the SPI data which I was sending from the master device. It confirmed that SPI configuration for the PSoC 62S4 kit is working and the device is sending the data to the slave SPI device. But when I connected the display it did not showing any response.
Before finally give up I again read the official wiki page for the display and one point drew my attention which I overlook before.
This was the first time I realized that the display board is connected to SPI pins through ICSP header. As the PSoC 62S4 doesn't have the ICSP header it was not being connected to the SPI pins of the display. The wiki page also mentioned the solution that SB1, SB2, and SB3 jumpers should be shorted for using the display without the ICSP header.
After shorting these three jumpers the problem was solved. The test code was working as expected. This is my final test code for PSoC 62S4 Kit for testing the display.
This was my working test code for the LCD initialization using PSoC 62S4 Kit:
#include "cyhal.h"
#include "cybsp.h"
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define LCD_CMD 0
#define LCD_DATA 1
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_BL_PIN CYBSP_D9
#define LCD_DC_PIN CYBSP_D7
#define LCD_CS_PIN CYBSP_D10
/* SPI baud rate in Hz */
#define SPI_FREQ_HZ (1000000UL)
/* SPI transfer bits per frame */
#define BITS_PER_FRAME (8)
void handle_error(uint32_t status)
{
if (status != CY_RSLT_SUCCESS)
{
CY_ASSERT(0);
}
}
void lcd_write_byte(uint8_t chByte, uint8_t chCmd);
void lcd_write_word(uint16_t hwData);
void lcd_write_register(uint8_t chRegister, uint8_t chValue);
void lcd_set_cursor(uint16_t hwXpos, uint16_t hwYpos);
void lcd_clear_screen(uint16_t hwColor);
void lcd_init();
cyhal_spi_t mSPI;
cy_rslt_t result;
int main(void)
{
/* Initialize the device and board peripherals */
result = cybsp_init();
/* Board init failed. Stop program execution */
handle_error(result);
/* Enable interrupts */
__enable_irq();
/* Init SPI master */
result = cyhal_spi_init(&mSPI,CYBSP_SPI_MOSI,CYBSP_SPI_MISO,CYBSP_SPI_CLK,
NC,NULL,BITS_PER_FRAME,
CYHAL_SPI_MODE_00_MSB,false);
handle_error(result);
result = cyhal_spi_set_frequency(&mSPI, SPI_FREQ_HZ);
handle_error(result);
lcd_init();
for (;;)
{
}
}
void lcd_write_byte(uint8_t chByte, uint8_t chCmd)
{
if (chCmd) {
cyhal_gpio_write(LCD_DC_PIN, true);
} else {
cyhal_gpio_write(LCD_DC_PIN, false);
}
cyhal_gpio_write(LCD_CS_PIN, false);
cyhal_spi_send(&mSPI, chByte);
cyhal_gpio_write(LCD_CS_PIN, true);
}
void lcd_write_word(uint16_t hwData)
{
uint32_t hval = hwData >> 8;
uint32_t lval = hwData & 0xFF;
cyhal_gpio_write(LCD_DC_PIN, true);
cyhal_gpio_write(LCD_CS_PIN, false);
cyhal_spi_send(&mSPI, hval);
cyhal_spi_send(&mSPI, lval);
cyhal_gpio_write(LCD_CS_PIN, true);
}
void lcd_write_register(uint8_t chRegister, uint8_t chValue)
{
lcd_write_byte(chRegister, LCD_CMD);
lcd_write_byte(chValue, LCD_DATA);
}
void lcd_set_cursor(uint16_t hwXpos, uint16_t hwYpos)
{
if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
return;
}
lcd_write_register(0x02, hwXpos >> 8);
lcd_write_register(0x03, hwXpos & 0xFF); //Column Start
lcd_write_register(0x06, hwYpos >> 8);
lcd_write_register(0x07, hwYpos & 0xFF); //Row Start
}
//clear the lcd with the specified color.
void lcd_clear_screen(uint16_t hwColor)
{
uint32_t i, wCount = LCD_WIDTH;
uint8_t hval = hwColor >> 8;
uint8_t lval = hwColor & 0xFF;
wCount *= LCD_HEIGHT;
lcd_set_cursor(0, 0);
lcd_write_byte(0x22, LCD_CMD);
cyhal_gpio_write(LCD_DC_PIN, true);
cyhal_gpio_write(LCD_CS_PIN, false);
for (i = 0; i < wCount; i ++) {
cyhal_spi_send(&mSPI, hval);
cyhal_spi_send(&mSPI, lval);
}
cyhal_gpio_write(LCD_CS_PIN, true);
}
void lcd_init()
{
result = cyhal_gpio_init(LCD_DC_PIN, CYHAL_GPIO_DIR_OUTPUT,
CYHAL_GPIO_DRIVE_STRONG, CYBSP_LED_STATE_OFF);
handle_error(result);
result = cyhal_gpio_init(LCD_BL_PIN, CYHAL_GPIO_DIR_OUTPUT,
CYHAL_GPIO_DRIVE_STRONG, CYBSP_LED_STATE_OFF);
handle_error(result);
result = cyhal_gpio_init(LCD_CS_PIN, CYHAL_GPIO_DIR_OUTPUT,
CYHAL_GPIO_DRIVE_STRONG, CYBSP_LED_STATE_OFF);
handle_error(result);
cyhal_gpio_write(LCD_CS_PIN, true);
cyhal_gpio_write(LCD_DC_PIN, false);
cyhal_gpio_write(LCD_BL_PIN, false);
//Driving ability Setting
lcd_write_register(0xEA,0x00); //PTBA[15:8]
cyhal_system_delay_ms(5);
lcd_write_register(0xEB,0x20); //PTBA[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xEC,0x0C); //STBA[15:8]
cyhal_system_delay_ms(5);
lcd_write_register(0xED,0xC4); //STBA[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xE8,0x38); //OPON[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xE9,0x10); //OPON1[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xF1,0x01); //OTPS1B
cyhal_system_delay_ms(5);
lcd_write_register(0xF2,0x10); //GEN
cyhal_system_delay_ms(5);
//Gamma 2.2 Setting
lcd_write_register(0x40,0x01); //
cyhal_system_delay_ms(5);
lcd_write_register(0x41,0x00); //
cyhal_system_delay_ms(5);
lcd_write_register(0x42,0x00); //
cyhal_system_delay_ms(5);
lcd_write_register(0x43,0x10); //
cyhal_system_delay_ms(5);
lcd_write_register(0x44,0x0E); //
cyhal_system_delay_ms(5);
lcd_write_register(0x45,0x24); //
cyhal_system_delay_ms(5);
lcd_write_register(0x46,0x04); //
cyhal_system_delay_ms(5);
lcd_write_register(0x47,0x50); //
cyhal_system_delay_ms(5);
lcd_write_register(0x48,0x02); //
cyhal_system_delay_ms(5);
lcd_write_register(0x49,0x13); //
cyhal_system_delay_ms(5);
lcd_write_register(0x4A,0x19); //
cyhal_system_delay_ms(5);
lcd_write_register(0x4B,0x19); //
cyhal_system_delay_ms(5);
lcd_write_register(0x4C,0x16); //
cyhal_system_delay_ms(5);
lcd_write_register(0x50,0x1B); //
cyhal_system_delay_ms(5);
lcd_write_register(0x51,0x31); //
cyhal_system_delay_ms(5);
lcd_write_register(0x52,0x2F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x53,0x3F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x54,0x3F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x55,0x3E); //
cyhal_system_delay_ms(5);
lcd_write_register(0x56,0x2F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x57,0x7B); //
cyhal_system_delay_ms(5);
lcd_write_register(0x58,0x09); //
cyhal_system_delay_ms(5);
lcd_write_register(0x59,0x06); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5A,0x06); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5B,0x0C); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5C,0x1D); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5D,0xCC); //
//Power Voltage Setting
lcd_write_register(0x1B,0x1B); //VRH=4.65V
cyhal_system_delay_ms(5);
lcd_write_register(0x1A,0x01); //BT (VGH~15V,VGL~-10V,DDVDH~5V)
cyhal_system_delay_ms(5);
lcd_write_register(0x24,0x2F); //VMH(VCOM High voltage ~3.2V)
cyhal_system_delay_ms(5);
lcd_write_register(0x25,0x57); //VML(VCOM Low voltage -1.2V)
cyhal_system_delay_ms(5);
//VCOM offset
lcd_write_register(0x23,0x88); //for Flicker adjust //can reload from OTP
cyhal_system_delay_ms(5);
//Power on Setting
lcd_write_register(0x18,0x34); //I/P_RADJ,N/P_RADJ, Normal mode 60Hz
cyhal_system_delay_ms(5);
lcd_write_register(0x19,0x01); //OSC_EN='1', start Osc
cyhal_system_delay_ms(5);
lcd_write_register(0x01,0x00); //DP_STB='0', out deep sleep
cyhal_system_delay_ms(5);
lcd_write_register(0x1F,0x88);// GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
//delay(5);
lcd_write_register(0x1F,0x80);// GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
//delay(5);
lcd_write_register(0x1F,0x90);// GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
//delay(5);
lcd_write_register(0x1F,0xD0);// GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
//delay(5);
//262k/65k color selection
lcd_write_register(0x17,0x05); //default 0x06 262k color // 0x05 65k color
cyhal_system_delay_ms(5);
//SET PANEL
lcd_write_register(0x36,0x00); //SS_P, GS_P,REV_P,BGR_P
cyhal_system_delay_ms(5);
//Display ON Setting
lcd_write_register(0x28,0x38); //GON=1, DTE=1, D=1000
cyhal_system_delay_ms(5);
//delay(40);
lcd_write_register(0x28,0x3F); //GON=1, DTE=1, D=1100
cyhal_system_delay_ms(5);
lcd_write_register(0x16,0x18);
cyhal_system_delay_ms(5);
//Set GRAM Area
lcd_write_register(0x02,0x00);
cyhal_system_delay_ms(5);
lcd_write_register(0x03,0x00); //Column Start
cyhal_system_delay_ms(5);
lcd_write_register(0x04,0x00);
cyhal_system_delay_ms(5);
lcd_write_register(0x05,0xEF); //Column End
cyhal_system_delay_ms(5);
lcd_write_register(0x06,0x00);
cyhal_system_delay_ms(5);
lcd_write_register(0x07,0x00); //Row Start
cyhal_system_delay_ms(5);
lcd_write_register(0x08,0x01);
cyhal_system_delay_ms(5);
lcd_write_register(0x09,0x3F); //Row End
cyhal_system_delay_ms(5);
lcd_clear_screen(BLUE);
cyhal_gpio_write(LCD_BL_PIN, true);
}
After successfully testing the LCD with the test code I developed the working library for the 2.8inch TFT LCD using ModusToolbox 3.0 and the HAL SPI library. I tried to keep the function same the Arduino and STM32 library. The library is capable to display any text and number in two fonts as well as display different symbol like circle, triangle, rectangular box and so on. The source c file for the library is as follows:
/* Includes ------------------------------------------------------------------*/
#include "Fonts/Fonts.h"
#include "lcd_driver.h"
#include "cyhal.h"
#include "cybsp.h"
uint8_t _rotation = 0;
extern cyhal_spi_t mSPI;
void lcd_write_byte(uint8_t chByte, uint8_t chCmd)
{
if (chCmd) {
__LCD_DC_SET();
} else {
__LCD_DC_CLR();
}
__LCD_CS_CLR();
cyhal_spi_send(&mSPI, chByte);
__LCD_CS_SET();
}
void lcd_write_word(uint16_t hwData)
{
uint8_t hval = hwData >> 8;
uint8_t lval = hwData & 0xFF;
__LCD_DC_SET();
__LCD_CS_CLR();
cyhal_spi_send(&mSPI, hval);
cyhal_spi_send(&mSPI, lval);
__LCD_CS_SET();
}
void lcd_write_register(uint8_t chRegister, uint8_t chValue)
{
lcd_write_byte(chRegister, LCD_CMD);
lcd_write_byte(chValue, LCD_DATA);
}
void lcd_init(void)
{
__LCD_DC_OUT();
__LCD_DC_SET();
__LCD_CS_OUT();
__LCD_CS_SET();
__LCD_BL_OUT();
__LCD_BL_OFF();
__LCD_DC_CLR();
__LCD_CS_CLR();
lcd_write_register(0xEA,0x00); //PTBA[15:8]
cyhal_system_delay_ms(5);
lcd_write_register(0xEB,0x20); //PTBA[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xEC,0x0C); //STBA[15:8]
cyhal_system_delay_ms(5);
lcd_write_register(0xED,0xC4); //STBA[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xE8,0x38); //OPON[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xE9,0x10); //OPON1[7:0]
cyhal_system_delay_ms(5);
lcd_write_register(0xF1,0x01); //OTPS1B
cyhal_system_delay_ms(5);
lcd_write_register(0xF2,0x10); //GEN
cyhal_system_delay_ms(5);
//Gamma 2.2 Setting
lcd_write_register(0x40,0x01); //
cyhal_system_delay_ms(5);
lcd_write_register(0x41,0x00); //
cyhal_system_delay_ms(5);
lcd_write_register(0x42,0x00); //
cyhal_system_delay_ms(5);
lcd_write_register(0x43,0x10); //
cyhal_system_delay_ms(5);
lcd_write_register(0x44,0x0E); //
cyhal_system_delay_ms(5);
lcd_write_register(0x45,0x24); //
cyhal_system_delay_ms(5);
lcd_write_register(0x46,0x04); //
cyhal_system_delay_ms(5);
lcd_write_register(0x47,0x50); //
cyhal_system_delay_ms(5);
lcd_write_register(0x48,0x02); //
cyhal_system_delay_ms(5);
lcd_write_register(0x49,0x13); //
cyhal_system_delay_ms(5);
lcd_write_register(0x4A,0x19); //
cyhal_system_delay_ms(5);
lcd_write_register(0x4B,0x19); //
cyhal_system_delay_ms(5);
lcd_write_register(0x4C,0x16); //
cyhal_system_delay_ms(5);
lcd_write_register(0x50,0x1B); //
cyhal_system_delay_ms(5);
lcd_write_register(0x51,0x31); //
cyhal_system_delay_ms(5);
lcd_write_register(0x52,0x2F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x53,0x3F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x54,0x3F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x55,0x3E); //
cyhal_system_delay_ms(5);
lcd_write_register(0x56,0x2F); //
cyhal_system_delay_ms(5);
lcd_write_register(0x57,0x7B); //
cyhal_system_delay_ms(5);
lcd_write_register(0x58,0x09); //
cyhal_system_delay_ms(5);
lcd_write_register(0x59,0x06); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5A,0x06); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5B,0x0C); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5C,0x1D); //
cyhal_system_delay_ms(5);
lcd_write_register(0x5D,0xCC); //
cyhal_system_delay_ms(5);
//Power Voltage Setting
lcd_write_register(0x1B,0x1B); //VRH=4.65V
cyhal_system_delay_ms(5);
lcd_write_register(0x1A,0x01); //BT (VGH~15V,VGL~-10V,DDVDH~5V)
cyhal_system_delay_ms(5);
lcd_write_register(0x24,0x2F); //VMH(VCOM High voltage ~3.2V)
cyhal_system_delay_ms(5);
lcd_write_register(0x25,0x57); //VML(VCOM Low voltage -1.2V)
cyhal_system_delay_ms(5);
//VCOM offset
lcd_write_register(0x23,0x88); //for Flicker adjust //can reload from OTP
cyhal_system_delay_ms(5);
//Power on Setting
lcd_write_register(0x18,0x34); //I/P_RADJ,N/P_RADJ, Normal mode 60Hz
cyhal_system_delay_ms(5);
lcd_write_register(0x19,0x01); //OSC_EN='1', start Osc
cyhal_system_delay_ms(5);
lcd_write_register(0x01,0x00); //DP_STB='0', out deep sleep
cyhal_system_delay_ms(5);
lcd_write_register(0x1F,0x88);// GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
lcd_write_register(0x1F,0x80);// GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
lcd_write_register(0x1F,0x90);// GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
lcd_write_register(0x1F,0xD0);// GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0
cyhal_system_delay_ms(5);
//262k/65k color selection
lcd_write_register(0x17,0x05); //default 0x06 262k color // 0x05 65k color
cyhal_system_delay_ms(5);
//SET PANEL
lcd_write_register(0x36,0x00); //SS_P, GS_P,REV_P,BGR_P
cyhal_system_delay_ms(5);
//Display ON Setting
lcd_write_register(0x28,0x38); //GON=1, DTE=1, D=1000
cyhal_system_delay_ms(5);
//delay(40);
lcd_write_register(0x28,0x3F); //GON=1, DTE=1, D=1100
cyhal_system_delay_ms(5);
lcd_write_register(0x16,0x18);
cyhal_system_delay_ms(5);
//Set GRAM Area
lcd_write_register(0x02,0x00);
cyhal_system_delay_ms(5);
lcd_write_register(0x03,0x00); //Column Start
cyhal_system_delay_ms(5);
lcd_write_register(0x04,0x00);
cyhal_system_delay_ms(5);
lcd_write_register(0x05,0xEF); //Column End
cyhal_system_delay_ms(5);
lcd_write_register(0x06,0x00);
cyhal_system_delay_ms(5);
lcd_write_register(0x07,0x00); //Row Start
cyhal_system_delay_ms(5);
lcd_write_register(0x08,0x01);
cyhal_system_delay_ms(5);
lcd_write_register(0x09,0x3F); //Row End
cyhal_system_delay_ms(5);
lcd_clear_screen(WHITE);
__LCD_BL_ON();
}
//draw a point on the lcd with the specified color.
//hwXpos specify x position.
//hwYpos specify y position.
//hwColor color of the point.
void lcd_draw_point(uint16_t hwXpos, uint16_t hwYpos, uint16_t hwColor)
{
lcd_set_cursor(hwXpos, hwYpos);
lcd_write_byte(0x22, LCD_CMD);
lcd_write_word(hwColor);
}
//display a char at the specified position on lcd.
void lcd_display_char( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint8_t chChr, //a char is display.
uint8_t chSize, //specify the size of the char
uint16_t hwColor) //specify the color of the char
{
uint8_t i, j, chTemp = 0;
uint16_t hwYpos0 = hwYpos, hwColorVal = 0;
for (i = 0; i < chSize; i ++) {
if (FONT_1206 == chSize) {
chTemp = c_chFont1206[chChr - 0x20][i];
}else if (FONT_1608 == chSize) {
chTemp = c_chFont1608[chChr - 0x20][i];
}
for (j = 0; j < 8; j ++) {
if (chTemp & 0x80) {
hwColorVal = hwColor;
lcd_draw_point(hwXpos, hwYpos, hwColorVal);
}
chTemp = chTemp << 1;
hwYpos ++;
if ((hwYpos - hwYpos0) == chSize) {
hwYpos = hwYpos0;
hwXpos ++;
break;
}
}
}
}
//_pow
static uint32_t _pow(uint8_t m, uint8_t n)
{
uint32_t result = 1;
while(n --) result *= m;
return result;
}
//display a number at the specified position on lcd.
void lcd_display_num( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint32_t chNum, //a number is display.
uint8_t chLen, //length ot the number
uint8_t chSize, //specify the size of the number
uint16_t hwColor) //specify the color of the number
{
uint8_t i;
uint8_t chTemp, chShow = 0;
for(i = 0; i < chLen; i ++) {
chTemp = (chNum / _pow(10, chLen - i - 1)) % 10;
if(chShow == 0 && i < (chLen - 1)) {
if(chTemp == 0) {
lcd_display_char(hwXpos + (chSize / 2) * i, hwYpos, ' ', chSize, hwColor);
continue;
} else {
chShow = 1;
}
}
lcd_display_char(hwXpos + (chSize / 2) * i, hwYpos, chTemp + '0', chSize, hwColor);
}
}
//display a string at the specified position on lcd.
void lcd_display_string( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
const uint8_t *pchString, //a pointer to string
uint8_t chSize, // the size of the string
uint16_t hwColor) // specify the color of the string
{
while (*pchString != '\0') {
if (hwXpos > (LCD_WIDTH - chSize / 2)) {
hwXpos = 0;
hwYpos += chSize;
if (hwYpos > (LCD_HEIGHT - chSize)) {
hwYpos = hwXpos = 0;
lcd_clear_screen(0x00);
}
}
lcd_display_char(hwXpos, hwYpos, (uint8_t)*pchString, chSize, hwColor);
hwXpos += chSize / 2;
pchString ++;
}
}
//draw a line at the specified position on lcd.
void lcd_draw_line( uint16_t hwXpos0, //specify x0 position.
uint16_t hwYpos0, //specify y0 position.
uint16_t hwXpos1, //specify x1 position.
uint16_t hwYpos1, //specify y1 position.
uint16_t hwColor) //specify the color of the line
{
int x = hwXpos1 - hwXpos0;
int y = hwYpos1 - hwYpos0;
int dx = abs(x), sx = hwXpos0 < hwXpos1 ? 1 : -1;
int dy = -abs(y), sy = hwYpos0 < hwYpos1 ? 1 : -1;
int err = dx + dy, e2;
for (;;){
lcd_draw_point(hwXpos0, hwYpos0 , hwColor);
e2 = 2 * err;
if (e2 >= dy) {
if (hwXpos0 == hwXpos1) break;
err += dy; hwXpos0 += sx;
}
if (e2 <= dx) {
if (hwYpos0 == hwYpos1) break;
err += dx; hwYpos0 += sy;
}
}
}
//draw a circle at the specified position on lcd.
void lcd_draw_circle( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwRadius, //specify the radius of the circle.
uint16_t hwColor) //specify the color of the circle.
{
int x = -hwRadius, y = 0, err = 2 - 2 * hwRadius, e2;
// if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
// return;
// }
do {
lcd_draw_point(hwXpos - x, hwYpos + y, hwColor);
lcd_draw_point(hwXpos + x, hwYpos + y, hwColor);
lcd_draw_point(hwXpos + x, hwYpos - y, hwColor);
lcd_draw_point(hwXpos - x, hwYpos - y, hwColor);
e2 = err;
if (e2 <= y) {
err += ++ y * 2 + 1;
if(-x == y && e2 <= x) e2 = 0;
}
if(e2 > x) err += ++ x * 2 + 1;
} while(x <= 0);
}
//fill a rectangle out at the specified position on lcd.
void lcd_fill_rect(uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwWidth, //specify the width of the rectangle.
uint16_t hwHeight, //specify the height of the rectangle.
uint16_t hwColor) //specify the color of rectangle.
{
uint16_t i, j;
// if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
// return;
// }
for(i = 0; i < hwHeight; i ++){
for(j = 0; j < hwWidth; j ++){
lcd_draw_point(hwXpos + j, hwYpos + i, hwColor);
}
}
}
//draw a vertical line at the specified position on lcd.
void lcd_draw_v_line( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwHeight, //specify the height of the vertical line.
uint16_t hwColor) //specify the color of the vertical line.
{
uint16_t i, y1 = MIN(hwYpos + hwHeight, LCD_HEIGHT - 1);
// if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
// return;
// }
for (i = hwYpos; i < y1; i ++) {
lcd_draw_point(hwXpos, i, hwColor);
}
}
//draw a horizonal line at the specified position on lcd.
void lcd_draw_h_line( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwWidth, //specify the width of the horizonal line.
uint16_t hwColor) //specify the color of the horizonal line.
{
uint16_t i, x1 = MIN(hwXpos + hwWidth, LCD_WIDTH - 1);
// if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
// return;
// }
for (i = hwXpos; i < x1; i ++) {
lcd_draw_point(i, hwYpos, hwColor);
}
}
void lcd_draw_rect( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwWidth, //specify the width of the rectangle.
uint16_t hwHeight, //specify the height of the rectangle.
uint16_t hwColor) //specify the color of rectangle.
{
// if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
// return;
// }
lcd_draw_h_line(hwXpos, hwYpos, hwWidth, hwColor);
lcd_draw_h_line(hwXpos, hwYpos + hwHeight, hwWidth, hwColor);
lcd_draw_v_line(hwXpos, hwYpos, hwHeight, hwColor);
lcd_draw_v_line(hwXpos + hwWidth, hwYpos, hwHeight + 1, hwColor);
}
void setRotation(uint8_t rotation)
{
//uint8_t st7789v_rotation = rotation%4;
switch(rotation){
case 0:
/* Memory access control: MY = 0, MX = 0, MV = 0, ML = 0 */
/* */
lcd_write_register(0X36, 0x00);
lcd_write_byte(0x2A,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte((LCD_WIDTH-1)&0xff,LCD_DATA);
lcd_write_byte(0x2B,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(((LCD_HEIGHT-1)>>8)&0xff,LCD_DATA);
lcd_write_byte((LCD_HEIGHT-1)&0xff,LCD_DATA);
lcd_write_byte(0x2C,LCD_CMD);
break;
case 1:
/* Memory access control: MY = 0, MX = 1, MV = 1, ML = 0 */
lcd_write_register(0X36, 0x60);
lcd_write_byte(0x2A,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(((LCD_HEIGHT-1)>>8)&0xff,LCD_DATA);
lcd_write_byte((LCD_HEIGHT-1)&0xff,LCD_DATA);
lcd_write_byte(0x2B,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte((LCD_WIDTH-1)&0xff,LCD_DATA);
lcd_write_byte(0x2C,LCD_CMD);
break;
case 2:
/* Memory access control: MY = 1, MX = 1, MV = 0, ML = 0 */
lcd_write_register(0X36, 0xC0);
lcd_write_byte(0x2A,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte((LCD_WIDTH-1)&0xff,LCD_DATA);
lcd_write_byte(0x2B,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(((LCD_HEIGHT-1)>>8)&0xff,LCD_DATA);
lcd_write_byte((LCD_HEIGHT-1)&0xff,LCD_DATA);
lcd_write_byte(0x2C,LCD_CMD);
break;
case 3:
/* Memory access control: MY = 1, MX = 0, MV = 1, ML = 0 */
lcd_write_register(0X36, 0xA0);
lcd_write_byte(0x2A,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(((LCD_HEIGHT-1)>>8)&0xff,LCD_DATA);
lcd_write_byte((LCD_HEIGHT-1)&0xff,LCD_DATA);
lcd_write_byte(0x2B,LCD_CMD);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte(0x00,LCD_DATA);
lcd_write_byte((LCD_WIDTH-1)&0xff,LCD_DATA);
lcd_write_byte(0x2C,LCD_CMD);
break;
}
}
void lcd_set_cursor(uint16_t hwXpos, uint16_t hwYpos)
{
if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
return;
}
lcd_write_register(0x02, hwXpos >> 8);
lcd_write_register(0x03, hwXpos & 0xFF); //Column Start
lcd_write_register(0x06, hwYpos >> 8);
lcd_write_register(0x07, hwYpos & 0xFF); //Row Start
}
//clear the lcd with the specified color.
void lcd_clear_screen(uint16_t hwColor)
{
uint32_t i, wCount = LCD_WIDTH;
uint8_t hval = hwColor >> 8;
uint8_t lval = hwColor & 0xFF;
wCount *= LCD_HEIGHT;
lcd_set_cursor(0, 0);
lcd_write_byte(0x22, LCD_CMD);
__LCD_DC_SET();
__LCD_CS_CLR();
for (i = 0; i < wCount; i ++) {
cyhal_spi_send(&mSPI, hval);
cyhal_spi_send(&mSPI, lval);
}
__LCD_CS_SET();
}
void lcd_write_ram_prepare(void)
{
lcd_write_byte(0x22, LCD_CMD);
}
void lcd_write_ram(uint16_t hwData)
{
lcd_write_word(hwData);
}
void lcd_set_window(uint16_t hwXpos, uint16_t hwYpos, uint16_t hwWidth, uint16_t hwHeight)
{
// lcd_write_register(0x04, (hwXpos + hwWidth - 1) >> 8);
// lcd_write_register(0x05, (hwXpos + hwWidth - 1) & 0xFF); //Column End
// lcd_write_register(0x08, (hwYpos + hwHeight - 1) >> 8);
// lcd_write_register(0x09, (hwYpos + hwHeight - 1) & 0xFF); //Row End
}
/*-------------------------------END OF FILE-------------------------------*/
And the header file for the library is as follows:
/*
* lcd_driver.h
*
* Created on: Apr 16, 2023
* Author: Md. Khairul Alam
*/
#ifndef LCD_LCD_DRIVER_H_
#define LCD_LCD_DRIVER_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "cyhal.h"
#include "cybsp.h"
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_CMD 0
#define LCD_DATA 1
#define FONT_1206 12
#define FONT_1608 16
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40
#define BRRED 0XFC07
#define GRAY 0X8430
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define LCD_BL_PIN CYBSP_D9
#define LCD_DC_PIN CYBSP_D7
#define LCD_CS_PIN CYBSP_D10
#define __LCD_CS_OUT() cyhal_gpio_init(LCD_CS_PIN, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false)
#define __LCD_DC_OUT() cyhal_gpio_init(LCD_DC_PIN, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false)
#define __LCD_BL_OUT() cyhal_gpio_init(LCD_BL_PIN, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false)
#define __LCD_CS_CLR() cyhal_gpio_write(LCD_CS_PIN, false)
#define __LCD_CS_SET() cyhal_gpio_write(LCD_CS_PIN, true)
#define __LCD_DC_CLR() cyhal_gpio_write(LCD_DC_PIN, false)
#define __LCD_DC_SET() cyhal_gpio_write(LCD_DC_PIN, true)
#define __LCD_BL_OFF() cyhal_gpio_write(LCD_BL_PIN, false)
#define __LCD_BL_ON() cyhal_gpio_write(LCD_BL_PIN, true)
extern void lcd_write_byte(uint8_t chByte, uint8_t chCmd);
extern void lcd_write_word(uint16_t hwData);
extern void lcd_write_register(uint8_t chRegister, uint8_t chValue);
extern void lcd_init(void);
extern void lcd_set_cursor( uint16_t hwXpos, uint16_t hwYpos);
extern void lcd_write_ram_prepare(void);
extern void lcd_write_ram( uint16_t hwData);
extern void lcd_set_window( uint16_t hwXpos, uint16_t hwYpos, uint16_t hwWidth, uint16_t hwHeight);
extern void lcd_draw_point( uint16_t hwXpos, uint16_t hwYpos, uint16_t hwColor);
extern void lcd_clear_screen( uint16_t hwColor);
extern void lcd_display_char( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint8_t chChr, //a char is display.
uint8_t chSize, //specify the size of the char
uint16_t hwColor); //specify the color of the char
extern void lcd_display_num( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint32_t chNum, //a number is display.
uint8_t chLen, //length ot the number
uint8_t chSize, //specify the size of the number
uint16_t hwColor); //specify the color of the number
extern void lcd_display_string( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
const uint8_t *pchString, //a pointer to string
uint8_t chSize, // the size of the string
uint16_t hwColor); // specify the color of the string
extern void lcd_draw_line( uint16_t hwXpos0, //specify x0 position.
uint16_t hwYpos0, //specify y0 position.
uint16_t hwXpos1, //specify x1 position.
uint16_t hwYpos1, //specify y1 position.
uint16_t hwColor); //specify the color of the line
extern void lcd_draw_circle( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwRadius, //specify the radius of the circle.
uint16_t hwColor); //specify the color of the circle.
extern void lcd_fill_rect( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwWidth, //specify the width of the rectangle.
uint16_t hwHeight, //specify the height of the rectangle.
uint16_t hwColor); //specify the color of rectangle.
extern void lcd_draw_v_line( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwHeight, //specify the height of the vertical line.
uint16_t hwColor); //specify the color of the vertical line.
extern void lcd_draw_h_line( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwWidth, //specify the width of the horizonal line.
uint16_t hwColor); //specify the color of the horizonal line.
extern void lcd_draw_rect( uint16_t hwXpos, //specify x position.
uint16_t hwYpos, //specify y position.
uint16_t hwWidth, //specify the width of the rectangle.
uint16_t hwHeight, //specify the height of the rectangle.
uint16_t hwColor); //specify the color of rectangle.
void setRotation( uint8_t rotation);
void lcd_write_word( uint16_t hwData);
#ifdef __cplusplus
}
#endif
#endif /* LCD_LCD_DRIVER_H_ */
Using the library I compiled the following code to the PSoC 62S4 Pioneer Kit for testing the library and I got the perfect result.
Test Code:
/*******************************************************************************
* Header Files
*******************************************************************************/
#include "cyhal.h"
#include "cybsp.h"
#include "Fonts/Fonts.h"
#include "LCD/lcd_driver.h"
/*******************************************************************************
* Macros
*******************************************************************************/
/* SPI baud rate in Hz */
#define SPI_FREQ_HZ (1000000UL)
/* Delay of 1000ms between commands */
#define CMD_TO_CMD_DELAY (1000UL)
/* SPI transfer bits per frame */
#define BITS_PER_FRAME (8)
cy_rslt_t result;
cyhal_spi_t mSPI;
void handle_error(uint32_t status)
{
if (status != CY_RSLT_SUCCESS)
{
CY_ASSERT(0);
}
}
int main(void)
{
/* Initialize the device and board peripherals */
result = cybsp_init();
/* Board init failed. Stop program execution */
handle_error(result);
/* Enable interrupts */
__enable_irq();
result = cyhal_spi_init(&mSPI,CYBSP_SPI_MOSI,CYBSP_SPI_MISO,CYBSP_SPI_CLK,
NC,NULL,BITS_PER_FRAME,
CYHAL_SPI_MODE_11_MSB,false);
handle_error(result);
result = cyhal_spi_set_frequency(&mSPI, SPI_FREQ_HZ);
handle_error(result);
lcd_init();
lcd_display_string(10,130,(const uint8_t *)"At The Core Design Challenge",FONT_1608,RED);
lcd_display_string(10,160,(const uint8_t *)"PSoC 62S4 Kit & ModusToolbox 3.0 Demo",FONT_1608,BLUE);
lcd_draw_circle(50,50,30,BLUE);
lcd_fill_rect(160,200,60,100,GREEN);
lcd_draw_rect(80,90,100,100,YELLOW);
lcd_draw_h_line(18,180,200,RED);
lcd_draw_v_line(30,120,100,GRAY);
for (;;)
{
/* Give delay between commands */
//cyhal_system_delay_ms(500);
}
}
A photo of the PSoC kit with the LCD is attached below:
In the next step, I will try to integrate emWin graphics library for the display.