2 3 + . \ Сложение 2+3 и вывод результата
: double 2 * ; \ Определение слова для умножения на 2
5 double . \ Результат: 10
\ Переключение в режим компиляции в RAM (будет потеряно при перезагрузке)
compiletoram
\ Переключение в режим компиляции во Flash (сохранится после перезагрузки)
compiletoflash \ Создание точки восстановления с именем "basic_image"
compiletoflash \ Важно: cornerstone работает только во Flash
: basic_image
begin here dup flash-pagesize 1- and while 0 h, repeat
does> begin dup dup flash-pagesize 1- and while 2+ repeat
cr eraseflashfrom ; basic_image \ Откат всех изменений, сделанных после создания cornerstone eraseflash \ Полная очистка пользовательской программы \ Начало разработки
compiletoram \ Компиляция в RAM для тестирования
\ Тестирование базовых функций
: test-led IO3 iox! ;
\ После отладки, сохранение во Flash
compiletoflash
: test-led IO3 iox! ;
\ Создание точки восстановления
: basic_image
begin here dup flash-pagesize 1- and while 0 h, repeat
does> begin dup dup flash-pagesize 1- and while 2+ repeat
cr eraseflashfrom ;
\ Продолжение разработки...
: more-functions
\ ... дополнительный код
\ В случае проблем возврат к базовой версии
basic_image \ Настройка пина на вывод (push-pull)
OMODE-PP IO3 io-mode!
\ Настройка пина на ввод с подтяжкой вверх
IMODE-HIGH IO7 io-mode!
\ Настройка пина на ввод с подтяжкой вниз
IMODE-LOW IO2 io-mode!
\ Настройка пина для аналогового ввода
IMODE-ADC IO6 io-mode! \ Установка высокого уровня
1 IO3 io!
\ Установка низкого уровня
0 IO3 io!
\ Инверсия состояния пина
IO3 iox!
\ Чтение состояния пина (результат: 0 или -1)
IO7 io@ . : timer-base ( n -- addr )
drop $40000000 ; \ Используем TIM2 для упрощения
\ Бит и адрес включения TIM2
: timer-enabit ( n -- bit addr )
drop 0 bit RCC RCC_APB1ENR_OFFSET + ;
\ Инициализация таймера
: timer-init ( u n -- ) \ u = combined prescaler and auto-reload value
dup timer-enabit bis! \ Clock enable
timer-base >r
dup 16 rshift \ Extract upper 16 bits (PSC)
TIM.PSC r@ + ! \ Write to PSC register
$FFFF and \ Extract lower 16 bits (ARR)
TIM.ARR r@ + ! \ Write to ARR register
8 bit TIM.DIER r@ + bis! \ Update event enable
%010 4 lshift TIM.CR2 r@ + ! \ MMS = update
0 bit TIM.CR1 r@ + bis! \ Enable timer
r> drop ;
: timer-deinit ( n -- ) \ disable timer n
timer-enabit bic! ;
\ The following pins are supported for PWM setup on STM32F042:
\ TIM2: PA0 PA1 PA2 PA3
\ Только TIM2
: p2tim ( pin -- n ) drop 2 ;
\ Получаем номер канала по пину (PA0=0, PA1=1, PA2=2, PA3=3)
: p2cmp ( pin -- n ) $3 and ;
\ Настройка альтернативных функций для всех поддерживаемых пинов
: pin-af2 ( pin -- )
dup PA0 = if
GPIO-BASE GPIO.AFRL + dup @
$FFFFFFF0 and 2 or swap ! \ AF2 для PA0
else dup PA1 = if
GPIO-BASE GPIO.AFRL + dup @
$FFFFF0FF and 2 4 lshift or swap ! \ AF2 для PA1
else dup PA2 = if
GPIO-BASE GPIO.AFRL + dup @
$FFFF0FFF and 2 8 lshift or swap ! \ AF2 для PA2
else dup PA3 = if
GPIO-BASE GPIO.AFRL + dup @
$FFF0FFFF and 2 12 lshift or swap ! \ AF2 для PA3
then then then then drop ;
: pwm-init ( hz pin -- )
>r
OMODE-AF-PP r@ io-mode!
r@ pin-af2
\ Корректный расчет PSC и ARR для заданной частоты
48000000 swap / \ Делитель для достижения нужной частоты
\ Разделим на PSC и ARR (оба 16-битные)
dup 65536 > if \ Если делитель > 65536, нужен предделитель
dup 65536 / 1+ dup ( div div/65536+1 div/65536+1 )
>r ( div div/65536+1 ) ( R: div/65536+1 )
* r> ( div*div/65536+1 div/65536+1 )
swap over / 1- \ ARR = (делитель / PSC) - 1
swap 1- \ PSC = div/65536+1 - 1
else \ Если делитель <= 65536
1 swap 1- \ PSC = 0, ARR = делитель - 1
then
\ Установка PSC и ARR
swap 16 lshift or \ Создаем комбинированное значение PSC:ARR
r@ p2tim timer-init
\ Настройка режима PWM mode 1
r@ p2cmp dup 2 < if
\ Каналы 1 и 2 (PA0, PA1) используют CCMR1
2 * 8 * $68 swap lshift
r@ p2tim timer-base TIM.CCMR1 + bis!
else
\ Каналы 3 и 4 (PA2, PA3) используют CCMR2
2 - 2 * 8 * $68 swap lshift
r@ p2tim timer-base TIM.CCMR2 + bis!
then
\ Включение выхода
r@ p2cmp 4 * bit r> p2tim timer-base TIM.CCER + bis!
;
\ Установка значения PWM
: pwm ( u pin -- )
>r
r@ p2tim timer-base TIM.ARR + @ \ Получаем значение ARR
1+ \ ARR+1 = полный период
swap 10000 */ \ Масштабирование: u * (ARR+1) / 10000
r@ p2cmp cells \ Смещение для нужного канала CCR
r> p2tim timer-base $34 + + \ Адрес регистра CCRx
! \ Записываем значение
;
\ Инициализация PWM на пине IO3 с частотой 1000 Гц
1000 IO3 pwm-init
\ Установка заполнения 50% (5000 из 10000)
5000 IO3 pwm : led-fade
1000 IO3 pwm-init \ инициализация PWM
10 0 do \ 10 циклов
i 1000 * IO3 pwm \ значение PWM от 0 до 9000
500 ms-delay \ пауза 500 мс
loop
0 IO3 pwm ; \ выключаем в конце \ Инициализация системного таймера
systick-init
\ Чтение текущего значения счетчика миллисекунд
ms_tick_cnt @ . : measure-time
systick-init
ms_tick_cnt @
\ выполняем измеряемую операцию
1000 0 do loop
ms_tick_cnt @ swap -
." Время выполнения: " . ." мс" ; \ Инициализация IWDG с таймаутом 1000 мс
1000 iwdg-init-timeout
\ Сброс сторожевого таймера (необходимо вызывать периодически)
iwdg-refresh : safe-loop
1000 iwdg-init-timeout
begin
\ Основной код
." Работаю... " cr
500 ms-delay
\ Сброс сторожевого таймера
iwdg-refresh
again ; : settings-write ( value addr -- )
SETTINGS_PAGE + \ ( value abs_addr )
2dup h@ = if \ Check if value equals current value at abs_addr
2drop \ If equal, do nothing
else
$08000000 - hflash! \ If different, write value
then ;
: settings-read ( addr -- value )
SETTINGS_PAGE + h@ ; \ Read half-word from absolute address
\ Сохранение настроек во флеш
: settings-erase ( -- )
SETTINGS_PAGE $08000000 - flashpageerase
;
\ Стирание страницы настроек
settings-erase
\ Запись значения в адрес
123 0 settings-write \ Запись числа 123 по смещению 0 последнего блока 1 КБ
\ Чтение значения из адреса
0 settings-read . \ Чтение значения по смещению 0 \ Структура конфигурации
0 constant CFG_PWM_FREQ \ смещение для частоты PWM
2 constant CFG_ADC_THRESH \ смещение для порога ADC
: save-config ( pwm-freq adc-thresh -- )
settings-erase
CFG_ADC_THRESH settings-write
CFG_PWM_FREQ settings-write ;
: load-config
CFG_PWM_FREQ settings-read
CFG_ADC_THRESH settings-read ; : blink
10 0 do
1 LED1 io!
500 ms-delay
0 LED1 io!
500 ms-delay
loop ; : wait-button
IMODE-HIGH IO7 io-mode! \ Кнопка с подтяжкой вверх
begin
IO7 io@ 0= \ Проверка на нажатие (0 = нажата)
until
." Кнопка нажата!" ; : show-device-info
." Chip ID: " chipid drop drop drop .
." Hardware ID: " hwid .
." Flash size: " flash-kb . ." KB" ;