-
-
Notifications
You must be signed in to change notification settings - Fork 55
/
Copy pathspi.pio
112 lines (95 loc) · 4.33 KB
/
spi.pio
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
; Copyright (c) 2022 Balázs Triszka <balika011@gmail.com>
;
; This program is free software; you can redistribute it and/or modify it
; under the terms and conditions of the GNU General Public License,
; version 2, as published by the Free Software Foundation.
;
; This program is distributed in the hope it will be useful, but WITHOUT
; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
; more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
; 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 0x2
jmp x-- bitloop side 0x2
out pins, 1 side 0x0
mov x, y side 0x0 ; Reload bit counter from Y
in pins, 1 side 0x2
jmp !osre bitloop side 0x2 ; 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 0x1 [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
byteloop:
wait 1 GPIO 11 side 0x0 ; hack for nuvoton RDY/BSYB
bitloop:
out pins, 1 side 0x2 [1]
in pins, 1 side 0x0
jmp x-- bitloop side 0x0
out pins, 1 side 0x2
mov x, y side 0x2
in pins, 1 side 0x0
jmp !osre byteloop side 0x0
public entry_point: ; Must set X,Y to n-2 before starting!
pull ifempty side 0x1 [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_ss, uint pin_mosi, uint pin_miso, uint order) {
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_ss);
sm_config_set_out_shift(&c, order ? false : true, true, n_bits);
sm_config_set_in_shift(&c, order ? false : true, true, n_bits);
sm_config_set_clkdiv(&c, clkdiv);
pio_sm_set_pins_with_mask(pio, sm, (1u << pin_ss), (1u << pin_ss) | (1u << (pin_ss + 1)) | (1u << pin_mosi));
pio_sm_set_pindirs_with_mask(pio, sm, (1u << pin_ss) | (1u << (pin_ss + 1)) | (1u << pin_mosi), (1u << pin_ss) | (1u << (pin_ss + 1)) | (1u << pin_mosi) | (1u << pin_miso));
pio_gpio_init(pio, pin_mosi);
pio_gpio_init(pio, pin_miso);
pio_gpio_init(pio, pin_ss);
pio_gpio_init(pio, pin_ss + 1);
gpio_set_outover(pin_ss + 1, 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);
}
%}