Фев 122012
 

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

На следующем рисунке приведена блок-схема АЦП микроконтроллера серии STM32L15xx.

Блок-схема АЦП

Пройдемся по схеме и посмотрим что входит в состав модуля АЦП. Основной узел тут, естественно, сам аналого-цифровой преобразователь. Как видно, он разделен на две части: для регулярных и инжектированных каналов. Тактирование АЦП может быть только от одного источника – это внутренний RC-генератор HSI (подробней о системе тактирования можно почитать ТУТ). После HSI частоту можно поделить на 2 или 4. Итак, частота преобразования может быть равна 4, 8 или 16 МГц, других вариантов нет. Сразу замечу, от источника тактирования HSI у нас выполняются следующие задачи: АЦ преобразование и сохранение результата преобразования в специальные регистры данных. Код программы может выполняться совсем на другой частоте тактирования и от других источников, никак не согласованных с HSI. Поэтому, читать результат преобразования и запускать следующее преобразование надо с учетом этого, может потребоваться некоторая задержка из-за несинхронности источников тактирования.

Аналоговые величины поступают в преобразователь либо с внешних входов (для этого они должны быть сконфигурированы на работу в аналоговом режиме), либо от двух внутренних источников. Внутренние источники для АЦП – это температурный датчик и внутреннее опорное напряжение. С помощью температурного датчика можно измерить внутреннюю температуру чипа. Подключаются они к следующим каналам: термодатчик – входной канал 16, источник внутреннего опорного напряжения – входной канал 17. Если взглянуть на блок-схему, входных каналов может быть до 26. Фактически же, каналы ADC_IN16 и ADC_IN17 только изображены как внешние, физически ни на какие ножки они не выведены. То есть, максимальное число каналов для измерения аналоговых величин – это до 24 внешних вывода плюс два внутренних источника (термодатчик и Vref – внутреннее опорное напряжение). Количество внешних каналов может быть разное:

  • 16 каналов у STM32L15xCx (в корпусе на 48 выводов)
  • 20 каналов у STM32L15xRx (в корпусе на 64 вывода)
  • 24 канала у STM32L15xVx (в корпусе на 100 выводов)

Как видим, в нашем случае 20 внешних выводов можно задействовать под измерения. Это каналы от ADC_IN0 до ADC_IN21, поскольку ADC_IN16 и ADC_IN17 физически на ножки не выведены.

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

Результат преобразования сохраняется в специальных регистрах. Для регулярных каналов регистр данных имеет всего одну ячейку размерностью 16 бит. Для инжектированных каналов можно сохранить результаты сразу 4 преобразований подряд (размерность тоже 16 бит). Перед следующими преобразованиями результат нужно считать, иначе он будет перезаписан новым значением. Для регулярных каналов в этом случае можно сразу же после преобразования пересылать результаты в выделенную область памяти, для этого предусмотрен режим “прямого доступа к памяти” – DMA (Direct Memory Access).

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

Аналоговая схема контроля (Analog Watchdog). По сути это аналоговый компаратор с двумя пороговыми значениями – верхним и нижним, их величины задаются в двух 12-разрядных регистрах. Результат преобразования сравнивается с этими величинами. И если результат ниже нижнего или выше верхнего значений, устройство на это реагирует. Задействовать можно по разному. Использовать эти пороговые значения как некие критические пределы, уходить за которые нельзя. Либо наоборот оставлять результаты измерения, вышедшие за предельное значение, остальные отбрасывать. Для этого схема контроля формирует прерывание.

Прерываний АЦП формирует всего 4.

  • OVR – переполнение. Это прерывание вызывается только при преобразованиях в регулярных каналах. Здесь точнее будет сказать “затирание” или же “наслоение” данных. Речь идет, естественно, о регистре данных для результата преобразования в регулярных каналах, который может хранить только одно значение. И если предыдущий результат еще не считан или не передан в память с использованием DMA, а уже прошло следующее преобразование и в регистр “лезут” новые данные, вот тогда произойдет потеря данных. О чем и будет просигнализировано выставлением флага прерывания OVR. То есть в данном случае вовсе не идет речь о превышении напряжения на входе, как можно ошибочно подумать из названия. Кстати, регистр результата преобразования автоматически очищается при чтении из него данных или передаче их в память через DMA.
  • EOC – завершение преобразования в регулярном канале.
  • JEOC – завершение преобразования в инжектированном канале
  • AWD – аналоговая схема контроля обнаружила выход результата измерения за пределы установленных порогов. 

