Forum: Mikrocontroller und Digitale Elektronik STM32f4 SPI + DMA


von Alex (Gast)


Lesenswert?

Hey,
ich versuche gerade meine SPI Schnittstelle mit DMA zum laufen zu 
kriegen, aber leider kriege ich nur 0er zurück. Vielleicht kann ja 
jemand mal kurz draufschauen.

LG und vielen Dank


void init_SPI_DMA(void){

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | 
GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);


    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_SetBits(GPIOB, GPIO_Pin_12);


    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//MSB
    SPI_InitStructure.SPI_CRCPolynomial = 0;
    SPI_Init(SPI2, &SPI_InitStructure);

    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);

    SPI_Cmd(SPI2, ENABLE);

  // DMA Channel 3 - SPI RX
  DMA_InitStructure.DMA_Channel = DMA_Channel_0; 
//SPI2 Tx DMA is DMA1/Stream4/Channel0
  DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI2->DR); 
//Set the SPI2 Tx
  DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t)SPIBuffer; 
//Set the memory location
  DMA_InitStructure.DMA_DIR  = DMA_DIR_PeripheralToMemory; 
//Sending data from memory to the peripheral's Tx register
  DMA_InitStructure.DMA_BufferSize  = DMA_MemoryDataSize_HalfWord; 
//Define the number of bytes to send
  DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable; 
//Don't increment the peripheral 'memory'
  DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Disable; 
//Increment the memory location
  DMA_InitStructure.DMA_PeripheralDataSize  = 
DMA_PeripheralDataSize_HalfWord;    //Byte size memory transfers
  DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_HalfWord; 
//Byte size memory transfers
  DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal; 
//Normal mode (not circular)
  DMA_InitStructure.DMA_Priority  = DMA_Priority_High; 
//Priority is high to avoid saturating the FIFO since we are in direct 
mode
  DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable; 
//Operate in 'direct mode' without FIFO
  DMA_Init(DMA1_Stream3, &DMA_InitStructure);

  DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);

  // DMA Channel 4 - SPI TX
    DMA_InitStructure.DMA_Channel = DMA_Channel_0; 
//SPI2 Tx DMA is DMA1/Stream4/Channel0
    DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI2->DR); 
//Set the SPI2 Tx
    DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t)SPIBuffer; 
//Set the memory location
    DMA_InitStructure.DMA_DIR  = DMA_DIR_MemoryToPeripheral; 
//Sending data from memory to the peripheral's Tx register
    DMA_InitStructure.DMA_BufferSize  = DMA_MemoryDataSize_HalfWord; 
//Define the number of bytes to send
    DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable; 
//Don't increment the peripheral 'memory'
    DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Disable; 
//Increment the memory location
    DMA_InitStructure.DMA_PeripheralDataSize  = 
DMA_PeripheralDataSize_HalfWord;    //Byte size memory transfers
    DMA_InitStructure.DMA_MemoryDataSize  = 
DMA_MemoryDataSize_HalfWord;;         //Byte size memory transfers
    DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal; 
//Normal mode (not circular)
    DMA_InitStructure.DMA_Priority  = DMA_Priority_High; 
//Priority is high to avoid saturating the FIFO since we are in direct 
mode
    DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable; 
//Operate in 'direct mode' without FIFO
    DMA_Init(DMA1_Stream4, &DMA_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

  }

void SPI_DMA(void){

  DMA_Cmd(DMA1_Stream3, DISABLE);
  DMA_Cmd(DMA1_Stream4, DISABLE);
  SPIBuffer[0] = 0b1111111111111111;


  // Chip Select Low
  GPIO_WriteBit(GPIOB, GPIO_Pin_12, RESET);

  DMA_Cmd(DMA1_Stream3, ENABLE);
  DMA_Cmd(DMA1_Stream4, ENABLE);
  }

