Перейти к содержимому

#43. SDADC

Общее описание сигма дельта ацп:

Модуль SDADC представляет собой высокопроизводительный и маломощный сигма-дельта-аналого-цифровой преобразователь с 16-разрядным разрешением и 9 дифференциальными аналоговыми каналами с возможностью выбора коэффициентов усиления.

Скорость преобразования составляет до 16,6 к/с (кило выборок в секунду) для каждого SDADC при преобразовании нескольких каналов и до 50 к/с на SDADC, если используется только одно преобразование каналов. Существует два режима преобразования: режим одиночного преобразования и непрерывный режим, способный автоматически сканировать любое количество каналов. Данные могут быть автоматически сохранены в системном буфере ОЗУ, что снижает накладные расходы на программное обеспечение.

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

Опорное напряжение для SDADC может быть выбрано из внешних опорных источников, внутренних 1.2 / 1.8V reference или SDADC аналогового питания.

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

Настройка Сигма Дельта АЦП:

  1. Включаем тактирование на SDADC
/* Включение тактирования на SDA1EN RCC->APB2ENR |= RCC_APB2Periph*/
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDADC1, ENABLE);

2. Установим делитель перед SDADC на 12, так как System clock 72 MHZ

 /* Set the SDADC divider: The SDADC should run @6MHz */
  /* If Sysclk is 72MHz, SDADC divider should be 12 */
  RCC_SDADCCLKConfig(RCC_SDADCCLK_SYSCLK_Div12);

3. В stm32f373 имеется встроенный внутренний регулятор который подаёт питание на сигма дельта АЦП его нужно затактировать.

//Включение тактирования на Power control (PWR) RCC->APB1ENR |= //RCC_APB1Periph 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

4. Подаём питание на SDADC

/* Enable  analog interface, PWR->CR |= PWR_SDADCAnalog  enable SD1 ADC*/
  PWR_SDADCAnalogCmd(PWR_SDADCAnalog_1, ENABLE);

5. Я использую плату STM32373 eval там имеется встроенный потенциометр он подключен к порту PB1

6. В даташите к PORTB1 можно подключить 5 канал + SDADC, note всё это также можно узнать в CUBE

6.1 Поэтому включаем в начале тактирование на PORTB, а затем настраиваем его как аналоговый выход

/* GPIO Peripheral clock enable */
/* Включение тактирования на порту*/
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

6.2 Перед заполнением структуры по настройке GPIO нужно в начале функции настройки создать структуру

//Структура для настройки портов
GPIO_InitTypeDef GPIO_InitStructure;

6.3 Заполнение структуры GPIO_InitStructure

/* SDADC channel 3P pin configuration: PB1 */
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1|GPIO_Pin_2;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

7. Выбор источника опорного напряжения, также написано что перед включением SDADC нужно подождать как минимум 2ms.

/* Select External reference: The reference voltage selection is available
 only in SDADC1 and therefore to select the VREF for SDADC2/SDADC3, SDADC1
 clock must be already enabled */

  SDADC_VREFSelect(SDADC_VREF_VDDA );
/* Insert delay equal to ~10 ms */
  Delay(10);
/* Enable SDADC1 SDADCx->CR2 |= (uint32_t)SDADC_CR2_ADON; */
  SDADC_Cmd(SDADC1, ENABLE);

8. Чтобы настроить режимы работы SDADC нужно перевести SDADC в режим инициализации, перед переходом в режим инициализации в примере включают SDADC установкой бита ADON в регистре CR2.

/* Enable SDADC1 SDADCx->CR2 |= (uint32_t)SDADC_CR2_ADON;*/
  SDADC_Cmd(SDADC1, ENABLE);

8.1 Переходим в режим инициализации SDADC, установкой бита INIT в регистре CR1.

SDADC_InitModeCmd(SDADC1, ENABLE);

на данном участке кода проверяется вошёл ли SDADC в режим инициализации в течении какого то определённого времени заданного переменной SDADC_INIT_TIMEOUT=30.

SDADCTimeout = SDADC_INIT_TIMEOUT;
  /* wait for INITRDY flag to be set	если в течении определенного времени не произошёл INITRDY flag can not set	*/
  while((SDADC_GetFlagStatus(SDADC1, SDADC_FLAG_INITRDY) == RESET) && (--SDADCTimeout != 0));
		if(SDADCTimeout == 0)
  {
    /* 
		INITRDY flag can not set */
    return 1;
  }

9. Настройка конфигурации SDADC, а именно выбор режима Differential mode (дифференциальный режим), Single ended offset mode(), Single ended zero reference mode(), Коэффициент усиления(в SDADC встроены усилители), ………………………………………………………………………………………, при этом этих конфигураций может быть три для определённых каналов выбранных в SDADC. Всё это по сути запись требуемых значений в регистр SDADC_CONF1R. OFFSET можно прописать вручную но как правило его устанавливают при калибровке SDADC.

