kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			
		
			
	
	
		
			159 wiersze
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
		
		
			
		
	
	
			159 wiersze
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; SPDX-License-Identifier: BSD-3-Clause
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.program hub75_row
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								; side-set pin 0 is LATCH
							 | 
						||
| 
								 | 
							
								; side-set pin 1 is OEn
							 | 
						||
| 
								 | 
							
								; OUT pins are row select A-E
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; Each FIFO record consists of:
							 | 
						||
| 
								 | 
							
								; - 5-bit row select (LSBs)
							 | 
						||
| 
								 | 
							
								; - Pulse width - 1 (27 MSBs)
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; Repeatedly select a row, pulse LATCH, and generate a pulse of a certain
							 | 
						||
| 
								 | 
							
								; width on OEn.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.side_set 2
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.wrap_target
							 | 
						||
| 
								 | 
							
								    out pins, 5 [1]    side 0x2 ; Deassert OEn, output row select
							 | 
						||
| 
								 | 
							
								    out x, 27   [7]    side 0x3 ; Pulse LATCH, get OEn pulse width
							 | 
						||
| 
								 | 
							
								pulse_loop:
							 | 
						||
| 
								 | 
							
								    jmp x-- pulse_loop side 0x0 ; Assert OEn for x+1 cycles
							 | 
						||
| 
								 | 
							
								.wrap
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.program hub75_row_inverted
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								; side-set pin 0 is LATCH
							 | 
						||
| 
								 | 
							
								; side-set pin 1 is OEn
							 | 
						||
| 
								 | 
							
								; OUT pins are row select A-E
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; Each FIFO record consists of:
							 | 
						||
| 
								 | 
							
								; - 5-bit row select (LSBs)
							 | 
						||
| 
								 | 
							
								; - Pulse width - 1 (27 MSBs)
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; Repeatedly select a row, pulse LATCH, and generate a pulse of a certain
							 | 
						||
| 
								 | 
							
								; width on OEn.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.side_set 2
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.wrap_target
							 | 
						||
| 
								 | 
							
								    out pins, 5 [1]    side 0x3 ; Deassert OEn, output row select
							 | 
						||
| 
								 | 
							
								    out x, 27   [7]    side 0x2 ; Pulse LATCH, get OEn pulse width
							 | 
						||
| 
								 | 
							
								pulse_loop:
							 | 
						||
| 
								 | 
							
								    jmp x-- pulse_loop side 0x1 ; Assert OEn for x+1 cycles
							 | 
						||