Далее вкратце описаны основные возможности встроенного АЦП:

  • Разрядность АЦП можно изменять – это может быть 6, 8, 10, или 12 разрядов.
  • Для одного канала можно задать разные режимы: однократно измерить аналоговую величину или же запустить канал в режиме непрерывного измерения.
  • Режим сканирования. Можно создать группу каналов, задать порядок следования каналов в группе. Тогда измерения будут идти последовательно друг за другом, входной мультиплексор будет подключать внешние каналы к АЦП по очереди, в соответствии с запрограммированным порядком.
  • Выравнивание результата преобразования влево или вправо.
  • Время выборки можно запрограммировать индивидуально для каждого канала.
  • Функция внешнего запуска для регулярных и инжектированных каналов.
  • Режим “прерывистых” преобразований.
  • Преобразование всегда происходит на максимальной скорости, она зависит только от частоты тактирования АЦП (ADCCLK = 4, 8, 16 МГц). При 4 МГц оно равно 4 мкс, при 16МГЦ – 1 мкс.
  • Функции автоматического включения/выключения АЦП при наличии/отсутствии преобразований. Опять же в целях снижения энергопотребления.
  • Требования к напряжению питания: 2.4В – 3.6В при работе на максимальной скорости, не менее 1.8 вольт на медленных скоростях.
  • Размах входного сигнала не должен выходить за пределы опорного напряжения Vref.
  • Возможность введения временной задержки, автоматически вставляемой между преобразованиями. Длительность задержки программируется.
  • Генерация запроса для прямого доступа к памяти (режим DMA) во время преобразования в регулярном канале.

Порядок запуска АЦ преобразования.

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

  • Изначально, необходимо сконфигурировать порты. Определиться по каким каналам будут проводиться измерения, затем соответствующие выводы портов настроить для работы в аналоговом режиме.
  • Как а для всех других модулей, на АЦП нужно подать тактовый сигнал. То есть, необходимо включить генератор HSI установкой бита HSION в регистре RCC_CR. Затем дождаться готовности генератора к работе – аппаратной установки бита HSIRDY в том же регистре.
  • После этого можно подключать АЦП к источнику тактирования – устанавливаем бит ADC1EN в регистре RCC_APB2ENR (АЦП тактируется от матрицы шин APB2).
  • Теперь можно включать АЦП. Это делается установкой бита ADON в регистре ADC_CR2. В регистре статуса ADC_SR контролируем состояние бита ADONS, он аппаратно устанавливается в 1 при готовности АЦП к работе.
  • А вот теперь, перед непосредственным запуском преобразования необходимо сконфигурировать АЦП. Этот вопрос пока опустим, далее все рассмотрим подробней. Пока же будем считать, что АЦП настроили как нужно, и можно запускать преобразование.
  • Запускается оно установкой бита SWSTART в регистре ADC_CR2 для регулярных каналов, для инжектированных каналов это будет бит JSWSTART в том же регистре. Тут речь пока идет о программном запуске. Если модуль настроен на ожидание внешнего запуска, этот последний пункт можно исключить.

Вот и все, а далее рассмотрим различные режимы работы АЦП.

Режим Power-down. Принудительное выключение АЦП между преобразованиями.

В выключенном состоянии АЦП имеет практически нулевое потребление. Для снижения энергопотребления есть возможность принудительного отключения модуля, когда нет преобразований. Здесь возможны 2 режима, которые задаются установкой бит PDI или PDD в регистре ADC_CR1.

  • PDI – выключение АЦП во время “простоя” (idle). После каждого преобразования АЦП принудительно выключается до поступления новой команды на выполнение преобразования, программной (SWSTART, JSWSTART) или сигнала внешнего запуска.
  • PDD – выключение АЦП на время задержки между преобразованиями. Этот режим используется, когда задана временная задержка, автоматически вставляемая после каждого преобразования.

Необходимо помнить, что АЦП каждый раз после включения нужно какое-то время для “пробуждения” (стабилизации) – Tstab. В этом случае преобразование начнется с некоторой задержкой.

Выбор каналов.

Здесь все сделано довольно хитро. Изначально предполагается, что измерения будут проводиться сразу в группе каналов. А сколько каналов в группе: 1 или 27 – это уже второстепенно. Поэтому, если мы измеряем напряжение всего на одном выводе, мы должны понимать, что у нас не один канал для измерения. У нас группа каналов для измерений, но в группе всего один канал, и длина последовательности измерений равна единице. Вот такой подход. С другой стороны, все логично, если предусмотрена возможность проводить измерения друг за другом в разных каналах, и для этого формируется группа каналов, задается общая длина последовательности измерений, порядок следования каналов, то выделять как-то режимы для одиночных измерений нет необходимости.

Итак, существуют 5 регистров для регулярных каналов: ADC_SQR1 — ADC_SQR5. Они разбиты на секции по 5 бит.

ADC_SQR1

ADC_SQR1

…………………………………………………….

ADC_SQR5

ADC_SQR5

