Forum: Mikrocontroller und Digitale Elektronik STM32 F4 Discovery USART mit DMA


von Sergej E. (esergej)


Lesenswert?

Hallo
Bin grade dabei  sich in die Programmierung des ARM Mikrocontrollers 
einzuarbeiten. Benutze  STM32 F4 discovery  Board und Keil µVision4. Hab 
jetzt aber Schwierigkeiten die USART Schnittstelle mit DMA zum Laufen zu 
bringen  (mit Interrupts und ohne DMA hat es schon funktioniert). Und 
zwar sehe ich mit dem Oszilloskop das es irgendwelche  Daten verschickt 
werden 1.6 Sekunden nach dem Start bricht die Übertragung aber ab und 
Transfer Error Interrupt Flag kommt. Dies Pasier in Circular mode  sowie 
bei nur einmaliger Übertragung.  Ich verschicke aber nur 8 Byte  mir 2 
Stopbits die sollte bei einmaliger Übertragung nur  0,954ms dauern. 
Schalte ich Memory Inkrementierung ab so wird nur der erste Byte dauernd 
ohne Unterbrechung übertragen, aber dann auch wen Circular mode 
ausgeschaltet wird was eigentlich nicht sein dürfte. Und wenn ich es 
anhalte und im NDTR Register den Wert nachschaue dann hat es auch einen 
Wert den er gar nicht erreichen sollte. Kann da vielleicht jemand meinen 
Code  anschauen vielleicht sieht da jemand mein Fehler.
1
#include "stm32f4xx.h"
2
#include "stm32f4xx_conf.h"
3
4
int main(void){  
5
  uint32_t Warteschleife = 0;  
6
  unsigned char USART_String[8];   
7
   
8
  USART_String[0] = 170;
9
  USART_String[1] = 240;
10
  USART_String[2] = 40;
11
  USART_String[3] = 230;
12
  USART_String[4] = 50;
13
  USART_String[5] = 220;
14
  USART_String[6] = 60;
15
  USART_String[7] = 210;
16
17
  RCC->CFGR &= ~2;
18
  RCC->CR &= ~RCC_CR_PLLON;    
19
  RCC->PLLCFGR &= ~0xFFFFFFFF;
20
  RCC->PLLCFGR |= 16 << 0;     // 16 PLLM  Teiler für 163 MHz
21
  RCC->PLLCFGR |= 336 << 6;     // 336 PLLN  Multiplikator für 168 MHz
22
  RCC->CR |= RCC_CR_PLLON;   
23
  RCC->CFGR = RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_SW_PLL; 
24
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_DMA2EN;    
25
  RCC->APB2ENR |= RCC_APB2ENR_USART6EN;  
26
    
27
  GPIOC->MODER |= GPIO_Mode_AF << 14| GPIO_Mode_AF << 12;
28
  GPIOC->OSPEEDR |= GPIO_Speed_100MHz << 14 | GPIO_Speed_100MHz << 12;
29
  GPIOC->PUPDR |= GPIO_PuPd_UP << 14 | GPIO_PuPd_UP << 12; 
30
  GPIOC->AFR[0] |= GPIO_AF_USART6 << 24 | GPIO_AF_USART6 << 28;     
31
32
  USART6->CR1 = USART_CR1_OVER8 | USART_Mode_Tx | USART_Mode_Rx; 
33
  USART6->BRR = 11 << 4 | 7 << 0;  
34
  USART6->CR2 = USART_StopBits_2;    
35
  USART6->CR3 = USART_DMAReq_Tx ;
36
  USART6->CR1 |= USART_CR1_UE;
37
38
  DMA2_Stream7->CR = DMA_Channel_5 | DMA_MemoryInc_Enable 
39
                    | DMA_DIR_MemoryToPeripheral | DMA_FlowCtrl_Peripheral;
40
  DMA2_Stream7->NDTR = 8;
41
  DMA2_Stream7->PAR = (uint32_t)&USART6->DR;
42
  DMA2_Stream7->M0AR = (uint32_t)&USART_String;            
43
  DMA2_Stream7->FCR |= DMA_FIFOMode_Enable | DMA_FIFOThreshold_Full;
44
  DMA2_Stream7->CR |= DMA_Mode_Circular;
45
  DMA2_Stream7->CR |= DMA_SxCR_EN;
46
          
47
  while(1){
48
     while(Warteschleife < 10000){
49
        Warteschleife++;
50
     }
51
     Warteschleife=0;    
52
  }
53
}

von Sergej E. (esergej)


Lesenswert?

Hat keiner eine Idee?

von Matthias K. (matthiask)


Lesenswert?

Was hat es mit der Warteschleife auf sich?

von Sergej E. (esergej)


Lesenswert?

Gar nichts ist eine endlosschleife kann  man eigentlich entfernen. Ist 
noch davon übrig geblieben als ich versucht hatte die Daten ohne 
Circular Modus zu verschicken  im zeitabstand dieser Warteschleife.

von David Hediger (Gast)


Lesenswert?

Unkommentierten Code zu lesen macht leider nicht besonders an. Kannst du 
im Code beschreiben, was du ungefähr machst?

PS: Ich wäre auch sehr interessiert an einer DMA-Lösung für die UART.

von Tomasz M. (tomasz_m)


Lesenswert?

Hi,

I had the same problem. I worked without DMA_Mode_Circular and without 
DMA_FIFOMode_Enable. It should just send 8 characters and STOP !

