A lib to handle a E-Paper display from Pervasive Displays. There is a interface board from Embedded Artists. The lib can handle graphic and text drawing and is using external fonts.
Dependents: epaper_mbed_130411_KL25Z epaper_mbed_test epaper_KL25Z_2 test_he10 ... more
The E-Paper display from Pervasive Displays with a interface board is available from Embedded Artists : http://www.embeddedartists.com/products/displays/lcd_27_epaper.php The 2.7 inch display have 264*176 pixel, monochrome.
Technology
You can look at the webside from Pervasive to see how the display works. http://www.pervasivedisplays.com/technology/home
This type of display have ultra low power consumption - due to its bi-stable nature. It requires only very little power to update the display and needs no power to maintain an image. You can disconnect the display - the image is still there. The viewing angle is like real paper - near 180°.
There are also some disadvantages of this technology. To change the image, we have to rewrite the full display in 4 steps. Invert, clear, invert new, new image. This process is visible and take a while -2s at room temperature. If it gets colder the display reacts slower and the interface timing has to be slow down. To compensate this, there is a LM75 temp sensor on the interface board. We also need ram to double buffer the display. 264 * 176 / 8 = 5808 Byte. To double buffer we need 11616 byte of ram. This is no problem for most mbed devices, but it will not run on the LPC11U24 or LPC800-MAX.
Interface
The graphic data is transferred to the display via spi. The maximum speed is 12Mhz. There are also some control signal and the I2C for the temperature sensor. Together we need 12 signals.
Display | mbed LPC1768 | mbed KL25Z | signal type |
---|---|---|---|
1 GND | GND | GND | GND |
2 3V3 | VOUT | P3V3 | 3.3 V power |
3 SCK | p7 | PTD1 | SCK |
4 MOSI | p5 | PTD2 | MOSI |
5 MISO | p6 | PTD3 | MISO |
6 SSEL | p8 | PTC17 | GPIO |
7 Busy | p13 | PTA16 | GPIO |
8 Border | p10 | PTD6 | GPIO |
9 SCL | p27 | PTE1 | SCL |
10 SDA | p28 | PTE0 | SDA |
11 PWM | p26 | PTD4 | PWM |
12 Reset | p12 | PTA17 | GPIO |
13 Power control | p9 | PTD7 | GPIO |
14 Discharge | p11 | PTE31 | GPIO |
Software
Fonts
How to get nice looking fonts ?
To print characters to a graphic screen we need a font. To code a font by paper is ok for a small lcd, but for a 264*176 pixel display we need bigger fonts. A 12*12 pixel font is readable, but it a lot of work to construct it by hand.
Fonts can be made with the GLCD Font Creator also from http://www.mikroe.com .
With this program you can load a window font and convert it into a c-array. To use this Font with my lib you have to add 4 parameter at the beginning of the font array. - the number of byte / char - the vertial size in pixel - the horizontal size in pixel - the number of byte per vertical line (it is vertical size / 8 ) You also have to change the type of array to char[]. After that you can switch between different fonts with set_font(unsigned char* font); The horizontal size of each character is also stored in the font. It look better if you use bigger fonts or italic. The letter M is wider than a l.
Here are some Fonts from me : http://mbed.org/users/dreschpe/code/TFT_fonts/
The small made for the mbed lab board can also be used : http://mbed.org/users/dreschpe/code/LCD_fonts/
And from Peter Holzleitner : http://mbed.org/users/pholzleitner/code/SourceCodePro31-SB/
Text commands :
You can use the claim() function to redirect the output to stdout or stderr to the display. After claim(stdout) you can simply use the printf function without the classname to print to the display. All other printf from other libs are also redirected to the display if you use this.
- printf(...); print text and variables to the buffer with format options.
- locate(x,y); function is used to setup the cursor position. x,y are the pixel position.
Graphics
Graphic commands :
- cls(); Fill the screen with background color
- pixel(x,y,color); set a single pixel at x,y with 1 : black or 0 : white
- line(x0,y0,x1,y1,color); draw a line from x0,y0 to x1,y1 with color
- rect(x0,y0,x1,y1,color); draw a rectangle x0,y0 to x1,y1 with color
- fillrect(x0,y0,x1,y1,color); draw a filled rectangle
- circle( x0,y0,radius ,color); draw a circle around x0,y0 with radius
- fillcircle(x0,y0,radius ,color); draw a filled circle around x0,y0 with radius
- setmode(mode); Set the drawing mode for all functions. mode can be NORMAL -> 0 is white and 1 is black or XOR -> the new pixel is a xor between the old display and the new. This mode will invert if a black pixel is draw over a black pixel.
- print_bm(Bitmap ,x0,x0); Print a monochrome bitmap array. This graphic is defined by a Bitmap struct :
The pixel date array :
static char arm_logo[]={ 0x00,0x00... };
and a Bitmap struct:
Bitmap bitmARM = { 48, // XSize 48, // YSize 6, // Bytes in Line arm_logo // Pointer to picture data };
To convert a graphic into a byte array we can use the tool Picture Converter 1bpp from http://www.embedded-tools.de.vu/ With this tool we load a image, press the convert button and save it as C-Header file. We have to save with horizontal orientation, so we have to press "No". Inside this file we find the data array which we can copy into a header file.
All this commands are writing to the frame buffer only ! To change the active display we have to call
- write_disp(); This will refresh the display.
Sample code
test code for the LPC1768: http://mbed.org/users/dreschpe/code/epaper_mbed_test/
test code for KL25Z: http://mbed.org/users/dreschpe/code/epaper_mbed_130411_KL25Z/
#include "mbed.h" #include "EaEpaper.h" #include "Arial28x28.h" #include "Arial12x12.h" #include "font_big.h" #include "graphics.h" 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); // print a frame epaper.set_font((unsigned char*) Arial12x12); // change font epaper.locate(5,60); // set cursor epaper.printf("small Font"); // print text epaper.set_font((unsigned char*) Neu42x35); // change font epaper.locate(5,70); //set cursor epaper.printf("big Font"); // change font epaper.write_disp(); // update screen // update display wait(5); // wait 5 s epaper.fillcircle(180,30,22,1); // paint filled circle epaper.circle(160,150,20,1); // paint circle epaper.write_disp(); // update screen // update display }
EPD.h@0:fedcef5319f5, 2013-11-09 (annotated)
- Committer:
- dreschpe
- Date:
- Sat Nov 09 23:37:43 2013 +0000
- Revision:
- 0:fedcef5319f5
- Child:
- 3:1371614703cd
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.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dreschpe | 0:fedcef5319f5 | 1 | // Copyright 2013 Pervasive Displays, Inc. |
dreschpe | 0:fedcef5319f5 | 2 | // |
dreschpe | 0:fedcef5319f5 | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
dreschpe | 0:fedcef5319f5 | 4 | // you may not use this file except in compliance with the License. |
dreschpe | 0:fedcef5319f5 | 5 | // You may obtain a copy of the License at: |
dreschpe | 0:fedcef5319f5 | 6 | // |
dreschpe | 0:fedcef5319f5 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
dreschpe | 0:fedcef5319f5 | 8 | // |
dreschpe | 0:fedcef5319f5 | 9 | // Unless required by applicable law or agreed to in writing, |
dreschpe | 0:fedcef5319f5 | 10 | // software distributed under the License is distributed on an |
dreschpe | 0:fedcef5319f5 | 11 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
dreschpe | 0:fedcef5319f5 | 12 | // express or implied. See the License for the specific language |
dreschpe | 0:fedcef5319f5 | 13 | // governing permissions and limitations under the License. |
dreschpe | 0:fedcef5319f5 | 14 | |
dreschpe | 0:fedcef5319f5 | 15 | #ifndef EPD_H |
dreschpe | 0:fedcef5319f5 | 16 | #define EPD_H |
dreschpe | 0:fedcef5319f5 | 17 | |
dreschpe | 0:fedcef5319f5 | 18 | #include "mbed.h" |
dreschpe | 0:fedcef5319f5 | 19 | #include "BurstSPI.h" |
dreschpe | 0:fedcef5319f5 | 20 | |
dreschpe | 0:fedcef5319f5 | 21 | #define PROGMEM |
dreschpe | 0:fedcef5319f5 | 22 | |
dreschpe | 0:fedcef5319f5 | 23 | |
dreschpe | 0:fedcef5319f5 | 24 | typedef enum { |
dreschpe | 0:fedcef5319f5 | 25 | EPD_1_44, // 128 x 96 |
dreschpe | 0:fedcef5319f5 | 26 | EPD_2_0, // 200 x 96 |
dreschpe | 0:fedcef5319f5 | 27 | EPD_2_7 // 264 x 176 |
dreschpe | 0:fedcef5319f5 | 28 | } EPD_size; |
dreschpe | 0:fedcef5319f5 | 29 | |
dreschpe | 0:fedcef5319f5 | 30 | typedef enum { // Image pixel -> Display pixel |
dreschpe | 0:fedcef5319f5 | 31 | EPD_compensate, // B -> W, W -> B (Current Image) |
dreschpe | 0:fedcef5319f5 | 32 | EPD_white, // B -> N, W -> W (Current Image) |
dreschpe | 0:fedcef5319f5 | 33 | EPD_inverse, // B -> N, W -> B (New Image) |
dreschpe | 0:fedcef5319f5 | 34 | EPD_normal // B -> B, W -> W (New Image) |
dreschpe | 0:fedcef5319f5 | 35 | } EPD_stage; |
dreschpe | 0:fedcef5319f5 | 36 | |
dreschpe | 0:fedcef5319f5 | 37 | typedef void EPD_reader(void *buffer, uint32_t address, uint16_t length); |
dreschpe | 0:fedcef5319f5 | 38 | |
dreschpe | 0:fedcef5319f5 | 39 | class EPD_Class { |
dreschpe | 0:fedcef5319f5 | 40 | private: |
dreschpe | 0:fedcef5319f5 | 41 | DigitalOut EPD_Pin_PANEL_ON; |
dreschpe | 0:fedcef5319f5 | 42 | DigitalOut EPD_Pin_BORDER; |
dreschpe | 0:fedcef5319f5 | 43 | DigitalOut EPD_Pin_DISCHARGE; |
dreschpe | 0:fedcef5319f5 | 44 | PwmOut EPD_Pin_PWM; |
dreschpe | 0:fedcef5319f5 | 45 | DigitalOut EPD_Pin_RESET; |
dreschpe | 0:fedcef5319f5 | 46 | DigitalIn EPD_Pin_BUSY; |
dreschpe | 0:fedcef5319f5 | 47 | DigitalOut EPD_Pin_EPD_CS; |
dreschpe | 0:fedcef5319f5 | 48 | BurstSPI spi_; |
dreschpe | 0:fedcef5319f5 | 49 | |
dreschpe | 0:fedcef5319f5 | 50 | EPD_size size; |
dreschpe | 0:fedcef5319f5 | 51 | uint16_t stage_time; |
dreschpe | 0:fedcef5319f5 | 52 | uint16_t factored_stage_time; |
dreschpe | 0:fedcef5319f5 | 53 | uint16_t lines_per_display; |
dreschpe | 0:fedcef5319f5 | 54 | uint16_t dots_per_line; |
dreschpe | 0:fedcef5319f5 | 55 | uint16_t bytes_per_line; |
dreschpe | 0:fedcef5319f5 | 56 | uint16_t bytes_per_scan; |
dreschpe | 0:fedcef5319f5 | 57 | PROGMEM const uint8_t *gate_source; |
dreschpe | 0:fedcef5319f5 | 58 | uint16_t gate_source_length; |
dreschpe | 0:fedcef5319f5 | 59 | PROGMEM const uint8_t *channel_select; |
dreschpe | 0:fedcef5319f5 | 60 | uint16_t channel_select_length; |
dreschpe | 0:fedcef5319f5 | 61 | |
dreschpe | 0:fedcef5319f5 | 62 | bool filler; |
dreschpe | 0:fedcef5319f5 | 63 | |
dreschpe | 0:fedcef5319f5 | 64 | void SPI_put(uint8_t c); |
dreschpe | 0:fedcef5319f5 | 65 | void SPI_put_wait(uint8_t c, DigitalIn busy_pin); |
dreschpe | 0:fedcef5319f5 | 66 | void SPI_send(DigitalOut cs_pin, const uint8_t *buffer, uint16_t length); |
dreschpe | 0:fedcef5319f5 | 67 | |
dreschpe | 0:fedcef5319f5 | 68 | public: |
dreschpe | 0:fedcef5319f5 | 69 | // power up and power down the EPD panel |
dreschpe | 0:fedcef5319f5 | 70 | void begin(); |
dreschpe | 0:fedcef5319f5 | 71 | void end(); |
dreschpe | 0:fedcef5319f5 | 72 | |
dreschpe | 0:fedcef5319f5 | 73 | void setFactor(int temperature = 25) { |
dreschpe | 0:fedcef5319f5 | 74 | this->factored_stage_time = this->stage_time * this->temperature_to_factor_10x(temperature) / 10; |
dreschpe | 0:fedcef5319f5 | 75 | } |
dreschpe | 0:fedcef5319f5 | 76 | |
dreschpe | 0:fedcef5319f5 | 77 | // clear display (anything -> white) |
dreschpe | 0:fedcef5319f5 | 78 | void clear() { |
dreschpe | 0:fedcef5319f5 | 79 | this->frame_fixed_repeat(0xff, EPD_compensate); |
dreschpe | 0:fedcef5319f5 | 80 | this->frame_fixed_repeat(0xff, EPD_white); |
dreschpe | 0:fedcef5319f5 | 81 | this->frame_fixed_repeat(0xaa, EPD_inverse); |
dreschpe | 0:fedcef5319f5 | 82 | this->frame_fixed_repeat(0xaa, EPD_normal); |
dreschpe | 0:fedcef5319f5 | 83 | } |
dreschpe | 0:fedcef5319f5 | 84 | |
dreschpe | 0:fedcef5319f5 | 85 | // assuming a clear (white) screen output an image (PROGMEM data) |
dreschpe | 0:fedcef5319f5 | 86 | void image(const uint8_t *image) { |
dreschpe | 0:fedcef5319f5 | 87 | this->frame_fixed_repeat(0xaa, EPD_compensate); |
dreschpe | 0:fedcef5319f5 | 88 | this->frame_fixed_repeat(0xaa, EPD_white); |
dreschpe | 0:fedcef5319f5 | 89 | this->frame_data_repeat(image, EPD_inverse); |
dreschpe | 0:fedcef5319f5 | 90 | this->frame_data_repeat(image, EPD_normal); |
dreschpe | 0:fedcef5319f5 | 91 | } |
dreschpe | 0:fedcef5319f5 | 92 | |
dreschpe | 0:fedcef5319f5 | 93 | // change from old image to new image (PROGMEM data) |
dreschpe | 0:fedcef5319f5 | 94 | void image(const uint8_t *old_image, const uint8_t *new_image) { |
dreschpe | 0:fedcef5319f5 | 95 | this->frame_data_repeat(old_image, EPD_compensate); |
dreschpe | 0:fedcef5319f5 | 96 | this->frame_data_repeat(old_image, EPD_white); |
dreschpe | 0:fedcef5319f5 | 97 | this->frame_data_repeat(new_image, EPD_inverse); |
dreschpe | 0:fedcef5319f5 | 98 | this->frame_data_repeat(new_image, EPD_normal); |
dreschpe | 0:fedcef5319f5 | 99 | } |
dreschpe | 0:fedcef5319f5 | 100 | |
dreschpe | 0:fedcef5319f5 | 101 | #if defined(EPD_ENABLE_EXTRA_SRAM) |
dreschpe | 0:fedcef5319f5 | 102 | |
dreschpe | 0:fedcef5319f5 | 103 | // change from old image to new image (SRAM version) |
dreschpe | 0:fedcef5319f5 | 104 | void image_sram(const uint8_t *old_image, const uint8_t *new_image) { |
dreschpe | 0:fedcef5319f5 | 105 | this->frame_sram_repeat(old_image, EPD_compensate); |
dreschpe | 0:fedcef5319f5 | 106 | this->frame_sram_repeat(old_image, EPD_white); |
dreschpe | 0:fedcef5319f5 | 107 | this->frame_sram_repeat(new_image, EPD_inverse); |
dreschpe | 0:fedcef5319f5 | 108 | this->frame_sram_repeat(new_image, EPD_normal); |
dreschpe | 0:fedcef5319f5 | 109 | } |
dreschpe | 0:fedcef5319f5 | 110 | #endif |
dreschpe | 0:fedcef5319f5 | 111 | |
dreschpe | 0:fedcef5319f5 | 112 | // Low level API calls |
dreschpe | 0:fedcef5319f5 | 113 | // =================== |
dreschpe | 0:fedcef5319f5 | 114 | |
dreschpe | 0:fedcef5319f5 | 115 | // single frame refresh |
dreschpe | 0:fedcef5319f5 | 116 | void frame_fixed(uint8_t fixed_value, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 117 | void frame_data(const uint8_t *new_image, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 118 | #if defined(EPD_ENABLE_EXTRA_SRAM) |
dreschpe | 0:fedcef5319f5 | 119 | void frame_sram(const uint8_t *new_image, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 120 | #endif |
dreschpe | 0:fedcef5319f5 | 121 | void frame_cb(uint32_t address, EPD_reader *reader, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 122 | |
dreschpe | 0:fedcef5319f5 | 123 | // stage_time frame refresh |
dreschpe | 0:fedcef5319f5 | 124 | void frame_fixed_repeat(uint8_t fixed_value, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 125 | void frame_data_repeat(const uint8_t *new_image, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 126 | #if defined(EPD_ENABLE_EXTRA_SRAM) |
dreschpe | 0:fedcef5319f5 | 127 | void frame_sram_repeat(const uint8_t *new_image, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 128 | #endif |
dreschpe | 0:fedcef5319f5 | 129 | void frame_cb_repeat(uint32_t address, EPD_reader *reader, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 130 | |
dreschpe | 0:fedcef5319f5 | 131 | // convert temperature to compensation factor |
dreschpe | 0:fedcef5319f5 | 132 | int temperature_to_factor_10x(int temperature); |
dreschpe | 0:fedcef5319f5 | 133 | |
dreschpe | 0:fedcef5319f5 | 134 | // single line display - very low-level |
dreschpe | 0:fedcef5319f5 | 135 | // also has to handle AVR progmem |
dreschpe | 0:fedcef5319f5 | 136 | void line(uint16_t line, const uint8_t *data, uint8_t fixed_value, bool read_progmem, EPD_stage stage); |
dreschpe | 0:fedcef5319f5 | 137 | |
dreschpe | 0:fedcef5319f5 | 138 | // inline static void attachInterrupt(); |
dreschpe | 0:fedcef5319f5 | 139 | // inline static void detachInterrupt(); |
dreschpe | 0:fedcef5319f5 | 140 | |
dreschpe | 0:fedcef5319f5 | 141 | EPD_Class(EPD_size size, |
dreschpe | 0:fedcef5319f5 | 142 | PinName panel_on_pin, |
dreschpe | 0:fedcef5319f5 | 143 | PinName border_pin, |
dreschpe | 0:fedcef5319f5 | 144 | PinName discharge_pin, |
dreschpe | 0:fedcef5319f5 | 145 | PinName pwm_pin, |
dreschpe | 0:fedcef5319f5 | 146 | PinName reset_pin, |
dreschpe | 0:fedcef5319f5 | 147 | PinName busy_pin, |
dreschpe | 0:fedcef5319f5 | 148 | PinName chip_select_pin, |
dreschpe | 0:fedcef5319f5 | 149 | PinName mosi, |
dreschpe | 0:fedcef5319f5 | 150 | PinName miso, |
dreschpe | 0:fedcef5319f5 | 151 | PinName sck); |
dreschpe | 0:fedcef5319f5 | 152 | |
dreschpe | 0:fedcef5319f5 | 153 | }; |
dreschpe | 0:fedcef5319f5 | 154 | |
dreschpe | 0:fedcef5319f5 | 155 | #endif |
dreschpe | 0:fedcef5319f5 | 156 |