| 
								 | 
							
								.wrap
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% c-sdk {
							 | 
						||
| 
								 | 
							
								static inline void hub75_row_program_init(PIO pio, uint sm, uint offset, uint row_base_pin, uint n_row_pins, uint latch_base_pin) {
							 | 
						||
| 
								 | 
							
								    pio_sm_set_consecutive_pindirs(pio, sm, row_base_pin, n_row_pins, true);
							 | 
						||
| 
								 | 
							
								    pio_sm_set_consecutive_pindirs(pio, sm, latch_base_pin, 2, true);
							 | 
						||
| 
								 | 
							
								    for (uint i = row_base_pin; i < row_base_pin + n_row_pins; ++i)
							 | 
						||
| 
								 | 
							
								        pio_gpio_init(pio, i);
							 | 
						||
| 
								 | 
							
								    pio_gpio_init(pio, latch_base_pin);
							 | 
						||
| 
								 | 
							
								    pio_gpio_init(pio, latch_base_pin + 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pio_sm_config c = hub75_row_program_get_default_config(offset);
							 | 
						||
| 
								 | 
							
								    sm_config_set_out_pins(&c, row_base_pin, n_row_pins);
							 | 
						||
| 
								 | 
							
								    sm_config_set_sideset_pins(&c, latch_base_pin);
							 | 
						||
| 
								 | 
							
								    sm_config_set_out_shift(&c, true, true, 32);
							 | 
						||
| 
								 | 
							
								    pio_sm_init(pio, sm, offset, &c);
							 | 
						||
| 
								 | 
							
								    pio_sm_set_enabled(pio, sm, true);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static inline void hub75_wait_tx_stall(PIO pio, uint sm) {
							 | 
						||
| 
								 | 
							
								    uint32_t txstall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + sm);
							 | 
						||
| 
								 | 
							
								    pio->fdebug = txstall_mask;
							 | 
						||
| 
								 | 
							
								    while (!(pio->fdebug & txstall_mask))
							 | 
						||
| 
								 | 
							
								        tight_loop_contents();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								%}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.program hub75_data_rgb888
							 | 
						||
| 
								 | 
							
								.side_set 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								; Each FIFO record consists of a RGB888 pixel. (This is ok for e.g. an RGB565
							 | 
						||
| 
								 | 
							
								; source which has been gamma-corrected)
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; Even pixels are sent on R0, G0, B0 and odd pixels on R1, G1, B1 (typically
							 | 
						||
| 
								 | 
							
								; these are for different parts of the screen, NOT for adjacent pixels, so the
							 | 
						||
| 
								 | 
							
								; frame buffer must be interleaved before passing to PIO.)
							 | 
						||
| 
								 | 
							
								;
							 | 
						||
| 
								 | 
							
								; Each pass through, we take bit n, n + 8 and n + 16 from each pixel, for n in
							 | 
						||
| 
								 | 
							
								; {0...7}. Therefore the pixels need to be transmitted 8 times (ouch) to build
							 | 
						||
| 
								 | 
							
								; up the full 8 bit value for each channel, and perform bit-planed PWM by
							 | 
						||
| 
								 | 
							
								; varying pulse widths on the other state machine, in ascending powers of 2.
							 | 
						||
| 
								 | 
							
								; This avoids a lot of bit shuffling on the processors, at the cost of DMA
							 | 
						||
| 
								 | 
							
								; bandwidth (which we have loads of).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								; Might want to close your eyes before you read this
							 | 
						||
| 
								 | 
							
								public entry_point:
							 | 
						||
| 
								 | 
							
								.wrap_target
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								public shift0:              ; R0 G0 B0 (Top half of 64x64 displays)
							 | 
						||
| 
								 | 
							
								    pull             side 0 ; gets patched to `out null, n` if n nonzero (otherwise the PULL is required for fencing)
							 | 
						||
| 
								 | 
							
								    in osr, 1        side 0 ; Red0 N
							 | 
						||
| 
								 | 
							
								    out null, 10     side 0 ; Red0 discard
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    in osr, 1        side 0 ; Green0 N
							 | 
						||
| 
								 | 
							
								    out null, 10     side 0 ; Green0 discard
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    in osr, 1        side 0 ; Blue0 N
							 | 
						||
| 
								 | 
							
								    out null, 32     side 0 ; Remainder discard
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								public shift1:              ; R1 G1 B1 (Bottom half of 64x64 displays)
							 | 
						||
| 
								 | 
							
								    pull             side 0 ; gets patched to `out null, n` if n nonzero (otherwise the PULL is required for fencing)
							 | 
						||
| 
								 | 
							
								    in osr, 1        side 1 ; Red1 N
							 | 
						||
| 
								 | 
							
								    out null, 10     side 1 ; Red1 discard
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    in osr, 1        side 1 ; Green1 N
							 | 
						||
| 
								 | 
							
								    out null, 10     side 1 ; Green1 discard
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    in osr, 1        side 1 ; Blue1 N
							 | 
						||
| 
								 | 
							
								    out null, 32     side 1 ; Remainder discard
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    in null, 26      side 1 ; Note we are just doing this little manoeuvre here to get GPIOs in the order
							 | 
						||
| 
								 | 
							
								    mov pins, ::isr  side 1 ; R0, G0, B0, R1, G1, B1. Can go 1 cycle faster if reversed
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.wrap
							 | 
						||
| 
								 | 
							
								; Note that because the clock edge for pixel n is in the middle of pixel n +
							 | 
						||
| 
								 | 
							
								; 1, a dummy pixel at the end is required to clock the last piece of genuine
							 | 
						||
| 
								 | 
							
								; data. (Also 1 pixel of garbage is clocked out at the start, but this is
							 | 
						||
| 
								 | 
							
								; harmless)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% c-sdk {
							 | 
						||
| 
								 | 
							
								static inline void hub75_data_rgb888_program_init(PIO pio, uint sm, uint offset, uint rgb_base_pin, uint clock_pin) {
							 | 
						||
| 
								 | 
							
								    pio_sm_set_consecutive_pindirs(pio, sm, rgb_base_pin, 6, true);
							 | 
						||
| 
								 | 
							
								    pio_sm_set_consecutive_pindirs(pio, sm, clock_pin, 1, true);
							 | 
						||
| 
								 | 
							
								    for (uint i = rgb_base_pin; i < rgb_base_pin + 6; ++i)
							 | 
						||
| 
								 | 
							
								        pio_gpio_init(pio, i);
							 | 
						||
| 
								 | 
							
								    pio_gpio_init(pio, clock_pin);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pio_sm_config c = hub75_data_rgb888_program_get_default_config(offset);
							 | 
						||
| 
								 | 
							
								    sm_config_set_out_pins(&c, rgb_base_pin, 6);
							 | 
						||
| 
								 | 
							
								    sm_config_set_sideset_pins(&c, clock_pin);
							 | 
						||
| 
								 | 
							
								    sm_config_set_out_shift(&c, true, true, 32);
							 | 
						||
| 
								 | 
							
								    // ISR shift to left. R0 ends up at bit 5. We push it up to MSB and then flip the register.
							 | 
						||
| 
								 | 
							
								    sm_config_set_in_shift(&c, false, false, 32);
							 | 
						||
| 
								 | 
							
								    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
							 | 
						||
| 
								 | 
							
								    pio_sm_init(pio, sm, offset, &c);
							 | 
						||
| 
								 | 
							
								    pio_sm_exec(pio, sm, offset + hub75_data_rgb888_offset_entry_point);
							 | 
						||
| 
								 | 
							
								    pio_sm_set_enabled(pio, sm, true);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Patch a data program at `offset` to preshift pixels by `shamt`
							 | 
						||
| 
								 | 
							
								static inline void hub75_data_rgb888_set_shift(PIO pio, uint sm, uint offset, uint shamt) {
							 | 
						||
| 
								 | 
							
								    uint16_t instr;
							 | 
						||
| 
								 | 
							
								    if (shamt == 0)
							 | 
						||
| 
								 | 
							
								        instr = pio_encode_pull(false, true); // blocking PULL
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								        instr = pio_encode_out(pio_null, shamt);
							 | 
						||
| 
								 | 
							
								    pio->instr_mem[offset + hub75_data_rgb888_offset_shift0] = instr;
							 | 
						||
| 
								 | 
							
								    pio->instr_mem[offset + hub75_data_rgb888_offset_shift1] = instr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								%}
							 |