EaPaper Library for EM027BS013
Dependencies: EM027BS013 TFT_fonts
Fork of EaEpaper by
Revision 0:fedcef5319f5, committed 2013-11-09
- Comitter:
- dreschpe
- Date:
- Sat Nov 09 23:37:43 2013 +0000
- Child:
- 1:90d18805a8a4
- Commit message:
- Lib for using a E-Paper display from Pervasive Displays.; There is a interface board from Embedded Artists.; It can handle graphic and text drawing and is using external fonts.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EPD.cpp Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,613 @@ +// 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" +#include "BurstSPI.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_.fastWrite(*buffer++); + spi_.clearRX(); + } + + // 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); +//}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EPD.h Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,156 @@ +// 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. + +#ifndef EPD_H +#define EPD_H + +#include "mbed.h" +#include "BurstSPI.h" + +#define PROGMEM + + +typedef enum { + EPD_1_44, // 128 x 96 + EPD_2_0, // 200 x 96 + EPD_2_7 // 264 x 176 +} EPD_size; + +typedef enum { // Image pixel -> Display pixel + EPD_compensate, // B -> W, W -> B (Current Image) + EPD_white, // B -> N, W -> W (Current Image) + EPD_inverse, // B -> N, W -> B (New Image) + EPD_normal // B -> B, W -> W (New Image) +} EPD_stage; + +typedef void EPD_reader(void *buffer, uint32_t address, uint16_t length); + +class EPD_Class { +private: + DigitalOut EPD_Pin_PANEL_ON; + DigitalOut EPD_Pin_BORDER; + DigitalOut EPD_Pin_DISCHARGE; + PwmOut EPD_Pin_PWM; + DigitalOut EPD_Pin_RESET; + DigitalIn EPD_Pin_BUSY; + DigitalOut EPD_Pin_EPD_CS; + BurstSPI spi_; + + EPD_size size; + uint16_t stage_time; + uint16_t factored_stage_time; + uint16_t lines_per_display; + uint16_t dots_per_line; + uint16_t bytes_per_line; + uint16_t bytes_per_scan; + PROGMEM const uint8_t *gate_source; + uint16_t gate_source_length; + PROGMEM const uint8_t *channel_select; + uint16_t channel_select_length; + + bool filler; + + void SPI_put(uint8_t c); + void SPI_put_wait(uint8_t c, DigitalIn busy_pin); + void SPI_send(DigitalOut cs_pin, const uint8_t *buffer, uint16_t length); + +public: + // power up and power down the EPD panel + void begin(); + void end(); + + void setFactor(int temperature = 25) { + this->factored_stage_time = this->stage_time * this->temperature_to_factor_10x(temperature) / 10; + } + + // clear display (anything -> white) + void clear() { + this->frame_fixed_repeat(0xff, EPD_compensate); + this->frame_fixed_repeat(0xff, EPD_white); + this->frame_fixed_repeat(0xaa, EPD_inverse); + this->frame_fixed_repeat(0xaa, EPD_normal); + } + + // assuming a clear (white) screen output an image (PROGMEM data) + void image(const uint8_t *image) { + this->frame_fixed_repeat(0xaa, EPD_compensate); + this->frame_fixed_repeat(0xaa, EPD_white); + this->frame_data_repeat(image, EPD_inverse); + this->frame_data_repeat(image, EPD_normal); + } + + // change from old image to new image (PROGMEM data) + void image(const uint8_t *old_image, const uint8_t *new_image) { + this->frame_data_repeat(old_image, EPD_compensate); + this->frame_data_repeat(old_image, EPD_white); + this->frame_data_repeat(new_image, EPD_inverse); + this->frame_data_repeat(new_image, EPD_normal); + } + +#if defined(EPD_ENABLE_EXTRA_SRAM) + + // change from old image to new image (SRAM version) + void image_sram(const uint8_t *old_image, const uint8_t *new_image) { + this->frame_sram_repeat(old_image, EPD_compensate); + this->frame_sram_repeat(old_image, EPD_white); + this->frame_sram_repeat(new_image, EPD_inverse); + this->frame_sram_repeat(new_image, EPD_normal); + } +#endif + + // Low level API calls + // =================== + + // single frame refresh + void frame_fixed(uint8_t fixed_value, EPD_stage stage); + void frame_data(const uint8_t *new_image, EPD_stage stage); +#if defined(EPD_ENABLE_EXTRA_SRAM) + void frame_sram(const uint8_t *new_image, EPD_stage stage); +#endif + void frame_cb(uint32_t address, EPD_reader *reader, EPD_stage stage); + + // stage_time frame refresh + void frame_fixed_repeat(uint8_t fixed_value, EPD_stage stage); + void frame_data_repeat(const uint8_t *new_image, EPD_stage stage); +#if defined(EPD_ENABLE_EXTRA_SRAM) + void frame_sram_repeat(const uint8_t *new_image, EPD_stage stage); +#endif + void frame_cb_repeat(uint32_t address, EPD_reader *reader, EPD_stage stage); + + // convert temperature to compensation factor + int temperature_to_factor_10x(int temperature); + + // single line display - very low-level + // also has to handle AVR progmem + void line(uint16_t line, const uint8_t *data, uint8_t fixed_value, bool read_progmem, EPD_stage stage); + + // inline static void attachInterrupt(); + // inline static void detachInterrupt(); + + 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); + +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EaEpaper.cpp Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,353 @@ + +#include "EaEpaper.h" + +#define EA_IMG_BUF_SZ (5808) // 264 x 176 / 8 = 5808 + +#define LM75A_ADDRESS (0x92) // 0x49 << 1 +#define LM75A_CMD_TEMP 0x00 + +static uint8_t _oldImage[EA_IMG_BUF_SZ]; +static uint8_t _newImage[EA_IMG_BUF_SZ]; + +EaEpaper::EaEpaper(PinName p_on, PinName border, PinName discharge, PinName reset, PinName busy, PinName cs, + PinName pwm, + PinName mosi, PinName miso, PinName sck, + PinName sda, PinName scl, + const char* name): + epd_(EPD_2_7, + p_on, // panel_on_pin + border, // border_pin + discharge, // discharge_pin + pwm, // pwm_pin + reset, // reset_pin + busy, // busy_pin + cs, // chip_select_pin + mosi, // mosi + miso, // miso + sck), // sck + i2c_(sda, scl), + GraphicsDisplay(name) +{ + draw_mode = NORMAL; + memset(_oldImage, 0, EA_IMG_BUF_SZ); + memset(_newImage, 0, EA_IMG_BUF_SZ); +} + + +int EaEpaper::width() +{ + return 264; +} + +int EaEpaper::height() +{ + return 176; +} + + +// erase pixel after power up +void EaEpaper::clear() +{ + epd_.begin(); + epd_.setFactor(readTemperature()/100); + epd_.clear(); + epd_.end(); + + memset(_oldImage, 0, EA_IMG_BUF_SZ); + memset(_newImage, 0, EA_IMG_BUF_SZ); +} + +// update screen _newImage -> _oldImage +void EaEpaper::write_disp(void) +{ + epd_.begin(); + epd_.setFactor(readTemperature()/100); + epd_.image(_oldImage, _newImage); + epd_.end(); + + memcpy(_oldImage, _newImage, EA_IMG_BUF_SZ); +} + +// read LM75A sensor on board to calculate display speed +int32_t EaEpaper::readTemperature() +{ + char buf[2]; + int32_t t = 0; + char reg = LM75A_CMD_TEMP; + + i2c_.write(LM75A_ADDRESS, ®, 1); + i2c_.read(LM75A_ADDRESS, buf, 2); + + t = ((buf[0] << 8) | (buf[1])); + + return ((t * 100) >> 8); +} + +// set one pixel in buffer _newImage + +void EaEpaper::pixel(int x, int y, int color) +{ + // first check parameter + if(x > 263 || y > 175 || x < 0 || y < 0) return; + + if(draw_mode == NORMAL) { + if(color == 0) + _newImage[(x / 8) + ((y-1) * 33)] &= ~(1 << (x%8)); // erase pixel + else + _newImage[(x / 8) + ((y-1) * 33)] |= (1 << (x%8)); // set pixel + } else { // XOR mode + if(color == 1) + _newImage[(x / 8) + ((y-1) * 33)] ^= (1 << (x%8)); // xor pixel + } +} + +// clear screen +void EaEpaper::cls(void) +{ + memset(_newImage, 0, EA_IMG_BUF_SZ); // clear display buffer +} + +// print line +void EaEpaper::line(int x0, int y0, int x1, int y1, int color) +{ + int dx = 0, dy = 0; + int dx_sym = 0, dy_sym = 0; + int dx_x2 = 0, dy_x2 = 0; + int di = 0; + + dx = x1-x0; + dy = y1-y0; + + if (dx > 0) { + dx_sym = 1; + } else { + dx_sym = -1; + } + + if (dy > 0) { + dy_sym = 1; + } else { + dy_sym = -1; + } + + dx = dx_sym*dx; + dy = dy_sym*dy; + + dx_x2 = dx*2; + dy_x2 = dy*2; + + if (dx >= dy) { + di = dy_x2 - dx; + while (x0 != x1) { + + pixel(x0, y0, color); + x0 += dx_sym; + if (di<0) { + di += dy_x2; + } else { + di += dy_x2 - dx_x2; + y0 += dy_sym; + } + } + pixel(x0, y0, color); + } else { + di = dx_x2 - dy; + while (y0 != y1) { + pixel(x0, y0, color); + y0 += dy_sym; + if (di < 0) { + di += dx_x2; + } else { + di += dx_x2 - dy_x2; + x0 += dx_sym; + } + } + pixel(x0, y0, color); + } +} + +// print rect +void EaEpaper::rect(int x0, int y0, int x1, int y1, int color) +{ + + if (x1 > x0) line(x0,y0,x1,y0,color); + else line(x1,y0,x0,y0,color); + + if (y1 > y0) line(x0,y0,x0,y1,color); + else line(x0,y1,x0,y0,color); + + if (x1 > x0) line(x0,y1,x1,y1,color); + else line(x1,y1,x0,y1,color); + + if (y1 > y0) line(x1,y0,x1,y1,color); + else line(x1,y1,x1,y0,color); +} + +// print filled rect +void EaEpaper::fillrect(int x0, int y0, int x1, int y1, int color) +{ + int l,c,i; + if(x0 > x1) { + i = x0; + x0 = x1; + x1 = i; + } + + if(y0 > y1) { + i = y0; + y0 = y1; + y1 = i; + } + + for(l = x0; l<= x1; l ++) { + for(c = y0; c<= y1; c++) { + pixel(l,c,color); + } + } +} + +// print circle +void EaEpaper::circle(int x0, int y0, int r, int color) +{ + int x = -r, y = 0, err = 2-2*r, e2; + do { + pixel(x0-x, y0+y,color); + pixel(x0+x, y0+y,color); + pixel(x0+x, y0-y,color); + pixel(x0-x, y0-y,color); + e2 = err; + if (e2 <= y) { + err += ++y*2+1; + if (-x == y && e2 <= x) e2 = 0; + } + if (e2 > x) err += ++x*2+1; + } while (x <= 0); + +} + +// print filled circle +void EaEpaper::fillcircle(int x0, int y0, int r, int color) +{ + int x = -r, y = 0, err = 2-2*r, e2; + do { + line(x0-x, y0-y, x0-x, y0+y, color); + line(x0+x, y0-y, x0+x, y0+y, color); + e2 = err; + if (e2 <= y) { + err += ++y*2+1; + if (-x == y && e2 <= x) e2 = 0; + } + if (e2 > x) err += ++x*2+1; + } while (x <= 0); +} + +// set drawing mode +void EaEpaper::setmode(int mode) +{ + draw_mode = mode; +} + +// set cursor position +void EaEpaper::locate(int x, int y) +{ + char_x = x; + char_y = y; +} + +// calc char columns +int EaEpaper::columns() +{ + return width() / font[1]; +} + +// calc char rows +int EaEpaper::rows() +{ + return height() / font[2]; +} + +// print char +int EaEpaper::_putc(int value) +{ + if (value == '\n') { // new line + char_x = 0; + char_y = char_y + font[2]; + if (char_y >= height() - font[2]) { + char_y = 0; + } + } else { + character(char_x, char_y, value); + } + return value; +} + +// paint char out of font +void EaEpaper::character(int x, int y, int c) +{ + unsigned int hor,vert,offset,bpl,j,i,b; + unsigned char* zeichen; + unsigned char z,w; + + if ((c < 31) || (c > 127)) return; // test char range + + // read font parameter from start of array + offset = font[0]; // bytes / char + hor = font[1]; // get hor size of font + vert = font[2]; // get vert size of font + bpl = font[3]; // bytes per line + + if (char_x + hor > width()) { + char_x = 0; + char_y = char_y + vert; + if (char_y >= height() - font[2]) { + char_y = 0; + } + } + + zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap + w = zeichen[0]; // width of actual char + // construct the char into the buffer + for (j=0; j<vert; j++) { // vert line + for (i=0; i<hor; i++) { // horz line + z = zeichen[bpl * i + ((j & 0xF8) >> 3)+1]; + b = 1 << (j & 0x07); + if (( z & b ) == 0x00) { + pixel(x+i,y+j,0); + } else { + pixel(x+i,y+j,1); + } + + } + } + + char_x += w; +} + +// set actual font +void EaEpaper::set_font(unsigned char* f) +{ + font = f; +} + +void EaEpaper::print_bm(Bitmap bm, int x, int y) +{ + int h,v,b; + char d; + + for(v=0; v < bm.ySize; v++) { // lines + for(h=0; h < bm.xSize; h++) { // pixel + if(h + x > width()) break; + if(v + y > height()) break; + d = bm.data[bm.Byte_in_Line * v + ((h & 0xF8) >> 3)]; + b = 0x80 >> (h & 0x07); + if((d & b) == 0) { + pixel(x+h,y+v,0); + } else { + pixel(x+h,y+v,1); + } + } + } + +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EaEpaper.h Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,260 @@ +/* mbed library for 264*176 pixel 2.7 INCH E-PAPER DISPLAY from Pervasive Displays + * Copyright (c) 2013 Peter Drescher - DC2PD + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +// 09.11.2013 initial Version + +#ifndef EAEPAPER_H +#define EAEPAPER_H + +/** + * Includes + */ +#include "mbed.h" +#include "EPD.h" +#include "GraphicsDisplay.h" + +// we have to double buffer the display +#define EA_IMG_BUF_SZ (5808) // 264 x 176 / 8 = 5808 + +/** Draw mode + * NORMAl + * XOR set pixel by xor of the screen + */ +enum {NORMAL,XOR}; + +/** Bitmap + */ +struct Bitmap{ + int xSize; + int ySize; + int Byte_in_Line; + char* data; + }; + +/* color definitions */ +#define Black 0x0 +#define White 0x1 + +/** Display control class, based on GraphicsDisplay and TextDisplay + * + * Example: + * @code + * #include "mbed.h" + * #include "EaEpaper.h" + * #include "Arial28x28.h" + * #include "Arial12x12.h" + * #include "font_big.h" + * #include "graphics.h" + + * // the E-Paper board from embedded artists has a LM75 temp sensor to compensate the temperature effect. If it is cold the display reacts slower. + * // The LM75 need a I2C -> 2 pins : sda and scl + * // The display data is written via SPI -> 3 pins : mosi,miso,sck + * // There are also some control signals + * // The pwm pin has to be connected to a PWM enabled pin : pwm + * // The other signals are connected to normal IO`s + * // + * EaEpaper epaper(PTD7, // PWR_CTRL + * PTD6, // BORDER + * PTE31, // DISCHARGE + * PTA17, // RESET_DISP + * PTA16, // BUSY + * PTC17, // SSEL + * PTD4, // PWM + * PTD2,PTD3,PTD1, // MOSI,MISO,SCLK + * PTE0,PTE1); // SDA,SDL + * + * int main() { + * + * epaper.cls(); // clear screen + * epaper.set_font((unsigned char*) Arial28x28); // select the font + * epaper.locate(5,20); // set cursor + * epaper.printf("Hello Mbed"); // print text + * epaper.rect(3,15,150,50,1); // draw frame + * epaper.write_disp(); // update screen + * + * @endcode + */ + + +class EaEpaper : public GraphicsDisplay { + +public: + + /** + * Constructor. + */ + EaEpaper(PinName p_on, PinName border, PinName discharge, PinName reset, PinName busy, PinName cs, // IO-Pins + PinName pwm, // PWM Pin + PinName mosi, PinName miso, PinName sck, // SPI + PinName sda, PinName scl, // I2C + const char* name ="E_Paper"); + + /** Get the width of the screen in pixel + * + * @param + * @returns width of screen in pixel + * + */ + virtual int width(); + + /** Get the height of the screen in pixel + * + * @returns height of screen in pixel + * + */ + virtual int height(); + + + /** + * Clear the display + */ + void clear(); + + /** + * Write image buffer to display + */ + void write_disp(void); + + /** + * set or reset a single pixel + * + * @param x horizontal position + * @param y vertical position + * @param color : 0 white, 1 black + */ + virtual void pixel(int x, int y, int color); + + /** Fill the screen with white + * + */ + virtual void cls(void); + + /** draw a 1 pixel line + * + * @param x0,y0 start point + * @param x1,y1 stop point + * @param color : 0 white, 1 black + */ + void line(int x0, int y0, int x1, int y1, int color); + + /** draw a rect + * + * @param x0,y0 top left corner + * @param x1,y1 down right corner + * @param color : 0 white, 1 black + */ + void rect(int x0, int y0, int x1, int y1, int color); + + /** draw a filled rect + * + * @param x0,y0 top left corner + * @param x1,y1 down right corner + * @param color : 0 white, 1 black + */ + void fillrect(int x0, int y0, int x1, int y1, int color); + + /** draw a circle + * + * @param x0,y0 center + * @param r radius + * @param color : 0 white, 1 black * + */ + void circle(int x0, int y0, int r, int color); + + /** draw a filled circle + * + * @param x0,y0 center + * @param r radius + * @param color : 0 white, 1 black * + */ + void fillcircle(int x0, int y0, int r, int color); + + /** set drawing mode + * @param NORMAL : paint normal color, XOR : paint XOR of current pixels + */ + void setmode(int mode); + + /** setup cursor position + * + * @param x x-position (top left) + * @param y y-position + */ + virtual void locate(int x, int y); + + /** calculate the max number of char in a line + * + * @returns max columns + * depends on actual font size + */ + virtual int columns(); + + /** calculate the max number of columns + * + * @returns max column + * depends on actual font size + */ + virtual int rows(); + + /** put a char on the screen + * + * @param value char to print + * @returns printed char + */ + virtual int _putc(int value); + + /** paint a character on given position out of the active font to the screen buffer + * + * @param x x-position (top left) + * @param y y-position + * @param c char code + */ + virtual void character(int x, int y, int c); + + /** select the font to use + * + * @param f pointer to font array + * + * font array can created with GLCD Font Creator from http://www.mikroe.com + * you have to add 4 parameter at the beginning of the font array to use: + * - the number of byte / char + * - the vertial size in pixel + * - the horizontal size in pixel + * - the number of byte per vertical line + * you also have to change the array to char[] + */ + void set_font(unsigned char* f); + + /** print bitmap to buffer + * + * @param bm struct Bitmap in flash + * @param x x start + * @param y y start + * + */ + void print_bm(Bitmap bm, int x, int y); + + + unsigned char* font; + unsigned int draw_mode; + + private: + + EPD_Class epd_; + I2C i2c_; + unsigned int char_x; + unsigned int char_y; + int32_t readTemperature(); + +}; + + #endif /* EAEPAPER_H */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GraphicsDisplay.cpp Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,176 @@ +/* mbed GraphicsDisplay Display Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + */ + +#include "GraphicsDisplay.h" + +const unsigned char FONT8x8[97][8] = { +0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00, // columns, rows, num_bytes_per_char +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // space 0x20 +0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00, // ! +0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00, // " +0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00, // # +0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00, // $ +0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00, // % +0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00, // & +0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00, // ' +0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00, // ( +0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00, // ) +0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00, // * +0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00, // + +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30, // , +0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, // - +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, // . +0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00, // / (forward slash) +0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00, // 0 0x30 +0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00, // 1 +0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00, // 2 +0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00, // 3 +0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00, // 4 +0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00, // 5 +0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00, // 6 +0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00, // 7 +0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00, // 8 +0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00, // 9 +0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00, // : +0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30, // ; +0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00, // < +0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00, // = +0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00, // > +0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00, // ? +0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00, // @ 0x40 +0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00, // A +0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00, // B +0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00, // C +0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00, // D +0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00, // E +0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00, // F +0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00, // G +0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00, // H +0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // I +0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, // J +0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00, // K +0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00, // L +0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00, // M +0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00, // N +0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00, // O +0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00, // P 0x50 +0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00, // Q +0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00, // R +0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00, // S +0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00, // T +0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00, // U +0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00, // V +0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00, // W +0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00, // X +0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00, // Y +0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00, // Z +0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00, // [ +0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00, // \ (back slash) +0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00, // ] +0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00, // ^ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, // _ +0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00, // ` 0x60 +0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00, // a +0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00, // b +0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00, // c +0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00, // d +0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00, // e +0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00, // f +0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C, // g +0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00, // h +0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00, // i +0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C, // j +0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00, // k +0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // l +0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00, // m +0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00, // n +0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00, // o +0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78, // p +0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F, // q +0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00, // r +0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00, // s +0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00, // t +0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00, // u +0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00, // v +0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00, // w +0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00, // x +0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C, // y +0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00, // z +0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00, // { +0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00, // | +0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00, // } +0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00, // ~ +0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00}; // DEL + +GraphicsDisplay::GraphicsDisplay(const char *name):TextDisplay(name) { + foreground(0xFFFF); + background(0x0000); +} + +void GraphicsDisplay::character(int column, int row, int value) { + blitbit(column * 8, row * 8, 8, 8, (char*)&(FONT8x8[value - 0x1F][0])); +} + +void GraphicsDisplay::window(int x, int y, int w, int h) { + // current pixel location + _x = x; + _y = y; + // window settings + _x1 = x; + _x2 = x + w - 1; + _y1 = y; + _y2 = y + h - 1; +} + +void GraphicsDisplay::putp(int colour) { + // put pixel at current pixel location + pixel(_x, _y, colour); + // update pixel location based on window settings + _x++; + if(_x > _x2) { + _x = _x1; + _y++; + if(_y > _y2) { + _y = _y1; + } + } +} + +void GraphicsDisplay::fill(int x, int y, int w, int h, int colour) { + window(x, y, w, h); + for(int i=0; i<w*h; i++) { + putp(colour); + } +} + +void GraphicsDisplay::cls() { + fill(0, 0, width(), height(), _background); +} + +void GraphicsDisplay::blit(int x, int y, int w, int h, const int *colour) { + window(x, y, w, h); + for(int i=0; i<w*h; i++) { + putp(colour[i]); + } +} + +void GraphicsDisplay::blitbit(int x, int y, int w, int h, const char* colour) { + window(x, y, w, h); + for(int i = 0; i < w*h; i++) { + char byte = colour[i >> 3]; + int offset = i & 0x7; + int c = ((byte << offset) & 0x80) ? _foreground : _background; + putp(c); + } +} + +int GraphicsDisplay::columns() { + return width() / 8; +} + +int GraphicsDisplay::rows() { + return height() / 8; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GraphicsDisplay.h Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,55 @@ +/* mbed GraphicsDisplay Display Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + * + * A library for providing a common base class for Graphics displays + * To port a new display, derive from this class and implement + * the constructor (setup the display), pixel (put a pixel + * at a location), width and height functions. Everything else + * (locate, printf, putc, cls, window, putp, fill, blit, blitbit) + * will come for free. You can also provide a specialised implementation + * of window and putp to speed up the results + */ + +#ifndef MBED_GRAPHICSDISPLAY_H +#define MBED_GRAPHICSDISPLAY_H + +#include "TextDisplay.h" + +class GraphicsDisplay : public TextDisplay { + +public: + + GraphicsDisplay(const char* name); + + virtual void pixel(int x, int y, int colour) = 0; + virtual int width() = 0; + virtual int height() = 0; + + virtual void window(int x, int y, int w, int h); + virtual void putp(int colour); + + virtual void cls(); + virtual void fill(int x, int y, int w, int h, int colour); + virtual void blit(int x, int y, int w, int h, const int *colour); + virtual void blitbit(int x, int y, int w, int h, const char* colour); + + virtual void character(int column, int row, int value); + virtual int columns(); + virtual int rows(); + +protected: + + // pixel location + short _x; + short _y; + + // window location + short _x1; + short _x2; + short _y1; + short _y2; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextDisplay.cpp Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,77 @@ +/* mbed TextDisplay Display Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + */ + +#include "TextDisplay.h" + +TextDisplay::TextDisplay(const char *name) : Stream(name){ + _row = 0; + _column = 0; + if (name == NULL) { + _path = NULL; + } else { + _path = new char[strlen(name) + 2]; + sprintf(_path, "/%s", name); + } +} + +int TextDisplay::_putc(int value) { + if(value == '\n') { + _column = 0; + _row++; + if(_row >= rows()) { + _row = 0; + } + } else { + character(_column, _row, value); + _column++; + if(_column >= columns()) { + _column = 0; + _row++; + if(_row >= rows()) { + _row = 0; + } + } + } + return value; +} + +// crude cls implementation, should generally be overwritten in derived class +void TextDisplay::cls() { + locate(0, 0); + for(int i=0; i<columns()*rows(); i++) { + putc(' '); + } +} + +void TextDisplay::locate(int column, int row) { + _column = column; + _row = row; +} + +int TextDisplay::_getc() { + return -1; +} + +void TextDisplay::foreground(uint16_t colour) { + _foreground = colour; +} + +void TextDisplay::background(uint16_t colour) { + _background = colour; +} + +bool TextDisplay::claim (FILE *stream) { + if ( _path == NULL) { + fprintf(stderr, "claim requires a name to be given in the instantioator of the TextDisplay instance!\r\n"); + return false; + } + if (freopen(_path, "w", stream) == NULL) { + // Failed, should not happen + return false; + } + // make sure we use line buffering + setvbuf(stdout, NULL, _IOLBF, columns()); + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TextDisplay.h Sat Nov 09 23:37:43 2013 +0000 @@ -0,0 +1,80 @@ +/* mbed TextDisplay Library Base Class + * Copyright (c) 2007-2009 sford + * Released under the MIT License: http://mbed.org/license/mit + * + * A common base class for Text displays + * To port a new display, derive from this class and implement + * the constructor (setup the display), character (put a character + * at a location), rows and columns (number of rows/cols) functions. + * Everything else (locate, printf, putc, cls) will come for free + * + * The model is the display will wrap at the right and bottom, so you can + * keep writing and will always get valid characters. The location is + * maintained internally to the class to make this easy + */ + +#ifndef MBED_TEXTDISPLAY_H +#define MBED_TEXTDISPLAY_H + +#include "mbed.h" + +class TextDisplay : public Stream { +public: + + // functions needing implementation in derived implementation class + /** Create a TextDisplay interface + * + * @param name The name used in the path to access the strean through the filesystem + */ + TextDisplay(const char *name = NULL); + + /** output a character at the given position + * + * @param column column where charater must be written + * @param row where character must be written + * @param c the character to be written to the TextDisplay + */ + virtual void character(int column, int row, int c) = 0; + + /** return number if rows on TextDisplay + * @result number of rows + */ + virtual int rows() = 0; + + /** return number if columns on TextDisplay + * @result number of rows + */ + virtual int columns() = 0; + + // functions that come for free, but can be overwritten + + /** redirect output from a stream (stoud, sterr) to display + * @param stream stream that shall be redirected to the TextDisplay + */ + virtual bool claim (FILE *stream); + + /** clear screen + */ + virtual void cls(); + virtual void locate(int column, int row); + virtual void foreground(uint16_t colour); + virtual void background(uint16_t colour); + // putc (from Stream) + // printf (from Stream) + +protected: + + virtual int _putc(int value); + virtual int _getc(); + + // character location + uint16_t _column; + uint16_t _row; + + // colours + uint16_t _foreground; + uint16_t _background; + char *_path; +}; + +#endif