-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTCD1304_backup.c
165 lines (143 loc) · 5.88 KB
/
TCD1304_backup.c
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
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "hardware/i2c.h"
#include "hardware/pio.h"
#include "hardware/timer.h"
#include "hardware/clocks.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
// For ADC input:
#include "hardware/adc.h"
#include "hardware/dma.h"
// For resistor DAC output:
#include "pico/multicore.h"
// TCD1304 pinout
#define PWM_PIN 14
#define PWM_TEST_PIN 9
#define SH_PIN 15
#define ICG_PIN 13
#define ADC_PIN 26
// PWM configuration
void setup_pwm(uint slice_num, uint channel)
{
// Set the wrap value to generate 2 MHz frequency
uint32_t wrap_value = 69; // Based on 230 MHz system clock and 2 MHz frequency. wrap_value = (sys_clock / PWM frequency)-1
pwm_set_wrap(slice_num, wrap_value); // Set the wrap value (16-bit)
pwm_set_chan_level(slice_num, channel, wrap_value / 2); // Set duty cycle (50%)
pwm_set_enabled(slice_num, true); // Enable PWM output
}
// PWM test pin configuration
void setup_pwm2(uint slice_num, uint channel)
{
// Set the wrap value to generate 2 MHz frequency
uint32_t wrap_value = 13999; // Based on 230 MHz system clock and 2 MHz frequency. wrap_value = (sys_clock / PWM frequency)-1
pwm_set_wrap(slice_num, wrap_value); // Set the wrap value (16-bit)
pwm_set_chan_level(slice_num, channel, wrap_value / 2); // Set duty cycle (50%)
pwm_set_enabled(slice_num, true); // Enable PWM output
}
// Channel 0 is GPIO26
#define CAPTURE_CHANNEL 0
#define CAPTURE_DEPTH 3700 // 3694 samples by datasheet
// dma read from adc fifo
void dma_adc_read(uint dma_chan, uint8_t *capture_buf, dma_channel_config cfg)
{
// Set up the DMA to start transferring data as soon as it appears in FIFO
dma_channel_configure(dma_chan, &cfg,
capture_buf, // dst
&adc_hw->fifo, // src
CAPTURE_DEPTH, // transfer count
true // start immediately
);
// printf("Starting capture\n");
adc_run(true);
// Once DMA finishes, stop any new conversions from starting, and clean up
// the FIFO in case the ADC was still mid-conversion.
dma_channel_wait_for_finish_blocking(dma_chan);
printf("\n\rCapture finished\n\r");
adc_run(false);
adc_fifo_drain();
}
// initiate CCD readout
void start_ccd_readout()
{
// Control SH and ICG pins
gpio_put(ICG_PIN, 0); // without 74hc04
// delay before exposure for 100 cpu cycles (~430 ns)
__asm volatile("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
gpio_put(SH_PIN, 1); // without 74hc04
// SH pulse width
busy_wait_us_32(4);
gpio_put(SH_PIN, 0); // without 74hc04
// delay after exposure
busy_wait_us_32(6);
gpio_put(ICG_PIN, 1); // without 74hc04
}
int main()
{
// Set system clock frequency
set_sys_clock_khz(140000, true);
stdio_init_all();
// Initialize PWM on the specified pin
gpio_set_function(PWM_PIN, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(PWM_PIN);
uint channel = pwm_gpio_to_channel(PWM_PIN);
setup_pwm(slice_num, channel);
// Initialize PWM test on the specified pin
gpio_set_function(PWM_TEST_PIN, GPIO_FUNC_PWM);
uint slice_num_test = pwm_gpio_to_slice_num(PWM_TEST_PIN);
uint channel_test = pwm_gpio_to_channel(PWM_TEST_PIN);
setup_pwm2(slice_num_test, channel_test);
// Initialize GPIO for SH and ICG
gpio_init(SH_PIN);
gpio_set_dir(SH_PIN, GPIO_OUT);
gpio_put(SH_PIN, 0); // without 74hc04
gpio_init(ICG_PIN);
gpio_set_dir(ICG_PIN, GPIO_OUT);
gpio_put(ICG_PIN, 1); // without 74hc04
// Init GPIO for analogue use: hi-Z, no pulls, disable digital input buffer.
adc_gpio_init(ADC_PIN + CAPTURE_CHANNEL);
adc_init();
adc_select_input(CAPTURE_CHANNEL);
adc_fifo_setup(
true, // Write each completed conversion to the sample FIFO
true, // Enable DMA data request (DREQ)
1, // DREQ (and IRQ) asserted when at least 1 sample present
false, // We won't see the ERR bit because of 8 bit reads; disable.
true // Shift each sample to 8 bits when pushing to FIFO
);
// Divisor of 0 -> full speed. Free-running capture with the divider is
// equivalent to pressing the ADC_CS_START_ONCE button once per `div + 1`
// cycles (div not necessarily an integer). Each conversion takes 96
// cycles, so in general you want a divider of 0 (hold down the button
// continuously) or > 95 (take samples less frequently than 96 cycle
// intervals). This is all timed by the 48 MHz ADC clock.
adc_set_clkdiv(0);
printf("Arming DMA\n");
sleep_ms(1000);
// Set up the DMA to start transferring data as soon as it appears in FIFO
uint dma_chan = dma_claim_unused_channel(true);
dma_channel_config cfg = dma_channel_get_default_config(dma_chan);
// Reading from constant address, writing to incrementing byte addresses
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8);
channel_config_set_read_increment(&cfg, false);
channel_config_set_write_increment(&cfg, true);
// Pace transfers based on availability of ADC samples
channel_config_set_dreq(&cfg, DREQ_ADC);
uint8_t capture_buf[CAPTURE_DEPTH];
while (true)
{
setup_pwm(slice_num, channel);
start_ccd_readout();
dma_adc_read(dma_chan, capture_buf, cfg);
// Print samples to stdout so you can display them in pyplot, excel, matlab
for (int i = 0; i < CAPTURE_DEPTH; ++i)
{
printf("%-3d, ", capture_buf[i]);
if (i % 30 == 29)
printf("\n");
__asm volatile("nop\n");
// busy_wait_us_32(1);
}
}
}