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

Нужна помощь по ADC stm32f303 )

Всем здравствуйте.

Сейчас застопорился на ADC этого камня. На 103 работало нормально.На 303 делает одно преобразование с DMA и все, больше в прерывание DMA не заходит. У меня зацикленный режим, что бы DMA постоянно считывал ADC. Вот код это инициализация

void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);

  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  /**ADC1 GPIO Configuration
  PA0   ------> ADC1_IN1
  PA1   ------> ADC1_IN2
  PA2   ------> ADC1_IN3
  PA3   ------> ADC1_IN4
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0|LL_GPIO_PIN_1|LL_GPIO_PIN_2|LL_GPIO_PIN_3;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* ADC1 DMA Init */

  /* ADC1 Init */
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_MEDIUM);

  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);

  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);

  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);

  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);

  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */
  /** Common config
  */
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  LL_ADC_Init(ADC1, &ADC_InitStruct);
  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_4RANKS;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
  ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV1;
  ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);

  /* Enable ADC internal voltage regulator */
  LL_ADC_EnableInternalRegulator(ADC1);
  /* Delay for ADC internal voltage regulator stabilization. */
  /* Compute number of CPU cycles to wait for, from delay in us. */
  /* Note: Variable divided by 2 to compensate partially */
  /* CPU processing cycles (depends on compilation optimization). */
  /* Note: If system core clock frequency is below 200kHz, wait time */
  /* is only a few CPU processing cycles. */
  uint32_t wait_loop_index;
  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
  while(wait_loop_index != 0)
  {
    wait_loop_index--;
  }
  /** Configure Regular Channel
  */
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_1);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_1, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_1, LL_ADC_SINGLE_ENDED);
  /** Configure Regular Channel
  */
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_2);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SINGLE_ENDED);
  /** Configure Regular Channel
  */
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_3);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SINGLE_ENDED);
  /** Configure Regular Channel
  */
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_4, LL_ADC_CHANNEL_4);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_4, LL_ADC_SINGLE_ENDED);
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */

}

 

Это дополнительная настройка

void ADC1nextinit(void)
{
	LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 4);
	LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)ADC1buff);
	LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)&ADC1->DR);
	LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1);

	ADC1->SQR1 |= LL_ADC_REG_SEQ_SCAN_ENABLE_4RANKS;
	//LL_ADC_REG_SetSequencerLength(ADC1, LL_ADC_REG_SEQ_SCAN_ENABLE_4RANKS);
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);

	LL_ADC_StartCalibration(ADC1,LL_ADC_SINGLE_ENDED);
	while(LL_ADC_IsCalibrationOnGoing(ADC1));

	LL_ADC_Enable(ADC1);
	while(!LL_ADC_IsActiveFlag_ADRDY(ADC1));
}

 

Это тело прерывания DMA

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
	static uint8_t ADCfiltr;

	 LL_DMA_ClearFlag_HT1(DMA1);


	if((ADCfiltr < 0x04) && (flagADC1 == 0)) {
		ADC1array[0] += ADC1buff[0];
		ADC1array[1] += ADC1buff[1];
		ADC1array[2] += ADC1buff[2];
		ADC1array[3] += ADC1buff[3];
		ADCfiltr++;
	} else if(ADCfiltr > 0) {
		LL_DMA_ClearFlag_HT1(DMA1);
		ADCfiltr = 0;
		flagADC1 = 1;
		ADC1data[0] = ADC1array[0] >> 2;
		ADC1data[1] = ADC1array[1] >> 2;
		ADC1data[2] = ADC1array[2] >> 2;
		ADC1data[3] = ADC1array[3] >> 2;
		ADC1array[0] = 0;
		ADC1array[1] = 0;
		ADC1array[2] = 0;
		ADC1array[3] = 0;
	}

 

Он преобразует 1 раз и все. это когда я очищаю флаг DMAx->IFCR с помощью макроса LL_DMA_ClearFlag_HT1(DMA1);

Больше преобразований АЦП нет


 

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


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

13 minutes ago, khlenar said:

Он преобразует 1 раз и все. это когда я очищаю флаг DMAx->IFCR

Это нужно делать в самом конце:

13 minutes ago, khlenar said:

void DMA1_Channel1_IRQHandler(void)

Перед выходом. Ибо если вы отчистили флаг, а он опять установился, до выхода, то больше не сработает. По крайней мере у меня стоит в конце и все работает.

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


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

4 минуты назад, Alex-lab сказал:

Это нужно делать в самом конце...

Вредный совет, так то... И причин этому как минимум 2.

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


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

