Forum: Mikrocontroller und Digitale Elektronik stm32 DMA läuft nur in Simulation!?


von stef b. (joe_)


Lesenswert?

Hallo!

Habe auf dem STM32 einen ADC mit DMA programmiert. Der ADC alleine läuft 
problemlos. Mit DMA läuft das ganze aber nur in der Simulation 
(KEIL-µVision) ... und auf dem Board passiert nix! Hat jemand ne Idee 
woran das liegen kann? Bin langsam am verzweifeln!

Wird das transfer complete flag (TCIF1) gesetzt geht die LED an ... aber 
halt nur in der Simulation, nicht aber auf dem STM32!

1
#include "stm32f10x.h"
2
uint32_t DMA;  // DMA goal
3
4
int main(void)
5
{
6
// enable clock
7
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;   // GPIOC
8
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;  // Alternate Function
9
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;  // ADC
10
/* Input @ PC0 */
11
GPIOC->CRL  &= ~GPIO_CRL_MODE0;  // Input
12
GPIOC->CRL  &= ~GPIO_CRL_CNF0;   // Analog
13
/* LED @ PC8 */
14
GPIOC->CRH |= GPIO_CRH_MODE8_1;  // Output 2MHz     
15
GPIOC->CRH &= ~GPIO_CRH_CNF8;    // General push-pull
16
17
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CONT;  // ADC wakeup / continuous 
18
ADC1->CR1 |= ADC_CR1_AWDIE;   // enable interrupt: analog watchdog
19
ADC1->CR1 |= ADC_CR1_AWDEN;   // enable analog watchdog for regular channel
20
ADC1->CR1 |= ADC_CR1_AWDSGL;      // watchdog enabled on a single channel
21
ADC1->CR1 |= ADC_CR1_AWDCH_1 | ADC_CR1_AWDCH_3;  // watchdog on channel 10
22
ADC1->CR1 |= ADC_CR1_SCAN;        // enable scan mode
23
ADC1->CR2 |= ADC_CR2_DMA;         // enable dma mode
24
ADC1->SMPR1 &= ~ADC_SMPR1_SMP10;  // set sample time for channel 10 to 1.5 
25
ADC1->SQR1 &= ~ADC_SQR1_L;        // 1 conversions
26
ADC1->SQR3|= ADC_SQR3_SQ1_1 | ADC_SQR3_SQ1_3;//channel 10 first    
27
ADC1->HTR |= (uint16_t)(0x0FF0);  // set watchdog high threshold
28
ADC1->LTR |= (uint16_t)(0x000F);  // set watchdog low threshold
29
30
DMA1_Channel1->CPAR  = (uint32_t)(&(ADC1->DR)); // peripheral address
31
DMA1_Channel1->CNDTR = (uint16_t)(0x0001);  // 1 transfers
32
DMA1_Channel1->CCR |= DMA_CCR1_CIRC;        // circular mode enable
33
DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;     // memory size 16 bits
34
DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;     // peripheral size 16 bits
35
DMA1_Channel1->CMAR = (uint32_t)(&(DMA));   // set DMA goal for ADC
36
DMA1_Channel1->CCR |= DMA_CCR1_TCIE;  //enable interrupt transfer complete
37
DMA1_Channel1->CCR |= DMA_CCR1_EN;   // DMA on
38
ADC1->SR |= ADC_CR1_EOCIE;      // enable interrupt End of conversation
39
ADC1->CR2|= ADC_CR2_CAL;        // start ADC calibration
40
while(ADC1->CR2 & ADC_CR2_CAL){}// wait during calibration 
41
ADC1->CR2   |= ADC_CR2_ADON;    // turn ADC on
42
  
43
while (1)
44
{
45
   if(DMA1->ISR & DMA_ISR_TCIF1)    //<- TCIF1 wird nur in Software gesetzt
46
   {
47
     DMA1->IFCR |= DMA_IFCR_CTCIF1; // clear interrupt
48
     GPIOC->BSRR |= GPIO_BSRR_BS8;  // LED on
49
50
   }        
51
52
}
53
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich seh nirgends, das du die Clock für die DMA auch anschaltest?

stef ba schrieb:
> DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;     // peripheral size 16 bits
> DMA1_Channel1->CMAR = (uint32_t)(&(DMA));   // set DMA goal for ADC

Das sieht auch nicht richtig aus. Mach dir lieber ein struct mit 2 
16-bit Zielen anstatt einem 32-bit target. Könnte sein, das der Compiler 
dir sonst einen Strich durch die Rechnung macht. Leider benutze ich die 
Std. Peri Lib, dewegen kann ich deine Registerbeschreiberei nicht im 
einzelnen nachvollziehen. Auf Wunsch poste ich aber mal meinen Code.

von stef b. (joe_)


Lesenswert?

Matthias Sch. schrieb:
> Ich seh nirgends, das du die Clock für die DMA auch anschaltest?

das stimmt, hab ich auch nicht ...mal schauen ob es damit geht! aber 
komisch dass die simulation trotzdem geht!

ich probier nochmal aus und meld mich wieder! vielen dank erstmal!

von Star K. (starkeeper)


Lesenswert?

Du bindest den Header von der STM32-Lib ein aber nutzt sie nicht? Oder 
was ist der Grund dafür, dass du jedes Register von Hand beschreiben 
möchtest?

Von ST gibt es eine Peripherals Library die dir einiges an Arbeit 
abnehmen kann und so schon mal die Fehlermöglichkeiten minimiert.

von stef b. (joe_)


Lesenswert?

Star Keeper schrieb:
> Von ST gibt es eine Peripherals Library

das wusste ich noch nicht ... aber gut zu wissen!

aber wieso benutze ich sie nicht? dort stehen doch eh nur die adressen 
der Ports und Register drin, so z.B. RCC_APB2ENR_IOPCEN ... ist aus der 
stm32f10x.h

von Star K. (starkeeper)


Lesenswert?

stef ba schrieb:
> dort stehen doch eh nur die adressen
> der Ports und Register drin

mmmmh, nein.
Dort stehen für jede Peripherie Funktionen zum Einrichten und Benutzen 
zur Verfügung. Dies vereinfacht den Einsatz der Peripherie ungemein.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Hier ist mal ein Beispel mit Std. Peri.Lib. für den ADC mit 4 Kanälen:
1
// defines for readability
2
#define SPAREINPUT_CHANNEL          ADC_Channel_0
3
#define SPEEDINPUT_CHANNEL          ADC_Channel_1
4
#define PHASE_CURRENTS_CHANNEL          ADC_Channel_2
5
#define TEMP_CHANNEL                    ADC_Channel_3
6
7
typedef struct ADCValues
8
{
9
  uint16_t spare1;
10
  uint16_t speedInput;
11
  uint16_t current;
12
  uint16_t temp;
13
  uint16_t spare2;
14
} ADCValues_t;
15
16
volatile ADCValues_t ADCRead;
17
/* Init the ADC converter to free-run with 4 channels
18
 *
19
 */
20
void ADCInit(void) {
21
ADC_InitTypeDef       ADC_InitStructure;
22
DMA_InitTypeDef    DMA_InitStructure;
23
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
24
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
25
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
26
/* DMA1 channel1 configuration ----------------------------------------------*/
27
  DMA_DeInit(DMA1_Channel1);    // Clear everything we had 
28
  DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t)&(ADC1->DR); // source address is the ADC result register
29
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADCRead;      // Its the target struct
30
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;   // from Peripheral to RAM
31
  DMA_InitStructure.DMA_BufferSize = 4;    /// Note that we have 4 Channels
32
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // Source stays same address
33
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;     //destination will be incremented
34
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  // 16 bit results
35
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;   // yeah same size -> 16 bit
36
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // Wrap around the destination address
37
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;   // why not? its the only DMA thingy in this program
38
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;   // we don't want RAM to RAM
39
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);   // Init the stuff finally 
40
  /* Enable DMA1 channel1 */
