1
0
Fork 0

extract config.h

main
radex 2024-06-04 18:31:09 +02:00
parent 0c2f64a973
commit a2f703c2e1
Signed by: radex
SSH Key Fingerprint: SHA256:hvqRXAGG1h89yqnS+cyFTLKQbzjWD4uXIqw7Y+0ws30
12 changed files with 191 additions and 111 deletions

View File

@ -5,8 +5,6 @@
#include "hardware/gpio.h" #include "hardware/gpio.h"
#include "audio.h" #include "audio.h"
// #include "audio_sample.h"
// Adapted from https://github.com/rgrosset/pico-pwm-audio // Adapted from https://github.com/rgrosset/pico-pwm-audio
#define MAX_PWM_POS (BUFFER_LEN << 3) #define MAX_PWM_POS (BUFFER_LEN << 3)
@ -42,9 +40,8 @@ void pwm_interrupt_handler() {
} }
// 11 KHz is fine for speech. Phone lines generally sample at 8 KHz // 11 KHz is fine for speech. Phone lines generally sample at 8 KHz
#define SYS_CLOCK 125000000.0f
#define AUDIO_WRAP 256.0f #define AUDIO_WRAP 256.0f
#define AUDIO_CLK_DIV (SYS_CLOCK / AUDIO_WRAP / 8.0f / AUDIO_RATE) #define AUDIO_CLK_DIV (CPU_CLOCK_HZ / AUDIO_WRAP / 8.0f / AUDIO_RATE)
void init_audio() { void init_audio() {
gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM); gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM);

View File

@ -3,11 +3,7 @@
#ifndef _audio_h #ifndef _audio_h
#define _audio_h #define _audio_h
#define AUDIO_PIN 8 #include "config.h"
#define AUDIO_RATE 44000.0f
#define BUFFER_LEN 512*16
#define BUFFER_LEN_MS (BUFFER_LEN / AUDIO_RATE) * 1000.0f
extern uint8_t wav_buffer_0[BUFFER_LEN]; extern uint8_t wav_buffer_0[BUFFER_LEN];
extern uint8_t wav_buffer_1[BUFFER_LEN]; extern uint8_t wav_buffer_1[BUFFER_LEN];

36
firmware/src/config.cpp Normal file
View File

@ -0,0 +1,36 @@
#include <Arduino.h>
#include "config.h"
#define CPU_MHZ ((uint32_t) CPU_CLOCK_HZ / 1000000)
#define NS_PER_CYCLE (1000 / CPU_MHZ)
#define NS_TO_DELAY(ns) (ns / NS_PER_CYCLE / LEDS_PIO_CLKDIV)
// delays in nanoseconds per brightness phase (i.e. depth bit index)
uint32_t brightnessPhaseDelays[COLOR_BITS] = {
// NOTE: 100ns seems to be the minimum that's (barely) visible on current hardware
/* 1 */ NS_TO_DELAY(170),
/* 2 */ NS_TO_DELAY(180),
/* 4 */ NS_TO_DELAY(210),
/* 8 */ NS_TO_DELAY(540),
/* 16 */ NS_TO_DELAY(2300), // x2
/* 32 */ NS_TO_DELAY(3000), // x4
/* 64 */ NS_TO_DELAY(2500), // x10
/* 128 */ NS_TO_DELAY(3300), // x20
};
uint8_t brightnessPhaseDithering[COLOR_BITS] = {
// Out of DITHERING_PHASES, how many of these should a given
// brightness phase be displayed?
// NOTE: This is done brecause for small delays, pixel pushing dominates the time, making
// the display's duty cycle (and hence brightness) low. But since these less significant bits
// contribute little to the overall brightness, and overall displaying time is short (a fraction of
// a framerate), we can skip displaying these small brightness levels most of the time.
/* 1 */ 1,
/* 2 */ 1,
/* 4 */ 1,
/* 8 */ 1,
/* 16 */ 2,
/* 32 */ 4,
/* 64 */ 10,
/* 128 */ 20,
};

95
firmware/src/config.h Normal file
View File

