Перейти к содержанию
    

STM32 АЦП. Пожалуйста помогите разобраться

Я начал разбираться с АЦП на STM32F4Discovery.

Вычитал, что у АЦП существуют два метода опроса: регулярные каналы и инжектированные каналы.

Разницу между ними я более менее понял. Первая группа запись данных в один регистр, вторая группа результат можно записать в один из 4-х регистров.

Я стараюсь писать код используя CMSIS.

К порту PA1 прикрутил переменный резистор, и по изменению значения должны зажигаться диоды на PD12, 13, 14, 15 но почему-то не работает, подскажите пожалуйста что не так.

Код:

#include "stm32f4xx.h"
uint32_t LED_STATE = 0xF000;
uint32_t res;
int main()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN|RCC_AHB1ENR_GPIODEN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
//GPIOA->MODER |= 0x0000000C;
GPIOD->MODER |= 0x55000000;
GPIOD->OTYPER |= 0;
GPIOD->OSPEEDR |= 0;
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_0); //Задаем время выборки
	 ADC1->CR2 |= ADC_CR2_JEXTSEL; //Преобразование инжектированной группы
	 ADC1->CR2 |= ADC_CR2_JEXTEN; //Разрешаем внешний запуск инжектированной группы
	 ADC1->CR2 |= ADC_CR2_CONT; //Преобразования запускаются одно за другим
	 ADC1->CR1 |= ADC_CR1_JAUTO;
	 ADC1->JSQR |= (1<<15); //Задаем номер канала - ADC1
	 ADC1->CR2 |= ADC_CR2_ADON;//Теперь включаем АЦП
	 ADC1->CR2 |= ADC_CR2_JSWSTART; //Запуск преобразований
	 while (!(ADC1->SR & ADC_SR_JEOC)); //ждем пока первое преобразование завершится
	 while(1)
{

	 res = ADC1->JDR1;
	 if (res > 1024)
	 {
			 GPIOD->ODR=LED_STATE;
	 }
	 }
}

Поскольку я разбираюсь в режимах преобразования, то я так же пробовал написать код и для регулярных каналов:

Код:

#include "stm32f4xx.h"
uint32_t LED_STATE = 0xF000;
int main()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN|RCC_AHB1ENR_GPIODEN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
GPIOA->MODER |= 0x0000000C;
GPIOD->MODER |= 0x55000000;
GPIOD->OTYPER |= 0;
GPIOD->OSPEEDR |= 0;

ADC1->SMPR2 |= (ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_0);
ADC1->CR2 |= ADC_CR2_EXTSEL;
ADC1->CR2 |= ADC_CR2_EXTEN;
ADC1->CR2 |= ADC_CR2_CONT;
ADC1->SQR1 |= (1<<15); //Задаем номер канала - ADC1
ADC1->CR2 |= ADC_CR2_ADON;//Теперь включаем АЦП
ADC1->CR2 |= ADC_CR2_SWSTART; //Запуск преобразований
while (!(ADC1->SR & ADC_SR_EOC)); //ждем пока первое преобразование завершится
uint32_t res;
while(1)
{
	 res = ADC1->DR;
	 if (res > 1024)
	 {
			 GPIOD->ODR=LED_STATE;
	 }
	 }
}

