firmware  v0.1.2
Chromation Spectrometer Dev-Kit
Lis.h
Go to the documentation of this file.
1 #ifndef _LIS_H
2 #define _LIS_H
3 #include <stdint.h>
4 #include "ReadWriteBits.h"
5 #include "LisConfig.h"
6 #ifdef USE_FAKES
7 #include "Lis_faked.h" // declare fakes
8 #endif
9 //---Hardware types: register addresses, pin numbers, bit numbers---
10 typedef uint8_t volatile * const lis_ptr; // i/o reg address
11 typedef uint8_t const lis_pin; // bit index into i/o reg for an i/o pin
12 typedef uint8_t const lis_bit; // bit index into i/o reg
13 
14 // Register address, pin number, and bit definitions depend on compiler:
15  // "gcc" uses test/HardwareFake.h
16  // "avr-gcc" uses src/Lis-Hardware.h
17 // ---Registers---
18 extern lis_ptr Lis_ddr1;
19 extern lis_ptr Lis_port1;
20 extern lis_ptr Lis_pin1;
21 extern lis_ptr Lis_ddr2;
22 extern lis_ptr Lis_port2;
23 extern lis_ptr Lis_TCCR0A; // PWM timer 0 ctrl reg A
24 extern lis_ptr Lis_TCCR0B; // PWM timer 0 ctrl reg B
25 extern lis_ptr Lis_TIFR0; // PWM timer 0 interrupt flags
26 extern lis_ptr Lis_OCR0A; // PWM period: fcpu/OCR0A
27 extern lis_ptr Lis_OCR0B; // PWM duty cycle: OCR0B/OCR0A
28 // ---Pins---
29 extern lis_pin Lis_PixSelect; // port2 and ddr2
30 extern lis_pin Lis_Clk; // port1 and ddr1 (PWM)
31 extern lis_pin Lis_Rst; // port1 and ddr1
32 extern lis_pin Lis_Sync; // pin1 and ddr1
33 // ---Bits---
34 extern lis_bit Lis_WGM00; // PWM
35 extern lis_bit Lis_WGM01; // PWM
36 extern lis_bit Lis_WGM02; // PWM
37 extern lis_bit Lis_CS00; // PWM
38 extern lis_bit Lis_CS01; // PWM
39 extern lis_bit Lis_CS02; // PWM
40 extern lis_bit Lis_COM0B0; // PWM
41 extern lis_bit Lis_COM0B1; // PWM
42 extern lis_bit Lis_OCF0A; // PWM
43 extern lis_bit Lis_OCF0B; // PWM
44 // ---Private---
45 inline void Pin_LisPixSelect_SetOutput(void)
46 {
47  SetBit(Lis_ddr2, Lis_PixSelect);
48  // ---Expected Assembly---
49  // sbi 0x04, 0 ; 4
50 }
51 inline void LisPixSelectIdleLow(void)
52 {
53  ClearBit(Lis_port2, Lis_PixSelect);
54  // ---Expected Assembly---
55  // cbi 0x05, 0 ; 5
56 }
57 inline void Pin_LisClk_SetOutput(void)
58 {
59  SetBit(Lis_ddr1, Lis_Clk);
60  // ---Expected Assembly---
61  // sbi 0x0a, 5 ; 10
62 }
63 inline void Pin_LisRst_SetOutput(void)
64 {
65  SetBit(Lis_ddr1, Lis_Rst);
66  // ---Expected Assembly---
67  // sbi 0x0a, 6 ; 10
68 }
69 inline void LisRstIdleLowAfterPowerUp(void)
70 {
71  ClearBit(Lis_port1, Lis_Rst);
72  // ---Expected Assembly---
73  // cbi 0x0b, 6 ; 11
74 }
75 inline void Pin_LisSync_SetInput(void)
76 {
77  ClearBit(Lis_ddr1, Lis_Sync);
78  // ---Expected Assembly---
79  // cbi 0x0a, 7 ; 10
80 }
81 inline void ResetPwmTimerAtTop(void)
82 {
83  SetBit(Lis_TCCR0A, Lis_WGM00);
84  SetBit(Lis_TCCR0A, Lis_WGM01);
85  // ---Expected Assembly---
86  // Lis_TCCR0A is 0x24: expect direct reg-access in/out
87  // in r24, 0x24 ; 36
88  // ori r24, 0x01 ; 1
89  // out 0x24, r24 ; 36
90  // in r24, 0x24 ; 36
91  // ori r24, 0x02 ; 2
92  // out 0x24, r24 ; 36
93 }
94 inline void PwmTimerTopIsOCR0A(void)
95 {
96  SetBit(Lis_TCCR0B, Lis_WGM02);
97  // ---Expected Assembly---
98  // in r24, 0x25 ; 37
99  // ori r24, 0x08 ; 8
100  // out 0x25, r24 ; 37
101 }
102 inline void PwmTimerClockedByCpu_NoPrescaling(void)
103 {
104  SetBit(Lis_TCCR0B, Lis_CS00);
105  ClearBit(Lis_TCCR0B, Lis_CS01);
106  ClearBit(Lis_TCCR0B, Lis_CS02);
107  // ---Expected Assembly---
108  // Clear bit 1:
109  // in r24, 0x25 ; 37
110  // andi r24, 0xFD ; 253
111  // out 0x25, r24 ; 37
112  // Clear bit 2:
113  // in r24, 0x25 ; 37
114  // andi r24, 0xFB ; 251
115  // out 0x25, r24 ; 37
116 }
117 inline void LisClkFreq50kHz(void)
118 {
121  ResetPwmTimerAtTop();
122  PwmTimerTopIsOCR0A();
123  PwmTimerClockedByCpu_NoPrescaling();
124  // timer top = 10MHz CPU clock / desired 50kHz PWM frequency
125  // 10.0e6/50.0e3 = 200.0 tics
126  *Lis_OCR0A = 200;
127  // duty cycle = OCR0B/OCR0A
128  // 50% = 100/200
129  *Lis_OCR0B = 100;
130  // ---Expected Assembly---
131  // OCR0A is 0x27, OCR0B is 0x28: expect "out" writes to reg
132  // ldi r24, 0xC8 ; 200
133  // out 0x27, r24 ; 39
134  // ldi r24, 0x64 ; 100
135  // out 0x28, r24 ; 40
136 }
137 inline void LisClkOn(void)
138 {
142  ClearBit(Lis_TCCR0A, Lis_COM0B0);
143  SetBit(Lis_TCCR0A, Lis_COM0B1);
144  // ---Expected Assembly---
145  // Clear bit
146  // in r24, 0x24 ; 36
147  // andi r24, 0xEF ; 239
148  // out 0x24, r24 ; 36
149  // Set bit
150  // in r24, 0x24 ; 36
151  // in r24, 0x24 ; 36
152  // ori r24, 0x20 ; 32
153  // out 0x24, r24 ; 36
154 }
155 inline void _ConfigAs28bits(uint8_t *config)
156 {
173  // ---Expected Assembly---
174  // Y is r28 and r29
175  // std (store indirect with displacement)
176  // std Y+1, r24 -- stores value in r24 at address in Y plus 1
177  // The following stores the 4-byte config at the address in Y:
178  // config byte 0 is 0xF9: 11111001 (bits 7 to 0)
179  // config byte 1 is 0xFF: 11111111 (bits 15 to 8)
180  // config byte 2 is 0xFF: 11111111 (bits 23 to 16)
181  // config byte 3 is 0x0F: 00001111 (bits 31 to 24)
182  // ldi r24, 0xF9 ; 249
183  // std Y+1, r24 ; 0x01
184  // ldi r24, 0xFF ; 255
185  // std Y+2, r24 ; 0x02
186  // std Y+3, r24 ; 0x03
187  // ldi r24, 0x0F ; 15
188  // std Y+4, r24 ; 0x04
189 
190  // Clear all bits in array at input address `config`.
191  config[0]=0x00; config[1]=0x00; config[2]=0x00; config[3]=0x00;
192  // binning is bit 0 of byte 0
193  uint8_t bit = 0;
194  if (BINNING_ON == binning) config[0] |= 1<<(bit++);
195  else bit++;
196  // bit 1 of byte 0 is datasheet "gain bit G2"
197  // bit 2 of byte 0 is datasheet "gain bit G1"
198  // {G2,G1}: {0,0} 1x; {0,1} 2.5x; {1,0} 4x; {1,1} 5x
199  if (GAIN_2X5 == gain) { bit++; config[0] |= 1<<(bit++); }
200  else if (GAIN_4X == gain) { config[0] |= 1<<(bit++); bit++; }
201  else if (GAIN_5X == gain) { config[0] |= 1<<(bit++); config[0] |= 1<<(bit++); }
202  else { bit++; bit++; }
203  // bit 3 to 27 are pixel groups P25 to P1 to select active rows
204  // Example with binning_on and gain1x
205  // ----3---- ----2---- ----1---- ----0-(---) // byte
206  // 7654 3210 7654 3210 7654 3210 7654 3(210) // bit
207  // xxxx 1111 1111 1111 1111 1111 1111 1(001) // all rows on
208  // xxxx 0000 1000 0100 0010 0001 0000 1(001) // row 1 (or 5?)
209  // xxxx 0001 0000 1000 0100 0010 0001 0(001) // row 2 (or 4?)
210  // xxxx 0010 0001 0000 1000 0100 0010 0(001) // row 3
211  // xxxx 0100 0010 0001 0000 1000 0100 0(001) // row 4 (or 2?)
212  // xxxx 1000 0100 0010 0001 0000 1000 0(001) // row 5 (or 1?)
213  uint8_t const row1 = 0; uint8_t const row1_mask[] = {0x00,0x84,0x21,0x08};
214  uint8_t const row2 = 1; uint8_t const row2_mask[] = {0x01,0x08,0x42,0x10};
215  uint8_t const row3 = 2; uint8_t const row3_mask[] = {0x02,0x10,0x84,0x20};
216  uint8_t const row4 = 3; uint8_t const row4_mask[] = {0x04,0x21,0x08,0x40};
217  uint8_t const row5 = 4; uint8_t const row5_mask[] = {0x08,0x42,0x10,0x80};
218  // byte orders are mirrored below because
219  // rowN_mask[] is big endian, but
220  // config[] is little endian
221  if (active_rows&(1<<row1))
222  {
223  config[0] |= row1_mask[3];
224  config[1] |= row1_mask[2];
225  config[2] |= row1_mask[1];
226  config[3] |= row1_mask[0];
227  }
228  if (active_rows&(1<<row2))
229  {
230  config[0] |= row2_mask[3];
231  config[1] |= row2_mask[2];
232  config[2] |= row2_mask[1];
233  config[3] |= row2_mask[0];
234  }
235  if (active_rows&(1<<row3))
236  {
237  config[0] |= row3_mask[3];
238  config[1] |= row3_mask[2];
239  config[2] |= row3_mask[1];
240  config[3] |= row3_mask[0];
241  }
242  if (active_rows&(1<<row4))
243  {
244  config[0] |= row4_mask[3];
245  config[1] |= row4_mask[2];
246  config[2] |= row4_mask[1];
247  config[3] |= row4_mask[0];
248  }
249  if (active_rows&(1<<row5))
250  {
251  config[0] |= row5_mask[3];
252  config[1] |= row5_mask[2];
253  config[2] |= row5_mask[1];
254  config[3] |= row5_mask[0];
255  }
256 }
257 inline void _WaitForLisClkLow(void)
258 {
263  // Clear flag that is set when Counter0 matches OCR0B
264  SetBit(Lis_TIFR0, Lis_OCF0B); // set bit to clear flag: sbi 0x15, 2
265  // Wait for flag to set again
266  while(BitIsClear(Lis_TIFR0, Lis_OCF0B)); // sbis 0x15, 2
267 }
268 inline void _WaitForLisClkHigh(void)
269 {
274  // Clear flag that is set when Counter0 matches OCR0A
275  SetBit(Lis_TIFR0, Lis_OCF0A);
276  // Wait for flag to set again
277  while(BitIsClear(Lis_TIFR0, Lis_OCF0A));
278 }
279 
280 #ifdef USE_FAKES
281 #define _WaitForLisClkLow _WaitForLisClkLow_fake
282 #endif // USE_FAKES
283 inline void _EnterLisProgrammingMode(void)
284 {
289  // Total number of cycles: 8
290  // Total number of instructions: 4
292  // ---Expected Assembly---
293  // 708: sbi 0x15, 2 ; 21
294  // 70a: sbis 0x15, 2 ; 21
295  // 70c: rjmp .-4 ; 0x70a
296  SetBit(Lis_port2, Lis_PixSelect);
297  // ---Expected Assembly---
298  // 70e: sbi 0x05, 0 ; 5
299 }
300 #ifdef USE_FAKES
301 #undef _WaitForLisClkLow
302 #endif // USE_FAKES
303 
304 inline void _ExitLisProgrammingMode(void)
305 {
310  // Total number of cycles: 4
311  // Total number of instructions: 2
312  ClearBit(Lis_port1, Lis_Rst);
313  // ---Expected Assembly---
314  // 788: cbi 0x0b, 6 ; 11
315  ClearBit(Lis_port2, Lis_PixSelect);
316  // ---Expected Assembly---
317  // 78a: cbi 0x05, 0 ; 5
318 }
319 
320 #ifdef USE_FAKES
321 #define _WaitForLisClkLow _WaitForLisClkLow_fake
322 #define _WaitForLisClkHigh _WaitForLisClkHigh_fake
323 #endif // USE_FAKES
324 inline void _WriteLisConfigBit(uint8_t const * config, uint8_t bit_index)
325 {
343  // Set up pin `Lis_Rst` with value to write
344  BitIsSet((uint8_t *)config, bit_index) ?
345  SetBit(Lis_port1, Lis_Rst)
346  :
347  ClearBit(Lis_port1, Lis_Rst);
348  // Clock in the value
351 }
352 #ifdef USE_FAKES
353 #undef _WaitForLisClkLow
354 #undef _WaitForLisClkHigh
355 #endif // USE_FAKES
356 
357 #ifdef USE_FAKES
358 #define _WriteLisConfigBit _WriteLisConfigBit_fake
359 #endif // USE_FAKES
360 inline void _Write28bitLisConfig(uint8_t const *config)
361 {
365  // Write all bits in the first three bytes of config
366  for (uint8_t cfg_byte_i = 0; cfg_byte_i < 3; cfg_byte_i++)
367  {
368  for (uint8_t bit_i = 0; bit_i<8; bit_i++)
369  {
370  _WriteLisConfigBit(config, bit_i);
371  }
372  config++;
373  }
374  // Write first four bits of last byte of config
375  uint8_t bit_i = 0;
376  while(bit_i < 4) _WriteLisConfigBit(config, bit_i++);
377 }
378 #ifdef USE_FAKES
379 #undef _WriteLisConfigBit
380 #endif // USE_FAKES
381 
382 // ---API---
394 extern uint16_t exposure_ticks;
400 #define MAX_NUM_PIXELS 784
401 inline uint8_t MSB(uint16_t msb_lsb)
402 {
406  return msb_lsb >> 8;
407 }
408 inline uint8_t LSB(uint16_t msb_lsb)
409 {
413  return msb_lsb & 0xFF;
414 }
415 
416 inline void LisInit(void)
417 {
432  Pin_LisPixSelect_SetOutput();
433  LisPixSelectIdleLow();
434  Pin_LisClk_SetOutput();
435  Pin_LisRst_SetOutput();
436  LisRstIdleLowAfterPowerUp();
437  Pin_LisSync_SetInput();
438  LisClkFreq50kHz();
439  LisClkOn();
440 }
441 inline bool LisConfigIsValid(
442  uint8_t binning,
443  uint8_t gain,
444  uint8_t active_rows)
445 {
452  return
453  (
454  (binning == BINNING_OFF) || (binning == BINNING_ON)
455  )
456  &&
457  (
458  (gain == GAIN_1X) ||
459  (gain == GAIN_2X5) ||
460  (gain == GAIN_4X) ||
461  (gain == GAIN_5X)
462  )
463  &&
464  (
465  (active_rows & 0xE0) == 0x00
466  );
467 }
468 
469 #ifdef USE_FAKES
470 #define _ConfigAs28bits _ConfigAs28bits_fake
471 #define _EnterLisProgrammingMode _EnterLisProgrammingMode_fake
472 #define _Write28bitLisConfig _Write28bitLisConfig_fake
473 #define _ExitLisProgrammingMode _ExitLisProgrammingMode_fake
474 #endif // USE_FAKES
475 inline void LisWriteConfig(void)
476 {
483  // Store global lis_cfg parameters as a 28-bit config
484  uint8_t config[4]; // memory for 28-bit config
485  _ConfigAs28bits(config);
486  // Program LIS with 28-bit config
488  _Write28bitLisConfig(config);
490 }
491 #ifdef USE_FAKES
492 #undef _ConfigAs28bits
493 #undef _EnterLisProgrammingMode
494 #undef _Write28bitLisConfig
495 #undef _ExitLisProgrammingMode
496 #endif // USE_FAKES
497 
498 inline void LisExpose(void)
499 {
506  // wait for the falling clock edge
508 
509  // start exposure
510  SetBit(Lis_port1, Lis_Rst); // sbi 0x0b, 6
511 
512  // count falling edges as ticks
513  uint16_t tick_count = 0;
514  while (tick_count++ < exposure_ticks)
515  {
516  // wait for the falling clock edge
518  }
519 
520  // stop exposure
521  ClearBit(Lis_port1, Lis_Rst); // cbi 0x0b, 6
522 }
523 
524 #endif // _LIS_H
LIS-770i configuration
bool LisConfigIsValid(uint8_t binning, uint8_t gain, uint8_t active_rows)
Definition: Lis.h:441
void _ExitLisProgrammingMode(void)
Definition: Lis.h:304
uint8_t MSB(uint16_t msb_lsb)
Definition: Lis.h:401
void _ConfigAs28bits(uint8_t *config)
Definition: Lis.h:155
void _EnterLisProgrammingMode(void)
Definition: Lis.h:283
void _WaitForLisClkHigh(void)
Definition: Lis.h:268
void _WriteLisConfigBit(uint8_t const *config, uint8_t bit_index)
Definition: Lis.h:324
void LisWriteConfig(void)
Definition: Lis.h:475
uint16_t exposure_ticks
LIS-770i exposure time.
Definition: Lis.c:32
void LisInit(void)
Definition: Lis.h:416
void LisClkOn(void)
Definition: Lis.h:137
void LisClkFreq50kHz(void)
Definition: Lis.h:117
void _WaitForLisClkLow(void)
Definition: Lis.h:257
void LisExpose(void)
Definition: Lis.h:498
void _Write28bitLisConfig(uint8_t const *config)
Definition: Lis.h:360
uint8_t LSB(uint16_t msb_lsb)
Definition: Lis.h:408