QUOTE (uriy @ Mar 1 2012, 15:30)

Где-то встречал упоминание что можно настроить DMA на работу с несколькими каналами АЦП. При этом определяется несколько буферов по количеству опрашиваемых каналов. Дальше АЦП (или DMA) как-то сам складывает семплы в свой буфер и генерит прерывание по заполнению буфера.
Нет, буфер один, общий. И АЦП складывает в него данные по очереди от первого, второго и т.д. каналов.
Готового кода у меня нет - я использую один канал, по его мотивам для двух каналов должно быть что-то такое:
CODE
extern "C" void DMA1_Channel1_IRQHandler();
class adc
{
public:
typedef uint8_t sample_t[2];
static size_t const ADC_BUFFER_SIZE = 128;
sample_t const * result() { Ready.wait(); return Ready; }
private:
void dma_handler();
friend void DMA1_Channel1_IRQHandler();
private:
typedef sample_t buffer_t[ADC_BUFFER_SIZE];
buffer_t Buffer[2]; // twice the buffer size, to get DMA "half ready" int in the middle
OS::message<sample_t *> Ready;
}
adc::adc()
{
// --------- ADC setup -----------
ADC1->CR1 = 0
| 15 * ADC_CR1_AWDCH_0 // Analog watchdog channel, unused channel
| 0 * ADC_CR1_EOCIE // EOC interrupt disabled
| 0 * ADC_CR1_AWDIE // Analog Watchdog interrupt disabled
| 0 * ADC_CR1_JEOCIE // Injected channels interrupt disabled
| 1 * ADC_CR1_SCAN // Scan mode, enabled
| 1 * ADC_CR1_AWDSGL // watchdog on a single (AWDCH) channel in scan mode
| 0 * ADC_CR1_JAUTO // Automatic injected group conversion
| 1 * ADC_CR1_DISCEN // Discontinuous mode on regular channels, enabled. One pulse=all conversions
| 0 * ADC_CR1_JDISCEN // Discontinuous mode on injected channels
| 1 * ADC_CR1_DISCNUM_0 // Discontinuous mode channel count = 2
| 0 * ADC_CR1_JAWDEN // Analog watchdog disabled on injected channels
| 0 * ADC_CR1_AWDEN // Analog watchdog disabled on regular channels
;
// calibrate ADC
ADC1->CR2 = 0
| 1 * ADC_CR2_ADON // A/D Converter ON
| 0 * ADC_CR2_CONT // Continuous Conversion disabled
| 1 * ADC_CR2_CAL // A/D Calibration
| 0 * ADC_CR2_RSTCAL // Reset Calibration
| 0 * ADC_CR2_DMA // Direct Memory access mode
| 0 * ADC_CR2_ALIGN // Data Alignment: right
| 0 * ADC_CR2_JEXTSEL_0 // External event for injected group: TIM2CC1
| 0 * ADC_CR2_JEXTTRIG // External Trigger Conversion mode for injected channels: disabled
| 0 * ADC_CR2_EXTSEL_0 // External Event for regular group: TIM2CC2
| 0 * ADC_CR2_EXTTRIG // External Trigger Conversion mode for regular channels: enabled
| 0 * ADC_CR2_JSWSTART // Start Conversion of injected channels
| 0 * ADC_CR2_SWSTART // Start Conversion of regular channels
| 0 * ADC_CR2_TSVREFE // Temperature Sensor and VREFINT disabled
;
/* default values
ADC1->SMPR1 = 0
| 0 * ADC_SMPR1_SMP10_0 // Channel 10 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP11_0 // Channel 11 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP12_0 // Channel 12 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP13_0 // Channel 13 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP14_0 // Channel 14 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP15_0 // Channel 15 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP16_0 // Channel 16 Sample time - 1.5 ticks
| 0 * ADC_SMPR1_SMP17_0 // Channel 17 Sample time - 1.5 ticks
;
*/
ADC1->SMPR2 = 0
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP0_0 // Channel 0 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP1_0 // Channel 1 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP2_0 // Channel 2 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP3_0 // Channel 3 Sample time
| 0 * ADC_SMPR2_SMP4_0 // Channel 4 Sample time - 1.5 ticks
| 0 * ADC_SMPR2_SMP5_0 // Channel 5 Sample time - 1.5 ticks
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP6_0 // Channel 6 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP7_0 // Channel 7 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP8_0 // Channel 8 Sample time
| ADC_SAMPLE_TIME * ADC_SMPR2_SMP9_0 // Channel 9 Sample time
;
/* default values
ADC1->JOFR1 = 0; // Injected channel offset
ADC1->JOFR2 = 0;
ADC1->JOFR3 = 0;
ADC1->JOFR4 = 0;
ADC1->HTR = 0xFFF;
ADC1->LTR = 0;
*/
ADC1->SQR1 = 0
| 0 * ADC_SQR1_SQ13_0 // 13th conversion in regular sequence channel: default
| 0 * ADC_SQR1_SQ14_0 // 14th conversion in regular sequence channel: default
| 0 * ADC_SQR1_SQ15_0 // 15th conversion in regular sequence channel: default
| 0 * ADC_SQR1_SQ16_0 // 16th conversion in regular sequence channel: default
| 1 * ADC_SQR1_L_0 // Regular channel sequence length: 2
;
/* default
ADC1->SQR2 = 0
| 0 * ADC_SQR2_SQ12_0 // 12th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ11_0 // 11th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ10_0 // 10th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ9_0 // 9th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ8_0 // 8th conversion in regular sequence channel: default
| 0 * ADC_SQR2_SQ7_0 // 7th conversion in regular sequence channel: default
;
*/
ADC1->SQR3 = 0
| 0 * ADC_SQR3_SQ6_0 // 6th conversion in regular sequence channel: default
| 0 * ADC_SQR3_SQ5_0 // 5th conversion in regular sequence channel: default
| 0 * ADC_SQR3_SQ4_0 // 4th conversion in regular sequence channel: default
| 0 * ADC_SQR3_SQ3_0 // 3rd conversion in regular sequence channel: default
| 8 * ADC_SQR3_SQ2_0 // 2nd conversion in regular sequence channel: ADC_IN8
| 9 * ADC_SQR3_SQ1_0 // 1st conversion in regular sequence channel: ADC_IN9
;
/* default value
ADC1->JSQR = 0;
*/
// --------- DMA setup -----------
DMA1_Channel1->CPAR = uintptr_t(((uint8_t *)&ADC1->DR) + 1); // hi byte of left-aligned result
DMA1_Channel1->CMAR = uintptr_t(Buffer[0]);
DMA1_Channel1->CNDTR = sizeof(Buffer) / sizeof(Buffer[0][0]);
DMA1_Channel1->CCR = 0
| 1 * DMA_CCR1_EN // Channel enable
| 1 * DMA_CCR1_TCIE // Transfer complete interrupt enable
| 1 * DMA_CCR1_HTIE // Half Transfer interrupt enable
| 0 * DMA_CCR1_TEIE // Transfer error interrupt enable
| 0 * DMA_CCR1_DIR // Data transfer direction: Peripheral->Memory
| 1 * DMA_CCR1_CIRC // Circular mode
| 0 * DMA_CCR1_PINC // Peripheral increment mode
| 1 * DMA_CCR1_MINC // Memory increment mode
| 0 * DMA_CCR1_PSIZE_0 // Peripheral size: 8 bits
| 0 * DMA_CCR1_MSIZE_0 // Memory size: 8 bits
| 0 * DMA_CCR1_PL_0 // Channel Priority level: lowest, conversion frequency is low enough
| 0 * DMA_CCR1_MEM2MEM // Memory to memory mode disabled
;
// wait until calibration is complete
while(ADC1->CR2 & ADC_CR2_CAL)
;
// start conversions
ADC1->CR2 = 0
| 1 * ADC_CR2_ADON // A/D Converter ON
| 0 * ADC_CR2_CONT // Continuous Conversion disabled
| 0 * ADC_CR2_CAL // A/D Calibration
| 0 * ADC_CR2_RSTCAL // Reset Calibration
| 1 * ADC_CR2_DMA // Direct Memory access enabled
| 1 * ADC_CR2_ALIGN // Data Alignment: left
| 3 * ADC_CR2_JEXTSEL_0 // External event for injected group: TIM2CC1
| 0 * ADC_CR2_JEXTTRIG // External Trigger Conversion mode for injected channels: disabled
| 3 * ADC_CR2_EXTSEL_0 // External Event for regular group: TIM2CC2
| 1 * ADC_CR2_EXTTRIG // External Trigger Conversion mode for regular channels: enabled
| 0 * ADC_CR2_JSWSTART // Start Conversion of injected channels
| 0 * ADC_CR2_SWSTART // Start Conversion of regular channels
| 0 * ADC_CR2_TSVREFE // Temperature Sensor and VREFINT disabled
;
}
INLINE void adc::dma_handler()
{
if(DMA1->ISR & DMA_ISR_HTIF1)
{
Ready = Buffer[0];
Ready.send_isr();
DMA1->IFCR = DMA_IFCR_CHTIF1;
}
if(DMA1->ISR & DMA_ISR_TCIF1)
{
Ready = Buffer[1];
Ready.send_isr();
DMA1->IFCR = DMA_IFCR_CTCIF1;
}
}
extern "C" void DMA1_Channel1_IRQHandler(void)
{
OS::TISRW ISR_wrapper;
ADC.dma_handler();
}