STM Урок 195. LL. STM32F1. ADC. Injected Once. Запуск по таймеру

Продолжаем работать с АЦП (ADC) контроллера STM32F1 с использованием библиотеки LL. Также работать мы продолжим с инжектированным каналом. Запускать мы будем также наш АЦП на данном уроке автоматически, хотя вернёмся мы в режим однократного преобразования. Как же такое возможно и для чего это нужно?

В режиме кольцевого запуска (continuous) АЦП не может запускаться реже чем через 252 цикла (12,5 + 239,5). Порой бывает нужно запускать АЦП автоматически гораздо реже. Для этого существует у контроллера STM32F1 а АЦП запуск от таймера. Причём запустить наш АЦП мы можем, используя различные события таймера, такие как захват, сравнение и переполнение счётчика.

От таймера мы наш АЦП уже запускали в уроке 188, только работали мы тогда с регулярным каналом. Сегодня же попробуем от таймера запустить инжектированный канал.

Схема наша не изменилась

 

 

Проект был сделан из проекта урока 192 с именем LL_ADC_INJ_ONCE и назван LL_ADC_INJ_ONCE_TIM.

Откроем проект в Cobe MX и включим глобальные прерывания в ADC1

 

 

Включим таймер 4

 

 

 

Настроим его на период в 1 милисекунду и выберем событие обновления

 

 

В свойствах ADC1 выберем срабатывание от нашего таймера

 

 

Также не забываем выбрать библиотеку здесь

 

 

Сгенерируем проект и откроем его в Keil, настроим автоперезагрузку после прошивки, отключим оптимизацию, подключим к дереву проекта файлы lcd.c и i2c_user.c, откроем main.c и добавим глобальную переменную для хранения сырого значения АЦП

 

 

В функции main() объявление подобной переменной удалим

 

__IO uint16_t ADC_Data;

 

Здесь изменим триггер на таймерный

 

LL_ADC_INJ_SetTriggerSource(ADC1, LL_ADC_INJ_TRIG_EXT_TIM4_TRGO);

 

Включим локальные прерывания по событию окончания преобразования

 

 

Включим бит JEXTTRIG в регистре CR2 при помощи специальной функции

 

 

Выведем ещё одну строку на дисплей

 

 

 

Запустим таймер и немного подождём

 

 

Добавим функцию, которую будем вызвать из обработчика прерываний от АЦП, в которой считаем значение из регистра АЦП в переменную

 

 

В файле stm32f1xx_it.c добавим для данной функции прототип

 

 

Вызовем данную функцию и сбросим флаг в функции-обработчике ADC1_2_IRQHandler

 

 

В функции main() файла main.c в бесконечном цикле вот это вот всё можем вполне удалить

 

LL_ADC_INJ_StartConversionSWStart(ADC1);

while (!LL_ADC_IsActiveFlag_JEOS(ADC1)) {}

LL_ADC_ClearFlag_JEOS(ADC1);

ADC_Data = LL_ADC_INJ_ReadConversionData12(ADC1, LL_ADC_INJ_RANK_1);

 

Соберём код, прошьём контроллер и посмотрим, как работает наш код

 

 

 

Всё работает.

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

Всем спасибо за внимание!

 

 

 

Исходный код

 

 

Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6

Программатор недорогой можно купить здесь ST-Link V2

Дисплей LCD 16×2

Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004

Логический анализатор 16 каналов можно приобрести здесь

 

 

Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)

STM LL. STM32F1. ADC. Injected Once. Запуск по таймеру

 

Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)

STM LL. STM32F1. ADC. Injected Once. Запуск по таймеру

5 комментариев к “STM Урок 195. LL. STM32F1. ADC. Injected Once. Запуск по таймеру

  1. Добрый вечер, хотел написать на ваш форум, но не получается зарегистрироваться. Поэтому, сорри, напишу здесь. Во-первых, спасибо большое за работу, которую вы делаете, с удовольствием смотрю ваши ролики даже если тема знакома, очень нравится ваш стиль изложения, спокойный такой. Теперь от комплиментов к делу. ))) Недавно приобрел новые платки в формате BluePill но с stm32f411ceu6, вы наверняка их знаете. Там на обратной стороне платы есть место для SPI Flash типа W32QXX. Ну я и впаял туда 4х-мегабайтную W25Q32. Теперь жеж надо использовать? Попробовал я хранить на ней картинки для отрисовки GUI на ili9341. Все хорошо, залил картинки, читаю, рисую. Но медленно. И подумалось мне, а почему бы не попробовать заделать DMA RX стрим, считывающий с SPI флешки сразу в SPI->DR экранчика. Конечно, предварительно предупредив его, что щас будем писать данные в фреймбаффер. Сказано-сделано. В кубе RX стрим без инкрементирования MEM, и HAL_SPI_Receive_DMA вместо указателя на буфер пишем (uint8_t *)&SPI2->DR. Самое прикольное, что работает. Правда, флешка не умеет читать (или это я дурак) выравненные по HALFWORD, а ili9341 хочет именно это. Поэтому картинка у меня малость испорчена, но если записать на флешку картинку, где после каждого байта rgb565 вставить байт с нулем, тем самым удваивая размер картинки, то все работает офигенно и, что самое главное, моментально.
    Вы наверное спросите, нафига я вам все это тут пишу. А вот зачем. Удваивание картинки, конечно, выход, но хреновый. Жаль память. Поэтому я уже неделю бьюсь над проблемой как же подружить DMA экранчика и флешки, а именно их неодинаковые пожелания по выравниванию. Мне не хватает таких глубоких познаний как у вас, поэтому подумал, мож вы чем поможете? Вы, кстати, не поднимали еще проблему DMA из периферии в периферию, насколько я помню. А ведь тема интересная, особенно вышеописанный пример. Как вы считаете?

  2. Нема QSPI. 5 обычных SPI и 5 I2S, которые на них сидят. Если бы был QSPI, я бы вообще его проадресовал напрямую из ld и рисовал бы как из RAM.
    Ну да бог с ним. Вы все-таки сделайте урок по Perif-to-Perif DMA, интересная ведь тема, и не стандартная.

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

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

*