firmware  v0.1.2
Chromation Spectrometer Dev-Kit
S13131.h
Go to the documentation of this file.
1 #ifndef _S13131_H
2 #define _S13131_H
3 #include <stdint.h>
4 #include <ReadWriteBits.h>
5 #ifdef USE_FAKES
6 #include "S13131_faked.h" // declare fakes
7 #endif
8 
26 extern uint16_t exposure_ticks;
28 #define MAX_NUM_PIXELS 512
29 
30 // TODO(sustainablelab): eliminate redundant MSB/LSB definitions in S13131.h and LIS.h
31 inline uint8_t MSB(uint16_t msb_lsb)
32 {
36  return msb_lsb >> 8;
37 }
38 inline uint8_t LSB(uint16_t msb_lsb)
39 {
43  return msb_lsb & 0xFF;
44 }
45 
46 typedef uint8_t volatile * const s13131_ptr; // reg address type
47 typedef uint8_t const s13131_pin; // pin-number type
48 typedef uint8_t const s13131_bit; // bit-index type
49 
50 // Register address, pin number, and bit definitions depend on compiler:
51  // "gcc" uses test/HardwareFake.h -> S13131-HardwareFake.h
52  // "avr-gcc" uses src/S13131-Hardware.h
53 // ---Registers---
54 extern s13131_ptr S13131_ddr;
55 extern s13131_ptr S13131_port;
56 extern s13131_ptr S13131_pin; // PortINput reg, NOT pin-number
57 extern s13131_ptr S13131_TCCR0A; // PWM timer 0 ctrl reg A
58 extern s13131_ptr S13131_TCCR0B; // PWM timer 0 ctrl reg B
59 extern s13131_ptr S13131_TIFR0; // PWM timer 0 interrupt flags
60 extern s13131_ptr S13131_OCR0A; // PWM period: fcpu/OCR0A
61 extern s13131_ptr S13131_OCR0B; // PWM duty cycle: OCR0B/OCR0A
62 
63 // ---Pins---
64 extern s13131_pin S13131_Clk; // port and ddr (PWM)
65 extern s13131_pin S13131_St; // port and ddr
66 extern s13131_pin S13131_Eos; // pin and ddr
67 
68 // ---Bits---
69 extern s13131_bit S13131_WGM00; // PWM
70 extern s13131_bit S13131_WGM01; // PWM
71 extern s13131_bit S13131_WGM02; // PWM
72 extern s13131_bit S13131_CS00; // PWM
73 extern s13131_bit S13131_CS01; // PWM
74 extern s13131_bit S13131_CS02; // PWM
75 extern s13131_bit S13131_COM0B0; // PWM
76 extern s13131_bit S13131_COM0B1; // PWM
77 extern s13131_bit S13131_OCF0A; // PWM
78 extern s13131_bit S13131_OCF0B; // PWM
79 
80 // ---API---
81 inline void S13131PinSetup(void)
82 {
83  // S13131_Clk is an OUTPUT pin
84  SetBit(S13131_ddr, S13131_Clk); // sbi 0xa,5
85  // S13131_CLK idles LOW
86  ClearBit(S13131_port, S13131_Clk); // cbi 0xb,5
87 
88  // S13131_St is an OUTPUT pin
89  SetBit(S13131_ddr, S13131_St); // sbi 0xa,6
90  // S13131_ST idles LOW
91  ClearBit(S13131_port, S13131_St); // cbi 0xb,6
92 
93  // S13131_Eos is an INPUT pin
94  ClearBit(S13131_ddr, S13131_Eos); // cbi 0xa,7
95  // Disable internal pull-up resistor on S13131_Eos
96  ClearBit(S13131_port, S13131_Eos); // cbi 0xb,7
97 }
98 
99 inline void S13131StartClocking(void)
100 {
101  // S13131_Clk is a PWM pin
102  // Output a 50kHz clock
103 
104  // ---ResetPwmTimerAtTop---
105  SetBit(S13131_TCCR0A, S13131_WGM00);
106  // in r24,0x24
107  // ori r24,lo8(1) ; WGM00 is bit 0
108  // out 0x24,r24
109  //
110  SetBit(S13131_TCCR0A, S13131_WGM01);
111  // in r24,0x24
112  // ori r24,lo8(2) ; WGM01 is bit 1
113  // out 0x24,r24
114  //
115  // PwmTimerTopIsOCR0A
116  SetBit(S13131_TCCR0B, S13131_WGM02);
117  // in r24,0x25
118  // ori r24,lo8(8) ; WGM02 is bit 3
119  // out 0x25,r24
120 
121  // ---PwmTimerClockedByCpu_NoPrescaling---
122  SetBit(S13131_TCCR0B, S13131_CS00);
123  // in r24,0x25
124  // ori r24,lo8(1) ; CS00 is bit 0
125  // out 0x25,r24
126  //
127  ClearBit(S13131_TCCR0B, S13131_CS01);
128  // in r24,0x25
129  // andi r24,lo8(-3) ; CS01 is bit 1 and -3 is 0b 1111 1101
130  // out 0x25,r24
131  //
132  ClearBit(S13131_TCCR0B, S13131_CS02);
133  // in r24,0x25
134  // andi r24,lo8(-5) ; CS02 is bit 2 and -5 is 0b 1111 1011
135  // out 0x25,r24
136 
137  // ---Set50kHzClockFreq---
138  // Timer top = 10MHz CPU clock / desired 50kHz PWM frequency
139  // 10.0e6/50.0e3 = 200.0 tics
140  *S13131_OCR0A = 200;
141  // ldi r24,lo8(-56) ; 256-56 is 200
142  // out 0x27,r24
143 
144  // ---Set 50% duty cycle---
145  // duty cycle = OCR0B/OCR0A
146  // 50% = 100/200
147  *S13131_OCR0B = 100;
148  // ldi r24,lo8(100)
149  // out 0x28,r24
150 
151  // ---Turn on the Clock Signal---
152  // Clock goes HIGH when timer restarts, and LOW when timer hits 100.
153  ClearBit(S13131_TCCR0A, S13131_COM0B0);
154  // in r24,0x24
155  // andi r24,lo8(-17) ; COM0B0 is bit 3 and -17 is 0b 1110 1111
156  // out 0x24,r24
157  SetBit(S13131_TCCR0A, S13131_COM0B1);
158  // in r24,0x24
159  // ori r24,lo8(32) ; COM0B1 is bit 5
160  // out 0x24,r24
161 }
162 
163 inline void WaitForS13131ClkLow(void)
164 {
165  // Clear flag that is set when Counter0 matches OCR0B
166  // SET BIT to clear flag in TIFR0
167  SetBit(S13131_TIFR0, S13131_OCF0B);
168  // set bit to clear flag: sbi 0x15, 2
169 
170  // Wait for flag to set again
171  while(BitIsClear(S13131_TIFR0, S13131_OCF0B));
172  // .L2:
173  // sbis 0x15,2
174  // rjmp .L2
175 }
176 
177 inline void WaitForS13131ClkHigh(void)
178 {
179  // Clear flag that is set when Counter0 matches OCR0A
180  // SET BIT to clear flag in TIFR0
181  SetBit(S13131_TIFR0, S13131_OCF0A);
182  // sbi 0x15,1
183 
184  // Wait for flag to set again
185  while(BitIsClear(S13131_TIFR0, S13131_OCF0A));
186  //.L7:
187  // sbis 0x15,1
188  // rjmp .L7
189 }
190 
191 inline void S13131Expose(void)
192 {
276  // Expose S13131.
277  // Exposure time is set by global variable exposure_ticks.
278 
279  // -------------------------------------------------
280  // TODO(sustainablelab): move this clamp code to response to VisCmd.SetExposure.
281  // Clamp exposure_ticks to minimum allowed value.
282  if (exposure_ticks < 9)
283  exposure_ticks = 9;
284  // -------------------------------------------------
285 
286  // Compensate for the 6 cycles S13131 adds to exposure set by ST
287  exposure_ticks -= 6;
288 
289  // ---ONLY TRANSITION ST AFTER A CLK FALLING EDGE---
290 
291  // STATE: CLK is running and ST is idling LOW
292  WaitForS13131ClkLow();
293  SetBit(S13131_port, S13131_St); // sbi 0xb,6
294 
295  // Count CLK rising edges until count == exposure_ticks
296  for(uint16_t r_count = 0; r_count < exposure_ticks; r_count++)
297  {
298  WaitForS13131ClkHigh();
299 
300  // 0 < 4: Wait for CLK rising-edge (r_count 0->1)
301  // 1 < 4: Wait for CLK rising-edge (r_count 1->2)
302  // 2 < 4: Wait for CLK rising-edge (r_count 2->3)
303  // There have been three rising edges so far.
304  // STATE: Exposure Starts
305 
306  // 3 < 4: Wait for CLK rising-edge (r_count 3->4)
307  // ...
308  // Eventually r_count == exposure_ticks!
309  // -> r_count !< exposure_ticks: Exit loop
310  // Total of number of rising edges so far == r_count == exposure_ticks
311  // Exposed for a total of (r_count - 3) clock cycles so far.
312  // Loop exits *just after* the rising edge where r_count == exposure_ticks.
313  }
314 
315  WaitForS13131ClkLow();
316  ClearBit(S13131_port, S13131_St); // cbi 0xb,6
317  // STATE: Exposure will stop 9 clock rising-edges later
318 
319  // Clock-in ST LOW
320  WaitForS13131ClkHigh(); // (1st of the 9 rising edges)
321 
322  // Start the falling-edge count-down to pixel readout.
323  // Exit this count-down just after the 13th clock falling edge.
324  for(uint16_t f_count = 0; f_count < (14-1); f_count++)
325  {
326  // Loop enters *just after* 5th rising edge.
327  WaitForS13131ClkLow();
328  // 0 < 13: Wait for CLK falling-edge (f_count 0 -> 1)
329  // 1 < 13: Wait for CLK falling-edge (f_count 1 -> 2)
330  // ...
331  // 12 < 13: Wait for CLK falling-edge (f_count 12 -> 13)
332  // 13 < 13: Exit loop
333  }
334 
335  // STATE: Readout pixel 1 on next falling edge of CLK
336 }
337 
338 #endif // _S13131_H
uint8_t MSB(uint16_t msb_lsb)
Definition: S13131.h:31
void S13131Expose(void)
Definition: S13131.h:191
uint16_t exposure_ticks
S13131 exposure time.
Definition: Lis.c:32
uint8_t LSB(uint16_t msb_lsb)
Definition: S13131.h:38