von
Alex (Gast)
27.08.2015 09:32
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);
}
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)
27.08.2015 10:51
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)
27.08.2015 10:55
okay, habe den Fehler vermutlich gefunden. Buffersize ist total quatsch,
was ich da eingestellt habe.
LG Alex
von
Alex (Gast)
27.08.2015 10:59
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
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
von
Alex (Gast)
27.08.2015 12:32
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
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).
von
Alex (Gast)
27.08.2015 21:44
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 ] = 0 b1111111111111 ;
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)
27.08.2015 21:45
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 }
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
von
Alex (Gast)
28.08.2015 17:22
alles klar, vielen Dank!
Ich werde das gleich mal ausprobieren ;)
LG
von
Alex (Gast)
28.08.2015 22:48
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
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.