-
-
Save fanoush/627200137d8199c993d6c54901c1c819 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/libs/graphics/lcd_spi_unbuf.c b/libs/graphics/lcd_spi_unbuf.c | |
index b6214378f..d69b67431 100644 | |
--- a/libs/graphics/lcd_spi_unbuf.c | |
+++ b/libs/graphics/lcd_spi_unbuf.c | |
@@ -28,52 +28,116 @@ static int _pin_mosi; | |
static int _pin_clk; | |
static int _pin_cs; | |
static int _pin_dc; | |
+static int _pin_flash_cs; | |
static int _colstart; | |
static int _rowstart; | |
static int _lastx=-1; | |
static int _lasty=-1; | |
-static uint16_t _chunk_buffer[LCD_SPI_UNBUF_LEN]; | |
+ | |
+#ifdef LCD_SPI_DOUBLEBUFF | |
+static uint16_t _chunk_buffers[2][LCD_SPI_UNBUF_LEN]; | |
+volatile uint16_t *_chunk_buffer = &_chunk_buffers[0][0]; | |
+volatile int _current_buf = 0; | |
+#else | |
+#ifdef LCD_SPI_BIGPIX | |
+static uint32_t _chunk_buffers[LCD_SPI_UNBUF_LEN]; | |
+volatile uint32_t *_chunk_buffer = &_chunk_buffers[0]; | |
+#else | |
+static uint16_t _chunk_buffers[LCD_SPI_UNBUF_LEN]; | |
+volatile uint16_t *_chunk_buffer = &_chunk_buffers[0]; | |
+#endif | |
+static int _firstx=-1; | |
+void disp_spi_transfer_addrwin(int x1, int y1, int x2, int y2); | |
+#endif | |
+ | |
static int _chunk_index = 0; | |
IOEventFlags _device; | |
-static void spi_cmd(const uint8_t cmd) | |
-{ | |
+volatile int _cs_count=0; // to manage selected pin | |
+ | |
+static void set_cs(){ | |
+ jshInterruptOff(); | |
+ if (!_cs_count) { | |
+#ifdef SPIFLASH_SHARED_SPI | |
+ jshPinSetValue(_pin_flash_cs, 1); | |
+ jshSPIEnable(_device,true); | |
+#endif | |
+#ifdef ESPR_USE_SPI3 | |
+ // anomaly 195 workaround - enable SPI before use | |
+ *(volatile uint32_t *)0x4002F500 = 7; | |
+#endif | |
+ jshPinSetValue(_pin_cs, 0); | |
+ } | |
+ ++_cs_count; | |
+ jshInterruptOn(); | |
+} | |
+ | |
+static void rel_cs(){ | |
+ jshInterruptOff(); | |
+ --_cs_count; | |
+ if (!_cs_count) { | |
+ jshPinSetValue(_pin_cs, 1); | |
+#ifdef SPIFLASH_SHARED_SPI | |
+ jshSPIEnable(_device,false); | |
+#endif | |
+#ifdef ESPR_USE_SPI3 | |
+ // anomaly 195 workaround - disable SPI when done | |
+ *(volatile uint32_t *)0x4002F500 = 0; | |
+ *(volatile uint32_t *)0x4002F004 = 1; | |
+#endif | |
+ } | |
+ jshInterruptOn(); | |
+} | |
+ | |
+static void spi_cmd(const uint8_t cmd, uint8_t *data, int dsize){ | |
jshPinSetValue(_pin_dc, 0); | |
- jshSPISend(_device, cmd); | |
+ jshSPISendMany(_device, &cmd, NULL, 1, NULL); | |
jshPinSetValue(_pin_dc, 1); | |
+ if (data) jshSPISendMany(_device, data, NULL, dsize, NULL); | |
} | |
-static inline void spi_data(const uint8_t *data, int len) | |
-{ | |
- jshSPISendMany(_device, data, NULL, len, NULL); | |
+#ifdef LCD_SPI_DOUBLEBUFF | |
+static void endxfer(){ | |
+ rel_cs(); | |
} | |
static void flush_chunk_buffer(){ | |
if(_chunk_index == 0) return; | |
- spi_data((uint8_t *)&_chunk_buffer, _chunk_index*2); | |
+ set_cs(); | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, _chunk_index*2, &endxfer); | |
_chunk_index = 0; | |
+ _current_buf = _current_buf?0:1; | |
+ _chunk_buffer = &_chunk_buffers[_current_buf][0]; | |
} | |
- | |
-static inline bool willFlush(){ | |
- return _chunk_index == LCD_SPI_UNBUF_LEN - 1; | |
-} | |
- | |
-static inline _put_pixel( uint16_t c) { | |
- _chunk_buffer[_chunk_index++] = c; | |
- if (_chunk_index==LCD_SPI_UNBUF_LEN) flush_chunk_buffer(); | |
+#else | |
+static void flush_chunk_buffer(){ | |
+ if(_chunk_index == 0) return; | |
+ set_cs(); | |
+#ifdef LCD_SPI_BIGPIX | |
+ disp_spi_transfer_addrwin(_firstx*2, _lasty*2, _lastx*2+1, _lasty*2+1); | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, _chunk_index*4, NULL); | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, _chunk_index*4, NULL); | |
+#else | |
+ disp_spi_transfer_addrwin(_firstx, _lasty, _lastx, _lasty); | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, _chunk_index*2, NULL); | |
+#endif | |
+ rel_cs(); | |
+ _chunk_index = 0; | |
} | |
+#endif | |
/// flush chunk buffer to screen | |
void lcd_flip(JsVar *parent) { | |
if(_chunk_index == 0) return; | |
- jshPinSetValue(_pin_cs, 0); | |
+ set_cs(); | |
flush_chunk_buffer(); | |
- jshPinSetValue(_pin_cs, 1); | |
+ rel_cs(); | |
} | |
void jshLCD_SPI_UNBUFInitInfo(JshLCD_SPI_UNBUFInfo *inf) { | |
inf->pinCS = PIN_UNDEFINED; | |
inf->pinDC = PIN_UNDEFINED; | |
+ inf->pinflashCS = 5; | |
inf->width = 240; | |
inf->height = 320; | |
inf->colstart = 0; | |
@@ -85,6 +149,7 @@ bool jsspiPopulateOptionsInfo( JshLCD_SPI_UNBUFInfo *inf, JsVar *options){ | |
jsvConfigObject configs[] = { | |
{"cs", JSV_PIN, &inf->pinCS}, | |
{"dc", JSV_PIN, &inf->pinDC}, | |
+ {"flashcs", JSV_PIN, &inf->pinflashCS}, | |
{"width", JSV_INTEGER , &inf->width}, | |
{"height", JSV_INTEGER , &inf->height}, | |
{"colstart", JSV_INTEGER , &inf->colstart}, | |
@@ -132,6 +197,7 @@ JsVar *jswrap_lcd_spi_unbuf_connect(JsVar *device, JsVar *options) { | |
} | |
_pin_cs = inf.pinCS; | |
_pin_dc = inf.pinDC; | |
+ _pin_flash_cs = inf.pinflashCS; | |
_colstart = inf.colstart; | |
_rowstart = inf.rowstart; | |
_device = jsiGetDeviceFromClass(device); | |
@@ -166,54 +232,115 @@ JsVar *jswrap_lcd_spi_unbuf_connect(JsVar *device, JsVar *options) { | |
void disp_spi_transfer_addrwin(int x1, int y1, int x2, int y2) { | |
unsigned char wd[4]; | |
+#ifdef LCD_SPI_DOUBLEBUFF | |
flush_chunk_buffer(); | |
+#endif | |
+ jshSPIWait(_device); //wait for any async transfer to finish | |
x1 += _colstart; | |
y1 += _rowstart; | |
x2 += _colstart; | |
y2 += _rowstart; | |
- spi_cmd(0x2A); | |
wd[0] = x1>>8; | |
wd[1] = x1 & 0xFF; | |
wd[2] = x2>>8; | |
wd[3] = x2 & 0xFF; | |
- spi_data((uint8_t *)&wd, 4); | |
- spi_cmd(0x2B); | |
+ spi_cmd(0x2A, &wd, 4); | |
wd[0] = y1>>8; | |
wd[1] = y1 & 0xFF; | |
wd[2] = y2>>8; | |
wd[3] = y2 & 0xFF; | |
- spi_data((uint8_t *)&wd, 4); | |
- spi_cmd(0x2C); | |
+ spi_cmd(0x2B, &wd, 4); | |
+ spi_cmd(0x2C, NULL, NULL); | |
} | |
+#ifdef LCD_SPI_DOUBLEBUFF | |
void lcd_spi_unbuf_setPixel(JsGraphics *gfx, int x, int y, unsigned int col) { | |
- uint16_t color = (col>>8) | (col<<8); | |
+ uint16_t color = __builtin_bswap16(col); | |
if (x!=_lastx+1 || y!=_lasty) { | |
- jshPinSetValue(_pin_cs, 0); | |
+ set_cs(); | |
disp_spi_transfer_addrwin(x, y, gfx->data.width, y+1); | |
- jshPinSetValue(_pin_cs, 1); //will never flush after | |
- _put_pixel(color); | |
+ rel_cs(); //will never flush after | |
+ _chunk_buffer[_chunk_index++] = color; | |
+ _lastx = x; | |
+ _lasty = y; | |
+ } else { | |
+ _lastx++; | |
+ if ( _chunk_index == LCD_SPI_UNBUF_LEN - 1){ | |
+ _chunk_buffer[_chunk_index++] = color; | |
+ flush_chunk_buffer(); | |
+ } else { | |
+ _chunk_buffer[_chunk_index++] = color; | |
+ } | |
+ } | |
+} | |
+#else | |
+void lcd_spi_unbuf_setPixel(JsGraphics *gfx, int x, int y, unsigned int col) { | |
+#ifdef LCD_SPI_BIGPIX | |
+ uint16_t tmp = __builtin_bswap16(col); | |
+ uint32_t color = ((uint32_t)(tmp) << 16) + (uint32_t)(tmp); | |
+#else | |
+ uint16_t color = __builtin_bswap16(col); | |
+#endif | |
+ if (x!=_lastx+1 || y!=_lasty) { | |
+ flush_chunk_buffer(); | |
+ _chunk_buffer[_chunk_index++] = color; | |
_lastx = x; | |
_lasty = y; | |
+ _firstx =x; | |
} else { | |
_lastx++; | |
- if (willFlush()){ | |
- jshPinSetValue(_pin_cs, 0); | |
- _put_pixel(color); | |
- jshPinSetValue(_pin_cs, 1); | |
+ if ( _chunk_index == LCD_SPI_UNBUF_LEN - 1){ | |
+ _chunk_buffer[_chunk_index++] = color; | |
+ flush_chunk_buffer(); | |
+ _firstx=_lastx; | |
} else { | |
- _put_pixel(color); | |
+ _chunk_buffer[_chunk_index++] = color; | |
} | |
} | |
} | |
+#endif | |
+/* | |
+* Optimised so that we only fill buffer with pixel color once | |
+* Leaves _chunk_index at 0 and all pixels transferred | |
+* does nout use double buffering as not helpful here. | |
+*/ | |
void lcd_spi_unbuf_fillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col) { | |
int pixels = (1+x2-x1)*(1+y2-y1); | |
- uint16_t color = (col>>8) | (col<<8); | |
- jshPinSetValue(_pin_cs, 0); | |
- disp_spi_transfer_addrwin(x1, y1, x2, y2); | |
- for (int i=0; i<pixels; i++) _put_pixel(color); | |
- jshPinSetValue(_pin_cs, 1); | |
+#ifdef LCD_SPI_BIGPIX | |
+ uint16_t tmp = __builtin_bswap16(col); | |
+ uint32_t color = ((uint32_t)(tmp) << 16) + (uint32_t)(tmp); | |
+#else | |
+ uint16_t color = __builtin_bswap16(col); | |
+#endif | |
+ set_cs(); | |
+#ifndef LCD_SPI_DOUBLEBUFF | |
+ flush_chunk_buffer(); | |
+#endif | |
+#ifdef LCD_SPI_BIGPIX | |
+ disp_spi_transfer_addrwin(x1*2, y1*2, x2*2+1, y2*2+1); //always flushes buffer | |
+ int fill = pixels>LCD_SPI_UNBUF_LEN ? LCD_SPI_UNBUF_LEN : pixels; | |
+ for (int i=0; i<fill; i++) _chunk_buffer[i] = color; //fill buffer with color for reuse | |
+ while (pixels>=fill) { | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, fill*4,NULL); | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, fill*4,NULL); | |
+ pixels-=fill; | |
+ } | |
+ if (pixels>0) { | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, pixels*4,NULL); | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, pixels*4,NULL); | |
+ } | |
+#else | |
+ disp_spi_transfer_addrwin(x1, y1, x2, y2); //always flushes buffer | |
+ int fill = pixels>LCD_SPI_UNBUF_LEN ? LCD_SPI_UNBUF_LEN : pixels; | |
+ for (int i=0; i<fill; i++) _chunk_buffer[i] = color; //fill buffer with color for reuse | |
+ while (pixels>=fill) { | |
+ jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, fill*2,NULL); | |
+ pixels-=fill; | |
+ } | |
+ if (pixels>0) jshSPISendMany(_device,(uint8_t *)_chunk_buffer,NULL, pixels*2,NULL); | |
+#endif | |
+ rel_cs(); | |
_lastx=-1; | |
_lasty=-1; | |
} | |
@@ -222,3 +349,43 @@ void lcd_spi_unbuf_setCallbacks(JsGraphics *gfx) { | |
gfx->setPixel = lcd_spi_unbuf_setPixel; | |
gfx->fillRect = lcd_spi_unbuf_fillRect; | |
} | |
+ | |
+ | |
+/*JSON{ | |
+ "type" : "staticmethod", | |
+ "class" : "lcd_spi_unbuf", | |
+ "name" : "command", | |
+ "generate" : "jswrap_lcd_spi_unbuf_command", | |
+ "params" : [ | |
+ ["cmd","int32","The 8 bit command"], | |
+ ["data","JsVar","The data to send with the command either an integer, array, or string"] | |
+ ] | |
+} | |
+Used to send initialisation commands to LCD driver - has to be in native C to allow sharing SPI pins with SPI flash | |
+Must not be called before connect sets up device. | |
+ */ | |
+void jswrap_lcd_spi_unbuf_command(int cmd, JsVar *data) { | |
+ unsigned char cc = (unsigned char)cmd; | |
+ unsigned char bb[64]; // allow for up to 64 data bytes; | |
+ int len = 0; | |
+ set_cs(); | |
+ if (!data) { | |
+ spi_cmd(cc,NULL,NULL); | |
+ } else if (jsvIsNumeric(data)) { | |
+ bb[0] = (unsigned char)jsvGetInteger(data);len =1; | |
+ spi_cmd(cc,&bb,1); | |
+ } else if (jsvIsIterable(data)) { | |
+ JsvIterator it; | |
+ jsvIteratorNew(&it, data, JSIF_EVERY_ARRAY_ELEMENT); | |
+ while (jsvIteratorHasElement(&it) && len<64) { | |
+ bb[len] = (unsigned char)jsvIteratorGetIntegerValue(&it); ++len; | |
+ jsvIteratorNext(&it); | |
+ } | |
+ jsvIteratorFree(&it); | |
+ spi_cmd(cc,&bb,len); | |
+ } else { | |
+ jsExceptionHere(JSET_ERROR, "data Variable type %t not suited to command operation", data); | |
+ } | |
+ rel_cs(); | |
+} | |
+ | |
diff --git a/libs/graphics/lcd_spi_unbuf.h b/libs/graphics/lcd_spi_unbuf.h | |
index 04389ee3a..9170ecd1c 100644 | |
--- a/libs/graphics/lcd_spi_unbuf.h | |
+++ b/libs/graphics/lcd_spi_unbuf.h | |
@@ -21,6 +21,7 @@ | |
typedef struct { | |
Pin pinCS; //!< Pin to use for cs. | |
Pin pinDC; //!< Pin to use for Data Command. | |
+ Pin pinflashCS; //!< Pin to restart SPI flash read | |
int width; //!< Display pixel size X | |
int height; //!< Display pixel size Y | |
int colstart; //!< Aditional starting address some pixels dont begin at 0 | |
@@ -30,3 +31,4 @@ typedef struct { | |
bool jswrap_lcd_spi_unbuf_idle(); | |
JsVar *jswrap_lcd_spi_unbuf_connect(JsVar *device, JsVar *options); | |
void lcd_spi_unbuf_setCallbacks(JsGraphics *gfx); | |
+void jswrap_lcd_spi_unbuf_command(int cmd, JsVar *data); | |
diff --git a/targets/nrf5x/jshardware.c b/targets/nrf5x/jshardware.c | |
index 8007b79da..4118cd7cf 100644 | |
--- a/targets/nrf5x/jshardware.c | |
+++ b/targets/nrf5x/jshardware.c | |
@@ -317,6 +317,11 @@ unsigned char *spi0RxPtr; | |
unsigned char *spi0TxPtr; | |
size_t spi0Cnt; | |
+#ifdef LCD_SPI_DOUBLEBUFF | |
+//lock for sharing spi if async double buffering | |
+volatile spi0isFree = true; | |
+#endif | |
+ | |
// Handler for async SPI transfers | |
volatile bool spi0Sending = false; | |
void (*volatile spi0Callback)() = NULL; | |
@@ -1943,7 +1948,9 @@ void jshSPISetup(IOEventFlags device, JshSPIInfo *inf) { | |
#endif | |
if (err_code != NRF_SUCCESS) | |
jsExceptionHere(JSET_INTERNALERROR, "SPI Initialisation Error %d\n", err_code); | |
- | |
+#ifdef SPIFLASH_SHARED_SPI | |
+ jshSPIEnable(device,false); | |
+#else | |
// nrf_drv_spi_init will set pins, but this ensures we know so can reset state later | |
if (jshIsPinValid(inf->pinSCK)) { | |
jshPinSetFunction(inf->pinSCK, JSH_SPI1|JSH_SPI_SCK); | |
@@ -1955,6 +1962,7 @@ void jshSPISetup(IOEventFlags device, JshSPIInfo *inf) { | |
jshPinSetFunction(inf->pinMISO, JSH_SPI1|JSH_SPI_MISO); | |
} | |
#endif | |
+#endif | |
} | |
/** Send data through the given SPI device (if data>=0), and return the result | |
@@ -2008,6 +2016,38 @@ int jshSPISend(IOEventFlags device, int data) { | |
jshSPISendMany(device, &d, &d, 1, NULL); | |
return d;*/ | |
} | |
+/* Enable and Disable SPI device */ | |
+void jshSPIEnable(IOEventFlags device, bool enable) { | |
+#if defined(SPI0_USE_EASY_DMA) && (SPI0_USE_EASY_DMA==1) | |
+#if NRF_SD_BLE_API_VERSION>5 | |
+ NRF_SPIM_Type *p_spim = (NRF_SPIM_Type *)spi0.u.spim.p_reg; | |
+#else | |
+ NRF_SPIM_Type *p_spim = (NRF_SPIM_Type *)spi0.p_registers; | |
+#endif | |
+ if (enable) { | |
+#ifdef LCD_SPI_DOUBLEBUFF | |
+ spi0isFree = false; | |
+#endif | |
+ nrf_spim_enable(p_spim); | |
+ } | |
+ else { | |
+ nrf_spim_disable(p_spim); | |
+#ifdef LCD_SPI_DOUBLEBUFF | |
+ spi0isFree = true; | |
+#endif | |
+ } | |
+#else | |
+#if NRF_SD_BLE_API_VERSION>5 | |
+ NRF_SPI_Type *p_spi = (NRF_SPI_Type *)spi0.u.spi.p_reg; | |
+#else | |
+ NRF_SPI_Type *p_spi = (NRF_SPI_Type *)spi0.p_registers; | |
+#endif | |
+ if (enable) { | |
+ nrf_spi_enable(p_spi); | |
+ } | |
+ else nrf_spi_disable(p_spi); | |
+#endif | |
+} | |
/** Send 16 bit data through the given SPI device. */ | |
void jshSPISend16(IOEventFlags device, int data) { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment