Урок 26. АЦП STM32. Общие сведения, режимы. Установка конфигурации через регистры CMSIS.

ADC STM32

Начинается серия уроков о работе с АЦП. Я постараюсь последовательно, шаг за шагом объяснить работу с этим узлом во всех основных режимах, привести примеры. В этом уроке расскажу, что представляет собой АЦП микроконтроллера STM32. Объясню, как задавать его конфигурацию через регистры CMSIS.

Предыдущий урок     Список уроков     Следующий урок

АЦП любого микроконтроллера это узел, возможностей которого всегда не хватает. Измеряешь напряжение – надо высокую точность, оцифровываешь звук – скорость преобразования. Обрабатываешь видеосигнал – нужна еще большая скорость. Подключил тензодатчик – опять не хватает точности. В системе много аналоговых датчиков – теперь не успеваешь коммутировать, все ресурсы микроконтроллера уходят на управление АЦП. И так до бесконечности. Поэтому очень важно научиться оптимально управлять модулем АЦП.

 

АЦП микроконтроллеров STM32 обладает чрезвычайно широкими возможностями. Разобраться в них непросто. Но оптимальное управление этим модулем позволит реализовывать многие задачи, которые невозможно решить с помощью обычного для микроконтроллеров режима - запустил преобразование, получил результат.

В зависимости от типа микроконтроллеров у STM32 может быть от одного до трех модулей АЦП. Наш микроконтроллер STM32F103C8T6 содержит 2 однотипных АЦП. Используя режим сдвоенных преобразований его можно превратить в один АЦП с более высокой скоростью преобразования.

 

Общие сведения.

Я бы выделил следующие черты.

  • Это АЦП последовательного преобразования.
  • В микроконтроллере 2 однотипных модуля АЦП.
  • Разрешение – 12 бит.
  • Минимальное время преобразования – 1 мкс.
  • До 16 каналов внешних аналоговых сигналов, по одному каналу для встроенного датчика температуры и источника опорного напряжения. В STM32F103C8T6 10 каналов для внешних сигналов.
  • В плате STM32F103C8T6 АЦП измеряет напряжение в пределах 0…3,3 В.
  • Есть режим самокалибровки.
  • Встроенный источник опорного напряжения и датчик температуры.
  • Имеет множество режимов однократных и циклических преобразований с запуском от разных источников, в том числе и внешних.
  • Модули АЦП могут работать в режиме сдвоенных преобразований.

Электрическим параметрам и точностным характеристикам АЦП я посвящу отдельный урок.

В STM32 используются АЦП последовательного приближения. Не буду рассказывать принцип действия АЦП такого типа. Для нас, как пользователей микроконтроллера это неважно. Главное, что преобразование необходимо запустить и через некоторое время будет готов результат.

Обычно в микроконтроллерах, в том числе и ATmega168/328, модуль измерения аналоговых сигналов представляет собой собственно АЦП и коммутатор входных сигналов. В этом случае для измерения напряжения на внешних выводах необходимо произвести следующие действия:

  • Установить коммутатор на нужный входной сигнал.
  • Запустить аналогово-цифровое преобразование.
  • Дождаться его окончания, отсчетом времени или проверкой состояния флага готовности.
  • Считать результат.

В STM32 используется сложный автомат управления АЦП, который позволяет производить измерение аналоговых сигналов в автоматическом режиме.

 

Регулярные и инжектированные каналы.

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

  • Регулярные каналы предназначены для обработки входных сигналов поочередно с определенной периодичностью. Поэтому они и называются  регулярными.
  • При запуске опроса инжектированных каналов, обработка регулярных каналов приостанавливается. Инжектировать (inject) означает вводить, впрыскивать, вставлять. Инжектированные каналы опрашиваются между регулярными.

Я вырезал часть функциональной схемы АЦП, на которой показаны основные компоненты модуля.

Схема АЦП STM32

