Compare commits
20 Commits
hello-worl
...
36788ac5a6
| Author | SHA1 | Date | |
|---|---|---|---|
| 36788ac5a6 | |||
| 335452cc6d | |||
| 532d93d5d7 | |||
| e3090bf1f5 | |||
| 99e73d5d6b | |||
| 4f333435ea | |||
| 9f884b41e7 | |||
| bb8dcd76b2 | |||
| 7a2f701653 | |||
|
|
1248a0ac39 | ||
| 5cde1bdfce | |||
| a80e918d63 | |||
| c4644105a7 | |||
| 54c9672ba0 | |||
| 8e9d459345 | |||
| 68842bbe0f | |||
| 4588825986 | |||
|
|
32ddc11d6e | ||
|
|
97d7a02218 | ||
| 96ef55e589 |
@@ -5,7 +5,11 @@ set(PROJECT_MAIN_COMPONENT ${CMAKE_CURRENT_LIST_DIR}/src)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
${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
|
||||
|
||||
24
README.md
24
README.md
@@ -10,11 +10,11 @@ Scripts are in scripts directory, named appropriately.
|
||||
|
||||
## Development plan:
|
||||
- [x] Create repository.
|
||||
- [ ] Build setup, get working hello-world program.
|
||||
- [ ] Develop 7-segment display driver for the soburg-v2 board, which uses 32-bit shift registers.
|
||||
- [x] Build setup, get working hello-world program.
|
||||
- [x] Develop 7-segment display driver for the soburg-v2 board, which uses 32-bit shift registers.
|
||||
Ensures functional hardware interaction and interface design.
|
||||
- [ ] 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 driver, would be nice to have some kind of testing for this.
|
||||
- [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
|
||||
- [ ] 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)
|
||||
@@ -31,7 +31,15 @@ Scripts are in scripts directory, named appropriately.
|
||||
This is basic but hopefully can be good platform for future WS2812b projects.
|
||||
|
||||
## Scripts:
|
||||
After cloning: $ ./scripts/repo-setup # installs esp-idf, sets up target configurations
|
||||
To build: $ ./scripts/build.sh
|
||||
To flash: $ ./scripts/flash.sh # note: flash.sh automatically builds
|
||||
To monitor: $ ./scripts/monitor.sh
|
||||
After cloning: $ ./scripts/repo-setup # installs esp-idf, sets up target configurations\
|
||||
To build: $ ./scripts/build.sh\
|
||||
To flash: $ ./scripts/flash.sh # note: flash.sh automatically builds\
|
||||
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
BIN
pcb/control/TEMPLATE.xlsx
Normal file
Binary file not shown.
BIN
pcb/panel/bom.xlsx
Normal file
BIN
pcb/panel/bom.xlsx
Normal file
Binary file not shown.
@@ -22084,7 +22084,7 @@
|
||||
(justify mirror)
|
||||
)
|
||||
)
|
||||
(property "Value" "B1911B"
|
||||
(property "Value" "B1911R"
|
||||
(at 0 -1.43 90)
|
||||
(layer "B.Fab")
|
||||
(uuid "c1484363-b3dc-48b7-9c64-d06df10d96a2")
|
||||
@@ -22764,7 +22764,7 @@
|
||||
(justify mirror)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBDuF"
|
||||
(property "Value" "100uF"
|
||||
(at 2.5 -5.25 0)
|
||||
(layer "B.Fab")
|
||||
(uuid "a592ba06-f886-4233-b793-557c4b352735")
|
||||
@@ -26393,7 +26393,7 @@
|
||||
(justify mirror)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBDuF"
|
||||
(property "Value" "100uF"
|
||||
(at 2.5 -5.25 0)
|
||||
(layer "B.Fab")
|
||||
(uuid "036ec2e2-300a-42a7-987d-e4811bf430e0")
|
||||
@@ -28139,7 +28139,7 @@
|
||||
(justify mirror)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBD"
|
||||
(property "Value" "0.1μF"
|
||||
(at 0 -1.43 90)
|
||||
(layer "B.Fab")
|
||||
(uuid "2125effb-a0e4-4175-9ce6-cce3daef6fd0")
|
||||
@@ -29018,7 +29018,7 @@
|
||||
(justify mirror)
|
||||
)
|
||||
)
|
||||
(property "Value" "52.3Ω"
|
||||
(property "Value" "52.3kΩ"
|
||||
(at 0 -1.43 90)
|
||||
(layer "B.Fab")
|
||||
(uuid "f8ed0ff3-21fe-4dac-b950-096d117b1132")
|
||||
@@ -30643,7 +30643,7 @@
|
||||
(justify mirror)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBD"
|
||||
(property "Value" "100pF"
|
||||
(at 0 -1.43 90)
|
||||
(layer "B.Fab")
|
||||
(uuid "f93816e5-03a1-48e1-b93c-11d13f82d8e9")
|
||||
@@ -31613,7 +31613,7 @@
|
||||
(justify mirror)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBD"
|
||||
(property "Value" "10μF"
|
||||
(at 0 -1.43 0)
|
||||
(layer "B.Fab")
|
||||
(uuid "4ecb6ecd-64d9-4e42-b908-ec3e49aafb1b")
|
||||
@@ -45894,7 +45894,6 @@
|
||||
(polygon
|
||||
(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 150.75 87.5)
|
||||
)
|
||||
)
|
||||
(filled_polygon
|
||||
|
||||
@@ -527,11 +527,23 @@
|
||||
"label": "DNP",
|
||||
"name": "${DNP}",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "#",
|
||||
"name": "${ITEM_NUMBER}",
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Description",
|
||||
"name": "Description",
|
||||
"show": false
|
||||
}
|
||||
],
|
||||
"filter_string": "",
|
||||
"group_symbols": true,
|
||||
"name": "Grouped By Value",
|
||||
"name": "",
|
||||
"sort_asc": true,
|
||||
"sort_field": "Reference"
|
||||
},
|
||||
|
||||
@@ -6143,7 +6143,7 @@
|
||||
(justify left)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBD"
|
||||
(property "Value" "0.1μF"
|
||||
(at 330.2 91.948 0)
|
||||
(effects
|
||||
(font
|
||||
@@ -7559,7 +7559,7 @@
|
||||
(justify right)
|
||||
)
|
||||
)
|
||||
(property "Value" "B1911B"
|
||||
(property "Value" "B1911R"
|
||||
(at 360.68 56.1974 90)
|
||||
(effects
|
||||
(font
|
||||
@@ -7694,7 +7694,7 @@
|
||||
(justify left)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBDuF"
|
||||
(property "Value" "100uF"
|
||||
(at 365.252 91.948 0)
|
||||
(effects
|
||||
(font
|
||||
@@ -8055,7 +8055,7 @@
|
||||
(justify left)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBDuF"
|
||||
(property "Value" "100uF"
|
||||
(at 357.632 91.948 0)
|
||||
(effects
|
||||
(font
|
||||
@@ -8556,8 +8556,8 @@
|
||||
(justify left)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBD"
|
||||
(at 295.91 94.488 0)
|
||||
(property "Value" "10μF"
|
||||
(at 295.402 94.488 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@@ -9264,8 +9264,8 @@
|
||||
(justify left)
|
||||
)
|
||||
)
|
||||
(property "Value" "TBD"
|
||||
(at 342.9 91.948 0)
|
||||
(property "Value" "100pF"
|
||||
(at 341.63 92.456 0)
|
||||
(effects
|
||||
(font
|
||||
(size 1.27 1.27)
|
||||
@@ -10421,7 +10421,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(property "Value" "52.3Ω"
|
||||
(property "Value" "52.3kΩ"
|
||||
(at 348.488 88.646 90)
|
||||
(effects
|
||||
(font
|
||||
|
||||
2
scripts/build.sh
Normal file → Executable file
2
scripts/build.sh
Normal file → Executable file
@@ -8,8 +8,10 @@ export IDF_PATH=${PWD}/lib/esp-idf
|
||||
export SDKCONFIG=${PWD}/config/sdkconfig
|
||||
export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults
|
||||
|
||||
export IDF_PATH_FORCE=1
|
||||
. ${IDF_PATH}/export.sh
|
||||
|
||||
idf.py set-target esp32s3
|
||||
idf.py build
|
||||
|
||||
# idk how to put it in the right place
|
||||
|
||||
1
scripts/flash.sh
Normal file → Executable file
1
scripts/flash.sh
Normal file → Executable file
@@ -8,6 +8,7 @@ export IDF_PATH=${PWD}/lib/esp-idf
|
||||
export SDKCONFIG=${PWD}/config/sdkconfig
|
||||
export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults
|
||||
|
||||
export IDF_PATH_FORCE=1
|
||||
. ${IDF_PATH}/export.sh
|
||||
|
||||
idf.py fullclean
|
||||
|
||||
1
scripts/monitor.sh
Normal file → Executable file
1
scripts/monitor.sh
Normal file → Executable file
@@ -5,6 +5,7 @@ set -e
|
||||
export IDF_TOOLS_PATH=${PWD}/lib/idf-tools
|
||||
export IDF_PATH=${PWD}/lib/esp-idf
|
||||
|
||||
export IDF_PATH_FORCE=1
|
||||
. ${IDF_PATH}/export.sh
|
||||
|
||||
idf.py -b 115200 monitor
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
|
||||
file(GLOB SRC_FILES "*.c" "*.cpp")
|
||||
file(GLOB SRC_FILES
|
||||
"*.c"
|
||||
"*.cpp"
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SRC_FILES}
|
||||
PRIV_REQUIRES spi_flash
|
||||
REQUIRES esp_driver_gpio
|
||||
REQUIRES esp_driver_gpio esp_driver_spi
|
||||
INCLUDE_DIRS "."
|
||||
)
|
||||
)
|
||||
59
src/drivers/ssd.c
Normal file
59
src/drivers/ssd.c
Normal 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
70
src/drivers/ssd.h
Normal 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
116
src/drivers/wsled.c
Normal 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
49
src/drivers/wsled.h
Normal 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
28
src/main/App.cpp
Normal 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
20
src/main/App.hpp
Normal 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
10
src/main/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
file(GLOB SRC_FILES
|
||||
"*.c"
|
||||
"*.cpp"
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SRC_FILES}
|
||||
INCLUDE_DIRS "." ".."
|
||||
)
|
||||
@@ -14,7 +14,7 @@ void app_main(void) {
|
||||
ESP_LOGI(TAG, "Program start");
|
||||
|
||||
App app;
|
||||
int8_t status = app.main();
|
||||
int32_t status = app.main();
|
||||
ESP_LOGI(TAG, "App main returned status %d", status);
|
||||
}
|
||||
|
||||
8
src/shared/common.h
Normal file
8
src/shared/common.h
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
enum STATUS {
|
||||
OKAY = 0,
|
||||
ERROR = -1,
|
||||
NOT_IMPLEMENTED = -2,
|
||||
};
|
||||
34
src/shared/pins.h
Normal file
34
src/shared/pins.h
Normal 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
12
src/ssd/CMakeLists.txt
Normal 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
28
src/ssd/SsdInterface.cpp
Normal 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
43
src/ssd/SsdInterface.hpp
Normal 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
12
src/tasks/CMakeLists.txt
Normal 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
46
src/tasks/DemoTask.cpp
Normal 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
16
src/tasks/DemoTask.hpp
Normal 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
17
src/tasks/TaskBase.cpp
Normal 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
20
src/tasks/TaskBase.hpp
Normal 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
12
src/wsled/CMakeLists.txt
Normal 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 "." ".."
|
||||
)
|
||||
50
src/wsled/WsledInterface.cpp
Normal file
50
src/wsled/WsledInterface.cpp
Normal 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;
|
||||
}
|
||||
47
src/wsled/WsledInterface.hpp
Normal file
47
src/wsled/WsledInterface.hpp
Normal 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_;
|
||||
|
||||
};
|
||||
0
src/wsled/effects/.gitkeep
Normal file
0
src/wsled/effects/.gitkeep
Normal file
Reference in New Issue
Block a user