I suspect it may have something to do with DMA_FlowCtrl_Peripheral.
I have just tested - it goes better without DMA_FlowCtrl_Peripheral.

Then I had next problem - I could not  pause it - it did not restart 
after re-enabling.

dmastr->CR &= ~DMA_SxCR_EN;
for(i = 0; i < 0x800; i++);
dmastr->CR |= DMA_SxCR_EN;
// DMA does not continue

I had to clear TCIF flag in *IFCR register before DMA_SxCR_EN

--
Tomasz Motylewski
K&J Schmittschneider AG

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

also unter Atollic TrueStudio funktioniert es so:
1
#include "stm32f4xx.h"
2
3
4
void USART3_Init(void);
5
void DMAStream3_Channel4_Init();
6
7
unsigned char buffer[129] = "Hello World, this is a DMA test. If you can read this the DMA is still working!\n";
8
9
int main(void)
10
{
11
  USART3_Init();
12
  DMAStream3_Channel4_Init();
13
  USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
14
  DMA_Cmd(DMA1_Stream3, ENABLE);
15
  while(1);
16
}
17
18
void USART3_Init(void)
19
{
20
  GPIO_InitTypeDef GPIOC_10_11_InitStructure;
21
  USART_InitTypeDef USART3_InitStructure;
22
23
  //GPIO C 10/11 Init
24
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
25
26
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
27
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);
28
29
  GPIOC_10_11_InitStructure.GPIO_Mode = GPIO_Mode_AF;
30
  GPIOC_10_11_InitStructure.GPIO_OType = GPIO_OType_PP;
31
  GPIOC_10_11_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
32
  GPIOC_10_11_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
33
  GPIOC_10_11_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
34
35
  GPIO_Init(GPIOC, &GPIOC_10_11_InitStructure);
36
37
  //USART 3 Init
38
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
39
40
  USART3_InitStructure.USART_BaudRate = 9600;
41
  USART3_InitStructure.USART_WordLength = USART_WordLength_8b;
42
  USART3_InitStructure.USART_StopBits = USART_StopBits_1;
43
  USART3_InitStructure.USART_Parity = USART_Parity_No;
44
  USART3_InitStructure.USART_HardwareFlowControl =
45
USART_HardwareFlowControl_None;
46
  USART3_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
47
48
  USART_Init(USART3, &USART3_InitStructure);
49
  USART_Cmd(USART3, ENABLE);
50
}
51
void DMAStream3_Channel4_Init(void)
52
{
53
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
54
55
  DMA_InitTypeDef DMA_InitStruct;
56
  DMA_StructInit(&DMA_InitStruct);
57
  DMA_InitStruct.DMA_Channel = DMA_Channel_4;
58
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART3->DR);
59
  DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&buffer;
60
  DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
61
  DMA_InitStruct.DMA_BufferSize = 129;
62
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
63
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
64
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
65
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
66
  DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
67
  DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
68
  DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
69
  DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
70
  DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
71
  DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
72
  DMA_Init(DMA1_Stream3, &DMA_InitStruct);
73
}

von Dimitri M. (dimitri)


Lesenswert?

In Keil finzt es ebenfalls. Mein Dank geht an Moritz :)

von W.S. (Gast)


Lesenswert?

Sergej E. schrieb:
> Hab jetzt aber Schwierigkeiten die USART Schnittstelle mit DMA zum Laufen zu 
bringen

Wozu eigentlich?
Gerade der USART ist - wenn man ihn für gewöhnliche Zwecke gebraucht - 
eher etwas für einen gemütlichen Interrupt-Betrieb mit softwareseitigem 
Ringpuffer als für DMA. Schau doch nur, was du selbst in deinem Beispiel 
für Aufwand treiben mußt, um die DMA überhaupt nur erstmal anzulassen.

Kurz gesagt, ich würde den USART eher nicht per DMA betreiben wollen, 
es macht mehr Probleme als es nützt.

W.S.

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

ja aber wenn man Datenmengen vom mehreren hundert KB dauernd übertragen 
muss ist es denke ich schon sinnvoll nicht die ganze Zeit die CPU zu 
blockieren. Das das so viel Code ist liegt nicht an der DMA sondern ehr 
an der Lib und dem µC, wobei die Lib schon eine sehr große hilfe ist, um 
nicht alle Register einzeln setzen zu müssen.

Moritz

von Tobias S. (tryan)


Lesenswert?

Hallo,
ich bin auch grade dabei Mir USART und DMA zu experimentieren.

Dank dem Quellcode von Moritz M. (Umgeschireben auf USART2) funktioniert 
die Übertragung schon gut außer es werden noch viele "Nullen" 
mitgeschickt, aber das ist ein anderes Thema.

Leider werden die Daten permanent geschickt. Wie deaktiviere ich das DMA 
nach einer Übertragung am besten? Bzw. wie erkläre ich dem DMA das der 
String zu Ende ist und die Übertragung abgeschlossen ist und ich das DMA 
wieder Deaktivieren kann.

Viele grüße Tobias

von Moritz M. (moritz_m72)


Lesenswert?

Hallo,

ich schätze DMA_Mode ändern. Sieh doch mal in der dma.c nach.

Moritz M.

von Moritz M. (moritz_m72)


Lesenswert?

Hallo nochmal,

DMA_Mode = DMA_Mode_Normal;

Beschreibung der einzelnen Parameter sind in der dma.h

Moritz M.

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.