kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			
		
			
				
	
	
		
			168 wiersze
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			168 wiersze
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
;
 | 
						|
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 | 
						|
;
 | 
						|
; SPDX-License-Identifier: BSD-3-Clause
 | 
						|
;
 | 
						|
 | 
						|
; These programs implement full-duplex SPI, with a SCK period of 4 clock
 | 
						|
; cycles. A different program is provided for each value of CPHA, and CPOL is
 | 
						|
; achieved using the hardware GPIO inversion available in the IO controls.
 | 
						|
;
 | 
						|
; Transmit-only SPI can go twice as fast -- see the ST7789 example!
 | 
						|
 | 
						|
 | 
						|
.program spi_cpha0
 | 
						|
.side_set 1
 | 
						|
 | 
						|
; Pin assignments:
 | 
						|
; - SCK is side-set pin 0
 | 
						|
; - MOSI is OUT pin 0
 | 
						|
; - MISO is IN pin 0
 | 
						|
;
 | 
						|
; Autopush and autopull must be enabled, and the serial frame size is set by
 | 
						|
; configuring the push/pull threshold. Shift left/right is fine, but you must
 | 
						|
; justify the data yourself. This is done most conveniently for frame sizes of
 | 
						|
; 8 or 16 bits by using the narrow store replication and narrow load byte
 | 
						|
; picking behaviour of RP2040's IO fabric.
 | 
						|
 | 
						|
; Clock phase = 0: data is captured on the leading edge of each SCK pulse, and
 | 
						|
; transitions on the trailing edge, or some time before the first leading edge.
 | 
						|
 | 
						|
    out pins, 1 side 0 [1] ; Stall here on empty (sideset proceeds even if
 | 
						|
    in pins, 1  side 1 [1] ; instruction stalls, so we stall with SCK low)
 | 
						|
 | 
						|
.program spi_cpha1
 | 
						|
.side_set 1
 | 
						|
 | 
						|
; Clock phase = 1: data transitions on the leading edge of each SCK pulse, and
 | 
						|
; is captured on the trailing edge.
 | 
						|
 | 
						|
    out x, 1    side 0     ; Stall here on empty (keep SCK deasserted)
 | 
						|
    mov pins, x side 1 [1] ; Output data, assert SCK (mov pins uses OUT mapping)
 | 
						|
    in pins, 1  side 0     ; Input data, deassert SCK
 | 
						|
 | 
						|
% c-sdk {
 | 
						|
#include "hardware/gpio.h"
 | 
						|
static inline void pio_spi_init(PIO pio, uint sm, uint prog_offs, uint n_bits,
 | 
						|
        float clkdiv, bool cpha, bool cpol, uint pin_sck, uint pin_mosi, uint pin_miso) {
 | 
						|
    pio_sm_config c = cpha ? spi_cpha1_program_get_default_config(prog_offs) : spi_cpha0_program_get_default_config(prog_offs);
 | 
						|
    sm_config_set_out_pins(&c, pin_mosi, 1);
 | 
						|
    sm_config_set_in_pins(&c, pin_miso);
 | 
						|
    sm_config_set_sideset_pins(&c, pin_sck);
 | 
						|
    // Only support MSB-first in this example code (shift to left, auto push/pull, threshold=nbits)
 | 
						|
    sm_config_set_out_shift(&c, false, true, n_bits);
 | 
						|
    sm_config_set_in_shift(&c, false, true, n_bits);
 | 
						|
    sm_config_set_clkdiv(&c, clkdiv);
 | 
						|
 | 
						|
    // MOSI, SCK output are low, MISO is input
 | 
						|
    pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_sck) | (1u << pin_mosi));
 | 
						|
    pio_sm_set_pindirs_with_mask(pio, sm, (1u << pin_sck) | (1u << pin_mosi), (1u << pin_sck) | (1u << pin_mosi) | (1u << pin_miso));
 | 
						|
    pio_gpio_init(pio, pin_mosi);
 | 
						|
    pio_gpio_init(pio, pin_miso);
 | 
						|
    pio_gpio_init(pio, pin_sck);
 | 
						|
 | 
						|
    // The pin muxes can be configured to invert the output (among other things
 | 
						|
    // and this is a cheesy way to get CPOL=1
 | 
						|
    gpio_set_outover(pin_sck, cpol ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
 | 
						|
    // SPI is synchronous, so bypass input synchroniser to reduce input delay.
 | 
						|
    hw_set_bits(&pio->input_sync_bypass, 1u << pin_miso);
 | 
						|
 | 
						|
    pio_sm_init(pio, sm, prog_offs, &c);
 | 
						|
    pio_sm_set_enabled(pio, sm, true);
 | 
						|
}
 | 
						|
%}
 | 
						|
 | 
						|
; SPI with Chip Select
 | 
						|
; -----------------------------------------------------------------------------
 | 
						|
;
 | 
						|
; For your amusement, here are some SPI programs with an automatic chip select
 | 
						|
; (asserted once data appears in TX FIFO, deasserts when FIFO bottoms out, has
 | 
						|
; a nice front/back porch).
 | 
						|
;
 | 
						|
; The number of bits per FIFO entry is configured via the Y register
 | 
						|
; and the autopush/pull threshold. From 2 to 32 bits.
 | 
						|
;
 | 
						|
; Pin assignments:
 | 
						|
