1 | // Bibliographies to be included
|
2 | #include <math.h>
|
3 | #include <avr/io.h>
|
4 | #include "high_acc_ADC.h"
|
5 | #include "main.h"
|
6 | #include <util/delay.h>
|
7 | #include "user_com.h"
|
8 | #include <stdio.h>
|
9 |
|
10 | // Global defines for the SPI-Interface
|
11 | #define SPI_CS_LOW PORTB &= ~(1<<PB0)
|
12 | #define SPI_CS_HIGH PORTB |= (1<<PB0)
|
13 |
|
14 |
|
15 | // Global variable for the ADC LSB
|
16 | float LTC2418_lsb = 5.0 / pow(2,24); // 5V / 2^24
|
17 |
|
18 |
|
19 | // Structure written by LT, which contains variables for the ADC result evaluation
|
20 | typedef struct
|
21 | {
|
22 | int32_t LT_int32; // 32-bit signed integer to be converted to four bytes
|
23 | uint32_t LT_uint32; // 32-bit unsigned integer to be converted to four bytes
|
24 | uint8_t LT_byte[4]; // 4 bytes (unsigned 8-bit integers) to be converted to a 32-bit signed or unsigned integer
|
25 | }LT_union_int32_4bytes;
|
26 |
|
27 |
|
28 | // Functions in this file
|
29 | uint8_t wait_for_eoc(void);
|
30 | uint32_t LTC2418_read(uint8_t channel);
|
31 | void init_SPI(void);
|
32 | void lt_spi_transfer_block(uint8_t *tx, uint8_t *rx, uint8_t length);
|
33 | float LT_code_to_voltage(int32_t adc_code, float LTC2418_lsb);
|
34 |
|
35 |
|
36 | // Function to initialize the microcontroller`s SPI-Interface
|
37 | void init_SPI(void)
|
38 | {
|
39 | DDRB |= (1<<PB0) | (1<<PB2) | (1<<PB1); // Set CS, SCK and MOSI pin as output
|
40 |
|
41 | SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0); // SPI master mode, prescaler 8MHz/16 = 500kHz, SPI enable
|
42 | }
|
43 |
|
44 |
|
45 | // ************************************************ Functions from LT (modified for control unit) **********************************************************************
|
46 |
|
47 |
|
48 | // Function, which triggers an ADC-Conversion. It gets an ADC channel and returns the actual voltage value at this channel
|
49 | int16_t adc_conversion(uint8_t channel)
|
50 | {
|
51 | // Local variable
|
52 | uint32_t adc_val = 0;
|
53 |
|
54 |
|
55 | // Check if ADC conversion is done
|
56 | if(wait_for_eoc())
|
57 | {
|
58 | debug_message("Error reading EOC!\n\r");
|
59 | }
|
60 |
|
61 |
|
62 | // A ADC conversion works as follows: The ADC value is read together with the next channel to read from. So the first conversion contains the result of the selected channel, set in the previous conversion.
|
63 | // Therefore the first value is read and gets thrown away. With this conversion the right channel gets selected for the next and finial conversion
|
64 | LTC2418_read(channel);
|
65 |
|
66 | // Check if ADC conversion is done
|
67 | if(wait_for_eoc())
|
68 | {
|
69 | debug_message("Error reading EOC!\n\r");
|
70 | }
|
71 |
|
72 | adc_val = LTC2418_read(channel); // Get ADC value previous from selected channel
|
73 |
|
74 | return LT_code_to_voltage(adc_val, LTC2418_lsb); // Convert the ADC value into a voltage value and return it
|
75 | }
|
76 |
|
77 |
|
78 | // Function to wait for conversion done by using the EOC-Bit: 1 = Conversion ongoing, 0 = Conversion done
|
79 | uint8_t wait_for_eoc(void)
|
80 | {
|
81 | // Local variable timer count for MISO
|
82 | uint16_t timer_count = 0;
|
83 |
|
84 |
|
85 | SPI_CS_LOW; // 1.) SPI-CS is pulled low
|
86 | _delay_us(100);
|
87 | while (1) // 2.) Wait for SDO (MISO) to go low
|
88 | {
|
89 | if (!(PINB & (1<<PINB3))) // 3) If SDO is low, break loop
|
90 | {
|
91 | SPI_CS_HIGH;
|
92 | break;
|
93 | }
|
94 | /*
|
95 | if (timer_count++ > 1000) // If timeout is reached, return 1 (failure)
|
96 | {
|
97 | SPI_CS_HIGH; // Pull SPI-CS high
|
98 | return(1);
|
99 | }*/
|
100 | // else
|
101 | // _delay_ms(1); // Wait for next loop
|
102 | }
|
103 |
|
104 | return(0);
|
105 | }
|
106 |
|
107 |
|
108 | // Function to read an ADC value from a selected channel
|
109 | uint32_t LTC2418_read(uint8_t channel)
|
110 | {
|
111 | // Local variables
|
112 | LT_union_int32_4bytes data, command;
|
113 |
|
114 |
|
115 | // Set channel selection to the data-byte
|
116 | command.LT_byte[3] = channel;
|
117 | command.LT_byte[2] = 0;
|
118 | command.LT_byte[1] = 0;
|
119 | command.LT_byte[0] = 0;
|
120 |
|
121 |
|
122 | // Data-byte transmission
|
123 | SPI_CS_LOW; // 1.) SPI-CS is pulled low
|
124 |
|
125 | lt_spi_transfer_block(command.LT_byte, data.LT_byte, 4); // 2) Transfer 4 data-bytes
|
126 |
|
127 | SPI_CS_HIGH; // 3) Pull SPI-CS high
|
128 |
|
129 |
|
130 | return data.LT_int32; // Return raw ADC value
|
131 | }
|
132 |
|
133 |
|
134 | // Function, which reads and sends a byte array
|
135 | void lt_spi_transfer_block(uint8_t *tx, uint8_t *rx, uint8_t length)
|
136 | {
|
137 | // Local counting variable
|
138 | int8_t cnt;
|
139 |
|
140 |
|
141 | SPI_CS_LOW; // 1.) SPI-CS is pulled low
|
142 |
|
143 | for (cnt = (length - 1); cnt >= 0; cnt--) // 2) Read and send byte array
|
144 | {
|
145 | SPDR = tx[cnt]; // Write data-byte
|
146 |
|
147 | while(!(SPSR & (1<<SPIF))); // Wait until data is transmitted
|
148 |
|
149 | rx[cnt] = SPDR; // Read data-byte
|
150 | }
|
151 |
|
152 | SPI_CS_HIGH; // 3) Pull SPI-CS high
|
153 | }
|
154 |
|
155 |
|
156 | // Function, which calculates the LTC2418 input bipolar voltage
|
157 | float LT_code_to_voltage(int32_t adc_code, float LTC2418_lsb)
|
158 | {
|
159 | // Local variable for the ADC voltage
|
160 | float adc_voltage;
|
161 |
|
162 |
|
163 | adc_code = adc_code >> 6; // 1) Bit-shift ADC code to the right 6 bits (remove last 6 bits with address, sign and sgl)
|
164 | adc_code -= 8388608; // 2) Convert ADC code from offset binary to binary
|
165 | adc_voltage = (float) adc_code * (LTC2418_lsb); // 3) Calculate voltage from ADC code and lsb.
|
166 |
|
167 | return(adc_voltage); // Return the ADC voltage value
|
168 | }
|