STM32 DMA umstellung vom Circular Buffer zu Einfachen Buffer

OP Persönliche Seite #5059684
Lesenswert?

Hallo meine Lieben,

Ich schreibe bei meinem STM32 dauernd in einen Ringbuffer - das 
Funktioniert bereits wunderbar.

Ich möchte wenn der Analog Watchdog einen Grenzwert überschritten hat 
von dem circulat buffer auf einen anderen Buffer in einem anderen 
Speicherbereich umstellen.
Leider tut der DMA das nicht:
1
/*
2
 * When the Analog Watchdog is tripped this callback function gets executed
3
 */
4
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
5
{
6
  DMA_Stream_TypeDef * dmaStreamTypeDefInstance = hadc->DMA_Handle->Instance;
7

8
  // (1) Stop ongoing DMA transfer with setting EN to Zero
9
  dmaStreamTypeDefInstance->CR &= ~DMA_SxCR_EN;
10
  //DMA Channel is stopped when EN is 0
11
  uint8_t i = 0;
12
  while(hadc->DMA_Handle->Instance->CR & DMA_SxCR_EN )
13
  {
14
    //DMA not Stopping )-;
15
    if(i>100)
16
      _Error_Handler(__FILE__, __LINE__);
17
    i++;
18
  }
19
  //DMA now is stopped and can be reconfigured
20

21
  //Read the position of the last circular write operation - needed for later move operations and is away when restarting
22
  uint32_t ndtr = dmaStreamTypeDefInstance->NDTR;
23

24
  // (2) Set Peripherial Register
25
  // Nothing TODO
26

27
  // (3) Set Memory Address
28
  dmaStreamTypeDefInstance->M0AR = (uint32_t)memoryPostRecordPtr;
29

30
  // (4) Configure Item Numbers
31
  dmaStreamTypeDefInstance->NDTR = memoryPostRecord;
32

33
  // (5) Set DMA channel
34
  // (6) Set Flow CNTRL
35
  // (7) Configure Stream Priority
36
  // (8) FIFO Mode
37
  // (9) Configure Direction, increment, data widths, circular and interrupts
38
  // Disable Circular mode Enable DMA
39
  dmaStreamTypeDefInstance->CR &= (~DMA_SxCR_CIRC);
40

41
  // (10) (Re)Enable DMA
42
  dmaStreamTypeDefInstance->CR |= DMA_SxCR_EN ;
43

44
  if(hadc1.Instance->SR & ADC_SR_OVR)
45
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
46
  if(!(dmaStreamTypeDefInstance->CR&DMA_SxCR_EN))
47
    HAL_GPIO_WritePin(white_Led_GPIO_Port, white_Led_Pin, GPIO_PIN_SET);
48

49

50

51
  //Disable Analog Watchdog before exiting
52
  hadc->Instance->CR1 &= (~ADC_CR1_AWDEN);
53

54
  //Calculate the position  of the last circular write operation
55
  uint32_t elementPos = memoryCyclicSize - 1 - ndtr;
56
  uint16_t* ndtrPtr = &memoryCyclicPtr[elementPos];
57

58
  //Set LD2 LED
59
  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
60

61
  systemState = LinearRecordingAndDataRearrangement;
62
}


Leider geht die weiße LED an, d.h. das das Enable vom DMA gleich wieder 
zurück genommen wird.
Es tritt jedoch kein OVR beim ADC auf.

Danach hab ich dem DMA einen Wartepunkt gesetzt.
Der Teil unter //Disable Analog Watchdog before exiting wird also nichgt 
aufgerufen.

Hat jemand einen Plan?

Gruß und Danke, Markus
#5060172
Lesenswert?

Ich habe vor einiger Zeit auch sehr lange intensiv mit Stop/Go Betrieb 
des ADC + DMA experimentiert. Erschwerend auch noch im Dual bzw. Triple 
Mode.

Zu deiner Vorgehensweise den DMA bei laufendem ADC abzuschalten, zu 
rekonfigurieren und wieder einzuschalten kann ich sagen, ist kritisch. 
Der ADC wird höchstwahrscheinlich nach Deaktivierung des DMA ebenfalls 
den Dienst quittieren. Je nachdem welchen STM32 du verwendest steht dir 
zwar das DDS Bit im CR2 Register zur Verfügung, um ein Stoppen des ADC 
Wandlungen am Ende des DMA Transfers zu Verhindern. Das ist laut 
Reference Manual aber nur für Double Buffer Betrieb vorgesehen.

Mein Vorgehen ist nach Deaktivierung des DMA auch den ADC zu 
deaktivieren und eine Neukonfiguration und Neustart beider.
Du könntest in deiner Anwendung alternativ versuchen, den DMA im Double 
Buffer Mode zu konfigurieren und im Analog Watchdog Interrupt On-The-Fly 
die DMA Memory Zieladresse umzusetzen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren