20 Commits

Author SHA1 Message Date
36788ac5a6 comments and update readme 2026-02-14 21:33:55 -06:00
335452cc6d simplify driver to be stateless 2026-02-14 21:09:15 -06:00
532d93d5d7 reorganize project structure 2026-02-14 19:05:26 -06:00
e3090bf1f5 flesh out wsled interface 2026-02-14 13:19:41 -06:00
99e73d5d6b Merge branch 'feature/ssd-driver' 2026-02-14 12:04:24 -06:00
4f333435ea wsled interface skeleton 2026-02-13 12:29:59 -06:00
9f884b41e7 working wsled driver checkpoint 2026-02-13 12:21:31 -06:00
bb8dcd76b2 fix wsled build 2026-02-11 22:31:03 -06:00
7a2f701653 add untested wsled drivers 2026-02-11 20:57:15 -06:00
Preston McGee
1248a0ac39 Merge pull request #2 from Blitblank/feature/ssd-driver
Feature/ssd driver
2025-12-14 18:58:12 -06:00
5cde1bdfce make ssd driver work 2025-12-14 18:51:52 -06:00
a80e918d63 task base 2025-12-14 00:23:30 -06:00
c4644105a7 add drivers and interface and task classes 2025-12-14 00:23:15 -06:00
54c9672ba0 checkpoint 2025-12-11 20:10:35 -06:00
8e9d459345 add driver 2025-12-07 18:20:08 -06:00
68842bbe0f update readme 2025-12-07 16:05:52 -06:00
4588825986 add app 2025-12-07 15:59:56 -06:00
Preston McGee
32ddc11d6e Merge pull request #1 from Blitblank/hello-world
Hello world
2025-12-07 15:06:07 -06:00
Preston McGee
97d7a02218 Merge branch 'main' into hello-world 2025-12-07 15:05:56 -06:00
96ef55e589 added bill of materials 2025-11-30 20:38:10 -06:00
33 changed files with 758 additions and 31 deletions

View File

@@ -5,7 +5,11 @@ set(PROJECT_MAIN_COMPONENT ${CMAKE_CURRENT_LIST_DIR}/src)
set(EXTRA_COMPONENT_DIRS set(EXTRA_COMPONENT_DIRS
${CMAKE_CURRENT_LIST_DIR}/config ${CMAKE_CURRENT_LIST_DIR}/config
${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_LIST_DIR}/src/drivers
${CMAKE_CURRENT_LIST_DIR}/src/main
${CMAKE_CURRENT_LIST_DIR}/src/tasks
${CMAKE_CURRENT_LIST_DIR}/src/ssd
${CMAKE_CURRENT_LIST_DIR}/src/wsled
) )
# For the esp-idf configuration # For the esp-idf configuration

View File

