mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
205 lines
5.9 KiB
C
205 lines
5.9 KiB
C
/*
|
|
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
|
*
|
|
* Copyright (C) 2019 Gordon Williams <gw@pur3.co.uk>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
* Graphics Backend for drawing to SPI displays
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "platform_config.h"
|
|
#include "jsutils.h"
|
|
#include "jshardware.h"
|
|
#include "lcd_spilcd.h"
|
|
#include "lcd_spilcd_info.h"
|
|
#include "lcd_spilcd_palette.h"
|
|
|
|
// ======================================================================
|
|
|
|
#define LCD_STRIDE ((LCD_WIDTH*LCD_BPP+7)>>3)
|
|
unsigned char lcdBuffer[LCD_STRIDE*LCD_HEIGHT];
|
|
#if LCD_BPP==4
|
|
unsigned short lcdPalette[16];
|
|
#endif
|
|
#if LCD_BPP==8
|
|
unsigned short lcdPalette[256];
|
|
#endif
|
|
|
|
#define LCD_SPI EV_SPI1
|
|
|
|
// ======================================================================
|
|
|
|
|
|
// ======================================================================
|
|
|
|
void lcdCmd_SPILCD(int cmd, int dataLen, const char *data) {
|
|
jshPinSetValue(LCD_SPI_CS, 0);
|
|
jshPinSetValue(LCD_SPI_DC, 0); // command
|
|
jshSPISend(LCD_SPI, cmd);
|
|
if (dataLen) {
|
|
jshPinSetValue(LCD_SPI_DC, 1); // data
|
|
while (dataLen) {
|
|
jshSPISend(LCD_SPI, *(data++));
|
|
dataLen--;
|
|
}
|
|
}
|
|
jshPinSetValue(LCD_SPI_CS, 1);
|
|
}
|
|
void lcdSendInitCmd_SPILCD() {
|
|
// Send initialization commands to ST7735
|
|
const char *cmd = SPILCD_INIT_CODE;
|
|
while(cmd[CMDINDEX_DATALEN]!=255) {
|
|
lcdCmd_SPILCD(cmd[CMDINDEX_CMD], cmd[CMDINDEX_DATALEN], &cmd[3]);
|
|
if (cmd[CMDINDEX_DELAY])
|
|
jshDelayMicroseconds(1000*cmd[CMDINDEX_DELAY]);
|
|
cmd += 3 + cmd[CMDINDEX_DATALEN];
|
|
}
|
|
}
|
|
void lcdSetPalette_SPILCD(const char *pal) {
|
|
memcpy(lcdPalette, pal ? pal : SPILCD_PALETTE, sizeof(lcdPalette));
|
|
}
|
|
|
|
// ======================================================================
|
|
|
|
|
|
unsigned int lcdGetPixel_SPILCD(JsGraphics *gfx, int x, int y) {
|
|
#if LCD_BPP==4
|
|
int addr = (x + (y*LCD_WIDTH)) >> 1;
|
|
unsigned char b = lcdBuffer[addr];
|
|
return (x&1) ? (b&15) : (b>>4);
|
|
#endif
|
|
#if LCD_BPP==8
|
|
int addr = x + (y*LCD_WIDTH);
|
|
return lcdBuffer[addr];
|
|
#endif
|
|
}
|
|
|
|
|
|
void lcdSetPixel_SPILCD(JsGraphics *gfx, int x, int y, unsigned int col) {
|
|
#if LCD_BPP==4
|
|
int addr = (x + (y*LCD_WIDTH)) >> 1;
|
|
if (x&1) lcdBuffer[addr] = (lcdBuffer[addr] & 0xF0) | (col&0x0F);
|
|
else lcdBuffer[addr] = (lcdBuffer[addr] & 0x0F) | (col << 4);
|
|
#endif
|
|
#if LCD_BPP==8
|
|
int addr = x + (y*LCD_WIDTH);
|
|
lcdBuffer[addr] = col;
|
|
#endif
|
|
}
|
|
|
|
void lcdFlip_SPILCD_callback() {
|
|
// just an empty stub for SPIsend - we'll just push data as fast as we can
|
|
}
|
|
|
|
void lcdFlip_SPILCD(JsGraphics *gfx) {
|
|
if (gfx->data.modMinX > gfx->data.modMaxX) return; // nothing to do!
|
|
|
|
unsigned char buffer1[LCD_WIDTH*2]; // 16 bits per pixel
|
|
unsigned char buffer2[LCD_WIDTH*2]; // 16 bits per pixel
|
|
|
|
// use nearest 2 pixels as we're sending 12 bits
|
|
gfx->data.modMinX = (gfx->data.modMinX)&~1;
|
|
gfx->data.modMaxX = (gfx->data.modMaxX+2)&~1;
|
|
int xlen = gfx->data.modMaxX - gfx->data.modMinX;
|
|
int xstart = gfx->data.modMinX;
|
|
|
|
jshPinSetValue(LCD_SPI_CS, 0);
|
|
jshPinSetValue(LCD_SPI_DC, 0); // command
|
|
buffer1[0] = SPILCD_CMD_WINDOW_X;
|
|
jshSPISendMany(LCD_SPI, buffer1, NULL, 1, NULL);
|
|
jshPinSetValue(LCD_SPI_DC, 1); // data
|
|
buffer1[0] = 0;
|
|
buffer1[1] = gfx->data.modMinX;
|
|
buffer1[2] = 0;
|
|
buffer1[3] = gfx->data.modMaxX;
|
|
jshSPISendMany(LCD_SPI, buffer1, NULL, 4, NULL);
|
|
jshPinSetValue(LCD_SPI_DC, 0); // command
|
|
buffer1[0] = SPILCD_CMD_WINDOW_Y;
|
|
jshSPISendMany(LCD_SPI, buffer1, NULL, 1, NULL);
|
|
jshPinSetValue(LCD_SPI_DC, 1); // data
|
|
buffer1[0] = 0;
|
|
buffer1[1] = gfx->data.modMinY;
|
|
buffer1[2] = 0;
|
|
buffer1[3] = gfx->data.modMaxY+1;
|
|
jshSPISendMany(LCD_SPI, buffer1, NULL, 4, NULL);
|
|
jshPinSetValue(LCD_SPI_DC, 0); // command
|
|
buffer1[0] = SPILCD_CMD_DATA;
|
|
jshSPISendMany(LCD_SPI, buffer1, NULL, 1, NULL);
|
|
jshPinSetValue(LCD_SPI_DC, 1); // data
|
|
|
|
for (int y=gfx->data.modMinY;y<=gfx->data.modMaxY;y++) {
|
|
unsigned char *buffer = (y&1)?buffer1:buffer2;
|
|
// skip any lines that don't need updating
|
|
#if LCD_BPP==4
|
|
unsigned char *px = &lcdBuffer[y*LCD_STRIDE + (xstart>>1)];
|
|
#endif
|
|
#if LCD_BPP==8
|
|
unsigned char *px = &lcdBuffer[y*LCD_STRIDE + xstart];
|
|
#endif
|
|
unsigned char *bufPtr = (unsigned char*)buffer;
|
|
for (int x=0;x<xlen;x+=2) {
|
|
#if LCD_BPP==4
|
|
unsigned char c = *(px++);
|
|
unsigned int a = lcdPalette[c >> 4];
|
|
unsigned int b = lcdPalette[c & 15];
|
|
#endif
|
|
#if LCD_BPP==8
|
|
unsigned int a = lcdPalette[*(px++)];
|
|
unsigned int b = lcdPalette[*(px++)];
|
|
#endif
|
|
*(bufPtr++) = a>>4;
|
|
*(bufPtr++) = (a<<4) | (b>>8);
|
|
*(bufPtr++) = b;
|
|
}
|
|
size_t len = ((unsigned char*)bufPtr)-buffer;
|
|
jshSPISendMany(LCD_SPI, buffer, 0, len, lcdFlip_SPILCD_callback);
|
|
}
|
|
jshSPIWait(LCD_SPI);
|
|
jshPinSetValue(LCD_SPI_CS,1);
|
|
// Reset modified-ness
|
|
gfx->data.modMaxX = -32768;
|
|
gfx->data.modMaxY = -32768;
|
|
gfx->data.modMinX = 32767;
|
|
gfx->data.modMinY = 32767;
|
|
}
|
|
|
|
|
|
void lcdInit_SPILCD(JsGraphics *gfx) {
|
|
gfx->data.width = LCD_WIDTH;
|
|
gfx->data.height = LCD_HEIGHT;
|
|
gfx->data.bpp = LCD_BPP;
|
|
|
|
lcdSetPalette_SPILCD(0);
|
|
|
|
jshPinOutput(LCD_BL,0); // backlight on
|
|
jshPinOutput(LCD_SPI_CS,1);
|
|
jshPinOutput(LCD_SPI_DC,1);
|
|
jshPinOutput(LCD_SPI_SCK,1);
|
|
jshPinOutput(LCD_SPI_MOSI,1);
|
|
jshPinOutput(LCD_SPI_RST,1);
|
|
jshDelayMicroseconds(10000);
|
|
jshPinOutput(LCD_SPI_RST, 1);
|
|
jshDelayMicroseconds(10000);
|
|
|
|
JshSPIInfo inf;
|
|
jshSPIInitInfo(&inf);
|
|
inf.baudRate = 8000000;
|
|
inf.pinMOSI = LCD_SPI_MOSI;
|
|
inf.pinSCK = LCD_SPI_SCK;
|
|
jshSPISetup(LCD_SPI, &inf);
|
|
|
|
lcdSendInitCmd_SPILCD();
|
|
}
|
|
|
|
void lcdSetCallbacks_SPILCD(JsGraphics *gfx) {
|
|
gfx->setPixel = lcdSetPixel_SPILCD;
|
|
gfx->getPixel = lcdGetPixel_SPILCD;
|
|
//gfx->idle = lcdIdle_PCD8544;
|
|
}
|
|
|