@ -0,0 +1,95 @@
#pragma once
#ifndef _config_h
#define _config_h
// --- pinout ---
#define AUDIO_PIN 8
#define SD_PIN_SS 1
#define SD_PIN_SCK 2
#define SD_PIN_MOSI 3
#define SD_PIN_MISO 0
#define SD_HAS_DETECTION true
#define SD_DET_PIN 4
#define CAN_ENABLED false
#define CAN_PIN_RX 5
#define CAN_PIN_TX 7
#define CAN_PIN_SILENT 6
#define UART_TX_PIN 16
#define UART_RX_PIN 17
// NOTE: with current layout, 9-15 are free GPIOs (14, 15 only when using shared SER, SRCLR)
#define NEXT_PIN 9
#define CC1_PIN 26
#define CC2_PIN 27
#define V_SENSE_PIN 28
#define I_SENSE_PIN 29
// --- pinout - screen ---
#define COMMON_SER 21
// #define COMMON_RCLK 23
#define COMMON_SRCLR 25
// #define COL_SER 21
#define COL_OE 22
#define COL_RCLK 23
#define COL_SRCLK 24
// #define COL_SRCLR 25
// #define ROW_SER 14
#define ROW_OE 13
#define ROW_RCLK 20
#define ROW_SRCLK 18
// #define ROW_SRCLR 15
// --- screen settings ---
#define ROW_MODULES 2
#define COL_MODULES 2
#define COLOR_BITS 8
#define MAX_FPS 30
#define MAX_LENGTH_MIN 10
#define ROW_COUNT ROW_MODULES * 20
#define COL_COUNT COL_MODULES * 20
// --- audio settings ---
#define AUDIO_RATE 44000.0f
#define BUFFER_LEN 512*16
// --- other settings ---
#define CPU_CLOCK_HZ 125000000.0f
#define SD_CARD_BAUD_RATE 10 * 1000 * 1000
#define REFERENCE_VOLTAGE 3.3f // for ADC
// --- debug settings ---
#define DEBUG_TEST_FRAME false
#define DEBUG_FIRST_FRAME false
#define DEBUG_FRAMEBUFFER false
// --- screen - performance ---
// NOTE: In case of screen glitching, these may need to be tweaked to decrease
// data rate to the display and stay within the limits of the hardware/electrical connection
#define LEDS_PIO_CLKDIV 1
// Also see leds.pio where delays may be adjusted (need manual compilation)
// --- screen - color correction ---
// I do not understand color correction, gamma, it's all black magic to me
// This was manually tuned using DEBUG_TEST_FRAME=true test pattern
// See config.cpp
extern uint32_t brightnessPhaseDelays[COLOR_BITS];
extern uint8_t brightnessPhaseDithering[COLOR_BITS];
#define DITHERING_PHASES 20;
#endif

View File

