Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/21: Рейтинг темы: голосов - 21, средняя оценка - 4.67
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
1

Опрос нескольких регулярных каналов АЦП STM32F100

20.11.2018, 09:17. Просмотров 3954. Ответов 30

Всем привет! Проблема с опросом нескольких регулярных каналов АЦП STM32F100 (Отл плата STM32F100VL Discouvery). На входы PA0 и PA1 повесил потенциометры. При пошаговой отладке в IAR данные из ADC1->DR в a[0] попадают, а вот a[1] по нулям, как потенциометр ни крути.
Читал, что такие вещи лучше делать через DMA, но хотелось бы для начала попробовать без него...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "stm32f10x.h"
 
int a[2],b=0;
 
void ADC1_IRQHandler () {
  
  if(ADC1->SR &ADC_SR_EOC) {
  
    
    GPIOC->BSRR |= GPIO_BSRR_BS9;
    a[b] = ADC1->DR;
    b++;
    ADC1->SR &= ~ADC_SR_EOC;
   
    if (b>=1) b=0;
    
  }
  
}
 
  
  
 
 
 
void  main () {
  
 
  
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);                      // Enable HSE
    while (!(RCC->CR & RCC_CR_HSERDY));                 // Ready start HSE      
    
    FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;          // Cloclk Flash memory
    
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;                    // AHB = SYSCLK/1
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;                   // APB1 = HCLK/1
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;                   // APB2 = HCLK/1
    
    RCC->CFGR &= ~RCC_CFGR_PLLMULL;                             // clear PLLMULL bits
    RCC->CFGR &= ~RCC_CFGR_PLLSRC;                      // clearn PLLSRC bits
    RCC->CFGR &= ~RCC_CFGR_PLLXTPRE;                    // clearn PLLXTPRE bits
    
    RCC->CFGR |= RCC_CFGR_PLLSRC_PREDIV1;                   // source HSE
    RCC->CFGR |= RCC_CFGR_PLLXTPRE_PREDIV1_Div2;                // source HSE/2 = 4 MHz
    RCC->CFGR |= RCC_CFGR_PLLMULL6;                     // PLL x6: clock = 4 MHz * 6 = 24 MHz
    
    RCC->CR |= RCC_CR_PLLON;                                    // enable PLL
    while((RCC->CR & RCC_CR_PLLRDY) == 0) {}                    // wait till PLL is ready
    
    RCC->CFGR &= ~RCC_CFGR_SW;                                  // clear SW bits
        RCC->CFGR |= RCC_CFGR_SW_PLL;                                   // select source SYSCLK = PLL
    while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_1) {}          // wait till PLL is used
        
        //Тактирование периферии
  
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_AFIOEN | RCC_APB2ENR_ADC1EN;
 
RCC->CFGR &= ~RCC_CFGR_ADCPRE; //АЦП тактируется без предделителя
 
 //Светодиод PC9 зеленый                       
GPIOC->CRH &= ~GPIO_CRH_MODE9;     GPIOC->CRH &= ~GPIO_CRH_CNF9; //MODE = 1,0; CNF = 0,0. Это General-purpose, Push-pull, 2MHz
GPIOC->CRH |= GPIO_CRH_MODE9_1; 
 
 
                                                                         //Настраиваем ADC1
 
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;
while (ADC1->CR2 & ADC_CR2_CAL);
NVIC_EnableIRQ(ADC1_IRQn);
ADC1->CR1 |= ADC_CR1_EOCIE;
ADC1->SMPR2 |= ADC_SMPR2_SMP1_0;
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT;
ADC1->SQR3 &= ~ADC_SQR3_SQ1;
ADC1->SQR3 |= ADC_SQR3_SQ2_0;
ADC1->SQR1 |= ADC_SQR1_L_1;
//ADC1->CR1 |= ADC_CR1_SCAN;
//ADC1->CR1 |= ADC_CR1_DISCNUM_0 | ADC_CR1_DISCEN;
ADC1->CR2 |= ADC_CR2_SWSTART;
 
  
  while(1) //Крутимся в бесконечном цикле
 
  {
    
  
  
}
  
  
  }
0
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.11.2018, 09:17
Ответы с готовыми решениями:

Порядок оцифровки групп регулярных каналов АЦП в режиме dual mode
Ситуация... моделирую на плате stm32f103c8t6 режим АЦП dual regular simultaneous only. Настроил...