void DMA1_Stream3_IRQHandler(void)
{
  /* Test on DMA Stream Transfer Complete interrupt */
  if(DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3))
  {
    /* Clear DMA Stream Transfer Complete interrupt pending bit */
    DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
    spi_handleDMAInterrupt();

  }
}

  void spi_handleDMAInterrupt(void){
    // Chip Select High
  GPIO_WriteBit(GPIOB, GPIO_Pin_12, SET);

  DMA_Cmd(DMA1_Stream3, DISABLE);
  DMA_Cmd(DMA1_Stream4, DISABLE);
  }

von Little B. (lil-b)


Lesenswert?

Alex schrieb:
> RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

Alex schrieb:
> GPIO_Init(GPIOB, &GPIO_InitStructure);
>
>     GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
>     GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
>     GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
>
> ...
>     GPIO_Init(GPIOB, &GPIO_InitStructure);
>
>     GPIO_SetBits(GPIOB, GPIO_Pin_12);

check das mal

von Alex (Gast)


Lesenswert?

okay, das habe ich komplett übersehen. jetzt liefert er immerhin nur 1en 
aber laufen tut es leider immernoch nicht. der Interrupt löst auch aus.

LG Alex

von Alex (Gast)


Lesenswert?

okay, habe den Fehler vermutlich gefunden. Buffersize ist total quatsch, 
was ich da eingestellt habe.

LG Alex

von Alex (Gast)


Lesenswert?

also er überträgt,aber immer nur 1mal, wenn ich es zweimal 
hintereinander mache, klappt es nicht mehr. scheinbar habe ich 
vergessen, irgendwas zurückzusetzen, jetzt muss ich mir noch überlegen, 
was ;)

LG Alex

von Patrick B. (p51d)


Lesenswert?

1
DMA_InitStructure.DMA_BufferSize  = DMA_MemoryDataSize_HalfWord;

Das ist ja mehr als falsch: Buffersize gibt die Anzahl zu übertragenden 
Werte an. Also wenn das Array komplett gesendet werden soll, kann man 
das so machen:
1
DMA_InitStructure.DMA_BufferSize  = 3;
oder
1
DMA_InitStructure.DMA_BufferSize  = sizeof(SPIBuffer)/sizeof(SPIBuffer[0]);

MemoryDataSize gibt nur an, wie die Daten auf dem Speicher gepackt 
werden werden soll. Im Header-File sind das nur Flag-Definitionen.
1
#define DMA_MemoryDataSize_Byte           ((uint32_t)0x00000000) 
2
#define DMA_MemoryDataSize_HalfWord       ((uint32_t)0x00002000) 
3
#define DMA_MemoryDataSize_Word           ((uint32_t)0x00004000)

Noch ein Fehler:
1
DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Disable;
Du willst ja nicht immer wieder das gleiche Byte übertragen, also muss 
der Memory-Pointer ja erhöht werden.
Beim Empfangen das selbe: so überschreibst du die bisher empfangenen 
Daten immer wieder.

Zum Problem beim mehrmaligen senden: Ich vermute mal, dass du den 
Data-Counter nicht richtig setzt. Dieser gibt an, wieviele Daten noch 
gesendet werden sollen (zählt also zurück). Du musst also den Counter 
wieder setzen und dann den Transfer über DMA_Enable neu starten.
1
void DMA_SetCurrDataCounter(DMA_Stream_TypeDef* DMAy_Streamx, uint16_t Counter);

Ach noch was: DMA ist supper, wenn du VIEL Daten im Block-System 
(bekannte Packetgrössen) übertragen willst.

Btw: stell do deinen jetzigen Code einmal ein und nutze bitte die 
Code-Tags

: Bearbeitet durch User
von Alex (Gast)


Lesenswert?

Hey Patrick,
vielen Dank für deine Hilfe.

Ich möchte erstmal nur ein Eintrag des Array übertragen. Daher habe ich 
MemoryInc ausgestellt.
Da ich immer nur 16bit übertrage, dachte ich eigentlich, ich müsste den 
datacounter nicht zurücksetzen, denn er dürfte ja eigentlich nicht 
hochzählen.

