Ein Atmega soll aus einem 16Bit ADC lesen. Der eingesetzte ADC von
Analog Devices AD7683 hat eine lustige Eigenschaft, dass der für diese
16 Bit 3 Bytes anbietet, wobei die Nutzdaten im ersten Bytes an einer
fast beliebigen Stelle anfangen können. Das heißt, dass der ADC paar SPI
Takte zum Wandeln braucht. Es wäre alles easy, würde ich die Software
SPI Routinen benutzen, da aber am BUS noch ca. 12 weitere SPI Bausteine
hängen, für die ich Hardware SPI Routinen bereits programmiert habe,
muss ich bei bei Hardware SPI bleiben, ist ja auch sicherer und
schneller.
Also den Anfang der Nutzdaten kann man folgendermaßen erkennen. Hängt
man an die MISO Leitung einen Pull-Up ran, muss man gucken, wo im
erstempfangenen Byte die erste Null vorkommt (diese kommt laut dem
Datenbyte immer vor). Jetzt habe ich was programmiert. Kann man das
Ganze performance-technisch noch verbessern? Sicher gibt es für die
Problemlösung noch paar andere Ansätze, von insgesamt 3
unterschiedlichen habe ich mich für folgende Variante entschieden:
1 | unsigned int ad7683_read_data (u8 sl_num) {
|
2 |
|
3 | unsigned long spi_data_long = 0;
|
4 | unsigned int spi_data_int = 0;
|
5 |
|
6 | u8 adc_byte[3] = {0,0,0};
|
7 | u8 shift_operations;
|
8 |
|
9 | adc_byte[2] = spi_read_byte();
|
10 | adc_byte[1] = spi_read_byte();
|
11 | adc_byte[0] = spi_read_byte();
|
12 |
|
13 | // wenn sich die erste Null an der Posi befindet
|
14 | if (!(adc_byte[2] & 0x10)) {
|
15 | shift_operations = 4;
|
16 | }
|
17 | else
|
18 | // wenn sich die erste Null an der Posi 3 befindet
|
19 | if (!(adc_byte[2] & 0x08)) {
|
20 | shift_operations = 3;
|
21 | }
|
22 | else
|
23 | // wenn sich die erste Null an der Posi 2 befindet
|
24 | if (!(adc_byte[2] & 0x04)) {
|
25 | shift_operations = 2;
|
26 | }
|
27 | else
|
28 | // wenn sich die erste Null an der Posi 1 befindet
|
29 | if (!(adc_byte[2] & 0x02)) {
|
30 | shift_operations = 1;
|
31 | }
|
32 | spi_data_long = *((unsigned long *)&adc_byte[0]);
|
33 | spi_data_long = (spi_data_long >> shift_operations);
|
34 | spi_data_int = (u16*)spi_data_long;
|
35 |
|
36 | return spi_data_int;
|
37 | }
|
Die Hardware ist leider noch nicht da, dass ich was ausprobieren könnte.
Wenn ich später durch Test rausfinden kann, wo tendenziell die erste
Null vorkommt, könnte man diese Routine noch weiter optimieren. Wie
würdet Ihr das umsetzen?