Названия этих секций SQ1 – SQ27 (от слова sequence – последовательность). Каждая из этих секций – это номер преобразования в общей последовательности: SQ1 – первое преобразование в группе, SQ2 – второе и т.д. А уже в этих секциях пишем число, соответствующее номеру канала. Первое преобразование делаем в 1 канале – в SQ1 пишем 1. Второе преобразование в 14 канале – в SQ2 пишем 14 и т.д., вплоть до 27 преобразований подряд. А общую длину последовательности задаем в разрядах L регистра ADC_SQR1. Причем, длина не может быть нулевой, если там нули то это означает выполнение одного преобразования в группе, если единица – двух и т.д., вот так:

  • 00000 – 1 преобразование
  • 00001 – 2 преобразования
  • …………
  • 11010 – 27 преобразований

Для инжектированных каналов используется всего один регистр ADC_JCQR. Тут все аналогично, только максимальная длина последовательности преобразований не более 4-х, и задается двумя битами JL.

ADC_JSQR

ADC_JSQR

Примечание: если регистры ADC_SQRx или ADC_JSQR модифицируются во время выполнения преобразований, то текущее преобразование прекращается, и АЦП будет ждать нового запуска. Если инжектированное преобразование прервало выполнение регулярного, то регулярное преобразование в дальнейшем будет возобновлено.

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

Режимы одиночного или непрерывного преобразований.

Выбор режима осуществляется битом CONT в регистре ADC_CR2.

  • CONT = 0 – одиночное преобразование
  • CONT = 1 – непрерывное преобразование

При одиночном преобразовании (CONT = 0) номер канала выбирается в разрядах SQ1[4:0] регистра ADC_SQR5 (регулярный канал) или в разрядах JSQ1[4:0] регистра ADC_JSQR (инжектированный канал). Запускается программно (SWSTART для регулярных каналов, JSWSTART для инжектированных), или по внешнему запуску.

По завершению преобразования результат сохраняется в регистре ADC_DR (регулярный канал) или ADC_JDR1 (инжектированный канал). Выставляются флаги окончания преобразования: EOC (регулярный канал) или JEOC (инжектированный канал) в регистре статуса ADC_SR. Генерируются прерывания, если они заранее были разрешены установкой бит EOCIE или JEOCIE в регистре ADC_CR1 (опять же для регулярных или инжектированных каналов соответственно). Затем АЦП останавливается до новой команды запуска.

В режиме непрерывного преобразования (CONT = 1 в регистре ADC_CR2), для регулярных каналов каналов каждое новое преобразование начинается автоматически после предыдущего. Запускаем теми же способами, что и одиночное. По окончании каждого преобразования все происходит так же, результат сохраняется в ADC_DR, выставляется флаг EOC и генерируется прерывание, если оно разрешено. Остановить преобразования теперь можно только принудительно.

В инжектированных каналах режим непрерывного преобразования не предусмотрен. За исключением случая, когда инжектированные каналы сконфигурированы на автоматический запуск после регулярных каналов в непрерывном режиме. Об этом режиме будет далее.

Режим сканирования.

В этом режиме опрашивается группа каналов. Режим выбирается установкой бита SCAN в регистре ADC_CR1. АЦП опрашивает все каналы, выбранные в регистрах ADC_SQRx (регулярные каналы) или в регистре ADC_JSQR (инжектированные каналы). Для каждого канала группы выполняется одиночное преобразование. После окончания каждого преобразования следующий канал в группе опрашивается автоматически. Если к тому же установлен режим непрерывного преобразования (CONT = 1), то после последнего преобразования в группе, преобразования не прекращаются, а заново начинаются от первого выбранного канала в группе. Если установлен бит DMA, то данные из регистра ADC_DR пересылаются в память после каждого преобразования. Результат преобразования инжектированных каналов всегда сохраняется в регистрах ADC_JDRx. В регулярных каналах флаг окончания преобразования EOC может устанавливаться либо в конце каждого преобразования, либо только по окончании всей последовательности (а соответственно и генерация прерывания). Для этого в регистре ADC_CR2 предусмотрен управляющий бит EOCS (устанавливается программно)

  • EOCS = 0 – бит окончания преобразования EOC устанавливается после завершения всей последовательности регулярных преобразований.
  • EOCS = 1 – бит окончания преобразования EOC устанавливается после завершения каждого регулярного преобразования.

Автоинжектированное преобразование.

Режим включается установкой бита JAUTO в регистре ADC_CR1. Выполняется автоматических запуск преобразований в инжектированных каналах сразу по окончании опроса в регулярной группе каналов. Этот режим может быть использован для увеличения длины последовательности преобразований до 31 (27 регулярных каналов, затем 4 инжектированных). При этом возможность внешнего запуска инжектированных каналов должна быть отключена. Возможно также установить бит непрерывного преобразования (CONT = 1), в этом случае циклически будут опрашиваться регулярные каналы, затем инжектированные, а затем снова регулярные и т.д.

