| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 | 
							- /**
 
-  * Copyright (c) 2017-2018 Tara Keeling
 
-  *				 2020 Philippe G.
 
-  * 
 
-  * This software is released under the MIT License.
 
-  * https://opensource.org/licenses/MIT
 
-  */
 
- #include <stdio.h>
 
- #include <string.h>
 
- #include <stdint.h>
 
- #include <stdbool.h>
 
- #include "freertos/FreeRTOS.h"
 
- #include "freertos/task.h"
 
- #include "driver/gpio.h"
 
- #include <esp_log.h>
 
- #include "gds.h"
 
- #include "gds_private.h"
 
- static char TAG[] = "SSD1675";
 
- const unsigned char EPD_lut_full_update[] = {
 
-     0x80,0x60,0x40,0x00,0x00,0x00,0x00,             //LUT0: BB:     VS 0 ~7
 
-     0x10,0x60,0x20,0x00,0x00,0x00,0x00,             //LUT1: BW:     VS 0 ~7
 
-     0x80,0x60,0x40,0x00,0x00,0x00,0x00,             //LUT2: WB:     VS 0 ~7
 
-     0x10,0x60,0x20,0x00,0x00,0x00,0x00,             //LUT3: WW:     VS 0 ~7
 
-     0x00,0x00,0x00,0x00,0x00,0x00,0x00,             //LUT4: VCOM:   VS 0 ~7
 
-     0x03,0x03,0x00,0x00,0x02,                       // TP0 A~D RP0
 
-     0x09,0x09,0x00,0x00,0x02,                       // TP1 A~D RP1
 
-     0x03,0x03,0x00,0x00,0x02,                       // TP2 A~D RP2
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP3 A~D RP3
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP4 A~D RP4
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP5 A~D RP5
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP6 A~D RP6
 
-     0x15,0x41,0xA8,0x32,0x30,0x0A,
 
- };
 
- const unsigned char EPD_lut_partial_update[]= { //20 bytes
 
-     0x00,0x00,0x00,0x00,0x00,0x00,0x00,             //LUT0: BB:     VS 0 ~7
 
-     0x80,0x00,0x00,0x00,0x00,0x00,0x00,             //LUT1: BW:     VS 0 ~7
 
-     0x40,0x00,0x00,0x00,0x00,0x00,0x00,             //LUT2: WB:     VS 0 ~7
 
-     0x00,0x00,0x00,0x00,0x00,0x00,0x00,             //LUT3: WW:     VS 0 ~7
 
-     0x00,0x00,0x00,0x00,0x00,0x00,0x00,             //LUT4: VCOM:   VS 0 ~7
 
-     0x0A,0x00,0x00,0x00,0x00,                       // TP0 A~D RP0
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP1 A~D RP1
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP2 A~D RP2
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP3 A~D RP3
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP4 A~D RP4
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP5 A~D RP5
 
-     0x00,0x00,0x00,0x00,0x00,                       // TP6 A~D RP6
 
-     0x15,0x41,0xA8,0x32,0x30,0x0A,
 
- };
 
- struct PrivateSpace {
 
- 	int	ReadyPin;
 
- 	uint16_t Height;
 
- };
 
- // Functions are not declared to minimize # of lines
 
- void WaitReady( struct GDS_Device* Device) {
 
- 	struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
 
- 	if (Private->ReadyPin >= 0) {
 
- 		int count = 4*1000;
 
- 		while (gpio_get_level( Private->ReadyPin ) && count) {
 
- 			vTaskDelay( pdMS_TO_TICKS(100) );
 
- 			count -= 100;
 
- 		}	
 
- 	} else {
 
- 		vTaskDelay( pdMS_TO_TICKS(2000) );
 
- 	}	
 
- }	
 
- static void WriteByte( struct GDS_Device* Device, uint8_t Data ) {
 
- 	Device->WriteData( Device, &Data, 1 );
 
- }
 
- static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
 
- 	// start might be greater than end if we decrement
 
- 	Device->WriteCommand( Device, 0x44 );
 
- 	Device->WriteData( Device, &Start, 1 );
 
