1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/EPD.c Sun May 19 22:06:40 2013 +0000
1.3 @@ -0,0 +1,714 @@
1.4 +// Copyright 2013 Pervasive Displays, Inc.
1.5 +//
1.6 +// Licensed under the Apache License, Version 2.0 (the "License");
1.7 +// you may not use this file except in compliance with the License.
1.8 +// You may obtain a copy of the License at:
1.9 +//
1.10 +// http://www.apache.org/licenses/LICENSE-2.0
1.11 +//
1.12 +// Unless required by applicable law or agreed to in writing,
1.13 +// software distributed under the License is distributed on an
1.14 +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
1.15 +// express or implied. See the License for the specific language
1.16 +// governing permissions and limitations under the License.
1.17 +
1.18 +
1.19 +#include "EPD.h"
1.20 +
1.21 +typedef enum {
1.22 + LOW=0,
1.23 + HIGH=1
1.24 +} EPD_pinstate;
1.25 +
1.26 +static void EPD_line(uint16_t line, const uint8_t *data, uint8_t fixed_value, uint8_t read_progmem, EPD_stage stage);
1.27 +static void SPI_send(const uint8_t *buffer, uint16_t length);
1.28 +static void SPI_put(uint8_t c);
1.29 +static void SPI_put_wait(uint8_t c);
1.30 +
1.31 +static void EPD_Pin_init();
1.32 +static void EPD_Pin_EPD_CS(EPD_pinstate pin);
1.33 +static void EPD_Pin_RESET(EPD_pinstate pin);
1.34 +static void EPD_Pin_PANEL_ON(EPD_pinstate pin);
1.35 +static void EPD_Pin_DISCHARGE(EPD_pinstate pin);
1.36 +static void EPD_Pin_BORDER(EPD_pinstate pin);
1.37 +static EPD_pinstate epd_get_busy(void);
1.38 +
1.39 +static void epd_pwm_active(uint16_t delayInMs);
1.40 +
1.41 +
1.42 +// inline arrays
1.43 +#define ARRAY(type, ...) ((type[]){__VA_ARGS__})
1.44 +#define CU8(...) (ARRAY(const uint8_t, __VA_ARGS__))
1.45 +
1.46 +static COG_Parameters_t epd;
1.47 +
1.48 +/******************************************************************************
1.49 + * Local functions
1.50 + *****************************************************************************/
1.51 +
1.52 +
1.53 +// convert a temperature in Celcius to
1.54 +// the scale factor for frame_*_repeat methods
1.55 +static int16_t EPD_temperature_to_factor_10x(int16_t temperature) {
1.56 + if (temperature <= -10) {
1.57 + return 170;
1.58 + } else if (temperature <= -5) {
1.59 + return 120;
1.60 + } else if (temperature <= 5) {
1.61 + return 80;
1.62 + } else if (temperature <= 10) {
1.63 + return 40;
1.64 + } else if (temperature <= 15) {
1.65 + return 30;
1.66 + } else if (temperature <= 20) {
1.67 + return 20;
1.68 + } else if (temperature <= 40) {
1.69 + return 10;
1.70 + }
1.71 + return 7;
1.72 +}
1.73 +
1.74 +
1.75 +// One frame of data is the number of lines * rows. For example:
1.76 +// The 1.44” frame of data is 96 lines * 128 dots.
1.77 +// The 2” frame of data is 96 lines * 200 dots.
1.78 +// The 2.7” frame of data is 176 lines * 264 dots.
1.79 +
1.80 +// the image is arranged by line which matches the display size
1.81 +// so smallest would have 96 * 32 bytes
1.82 +
1.83 +static void EPD_frame_fixed(uint8_t fixed_value, EPD_stage stage) {
1.84 + uint8_t line;
1.85 + for (line = 0; line < epd.lines_per_display ; ++line) {
1.86 + EPD_line(line, 0, fixed_value, FALSE, stage);
1.87 + }
1.88 +}
1.89 +
1.90 +static void EPD_frame_data(PROGMEM const uint8_t *image, EPD_stage stage){
1.91 + uint8_t line;
1.92 + for (line = 0; line < epd.lines_per_display ; ++line) {
1.93 + EPD_line(line, &image[line * epd.bytes_per_line], 0, TRUE, stage);
1.94 + }
1.95 +}
1.96 +
1.97 +
1.98 +#if defined(EPD_ENABLE_EXTRA_SRAM)
1.99 +static void EPD_frame_sram(const uint8_t *image, EPD_stage stage){
1.100 + uint8_t line;
1.101 + for (line = 0; line < epd.lines_per_display ; ++line) {
1.102 + EPD_line(line, &image[line * epd.bytes_per_line], 0, FALSE, stage);
1.103 + }
1.104 +}
1.105 +#endif
1.106 +
1.107 +
1.108 +static void EPD_frame_fixed_repeat(uint8_t fixed_value, EPD_stage stage) {
1.109 + int32_t stage_time = epd.factored_stage_time;
1.110 + do {
1.111 + uint32_t t_start = bsp_getMsTicks();
1.112 + EPD_frame_fixed(fixed_value, stage);
1.113 + uint32_t t_end = bsp_getMsTicks();
1.114 + if (t_end > t_start) {
1.115 + stage_time -= t_end - t_start;
1.116 + } else {
1.117 + stage_time -= t_start - t_end + 1 + 0xffffffffU;
1.118 + }
1.119 + } while (stage_time > 0);
1.120 +}
1.121 +
1.122 +
1.123 +static void EPD_frame_data_repeat(PROGMEM const uint8_t *image, EPD_stage stage) {
1.124 + int32_t stage_time = epd.factored_stage_time;
1.125 + do {
1.126 + uint32_t t_start = bsp_getMsTicks();
1.127 + EPD_frame_data(image, stage);
1.128 + uint32_t t_end = bsp_getMsTicks();
1.129 + if (t_end > t_start) {
1.130 + stage_time -= t_end - t_start;
1.131 + } else {
1.132 + stage_time -= t_start - t_end + 1 + 0xffffffffU;
1.133 + }
1.134 + } while (stage_time > 0);
1.135 +}
1.136 +
1.137 +#include <limits.h>
1.138 +#if defined(EPD_ENABLE_EXTRA_SRAM)
1.139 +static void EPD_frame_sram_repeat(const uint8_t *image, EPD_stage stage) {
1.140 + int32_t stage_time = epd.factored_stage_time;
1.141 + do {
1.142 + uint32_t t_start = bsp_getMsTicks();
1.143 + EPD_frame_sram(image, stage);
1.144 + uint32_t t_end = bsp_getMsTicks();
1.145 + if (t_end > t_start) {
1.146 + stage_time -= t_end - t_start;
1.147 + } else {
1.148 + stage_time -= t_start - t_end + 1 + 0xffffffffU;
1.149 + }
1.150 + } while (stage_time > 0);
1.151 +}
1.152 +#endif
1.153 +
1.154 +#if 0
1.155 +typedef void EPD_reader(void *buffer, uint32_t address, uint16_t length);
1.156 +
1.157 +static void EPD_frame_cb(uint32_t address, EPD_reader *reader, EPD_stage stage) {
1.158 + static uint8_t buffer[264 / 8];
1.159 + uint8_t line;
1.160 + for (line = 0; line < epd.lines_per_display; ++line) {
1.161 + reader(buffer, address + line * epd.bytes_per_line, epd.bytes_per_line);
1.162 + EPD_line(line, buffer, 0, FALSE, stage);
1.163 + }
1.164 +}
1.165 +
1.166 +static void EPD_frame_cb_repeat(uint32_t address, EPD_reader *reader, EPD_stage stage) {
1.167 + int32_t stage_time = epd.factored_stage_time;
1.168 + do {
1.169 + uint32_t t_start = bsp_getMsTicks();
1.170 + EPD_frame_cb(address, reader, stage);
1.171 + uint32_t t_end = bsp_getMsTicks();
1.172 + if (t_end > t_start) {
1.173 + stage_time -= t_end - t_start;
1.174 + } else {
1.175 + stage_time -= t_start - t_end + 1 + 0xffffffffU;
1.176 + }
1.177 + } while (stage_time > 0);
1.178 +}
1.179 +#endif
1.180 +
1.181 +static void EPD_line(uint16_t line, const uint8_t *data, uint8_t fixed_value, uint8_t read_progmem, EPD_stage stage) {
1.182 + // charge pump voltage levels
1.183 + bsp_delayUs(10);
1.184 + SPI_send(CU8(0x70, 0x04), 2);
1.185 + bsp_delayUs(10);
1.186 + SPI_send(epd.gate_source, epd.gate_source_length);
1.187 +
1.188 + // send data
1.189 + bsp_delayUs(10);
1.190 + SPI_send(CU8(0x70, 0x0a), 2);
1.191 + bsp_delayUs(10);
1.192 +
1.193 + // CS low
1.194 + EPD_Pin_EPD_CS(LOW);
1.195 + SPI_put_wait(0x72);
1.196 +
1.197 + // even pixels
1.198 + uint16_t b;
1.199 + for (b = epd.bytes_per_line; b > 0; --b) {
1.200 + if (0 != data) {
1.201 + uint8_t pixels = data[b - 1] & 0xaa;
1.202 + switch(stage) {
1.203 + case EPD_compensate: // B -> W, W -> B (Current Image)
1.204 + pixels = 0xaa | ((pixels ^ 0xaa) >> 1);
1.205 + break;
1.206 + case EPD_white: // B -> N, W -> W (Current Image)
1.207 + pixels = 0x55 + ((pixels ^ 0xaa) >> 1);
1.208 + break;
1.209 + case EPD_inverse: // B -> N, W -> B (New Image)
1.210 + pixels = 0x55 | (pixels ^ 0xaa);
1.211 + break;
1.212 + case EPD_normal: // B -> B, W -> W (New Image)
1.213 + pixels = 0xaa | (pixels >> 1);
1.214 + break;
1.215 + }
1.216 + SPI_put_wait(pixels);
1.217 + } else {
1.218 + SPI_put_wait(fixed_value);
1.219 + } }
1.220 +
1.221 + // scan line
1.222 + for (b = 0; b < epd.bytes_per_scan; ++b) {
1.223 + if (line / 4 == b) {
1.224 + SPI_put_wait(0xc0 >> (2 * (line & 0x03)));
1.225 + } else {
1.226 + SPI_put_wait(0x00);
1.227 + }
1.228 + }
1.229 +
1.230 + // odd pixels
1.231 + for (b = 0; b < epd.bytes_per_line; ++b) {
1.232 + if (0 != data) {
1.233 + uint8_t pixels = data[b] & 0x55;
1.234 + switch(stage) {
1.235 + case EPD_compensate: // B -> W, W -> B (Current Image)
1.236 + pixels = 0xaa | (pixels ^ 0x55);
1.237 + break;
1.238 + case EPD_white: // B -> N, W -> W (Current Image)
1.239 + pixels = 0x55 + (pixels ^ 0x55);
1.240 + break;
1.241 + case EPD_inverse: // B -> N, W -> B (New Image)
1.242 + pixels = 0x55 | ((pixels ^ 0x55) << 1);
1.243 + break;
1.244 + case EPD_normal: // B -> B, W -> W (New Image)
1.245 + pixels = 0xaa | pixels;
1.246 + break;
1.247 + }
1.248 + uint8_t p1 = (pixels >> 6) & 0x03;
1.249 + uint8_t p2 = (pixels >> 4) & 0x03;
1.250 + uint8_t p3 = (pixels >> 2) & 0x03;
1.251 + uint8_t p4 = (pixels >> 0) & 0x03;
1.252 + pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6);
1.253 + SPI_put_wait(pixels);
1.254 + } else {
1.255 + SPI_put_wait(fixed_value);
1.256 + }
1.257 + }
1.258 +
1.259 + if (epd.filler == TRUE) {
1.260 + SPI_put_wait(0x00);
1.261 + }
1.262 +
1.263 + // CS high
1.264 + EPD_Pin_EPD_CS(HIGH);
1.265 +
1.266 + // output data to panel
1.267 + bsp_delayUs(10);
1.268 + SPI_send(CU8(0x70, 0x02), 2);
1.269 + bsp_delayUs(10);
1.270 + SPI_send(CU8(0x72, 0x2f), 2);
1.271 +}
1.272 +
1.273 +
1.274 +/******************************************************************************
1.275 + * Public functions
1.276 + *****************************************************************************/
1.277 +
1.278 +
1.279 +void EPD_init(EPD_size size) {
1.280 + static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00};
1.281 + static uint8_t gs[] = {0x72, 0x03};
1.282 +
1.283 + EPD_Pin_init();
1.284 +
1.285 + epd.size = size;
1.286 + epd.stage_time = 480; // milliseconds
1.287 + epd.lines_per_display = 96;
1.288 + epd.dots_per_line = 128;
1.289 + epd.bytes_per_line = 128 / 8;
1.290 + epd.bytes_per_scan = 96 / 4;
1.291 + epd.filler = FALSE;
1.292 + epd.channel_select = cs;
1.293 + epd.channel_select_length = sizeof(cs);
1.294 + epd.gate_source = gs;
1.295 + epd.gate_source_length = sizeof(gs);
1.296 +
1.297 + // set up size structure
1.298 + switch (size) {
1.299 + default:
1.300 + case EPD_1_44: // default so no change
1.301 + break;
1.302 +
1.303 + case EPD_2_0: {
1.304 + epd.lines_per_display = 96;
1.305 + epd.dots_per_line = 200;
1.306 + epd.bytes_per_line = 200 / 8;
1.307 + epd.bytes_per_scan = 96 / 4;
1.308 + epd.filler = TRUE;
1.309 + cs[0] = 0x72;
1.310 + cs[1] = 0x00;
1.311 + cs[2] = 0x00;
1.312 + cs[3] = 0x00;
1.313 + cs[4] = 0x00;
1.314 + cs[5] = 0x01;
1.315 + cs[6] = 0xff;
1.316 + cs[7] = 0xe0;
1.317 + cs[8] = 0x00;
1.318 + gs[0] = 0x72;
1.319 + gs[1] = 0x03;
1.320 + break;
1.321 + }
1.322 +
1.323 + case EPD_2_7: {
1.324 + epd.stage_time = 630; // milliseconds
1.325 + epd.lines_per_display = 176;
1.326 + epd.dots_per_line = 264;
1.327 + epd.bytes_per_line = 264 / 8;
1.328 + epd.bytes_per_scan = 176 / 4;
1.329 + epd.filler = TRUE;
1.330 + cs[0] = 0x72;
1.331 + cs[1] = 0x00;
1.332 + cs[2] = 0x00;
1.333 + cs[3] = 0x00;
1.334 + cs[4] = 0x7f;
1.335 + cs[5] = 0xff;
1.336 + cs[6] = 0xfe;
1.337 + cs[7] = 0x00;
1.338 + cs[8] = 0x00;
1.339 + gs[0] = 0x72;
1.340 + gs[1] = 0x00;
1.341 + break;
1.342 + }
1.343 + }
1.344 +
1.345 + epd.factored_stage_time = epd.stage_time;
1.346 +}
1.347 +
1.348 +
1.349 +void EPD_begin(void)
1.350 +{
1.351 + // power up sequence
1.352 + SPI_put(0x00);
1.353 +
1.354 + EPD_Pin_RESET(LOW);
1.355 + EPD_Pin_PANEL_ON(LOW);
1.356 + EPD_Pin_DISCHARGE(LOW);
1.357 + EPD_Pin_BORDER(LOW);
1.358 + EPD_Pin_EPD_CS(LOW);
1.359 +
1.360 + // PWM_start(this->EPD_Pin_PWM);
1.361 + // Delay_ms(5);
1.362 + epd_pwm_active(5);
1.363 + EPD_Pin_PANEL_ON(HIGH);
1.364 + // Delay_ms(10);
1.365 + epd_pwm_active(10);
1.366 +
1.367 + EPD_Pin_RESET(HIGH);
1.368 + EPD_Pin_BORDER(HIGH);
1.369 + EPD_Pin_EPD_CS(HIGH);
1.370 + // Delay_ms(5);
1.371 + epd_pwm_active(5);
1.372 +
1.373 + EPD_Pin_RESET(LOW);
1.374 + // Delay_ms(5);
1.375 + epd_pwm_active(5);
1.376 +
1.377 + EPD_Pin_RESET(HIGH);
1.378 + // Delay_ms(5);
1.379 + epd_pwm_active(5);
1.380 +
1.381 + // wait for COG to become ready
1.382 + while (HIGH == epd_get_busy()) {
1.383 + epd_pwm_active(10);
1.384 + }
1.385 +
1.386 + // channel select
1.387 + bsp_delayUs(10);
1.388 + SPI_send(CU8(0x70, 0x01), 2);
1.389 + bsp_delayUs(10);
1.390 + SPI_send(epd.channel_select, epd.channel_select_length);
1.391 +
1.392 + // DC/DC frequency
1.393 + bsp_delayUs(10);
1.394 + SPI_send(CU8(0x70, 0x06), 2);
1.395 + bsp_delayUs(10);
1.396 + SPI_send(CU8(0x72, 0xff), 2);
1.397 +
1.398 + // high power mode osc
1.399 + bsp_delayUs(10);
1.400 + SPI_send(CU8(0x70, 0x07), 2);
1.401 + bsp_delayUs(10);
1.402 + SPI_send(CU8(0x72, 0x9d), 2);
1.403 +
1.404 +
1.405 + // disable ADC
1.406 + bsp_delayUs(10);
1.407 + SPI_send(CU8(0x70, 0x08), 2);
1.408 + bsp_delayUs(10);
1.409 + SPI_send(CU8(0x72, 0x00), 2);
1.410 +
1.411 + // Vcom level
1.412 + bsp_delayUs(10);
1.413 + SPI_send(CU8(0x70, 0x09), 2);
1.414 + bsp_delayUs(10);
1.415 + SPI_send(CU8(0x72, 0xd0, 0x00), 3);
1.416 +
1.417 + // gate and source voltage levels
1.418 + bsp_delayUs(10);
1.419 + SPI_send(CU8(0x70, 0x04), 2);
1.420 + bsp_delayUs(10);
1.421 + SPI_send(epd.gate_source, epd.gate_source_length);
1.422 +
1.423 + // Delay_ms(5); //???
1.424 + epd_pwm_active(5);
1.425 +
1.426 + // driver latch on
1.427 + bsp_delayUs(10);
1.428 + SPI_send(CU8(0x70, 0x03), 2);
1.429 + bsp_delayUs(10);
1.430 + SPI_send(CU8(0x72, 0x01), 2);
1.431 +
1.432 + // driver latch off
1.433 + bsp_delayUs(10);
1.434 + SPI_send(CU8(0x70, 0x03), 2);
1.435 + bsp_delayUs(10);
1.436 + SPI_send(CU8(0x72, 0x00), 2);
1.437 +
1.438 + // Delay_ms(5);
1.439 + epd_pwm_active(5);
1.440 +
1.441 + // charge pump positive voltage on
1.442 + bsp_delayUs(10);
1.443 + SPI_send(CU8(0x70, 0x05), 2);
1.444 + bsp_delayUs(10);
1.445 + SPI_send(CU8(0x72, 0x01), 2);
1.446 +
1.447 + // final delay before PWM off
1.448 + // Delay_ms(30);
1.449 + // PWM_stop(this->EPD_Pin_PWM);
1.450 + epd_pwm_active(30);
1.451 +
1.452 + // charge pump negative voltage on
1.453 + bsp_delayUs(10);
1.454 + SPI_send(CU8(0x70, 0x05), 2);
1.455 + bsp_delayUs(10);
1.456 + SPI_send(CU8(0x72, 0x03), 2);
1.457 +
1.458 + bsp_delayMs(30);
1.459 +
1.460 + // Vcom driver on
1.461 + bsp_delayUs(10);
1.462 + SPI_send(CU8(0x70, 0x05), 2);
1.463 + bsp_delayUs(10);
1.464 + SPI_send(CU8(0x72, 0x0f), 2);
1.465 +
1.466 + bsp_delayMs(30);
1.467 +
1.468 + // output enable to disable
1.469 + bsp_delayUs(10);
1.470 + SPI_send(CU8(0x70, 0x02), 2);
1.471 + bsp_delayUs(10);
1.472 + SPI_send(CU8(0x72, 0x24), 2);
1.473 +}
1.474 +
1.475 +
1.476 +void EPD_end(void) {
1.477 +
1.478 + EPD_frame_fixed(0x55, EPD_normal); // dummy frame
1.479 + EPD_line(0x7fffu, 0, 0x55, FALSE, EPD_normal); // dummy_line
1.480 +
1.481 + bsp_delayMs(25);
1.482 +
1.483 + EPD_Pin_BORDER(LOW);
1.484 + bsp_delayMs(30);
1.485 +
1.486 + EPD_Pin_BORDER(HIGH);
1.487 +
1.488 + // latch reset turn on
1.489 + bsp_delayUs(10);
1.490 + SPI_send(CU8(0x70, 0x03), 2);
1.491 + bsp_delayUs(10);
1.492 + SPI_send(CU8(0x72, 0x01), 2);
1.493 +
1.494 + // output enable off
1.495 + bsp_delayUs(10);
1.496 + SPI_send(CU8(0x70, 0x02), 2);
1.497 + bsp_delayUs(10);
1.498 + SPI_send(CU8(0x72, 0x05), 2);
1.499 +
1.500 + // Vcom power off
1.501 + bsp_delayUs(10);
1.502 + SPI_send(CU8(0x70, 0x05), 2);
1.503 + bsp_delayUs(10);
1.504 + SPI_send(CU8(0x72, 0x0e), 2);
1.505 +
1.506 + // power off negative charge pump
1.507 + bsp_delayUs(10);
1.508 + SPI_send(CU8(0x70, 0x05), 2);
1.509 + bsp_delayUs(10);
1.510 + SPI_send(CU8(0x72, 0x02), 2);
1.511 +
1.512 + // discharge
1.513 + bsp_delayUs(10);
1.514 + SPI_send(CU8(0x70, 0x04), 2);
1.515 + bsp_delayUs(10);
1.516 + SPI_send(CU8(0x72, 0x0c), 2);
1.517 +
1.518 + bsp_delayMs(120);
1.519 +
1.520 + // all charge pumps off
1.521 + bsp_delayUs(10);
1.522 + SPI_send(CU8(0x70, 0x05), 2);
1.523 + bsp_delayUs(10);
1.524 + SPI_send(CU8(0x72, 0x00), 2);
1.525 +
1.526 + // turn of osc
1.527 + bsp_delayUs(10);
1.528 + SPI_send(CU8(0x70, 0x07), 2);
1.529 + bsp_delayUs(10);
1.530 + SPI_send(CU8(0x72, 0x0d), 2);
1.531 +
1.532 + // discharge internal - 1
1.533 + bsp_delayUs(10);
1.534 + SPI_send(CU8(0x70, 0x04), 2);
1.535 + bsp_delayUs(10);
1.536 + SPI_send(CU8(0x72, 0x50), 2);
1.537 +
1.538 + bsp_delayMs(40);
1.539 +
1.540 + // discharge internal - 2
1.541 + bsp_delayUs(10);
1.542 + SPI_send(CU8(0x70, 0x04), 2);
1.543 + bsp_delayUs(10);
1.544 + SPI_send(CU8(0x72, 0xA0), 2);
1.545 +
1.546 + bsp_delayMs(40);
1.547 +
1.548 + // discharge internal - 3
1.549 + bsp_delayUs(10);
1.550 + SPI_send(CU8(0x70, 0x04), 2);
1.551 + bsp_delayUs(10);
1.552 + SPI_send(CU8(0x72, 0x00), 2);
1.553 +
1.554 + // turn of power and all signals
1.555 + EPD_Pin_RESET(LOW);
1.556 + EPD_Pin_PANEL_ON(LOW);
1.557 + EPD_Pin_BORDER(LOW);
1.558 + EPD_Pin_EPD_CS(LOW);
1.559 +
1.560 + EPD_Pin_DISCHARGE(HIGH);
1.561 +
1.562 + SPI_put(0x00);
1.563 +
1.564 + bsp_delayMs(150);
1.565 +
1.566 + EPD_Pin_DISCHARGE(LOW);
1.567 +}
1.568 +
1.569 +
1.570 +void EPD_setFactor(int16_t temperature) {
1.571 + epd.factored_stage_time = epd.stage_time * EPD_temperature_to_factor_10x(temperature) / 10;
1.572 +}
1.573 +
1.574 +// clear display (anything -> white)
1.575 +void EPD_clear() {
1.576 + EPD_frame_fixed_repeat(0xff, EPD_compensate);
1.577 + EPD_frame_fixed_repeat(0xff, EPD_white);
1.578 + EPD_frame_fixed_repeat(0xaa, EPD_inverse);
1.579 + EPD_frame_fixed_repeat(0xaa, EPD_normal);
1.580 +}
1.581 +
1.582 +// assuming a clear (white) screen output an image (PROGMEM data)
1.583 +void EPD_image(PROGMEM const uint8_t *image) {
1.584 + EPD_frame_fixed_repeat(0xaa, EPD_compensate);
1.585 + EPD_frame_fixed_repeat(0xaa, EPD_white);
1.586 + EPD_frame_data_repeat(image, EPD_inverse);
1.587 + EPD_frame_data_repeat(image, EPD_normal);
1.588 +}
1.589 +
1.590 +// change from old image to new image (PROGMEM data)
1.591 +void EPD_image_progmem(PROGMEM const uint8_t *old_image, PROGMEM const uint8_t *new_image) {
1.592 + EPD_frame_data_repeat(old_image, EPD_compensate);
1.593 + EPD_frame_data_repeat(old_image, EPD_white);
1.594 + EPD_frame_data_repeat(new_image, EPD_inverse);
1.595 + EPD_frame_data_repeat(new_image, EPD_normal);
1.596 +}
1.597 +
1.598 +#if defined(EPD_ENABLE_EXTRA_SRAM)
1.599 +// change from old image to new image (SRAM version)
1.600 +void EPD_image_sram(const uint8_t *old_image, const uint8_t *new_image) {
1.601 + EPD_frame_sram_repeat(old_image, EPD_compensate);
1.602 + EPD_frame_sram_repeat(old_image, EPD_white);
1.603 + EPD_frame_sram_repeat(new_image, EPD_inverse);
1.604 + EPD_frame_sram_repeat(new_image, EPD_normal);
1.605 +}
1.606 +#endif
1.607 +
1.608 +
1.609 +static void SPI_put(uint8_t c) {
1.610 + uint8_t placeholder = c;
1.611 + bsp_spiWrite(&placeholder, 1);
1.612 +}
1.613 +
1.614 +
1.615 +static void SPI_put_wait(uint8_t c) {
1.616 +
1.617 + SPI_put(c);
1.618 +
1.619 + // wait for COG ready
1.620 + while (HIGH == epd_get_busy()) {
1.621 + }
1.622 +}
1.623 +
1.624 +
1.625 +static void SPI_send(const uint8_t *buffer, uint16_t length) {
1.626 + // CS low
1.627 + EPD_Pin_EPD_CS(LOW);
1.628 +
1.629 + bsp_spiWrite((uint8_t*)buffer, length);
1.630 +
1.631 + // CS high
1.632 + EPD_Pin_EPD_CS(HIGH);
1.633 +}
1.634 +
1.635 +static void EPD_Pin_init()
1.636 +{
1.637 + bsp_pinDir(6, 1); // CS
1.638 + bsp_pinDir(7, 0); // Driver Busy
1.639 + bsp_pinDir(8, 1); // Border
1.640 + bsp_pinDir(11, 1); // Pwm
1.641 + bsp_pinDir(12, 1); // Reset
1.642 + bsp_pinDir(13, 1); // Panel On
1.643 + bsp_pinDir(14, 1); // Discharge
1.644 +}
1.645 +
1.646 +static void EPD_Pin_EPD_CS(EPD_pinstate pin)
1.647 +{
1.648 + if (HIGH == pin) {
1.649 + bsp_pinSet(6);
1.650 + }
1.651 + else {
1.652 + bsp_pinClr(6);
1.653 + }
1.654 +}
1.655 +
1.656 +static void EPD_Pin_RESET(EPD_pinstate pin)
1.657 +{
1.658 + if (HIGH == pin) {
1.659 + bsp_pinSet(12);
1.660 + }
1.661 + else {
1.662 + bsp_pinClr(12);
1.663 + }
1.664 +}
1.665 +
1.666 +static void EPD_Pin_PANEL_ON(EPD_pinstate pin)
1.667 +{
1.668 + if (HIGH == pin) {
1.669 + bsp_pinSet(13);
1.670 + }
1.671 + else {
1.672 + bsp_pinClr(13);
1.673 + }
1.674 +}
1.675 +
1.676 +static void EPD_Pin_DISCHARGE(EPD_pinstate pin)
1.677 +{
1.678 + if (HIGH == pin) {
1.679 + bsp_pinSet(14);
1.680 + }
1.681 + else {
1.682 + bsp_pinClr(14);
1.683 + }
1.684 +}
1.685 +
1.686 +static void EPD_Pin_BORDER(EPD_pinstate pin)
1.687 +{
1.688 + if (HIGH == pin) {
1.689 + bsp_pinSet(8);
1.690 + }
1.691 + else {
1.692 + bsp_pinClr(8);
1.693 + }
1.694 +}
1.695 +
1.696 +static EPD_pinstate epd_get_busy(void)
1.697 +{
1.698 + if (bsp_pinState(7))
1.699 + return HIGH;
1.700 + else
1.701 + return LOW;
1.702 +}
1.703 +
1.704 +static void epd_pwm_active(uint16_t delayInMs)
1.705 +{
1.706 + uint16_t numOfIterations;
1.707 +
1.708 + numOfIterations = delayInMs * 100;
1.709 +
1.710 + for(; numOfIterations > 0; numOfIterations--)
1.711 + {
1.712 + bsp_pinSet(11);
1.713 + bsp_delayUs(5); //100kHz
1.714 + bsp_pinClr(11);
1.715 + bsp_delayUs(5);
1.716 + }
1.717 +}