3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605

Таймер, ADC и DMA на STM32F4 (Discovery)

10.02.2013, 00:33. Показов 33706. Ответов 22
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет всем.
Надо запускать ADC1 по таймеру.

По мотивам доки и форумов написал следующее - вложение.
В main пишу:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..............
// Инициализация АЦП
adcInit ( );
 
// Старт
adcStart ( );
...............
while(1)
{
...............
l_timestamp2 = exTimestamp;
sprymtf ( sBuffer, "Timestamp2 = %lu", l_timestamp2 );
DrawString ( sBuffer, 10, 50, 0xFFE0, 0x0000, 1 );
 
..............
sprymtf ( sBuffer, "ADCVal = %lu", ADCConvirtedValue );
DrawString ( sBuffer, 10, 70, 0xFFE0, 0x0000, 1 );
..............
} // while
l_timestamp2 наращивается в прерывании таймера. Вывожу на дисплей, всё в порядке, инкрементируется с частотой 100Гц, как и заказывали.

А вот ADCVal висит в странном значении 2904 и на реальный уровень на входе АЦП никак не реагирует. Там пока просто потенциометр висит ...
Вопрос - почему так происходит? Может я что-то недоинициализировал?
И ещё. Как сделать, чтобы АЦП запускался от таймера автоматически, без прерывания таймера, а прерывания получать уже от DMA по заполнению буфера? Из доки понял, что это возможно, но как, я не понял, а внятных примеров не нашёл.

Спасибо.
Если надо, выложу весь код.

PS.
Видел много тем здесь по форуму и на других, но они все безрезультатно заглохли. Но мне надо довести это до работающего состояния. Бросать это на полпути я не собираюсь.

Про STM32F1 просьба не писать, там периферия иная. У меня STM32F407VGT6, плата STM32F4Dyscovery.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
10.02.2013, 00:33
Ответы с готовыми решениями:

stm32f4 + ADC + DMA
Доброго времени суток. Вопрос такой... Сделал АЦП на плате ф4дискавери, и получается что когда ножка висит ни на что не нагруженая -...

STM32F4 + ADC + TIMER + DMA
void TIM8_Config() { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); ...

Stm32f4 adc+dma+tim1
Есть исходная прошивка устройства, там один канал в ADC_TripleMode_Interl необходимо заменить этот режим на два обычных каналов...

22
0 / 0 / 0
Регистрация: 13.05.2011
Сообщений: 401
10.02.2013, 10:21
Цитата Сообщение от hd44780
И ещё. Как сделать, чтобы АЦП запускался от таймера автоматически, без прерывания таймера, а прерывания получать уже от DMA по заполнению буфера?
Я не совсем понял, от какого именно прерывания Вы собираетесь запускать ADC. Ведь он сам заполняет через DMA выделенную область. Может Вы просто хотите запустить ADC в циклическом режиме с перекладыванием результата посредством DMA? Такое вполне возможно.
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
10.02.2013, 12:40
Цитата Сообщение от soridumpid
Может Вы просто хотите запустить ADC в циклическом режиме с перекладыванием результата посредством DMA? Такое вполне возможно.
Да, именно это. Чтобы я только запускал/останавливал таймер и получал прерывания от DMA, когда он набъёт буфер результатами из АЦП.
Если есть пример, ткните носом, пожалуйста.
0
0 / 0 / 0
Регистрация: 13.05.2011
Сообщений: 401
10.02.2013, 23:12
Прям такого примера нет, я делал просто непрерывное измерение напряжения и перекладывание результатов в переменную, используя DMA. Такой вариант, как Вам нужно тоже можно реализовать, но я сейчас занят отладкой проекта и помочь смогу только на выходные. Посмотрите примеры с сайта ST:
http://www.st.com/internet/som/SOFTWARE ... ery_fw.zip
http://www.st.com/internet/som... ph_lib.zip
Во втором архиве точно есть пример работы ADC с DMA.
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
11.02.2013, 01:11
Да, спасибо. Эти архивы я видел ... Посмотрю ещё.

