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 "audio.h"
// #include "audio_sample.h"
// Adapted from https://github.com/rgrosset/pico-pwm-audio
#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
#define SYS_CLOCK 125000000.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() {
gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM);

View File

@ -3,11 +3,7 @@
#ifndef _audio_h
#define _audio_h
#define AUDIO_PIN 8
#define AUDIO_RATE 44000.0f
#define BUFFER_LEN 512*16
#define BUFFER_LEN_MS (BUFFER_LEN / AUDIO_RATE) * 1000.0f
#include "config.h"
extern uint8_t wav_buffer_0[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 "leds.h"
uint16_t gfxFrameLengthsBuffer[24000] = {0};
uint16_t gfxFrameLengthsBuffer[GFX_DECODER_LENGTH_BUFFER_SIZE] = {0};
uint16_t frameCount = 0;
uint8_t gfxFrameBuffer[6400] = {0};
uint8_t gfxFrameBuffer[GFX_DECODER_FRAME_BUFFER_SIZE] = {0};
int32_t gfx_decoder_loadNextFrame() {
// load frame from SD card

View File

@ -3,10 +3,14 @@
#define GFX_DECODER_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 uint8_t gfxFrameBuffer[6400];
extern uint8_t gfxFrameBuffer[GFX_DECODER_FRAME_BUFFER_SIZE];
int32_t gfx_decoder_loadNextFrame();
int32_t gfx_decoder_handleLoop();

View File

@ -11,12 +11,9 @@ uint pusher_sm = 255; // invalid
uint delay_sm = 255; // invalid
uint row_sm = 255; // invalid
#define LEDS_PIO_CLKDIV 1
// NOTE: RCLK, SRCLK capture on *rising* edge
inline void pulsePin(uint8_t pin) {
gpio_put(pin, HIGH);
// there are glitches without this (maybe just due to breadboard...)
asm volatile("nop \n nop \n nop");
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 go from phase 0 to phase (COLOR_BITS-1)
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 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
uint8_t framebuffer[ROW_COUNT * COL_COUNT] __attribute__((aligned(32))) = {0};
#if DEBUG_FRAMEBUFFER
uint8_t framebuffer[ROW_COUNT * COL_COUNT] = {0};
#endif
// Framebuffer encoded for fast PIO pixel pushing
// 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)
// remaining bits to indicate a number of shift register pulses
// (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;
void leds_set_framebuffer(uint8_t *buffer) {
// TODO: Use a separate buffer, then copy to ledsBuffer to avoid tearing
for (int bi = 0; bi < 8; bi++) {
uint8_t bitPosition = 1 << bi;
#define UNUSED_BITS 8 - COLOR_BITS
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 moduleY = 0; moduleY < 20; moduleY++) {
@ -142,13 +109,17 @@ void leds_set_framebuffer(uint8_t *buffer) {
}
ledBufferReady = true;
#if DEBUG_FRAMEBUFFER
// copy to framebuffer
// TODO: mutex? double buffer? or something...
memcpy(framebuffer, buffer, ROW_COUNT * COL_COUNT);
#endif
}
void leds_init() {
#if DEBUG_FRAMEBUFFER
memset(framebuffer, 0, sizeof(framebuffer));
#endif
// disable output
outputEnable(COL_OE, false);
@ -192,14 +163,9 @@ void main2() {
}
}
void leds_initPusher();
void leds_initRowSelector();
void leds_initDelay();
void leds_initPIO();
void leds_initRenderer() {
leds_initPusher();
leds_initRowSelector();
leds_initDelay();
multicore_reset_core1();
multicore_launch_core1(main2);
}
@ -341,3 +307,9 @@ void leds_initDelay() {
pio_sm_init(pio, sm, offset, &config);
pio_sm_set_enabled(pio, sm, true);
}
void leds_initPIO() {
leds_initPusher();
leds_initRowSelector();
leds_initDelay();
}

View File

@ -1,24 +1,8 @@
#pragma once
#ifndef LEDS_H
#define LEDS_H
#include <Arduino.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
#include "config.h"
#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"
@ -47,17 +31,9 @@
#define ROW_SRCLR COMMON_SRCLR
#endif
#define ROW_MODULES 2
#define ROW_COUNT ROW_MODULES * 20
#define COL_MODULES 2
#define COL_COUNT COL_MODULES * 20
#define COLOR_BITS 8
#define FPS 30
#define FPS MAX_FPS
#define MS_PER_FRAME (1000 / FPS)
#define CPU_MHZ 125
#define NS_PER_CYCLE (1000 / CPU_MHZ)
void leds_init();
void leds_initRenderer();

View File

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

View File

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

View File

@ -3,24 +3,18 @@
#include "sd.h"
#include "audio.h"
#include "gfx_decoder.h"
#include "config.h"
#include "hw_config.h"
#include "ff.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 = {
.hw_inst = spi0,
.miso_gpio = SD_PIN_MISO,
.mosi_gpio = SD_PIN_MOSI,
.sck_gpio = SD_PIN_SCK,
.baud_rate = 10 * 1000 * 1000,
.baud_rate = SD_CARD_BAUD_RATE,
};
static sd_spi_if_t spi_if = {
@ -31,6 +25,10 @@ static sd_spi_if_t spi_if = {
static sd_card_t sd_card = {
.type = SD_IF_SPI,
.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() {
@ -45,10 +43,6 @@ sd_card_t *sd_get_by_num(size_t num) {
return nullptr;
}
void setupSDPins() {
// TODO: Is that even needed if we use built-in SPI?
}
bool isSDCardInserted() {
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
int32_t sd_loadNextFrame() {
#if DEBUG_FIRST_FRAME
if (frameIdx > 0) {
// return -1;
return -1;
}
#endif
if (!gfxFile) {
Serial.println("Gfx file not available");

View File

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