Использование нескольких каналов АЦП
Всем привет. Пишу небольшую прогу для ATmega8, и возник вопрос как считывать данные сразу с двух...

AVR АЦП использование нескольких каналов
Кто пробовал использовать несколько каналов АЦП одновременно (ну, почти одновременно) - как это...

АЦП несколько каналов
Нужно замерять сигналы с трех выводов АЦП МК, как это сделать грамотно?

30
_SayHello
801 / 485 / 158
Регистрация: 30.07.2015
Сообщений: 1,601
20.11.2018, 11:58 2
Vozz, оптимизация включена? Если да, то попробуй
C
1
2
volatile int a[2];
volatile int b=0;
Добавлено через 31 минуту

C
1
2
3
4
5
6
7
8
9
10
11
12
13
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   //включили модуль, включили калибровку
while (ADC1->CR2 & ADC_CR2_CAL);                                 // Ждем конца калибровки, все ОК
NVIC_EnableIRQ(ADC1_IRQn);                                           // Настроили вектор прерываний, ОК
ADC1->CR1 |= ADC_CR1_EOCIE;                                       // Разрешили модулю прерывания по событию EOC
ADC1->SMPR2 |= ADC_SMPR2_SMP1_0;                            // Установили время измерения  для 1 канала 7,5 циклов. (а для канала 0?)
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_1;    // Тут вы зачем то поставили количество каналов в группе равным 3(?)
//ADC1->CR1 |= ADC_CR1_SCAN;
//ADC1->CR1 |= ADC_CR1_DISCNUM_0 | ADC_CR1_DISCEN;
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
Так вот когда нужно оцифровать группу, нужно использовать режим сканирования. Проблема тут единственная в том что, насколько я помню в режиме сканирования событие EOC возникает не после оцифровки каждого канала, а после оцифровки группы. А DR регистр один, то есть по прерыванию EOC в DR лежит результат измерения последнего канала в группе. Поэтому тут без DMA никак. Либо Настраивать на первый канал, дергать, забирать результат, перенастраивать на второй канал, дергать , забирать результат и так по кругу.


C
1
2
3
4
5
6
7
8
9
10
11
12
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   
while (ADC1->CR2 & ADC_CR2_CAL);                                 
NVIC_EnableIRQ(ADC1_IRQn);                                           
ADC1->CR1 |= ADC_CR1_EOCIE;                                       
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP2_0);                            // Установили время измерения  для 1 канала 7,5 циклов. (а для канала 0?)
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_0;    // Тут вы зачем то поставили количество каналов в группе равным 2!
ADC1->CR1 |= ADC_CR1_SCAN; // ражим сканирования
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
0
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
20.11.2018, 12:50  [ТС] 3
И правда, небольшая ссылочка под описанием бита SCAN в референс мануале . Да и в самом RM0041 прописано, ибо если используете несколько регулярных каналов, то только через DMA.
Второй вариант с ногодрыгом как-то не вызывает доверия ))) Дело в том, что DMA еще не юзал ни разу, а тут сразу АЦП через него... Ну, попробую, благо примеров много
0
_SayHello
801 / 485 / 158
Регистрация: 30.07.2015
Сообщений: 1,601
20.11.2018, 12:53 4
Vozz, да там не особо есть разница АЦП или не АЦП запускать с DMA. Оно почти везде одинаково. Если что скидывай код поправим
0
Serbis
19 / 19 / 2
Регистрация: 13.07.2012
Сообщений: 161
20.11.2018, 13:45 5
Vozz, вы меня конечно извините, но вот то что вы делаете это просто фантастика по современным меркам! Никогда в прикладных задачах не оперируют с аппаратной частью на уровне регистров, это чревато катастрофическими ошибками при увеличении объемов кода, а при работе с операционной системой на борту так вообще очень быстро приведет к серьезным гейзенбагам уже при двух-трех потоках. Прошивки пишут с использованием HAL(Hardware Abstraction Layer) - специального набора библиотек, задачей которого является максимальное абстрагирование от такого кода как у вас, сводя десятки строк подобного кода-лапши к функции HAL_ADC_GetValue(&hadc1). Самым мощным hal для stm32 на данный момент является оригинальный набор библиотек от ST Microelectronics идущий комплектом в пресловутом Stm32CubeMx. И изучать вопросы как работает ацп, нужно именно с позиции хала, попутно изучая код самих библиотечных функций, для общего понимания того, что же на самом делает низкоуровневый код.

