Forum: Mikrocontroller und Digitale Elektronik STM32F4 - SPI und DMA


von Op C. (opcode_x64)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
von Op C. (opcode_x64)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Op C. (opcode_x64)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von Op C. (opcode_x64)


Lesenswert?

Guten Tag A.K.,

vielen Dank für den Code. Ich werde diesen jetzt erst mal studieren.

von Op C. (opcode_x64)


Lesenswert?

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
Noch kein Account? Hier anmelden.