Еще раз.

  • В модуле один АЦП.
  • Ему на вход через коммутатор Analog MUX могут подключаться аналоговые сигналы с выводов микроконтроллера IN0…IN15.
  • Существует определенная логика, по которой модуль АЦП сам по себе переключает коммутатор и запускает преобразования.
  • По логике опроса выделены 2 типа каналов: регулярные и инжектированные.
  • Оба типа каналов работают с общими аналоговыми входами микроконтроллера. Отличаются только приоритетом, последовательностью и способом инициализации опроса.

Для регулярных каналов в специальных регистрах формируется список последовательности работы. Согласно ему АЦП поочередно опрашивает эти каналы. Порядок следования не имеет значения. Допускается до 16ти регулярных преобразований. Один и тот же канал может опрашиваться несколько раз в одной последовательности. Сами последовательности могут вызываться циклически, т.е. непрерывно.

Результаты преобразования регулярных каналов сохраняются в одном 16ти разрядном регистре (Regular data register). Естественно, до окончания следующего преобразования результат должен быть считан из регистра, иначе он будет потерян.

У инжектированных каналов максимальное количество измерений в цикле составляет 4. Для сохранения результата преобразования каждого канала выделены отдельные 16ти разрядные регистры (Injected data registers). Всего 4 регистра.

Вот полная функциональная схема модуля  АЦП из технической документации. При дальнейшем описании я буду ссылаться на нее.

Функциональная схема АЦП STM32

 

Работа с модулем АЦП.

Собирался, как обычно, сначала описать режимы работы и регистры, а в последующих уроках привести примеры использования АЦП.  Но режимов слишком много, регистров тоже. Я буду несколько уроков описывать теорию управления модулем, а когда дело дойдет до практики, то все забудется. Придется все время возвращаться к теоретической части.

Поэтому, буду объяснять работу отдельных узлов, режимов АЦП и тут же приводить практический пример. Придется начать с установки конфигурации, выбора режимов. Без этого практическая работа с АЦП невозможна.

Описание форматов регистров АЦП я вынес на отдельную страницу. Можно открыть ее в начале урока или переходить по ссылкам на описание отдельных регистров по ходу урока.

Постараюсь не просто формально описывать режимы, а передать логику управления модулем.

 

Подготовительные операции.

Для проверки работы модуля АЦП я собрал несложную схему, позволяющую формировать 4 аналоговых сигналов.

Схема стенда

Четыре делителя напряжения на переменных резисторах подключил к аналоговым входам A0-A3.

Эту схему я добавил к отладочной плате с LCD-дисплеем из предыдущего урока. Дисплей заменил на другой с разрешением 2 строки по 16 символов.

Макет для проверки

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

Создал проект Lesson26_1.  Для этого:

  • Копировал проект предыдущего урока Lesson25_1 в папку Lesson26.
  • Переименовал ее в Lesson26_1.
  • Открыл проект в STM32CubeMX и разрешил работу UART1 без прерываний.
  • Открыл проект в Atollic True Studio.
  • Переименовал его в Lesson26_1.
  • В файле main.c удалил блоки для проверки LCD-дисплея из прошлого урока, но оставил инициализацию дисплея.

Таким образом, у меня получился проект, в котором STM32 конфигурирован на 72 мГц, разрешена работа UART1, а также подключена и инициализирована библиотека управления дисплеем LCD780. Можно все это сделать в STM32CubeMX, но я поступил проще.

 

Конфигурация АЦП через регистры CMSIS.

Добавим в программу блок инициализации АЦП, пока только его заголовок.

/* USER CODE BEGIN WHILE */

// инициализация дисплея

RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPAEN ;
initDelayDwt();
init_LCD(GPIOA, 1<<12, GPIOA, 1<<15, GPIOB, 1<<14, GPIOB, 1<<15, GPIOA, 1<<8, GPIOA, 1<<11, 16, 2, 1);

// инициализация АЦП

Конфигурируем выводы, сигналы с которых собираемся обрабатывать  с помощью АЦП, как аналоговые входы. Об этом мы говорили в уроке 7.

// инициализация АЦП

