You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
7.5 KiB

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <stdlib.h>
  4. #include "st7735.h"
  5. #include "font8x8_basic.h"
  6. /********************************** EASY PORT *********************************/
  7. /*
  8. * If you porting this code, you can change below headers and function pointers
  9. * in gpio structure.
  10. */
  11. #include <wiringPi.h>
  12. #include <wiringPiSPI.h>
  13. struct
  14. {
  15. void (* const delay)(unsigned int milliseconds);
  16. void (* const pinMode)(int pin, int mode);
  17. void (* const digitalWrite)(int pin, int value);
  18. int (* const spiSetup)(int channel, int speed);
  19. int (* const spiDataRW)(int channel, uint8 *data, int length);
  20. } static const gpio =
  21. {
  22. delay,
  23. pinMode,
  24. digitalWrite,
  25. wiringPiSPISetup,
  26. wiringPiSPIDataRW
  27. };
  28. /****************************** END EASY PORT END *****************************/
  29. /* The global variable that stores the pointer to the structure,
  30. * with the current active display.
  31. */
  32. static lcd_t *activeDisplay;
  33. /*
  34. * Safe allocation of the memory block.
  35. *
  36. * Parameters:
  37. * size - Size of memory block to allocate.
  38. *
  39. * Return:
  40. * Pointer to the memory block. If an error occurs, stop the program.
  41. */
  42. static inline void *safeMalloc(size_t size)
  43. {
  44. void *memoryBlock = (void*) malloc(size);
  45. /* Check the pointer */
  46. if(memoryBlock == NULL)
  47. {
  48. fprintf(stderr, "Out of RAM memory!\n");
  49. exit(EXIT_FAILURE);
  50. }
  51. return memoryBlock;
  52. } /* safeMalloc */
  53. void lcd_setOrientation(uint8 orientation);
  54. void lcd_setGamma(uint8 state);
  55. void lcd_pushPx(uint8 r, uint8 g, uint8 b);
  56. void lcd_pushPixels(uint8* pixels, size_t count);
  57. void lcd_pushChar(char c);
  58. /*
  59. * Write the command to the display driver.
  60. *
  61. * Parameters:
  62. * cmd - The command to write.
  63. */
  64. static inline void writeCommand(uint8 cmd)
  65. {
  66. gpio.digitalWrite(activeDisplay->a0, LOW);
  67. gpio.spiDataRW(activeDisplay->cs, &cmd, 1);
  68. } /* writeCommand */
  69. /*
  70. * Write the data to the display driver.
  71. *
  72. * Parameters:
  73. * data - The data to write.
  74. */
  75. static inline void writeData(uint8 data)
  76. {
  77. gpio.digitalWrite(activeDisplay->a0, HIGH);
  78. gpio.spiDataRW(activeDisplay->cs, &data, 1);
  79. } /* writeData */
  80. lcd_t *lcd_init(int spiSpeed, int cs, int a0, int rs)
  81. {
  82. /* Create the one instance of the lcdst_t structure and activate it */
  83. lcd_t *instance = (lcd_t *) safeMalloc(sizeof(lcd_t));
  84. activeDisplay = instance;
  85. /* Assign specific pins */
  86. instance->cs = cs;
  87. instance->a0 = a0;
  88. instance->rs = rs;
  89. /*
  90. * instance->width; instance->height
  91. * The setting of this variables will take place
  92. * in the function lcdst_setOrientation() below.
  93. */
  94. /* Configure the a0 pin. The logic level is not significant now. */
  95. gpio.pinMode(instance->a0, OUTPUT);
  96. /* If the rs pin is connected then configure it */
  97. if(instance->rs != -1)
  98. {
  99. gpio.pinMode(instance->rs, OUTPUT);
  100. gpio.digitalWrite(instance->rs, HIGH); /* Reset OFF */
  101. gpio.delay(10);
  102. }
  103. /* Configure the SPI interface */
  104. if(gpio.spiSetup(instance->cs, spiSpeed) == -1)
  105. {
  106. fprintf(stderr, "Failed to setup the SPI interface!\n");
  107. exit(EXIT_FAILURE);
  108. }
  109. /* Software reset; Wait minimum 120ms */
  110. writeCommand(0x01);
  111. gpio.delay(150);
  112. /* Sleep out; Wait minimum 120ms */
  113. writeCommand(0x11);
  114. gpio.delay(150);
  115. /* Set the orientation and the gamma */
  116. lcd_setOrientation(0);
  117. lcd_setGamma(2); /* Optional */
  118. /* Set the pixel format */
  119. writeCommand(0x3A);
  120. writeData(0x06);
  121. /* Display ON; Wait 100ms before start */
  122. writeCommand(0x29);
  123. gpio.delay(100);
  124. return instance;
  125. } /* lcd_init */
  126. void lcd_deinit(lcd_t *display)
  127. {
  128. if(display == NULL) return;
  129. free(display);
  130. } /* lcdst_uninit */
  131. void lcd_setOrientation(uint8 orientation)
  132. {
  133. writeCommand(0x36); /* Memory Data Access Control */
  134. switch(orientation)
  135. {
  136. case 1:
  137. writeData(0x60); /* MX + MV */
  138. activeDisplay->width = 160;
  139. activeDisplay->height = 128;
  140. lcd_setWindow(0, 0, 159, 127);
  141. break;
  142. case 2:
  143. writeData(0xC0); /* MY + MX */
  144. activeDisplay->width = 128;
  145. activeDisplay->height = 160;
  146. lcd_setWindow(0, 0, 127, 159);
  147. break;
  148. case 3:
  149. writeData(0xA0); /* MY + MV */
  150. activeDisplay->width = 160;
  151. activeDisplay->height = 128;
  152. lcd_setWindow(0, 0, 159, 127);
  153. break;
  154. default:
  155. writeData(0x00); /* None */
  156. activeDisplay->width = 128;
  157. activeDisplay->height = 160;
  158. lcd_setWindow(0, 0, 127, 159);
  159. break;
  160. }
  161. } /* lcdst_setOrientation */
  162. void lcd_setGamma(uint8 state)
  163. {
  164. /* The status (0 or 1) of the GS pin can only be empirically tested */
  165. switch(state)
  166. {
  167. case 1: state = 2; break; /* GS_pin=1: 1.8; GS_pin=0: 2.5 */
  168. case 2: state = 4; break; /* GS_pin=1: 2.5; GS_pin=0: 2.2 */
  169. case 3: state = 8; break; /* GS_pin=1: 1.0; GS_pin=0: 1.8 */
  170. default: state = 1; break; /* GS_pin=1: 2.2; GS_pin=0: 1.0 */
  171. }
  172. /* Set built-in gamma */
  173. writeCommand(0x26);
  174. writeData(state);
  175. } /* lcdst_setGamma */
  176. void lcd_setInversion(uint8 state)
  177. {
  178. /* Display inversion ON/OFF */
  179. writeCommand(state ? 0x21 : 0x20);
  180. } /* lcdst_setInversion */
  181. uint8 lcd_setWindow(uint8 x1, uint8 y1, uint8 x2, uint8 y2)
  182. {
  183. /* Accept: 0 <= x1 <= x2 < activeDisplay->width */
  184. if(x2 < x1) return 1;
  185. if(x2 >= activeDisplay->width) return 1;
  186. /* Accept: 0 <= y1 <= y2 < activeDisplay->height */
  187. if(y2 < y1) return 1;
  188. if(y2 >= activeDisplay->height) return 1;
  189. /* Set column address */
  190. writeCommand(0x2A);
  191. writeData(0); writeData(x1);
  192. writeData(0); writeData(x2);
  193. /* Set row address */
  194. writeCommand(0x2B);
  195. writeData(0); writeData(y1);
  196. writeData(0); writeData(y2);
  197. /* Activate RAW write */
  198. writeCommand(0x2C);
  199. //gpio.delay(5);
  200. return 0;
  201. } /* lcdst_setWindow */
  202. void lcd_activateRamWrite(void)
  203. {
  204. writeCommand(0x2C);
  205. //gpio.delay(5);
  206. } /* lcdst_activateRamWrite */
  207. uint8 pixel[3];
  208. inline void lcd_pushPx(uint8 r, uint8 g, uint8 b)
  209. {
  210. gpio.digitalWrite(activeDisplay->a0, HIGH);
  211. pixel[0] = r;
  212. pixel[1] = g;
  213. pixel[2] = b;
  214. gpio.spiDataRW(activeDisplay->cs, pixel, 3);
  215. } /* lcdst_pushPx */
  216. void lcd_pushPixels(uint8* pixels, size_t count)
  217. {
  218. gpio.digitalWrite(activeDisplay->a0, HIGH);
  219. gpio.spiDataRW(activeDisplay->cs, pixels, count * 3);
  220. }
  221. void lcd_drawPx(uint8 x, uint8 y, uint8 r, uint8 g, uint8 b)
  222. {
  223. if(lcd_setWindow(x, y, x, y)) return;
  224. lcd_pushPx(r, g, b);
  225. } /* lcdst_drawPx */
  226. void lcd_fillRect(uint8 x, uint8 y, uint8 w, uint8 h,
  227. uint8 r, uint8 g, uint8 b)
  228. {
  229. /* Draw only in the display space */
  230. if((w == 0) || (h == 0)) return;
  231. if((x+w-1) >= activeDisplay->width) w = activeDisplay->width - x;
  232. if((y+h-1) >= activeDisplay->height) h = activeDisplay->height - y;
  233. /* Draw the filled rectangle */
  234. if(lcd_setWindow(x, y, x+w-1, y+h-1)) return;
  235. #define BUFFER_PIXELS 64
  236. int wh = w*h;
  237. uint8 buffer[BUFFER_PIXELS * sizeof(uint8) * 3];
  238. for (int p = 0; p < wh; p += BUFFER_PIXELS) {
  239. for(int pb = 0; pb < BUFFER_PIXELS; pb++) {
  240. buffer[pb * 3 + 0] = r;
  241. buffer[pb * 3 + 1] = g;
  242. buffer[pb * 3 + 2] = b;
  243. }
  244. int rem = wh - p;
  245. lcd_pushPixels(buffer, ((rem < BUFFER_PIXELS) ? rem : BUFFER_PIXELS));
  246. }
  247. }
  248. void lcd_fillScreen(uint8 r, uint8 g, uint8 b)
  249. {
  250. /* Fill the whole screen with one color */
  251. lcd_fillRect(0, 0, activeDisplay->width, activeDisplay->height, r, g, b);
  252. } /* lcdst_drawScreen */
  253. void lcd_pushChar(char c)
  254. {
  255. char* bitmap = font8x8_basic[(unsigned int) c];
  256. int x,y;
  257. int set;
  258. int mask;
  259. for (x=0; x < 8; x++) {
  260. for (y=0; y < 8; y++) {
  261. set = bitmap[x] & 1 << y;
  262. printf("%c", set ? 'X' : ' ');
  263. if (set) {
  264. lcd_pushPx(200, 0, 0);
  265. } else {
  266. lcd_pushPx(0, 0, 0);
  267. }
  268. }
  269. printf("\n");
  270. }
  271. }
  272. void lcd_printChar(uint8 x, uint8 y, char c)
  273. {
  274. lcd_setWindow(x, y, x+8 - 1, y+8 - 1);
  275. lcd_pushChar(c);
  276. }
  277. void lcd_printText(uint8 x, uint8 y, char* text)
  278. {
  279. for (int i = 0; i < strlen(text); i++) {
  280. lcd_printChar(x + i * 8, y, text[i]);
  281. }
  282. }