ESP32 Урок 45. ULP. GPIO. Мигаем светодиодом



Продолжаем работу с сопроцессором ULP (ultra-low-power processor или процессор со сверхнизким потреблением).

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

 

                                                                                        

 

Проект мы создадим на основе проекта прошлого урока с именем ULP_FSM_DELAY и присвоим ему имя ULP_FSM_BLINK.

Откроем наш проект в Espressif IDE, откроем файл main.c и удалим полностью функцию update_count.

В функции app_main удалим вызов данной функции

 

update_count();

 

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

 

printf("ULP wakeup, saving pulse count\n");

 

В функции init_ulp_program настроим наш светодиод на выход

 

 

А следующая переменная нам также будет не нужна

 

ulp_cnt = 0;

 

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

 

 

Затем идём в файл ulp_assembly_source_file.S и удалим объявление переменной

 

  .global cnt cnt:   .long 0

 

Задержка в начале программы у нас будет 1 секунда, поэтому вносим исправления в коде

 

//delay(1 sec) move r0, 1000

 

Но, так как задержка у нас будет не одна, а несколько, то хотелось бы процедуру задержки организовать именно как процедуру с выходом из неё. А такой возможности у ассемблера, который понимает сопроцессор ULP, как-таковой нет. Поэтому давайте как-то организуем такую возможность самостоятельно, организовав стек и выход из процедуры.

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

 

delay_ms_loop: sub r0, r0, 1 wait(7990) /* 1millsecond = 1000 microsecond */

jumpr delay_ms_loop, 1, GE //cnt += 1

move r1, cnt //r1 = mem[cnt]

ld r2, r1, 0 //r2 = cnt

add r2, r2, 1 //r2 += 1

st r2, r1, 0 //cnt = r2

 

Организуем небольшой стек, зарезервировав несколько байт в секции bss и добавив метки начала и конца данного участка памяти

 

В самом начале программы объявим макрос сохранения значения в стек с последующим декрементированием вершины стека

 

 

 

Затем добавим макрос возврата значения из стека с предварительным инкрементированием вершины стека

 

 

Следующий макрос — запись в стек адреса выполнения (адрес, куда после выполнения процедуры нужно будет возвращаться

 

 

В основном тут всё понятно, стандартное написание макросов. Заинтересовать нас может команда .set. Это директива, задающая временный символьный эквивалент выражению.

В 3 строке макроса мы используем другой макрос — push.

Ну и объявим ещё один макрос, который будет нас возвращать в то место, из которого мы попали в процедуру по метке

 

 

И также добавим макросы, которые будут устанавливать уровни на ножке GPIO

 

 

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

 

 

Мы используем регистры RTC_GPIO_OUT_W1TC_REG и RTC_GPIO_OUT_W1TS_REG, которые отвечают соответственно за установку и сброс битов, соответствующим уровню ножек GPIO. Тем самым мы можем установить или высокий или низкий уровень ножки. Поля RTC_GPIO_OUT_DATA_W1TC_S и RTC_GPIO_OUT_DATA_W1TS_S — это примерно то же самое, но только это не сам регистр, а определённая его часть.

В технической документации это всё отображено

 

 

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

Также есть вопрос, почему мы смещаемся от 0 ножки на 10, а не на 4, ведь у нас 4 ножка. А это потому, что для RTC нумерация ножек другая, вот таблица

 

 

В самом начале программы сохраним в регистр R3 адрес вершины стека

 

 

А в самом конце файла, после команды перехода к процедуре пробуждения добавим процедуру нашей задержки, практически без изменений кода

 

 

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

Число для задержки в регистре R0, как мы помним, у нас уже в начале нашей программы занесено, поэтому сохраняем счётчик программы и переходим к задержке

 

 

При помощи макроса устанавливаем низкий уровень на ножке GPIO. По подключению светодиода мы понимаем, что мы его сейчас зажигаем

 

 

Добавляем ещё задержку на 1 секунду

 

 

Гасим наш светодиод, устанавливая высокий уровень на ножке

 

 

И затем перед пробуждением ждём ещё 4 секунды

 

 

Мы видим, что у кода появилась читабельность за счёт наших макросов. Только единственный минус — два регистра — r1 и r3 у нас задействованы для работы макросов, поэтому мы должны это учитывать и не использовать их для работы с другими величинами во время работы с макросами.

Вот и вся программа. Собираем код, прошиваем наш контроллер и смотрим, что нам выдаст терминал

 

 

Через секунду после старта светодиод зажигается

 

 

Через секунду светодиод гаснет, затем через 4 секунды мы видим информацию в терминале о пробуждении основного процессора

 

И так по кругу.

Итак, на данном уроке нам удалось при помощи сопроцессора ULP управлять уровнем на ножке GPIO. Также мы научились использовать макросы, что позволило нам организовать выход из процедур, что в дальнейшем, думаю принесёт очень большую пользу читабельности нашего кода и его размеру.

 

Данная статья в Дзен.

 

 

Предыдущий урок Программирование МК ESP32 Следующий урок

 

Исходный код

 

 

Недорогие отладочные платы ESP32 можно купить здесь:

На AliExpress Недорогие отладочные платы ESP32

На Яндекс.Маркет Недорогие отладочные платы ESP32

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

 

 

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

ESP32 ULP. GPIO. Мигаем светодиодом

 

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

ESP32 ULP. GPIO. Мигаем светодиодом

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

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

*