lcd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <sys/mman.h>
  7. #include <sys/ioctl.h>
  8. #include <linux/fb.h>
  9. #include <linux/spi/spidev.h>
  10. #include "gpio.h"
  11. #include "lcd.h"
  12. #include "elog.h"
  13. //#define USE_FB
  14. #if 1
  15. #define LOGD log_d
  16. #define LOGE log_e
  17. #else
  18. #define LOGD printf
  19. #define LOGE printf
  20. #endif
  21. #define BIT(x) (1<<x)
  22. #define SWAP16(a) ((uint16_t)((a<<8)|(a>>8)))
  23. #ifdef USE_FB
  24. #define DEV_PATH "/dev/fb0"
  25. typedef struct fb_fix_screeninfo fb_finfo_t;
  26. typedef struct fb_var_screeninfo fb_vinfo_t;
  27. #else
  28. #define DEV_PATH "/dev/spidev1.0"
  29. #define DC_GPIO 99 //PD3, 96+3=99
  30. #define RST_GPIO 100 //PD4, 96+4=100
  31. #endif
  32. typedef struct {
  33. int x;
  34. int y;
  35. int w;
  36. int h;
  37. }lcd_rect_t;
  38. typedef struct {
  39. int width;
  40. int height;
  41. int color;
  42. int fd;
  43. #ifdef USE_FB
  44. uint16_t *buf;
  45. #else
  46. int io;
  47. uint8_t *buf;
  48. #endif
  49. int buflen;
  50. }lcd_handle_t;
  51. static lcd_handle_t lcdHandle={0};
  52. static int ssd1309_init(lcd_handle_t *h);
  53. static void ssd1309_refresh(lcd_handle_t *h);
  54. static int lcd_hw_init(lcd_handle_t *h)
  55. {
  56. h->fd = open(DEV_PATH, O_RDWR);
  57. if (h->fd < 0) {
  58. LOGE("___ open %s failed\n", DEV_PATH);
  59. return -1;
  60. }
  61. #ifdef USE_FB
  62. fb_vinfo_t vinfo;
  63. if (ioctl(h->fd, FBIOGET_VSCREENINFO, &vinfo)) {
  64. LOGE("___ get screen info failed\n");
  65. return -1;
  66. }
  67. h->buflen = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
  68. h->buf = (uint16_t *)mmap(0, h->buflen, PROT_READ | PROT_WRITE, MAP_SHARED, h->fd, 0);
  69. if ((int)h->buf == -1) {
  70. LOGE("Error: failed to map framebuffer device to memory\n");
  71. return -1;
  72. }
  73. #else
  74. h->io = gpio_init(DC_GPIO, GPIO_OUT);
  75. h->buflen = h->width*h->height/8;
  76. h->buf = (uint8_t*)calloc(1, h->buflen);
  77. if (!h->buf) {
  78. LOGE("malloc buffer falied\n");
  79. return -1;
  80. }
  81. #if 0
  82. uint8_t mode = SPI_MODE_0;
  83. if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
  84. LOGE("Can't set SPI mode\n");
  85. return -1;
  86. }
  87. uint32_t speed = 8000000;
  88. if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
  89. LOGE("Can't set max speed\n");
  90. return -1;
  91. }
  92. #endif
  93. ssd1309_init(h);
  94. #endif
  95. return 0;
  96. }
  97. static int lcd_hw_write(lcd_handle_t *h, void *data, int len)
  98. {
  99. int r;
  100. struct spi_ioc_transfer tr = {
  101. .tx_buf = (unsigned long)data,
  102. .rx_buf = 0,
  103. .len = len,
  104. .speed_hz = 8000000,
  105. .bits_per_word = 8,
  106. };
  107. r = ioctl(h->fd, SPI_IOC_MESSAGE(1), &tr);
  108. if (r < 1) {
  109. LOGE("Can't send spi message");
  110. }
  111. return 0;
  112. }
  113. static void lcd_write_reg(lcd_handle_t *h, uint8_t reg)
  114. {
  115. gpio_set(h->io, 0);
  116. lcd_hw_write(h, &reg, 1);
  117. }
  118. static int ssd1309_reset(void)
  119. {
  120. int fd = gpio_init(RST_GPIO, GPIO_OUT);
  121. gpio_set(fd, 0);
  122. usleep(100*1000);
  123. gpio_set(fd, 1);
  124. gpio_deinit(fd);
  125. return 0;
  126. }
  127. static void ssd1309_on(lcd_handle_t *h, int flag)
  128. {
  129. if(flag) {
  130. lcd_write_reg(h,0x8D);
  131. lcd_write_reg(h,0x14);
  132. lcd_write_reg(h,0xAF);
  133. }
  134. else {
  135. lcd_write_reg(h,0x8D);
  136. lcd_write_reg(h,0x10);
  137. lcd_write_reg(h,0xAE);
  138. }
  139. }
  140. static int ssd1309_init(lcd_handle_t *h)
  141. {
  142. ssd1309_reset();
  143. lcd_write_reg(h,0xFD);
  144. lcd_write_reg(h,0x12);
  145. lcd_write_reg(h,0xAE);//--turn off oled panel
  146. lcd_write_reg(h,0xd5);//--set display clock divide ratio/oscillator frequency
  147. lcd_write_reg(h,0xA0);
  148. lcd_write_reg(h,0xA8);//--set multiplex ratio(1 to 64)
  149. lcd_write_reg(h,0x3f);//--1/64 duty
  150. lcd_write_reg(h,0xD3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
  151. lcd_write_reg(h,0x00);//-not offset
  152. lcd_write_reg(h,0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
  153. lcd_write_reg(h,0xA1);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
  154. lcd_write_reg(h,0xC8);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
  155. lcd_write_reg(h,0xDA);//--set com pins hardware configuration
  156. lcd_write_reg(h,0x12);
  157. lcd_write_reg(h,0x81);//--set contrast control register
  158. lcd_write_reg(h,0x7F);// Set SEG Output Current Brightness
  159. lcd_write_reg(h,0xD9);//--set pre-charge period
  160. lcd_write_reg(h,0x82);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
  161. lcd_write_reg(h,0xDB);//--set vcomh
  162. lcd_write_reg(h,0x34);//Set VCOM Deselect Level
  163. lcd_write_reg(h,0xA4);// Disable Entire Display On (0xa4/0xa5)
  164. lcd_write_reg(h,0xA6);// Disable Inverse Display On (0xa6/a7)
  165. ssd1309_refresh(h);
  166. ssd1309_on(h,1);
  167. return 0;
  168. }
  169. static void ssd1309_refresh(lcd_handle_t *h)
  170. {
  171. int i,n,offset;
  172. for(i=0;i<8;i++) {
  173. lcd_write_reg(h,0xb0+i); //设置行起始地址
  174. lcd_write_reg(h,0x00); //设置低列起始地址
  175. lcd_write_reg(h,0x10); //设置高列起始地址
  176. gpio_set(h->io, 1);
  177. offset = i*128;
  178. for(n=0;n<128;n++) {
  179. lcd_hw_write(h, &h->buf[offset+n], 1);
  180. }
  181. }
  182. }
  183. static int lcd_hw_deinit(lcd_handle_t *h)
  184. {
  185. #ifdef USE_FB
  186. munmap(h->buf, h->buflen);
  187. #else
  188. gpio_deinit(h->io);
  189. free(h->buf);
  190. #endif
  191. close(h->fd);
  192. return 0;
  193. }
  194. static inline int set_point(lcd_handle_t *h, int x, int y, int data)
  195. {
  196. #ifdef USE_FB
  197. h->buf[y*h->width+x] = (uint16_t)data;
  198. #else
  199. uint8_t pos,bit;
  200. pos = y / 8; /* get y page */
  201. bit = y % 8; /* get y point */
  202. if (data) { /* if 1 */
  203. h->buf[pos*h->width+x] |= BIT(bit); /* set 1 */
  204. }
  205. else {
  206. h->buf[pos*h->width+x] &= ~BIT(bit); /* set 0 */
  207. }
  208. #endif
  209. return 0;
  210. }
  211. static int get_color_bits(int color)
  212. {
  213. if(color==COLOR_WB) {
  214. return 1;
  215. }
  216. else if(color==COLOR_RGB8) {
  217. return 8;
  218. }
  219. else if(color==COLOR_RGB565) {
  220. return 16;
  221. }
  222. else {
  223. return 32;
  224. }
  225. }
  226. ////////////////////////////////////////////////////////////
  227. void lcd_init(int width, int height, int color)
  228. {
  229. lcd_handle_t *h=&lcdHandle;
  230. h->width = width;
  231. h->height = height;
  232. h->color = color;
  233. lcd_hw_init(h);
  234. }
  235. void lcd_deinit(void)
  236. {
  237. lcd_handle_t *h=&lcdHandle;
  238. lcd_hw_deinit(h);
  239. }
  240. void lcd_rotate(int angle)
  241. {
  242. lcd_handle_t *h=&lcdHandle;
  243. }
  244. void lcd_set_backlight(int on)
  245. {
  246. lcd_handle_t *h=&lcdHandle;
  247. }
  248. void lcd_fill(int color)
  249. {
  250. lcd_handle_t *h=&lcdHandle;
  251. lcd_fill_rect(0, 0, h->width-1, h->height-1, color);
  252. }
  253. void lcd_draw_line(int x1, int y1, int x2, int y2, int color)
  254. {
  255. int incx = 0, incy = 0;
  256. int delta_x = 0, delta_y = 0;
  257. int distance = 0;
  258. int t = 0;
  259. int x = 0, y = 0;
  260. int x_temp = 0, y_temp = 0;
  261. lcd_handle_t *h=&lcdHandle;
  262. /* 画斜线(Bresenham算法) */
  263. delta_x = x2 - x1;
  264. delta_y = y2 - y1;
  265. if(delta_x > 0) {
  266. //斜线(从左到右)
  267. incx = 1;
  268. }
  269. else if(delta_x == 0) {
  270. //垂直斜线(竖线)
  271. incx = 0;
  272. }
  273. else {
  274. //斜线(从右到左)
  275. incx = -1;
  276. delta_x = -delta_x;
  277. }
  278. if(delta_y > 0) {
  279. //斜线(从左到右)
  280. incy = 1;
  281. }
  282. else if(delta_y == 0) {
  283. //水平斜线(水平线)
  284. incy = 0;
  285. }
  286. else {
  287. //斜线(从右到左)
  288. incy = -1;
  289. delta_y = -delta_y;
  290. }
  291. /* 计算画笔打点距离(取两个间距中的最大值) */
  292. if(delta_x > delta_y) {
  293. distance = delta_x;
  294. }
  295. else {
  296. distance = delta_y;
  297. }
  298. /* 开始打点 */
  299. x = x1;
  300. y = y1;
  301. //第一个点无效,所以t的次数加一
  302. for(t = 0; t <= distance + 1;t++) {
  303. set_point(h, x, y, color);
  304. /* 判断离实际值最近的像素点 */
  305. x_temp += delta_x;
  306. if(x_temp > distance) {
  307. //x方向越界,减去距离值,为下一次检测做准备
  308. x_temp -= distance;
  309. //在x方向递增打点
  310. x += incx;
  311. }
  312. y_temp += delta_y;
  313. if(y_temp > distance) {
  314. //y方向越界,减去距离值,为下一次检测做准备
  315. y_temp -= distance;
  316. //在y方向递增打点
  317. y += incy;
  318. }
  319. }
  320. }
  321. void lcd_draw_rect(int x, int y, int w, int h, int color)
  322. {
  323. int x2,y2;
  324. x2 = x + w;
  325. y2 = y + h;
  326. lcd_draw_line(x,y,x2,y,color);
  327. lcd_draw_line(x,y,x,y2,color);
  328. lcd_draw_line(x,y2,x2,y2,color);
  329. lcd_draw_line(x,y,x2,y2,color);
  330. }
  331. void lcd_fill_rect(int x, int y, int w, int h, int color)
  332. {
  333. int i,j;
  334. lcd_handle_t *h2=&lcdHandle;
  335. for(i=x; i<x+w; i++) {
  336. for(j=y; j<y+h; j++) {
  337. set_point(h2, i, j, color);
  338. }
  339. }
  340. }
  341. void lcd_refresh(void)
  342. {
  343. lcd_handle_t *h=&lcdHandle;
  344. #ifndef USE_FB
  345. ssd1309_refresh(h);
  346. #endif
  347. }
  348. void lcd_draw_char(lcd_handle_t *hd, int x, int y, int w, int h, int c, int font, int color, int bgcolor)
  349. {
  350. uint8_t tmp;
  351. font_data_t fdata;
  352. font_info_t finfo=font_info(font);
  353. int i,j,x0=x,y0=y,x1=x+w,y1=y+h;
  354. fdata = font_data(font, c);
  355. for(i=0; i<fdata.dlen; i++) { /*遍历打印所有像素点到LCD */
  356. tmp = fdata.data[i];
  357. for(j=0; j<8; j++) {
  358. //if((x<x1 && x<hd->width) && (y<y1 && y<hd->height))
  359. {
  360. if(tmp&0x01) {
  361. set_point(hd, x, y, color);
  362. }
  363. else {
  364. set_point(hd, x, y, bgcolor);
  365. }
  366. }
  367. tmp >>= 1;
  368. y++;
  369. }
  370. #if 0
  371. if((y-y0)>=finfo.height) {
  372. x++;
  373. y = y0;
  374. }
  375. #else
  376. x++;
  377. if((font!=FONT_0806) && ((x-x0)>=finfo.width)) {
  378. x = x0;
  379. y0 += 8;
  380. }
  381. y = y0;
  382. #endif
  383. }
  384. }
  385. static void draw_string(lcd_handle_t *hd, int x, int y, int w, int h, char *str, int font, int color, int bgcolor)
  386. {
  387. char *pstr=str;
  388. int xmax,ymax,w2;
  389. font_info_t finfo=font_info(font);
  390. w2 = finfo.width;
  391. xmax = x+w; ymax = y+h;
  392. while((*pstr<='~') && (*pstr>=' ')) { /* 判断是不是非法字符! */
  393. if(x >= xmax) {
  394. break;
  395. }
  396. if(x+finfo.width>=xmax) {
  397. w2 = xmax-x;
  398. }
  399. lcd_draw_char(hd, x, y, w2, h, *pstr, font, color, bgcolor);
  400. x += finfo.width;
  401. pstr++;
  402. }
  403. }
  404. void lcd_draw_string(int x, int y, int w, int h, char *str, int font, int color, int bgcolor, int hori, int vert)
  405. {
  406. int sw;
  407. lcd_rect_t rect;
  408. lcd_handle_t *h2=&lcdHandle;
  409. font_info_t finfo=font_info(font);
  410. sw = strlen((char*)str)*finfo.width;
  411. if(sw>w) {
  412. sw = w;
  413. }
  414. if(hori==HORIZONTAL_LEFT) {
  415. rect.x = x;
  416. }
  417. else if(hori==HORIZONTAL_RIGHT) {
  418. rect.x = x+w-sw;
  419. }
  420. else if(hori==HORIZONTAL_CENTER) {
  421. rect.x = x+(w-sw)/2;
  422. }
  423. else {
  424. return;
  425. }
  426. if(vert==VERTICAL_TOP) {
  427. rect.y = y;
  428. }
  429. else if(vert==VERTICAL_BOTTOM) {
  430. rect.y = y+h-finfo.height;
  431. }
  432. else if(vert==VERTICAL_CENTER) {
  433. rect.y = y+(h-finfo.height)/2;
  434. }
  435. else {
  436. return;
  437. }
  438. rect.h = finfo.height;
  439. if(rect.x+sw>=h2->width) {
  440. rect.w = h2->width-rect.x;
  441. }
  442. else {
  443. rect.w = sw;
  444. }
  445. draw_string(h2, rect.x, rect.y, rect.w, rect.h, str, font, color, bgcolor);
  446. }