Прерывистый режим (Discontinuous mode).

Этот режим позволяет разбить заданную последовательность преобразований на несколько частей и выполнять их друг за другом. К примеру, имеем общую последовательность преобразований в следующих каналах: 0, 1, 2, 3, 6, 7, 9, 10. Разделим эту последовательность на более мелкие группы по 3 преобразования. Тогда АЦП будет работать следующим образом:

  • 1 запуск: выполняются преобразования в каналах 0, 1, 2
  • 2 запуск: преобразования в каналах 3, 6, 7
  • 3 запуск: преобразования в каналах 9, 10 и выставляется флаг завершения EOC
  • 4 запуск: снова преобразования в каналах 0, 1, 2
  • и т.д.

Для регулярной группы каналов. Режим задается установкой бита DISCEN в регистре ADC_CR1. Напомню, что общая длина последовательности преобразований задается в разрядах L[4:0] регистра ADC_SQR1. В этом же регистре, в разрядах DISCNUM[2:0] можно задать длину отдельной части, на которые разбивается общая последовательность (максимальная длина одной части не более 8).

Для инжектированных каналов. Режим разрешается битом JDISCEN = 1. Поскольку тут общая длина последовательности не более 4 преобразований, то разбить ее можно на части длиной не более 3 преобразований. Длина задается теми же битами DISCNUM[2:0].

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

Время выборки.

Время выборки равняется числу тактов ADCCLK, задается в разрядах SMPx[2:0] регистров ADC_SMPRx индивидуально для каждого канала. Вот, например, регистр ADC_SMPR3:

ADC_SMPR3

Здесь задаются времена выборки для каналов 0-9. В регистре ADC_SMPR2 – для каналов 10-19, в регистре ADC_SMPR1 – для каналов 20-25. Значения выбираются следующие:

  • 000: 4 такта
  • 001: 9 тактов
  • 010: 16 тактов
  • 011: 24 такта
  • 100: 48 тактов
  • 101: 96 тактов
  • 110: 192 такта
  • 111: 384 такта

Разрядность АЦП.

Возможны следующие варианты 6, 8, 10, 12 разрядов. Разрядность устанавливается битами RES[1:0] регистра ADC_CR1. При уменьшении разрядности также уменьшается и время преобразования. Варианты такие (при времени выборки 4 такта):

  • 00 – разрядность 12 бит (время преобразования 12 + 4 = 16 тактов)
  • 01 – разрядность 10 бит (время преобразования 11 + 4 = 15 тактов)
  • 10 – разрядность 8 бит (время преобразования 9 + 4 = 13 тактов)
  • 11 – разрядность 6 бит (время преобразования 7 + 4 =11 тактов)

Выравнивание данных.

Задается битом ALIGN регистра ADC_CR2. Выравнивает результат преобразования в регистре данных по левому или правому краю. 0 – выравнивание вправо, 1 – влево.

alignment 12 bit

Вот пример выравнивания 12-разрядного результата преобразования. Обратите внимание на биты SEXT. Это биты знака числа. Для инжектированных каналов можно задать еще и дополнительное смещение, вычитаемое из результата преобразования. Задается смещение в четырех регистрах ADC_JOFRx (поскольку у инжектированных каналов под результаты преобразования отведены 4 регистра, то и смещений можно задать 4). Поэтому числа в регистрах данных для инжектированных каналов могут получиться отрицательными. Для регулярных каналов такое смещение не предусмотрено.

Внешний запуск.

Преобразование может быть запущено от внешнего события. Например, по захвату таймера или сигналом с внешнего вывода (EXTI). В этом случае, если биты EXTEN[1:0] (регулярные каналы) или JEXTEN[1:0] (инжектированные каналы) регистра ADC_CR2 отличны от 0b00, внешнее событие способно вызвать запуск преобразования. Значения бит EXTEN / JEXTEN задают такие события для запуска:

  • 00 – внешний запуск не предусмотрен
  • 01 – запуск по переднему срезу сигнала
  • 10 – запуск по заднему срезу сигнала
  • 11 – запуск в обоих случаях: и по переднему и по заднему срезам сигнала

Источники запуска выбираются в разрядах EXTSEL и JEXTSEL для регулярных и инжектированных каналов соответственно. Не буду все их здесь приводить, посмотреть можно в Reference manual (RM0038 стр. 183-184).

Аппаратная приостановка и вставка задержки для медленных преобразований.

