Sehr geehrte Forumuser, ich beschäftige mich zur Zeit mit SPI und DMA auf dem STM32F4 Discovery Board. Ich habe eine allgemeine Frage: Ist es möglich SPI und DMA nur im Datenempfangmodus zu betreiben ? D.h. ich verschicke die Daten ohne DMA, also mit SPI2->DR = .... empfange sie aber mit DMA ?! Oder muss ich den Datentransfer zum Slave (Master ist der STM32F407) ebenfalls mit DMA ausführen ? Danke.
Tx und Rx sind bei SPI technisch gekoppelt. Wenn der Master ein Byte empfangen will, dann muss er dazu eines senden. Auch wenn da nichts Sinnvolles drinstehen sollte. Wenn der Inhalt von Tx keine Rolle spielt, dann kannst du den dazu gehörenden DMA-Kanal aber auf nichtinkrementierende Speicheradresse einstellen. Umgekehrt ebenso - das reale Ende einer Tx-Übertragung kriegt man bei SPI mit DMA ohnehin nur dadurch raus, indem man auf das Ende des Rx-Kanals wartet (jedenfalls bei den F1xx). Wenn das die falsche Antwort war, dann solltest du etwas mehr drüber verraten, um was es geht.
:
Bearbeitet durch User
Hallo A.K., danke für deine Antwort. Ich versuche dieses Programm: Beitrag "AD7680 (SPI) + STM32F4Discovery" auf DMA umzubauen. Ich möchte nicht nur ein Abtastwert, sondern 10k oder 20k Werte abtasten per DMA schnell "wegspeichern". Ohne DMA Version kann ich einen Abtastwert ohne Probleme auslesen. Ich möchte quasi erstmal eine gewisse Anzahl von Bytes, sagen wir mal, 1000 per DMA von dem Analog Digital Umsetzer auslesen. Ich muss den DMA so konfigurieren, dass dieser jedesmal wenn ich etwas ausgelesen habe, wieder etwas gesendet wird, sonst geht das auslesen ja nicht, wie du beschrieben hast.
Wie soll das zeitlich ablaufen? Nonstop, oder in kontrolliertem Zeitraster? Grundprinzip: Je einen DMA Kanal für Rx und Tx auf den Speicherblock für die zu empfangenen Daten programmieren, N Bytes. Was dabei gesendet wird ist ja wohl egal. Der Rx DMA Kanal triggert auf den SPI Empfang. Für nonstop Modus triggert der Tx DMA Kanal auf Tx vom SPI. Für Zeitraster-Modus triggert der Tx DMA Kanal auf einen Timer. Jedes mal wenn ein Tx DMA Byte im SPI landet und rausgeschoben wird kommt eines retour und wird per Rx DMA im Block gespeichert. Das Tx DMA dient hier nur zur Taktung. Läuft so völlig automatisch ab.
Hallo A.K., danke für die schnelle Rückmeldung. Hättest du eventuell ein Minimal-Beispiel oder eine Art Pseudo-Code für dein "Grundprinzip" ? Danke
Testcode für SPI mit DMA, vom STM32F103. Verwendet Teile eigener Umgebung und einige eigene Defines der Peripherie, also versuch gar nicht erst, ihn direkt zu verwenden.
1 | void
|
2 | spi_init(int size, int mode) |
3 | {
|
4 | // enable DMA1, SPI2 and PortB clocks
|
5 | BBPeriphMask(RCC->AHBENR, RCC_AHBENR_DMA1EN) = 1; |
6 | BBPeriphMask(RCC->APB1ENR, RCC_APB1ENR_SPI2EN) = 1; |
7 | BBPeriphMask(RCC->APB2ENR, RCC_APB2ENR_IOPBEN) = 1; |
8 | |
9 | // GPIOB:
|
10 | // 9 = IRQ, port input with pullup
|
11 | // 12 = SS, port output
|
12 | // 13 = SCK, alternate output
|
13 | // 14 = MISO, alternate input
|
14 | // 15 = MOSI, alternate output
|
15 | gpio_config(GPIOB, 1<<9, GPIO_Mode_Input | GPIO_Input_Pullup); |
16 | gpio_config(GPIOB, 1<<12, GPIO_Mode_Output50MHz | GPIO_Output_PushPull); |
17 | gpio_config(GPIOB, 1<<13|1<<15, GPIO_Mode_Output50MHz | GPIO_AltOut_PushPull); |
18 | gpio_config(GPIOB, 1<<14, GPIO_Mode_Input | GPIO_Input_Pullup); |
19 | |
20 | // DMA:
|
21 | // 4 = RX
|
22 | // 5 = TX
|
23 | DMA1_Channel4->CCR = DMA_CCR_DIR_per2mem |
24 | | DMA_CCR_MINC |
25 | | DMA_CCR_PSIZE_16bits |
26 | | (size==16 ? DMA_CCR_MSIZE_16bits : DMA_CCR_MSIZE_8bits) |
27 | | DMA_CCR_PL_high |
28 | | DMA_CCR_TCIE; |
29 | DMA1_Channel5->CCR = DMA_CCR_DIR_mem2per |
30 | | DMA_CCR_MINC |
31 | | DMA_CCR_PSIZE_16bits |
32 | | (size==16 ? DMA_CCR_MSIZE_16bits : DMA_CCR_MSIZE_8bits) |
33 | | DMA_CCR_PL_low; |
34 | DMA1_Channel4->CPAR = (unsigned)&SPI2->DR; |
35 | DMA1_Channel5->CPAR = (unsigned)&SPI2->DR; |
36 | |
37 | SPI2->CR1 = (size==16 ? SPI_CR1_DFF_16bit : SPI_CR1_DFF_8bit) |
38 | | SPI_CR1_MSBFIRST |
39 | | SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI |
40 | | SPI_CR1_SPE | SPI_CR1_MODE(mode) |
41 | | SPI_CR1_BR_by4; |
42 | SPI2->CR2 = SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN; |
43 | }
|
44 | |
45 | unsigned
|
46 | spi_transfer(volatile void *data, unsigned count) |
47 | {
|
48 | GPIOB->BRR = 1<<12; // activate SS |
49 | |
50 | DMA1_Channel4->CMAR = (unsigned)data; // setup memory buffer |
51 | DMA1_Channel5->CMAR = (unsigned)data; |
52 | DMA1_Channel4->CNDTR = count; |
53 | DMA1_Channel5->CNDTR = count; |
54 | |
55 | BBPeriphMask(DMA1_Channel4->CCR, DMA_CCR_EN) = 1; // enable RX DMA |
56 | BBPeriphMask(DMA1_Channel5->CCR, DMA_CCR_EN) = 1; // enable TX DMA |
57 | |
58 | while (!(DMA1->ISR & DMA_ISR_TCIF4)) ; // wait until RX DMA complete |
59 | DMA1->IFCR = DMA_IFCR_CGIF4 | DMA_IFCR_CGIF5; // clear DMA interrupt flags |
60 | |
61 | BBPeriphMask(DMA1_Channel4->CCR, DMA_CCR_EN) = 0; // disable RX DMA |
62 | BBPeriphMask(DMA1_Channel5->CCR, DMA_CCR_EN) = 0; // disable TX DMA |
63 | |
64 | GPIOB->BSRR = 1<<12; // deactivate SS |
65 | }
|
66 | |
67 | volatile uint8_t buffer[2]; |
68 | |
69 | int
|
70 | main(void) |
71 | {
|
72 | rcc_clock(); |
73 | usart_init(); |
74 | systick_init(F_HCLK / 100); |
75 | spi_init(8, 0); |
76 | |
77 | for (unsigned v = 0x0001;;) { |
78 | printf("%04X =>", v); |
79 | |
80 | buffer[0] = v; |
81 | buffer[1] = v >> 8; |
82 | spi_transfer(buffer, 2); |
83 | printf(" %02X%02X\n", buffer[1], buffer[0]); |
84 | |
85 | v <<= 1; |
86 | if (!(v & 0xFFFF)) |
87 | v = 0x0001; |
88 | delay_ms(500); |
89 | }
|
90 | }
|
:
Bearbeitet durch User
Guten Tag A.K., vielen Dank für den Code. Ich werde diesen jetzt erst mal studieren.
Ich frage mich (seit gestern :-)...), warum die Interrupt Handler z.B. der zum Empfangen, also Stream3, nie auslöst ?!. Versteh ich das richtig, dass der Interrupt Handler für Stream3, der ja hier für SPI2 RX steht, dann auslöst, wenn der Datentransfer von Peripherie zum Speicher beendet wurde, also alle Bytes empfangen worden sind. Hier der Code:
1 | //---------------------------------------------------------------------------------------------------
|
2 | // Includes
|
3 | //---------------------------------------------------------------------------------------------------
|
4 | #include <stdio.h> |
5 | #include "stm32f4xx_dma.h" |
6 | #include "stm32f4xx_rcc.h" |
7 | #include "stm32f4xx_gpio.h" |
8 | #include "stm32f4xx_spi.h" |
9 | #include "misc.h" |
10 | |
11 | //---------------------------------------------------------------------------------------------------
|
12 | // Defines
|
13 | //---------------------------------------------------------------------------------------------------
|
14 | #define LED_GREEN GPIO_Pin_12 // Grün auf PD12
|
15 | #define LED_ORANGE GPIO_Pin_13 // Orange auf PD13
|
16 | #define LED_RED GPIO_Pin_14 // Rot auf PD14
|
17 | #define LED_BLUE GPIO_Pin_15 // Blaue auf PD15
|
18 | |
19 | #define SCLK GPIO_Pin_10 // PB10 // Takt-Ausgang für SPI
|
20 | #define SDATA GPIO_Pin_2 // PC2 // Datenleitung für die Samples bzw. MISO
|
21 | #define MOSI GPIO_Pin_3 // PC3 // MOSI; existiert in diesem Beispiel nicht
|
22 | #define CS GPIO_Pin_3 // PA3 // ChipSelect (auch SlaveSelect genannt)
|
23 | |
24 | #define ADC_RES 65535 // Der AD7680 hat eine Auflösung von 16 Bit: (2^16)-1=65535 Abstufungen
|
25 | #define VREF 2.94 // Referenzsspannung des A-D Umsetzer ist bei beim AD7680 die Versorgungsspannung Vss
|
26 | // Die Versorgungsspannung des AD-Umsetzer wird dem Vdd Pin des STM32F4 Discovery Boards
|
27 | // entnommen, die bei USB Speisung c.a. 2.94 V beträgt (Schutzdioden auf dem Board...).
|
28 | |
29 | #define SPI2_DMA DMA1 // DMA Controller für den SPI2, S. 304, Tab. 43 im Reference Manual RM0090 => http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf
|
30 | #define SPI2_TX_DMA_CHANNEL DMA_Channel_0 // DMA Kanal für den SPI2 Datenversand, S. 304, Tab. 43 im Reference Manual RM0090
|
31 | #define SPI2_RX_DMA_CHANNEL DMA_Channel_0 // DMA Kanal für den SPI2 Datenempfang, S. 304, Tab. 43 im Reference Manual RM0090
|
32 | #define SPI2_TX_DMA_STREAM DMA1_Stream4 // DMA Stream für den SPI2 Datenversand, S. 304, Tab. 43 im Reference Manual RM0090
|
33 | #define SPI2_RX_DMA_STREAM DMA1_Stream3 // DMA Stream für den SPI2 Datenempfang, S. 304, Tab. 43 im Reference Manual RM0090
|
34 | #define SPI2_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF4 // Interrupt-Flag für den Transfer Complete von Stream 4 des SPI2 Datenversands
|
35 | #define SPI2_RX_DMA_FLAG_TCIF DMA_FLAG_TCIF3 // Interrupt-Flag für den Transfer Complete von Stream 3 des SPI2 Datenempfangs
|
36 | #define SPI2_RX_DMA_IRQHANDLER DMA1_Stream3_IRQHandler // Interrupt-Handler für SPI2_RX_DMA
|
37 | #define SPI2_TX_DMA_IRQHANDLER DMA1_Stream4_IRQHandler // Interrupt-Handler für SPI2_TX_DMA
|
38 | |
39 | |
40 | #define SAMPLE_COUNT 3 // Anzahl der gewünschten Samples d.h. die Größe des SAMPLES Arrays, wo die Abtastwerte gespeichert werden
|
41 | |
42 | #define SPI2_DR_ADDRESS ((uint32_t)&(SPI2->DR)) // Adresse des Datenregisters von SPI2. Wird für die Konfiguration des DMAs als 32 Bit Adresse übergeben.
|
43 | |
44 | |
45 | |
46 | |
47 | //---------------------------------------------------------------------------------------------------
|
48 | // Prototpes
|
49 | //---------------------------------------------------------------------------------------------------
|
50 | void EnableRCC(void); |
51 | void ConfigGPIO(void); |
52 | void ConfigSPI(void); |
53 | void ConfigDMA(void); |
54 | void ConfigNVIC(void); |
55 | uint8_t ReadSPI(void); |
56 | void SPI2_RX_DMA_IRQHANDLER(void); |
57 | void SPI2_TX_DMA_IRQHANDLER(void); |
58 | //---------------------------------------------------------------------------------------------------
|
59 | // Global Variables
|
60 | //---------------------------------------------------------------------------------------------------
|
61 | __IO uint8_t SAMPLES[SAMPLE_COUNT]; |
62 | __IO uint8_t DUMMYDATA[] = {0xAA, 0xAA, 0xAA}; |
63 | |
64 | volatile int n; |
65 | volatile int i; |
66 | |
67 | int main(void) |
68 | {
|
69 | 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 |
70 | unsigned sample_value = 0; // Hier wird der 16 Bit Abtastwert gespeichert |
71 | float voltage_value = 0; // Der berechnete Spannungswert wird hier gespeichert |
72 | int i = 0; |
73 | |
74 | //DUMMYDATA[] // "dummy" Daten für SPI2_DMA_TX
|
75 | |
76 | /*!! Wichtig !!*/
|
77 | SystemInit(); // ggf. nötig, damit die Takteinstellungen richtig übernommen werden |
78 | |
79 | /* Deinitialisation */
|
80 | DMA_DeInit(SPI2_RX_DMA_STREAM); // SPI2_RX_DMA deinitialisieren |
81 | DMA_DeInit(SPI2_TX_DMA_STREAM); // SPI2_TX_DMA deinitialisieren |
82 | SPI_I2S_DeInit(SPI2); // SPI2 deinitialisieren |
83 | |
84 | /* Konfiguration der Peripherien */
|
85 | EnableRCC(); // Takt für die benötigten Peripherien einschalten |
86 | ConfigGPIO(); // Die GPIO Pins konfigurieren |
87 | ConfigDMA(); // DMA1 für SPI2 Datenempfang konfigurieren |
88 | ConfigNVIC(); // Interrupt für DMA1 konfigurieren |
89 | ConfigSPI(); // SPI2 Controller konfigurieren |
90 | |
91 | DMA_Cmd(SPI2_TX_DMA_STREAM, DISABLE); // DMA1 mit Stream4 deaktivieren |
92 | DMA_Cmd(SPI2_RX_DMA_STREAM, DISABLE); // DMA1 mit Stream3 deaktivieren |
93 | |
94 | SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE); // SPI2 Datenempfang Request aktivieren |
95 | SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE); // SPI2 Datenversand Request aktivieren |
96 | |
97 | SPI_Cmd(SPI2, ENABLE); // SPI2 Interface aktivieren |
98 | |
99 | GPIO_SetBits(GPIOD,LED_BLUE); // blaue LED einschalten (Lebenszeichen) |
100 | |
101 | //DMA_SetCurrDataCounter(SPI2_TX_DMA_STREAM,3);
|
102 | |
103 | GPIO_ResetBits(GPIOA,CS); // ChipSelect Ausgang auf Low setzen, damit der AD7680 mit Abtastvorgang anfängt |
104 | DMA_Cmd(SPI2_RX_DMA_STREAM, ENABLE); // DMA1 mit Stream3 aktivieren |
105 | DMA_Cmd(SPI2_TX_DMA_STREAM, ENABLE); // DMA1 mit Stream4 aktivieren |
106 | |
107 | while(1) |
108 | {
|
109 | //GPIO_ResetBits(GPIOA,CS); // ChipSelect Ausgang auf Low setzen, damit der AD7680 mit Abtastvorgang anfängt
|
110 | for(i=0; i<3; i++) |
111 | {
|
112 | // raw_bytes[i]=ReadSPI(); // Alle drei "Roh-Bytes" in das Array speichern
|
113 | }
|
114 | //GPIO_SetBits(GPIOA,CS); // ChipSelect Ausgang auf High setzen, damit der AD7680 mit Abtastvorgang aufhört
|
115 | |
116 | //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
|
117 | // relevanten 16 Bit Daten (Abtastwert) heranzukommen.
|
118 | //voltage_value=(VREF/ADC_RES)*sample_value; // Spannungswert aus dem Abtastwert (16 Bit ADC Wert) berechnen
|
119 | //i++;
|
120 | }
|
121 | }
|
122 | |
123 | |
124 | uint8_t ReadSPI(void) |
125 | {
|
126 | SPI2->DR = 0xAA; // "dummy" Daten schreiben, dies ist nötig, damit überhaupt Empfangen werden kann. |
127 | while( !(SPI2->SR & SPI_I2S_FLAG_TXE)); // warten bis der Sendevorgang abgeschlossen ist |
128 | while( !(SPI2->SR & SPI_I2S_FLAG_RXNE)); // warten bis der Datenempfang abgeschlossen ist |
129 | while( SPI2->SR & SPI_I2S_FLAG_BSY); // warten bis der SPI2 nicht mehr "beschäftigt" ist. |
130 | return SPI2->DR; // Daten im SPI2 Datenregister als Rückgabewert ausgeben |
131 | }
|
132 | |
133 | |
134 | void ConfigSPI() |
135 | {
|
136 | SPI_InitTypeDef SPI_InitStructure; |
137 | |
138 | SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // Daten empfangen und senden |
139 | SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // STM32F407VGT ist der Master und AD7680 der Slace |
140 | 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 |
141 | SPI_InitStructure.SPI_DataSize = SPI_FirstBit_MSB; // Der AD7680 überträgt die Daten als "MSB first" |
142 | SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // Clock Polarity (CPOL) = 1 |
143 | SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // Clock Phase (CPHA) = 1 (entspricht hier CPHA_2Edge !) |
144 | SPI_InitStructure.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // NSS Pin als GPIO Pin einstellen und intern auf High setzen |
145 | |
146 | SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; // SCLK=42MHz/64=656.2kHz APB1=42 MHz, SYSCLK=168 MHz |
147 | SPI_InitStructure.SPI_CRCPolynomial = 0; // kein CRC bilden |
148 | |
149 | SPI_Init(SPI2, &SPI_InitStructure); // SPI2 Interface initialisieren |
150 | SPI_CalculateCRC(SPI2, DISABLE); // CRC Berechnung deaktivieren |
151 | |
152 | }
|
153 | |
154 | |
155 | void EnableRCC(void) |
156 | {
|
157 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // Takt für die GPIOA's aktivieren |
158 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // Takt für die GPIOB's aktivieren |
159 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); // Takt für die GPIOC's aktivieren |
160 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); // Takt für die GPIOD's aktivieren |
161 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); // Takt für den SPI2 aktivieren |
162 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); // Takt für DMA1 aktivieren |
163 | }
|
164 | |
165 | |
166 | void ConfigGPIO(void) |
167 | {
|
168 | GPIO_InitTypeDef GPIO_InitStructure; |
169 | |
170 | |
171 | //---------------------------------------------------------------------------------------------------
|
172 | // Pin für die blaue LED (PD15) konfigurieren
|
173 | //---------------------------------------------------------------------------------------------------
|
174 | GPIO_InitStructure.GPIO_Pin = LED_BLUE | LED_ORANGE | LED_GREEN; |
175 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; |
176 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; |
177 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; |
178 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; |
179 | |
180 | GPIO_Init(GPIOD, &GPIO_InitStructure); |
181 | //---------------------------------------------------------------------------------------------------
|
182 | |
183 | //---------------------------------------------------------------------------------------------------
|
184 | // SCLK Ausgang konfigurieren
|
185 | // -restliche Einstellungen können aus der LED Konfiguration übernommen werden.
|
186 | //---------------------------------------------------------------------------------------------------
|
187 | GPIO_InitStructure.GPIO_Pin = SCLK; |
188 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // SCLK, also PB10, auf Alternativ-Modus umschalten |
189 | |
190 | GPIO_Init(GPIOB, &GPIO_InitStructure); |
191 | |
192 | GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2); // PB10 mit dem SPI2 Controller verbinden |
193 | // PB10 ist nun die SCLK Quelle
|
194 | //---------------------------------------------------------------------------------------------------
|
195 | |
196 | //---------------------------------------------------------------------------------------------------
|
197 | // SDATA (MISO) und MOSI konfigurieren
|
198 | //---------------------------------------------------------------------------------------------------
|
199 | GPIO_InitStructure.GPIO_Pin = SDATA | MOSI; |
200 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // PC2 und PC3 auf Alternativ-Modus umschalten |
201 | |
202 | GPIO_Init(GPIOC, &GPIO_InitStructure); |
203 | |
204 | GPIO_PinAFConfig(GPIOC, GPIO_PinSource2, GPIO_AF_SPI2); // PC2 mit SDATA(MISO) von SPI2 verbinden |
205 | GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_SPI2); // PC3 mit MOSI von SPI2 verbinden |
206 | //---------------------------------------------------------------------------------------------------
|
207 | |
208 | //---------------------------------------------------------------------------------------------------
|
209 | // ChipSelect(CS) bzw. SlaveSelect(SS) konfigurieren
|
210 | //---------------------------------------------------------------------------------------------------
|
211 | GPIO_InitStructure.GPIO_Pin = CS; |
212 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // Normaler Ausgang... |
213 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // PullUp aktivieren |
214 | GPIO_Init(GPIOA, &GPIO_InitStructure); |
215 | |
216 | GPIO_SetBits(GPIOA,CS); // ChipSelect sofort auf High setzen, |
217 | // damit der AD7680 nicht gleich anfängt
|
218 | // zu "arbeiten".
|
219 | //---------------------------------------------------------------------------------------------------
|
220 | }
|
221 | |
222 | |
223 | void ConfigDMA(void) |
224 | {
|
225 | |
226 | DMA_InitTypeDef DMA_InitStructure; |
227 | |
228 | /* Konfiguration für SPI_DMA_RX und SPI_DMA_TX */
|
229 | DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // Normaler Modus: Kein Datentransfer mehr, wenn der Speicher SAMPLES voll ist bzw. SAMPLE_COUNT erreicht wurde |
230 | DMA_InitStructure.DMA_Priority = DMA_Priority_High; // Prioriät des Datenflusses von Kanal 0 auf hoch setzen. |
231 | DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // Kein First In First Out aktivieren |
232 | DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; |
233 | DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; |
234 | DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; |
235 | DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SPI2_DR_ADDRESS; // Adresse des Datenregisters der jeweiligen Peripherie, hier SPI2. |
236 | DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Peripherieadresse nicht inkrementieren. |
237 | DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // Datengröße in der Peripherie, also des SPI's. Entspricht hier 32-Bit. |
238 | DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // Datengröße der Speicherstelle. Entspricht hier ebenfals 32-Bit. |
239 | |
240 | /* Konfiguration nur für SPI2_DMA_TX */
|
241 | DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&DUMMYDATA; // Adresse der "Dummy-Daten", die verschickt werden müssen, damit wir überhaupt was empfange können. |
242 | DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Datenflussrichtung: von dem Speicher zur Peripherie, da wir Daten ("Dummy-Daten") in den SPI2 Datenregister laden wollen, um diese zu verschicken. |
243 | DMA_InitStructure.DMA_BufferSize = 3; // Die Größe des Speichers der "Dummy-Daten", hier 1, da wir immer nur die gleihen "Dummy-Daten" verschicken müssen. |
244 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Speicherinkrementierung deaktivieren. Es gibt nur ein "Dummy-Daten" Eintrag im Array DUMMYDATA. |
245 | DMA_InitStructure.DMA_Channel = SPI2_TX_DMA_CHANNEL; // siehe oben in den "Defines" |
246 | DMA_Init(SPI2_TX_DMA_STREAM, &DMA_InitStructure); // SPI2 hängt am ABP1 und dafür ist der DMA1 zuständig. (S. 18, Fig. 5 Datenblatt des STM32F407VGT6) |
247 | // Der Datenversand (SPI2_DMA_TX) erfolgt über Stream 4. (S. 18, Fig. 5 Datenblatt des STM32F407VGT6)
|
248 | // http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00037051.pdf
|
249 | |
250 | /* Konfiguration nur für SPI_DMA_RX */
|
251 | DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; |
252 | DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&SAMPLES; // Der Speicher bzw. die Variable(Array) wo die Abtastwerte gespeichert werden sollen. Muss auch als 32-Bit angegeben werden. |
253 | DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Datenflussrichtung: von der Peripherie zum Speicher, also wir lesen aus dem SPI2 Datenregister in die Variable/Array SAMPLES, die im RAM ist. |
254 | DMA_InitStructure.DMA_BufferSize = SAMPLE_COUNT; // Die Größe des Speichers, hier die Anzahl der gewünschten Abtastwerte (Samples) |
255 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Speicherinkrementierung aktivieren d.h. die neuen Daten werden nacheinander in das Array (SAMPLES) gespeichert. |
256 | DMA_InitStructure.DMA_Channel = SPI2_RX_DMA_CHANNEL; // siehe oben in den "Defines" |
257 | DMA_Init(SPI2_RX_DMA_STREAM, &DMA_InitStructure); // SPI2 hängt am ABP1 und dafür ist der DMA1 zuständig. (S. 18, Fig. 5 Datenblatt des STM32F407VGT6) |
258 | // Der Datenversand (SPI2_DMA_RX) erfolgt über Stream 3. (S. 18, Fig. 5 Datenblatt des STM32F407VGT6)
|
259 | // http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00037051.pdf
|
260 | |
261 | DMA_ITConfig(SPI2_TX_DMA_STREAM, DMA_IT_TC, ENABLE); // Interrupt Routine ausführen, wenn der Datentransfer des DMA beendet ist. |
262 | DMA_ITConfig(SPI2_RX_DMA_STREAM, DMA_IT_TC, ENABLE); // Interrupt Routine ausführen, wenn der Datentransfer des DMA beendet ist. |
263 | }
|
264 | |
265 | |
266 | |
267 | void ConfigNVIC(void) |
268 | {
|
269 | NVIC_InitTypeDef NVIC_InitStructure; |
270 | |
271 | NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn; // IRQ Kanal (Stream3 von DMA1) angeben |
272 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // Präemptiv Priorität-Level auf 0 (Höchste Prioriät) (ist eigentlich egal, da wir keinen anderen Interrupt konfiguriert haben ?!) |
273 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // Sub Priorität ebenfalls auf 0 setzen |
274 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // Interrupt aktivieren |
275 | NVIC_Init(&NVIC_InitStructure); |
276 | }
|
277 | |
278 | |
279 | /* Interrupt Handler für SPA_DMA_RX */
|
280 | void SPI2_RX_DMA_IRQHANDLER(void) |
281 | {
|
282 | |
283 | GPIO_SetBits(GPIOD,LED_GREEN); |
284 | |
285 | //GPIO_SetBits(GPIOA,CS);
|
286 | |
287 | //DMA_ClearFlag(SPI2_RX_DMA_STREAM, SPI2_RX_DMA_FLAG_TCIF);
|
288 | |
289 | /*if(DMA_GetITStatus(SPI2_RX_DMA_STREAM, SPI2_RX_DMA_FLAG_TCIF) == SET)
|
290 | {
|
291 | n++;
|
292 | // GPIO_SetBits(GPIOD,LED_ORANGE);
|
293 | // GPIO_SetBits(GPIOA,CS);
|
294 | // DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
|
295 | DMA_ClearFlag(SPI2_RX_DMA_STREAM, SPI2_RX_DMA_FLAG_TCIF);
|
296 | }*/
|
297 | }
|
298 | |
299 | |
300 | /* Interrupt Handler für SPA_DMA_TX */
|
301 | void SPI2_TX_DMA_IRQHANDLER(void) |
302 | {
|
303 | GPIO_SetBits(GPIOD,LED_ORANGE); |
304 | |
305 | // GPIO_SetBits(GPIOA,CS);
|
306 | // GPIO_SetBits(GPIOD,LED_ORANGE);
|
307 | /* if(DMA_GetITStatus(SPI2_TX_DMA_STREAM, SPI2_TX_DMA_FLAG_TCIF) == SET)
|
308 | {
|
309 | n++;
|
310 | //GPIO_SetBits(GPIOD,LED_ORANGE);
|
311 | //GPIO_SetBits(GPIOA,CS);
|
312 | //DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
|
313 | DMA_ClearFlag(SPI2_TX_DMA_STREAM, SPI2_TX_DMA_FLAG_TCIF);
|
314 | }*/
|
315 | }
|
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.