Кафедра света и электричества

Используем AWU

В прошлый раз нам удалось победно помигать светодиодом. Однако, в той программе есть два недостатка. Во-первых, даже при максимальном значении задержки, возможном при 16-разрядном счетчике, диод мигает как-то слишком часто. Суетливо как-то, несолидно. Во-вторых, во время задержки процессор занят прибавлением единички к счетчику, зря потребляя электроэнергию. Для решения обеих этих проблем в контроллере STM8 предусмотрено полезное устройство под названием AWU - Auto Wake Up. Оно предназначено для выведения процессора из состояния "сна" через указанное время. В принципе, в контроллере Atmel такое тоже возможно, надо всего лишь завести таймер, остановить процессор, обработать пустое прерывание и выключить таймер. Отличие AWU в том, что его не надо выключать. Или, если быть точным, все-таки надо. Итак, начнем по порядку.

Запустим среду разработки ST Visual Develop и откроем Workspace, созданный в прошлый раз. Далее надо написать в файле main.asm следующий код:

   jra program ; обход подпрограмм

delay.w
   mov AWU_APR,#62
   mov AWU_TBR,#12
   mov AWU_CSR,#16
   halt
   nop
   ret

program.l
   mov PD_DDR,#1 ; установить режим работы порта
blink.l
   call delay
   bcpl PD_DDR,#0 ; переключить светодиод
   jra blink

Что все это значит ? Мы вызываем подпрограмму с меткой delay, которая пишет что-то куда-то, а потом останавливает процессор командой halt. Осталось разобраться, что и куда оно пишет. И тут надо сделать небольшое отступление.

Документация по STM8

Для того, чтобы спокойно работать с STM8 на ассемблере, нужно держать открытыми сразу несколько PDF файлов. Во-первых, документ под названием STM8S microcontroller family Reference manual. Во-вторых, документацию на тот контроллер, с которым в данный момент идет работа (в нашем случае это STM8S105. Эти документы можно скачать с сайта st.com. Далее нужен справочник по командам ассемблера - STM8 CPU programming manual. И, наконец, нужен справочник по директивам ассемблера. Это файл asm_lnk_user_manual.pdf. Вооружившись всеми этими электронными бумажками, разберемся со смыслом происходящего.

Как работает AWU

По идее все просто. У контроллера есть внутренний RC генератор, его частота делится на некое число и подается на счетчик, который тоже считает до какого-то числа. По завершении счета генерируется прерывание и процессор выходит из состояния сна. Но просто оно только в теории. На практике фирма ST сделала эту систему довольно запутанной и сложной. Хотя для управления счетчиком служат два числа, о 4 и 6 разрядах (итого 10), зависимость времени счета от значени регистра AWU_TBR не идет по степеням 2. Вернее, сначала идет, а потом нет. Короче говоря, ищите таблицу 21 в документе STM8S microcontroller family Reference manual и разбирайтесь. Нам предлагают вручную вычислять значения регистров для конкретной величины задержки. 62 и 12, указанные выше, обеспечат нам задержку примерно в 1 секунду. И тут нас ждет следующая засада. Фирма ST пишет, что отклонение RC генератора от положенных ему 128 килогерц может быть довольно значительным (до 12%) и предлагает откалибровать задержку. В общем, считай, приехали. Для каждого диапазона задержек, такого как 8 ms - 16 ms или 1.024 s - 2.048 s предлагается взять из таблицы некое значение регистра AWU_TBR. Внутри диапазона значение величина определяется значением регистра AWU_APR. Которую надо подогнать под измеренное значение частоты. При этом вообще-то диапазона AWU_APR может и не хватить, тогда придется пересчитывать AWU_TBR. Что делать в такой ситуации ? Как говорил комдив Чапаев - наплевать и забыть ! Дело в том, что точность, с которой регистрами AWU_TBR и AWU_APR можно выбрать желаемую величину задержки весьма условна. Поэтому нужно смириться с тем фактом, что от данного устройства реально можно получить лишь приблизительные тайминги. В пределах 12 процентов.

Обработка прерываний

Осталось совсем немного - сделать обработку прерывания от AWU. Как же так ? - спросит внимательный читатель. У нас ведь уже есть все обработчики прерываний, а пустой обработчик - это именно то, что нам надо. Увы, это не так. В обработчике прерываний нам надо прочитать регистр AWU_CSR чтобы "погасить" бит готовности AWUF.

   interrupt AWUInterrupt
AWUInterrupt.l
   push A
   ld A,AWU_CSR
   pop A
   iret

   interrupt NonHandledInterrupt
NonHandledInterrupt.l
   iret

   segment 'vectit'
   dc.l {$82000000+main} ; reset
   dc.l {$82000000+NonHandledInterrupt} ; trap
   dc.l {$82000000+NonHandledInterrupt} ; irq0
   dc.l {$82000000+AWUInterrupt}        ; AWU
   dc.l {$82000000+NonHandledInterrupt} ; irq2
   dc.l {$82000000+NonHandledInterrupt} ; irq3
   dc.l {$82000000+NonHandledInterrupt} ; irq4
   dc.l {$82000000+NonHandledInterrupt} ; irq5
...

Ключевое слово interrupt сообщает отладчику, что тут находится процедура обработки прерывания. Тогда отладчик сможет правильно показать содержимое стека. Ассемблируем, включаем. Проверка показывает, что частота RC генератора ниже номинальной на 9%. Допустимо.

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

set_delay_ms.w
; IN X = Delay in ms 1..1000
   push A
   sllw X
   sllw X
   sllw X
   sllw X
   sllw X
   sllw X
   ld A,#2
loop64.l
   srlw X
   inc A
   cpw X, #64
   jrule l64
   jra loop64
l64.l
   ld AWU_TBR,A
   ld A,XL
   ld AWU_APR,A
   pop A
   ret

На входе - в регистре X число миллисекунд задержки. Подпрограмма устанавливает значения регистров и готовит все для включения AWU.

delay.w
   mov AWU_CSR,#16
   HALT
   ret

Таким образом главная программа приходит к виду:

   mov PD_DDR,#1 ; установить режим работы порта
   ldw X, #1000
   call set_delay_ms
blink.l
   call delay
   bcpl PD_DDR,#0 ; переключить светодиод
   jra blink