Но он тоже не работает(((

Если честно то я ковырял пример отсюда: http://blog.radiotech.kz/blog/52.html

И еще ну совсем нубский вопрос. Не могу понять связь между каналом АЦП и пином с которого я хочу снять сигнал. Объясните пожалуйста.

Мануал читал. Из него я понял, что на некоторых пинах висит АЦП, так кажется на PA1 висит ADC1, а что с каналами?

Спасибо!

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мануал читал. Из него я понял, что на некоторых пинах висит АЦП, так кажется на PA1 висит ADC1, а что с каналами?

 

Так там же и написано, какие каналы. Например "ADC123_IN1". Канал 1 для АЦП 1,2 и 3. Или "АDC12_IN7" - канал 7 для АЦП 1 и 2.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я начал разбираться с АЦП на STM32F4Discovery.

 

Во первых в первой проге заремарен GPIOA->MODER |= 0x0000000C;

во вторых RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_SYSCFGEN; надо ещё включить тактирование на SYSCFG

в третьих перед каждым забором данных из АЦП его надо запускать как я написал ниже. :)

 

ADC1->CR2 |= ADC_CR2_JSWSTART;

while (!(ADC1->SR & ADC_SR_JEOC));

ADC1->SR =0; // Очищаем флаг «преобразование завершено»

res = ADC1->JDR1;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Во первых в первой проге заремарен GPIOA->MODER |= 0x0000000C;

 

А я пытался сконфигурировать PA1 как альтернативную функцию.

 

в третьих перед каждым забором данных из АЦП его надо запускать как я написал ниже. sm.gif

 

ADC1->CR2 |= ADC_CR2_JSWSTART;

while (!(ADC1->SR & ADC_SR_JEOC));

ADC1->SR =0; // Очищаем флаг «преобразование завершено»

res = ADC1->JDR1;

Изменил код, но проблема не исчезла=(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А я пытался сконфигурировать PA1 как альтернативную функцию.

 

 

Изменил код, но проблема не исчезла=(

Полностью рабочий код инициализации ЦАП:

ADC1->CR2 |= ADC_CR2_CONT; //Преобразования запускаются одно за другим

ADC1->CR1 |= ADC_CR1_JAUTO | ADC_CR1_SCAN; //Разрешить автопреобразование инжектированной группы и SCAN означает брать номера каналов для сканирования из JSQR.

ADC1->JSQR |= (ADC_JSQR_JSQ4_0 ); //Задаем номер канала (выбран ADC1)

ADC1->CR2 |= ADC_CR2_ADON;//Теперь включаем АЦП

 

Здесь получаем данные:

ADC1->CR2 |= ADC_CR2_JSWSTART;

while (!(ADC1->SR & ADC_SR_JEOC));

ADC1->SR =0; // Очищаем флаг «преобразование завершено»

res = ADC1->JDR1;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полностью рабочий код инициализации ЦАП:

ADC1->CR2 |= ADC_CR2_CONT; //Преобразования запускаются одно за другим

ADC1->CR1 |= ADC_CR1_JAUTO | ADC_CR1_SCAN; //Разрешить автопреобразование инжектированной группы и SCAN означает брать номера каналов для сканирования из JSQR.

ADC1->JSQR |= (ADC_JSQR_JSQ4_0 ); //Задаем номер канала (выбран ADC1)

ADC1->CR2 |= ADC_CR2_ADON;//Теперь включаем АЦП

 

Здесь получаем данные:

ADC1->CR2 |= ADC_CR2_JSWSTART;

while (!(ADC1->SR & ADC_SR_JEOC));

ADC1->SR =0; // Очищаем флаг «преобразование завершено»

res = ADC1->JDR1;

Спасибо, большое, завтра попробую в камне.

А что насчет регулярных каналов? По идее те же яйца только в профиль.

ADC1->CR2 |= ADC_CR2_CONT; //Преобразования запускаются одно за другим
    ADC1->CR1 |= ADC_CR1_AUTO | ADC_CR1_SCAN; //Разрешить автопреобразование инжектированной группы и SCAN означает брать номера каналов для сканирования из JSQR.
    ADC1->JSQR |= (ADC_SQR_SQ4_0 ); //Задаем номер канала (выбран ADC1)
    ADC1->CR2 |= ADC_CR2_ADON;//Теперь включаем АЦП

Здесь получаем данные:
ADC1->CR2 |= ADC_CR2_SWSTART;
while (!(ADC1->SR & ADC_SR_EOC));
ADC1->SR =0; // Очищаем флаг «преобразование завершено»
res = ADC1->DR;

Наверно так, да?

И что на счет конфигурации пина PA1? надо его на альтернативную функцию настраивать? Ведь SYSCFG мы для тактирования альтернативных функций и включали.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там целая наука. Дело в том что инжектированных каналов может быть максимум 4 и каждый имеет свой регистр данных, а регулярных 16 и у них один регистр данных на всех. По этому данные из них можно читать либо по прерыванию (окончание преобразования) либо DMA. Здесь если всё писать то целая статья выйдет. Дело в том что АЦП не сложный, но навороченный. Например он может вызывать прерывания при достижении определённого уровня сигнала на входе и т.д. Скажу только про один момент с инжектированными каналами. В инжектированных каналах есть одно неудобство, когда конфигуришь один канал, то в регистр ADC1->JSQR надо заполнять его как четвёртый. Это многих сбивает с толку.

Да SYSCFG мы для тактирования альтернативных функций и включали. Но для конфигурации порта мы их не используем. Просто в модере включаем аналоговый режим. Альтернативные функции касаются таймеров уартсов и прочего что конфигурится в GPIOA->AFR. Здесь на всякий случай :).

Просьба, если всё запашет, то отпишитесь.

Изменено пользователем glags

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Просьба, если всё запашет, то отпишитесь.

#include "stm32f4xx.h"
uint32_t LED_STATE = 0xF000;
uint32_t res;
int main()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN|RCC_AHB1ENR_GPIODEN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN|RCC_APB2ENR_SYSCFGEN;
GPIOA->MODER |= 0x0000000C;
GPIOD->MODER |= 0x55000000;
GPIOD->OTYPER |= 0;
GPIOD->OSPEEDR |= 0;
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_0); //Задаем время выборки
	 ADC1->CR2 |= ADC_CR2_JEXTSEL; //Преобразование инжектированной группы
	 ADC1->CR2 |= ADC_CR2_JEXTEN; //Разрешаем внешний запуск инжектированной группы
	 ADC1->CR2 |= ADC_CR2_CONT; //Преобразования запускаются одно за другим
	 ADC1->CR1 |= ADC_CR1_JAUTO;
	 //ADC1->CR1 |= 0x00000020;
	 ADC1->JSQR |= ADC_JSQR_JSQ4_0; //Задаем номер канала - ADC1
	 ADC1->CR2 |= ADC_CR2_ADON;//Теперь включаем АЦП
	 while(1)
{
	 ADC1->CR2 |= ADC_CR2_JSWSTART; //Запуск преобразований
	 while (!(ADC1->SR & ADC_SR_JEOC)); //ждем пока первое преобразование завершится
	 ADC1->SR = 0; 
	 res = ADC1->JDR1;
	 if (res > 1024)
	 {
	   GPIOD->ODR = LED_STATE;
	 }
	 else
	 {
	   GPIOD->ODR ^= LED_STATE;
	 }
}
}

Ну эта бредятина работает в режиме отладки. Проблема была в JSQR.

С регулярными каналами пока бьюсь. Потом планирую перейти на прерывания по EOC

Вот не могу понять связь между JSQR и PA1 по какому принципу я должен выставлять биты в регистре, чтобы читать именно из этого пина?

 

Ну эта бредятина работает в режиме отладки. Проблема была в JSQR.

И не только)

