2024-05-09 23:56:32 +02:00
|
|
|
#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
|
2024-05-09 23:56:32 +02:00
|
|
|
static uint8_t ascii_to_sseg(char c)
|
|
|
|
{
|
|
|
|
switch(c) {
|
2024-05-15 22:06:23 +02:00
|
|
|
case 'o':
|
|
|
|
case 'O':
|
2024-05-09 23:56:32 +02:00
|
|
|
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':
|
2024-05-09 23:56:32 +02:00
|
|
|
case 'M':
|
|
|
|
return 0x76;
|
|
|
|
|
2024-05-15 22:06:23 +02:00
|
|
|
case 'a':
|
2024-05-09 23:56:32 +02:00
|
|
|
case 'A':
|
|
|
|
return 0x77;
|
|
|
|
|
2024-05-15 22:06:23 +02:00
|
|
|
case 'f':
|
|
|
|
case 'F':
|
2024-05-18 00:07:55 +02:00
|
|
|
return 0x17;
|
2024-05-15 22:06:23 +02:00
|
|
|
|
2024-05-16 21:22:16 +02:00
|
|
|
case '#':
|
|
|
|
return 0x66;
|
|
|
|
|
|
|
|
case 'i':
|
|
|
|
case 'I':
|
|
|
|
case '|':
|
|
|
|
return 0x06;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
case 'D':
|
|
|
|
return 0x6D;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
case 'H':
|
|
|
|
return 0x67;
|
|
|
|
|
2024-05-18 00:07:55 +02:00
|
|
|
case 'n':
|
|
|
|
case 'N':
|
|
|
|
return 0x45;
|
|
|
|
|
2024-05-16 21:22:16 +02:00
|
|
|
case ' ':
|
|
|
|
return 0x00;
|
|
|
|
|
2024-05-09 23:56:32 +02:00
|
|
|
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);
|
|
|
|
}
|