| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 | 
							- /**
 
-  * 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 <esp_heap_caps.h>
 
- #include <esp_log.h>
 
- #include "gds.h"
 
- #include "gds_private.h"
 
- #define SHADOW_BUFFER
 
- #define PAGE_BLOCK	1024
 
- #define min(a,b) (((a) < (b)) ? (a) : (b))
 
- static char TAG[] = "SSD1322";
 
- struct PrivateSpace {
 
- 	uint8_t *iRAM, *Shadowbuffer;
 
- 	uint8_t ReMap, PageSize;
 
- 	uint8_t Offset;
 
- };
 
- // Functions are not declared to minimize # of lines
 
- static void WriteDataByte( 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 ) {
 
- 	Device->WriteCommand( Device, 0x15 );
 
- 	Device->WriteData( Device, &Start, 1 );
 
- 	Device->WriteData( Device, &End, 1 );
 
- }
 
- static void SetRowAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
 
- 	Device->WriteCommand( Device, 0x75 );
 
- 	Device->WriteData( Device, &Start, 1 );
 
- 	Device->WriteData( Device, &End, 1 );
 
- }
 
- static void Update( struct GDS_Device* Device ) {
 
- 	struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
 
- 		
 
- 	// RAM is by columns of 4 pixels ...
 
- 	SetColumnAddress( Device, Private->Offset, Private->Offset + Device->Width / 4 - 1);
 
- 	
 
- #ifdef SHADOW_BUFFER
 
- 	uint16_t *optr = (uint16_t*) Private->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer;
 
- 	bool dirty = false;
 
- 	
 
- 	for (int r = 0, page = 0; r < Device->Height; r++) {
 
- 		// look for change and update shadow (cheap optimization = width always / by 2)
 
- 		for (int c = Device->Width / 2 / 2; --c >= 0;) {
 
- 			if (*optr != *iptr) {
 
- 				dirty = true;
 
- 				*optr = *iptr;
 
- 			}
 
- 			iptr++; optr++;
 
- 		}
 
- 		
 
- 		// one line done, check for page boundary
 
- 		if (++page == Private->PageSize) {
 
- 			if (dirty) {
 
- 				uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Private->Shadowbuffer + (r - page + 1) * Device->Width / 2);
 
- 				SetRowAddress( Device, r - page + 1, r );
 
- 				for (int i = page * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
 
- 				//memcpy(Private->iRAM, Private->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 );
 
- 				Device->WriteCommand( Device, 0x5c );
 
- 				Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 );
 
- 				dirty = false;
 
- 			}	
 
- 			page = 0;
 
- 		}	
 
- 	}	
 
- #else
 
- 	for (int r = 0; r < Device->Height; r += Private->PageSize) {
 
- 		SetRowAddress( Device, r, r + Private->PageSize - 1 );
 
- 		Device->WriteCommand( Device, 0x5c );
 
- 		if (Private->iRAM) {
 
- 			uint16_t *optr = (uint16_t*) Private->iRAM, *iptr = (uint16_t*) (Device->Framebuffer + r * Device->Width / 2);
 
- 			for (int i = Private->PageSize * Device->Width / 2 / 2; --i >= 0; iptr++) *optr++ = (*iptr >> 8) | (*iptr << 8);
 
- 			//memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
 
- 			Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 );
 
- 		} else	{
 
- 			Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 );
 
- 		}	
 
- 	}	
 
- #endif	
 
- }
 
- static void SetHFlip( struct GDS_Device* Device, bool On ) { 
 
- 	struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
 
- 	Private->ReMap = On ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1));
 
- 	Device->WriteCommand( Device, 0xA0 );
 
- 	Device->WriteData( Device, &Private->ReMap, 1 );
 
- 	WriteDataByte( Device, 0x11 );		
 
- }	
 
- static void SetVFlip( struct GDS_Device *Device, bool On ) { 
 
- 	struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
 
- 	Private->ReMap = On ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
 
- 	Device->WriteCommand( Device, 0xA0 );
 
- 	Device->WriteData( Device, &Private->ReMap, 1 );
 
- 	WriteDataByte( Device, 0x11 );		
 
- }	
 
- 	
 
- static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
 
- static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
 
- static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
 
-     Device->WriteCommand( Device, 0xC1 );
 
-     Device->WriteData( Device, &Contrast, 1 );
 
- }
 
- static bool Init( struct GDS_Device* Device ) {
 
- 	struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
 
- 	
 
- 	// these displays seems to be layout centered (1 column = 4 pixels of 4 bits each, little endian)
 
- 	Private->Offset = (480 - Device->Width) / 4 / 2;
 
- 	
 
- 	// find a page size that is not too small is an integer of height
 
- 	Private->PageSize = min(8, PAGE_BLOCK / (Device->Width / 2));
 
- 	Private->PageSize = Device->Height / (Device->Height / Private->PageSize) ;	
 
- 	
 
- #ifdef SHADOW_BUFFER	
 
- 	Private->Shadowbuffer = malloc( Device->FramebufferSize );	
 
- 	memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize);
 
- #endif
 
- 	Private->iRAM = heap_caps_malloc( Private->PageSize * Device->Width / 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
 
- 	ESP_LOGI(TAG, "SSD1322 with offset %u, page %u, iRAM %p", Private->Offset, Private->PageSize, Private->iRAM);
 
- 			
 
- 	// need to be off and disable display RAM
 
- 	Device->DisplayOff( Device );
 
-     Device->WriteCommand( Device, 0xA5 );
 
- 	
 
- 	// Display Offset
 
-     Device->WriteCommand( Device, 0xA2 );
 
-     WriteDataByte( Device, 0 );
 
- 	
 
- 	// Display Start Line
 
-     Device->WriteCommand( Device, 0xA1 );
 
- 	WriteDataByte( Device, 0x00 );
 
- 	
 
- 	// set flip modes
 
- 	Private->ReMap = 0;
 
- 	Device->SetVFlip( Device, false );
 
- 	Device->SetHFlip( Device, false );
 
- 	
 
- 	// set Clocks
 
-     Device->WriteCommand( Device, 0xB3 );
 
- 	WriteDataByte( Device, 0x91 );
 
- 	
 
- 	// set MUX
 
- 	Device->WriteCommand( Device, 0xCA );
 
- 	WriteDataByte( Device, Device->Height - 1 );
 
- 	
 
- 	// phase 1 & 2 period (needed?)	
 
- 	Device->WriteCommand( Device, 0xB1 );
 
- 	WriteDataByte( Device, 0xE2 );
 
- 	
 
- 	// set pre-charge V (needed?°)
 
- 	Device->WriteCommand( Device, 0xBB );
 
- 	WriteDataByte( Device, 0x1F );
 
- 	
 
- 	// set COM deselect voltage (needed?)
 
- 	Device->WriteCommand( Device, 0xBE );
 
- 	WriteDataByte( Device, 0x07 );
 
- 	
 
- 	// no Display Inversion
 
-     Device->WriteCommand( Device, 0xA6 );
 
- 	
 
- 	// gone with the wind
 
- 	Device->DisplayOn( Device );
 
- 	Device->Update( Device );
 
- 	
 
- 	return true;
 
- }	
 
- static const struct GDS_Device SSD1322 = {
 
- 	.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
 
- 	.SetVFlip = SetVFlip, .SetHFlip = SetHFlip,
 
- 	.Update = Update, .Init = Init,
 
- };	
 
- struct GDS_Device* SSD1322_Detect(char *Driver, struct GDS_Device* Device) {
 
- 	if (!strcasestr(Driver, "SSD1322")) return NULL;
 
- 		
 
- 	if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
 
- 	
 
- 	*Device = SSD1322;	
 
- 	Device->Depth = 4;
 
- 		
 
- 	return Device;
 
- }
 
 
  |