LG Alex

von Patrick B. (p51d)


Lesenswert?

Alex schrieb:
> Da ich immer nur 16bit übertrage, dachte ich eigentlich, ich müsste den
> datacounter nicht zurücksetzen, denn er dürfte ja eigentlich nicht
> hochzählen.

Das stimmt so nicht. Der Data-Counter zählt herunter. So weiss der DMA 
auch wieviel er noch übertragen muss.
Also, du initialisierst alles so, setzt BufferSize auf 1 (für 1 HalfWord 
zu übertragen), und startest die Übertragung mit DMA_Enable. Dann sollte 
nur 2 Byte übertragen werden und der DMA stellt sich ab (wenn DMA_Mode = 
Normal, bei Circular fängt er wieder vorne an). Der Data-Counter hat nun 
von 1 auf 0 gezählt und bleibt da. Um eine neue Übertragung zu starten 
(z.B 100 HalfWords) setzt du den Counter auf 100 und startes das ganze 
wieder über DMA_Enable. Ev musst du die Basisaddresse des Memory auch 
noch neu setzen (weiss ich jetzt aber nicht mehr ausswendig, wie ST das 
gelöst hat). Aber das kannst du ja im Debugger sehr schnell 
herausfinden.

Noch was, ist SPIBuffer auch wirklich 16 Bit gross? Sonst könnte es da 
auch noch Probleme geben (da die MemorySize nicht passt).

: Bearbeitet durch User
von Alex (Gast)


Lesenswert?

Hey,
also hier mal mein Code. es funktioniert leider immernoch nur beim 
ersten mal, danach wird der Interrupt ausgelöst, aber leider kommt immer 
nur 500 zurück. was ich bei MOSI rausgebe ist komplett egal, es soll nur 
ein dummybyte sein. rein prinzipiell brauche ich auch nur den Rx Part 
von dem DMA, ich schreibe einfach mit 16bit wert in die SPI-Peripherie 
und warte dann, bis der DMA fertig ist.
1
void init_SPI_DMA(void){
2
3
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
4
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
5
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
6
7
8
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
9
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
10
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
11
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
12
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
13
    GPIO_Init(GPIOB, &GPIO_InitStructure);
14
15
16
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
17
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
18
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
19
20
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
21
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
22
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
23
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
24
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
25
    GPIO_Init(GPIOB, &GPIO_InitStructure);
26
27
    GPIO_SetBits(GPIOB, GPIO_Pin_12);
28
29
30
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
31
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
32
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
33
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
34
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
35
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
36
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
37
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//MSB
38
    SPI_InitStructure.SPI_CRCPolynomial = 0;
39
    SPI_Init(SPI2, &SPI_InitStructure);
40
41
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
42
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
43
44
    SPI_Cmd(SPI2, ENABLE);
45
46
  // DMA Channel 3 - SPI RX
47
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                          //SPI2 Tx DMA is DMA1/Stream4/Channel0
48
  DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI2->DR);                //Set the SPI2 Tx
49
  DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t)SPIBuffer;                   //Set the memory location
50
  DMA_InitStructure.DMA_DIR  = DMA_DIR_PeripheralToMemory;                          //Sending data from memory to the peripheral's Tx register
51
  DMA_InitStructure.DMA_BufferSize  = 1;                          //Define the number of bytes to send
52
  DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;                  //Don't increment the peripheral 'memory'
53
  DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Disable;                        //Increment the memory location
54
  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_HalfWord;    //Byte size memory transfers
55
  DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_HalfWord;         //Byte size memory transfers
56
  DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;                                        //Normal mode (not circular)
57
  DMA_InitStructure.DMA_Priority  = DMA_Priority_High;                                       //Priority is high to avoid saturating the FIFO since we are in direct mode
58
  DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable;                         //Operate in 'direct mode' without FIFO
59
  DMA_Init(DMA1_Stream3, &DMA_InitStructure);
