-
Notifications
You must be signed in to change notification settings - Fork 0
/
Sketch.cpp
271 lines (208 loc) · 5.15 KB
/
Sketch.cpp
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/*Begining of Auto generated code by Atmel studio */
#include <Arduino.h>
/*End of auto generated code by Atmel studio */
*/This firmware is related to the AD7667ASTZ (ADC) and the ATMega1284P MCU used in the CCD driver circuit for the TCD1304DG.
*/All details pertaining to programming peripherals and settings are taken from the appropriate data sheets.
#include <util/delay_basic.h>
#define RD (1<<2)
#define CNVST (1<<3)
#define BYTESWAP (1<<4)
#define ICG (1<<5)
#define SH (1<<6)
#define MCLK (1<<7)
// Full frame, including dark pixels
// and dead pixels.
#define PIXEL_COUNT 3691
// Ports and pins
#define CLOCKS PORTD
#define CLOCKP PIND
#define CLOCKS_DDR DDRD
#define DATA_PINS PINC
#define DATA_PORT PORTC
#define DATA_DDR DDRC
// 10mS exposure time.
#define EXPOSURE_TIME 10
// Initial clock state.
uint8_t clocks0 = (RD + CNVST + ICG);
// 16-bit pixel buffer
uint16_t pixBuf[PIXEL_COUNT];
char cmdBuffer[16];
int cmdIndex;
int exposureTime = EXPOSURE_TIME;
int cmdRecvd = 0;
/*
* readLine() Reads all pixels into a buffer.
*/
void readLine() {
// Get an 8-bit pointer to the 16-bit buffer.
uint8_t *buf = (uint8_t *) pixBuf;
int x = 0;
uint8_t scratch = 0;
// Disable interrupts or the timer will get us.
cli();
// Synchronize with MCLK and
// set ICG low and SH high.
scratch = CLOCKS;
scratch &= ~ICG;
scratch |= SH;
while(!(CLOCKP & MCLK));
while((CLOCKP & MCLK));
TCNT2 = 0;
_delay_loop_1(1);
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
CLOCKS = scratch;
// Wait the remainder of 4uS @ 20MHz.
_delay_loop_1(22);
__asm__("nop");
__asm__("nop");
// Set SH low.
CLOCKS ^= SH;
// Wait the reaminder of 4uS.
_delay_loop_1(23);
// Start the readout loop at the first pixel.
CLOCKS |= (RD + CNVST + ICG + BYTESWAP + SH);
__asm__("nop");
do {
// Wait a minimum of 250nS for acquisition.
_delay_loop_1(2);
// Start the conversion.
CLOCKS &= ~CNVST;
CLOCKS |= CNVST;
// Wait a minimum of 1uS for conversion.
_delay_loop_1(4);
// Read the low byte of the result.
CLOCKS &= ~RD;
_delay_loop_1(4);
*buf++ = DATA_PINS;
// Setup and read the high byte.
CLOCKS &= ~(BYTESWAP);
_delay_loop_1(4);
*buf++ = DATA_PINS;
// Set the clocks back to idle state
CLOCKS |= (RD + BYTESWAP);
// Toggle SH for the next pixel.
CLOCKS ^= SH;
} while (++x < PIXEL_COUNT);
sei();
}
/*
* clearLine() Clears the CCD.
*/
void clearLine() {
int x = 0;
// Set ICG low.
CLOCKS &= ~ICG;
CLOCKS |= SH;
_delay_loop_1(14);
// Set SH low.
CLOCKS ^= SH;
_delay_loop_1(10);
// Reset the timer so the edges line up.
TCNT2 = 0;
CLOCKS |= (RD + CNVST + ICG + BYTESWAP + MCLK);
do {
CLOCKS ^= SH;
_delay_loop_1(10);
} while (++x < PIXEL_COUNT);
}
/*
* sendLine() Send the line of pixels to the user.
*/
void sendLine() {
uint16_t x;
for (x = 0; x < PIXEL_COUNT; ++x) {
Serial.print(x);
Serial.print(",");
Serial.print(pixBuf[x]);
Serial.print("\n");
}
}
/*
* setup()
* Set the data port to input.
* Set the clock port to output.
* Start timer2 generating the Mclk signal
*/
void setup() {
delay(10);
CLOCKS_DDR = 0xff;
CLOCKS = 0; //clocks0;
DATA_DDR = 0x0;
Serial.begin(115200);
// Setup timer2 to generate an 888kHz frequency on D10
TCCR2A = (0 << COM2A1) | (1 << COM2A0) | (1 << WGM21) | (0 << WGM20);
TCCR2B = (0 << WGM22) | (1 << CS20);
OCR2A = 8;
TCNT2 = 0;
delay(10);
}
/*
* loop()
* Read the CCD continuously.
* Upload to user on switch press.
*/
void loop() {
int x;
char ch;
// If we got a command last time, execute it now.
if (cmdRecvd) {
if (cmdBuffer[0] == 'r') {
// Send the readout to the host.
sendLine();
} else if (cmdBuffer[0] == 'e') {
delay(10);
Serial.write(cmdBuffer);
// Set the exposure time.
sscanf(cmdBuffer + 1, "%d", &exposureTime);
if (exposureTime > 1000) exposureTime = 1000;
if (exposureTime < 1) exposureTime = 1;
}
// Get ready for the next command.
memset(cmdBuffer, 0, sizeof(cmdBuffer));
cmdIndex = 0;
cmdRecvd = 0;
}
// Clear the CCD.
clearLine();
// Integrate.
delay(exposureTime);
// Read it for real.
readLine();
// See if the host is talking to us.
if (Serial.available()) {
ch = Serial.read();
// If char is linefeed, it is end of command.
if (ch == 0x0a) {
cmdBuffer[cmdIndex++] = '\0';
cmdRecvd = 1;
// Otherwise it is a command character.
} else {
cmdBuffer[cmdIndex++] = ch;
cmdRecvd = 0;
}
}
}
#include "adc.h"
//Beginning of Auto generated function prototypes by Atmel Studio
void readLine();
void clearLine();
void sendLine();
int main(void );
//End of Auto generated function prototypes by Atmel Studio
#define ADC_INPUT ADC_MUX_ADC0
#define ADC_VREF ADC_VREF_AVCC
int main(void)
{
// set PORTB as output
DDRB = 0xFF;
// set prescaler and enable ADC
adc_init(ADC_PRESCALER_DIV128);
// output inverted ADC value on PORTB
while (1) {
PORTB = ~(adc_read_8bit(ADC_INPUT, ADC_VREF));
}
}