st7735s: bug fix uninitialized value
[cortex-from-scratch] / drivers / st7735s.c
1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
2  * 
3  * $LOG$
4  * 2019/9/14 - ROBIN KRENS      
5  * Initial version 
6  * 
7  * $DESCRIPTION$
8  * 
9  * $USAGE$
10  *
11  * */
12
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <stdarg.h>
17
18 #include <sys/mmap.h>
19 #include <sys/robsys.h>
20
21 #include <lib/regfunc.h>
22 #include <lib/string.h>
23 #include <lib/tinyprintf.h>
24 //#include <lib/fonts/wogfont.h>
25
26 #include <drivers/st7735s.h>
27
28 #define TIMEOUT 500
29 #define SCRWIDTH 132
30 #define SCRHEIGHT 132
31
32 int tft_putc(uint16_t, uint16_t, char);
33 void tft_init() {
34
35         /* Peripherial init */
36         rsetbit(RCC_APB1ENR, 14); // enable SPI2
37         rsetbit(RCC_APB2ENR, 3); // enable GPIOB
38         rsetbit(RCC_APB2ENR, 4); // enable GPIOC
39
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);
48
49         /* Chip select: software enabled
50          * In case for a hardware setup, connect NSS (CS) to 
51          * ground  */
52         rsetbit(SPI2_CR1, 9);
53         rsetbit(SPI2_CR1, 8);
54
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
60
61         /* Init sequence */
62         tft_command(TFT_SWRESET, 0);
63         _block(120000); 
64         tft_command(0x11, 0);
65         _block(120000); 
66
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);        
71
72         /* Power control */
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);
79
80         tft_command(TFT_INVOFF, 0);
81         tft_command(TFT_COLMOD, 1, 0x05); // 0x05
82         tft_command(TFT_MADCTL, 1, 0xC0); // TODO: check
83
84         tft_command(TFT_CASET, 4, 0x00, 0x00, 0x00, 0x7F);
85         tft_command(TFT_RASET, 4, 0x00, 0x00, 0x00, 0x9F);
86
87         /* Gamma Settings */
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);
96
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');
102         
103         /* Turn on */
104         tft_command(TFT_NORON, 0);
105         _block(10000);
106         tft_command(TFT_DISPON, 0);
107         _block(100000);
108
109
110         /* //_block(10000); 
111
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);
115
116         //tft_command(0x0C, 0);
117         //tft_command(0x0A, 0);
118         
119         rclrbit(SPI2_CR1, 14); // receive
120
121         while(!rchkbit(SPI2_SR, 0));
122         uint8_t chip_id = *SPI2_DR;
123         printf("COLMOD: %#x\n", chip_id); */
124
125         rclrbit(SPI2_CR1, 8); // deselect
126 }
127
128 /* Helper function */
129 static int txbuf_empty () {
130         int cnt = 0;
131         while(!rchkbit(SPI2_SR, 1)) {
132                 cnt++;
133                 if (cnt > TIMEOUT) {
134                         printf("Error: transmit timeout!\n");
135                         return 0;
136                 }
137         }
138         return 1;
139
140 }
141
142
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) {
147
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 
152          * 3 are always 0. 
153          *
154          * In theory, TFT screens of 65,535 by 65,535 could be
155          * supported */
156         tft_command(TFT_CASET, 4, 0x00, beginx, 0x00, endx);
157         tft_command(TFT_RASET, 4, 0x00, beginy, 0x00, endy);
158
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 
163          * bit mode: ...)   */
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));
170                         if (!txbuf_empty())
171                                 return -1;
172                         rwrite(SPI2_DR, (uint8_t) (color & 0xFF));
173                         if (!txbuf_empty())
174                                 return -1;
175         }
176         return 0;
177 }
178
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) {
182
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));
186         return 0;
187 }
188
189 /* Low-level function to print a character to the display
190  * Should not be used directly, since it does not set
191  * the location */
192 int tft_putc(uint16_t fg, uint16_t bg, char c) {
193
194         //chipselect();
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};
198         
199         int totalpixels = 72;
200         int column = 0;
201         int row = 0;
202         uint8_t current;
203
204         tft_command(TFT_CASET, 4, 0x00, 10, 0x00, 18);
205         tft_command(TFT_RASET, 4, 0x00, 10, 0x00, 17);
206         tft_command(TFT_RAMWR, 0);
207         rsetbit(GPIOC_ODR, 6); // data = 1      
208         for (int i = 0; i < totalpixels; i++) {
209                 
210                 current = databuf[column];
211
212                 if ((current >> (7 - row)) & 0x1) {
213                         rwrite(SPI2_DR, (uint8_t) (fg >> 8));
214                         if (!txbuf_empty())
215                                 return -1;
216                         rwrite(SPI2_DR, (uint8_t) (fg & 0xFF));
217                         if (!txbuf_empty())
218                                 return -1;
219                 }
220                 else {
221                         rwrite(SPI2_DR, (uint8_t) (bg >> 8));
222                         if (!txbuf_empty())
223                                 return -1;
224                         rwrite(SPI2_DR, (uint8_t) (bg & 0xFF));
225                         if (!txbuf_empty())
226                                 return -1;
227                 }
228
229                 /* Algoritm dependent on draw mode: top down, left right */
230                 column++;
231                 if (column > 8) {
232                         column = 0;
233                         row++;  
234                 }
235         }
236         return 0;
237         // lookup table
238 }
239
240
241 /* Invokes commands with a variable list of paramaters. Sending parameters
242  * requires the D/CX line to be high  */
243 int tft_command(uint8_t cmd, int argsc, ...) {
244
245         va_list ap;
246         // command
247         rclrbit(GPIOC_ODR, 6); // D/CX line low
248         rwrite(SPI2_DR, cmd);
249         if (!txbuf_empty()) 
250                 return -1;
251
252         // parameter or data
253         if (argsc > 0) {
254                 va_start(ap, argsc);
255                 rsetbit(GPIOC_ODR, 6); // D/CX line high        
256                 for (int i = 0; i < argsc; i++) {
257                         uint8_t p = (uint8_t) va_arg(ap, unsigned int);
258                         rwrite(SPI2_DR, p);
259                         if (!txbuf_empty())
260                                 return -1;
261                 }
262                 va_end(ap);
263         }
264         return 0;
265 }       
266