Не, то же самое.(

У меня флаг переполнения OVR висит. Его программно что ли нужно очищать. Вроде же DMA считывает данные

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


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

А чему равен битик DMACFG регистра ADC_CFGR ?

У вас очень маленькое время семплирования (1.5). Можете его поднять? Хотя бы в экспериментальных целях.

Регулятор для АЦП включаете ПОСЛЕ инициализации АЦП - это вообще законно?

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

Или очищать в самом начале, или барьерами перед выходом пользоваться.

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


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

Обработчик в самом начале очищается. Да, я его не проверяю. Наверное нужно. Сэмплирование подниму.  Сейчас проверю DMACFG

DMACFG == 1

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


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

Что то ничего не помогает (. Биты показывают, что передача произошла. Что же он затыкается?

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


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

2 часа назад, khlenar сказал:

Это тело прерывания DMA


void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
	static uint8_t ADCfiltr;

	 LL_DMA_ClearFlag_HT1(DMA1);


	if((ADCfiltr < 0x04) && (flagADC1 == 0)) {
		ADC1array[0] += ADC1buff[0];
		ADC1array[1] += ADC1buff[1];
		ADC1array[2] += ADC1buff[2];
		ADC1array[3] += ADC1buff[3];
		ADCfiltr++;
	} else if(ADCfiltr > 0) {
		LL_DMA_ClearFlag_HT1(DMA1);
		ADCfiltr = 0;
		flagADC1 = 1;
		ADC1data[0] = ADC1array[0] >> 2;
		ADC1data[1] = ADC1array[1] >> 2;
		ADC1data[2] = ADC1array[2] >> 2;
		ADC1data[3] = ADC1array[3] >> 2;
		ADC1array[0] = 0;
		ADC1array[1] = 0;
		ADC1array[2] = 0;
		ADC1array[3] = 0;
	}

 

Какой-то бессмысленный набор строк... :wacko:  Тут больше половины этого безобразия следует выкинуть, и оставить:

u8 volatile ADCfiltr;
void DMA1_Channel1_IRQHandler(void)
{
  LL_DMA_ClearFlag_HT1(DMA1);
  uint i = ADCfiltr;
  if (i >= 4) return;
  ADCfiltr = ++i;
  ADC1array[0] += ADC1buff[0];
  ADC1array[1] += ADC1buff[1];
  ADC1array[2] += ADC1buff[2];
  ADC1array[3] += ADC1buff[3];
}

Этого достаточно. У Вас видимо есть фоновый процесс, который ждёт накопления данных в ADC1array? Вот он должен ждать пока ADCfiltr не станет >= 4, забирать данные (сдвигая их) и затем делать ADCfiltr=0 для нового цикла усреднения.

ADC1data - бесполезна в этом коде. Также как и дополнительная переменная flagADC1. И не нужен ни сдвиг данных в ISR (зачем, если фоновый процесс всё равно читает результат и может его сдвинуть?). Ни дублирующий вызов LL_DMA_ClearFlag_HT1(DMA1) - тоже не нужен, чтобы он там ни делал.

 

PS: Вобщем - код в 3 раза меньше и менее запутан, при том что функции выполняет те же самые.

 

38 минут назад, adnega сказал:

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

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

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


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

Это совсем ничего не меняет. Он как на первом преобразовании заткнется так и будет, пока конкретную причину затыка не найду, с вашей помощью)

Ради интереса я полностью исключил все, оставил только LL_DMA_ClearFlag_HT1(DMA1); Результат тот же.  У меня такое было, помнится. Не помню в чем была причина.

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


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

3 hours ago, khlenar said:

Больше преобразований АЦП нет

А что у вас запускает преобразование?

У меня не запускалось от таймера, если в конце инициализации не сделать один ручной запуск.

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


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

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

в начале  стартуешь и он DMA + ADC должны циклично работать

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


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

1 час назад, jcxz сказал:

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

Ответьте на прямой вопрос: может быть так, что вы входите в такой обработчик, а флаг события при этом сброшен?

27 минут назад, khlenar сказал:

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

в начале  стартуешь и он DMA + ADC должны циклично работать

Я делаю так:

- включение регулятора АЦП;

- ожидание;

- калибровка;

- настройка АЦП;

- настройка DMA с циклическим буфером с HT+TC-прерываниями;

- запуск АЦП.

Внутри прерывания DMA устанавливаю флаг - какая половина заполнилась.

Внутри mainloop'а анализирую флаг и делаю весь матан.

Ничего перезапускать в АЦП не нужно.

У вас 4 канала и размер буфера 4. При этом семплирование минимальное - у вас CPU тупо входить-выходить в такое прерывание не будет успевать, не говоря уже про какую-то математику внутри обработчика.

Почему не пользуетесь инжектированными преобразованиями (раз у вас всего 4 канала)?

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


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

время сэмплирования я увеличил. 19.5 поставил. Мне кажется не обязательно НТ+ ТС. Одного НТ достаточно. 

Я и не перезапускаю. Это должно автоматом работать. На 100 и 103 работает прекрасно. Вообще без проблем. На 303 столкнулся с непонятками. По битам показывает, что все прошло все хорошо. Будем дальше разбираться.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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