1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
4 * 2019/9/14 - ROBIN KRENS
19 #include <sys/robsys.h>
21 #include <lib/regfunc.h>
22 #include <lib/string.h>
23 #include <lib/tinyprintf.h>
24 //#include <lib/fonts/wogfont.h>
26 #include <drivers/st7735s.h>
32 int tft_putc(uint16_t, uint16_t, char);
35 /* Peripherial init */
36 rsetbit(RCC_APB1ENR, 14); // enable SPI2
37 rsetbit(RCC_APB2ENR, 3); // enable GPIOB
38 rsetbit(RCC_APB2ENR, 4); // enable GPIOC
40 /* The PINS used are PB12, PB13, PB15 and PC6 respectively
41 * NSS (or CS): alternative function pusp-pull
42 * NSS Output is (always high) enabled with this setting
43 * SCK Master: alternate function push-pull
44 * MOSI (or DI): alternate function push-pull
45 * D/CX (or A0): Command or data write line PC6 */
46 rwrite(GPIOB_CRH, 0xA4AA4444);
47 rwrite(GPIOC_CRL, 0x42444444);
49 /* Chip select: software enabled
50 * In case for a hardware setup, connect NSS (CS) to
55 rsetbit(SPI2_CR1, 15); // one-wire mode
56 rsetbit(SPI2_CR1, 14); // start with transfer
57 rsetbit(SPI2_CR1, 4); // FPLCK div 8
58 rsetbit(SPI2_CR1, 2); // master selection
59 rsetbit(SPI2_CR1, 6); // enable SPI
62 tft_command(TFT_SWRESET, 0);
67 /* Frame rate control */
68 tft_command(TFT_FRMCTR1, 3, 0x01, 0x2C, 0x2D);
69 tft_command(TFT_FRMCTR2, 3, 0x01, 0x2C, 0x2D);
70 tft_command(TFT_FRMCTR3, 6, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D);
73 tft_command(TFT_PWCTR1, 3, 0xA2, 0x02, 0x84);
74 tft_command(TFT_PWCTR2, 1, 0xC5);
75 tft_command(TFT_PWCTR3, 2, 0x0A, 0x00);
76 tft_command(TFT_PWCTR4, 2, 0x8A, 0x2A);
77 tft_command(TFT_PWCTR5, 2, 0x8A, 0xEE);
78 tft_command(TFT_VMCTR1, 1, 0x0E);
80 tft_command(TFT_INVOFF, 0);
81 tft_command(TFT_COLMOD, 1, 0x05); // 0x05
82 tft_command(TFT_MADCTL, 1, 0xC0); // TODO: check
84 tft_command(TFT_CASET, 4, 0x00, 0x00, 0x00, 0x7F);
85 tft_command(TFT_RASET, 4, 0x00, 0x00, 0x00, 0x9F);
88 tft_command(TFT_GMCTRP1, 16, 0x02, 0x1C, 0x07, 0x12,
89 0x37, 0x32, 0x29, 0x2D,
90 0x29, 0x25, 0x2B, 0x39,
91 0x00, 0x01, 0x03, 0x10);
92 tft_command(TFT_GMCTRN1, 16, 0x03, 0x1D, 0x07, 0x06,
93 0x2E, 0x2C, 0x29, 0x2D,
94 0x2E, 0x2E, 0x37, 0x3F,
95 0x00, 0x00, 0x02, 0x10);
97 /* Before turning on the display, fill the display
98 * so no random display data is shown */
99 tft_fill(0,0,SCRWIDTH-1,SCRHEIGHT-1,0x0000);
100 //tft_setpixel(50,50,0xFFFF);
101 tft_putc(0xFFFF, 0x0000, 's');
104 tft_command(TFT_NORON, 0);
106 tft_command(TFT_DISPON, 0);
112 tft_command(TFT_CASET, 4, 0x00, 0x08, 0x00, 0x09);
113 tft_command(TFT_RASET, 4, 0x00, 0x08, 0x00, 0x09);
114 tft_command(TFT_RAMRD, 0);
116 //tft_command(0x0C, 0);
117 //tft_command(0x0A, 0);
119 rclrbit(SPI2_CR1, 14); // receive
121 while(!rchkbit(SPI2_SR, 0));
122 uint8_t chip_id = *SPI2_DR;
123 printf("COLMOD: %#x\n", chip_id); */
125 rclrbit(SPI2_CR1, 8); // deselect
128 /* Helper function */
129 static int txbuf_empty () {
131 while(!rchkbit(SPI2_SR, 1)) {
134 printf("Error: transmit timeout!\n");
143 /* Function to fill an area starting at (beginx, beginy)
144 * and end ending at (endx, endy */
145 int tft_fill(uint8_t beginx, uint8_t beginy, uint8_t endx,
146 uint8_t endy, uint16_t color) {
148 /* The CASET and RASET commands set the begin X/Y
149 * and end X/Y of the fill area. Both are split over
150 * two paramters/bytes. Most screen are small, so you will
151 * only need to consider the first 8 MSBs. Parameter 1 and
154 * In theory, TFT screens of 65,535 by 65,535 could be
156 tft_command(TFT_CASET, 4, 0x00, beginx, 0x00, endx);
157 tft_command(TFT_RASET, 4, 0x00, beginy, 0x00, endy);
159 /* After setting the fill area, we can send the color
160 * data. The chip autoincrements the address so we can
161 * keep writing continiously for the fill area. Note
162 * that each pixel requires two bytes to be send (16
164 uint32_t totalwrites = (endx - beginx) * (endy - beginy) * 2;
165 //printf("tw: %d, x: %d, y: %d\n", totalwrites, beginx, beginy);
166 tft_command(TFT_RAMWR, 0);
167 rsetbit(GPIOC_ODR, 6); // data = 1
168 for (int i = 0; i < totalwrites; i++) {
169 rwrite(SPI2_DR, (uint8_t) (color >> 8));
172 rwrite(SPI2_DR, (uint8_t) (color & 0xFF));
179 /* Function to individually set a pixel
180 * Refer to tft_fill, similar calls */
181 int tft_setpixel(uint8_t x, uint8_t y, uint16_t color) {
183 tft_command(TFT_CASET, 4, 0x00, x, 0x00, x+1);
184 tft_command(TFT_RASET, 4, 0x00, y, 0x00, y+1);
185 tft_command(TFT_RAMWR, 2, (uint8_t) (color >> 8), (uint8_t) (color & 0xFF));
189 /* Low-level function to print a character to the display
190 * Should not be used directly, since it does not set
192 int tft_putc(uint16_t fg, uint16_t bg, char c) {
195 // Bitmaps are 9 by 8
196 uint8_t databuf[9] = {0x73, 0xFB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDF, 0xDA};
197 //uint8_t databuf[9] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
199 int totalpixels = 72;
203 tft_command(TFT_CASET, 4, 0x00, 10, 0x00, 18);
204 tft_command(TFT_RASET, 4, 0x00, 10, 0x00, 17);
205 tft_command(TFT_RAMWR, 0);
206 rsetbit(GPIOC_ODR, 6); // data = 1
207 for (int i = 0; i < totalpixels; i++) {
209 current = databuf[column];
211 if ((current >> (7 - row)) & 0x1) {
212 rwrite(SPI2_DR, (uint8_t) (fg >> 8));
215 rwrite(SPI2_DR, (uint8_t) (fg & 0xFF));
220 rwrite(SPI2_DR, (uint8_t) (bg >> 8));
223 rwrite(SPI2_DR, (uint8_t) (bg & 0xFF));
228 /* Algoritm dependent on draw mode: top down, left right */
240 /* Invokes commands with a variable list of paramaters. Sending parameters
241 * requires the D/CX line to be high */
242 int tft_command(uint8_t cmd, int argsc, ...) {
246 rclrbit(GPIOC_ODR, 6); // D/CX line low
247 rwrite(SPI2_DR, cmd);
254 rsetbit(GPIOC_ODR, 6); // D/CX line high
255 for (int i = 0; i < argsc; i++) {
256 uint8_t p = (uint8_t) va_arg(ap, unsigned int);