1 /*
2  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
3  * Copyright (c) 2014 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <iostream>
26 #include <string>
27 #include <stdexcept>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "st7735.h"
34 
35 using namespace upm;
36 
ST7735(uint8_t csLCD,uint8_t cSD,uint8_t rs,uint8_t rst)37 ST7735::ST7735 (uint8_t csLCD, uint8_t cSD, uint8_t rs, uint8_t rst)
38     : GFX (160, 128, m_map, font), m_csLCDPinCtx(csLCD), m_cSDPinCtx(cSD),
39       m_rSTPinCtx(rst), m_rSPinCtx(rs), m_spi(0) {
40 
41       initModule ();
42     configModule ();
43 }
44 
45 void
initModule()46 ST7735::initModule () {
47     mraa::Result error = mraa::SUCCESS;
48 
49     m_height = 160;
50     m_width  = 128;
51 
52     m_spi.frequency(15 * 1000000);
53 
54     error = m_csLCDPinCtx.dir(mraa::DIR_OUT);
55     if (error != mraa::SUCCESS) {
56         mraa::printError (error);
57     }
58 
59     error = m_cSDPinCtx.dir(mraa::DIR_OUT);
60     if (error != mraa::SUCCESS) {
61         mraa::printError (error);
62     }
63 
64     error = m_rSTPinCtx.dir(mraa::DIR_OUT);
65     if (error != mraa::SUCCESS) {
66         mraa::printError (error);
67     }
68 
69     error = m_rSPinCtx.dir(mraa::DIR_OUT);
70     if (error != mraa::SUCCESS) {
71         mraa::printError (error);
72     }
73 
74     error = m_spi.frequency(15 * 1000000);
75     if (error != mraa::SUCCESS) {
76         mraa::printError (error);
77     }
78 
79     lcdCSOn ();
80 }
81 
82 void
write(uint8_t value)83 ST7735::write (uint8_t value) {
84     rsLOW ();
85     m_spi.writeByte(value);
86 }
87 
88 void
data(uint8_t value)89 ST7735::data (uint8_t value) {
90     rsHIGH ();
91     m_spi.writeByte(value);
92 }
93 
94 void
executeCMDList(const uint8_t * addr)95 ST7735::executeCMDList(const uint8_t *addr) {
96     uint8_t  numCommands, numArgs;
97     uint16_t ms;
98 
99     numCommands = *(addr++);           // Number of commands to follow
100     while(numCommands--) {             // For each command...
101         write (*(addr++));             // Read, issue command
102         numArgs  = *(addr++);          // Number of args to follow
103         ms       = numArgs & DELAY;    // If hibit set, delay follows args
104         numArgs &= ~DELAY;             // Mask out delay bit
105         while(numArgs--) {             // For each argument...
106             data (*(addr++));          // Read, issue argument
107         }
108 
109         if(ms) {
110             ms = *(addr++);            // Read post-command delay time (ms)
111             if (ms == 255) {
112                 ms = 500;              // If 255, delay for 500 ms
113             }
114             usleep (ms * 1000);
115         }
116     }
117 }
118 
119 void
setAddrWindow(uint8_t x0,uint8_t y0,uint8_t x1,uint8_t y1)120 ST7735::setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
121     uint8_t colstart, rowstart;
122     colstart  = rowstart = 0;
123 
124     write (ST7735_CASET);                       // Column addr set
125 
126     rsHIGH ();
127     m_spiBuffer[0] = 0x00;
128     m_spiBuffer[1] = x0 + colstart;             // XSTART
129     m_spiBuffer[2] = 0x00;
130     m_spiBuffer[3] = x1 + colstart;             // XEND
131     m_spi.write(m_spiBuffer, 4);
132 
133     write (ST7735_RASET);                       // Row addr set
134 
135     rsHIGH ();
136     m_spiBuffer[0] = 0x00;
137     m_spiBuffer[1] = y0 + rowstart;             // YSTART
138     m_spiBuffer[2] = 0x00;
139     m_spiBuffer[3] = y1 + rowstart;             // YEND
140     m_spi.write(m_spiBuffer, 4);
141 
142     write (ST7735_RAMWR);                       // write to RAM
143 }
144 
145 void
drawPixel(int16_t x,int16_t y,uint16_t color)146 ST7735::drawPixel(int16_t x, int16_t y, uint16_t color) {
147     if (mraa::SUCCESS != setPixel (x, y, color)) {
148         return;
149     }
150 
151     refresh ();
152 }
153 
154 void
refresh()155 ST7735::refresh () {
156     rsHIGH ();
157 
158     int fragmentSize = m_height * m_width * 2 / 20;
159     for (int fragment = 0; fragment < 20; fragment++) {
160         m_spi.write(&m_map[fragment * fragmentSize], fragmentSize);
161     }
162 }
163 
164 void
configModule()165 ST7735::configModule() {
166     rsHIGH ();
167     lcdCSOff ();
168     lcdCSOn ();
169 
170     m_rSTPinCtx.write(HIGH);
171     usleep (500000);
172     m_rSTPinCtx.write(LOW);
173     usleep (500000);
174     m_rSTPinCtx.write(HIGH);
175     usleep (500000);
176 
177     executeCMDList (Rcmd1);
178     executeCMDList (Rcmd2red);
179     executeCMDList (Rcmd3);
180 
181     write (ST7735_MADCTL);
182     data (0xC0);
183 
184     setAddrWindow (0, 0, m_width - 1, m_height - 1);
185 
186     fillScreen (ST7735_BLACK);
187     refresh ();
188 }
189 
190 mraa::Result
lcdCSOn()191 ST7735::lcdCSOn () {
192     mraa::Result error = mraa::SUCCESS;
193 
194     error = m_csLCDPinCtx.write(LOW);
195     if (error != mraa::SUCCESS) {
196         mraa::printError (error);
197     }
198 
199     error = m_cSDPinCtx.write(HIGH);
200     if (error != mraa::SUCCESS) {
201         mraa::printError (error);
202     }
203 
204     return error;
205 }
206 
207 mraa::Result
lcdCSOff()208 ST7735::lcdCSOff () {
209     mraa::Result error = mraa::SUCCESS;
210 
211     error = m_csLCDPinCtx.write(HIGH);
212     if (error != mraa::SUCCESS) {
213         mraa::printError (error);
214     }
215 
216     return error;
217 }
218 
219 mraa::Result
sdCSOn()220 ST7735::sdCSOn () {
221     mraa::Result error = mraa::SUCCESS;
222 
223     error = m_cSDPinCtx.write(LOW);
224     if (error != mraa::SUCCESS) {
225         mraa::printError (error);
226     }
227 
228     error = m_csLCDPinCtx.write(HIGH);
229     if (error != mraa::SUCCESS) {
230         mraa::printError (error);
231     }
232 
233     return error;
234 }
235 
236 mraa::Result
sdCSOff()237 ST7735::sdCSOff () {
238     mraa::Result error = mraa::SUCCESS;
239 
240     error = m_cSDPinCtx.write(HIGH);
241     if (error != mraa::SUCCESS) {
242         mraa::printError (error);
243     }
244 
245     return error;
246 }
247 
248 mraa::Result
rsHIGH()249 ST7735::rsHIGH () {
250     mraa::Result error = mraa::SUCCESS;
251 
252     error = m_rSPinCtx.write(HIGH);
253     if (error != mraa::SUCCESS) {
254         mraa::printError (error);
255     }
256 
257     return error;
258 }
259 
260 mraa::Result
rsLOW()261 ST7735::rsLOW () {
262     mraa::Result error = mraa::SUCCESS;
263 
264     error = m_rSPinCtx.write(LOW);
265     if (error != mraa::SUCCESS) {
266         mraa::printError (error);
267     }
268 
269     return error;
270 }
271