/* TFT lowlevel functions * * Pinout: * ---------------------------------------- * PB0 -> LCD_Backlight PE3 -> LCD_RS * PD0 -> LCD_DB2 PE7 -> LCD_DB4 * PD1 -> LCD_DB3 PE8 -> LCD_DB5 * PD4 -> LCD_RD PE9 -> LCD_DB6 * PD5 -> LCD_WR PE10 -> LCD_DB7 * PD7 -> LCD_CS PE11 -> LCD_DB10 * PD8 -> LCD_DB15 PE12 -> LCD_DB11 * PD9 -> LCD_DB16 PE13 -> LCD_DB12 * PD10 -> LCD_DB17 PE14 -> LCD_DB13 * PD14 -> LCD_DB0 PE15 -> LCD_DB14 * PD15 -> LCD_DB1 * ---------------------------------------- */ #include "ll_tft.h" #include "tft.h" #include "system.h" #include "stm32f4xx.h" #include "font.h" #include "stdlib.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_fsmc.h" /* * ---------------------- prototypes -------------------------------------------------------------- */ /* init functions */ bool ll_tft_init(); static bool display_init(); static bool fsmc_init(); static bool gpio_init(); /* display functions */ void ll_tft_clear(uint16_t color); static void tft_set_cursor(uint16_t xpos, uint16_t ypos); static void tft_set_backlight(bool state); static void tft_reset(bool state); static void tft_write_reg(uint8_t reg_adr, uint16_t reg_value); static uint16_t tft_read_reg(uint8_t reg_adr); static void tft_set_window(uint16_t xstart, uint16_t ystart, uint16_t xend, uint16_t yend);void tft_reset_window(); /* draw functions */ void ll_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); void ll_tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color); void ll_tft_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); void ll_tft_draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t* dat); void ll_tft_draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color); /* font functions */ static const char *get_font(uint8_t font); uint8_t ll_tft_num_fonts(); uint8_t ll_tft_font_height(uint8_t fontnum); uint8_t ll_tft_font_width(uint8_t fontnum); void ll_tft_draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t fontnum, char c); /* * ---------------------- defines and makros ------------------------------------------------------ */ // Colors #define DISPLAY_COLOR_BLACK 0x0000 #define DISPLAY_COLOR_BLUE 0x001F #define DISPLAY_COLOR_GREEN 0x07E0 #define DISPLAY_COLOR_RED 0xF800 #define DISPLAY_COLOR_WHITE 0xFFFF #define DISPLAY_COLOR_CYAN 0x07FF #define DISPLAY_COLOR_MAGENTA 0xF81F #define DISPLAY_COLOR_YELLOW 0xFFE0 #define DISPLAY_COLOR_GREY 0xF7DE // FSMC adresses #define TFT_REG (*((volatile unsigned short *) 0x60000000)) // RS = 0 #define TFT_RAM (*((volatile unsigned short *) 0x60100000)) // RS = 1 #define TFT_RAM_ADR 0x60100000 // RAM adress // Display defines #define TFT_SSD1289_ID1 0x1289 // ID -> SSD1289 (New) #define TFT_SSD1289_ID2 0x8989 // ID -> SSD1289 (Old) #define TFT_MAXX 240 // Number of pixels x axis #define TFT_MAXY 320 // Number of pixels y axis #define TFT_PIXEL TFT_MAXX*TFT_MAXY // Total number of pixels #define TFT_SSD1289_FSMC_AST 15 // AdressSetupTime (AST >= 9) #define TFT_SSD1289_FSMC_DST 15 // DataSetupTime (DST >= 7) #define TFT_SSD1289_PORTRAIT 0x6830 // Mode = Portrait #define TFT_SSD1289_LANDSCAPE 0x6838 // Mode = Landscape #define CURRENT_MODE TFT_SSD1289_LANDSCAPE // Display controller adresses #define TFT_SSD1289_REG_00 0x00 // Display-ID register #define TFT_SSD1289_REG_11 0x11 // Display-Mode register #define TFT_SSD1289_REG_4E 0x4E // Cursor-Pos (x) register #define TFT_SSD1289_REG_4F 0x4F // Cursor-Pos (y) register #define TFT_SSD1289_REG_22 0x22 // RAM start register #define TFT_SSD1289_REG_44 0x44 // X-start+end register #define TFT_SSD1289_REG_45 0x45 // Y-start register #define TFT_SSD1289_REG_46 0x46 // Y-end register // Timeouts #define TFT_INIT_TIMEOUT 10 // 1ms timeout /* * ---------------------- init functions ---------------------------------------------------------- */ bool ll_tft_init() { bool gpio, fsmc, display; gpio = gpio_init(); // init gpio system_delay(TFT_INIT_TIMEOUT); // delay fsmc = fsmc_init(); // init fsmc system_delay(TFT_INIT_TIMEOUT); // delay display = display_init(); // init display return (gpio & fsmc & display); } static bool display_init() { tft_reset(true); // toggle reset system_delay(TFT_INIT_TIMEOUT); tft_reset(false); tft_write_reg(0x0007,0x0021); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0000,0x0001); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0007,0x0023); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0010,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0007,0x0033); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(TFT_SSD1289_REG_11,0x6018); // set mode (landscape, portrait) system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0002,0x0600); system_delay(TFT_INIT_TIMEOUT); //tft_write_reg(0x0012,0x6CEB); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0003,0xA8A4); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x000C,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x000D,0x080C); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x000E,0x2B00); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x001E,0x00B0); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0001,0x2b3F); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0005,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0006,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0016,0xEF1C); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0017,0x0103); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x000B,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x000F,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0041,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0042,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0048,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0049,0x013F); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x004A,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x004B,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0044,0xEF00); // horizontal start and end system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0045,0x0000); // vertical start system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0046,0x013F); // vertical end system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0030,0x0707); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0031,0x0204); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0032,0x0204); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0033,0x0502); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0034,0x0507); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0035,0x0204); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0036,0x0204); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0037,0x0502); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x003A,0x0302); system_delay(TFT_INIT_TIMEOUT); //tft_write_reg(0x002F,0x12BE); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x003B,0x0302); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0023,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0024,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x0025,0x8000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x004f,0x0000); system_delay(TFT_INIT_TIMEOUT); tft_write_reg(0x004e,0x0000); system_delay(TFT_INIT_TIMEOUT); TFT_REG = TFT_SSD1289_REG_22; return true; } static bool fsmc_init() { // generate init structures FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef FSMC_NORSRAMTimingInitStructure; // clock enable RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE); // prepare timing struct FSMC_NORSRAMTimingInitStructure.FSMC_AddressSetupTime = TFT_SSD1289_FSMC_AST; FSMC_NORSRAMTimingInitStructure.FSMC_AddressHoldTime = 1; FSMC_NORSRAMTimingInitStructure.FSMC_DataSetupTime = TFT_SSD1289_FSMC_DST; FSMC_NORSRAMTimingInitStructure.FSMC_BusTurnAroundDuration = 0; FSMC_NORSRAMTimingInitStructure.FSMC_CLKDivision = 0; FSMC_NORSRAMTimingInitStructure.FSMC_DataLatency = 0; FSMC_NORSRAMTimingInitStructure.FSMC_AccessMode = FSMC_AccessMode_A; // bank-1 / PSRAM-1 FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1; FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable; FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &FSMC_NORSRAMTimingInitStructure; FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &FSMC_NORSRAMTimingInitStructure; // config FSMC FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); // enable Bank-1 / PSRAM-1 FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE); return true; } static bool gpio_init() { // generate init structure GPIO_InitTypeDef GPIO_InitStructure; // clock enable PORT_B, PORT_D, PORT_E RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE); // PORT_B init GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // configure PORT_B GPIO_Init(GPIOB, &GPIO_InitStructure); // PORT_D init GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC); // PD0=FSMC_D2 -> DB2 GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC); // PD1=FSMC_D3 -> DB3 GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC); // PD4=FSMC_NOE -> RD GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FSMC); // PD5=FSMC_NWE -> WR GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_FSMC); // PD7=FSMC_NE1 -> CS GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FSMC); // PD8=FSMC_D13 -> DB15 GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FSMC); // PD9=FSMC_D14 -> DB16 GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FSMC); // PD10=FSMC_D15 -> DB17 GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC); // PD14=FSMC_D0 -> DB0 GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC); // PD15=FSMC_D1 -> DB1 // PORT_D struct GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // configure PORT_D GPIO_Init(GPIOD, &GPIO_InitStructure); // PORT_E init GPIO_PinAFConfig(GPIOE, GPIO_PinSource3, GPIO_AF_FSMC); // PE3=FSMC_A19 -> RS GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC); // PE7=FSMC_D4 -> DB4 GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FSMC); // PE8=FSMC_D5 -> DB5 GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FSMC); // PE9=FSMC_D6 -> DB6 GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC); // PE10=FSMC_D7 -> DB7 GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FSMC); // PE11=FSMC_D8 -> DB10 GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FSMC); // PE12=FSMC_D9 -> DB11 GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FSMC); // PE13=FSMC_D10 -> DB12 GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC); // PE14=FSMC_D11 -> DB13 GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC); // PE15=FSMC_D12 -> DB14 // PORT_E struct GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // configure PORT_E GPIO_Init(GPIOE, &GPIO_InitStructure); return true; } /* * ---------------------- display control functions ------------------------------------------------------- */ // Clear the whole screen by filling it with a specifig color void ll_tft_clear(uint16_t color) { uint32_t n = 0; // set cursor to 0 tft_set_cursor(0,0); for(n = 0; n < TFT_PIXEL; n++) { TFT_RAM = color; } } // Set the cursorposition static void tft_set_cursor(uint16_t xpos, uint16_t ypos) { // set cursor tft_write_reg(TFT_SSD1289_REG_4E, ypos); tft_write_reg(TFT_SSD1289_REG_4F, 319-xpos); TFT_REG = TFT_SSD1289_REG_22; } // Enable / Disable the backlight static void tft_set_backlight(bool state) { if(state){ // if state is true GPIOB->BSRRH = GPIO_Pin_0; // set the backlight output } else { // else GPIOB->BSRRL = GPIO_Pin_0; // reset the backlight } } // Port operations on the screen RS PIN static void tft_reset(bool state) { if(state){ // if state is ture GPIOB->BSRRH = GPIO_Pin_0; // Set the reset pin } else { // else GPIOB->BSRRL = GPIO_Pin_0; // reset the reset pin } } // Send a single command to the display controller static void tft_write_reg(uint8_t reg_adr, uint16_t reg_value) { TFT_REG = reg_adr; // set adress TFT_RAM = reg_value; // send command } // Read a register value of the display controller static uint16_t tft_read_reg(uint8_t reg_adr) { TFT_REG = reg_adr; // set adress return TFT_RAM; // return value } // This sets a window for current draw functions static void tft_set_window(uint16_t xstart, uint16_t ystart, uint16_t xend, uint16_t yend) { uint16_t start,end; uint16_t ystart_end; start = (ystart & 0x00FF); // Start adress of the window end = ((yend & 0x00FF) << 8); // End adress of the window ystart_end = (start | end); // Calculate y endpoint tft_write_reg(TFT_SSD1289_REG_44, ystart_end); // Send y size tft_write_reg(TFT_SSD1289_REG_45, 319-xend); // Send x start tft_write_reg(TFT_SSD1289_REG_46, 319-xstart); // Send x end } // Reset a Window void tft_reset_window() { // Commands according to the datasheet tft_write_reg(0x44, 239 << 8); tft_write_reg(0x45, 0); tft_write_reg(0x46, 319); } /* * ---------------------- draw functions ----------------------------------------------------------- */ // Draw a line on the given coordinates void ll_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { if(abs(x2-x1) > abs(y2-y1)) //line has more distance in x than y => iterate over x distance { //Without floating point! int deltax = ((int)x2-(int)x1); int deltay = ((int)y2-(int)y1)<<1; int x = 0; if (x1>x2) { do { tft_set_cursor(x1+x,y1+ (((long)deltay*(long)x/deltax+1)>>1)); TFT_RAM = color; } while(x--!=deltax); } else { do { tft_set_cursor(x1+x,y1+ (((long)deltay*(long)x/deltax+1)>>1)); TFT_RAM = color; } while(x++!=deltax); } } else // => iterate over y distance { int deltax = ((int)x2-(int)x1)<<1; int deltay = ((int)y2-(int)y1); int y = 0; if (y1>y2) { do { tft_set_cursor(x1+ (((long)deltax*(long)y/deltay+1)>>1),y1+ y); TFT_RAM = color; } while(y--!=deltay); } else { do { tft_set_cursor(x1+ (((long)deltax*(long)y/deltay+1)>>1),y1+ y); TFT_RAM = color; } while(y++!=deltay); } } } // Draw a single pixel on (x,y) with the given color void ll_tft_draw_pixel(uint16_t x,uint16_t y,uint16_t color) { tft_set_cursor(x,y); // Set the cursor position TFT_RAM = color; // Draw the pixel } // Draw a rectangle at the given coordinates with the given color void ll_tft_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { unsigned int tmp; unsigned int i; if(x1 > x2){ tmp = x1; x1 = x2; x2 = tmp; } if(y1 > y2){ tmp = y1; y1 = y2; y2 = tmp; } i = x1; //Drawing the two horizontal lines tft_set_cursor(x1, y1); while(i++ != x2) TFT_RAM = color; tft_set_cursor(x1,y2); while(i-- != x1) TFT_RAM = color; /* //uncommented because tft_write_reg seems to fail sometimes so it's safer to use draw line instead (below) i = y1; tft_write_reg(0x11,0x6030); // Change adresspointer direction tft_set_cursor(x2, y1); while(i++ != y2) TFT_RAM = color; tft_set_cursor(x1, y1); while(i-- != y1) TFT_RAM = color; tft_write_reg(0x11,0x6018); // Set adresspointer direction normal again */ tft_draw_line(x1,y1,x1,y2,color); tft_draw_line(x2,y1,x2,y2,color); } // Draw a filled rectangle at the given coordinates with the given color void ll_tft_fill_rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2, uint16_t color) { uint16_t area; uint32_t n; unsigned int tmp; if(x1 > x2){ tmp = x1; x1 = x2; x2 = tmp; } if(y1 > y2){ tmp = y1; y1 = y2; y2 = tmp; } // set window tft_set_window(x1, y1, x2, y2); tft_set_cursor(x1, y1); // calculate area area = (x2 - x1 + 1) * (y2 - y1 + 1); // fill area for(n = 0; n < area; n++) { TFT_RAM = color; } tft_reset_window(); } void ll_tft_draw_bitmap_unscaled(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint16_t* dat) { // TODO } void ll_tft_draw_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color) { // TODO } /* * ---------------------- font functions ----------------------------------------------------------- */ static const char *get_font(uint8_t font) { switch(font){ case 0: return small_font; case 1: return big_font; case 2: return seven_seg_num_font; } } uint8_t ll_tft_num_fonts() { return 3; } uint8_t ll_tft_font_height(uint8_t fontnum) { const char *font = get_font(fontnum); return (uint8_t) font[1]; } uint8_t ll_tft_font_width(uint8_t fontnum) { const char *font = get_font(fontnum); return (uint8_t) font[0]; } void ll_tft_draw_char(uint16_t x, uint16_t y, uint16_t color, uint16_t bgcolor, uint8_t fontnum, char c) { const char *font = get_font(fontnum); unsigned char width = (uint8_t) font[0]; unsigned char height = (uint8_t) font[1]; unsigned char offset = (uint8_t) font[2]; unsigned int ind = ((c-offset) * ((width / 8) * height)) + 4; unsigned int cnt = 0; unsigned char bitm = 0; bool bgIsTrans = (bgcolor == TRANSPARENT); unsigned char xadd=0; unsigned char yadd=0; tft_set_window(x, y, x + width - 1, y + height - 1); tft_set_cursor(x, y); for(cnt = (width / 8) * height; cnt > 0; cnt--){ for(bitm = 0x80; bitm > 0; bitm >>= 1){ if((font[ind]) & bitm){ if(bgIsTrans) { tft_set_cursor(x+xadd,y+yadd); } TFT_RAM = color; } else { if(!bgIsTrans) { TFT_RAM = bgcolor; } } if(bgIsTrans) { xadd++; if(xadd==width) { xadd=0; yadd++; } } } ind++; } tft_reset_window(); }