Added full esp-idf support

This commit is contained in:
Larry Bank
2025-05-28 20:36:56 +01:00
parent bc567c9ab5
commit e80c39b71f
9 changed files with 4504 additions and 7 deletions
+280
View File
@@ -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__
+8
View File
@@ -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 ".")
+39
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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() */