- 	Device->WriteData( Device, &End, 1 );
 
- 	
 
- 	// we obviously want to start ... from the start
 
- 	Device->WriteCommand( Device, 0x4e );	
 
- 	WriteByte( Device, Start );
 
- }
 
- static void SetRowAddress( struct GDS_Device* Device, uint16_t Start, uint16_t End ) {
 
- 	// start might be greater than end if we decrement
 
- 	Device->WriteCommand( Device, 0x45 );	
 
- 	WriteByte( Device, Start );
 
- 	WriteByte( Device, Start >> 8 );
 
- 	WriteByte( Device, End );
 
- 	WriteByte( Device, End >> 8 );
 
- 	
 
- 	// we obviously want to start ... from the start
 
- 	Device->WriteCommand( Device, 0x4f );	
 
- 	WriteByte( Device, Start );
 
- 	WriteByte( Device, Start >> 8 );
 
- }
 
- static void Update( struct GDS_Device* Device ) {
 
- 	uint8_t *iptr = Device->Framebuffer;
 
- 	
 
- 	Device->WriteCommand( Device, 0x24 );
 
- 	
 
- 	// this is awfully slow, but e-ink are slow anyway ...
 
- 	for (int i = Device->FramebufferSize; --i >= 0;) {
 
- 		WriteByte( Device, ~*iptr++ );
 
- 	}	
 
- 	
 
- 	Device->WriteCommand( Device, 0x22 ); 
 
-     WriteByte( Device, 0xC7);
 
-     Device->WriteCommand( Device, 0X20 );
 
- 	WaitReady( Device );
 
- }
 
- // remember that for these ELD drivers W and H are "inverted"
 
- static inline void _DrawPixel( struct GDS_Device* Device, int X, int Y, int Color ) {
 
-     uint32_t YBit = ( Y & 0x07 );
 
-     Y>>= 3;
 
-     uint8_t* FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
 
-     *FBOffset = ( Color == GDS_COLOR_BLACK ) ? *FBOffset & ~BIT( 7-YBit ) : *FBOffset | BIT( 7-YBit );
 
- }	
 
- static void ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ) {
 
- 	for (int r = y1; r <= y2; r++) {
 
- 		for (int c = x1; c <= x2; c++) {
 
- 			_DrawPixel( Device, c, r, Color );
 
- 		}	
 
- 	}
 
- }
 
- static void DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color ) {
 
- 	if (!Height) Height = Device->Height;
 
- 	if (!Width) Width = Device->Width;
 
- 	
 
- 	// just do row/column swap
 
- 	for (int r = 0; r < Height; r++) {
 
- 		uint8_t *optr = Device->Framebuffer + r*Device->Width, *iptr = Data + r;
 
- 		for (int c = Width; --c >= 0;) {
 
- 			*optr++ = *iptr;
 
- 			iptr += Height;
 
- 		}	
 
- 	}
 
- }
 
