Skip to content

Instantly share code, notes, and snippets.

@fanoush
Created January 8, 2023 22:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fanoush/627200137d8199c993d6c54901c1c819 to your computer and use it in GitHub Desktop.
Save fanoush/627200137d8199c993d6c54901c1c819 to your computer and use it in GitHub Desktop.
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