Вот преобразования то как раз у нас вовсе и не медленные. Они всегда идут на максимальной скорости при тактировании от HSI (а это 4, 8 или 16 МГц). Медленными могут быть считывание и обработка результата, не успевать за потоком данных, идущих от АЦП. Поскольку программа может выполняться совсем на другой частоте, значительно меньшей и от другого источника тактирования. Тогда вводится автоматическая задержка после каждого регулярного преобразования или последовательности инжектированных преобразований. И если во время задержки пришло новое внешнее событие запуска, оно в этом случае просто игнорируется. Задержка не вставляется между преобразованиями разных групп (регулярной и инжектированной). При этом, поскольку регулярные и инжектированные преобразования имеют отдельные регистры для хранения результата, то есть еще две особенности:

  • Если событие запуска для инжектированного канала пришло во время задержки в регулярном канале, то запуск инжектированного канала на измерение происходит незамедлительно. Действительно, зачем ему ждать обработки данных регулярного канала, у инжектированных каналов свои регистры результата преобразования, можно не бояться потери данных.
  • Затем, когда регулярное преобразование возобновляется после прерывания инжектированной последовательностью, оно запускается только после завершения задержки предыдущего регулярного преобразования.

Есть отличие только для автоинжектированного режима. В этом случае, если регулярное преобразование запускается после инжектированного, то все таки оно ожидает окончания задержки, введенной после последнего инжектированного преобразования. В этом случае можно гарантировать, что между всеми регулярными преобразованиями выполняется необходимая задержка (поскольку время выполнения инжектированных преобразований может оказаться короче необходимой задержки для регулярных каналов). Длительность задержки задается битами DELS[2:0] регистра ADC_CR2:

  • 000 – задержки нет
  • 001 – новое преобразование может начаться только после обработки всех данных предыдущих преобразований (EOC = 0, JEOC = 0).
  • 010 – задержка 7 периодов APB
  • 011 – 15 периодов APB
  • 100 – 31 периодов APB
  • 101 – 63 периода APB
  • 110 – 127 периодов APB
  • 111 – 255 периодов APB

APB здесь – более “медленная” частотная шина, не та на которой работает АЦП (ADCCLK). Когда биты задержки равны 001 – это особый случай, здесь работа АЦП просто приостанавливается без определенных задержек, ожидается пока все данные не будут считаны.

Примечание: если бит EOCS = 1, задержка вводится после каждой последовательности преобразований в регулярной группе.

Примечание: как уже упоминалось ранее, в этом режиме можно отключать АЦП во время задержки для снижения потребления энергии. Делается это установкой бита PDD в регистре ADC_CR1.

Режим DMA.

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

Аналоговая схема контроля – AWD (Analog WatchDog).

Как уже упоминал вначале, этот модуль предназначен для контроля за нахождением измеряемого значения в заданном диапазоне. Включается установкой бит AWDEN (регулярные каналы), JAWDEN (инжектированные каналы) в регистре ADC_CR1. Там же разрешаются прерывание при выходе за пределы диапазона, установкой бита AWDIE. Бит AWDSGL отвечает за контроль в сканирующем режиме.

  • AWDSGL = 0 – контроль разрешен для всех каналов
  • AWDSGL = 1 – контроль разрешен для одного канала

Контролируемый канал для последнего варианта выбирается в битах AWDCH[4:0].

Предельные пороги задаются в двух регистрах ADC_HTR (верхний предел, 12-разрядное число) и ADC_LTR (нижний предел, 12-разрядное число). При выходе за эти пределы аппаратно устанавливается флаг AWD в регистре статуса ADC_SR.

Пример программы.

Для начала рассмотрим простейшую задачу – одиночное преобразование.

#include "stm32l1xx.h"

void adc_settings(void); //Объявляем функцию конфигурирования АЦП
void gpio_init(void); //Объявляем функцию инициализации портов

int main()
{
  gpio_init(); //Вызов функции инициализации портов
  adc_settings(); //Вызов функции конфигурирования АЦП
  ADC1->CR2 |= ADC_CR2_SWSTART; //Запуск преобразования
  while(1);
}

void gpio_init(void)
{
  RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //Разрешаем тактирование порта А
  GPIOA->MODER |= GPIO_MODER_MODER5;  //Устанавливаем 11 - аналоговый вход/выход для PA5
  GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5; //Очищаем быты 00 - аналоговый вход/выход без подтяжки для PA5  
}

void adc_settings(void)
{
  RCC->CR |= RCC_CR_HSION; //Включаем внутренний генератор HSI - 16МГц
  while(!(RCC->CR&RCC_CR_HSIRDY)); //Ждем его стабилизации
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; //Разрешаем тактирование АЦП
  ADC1->CR2 |= ADC_CR2_ADON; //Включаем АЦП
  while(!(ADC1->SR&ADC_SR_ADONS)); //Ждем готовности АЦП 
  ADC1->SQR5 |= (ADC_SQR5_SQ1_2 | ADC_SQR5_SQ1_0); //Устанавливаем биты 0 и 2. Таким образом, выбираем канал ADC_IN5 для выполнения 1-го преобразования
  ADC1->CR1 &= ~ADC_CR1_RES; //Разрядность АЦП - 12 бит
  ADC1->CR2 &= ~ADC_CR2_ALIGN; //Выравнивание результата вправо
}

