#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; // see doc/sseg_codes.txt for construction details static uint8_t ascii_to_sseg(char c) { switch(c) { 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; case 'm': case 'M': return 0x76; case 'a': case 'A': return 0x77; case 'f': case 'F': return 0x17; case '#': return 0x66; case 'i': case 'I': case '|': return 0x06; case 'd': case 'D': return 0x6D; case 'h': case 'H': return 0x67; case 'n': case 'N': return 0x45; case ' ': return 0x00; 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); }