Создание структуры, с именем SDADC_AINStructure.

//Структура
	SDADC_AINStructTypeDef SDADC_AINStructure;

Заполнение структуры SDADC_AINStructure ,1) режим Single Ended Offset mode,2) SDADC_Gain_1 (усиление равно 1), 3) SDADC_CommonMode_VDDA_2(по какому сигналу калибруется SDADC) 4) Установка смещения 0

/* Настройка режма интерпретации то что на АЦП в биты Single Ended Offset mode
	запись коэффициента усиления
	Analog Input configuration conf0: use Single Ended Offset mode */
  SDADC_AINStructure.SDADC_InputMode = SDADC_InputMode_SEZeroReference;  ;
  SDADC_AINStructure.SDADC_Gain = SDADC_Gain_1;
  SDADC_AINStructure.SDADC_CommonMode = SDADC_CommonMode_VDDA_2;
  SDADC_AINStructure.SDADC_Offset = 0;
  

В функции 1-ый параметр это SDADC1 или 2 или 3, 2-ой это конфиг в который запишутся параметры структуры SDADC_AINStructure, 3-й это адрес самой структуры.

SDADC_AINInit(SDADC1, SDADC_Conf_0, &SDADC_AINStructure);

10. По сути не нужная функция в данной программе, так как используется один канал с одной конфигурацией, в этой функции мы выбираем какому каналу (2 параметр=SDADC_Channel_5), какого SDADC(1 параметр=SDADC1) какую выбрать конфигурацию(3 параметр SDADC_Conf_0), эта функция работает с регистрами SDADC_CONFCHR1 и SDADC_CONFCHR1

/* select channel to use conf0 канал 5 соответсвует PB1
	 Select the SDADC injected channel 
  SDADCx->JCHGR = (uint32_t) (SDADC_Channel & 0x0000FFFF);
	установка бита в 1 в нужное место включает этот канал*/
  SDADC_ChannelConfig(SDADC1, SDADC_Channel_5, SDADC_Conf_0);

11. Так как можно при использовании регулярной группы у нас может использоваться только один канал, то использую инжектированную группу в непрерывном режиме, запуская программно.

11.1 Далее добавляем в инжектированную группу канал, путем установкой бита в регистре SDADC_JCHGR (5 канал запись 0x20)

/* select channel 5 */
  SDADC_InjectedChannelSelect(SDADC1, SDADC_Channel_5);

11.2 Переводим инжектированную группу в непрерывный режим путём установки бита JCONT в регистре SDADC_CR2

/* Enable continuous mode */
  SDADC_InjectedContinuousModeCmd(SDADC1, ENABLE);

12. Выход из режима инициализации путём снятия бита INIT в регистре CR1

/* Exit initialization mode */
  SDADC_InitModeCmd(SDADC1, DISABLE);

13. Далее запуск калиброки SDADC при которой определяется смещение OFFSET SDADC это значение хранится в регистре SDADC_CONF1R. по окончании калибровки разрешаем прерывания от SDADC, и запускаем программно SDADC.

	/* Set calibration timeout: 5.12 ms at 6 MHz in a single calibration sequence */
  SDADCTimeout = SDADC_CAL_TIMEOUT;
  /* wait for PT100_SDADC Calibration process to end */
  while((SDADC_GetFlagStatus(SDADC1, SDADC_FLAG_EOCAL) == RESET) && (--SDADCTimeout != 0));
  if(SDADCTimeout == 0)
  {
    /* EOCAL flag can not set */
    return 2;
  }

  /* SDADC successfully configured */
  /* Enable end of injected conversion interrupt */
  SDADC_ITConfig(SDADC1, SDADC_IT_JEOC, ENABLE);
  /* Start a software start conversion */
  SDADC_SoftwareStartInjectedConv(SDADC1);

Полностью функция настройки.

/**
  * @brief  ConfigureSDADC channel 5P in Single Ended Zero Reference mode using
  *         injected conversion with continuous mode enabled.
  * @param  None
  * @retval 0: SDADC Configured successfully
  *         1: INITRDY flag is not set, check the SDVDDA and SDVREF
  *         2: EOCAL flag is not set
  */