Результат АЦ преобразования можно посмотреть в регистре ADC_DR в режиме отладки после выполнения команды запуска преобразования ADC1->CR2 |= ADC_CR2_SWSTART. При этом, опорное напряжение равно 3 вольтам. От него и пляшем, при 3 вольтах на входе в регистре ADC_DR будет максимальное значение — 0x0FFF.

Готовый проект можно загрузить по ссылке Проект АЦП

Другие статьи:

  22 Responses to “STM32L. ADC — Аналого-цифровой преобразователь.”

  1. Хотелось бы увидеть работу STM32L-DISCOVERY + libusb =) хотя бы мигание светодиодов, консоль или гуи без разницы)

  2. В режиме отладки в регистре ADC->DR висит значение около 590 ед. АЦП., почему так ?! хотя на ножку PA5 ничего не подовалось. После этого решил проверить как измениться значение АЦП при подачи напряжения на ножку PA5 ( подал выскоий уровень на ножку PB5, померил вольтметром = 2.88 В. и разумеется замкнул на ножку PA5).
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN; //тактирование GPIOB
    GPIOB->MODER |= GPIO_MODER_MODER5_0;
    GPIOB->OTYPER &= ~GPIO_OTYPER_OT_5;
    GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR5;
    GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5;
    GPIOB->BSRRL |= GPIO_BSRR_BS_5; установка высокого уровня.
    После этого ADC->DR висит 0.
    Еще не понятно было сколько будет делать преобразований АЦП — 1 ? или непрерывно, для этого нужно устанавливать флаг ADC1->CR2 |= ADC_CR2_CONT; ?

  3. Оо еще, как узнать и как сконфигурировать опорное напряжение Внутрениее или Внешнее !? в Данном случае оно внутреннее !? и равно напряжению питания кнтроллера ?!

    • В режиме отладки в регистре ADC->DR висит значение около 590 ед. АЦП., почему так ?!
      Не сталкивался с такой проблемой.
      хотя на ножку PA5 ничего не подовалось.
      Висит в воздухе? Надо соединить с GND, тогда в регистре DR должен быть 0.
      Высокий уровень на вход можно подать прямо с вывода питания +3V, опорное напряжение на этой плате соединено с этим выводом напрямую, через LC-фильтр.
      У данного микроконтроллера внутреннее опорное напряжение для ADC нельзя задействовать. Это есть в errata sheet и на сайте ST в сообществе обсуждалось. Используется только внешнее, причем в данном корпусе опорное напряжение берется с вывода питания VDDA.
      Еще не понятно было сколько будет делать преобразований АЦП — 1 ? или непрерывно, для этого нужно устанавливать флаг ADC1->CR2 |= ADC_CR2_CONT; ?
      В этой программе выполняется всего одно преобразование. Да, для режима непрерывного преобразования надо установить этот флаг. Или перенести запуск преобразования в бесконечный цикл
      while(1)
      {
      ADC1->CR2 |= ADC_CR2_SWSTART; //Запуск преобразования
      }
      поставить здесь точку останова смотреть за результатом в регистре данных.

  4. •00 – внешний запуск не предусмотрен
    •01 – запуск по переднему срезу сигнала
    •10 – запуск по заднему срезу сигнала
    •11 – запуск в обоих случаях: и по переднему и по заднему срезам сигнала
    То есть, к примеру, если мы хотим использовать внешний запуск АЦП по переполнению таймера TIM6_TRGO ( как я понял TRGO это флаг переполнения таймера или сброс таймера на начало счета так ? ), то в регистре EXTEN = 10 ( по спаду к примеру), а в регситре EXTSEL записываем 1010 (с даташита TIM6_TRGO) так ?! Так же не нужно выставлять флаг ADC1->CR2 |= ADC_CR2_SWSTART ? И как будет выглядить структура кода ?!
    void InitPeriph(void); //
    void ADC_settings(void); //
    void TimerTIM6(void);//
    void Delay(uint32_t step); //êà

    uint32_t step = 0x1FFFF;

    int main()
    {
    InitPeriph();
    ADC_settings();
    TimerTIM6();

    while(1)
    {

    }

    void InitPeriph(void)
    {
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;//òàêòèðóåì A
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;//òàêòèðóåì B
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
    GPIOA->MODER |= GPIO_MODER_MODER5;
    }

    void ADC_settings(void)
    {
    RCC->CR |= RCC_CR_HSION;
    while(!(RCC->CR&RCC_CR_HSIRDY));
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    ADC1->CR2 |= ADC_CR2_ADON;
    while(!(ADC1->SR&ADC_SR_ADONS));
    ADC1->SQR5 |= (ADC_SQR5_SQ1_2 | ADC_SQR5_SQ1_0);
    ADC1->CR1 &= ~ADC_CR1_RES;
    ADC1->CR2 &= ~ADC_CR2_ALIGN;
    ADC1->CR2 |= ADC_CR2_EXTEN_0 //выставляем значение 10
    ADC1->CR2 |= (ADC_CR2_EXTSEL_3 | ADC_CR2_EXTSEL_1); //выставляем значение 1010 TIM6_TRGO
    //ADC1->CR2 |= ADC_CR2_CONT;
    //ADC1->CR2 |= ADC_CR2_SWSTART;
    }

    void TimerTIM6(void)
    {
    RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
    TIM6->PSC = 0xFFFF;
    TIM6->ARR = 0x0010;
    TIM6->DIER |= TIM_DIER_UIE; //Нужно ?
    TIM6->CR1 |= TIM_CR1_CEN;
    }

  5. Блин в даташите на странице 439.для TIM6-TIM7.
    MMS: Master mode selection
    Блин нашел с помощью CNT_EN, UG можно сформировать выходной сигнал с триггера TRGO. Вот после того как меняю состояния битов в отладчике,происходит АЦП преобразование. Один раз сменил — одно АЦП преобразование.

    • UG — update generation или формирования события программно. Имеется в виду режим «MMS=010 — Update» или «MMS=001 — Enable»? Какие биты меняются в отладчике и вызывают АЦ преобразование? Если при этом формируется событие и задействует выход TRGO, то почему не может быть АЦ преобразования от внешнего запуска? Что есть «блин в даташите»? Пытаюсь понять проблему :)
      Возможно, никакого несоответствия здесь и нет, давайте попробуем нормальным техническим языком и последовательно описать порядок действий, и что происходит не так. Сразу же скажу, что менять содержимое регистров в отладчике — плохой вариант, это не AVR Studio, и нет гарантии, что все эти действия выполняться верно. Может да, а может и нет, не всегда предсказуемо. IAR корректно выполняет только код, периферию он не симулирует. Поэтому и изменения правильней вносить в код, а потом заново перезагружать.

  6. Так ща я попытаюсь спокойно объяснить.
    Вот часть программы
    void ADC_settings(void)
    {
    RCC->CR |= RCC_CR_HSION;
    while(!(RCC->CR&RCC_CR_HSIRDY));
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    ADC1->CR2 |= ADC_CR2_ADON;
    while(!(ADC1->SR&ADC_SR_ADONS));
    ADC1->SQR5 |= (ADC_SQR5_SQ1_2 | ADC_SQR5_SQ1_0);
    ADC1->CR1 &= ~ADC_CR1_RES;
    ADC1->CR2 &= ~ADC_CR2_ALIGN;
    ADC1->CR2 |= ADC_CR2_EXTEN_0 //выставляем значение 0b10
    ADC1->CR2 |= (ADC_CR2_EXTSEL_3 | ADC_CR2_EXTSEL_1); //выставляем значение 0b1010 TIM6_TRGO
    //ADC1->CR2 |= ADC_CR2_CONT;
    //ADC1->CR2 |= ADC_CR2_SWSTART;
    }
    1.После запуска отладчика . во вкладке ADC-> DR показывало по нулям. Открыл даташит, нашел описание таймеров TIM6&TIM7 и дальше TIM6&TIM7 control register 2 (TIMx_CR2)(Reference manual (RM0038 стр. 378 ).). Тут рассказывалось какие события влияют задействуют выход TRGO.
    2.Запустил вновь отладчик, открыл вкладку TIM6->EGR->UG установил бит, он тут же системно сбросился.Открыл вкладку ADC->DR и появилсоь преобразование АЦП.
    3.Дальше я в режиме отладки перешел во вкладку TIM6->CR1->CEN остановил счетчик и запустил. Открыл вкладку ADC->DR и появилсоь преобразование АЦП.
    Вывод эти регистры действительно приводят к внешнему запуску АЦП. Но в описаний ( если я правильно понял ).

    UG — 00 ничего не делает, 01 — заново инициализирует счетчик времени ( надеюсь я правильно пеервел).
    Приводит ли к инициализации счетчика событие при достижении счетчиком велечины к примеру TIM6->ARR = 0x00FF; ?
    Когда я смотрел в отладчике и счетчик доходил до этого значения и сбрасывался, бит UG не устанавливался программно, и соответственно АЦП преобразования не происходило.

    Просто мне хотелось знать как правильно пользоваться внешним запуском АЦП, и в каком порядке.

    • Чуть позже выложу проект с запуском АЦП от таймера. Через пару дней.

    • Ну вот, выкладываю архив с проектом в IAR. Здесь используется запуск преобразования в АЦП через заданные интервалы времени, формируемые таймером TIM6. Таймер при переполнении счетчика генерирует сигнал TRGO, который и запускает АЦП. В архиве есть текстовый документ «Изменения в программе», где я и поясняю все подробней, а также там собраны строки кода, которые я добавил в исходный проект. Текста много, поэтому сюда не стал добавлять.
      И еще. Не меняйте содержимое бит в регистрах в режиме отладки, это тупиковый путь. Таймер работает аппаратно, хоть вы и в режиме пошаговой отладки, все равно он считает.
      Архив с проектом по этой ссылке
      http://chipspace.ru/archives/adc_ext_trigger.rar

  7. Спасибо большое за приложенные материалы !!!! вот, решил полностью изучить возможности АЦП( пока регулярных каналов). Вот такой вопрос, правильно ли я понимаю. Входной аналоговый сигнал поступает на мультиплексор, который подключает и отключает кондеснатор (время подключения конденсатора «время выборки» мы можем задавать «sampling time» записав значение в регистр ADC_SMPR3) ?
    АПЦ используем метод последовательного приближения так ? То есть после того как считали напряжения с входного конденстора, заетм проверяется среднее значение половины всех опорных напряжений и выставляется старший разряд «бит» в регистре , 0 если меньше, 1 если больше половины всех опорных напряжений ? Так вот я и не понимаю для выставления одного бита требуется (при 16Мгц) минимальное количество времени равное = 4такта+время преобразования значения с конденсатора ) то есть для 12 разрядного АЦП потребуется = (4 такта+время преобразования значения с конденсатора)*12.
    И хотелось бы значть как правильно выставлять время выборки и время преобразования для оптимальной работы. вдаташите не могу найти , привидены примеры в зависимости от частоты ADCCLK.

  8. Блин или все же время выборки «sampling time» задается для установления всех битов АЦП. ? тогда вот •00 – разрядность 12 бит (время преобразования 12 + 4 = 16 тактов) истина.

  9. Запустил пример, прогнал в железе stm32ldiscovery, одиночное преобразование в регулярном канале вроде проходит успешно, данные в ADC_DR верны, но в регистре ADC_SR не устанавливается флаг завершения переобразования EOC. Но в то же время флаг EOC1 в регистре ADC_CSR устанвливается. Изменил пример на работу с инжектированным каналом, в этом случае флаг JEOC в ADC_SR устанавливается…
    Два вопроса: 1)Почему не устанавливается флаг EOC в ADC_SR в случае регулярного преобразования?
    2) Что это за регист ADC_CSR ?

    • 1) Может просто в отладчике не отображаться. Точнее сказать не могу, надо самому смотреть.
      2) В Reference manual описан данный регистр, там можно посмотреть.

      • Да, действительно чудит отладчик IAR.Надо будет проверить в другой среде.

        • Остался лишь не совсем понятный момент про задержки междe преобразованиями. Допустим имеем режим SCAN и непрврывный режим работы ADC (CONT=1 и SCAN=3) , три преобразования в регулярной группе:
          1 канал ->задержка->2 канал->задержка->3 канал->задержка-> 1канал и т.д..
          Если в момент задержки(А) между 3-м и 1-м каналом(т.е. перед началом новой последовательности) наступит событие на запуск инжектированного канала, то преобразование в инжектированной группе начнеться недожидаясь задержки (А) в регулярном канале, затем преобразование в 1-м канале рег.группы возобновиться только после после задержки (А)
          Но если инжектированные каналы настроены на автозапуск после регулярных каналов(автоинжектированный режим), то задержки (А) нет вообще?т.е. Преобразование последовательности с начала в регулярной группе начнеться не после этой задержки (А) а после задержки инжектрованных каналов??

  10. Добрый день!
    Я вот тут никак не могу понять вот эту строку

    ADC1->SQR5 |= (ADC_SQR5_SQ1_2 | ADC_SQR5_SQ1_0);

    Тут мы указываем, приёмником результата преобразования регистр — SQR5
    А вот SQR5 выбран случайно или нет? И ещё биты ADC_SQR5_SQ1_2 и ADC_SQR5_SQ1_0 выбраны случайно или нет? Если нет, то по какому принципу выбирать биты в реальных условиях?

    Заранее благодарен!

    PS Большое спасибо за статьи!

    • Ну это не приемник результата, а канал АЦП, их довольно много. Выбор тут, естественно случаен, поскольку это всего лишь пример.
      В реальных условиях выбор и будет зависеть от реальных условий :), может быть даже от разводки платы, чтобы дорожки были покороче или шли на одном слое. Или от других условий, тут нет каких-то предпочтений заранее.