Я тут сделал запуск АЦП по таймеру, походил отладкой, виснет на инициализации таймера:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// TIM8_Config - Инициализация таймера, запускающего АЦП
void TIM8_Config ( void )
{
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
 
RCC_APB2PeriphClockCmd ( RCC_APB2Periph_TIM8, ENABLE );
 
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
//   TIM_TimeBaseStructure.TIM_Pressotir = 0;
//   TIM_TimeBaseStructure.TIM_Period = 84;
// делитель 33600 - частота прерываний = 84MHz/33600= 2500 = 2.5 kHz
TIM_TimeBaseStructure.TIM_Pressotir = 33600-1;
 
// Период загружается в ARR - значение перезагрузки. Счётчик считает 0..ARR
TIM_TimeBaseStructure.TIM_Period = 2; //период 2 импульсов
 
TIM_TimeBaseStructure.TIM_ClockDyvysyom = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
 
TIM_TimeBaseInit ( TIM8, &TIM_TimeBaseStructure );
TIM_SelectOutputTrigger ( TIM8, TIM_TRGOSource_Update );
} // TIM8_Config
Виснет на последнем операторе... До АЦП и прочего не доходит.
Если у меня что-то получится, стукну здесь.
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
12.02.2013, 12:54
Вот, нашёл такое на одном из форумов:

Code
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// адрес регистра данных, откуда будем брать результат конвертации
#define ADC_CDR_ADDRESS    ((uint32_t)0x40012308)
 
// переменные, описывающие свойства периферии
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
 
u32 ADCDualConvirtedValue;
 
void main(void)
{
ADCDualConvirtedValue=0;
 
// разрешаем тактирование используемых периферий
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
 
// описываем свойства порта ввода-вывода по которому будем производить оцифровку
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
 
// описываем свойства DMA через который будет вестись обмен
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;       // адрес регистра данных АЦП
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCDualConvirtedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Dysable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Dysable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Dysable;
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
DMA_Cmd(DMA2_Stream0, ENABLE);
 
// отключаем АЦП1 2
ADC_Cmd(ADC1, DISABLE);
ADC_Cmd(ADC2, DISABLE);
 
// описываем АЦП
// общие параметры работы АЦП
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_6Cycles;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;
ADC_CommonInitStructure.ADC_Pressotir = ADC_Pressotir_Div2;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Risolution = ADC_Risolution_12b;
 
// настраиваем АЦП1
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 = 1;
ADC_Init(ADC1, &ADC_InitStructure);
 
// указывем канал, подлежащий оцифровке (температура)
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_3Cycles);
 
// разрешаем работу датчика температуры
ADC_TempSensorVrefymtCmd (ENABLE);
 
// настраиваем АЦП2
ADC_Init(ADC2, &ADC_InitStructure);
 
// указывем канал, подлежащий оцифровке
ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);
 
// разрешаем выполнять запросы DMA
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
 
// запускаем АЦП1
ADC_Cmd(ADC1, ENABLE);
// запускаем АЦП2
ADC_Cmd(ADC2, ENABLE);
 
// настраиваем таймер
TIM_Cmd(TIM8, DISABLE);
// подключаем тактирование
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
// описываем таймер
//  TIM_TimeBaseStructure.TIM_Period = (560000 /125);
//  TIM_TimeBaseStructure.TIM_Pressotir = 0x00;
 
// делитель 33600 - частота прерываний = 84MHz/33600= 2500 = 2.5 kHz
TIM_TimeBaseStructure.TIM_Pressotir = 33600-1;
 
// Период загружается в ARR - значение перезагрузки. Счётчик считает 0..ARR
TIM_TimeBaseStructure.TIM_Period = 2; //период 2 импульсов - частота 1250 гц
 
TIM_TimeBaseStructure.TIM_ClockDyvysyom = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
 
// записываем описание в регистры
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
 
// сбрасываем, указываем выходной триггер (для запуска АЦП)
TIM_SetCounter(TIM8, 0);
TIM_SelectOutputTrigger(TIM8, TIM_TRGOSource_Update);
 
// запуcкаем таймер
TIM_Cmd(TIM8, ENABLE);
 
