mirror of
https://github.com/usetrmnl/bb_epaper.git
synced 2026-04-29 13:43:26 -07:00
Added full esp-idf support
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
//
|
||||
// I/O wrapper functions for the ESP-IDF
|
||||
// These functions are I/O wrapper functions
|
||||
// suitable for all ESP32 MCUs
|
||||
//
|
||||
#ifndef __ESP_IDF_IO__
|
||||
#define __ESP_IDF_IO__
|
||||
|
||||
#include "driver/spi_master.h"
|
||||
|
||||
#define INPUT 0
|
||||
#define INPUT_PULLUP 1
|
||||
#define OUTPUT 2
|
||||
#define DISABLED 3
|
||||
#define HIGH 1
|
||||
#define LOW 0
|
||||
|
||||
#define pgm_read_byte(a) *(uint8_t *)(a)
|
||||
#define pgm_read_word(a) *(uint16_t *)(a)
|
||||
#define pgm_read_dword(a) *(uint32_t *)(a)
|
||||
#define memcpy_P memcpy
|
||||
|
||||
static spi_bus_config_t buscfg;
|
||||
static spi_device_interface_config_t devcfg;
|
||||
static spi_transaction_t trans;
|
||||
static spi_device_handle_t spi;
|
||||
|
||||
#ifdef VSPI_HOST
|
||||
#define ESP32_SPI_HOST VSPI_HOST
|
||||
#else
|
||||
#define ESP32_SPI_HOST SPI2_HOST
|
||||
#endif // VSPI_HOST
|
||||
// foreward references
|
||||
void bbepWakeUp(BBEPDISP *pBBEP);
|
||||
void bbepSendCMDSequence(BBEPDISP *pBBEP, const uint8_t *pSeq);
|
||||
|
||||
void digitalWrite(int iPin, int iState) {
|
||||
gpio_set_level((gpio_num_t)iPin, (uint32_t)iState);
|
||||
}
|
||||
void pinMode(int iPin, int iMode)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
|
||||
gpio_reset_pin(iPin);
|
||||
if (iMode == DISABLED) return;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
|
||||
//bit mask of the pins that you want to set,e.g.GPIO18/19
|
||||
io_conf.pin_bit_mask = (1ULL << iPin);
|
||||
io_conf.pull_down_en = 0; //disable pull-down mode
|
||||
io_conf.pull_up_en = (iMode == INPUT_PULLUP); // pull-up mode
|
||||
if (iMode == INPUT || iMode == INPUT_PULLUP) {
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
} else { // must be output
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
}
|
||||
gpio_config(&io_conf); //configure GPIO with the given settings
|
||||
} /* pinMode() */
|
||||
int digitalRead(int iPin)
|
||||
{
|
||||
return (int)gpio_get_level((gpio_num_t)iPin);
|
||||
} /* digitalRead() */
|
||||
void delayMicroseconds(long l)
|
||||
{
|
||||
l *= 40;
|
||||
while (l) {
|
||||
__asm__ __volatile__ ("nop");
|
||||
l--;
|
||||
}
|
||||
}
|
||||
void delay(long l)
|
||||
{
|
||||
delayMicroseconds(l*1000);
|
||||
}
|
||||
void mymemset(void *d, uint8_t u8, int len)
|
||||
{
|
||||
uint8_t *d8;
|
||||
if (((intptr_t)d & 3) == 0) { // dword aligned
|
||||
uint32_t u32, *d32 = (uint32_t *)d;
|
||||
u32 = u8 | (u8 << 8);
|
||||
u32 |= (u32 << 16);
|
||||
while (len >= 4) {
|
||||
*d32++ = u32;
|
||||
len -= 4;
|
||||
}
|
||||
d = d32;
|
||||
}
|
||||
d8 = (uint8_t *)d;
|
||||
while (len) {
|
||||
*d8++ = u8;
|
||||
len--;
|
||||
}
|
||||
} /* mymemset() */
|
||||
void mymemcpy(void *d, void *s, size_t iLen)
|
||||
{
|
||||
uint8_t *d8 = (uint8_t *)d;
|
||||
uint8_t *s8 = (uint8_t *)s;
|
||||
while (iLen) {
|
||||
*d8++ = *s8++;
|
||||
iLen--;
|
||||
}
|
||||
} /* mymemcpy() */
|
||||
//
|
||||
// Convert a number into a fixed length, zero-terminated string
|
||||
//
|
||||
void i2strf(char *pDest, int iVal, int iDigits)
|
||||
{
|
||||
char *d = pDest;
|
||||
int i;
|
||||
pDest[iDigits] = 0;
|
||||
while (iDigits) {
|
||||
iDigits--;
|
||||
i = iVal % 10;
|
||||
d[iDigits] = '0' + (char)i;
|
||||
iVal /= 10;
|
||||
}
|
||||
} /* i2strf() */
|
||||
//
|
||||
// Convert a number into a zero-terminated string
|
||||
//
|
||||
int i2str(char *pDest, int iVal)
|
||||
{
|
||||
char *d = pDest;
|
||||
int i, iPlaceVal = 10000;
|
||||
int iDigits = 0;
|
||||
|
||||
if (iVal < 0) {
|
||||
iDigits++;
|
||||
*d++ = '-';
|
||||
iVal = -iVal;
|
||||
}
|
||||
while (iPlaceVal) {
|
||||
if (iVal >= iPlaceVal) {
|
||||
i = iVal / iPlaceVal;
|
||||
*d++ = '0' + (char)i;
|
||||
iVal -= (i*iPlaceVal);
|
||||
iDigits++;
|
||||
} else if (iDigits != 0) {
|
||||
*d++ = '0'; // non-zeros were already displayed
|
||||
}
|
||||
iPlaceVal /= 10;
|
||||
}
|
||||
if (d == pDest) // must be zero
|
||||
*d++ = '0';
|
||||
*d++ = 0; // terminator
|
||||
return (int)(d - pDest - 1); // string length
|
||||
} /* i2str() */
|
||||
void delayCycles(int i)
|
||||
{
|
||||
while (i > 3) {
|
||||
__asm__ __volatile__ ("nop\n\t");
|
||||
i -= 3;
|
||||
}
|
||||
}
|
||||
void spi_write(BBEPDISP *pBBEP, uint8_t *pBuf, int iLen)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
digitalWrite(pBBEP->iCSPin, LOW);
|
||||
memset(&trans, 0, sizeof(trans)); //Zero out the transaction
|
||||
while (iLen) {
|
||||
int l = iLen;
|
||||
if (l > 4000) { // transmit maximum length (full duplex mode)
|
||||
l = 4000;
|
||||
}
|
||||
trans.length=l*8; // length in bits
|
||||
trans.rxlength = 0;
|
||||
trans.tx_buffer=pBuf;
|
||||
// Queue the transaction
|
||||
ret = spi_device_polling_transmit(spi, &trans); //Transmit!
|
||||
assert(ret==ESP_OK); //Should have had no issues.
|
||||
iLen -= l;
|
||||
pBuf += l;
|
||||
} // while (iLen)
|
||||
digitalWrite(pBBEP->iCSPin, HIGH);
|
||||
} /* spi_write() */
|
||||
//
|
||||
// Set the second CS pin for dual-controller displays
|
||||
//
|
||||
void bbepSetCS2(BBEPDISP *pBBEP, uint8_t cs)
|
||||
{
|
||||
pBBEP->iCS1Pin = pBBEP->iCSPin;
|
||||
pBBEP->iCS2Pin = cs;
|
||||
pinMode(cs, OUTPUT);
|
||||
digitalWrite(cs, HIGH); // disable second CS for now
|
||||
} /* bbepSetCS2() */
|
||||
//
|
||||
// Write a single byte as a COMMAND (D/C set low)
|
||||
//
|
||||
void bbepWriteCmd(BBEPDISP *pBBEP, uint8_t cmd)
|
||||
{
|
||||
if (!pBBEP->is_awake) {
|
||||
// if it's asleep, it can't receive commands
|
||||
bbepWakeUp(pBBEP);
|
||||
pBBEP->is_awake = 1;
|
||||
}
|
||||
digitalWrite(pBBEP->iDCPin, LOW);
|
||||
delay(1);
|
||||
spi_write(pBBEP, &cmd, 1);
|
||||
digitalWrite(pBBEP->iDCPin, HIGH); // leave data mode as the default
|
||||
} /* bbepWriteCmd() */
|
||||
//
|
||||
// Convenience function to write a command byte along with a data
|
||||
// byte (it's single parameter)
|
||||
//
|
||||
void bbepCMD2(BBEPDISP *pBBEP, uint8_t cmd1, uint8_t cmd2)
|
||||
{
|
||||
bbepWriteCmd(pBBEP, cmd1);
|
||||
bbepWriteData(pBBEP, &cmd2, 1);
|
||||
} /* bbepCMD2() */
|
||||
//
|
||||
// Write 1 or more bytes as DATA (D/C set high)
|
||||
//
|
||||
void bbepWriteData(BBEPDISP *pBBEP, uint8_t *pData, int iLen)
|
||||
{
|
||||
if (pBBEP->iFlags & BBEP_CS_EVERY_BYTE) {
|
||||
for (int i=0; i<iLen; i++) {
|
||||
spi_write(pBBEP, &pData[i], 1);
|
||||
}
|
||||
} else {
|
||||
spi_write(pBBEP, pData, iLen);
|
||||
}
|
||||
} /* bbepWriteData() */
|
||||
|
||||
//
|
||||
// Initialize the SPI bus and connections for e-paper displays
|
||||
//
|
||||
void bbepInitIO(BBEPDISP *pBBEP, uint8_t u8DC, uint8_t u8RST, uint8_t u8BUSY, uint8_t u8CS, uint8_t u8MOSI, uint8_t u8SCK, uint32_t u32Speed)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
pBBEP->iDCPin = u8DC;
|
||||
pBBEP->iCSPin = u8CS;
|
||||
pBBEP->iMOSIPin = u8MOSI;
|
||||
pBBEP->iCLKPin = u8SCK;
|
||||
pBBEP->iRSTPin = u8RST;
|
||||
pBBEP->iBUSYPin = u8BUSY;
|
||||
|
||||
pinMode(pBBEP->iDCPin, OUTPUT);
|
||||
pinMode(pBBEP->iRSTPin, OUTPUT);
|
||||
digitalWrite(pBBEP->iRSTPin, LOW);
|
||||
delay(100);
|
||||
digitalWrite(pBBEP->iRSTPin, HIGH);
|
||||
delay(100);
|
||||
if (pBBEP->iBUSYPin != 0xff) {
|
||||
pinMode(pBBEP->iBUSYPin, INPUT);
|
||||
}
|
||||
pBBEP->iSpeed = u32Speed;
|
||||
pinMode(pBBEP->iCSPin, OUTPUT);
|
||||
digitalWrite(pBBEP->iCSPin, HIGH); // manually control the CS pin
|
||||
|
||||
memset(&buscfg, 0, sizeof(buscfg));
|
||||
buscfg.miso_io_num = -1; //u8MISO;
|
||||
buscfg.mosi_io_num = u8MOSI;
|
||||
buscfg.sclk_io_num = u8SCK;
|
||||
buscfg.max_transfer_sz=4096;
|
||||
buscfg.quadwp_io_num=-1;
|
||||
buscfg.quadhd_io_num=-1;
|
||||
//Initialize the SPI bus
|
||||
ret=spi_bus_initialize(ESP32_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||
assert(ret==ESP_OK);
|
||||
|
||||
memset(&devcfg, 0, sizeof(devcfg));
|
||||
devcfg.clock_speed_hz = u32Speed;
|
||||
devcfg.mode = 0;
|
||||
devcfg.spics_io_num = -1; // we control the CS pin
|
||||
devcfg.queue_size = 2; //We want to be able to queue 2 transactions at a time
|
||||
// These callbacks currently don't do anything
|
||||
// devcfg.pre_cb = spi_pre_transfer_callback; //Specify pre-transfer callback to handle D/C line
|
||||
// devcfg.post_cb = spi_post_transfer_callback;
|
||||
// devcfg.flags = SPI_DEVICE_NO_DUMMY; // allow speeds > 26Mhz
|
||||
devcfg.flags = SPI_DEVICE_HALFDUPLEX; // this disables SD card access
|
||||
ret=spi_bus_add_device(ESP32_SPI_HOST, &devcfg, &spi); // attach to bus
|
||||
assert(ret==ESP_OK);
|
||||
|
||||
if (pBBEP->iFlags & BBEP_7COLOR) { // need to send before you can send it data
|
||||
bbepSendCMDSequence(pBBEP, pBBEP->pInitFull);
|
||||
}
|
||||
} /* spi_init() */
|
||||
|
||||
#endif // __ESP_IDF_IO__
|
||||
@@ -0,0 +1,8 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(hello_world)
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "hello_world.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,39 @@
|
||||
#include <stdio.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "../../../src/bb_epaper.h"
|
||||
#include "../../esp_generic.inl"
|
||||
#include "../../../src/bb_ep.inl"
|
||||
#include "../../../src/bb_ep_gfx.inl"
|
||||
|
||||
// Pinout for the LilyGo mini-epaper S3
|
||||
#define PIN_BUSY 10
|
||||
#define PIN_RST 11
|
||||
#define PIN_DC 12
|
||||
#define PIN_CS 13
|
||||
#define PIN_SCK 14
|
||||
#define PIN_MOSI 15
|
||||
|
||||
// static instance of bb_epaper state
|
||||
static BBEPDISP disp;
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Starting...\n");
|
||||
bbepSetPanelType(&disp, EP102_80x128); // This must be called first
|
||||
bbepInitIO(&disp, PIN_DC, PIN_RST, PIN_BUSY, PIN_CS, PIN_MOSI, PIN_SCK, 4000000);
|
||||
bbepAllocBuffer(&disp);
|
||||
bbepFill(&disp, BBEP_WHITE, PLANE_BOTH);
|
||||
bbepWriteString(&disp, 0, 4, "Hello", FONT_12x16, BBEP_BLACK, BBEP_WHITE);
|
||||
bbepWriteString(&disp, 0, 20, "World!", FONT_12x16, BBEP_BLACK, BBEP_WHITE);
|
||||
bbepWritePlane(&disp, PLANE_BOTH);
|
||||
bbepRefresh(&disp, REFRESH_FULL);
|
||||
bbepWaitBusy(&disp);
|
||||
bbepSleep(&disp, 1); // deep sleep
|
||||
printf("Finished\n");
|
||||
while (1) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -280,8 +280,8 @@ const uint8_t epd29r_init_sequence_full[] PROGMEM = {
|
||||
0x02, 0x18, 0x80, // temp sensor = internal
|
||||
0x02, 0x21, 0x00, // display update ctrl 1
|
||||
0x02, 0x22, 0xb1, // display update ctrl 2
|
||||
0x01, 0x20, // master activation
|
||||
BUSY_WAIT,
|
||||
// 0x01, 0x20, // master activation
|
||||
// BUSY_WAIT,
|
||||
0x02, 0x4e, 0x00, // RAM X counter
|
||||
0x03, 0x4f, 0x27, 0x01, // RAM Y counter
|
||||
0x00
|
||||
|
||||
+1
-3
@@ -1099,12 +1099,11 @@ int tx, ty, iPitch, iDestPitch;
|
||||
// Draw a string of normal (8x8), small (6x8) or large (16x32) characters
|
||||
// At the given col+row
|
||||
//
|
||||
int bbepWriteString(BBEPDISP *pBBEP, int x, int y, char *szMsg, int iSize, int iColor)
|
||||
int bbepWriteString(BBEPDISP *pBBEP, int x, int y, char *szMsg, int iSize, int iColor, int iBG)
|
||||
{
|
||||
int i, iFontOff, iLen;
|
||||
uint8_t c, *s, ucCMD, ucCMD1, ucCMD2;
|
||||
uint8_t u8Temp[40];
|
||||
int iBG;
|
||||
|
||||
if (pBBEP == NULL) {
|
||||
return BBEP_ERROR_BAD_PARAMETER;
|
||||
@@ -1112,7 +1111,6 @@ int bbepWriteString(BBEPDISP *pBBEP, int x, int y, char *szMsg, int iSize, int i
|
||||
if (iColor != BBEP_TRANSPARENT) {
|
||||
iColor = pBBEP->pColorLookup[iColor & 0xf];
|
||||
}
|
||||
iBG = pBBEP->iBG;
|
||||
if (iBG == -1) iBG = BBEP_TRANSPARENT; // -1 = don't care
|
||||
if (iBG != BBEP_TRANSPARENT) {
|
||||
iBG = pBBEP->pColorLookup[iBG & 0xf];
|
||||
|
||||
+2
-2
@@ -384,7 +384,7 @@ int w=8, h=8;
|
||||
_bbep.iCursorX = 0; // Reset x to zero,
|
||||
_bbep.iCursorY += h; // advance y one line
|
||||
}
|
||||
bbepWriteString(&_bbep, -1, -1, szTemp, _bbep.iFont, _bbep.iFG);
|
||||
bbepWriteString(&_bbep, -1, -1, szTemp, _bbep.iFont, _bbep.iFG, _bbep.iBG);
|
||||
}
|
||||
} else { // Custom font
|
||||
BB_FONT *pBBF = (BB_FONT *)_bbep.pFont;
|
||||
@@ -490,7 +490,7 @@ void BBEPAPER::drawString(const char *pText, int x, int y)
|
||||
if (_bbep.pFont) {
|
||||
bbepWriteStringCustom(&_bbep, (BB_FONT *)_bbep.pFont, x, y, (char *)pText, _bbep.iFG, 0); // iPlane);
|
||||
} else if (_bbep.iFont >= FONT_6x8 && _bbep.iFont < FONT_COUNT) {
|
||||
bbepWriteString(&_bbep, x, y, (char *)pText, _bbep.iFont, _bbep.iFG);
|
||||
bbepWriteString(&_bbep, x, y, (char *)pText, _bbep.iFont, _bbep.iFG, _bbep.iBG);
|
||||
}
|
||||
} /* drawString() */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user