Forum: Mikrocontroller und Digitale Elektronik STM32F207: SPI Kommunikation mit DMA


von paul (Gast)


Lesenswert?

Hallo, für den Datenaustausch zwischen STM32F207 Mikrocontroller und 
einem FPGA benutzte ich die SPI Schnittstelle. Das Senden und Empfangen 
mittels Interrptroutinen funktioniert. Ich kann 16 Bit senden und 
empfange auch 16 Bit. Wenn ich nun eine Anfrage vom STM32 an den FPGA 
via SPI versende soll der FPGA mehrere 16 Bit Datenwerte an den STM32 
senden. Dazu bräuchte ich noch den DMA, der die ankommenden Daten in 
einen Puffer im DMA ablegen soll. Bei der Implementierung des DMA 
zusammen mit der SPI Schnittstelle auf dem STM32 habe ich Probleme. Wie 
könnte die Initialisierung des STM32 dazu aussehen ? Für das Empfangen 
soll ein Interrupthandler verwendet werden.

von Mike R. (thesealion)


Lesenswert?

Hier einmal einige Ausschnitte von meinem SPI Treiber: vielleicht hilft 
er dir ja weiter:

Init:
1
      // recieve
2
   DMA_DeInit(DMA1_Channel2);
3
   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x4001300C;
4
   DMA_InitStructure.DMA_MemoryBaseAddr = NULL;
5
   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
6
   DMA_InitStructure.DMA_BufferSize = 0;
7
   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
8
   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
9
   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
10
   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
11
   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
12
   DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
13
   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
14
   DMA_Init(DMA1_Channel2, &DMA_InitStructure);
15
16
   // Enable the SPI DMA RX Interrupt
17
   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
18
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
19
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
20
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
21
   NVIC_Init(&NVIC_InitStructure); 
22
23
   // initialize SPI 
24
   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
25
   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
26
   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
27
   SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
28
   SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
29
   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
30
   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
31
   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
32
   SPI_InitStructure.SPI_CRCPolynomial = 7;
33
   SPI_Init(SPI1, &SPI_InitStructure);
34
35
   // Enable SPI DMA requests 
36
   SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);  
37
   SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);  
38
   
39
   // Enable SPI
40
   SPI_Cmd(SPI1, ENABLE);

recieve function
1
bool spiReadBytes(enum spiDevices target, uint8_t dataIn[], uint16_t countIn) {
2
   
3
   if (spiBusy == TRUE) {
4
      return FALSE;
5
   }
6
  
7
   // mark bus as busy 
8
   spiBusy = TRUE;
9
10
   if (selectSpiDevice(target) == FALSE) {
11
      return FALSE;
12
   }
13
   
14
   //increment only the destination buffer, 
15
   DMA1_Channel2->CCR |=  DMA_MemoryInc_Enable;
16
   DMA1_Channel3->CCR &= ~DMA_MemoryInc_Enable;
17
   
18
   // we will transmit only 0x00   
19
   spiDevNull = 0x00;
20
   
21
   //set DMA source address
22
   DMA1_Channel3->CMAR = (uint32_t) &spiDevNull;        
23
   DMA1_Channel2->CMAR = (uint32_t) dataIn;   
24
   
25
   // in duplex we will also recieve the same number of data
26
   DMA1_Channel2->CNDTR = countIn;
27
   DMA1_Channel3->CNDTR = countIn;
28
29
   //activated SPI DMA TC and Error IRQ   
30
   DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
31
   DMA_ITConfig(DMA1_Channel2, DMA_IT_TE, ENABLE);
32
   DMA_ITConfig(DMA1_Channel3, DMA_IT_TE, ENABLE);   
33
   
34
   // Enable DMA1 Chanel2 and Channel3
35
   DMA_Cmd(DMA1_Channel2, ENABLE);
36
   DMA_Cmd(DMA1_Channel3, ENABLE);
37
        
38
   return TRUE;
39
}

und ein wenig IRQ
1
   // check if the transmission is complete 
2
   if (DMA_GetITStatus(DMA1_IT_TC2) != RESET) {
3
     
4
      // clear Interrupr Flag
5
      DMA_ClearITPendingBit(DMA1_IT_TC2);
6
      
7
      //deactivated DMA TC IRQ   
8
      DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, DISABLE); 
9
   
10
      // Disable DMA1 Channel2 and Channel3
11
      DMA_Cmd(DMA1_Channel2, DISABLE);
12
      DMA_Cmd(DMA1_Channel3, DISABLE);
13
      
14
      // reset all CS Lines      
15
      GPIOA->BSRR = GPIO_Pin_4; // EEPROM
16
      
17
      // mark bus as free
18
      spiBusy = FALSE;
19
   }

von paul (Gast)


Lesenswert?

Hi Mike S.,

vielen Dank für den Code. So wie es aussieht verwendest du ebenfalls das 
Evaluationboard STM3220G-EVAL von STMicroelectronics. Ich benutzte die 
SPI2 Schnittstelle.

Folgende Namen sind bei mir nicht definiert:
--> DMA1_Channel2_IRQn;
--> DMA1_Channel2;
--> DMA_DIR_PeripheralSRC;
--> DMA_M2M_Disable;

Wleche DMA MemoryBaseAddr muss ich hier einstellen ? NULL wird nicht 
akzeptiert.

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

Ab STM32F2xx/4xx heißt das auch nicht mehr "DMA1_Channel..." sondern 
"DMA1_Stream...".

von Mike R. (thesealion)


Lesenswert?

Mein Code ist eine Mischung aus Library Funktionen und direkten Register 
zugriffen.

Die MemoryBaseAddr ist das Ort im Speicher, wo deine Daten 
hingeschrieben werden sollen.
Bei mir wird die erst später mit
1
DMA1_Channel2->CNDTR = countIn;
gesetzt.

Und wie Markus schon feststellte ist der Code nicht für STM32F2... 
geschrieben sondern noch für einen STM32F103. (Allerdings auf einem 
selbst entworfenem Board.

von paul (Gast)


Lesenswert?

Nochmals danke für eure Hilfe. Das mit der SPI/DMA Konfiguration scheint 
nicht so leicht zu sein. Mir würde eine Beispielapplikation für den 
STM32F207 weiterhelfen.

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.