; - SCK is side-set bit 0
 | 
						|
; - CSn is side-set bit 1
 | 
						|
; - MOSI is OUT bit 0 (host-to-device)
 | 
						|
; - MISO is IN bit 0 (device-to-host)
 | 
						|
;
 | 
						|
; This program only supports one chip select -- use GPIO if more are needed
 | 
						|
;
 | 
						|
; Provide a variation for each possibility of CPHA; for CPOL we can just
 | 
						|
; invert SCK in the IO muxing controls (downstream from PIO)
 | 
						|
 | 
						|
 | 
						|
; CPHA=0: data is captured on the leading edge of each SCK pulse (including
 | 
						|
; the first pulse), and transitions on the trailing edge
 | 
						|
 | 
						|
.program spi_cpha0_cs
 | 
						|
.side_set 2
 | 
						|
 | 
						|
.wrap_target
 | 
						|
bitloop:
 | 
						|
    out pins, 1        side 0x0 [1]
 | 
						|
    in pins, 1         side 0x1
 | 
						|
    jmp x-- bitloop    side 0x1
 | 
						|
 | 
						|
    out pins, 1        side 0x0
 | 
						|
    mov x, y           side 0x0     ; Reload bit counter from Y
 | 
						|
    in pins, 1         side 0x1
 | 
						|
    jmp !osre bitloop  side 0x1     ; Fall-through if TXF empties
 | 
						|
 | 
						|
    nop                side 0x0 [1] ; CSn back porch
 | 
						|
public entry_point:                 ; Must set X,Y to n-2 before starting!
 | 
						|
    pull ifempty       side 0x2 [1] ; Block with CSn high (minimum 2 cycles)
 | 
						|
.wrap                               ; Note ifempty to avoid time-of-check race
 | 
						|
 | 
						|
; CPHA=1: data transitions on the leading edge of each SCK pulse, and is
 | 
						|
; captured on the trailing edge
 | 
						|
 | 
						|
.program spi_cpha1_cs
 | 
						|
.side_set 2
 | 
						|
 | 
						|
.wrap_target
 | 
						|
bitloop:
 | 
						|
    out pins, 1        side 0x1 [1]
 | 
						|
    in pins, 1         side 0x0
 | 
						|
    jmp x-- bitloop    side 0x0
 | 
						|
 | 
						|
    out pins, 1        side 0x1
 | 
						|
    mov x, y           side 0x1
 | 
						|
    in pins, 1         side 0x0
 | 
						|
    jmp !osre bitloop  side 0x0
 | 
						|
 | 
						|
public entry_point:                 ; Must set X,Y to n-2 before starting!
 | 
						|
    pull ifempty       side 0x2 [1] ; Block with CSn high (minimum 2 cycles)
 | 
						|
    nop                side 0x0 [1]; CSn front porch
 | 
						|
.wrap
 | 
						|
 | 
						|
% c-sdk {
 | 
						|
#include "hardware/gpio.h"
 | 
						|
static inline void pio_spi_cs_init(PIO pio, uint sm, uint prog_offs, uint n_bits, float clkdiv, bool cpha, bool cpol,
 | 
						|
        uint pin_sck, uint pin_mosi, uint pin_miso) {
 | 
						|
    pio_sm_config c = cpha ? spi_cpha1_cs_program_get_default_config(prog_offs) : spi_cpha0_cs_program_get_default_config(prog_offs);
 | 
						|
    sm_config_set_out_pins(&c, pin_mosi, 1);
 | 
						|
    sm_config_set_in_pins(&c, pin_miso);
 | 
						|
    sm_config_set_sideset_pins(&c, pin_sck);
 | 
						|
    sm_config_set_out_shift(&c, false, true, n_bits);
 | 
						|
    sm_config_set_in_shift(&c, false, true, n_bits);
 | 
						|
    sm_config_set_clkdiv(&c, clkdiv);
 | 
						|
 | 
						|
    pio_sm_set_pins_with_mask(pio, sm, (2u << pin_sck), (3u << pin_sck) | (1u << pin_mosi));
 | 
						|
    pio_sm_set_pindirs_with_mask(pio, sm, (3u << pin_sck) | (1u << pin_mosi), (3u << pin_sck) | (1u << pin_mosi) | (1u << pin_miso));
 | 
						|
    pio_gpio_init(pio, pin_mosi);
 | 
						|
    pio_gpio_init(pio, pin_miso);
 | 
						|
    pio_gpio_init(pio, pin_sck);
 | 
						|
    pio_gpio_init(pio, pin_sck + 1);
 | 
						|
    gpio_set_outover(pin_sck, cpol ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
 | 
						|
    hw_set_bits(&pio->input_sync_bypass, 1u << pin_miso);
 | 
						|
 | 
						|
    uint entry_point = prog_offs + (cpha ? spi_cpha1_cs_offset_entry_point : spi_cpha0_cs_offset_entry_point);
 | 
						|
    pio_sm_init(pio, sm, entry_point, &c);
 | 
						|
    pio_sm_exec(pio, sm, pio_encode_set(pio_x, n_bits - 2));
 | 
						|
    pio_sm_exec(pio, sm, pio_encode_set(pio_y, n_bits - 2));
 | 
						|
    pio_sm_set_enabled(pio, sm, true);
 | 
						|
}
 | 
						|
%} |