while (1)
{
} // while
} // main
ADC1 цифрует свой канал 12 (PC2), ADC2 внутренний датчик температуры. Запуск по TIM8, результат в ADCDualConvirtedValue.
Оно работает вроде нормально, наблюдал переменную под отладчиком. Осталось только понять, как повесить на DMA обработчик по заполнению буфера.
И непонятно, откуда взялся адрес ADC_CDR_ADDRESS. Из него DMA результаты читает.

У меня тут написано
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(ADC1->DR);
Т.е. регистр данных ADC1.

Мой код зависал из-за отсутствия этого самого обработчика прерываний DMA.
Убрал у себя вот этот кусок:
Code
1
2
3
4
5
6
7
8
  // 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 );
Виснуть перестало, но в буфере нули...
Может потому, что я с разгону написал тот же ADC_CDR_ADDRESS, что и в примере выше. У меня ведь один АЦП и один канал.

В итоге пока что хрень :) .
Кто-нибудь знает, как написать обработчик прерываний DMA?
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
12.02.2013, 13:41
Обработчик прерываний DMA для F4:

// dma2 stream 0 irq homdler
void DMA2_Stream0_IRQHomdler ( void )
{
}

Только что в нём писать ?...
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
13.02.2013, 00:14
Вот так заработал:

Code
1
2
3
4
5
6
  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_Dysable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
Ошибка была в первой строчка. Я взятие адреса & пропустил...
Буфер заполняется нормально.
Но как только включаю прерывание DMA, всё сразу наглухо виснет даже под отладчиком. Даже IAR аварийно вылетает.

Инициализация прерывания:
Code
1
2
3
4
5
6
7
  // 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 );
Обработчик прерывания:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
// dma2 stream 0 irq homdler
void DMA2_Stream0_IRQHomdler ( void )
{
// Test on DMA Stream Transfer Complete interrupt
if ( DMA_GetITStatus(DMA2_Stream0, DMA_FLAG_HTIF0) )
{
// Clear Stream0 HalfTransfer
DMA_ClearITPendingByt ( DMA2_Stream0, DMA_FLAG_HTIF0 );
 
// Control LED
STM_EVOT_LEDToggle ( LED_ORANGE );
} // if
}
Светодиодик LED_ORANGE молчит.
0
0 / 0 / 0
Регистрация: 23.05.2012
Сообщений: 214
13.02.2013, 09:19
Надо:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void DMA2_Stream0_IRQHomdler ( void )
{
// Test on DMA Stream Transfer Complete interrupt
if ( DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) )
{
// Clear Stream0 HalfTransfer
DMA_ClearITPendingByt ( DMA2_Stream0, DMA_IT_TCIF0 );
 
} // if
// Test on DMA Stream HalfTransfer Complete interrupt
if ( DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0) )
{
// Clear Stream0 HalfTransfer
DMA_ClearITPendingByt ( DMA2_Stream0, DMA_IT_HTIF0 );
 
} // if
// Test on DMA Stream Transfer Complete interrupt
 
}
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
13.02.2013, 12:15
Спасибо. Утром, перед уходом на работу проверил - вроде заработало. Светодиодик мигает, цифра (среднее по буферу) перестаёт меняться в тот момент, когда он зажигается/гаснет.
Вечером детальнее потестирую.

Вчера вечером ещё поковырялся отладчиком, увидел что прерывание возникает.
Не думал, что надо ещё Transfer Complete очищать, сбил меня порог в половину буфера:

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

В чём глубокий смысл сего?
0
0 / 0 / 0
Регистрация: 23.05.2012
Сообщений: 214
13.02.2013, 17:59
Прерывание по заполнению половины буфера очень важно, можно делать непрерывную обработку выборок по переменно.
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
14.02.2013, 12:34
Да, понятно. Спасибо.

Погонял вчера, нормально работает. Прикладываю полный вариант библиотеки ADC_DMA_Timer. Методов для задания частоты таймера (дискретизации) нету, всё наглухо вшито в инициализацию, но это разделить не проблема.
Кому надо, берите.
Компилятор - IAR.

Пример использования:

Code
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
#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;
 