Вот таких вот примеров кода в интернете масса, но проблема в том, что он не имеет никакой связью с реальностью, stm32 это довольно серьезные мк на которых решают прикладные задачи сильно отличающиеся от мигания светодиодом. У меня в практике есть прошивка состоящая из 22000 строк прикладного кода поверх HAL и FreeRTOS. Больше половины времени разработки были потрачены на отладочные мероприятия, если бы она писалась предлагаемыми методиками, то прошивка в релиз никогда бы и не вышла в принципе.

Поэтому мой вам совет, если хотите писать на данных мк что-то более серьезные чем снятие значение с канала ацп, изучайте данные мк со стороны CubeMx.
0
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
20.11.2018, 14:02  [ТС] 6
Ну тут уж на вкус и цвет ... Я видел код для TFT-дисплея, написанный на CMSIS и ничего... Кто-то плюется от SPL и HAL, предпочитая CMSIS, кто-то наоборот.
Для меня понятнее, заглянув в reference manual, видеть регистры и непосредственно биты в них.
0
_SayHello
801 / 485 / 158
Регистрация: 30.07.2015
Сообщений: 1,601
20.11.2018, 14:08 7
Serbis, не вводите ТСа и начинающих в заблуждение.
Цитата Сообщение от Serbis Посмотреть сообщение
а при работе с операционной системой на борту так вообще очень быстро приведет к серьезным гейзенбагам уже при двух-трех потоках.
Каким же образом функционирование/портирование FreeRTOS зависит от того какие либы ST вы используете? CMSIS как и HAL как и SPL это инструмент для работы с периферией контроллера. FreeRTOS из периферии использует только системный таймер. Остальное все - это софтварная оболочка.
Цитата Сообщение от Serbis Посмотреть сообщение
У меня в практике есть прошивка состоящая из 22000 строк прикладного кода поверх HAL и FreeRTOS. Больше половины времени разработки были потрачены на отладочные мероприятия, если бы она писалась предлагаемыми методиками, то прошивка в релиз никогда бы и не вышла в принципе
Это только ваши домыслы.

Цитата Сообщение от Serbis Посмотреть сообщение
Поэтому мой вам совет, если хотите писать на данных мк что-то более серьезные чем снятие значение с канала ацп, изучайте данные мк со стороны CubeMx.
HAL как и CMSIS как и SPL (до F7, L4 серии), LL являются равноправными инструментами которые поддерживает ST. Какой из них выбрать дело каждого.

Не по теме:

Топящих за CMSIS я уже видел, но ярые фаны HAL, да еще и в разработке - это что-то новенькое.

0
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
21.11.2018, 11:56  [ТС] 8
Первая тренировка с DMA поставила в тупик .

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "stm32f10x.h"
 
 
uint16_t Buffer[4];
int a,b;
 
 
void ADC1_IRQHandler() {
  
  if(ADC1->SR & ADC_SR_EOC) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS8;
    
  }
  
}
 
 
void DMA1_Channel1_IRQHandler() {
  
  if(DMA1->ISR & DMA_ISR_TCIF1) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS9;
    
  }
  
}
 
void init_GPIOs() { 
                                    
  //Светодиод PC9 зеленый                       
GPIOC->CRH &= ~GPIO_CRH_MODE9;     GPIOC->CRH &= ~GPIO_CRH_CNF9; //MODE = 1,0; CNF = 0,0. Это General-purpose, Push-pull, 2MHz
GPIOC->CRH |= GPIO_CRH_MODE9_1;    
  
  //Светодиод PC8 синий
GPIOC->CRH &= ~GPIO_CRH_MODE8;     GPIOC->CRH &= ~GPIO_CRH_CNF8; 
GPIOC->CRH |= GPIO_CRH_MODE8_1;  
  
}
 
 
void init_ADC1 () {
  
   //Настраиваем ADC1
 
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   
while (ADC1->CR2 & ADC_CR2_CAL);                                 
//NVIC_EnableIRQ(ADC1_IRQn);                                           
//ADC1->CR1 |= ADC_CR1_EOCIE;                                       
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP0_0);                            // Установили время измерения  для 1 и 0  канала 7,5 циклов.
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_0;    // 
ADC1->CR1 |= ADC_CR1_SCAN; // ражим сканирования
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
 
  
}
 
