1
0
Fork 0

Compare commits

...

2 Commits

Author SHA1 Message Date
radex 73b3760f68
can: add basic heartbeat (untested) 2024-06-05 22:26:42 +02:00
radex 90d9d64e12
leds: fix for new pcb (untested) 2024-06-05 22:26:33 +02:00
8 changed files with 164 additions and 43 deletions

View File

@ -8,7 +8,8 @@
#include <string.h> // memset
// NOTE: This was changed from the original checkout
// #include "RP2040.h" // hw_set_bits
#include "hardware/address_mapped.h" // hw_set_bits
#include "hardware/address_mapped.h" // hw_set_bit
#include "cmsis_gcc.h" // NOTE: this was added for _DMB() to build
#include "can2040.h" // can2040_setup
#include "hardware/regs/dreq.h" // DREQ_PIO0_RX1
#include "hardware/structs/dma.h" // dma_hw

54
firmware/src/can.cpp Normal file
View File

@ -0,0 +1,54 @@
#include <Arduino.h>
#include "config.h"
#include "can.h"
static void can2040_callback(struct can2040 *cd, uint32_t notify, struct can2040_msg *msg) {
}
static void canbus_pio_irq_handler() {
can2040_pio_irq_handler(&canbus);
}
void canbus_setup() {
uint32_t pio_num = 1;
can2040_setup(&canbus, pio_num);
can2040_callback_config(&canbus, can2040_callback);
irq_set_exclusive_handler(PIO1_IRQ_0, canbus_pio_irq_handler);
irq_set_priority(PIO1_IRQ_0, 1);
irq_set_enabled(PIO1_IRQ_0, true);
can2040_start(&canbus, CPU_CLOCK_HZ, CAN_BITRATE, CAN_PIN_RX, CAN_PIN_TX);
}
unsigned long canbus_last_heartbeat_at = 0;
int canbus_heartbeat_interval = 1000;
void canbus_heartbeat();
void canbus_loop() {
auto now = millis();
if (canbus_last_heartbeat_at + canbus_heartbeat_interval < now) {
canbus_last_heartbeat_at = now;
// add some jitter to reduce collision likelihood
canbus_heartbeat_interval = 1000 + random(-200, 200);
canbus_heartbeat();
}
}
void canbus_heartbeat() {
int device_id = 224;
int msg_kind = 31;
int msg_type = 31;
// {kind:5}{device:8}{type:5}{reserved:11}
uint32_t id = CAN2040_ID_EFF | ((msg_kind << (8 + 5)) | (device_id << 5) | msg_type) << 11;
can2040_msg msg = {
.id = id,
.dlc = 0,
};
auto result = can2040_transmit(&canbus, &msg);
if (result != 0) {
Serial.println("CAN: heartbeat failed");
}
}

15
firmware/src/can.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#ifndef _can_h
#define _can_h
extern "C" {
#include "can2040.h"
}
static struct can2040 canbus;
void canbus_setup();
void canbus_loop();
#endif

View File

@ -48,6 +48,12 @@
#define ROW_SRCLK 18
// #define ROW_SRCLR 15
#define COL_SER_INVERTED false // double inverted
#define COL_OE_INVERTED true
#define COL_RCLK_INVERTED true
#define COL_SRCLK_INVERTED true
#define COL_SRCLR_INVERTED false
// --- screen settings ---
#define ROW_MODULES 2
@ -71,6 +77,7 @@
#define CPU_CLOCK_HZ 125000000.0f
#define SD_CARD_BAUD_RATE 10 * 1000 * 1000
#define REFERENCE_VOLTAGE 3.3f // for ADC
#define CAN_BITRATE 500000
// --- debug settings ---

View File