static uint32_t SDADC1_Config(void)
{
	//-----создание структур-----
  //Структура
	SDADC_AINStructTypeDef SDADC_AINStructure;
  //Структура для настройки портов
	GPIO_InitTypeDef GPIO_InitStructure;
	//Структура для настройки п
	NVIC_InitTypeDef NVIC_InitStructure;
  //переменная для циклов ожидания
	uint32_t SDADCTimeout = 0;
	/* Включение тактирования на Power control (PWR) RCC->APB1ENR |= RCC_APB1Periph */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDADC1, ENABLE);
	/* Set the SDADC divider: The SDADC should run @6MHz */
  /* If Sysclk is 72MHz, SDADC divider should be 12 */
  RCC_SDADCCLKConfig(RCC_SDADCCLK_SYSCLK_Div12);
	/* DeInit _SDADC */
  SDADC_DeInit(SDADC1);
	/* PWR APB1 interface clock enable */
	/* RCC->APB1ENR |= RCC_APB1Periph */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	/* Enable PT100_SDADC analog interface 
	PWR->CR |= PWR_SDADCAnalog  enable SD1 ADC*/
  PWR_SDADCAnalogCmd(PWR_SDADCAnalog_1, ENABLE);
	/* GPIO Peripheral clock enable */
	/* Включение тактирования */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
	/* SDADC channel 3P pin configuration: PB1 */
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	/* Select External reference: The reference voltage selection is available
  only in SDADC1 and therefore to select the VREF for SDADC2/SDADC3, SDADC1
  clock must be already enabled 
	*/
  SDADC_VREFSelect(SDADC_VREF_Ext);
	 /* Insert delay equal to ~10 ms */
  Delay(10);
	
	/* Enable SDADC1 SDADCx->CR2 |= (uint32_t)SDADC_CR2_ADON;	*/
  SDADC_Cmd(SDADC1, ENABLE);
	
  SDADC_InitModeCmd(SDADC1, ENABLE);
	SDADCTimeout = SDADC_INIT_TIMEOUT;
  /* wait for INITRDY flag to be set
	если в течении определенного времени не произошёл INITRDY flag can not set
	*/
  while((SDADC_GetFlagStatus(SDADC1, SDADC_FLAG_INITRDY) == RESET) && (--SDADCTimeout != 0));
		if(SDADCTimeout == 0)
  {
    /* 
		INITRDY flag can not set */
    return 1;
  }
	/* Настройка режма интерпретации то что на АЦП в биты Single Ended Offset mode
	запись коэффициента усиления
	Analog Input configuration conf0: use Single Ended Offset mode */
  SDADC_AINStructure.SDADC_InputMode = SDADC_InputMode_SEZeroReference;  ;
  SDADC_AINStructure.SDADC_Gain = SDADC_Gain_1;
  SDADC_AINStructure.SDADC_CommonMode = SDADC_CommonMode_VDDA_2;
  SDADC_AINStructure.SDADC_Offset = 0;
  SDADC_AINInit(SDADC1, SDADC_Conf_0, &SDADC_AINStructure);
	
	
	/* select SDADC1 channel 5 to use conf0 канал 5 соответсвует PB1
	 Select the SDADC injected channel 
  SDADCx->JCHGR = (uint32_t) (SDADC_Channel & 0x0000FFFF);
	установка бита в 1 в нужное место включает этот канал*/
  SDADC_ChannelConfig(SDADC1, SDADC_Channel_5, SDADC_Conf_0);
	

	/* select channel 5 */
  SDADC_InjectedChannelSelect(SDADC1, SDADC_Channel_5);
  /* Enable continuous mode */
  SDADC_InjectedContinuousModeCmd(SDADC1, ENABLE);
  /* Exit initialization mode */
  SDADC_InitModeCmd(SDADC1, DISABLE);
	
	/* configure calibration to be performed on conf0 */
	SDADC_CalibrationSequenceConfig(SDADC1, SDADC_CalibrationSequence_1);
  /* start PT100_SDADC Calibration */
  SDADC_StartCalibration(SDADC1);
	
	 	
	/* Set calibration timeout: 5.12 ms at 6 MHz in a single calibration sequence */
  SDADCTimeout = SDADC_CAL_TIMEOUT;
  /* wait for PT100_SDADC Calibration process to end */
  while((SDADC_GetFlagStatus(SDADC1, SDADC_FLAG_EOCAL) == RESET) && (--SDADCTimeout != 0));
  if(SDADCTimeout == 0)
  {
    /* EOCAL flag can not set */
    return 2;
  }

  /* SDADC successfully configured */
  /* Enable end of injected conversion interrupt */
  SDADC_ITConfig(SDADC1, SDADC_IT_JEOC, ENABLE);
  /* Start a software start conversion */
  SDADC_SoftwareStartInjectedConv(SDADC1);
  
	/* NVIC Configuration */
  NVIC_InitStructure.NVIC_IRQChannel = SDADC1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
			
  return 0;
}

Добавить комментарий