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
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
okay, habe den Fehler vermutlich gefunden. Buffersize ist total quatsch, was ich da eingestellt habe. LG Alex
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
:
Bearbeitet durch User
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).
:
Bearbeitet durch User
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 | }
|
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
:
Bearbeitet durch User
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.
:
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.