60
61
  DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);
62
63
  // DMA Channel 4 - SPI TX
64
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                          //SPI2 Tx DMA is DMA1/Stream4/Channel0
65
    DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI2->DR);                //Set the SPI2 Tx
66
    DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t)SPIBuffer;                   //Set the memory location
67
    DMA_InitStructure.DMA_DIR  = DMA_DIR_MemoryToPeripheral;                          //Sending data from memory to the peripheral's Tx register
68
    DMA_InitStructure.DMA_BufferSize  = 1;                          //Define the number of bytes to send
69
    DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;                  //Don't increment the peripheral 'memory'
70
    DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Disable;                        //Increment the memory location
71
    DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_HalfWord;    //Byte size memory transfers
72
    DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_HalfWord;         //Byte size memory transfers
73
    DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;                                        //Normal mode (not circular)
74
    DMA_InitStructure.DMA_Priority  = DMA_Priority_High;                                       //Priority is high to avoid saturating the FIFO since we are in direct mode
75
    DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable;                         //Operate in 'direct mode' without FIFO
76
    DMA_Init(DMA1_Stream4, &DMA_InitStructure);
77
78
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
79
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
80
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
81
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
82
    NVIC_Init(&NVIC_InitStructure);
83
84
  }
85
86
void SPI_DMA(void){
87
88
  DMA_Cmd(DMA1_Stream3, DISABLE);
89
  DMA_Cmd(DMA1_Stream4, DISABLE);
90
  SPIBuffer[0] = 0b1111111111111;
91
92
93
  // Chip Select Low
94
  GPIO_WriteBit(GPIOB, GPIO_Pin_12, RESET);
95
96
  DMA_SetCurrDataCounter(DMA1_Stream3,1);
97
  DMA_SetCurrDataCounter(DMA1_Stream4,1);
98
99
  DMA_Cmd(DMA1_Stream3, ENABLE);
100
  DMA_Cmd(DMA1_Stream4, ENABLE);
101
  }
102
103
void DMA1_Stream3_IRQHandler(void)
104
{
105
  /* Test on DMA Stream Transfer Complete interrupt */
106
  if(DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3))
107
  {
108
    /* Clear DMA Stream Transfer Complete interrupt pending bit */
109
    DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
110
    spi_handleDMAInterrupt();
111
  }

von Alex (Gast)


Lesenswert?

der Interrupt handler:
1
  void spi_handleDMAInterrupt(void){
2
    // Chip Select High
3
  GPIO_WriteBit(GPIOB, GPIO_Pin_12, SET);
4
5
  DMA_Cmd(DMA1_Stream3, DISABLE);
6
  DMA_Cmd(DMA1_Stream4, DISABLE);
7
  }

von Patrick B. (p51d)


Lesenswert?

Das ist getested und läuft auf dem STM32F4-Discovery... Kannst es also 
für deine Zwecke abändern.
Zu Testzwecken habe ich MOSI und MISO verbunden. Die Werte im RX und TX 
Buffer sind die richtigen, und der LA zeigte auch alles korrekt.
1
#define BUFFER_SIZE              32
2
uint16_t SPIBufferRX[BUFFER_SIZE] = {0};
3
uint16_t SPIBufferTX[BUFFER_SIZE] = {0};
4
5
6
/**
7
 * @brief  Init SPI2 module for DMA transfers
8
 * @param  none
9
 * @retval  none
10
 */
