Forum: Mikrocontroller und Digitale Elektronik STM32 DMA SPI SD-Karte


von Stephan (Gast)


Lesenswert?

Ich bin gerade dabei zu versuchen per DMA über SPI auf eine SD-Karte zu 
schreiben. Ich habe meinen aktuellen DMA-Code mit angehängt, da ich 
vermute dort irgendwo Fehler eingebaut zu haben.
Als Fehler bekomme ich von dem FatFs manchmal FR_NO_FILESYSTEM oder 
FR_NOT_READY. Meine Vermutung ist jetzt, dass etwas mit dem Lesen nicht 
zu funktionieren scheint, weil die Karte laut Oszi eigentlich richtig 
antwortet, der MCU dies aber zu ignorieren scheint.

Und in der while-Schleife mit DMA_GetFlagStatus scheint auch ein Fehler 
zu sein, denn dort bleibt er immer hängen, wenn sie nicht auskommentiert 
ist.
1
#define DMA_SPI2_RX_STREAM DMA1_Stream3
2
#define DMA_SPI2_TX_STREAM DMA1_Stream4
3
4
void stm32_dma_transfer(
5
  UINT receive,    /* FALSE for buff->SPI, TRUE for SPI->buff               */
6
  const BYTE *buff,  /* receive TRUE  : 512 byte data block to be transmitted
7
               receive FALSE : Data buffer to store received data    */
8
  UINT btr       /* receive TRUE  : Byte count (must be multiple of 2)
9
               receive FALSE : Byte count (must be 512)              */
10
)
11
{
12
  DMA_InitTypeDef DMA_InitStructure;
13
  WORD rw_workbyte[] = { 0xffff };
14
15
  //enable clock
16
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
17
18
  //start with a blank DMA configuration
19
  DMA_DeInit(DMA_SPI2_RX_STREAM); //SPI-RX
20
  DMA_DeInit(DMA_SPI2_TX_STREAM); //SPI-TX
21
22
  //only these parameters differ from default values
23
  DMA_InitStructure.DMA_Channel        = DMA_Channel_0;
24
  DMA_InitStructure.DMA_PeripheralBaseAddr = (DWORD) & (SPI2->DR);
25
  DMA_InitStructure.DMA_MemoryDataSize    = DMA_MemoryDataSize_Byte;
26
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
27
  DMA_InitStructure.DMA_PeripheralInc     = DMA_PeripheralInc_Disable;
28
  DMA_InitStructure.DMA_BufferSize      = btr;
29
  DMA_InitStructure.DMA_Priority       = DMA_Priority_VeryHigh;
30
  DMA_InitStructure.DMA_Mode          = DMA_Mode_Normal;
31
32
  if (receive){
33
    // DMA1-Channel0-Stream3 configured as SPI2-RX
34
    DMA_InitStructure.DMA_Memory0BaseAddr   = (DWORD)buff;
35
    DMA_InitStructure.DMA_DIR          = DMA_DIR_PeripheralToMemory;
36
    DMA_InitStructure.DMA_MemoryInc      = DMA_MemoryInc_Enable;
37
    DMA_Init(DMA_SPI2_RX_STREAM, &DMA_InitStructure);
38
39
    // DMA1-Channel0-Stream4 configured as SPI2-TX
40
    DMA_InitStructure.DMA_Memory0BaseAddr    = (DWORD)rw_workbyte;
41
    DMA_InitStructure.DMA_DIR          = DMA_DIR_MemoryToPeripheral;
42
    DMA_InitStructure.DMA_MemoryInc      = DMA_MemoryInc_Disable;
43
    DMA_Init(DMA_SPI2_TX_STREAM, &DMA_InitStructure);
44
  }
45
  else {
46
    // DMA1-Channel0-Stream3 configured as SPI2-RX
47
    DMA_InitStructure.DMA_Memory0BaseAddr   = (DWORD)rw_workbyte;
48
    DMA_InitStructure.DMA_DIR          = DMA_DIR_PeripheralToMemory;
49
    DMA_InitStructure.DMA_MemoryInc      = DMA_MemoryInc_Disable;
50
    DMA_Init(DMA_SPI2_RX_STREAM, &DMA_InitStructure);
51
52
    // DMA1-Channel0-Stream4 configured as SPI2-TX
53
    DMA_InitStructure.DMA_Memory0BaseAddr    = (DWORD)buff;
54
    DMA_InitStructure.DMA_DIR          = DMA_DIR_MemoryToPeripheral;
55
    DMA_InitStructure.DMA_MemoryInc      = DMA_MemoryInc_Enable;
56
    DMA_Init(DMA_SPI2_TX_STREAM, &DMA_InitStructure);
57
  }
58
59
  //Enable DMA RX/TX
60
  DMA_Cmd(DMA_SPI2_RX_STREAM, ENABLE); //SPI-RX
61
  DMA_Cmd(DMA_SPI2_TX_STREAM, ENABLE); //SPI-TX
62
63
  /* Enable SPI TX/RX request */
64
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
65
66
  /* Wait until DMA1_Channel 2 Receive Complete */
67
  //while (DMA_GetFlagStatus(DMA_SPI2_RX_STREAM, DMA_FLAG_TCIF4) == RESET) { ; }
68
69
  //Disable DMA RX/TX
70
  DMA_Cmd(DMA_SPI2_RX_STREAM, DISABLE); //SPI-RX
71
  DMA_Cmd(DMA_SPI2_TX_STREAM, DISABLE); //SPI-TX
72
73
  /* Disable SPI RX/TX request */
74
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, DISABLE);
75
}