// конфигурирование выводов для аналоговых сигналов (PA0...PA3)
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN ; // разрешение тактирования порта A
GPIOA->CRL &= ~ (GPIO_CRL_MODE0 | GPIO_CRL_CNF0); // PA0 - аналоговый вход
GPIOA->CRL &= ~ (GPIO_CRL_MODE1 | GPIO_CRL_CNF1); // PA1 - аналоговый вход
GPIOA->CRL &= ~ (GPIO_CRL_MODE2 | GPIO_CRL_CNF2); // PA2 - аналоговый вход
GPIOA->CRL &= ~ (GPIO_CRL_MODE3 | GPIO_CRL_CNF3); // PA3 - аналоговый вход

 

Тактирование АЦП.

Включим тактирование АЦП. Он использует синхроимпульсы шины ABP2.

RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // разрешение тактирование АЦП

Между синхроимпульсами шины и таковым входом модуля АЦП установлен программно управляемый делитель (ADC Prescaler).

Предделитель

Он позволяет делить частоту тактирования шины APB2 на 2, 4, 6 и 8. Делитель общий для обоих модулей АЦП.

АЦП последовательного приближения – это синхронное устройство, выполняющее преобразование за определенное число синхроимпульсов. Частота этих импульсов ограничена.

Если заглянем, в техническую документацию микроконтроллера STM32F103C8T6, то увидим, что максимальная допустимая частота его тактирования 14 мГц.

Максимальная частота

Значение делителя должно быть таким, чтобы частота тактирования АЦП не превысила 14 мГц.

В нашем случае, при частоте шины 72 мГц коэффициент деление выбираем равным 6. Тогда частота тактирования АЦП будет 12 мГц. Быстродействие преобразования уменьшится до 1,2 мкс. Если необходимо добиться минимального времени преобразования 1 мкс, то придется уменьшить частоту тактирования микроконтроллера, чтобы “попасть” ровно в 14 мГц .

Например, если установить частоту 56 мГц (PLLMul = 7), то при коэффициенте деления 4 получим 14 мГц.

Значение коэффициента делителя задается в регистре RCC_CFGR.

Биты 15:14 ADCPRE [1:0]. Предделитель АЦП.

  • 00: / 2
  • 01: / 4
  • 10: / 6
  • 11: / 8

Добавляем в блок инициализации.

RCC->CFGR &= ~RCC_CFGR_ADCPRE_0;  // предделитель АЦП = 10 (/6)
RCC->CFGR |=  RCC_CFGR_ADCPRE_1;

Основные режимы АЦП устанавливаются в 2х регистрах управления ADC_CR1 и ADC_CR2.

Сейчас запретим в них все. Будем устанавливать только то, что нам нужно.

ADC1->CR1 = 0;      // запрещаем все в управляющих регистрах
ADC1->CR2 = 0;

Хотя, после сброса микроконтроллера их состояние уже будет таким – сброшены все биты.

Включим АЦП установкой бита ADON.

ADC1->CR2 |= ADC_CR2_ADON; // разрешить АЦП

 

Выборка аналогового сигнала.

Раз начал говорить о временных параметрах АЦП, затрону этот вопрос в полной мере.

АЦП последовательного приближения выполняет преобразование за определенное время. И в течение этого времени аналоговый сигнал на его входе должен оставаться стабильным. Иначе непонятно, что он измерит.

Поэтому на входе АЦП такого типа всегда установлен аппаратный узел – устройство выборки и хранения аналогового сигнала. Упрощенно, он представляет собой конденсатор на входе АЦП, с аналоговым ключом в цепи входного сигнала.

  • Ключ замыкается, и конденсатор заряжается от аналогового входа. Это процесс выборки.
  • Затем ключ размыкается, и напряжение остается на конденсаторе неизменным, а значит и стабильным на входе АЦП. Это процесс хранения, в течение которого происходит аналогово-цифровое преобразование.

Точность преобразования зависит, в том числе и от времени заряда конденсатора хранения. Вместе с выходным сопротивлением источника аналогового сигнала конденсатор образует RC-цепочку. Время, необходимое для полного заряда конденсатора хранения, определяется постоянной времени RC-цепочки. А значит и в том числе выходным сопротивлением источника сигнала.