@ -3,10 +3,10 @@
#include "lodepng.h" #include "lodepng.h"
#include "leds.h" #include "leds.h"
uint16_t gfxFrameLengthsBuffer[24000] = {0}; uint16_t gfxFrameLengthsBuffer[GFX_DECODER_LENGTH_BUFFER_SIZE] = {0};
uint16_t frameCount = 0; uint16_t frameCount = 0;
uint8_t gfxFrameBuffer[6400] = {0}; uint8_t gfxFrameBuffer[GFX_DECODER_FRAME_BUFFER_SIZE] = {0};
int32_t gfx_decoder_loadNextFrame() { int32_t gfx_decoder_loadNextFrame() {
// load frame from SD card // load frame from SD card

View File

@ -3,10 +3,14 @@
#define GFX_DECODER_H #define GFX_DECODER_H
#include <Arduino.h> #include <Arduino.h>
#include "config.h"
extern uint16_t gfxFrameLengthsBuffer[24000]; #define GFX_DECODER_LENGTH_BUFFER_SIZE MAX_LENGTH_MIN * 60 * MAX_FPS
#define GFX_DECODER_FRAME_BUFFER_SIZE ROW_COUNT * COL_COUNT * 4
extern uint16_t gfxFrameLengthsBuffer[GFX_DECODER_LENGTH_BUFFER_SIZE];
extern uint16_t frameCount; extern uint16_t frameCount;
extern uint8_t gfxFrameBuffer[6400]; extern uint8_t gfxFrameBuffer[GFX_DECODER_FRAME_BUFFER_SIZE];
int32_t gfx_decoder_loadNextFrame(); int32_t gfx_decoder_loadNextFrame();
int32_t gfx_decoder_handleLoop(); int32_t gfx_decoder_handleLoop();

View File

@ -11,12 +11,9 @@ uint pusher_sm = 255; // invalid
uint delay_sm = 255; // invalid uint delay_sm = 255; // invalid
uint row_sm = 255; // invalid uint row_sm = 255; // invalid
#define LEDS_PIO_CLKDIV 1
// NOTE: RCLK, SRCLK capture on *rising* edge // NOTE: RCLK, SRCLK capture on *rising* edge
inline void pulsePin(uint8_t pin) { inline void pulsePin(uint8_t pin) {
gpio_put(pin, HIGH); gpio_put(pin, HIGH);
// there are glitches without this (maybe just due to breadboard...)
asm volatile("nop \n nop \n nop"); asm volatile("nop \n nop \n nop");
gpio_put(pin, LOW); gpio_put(pin, LOW);
} }
@ -34,42 +31,11 @@ inline void outputEnable(uint8_t pin, bool enable) {
// we have COLOR_BITS-bit color depth, so 2^COLOR_BITS levels of brightness // we have COLOR_BITS-bit color depth, so 2^COLOR_BITS levels of brightness
// we go from phase 0 to phase (COLOR_BITS-1) // we go from phase 0 to phase (COLOR_BITS-1)
uint8_t brightnessPhase = 0; uint8_t brightnessPhase = 0;
// delays in nanoseconds
#define NS_TO_DELAY(ns) (ns / NS_PER_CYCLE / LEDS_PIO_CLKDIV)
uint32_t brightnessPhaseDelays[COLOR_BITS] = {
// NOTE: 100ns seems to be the minimum that's (barely) visible
/* 1 */ NS_TO_DELAY(170),
/* 2 */ NS_TO_DELAY(180),
/* 4 */ NS_TO_DELAY(210),
/* 8 */ NS_TO_DELAY(540),
/* 16 */ NS_TO_DELAY(2300), // x2
/* 32 */ NS_TO_DELAY(3000), // x4
/* 64 */ NS_TO_DELAY(2500), // x10
/* 128 */ NS_TO_DELAY(3300), // x20
};
#define DITHERING_PHASES 20;
uint8_t ditheringPhase = 0; uint8_t ditheringPhase = 0;
uint8_t brightnessPhaseDithering[COLOR_BITS] = {
// Out of DITHERING_PHASES, how many of these should a given
// brightness phase be displayed?
// NOTE: This is done brecause for small delays, pixel pushing dominates the time, making
// the display's duty cycle (and hence brightness) low. But since these less significant bits
// contribute little to the overall brightness, and overall displaying time is short (a fraction of
// a framerate), we can skip displaying these small brightness levels most of the time.
/* 1 */ 1,
/* 2 */ 1,
/* 4 */ 1,
/* 8 */ 1,
/* 16 */ 2,
/* 32 */ 4,
/* 64 */ 10,
/* 128 */ 20,
};
// NOTE: Alignment required to allow 4-byte reads #if DEBUG_FRAMEBUFFER
uint8_t framebuffer[ROW_COUNT * COL_COUNT] __attribute__((aligned(32))) = {0}; uint8_t framebuffer[ROW_COUNT * COL_COUNT] = {0};
#endif
// Framebuffer encoded for fast PIO pixel pushing // Framebuffer encoded for fast PIO pixel pushing
// There's one buffer for each of pixel's bit indices (aka brightness phases), // There's one buffer for each of pixel's bit indices (aka brightness phases),
@ -81,13 +47,14 @@ uint8_t framebuffer[ROW_COUNT * COL_COUNT] __attribute__((aligned(32))) = {0};
// 1 bit (LSB) to indicate start of frame (1) or not (0) // 1 bit (LSB) to indicate start of frame (1) or not (0)
// remaining bits to indicate a number of shift register pulses // remaining bits to indicate a number of shift register pulses
// (again, 24 shift register stages per 20 rows, so there are placeholders) // (again, 24 shift register stages per 20 rows, so there are placeholders)
uint32_t ledBuffer[8][ROW_COUNT * (COL_MODULES + 1)] = {0}; uint32_t ledBuffer[COLOR_BITS][ROW_COUNT * (COL_MODULES + 1)] = {0};
bool ledBufferReady = false; bool ledBufferReady = false;
void leds_set_framebuffer(uint8_t *buffer) { void leds_set_framebuffer(uint8_t *buffer) {
// TODO: Use a separate buffer, then copy to ledsBuffer to avoid tearing // TODO: Use a separate buffer, then copy to ledsBuffer to avoid tearing
for (int bi = 0; bi < 8; bi++) { #define UNUSED_BITS 8 - COLOR_BITS
uint8_t bitPosition = 1 << bi; for (int bi = 0; bi < COLOR_BITS; bi++) {
uint8_t bitPosition = 1 << (bi + UNUSED_BITS);
for (int yModule = 0; yModule < ROW_MODULES; yModule++) { for (int yModule = 0; yModule < ROW_MODULES; yModule++) {
for (int moduleY = 0; moduleY < 20; moduleY++) { for (int moduleY = 0; moduleY < 20; moduleY++) {
@ -142,13 +109,17 @@ void leds_set_framebuffer(uint8_t *buffer) {
} }
ledBufferReady = true; ledBufferReady = true;
#if DEBUG_FRAMEBUFFER
// copy to framebuffer // copy to framebuffer
// TODO: mutex? double buffer? or something... // TODO: mutex? double buffer? or something...
memcpy(framebuffer, buffer, ROW_COUNT * COL_COUNT); memcpy(framebuffer, buffer, ROW_COUNT * COL_COUNT);
#endif
} }
void leds_init() { void leds_init() {
#if DEBUG_FRAMEBUFFER
memset(framebuffer, 0, sizeof(framebuffer)); memset(framebuffer, 0, sizeof(framebuffer));
#endif
// disable output // disable output
outputEnable(COL_OE, false); outputEnable(COL_OE, false);
@ -192,14 +163,9 @@ void main2() {
} }
} }
void leds_initPusher(); void leds_initPIO();
void leds_initRowSelector();
void leds_initDelay();
void leds_initRenderer() { void leds_initRenderer() {
leds_initPusher();
leds_initRowSelector();
leds_initDelay();
multicore_reset_core1(); multicore_reset_core1();
multicore_launch_core1(main2); multicore_launch_core1(main2);
} }
@ -341,3 +307,9 @@ void leds_initDelay() {
pio_sm_init(pio, sm, offset, &config); pio_sm_init(pio, sm, offset, &config);
pio_sm_set_enabled(pio, sm, true); pio_sm_set_enabled(pio, sm, true);
} }
void leds_initPIO() {
leds_initPusher();
leds_initRowSelector();
leds_initDelay();
}

View File

@ -1,24 +1,8 @@
#pragma once #pragma once
#ifndef LEDS_H #ifndef LEDS_H
#define LEDS_H #define LEDS_H
#include <Arduino.h> #include <Arduino.h>
#include "config.h"
#define COMMON_SER 21
// #define COMMON_RCLK 23
#define COMMON_SRCLR 25
// #define COL_SER 21
#define COL_OE 22
#define COL_RCLK 23
#define COL_SRCLK 24
// #define COL_SRCLR 25
// #define ROW_SER 14
#define ROW_OE 13
#define ROW_RCLK 20
#define ROW_SRCLK 18
// #define ROW_SRCLR 15
#if defined(COMMON_SER) && (defined(ROW_SER) || defined(COL_SER)) #if defined(COMMON_SER) && (defined(ROW_SER) || defined(COL_SER))
#error "COMMON_SER and ROW_SER/COL_SER cannot be defined at the same time" #error "COMMON_SER and ROW_SER/COL_SER cannot be defined at the same time"
@ -47,17 +31,9 @@
#define ROW_SRCLR COMMON_SRCLR #define ROW_SRCLR COMMON_SRCLR
#endif #endif
#define ROW_MODULES 2 #define FPS MAX_FPS
#define ROW_COUNT ROW_MODULES * 20
#define COL_MODULES 2
#define COL_COUNT COL_MODULES * 20
#define COLOR_BITS 8
#define FPS 30
#define MS_PER_FRAME (1000 / FPS) #define MS_PER_FRAME (1000 / FPS)
#define CPU_MHZ 125
#define NS_PER_CYCLE (1000 / CPU_MHZ)
void leds_init(); void leds_init();
void leds_initRenderer(); void leds_initRenderer();

View File

@ -1,8 +1,9 @@
#include <string.h> #include <string.h>
#include <Arduino.h> #include <Arduino.h>
#include "config.h"
#define CELLS_X 40 #define CELLS_X COL_MODULES * 20
#define CELLS_Y 40 #define CELLS_Y ROW_MODULES * 20
#define CELL_COUNT (CELLS_X * CELLS_Y) #define CELL_COUNT (CELLS_X * CELLS_Y)
bool cells[CELL_COUNT] = {0}; bool cells[CELL_COUNT] = {0};

View File

@ -5,13 +5,13 @@
#include "leds.h" #include "leds.h"
#include "gfx_decoder.h" #include "gfx_decoder.h"
#include "can2040.h" #include "can2040.h"
#include "config.h"
void loadVideo(size_t index); void loadVideo(size_t index);
void setup() { void setup() {
leds_init(); leds_init();
setupSDPins(); pinMode(NEXT_PIN, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
delay(2000); delay(2000);
Serial.begin(115200); Serial.begin(115200);
@ -20,24 +20,32 @@ void setup() {
init_audio(); init_audio();
leds_initRenderer(); leds_initRenderer();
// while (!isSDCardInserted()) { #if SD_HAS_DETECTION
// Serial.println("SD card not connected, waiting..."); while (!isSDCardInserted()) {
// delay(1000); Serial.println("SD card not connected, waiting...");
// } delay(1000);
// delay(100); }
delay(100);
#endif
setupSD(); setupSD();
sd_loadPlaylist(); sd_loadPlaylist();
#if DEBUG_TEST_FRAME
gfx_decoder_setTestFrame();
#else
loadVideo(0); loadVideo(0);
#endif
// gfx_decoder_setTestFrame();
} }
size_t currentVideoIndex = 0; size_t currentVideoIndex = 0;
bool isLoaded = false; bool isLoaded = false;
void loadVideo(size_t index) { void loadVideo(size_t index) {
#if DEBUG_TEST_FRAME
return;
#endif
audio_stop(); audio_stop();
sd_loadAudio(index); sd_loadAudio(index);
@ -62,7 +70,7 @@ void nextSong() {
} }
void loop() { void loop() {
if (digitalRead(9) == LOW) { if (digitalRead(NEXT_PIN) == LOW) {
delay(100); delay(100);
nextSong(); nextSong();
delay(50); delay(50);

View File

@ -3,24 +3,18 @@
#include "sd.h" #include "sd.h"
#include "audio.h" #include "audio.h"
#include "gfx_decoder.h" #include "gfx_decoder.h"
#include "config.h"
#include "hw_config.h" #include "hw_config.h"
#include "ff.h" #include "ff.h"
#include "f_util.h" #include "f_util.h"
#define SD_DET_PIN 4
#define SD_PIN_SS 1
#define SD_PIN_SCK 2
#define SD_PIN_MOSI 3
#define SD_PIN_MISO 0
static spi_t spi = { static spi_t spi = {
.hw_inst = spi0, .hw_inst = spi0,
.miso_gpio = SD_PIN_MISO, .miso_gpio = SD_PIN_MISO,
.mosi_gpio = SD_PIN_MOSI, .mosi_gpio = SD_PIN_MOSI,
.sck_gpio = SD_PIN_SCK, .sck_gpio = SD_PIN_SCK,
.baud_rate = 10 * 1000 * 1000, .baud_rate = SD_CARD_BAUD_RATE,
}; };
static sd_spi_if_t spi_if = { static sd_spi_if_t spi_if = {
@ -31,6 +25,10 @@ static sd_spi_if_t spi_if = {
static sd_card_t sd_card = { static sd_card_t sd_card = {
.type = SD_IF_SPI, .type = SD_IF_SPI,
.spi_if_p = &spi_if, .spi_if_p = &spi_if,
#if SD_HAS_DETECTION
.use_card_detect = true,
.card_detect_gpio = SD_DET_PIN,
#endif
}; };
size_t sd_get_num() { size_t sd_get_num() {
@ -45,10 +43,6 @@ sd_card_t *sd_get_by_num(size_t num) {
return nullptr; return nullptr;
} }
void setupSDPins() {
// TODO: Is that even needed if we use built-in SPI?
}
bool isSDCardInserted() { bool isSDCardInserted() {
return digitalRead(SD_DET_PIN) == LOW; return digitalRead(SD_DET_PIN) == LOW;
} }
@ -296,9 +290,11 @@ bool sd_loadGfxBlob(size_t index) {
// Returns size of frame read or -1 if error // Returns size of frame read or -1 if error
int32_t sd_loadNextFrame() { int32_t sd_loadNextFrame() {
#if DEBUG_FIRST_FRAME
if (frameIdx > 0) { if (frameIdx > 0) {
// return -1; return -1;
} }
#endif
if (!gfxFile) { if (!gfxFile) {
Serial.println("Gfx file not available"); Serial.println("Gfx file not available");

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
void setupSDPins();
void setupSD(); void setupSD();
bool isSDCardInserted(); bool isSDCardInserted();