- static bool Init( struct GDS_Device* Device ) {
 
- 	struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
 
- 	
 
- 	// need to re-adjust framebuffer because these are non % 8 
 
- 	Private->Height = Device->Height;
 
- 	if (Device->Height & 0x07) Device->Height = ((Device->Height >> 3) + 1) << 3;
 
- 	
 
- 	Device->FramebufferSize = Device->Width * Device->Height / 8;
 
- 	Device->Framebuffer = calloc(1, Device->FramebufferSize);
 
- 	NullCheck( Device->Framebuffer, return false );
 
- 	
 
- 	if (Private->ReadyPin >= 0) {
 
- 		gpio_pad_select_gpio( Private->ReadyPin );
 
- 		gpio_set_pull_mode( Private->ReadyPin, GPIO_PULLUP_ONLY);
 
- 		gpio_set_direction( Private->ReadyPin, GPIO_MODE_INPUT );
 
- 	}
 
- 	
 
- 	// soft reset	
 
- 	vTaskDelay(pdMS_TO_TICKS( 2000 ));
 
-     Device->WriteCommand( Device, 0x12 ); 	
 
- 	WaitReady( Device );
 
- 	
 
- 	Device->WriteCommand( Device, 0x74 ); 			
 
-     WriteByte( Device, 0x54 );
 
- 	Device->WriteCommand( Device, 0x7e ); 			
 
-     WriteByte( Device, 0x3B );
 
- 	
 
- 	Device->WriteCommand( Device, 0x3c );	
 
-     WriteByte( Device, 0x03 );
 
- 	
 
- 	Device->WriteCommand( Device, 0x2c );	
 
-     WriteByte( Device, 0x55 );
 
- 	Device->WriteCommand( Device, 0x03 );	
 
- 	WriteByte( Device, EPD_lut_full_update[70] );
 
- 	
 
- 	Device->WriteCommand( Device, 0x04 );	
 
- 	WriteByte( Device, EPD_lut_full_update[71] );
 
- 	WriteByte( Device, EPD_lut_full_update[72] );
 
- 	WriteByte( Device, EPD_lut_full_update[73] );
 
- 	
 
- 	Device->WriteCommand( Device, 0x3a );	
 
- 	WriteByte( Device, EPD_lut_full_update[74] );
 
- 	Device->WriteCommand( Device, 0x3b );	
 
- 	WriteByte( Device, EPD_lut_full_update[75] );
 
- 	
 
- 	Device->WriteCommand( Device, 0X32 );	
 
- 	for (int i = 0; i < 70; i++) {
 
- 		WriteByte( Device, EPD_lut_full_update[i] );
 
- 	}	
 
- 	// now deal with funny X/Y layout (W and H are "inverted")
 
- 	Device->WriteCommand( Device, 0x01 );
 
-     WriteByte( Device, Device->Width - 1 );
 
-     WriteByte( Device, (Device->Width - 1) >> 8 );
 
-     WriteByte( Device, (0 << 0) );		
 
- 	/* 
 
- 	 Start from 0, Ymax, incX, decY. Starting from X=Height would be difficult
 
- 	 as we would hit the extra bits added because height % 8 != 0 and they are
 
- 	 not written by the DrawPixel. By starting from X=0 we are aligned and 
 
- 	 doing incY is like a clockwise 90° rotation (vs otherwise we would virtually 
 
- 	 do a counter-clockwise rotation but again have the "border" issue.
 
- 	*/ 
 
- 	Device->WriteCommand( Device, 0x11 ); 			
 
- 	WriteByte( Device, (1 << 2) | (0 << 1) | (1 << 0));
 
- 		
 
- 	// must be in order with increment/decrement i.e start might be > end if we decrement
 
- 	SetColumnAddress( Device, 0x0, (Device->Height >> 3) - 1 );
 
- 	SetRowAddress ( Device, Device->Width - 1, 0 );
 
- 	WaitReady( Device );
 
- 	
 
- 	Update( Device );
 
- 	
 
- 	return true;
 
- }	
 
- static const struct GDS_Device SSD1675 = {
 
- 	.DrawBitmapCBR = DrawBitmapCBR, .ClearWindow = ClearWindow,
 
- 	.DrawPixelFast = _DrawPixel,
 
- 	.Update = Update, .Init = Init,
 
- 	.Mode = GDS_MONO, .Depth = 1,
 
- 	.Alloc = GDS_ALLOC_NONE,
 
- };	
 
- struct GDS_Device* SSD1675_Detect(char *Driver, struct GDS_Device* Device) {
 
- 	if (!strcasestr(Driver, "SSD1675")) return NULL;
 
- 	
 
- 	if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
 
- 	*Device = SSD1675;	
 
- 	
 
- 	char *p;
 
- 	struct PrivateSpace* Private = (struct PrivateSpace*) Device->Private;
 
- 	Private->ReadyPin = -1;
 
- 	if ((p = strcasestr(Driver, "ready")) && (p = strchr(p, '='))) Private->ReadyPin = atoi(p + 1);
 
- 	
 
- 	ESP_LOGI(TAG, "SSD1675 driver with ready GPIO %d", Private->ReadyPin);
 
- 	
 
- 	return Device;
 
- }
 
 
  |