Для обеспечения точности измерения АЦП время выборки должно быть не менее определенного значения, зависящего от выходного сопротивления источника сигнала. Разработчики STM32 рассчитали эту зависимость для максимально-допустимой частоты тактирования 14 мГц.

Количество циклов Время выборки, мкс Выходное сопротивление источника сигнала, кОм
1,5 0,11 0,4
7,5 0,54 5,9
13,5 0,96 11,4
28,5 2,04 25,2
41,5 2,96 37,2
55,5 3,96 50

STM32 позволяет устанавливать время выборки для каждого канала отдельно. Используются регистры ADC_SMPR1 и ADC_SMPR2. Для каждого канала выделены поля по 3 бита.

SMPx [2:0]. Время выборки канала

  • 000: 1,5 цикла
  • 001: 7,5 цикла
  • 010: 13,5 цикла
  • 011: 28,5 цикла
  • 100: 41,5 цикла
  • 101: 55,5 цикла
  • 110: 71,5 цикла
  • 111: 239,5 цикла

Конечно, время выборки увеличивает время преобразования. В минимальном варианте:

  • Время выборки равно 1,5 цикла.
  • Преобразование требует 12,5 цикла.
  • Общее время 14 циклов.

Давайте установим время выборки для каждого канала примерно 2 мкс, что соответствует 28,5 циклам.

Добавляем.

ADC1->SMPR2 |= ADC_SMPR2_SMP0_0 | ADC_SMPR2_SMP0_1 ; // время выборки 28,5 циклов
ADC1->SMPR2 &= ~ADC_SMPR2_SMP0_2 ;
ADC1->SMPR2 |= ADC_SMPR2_SMP1_0 | ADC_SMPR2_SMP1_1 ; // время выборки 28,5 циклов
ADC1->SMPR2 &= ~ADC_SMPR2_SMP1_2 ;
ADC1->SMPR2 |= ADC_SMPR2_SMP2_0 | ADC_SMPR2_SMP2_1 ; // время выборки 28,5 циклов
ADC1->SMPR2 &= ~ADC_SMPR2_SMP2_2 ;
ADC1->SMPR2 |= ADC_SMPR2_SMP3_0 | ADC_SMPR2_SMP3_1 ; // время выборки 28,5 циклов
ADC1->SMPR2 &= ~ADC_SMPR2_SMP3_2 ;

 

Выбор каналов преобразования.

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

Для регулярных каналов есть 3 регистра, которые определяют последовательность преобразований в одном цикле ADC_SQR1, ADC_SQR2 и ADC_SQR3.

Поле L [3:0] регистра ADC_SQR1 определяет количество регулярных каналов, которые надо опросить. Напомню, что в одном цикле может быть опрошено до 16ти регулярных каналов, и они могут повторяться.

Для каждого номера в последовательности опроса отведены по 5 бит SQ, которые определяют номер канала. Вместе с ИОН и датчиком температуры каналов может быть до 18. В поле SQ1 надо установить номер канала, который будет опрашиваться первым, в поле SQ2 – вторым и т.д.

Для задания последовательности опроса инжектированных каналов используется регистр ADC_JSQR.

Каждому номеру в последовательности опроса отведены по 5 бит JSQ, которые определяют номер канала. В поле JSQ1 надо установить номер канала, который будет опрашиваться первым, в поле JSQ2 – вторым и т.д.

В случае, если требуется опрашивать число каналов меньше 4, то биты JSQ смещаются в сторону старших разрядов.

Поля регистра

ADC_JSQR

Количество опросов
1 2 3 4
JSQ4 1 преобразование 2 преобразование 3 преобразование 4 преобразование
JSQ3 1 преобразование 2 преобразование 3 преобразование
JSQ2 1 преобразование 2 преобразование
JSQ1 1 преобразование

Установка этих регистров зависит от режима. В примерах мы ее будем изменять. Давайте пока зададим по одному каналу для каждой последовательности.

// выбор каналов
ADC1->SQR1 =0; // 1 регулярный канал
ADC1->SQR3 =0; // 1е преобразование - канал 0
ADC1->JSQR =0; // 1 инжектированный канал
ADC1->JSQR |= ADC_JSQR_JSQ4_0; // 1е преобразование - канал 1

 

