|
Опять таймер, ADC и DMA на STM32F4 (Discovery), Заезженная уже, наверное, тема. |
|
|
|
Feb 12 2013, 07:53
|

Профессионал
    
Группа: Свой
Сообщений: 1 202
Регистрация: 26-08-05
Из: Донецк, ДНР
Пользователь №: 7 980

|
Привет всем. Надо запускать ADC1 по таймеру, забирать результаты через DMA с получением какого-нибудь прерывания по заполнению буфера. По мотивам доки и форумов написал: CODE volatile uint16_t adcBuffer[4096]; // <- the results are here
........................................
// ADC1 CH0 - PA0 void adcInit ( void ) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // Enable ADC3, DMA2 and GPIO clocks RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE ); RCC_APB2PeriphClockCmd ( RCC_APB2Periph_ADC1, ENABLE ); // DMA2 Stream0 channel0 configuration DMA_DeInit(DMA2_Stream0); DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(ADC1->DR); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adcBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = 4096; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init ( DMA2_Stream0, &DMA_InitStructure ); DMA_Cmd ( DMA2_Stream0, ENABLE );
// Enable the DMA Stream IRQ Channel NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init ( &NVIC_InitStructure );
DMA_ITConfig ( DMA2_Stream0, DMA_IT_HT | DMA_IT_TC, ENABLE );
// Configure ADC1 Channel1 (PA0) pin as analog input GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init ( GPIOA, &GPIO_InitStructure ); // ADC Common Init ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit ( &ADC_CommonInitStructure ); // ADC1 Init ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_TRGO; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 0; ADC_Init ( ADC1, &ADC_InitStructure ); // ADC1 regular channel1 configuration ADC_RegularChannelConfig ( ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles );
// Enable DMA request after last transfer (Single-ADC mode) ADC_DMARequestAfterLastTransferCmd ( ADC1, ENABLE ); // Enable ADC1 DMA ADC_DMACmd ( ADC1, ENABLE ); // Enable ADC1 ADC_Cmd ( ADC1, ENABLE );
// Инициализация TIM8, запускающего АЦП TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_TIM8, ENABLE ); TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // делитель 33600 - частота прерываний = 84MHz/33600= 2500 = 2.5 kHz TIM_TimeBaseStructure.TIM_Prescaler = 33600-1; // Период загружается в ARR - значение перезагрузки. Счётчик считает 0..ARR TIM_TimeBaseStructure.TIM_Period = 2; //период 2 импульсов - частота 1250 гц TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit ( TIM8, &TIM_TimeBaseStructure ); TIM_SelectOutputTrigger ( TIM8, TIM_TRGOSource_Update ); } // adcInit
// Старт void adcStart ( void ) { TIM_Cmd ( TIM8, ENABLE ); } // adcStart
Из main-а вызываю adcInit, adcStart (т.е. запускаю таймер). Результат - зависание на последней команде adcInit TIM_SelectOutputTrigger ( TIM8, TIM_TRGOSource_Update );До запуска и всего прочего дело не доходит .... Наверное в инициализации накосячил. Но не пойму где. Пробовал ручной запуск, типа как здесь - http://electronix.ru/forum/index.php?showtopic=104701 и в примерах от ST, т.е. вместо таймера команда ADC_SoftwareStartConv(ADC1); // start ADC conversions Не виснет, но в буфере нули ... В той теме пошли разговоры на религиозные темы - "регистры против библиотек и функций"  . Да и нужен мне не ручной запуск, а по таймеру, с определённой частотой. Сам таймер работает, если убрать триггер и повесить прерывание, то оно исправно тикает с указанной частотой. Я также пытался ставить ADC_SoftwareStartConv(ADC1); в прерывание таймера (метод а-ля AVR), получил пустой буфер с нулями. На ноге PA0 (канал 0) висит потенциометр для отладки. От его положения соответственно ничего не зависит. Также интересует, как установить прерывание DMA по заполнению буфера. Примеров не нашёл. В примере ADC3_DMA от ST (архив STM32F4xx_DSP_StdPeriph_Lib_V1.0.1) тупо выводит на дисплей 2-байтовую переменную, которую заполняет DMA. Но это ж некошерно ... Помогите, кто может. Спасибо. PS. Плата STM32F4Discovery, проц STM32F4VGT6. Дисплей графический, ILI9320, работает по FSMC. С этим всё в норме.
--------------------
Чтобы возить такого пассажира, необходим лимузин другого класса. (с) Мария Эдуарда
|
|
|
|
|
 |
