Library for interacting with seeedstudio epaper

Dependents:   display-puck display-puck

Committer:
sigveseb
Date:
Fri Jul 18 09:20:24 2014 +0000
Revision:
1:2f62e2b80305
Parent:
0:6ac5ba1343bf
clean up;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sigveseb 1:2f62e2b80305 1 // TODO: update copyright notice
sigveseb 1:2f62e2b80305 2
sigveseb 0:6ac5ba1343bf 3 // Copyright 2013 Pervasive Displays, Inc.
sigveseb 0:6ac5ba1343bf 4 //
sigveseb 0:6ac5ba1343bf 5 // Licensed under the Apache License, Version 2.0 (the "License");
sigveseb 0:6ac5ba1343bf 6 // you may not use this file except in compliance with the License.
sigveseb 0:6ac5ba1343bf 7 // You may obtain a copy of the License at:
sigveseb 0:6ac5ba1343bf 8 //
sigveseb 0:6ac5ba1343bf 9 // http://www.apache.org/licenses/LICENSE-2.0
sigveseb 0:6ac5ba1343bf 10 //
sigveseb 0:6ac5ba1343bf 11 // Unless required by applicable law or agreed to in writing,
sigveseb 0:6ac5ba1343bf 12 // software distributed under the License is distributed on an
sigveseb 0:6ac5ba1343bf 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
sigveseb 0:6ac5ba1343bf 14 // express or implied. See the License for the specific language
sigveseb 0:6ac5ba1343bf 15 // governing permissions and limitations under the License.
sigveseb 0:6ac5ba1343bf 16
sigveseb 0:6ac5ba1343bf 17
sigveseb 0:6ac5ba1343bf 18 #include <limits.h>
sigveseb 0:6ac5ba1343bf 19 #include <SPI.h>
sigveseb 0:6ac5ba1343bf 20
sigveseb 0:6ac5ba1343bf 21 #include "EPD.h"
sigveseb 0:6ac5ba1343bf 22 #include <mbed.h>
sigveseb 0:6ac5ba1343bf 23
sigveseb 0:6ac5ba1343bf 24 // inline arrays
sigveseb 0:6ac5ba1343bf 25 #define ARRAY(type, ...) ((type[]){__VA_ARGS__})
sigveseb 0:6ac5ba1343bf 26 #define CU8(...) (ARRAY(const uint8_t, __VA_ARGS__))
sigveseb 0:6ac5ba1343bf 27
sigveseb 0:6ac5ba1343bf 28 Timer timer;
sigveseb 0:6ac5ba1343bf 29 SPI spi(p20, p22, p25);
sigveseb 0:6ac5ba1343bf 30
sigveseb 0:6ac5ba1343bf 31 static void SPI_put(uint8_t c);
sigveseb 0:6ac5ba1343bf 32 static void SPI_put_wait(uint8_t c, DigitalIn busy_pin);
sigveseb 0:6ac5ba1343bf 33 static void SPI_send(DigitalOut cs_pin, const uint8_t *buffer, uint16_t length);
sigveseb 0:6ac5ba1343bf 34 static void SPI_on();
sigveseb 0:6ac5ba1343bf 35
sigveseb 0:6ac5ba1343bf 36
sigveseb 0:6ac5ba1343bf 37 EPD_Class::EPD_Class(PinName Pin_EPD_CS, PinName Pin_PANEL_ON, PinName Pin_BORDER, PinName Pin_DISCHARGE, PinName Pin_PWM, PinName Pin_RESET, PinName Pin_BUSY) :
sigveseb 0:6ac5ba1343bf 38 EPD_Pin_EPD_CS(Pin_EPD_CS),
sigveseb 0:6ac5ba1343bf 39 EPD_Pin_PANEL_ON(Pin_PANEL_ON),
sigveseb 0:6ac5ba1343bf 40 EPD_Pin_BORDER(Pin_BORDER),
sigveseb 0:6ac5ba1343bf 41 EPD_Pin_DISCHARGE(Pin_DISCHARGE),
sigveseb 0:6ac5ba1343bf 42 EPD_Pin_PWM(Pin_PWM),
sigveseb 0:6ac5ba1343bf 43 EPD_Pin_RESET(Pin_RESET),
sigveseb 0:6ac5ba1343bf 44 EPD_Pin_BUSY(Pin_BUSY) {
sigveseb 0:6ac5ba1343bf 45
sigveseb 0:6ac5ba1343bf 46 }
sigveseb 0:6ac5ba1343bf 47
sigveseb 0:6ac5ba1343bf 48 void EPD_Class::begin(EPD_size sz)
sigveseb 0:6ac5ba1343bf 49 {
sigveseb 0:6ac5ba1343bf 50 this->size = sz;
sigveseb 0:6ac5ba1343bf 51 this->stage_time = 480; // milliseconds
sigveseb 0:6ac5ba1343bf 52 this->lines_per_display = 96;
sigveseb 0:6ac5ba1343bf 53 this->dots_per_line = 128;
sigveseb 0:6ac5ba1343bf 54 this->bytes_per_line = 128 / 8;
sigveseb 0:6ac5ba1343bf 55 this->bytes_per_scan = 96 / 4;
sigveseb 0:6ac5ba1343bf 56 this->filler = false;
sigveseb 0:6ac5ba1343bf 57 timer.start();
sigveseb 0:6ac5ba1343bf 58 this->EPD_Pin_PWM.period(1.0/300000.0);
sigveseb 0:6ac5ba1343bf 59
sigveseb 0:6ac5ba1343bf 60
sigveseb 0:6ac5ba1343bf 61 // display size dependant items
sigveseb 0:6ac5ba1343bf 62 {
sigveseb 0:6ac5ba1343bf 63 static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00};
sigveseb 0:6ac5ba1343bf 64 static uint8_t gs[] = {0x72, 0x03};
sigveseb 0:6ac5ba1343bf 65 this->channel_select = cs;
sigveseb 0:6ac5ba1343bf 66 this->channel_select_length = sizeof(cs);
sigveseb 0:6ac5ba1343bf 67 this->gate_source = gs;
sigveseb 0:6ac5ba1343bf 68 this->gate_source_length = sizeof(gs);
sigveseb 0:6ac5ba1343bf 69 }
sigveseb 0:6ac5ba1343bf 70
sigveseb 0:6ac5ba1343bf 71 // set up size structure
sigveseb 0:6ac5ba1343bf 72 switch (size) {
sigveseb 0:6ac5ba1343bf 73 default:
sigveseb 0:6ac5ba1343bf 74 case EPD_1_44: // default so no change
sigveseb 0:6ac5ba1343bf 75 break;
sigveseb 0:6ac5ba1343bf 76
sigveseb 0:6ac5ba1343bf 77 case EPD_2_0: {
sigveseb 0:6ac5ba1343bf 78 this->lines_per_display = 96;
sigveseb 0:6ac5ba1343bf 79 this->dots_per_line = 200;
sigveseb 0:6ac5ba1343bf 80 this->bytes_per_line = 200 / 8;
sigveseb 0:6ac5ba1343bf 81 this->bytes_per_scan = 96 / 4;
sigveseb 0:6ac5ba1343bf 82 this->filler = true;
sigveseb 0:6ac5ba1343bf 83 static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00};
sigveseb 0:6ac5ba1343bf 84 static uint8_t gs[] = {0x72, 0x03};
sigveseb 0:6ac5ba1343bf 85 this->channel_select = cs;
sigveseb 0:6ac5ba1343bf 86 this->channel_select_length = sizeof(cs);
sigveseb 0:6ac5ba1343bf 87 this->gate_source = gs;
sigveseb 0:6ac5ba1343bf 88 this->gate_source_length = sizeof(gs);
sigveseb 0:6ac5ba1343bf 89 break;
sigveseb 0:6ac5ba1343bf 90 }
sigveseb 0:6ac5ba1343bf 91
sigveseb 0:6ac5ba1343bf 92 case EPD_2_7: {
sigveseb 0:6ac5ba1343bf 93 this->stage_time = 630; // milliseconds
sigveseb 0:6ac5ba1343bf 94 this->lines_per_display = 176;
sigveseb 0:6ac5ba1343bf 95 this->dots_per_line = 264;
sigveseb 0:6ac5ba1343bf 96 this->bytes_per_line = 264 / 8;
sigveseb 0:6ac5ba1343bf 97 this->bytes_per_scan = 176 / 4;
sigveseb 0:6ac5ba1343bf 98 this->filler = true;
sigveseb 0:6ac5ba1343bf 99 static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00};
sigveseb 0:6ac5ba1343bf 100 static uint8_t gs[] = {0x72, 0x00};
sigveseb 0:6ac5ba1343bf 101 this->channel_select = cs;
sigveseb 0:6ac5ba1343bf 102 this->channel_select_length = sizeof(cs);
sigveseb 0:6ac5ba1343bf 103 this->gate_source = gs;
sigveseb 0:6ac5ba1343bf 104 this->gate_source_length = sizeof(gs);
sigveseb 0:6ac5ba1343bf 105 break;
sigveseb 0:6ac5ba1343bf 106 }
sigveseb 0:6ac5ba1343bf 107 }
sigveseb 0:6ac5ba1343bf 108
sigveseb 0:6ac5ba1343bf 109 this->factored_stage_time = this->stage_time;
sigveseb 0:6ac5ba1343bf 110 }
sigveseb 0:6ac5ba1343bf 111
sigveseb 0:6ac5ba1343bf 112
sigveseb 0:6ac5ba1343bf 113 void EPD_Class::start() {
sigveseb 0:6ac5ba1343bf 114
sigveseb 0:6ac5ba1343bf 115 this->EPD_Pin_PWM = 0.5;
sigveseb 0:6ac5ba1343bf 116 this->EPD_Pin_RESET = 0;
sigveseb 0:6ac5ba1343bf 117 this->EPD_Pin_PANEL_ON = 0;
sigveseb 0:6ac5ba1343bf 118 this->EPD_Pin_DISCHARGE = 0;
sigveseb 0:6ac5ba1343bf 119 this->EPD_Pin_BORDER = 0;
sigveseb 0:6ac5ba1343bf 120 this->EPD_Pin_EPD_CS = 0;
sigveseb 0:6ac5ba1343bf 121
sigveseb 0:6ac5ba1343bf 122
sigveseb 0:6ac5ba1343bf 123 spi.format(8,0);
sigveseb 0:6ac5ba1343bf 124 spi.frequency(10000000);
sigveseb 0:6ac5ba1343bf 125 SPI_on();
sigveseb 0:6ac5ba1343bf 126
sigveseb 0:6ac5ba1343bf 127 wait_ms(5);
sigveseb 0:6ac5ba1343bf 128 this->EPD_Pin_PANEL_ON = 1;
sigveseb 0:6ac5ba1343bf 129 wait_ms(10);
sigveseb 0:6ac5ba1343bf 130
sigveseb 0:6ac5ba1343bf 131 this->EPD_Pin_RESET = 1;
sigveseb 0:6ac5ba1343bf 132 this->EPD_Pin_BORDER = 1;
sigveseb 0:6ac5ba1343bf 133 this->EPD_Pin_EPD_CS = 1;
sigveseb 0:6ac5ba1343bf 134 wait_ms(5);
sigveseb 0:6ac5ba1343bf 135
sigveseb 0:6ac5ba1343bf 136 this->EPD_Pin_RESET = 0;
sigveseb 0:6ac5ba1343bf 137 wait_ms(5);
sigveseb 0:6ac5ba1343bf 138
sigveseb 0:6ac5ba1343bf 139 this->EPD_Pin_RESET = 1;
sigveseb 0:6ac5ba1343bf 140 wait_ms(5);
sigveseb 0:6ac5ba1343bf 141
sigveseb 0:6ac5ba1343bf 142 // wait for COG to become ready
sigveseb 0:6ac5ba1343bf 143 while (this->EPD_Pin_BUSY) {
sigveseb 0:6ac5ba1343bf 144 }
sigveseb 0:6ac5ba1343bf 145
sigveseb 0:6ac5ba1343bf 146 // channel select
sigveseb 0:6ac5ba1343bf 147 wait_us(10);
sigveseb 0:6ac5ba1343bf 148 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x01), 2);
sigveseb 0:6ac5ba1343bf 149 wait_us(10);
sigveseb 0:6ac5ba1343bf 150 SPI_send(this->EPD_Pin_EPD_CS, this->channel_select, this->channel_select_length);
sigveseb 0:6ac5ba1343bf 151
sigveseb 0:6ac5ba1343bf 152 // DC/DC frequency
sigveseb 0:6ac5ba1343bf 153 wait_us(10);
sigveseb 0:6ac5ba1343bf 154 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x06), 2);
sigveseb 0:6ac5ba1343bf 155 wait_us(10);
sigveseb 0:6ac5ba1343bf 156 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xff), 2);
sigveseb 0:6ac5ba1343bf 157
sigveseb 0:6ac5ba1343bf 158 // high power mode osc
sigveseb 0:6ac5ba1343bf 159 wait_us(10);
sigveseb 0:6ac5ba1343bf 160 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x07), 2);
sigveseb 0:6ac5ba1343bf 161 wait_us(10);
sigveseb 0:6ac5ba1343bf 162 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x9d), 2);
sigveseb 0:6ac5ba1343bf 163
sigveseb 0:6ac5ba1343bf 164
sigveseb 0:6ac5ba1343bf 165 // disable ADC
sigveseb 0:6ac5ba1343bf 166 wait_us(10);
sigveseb 0:6ac5ba1343bf 167 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x08), 2);
sigveseb 0:6ac5ba1343bf 168 wait_us(10);
sigveseb 0:6ac5ba1343bf 169 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
sigveseb 0:6ac5ba1343bf 170
sigveseb 0:6ac5ba1343bf 171 // Vcom level
sigveseb 0:6ac5ba1343bf 172 wait_us(10);
sigveseb 0:6ac5ba1343bf 173 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x09), 2);
sigveseb 0:6ac5ba1343bf 174 wait_us(10);
sigveseb 0:6ac5ba1343bf 175 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xd0, 0x00), 3);
sigveseb 0:6ac5ba1343bf 176
sigveseb 0:6ac5ba1343bf 177 // gate and source voltage levels
sigveseb 0:6ac5ba1343bf 178 wait_us(10);
sigveseb 0:6ac5ba1343bf 179 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
sigveseb 0:6ac5ba1343bf 180 wait_us(10);
sigveseb 0:6ac5ba1343bf 181 SPI_send(this->EPD_Pin_EPD_CS, this->gate_source, this->gate_source_length);
sigveseb 0:6ac5ba1343bf 182
sigveseb 0:6ac5ba1343bf 183
sigveseb 0:6ac5ba1343bf 184 this->EPD_Pin_PWM = 0.5;
sigveseb 0:6ac5ba1343bf 185 wait_ms(5); // pwm toggle >= 5ms
sigveseb 0:6ac5ba1343bf 186
sigveseb 0:6ac5ba1343bf 187 // driver latch on
sigveseb 0:6ac5ba1343bf 188 wait_us(10);
sigveseb 0:6ac5ba1343bf 189 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2);
sigveseb 0:6ac5ba1343bf 190 wait_us(10);
sigveseb 0:6ac5ba1343bf 191 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2);
sigveseb 0:6ac5ba1343bf 192
sigveseb 0:6ac5ba1343bf 193 // driver latch off
sigveseb 0:6ac5ba1343bf 194 wait_us(10);
sigveseb 0:6ac5ba1343bf 195 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2);
sigveseb 0:6ac5ba1343bf 196 wait_us(10);
sigveseb 0:6ac5ba1343bf 197 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
sigveseb 0:6ac5ba1343bf 198
sigveseb 0:6ac5ba1343bf 199 wait_ms(5);
sigveseb 0:6ac5ba1343bf 200
sigveseb 0:6ac5ba1343bf 201 // charge pump positive voltage on
sigveseb 0:6ac5ba1343bf 202 wait_us(10);
sigveseb 0:6ac5ba1343bf 203 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
sigveseb 0:6ac5ba1343bf 204 wait_us(10);
sigveseb 0:6ac5ba1343bf 205 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2);
sigveseb 0:6ac5ba1343bf 206
sigveseb 0:6ac5ba1343bf 207 // final delay before PWM off
sigveseb 0:6ac5ba1343bf 208 wait_ms(30);
sigveseb 0:6ac5ba1343bf 209 this->EPD_Pin_PWM = 0;
sigveseb 0:6ac5ba1343bf 210
sigveseb 0:6ac5ba1343bf 211 // charge pump negative voltage on
sigveseb 0:6ac5ba1343bf 212 wait_us(10);
sigveseb 0:6ac5ba1343bf 213 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
sigveseb 0:6ac5ba1343bf 214 wait_us(10);
sigveseb 0:6ac5ba1343bf 215 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x03), 2);
sigveseb 0:6ac5ba1343bf 216
sigveseb 0:6ac5ba1343bf 217 wait_ms(30);
sigveseb 0:6ac5ba1343bf 218
sigveseb 0:6ac5ba1343bf 219 // Vcom driver on
sigveseb 0:6ac5ba1343bf 220 wait_us(10);
sigveseb 0:6ac5ba1343bf 221 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
sigveseb 0:6ac5ba1343bf 222 wait_us(10);
sigveseb 0:6ac5ba1343bf 223 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0f), 2);
sigveseb 0:6ac5ba1343bf 224
sigveseb 0:6ac5ba1343bf 225 wait_ms(30);
sigveseb 0:6ac5ba1343bf 226
sigveseb 0:6ac5ba1343bf 227 // output enable to disable
sigveseb 0:6ac5ba1343bf 228 wait_us(10);
sigveseb 0:6ac5ba1343bf 229 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2);
sigveseb 0:6ac5ba1343bf 230 wait_us(10);
sigveseb 0:6ac5ba1343bf 231 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x24), 2);
sigveseb 0:6ac5ba1343bf 232 }
sigveseb 0:6ac5ba1343bf 233
sigveseb 0:6ac5ba1343bf 234
sigveseb 0:6ac5ba1343bf 235 void EPD_Class::end()
sigveseb 0:6ac5ba1343bf 236 {
sigveseb 0:6ac5ba1343bf 237 // dummy frame
sigveseb 0:6ac5ba1343bf 238 //this->frame_fixed(0x55, EPD_normal);
sigveseb 0:6ac5ba1343bf 239 // dummy line and border
sigveseb 0:6ac5ba1343bf 240 if (EPD_1_44 == this->size) {
sigveseb 0:6ac5ba1343bf 241 // only for 1.44" EPD
sigveseb 0:6ac5ba1343bf 242 this->line(0x7fffu, 0, 0xaa, false, EPD_normal);
sigveseb 0:6ac5ba1343bf 243
sigveseb 0:6ac5ba1343bf 244 wait_ms(250);
sigveseb 0:6ac5ba1343bf 245
sigveseb 0:6ac5ba1343bf 246 }
sigveseb 0:6ac5ba1343bf 247 else {
sigveseb 0:6ac5ba1343bf 248 // all other display sizes
sigveseb 0:6ac5ba1343bf 249 this->line(0x7fffu, 0, 0x55, false, EPD_normal);
sigveseb 0:6ac5ba1343bf 250
sigveseb 0:6ac5ba1343bf 251 wait_ms(25);
sigveseb 0:6ac5ba1343bf 252
sigveseb 0:6ac5ba1343bf 253 this->EPD_Pin_BORDER = 0;
sigveseb 0:6ac5ba1343bf 254 wait_ms(250);
sigveseb 0:6ac5ba1343bf 255 this->EPD_Pin_BORDER = 1;
sigveseb 0:6ac5ba1343bf 256 }
sigveseb 0:6ac5ba1343bf 257 SPI_on();
sigveseb 0:6ac5ba1343bf 258 // latch reset turn on
sigveseb 0:6ac5ba1343bf 259 wait_us(10);
sigveseb 0:6ac5ba1343bf 260 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2);
sigveseb 0:6ac5ba1343bf 261 wait_us(10);
sigveseb 0:6ac5ba1343bf 262 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2);
sigveseb 0:6ac5ba1343bf 263
sigveseb 0:6ac5ba1343bf 264 // output enable off
sigveseb 0:6ac5ba1343bf 265 wait_us(10);
sigveseb 0:6ac5ba1343bf 266 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2);
sigveseb 0:6ac5ba1343bf 267 wait_us(10);
sigveseb 0:6ac5ba1343bf 268 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x05), 2);
sigveseb 0:6ac5ba1343bf 269
sigveseb 0:6ac5ba1343bf 270 // Vcom power off
sigveseb 0:6ac5ba1343bf 271 wait_us(10);
sigveseb 0:6ac5ba1343bf 272 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
sigveseb 0:6ac5ba1343bf 273 wait_us(10);
sigveseb 0:6ac5ba1343bf 274 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0e), 2);
sigveseb 0:6ac5ba1343bf 275
sigveseb 0:6ac5ba1343bf 276 // power off negative charge pump
sigveseb 0:6ac5ba1343bf 277 wait_us(10);
sigveseb 0:6ac5ba1343bf 278 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
sigveseb 0:6ac5ba1343bf 279 wait_us(10);
sigveseb 0:6ac5ba1343bf 280 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x02), 2);
sigveseb 0:6ac5ba1343bf 281
sigveseb 0:6ac5ba1343bf 282 // discharge
sigveseb 0:6ac5ba1343bf 283 wait_us(10);
sigveseb 0:6ac5ba1343bf 284 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
sigveseb 0:6ac5ba1343bf 285 wait_us(10);
sigveseb 0:6ac5ba1343bf 286 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0c), 2);
sigveseb 0:6ac5ba1343bf 287
sigveseb 0:6ac5ba1343bf 288 wait_ms(120);
sigveseb 0:6ac5ba1343bf 289
sigveseb 0:6ac5ba1343bf 290 // all charge pumps off
sigveseb 0:6ac5ba1343bf 291 wait_us(10);
sigveseb 0:6ac5ba1343bf 292 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
sigveseb 0:6ac5ba1343bf 293 wait_us(10);
sigveseb 0:6ac5ba1343bf 294 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
sigveseb 0:6ac5ba1343bf 295
sigveseb 0:6ac5ba1343bf 296 // turn of osc
sigveseb 0:6ac5ba1343bf 297 wait_us(10);
sigveseb 0:6ac5ba1343bf 298 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x07), 2);
sigveseb 0:6ac5ba1343bf 299 wait_us(10);
sigveseb 0:6ac5ba1343bf 300 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0d), 2);
sigveseb 0:6ac5ba1343bf 301
sigveseb 0:6ac5ba1343bf 302 // discharge internal - 1
sigveseb 0:6ac5ba1343bf 303 wait_us(10);
sigveseb 0:6ac5ba1343bf 304 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
sigveseb 0:6ac5ba1343bf 305 wait_us(10);
sigveseb 0:6ac5ba1343bf 306 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x50), 2);
sigveseb 0:6ac5ba1343bf 307
sigveseb 0:6ac5ba1343bf 308 wait_ms(40);
sigveseb 0:6ac5ba1343bf 309
sigveseb 0:6ac5ba1343bf 310 // discharge internal - 2
sigveseb 0:6ac5ba1343bf 311 wait_us(10);
sigveseb 0:6ac5ba1343bf 312 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
sigveseb 0:6ac5ba1343bf 313 wait_us(10);
sigveseb 0:6ac5ba1343bf 314 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xA0), 2);
sigveseb 0:6ac5ba1343bf 315
sigveseb 0:6ac5ba1343bf 316 wait_ms(40);
sigveseb 0:6ac5ba1343bf 317
sigveseb 0:6ac5ba1343bf 318 // discharge internal - 3
sigveseb 0:6ac5ba1343bf 319 wait_us(10);
sigveseb 0:6ac5ba1343bf 320 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
sigveseb 0:6ac5ba1343bf 321 wait_us(10);
sigveseb 0:6ac5ba1343bf 322 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
sigveseb 0:6ac5ba1343bf 323 // turn of power and all signals
sigveseb 0:6ac5ba1343bf 324 //
sigveseb 0:6ac5ba1343bf 325
sigveseb 0:6ac5ba1343bf 326 wait_ms(10);
sigveseb 0:6ac5ba1343bf 327 this->EPD_Pin_RESET = 0;
sigveseb 0:6ac5ba1343bf 328 this->EPD_Pin_PANEL_ON = 0;
sigveseb 0:6ac5ba1343bf 329 this->EPD_Pin_BORDER = 0;
sigveseb 0:6ac5ba1343bf 330
sigveseb 0:6ac5ba1343bf 331 // discharge pulse
sigveseb 0:6ac5ba1343bf 332 this->EPD_Pin_DISCHARGE = 1;
sigveseb 0:6ac5ba1343bf 333 wait_ms(250);
sigveseb 0:6ac5ba1343bf 334 this->EPD_Pin_DISCHARGE = 0;
sigveseb 0:6ac5ba1343bf 335
sigveseb 0:6ac5ba1343bf 336 EPD_Pin_EPD_CS = 1;
sigveseb 0:6ac5ba1343bf 337 }
sigveseb 0:6ac5ba1343bf 338
sigveseb 0:6ac5ba1343bf 339
sigveseb 0:6ac5ba1343bf 340 // convert a temperature in Celcius to
sigveseb 0:6ac5ba1343bf 341 // the scale factor for frame_*_repeat methods
sigveseb 0:6ac5ba1343bf 342 int EPD_Class::temperature_to_factor_10x(int temperature)
sigveseb 0:6ac5ba1343bf 343 {
sigveseb 0:6ac5ba1343bf 344 if (temperature <= -10) {
sigveseb 0:6ac5ba1343bf 345 return 170;
sigveseb 0:6ac5ba1343bf 346 } else if (temperature <= -5) {
sigveseb 0:6ac5ba1343bf 347 return 120;
sigveseb 0:6ac5ba1343bf 348 } else if (temperature <= 5) {
sigveseb 0:6ac5ba1343bf 349 return 80;
sigveseb 0:6ac5ba1343bf 350 } else if (temperature <= 10) {
sigveseb 0:6ac5ba1343bf 351 return 40;
sigveseb 0:6ac5ba1343bf 352 } else if (temperature <= 15) {
sigveseb 0:6ac5ba1343bf 353 return 30;
sigveseb 0:6ac5ba1343bf 354 } else if (temperature <= 20) {
sigveseb 0:6ac5ba1343bf 355 return 20;
sigveseb 0:6ac5ba1343bf 356 } else if (temperature <= 40) {
sigveseb 0:6ac5ba1343bf 357 return 10;
sigveseb 0:6ac5ba1343bf 358 }
sigveseb 0:6ac5ba1343bf 359 return 7;
sigveseb 0:6ac5ba1343bf 360 }
sigveseb 0:6ac5ba1343bf 361
sigveseb 0:6ac5ba1343bf 362
sigveseb 0:6ac5ba1343bf 363 // One frame of data is the number of lines * rows. For example:
sigveseb 0:6ac5ba1343bf 364 // The 1.44” frame of data is 96 lines * 128 dots.
sigveseb 0:6ac5ba1343bf 365 // The 2” frame of data is 96 lines * 200 dots.
sigveseb 0:6ac5ba1343bf 366 // The 2.7” frame of data is 176 lines * 264 dots.
sigveseb 0:6ac5ba1343bf 367
sigveseb 0:6ac5ba1343bf 368 // the image is arranged by line which matches the display size
sigveseb 0:6ac5ba1343bf 369 // so smallest would have 96 * 32 bytes
sigveseb 0:6ac5ba1343bf 370
sigveseb 0:6ac5ba1343bf 371 void EPD_Class::frame_fixed(uint8_t fixed_value, EPD_stage stage, int from_line, int to_line)
sigveseb 0:6ac5ba1343bf 372 {
sigveseb 0:6ac5ba1343bf 373 for (uint8_t line = from_line; line < to_line; line++)
sigveseb 0:6ac5ba1343bf 374 {
sigveseb 0:6ac5ba1343bf 375 this->line(line, 0, fixed_value, false, stage);
sigveseb 0:6ac5ba1343bf 376 }
sigveseb 0:6ac5ba1343bf 377 }
sigveseb 0:6ac5ba1343bf 378
sigveseb 0:6ac5ba1343bf 379 void EPD_Class::frame_data(const uint8_t *image, EPD_stage stage, int from_line, int to_line)
sigveseb 0:6ac5ba1343bf 380 {
sigveseb 0:6ac5ba1343bf 381 for (uint8_t line = from_line; line < to_line; line++)
sigveseb 0:6ac5ba1343bf 382 {
sigveseb 1:2f62e2b80305 383 this->line(line, &image[(line - from_line) * this->bytes_per_line], 0, true, stage);
sigveseb 0:6ac5ba1343bf 384 }
sigveseb 0:6ac5ba1343bf 385 }
sigveseb 0:6ac5ba1343bf 386
sigveseb 0:6ac5ba1343bf 387
sigveseb 0:6ac5ba1343bf 388 void EPD_Class::frame_fixed_repeat(uint8_t fixed_value, EPD_stage stage, int from_line, int to_line)
sigveseb 0:6ac5ba1343bf 389 {
sigveseb 0:6ac5ba1343bf 390 long stage_time = this->factored_stage_time;
sigveseb 0:6ac5ba1343bf 391 do {
sigveseb 0:6ac5ba1343bf 392 unsigned long t_start = timer.read_ms();
sigveseb 0:6ac5ba1343bf 393 this->frame_fixed(fixed_value, stage, from_line, to_line);
sigveseb 0:6ac5ba1343bf 394 unsigned long t_end = timer.read_ms();
sigveseb 0:6ac5ba1343bf 395 if (t_end > t_start) {
sigveseb 0:6ac5ba1343bf 396 stage_time -= t_end - t_start;
sigveseb 0:6ac5ba1343bf 397 } else {
sigveseb 0:6ac5ba1343bf 398 stage_time -= t_start - t_end + 1 + ULONG_MAX;
sigveseb 0:6ac5ba1343bf 399 }
sigveseb 0:6ac5ba1343bf 400 } while (stage_time > 0);
sigveseb 0:6ac5ba1343bf 401 }
sigveseb 0:6ac5ba1343bf 402
sigveseb 0:6ac5ba1343bf 403
sigveseb 0:6ac5ba1343bf 404 void EPD_Class::frame_data_repeat(const uint8_t *image, EPD_stage stage, int from_line, int to_line)
sigveseb 0:6ac5ba1343bf 405 {
sigveseb 0:6ac5ba1343bf 406
sigveseb 0:6ac5ba1343bf 407 long stage_time = this->factored_stage_time;
sigveseb 0:6ac5ba1343bf 408
sigveseb 0:6ac5ba1343bf 409 do {
sigveseb 0:6ac5ba1343bf 410 unsigned long t_start = timer.read_ms();
sigveseb 0:6ac5ba1343bf 411 this->frame_data(image, stage, from_line, to_line);
sigveseb 0:6ac5ba1343bf 412 unsigned long t_end = timer.read_ms();
sigveseb 0:6ac5ba1343bf 413 if (t_end > t_start) {
sigveseb 0:6ac5ba1343bf 414 stage_time -= t_end - t_start;
sigveseb 0:6ac5ba1343bf 415 } else {
sigveseb 0:6ac5ba1343bf 416 stage_time -= t_start - t_end + 1 + ULONG_MAX;
sigveseb 0:6ac5ba1343bf 417 }
sigveseb 0:6ac5ba1343bf 418 } while (stage_time > 0);
sigveseb 0:6ac5ba1343bf 419
sigveseb 0:6ac5ba1343bf 420 }
sigveseb 0:6ac5ba1343bf 421
sigveseb 0:6ac5ba1343bf 422 void EPD_Class::line(uint16_t line, const uint8_t *data, uint8_t fixed_value, bool read_progmem, EPD_stage stage)
sigveseb 0:6ac5ba1343bf 423 {
sigveseb 0:6ac5ba1343bf 424 // charge pump voltage levels
sigveseb 0:6ac5ba1343bf 425 SPI_on();
sigveseb 0:6ac5ba1343bf 426 wait_us(10);
sigveseb 0:6ac5ba1343bf 427 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
sigveseb 0:6ac5ba1343bf 428 wait_us(10);
sigveseb 0:6ac5ba1343bf 429 SPI_send(this->EPD_Pin_EPD_CS, this->gate_source, this->gate_source_length);
sigveseb 0:6ac5ba1343bf 430
sigveseb 0:6ac5ba1343bf 431 // send data
sigveseb 0:6ac5ba1343bf 432 wait_us(10);
sigveseb 0:6ac5ba1343bf 433 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x0a), 2);
sigveseb 0:6ac5ba1343bf 434 wait_us(10);
sigveseb 0:6ac5ba1343bf 435
sigveseb 0:6ac5ba1343bf 436 // CS low
sigveseb 0:6ac5ba1343bf 437 this->EPD_Pin_EPD_CS = 0;
sigveseb 0:6ac5ba1343bf 438 SPI_put_wait(0x72, this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 439
sigveseb 0:6ac5ba1343bf 440 // even pixels
sigveseb 0:6ac5ba1343bf 441 for (uint16_t b = this->bytes_per_line; b > 0; --b)
sigveseb 0:6ac5ba1343bf 442 {
sigveseb 0:6ac5ba1343bf 443 if (0 != data)
sigveseb 0:6ac5ba1343bf 444 {
sigveseb 0:6ac5ba1343bf 445
sigveseb 0:6ac5ba1343bf 446 uint8_t pixels = data[b - 1] & 0xaa;
sigveseb 0:6ac5ba1343bf 447
sigveseb 0:6ac5ba1343bf 448
sigveseb 0:6ac5ba1343bf 449 switch(stage)
sigveseb 0:6ac5ba1343bf 450 {
sigveseb 0:6ac5ba1343bf 451 case EPD_compensate: // B -> W, W -> B (Current Image)
sigveseb 0:6ac5ba1343bf 452 pixels = 0xaa | ((pixels ^ 0xaa) >> 1);
sigveseb 0:6ac5ba1343bf 453 break;
sigveseb 0:6ac5ba1343bf 454
sigveseb 0:6ac5ba1343bf 455 case EPD_white: // B -> N, W -> W (Current Image)
sigveseb 0:6ac5ba1343bf 456 pixels = 0x55 + ((pixels ^ 0xaa) >> 1);
sigveseb 0:6ac5ba1343bf 457 break;
sigveseb 0:6ac5ba1343bf 458
sigveseb 0:6ac5ba1343bf 459 case EPD_inverse: // B -> N, W -> B (New Image)
sigveseb 0:6ac5ba1343bf 460 pixels = 0x55 | (pixels ^ 0xaa);
sigveseb 0:6ac5ba1343bf 461 break;
sigveseb 0:6ac5ba1343bf 462
sigveseb 0:6ac5ba1343bf 463 case EPD_normal: // B -> B, W -> W (New Image)
sigveseb 0:6ac5ba1343bf 464 pixels = 0xaa | (pixels >> 1);
sigveseb 0:6ac5ba1343bf 465 break;
sigveseb 0:6ac5ba1343bf 466 }
sigveseb 0:6ac5ba1343bf 467
sigveseb 0:6ac5ba1343bf 468 SPI_put_wait(pixels, this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 469 }
sigveseb 0:6ac5ba1343bf 470 else
sigveseb 0:6ac5ba1343bf 471 {
sigveseb 0:6ac5ba1343bf 472 SPI_put_wait(fixed_value, this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 473 }
sigveseb 0:6ac5ba1343bf 474 }
sigveseb 0:6ac5ba1343bf 475
sigveseb 0:6ac5ba1343bf 476 // scan line
sigveseb 0:6ac5ba1343bf 477 for (uint16_t b = 0; b < this->bytes_per_scan; ++b)
sigveseb 0:6ac5ba1343bf 478 {
sigveseb 0:6ac5ba1343bf 479 if (line / 4 == b)
sigveseb 0:6ac5ba1343bf 480 {
sigveseb 0:6ac5ba1343bf 481 SPI_put_wait(0xc0 >> (2 * (line & 0x03)), this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 482 }
sigveseb 0:6ac5ba1343bf 483 else
sigveseb 0:6ac5ba1343bf 484 {
sigveseb 0:6ac5ba1343bf 485 SPI_put_wait(0x00, this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 486 }
sigveseb 0:6ac5ba1343bf 487 }
sigveseb 0:6ac5ba1343bf 488
sigveseb 0:6ac5ba1343bf 489 // odd pixels
sigveseb 0:6ac5ba1343bf 490 for (uint16_t b = 0; b < this->bytes_per_line; ++b)
sigveseb 0:6ac5ba1343bf 491 {
sigveseb 0:6ac5ba1343bf 492 if (0 != data)
sigveseb 0:6ac5ba1343bf 493 {
sigveseb 0:6ac5ba1343bf 494 uint8_t pixels = data[b] & 0x55;
sigveseb 0:6ac5ba1343bf 495
sigveseb 0:6ac5ba1343bf 496
sigveseb 0:6ac5ba1343bf 497 switch(stage)
sigveseb 0:6ac5ba1343bf 498 {
sigveseb 0:6ac5ba1343bf 499 case EPD_compensate: // B -> W, W -> B (Current Image)
sigveseb 0:6ac5ba1343bf 500 pixels = 0xaa | (pixels ^ 0x55);
sigveseb 0:6ac5ba1343bf 501 break;
sigveseb 0:6ac5ba1343bf 502 case EPD_white: // B -> N, W -> W (Current Image)
sigveseb 0:6ac5ba1343bf 503 pixels = 0x55 + (pixels ^ 0x55);
sigveseb 0:6ac5ba1343bf 504 break;
sigveseb 0:6ac5ba1343bf 505 case EPD_inverse: // B -> N, W -> B (New Image)
sigveseb 0:6ac5ba1343bf 506 pixels = 0x55 | ((pixels ^ 0x55) << 1);
sigveseb 0:6ac5ba1343bf 507 break;
sigveseb 0:6ac5ba1343bf 508 case EPD_normal: // B -> B, W -> W (New Image)
sigveseb 0:6ac5ba1343bf 509 pixels = 0xaa | pixels;
sigveseb 0:6ac5ba1343bf 510 break;
sigveseb 0:6ac5ba1343bf 511 }
sigveseb 0:6ac5ba1343bf 512 uint8_t p1 = (pixels >> 6) & 0x03;
sigveseb 0:6ac5ba1343bf 513 uint8_t p2 = (pixels >> 4) & 0x03;
sigveseb 0:6ac5ba1343bf 514 uint8_t p3 = (pixels >> 2) & 0x03;
sigveseb 0:6ac5ba1343bf 515 uint8_t p4 = (pixels >> 0) & 0x03;
sigveseb 0:6ac5ba1343bf 516 pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6);
sigveseb 0:6ac5ba1343bf 517 SPI_put_wait(pixels, this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 518 }
sigveseb 0:6ac5ba1343bf 519 else
sigveseb 0:6ac5ba1343bf 520 {
sigveseb 0:6ac5ba1343bf 521 SPI_put_wait(fixed_value, this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 522 }
sigveseb 0:6ac5ba1343bf 523 }
sigveseb 0:6ac5ba1343bf 524
sigveseb 0:6ac5ba1343bf 525 if (this->filler)
sigveseb 0:6ac5ba1343bf 526 {
sigveseb 0:6ac5ba1343bf 527 SPI_put_wait(0x00, this->EPD_Pin_BUSY);
sigveseb 0:6ac5ba1343bf 528 }
sigveseb 0:6ac5ba1343bf 529
sigveseb 0:6ac5ba1343bf 530 // CS high
sigveseb 0:6ac5ba1343bf 531 this->EPD_Pin_EPD_CS = 1;
sigveseb 0:6ac5ba1343bf 532
sigveseb 0:6ac5ba1343bf 533 // output data to panel
sigveseb 0:6ac5ba1343bf 534 wait_us(10);
sigveseb 0:6ac5ba1343bf 535 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2);
sigveseb 0:6ac5ba1343bf 536 wait_us(10);
sigveseb 0:6ac5ba1343bf 537 SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x2f), 2);
sigveseb 0:6ac5ba1343bf 538 }
sigveseb 0:6ac5ba1343bf 539
sigveseb 0:6ac5ba1343bf 540 static void SPI_on() {
sigveseb 0:6ac5ba1343bf 541 wait_us(10);
sigveseb 0:6ac5ba1343bf 542 }
sigveseb 0:6ac5ba1343bf 543
sigveseb 0:6ac5ba1343bf 544
sigveseb 0:6ac5ba1343bf 545 static void SPI_put(uint8_t c) {
sigveseb 0:6ac5ba1343bf 546 spi.write(c);
sigveseb 0:6ac5ba1343bf 547 }
sigveseb 0:6ac5ba1343bf 548
sigveseb 0:6ac5ba1343bf 549
sigveseb 0:6ac5ba1343bf 550 static void SPI_put_wait(uint8_t c, DigitalIn busy_pin) {
sigveseb 0:6ac5ba1343bf 551
sigveseb 0:6ac5ba1343bf 552 SPI_put(c);
sigveseb 0:6ac5ba1343bf 553
sigveseb 0:6ac5ba1343bf 554 // wait for COG ready
sigveseb 0:6ac5ba1343bf 555 while (1 == busy_pin) {
sigveseb 0:6ac5ba1343bf 556 }
sigveseb 0:6ac5ba1343bf 557 }
sigveseb 0:6ac5ba1343bf 558
sigveseb 0:6ac5ba1343bf 559
sigveseb 0:6ac5ba1343bf 560 static void SPI_send(DigitalOut cs_pin, const uint8_t *buffer, uint16_t length) {
sigveseb 0:6ac5ba1343bf 561 // CS low
sigveseb 0:6ac5ba1343bf 562 cs_pin = 0;
sigveseb 0:6ac5ba1343bf 563
sigveseb 0:6ac5ba1343bf 564 // send all data
sigveseb 0:6ac5ba1343bf 565 for (uint16_t i = 0; i < length; ++i) {
sigveseb 0:6ac5ba1343bf 566 SPI_put(*buffer++);
sigveseb 0:6ac5ba1343bf 567 }
sigveseb 0:6ac5ba1343bf 568
sigveseb 0:6ac5ba1343bf 569 // CS high
sigveseb 0:6ac5ba1343bf 570 cs_pin = 1;
sigveseb 0:6ac5ba1343bf 571 }