GPIOD->ODR ^= LED_STATE;

- неправильно) У меня всегда диоды будут вкл)))

В общем инжектированные каналы работают) буду ковырять регулярные и прерывания затем.

 

буду ковырять регулярные и прерывания затем.

 

#include "stm32f4xx.h"
uint32_t LED_STATE = 0xF000;
uint32_t res;
int main()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN|RCC_AHB1ENR_GPIODEN;
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN|RCC_APB2ENR_SYSCFGEN;
GPIOA->MODER |= 0x0000000C;
GPIOD->MODER |= 0x55000000;
GPIOD->OTYPER |= 0;
GPIOD->OSPEEDR |= 0;
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_2 | ADC_SMPR2_SMP1_1 | ADC_SMPR2_SMP1_0); //Задаем время выборки
	 ADC1->CR2 |= ADC_CR2_EXTSEL; //Преобразование инжектированной группы
	 ADC1->CR2 |= ADC_CR2_EXTEN; //Разрешаем внешний запуск инжектированной группы
	 ADC1->CR2 |= ADC_CR2_CONT; //Преобразования запускаются одно за другим
	 ADC1->SQR3 |= ADC_SQR3_SQ1_0; //Задаем номер канала - ADC1
	 ADC1->CR2 |= ADC_CR2_ADON;//Теперь включаем АЦП
	 while(1)
{
	 ADC1->CR2 |= ADC_CR2_SWSTART; //Запуск преобразований
	 while (!(ADC1->SR & ADC_SR_EOC)); //ждем пока первое преобразование завершится
	 ADC1->SR = 0; 
	 res = ADC1->DR;
	 if (res > 1024)
	 {
	   GPIOD->ODR = LED_STATE;
	 }
	 else
	 {
	   GPIOD->BSRRH |= (1 << 15)|(1 << 14)|(1 << 13)|(1 << 12);
	 }
}
}

Собственно методом тыка заработали и регулярные каналы)))

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот не могу понять связь между JSQR и PA1 по какому принципу я должен выставлять биты в регистре, чтобы читать именно из этого пина?

 

Привожу таблицу зависимости между ADC_JDR1 и JSQR

 

Кол-во каналов (JL) ADC_JDR1 ADC_JDR2 ADC_JDR3 ADC_JDR4

4.................................JSQ1........JSQ2...........JSQ3........JSQ4

3.................................JSQ2........JSQ3...........JSQ4

2.................................JSQ3........JSQ4

1.................................JSQ4

Например если один канал, то заполняем биты JSQ4 и данные будут при этом читатся из ADC1->JDR1

В регистре JSQR 4 бита для JSQ4, если их заполнить 0011 это будет третий канал ADC что соответствует РА3.

Изменено пользователем glags

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здравствуйте. Я только осваиваю АЦП у STM32.

Поставил задачу. Имеем 2 канала IN0 и IN1 ADC1. Сделать регулярными каналами. Значения забирать из регистра данных через прерывания.

Когда пробовал с одним каналом, то всё хорошо. Для интереса замерил частоту преобразования ~27 кГц.

