146 lines
3 KiB
C
146 lines
3 KiB
C
|
#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;
|
||
|
|
||
|
static uint8_t ascii_to_sseg(char c)
|
||
|
{
|
||
|
switch(c) {
|
||
|
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;
|
||
|
|
||
|
case 'M':
|
||
|
return 0x76;
|
||
|
|
||
|
case 'A':
|
||
|
return 0x77;
|
||
|
|
||
|
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);
|
||
|
}
|