void init_DMA1()
{
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_InitTypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //направление передачи из периферии в память
    DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR; //Из АЦП...
    DMA1_Channel1->CMAR = (uint16_t)Buffer[4]; //Задаем адрес памяти - базовый адрес массива во флэше
    DMA1_Channel1->CNDTR = 1; //Количество пересылаемых значений = 4;//Размер буфера DMA1 = 10
    DMA1_Channel1->CCR |= DMA_CCR1_MINC;// Инкрементация памяти после каждой передачи включена
    DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;//Размерность данных периферии 16 бит
        DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;//Размерность данных памяти 16 бит
    DMA1_Channel1->CCR |= DMA_CCR1_PL; //Приоритет - очень высокий 
        DMA1_Channel1->CCR |= DMA_CCR1_CIRC; //Разрешаем работу DMA в циклическом режиме
        DMA1_Channel1->CCR |= DMA_CCR1_TCIE;//Разрешили прерывание после передачи 16 байт
        NVIC_EnableIRQ(DMA1_Channel1_IRQn); //общее разрешение прерываний
        DMA1_Channel1->CCR |= DMA_CCR1_EN; //Разрешаем работу 1-го канала DMA
        
}
 
void main()
{
  
        RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_ADC1EN;
        RCC->AHBENR |= RCC_AHBENR_DMA1EN;
        
        RCC->CFGR &= ~RCC_CFGR_ADCPRE; //АЦП тактируется без предделителя
 
        init_GPIOs();
        init_ADC1();
    init_DMA1();
        __enable_irq();
    while(1);
}
Задача в том, чтобы передавать данные из АЦП в переменную buffer через DMA, но DMA1_CMAR1 почему то чист, а CPAR переполняется буквально. Все как по референс мануалу, а не работает, где ошибся .

Добавлено через 35 секунд
0
_SayHello
801 / 485 / 158
Регистрация: 30.07.2015
Сообщений: 1,601
21.11.2018, 12:15 9
Лучший ответ Сообщение было отмечено Vozz как решение

Решение

Vozz, пока в регистры DMA не смотрел, а вот в настройке АЦП не увидел выставления бита разрешения DMA
C
1
ADC1->CR2 |= ADC_CR2_DMA;
Ну и чистить за собой флажок DMA не забываем
C
1
DMA1->IFCR |= DMA_IFCR_TCIF1;
Добавлено через 8 минут
Vozz, едем дальше
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void init_DMA1()
{
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_InitTypeDef DMA_InitStruct;
    DMA_StructInit(&DMA_InitStruct);
    DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //направление передачи из периферии в память
    DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR; //Из АЦП...
// Вот тут ошибки
    DMA1_Channel1->CMAR = Buffer; //Задаем адрес буффера, а не ячейки!
    DMA1_Channel1->CNDTR = 2; //Количество пересылаемых значений = 2 так как 2 канала
/****************************************************************************/
    DMA1_Channel1->CCR |= DMA_CCR1_MINC;// Инкрементация памяти после каждой передачи включена
    DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;//Размерность данных периферии 16 бит
        DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;//Размерность данных памяти 16 бит
    DMA1_Channel1->CCR |= DMA_CCR1_PL; //Приоритет - очень высокий 
        DMA1_Channel1->CCR |= DMA_CCR1_CIRC; //Разрешаем работу DMA в циклическом режиме
        DMA1_Channel1->CCR |= DMA_CCR1_TCIE;//Разрешили прерывание после передачи 16 байт
        NVIC_EnableIRQ(DMA1_Channel1_IRQn); //общее разрешение прерываний
        DMA1_Channel1->CCR |= DMA_CCR1_EN; //Разрешаем работу 1-го канала DMA
}
1
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
21.11.2018, 14:11  [ТС] 10
Йесс, в CMAR1 появились данные от АЦП и загорелся зеленый светодиод на отладочной плате, что сигнализирует об окончании передачи 16 бит. В переменной Buffer валяются значения АЦП. Еще пару косяков у себя обнаружил, экпериментируем дальше)

Добавлено через 2 минуты
Да, спасибо уже увидел косяки, отладчик подсказывал предупреждением

Добавлено через 15 минут
Все, добил код. Надеюсь, если такой же новичек, как я будет ломать голову, то мой пример ему поможет). На PA0 и PA1 у меня висит по потенциометру. запитал их тут же на отладочной плате от 3,3В оба канала опрашивается нормально, прерывание DMA добавил просто по факту, чтобы его отследить (срабатывает или нет).

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "stm32f10x.h"
 
 
uint16_t Buffer[2];
int a,b;
 
 
void ADC1_IRQHandler() {
  
  if(ADC1->SR & ADC_SR_EOC) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS8;
    
  }
  
}
 
 
void DMA1_Channel1_IRQHandler() {
  
  if(DMA1->ISR & DMA_ISR_TCIF1) {
    
    GPIOC->BSRR |= GPIO_BSRR_BS9;
    
    
  }
  
}
 