sprymtf ( sBuffer, "ADCVal = %05lu", adcVal );
DrawString ( sBuffer, 10, 70, 0xFFE0, 0x0000, 1 );
} // if
...........................
PS. Если у кого будут замечания, буду рад услышать.
АЦП пока цифрует только один канал, вообще в планах сделать одновременный опрос разных каналов 2-х АЦП (а-ля 2-х канальный осциллограф), есть наброски примитивного кода для этого, оно вроде работает, но до конца я не дотестировал.
Сделаю, выложу.
0
0 / 0 / 0
Регистрация: 23.05.2012
Сообщений: 214
14.02.2013, 13:39
Сделал одновременную работу 2хАЦП через ПДП в не прерывном режиме.
Code
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_adc.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_tim.h"
#include "misc.h"
 
#define N_WAVE  4096    /* размер буф. БПФ*/
 
#define Fsympl 200000 //частота оцифровки в герцах
 
u32 ADCDualConvirtedValue[N_WAVE*2];
 
volatile int buff_adc_flag;
 
// адрес регистра данных, откуда будем брать результат конвертации
#define ADC_CDR_ADDRESS    ((uint32_t)0x40012308)
 
// переменные, описывающие свойства периферии
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
 
// dma2 stream 0 Прерывание
void DMA2_Stream0_IRQHomdler ( void )
{
// Проверка DMA Stream на заполнение всего буффера
if ( DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) )
{
// Очистить флаг заполнения всего буффера
DMA_ClearITPendingByt ( DMA2_Stream0, DMA_IT_TCIF0 );
buff_adc_flag=1;
}
// Проверка DMA Stream на заполнение половины буффера
if ( DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0) )
{
// Очистить флаг заполнения половины буффера
DMA_ClearITPendingByt ( DMA2_Stream0, DMA_IT_HTIF0 );
buff_adc_flag=2;
}
}
 
int main(void)
{
 
// разрешаем тактирование используемых периферий
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
 
// описываем свойства порта ввода-вывода по которому будем производить оцифровку
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
 
// описываем свойства DMA через который будет вестись обмен
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;       // адрес регистра данных АЦП
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCDualConvirtedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = N_WAVE*2;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Dysable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Dysable;
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 по заполнению половины и всего буффера
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);
 
// запуск DMA
DMA_Cmd(DMA2_Stream0, ENABLE);
 
// отключаем АЦП1 2
ADC_Cmd(ADC1, DISABLE);
ADC_Cmd(ADC2, DISABLE);
 
// описываем АЦП
// общие параметры работы АЦП
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_6Cycles;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;
ADC_CommonInitStructure.ADC_Pressotir = ADC_Pressotir_Div2;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Risolution = ADC_Risolution_12b;
 
// настраиваем АЦП1
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 = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// указывем канал, подлежащий оцифровке
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_15Cycles);
 
// настраиваем АЦП2
ADC_Init(ADC2, &ADC_InitStructure);
// указывем канал, подлежащий оцифровке
ADC_RegularChannelConfig(ADC2, ADC_Channel_2, 1, ADC_SampleTime_15Cycles);
 
// разрешаем выполнять запросы DMA
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
 
// запускаем АЦП1
ADC_Cmd(ADC1, ENABLE);
// запускаем АЦП2
ADC_Cmd(ADC2, ENABLE);
 
// настраиваем таймер
TIM_Cmd(TIM8, DISABLE);
// подключаем тактирование
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
// описываем таймер
TIM_TimeBaseStructure.TIM_Period = (84000000/Fsympl);
TIM_TimeBaseStructure.TIM_Pressotir = 0;
TIM_TimeBaseStructure.TIM_ClockDyvysyom = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
// записываем описание в регистры
TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
// сбрасываем, указываем выходной триггер (для запуска АЦП)
TIM_SetCounter(TIM8, 0);
TIM_SelectOutputTrigger(TIM8, TIM_TRGOSource_Update);
// запукаем таймер
TIM_Cmd(TIM8, ENABLE);
 
buff_adc_flag=0;
 