@ -141,6 +141,23 @@ void leds_init() {
pinMode(ROW_SRCLK, OUTPUT);
pinMode(ROW_SRCLR, OUTPUT);
// set pin inversion
#if COL_SER_INVERTED
gpio_set_outover(COL_SER, GPIO_OVERRIDE_INVERT);
#endif
#if COL_OE_INVERTED
gpio_set_outover(COL_OE, GPIO_OVERRIDE_INVERT);
#endif
#if COL_RCLK_INVERTED
gpio_set_outover(COL_RCLK, GPIO_OVERRIDE_INVERT);
#endif
#if COL_SRCLK_INVERTED
gpio_set_outover(COL_SRCLK, GPIO_OVERRIDE_INVERT);
#endif
#if COL_SRCLR_INVERTED
gpio_set_outover(COL_SRCLR, GPIO_OVERRIDE_INVERT);
#endif
// clear output
clearShiftReg(COL_SRCLK, COL_SRCLR);
clearShiftReg(ROW_SRCLK, ROW_SRCLR);
@ -238,18 +255,15 @@ void leds_initPusher() {
pio_gpio_init(pio, COL_SER);
pio_sm_set_consecutive_pindirs(pio, sm, COL_SER, 1, true);
// data is inverted
gpio_set_outover(COL_SER, GPIO_OVERRIDE_INVERT);
// Set sideset (SRCLK) pin, connect to pad, set as output
sm_config_set_sideset_pins(&config, COL_SRCLK);
pio_gpio_init(pio, COL_SRCLK);
pio_sm_set_consecutive_pindirs(pio, sm, COL_SRCLK, 1, true);
// Set SET (RCLK) pin, connect to pad, set as output
sm_config_set_set_pins(&config, ROW_RCLK, 1);
pio_gpio_init(pio, ROW_RCLK);
pio_sm_set_consecutive_pindirs(pio, sm, ROW_RCLK, 1, true);
sm_config_set_set_pins(&config, COL_RCLK, 1);
pio_gpio_init(pio, COL_RCLK);
pio_sm_set_consecutive_pindirs(pio, sm, COL_RCLK, 1, true);
// Load our configuration, and jump to the start of the program
pio_sm_init(pio, sm, offset, &config);
@ -269,9 +283,8 @@ void leds_initRowSelector() {
// Shift OSR to the right, autopull
sm_config_set_out_shift(&config, true, true, 32);
// Set OUT and SET (data) pin, connect to pad, set as output
// Set OUT/MOV (data) pin, connect to pad, set as output
sm_config_set_out_pins(&config, ROW_SER, 1);
sm_config_set_set_pins(&config, ROW_SER, 1);
pio_gpio_init(pio, ROW_SER);
pio_sm_set_consecutive_pindirs(pio, sm, ROW_SER, 1, true);
@ -280,6 +293,11 @@ void leds_initRowSelector() {
pio_gpio_init(pio, ROW_SRCLK);
pio_sm_set_consecutive_pindirs(pio, sm, ROW_SRCLK, 1, true);
// Set SET (RCLK) pin, connect to pad, set as output
sm_config_set_set_pins(&config, ROW_RCLK, 1);
pio_gpio_init(pio, ROW_RCLK);
pio_sm_set_consecutive_pindirs(pio, sm, ROW_RCLK, 1, true);
// Load our configuration, and jump to the start of the program
pio_sm_init(pio, sm, offset, &config);
pio_sm_set_enabled(pio, sm, true);

View File

@ -1,14 +1,14 @@
.define public irq_did_latch 0
.define public irq_row_selected 1
.define public irq_delaying 2
.define public irq_delaying 0
.define public irq_px_pushed 1
.define public irq_rclk_sync 2
.define public irq_did_latch 3
; TODO: check if delays can be lowered with a PCB
.define public srclk_0_delay 1
.define public srclk_1_delay 2
.define public rclk_1_delay 3
.program leds_px_pusher
.side_set 1 opt
.define public srclk_0_delay 1
.define public srclk_1_delay 2
entry_point:
.wrap_target
; get 32 bits from fifo (not required with autopull, useful for debug)
@ -29,13 +29,13 @@ end:
; MSB=1 indicates end of row
jmp !x entry_point
end_of_row:
; pixels pushed - can begin row selection
irq set irq_px_pushed
; wait until previous row's delay is complete
; (irq will be 0 on first row by default)
wait 0 irq irq_delaying
; wait until row is selected, and clear flag
wait 1 irq irq_row_selected
; signal that we're about to latch the row onto display
irq set irq_did_latch
; synchronize ROW_RCLK and COL_RCLK - note that the delays MUST be the same
wait 1 irq irq_rclk_sync
; clock RCLK (latch onto register output stage)
set pins, 1 [rclk_1_delay]
set pins, 0
@ -44,22 +44,31 @@ end_of_row:
.program leds_row_selector
.side_set 1 opt
.define public srclk_0_delay 1
.define public srclk_1_delay 2
entry_point:
.wrap_target
; wait until pixels are pushed
; (NOTE: This can happen in parallel if ROW_SER and COL_SER are separate)
wait 1 irq irq_px_pushed
; LSB=1 indicates first (bottom) row, ergo, high SER for the first pulse
out pins, 1 side 0 [srclk_0_delay]
; The rest of the word indicates number of extra SRCLK pulses
out x, 31
loop:
; pulse SRCLK x times
; set SER=0 after first pulse
nop side 1 [srclk_1_delay]
set pins, 0 side 0 [srclk_0_delay]
; set SER=0 after first pulse
mov pins, null side 0 [srclk_0_delay]
jmp x-- loop
end:
; signal that row is selected and wait until acknowledged
; some delay so that in the worst case scenario we don't start changing rows before RCLK latch
irq wait irq_row_selected [4]
; synchronize ROW_RCLK and COL_RCLK - note that the delays MUST be the same
irq wait irq_rclk_sync
; clock RCLK (latch onto register output stage)
set pins, 1 [rclk_1_delay]
; signal that rclk had latched (delay/oe can begin)
irq set irq_did_latch
set pins, 0
.wrap
.program leds_delay

View File

@ -8,11 +8,10 @@
#include "hardware/pio.h"
#endif
#define irq_did_latch 0
#define irq_row_selected 1
#define irq_delaying 2
#define srclk_0_delay 1
#define srclk_1_delay 2
#define irq_delaying 0
#define irq_px_pushed 1
#define irq_rclk_sync 2
#define irq_did_latch 3
#define rclk_1_delay 3
// -------------- //
@ -22,6 +21,9 @@
#define leds_px_pusher_wrap_target 0
#define leds_px_pusher_wrap 9
#define leds_px_pusher_srclk_0_delay 1
#define leds_px_pusher_srclk_1_delay 2
static const uint16_t leds_px_pusher_program_instructions[] = {
// .wrap_target
0xf037, // 0: set x, 23 side 0
@ -29,9 +31,9 @@ static const uint16_t leds_px_pusher_program_instructions[] = {
0x1a41, // 2: jmp x--, 1 side 1 [2]
0x7028, // 3: out x, 8 side 0
0x0020, // 4: jmp !x, 0
0x2042, // 5: wait 0 irq, 2
0x20c1, // 6: wait 1 irq, 1
0xc000, // 7: irq nowait 0
0xc001, // 5: irq nowait 1
0x2040, // 6: wait 0 irq, 0
0x20c2, // 7: wait 1 irq, 2
0xe301, // 8: set pins, 1 [3]
0xe000, // 9: set pins, 0
// .wrap
@ -57,23 +59,30 @@ static inline pio_sm_config leds_px_pusher_program_get_default_config(uint offse
// ----------------- //
#define leds_row_selector_wrap_target 0
#define leds_row_selector_wrap 5
#define leds_row_selector_wrap 9
#define leds_row_selector_srclk_0_delay 1
#define leds_row_selector_srclk_1_delay 2
static const uint16_t leds_row_selector_program_instructions[] = {
// .wrap_target
0x7101, // 0: out pins, 1 side 0 [1]
0x603f, // 1: out x, 31
0xba42, // 2: nop side 1 [2]
0xf100, // 3: set pins, 0 side 0 [1]
0x0042, // 4: jmp x--, 2
0xc421, // 5: irq wait 1 [4]
0x20c1, // 0: wait 1 irq, 1
0x7101, // 1: out pins, 1 side 0 [1]
0x603f, // 2: out x, 31
0xba42, // 3: nop side 1 [2]
0xb103, // 4: mov pins, null side 0 [1]
0x0043, // 5: jmp x--, 3
0xc022, // 6: irq wait 2
0xe301, // 7: set pins, 1 [3]
0xc003, // 8: irq nowait 3
0xe000, // 9: set pins, 0
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program leds_row_selector_program = {
.instructions = leds_row_selector_program_instructions,
.length = 6,
.length = 10,
.origin = -1,
};
@ -97,11 +106,11 @@ static inline pio_sm_config leds_row_selector_program_get_default_config(uint of
static const uint16_t leds_delay_program_instructions[] = {
// .wrap_target
0x20c0, // 0: wait 1 irq, 0
0xc002, // 1: irq nowait 2
0x20c3, // 0: wait 1 irq, 3
0xc000, // 1: irq nowait 0
0x6020, // 2: out x, 32
0x1043, // 3: jmp x--, 3 side 0
0xd842, // 4: irq clear 2 side 1
0xd840, // 4: irq clear 0 side 1
// .wrap
};

View File

@ -20,6 +20,10 @@ void setup() {
init_audio();
leds_initRenderer();
#if CAN_ENABLED
canbus_setup();
#endif
#if SD_HAS_DETECTION
while (!isSDCardInserted()) {
Serial.println("SD card not connected, waiting...");
@ -100,4 +104,8 @@ void loop() {
nextSong();
}
}
#if CAN_ENABLED
canbus_loop();
#endif
}