epaper-29-ws.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <math.h>
  17. #include "driver/gpio.h"
  18. #include "driver/spi_master.h"
  19. #include "freertos/FreeRTOS.h"
  20. #include "freertos/semphr.h"
  21. #include "freertos/xtensa_api.h"
  22. #include "freertos/task.h"
  23. #include "freertos/queue.h"
  24. #include "freertos/ringbuf.h"
  25. #include "esp_log.h"
  26. #include "epaper-29-ws.h"
  27. static const char* TAG = "ePaper Driver";
  28. #define EPAPER_QUE_SIZE_DEFAULT 10
  29. const unsigned char lut_full_update[] =
  30. {
  31. 0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22,
  32. 0x66, 0x69, 0x69, 0x59, 0x58, 0x99, 0x99, 0x88,
  33. 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB4, 0x13, 0x51,
  34. 0x35, 0x51, 0x51, 0x19, 0x01, 0x00
  35. };
  36. // This LUT is not yet used in the code below
  37. const unsigned char lut_partial_update[] =
  38. {
  39. 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00,
  40. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  41. 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12,
  42. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  43. };
  44. static portMUX_TYPE epaper_spinlock = portMUX_INITIALIZER_UNLOCKED;
  45. #define EPAPER_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
  46. #define EPAPER_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
  47. // LCD data/command
  48. typedef struct {
  49. uint8_t dc_io;
  50. uint8_t dc_level;
  51. } epaper_dc_t;
  52. typedef struct {
  53. spi_device_handle_t bus;
  54. epaper_conf_t pin; /* EPD properties */
  55. epaper_paint_t paint; /* Paint properties */
  56. epaper_dc_t dc;
  57. xSemaphoreHandle spi_mux;
  58. } epaper_dev_t;
  59. /* This function is called (in irq context!) just before a transmission starts.
  60. * It will set the D/C line to the value indicated in the user field
  61. */
  62. static void iot_epaper_pre_transfer_callback(spi_transaction_t *t)
  63. {
  64. epaper_dc_t *dc = (epaper_dc_t *) t->user;
  65. gpio_set_level((int)dc->dc_io, (int)dc->dc_level);
  66. }
  67. static esp_err_t _iot_epaper_spi_send(spi_device_handle_t spi, spi_transaction_t* t)
  68. {
  69. return spi_device_transmit(spi, t);
  70. }
  71. void iot_epaper_send(spi_device_handle_t spi, const uint8_t *data, int len, epaper_dc_t *dc)
  72. {
  73. esp_err_t ret;
  74. if (len == 0) {
  75. return; // no need to send anything
  76. }
  77. spi_transaction_t t = {
  78. .length = len * 8, // Len is in bytes, transaction length is in bits.
  79. .tx_buffer = data,
  80. .user = (void *) dc,
  81. };
  82. ret = _iot_epaper_spi_send(spi, &t);
  83. assert(ret == ESP_OK);
  84. }
  85. static void iot_epaper_send_command(epaper_handle_t dev, unsigned char command)
  86. {
  87. epaper_dev_t* device = (epaper_dev_t*) dev;
  88. device->dc.dc_io = device->pin.dc_pin;
  89. device->dc.dc_level = device->pin.dc_lev_cmd;
  90. iot_epaper_send(device->bus, &command, 1, &device->dc);
  91. }
  92. static void iot_epaper_send_byte(epaper_handle_t dev, const uint8_t data)
  93. {
  94. epaper_dev_t* device = (epaper_dev_t*) dev;
  95. device->dc.dc_io = device->pin.dc_pin;
  96. device->dc.dc_level = device->pin.dc_lev_data;
  97. iot_epaper_send(device->bus, &data, 1, &device->dc);
  98. }
  99. static void iot_epaper_send_data(epaper_handle_t dev, const uint8_t *data, int length)
  100. {
  101. epaper_dev_t* device = (epaper_dev_t*) dev;
  102. device->dc.dc_io = device->pin.dc_pin;
  103. device->dc.dc_level = device->pin.dc_lev_data;
  104. // To Do: original driver was sending byte by byte
  105. // Pay attention to possible performance issues
  106. iot_epaper_send(device->bus, data, length, &device->dc);
  107. ESP_LOGI(TAG, "SPI data sent %d", length);
  108. }
  109. static void iot_epaper_paint_init(epaper_handle_t dev, unsigned char* image, int width, int height)
  110. {
  111. epaper_dev_t* device = (epaper_dev_t*) dev;
  112. device->paint.rotate = E_PAPER_ROTATE_0;
  113. device->paint.image = image;
  114. /* 1 byte = 8 pixels, so the width should be the multiple of 8 */
  115. device->paint.width = width % 8 ? width + 8 - (width % 8) : width;
  116. device->paint.height = height;
  117. }
  118. static void iot_epaper_gpio_init(epaper_conf_t * pin)
  119. {
  120. gpio_pad_select_gpio(pin->reset_pin);
  121. gpio_set_direction(pin->reset_pin, GPIO_MODE_OUTPUT);
  122. gpio_set_level(pin->reset_pin, pin->rst_active_level);
  123. gpio_pad_select_gpio(pin->dc_pin);
  124. gpio_set_direction(pin->dc_pin, GPIO_MODE_OUTPUT);
  125. gpio_set_level(pin->dc_pin, 1);
  126. ets_delay_us(10000);
  127. gpio_set_level(pin->dc_pin, 0);
  128. gpio_pad_select_gpio(pin->busy_pin);
  129. gpio_set_direction(pin->busy_pin, GPIO_MODE_INPUT);
  130. gpio_set_pull_mode(pin->busy_pin, GPIO_PULLUP_ONLY);
  131. }
  132. static esp_err_t iot_epaper_spi_init(epaper_handle_t dev, spi_device_handle_t *e_spi, epaper_conf_t *pin)
  133. {
  134. esp_err_t ret;
  135. spi_bus_config_t buscfg = {
  136. .miso_io_num = -1, // MISO not used, we are transferring to the slave only
  137. .mosi_io_num = pin->mosi_pin,
  138. .sclk_io_num = pin->sck_pin,
  139. .quadwp_io_num = -1,
  140. .quadhd_io_num = -1,
  141. // The maximum size sent below covers the case
  142. // when the whole frame buffer is transferred to the slave
  143. .max_transfer_sz = EPD_WIDTH * EPD_HEIGHT / 8,
  144. };
  145. spi_device_interface_config_t devcfg = {
  146. .clock_speed_hz = pin->clk_freq_hz,
  147. .mode = 0, // SPI mode 0
  148. .spics_io_num = pin->cs_pin,
  149. // To Do: clarify what does it mean
  150. .queue_size = EPAPER_QUE_SIZE_DEFAULT,
  151. // We are sending only in one direction (to the ePaper slave)
  152. .flags = (SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE),
  153. //Specify pre-transfer callback to handle D/C line
  154. .pre_cb = iot_epaper_pre_transfer_callback,
  155. };
  156. ret = spi_bus_initialize(pin->spi_host, &buscfg, 1);
  157. assert(ret == ESP_OK);
  158. ret = spi_bus_add_device(pin->spi_host, &devcfg, e_spi);
  159. assert(ret == ESP_OK);
  160. return ret;
  161. }
  162. static void iot_epaper_set_lut(epaper_handle_t dev)
  163. {
  164. epaper_dev_t* device = (epaper_dev_t*) dev;
  165. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  166. iot_epaper_send_command(dev, E_PAPER_WRITE_LUT_REGISTER);
  167. iot_epaper_send_data(dev, lut_full_update, sizeof(lut_full_update));
  168. xSemaphoreGiveRecursive(device->spi_mux);
  169. }
  170. static void iot_epaper_epd_init(epaper_handle_t dev)
  171. {
  172. epaper_dev_t* device = (epaper_dev_t*) dev;
  173. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  174. iot_epaper_reset(dev);
  175. /* This part of code is ePaper module specific
  176. * It has been copied from the instructions as it is
  177. */
  178. iot_epaper_send_command(dev, E_PAPER_DRIVER_OUTPUT_CONTROL);
  179. iot_epaper_send_byte(dev, (EPD_HEIGHT - 1) & 0xff);
  180. iot_epaper_send_byte(dev, ((EPD_HEIGHT - 1) >> 8) & 0xff);
  181. iot_epaper_send_byte(dev, 0x00); // GD = 0; SM = 0; TB = 0
  182. iot_epaper_send_command(dev, E_PAPER_BOOSTER_SOFT_START_CONTROL);
  183. iot_epaper_send_byte(dev, 0xD7);
  184. iot_epaper_send_byte(dev, 0xD6);
  185. iot_epaper_send_byte(dev, 0x9D);
  186. iot_epaper_send_command(dev, E_PAPER_WRITE_VCOM_REGISTER);
  187. iot_epaper_send_byte(dev, 0xA8); // VCOM 7C
  188. iot_epaper_send_command(dev, E_PAPER_SET_DUMMY_LINE_PERIOD);
  189. iot_epaper_send_byte(dev, 0x1A); // 4 dummy lines per gate
  190. iot_epaper_send_command(dev, E_PAPER_SET_GATE_TIME);
  191. iot_epaper_send_byte(dev, 0x08); // 2us per line
  192. iot_epaper_send_command(dev, E_PAPER_DATA_ENTRY_MODE_SETTING);
  193. iot_epaper_send_byte(dev, 0x03); // X increment; Y increment
  194. iot_epaper_set_lut(dev);
  195. xSemaphoreGiveRecursive(device->spi_mux);
  196. }
  197. epaper_handle_t iot_epaper_create(spi_device_handle_t bus, epaper_conf_t *epconf)
  198. {
  199. epaper_dev_t* dev = (epaper_dev_t*) calloc(1, sizeof(epaper_dev_t));
  200. dev->spi_mux = xSemaphoreCreateRecursiveMutex();
  201. uint8_t* frame_buf = (unsigned char*) heap_caps_malloc(
  202. (epconf->width * epconf->height / 8), MALLOC_CAP_8BIT);
  203. if (frame_buf == NULL) {
  204. ESP_LOGE(TAG, "frame_buffer malloc fail");
  205. return NULL;
  206. }
  207. iot_epaper_gpio_init(epconf);
  208. ESP_LOGD(TAG, "gpio init ok");
  209. if (bus) {
  210. dev->bus = bus;
  211. } else {
  212. iot_epaper_spi_init(dev, &dev->bus, epconf);
  213. ESP_LOGD(TAG, "spi init ok");
  214. }
  215. dev->pin = *epconf;
  216. iot_epaper_epd_init(dev);
  217. iot_epaper_paint_init(dev, frame_buf, epconf->width, epconf->height);
  218. return (epaper_handle_t) dev;
  219. }
  220. esp_err_t iot_epaper_delete(epaper_handle_t dev, bool del_bus)
  221. {
  222. epaper_dev_t* device = (epaper_dev_t*) dev;
  223. iot_epaper_sleep(dev);
  224. spi_bus_remove_device(device->bus);
  225. if (del_bus) {
  226. spi_bus_free(device->pin.spi_host);
  227. }
  228. vSemaphoreDelete(device->spi_mux);
  229. if (device->paint.image) {
  230. free(device->paint.image);
  231. device->paint.image = NULL;
  232. }
  233. free(device);
  234. return ESP_OK;
  235. }
  236. int iot_epaper_get_width(epaper_handle_t dev)
  237. {
  238. epaper_dev_t* device = (epaper_dev_t*) dev;
  239. return device->paint.width;
  240. }
  241. void iot_epaper_set_width(epaper_handle_t dev, int width)
  242. {
  243. epaper_dev_t* device = (epaper_dev_t*) dev;
  244. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  245. device->paint.width = width % 8 ? width + 8 - (width % 8) : width;
  246. xSemaphoreGiveRecursive(device->spi_mux);
  247. }
  248. int iot_epaper_get_height(epaper_handle_t dev)
  249. {
  250. epaper_dev_t* device = (epaper_dev_t*) dev;
  251. return device->paint.height;
  252. }
  253. void iot_epaper_set_height(epaper_handle_t dev, int height)
  254. {
  255. epaper_dev_t* device = (epaper_dev_t*) dev;
  256. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  257. device->paint.height = height;
  258. xSemaphoreGiveRecursive(device->spi_mux);
  259. }
  260. int iot_epaper_get_rotate(epaper_handle_t dev)
  261. {
  262. epaper_dev_t* device = (epaper_dev_t*) dev;
  263. return device->paint.rotate;
  264. }
  265. void iot_epaper_set_rotate(epaper_handle_t dev, int rotate)
  266. {
  267. epaper_dev_t* device = (epaper_dev_t*) dev;
  268. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  269. device->paint.rotate = rotate;
  270. xSemaphoreGiveRecursive(device->spi_mux);
  271. }
  272. /**
  273. * @brief: Getters and Setters
  274. */
  275. unsigned char* iot_epaper_get_image(epaper_handle_t dev)
  276. {
  277. epaper_dev_t* device = (epaper_dev_t*) dev;
  278. return device->paint.image;
  279. }
  280. /**
  281. * @brief: this draws a pixel by absolute coordinates.
  282. * this function won't be affected by the rotate parameter.
  283. */
  284. static void iot_epaper_draw_absolute_pixel(epaper_handle_t dev, int x, int y, int colored)
  285. {
  286. epaper_dev_t* device = (epaper_dev_t*) dev;
  287. if (x < 0 || x >= device->paint.width || y < 0 || y >= device->paint.height) {
  288. return;
  289. }
  290. EPAPER_ENTER_CRITICAL(&epaper_spinlock);
  291. if (device->pin.color_inv) {
  292. if (colored) {
  293. device->paint.image[(x + y * device->paint.width) / 8] |= 0x80 >> (x % 8);
  294. } else {
  295. device->paint.image[(x + y * device->paint.width) / 8] &= ~(0x80 >> (x % 8));
  296. }
  297. } else {
  298. if (colored) {
  299. device->paint.image[(x + y * device->paint.width) / 8] &= ~(0x80 >> (x % 8));
  300. } else {
  301. device->paint.image[(x + y * device->paint.width) / 8] |= 0x80 >> (x % 8);
  302. }
  303. }
  304. EPAPER_EXIT_CRITICAL(&epaper_spinlock);
  305. }
  306. void iot_epaper_clean_paint(epaper_handle_t dev, int colored)
  307. {
  308. epaper_dev_t* device = (epaper_dev_t*) dev;
  309. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  310. for (int x = 0; x < device->paint.width; x++) {
  311. for (int y = 0; y < device->paint.height; y++) {
  312. iot_epaper_draw_absolute_pixel(dev, x, y, colored);
  313. }
  314. }
  315. xSemaphoreGiveRecursive(device->spi_mux);
  316. }
  317. /**
  318. * @brief: this displays a string on the frame buffer but not refresh
  319. */
  320. void iot_epaper_draw_string(epaper_handle_t dev, int x, int y, const char* text, epaper_font_t* font, int colored)
  321. {
  322. const char* p_text = text;
  323. unsigned int counter = 0;
  324. int refcolumn = x;
  325. epaper_dev_t* device = (epaper_dev_t*) dev;
  326. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  327. /* Send the string character by character on EPD */
  328. while (*p_text != 0) {
  329. /* Display one character on EPD */
  330. iot_epaper_draw_char(dev, refcolumn, y, *p_text, font, colored);
  331. /* Decrement the column position by 16 */
  332. refcolumn += font->width;
  333. /* Point on the next character */
  334. p_text++;
  335. counter++;
  336. }
  337. xSemaphoreGiveRecursive(device->spi_mux);
  338. }
  339. /**
  340. * @brief: this draws a pixel by the coordinates
  341. */
  342. void iot_epaper_draw_pixel(epaper_handle_t dev, int x, int y, int colored)
  343. {
  344. int point_temp;
  345. epaper_dev_t* device = (epaper_dev_t*) dev;
  346. if (device->paint.rotate == E_PAPER_ROTATE_0) {
  347. if (x < 0 || x >= device->paint.width || y < 0 || y >= device->paint.height) {
  348. return;
  349. }
  350. iot_epaper_draw_absolute_pixel(dev, x, y, colored);
  351. } else if (device->paint.rotate == E_PAPER_ROTATE_90) {
  352. if (x < 0 || x >= device->paint.height || y < 0 || y >= device->paint.width) {
  353. return;
  354. }
  355. point_temp = x;
  356. x = device->paint.width - y;
  357. y = point_temp;
  358. iot_epaper_draw_absolute_pixel(dev, x, y, colored);
  359. } else if (device->paint.rotate == E_PAPER_ROTATE_180) {
  360. if (x < 0 || x >= device->paint.width || y < 0 || y >= device->paint.height) {
  361. return;
  362. }
  363. x = device->paint.width - x;
  364. y = device->paint.height - y;
  365. iot_epaper_draw_absolute_pixel(dev, x, y, colored);
  366. } else if (device->paint.rotate == E_PAPER_ROTATE_270) {
  367. if (x < 0 || x >= device->paint.height || y < 0 || y >= device->paint.width) {
  368. return;
  369. }
  370. point_temp = x;
  371. x = y;
  372. y = device->paint.height - point_temp;
  373. iot_epaper_draw_absolute_pixel(dev, x, y, colored);
  374. }
  375. }
  376. /**
  377. * @brief: this draws a character on the frame buffer but not refresh
  378. */
  379. void iot_epaper_draw_char(epaper_handle_t dev, int x, int y, char ascii_char, epaper_font_t* font, int colored)
  380. {
  381. int i, j;
  382. unsigned int char_offset = (ascii_char - ' ') * font->height * (font->width / 8 + (font->width % 8 ? 1 : 0));
  383. const unsigned char* ptr = &font->font_table[char_offset];
  384. epaper_dev_t* device = (epaper_dev_t*) dev;
  385. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  386. for (j = 0; j < font->height; j++) {
  387. for (i = 0; i < font->width; i++) {
  388. if (*ptr & (0x80 >> (i % 8))) {
  389. iot_epaper_draw_pixel(dev, x + i, y + j, colored);
  390. }
  391. if (i % 8 == 7) {
  392. ptr++;
  393. }
  394. }
  395. if (font->width % 8 != 0) {
  396. ptr++;
  397. }
  398. }
  399. xSemaphoreGiveRecursive(device->spi_mux);
  400. }
  401. /**
  402. * @brief: this draws a line on the frame buffer
  403. */
  404. void iot_epaper_draw_line(epaper_handle_t dev, int x0, int y0, int x1, int y1,
  405. int colored)
  406. {
  407. /* Bresenham algorithm */
  408. int dx = x1 - x0 >= 0 ? x1 - x0 : x0 - x1;
  409. int sx = x0 < x1 ? 1 : -1;
  410. int dy = y1 - y0 <= 0 ? y1 - y0 : y0 - y1;
  411. int sy = y0 < y1 ? 1 : -1;
  412. int err = dx + dy;
  413. epaper_dev_t* device = (epaper_dev_t*) dev;
  414. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  415. while ((x0 != x1) && (y0 != y1)) {
  416. iot_epaper_draw_pixel(dev, x0, y0, colored);
  417. if (2 * err >= dy) {
  418. err += dy;
  419. x0 += sx;
  420. }
  421. if (2 * err <= dx) {
  422. err += dx;
  423. y0 += sy;
  424. }
  425. }
  426. xSemaphoreGiveRecursive(device->spi_mux);
  427. }
  428. /**
  429. * @brief: this draws a horizontal line on the frame buffer
  430. */
  431. void iot_epaper_draw_horizontal_line(epaper_handle_t dev, int x, int y, int width, int colored)
  432. {
  433. int i;
  434. epaper_dev_t* device = (epaper_dev_t*) dev;
  435. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  436. for (i = x; i < x + width; i++) {
  437. iot_epaper_draw_pixel(dev, i, y, colored);
  438. }
  439. xSemaphoreGiveRecursive(device->spi_mux);
  440. }
  441. /**
  442. * @brief: this draws a vertical line on the frame buffer
  443. */
  444. void iot_epaper_draw_vertical_line(epaper_handle_t dev, int x, int y, int height, int colored)
  445. {
  446. int i;
  447. epaper_dev_t* device = (epaper_dev_t*) dev;
  448. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  449. for (i = y; i < y + height; i++) {
  450. iot_epaper_draw_pixel(dev, x, i, colored);
  451. }
  452. xSemaphoreGiveRecursive(device->spi_mux);
  453. }
  454. /**
  455. * @brief: this draws a rectangle
  456. */
  457. void iot_epaper_draw_rectangle(epaper_handle_t dev, int x0, int y0, int x1, int y1, int colored)
  458. {
  459. int min_x, min_y, max_x, max_y;
  460. min_x = x1 > x0 ? x0 : x1;
  461. max_x = x1 > x0 ? x1 : x0;
  462. min_y = y1 > y0 ? y0 : y1;
  463. max_y = y1 > y0 ? y1 : y0;
  464. epaper_dev_t* device = (epaper_dev_t*) dev;
  465. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  466. iot_epaper_draw_horizontal_line(dev, min_x, min_y, max_x - min_x + 1, colored);
  467. iot_epaper_draw_horizontal_line(dev, min_x, max_y, max_x - min_x + 1, colored);
  468. iot_epaper_draw_vertical_line(dev, min_x, min_y, max_y - min_y + 1, colored);
  469. iot_epaper_draw_vertical_line(dev, max_x, min_y, max_y - min_y + 1, colored);
  470. xSemaphoreGiveRecursive(device->spi_mux);
  471. }
  472. /**
  473. * @brief: this draws a filled rectangle
  474. */
  475. void ior_epaper_draw_filled_rectangle(epaper_handle_t dev, int x0, int y0, int x1, int y1, int colored)
  476. {
  477. int min_x, min_y, max_x, max_y;
  478. int i;
  479. min_x = x1 > x0 ? x0 : x1;
  480. max_x = x1 > x0 ? x1 : x0;
  481. min_y = y1 > y0 ? y0 : y1;
  482. max_y = y1 > y0 ? y1 : y0;
  483. epaper_dev_t* device = (epaper_dev_t*) dev;
  484. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  485. for (i = min_x; i <= max_x; i++) {
  486. iot_epaper_draw_vertical_line(dev, i, min_y, max_y - min_y + 1, colored);
  487. }
  488. xSemaphoreGiveRecursive(device->spi_mux);
  489. }
  490. /**
  491. * @brief: this draws a circle
  492. */
  493. void iot_epaper_draw_circle(epaper_handle_t dev, int x, int y, int radius,
  494. int colored)
  495. {
  496. /* Bresenham algorithm */
  497. int x_pos = -radius;
  498. int y_pos = 0;
  499. int err = 2 - 2 * radius;
  500. int e2;
  501. epaper_dev_t* device = (epaper_dev_t*) dev;
  502. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  503. do {
  504. iot_epaper_draw_pixel(dev, x - x_pos, y + y_pos, colored);
  505. iot_epaper_draw_pixel(dev, x + x_pos, y + y_pos, colored);
  506. iot_epaper_draw_pixel(dev, x + x_pos, y - y_pos, colored);
  507. iot_epaper_draw_pixel(dev, x - x_pos, y - y_pos, colored);
  508. e2 = err;
  509. if (e2 <= y_pos) {
  510. err += ++y_pos * 2 + 1;
  511. if (-x_pos == y_pos && e2 <= x_pos) {
  512. e2 = 0;
  513. }
  514. }
  515. if (e2 > x_pos) {
  516. err += ++x_pos * 2 + 1;
  517. }
  518. } while (x_pos <= 0);
  519. xSemaphoreGiveRecursive(device->spi_mux);
  520. }
  521. /**
  522. * @brief: this draws a filled circle
  523. */
  524. void iot_epaper_draw_filled_circle(epaper_handle_t dev, int x, int y, int radius, int colored)
  525. {
  526. /* Bresenham algorithm */
  527. int x_pos = -radius;
  528. int y_pos = 0;
  529. int err = 2 - 2 * radius;
  530. int e2;
  531. epaper_dev_t* device = (epaper_dev_t*) dev;
  532. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  533. do {
  534. iot_epaper_draw_pixel(dev, x - x_pos, y + y_pos, colored);
  535. iot_epaper_draw_pixel(dev, x + x_pos, y + y_pos, colored);
  536. iot_epaper_draw_pixel(dev, x + x_pos, y - y_pos, colored);
  537. iot_epaper_draw_pixel(dev, x - x_pos, y - y_pos, colored);
  538. iot_epaper_draw_horizontal_line(dev, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored);
  539. iot_epaper_draw_horizontal_line(dev, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored);
  540. e2 = err;
  541. if (e2 <= y_pos) {
  542. err += ++y_pos * 2 + 1;
  543. if (-x_pos == y_pos && e2 <= x_pos) {
  544. e2 = 0;
  545. }
  546. }
  547. if (e2 > x_pos) {
  548. err += ++x_pos * 2 + 1;
  549. }
  550. } while (x_pos <= 0);
  551. xSemaphoreGiveRecursive(device->spi_mux);
  552. }
  553. void iot_epaper_wait_idle(epaper_handle_t dev)
  554. {
  555. epaper_dev_t* device = (epaper_dev_t*) dev;
  556. while (gpio_get_level((gpio_num_t) device->pin.busy_pin) == device->pin.busy_active_level) {
  557. vTaskDelay(10 / portTICK_RATE_MS);
  558. }
  559. }
  560. void iot_epaper_reset(epaper_handle_t dev)
  561. {
  562. epaper_dev_t* device = (epaper_dev_t*) dev;
  563. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  564. gpio_set_level((gpio_num_t) device->pin.reset_pin, (~(device->pin.rst_active_level)) & 0x1);
  565. ets_delay_us(200);
  566. gpio_set_level((gpio_num_t) device->pin.reset_pin, (device->pin.rst_active_level) & 0x1); //module reset
  567. ets_delay_us(200);
  568. gpio_set_level((gpio_num_t) device->pin.reset_pin, (~(device->pin.rst_active_level)) & 0x1);
  569. iot_epaper_wait_idle(dev);
  570. xSemaphoreGiveRecursive(device->spi_mux);
  571. }
  572. /* This function has been exposed to implement partial updates of the image
  573. * To Do: implement partial updates of the image
  574. */
  575. void iot_set_ram_area(epaper_handle_t dev, int x_start, int y_start, int x_end, int y_end)
  576. {
  577. iot_epaper_send_command(dev, E_PAPER_SET_RAM_X_ADDRESS_START_END_POSITION);
  578. iot_epaper_send_byte(dev, x_start >> 3); // 8 pixels per byte
  579. iot_epaper_send_byte(dev, x_end >> 3); // 8 pixels per byte
  580. iot_epaper_send_command(dev, E_PAPER_SET_RAM_Y_ADDRESS_START_END_POSITION);
  581. iot_epaper_send_byte(dev, y_start & 0xff);
  582. iot_epaper_send_byte(dev, y_start >> 8);
  583. iot_epaper_send_byte(dev, y_end & 0xff);
  584. iot_epaper_send_byte(dev, y_end >> 8);
  585. }
  586. /* This function has been exposed to implement partial updates of the image
  587. * To Do: implement partial updates of the image
  588. */
  589. void iot_set_ram_address_counter(epaper_handle_t dev, int x, int y)
  590. {
  591. iot_epaper_send_command(dev, E_PAPER_SET_RAM_X_ADDRESS_COUNTER);
  592. iot_epaper_send_byte(dev, x >> 3); // 8 pixels per byte
  593. iot_epaper_send_command(dev, E_PAPER_SET_RAM_Y_ADDRESS_COUNTER);
  594. iot_epaper_send_byte(dev, y & 0xff);
  595. iot_epaper_send_byte(dev, y >> 8);
  596. }
  597. /* This transfer to the display the whole image frame
  598. * To Do: implement partial updates of the image
  599. */
  600. void iot_epaper_display_frame(epaper_handle_t dev, const unsigned char* frame_buffer)
  601. {
  602. epaper_dev_t* device = (epaper_dev_t*) dev;
  603. if (frame_buffer == NULL) {
  604. frame_buffer = device->paint.image;
  605. }
  606. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  607. if (frame_buffer != NULL) {
  608. // configure ePaper's memory to send data
  609. iot_set_ram_area(dev, 0, 0, EPD_WIDTH-1, EPD_HEIGHT-1);
  610. iot_set_ram_address_counter(dev, 0, 0);
  611. // send image data
  612. iot_epaper_send_command(dev, E_PAPER_WRITE_RAM);
  613. iot_epaper_send_data(dev, frame_buffer, device->paint.width / 8 * device->paint.height);
  614. // update display
  615. iot_epaper_send_command(dev, E_PAPER_DISPLAY_UPDATE_CONTROL_2);
  616. iot_epaper_send_byte(dev, 0xC4);
  617. iot_epaper_send_command(dev, E_PAPER_MASTER_ACTIVATION);
  618. iot_epaper_send_command(dev, E_PAPER_TERMINATE_FRAME_READ_WRITE);
  619. iot_epaper_wait_idle(dev);
  620. }
  621. xSemaphoreGiveRecursive(device->spi_mux);
  622. }
  623. void iot_epaper_sleep(epaper_handle_t dev)
  624. {
  625. epaper_dev_t* device = (epaper_dev_t*) dev;
  626. xSemaphoreTakeRecursive(device->spi_mux, portMAX_DELAY);
  627. iot_epaper_send_command(dev, E_PAPER_DEEP_SLEEP_MODE);
  628. iot_epaper_wait_idle(dev);
  629. xSemaphoreGiveRecursive(device->spi_mux);
  630. }