PowerTimer-Firmware/src/sseg.c

155 lines
3.2 KiB
C
Raw Normal View History

#include "hardware/gpio.h"
#include "hardware/pio.h"
#include "hardware/dma.h"
#include "sseg.pio.h"
#include "sseg.h"
#include "pinout.h"
// Segment Layout:
//
// .--A--.
// | |
// F B
// | |
// +--G--+
// | |
// E C
// | |
// .--D--. .DP.
#define SSEG_START_PIN 0
static volatile uint32_t m_dma_buffer[4] __attribute__((aligned(4*sizeof(uint32_t *)))) = {
0x0000013D, // segment 0 = 'Z' = '2'
0x00000277, // segment 1 = A
0x00000476, // segment 2 = M
0x00000000, // dummy entry
};
static PIO m_pio;
static uint m_sm;
static int m_dma_chan;
2024-05-15 22:06:23 +02:00
// see doc/sseg_codes.txt for construction details
static uint8_t ascii_to_sseg(char c)
{
switch(c) {
2024-05-15 22:06:23 +02:00
case 'o':
case 'O':
case '0':
return 0x7E;
case '1':
return 0x60;
case 'Z':
case '2':
return 0x3D;
case '3':
return 0x79;
case '4':
return 0x63;
case '5':
return 0x5B;
case '6':
return 0x5F;
case '7':
return 0x70;
case '8':
return 0x7F;
case '9':
return 0x7B;
2024-05-15 22:06:23 +02:00
case 'm':
case 'M':
return 0x76;
2024-05-15 22:06:23 +02:00
case 'a':
case 'A':
return 0x77;
2024-05-15 22:06:23 +02:00
case 'f':
case 'F':
return 0x47;
default: // '-'
return 0x01;
}
}
void sseg_init(void)
{
// set up PIO for 7-segment display
m_pio = pio0;
uint offset = pio_add_program(m_pio, &sseg_program);
m_sm = pio_claim_unused_sm(m_pio, true);
pio_sm_config c = sseg_program_get_default_config(offset);
sm_config_set_clkdiv_int_frac(&c, 2000, 0);
sm_config_set_out_pins(&c, SSEG_START_PIN, 11);
sm_config_set_set_pins(&c, SSEG_START_PIN+8, 3);
pio_gpio_init(m_pio, SSEG_A_PIN);
pio_gpio_init(m_pio, SSEG_B_PIN);
pio_gpio_init(m_pio, SSEG_C_PIN);
pio_gpio_init(m_pio, SSEG_D_PIN);
pio_gpio_init(m_pio, SSEG_E_PIN);
pio_gpio_init(m_pio, SSEG_F_PIN);
pio_gpio_init(m_pio, SSEG_G_PIN);
pio_gpio_init(m_pio, SSEG_DP_PIN);
pio_gpio_init(m_pio, SSEG_MUX_1_PIN);
pio_gpio_init(m_pio, SSEG_MUX_2_PIN);
pio_gpio_init(m_pio, SSEG_MUX_3_PIN);
pio_sm_set_consecutive_pindirs(m_pio, m_sm, SSEG_START_PIN, 11, true);
pio_sm_init(m_pio, m_sm, offset, &c);
m_dma_chan = dma_claim_unused_channel(true);
dma_channel_config dma_config = dma_channel_get_default_config(m_dma_chan);
channel_config_set_transfer_data_size(&dma_config, DMA_SIZE_32);
channel_config_set_read_increment(&dma_config, true);
channel_config_set_write_increment(&dma_config, false);
channel_config_set_ring(&dma_config, false, 4); // read ringbuffer with 2^4 = 16 bytes = 4 entries
channel_config_set_dreq(&dma_config, DREQ_PIO0_TX0);
dma_channel_configure(
m_dma_chan,
&dma_config,
&pio0_hw->txf[0], // Write address (only need to set this once)
m_dma_buffer, // Read address
1<<14, // Write the buffer many times, then halt and interrupt
true // Start right now
);
pio_sm_set_enabled(m_pio, m_sm, true);
}
void sseg_loop(void)
{
// restart the DMA channel if it has completed the transfer
if((dma_hw->intr & (1u << m_dma_chan)) != 0) {
dma_hw->ints0 = 1u << m_dma_chan;
dma_channel_start(m_dma_chan);
}
}
void sseg_set_char(uint8_t seg, char c, bool with_dot)
{
uint dot_bit = with_dot ? 0x80 : 0x00;
m_dma_buffer[seg] = (m_dma_buffer[seg] & 0xFFFFFF00) | dot_bit | ascii_to_sseg(c);
}