Hallo,
könntet ihr mir etwas zum Verständnis von DMA/ADC weiterhelfen?
Ich habe an dem STM an 2 Pins analoge Eingänge.
PA.0 soll von ADC1 und
PA.1 soll von ADC2 bedient werden.
Im regular - simultanous mode heißt es im RM0008:
A 32-bit DMA transfer request is generated (if DMA bit is set) which
transfers to SRAM
the ADC1_DR 32-bit register containing the ADC2 converted data in the
upper
halfword and the ADC1 converted data in the lower halfword.
Sprich, in eine 32er Zelle werden "oben" die ADC2 Werte, und unten die
ADC1 Werte geschrieben.
Wenn ich nun den DMA wie gezeigt konfiguriere sollte doch das volle 32
bit Ergbenis in das Array "AcdResults" schreiben? Allerdings verstehe
ich den zusammenhand zwischen dem jeweiligem Kanal vom ADC Ergebnis und
der Speicherzelle (wo es der DMA ins Array liefert) nicht ganz. Daher
die Frage ob das so funktioniert wie ich das vorhatte:
ADC1 und ADC2 sind exakt gleich konfiguriert, hier nur der erste:
1 | // ADC1 initialization
|
2 | ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC's operate simultaneously
|
3 | ADC_InitStructure.ADC_ScanConvMode = ENABLE; // Scan multiple channels of this regular channel group consecutively
|
4 | ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Single conversion of this regular channel group
|
5 | ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; // Conversion started by Timer2 Capture Compare2
|
6 | ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // Data right aligned
|
7 | ADC_InitStructure.ADC_NbrOfChannel = ADC_CH_NBR; // channels to convert
|
8 | ADC_Init(ADC1, &ADC_InitStructure);
|
9 |
|
10 |
|
11 | //für Mikrocontroller.net: aus Übersichtsgründen nur der Erste und Letzte aller 15 Kanäle!!!
|
12 | ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_71Cycles5); // Convert channel 0 (PA.0) with 71.5 cycles sample time
|
13 | .........
|
14 | ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 15, ADC_SampleTime_71Cycles5); // Convert channel 0 (PA.0) with 71.5 cycles sample time
|
DMA Konfig:
•
1 | // DMA1 CH1 configuration
|
2 | DMA_DeInit(DMA1_Channel1);
|
3 | DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ADC1_DR_Address; // Peripheral base address
|
4 | DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AdcResults; // Memory base address
|
5 | DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // Peripheral is the source
|
6 | DMA_InitStructure.DMA_BufferSize = ADC_CH_NBR; // DMA buffer size (in data unit)
|
7 | DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Disable peripheral register incrementation
|
8 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Enable memory address register incrementation
|
9 | //ACHTUNG: Speicherbreite von HalfWord auf Word angepasst, unten stehen ADC1- oben ADC2-Ergebnisse
|
10 | DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; // Peripheral data width = 32 bits
|
11 | DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; // Memory data width = 32 bits
|
12 | DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Circular buffer mode is used
|
13 | DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA channel has a high priority
|
14 | DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // DMA channel not configured for memory-to memory transfer
|
15 | DMA_Init(DMA1_Channel1, &DMA_InitStructure); // Init DMA1
|
16 | DMA_Cmd(DMA1_Channel1, ENABLE);
|
In der ADC_IRQ (in beiden) wird nun eine Multiplexer variable von 1-15
erhöht und nach jeweiligem Stand wird ein Ausgang (von 15) auf high
gelegt um die verschiedenen analogen Signale zu multiplexen.
--> Das hat alles schon soweit funktioniert, aber nur mit 15 Signalen
und einem ADC. Ich möchte jetzt "einfach" den zweiten ADC hinzufügen
(mit gleicher Konfiguration)
Hier noch die ADC_IRQ routine vom ersten ADC, die vom 2. is beinahe
gleich. Nur dass ihr seht wie ich die Multiplexer Bits setze. Genauso,
dachte ich, soll das auch beim der 2. geschehen.
Ich hoff man kann sich einigermaßen rein denken und ihr könnt mir etwas
auf die Sprünge helfen.
•
1 | void ADC1_2_IRQHandler(void)
|
2 | {
|
3 | int i;
|
4 |
|
5 | //GPIO_SetBits(TEST0_PORT, TEST0_PIN);
|
6 |
|
7 | ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC); // Clear ADC1 JEOC pending interrupt bit
|
8 |
|
9 | // shift median buffer one position left
|
10 | for (i = 0; i < ADC1_MEDIAN_BUFFERSIZE-1; i++)
|
11 | MedianBuffer[Adc1TmpMux][i] = MedianBuffer[Adc1TmpMux][i+1];
|
12 |
|
13 | // hier muss für den ADC2 der tempmux mit adc_ch_nbr addiert werden
|
14 | // store actual conversion result at last position of median buffer
|
15 | // ACHTUNG: ALT: MedianBuffer[Adc1TmpMux][ADC1_MEDIAN_BUFFERSIZE-1] = AdcResults[Adc1TmpMux];
|
16 | // NEU:
|
17 | MedianBuffer[Adc1TmpMux][ADC1_MEDIAN_BUFFERSIZE-1] = GetAdc1Result(Adc1TmpMux);
|
18 |
|
19 | // Next Multiplexer State for temperature measurement
|
20 | Adc1TmpMux++;
|
21 |
|
22 | //Check if all Channels are converted
|
23 | if (++Adc1TmpMux >= ADC_SENS_MUX_CNT){
|
24 | Adc1TmpMux = 0; // Restart with first channel
|
25 | }
|
26 |
|
27 | // reset all active low temperature sensor selection signals
|
28 | GPIO_SetBits(TSEL_REF0_PORT, TSEL_REF0_PIN);
|
29 |
|
30 | //für µC.net: mittlren 13 Kanäle entfernt
|
31 |
|
32 | GPIO_SetBits(TSEL_HCP_PORT, TSEL_HCP_PIN);
|
33 |
|
34 |
|
35 | // select next temperature sensor for following conversion
|
36 | switch (Adc1TmpMux)
|
37 | {
|
38 | case ADC1_REF0:
|
39 | GPIO_ResetBits(TSEL_REF0_PORT, TSEL_REF0_PIN);
|
40 | break;
|
41 |
|
42 |
|
43 | //für µC.net: mittlere 13 Kanäle entfernt
|
44 | case ADC1_SENS_HCP:
|
45 | GPIO_ResetBits(TSEL_HCP_PORT, TSEL_HCP_PIN);
|
46 | break
|
47 |
|
48 | default:
|
49 | break;
|
50 |
|
51 | //ACHTUNG!! hier muss das toggle bit den zusätzlich ausgang setzen (Bei ADC2)
|
52 | }
|
53 | //GPIO_ResetBits(TEST0_PORT, TEST0_PIN);
|
54 | }
|