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>
33 #define XPOS(x) (x * 6)
34 #define YPOS(y) (y * 8)
48 int tft_putc(uint16_t, uint16_t, char);
49 int tft_putc_small(uint16_t, uint16_t, int);
55 tftscreen.textmemptr = tftscreen.buf;
57 memset(tftscreen.buf, 0x00, 352);
59 /* Peripherial init */
60 rsetbit(RCC_APB1ENR, 14); // enable SPI2
61 rsetbit(RCC_APB2ENR, 3); // enable GPIOB
62 rsetbit(RCC_APB2ENR, 4); // enable GPIOC
64 /* The PINS used are PB12, PB13, PB15 and PC6 respectively
65 * NSS (or CS): alternative function pusp-pull
66 * NSS Output is (always high) enabled with this setting
67 * SCK Master: alternate function push-pull
68 * MOSI (or DI): alternate function push-pull
69 * D/CX (or A0): Command or data write line PC6 */
70 rwrite(GPIOB_CRH, 0xA4AA4444);
71 rwrite(GPIOC_CRL, 0x42444444);
73 /* Chip select: software enabled
74 * In case for a hardware setup, connect NSS (CS) to
79 rsetbit(SPI2_CR1, 15); // one-wire mode
80 rsetbit(SPI2_CR1, 14); // start with transfer
81 rsetbit(SPI2_CR1, 4); // FPLCK div 8
82 rsetbit(SPI2_CR1, 2); // master selection
83 rsetbit(SPI2_CR1, 6); // enable SPI
86 tft_command(TFT_SWRESET, 0);
91 /* Frame rate control */
92 tft_command(TFT_FRMCTR1, 3, 0x01, 0x2C, 0x2D);
93 tft_command(TFT_FRMCTR2, 3, 0x01, 0x2C, 0x2D);
94 tft_command(TFT_FRMCTR3, 6, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D);
97 tft_command(TFT_PWCTR1, 3, 0xA2, 0x02, 0x84);
98 tft_command(TFT_PWCTR2, 1, 0xC5);
99 tft_command(TFT_PWCTR3, 2, 0x0A, 0x00);
100 tft_command(TFT_PWCTR4, 2, 0x8A, 0x2A);
101 tft_command(TFT_PWCTR5, 2, 0x8A, 0xEE);
102 tft_command(TFT_VMCTR1, 1, 0x0E);
104 tft_command(TFT_INVOFF, 0);
105 tft_command(TFT_COLMOD, 1, 0x05); // 0x05
106 tft_command(TFT_MADCTL, 1, 0xC0); // TODO: check
108 tft_command(TFT_CASET, 4, 0x00, 0x00, 0x00, 0x7F);
109 tft_command(TFT_RASET, 4, 0x00, 0x00, 0x00, 0x9F);
112 tft_command(TFT_GMCTRP1, 16, 0x02, 0x1C, 0x07, 0x12,
113 0x37, 0x32, 0x29, 0x2D,
114 0x29, 0x25, 0x2B, 0x39,
115 0x00, 0x01, 0x03, 0x10);
116 tft_command(TFT_GMCTRN1, 16, 0x03, 0x1D, 0x07, 0x06,
117 0x2E, 0x2C, 0x29, 0x2D,
118 0x2E, 0x2E, 0x37, 0x3F,
119 0x00, 0x00, 0x02, 0x10);
121 /* Before turning on the display, fill the display
122 * so no random display data is shown */
123 tft_fill(0,0,SCRWIDTH-1,SCRHEIGHT-1,0x0000);
124 //tft_setpixel(50,50,0xFFFF);
125 //tft_putc(0xFFFF, 0x0000, 's');
126 //tft_putc_small(0xFFFF, 0x0000, 's');
133 tft_command(TFT_NORON, 0);
135 tft_command(TFT_DISPON, 0);
138 tft_puts("rrrrrrrrrrrrrrrrrrrrrooooooooooooooooooooooooooooooooooooooooootttttttttttttttttttttoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooootttttttttttttttttttttoooooooooooooooooooootttttttttttttttttttttoooooooooooooooooooootttttttttttttttttttttoooooooooooooooooooootttttttttttttttttttttooooooooooooooooooooott");
144 tft_command(TFT_CASET, 4, 0x00, 0x08, 0x00, 0x09);
145 tft_command(TFT_RASET, 4, 0x00, 0x08, 0x00, 0x09);
146 tft_command(TFT_RAMRD, 0);
148 //tft_command(0x0C, 0);
149 //tft_command(0x0A, 0);
151 rclrbit(SPI2_CR1, 14); // receive
153 while(!rchkbit(SPI2_SR, 0));
154 uint8_t chip_id = *SPI2_DR;
155 printf("COLMOD: %#x\n", chip_id); */
157 rclrbit(SPI2_CR1, 8); // deselect
160 /* Helper function */
161 static int txbuf_empty () {
163 while(!rchkbit(SPI2_SR, 1)) {
166 printf("Error: transmit timeout!\n");
175 /* Function to fill an area starting at (beginx, beginy)
176 * and end ending at (endx, endy */
177 int tft_fill(uint8_t beginx, uint8_t beginy, uint8_t endx,
178 uint8_t endy, uint16_t color) {
180 /* The CASET and RASET commands set the begin X/Y
181 * and end X/Y of the fill area. Both are split over
182 * two paramters/bytes. Most screen are small, so you will
183 * only need to consider the first 8 MSBs. Parameter 1 and
186 * In theory, TFT screens of 65,535 by 65,535 could be
188 tft_command(TFT_CASET, 4, 0x00, beginx, 0x00, endx);
189 tft_command(TFT_RASET, 4, 0x00, beginy, 0x00, endy);
191 /* After setting the fill area, we can send the color
192 * data. The chip autoincrements the address so we can
193 * keep writing continiously for the fill area. Note
194 * that each pixel requires two bytes to be send (16
196 uint32_t totalwrites = (endx - beginx) * (endy - beginy) * 2;
197 //printf("tw: %d, x: %d, y: %d\n", totalwrites, beginx, beginy);
198 tft_command(TFT_RAMWR, 0);
199 rsetbit(GPIOC_ODR, 6); // data = 1
200 for (int i = 0; i < totalwrites; i++) {
201 rwrite(SPI2_DR, (uint8_t) (color >> 8));
204 rwrite(SPI2_DR, (uint8_t) (color & 0xFF));
211 /* Function to individually set a pixel
212 * Refer to tft_fill, similar calls */
213 int tft_setpixel(uint8_t x, uint8_t y, uint16_t color) {
215 tft_command(TFT_CASET, 4, 0x00, x, 0x00, x+1);
216 tft_command(TFT_RASET, 4, 0x00, y, 0x00, y+1);
217 tft_command(TFT_RAMWR, 2, (uint8_t) (color >> 8), (uint8_t) (color & 0xFF));
221 /* Low-level function to print a character to the display
222 * Should not be used directly, since it does not set
224 int tft_putc(uint16_t fg, uint16_t bg, char c) {
227 // Bitmaps are 9 by 8
228 uint8_t databuf[9] = {0x73, 0xFB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDF, 0xDA};
229 //uint8_t databuf[9] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
231 int totalpixels = 72;
236 tft_command(TFT_CASET, 4, 0x00, 10, 0x00, 18);
237 tft_command(TFT_RASET, 4, 0x00, 10, 0x00, 17);
238 tft_command(TFT_RAMWR, 0);
239 rsetbit(GPIOC_ODR, 6); // data = 1
240 for (int i = 0; i < totalpixels; i++) {
242 current = databuf[column];
244 if ((current >> (7 - row)) & 0x1) {
245 rwrite(SPI2_DR, (uint8_t) (fg >> 8));
248 rwrite(SPI2_DR, (uint8_t) (fg & 0xFF));
253 rwrite(SPI2_DR, (uint8_t) (bg >> 8));
256 rwrite(SPI2_DR, (uint8_t) (bg & 0xFF));
261 /* Algoritm dependent on draw mode: top down, left right */
273 int tft_puts(char * str) {
276 //char * string = "root#root#root#root#root#root#root#";
278 //printf("string length: %d\n", strlen(string));
280 //for (int i = 0; i < 35; i++) {
281 for (int i = 0; i < strlen(str); i++) {
283 if (tftscreen.y >= 15) {
287 tft_command(TFT_CASET, 4, 0x00, STARTX + XPOS(tftscreen.x), 0x00, (STARTX + 4) + XPOS(tftscreen.x));
288 tft_command(TFT_RASET, 4, 0x00, STARTY + YPOS(tftscreen.y), 0x00, (STARTY + 6) + YPOS(tftscreen.y));
289 tft_putc_small(0xFFFF, 0x0000, str[i]);
291 tftscreen.buf[tftscreen.cpos] = str[i];
295 if (tftscreen.x > 20) {
299 // if screen.y at end, "scroll" line
309 tftscreen.buf[BUFFER - 21] = '\0';
310 tftscreen.cpos -= 21;
315 /* Text scroll function
316 * Refeed the buffer */
319 /* Scroll the buffer */
320 memcpy(tftscreen.textmemptr, tftscreen.textmemptr + 21, BUFFER - 21);
321 for (int i = 21; i >= 0; i--)
322 tftscreen.buf[BUFFER - 21] = '\0';
324 printf(tftscreen.buf);
331 tft_puts(tftscreen.buf); // CHECK: ending
332 printf("screen.y %d", tftscreen.y);
336 int tft_putc_small(uint16_t fg, uint16_t bg, int c) {
339 // Bitmaps are 5 by 7
340 //uint8_t databuf[5] = {0xF6, 0x92, 0x92, 0x92, 0xDE};
343 int totalpixels = 35;
349 tft_command(TFT_RAMWR, 0);
350 rsetbit(GPIOC_ODR, 6); // data = 1
351 for (int i = 0; i < totalpixels; i++) {
353 current = ASCII5x7[(c * 5) + column];
354 //current = databuf[column];
356 if ((current >> (7 - row)) & 0x1) {
357 rwrite(SPI2_DR, (uint8_t) (fg >> 8));
360 rwrite(SPI2_DR, (uint8_t) (fg & 0xFF));
365 rwrite(SPI2_DR, (uint8_t) (bg >> 8));
368 rwrite(SPI2_DR, (uint8_t) (bg & 0xFF));
373 /* Algoritm dependent on draw mode: top down, left right */
388 /* Invokes commands with a variable list of paramaters. Sending parameters
389 * requires the D/CX line to be high */
390 int tft_command(uint8_t cmd, int argsc, ...) {
394 rclrbit(GPIOC_ODR, 6); // D/CX line low
395 rwrite(SPI2_DR, cmd);
402 rsetbit(GPIOC_ODR, 6); // D/CX line high
403 for (int i = 0; i < argsc; i++) {
404 uint8_t p = (uint8_t) va_arg(ap, unsigned int);