11
void init_SPI_DMA(void){
12
  GPIO_InitTypeDef GPIO_InitStructure;
13
  NVIC_InitTypeDef NVIC_InitStructure;
14
  SPI_InitTypeDef SPI_InitStructure;
15
  DMA_InitTypeDef DMA_InitStructure;
16
17
  // Enable clocks
18
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
19
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
20
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
21
22
  // GPIO settings
23
  GPIO_StructInit(&GPIO_InitStructure);
24
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
25
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
26
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
27
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
28
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
29
  GPIO_Init(GPIOB, &GPIO_InitStructure);
30
31
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
32
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
33
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
34
35
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
36
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
37
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
38
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
39
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
40
  GPIO_Init(GPIOB, &GPIO_InitStructure);
41
42
  GPIO_SetBits(GPIOB, GPIO_Pin_12);        // Set SS pin
43
44
  // Init SPI
45
  SPI_StructInit(&SPI_InitStructure);
46
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
47
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
48
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
49
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
50
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
51
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
52
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
53
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//MSB
54
  SPI_InitStructure.SPI_CRCPolynomial = 0;
55
  SPI_Init(SPI2, &SPI_InitStructure);
56
57
  // DMA Channel 3 - SPI RX
58
  DMA_StructInit(&DMA_InitStructure);
59
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                   //SPI2 Tx DMA is DMA1/Stream4/Channel0
60
  DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI2->DR);             //Set the SPI2 Tx
61
  DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t)SPIBufferRX;                //Set the memory location
62
  DMA_InitStructure.DMA_DIR  = DMA_DIR_PeripheralToMemory;                       //Sending data from memory to the peripheral's Tx register
63
  DMA_InitStructure.DMA_BufferSize  = BUFFER_SIZE;                              //Define the number of bytes to send
64
  DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;             //Don't increment the peripheral 'memory'
65
  DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Enable;                        //Increment the memory location
66
  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_HalfWord;    //Byte size memory transfers
67
  DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_HalfWord;           //Byte size memory transfers
68
  DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;                                   //Normal mode (not circular)
69
  DMA_InitStructure.DMA_Priority  = DMA_Priority_High;                           //Priority is high to avoid saturating the FIFO since we are in direct mode
70
  DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable;                         //Operate in 'direct mode' without FIFO
71
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
72
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
73
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
74
  DMA_Init(DMA1_Stream3, &DMA_InitStructure);
75
  DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);
76
77
  // DMA Channel 4 - SPI TX
78
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;                                //SPI2 Tx DMA is DMA1/Stream4/Channel0
79
  DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)&(SPI2->DR);             //Set the SPI2 Tx
80
  DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t)SPIBufferTX;                 //Set the memory location
81
  DMA_InitStructure.DMA_DIR  = DMA_DIR_MemoryToPeripheral;                      //Sending data from memory to the peripheral's Tx register
82
  DMA_InitStructure.DMA_BufferSize  = BUFFER_SIZE;                              //Define the number of bytes to send
83
  DMA_InitStructure.DMA_PeripheralInc  = DMA_PeripheralInc_Disable;             //Don't increment the peripheral 'memory'
84
  DMA_InitStructure.DMA_MemoryInc  = DMA_MemoryInc_Enable;                        //Increment the memory location
85
  DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_HalfWord;    //Byte size memory transfers
86
  DMA_InitStructure.DMA_MemoryDataSize  = DMA_MemoryDataSize_HalfWord;           //Byte size memory transfers
87
  DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;                                 //Normal mode (not circular)
88
  DMA_InitStructure.DMA_Priority  = DMA_Priority_High;                           //Priority is high to avoid saturating the FIFO since we are in direct mode
89
  DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable;                         //Operate in 'direct mode' without FIFO
90
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
91
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
92
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
93
  DMA_Init(DMA1_Stream4, &DMA_InitStructure);
94
  DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);
95
96
  DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
97
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
98
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
99
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
100
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
101
  NVIC_Init(&NVIC_InitStructure);
102
103
  DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);
104
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
105
  NVIC_Init(&NVIC_InitStructure);
106
107
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
108
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
109
  SPI_Cmd(SPI2, ENABLE);
110
}
111
112
/**
113
 * @brief  Start new SPI transfer
114
 * @param  none
115
 * @retval  none
116
 */
