EaPaper Library for EM027BS013
Dependencies: EM027BS013 TFT_fonts
Fork of EaEpaper by
Diff: EPD.cpp
- Revision:
- 4:672976335e80
- Parent:
- 3:1371614703cd
diff -r 1371614703cd -r 672976335e80 EPD.cpp --- a/EPD.cpp Wed Jun 25 17:43:32 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,610 +0,0 @@ -// Copyright 2013 Pervasive Displays, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at: -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -// express or implied. See the License for the specific language -// governing permissions and limitations under the License. - - - -#include <limits.h> - -#include "EPD.h" -#include "mbed.h" - -// delays - more consistent naming -#define Delay_ms(ms) wait_ms(ms) -#define Delay_us(us) wait_us(us) - -// inline arrays -#define ARRAY(type, ...) ((type[]){__VA_ARGS__}) -#define CU8(...) (ARRAY(const uint8_t, __VA_ARGS__)) - -#define LOW (0) -#define HIGH (1) -#define digitalWrite(pin, state) (pin) = (state) -#define digitalRead(pin) (pin) - -Timer _time; -#define millis() _time.read_ms() -#define millis_start() _time.start() - - -//static void PWM_start(int pin); -//static void PWM_stop(int pin); - -//static void SPI_put(uint8_t c); -//static void SPI_put_wait(uint8_t c, int busy_pin); -//static void SPI_send(uint8_t cs_pin, const uint8_t *buffer, uint16_t length); - - -EPD_Class::EPD_Class(EPD_size size, - PinName panel_on_pin, - PinName border_pin, - PinName discharge_pin, - PinName pwm_pin, - PinName reset_pin, - PinName busy_pin, - PinName chip_select_pin, - PinName mosi, - PinName miso, - PinName sck) : - EPD_Pin_PANEL_ON(panel_on_pin), - EPD_Pin_BORDER(border_pin), - EPD_Pin_DISCHARGE(discharge_pin), - EPD_Pin_PWM(pwm_pin), - EPD_Pin_RESET(reset_pin), - EPD_Pin_BUSY(busy_pin), - EPD_Pin_EPD_CS(chip_select_pin), - spi_(mosi,miso,sck) { - - this->size = size; - this->stage_time = 480; // milliseconds - this->lines_per_display = 96; - this->dots_per_line = 128; - this->bytes_per_line = 128 / 8; - this->bytes_per_scan = 96 / 4; - this->filler = false; - spi_.frequency(12000000); // 12 MHz SPI clock - - // display size dependant items - { - static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00}; - static uint8_t gs[] = {0x72, 0x03}; - this->channel_select = cs; - this->channel_select_length = sizeof(cs); - this->gate_source = gs; - this->gate_source_length = sizeof(gs); - } - - // set up size structure - switch (size) { - default: - case EPD_1_44: // default so no change - break; - - case EPD_2_0: { - this->lines_per_display = 96; - this->dots_per_line = 200; - this->bytes_per_line = 200 / 8; - this->bytes_per_scan = 96 / 4; - this->filler = true; - static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00}; - static uint8_t gs[] = {0x72, 0x03}; - this->channel_select = cs; - this->channel_select_length = sizeof(cs); - this->gate_source = gs; - this->gate_source_length = sizeof(gs); - break; - } - - case EPD_2_7: { - this->stage_time = 630; // milliseconds - this->lines_per_display = 176; - this->dots_per_line = 264; - this->bytes_per_line = 264 / 8; - this->bytes_per_scan = 176 / 4; - this->filler = true; - static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00}; - static uint8_t gs[] = {0x72, 0x00}; - this->channel_select = cs; - this->channel_select_length = sizeof(cs); - this->gate_source = gs; - this->gate_source_length = sizeof(gs); - break; - } - } - - this->factored_stage_time = this->stage_time; -} - - -void EPD_Class::begin() { - - // power up sequence - SPI_put(0x00); - - digitalWrite(this->EPD_Pin_RESET, LOW); - digitalWrite(this->EPD_Pin_PANEL_ON, LOW); - digitalWrite(this->EPD_Pin_DISCHARGE, LOW); - digitalWrite(this->EPD_Pin_BORDER, LOW); - digitalWrite(this->EPD_Pin_EPD_CS, LOW); - - //PWM_start(this->EPD_Pin_PWM); - EPD_Pin_PWM = 0.5; - Delay_ms(5); - digitalWrite(this->EPD_Pin_PANEL_ON, HIGH); - Delay_ms(10); - - digitalWrite(this->EPD_Pin_RESET, HIGH); - digitalWrite(this->EPD_Pin_BORDER, HIGH); - digitalWrite(this->EPD_Pin_EPD_CS, HIGH); - Delay_ms(5); - - digitalWrite(this->EPD_Pin_RESET, LOW); - Delay_ms(5); - - digitalWrite(this->EPD_Pin_RESET, HIGH); - Delay_ms(5); - - // wait for COG to become ready - while (HIGH == digitalRead(this->EPD_Pin_BUSY)) { - } - - // channel select - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x01), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, this->channel_select, this->channel_select_length); - - // DC/DC frequency - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x06), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xff), 2); - - // high power mode osc - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x07), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x9d), 2); - - - // disable ADC - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x08), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2); - - // Vcom level - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x09), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xd0, 0x00), 3); - - // gate and source voltage levels - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, this->gate_source, this->gate_source_length); - - Delay_ms(5); //??? - - // driver latch on - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2); - - // driver latch off - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2); - - Delay_ms(5); - - // charge pump positive voltage on - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2); - - // final delay before PWM off - Delay_ms(30); - //PWM_stop(this->EPD_Pin_PWM); - EPD_Pin_PWM = 0.0; - - // charge pump negative voltage on - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x03), 2); - - Delay_ms(30); - - // Vcom driver on - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0f), 2); - - Delay_ms(30); - - // output enable to disable - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x24), 2); -} - - -void EPD_Class::end() { - - this->frame_fixed(0x55, EPD_normal); // dummy frame - this->line(0x7fffu, 0, 0x55, false, EPD_normal); // dummy_line - - Delay_ms(25); - - digitalWrite(this->EPD_Pin_BORDER, LOW); - Delay_ms(30); - - digitalWrite(this->EPD_Pin_BORDER, HIGH); - - // latch reset turn on - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2); - - // output enable off - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x05), 2); - - // Vcom power off - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0e), 2); - - // power off negative charge pump - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x02), 2); - - // discharge - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0c), 2); - - Delay_ms(120); - - // all charge pumps off - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2); - - // turn of osc - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x07), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0d), 2); - - // discharge internal - 1 - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x50), 2); - - Delay_ms(40); - - // discharge internal - 2 - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xA0), 2); - - Delay_ms(40); - - // discharge internal - 3 - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2); - - // turn of power and all signals - digitalWrite(this->EPD_Pin_RESET, LOW); - digitalWrite(this->EPD_Pin_PANEL_ON, LOW); - digitalWrite(this->EPD_Pin_BORDER, LOW); - digitalWrite(this->EPD_Pin_EPD_CS, LOW); - - digitalWrite(this->EPD_Pin_DISCHARGE, HIGH); - - SPI_put(0x00); - - Delay_ms(150); - - digitalWrite(this->EPD_Pin_DISCHARGE, LOW); -} - - -// convert a temperature in Celcius to -// the scale factor for frame_*_repeat methods -int EPD_Class::temperature_to_factor_10x(int temperature) { - if (temperature <= -10) { - return 170; - } else if (temperature <= -5) { - return 120; - } else if (temperature <= 5) { - return 80; - } else if (temperature <= 10) { - return 40; - } else if (temperature <= 15) { - return 30; - } else if (temperature <= 20) { - return 20; - } else if (temperature <= 40) { - return 10; - } - return 7; -} - - -// One frame of data is the number of lines * rows. For example: -// The 1.44” frame of data is 96 lines * 128 dots. -// The 2” frame of data is 96 lines * 200 dots. -// The 2.7” frame of data is 176 lines * 264 dots. - -// the image is arranged by line which matches the display size -// so smallest would have 96 * 32 bytes - -void EPD_Class::frame_fixed(uint8_t fixed_value, EPD_stage stage) { - for (uint8_t line = 0; line < this->lines_per_display ; ++line) { - this->line(line, 0, fixed_value, false, stage); - } -} - - -void EPD_Class::frame_data(PROGMEM const uint8_t *image, EPD_stage stage){ - for (uint8_t line = 0; line < this->lines_per_display ; ++line) { - this->line(line, &image[line * this->bytes_per_line], 0, true, stage); - } -} - - -#if defined(EPD_ENABLE_EXTRA_SRAM) -void EPD_Class::frame_sram(const uint8_t *image, EPD_stage stage){ - for (uint8_t line = 0; line < this->lines_per_display ; ++line) { - this->line(line, &image[line * this->bytes_per_line], 0, false, stage); - } -} -#endif - - -void EPD_Class::frame_cb(uint32_t address, EPD_reader *reader, EPD_stage stage) { - static uint8_t buffer[264 / 8]; - for (uint8_t line = 0; line < this->lines_per_display; ++line) { - reader(buffer, address + line * this->bytes_per_line, this->bytes_per_line); - this->line(line, buffer, 0, false, stage); - } -} - -void EPD_Class::frame_fixed_repeat(uint8_t fixed_value, EPD_stage stage) { - long stage_time = this->factored_stage_time; - - do { - millis_start(); - unsigned long t_start = millis(); - this->frame_fixed(fixed_value, stage); - unsigned long t_end = millis(); - if (t_end > t_start) { - stage_time -= t_end - t_start; - } else { - stage_time -= t_start - t_end + 1 + ULONG_MAX; - } - } while (stage_time > 0); -} - - -void EPD_Class::frame_data_repeat(PROGMEM const uint8_t *image, EPD_stage stage) { - long stage_time = this->factored_stage_time; - do { - millis_start(); - unsigned long t_start = millis(); - this->frame_data(image, stage); - unsigned long t_end = millis(); - if (t_end > t_start) { - stage_time -= t_end - t_start; - } else { - stage_time -= t_start - t_end + 1 + ULONG_MAX; - } - } while (stage_time > 0); -} - - -#if defined(EPD_ENABLE_EXTRA_SRAM) -void EPD_Class::frame_sram_repeat(const uint8_t *image, EPD_stage stage) { - long stage_time = this->factored_stage_time; - do { - millis_start(); - unsigned long t_start = millis(); - this->frame_sram(image, stage); - unsigned long t_end = millis(); - if (t_end > t_start) { - stage_time -= t_end - t_start; - } else { - stage_time -= t_start - t_end + 1 + ULONG_MAX; - } - } while (stage_time > 0); -} -#endif - - -void EPD_Class::frame_cb_repeat(uint32_t address, EPD_reader *reader, EPD_stage stage) { - long stage_time = this->factored_stage_time; - do { - millis_start(); - unsigned long t_start = millis(); - this->frame_cb(address, reader, stage); - unsigned long t_end = millis(); - if (t_end > t_start) { - stage_time -= t_end - t_start; - } else { - stage_time -= t_start - t_end + 1 + ULONG_MAX; - } - } while (stage_time > 0); -} - - -void EPD_Class::line(uint16_t line, const uint8_t *data, uint8_t fixed_value, bool read_progmem, EPD_stage stage) { - // charge pump voltage levels - - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, this->gate_source, this->gate_source_length); - - // send data - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x0a), 2); - Delay_us(10); - - // CS low - digitalWrite(this->EPD_Pin_EPD_CS, LOW); - SPI_put_wait(0x72, this->EPD_Pin_BUSY); - - // even pixels - for (uint16_t b = this->bytes_per_line; b > 0; --b) { - if (0 != data) { - - uint8_t pixels = data[b - 1] & 0xaa; - - switch(stage) { - case EPD_compensate: // B -> W, W -> B (Current Image) - pixels = 0xaa | ((pixels ^ 0xaa) >> 1); - break; - case EPD_white: // B -> N, W -> W (Current Image) - pixels = 0x55 + ((pixels ^ 0xaa) >> 1); - break; - case EPD_inverse: // B -> N, W -> B (New Image) - pixels = 0x55 | (pixels ^ 0xaa); - break; - case EPD_normal: // B -> B, W -> W (New Image) - pixels = 0xaa | (pixels >> 1); - break; - } - SPI_put_wait(pixels, this->EPD_Pin_BUSY); - } else { - SPI_put_wait(fixed_value, this->EPD_Pin_BUSY); - } } - - // scan line - for (uint16_t b = 0; b < this->bytes_per_scan; ++b) { - if (line / 4 == b) { - SPI_put_wait(0xc0 >> (2 * (line & 0x03)), this->EPD_Pin_BUSY); - } else { - SPI_put_wait(0x00, this->EPD_Pin_BUSY); - } - } - - // odd pixels - for (uint16_t b = 0; b < this->bytes_per_line; ++b) { - if (0 != data) { - - uint8_t pixels = data[b] & 0x55; - - switch(stage) { - case EPD_compensate: // B -> W, W -> B (Current Image) - pixels = 0xaa | (pixels ^ 0x55); - break; - case EPD_white: // B -> N, W -> W (Current Image) - pixels = 0x55 + (pixels ^ 0x55); - break; - case EPD_inverse: // B -> N, W -> B (New Image) - pixels = 0x55 | ((pixels ^ 0x55) << 1); - break; - case EPD_normal: // B -> B, W -> W (New Image) - pixels = 0xaa | pixels; - break; - } - uint8_t p1 = (pixels >> 6) & 0x03; - uint8_t p2 = (pixels >> 4) & 0x03; - uint8_t p3 = (pixels >> 2) & 0x03; - uint8_t p4 = (pixels >> 0) & 0x03; - pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6); - SPI_put_wait(pixels, this->EPD_Pin_BUSY); - } else { - SPI_put_wait(fixed_value, this->EPD_Pin_BUSY); - } - } - - if (this->filler) { - SPI_put_wait(0x00, this->EPD_Pin_BUSY); - } - - // CS high - digitalWrite(this->EPD_Pin_EPD_CS, HIGH); - - // output data to panel - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2); - Delay_us(10); - SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x2f), 2); -} - - -void EPD_Class::SPI_put(uint8_t c) { - - spi_.write(c); - //spi_.fastWrite(c); - - -} - - - -void EPD_Class::SPI_put_wait(uint8_t c, DigitalIn busy_pin) { - - SPI_put(c); - - // wait for COG ready - while (HIGH == digitalRead(busy_pin)) { - } -} - - -void EPD_Class::SPI_send(DigitalOut cs_pin, const uint8_t *buffer, uint16_t length) { - - // CS low - digitalWrite(cs_pin, LOW); - - // send all data - for (uint16_t i = 0; i < length; ++i) { - spi_.write(*buffer++); - } - - // CS high - digitalWrite(cs_pin, HIGH); -} - - -//static void PWM_start(int pin) { -// analogWrite(pin, 128); // 50% duty cycle -//} - - -//static void PWM_stop(int pin) { -// analogWrite(pin, 0); -//}