void init_GPIOs() { 
                                    
  //Светодиод PC9 зеленый                       
GPIOC->CRH &= ~GPIO_CRH_MODE9;     GPIOC->CRH &= ~GPIO_CRH_CNF9; //MODE = 1,0; CNF = 0,0. Это General-purpose, Push-pull, 2MHz
GPIOC->CRH |= GPIO_CRH_MODE9_1;    
  
  //Светодиод PC8 синий
GPIOC->CRH &= ~GPIO_CRH_MODE8;     GPIOC->CRH &= ~GPIO_CRH_CNF8; 
GPIOC->CRH |= GPIO_CRH_MODE8_1;  
  
}
 
 
void init_ADC1 () {
  
   //Настраиваем ADC1
 
ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_CAL;   
while (ADC1->CR2 & ADC_CR2_CAL);                                 
//NVIC_EnableIRQ(ADC1_IRQn);                                           
//ADC1->CR1 |= ADC_CR1_EOCIE;                                       
ADC1->SMPR2 |= (ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP0_0);                            // Установили время измерения  для 1 канала 7,5 циклов. (а для канала 0?)
ADC1->CR2 |= ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG | ADC_CR2_CONT; // вклюдили программный триггер и установили круговой режим
//Формируем список каналов
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1
ADC1->SQR1 |= ADC_SQR1_L_0;    // Тут вы зачем то поставили количество каналов в группе равным 2!
ADC1->CR1 |= ADC_CR1_SCAN; // ражим сканирования
ADC1->CR2 |= ADC_CR2_SWSTART; // Ну и пинаете АЦП в первый раз.
ADC1->CR2 |= ADC_CR2_DMA;
 
  
}
 
void init_DMA1()
{
    
    
    DMA1_Channel1->CCR &= ~DMA_CCR1_DIR; //направление передачи из периферии в память
    DMA1_Channel1->CPAR |= (uint32_t)&ADC1->DR; //Из АЦП...
    DMA1_Channel1->CMAR = (uint32_t)Buffer; //Задаем адрес памяти - базовый адрес массива во флэше
    DMA1_Channel1->CNDTR = 2; //Количество пересылаемых значений = 2
    DMA1_Channel1->CCR |= DMA_CCR1_MINC;// Инкрементация памяти после каждой передачи включена
    DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_0;//Размерность данных периферии 16 бит
        DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_0;//Размерность данных памяти 16 бит
    DMA1_Channel1->CCR |= DMA_CCR1_PL; //Приоритет - очень высокий 
        DMA1_Channel1->CCR |= DMA_CCR1_CIRC; //Разрешаем работу DMA в циклическом режиме
        DMA1_Channel1->CCR |= DMA_CCR1_TCIE;//Разрешили прерывание после передачи 16 байт
        NVIC_EnableIRQ(DMA1_Channel1_IRQn); //общее разрешение прерываний
        DMA1_Channel1->CCR |= DMA_CCR1_EN; //Разрешаем работу 1-го канала DMA
        
}
 
void main()
{
  
        RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_ADC1EN;
        RCC->AHBENR |= RCC_AHBENR_DMA1EN;
        
        RCC->CFGR &= ~RCC_CFGR_ADCPRE; //АЦП тактируется без предделителя
 
        init_GPIOs();
        init_ADC1();
    init_DMA1();
        __enable_irq();
    while(1);
}
Спасибо за помощь!