Ответов
|
Feb 15 2013, 07:37
|

Профессионал
    
Группа: Свой
Сообщений: 1 202
Регистрация: 26-08-05
Из: Донецк, ДНР
Пользователь №: 7 980

|
Ну вот опять пошла религия  ... Пропустить амперсанд можно как в команде DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR); так и в команде DMA2_Stream0->PAR = (uint32_t)&(ADC1->DR); А неправильное значение Вы хоть сразу в регистр впишите, хоть ещё через десяток структур и пяток функций прогоните, ничего не изменится. Поверьте мне, как программисту с почти 15-летним стажем. И не только на МК... И ещё немного оффтопа: Я видел на разных форумах немало "простыней" типа этой: CODE /* Peripheral clock enable */ RCC->AHB1ENR |= (1<<4); // GPIOE clock enable RCC->AHB1ENR |= (1<<3); // GPIOD clock enable RCC->AHB1ENR |= (1<<2); // GPIOC clock enable RCC->AHB1ENR |= (1<<1); // GPIOB clock enable RCC->AHB1ENR |= (1<<0); // GPIOA clock enable RCC->APB1ENR |= (1<<18); // USART3 clock enable RCC->APB1ENR |= (1<<15); // SPI3 clock enable RCC->APB1ENR |= (1<<14); // SPI2 clock enable RCC->APB2ENR |= (1<<12); // SPI1 clock enable RCC->AHB1ENR |= (1<<21); // DMA1 clock enable RCC->APB1ENR |= (1<<4); // TIM6 clock enable RCC->APB1ENR |= (1<<5); // TIM7 clock enable RCC->APB2ENR |= (1<<1); // TIM8 clock enable RCC->AHB2ENR |= (1<<6); // RNG clock enable RCC->APB1ENR |= (1<<29); // DAC interface clock enable RCC->APB2ENR |= (1<<14); // SYSCFGEN clock enable RCC->APB2ENR |= (1<<8); // ADC1 clock enable RCC->APB1ENR |= (1<<21); // I2C1 clock enable RCC->AHB1ENR |= (1<<18); // SRAM backup enable RCC->APB1ENR |= (1<<28); // POWER enable RCC->AHB2ENR |= (1<<7); // USB OTG_FS clock enable /* Set I/O mode for GPIOA */ GPIOA->MODER = 0x6AAAAA54; // PORT A OUT PA14 - PA4 AF PA0 digital input for USER BUTTON GPIOA->OSPEEDR = 0xABFFAAAA; // 50 MHz all and PA12 - PA8 100 MHz speed GPIOA->PUPDR = 0x24000100; // pull-up PA13 PA4 pull-down PA14 GPIOA->AFR[1] |= (0xA<<16); // PA12 how to alternative function AF10 USB_OTG_FS_DP GPIOA->AFR[1] |= (0xA<<12); // PA11 how to alternative function AF10 USB_OTG_FS_DM GPIOA->AFR[1] |= (0xA<<8); // PA10 how to alternative function AF10 USB_OTG_FS_ID GPIOA->AFR[1] |= (0xA<<4); // PA9 how to alternative function AF10 USB_OTG_FS_VBUS GPIOA->AFR[1] |= (0xA<<0); // PA8 how to alternative function AF10 USB_OTG_FS_SOF GPIOA->AFR[0] |= (0x5<<28); // PA7 how to alternative function AF5 SPI1_MOSI GPIOA->AFR[0] |= (0x5<<24); // PA6 how to alternative function AF5 SPI1_MISO GPIOA->AFR[0] |= (0x5<<20); // PA5 how to alternative function AF5 SPI1_SCK GPIOA->AFR[0] |= (0x5<<16); // PA4 how to alternative function AF5 SPI1_NSS /* PA0 configuration interrupt input set */ EXTI->IMR |= (1<<0); // MR0 interrupt request from line 0 is not masked EXTI->RTSR |= (1<<0); // TR0 rising trigger enabled for input line SYSCFG->EXTICR[0] &= ~(0xF<<0); // EXTI0 PA pins set NVIC_SetPriority(EXTI0_IRQn, 0); // PA0 priority set 0 NVIC_EnableIRQ(EXTI0_IRQn); // EXTI0 interrupt enable /* Set I/O mode for GPIOB */ GPIOB->MODER = 0x55696555; // port B OUT PB10 AF GPIOB->OSPEEDR = 0xAAAAAAAA; // 50 MHz speed GPIOB->OTYPER |= (1<<9); // PB9 open-drain GPIOB->OTYPER |= (1<<6); // PB6 open-drain GPIOB->PUPDR = 0x00000000; // no pull-up or pull-down GPIOB->AFR[1] |= (0x5<<8); // PB10 how to alternative function AF5 I2S2_CK GPIOB->AFR[1] |= (0x4<<4); // PB9 how to alternative function AF4 I2C1_SDA GPIOB->AFR[0] |= (0x4<<24); // PB6 how to alternative function AF4 I2C1_SCL /* Set I/O mode for GPIOC */ GPIOC->MODER = 0x5669AD94; // port C OUT PC12 PC10 PC9 PC7 PC6 and PC3 AF PC5 analog mode ADC1 IN15 PC0 digital input GPIOC->OSPEEDR = 0xAAAAAAAA; // 50 MHz speed GPIOC->PUPDR = 0x00000080; // pull-down PC3 GPIOC->AFR[1] |= (0x6<<16); // PC12 how to alternative function AF6 I2S3_SD GPIOC->AFR[1] |= (0x6<<8); // PC10 how to alternative function AF6 I2S3_CK GPIOC->AFR[0] |= (0x6<<28); // PC7 how to alternative function AF6 I2S3_MCK GPIOC->AFR[1] &= ~(0xF<<0); // PC9 how to alternative function AF0 MCO_2 GPIOC->AFR[0] |= (0x3<<24); // PC6 how to alternative function AF3 TIMER_8 GPIOC->AFR[0] |= (0x5<<12); // PC3 how to alternative function AF5 I2S2_SD /* Set I/O mode for GPIOD */ GPIOD->MODER = 0x555A5155; // port D OUT PD5 digital input PD8 PD9 AF GPIOD->OSPEEDR = 0xAAAAAAAA; // speed 50 MHz GPIOD->PUPDR = 0x00040000; // pull-up PD9 USART3_RX GPIOD->AFR[1] |= (0x7<<4); // PD9 how to alternative function AF7 USART3_RX GPIOD->AFR[1] |= (0x7<<0); // PD8 how to alternative function AF7 USART3_TX GPIOD->BSRRL |= (1<<4); // PD4 set 1 for RESET OFF EXTERNAL AUDIO DAC /* Set I/O mode for GPIOE */ GPIOE->MODER = 0x55555550; // port E OUT PE0 and PE1 digital input from ACCELEROMETER GPIOE->OTYPER = 0x00000008; // PE3 open-drain output type GPIOE->OSPEEDR = 0xAAAAAAAA; // speed 50 MHz GPIOE->PUPDR = 0x00000000; // no pull-down or pull-up GPIOE->BSRRL |= (1<<3); // PE3 set 1 /* PE1 configuration interrupt input set */ EXTI->IMR |= (1<<1); // MR1 interrupt request from line 1 is not masked EXTI->RTSR |= (1<<1); // TR1 rising trigger enabled for input line 1 EXTI->FTSR |= (1<<1); // TR1 failing trigger enabled for input line 1 SYSCFG->EXTICR[0] |= (0x4<<4); // EXTI1 PE pins set NVIC_SetPriority(EXTI1_IRQn, 1); // PE1 priority set 1 NVIC_EnableIRQ(EXTI1_IRQn); // EXTI1 interrupt enable /* USART3 configuration set*/ USART3->BRR |= 0x00000030; // USART3 speed 2 Mb/c set dev 3 USART3->CR1 |= (1<<15); // Oversampling by 8 set USART3->CR1 &= ~(1<<12); // Word length 8 bit set USART3->CR1 &= ~(1<<10); // Parity control disable USART3->CR1 &= ~(1<<8); // Parity interrupt disable USART3->CR1 &= ~(1<<7); // Transmit data register empty interrupt disable USART3->CR1 &= ~(1<<6); // Transmission complete interrupt disable USART3->CR1 |= (1<<5); // Read data register interrupt enable USART3->CR1 |= (1<<3); // TX set On USART3->CR1 |= (1<<2); // RX set On USART3->CR1 &= ~(1<<1); // Receiver set in active mode USART3->CR2 &= ~(0x3<<12); // Set 1 stop bit USART3->CR3 &= ~(1<<11); // 3 sample bit method set USART3->CR3 &= ~(1<<7); // DMA transmitter disable USART3->CR3 &= ~(1<<6); // DMA receiver disable USART3->CR1 |= (1<<13); // USART3 On NVIC_SetPriority(USART3_IRQn, 2); // USART3 priority set 2 NVIC_EnableIRQ(USART3_IRQn); // USART3 interrupt enable /* Timer8 PWM PC6 configuration set */ TIM8->CR1 |= (1<<7); // Timer 8 TIM8 ARR register is buffered set TIM8->PSC = 0xFDE7; // Timer 8 prescaler configuration set 65000 - 1 TIM8->ARR = 0x0171; // Timer 8 auto-reload value before 1 c TIM8->CCR1 = 0x00B8; // Timer 8 capture compare register 500 mc set 1 TIM8->CCMR1 = 0x0068; // Timer 8 PWM output mode set TIM8->CCER &= ~(1<<1); // Timer 8 OC1 active high output polarity TIM8->CCER |= (1<<0); // Timer 8 OC1 signal On TIM8->BDTR |= (1<<15); // Timer 8 MOE main output enable TIM8->CR1 |= (1<<0); // Timer 8 On /* ADC1 IN15 configuration set */ ADC1->CR1 |= (1<<26); // ADC1 overrun interrupt enabled ADC1->CR1 &= ~(0x3<<24); // ADC1 resolution 12-bit 15 ADCCLK cycles ADC1->CR1 |= (1<<23); // ADC1 analog watchdog enabled on regular channels ADC1->CR1 &= ~(1<<22); // ADC1 analog watchdog disabled on injected channels ADC1->CR1 &= ~(0x7<<13); // ADC1 discontinuous mode channel count 1 channel ADC1->CR1 &= ~(1<<12); // ADC1 discontinuous mode on injected channels disabled ADC1->CR1 &= ~(1<<11); // ADC1 discontinuous mode on regular channels disabled ADC1->CR1 &= ~(1<<10); // ADC1 automatic injected group conversion disabled ADC1->CR1 |= (1<<9); // ADC1 analog watchdog enabled on one channel ADC1->CR1 &= ~(1<<8); // ADC1 scan mode disabled ADC1->CR1 &= ~(1<<7); // ADC1 interrupt disable for injected channels ADC1->CR1 |= (1<<6); // ADC1 analog watchdog interrupt enabled ADC1->CR1 |= (1<<5); // ADC1 EOC interrupt enabled ADC1->CR1 |= (0xF<<0); // ADC1 analog watchdog input channel 15 ADC1->CR2 &= ~(0x3<<28); // ADC1 external trigger detection disabled for regular channels ADC1->CR2 &= ~(0xF<<24); // ADC1 external event select for regular group timer 1 CC1 event ADC1->CR2 &= ~(0x3<<20); // ADC1 external trigger detection disabled for injected channels ADC1->CR2 &= ~(0xF<<16); // ADC1 external event select for regular group timer 1 CC4 event ADC1->CR2 &= ~(1<<11); // ADC1 data alignment right set ADC1->CR2 |= (1<<10); // ADC1 EOC bit is set at the end of each regular conversion overrun detection is enabled ADC1->CR2 &= ~(1<<9); // ADC1 no new DMA request is issued after the last transfer ADC1->CR2 &= ~(1<<8); // ADC1 DMA mode disabled ADC1->CR2 &= ~(1<<1); // ADC1 single conversion mode set ADC1->SMPR1 = 0x00000000; // ADC1 channels 18 - 10 sampling time selection 3 cycles ADC1->SMPR2 = 0x00000000; // ADC1 channels 9 - 0 sampling time selection 3 cycles ADC1->HTR = 0x00000100; // ADC1 analog watchdog higher threshold 0x100 ADC1->LTR = 0x00000000; // ADC1 analog watchdog lower threshold 0x000 ADC1->SQR1 &= ~(0xF<<20); // ADC1 regular channel sequence length 1 conversion ADC1->SQR3 |= (0xF<<0); // ADC1 1st conversion in regular sequence channel 15 ADC1->JSQR = 0x00000000; // ADC1 injected sequence register set ADC->CCR &= ~(1<<23); // ADC1 temperature sensor and Vref INT channel disabled ADC->CCR &= ~(1<<22); // ADC1 Vbat channel disabled ADC->CCR |= (0x2<<16); // ADC1 prescaler PCLK2 divided by 6 speed equal 2 MHz ADC->CCR &= ~(0x3<<14); // ADC1 DMA mode disabled ADC->CCR &= ~(1<<13); // ADC1 DMA disable selection for multi-ADC mode ADC->CCR &= ~(0xF<<8); // ADC1 delay between 2 sampling phases 5*TADCCLK ADC->CCR &= ~(0x1F<<0); // ADC1 multi ADC mode selection 'independent mode' ADC1->CR2 |= (1<<0); // ADC1 On NVIC_SetPriority(ADC_IRQn, 7); // ADC1 IN15 priority set 7 NVIC_EnableIRQ(ADC_IRQn); // ADC1 IN15 interrupt enable
Лично мне этот стиль не нравится. Здесь хоть комментарии есть  . А некоторым "спецам" вообще писать их облом. В итоге, чтобы понять как что делается, надо полдня посидеть глядя одним глазом в эту простыню, а другим в RefMan. А если надо перенести код с проца на проц - вообще мрак .... Приходилось. Такой способ я поддержу в одном единственном случае - только если я буду на 100% уверен, что в стандартных библиотеках в каком-то месте имеет место ошибка или нестабильность. Справедливости ради отмечу, что RTC на этом проце у меня не заработал со стандартной библиотекой, а с манипуляциями регистрами заработал. Но подобные разовые случаи не повод повсеместно и навсегда отказываться от библиотек. Это ж не AVR, где таймер в большинстве случаев программируется через 2-3 простеньких регистра и т.п. ... Извините, если обидел. Не выдержал... По делу. Прикладываю полный вариант библиотеки ADC_DMA_Timer. Методов для задания частоты таймера (дискретизации) нету, всё наглухо вшито в инициализацию, но это разделить не проблема. Кому надо, берите. Компилятор - IAR. Пример использования: Код #include "Adc.h"
............... // Данные АЦП extern uint16_t adcBuffer[4096]; // Флаг готовности данных extern bool isDataReady;
....................... uint32_t adcVal; ....................... if (isDataReady) { isDataReady = false; adcVal = 0; for ( i = 0; i < 4096; i ++ ) adcVal += adcBuffer [ i ]; adcVal /= 4096; sprintf ( sBuffer, "ADCVal = %05lu", adcVal ); DrawString ( sBuffer, 10, 70, 0xFFE0, 0x0000, 1 ); } // if ........................... PS. Если у кого будут замечания, буду рад услышать. АЦП пока цифрует только один канал, вообще в планах сделать одновременный опрос разных каналов 2-х АЦП (а-ля 2-х канальный осциллограф), есть наброски примитивного кода для этого, оно вроде работает, но до конца я не дотестировал. Сделаю, выложу.
Прикрепленные файлы
Adc.zip ( 2.18 килобайт )
Кол-во скачиваний: 33
--------------------
Чтобы возить такого пассажира, необходим лимузин другого класса. (с) Мария Эдуарда
|
|
|
|
|
Feb 15 2013, 08:28
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (hd44780 @ Feb 15 2013, 09:37)  Пропустить амперсанд можно как в команде DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR); так и в команде DMA2_Stream0->PAR = (uint32_t)&(ADC1->DR); Согласен. Но в первом случае этого можно легко избежать, правильно описав поле структуры. Во втором, кстати, тоже - достаточно поле PAR описать как void *. Почему этого не сделано - вопрос уже к авторам заголовочного файла. Хорошая мысль, кстати. Пошел лопатить заголовочные файлы в своих проектах... QUOTE (hd44780 @ Feb 15 2013, 09:37)  Я видел на разных форумах немало "простыней" типа этой: Ужас. Это уже другая крайность - все в "магических цифрах". Вот тут комментарии, по большому счету, уже лишние: CODE RCC->APB1ENR = 0 | 1 * RCC_APB1ENR_TIM2EN // Timer 2 clock | 1 * RCC_APB1ENR_TIM3EN // Timer 3 clock | 0 * RCC_APB1ENR_TIM4EN // Timer 4 clock | 0 * RCC_APB1ENR_TIM6EN // Timer 6 clock | 0 * RCC_APB1ENR_TIM7EN // Timer 7 clock | 0 * RCC_APB1ENR_WWDGEN // Window Watchdog clock | 1 * RCC_APB1ENR_SPI2EN // SPI 2 clock | 1 * RCC_APB1ENR_USART2EN // USART 2 clock | 0 * RCC_APB1ENR_USART3EN // USART 3 clock | 0 * RCC_APB1ENR_I2C1EN // I2C 1 clock | 0 * RCC_APB1ENR_I2C2EN // I2C 2 clock | 0 * RCC_APB1ENR_BKPEN // Backup interface clock | 0 * RCC_APB1ENR_PWREN // Power interface clock | 1 * RCC_APB1ENR_DACEN // DAC interface clock | 0 * RCC_APB1ENR_CECEN // CEC interface clock ; И вся инициализация укладывается в одну команду вместо трех (чтение-маска-запись) на каждое поле в вашем примере. Простите за отвлечение от темы, тоже не удержался. QUOTE (hd44780 @ Feb 15 2013, 09:37)  PS. Если у кого будут замечания, буду рад услышать. Можно сделать буфер циклическим и выдавать результат усреднения на каждый входной отсчет, тогда частота выдачи результатов не уменьшится. Примерно так: CODE template <uint_fast8_t const samples, typename in_t = int16_t, typename sum_t = int32_t> class moving_average { public: moving_average(); void sample(in_t new_value); int_fast16_t result() { return Sum / samples; } uint_fast8_t length() { return samples; } private: in_t Buffer[samples]; uint_fast8_t Index; sum_t Sum; };
template <uint_fast8_t samples, typename in_t, typename sum_t> moving_average<samples, in_t, sum_t>::moving_average() : Index(0) , Sum(0) { memset(Buffer, 0, sizeof(Buffer)); }
template <uint_fast8_t samples, typename in_t, typename sum_t> void moving_average<samples, in_t, sum_t>::sample(in_t new_value) { Sum -= Buffer[Index]; Buffer[Index] = new_value; Sum += new_value; if(++Index >= samples) Index = 0; }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
Сообщений в этой теме
hd44780 Опять таймер, ADC и DMA на STM32F4 (Discovery) Feb 12 2013, 07:53 hd44780 Может из-за этого: ADC_InitStructure.ADC_NbrOfCo... Feb 12 2013, 08:56 hd44780 Вот, нашёл такое на одном из форумов:
CODE
// адр... Feb 13 2013, 08:24 hd44780 Вот так заработал:
Код DMA_InitStructure.DMA_Per... Feb 13 2013, 18:53 Сергей Борщ QUOTE (hd44780 @ Feb 13 2013, 20:53) Ошиб... Feb 14 2013, 07:22 hd44780 Да-а, видать не по сеньке шапка...... Ладно, я раз... Feb 14 2013, 07:04 digitAll А есть ли какие-нибудь заморочки при запуске АЦП о... May 20 2013, 08:19 hd44780 Вы задаёте АЦП триггер ADC_InitStructure.ADC_Exter... May 20 2013, 11:10 digitAll Нужен именно Т1.
TIM_GenerateEvent(TIM1, TIM_Even... May 20 2013, 11:25 digitAll Обобщаю вопрос:
Кто делал запуск АЦП по любому ADC... May 20 2013, 13:15
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|