Калибровка.

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

Рекомендуется производить калибровку один раз при каждой подаче питания.

Перед началом калибровки АЦП должен находиться во включенном состоянии. Бит ADON управляющего регистра ADC_CR2 должен быть установлен.

Для запуска калибровки необходимо установить бит CAL регистра ADC_CR2. Но, до запуска калибровки АЦП должен быть включен (бит ADON=1) в течение времени не менее 2 периодов тактирования АЦП. У нас задана частота 12 мГц. Значит между установкой бита ADON в 1 и запуском АЦП должно пройти не менее 170 нс. Я вставил задержку на 10 мкс. Вдруг изменим частоту тактирования.

По окончании калибровки бит CAL сбрасывается аппаратно. Т.е. необходимо дождаться, когда бит CAL станет равным 0.

Добавим калибровку в наш блок инициализации АЦП.

// калибровка
delayMks(10); // задержка 10 мкс
ADC1->CR2 |= ADC_CR2_CAL; // запуск калибровки
while ((ADC1->CR2 & ADC_CR2_CAL) != 0) ; // ожидание окончания калибровки

Запуск преобразования АЦП может происходить от разных источников. Источник запуска выбирается в поле EXTSEL [2:0] управляющего регистра  ADC1->CR2. Эту тему подробно обсудим позже. А сейчас разрешим запуск от внешнего источника. А в качестве источника выберем программный запуск.

ADC1->CR2 |= ADC_CR2_EXTSEL; // источник запуска - SWSTART
ADC1->CR2 |= ADC_CR2_EXTTRIG; // разрешение внешнего запуска для регулярных каналов

Вот проект, который получился у меня.

 

Зарегистрируйтесь и оплатитеВсего 60 руб. в месяц за доступ ко всем ресурсам сайта!
 

Продолжим в следующем уроке.

 

Будем опрашивать аналоговые входы в разных режимах, измерять напряжение на них. Разработаем многоканальный вольтметр.

Предыдущий урок     Список уроков     Следующий урок

0

Автор публикации

не в сети 4 дня

Эдуард

285
Комментарии: 1946Публикации: 200Регистрация: 13-12-2015

4 комментария на «Урок 26. АЦП STM32. Общие сведения, режимы. Установка конфигурации через регистры CMSIS.»

  1. Очень, очень все интересно. Прошу Вас, не останавливайтесь, пишите ещё больше познавательных статей!

    0
  2. Какой же ужас с этими регистрами в STM32. Если в AVR написано в даташите имя регистра TIMSK0, то так его и переносишь в код. Если написано название бита в даташите OCIE0B, то так и его и заисываешь. В итоге код TIMSK0|= (0<SMPR2 |= ADC_SMPR2_SMP0_0; вываливается с ошибкой
    error: expected identifier or ‘(‘ before ‘ADC_TypeDef’
    #define ADC1 ((ADC_TypeDef *)ADC1_BASE)
    | ^~~~~~~~~~~
    ../core/src/main.c:63:1: note: in expansion of macro ‘ADC1’
    63 | ADC1->SMPR2 |= ADC_SMPR2_SMP0_0;
    | ^~~~
    D:/_MC/Test3/CMSIS/inc/stm32f103xb.h:607:31: error: expected ‘)’ before ‘(‘ token
    607 | #define ADC1_BASE (APB2PERIPH_BASE + 0x00002400UL)
    | ^
    D:/_MC/Test3/CMSIS/inc/stm32f103xb.h:669:45: note: in expansion of macro ‘ADC1_BASE’
    669 | #define ADC1 ((ADC_TypeDef *)ADC1_BASE)
    | ^~~~~~~~~
    ../core/src/main.c:63:1: note: in expansion of macro ‘ADC1’
    63 | ADC1->SMPR2 |= ADC_SMPR2_SMP0_0;
    | ^~~~
    Думал хоть на этой странице уже наконец нашел решение как эти несчастые биты вписать в регистр, ан нет.

    0

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".