1 | //------------------------------------------------------------------------------------------------------------
|
2 | //
|
3 | // Programmname: STM32F4_AD7680
|
4 | // Datum: 09.10.2013
|
5 | // IDE: CooCox COIDE V. 1.7.5
|
6 | // Autor: T. Öztürk
|
7 | //
|
8 | //
|
9 | //
|
10 | // Takt-Einstellungen: HSE=8 MHz, HCLK=168MHz, SYSCLK=168 MHz, PCLK1=42 MHz (Taktquelle für SPI2)
|
11 | // PLL_N=336
|
12 | // PLL_M=25
|
13 | // PLL_Q=7
|
14 | // PLL_P=2
|
15 | //
|
16 | // Beschreibung: Dieses Programm steuert über Serial Peripheral Interface (SPI) den externen
|
17 | // Analog-Digital Umsetzer AD7680 an und empfängt die Abtastwerte. Der AD7680
|
18 | // hat eine Auflösung von 16 Bit, also 65535 Abstufungen. Der 16-Bit Abtastwert
|
19 | // wird nicht "direkt" als 16-Bit geschickt, sondern in 24 Bits, d.h. der AD7680
|
20 | // füllt die restlichen Bit-Stellen mit Nullen auf. Der SPI wurde daher auf 8 Bit,
|
21 | // also 1 Byte, Datenpakete eingestellt. Es werden somit drei Byte Pakete empfangen,
|
22 | // aus denen der 16 Bit Abtastwert durch Bit-Verschiebung zusammengestellt wird.
|
23 | // Der Abtastvorgang beginnt mit der fallenden Flanke des Chip Select Signals.
|
24 | // Die Taktgeschwindigkeit SCLK des SPI's bestimmt auch die Abtastrate des AD7680.
|
25 | // Weitere Informationen sind dem Datenblatt des AD7680 zu entnehmen:
|
26 | // http://www.analog.com/static/imported-files/data_sheets/AD7680.pdf
|
27 | // (In CooCox CoIDE: STRG gedrückt halten und mit linken Mauszeiger auf Link klicken)
|
28 |
|
29 | // In diesem Beispiel wird der SPI2 Controller des STM32F4 verwendet. Die jeweiligen
|
30 | // Pin-Zuordnungen sind dem Datenblatt des STM32F4 zu entnehmen. (Abschnitt 3, Tab. 6):
|
31 | // http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00037051.pdf
|
32 | //
|
33 | // Eine weitere wichtige Quelle bzw. die einzige, die ich gefunden habe, wo der AD7680 eingesetzt wird:
|
34 | // http://abieneman.wordpress.com/2010/04/04/punch-acceleration-sensor/
|
35 | //
|
36 | //
|
37 | // Anschlussplan:
|
38 | //
|
39 | // AD7860 | STM32F4 Discovery Board
|
40 | //------------------------------------------------------------------------------------------------------------
|
41 | // VDD (Pin 1) VDD
|
42 | // GND (Pin2,Pin3) GND
|
43 | // VIN (Pin4) zu Messende Spannung z.B. VDD, Auf max. Spannung achten !
|
44 | // SCLK (Pin5) PB10
|
45 | // NC (Pin6) -
|
46 | // SDATA (Pin7) PC2
|
47 | // ~CS (Pin8) PA3
|
48 | //------------------------------------------------------------------------------------------------------------
|
49 | //
|
50 | // Ich habe keine Kondensatoren zum Glätten bzw. Entstören verwendet. Dies ist lediglich ein
|
51 | // Minimalbeispiel. Eine Beispiel-Schaltung nach Analog Devices befindet sich im Datenblatt
|
52 | // des AD7680 auf S. 13 (inklusive "saubere" Versorgungs- bzw. Referenzspannung)
|
53 | //
|
54 | // Ich bin kein "langjähriger" C-Programmierer, daher entschuldigt den nicht sauberen
|
55 | // bzw. nicht professionellen Code !
|
56 | //
|
57 | //
|
58 | // Viel Spass und Erfolg !
|
59 | //
|
60 | //------------------------------------------------------------------------------------------------------------
|
61 |
|
62 |
|
63 |
|
64 | //---------------------------------------------------------------------------------------------------
|
65 | // Includes
|
66 | //---------------------------------------------------------------------------------------------------
|
67 | #include "stm32f4xx_rcc.h"
|
68 | #include "stm32f4xx_gpio.h"
|
69 | #include "stm32f4xx_spi.h"
|
70 |
|
71 |
|
72 |
|
73 | //---------------------------------------------------------------------------------------------------
|
74 | // Defines
|
75 | //---------------------------------------------------------------------------------------------------
|
76 | #define LED_Green GPIO_Pin_12 // selbsterklärend
|
77 | #define LED_Orange GPIO_Pin_13 // ""
|
78 | #define LED_Red GPIO_Pin_14 // ""
|
79 | #define LED_Blue GPIO_Pin_15 // ""
|
80 |
|
81 | #define SCLK GPIO_Pin_10 //PB10 // Takt-Ausgang für SPI
|
82 | #define SDATA GPIO_Pin_2 //PC2 // Datenleitung für die Samples bzw. MISO
|
83 | #define MOSI GPIO_Pin_3 //PC3 // MOSI; existiert in diesem Beispiel nicht
|
84 | #define CS GPIO_Pin_3 //PA3 // ChipSelect (auch SlaveSelect genannt)
|
85 |
|
86 | #define ADC_RES 65535 // Der AD7680 hat eine Auflösung von 16 Bit: (2^16)-1=65535 Abstufungen
|
87 | #define Vref 2.94 // Referenzsspannung des A-D Umsetzer ist bei beim AD7680 die Versorgungsspannung Vss
|
88 | // Die Versorgungsspannung des AD-Umsetzer wird dem Vdd Pin des STM32F4 Discovery Boards
|
89 | // entnommen, die bei USB Speisung c.a. 2.94 V beträgt (Schutzdioden auf dem Board...).
|
90 |
|
91 | //---------------------------------------------------------------------------------------------------
|
92 | // Prototpes
|
93 | //---------------------------------------------------------------------------------------------------
|
94 | void EnableRCC(void);
|
95 | void ConfigGPIO(void);
|
96 | void ConfigSPI(void);
|
97 | uint8_t ReadSPI(void);
|
98 |
|
99 |
|
100 | int main(void)
|
101 | {
|
102 |
|
103 | uint8_t raw_bytes[3]; // Ein Array wo die drei "Roh-Bytes" gespeichert werden. "Roh-Bytes" sind die mit den Nullen aufgefüllten Bytes, die vom AD7680 gesendet werden
|
104 | unsigned sample_value = 0; // Hier wird der 16 Bit Abtastwert gespeichert
|
105 | float voltage_value = 0; // Der berechnete Spannungswert wird hier gespeichert
|
106 | int i = 0;
|
107 |
|
108 | SystemInit(); // ggf. nötig, damit die Takteinstellungen richtig übernommen werden
|
109 | EnableRCC(); // Takt für die benötigten Peripherien einschalten
|
110 | ConfigGPIO(); // Die GPIO Pins konfigurieren
|
111 | ConfigSPI(); // SPI2 Controller konfigurieren
|
112 | GPIO_SetBits(GPIOD,LED_Blue); // blaue LED einschalten (Lebenszeichen)
|
113 |
|
114 | while(1)
|
115 | {
|
116 | GPIO_ResetBits(GPIOA,CS); // ChipSelect Ausgang auf Low setzen, damit der AD7680 mit Abtastvorgang anfängt
|
117 | for(i=0; i<3; i++)
|
118 | {
|
119 | raw_bytes[i]=ReadSPI(); // Alle drei "Roh-Bytes" in das Array speichern
|
120 | }
|
121 | GPIO_SetBits(GPIOA,CS); // ChipSelect Ausgang auf High setzen, damit der AD7680 mit Abtastvorgang aufhört
|
122 |
|
123 |
|
124 | sample_value = (raw_bytes[0] << 11) | (raw_bytes[1] << 3) | (raw_bytes[2] >> 5); // Da wir 3 Bytes (24 Bit) erhalten, müssen wir Bits verschieben um an die
|
125 | // relevanten 16 Bit Daten (Abtastwert) heranzukommen.
|
126 |
|
127 | voltage_value=(Vref/ADC_RES)*sample_value; // Spannungswert aus dem Abtastwert (16 Bit ADC Wert) berechnen
|
128 | }
|
129 | }
|
130 |
|
131 |
|
132 | uint8_t ReadSPI(void)
|
133 | {
|
134 | SPI2->DR = 0xAA; // "dummy" Daten schreiben, dies ist nötig, damit überhaupt Empfangen werden kann.
|
135 | while( !(SPI2->SR & SPI_I2S_FLAG_TXE) ); // warten bis der Sendevorgang abgeschlossen ist
|
136 | while( !(SPI2->SR & SPI_I2S_FLAG_RXNE) ); // warten bis der Datenempfang abgeschlossen ist
|
137 | while( SPI2->SR & SPI_I2S_FLAG_BSY ); // warten bis der SPI2 nicht mehr "beschäftigt" ist.
|
138 | return SPI2->DR; // Daten im SPI2 Datenregister als Rückgabewert ausgeben
|
139 | }
|
140 |
|
141 |
|
142 | void ConfigSPI()
|
143 | {
|
144 |
|
145 | SPI_InitTypeDef SPI_InitStructure;
|
146 |
|
147 | SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // Daten empfangen und senden
|
148 | SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // STM32F407VGT ist der Master und AD7680 der Slace
|
149 | SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // Es werden 24 Bit's vom AD7680 ausgegeben 000016_Bit_Sample_Value0000, daher 3 x 8 Bit Packete
|
150 | SPI_InitStructure.SPI_DataSize = SPI_FirstBit_MSB; // Der AD7680 überträgt die Daten als "MSB first"
|
151 | SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // Clock Polarity (CPOL) = 1
|
152 | SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // Clock Phase (CPHA) = 1 (entspricht hier CPHA_2Edge !)
|
153 | SPI_InitStructure.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // NSS Pin als GPIO Pin einstellen und intern auf High setzen
|
154 |
|
155 | SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_64; // SCLK=42MHz/64=656.2kHz APB1=42 MHz, SYSCLK=168 MHz
|
156 | SPI_InitStructure.SPI_CRCPolynomial = 0; // kein CRC bilden
|
157 |
|
158 | SPI_Init(SPI2, &SPI_InitStructure); // SPI2 Interface initialisieren
|
159 | SPI_CalculateCRC(SPI2, DISABLE); // CRC Berechnung deaktivieren
|
160 |
|
161 | SPI_Cmd(SPI2,ENABLE); // SPI2 Interface aktivieren
|
162 | }
|
163 |
|
164 |
|
165 | void EnableRCC(void)
|
166 | {
|
167 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // Takt für die GPIOA's aktivieren
|
168 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // Takt für die GPIOB's aktivieren
|
169 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); // Takt für die GPIOC's aktivieren
|
170 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); // Takt für die GPIOD's aktivieren
|
171 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); // Takt für den SPI2 aktivieren
|
172 | }
|
173 |
|
174 |
|
175 | void ConfigGPIO(void)
|
176 | {
|
177 |
|
178 | GPIO_InitTypeDef GPIO_InitStructure;
|
179 |
|
180 |
|
181 | //---------------------------------------------------------------------------------------------------
|
182 | // Pin für die blaue LED (PD15) konfigurieren
|
183 | //---------------------------------------------------------------------------------------------------
|
184 | GPIO_InitStructure.GPIO_Pin = LED_Blue;
|
185 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
186 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
187 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
188 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
189 |
|
190 | GPIO_Init(GPIOD, &GPIO_InitStructure);
|
191 | //---------------------------------------------------------------------------------------------------
|
192 |
|
193 |
|
194 |
|
195 | //---------------------------------------------------------------------------------------------------
|
196 | // SCLK Ausgang konfigurieren
|
197 | // -restliche Einstellungen können aus der LED Konfiguration übernommen werden.
|
198 | //---------------------------------------------------------------------------------------------------
|
199 | GPIO_InitStructure.GPIO_Pin = SCLK;
|
200 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // SCLK, also PB10, auf Alternativ-Modus umschalten
|
201 |
|
202 | GPIO_Init(GPIOB, &GPIO_InitStructure);
|
203 |
|
204 | GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2); // PB10 mit dem SPI2 Controller verbinden
|
205 | // PB10 ist nun die SCLK Quelle
|
206 | //---------------------------------------------------------------------------------------------------
|
207 |
|
208 |
|
209 |
|
210 | //---------------------------------------------------------------------------------------------------
|
211 | // SDATA (MISO) und MOSI konfigurieren
|
212 | //---------------------------------------------------------------------------------------------------
|
213 | GPIO_InitStructure.GPIO_Pin = SDATA | MOSI;
|
214 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // PC2 und PC3 auf Alternativ-Modus umschalten
|
215 |
|
216 | GPIO_Init(GPIOC, &GPIO_InitStructure);
|
217 |
|
218 | GPIO_PinAFConfig(GPIOC, GPIO_PinSource2, GPIO_AF_SPI2); // PC2 mit SDATA(MISO) von SPI2 verbinden
|
219 | GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_SPI2); // PC3 mit MOSI von SPI2 verbinden
|
220 | //---------------------------------------------------------------------------------------------------
|
221 |
|
222 |
|
223 |
|
224 | //---------------------------------------------------------------------------------------------------
|
225 | // ChipSelect(CS) bzw. SlaveSelect(SS) konfigurieren
|
226 | //---------------------------------------------------------------------------------------------------
|
227 | GPIO_InitStructure.GPIO_Pin = CS;
|
228 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // Normaler Ausgang...
|
229 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // PullUp aktivieren
|
230 | GPIO_Init(GPIOA, &GPIO_InitStructure);
|
231 |
|
232 | GPIO_SetBits(GPIOA,CS); // ChipSelect sofort auf High setzen,
|
233 | // damit der AD7680 nicht gleich anfängt
|
234 | // zu "arbeiten".
|
235 | //---------------------------------------------------------------------------------------------------
|
236 | }
|