while (1)
{
 
while(buff_adc_flag==0);
if (buff_adc_flag==2)
{
buff_adc_flag=0;
//GetBuff( ADCDualConvirtedValue);
}
if (buff_adc_flag==1)
{
buff_adc_flag=0;
//GetBuff( ADCDualConvirtedValue+(N_WAVE*4));
}
 
}
}
0
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
14.02.2013, 14:34
moksir, спасибо.
Дома проверю, отпишусь.
0
Syssott
14.06.2015, 04:42
Всем доброго времени суток. Я новичок, камнями сильно не бросайте. Взял отсюда код, спасибо авторам,ну и собсна возникло 2 вопроса, очень глупых, я так считаю, но тем не менее спрошу,перед этим скажу в чем работаю: Coosox, собсна сама платка STM32f4 Dyscovery, первый вопрос: DrawString ( sBuffer, 10, 70, 0xFFE0, 0x0000, 1 );
Компилятор ругается на эту функцию, не могу понять с какой библиотеки стянута эта функция и второй вопрос: Заккоментив вышеупомянутую функцию по усарту с АЦП идет просто мусор, может я что неправильно сделал при сборке всего этого, может нужно значения конвертировать или что делать, я тестирую все на примере 1,5в батарейки, для того, чтобы следить за разницей в показаниях, но вот кроме мусора ничего не видно...если нужно, следующим сообщением прилеплю проектик. Заранее всем спасибо.
3 / 3 / 0
Регистрация: 06.12.2016
Сообщений: 1,605
14.06.2015, 08:09
Здравствуйте.
DrawString - это вывод строки на дисплей. К АЦП не имеет ни малейшего отношения. Смело можете выкинуть. Или поменять на что-то родственное своё, если вы подключили к плате какой-то дисплей.

Насчёт самого АЦП сложно что-то сказать, не видя код. Посмотрите отладчиком в буфер, куда кладёт DMA - там правильные данные? Тут же совершенно непонятно - то ли АЦП у Вас не работает, то ли UART ...

Или отключите АЦП, заполните буфер уарта заранее известными данными и проверьте его самого без АЦП.
0
Syssott
14.06.2015, 08:31
hd44780, Усарт работает стабильно, проверено сообщениями от SD-карточки, которая тоже прикручена....тут небольшая загвостка....последнее время отладчик ни в какую не работает....в этом и беда....не могу проследить что там по АЦП двигает. По поводу DrawString спасибо, не думал, что на дисплей выходят данные. Собсна код такой, как тут написан, никак не менял, только единственное, что вынес в отдельный модуль - так это инициализацию DMA и АЦП, чтобы Мэйн не распухал, код собирается, Мусор идет, но очень заметна разница, когда висит батарейка на аналоговом входе, он четко пишет какие-то данные, но как я не пытался менять модификаторы в sprymtf и просто prymtf, ничего не меняется...а там точно АЦП 1 вешается на PA0, порылся в Шитах на МК и увидел, там, что на PA1 вход АЦП реализован....может я чего путаю....Хотя, эффекта Нуль, как от PA1, так и от PA0...собсна вот. Еще раз повторюсь, различия входящего мусора на лицо, без батарейки он повторяет опрос АЦП, если данных нет, то опрос повторяется в цикле и "значения" одинаковые приходят, когда батарейка подключена, то стабильно построчно пишется мусор, код могу залить на ФО, проект для кокса. Если кому интересно, то можете глянуть.....единственное что, вот не могу понять почему отладчик отвалился...До этого работал стабильно, потом с перебоями, типа устройство не отсутствует, хотя сам прошивальщик от STM видит и шьет его стабильно...а вот кокс не видит, в настройках все стоит, но вот чот ни туда, ни сюда...ни значения не просмотреть, ни отследить откуда мусор прет..Спасибо за быстрый ответ.
0 / 0 / 0
Регистрация: 31.05.2017
Сообщений: 9
30.09.2019, 10:09
что-то не могу скачать бибилиотеку, нет ссылки. В чем прикол?
0
87 / 86 / 4
Регистрация: 20.11.2016
Сообщений: 269
30.09.2019, 19:47
marsden, как вы вообще собираетесь заняться программированием если вы даже не можете найти файлы в инете? Если файлы не скачиваются, значит они теперь уже располагаются по другим адресам. Открываете адрес ссылок, "вырезаете" из них имена файлов stm32f4_dsp_stdperiph_lib.zip и stm32f4discovery_fw.zip. Забиваете имена файлов в Яндекс и он вам покажет их новые "адреса" на сайте st.com
0
0 / 0 / 0
Регистрация: 31.05.2017
Сообщений: 9
30.09.2019, 20:15
Radikal_78, ну не надо так категорично. Судя по вашему нику, программированием я занялся тогда, когда вы в школу пошли в первый класс.
А если бы тему внимательно читали, то видели бы, что в Таймер, ADC и DMA на STM32F4 (Discovery) написано "Прикладываю". С утра внизу было
[2.8 кБ]
и никакой ссылки, после моего сообщения коммент потерли, а я, получается, оказался в дураках
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
30.09.2019, 20:15
Помогаю со студенческими работами здесь