Когда стал пробовать уже два канала, то по идее частота не должна уменьшиться в 2 раза (если прерывание будет после преобразования каждого канала)? А она уже 14 кГц. Что меня наводит на мысль, что прерывание происходит после 2-х преобразований.

Как надо настроить ADC для правильного прерывания?

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

// ноги PA0 и PA1 по умолчанию настроены на вход

ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //Режим Регулярный Одновременный
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // режим сканирования 
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // многократное измерение
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // без внешнего триггера
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //выравнивание битов результат - прижать вправо
ADC_InitStructure.ADC_NbrOfChannel = 2; //количество каналов
ADC_Init(ADC1, &ADC_InitStructure);
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE); // прерывание от окончании преобразования

ADC_Cmd(ADC1, ENABLE); // включение ADC
// настройка канала
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);

// калибровка АЦП 
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));



/* NVIC configuration */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

прерывание

void ADC1_2_IRQHandler (void)
{
    ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
    switch(cnt_number_channel_ADC1++)
    {
    case 0: ADC1_IN0_Value = ADC1->DR;
            break;
    case 1: cnt_number_channel_ADC1 = 0;
            ADC1_IN1_Value = ADC1->DR;
            break;
    default: break;
    }
              // передаем
    FlagADC1 = 1;
}

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что меня наводит на мысль, что прерывание происходит после 2-х преобразований.

Как надо настроить ADC для правильного прерывания?

Почитать мануал:

The EOC bit is set in the ADC_SR register:

• At the end of each regular group sequence if the EOCS bit is cleared to 0

• At the end of each regular channel conversion if the EOCS bit is set to 1

PS. В линейке STM32 очень много семейств с совершенно различными АЦП. Лучше указывать конкретный камень.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если хотите читать несколько регулярных каналов то только по DMA.

Если не хотите DMA можно использовать инжектированные каналы.

Там до 4 каналов можно читать из разных регистров.

 

Вот из моих проектов два канала по DMA.

АЦП тактируется от TIM3.

Прерывание по DMA по заполнению половины буферы и всего буфера.

 

void InitADC(void)
{
ADC_InitTypeDef		ADC_InitStructure;
GPIO_InitTypeDef 	GPIO_InitStructure;
DMA_InitTypeDef 	DMA_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);

/* DMA1 channel1 configuration ----------------------------------------------*/
//DMA_DeInit(DMA1_Channel1);
//DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1->DR;
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
#warning check it
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = ADC_BUF_SIZE;
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_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_ClearITPendingBit(DMA1_IT_HT1);
DMA_ClearITPendingBit(DMA1_IT_TC1);

DMA_ITConfig(DMA1_Channel1, (DMA_IT_TC | DMA_IT_HT), ENABLE);
//DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, ENABLE);
/* Enable DMA1 channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);

   NVIC_InitTypeDef NVIC_InitStructure;
   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);
   NVIC_EnableIRQ(DMA1_Channel1_IRQn);

/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 2;
ADC_Init(ADC1, &ADC_InitStructure);

/* ADC1 regular channel Configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5);

ADC_ExternalTrigConvCmd(ADC1, ENABLE);

/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);

/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while (ADC_GetResetCalibrationStatus(ADC1));

/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while (ADC_GetCalibrationStatus(ADC1));

}


void InitTimer3(void)
{
TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;

/* TIM3 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 23999;	/// 1 khz clock required	nned to check core frequency
TIM_TimeBaseStructure.TIM_Prescaler = 2;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

/* TIM3 TRGO selection */
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);

/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
}


void DMA1_Channel1_IRQHandler(void)
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

if (DMA_GetITStatus(DMA1_IT_HT1))
{
	DMA_ClearITPendingBit(DMA1_IT_HT1);
	xSemaphoreGiveFromISR(xSemaphoreADC_DMA_HT, &xHigherPriorityTaskWoken );
}
if (DMA_GetITStatus(DMA1_IT_TC1))
{
	DMA_ClearITPendingBit(DMA1_IT_TC1);
	xSemaphoreGiveFromISR(xSemaphoreADC_DMA_TC, &xHigherPriorityTaskWoken );
}
DMA_ClearITPendingBit(DMA1_IT_GL1);
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Камень 103VG

То что лучше с DMA и по таймеру это понятно. Просто хотелось бы узнать есть такая возможность (регулярные и по прерыванию) или нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Камень 103VG

То что лучше с DMA и по таймеру это понятно. Просто хотелось бы узнать есть такая возможность (регулярные и по прерыванию) или нет.

В 103 бита EOCS нет. Поэтому EOC только после обработки всех регулярных каналов.

Но это не страшно: просто в прерывании настраивайте следующий канал и запускайте одиночное преобразование.

А потом переходите на DMA (если кГц преобразований важны).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...