41
  DMA_Cmd(DMA1_Channel1, ENABLE);  // Run, but we wait for the ADC init
42
/* ADC1 configuration
43
 * 4 channel continuous
44
 */
45
  ADC_DeInit(ADC1);
46
47
ADC_StructInit(&ADC_InitStructure);
48
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
49
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
50
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
51
ADC_InitStructure.ADC_NbrOfChannel = 4;
52
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
53
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
54
/* Now do the setup */
55
ADC_DMACmd(ADC1, ENABLE);
56
ADC_Init(ADC1, &ADC_InitStructure);
57
/* Enable ADC1 */
58
ADC_RegularChannelConfig(ADC1,SPAREINPUT_CHANNEL,1,ADC_SampleTime_239Cycles5);
59
ADC_RegularChannelConfig(ADC1,SPEEDINPUT_CHANNEL,2,ADC_SampleTime_239Cycles5);
60
ADC_RegularChannelConfig(ADC1,PHASE_CURRENTS_CHANNEL,3,ADC_SampleTime_239Cycles5);
61
ADC_RegularChannelConfig(ADC1,TEMP_CHANNEL,4,ADC_SampleTime_239Cycles5);
62
ADC_Cmd(ADC1, ENABLE);
63
/* Enable ADC1 reset calibaration register */
64
ADC_ResetCalibration(ADC1);
65
/* Check the end of ADC1 reset calibration register */
66
while(ADC_GetResetCalibrationStatus(ADC1));
67
/* Start ADC1 calibaration */
68
ADC_StartCalibration(ADC1);
69
/* Check the end of ADC1 calibration */
70
while(ADC_GetCalibrationStatus(ADC1));
71
72
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
73
Delay(200);
74
}

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.