@@ -10,11 +10,11 @@ Scripts are in scripts directory, named appropriately.
## Development plan: ## Development plan:
- [x] Create repository. - [x] Create repository.
- [ ] Build setup, get working hello-world program. - [x] Build setup, get working hello-world program.
- [ ] Develop 7-segment display driver for the soburg-v2 board, which uses 32-bit shift registers. - [x] Develop 7-segment display driver for the soburg-v2 board, which uses 32-bit shift registers.
Ensures functional hardware interaction and interface design. Ensures functional hardware interaction and interface design.
- [ ] Develop WS2812b driver, would be nice to have some kind of testing for this. - [x] Develop WS2812b driver, would be nice to have some kind of testing for this.
- [ ] Develop WS2812b interface. I like the FastLed library for Arduino so might have a lot of similar functionality. - [x] Develop WS2812b interface. I like the FastLed library for Arduino so might have a lot of similar functionality.
- [ ] Implement proper app structure, with error checking and performance profiling - [ ] Implement proper app structure, with error checking and performance profiling
- [ ] Add a couple LED effects- the random blink and rainbow sweep are easy ones. - [ ] Add a couple LED effects- the random blink and rainbow sweep are easy ones.
- [ ] Create a mock LED panel that executes natively to test LED effects outside of hardware. (SDL2 or something) - [ ] Create a mock LED panel that executes natively to test LED effects outside of hardware. (SDL2 or something)
@@ -31,7 +31,15 @@ Scripts are in scripts directory, named appropriately.
This is basic but hopefully can be good platform for future WS2812b projects. This is basic but hopefully can be good platform for future WS2812b projects.
## Scripts: ## Scripts:
After cloning: $ ./scripts/repo-setup # installs esp-idf, sets up target configurations After cloning: $ ./scripts/repo-setup # installs esp-idf, sets up target configurations\
To build: $ ./scripts/build.sh To build: $ ./scripts/build.sh\
To flash: $ ./scripts/flash.sh # note: flash.sh automatically builds To flash: $ ./scripts/flash.sh # note: flash.sh automatically builds\
To monitor: $ ./scripts/monitor.sh To monitor: $ ./scripts/monitor.sh\
## TODOs for developers
- [ ] Move all hardware specifications to config/Kconfig.projbuild file. (things like NUM_LEDS, pins.h, ssd_digits, etc.)
- [ ] Create an effect base class for effects to inherit from
- [ ] Attach interrupts for hardware inputs
- [ ] Human I/O (like from buttons, knobs) needs to be in its own io task. Other tasks will be injected with a general I/O interface
- [ ] Investigate putting the wsled task on a separate core from io and such
- [ ] Wsled interface needs a platform for matrix creation

BIN
pcb/control/TEMPLATE.xlsx Normal file

Binary file not shown.

BIN
pcb/panel/bom.xlsx Normal file

Binary file not shown.

View File

@@ -22084,7 +22084,7 @@
(justify mirror) (justify mirror)
) )
) )
(property "Value" "B1911B" (property "Value" "B1911R"
(at 0 -1.43 90) (at 0 -1.43 90)
(layer "B.Fab") (layer "B.Fab")
(uuid "c1484363-b3dc-48b7-9c64-d06df10d96a2") (uuid "c1484363-b3dc-48b7-9c64-d06df10d96a2")
@@ -22764,7 +22764,7 @@
(justify mirror) (justify mirror)
) )
) )
(property "Value" "TBDuF" (property "Value" "100uF"
(at 2.5 -5.25 0) (at 2.5 -5.25 0)
(layer "B.Fab") (layer "B.Fab")
(uuid "a592ba06-f886-4233-b793-557c4b352735") (uuid "a592ba06-f886-4233-b793-557c4b352735")
@@ -26393,7 +26393,7 @@
(justify mirror) (justify mirror)
) )
) )
(property "Value" "TBDuF" (property "Value" "100uF"
(at 2.5 -5.25 0) (at 2.5 -5.25 0)
(layer "B.Fab") (layer "B.Fab")
(uuid "036ec2e2-300a-42a7-987d-e4811bf430e0") (uuid "036ec2e2-300a-42a7-987d-e4811bf430e0")
@@ -28139,7 +28139,7 @@
(justify mirror) (justify mirror)
) )
) )
(property "Value" "TBD" (property "Value" "0.1μF"
(at 0 -1.43 90) (at 0 -1.43 90)
(layer "B.Fab") (layer "B.Fab")
(uuid "2125effb-a0e4-4175-9ce6-cce3daef6fd0") (uuid "2125effb-a0e4-4175-9ce6-cce3daef6fd0")
@@ -29018,7 +29018,7 @@
(justify mirror) (justify mirror)
) )
) )
(property "Value" "52.3Ω" (property "Value" "52.3kΩ"
(at 0 -1.43 90) (at 0 -1.43 90)
(layer "B.Fab") (layer "B.Fab")
(uuid "f8ed0ff3-21fe-4dac-b950-096d117b1132") (uuid "f8ed0ff3-21fe-4dac-b950-096d117b1132")
@@ -30643,7 +30643,7 @@
(justify mirror) (justify mirror)
) )
) )
(property "Value" "TBD" (property "Value" "100pF"
(at 0 -1.43 90) (at 0 -1.43 90)
(layer "B.Fab") (layer "B.Fab")
(uuid "f93816e5-03a1-48e1-b93c-11d13f82d8e9") (uuid "f93816e5-03a1-48e1-b93c-11d13f82d8e9")
@@ -31613,7 +31613,7 @@
(justify mirror) (justify mirror)
) )
) )
(property "Value" "TBD" (property "Value" "10μF"
(at 0 -1.43 0) (at 0 -1.43 0)
(layer "B.Fab") (layer "B.Fab")
(uuid "4ecb6ecd-64d9-4e42-b908-ec3e49aafb1b") (uuid "4ecb6ecd-64d9-4e42-b908-ec3e49aafb1b")
@@ -45894,7 +45894,6 @@
(polygon (polygon
(pts (pts
(xy 152 87.5) (xy 153.75 85.5) (xy 154.75 84.5) (xy 149 84.5) (xy 150.75 86.25) (xy 150.75 87.5) (xy 152 87.5) (xy 153.75 85.5) (xy 154.75 84.5) (xy 149 84.5) (xy 150.75 86.25) (xy 150.75 87.5)
(xy 150.75 87.5)
) )
) )
(filled_polygon (filled_polygon

View File

@@ -527,11 +527,23 @@
"label": "DNP", "label": "DNP",
"name": "${DNP}", "name": "${DNP}",
"show": true "show": true
},
{
"group_by": false,
"label": "#",
"name": "${ITEM_NUMBER}",
"show": false
},
{
"group_by": false,
"label": "Description",
"name": "Description",
"show": false
} }
], ],
"filter_string": "", "filter_string": "",
"group_symbols": true, "group_symbols": true,
"name": "Grouped By Value", "name": "",
"sort_asc": true, "sort_asc": true,
"sort_field": "Reference" "sort_field": "Reference"
}, },

View File

@@ -6143,7 +6143,7 @@
(justify left) (justify left)
) )
) )
(property "Value" "TBD" (property "Value" "0.1μF"
(at 330.2 91.948 0) (at 330.2 91.948 0)
(effects (effects
(font (font
@@ -7559,7 +7559,7 @@
(justify right) (justify right)
) )
) )
(property "Value" "B1911B" (property "Value" "B1911R"
(at 360.68 56.1974 90) (at 360.68 56.1974 90)
(effects (effects
(font (font
@@ -7694,7 +7694,7 @@
(justify left) (justify left)
) )
) )
(property "Value" "TBDuF" (property "Value" "100uF"
(at 365.252 91.948 0) (at 365.252 91.948 0)
(effects (effects
(font (font
@@ -8055,7 +8055,7 @@
(justify left) (justify left)
) )
) )
(property "Value" "TBDuF" (property "Value" "100uF"
(at 357.632 91.948 0) (at 357.632 91.948 0)
(effects (effects
(font (font
@@ -8556,8 +8556,8 @@
(justify left) (justify left)
) )
) )
(property "Value" "TBD" (property "Value" "10μF"
(at 295.91 94.488 0) (at 295.402 94.488 0)
(effects (effects
(font (font
(size 1.27 1.27) (size 1.27 1.27)
@@ -9264,8 +9264,8 @@
(justify left) (justify left)
) )
) )
(property "Value" "TBD" (property "Value" "100pF"
(at 342.9 91.948 0) (at 341.63 92.456 0)
(effects (effects
(font (font
(size 1.27 1.27) (size 1.27 1.27)
@@ -10421,7 +10421,7 @@
) )
) )
) )
(property "Value" "52.3Ω" (property "Value" "52.3kΩ"
(at 348.488 88.646 90) (at 348.488 88.646 90)
(effects (effects
(font (font

2
scripts/build.sh Normal file → Executable file
View File

@@ -8,8 +8,10 @@ export IDF_PATH=${PWD}/lib/esp-idf
export SDKCONFIG=${PWD}/config/sdkconfig export SDKCONFIG=${PWD}/config/sdkconfig
export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults
export IDF_PATH_FORCE=1
. ${IDF_PATH}/export.sh . ${IDF_PATH}/export.sh
idf.py set-target esp32s3
idf.py build idf.py build
# idk how to put it in the right place # idk how to put it in the right place

1
scripts/flash.sh Normal file → Executable file
View File

@@ -8,6 +8,7 @@ export IDF_PATH=${PWD}/lib/esp-idf
export SDKCONFIG=${PWD}/config/sdkconfig export SDKCONFIG=${PWD}/config/sdkconfig
export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults
export IDF_PATH_FORCE=1
. ${IDF_PATH}/export.sh . ${IDF_PATH}/export.sh
idf.py fullclean idf.py fullclean

1
scripts/monitor.sh Normal file → Executable file
View File

@@ -5,6 +5,7 @@ set -e
export IDF_TOOLS_PATH=${PWD}/lib/idf-tools export IDF_TOOLS_PATH=${PWD}/lib/idf-tools
export IDF_PATH=${PWD}/lib/esp-idf export IDF_PATH=${PWD}/lib/esp-idf
export IDF_PATH_FORCE=1
. ${IDF_PATH}/export.sh . ${IDF_PATH}/export.sh
idf.py -b 115200 monitor idf.py -b 115200 monitor

View File

@@ -1,9 +1,12 @@
file(GLOB SRC_FILES "*.c" "*.cpp") file(GLOB SRC_FILES
"*.c"
"*.cpp"
)
idf_component_register( idf_component_register(
SRCS ${SRC_FILES} SRCS ${SRC_FILES}
PRIV_REQUIRES spi_flash PRIV_REQUIRES spi_flash
REQUIRES esp_driver_gpio REQUIRES esp_driver_gpio esp_driver_spi
INCLUDE_DIRS "." INCLUDE_DIRS "."
) )

59
src/drivers/ssd.c Normal file
View File

@@ -0,0 +1,59 @@
#include "ssd.h"
#include "esp_rom_sys.h"
#include "esp_log.h"
#ifdef __cplusplus
extern "C" {
#endif
inline void pulse(gpio_num_t pin) {
gpio_set_level(pin, 1);
gpio_set_level(pin, 0);
}
void shiftInit(const ssd_595_t* device) {
gpio_reset_pin(device->dataPin);
gpio_reset_pin(device->clockPin);
gpio_reset_pin(device->latchPin);
gpio_config_t ioConfig = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1ULL << device->dataPin) |
(1ULL << device->clockPin) |
(1ULL << device->latchPin),
};
gpio_config(&ioConfig);
gpio_set_level(device->dataPin, 0);
gpio_set_level(device->clockPin, 0);
gpio_set_level(device->latchPin, 0);
ESP_LOGI(__FILE__, "ssd_595 initialized");
}
void addDecimal(uint8_t* data) {
// TODO: fix
// data = (*data | 0x01);
}
void shiftByte(const ssd_595_t* device, uint8_t byte) {
for(int i = 0; i < __CHAR_BIT__ ; i++) {
uint32_t level = ((byte >> i) & 0x1) ^ device->commonCathode;
gpio_set_level(device->dataPin, level);
pulse(device->clockPin);
}
pulse(device->latchPin);
}
void shiftBytes(const ssd_595_t* device, uint8_t* bytes, size_t numBytes) {
for(size_t i = 0; i < numBytes; i++) {
shiftByte(device, bytes[i]);
}
}
#ifdef __cplusplus
}
#endif

70
src/drivers/ssd.h Normal file
View File

@@ -0,0 +1,70 @@
#pragma once
#include <stdint.h>
#include "driver/gpio.h"
#define SSD_DIGIT_MAP_LENGTH 32
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
gpio_num_t dataPin;
gpio_num_t clockPin;
gpio_num_t latchPin;
bool commonCathode; // false = common anode
} ssd_595_t;
// encoding of digits on the seven segment display
// 0bxxxxxxxx
// ABCDEFG.
static uint8_t digitMap[SSD_DIGIT_MAP_LENGTH] = {
0xFC, // 0
0x60, // 1
0xDA, // 2
0xF2, // 3
0x66, // 4
0xB6, // 5
0xBE, // 6
0xE0, // 7
0xFE, // 8
0xF6, // 9
0xEE, // A
0x3E, // B
0x9C, // C
0x7A, // D
0x9E, // E
0x8E, // F
0x02, // -
0x01, // .
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
0x92, // Error code (not implemented)
};
// TODO: have these return error codes likewise
void shiftInit(const ssd_595_t* device);
void pulse(gpio_num_t pin);
void addDecimal(uint8_t* data); // adds a decimal to a single digit
void shiftByte(const ssd_595_t* device, uint8_t byte); // outputs a serial byte, big-endian
void shiftBytes(const ssd_595_t* device, uint8_t* bytes, size_t numBytes); // outputs multiple bytes
#ifdef __cplusplus
}
#endif

116
src/drivers/wsled.c Normal file
View File

@@ -0,0 +1,116 @@
#include "wsled.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#ifdef __cplusplus
extern "C" {
#endif
static uint16_t* dmaBuffer;
static size_t dmaBufferSize;
static spi_settings_t spiSettings = {
.host = SPI2_HOST,
.dma_chan = SPI_DMA_CH_AUTO,
.buscfg =
{
.miso_io_num = -1,
.sclk_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
},
.devcfg =
{
.clock_speed_hz = 3.2 * 1000 * 1000, // Clock out at 3.2 MHz
.mode = 0, // SPI mode 0
.spics_io_num = -1, // CS pin
.queue_size = 1,
.command_bits = 0,
.address_bits = 0,
//.flags = SPI_DEVICE_TXBIT_LSBFIRST,
},
};
// translations from SPI -> ws2812b protocol
// [spi] 0b1110 = [ws2812b]0b1 and [spi] 0b1000 = [ws2812b]0b0
static const uint16_t timingBits[16] = {
0x1111, 0x7111, 0x1711, 0x7711, 0x1171, 0x7171, 0x1771, 0x7771,
0x1117, 0x7117, 0x1717, 0x7717, 0x1177, 0x7177, 0x1777, 0x7777};
// WS2812b can handle shorter reset delays than the WS2815
static inline uint32_t resetDelay(const wsled_t* dev) {
return (dev->type == WS2812B) ? WSLED_12_RESET_TIME : WSLED_15_RESET_TIME;
}
esp_err_t wsledInit(const wsled_t* dev) {
// 12 bytes for each led + bytes for initial zero and reset state
dmaBufferSize = dev->numLeds * 12 + (resetDelay(dev) + 1) * 2;
spiSettings.buscfg.mosi_io_num = dev->pin;
spiSettings.buscfg.max_transfer_sz = dmaBufferSize;
if (ESP_OK != spi_bus_initialize(spiSettings.host, &spiSettings.buscfg, spiSettings.dma_chan)) {
ESP_LOGI(__FILE__, "SPI initialization failed");
return -1;
}
if (ESP_OK != spi_bus_add_device(spiSettings.host, &spiSettings.devcfg, &spiSettings.spi)) {
ESP_LOGI(__FILE__, "Failed to add spi bus device");
return -1;
}
dmaBuffer = heap_caps_malloc(dmaBufferSize, MALLOC_CAP_DMA);
if (NULL == dmaBuffer) {
ESP_LOGI(__FILE__, "Failed to heap_caps_malloc");
return -1;
}
return ESP_OK;
}
esp_err_t wsledUpdate(const wsled_t* dev, const CRGB* pixels, size_t ledCount) {
uint32_t n = 0;
memset(dmaBuffer, 0, dmaBufferSize);
dmaBuffer[n++] = 0;
for (int i = 0; i < ledCount; i++) {
CRGB currentPixel = pixels[i];
uint8_t b0 = (dev->type == WS2812B) ? currentPixel.g : currentPixel.r;
uint8_t b1 = (dev->type == WS2812B) ? currentPixel.r : currentPixel.g;
uint8_t b2 = currentPixel.b;
// Green
dmaBuffer[n++] = timingBits[(b0 >> 4) & 0x0F];
dmaBuffer[n++] = timingBits[b0 & 0x0F];
// Red
dmaBuffer[n++] = timingBits[(b1 >> 4) & 0x0F];
dmaBuffer[n++] = timingBits[b1 & 0x0F];
// Blue
dmaBuffer[n++] = timingBits[(b2 >> 4) & 0x0F];
dmaBuffer[n++] = timingBits[b2 & 0x0F];
}
// reset pulse
for (int i = 0; i < resetDelay(dev); i++) {
dmaBuffer[n++] = 0;
}
esp_err_t error = spi_device_transmit(spiSettings.spi, &(spi_transaction_t) {
.length = dmaBufferSize * 8,
.tx_buffer = dmaBuffer,
});
return error;
}
#ifdef __cplusplus
}
#endif

49
src/drivers/wsled.h Normal file
View File

@@ -0,0 +1,49 @@
#pragma once
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include <stdio.h>
#include <string.h>
#define WSLED_12_RESET_TIME 5
#define WSLED_15_RESET_TIME 30
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
} CRGB;
typedef enum {
WS2812B = 0,
WS2815
} WsledType;
typedef struct {
spi_host_device_t host;
spi_device_handle_t spi;
int dma_chan;
spi_device_interface_config_t devcfg;
spi_bus_config_t buscfg;
} spi_settings_t;
typedef struct {
gpio_num_t pin;
WsledType type;
uint32_t numLeds;
} wsled_t;
// initializes the wsled device provided the device settings
esp_err_t wsledInit(const wsled_t* dev);
// outputs the pixel data in pixels to the device
esp_err_t wsledUpdate(const wsled_t* dev, const CRGB* pixels, size_t ledCount);
#ifdef __cplusplus
}
#endif

28
src/main/App.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include "App.hpp"
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "shared/pins.h"
#include "DemoTask.hpp"
App::App() {
ESP_LOGI(TAG, "App constructor");
}
uint32_t App::main() {
ESP_LOGI(__FILE__, "Running App::main()");
static DemoTask demoTask{};
ESP_LOGI(__FILE__, "Starting DemoTask");
demoTask.start("DemoTask", 4096, 5, 1);
return 1;
}

20
src/main/App.hpp Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include<stdint.h>
// This class is for managing tasks
class App {
public:
App();
~App() = default;
uint32_t main();
private:
const char *TAG = "app"; // TODO: instead of this for logging you can use __FILE__ or __func__
};

10
src/main/CMakeLists.txt Normal file
View File

@@ -0,0 +1,10 @@
file(GLOB SRC_FILES
"*.c"
"*.cpp"
)
idf_component_register(
SRCS ${SRC_FILES}
INCLUDE_DIRS "." ".."
)

View File

@@ -14,7 +14,7 @@ void app_main(void) {
ESP_LOGI(TAG, "Program start"); ESP_LOGI(TAG, "Program start");
App app; App app;
int8_t status = app.main(); int32_t status = app.main();
ESP_LOGI(TAG, "App main returned status %d", status); ESP_LOGI(TAG, "App main returned status %d", status);
} }

8
src/shared/common.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
enum STATUS {
OKAY = 0,
ERROR = -1,
NOT_IMPLEMENTED = -2,
};

34
src/shared/pins.h Normal file
View File

@@ -0,0 +1,34 @@
#include "driver/gpio.h"
// onboard led
const gpio_num_t gpio_onboardLed = GPIO_NUM_2;
// misc
const gpio_num_t gpio_msdDetect = GPIO_NUM_8;
const gpio_num_t gpio_ws2812b = GPIO_NUM_9;
// i2c
const gpio_num_t gpio_i2c_dout = GPIO_NUM_11;
const gpio_num_t gpio_i2c_din = GPIO_NUM_12;
// i2c expander interrupts
const gpio_num_t gpio_i2c_intrA = GPIO_NUM_14;
const gpio_num_t gpio_i2c_intrB = GPIO_NUM_13;
// uart
const gpio_num_t gpio_uart_rx = (gpio_num_t)44; // should already be configured
const gpio_num_t gpio_uart_tx = (gpio_num_t)43; // should already be configured
// seven segment display
const gpio_num_t gpio_ssd_latch = GPIO_NUM_17;
const gpio_num_t gpio_ssd_clk = GPIO_NUM_18;
const gpio_num_t gpio_ssd_data = GPIO_NUM_21;
// i2s
const gpio_num_t gpio_i2s_wsel = GPIO_NUM_38;
const gpio_num_t gpio_i2s_din = GPIO_NUM_39;
const gpio_num_t gpio_i2s_bck = (gpio_num_t)40; // idk why it only goes up to 40
const gpio_num_t gpio_i2s_mck = (gpio_num_t)41;
const gpio_num_t gpio_i2s_mute = (gpio_num_t)42;
const gpio_num_t gpio_i2s_shdn = (gpio_num_t)45;

12
src/ssd/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
file(GLOB SRC_FILES
"*.c"
"*.cpp"
)
idf_component_register(
SRCS ${SRC_FILES}
PRIV_REQUIRES spi_flash
REQUIRES esp_driver_gpio esp_driver_spi
INCLUDE_DIRS "." ".."
)

28
src/ssd/SsdInterface.cpp Normal file
View File

@@ -0,0 +1,28 @@
#include "SsdInterface.hpp"
SsdInterface::SsdInterface(const ssd_595_t* device, size_t numDigits) : device_(device), numDigits_(numDigits) {
shiftInit(device_);
}
STATUS SsdInterface::writeRaw(uint8_t* bytes, size_t numBytes) {
shiftBytes(device_, bytes, numBytes);
return OKAY;
}
STATUS SsdInterface::write10(int32_t value) {
// TODO: implement
return NOT_IMPLEMENTED;
}
STATUS SsdInterface::write16(int32_t value) {
// TODO: implement
return NOT_IMPLEMENTED;
}
STATUS SsdInterface::get(uint8_t* bytes) {
// TODO: implement
return NOT_IMPLEMENTED;
}

43
src/ssd/SsdInterface.hpp Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
#include "stdint.h"
#include "drivers/ssd.h"
#include "shared/common.h"
class SsdInterface {
public:
SsdInterface(const ssd_595_t* device, size_t numDigits);
~SsdInterface() = default;
// Outputs the data straight to hardware, mostly for testing purposes
// bytes: the data to write, with bits targetting an led on the ssd
// Returns: execution status
STATUS writeRaw(uint8_t* bytes, size_t numBytes);
// Displays a decimal integer on the ssd
// value: the integer to display
// Returns: execution status
STATUS write10(int32_t value);
// Displays a hexadecimal integer on the ssd
// value: the integer to display
// Returns: execution status
STATUS write16(int32_t value);
// Copies the data currently displayed on the ssd to bytes
// bytes: place to write to
// Returns: execution status
STATUS get(uint8_t* bytes);
private:
const ssd_595_t* device_;
size_t numDigits_; // number of chained digits
uint8_t* data_; // pointer to the data written
};

12
src/tasks/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
file(GLOB SRC_FILES
"*.c"
"*.cpp"
)
idf_component_register(
SRCS ${SRC_FILES}
PRIV_REQUIRES spi_flash
REQUIRES esp_driver_gpio esp_driver_spi
INCLUDE_DIRS "." ".."
)

46
src/tasks/DemoTask.cpp Normal file
View File

@@ -0,0 +1,46 @@
#include "DemoTask.hpp"
#include "esp_log.h"
#include "ssd/SsdInterface.hpp"
#include "wsled/WsledInterface.hpp"
#include "shared/pins.h"
#define NUM_LEDS 4
DemoTask::DemoTask() {
}
void DemoTask::run() {
ESP_LOGI(__FILE__, "Demo Task: run()");
// ssd device
ssd_595_t ssdDev = { gpio_ssd_data, gpio_ssd_clk, gpio_ssd_latch, true };
SsdInterface ssd(&ssdDev, ssdDigits);
// wsled device
wsled_t wsledDev = { gpio_ws2812b, WS2812B, NUM_LEDS};
WsledInterface wsled(&wsledDev);
uint32_t delay = 500; // ms
uint8_t digit = 0;
while(1) {
// the SSD demo shifts a single hex digit over
ssd.writeRaw(&digitMap[digit], 1);
digit++;
if(digit >= 16) digit = 0;
// the wsled demo toggles the entire array between red and blue
CRGB color = (digit % 2) ? CRGB{100, 20, 20} : CRGB{20, 20, 100};
wsled.fill(color);
wsled.flush();
vTaskDelay(delay / portTICK_PERIOD_MS);
}
}

16
src/tasks/DemoTask.hpp Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include "TaskBase.hpp"
class DemoTask : public TaskBase {
public:
DemoTask();
protected:
void run() override;
private:
const size_t ssdDigits = 4;
};

17
src/tasks/TaskBase.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include "TaskBase.hpp"
#include "esp_log.h"
void TaskBase::start(const char* name, uint32_t stackSize, UBaseType_t priority, BaseType_t core) {
xTaskCreatePinnedToCore(&TaskBase::taskEntryPoint, name, stackSize, this, priority, &handle, core);
return;
}
void TaskBase::taskEntryPoint(void* param) {
auto* task = static_cast<TaskBase*>(param);
task->run();
vTaskDelete(nullptr);
return;
}

20
src/tasks/TaskBase.hpp Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
class TaskBase {
public:
virtual ~TaskBase() = default;
void start(const char* name, uint32_t stackSize, UBaseType_t priority, BaseType_t core = tskNO_AFFINITY);
protected:
virtual void run() = 0;
private:
TaskHandle_t handle = nullptr;
static void taskEntryPoint(void* param);
};

12
src/wsled/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
file(GLOB SRC_FILES
"*.c"
"*.cpp"
)
idf_component_register(
SRCS ${SRC_FILES}
PRIV_REQUIRES spi_flash
REQUIRES esp_driver_gpio esp_driver_spi
INCLUDE_DIRS "." ".."
)

View File

@@ -0,0 +1,50 @@
#include "WsledInterface.hpp"
WsledInterface::WsledInterface(const wsled_t* device) : device_(device), numLeds_(device->numLeds) {
(void)wsledInit(device);
// who cares if its dynamically allocated we have like 4 Mb of ram
// an led strip 1024 long will use 3kb here and 12kb in the driver for dma
leds_.resize(numLeds_);
// turn all leds off
(void)fill(CRGB(0, 0, 0));
(void)flush();
}
STATUS WsledInterface::writePixel(CRGB pixel, size_t index) {
// is it really that easy
leds_[index] = pixel;
return OKAY;
}
STATUS WsledInterface::get(CRGB* pixel, size_t index) {
// I could just return the pixel but im so cool and C coded
*pixel = leds_[index];
return OKAY;
}
STATUS WsledInterface::flush() {
// man I wrote my driver so well that it really is that easy
wsledUpdate(device_, leds_.data(), numLeds_);
return OKAY;
}
STATUS WsledInterface::fill(CRGB color) {
// I HATE ITERATORS YOU CAN NEVER MAKE ME USE THEM !!!!
for (size_t i = 0; i < numLeds_; i++) {
leds_[i] = color;
}
return OKAY;
}

View File

@@ -0,0 +1,47 @@
#pragma once
#include "stdint.h"
#include <vector>
#include "drivers/wsled.h"
#include "shared/common.h"
class WsledInterface {
public:
WsledInterface(const wsled_t* device);
~WsledInterface() = default;
// Sets a pixel in the leds buffer to a particular color
// index: the order in the strip of the pixel
// Returns: execution status
STATUS writePixel(CRGB pixel, size_t index);
// Copies the color currently in a pixel to the pointer
// index: the order in the strip of the pixel
// Returns: execution status
STATUS get(CRGB* pixel, size_t index);
// Writes all the data in the leds buffer to hardware
// Returns: execution status
STATUS flush();
// Below are the helper functions for manipulating the led buffer
// Fills the buffer with a single color
// Returns: execution status
STATUS fill(CRGB color);
// getter for numLeds_
size_t ledCount() { return numLeds_; }
private:
const wsled_t* device_;
size_t numLeds_;
std::vector<CRGB> leds_;
};

View File