forked from usedbytes/camera-pico-ov7670
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcamera.pio
166 lines (141 loc) · 5.27 KB
/
camera.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
;
; Copyright (c) 2021 Brian Starkey <stark3y@gmail.com>
;
; SPDX-License-Identifier: BSD-3-Clause
;
.define PUBLIC PIN_OFFS_D0 0
.define PUBLIC PIN_OFFS_D1 1
.define PUBLIC PIN_OFFS_D2 2
.define PUBLIC PIN_OFFS_D3 3
.define PUBLIC PIN_OFFS_D4 4
.define PUBLIC PIN_OFFS_D5 5
.define PUBLIC PIN_OFFS_D6 6
.define PUBLIC PIN_OFFS_D7 7
.define PUBLIC PIN_OFFS_VSYNC 8
.define PUBLIC PIN_OFFS_HREF 9
.define PUBLIC PIN_OFFS_PXCLK 10
.define BYTE_IRQ_BASE 4
.program camera_pio_byte
.wrap_target
wait 1 irq BYTE_IRQ_BASE rel ; Wait to be triggered - waits for IRQ 4 + SM number
wait 1 pin PIN_OFFS_PXCLK [5] ; Wait for PXCLK to go high (otherwise inputs are "transparent")
in PINS, 8
wait 0 pin PIN_OFFS_PXCLK ; Wait for PXCLK to go low
irq set BYTE_IRQ_BASE
.wrap
% c-sdk {
static inline pio_sm_config camera_pio_get_byte_sm_config(PIO pio, uint sm, uint offset, uint base_pin, uint bpp)
{
pio_sm_config c = camera_pio_byte_program_get_default_config(offset);
sm_config_set_in_pins(&c, base_pin);
sm_config_set_in_shift(&c, true, true, bpp);
return c;
}
%}
.program camera_pio_frame
.wrap_target
pull ; Pull number of lines
out Y, 32 ; Store number of lines in Y
pull ; Pull "pixels" per line. Keep this in OSR to reload X each line
wait 1 pin PIN_OFFS_VSYNC ; Wait for start of frame
loop_line:
mov X, OSR ; Store number of pixels in X
wait 1 pin PIN_OFFS_HREF [2] ; Wait for start of line
; The pixel loop body can be patched for different pixel formats / plane
; layouts. Up to 4 bytes per pixel.
; For a format with less than 4 bytes per pixel, some of these commands will
; be patched to NOPs. For multi-plane formats, other SMs will be triggered
; as appropriate
; By default, this is set up for 2-bytes per pixel, in a single plane,
; handled by SM1, transferring "chunks" of 4 bytes (2 pixels)
public loop_pixel:
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 0)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 1)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 2)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 3)
wait 1 irq BYTE_IRQ_BASE
jmp x-- loop_pixel
wait 0 pin PIN_OFFS_HREF ; Wait for end of line
jmp y-- loop_line
irq wait 0 ; Signal the CPU that we're done, wait for ack
.wrap
% c-sdk {
static inline void camera_pio_init_gpios(PIO pio, uint sm, uint base_pin)
{
pio_sm_set_consecutive_pindirs(pio, sm, base_pin, (3 + 8), false);
for (uint i = 0; i < (3 + 8); i++) {
pio_gpio_init(pio, i + base_pin);
}
}
static inline pio_sm_config camera_pio_get_frame_sm_config(PIO pio, uint sm, uint offset, uint base_pin)
{
pio_sm_config c = camera_pio_frame_program_get_default_config(offset);
sm_config_set_in_pins(&c, base_pin);
sm_config_set_out_shift(&c, true, false, 0);
return c;
}
static inline bool camera_pio_frame_done(PIO pio)
{
return pio_interrupt_get(pio, 0);
}
static inline void camera_pio_wait_for_frame_done(PIO pio)
{
while (!camera_pio_frame_done(pio));
}
static inline void camera_pio_trigger_frame(PIO pio, uint32_t cols, uint32_t rows)
{
pio_interrupt_clear(pio, 0);
pio_sm_put_blocking(pio, 0, rows - 1);
pio_sm_put_blocking(pio, 0, cols - 1);
}
%}
.program pixel_loop_yuyv
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 0)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 1)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 2)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 3)
wait 1 irq BYTE_IRQ_BASE
.program pixel_loop_rgb565
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 0)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 1)
wait 1 irq BYTE_IRQ_BASE
nop
nop
nop
nop
// Two-plane YUV: [YY, UV]
.program pixel_loop_nv16
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 0)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 2) ; Trigger byte SM2 (byte 1)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 2)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 2) ; Trigger byte SM2 (byte 3)
wait 1 irq BYTE_IRQ_BASE
// Three-plane YUV: [YY, U, V]
.program pixel_loop_yu16
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 0)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 2) ; Trigger byte SM2 (byte 1)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 1) ; Trigger byte SM1 (byte 2)
wait 1 irq BYTE_IRQ_BASE
irq wait (BYTE_IRQ_BASE + 3) ; Trigger byte SM3 (byte 3)
wait 1 irq BYTE_IRQ_BASE
% c-sdk {
static inline void camera_pio_patch_pixel_loop(PIO pio, uint offset, const pio_program_t *loop) {
uint i;
// TODO: Assert that length of program is 8?
for (i = 0; i < loop->length; i++) {
pio->instr_mem[offset + camera_pio_frame_offset_loop_pixel + i] = loop->instructions[i];
}
}
%}