von Moritz M. (moritz_m35)


Lesenswert?

Hallo,

guck dir das mal an:
http://mikrocontroller.bplaced.net

Da gibt es auch was für sd karte und fat und ich galube auch mit dma. 
Kann ich nur empfehlen!

Moritz

von Jim M. (turboj)


Lesenswert?

Du solltest vielleicht für TX und RX nicht denselben DMA Kanal benutzen. 
Da brauchst Du jeweils einen eigenen IMO.

von Torsten S. (tse)


Lesenswert?


von Stephan (Gast)


Lesenswert?

@Jim
also den Kanal habe ich wie im Datenblatt dargestellt belegt, dort ist 
für SPI2-RX/TX nur der Kanal0 und die Streams 3/4 vorgesehen. Daher 
denke ich nicht, dass der Fehler dort liegt.
@Moritz
Die Seite ist sehr interessant, allerdings wird dort nur DMA mit SDIO 
zusammen verwendet und nicht mit SPI.

Ich hab noch einiges ausprobiert, konnte aber bisher den Fehler nicht 
finden. Bin jetzt dabei mal ein einfaches DMA-Beispiel für mich zu 
schreiben, wo ich nur einen Beschleunigungssensor auslesen will. 
Vielleicht bin ich dabei erfolgreicher.

von Stephan (Gast)


Lesenswert?

Hey zusammen,
hab DMA jetzt mit einem einfachen Beispiel zum Laufen bekommen. Dabei 
werden jetzt Daten per SPI an ein Display gesendet. Nach beendeter 
Übertragung wird ein Interrupt ausgelöst, in welchem dann das Chip 
Select zurückgesetzt wird.
Vielleicht hilft mein Code ja anderen beim Verstehen.
1
void DMA_TX(u8* buf, int count){
2
3
  DMA_InitTypeDef DMA_InitStructure_TX;
4
5
  //enable DMA-clock
6
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
7
8
  DMA_DeInit(DMA1_Stream4); // TX-Stream
9
10
  // TX-Configuration
11
  DMA_InitStructure_TX.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI2->DR));
12
  DMA_InitStructure_TX.DMA_Channel = DMA_Channel_0;
13
  DMA_InitStructure_TX.DMA_DIR = DMA_DIR_MemoryToPeripheral;
14
  DMA_InitStructure_TX.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
15
  DMA_InitStructure_TX.DMA_MemoryInc = DMA_MemoryInc_Enable;
16
  DMA_InitStructure_TX.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
17
  DMA_InitStructure_TX.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
18
  DMA_InitStructure_TX.DMA_Mode = DMA_Mode_Normal;
19
  DMA_InitStructure_TX.DMA_Priority = DMA_Priority_Medium;
20
  DMA_InitStructure_TX.DMA_BufferSize = count;
21
  DMA_InitStructure_TX.DMA_Memory0BaseAddr = (uint32_t)buf;
22
  DMA_Init(DMA1_Stream4,&DMA_InitStructure_TX);
23
24
  NVIC_InitTypeDef NVIC_InitStructure;
25
26
  // enable the interrupt in the NVIC
27
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
28
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
29
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
30
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
31
  NVIC_Init(&NVIC_InitStructure);
32
33
  // Enable dma tx request.
34
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
35
36
  // Enable the DMA transfer complete interrupt
37
  DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);
38
39
  //Enable DMA RX/TX
40
  DMA_Cmd(DMA1_Stream4, ENABLE); //SPI3-TX
41
42
}

von holger (Gast)


Lesenswert?

>Dabei werden jetzt Daten per SPI an ein Display gesendet. Nach beendeter
>Übertragung wird ein Interrupt ausgelöst, in welchem dann das Chip
>Select zurückgesetzt wird.

Das ist aber eine wackelige Angelegenheit. Ich hab festgestellt
das wenn der TX DMA fertig ist das SPI Modul noch ein bis zwei
Byte am senden ist. Mit deiner Konstruktion würdest du die
Chip Select Leitung möglicherweise zu früh hochziehen.

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.