Добавлено через 1 час 31 минуту
Без DMA тут получилась бы солянка. Удобно тем, что DMA по настройкам сам формирует кольцевой буфер. Его можно зациклить, можно сделать один проход ... и заполнить массив ну и плюс процессор не напрягается
0
_SayHello
801 / 485 / 158
Регистрация: 30.07.2015
Сообщений: 1,601
21.11.2018, 14:14 11
Vozz,
Цитата Сообщение от Vozz Посмотреть сообщение
Без DMA тут получилась бы солянка. Удобно тем, что DMA по настройкам сам формирует кольцевой буфер. Его можно зациклить, можно сделать один проход ... и заполнить массив ну и плюс процессор не напрягается
Именно это является огромным плюсом STM. Практически к каждой периферии можно приделать так или иначе DMA. Если научиться с ним работать, то можно избежать многих костылей и косяков в будущем.
0
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
21.11.2018, 14:25  [ТС] 12
Хотел поначалу использовать инжектированные каналы АЦП, но их всего 4... EXTI тоже всего 4 входа можно сделать (для регулирования выходного напряжения приделать инкрементальные энкодеры), а нужно 12 каналов, вот DMA и помог.
0
locm
2422 / 1084 / 136
Регистрация: 28.10.2011
Сообщений: 3,601
Записей в блоге: 6
21.11.2018, 17:51 13
Цитата Сообщение от Vozz Посмотреть сообщение
(для регулирования выходного напряжения приделать инкрементальные энкодеры
С ними таймеры работают.
0
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
21.11.2018, 18:19  [ТС] 14
Я думаю и через EXTIn можно ...
0
locm
2422 / 1084 / 136
Регистрация: 28.10.2011
Сообщений: 3,601
Записей в блоге: 6
21.11.2018, 20:18 15
Зачем использовать программную работу с энкодером, если он аппаратно поддерживается?
0
_SayHello
801 / 485 / 158
Регистрация: 30.07.2015
Сообщений: 1,601
21.11.2018, 20:35 16
Vozz, это как и ацп без дма, можно настраивать один канал и в прерывании перенастраивать. А можно использовать аппаратный ДМА.
Тут точно так же, зачем нагружать ядро, если есть специальный инструмент для работы с энкодерами.
0
Voland_
1758 / 1090 / 108
Регистрация: 04.01.2010
Сообщений: 3,782
27.11.2018, 09:59 17
Цитата Сообщение от _SayHello Посмотреть сообщение
ADC1->SQR3 &= ~ADC_SQR3_SQ1; // Первый для оцифровки канал 0
ADC1->SQR3 |= ADC_SQR3_SQ2_0; // Вторым идет канал 1

Не по теме:

что называется, "приехали"... )) Как же удобно было раньше на SPL'е...



Добавлено через 40 секунд
Vozz, почему вы не используете SPL, HAL и или готовые библиотеки?
0
_SayHello
801 / 485 / 158
Регистрация: 30.07.2015
Сообщений: 1,601
27.11.2018, 10:07 18
Voland_,
Цитата Сообщение от Voland_ Посмотреть сообщение
что называется, "приехали"... )) Как же удобно было раньше на SPL'е...
А что тут такого?)
Это не SPL, это CMSIS)
0
Vozz
1 / 1 / 0
Регистрация: 22.06.2016
Сообщений: 94
27.11.2018, 12:32  [ТС] 19
Цитата Сообщение от Voland_ Посмотреть сообщение
почему вы не используете SPL, HAL и или готовые библиотеки?
Если пишешь через CMSIS, то приходится частенько заглядывать в мануал. Таким образом лучше запоминается принцип работы отдельных модулей контроллера, регистры, биты в них.
Да, это дольше, чем через библиотеки, но никаких срочных проектов у меня нет. Разбираться в коде легче, если что-то не прет. Вот так получилось, что полюбился мне CMSIS
1
Voland_
1758 / 1090 / 108
Регистрация: 04.01.2010
Сообщений: 3,782
27.11.2018, 13:37 20
Цитата Сообщение от _SayHello Посмотреть сообщение
А что тут такого?)
Это не SPL, это CMSIS)
Та я в курсе ). Просто я так понимаю, идея с портацией кода от чипа к чипу (как у AVR) у STM32 с треском провалилась, ввиду невозможности реализации идеи - народ "не оценил" SPL. а так вообще - HAL и SPL - попытки сделать код универсальным, как на R_Pi, или еще что-то там.

PS: просто для новичка (на платформах ST) использование трушных регистров довольно муторное дело.
0
27.11.2018, 13:37
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
27.11.2018, 13:37

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Переключение каналов АЦП atmega88
Добрый день. В который раз сталкиваюсь с АЦП на меге и никак не могу понять как правильно...

Большое количество АЦП каналов
Здравствуйте! Подскажите микроконтроллеры с количеством АЦП 50 или больше каналов. И есть ли...

Защита каналов АЦП от импульсных помех
На входы ацп МК подаются сигналы обратной связи с двигателя и необходимо защитить АЦП от импульсных...

Данные с двух каналов АЦП по очередно.[Решено]
Всем привет. Столкнулся с непоняткой, чип stm8s003f на время теста подцепил два переменных...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.