117
void SPI_DMA_start(void){
118
  // Prevent errors
119
  while((DMA_GetCmdStatus(DMA1_Stream4) == ENABLE) || (DMA_GetCmdStatus(DMA1_Stream3) == ENABLE)){
120
    // DMA transfer still running
121
  }
122
123
  DMA_SetCurrDataCounter(DMA1_Stream3, BUFFER_SIZE);
124
  DMA_SetCurrDataCounter(DMA1_Stream4, BUFFER_SIZE);
125
126
  // Chip Select Low
127
  GPIO_WriteBit(GPIOB, GPIO_Pin_12, RESET);
128
129
  DMA_Cmd(DMA1_Stream3, ENABLE);
130
  DMA_Cmd(DMA1_Stream4, ENABLE);
131
}
132
133
/**
134
 * @brief  DMA RX complete interrupt
135
 * @param  none
136
 * @retval  none
137
 */
138
void DMA1_Stream3_IRQHandler(void){
139
  if(DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3))  {      // Test on DMA Stream Transfer Complete interrupt
140
    DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);    // Clear DMA Stream Transfer Complete interrupt pending bit
141
142
    // ToDo
143
  }
144
}
145
146
/**
147
 * @brief  DMA TX Complete interrupt
148
 * @param  none
149
 * @retval  none
150
 */
151
void DMA1_Stream4_IRQHandler(void){
152
  if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4))  {      // Test on DMA Stream Transfer Complete interrupt
153
    DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);    // Clear DMA Stream Transfer Complete interrupt pending bit
154
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, SET);          // Chip Select Low
155
  }
156
}
157
158
/**
159
 * @brief  main program
160
 * @param  none
161
 * @retval  none
162
 */
163
int main(void){
164
  volatile int i = 0;
165
166
  // Default values
167
  for(i=0; i<BUFFER_SIZE; i++){
168
    SPIBufferTX[i] = i;
169
  }
170
171
  init_SPI_DMA();                        // Init GPIO, SPI, DMA, NVIC
172
  SPI_DMA_start();                      // Start first transfer
173
174
  while (1){
175
    // Create delay
176
    i = 0;
177
    while(i < 10000) i++;
178
179
    SPI_DMA_start();                    // Start new transfer
180
  }
181
}

Damit das ganze auch Sinn ergibt musst du natürlich 2 getrennte Buffer 
für Rx und Tx verwenden!

Ich vermute jetzt einfach mal: Du hast bei der DMA-Struktur nicht ALLE 
Werte gesetzt (FIFO-Handhabung), was zu ganz üblen Problemen führen 
kann. Da die Werte unbekannt sind, haben die irgend einen Zustand und 
somit können auch andere Variablen überschrieben werden. Dein 
Beispiel-Code ist bei mir nie gelaufen, da der DMA sich nicht starten 
liess (EN-Bit war nie gesetzt, was auf eine Fehlkonfiguration 
hindeutete)...

Hatte damit auch schon fast eine Woche verblödelt. Also, immer schön 
xy_StructInit(&xy_Initstructure) verwenden und die Welt sieht viel 
besser aus (spielt ja bei der Initialisierung des Systems absolut keine 
Rolle, ob das 10ms oder 12ms dauert).

Gruss

: Bearbeitet durch User
von Alex (Gast)


Lesenswert?

alles klar, vielen Dank!

Ich werde das gleich mal ausprobieren ;)

LG

von Alex (Gast)


Lesenswert?

hey,
eine Sache die mir noch aufgefallen ist. müsste das SS Signal nicht in 
dem anderen interrupthandler gesetzt werden? wenn meine Daten angekommen 
sind, also im DMA-RX muss doch SS erst wieder auf high und nicht schon 
beim TX oder sehe ich das falsch?

LG

von Patrick B. (p51d)


Lesenswert?

Es ist sicher "sauberer" wenn es beim Rx gemacht wird (hier wird glaube 
ich mehrmals gesampelt und dann erst den Wert ermittelt). Also wird Rx 
immer nach Tx sein...

Du hast recht, wäre sicher besser.

: 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.