Инжектрированные каналы АЦП (ADC) в STM32F4 Discovery
Здравствуйте формучане, возникла задача настроить инжектированные каналы АЦП в STM32F4 Dyscovery. Примеры для F1 в сети есть, а вот для F4...

Прошу помощи с DMA на STM32F4 DISCOVERY [РЕШЕНО]
Пытаюсь разобраться с DMA + TIM, не понимаю, почему DMA не запускается. Основной смысл программы - через каждые пол секунды (отсчитывает...

STM32F4 ADC + DMA при передачи 1 байта входит в прерывания через 1 бит
Доброго времени - столкнулся с проблемкой Синий луч - данные Желтый луч - строб Красный луч - GPIOC (PC0) для контроля...

stm32f4 cmsis PWM-ADC-DMA
у меня вопрос По ДМА It can carry out the following transactions: • peripheral-to-memory • memory-to-peripheral • memory-to-memory ...

STM32F4 ADC + DMA передает только 2 раза и не запускаеться
Привет. Столкнулся с такой проблемой надо запускать не по таймеру и не по кругу замеры с ADC + DMA если запускать в прерываниях DMA -...


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

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

Новые блоги и статьи
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
PowerShell и онлайн сервисы. Валюта (floatrates.com руб.)
iNNOKENTIY21 11.11.2025
PowerShell функция floatrates-rub Примеры вызова: # Указанная валюта 'EUR' floatrates-rub -Code 'EUR' # Список имеющихся кодов валют floatrates-rub -Available function floatrates-rub {
PowerShell и онлайн сервисы. Погода (RP5.ru)
iNNOKENTIY21 11.11.2025
PowerShell функция Get-WeatherRP5rss для получения погоды с сервиса RP5 Примеры вызова Get-WeatherRP5rss с указанием id 5484 — Москва (восток, Измайлово) и переносом строки:. . .
PowerShell и онлайн сервисы. Погода (wttr)
iNNOKENTIY21 11.11.2025
PowerShell Функция для получения погоды с сервиса wttr Примеры вызова: Погода в городе Омск с прогнозом на день, можно изменить прогноз на более дней, для этого надо поменять запрос:. . .
PowerShell и онлайн сервисы. Валюта (ЦБР)
iNNOKENTIY21 11.11.2025
# Получение курса валют function cbr (] $Valutes = @('USD', 'EUR', 'CNY')) { $url = 'https:/ / www. cbr-xml-daily. ru/ daily_json. js' $data = Invoke-RestMethod -Uri $url $esc = 27 . . .
И решил я переделать этот ноут в машину для распределенных вычислений
Programma_Boinc 09.11.2025
И решил я переделать этот ноут в машину для распределенных вычислений Всем привет. А вот мой компьютер, переделанный из ноутбука. Был у меня ноут асус 2011 года. Со временем корпус превратился. . .
Мысли в слух
kumehtar 07.11.2025
Заметил среди людей, что по-настоящему верная дружба бывает между теми, с кем нечего делить.
Новая зверюга
volvo 07.11.2025
Подарок на Хеллоуин, и теперь у нас кроме Tuxedo Cat есть еще и щенок далматинца: Хочу еще Симбу взять, очень нравится. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru