Forum: Mikrocontroller und Digitale Elektronik STM32F4 USART und DMA


von Moritz M. (avrprogger)


Lesenswert?

Hallo,

hat jemand vielleicht ein Beispiel für DMA und USART am STM32F4. Ich 
steig durch die DMA_InitStructure noch nicht so richtig durch.

Moritz

von AVerr (Gast)


Lesenswert?

Mit USART + DMA kann ich zwar nicht direkt dienen, aber ich hätte mal 
ein Beispiel für ADC + DMA ( daraus sollte man ja auch schon einiges 
lernen können ) mit einem 128-Messwerte-Ringpuffer.
1
/* globale Variable */
2
uint16_t adcBuffer[128];
3
4
/* Initialisierung */
5
  /* DMA Init */
6
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
7
  
8
  DMA_InitTypeDef DMA_InitStruct;
9
  DMA_StructInit(&DMA_InitStruct);
10
  DMA_InitStruct.DMA_Channel = DMA_Channel_0;
11
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
12
  DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&adcBuffer;
13
  DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
14
  DMA_InitStruct.DMA_BufferSize = 128;
15
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
16
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
17
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
18
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
19
  DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
20
  DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
21
  DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
22
  DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
23
  DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
24
  DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
25
  DMA_Init(DMA2_Stream0, &DMA_InitStruct);
26
  DMA_Cmd(DMA2_Stream0, ENABLE);
27
  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
28
29
  /* DMA Interrupt Init */
30
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
31
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
32
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
33
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
34
  NVIC_Init(&NVIC_InitStructure);
35
  
36
  /* ADC Init */
37
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
38
  
39
  ADC_CommonInitTypeDef ADC_CommonInitStruct;
40
  ADC_CommonStructInit(&ADC_CommonInitStruct);
41
  ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
42
  ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;
43
  ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
44
  ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
45
  ADC_CommonInit(&ADC_CommonInitStruct);
46
  
47
  ADC_InitTypeDef ADC_InitStruct;
48
  ADC_StructInit(&ADC_InitStruct);
49
  ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
50
  ADC_InitStruct.ADC_ScanConvMode = DISABLE;
51
  ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
52
  ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
53
  ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
54
  ADC_InitStruct.ADC_NbrOfConversion = 1;
55
  ADC_Init(ADC1, &ADC_InitStruct);
56
  
57
  ADC_TempSensorVrefintCmd(ENABLE);
58
  ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_480Cycles);
59
  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
60
 
61
  ADC_DMACmd(ADC1, ENABLE);
62
  ADC_Cmd(ADC1, ENABLE);
63
  ADC_SoftwareStartConv(ADC1);
64
65
/* Interrupt Handler */
66
  void DMA2_Stream0_IRQHandler(void)
67
  {
68
    /* Hier kann man mit adcBuffer tun, was man will.
69
       Wird alle 128 ADC-Messungen aufgerufen,
70
       nachdem die Ergebnisse von der DMA in adcBuffer geschrieben
71
       wurden. */
72
 
73
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
74
  }

Du musst nur im DMA-Abschnitt im Reference Manual den richtigen 
DMA-Channel/Stream für deinen USART finden.
Ansonsten müsstest du nur die Adressen und die DataSizes anpassen, schon 
sollte das bei der USART-Schnittstelle funktionieren.

von RP6Conrad (Gast)


Lesenswert?

USART ueber DMA senden geht, aber hat das nachteil das du erst das 
anzahl bytes muss angeben, danach wird DMA gestart und genau diese 
anzahl von bytes wird dan ueber DMA an die USART gesendet.

von Moritz M. (avrprogger)


Lesenswert?

Hallo also ich versuch über usart 3 und dma  stream 3 channel 4 
(richtig?) einen Text auszugeben:


#include "stm32f4xx.h"


void USART3_Init(void);
void DMAStream3_Channel4_Init();

unsigned char buffer[129] = "Hello World, this is a DMA test. If you can 
read this the DMA is still working!\n";

int main(void)
{
  USART3_Init();
  DMAStream3_Channel4_Init();
  USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
  DMA_Cmd(DMA1_Stream3, ENABLE);
  while(1);
}

void USART3_Init(void)
{
  GPIO_InitTypeDef GPIOC_10_11_InitStructure;
  USART_InitTypeDef USART3_InitStructure;

  //GPIO C 10/11 Init
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);

  GPIOC_10_11_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIOC_10_11_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIOC_10_11_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
  GPIOC_10_11_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIOC_10_11_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOC, &GPIOC_10_11_InitStructure);

  //USART 3 Init
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

  USART3_InitStructure.USART_BaudRate = 9600;
  USART3_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART3_InitStructure.USART_StopBits = USART_StopBits_1;
  USART3_InitStructure.USART_Parity = USART_Parity_No;
  USART3_InitStructure.USART_HardwareFlowControl = 
USART_HardwareFlowControl_None;
  USART3_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  USART_Init(USART3, &USART3_InitStructure);
  USART_Cmd(USART3, ENABLE);
}
void DMAStream3_Channel4_Init(void)
{
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

  DMA_InitTypeDef DMA_InitStruct;
  DMA_StructInit(&DMA_InitStruct);
  DMA_InitStruct.DMA_Channel = DMA_Channel_4;
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART3->DR);
  DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&buffer;
  DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStruct.DMA_BufferSize = 129;
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStruct.DMA_PeripheralDataSize = 
DMA_PeripheralDataSize_HalfWord;
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream3, &DMA_InitStruct);
}

weiß vielleicht jemand was ich falsch mach?

Moritz

von AVerr (Gast)


Lesenswert?

Moritz M. schrieb:
> über usart 3 und dma  stream 3 channel 4
> (richtig?)

DMA 1, Stream 3, Channel 4, korrekt. (Alternativ ginge auch DMA 1, 
Stream 4, Channel 7)

Allerdings hast du wohl eine Stelle übersehen:

Moritz M. schrieb:
> DMA_Init(DMA2_Stream3, &DMA_InitStruct);
In der Funktion DMAStream3_Channel4_Init.

Da du Zeichen verschicken willst ( unsigned char ), beträgt deine 
DataSize ( sowohl Memory als auch Peripheral ) nur ein Byte und kein 
Half Word ( 2 Byte ).
Ansonsten habe ich die DMA noch nie für USART TX benutzt, daher kann ich 
nicht mehr dazu sagen.

von Moritz M. (avrprogger)


Lesenswert?

Hallo jetz funktioniert es wunderbar Dank an alle!

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.