Forum: Mikrocontroller und Digitale Elektronik STM32F4 USART DMA-Transmit Probleme


von herakles (Gast)


Lesenswert?

Moin!

Ich möchte gern über die USART1 eines STM32F4 Cortex-M4 Prozessors Daten 
senden. Das klappt auch wunderbar mit folgendem Code:
1
void configure_clocks( void ) {
2
  // Enable peripheral clock. USART2 liegt auf APB1 ( Handbuch, Tabelle 5,
3
  // "USART feature comparison" auf Seite 34
4
  //RCC_APB1PeriphClockCmd( B03_USART_DISPLAY_CLK, ENABLE );
5
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE );
6
  // Enable the GPIO clocks. Die USART2-Funktionen liegen allesamt auf GPIO port A.
7
  // Handbuch Seite 60
8
  RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE );
9
}
10
11
void init_usart( void ) {
12
  GPIO_InitTypeDef GPIO_InitStructure;
13
  USART_InitTypeDef USART_InitStructure;
14
  
15
  memset( &GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef) );
16
  memset( &USART_InitStructure, 0, sizeof(USART_InitTypeDef) );
17
  // Connect the pin to the desired peripherals' alternate function.
18
  // Wiederrum GPIOA, die TX-Source ist GPIO_PinSource2 und die alternate
19
  // Function ist die 7(und GPIO_AF_USART2 löst sich zu 0x07 auf) - laut Tabelle Seite 60.
20
  GPIO_PinAFConfig( GPIOB, GPIO_PinSource6, GPIO_AF_USART1 );
21
  GPIO_PinAFConfig( GPIOB, GPIO_PinSource7, GPIO_AF_USART1 );
22
  memset( &GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef) );
23
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
24
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
25
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
26
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
27
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
28
  GPIO_Init( GPIOB, &GPIO_InitStructure );
29
30
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
31
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
32
  GPIO_Init( GPIOB, &GPIO_InitStructure );
33
  // Configure USART
34
  memset( &USART_InitStructure, 0, sizeof(USART_InitTypeDef) );
35
  USART_InitStructure.USART_BaudRate = 115200;
36
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
37
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
38
  USART_InitStructure.USART_Parity = USART_Parity_No;
39
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
40
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
41
  USART_Init( USART1, &USART_InitStructure );
42
      // Enable the USART
43
  USART_Cmd( USART1, ENABLE );
44
}
45
46
int main() {
47
  configure_clocks();
48
  init_usart();
49
  
50
  uint8_t daten = 0xdb;
51
  USART_SendData(USART1, daten);
52
        while(1);
53
}

Nun möchte ich das aber gern mit einem DMA lösen, damit die CPU andere 
Dinge machen darf, während die USART Daten schreibt. Dafür habe ich nach 
intensivem Wühlen im Internet - darunter auch zahlreiche Seite von 
diesem erstklassigen Forum - keine wirkliche Lösung gefunden, sprich: 
Ich sehe keine Daten auf der Schnittstelle.

Hier meine Codelösung für eine Datenübertragung mit DMA-Zugriff:
1
unsigned char buffer[9] = {0x11,0x06,0x23,0x4d,0x4e,0x32,0x2c,0x0a,0x3d};
2
3
void configure_clocks( void ) {
4
  RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);
5
  // Enable peripheral clock. USART2 liegt auf APB1 ( Handbuch, Tabelle 5,
6
  // "USART feature comparison" auf Seite 34
7
  //RCC_APB1PeriphClockCmd( B03_USART_DISPLAY_CLK, ENABLE );
8
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE );
9
  // Enable the GPIO clocks. Die USART2-Funktionen liegen allesamt auf GPIO port A.
10
  // Handbuch Seite 60
11
  RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE );
12
}
13
14
void init_usart( void ) {
15
  GPIO_InitTypeDef GPIO_InitStructure;
16
  USART_InitTypeDef USART_InitStructure;
17
  
18
  memset( &GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef) );
19
  memset( &USART_InitStructure, 0, sizeof(USART_InitTypeDef) );
20
  // Connect the pin to the desired peripherals' alternate function.
21
  // Wiederrum GPIOA, die TX-Source ist GPIO_PinSource2 und die alternate
22
  // Function ist die 7(und GPIO_AF_USART2 löst sich zu 0x07 auf) - laut Tabelle Seite 60.
23
  GPIO_PinAFConfig( GPIOB, GPIO_PinSource6, GPIO_AF_USART1 );
24
  GPIO_PinAFConfig( GPIOB, GPIO_PinSource7, GPIO_AF_USART1 );
25
  memset( &GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef) );
26
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
27
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
28
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
29
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
30
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
31
  GPIO_Init( GPIOB, &GPIO_InitStructure );
32
33
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
34
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
35
  GPIO_Init( GPIOB, &GPIO_InitStructure );
36
  // Configure USART
37
  memset( &USART_InitStructure, 0, sizeof(USART_InitTypeDef) );
38
  USART_InitStructure.USART_BaudRate = 115200;
39
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
40
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
41
  USART_InitStructure.USART_Parity = USART_Parity_No;
42
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
43
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
44
  USART_Init( USART1, &USART_InitStructure );
45
}
46
47
void DMAStream7_Channel4_Init(void) {
48
  DMA_InitTypeDef DMA_InitStruct;
49
50
  /* USART1_TX DMA2 Channel 7 */
51
  
52
  DMA_DeInit(DMA2_Stream7);
53
  
54
  DMA_StructInit(&DMA_InitStruct);
55
    DMA_InitStruct.DMA_Channel = DMA_Channel_4;
56
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
57
  DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)buffer;
58
  DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
59
  DMA_InitStruct.DMA_BufferSize = 9;
60
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
61
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
62
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
63
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
64
  DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
65
  DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
66
  
67
//  6a. Configure the DMA using DMA_Init() function
68
  DMA_Init(DMA2_Stream7, &DMA_InitStruct);
69
70
//  6b.Active the needed channel Request using USART_DMACmd() function
71
  USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
72
//  7. Enable the USART using the USART_Cmd() function.
73
  USART_Cmd( USART1, ENABLE );
74
  
75
  DMA_Cmd(DMA2_Stream7, ENABLE);
76
}
77
78
int main() {
79
  configure_clocks();
80
  init_usart();
81
  DMAStream7_Channel4_Init();
82
  while(1);
83
}

Mit dem ersten Codebeispiel sehe ich mit einem Terminalprogramm auf der 
Schnittstelle ein hexadezimales "0xDB", was mir zeigt, dass 
hardwaremäßig alles funktioniert. Demzufolge sollte also mit 
entsprechender Initilisierung auch ein DMA-Transfer über die 
Schnittstelle funktionieren. Das ist aber nicht der Fall.

Sieht jemand, welchen Fehler ich gemacht haben könnte? Ich brüte nun 
wirklich seit Stunden, bekomme aber kein Byte aus der Schnittstelle über 
DMA gequescht.

Vielen Dank für jeden Tipp im Voraus,
Herakles

von Markus R. (maggus)


Lesenswert?

> DMA_InitStruct.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;

müsste eigentlich

> DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

sein, sollte hier aber egal sein (da beides 0x00 ist).

Hier hat es schon jemand mit der DMA1 zum laufen bekommen:
Beitrag "STM32 F4 Discovery USART mit DMA"

von (prx) A. K. (prx)


Lesenswert?

Du solltest genug Takt aufbringen, auch den DMA Controller damit zu 
versorgen. Vielleicht statt RCC_AHB1PeriphResetCmd.

: Bearbeitet durch User
von iwasz (Gast)


Lesenswert?

Hi, I don't know if your problem is resolved or not, because I don't 
speak German, and since I've translated this page from German to English 
with Google, not everything is clear to me here. I had the same issue, 
and spent 2 nights on this (fu.k!), and solution was really simple and 
stupid : change

 RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);

to

 RCC_APB2PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

You probably followed documentation in stm32f4xx_dma.c, which in very 
first paragraph says to use RCC_AHB1PeriphResetCmd. So did I, but in my 
opinion this is a mistake on their (ST) part.

Regs.
iwasz.pl

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.