Перейти к содержанию
GPIO Extender-F: руководство по Forth

GPIO Extender-F: руководство по Forth

Руководство GPIO Extender-F на Mecrisp-Stellaris: подключение, распиновка, оперативная и флеш-память, GPIO, АЦП, ШИМ и таймеры.

GPIO Extender-F — мини-контроллер на STM32F042 с интерактивным Mecrisp-Stellaris Forth. Команды и определения вводятся через USB CDC и выполняются сразу: программу можно отладить в оперативной памяти, а готовую версию сохранить во флеш-памяти.

Характеристики

ПараметрЗначение
МикроконтроллерSTM32F042, ARM Cortex-M0
Тактовая частота48 МГц
ИнтерфейсUSB CDC, виртуальный COM-порт
ПитаниеUSB 5 В
Управляемые выводы10 GPIO
АЦП (ADC)8 выводов
ШИМ (PWM)4 канала TIM2
Флеш-память32 КБ, пользовательскому коду доступно около 7 КБ
Габариты54 × 15 × 10 мм

Первый запуск

  1. Подключите контроллер к USB.
  2. Откройте появившийся порт в PuTTY, TeraTerm, Minicom, screen или pyserial-miniterm.
  3. Нажмите Enter. В терминале должно появиться приглашение Forth и ok..
  4. Проверьте интерпретатор выражением 2 3 + .: результат должен быть 5.

В Forth операнды сначала помещаются в стек, а операция снимает их со стека и возвращает результат. Слова разделяются пробелами; новое слово определяется между : и ;.

2 3 + .          \ сложение и вывод результата
: double 2 * ;   \ новое слово
5 double .       \ результат: 10

Распиновка

КонтактАлиасSTM32Функции
1IO1PA4GPIO, АЦП
2IO2PA2GPIO, ШИМ TIM2 CH3, АЦП
3IO3PA0GPIO, ШИМ TIM2 CH1, АЦП
4IO4PA7GPIO, АЦП
5IO5PA6GPIO, АЦП
6IO6PA3GPIO, ШИМ TIM2 CH4, АЦП
7IO7PA1GPIO, ШИМ TIM2 CH2, АЦП
8IO8PA13GPIO
9IO9PB1GPIO, АЦП
10IO10PA14GPIO
LED1PF0встроенный светодиод
LED2PF1встроенный светодиод

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

Оперативная и флеш-память

Во время разработки компилируйте слова в оперативную память: их можно быстро менять, а после перезагрузки они исчезнут. Когда программа проверена, переключитесь на флеш-память и повторно отправьте окончательный исходный текст. Переключение режима само по себе не переносит уже скомпилированные слова.

compiletoram     \ новые слова будут находиться в оперативной памяти
compiletoflash   \ новые слова будут записываться во флеш-память
eraseflash       \ удалить пользовательский код из флеш-памяти

Сохраните исходный текст на компьютере до eraseflash. Для точки возврата можно создать cornerstone во флеш-памяти:

compiletoflash
: 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 удалит определения, созданные после этой точки.

GPIO

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!                 \ инвертировать выход
IO7 io@ .                \ прочитать вход

Пример ожидания кнопки между IO7 и GND:

: wait-button
  IMODE-HIGH IO7 io-mode!
  begin IO7 io@ 0= until
  ." Кнопка нажата!" ;

АЦП (ADC)

Если adc-init, adc-deinit, adc-once и adc отсутствуют в списке words, сначала выполните приведённые ниже определения:

: adc-calib ( -- )
  31 bit ADC-CR bis!
  begin 31 bit ADC-CR bit@ 0= until ;

: adc-once ( -- u )
  2 bit ADC-CR bis!
  begin 2 bit ADC-ISR bit@ until
  ADC-DR @ ;

: adc-init ( -- )
  9 bit $40021018 bis!  \ включить тактирование ADC
  adc-calib
  1 ADC-CR !
  adc-once drop ;

: adc-deinit ( -- )
  1 bit ADC-CR bis!
  9 bit $40021018 bic! ;

: adc ( pin -- u )
  io# bit ADC-CHSELR !
  adc-once drop adc-once ;

После этого переведите вывод в аналоговый режим и включите АЦП. Необработанное значение лежит в диапазоне 0…4095; adc-mv возвращает милливольты.

adc-init
IMODE-ADC IO3 io-mode!
IO3 adc .       \ сырое значение
IO3 adc-mv .    \ милливольты
adc-temp .      \ температура кристалла
adc-deinit

Пример отдельного слова:

: check-voltage
  IMODE-ADC IO1 io-mode!
  adc-init
  ." Напряжение на IO1: " IO1 adc-mv . ." мВ" cr
  adc-deinit ;

ШИМ (PWM)

ШИМ доступна на IO3/PA0, IO7/PA1, IO2/PA2 и IO6/PA3. Если слов pwm-init и pwm нет в words, выполните приведённые ниже определения:

: timer-base ( n -- addr )
  drop $40000000 ;

: timer-enabit ( n -- bit addr )
  drop 0 bit RCC RCC_APB1ENR_OFFSET + ;

: timer-init ( u n -- )
  dup timer-enabit bis!
  timer-base >r
  dup 16 rshift TIM.PSC r@ + !
  $FFFF and TIM.ARR r@ + !
  8 bit TIM.DIER r@ + bis!
  %010 4 lshift TIM.CR2 r@ + !
  0 bit TIM.CR1 r@ + bis!
  r> drop ;

: timer-deinit ( n -- )
  timer-enabit bic! ;

: p2tim ( pin -- n ) drop 2 ;
: p2cmp ( pin -- n ) $3 and ;

: pin-af2 ( pin -- )
  dup PA0 = if
    GPIO-BASE GPIO.AFRL + dup @
    $FFFFFFF0 and 2 or swap !
  else dup PA1 = if
    GPIO-BASE GPIO.AFRL + dup @
    $FFFFF0FF and 2 4 lshift or swap !
  else dup PA2 = if
    GPIO-BASE GPIO.AFRL + dup @
    $FFFF0FFF and 2 8 lshift or swap !
  else dup PA3 = if
    GPIO-BASE GPIO.AFRL + dup @
    $FFF0FFFF and 2 12 lshift or swap !
  then then then then drop ;

: pwm-init ( hz pin -- )
  >r
  OMODE-AF-PP r@ io-mode!
  r@ pin-af2
  48000000 swap /
  dup 65536 > if
    dup 65536 / 1+
    dup 1- >r
    / 1-
    r> swap
  else
    0 swap 1-
  then
  swap 16 lshift or
  r@ p2tim timer-init
  r@ p2cmp dup 2 < if
    2 * 8 * $68 swap lshift
    r@ p2tim timer-base TIM.CCMR1 + bis!
  else
    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 ( u pin -- )
  >r
  r@ p2tim timer-base TIM.ARR + @
  1+ swap 10000 */
  r@ p2cmp cells
  r> p2tim timer-base $34 + + ! ;

Частота pwm-init задаётся в герцах, заполнение pwm — числом от 0 до 10000.

1000 IO3 pwm-init  \ частота 1000 Гц
5000 IO3 pwm       \ заполнение 50 %

: led-fade
  1000 IO3 pwm-init
  10 0 do
    i 1000 * IO3 pwm
    500 ms-delay
  loop
  0 IO3 pwm ;

Все четыре ШИМ-вывода используют TIM2. При одновременной работе нескольких каналов задавайте одну и ту же частоту:

: multi-pwm-test
  1000 IO3 pwm-init
  1000 IO7 pwm-init
  1000 IO2 pwm-init
  1000 IO6 pwm-init
  2500 IO3 pwm
  5000 IO7 pwm
  7500 IO2 pwm
  9000 IO6 pwm ;

Системный и сторожевой таймеры

systick-init
ms_tick_cnt @ .

: measure-time
  systick-init
  ms_tick_cnt @
  1000 0 do loop
  ms_tick_cnt @ swap -
  ." Время выполнения: " . ." мс" ;

IWDG должен обновляться чаще заданного тайм-аута:

1000 iwdg-init-timeout
iwdg-refresh

: safe-loop
  1000 iwdg-init-timeout
  begin
    ." Работаю... " cr
    500 ms-delay
    iwdg-refresh
  again ;

После запуска IWDG остановить его программно нельзя; сначала проверяйте цикл в оперативной памяти и держите исходник сохранённым на компьютере.

Пользовательские настройки во флеш-памяти

Последняя страница флеш-памяти зарезервирована под настройки по адресу 0x08007c00. Не размещайте там пользовательский код, если планируете хранить настройки. Запись во флеш-память имеет ограниченный ресурс, поэтому не выполняйте её в каждом проходе цикла.

$08007c00 constant SETTINGS_PAGE

: settings-write ( value addr -- )
  SETTINGS_PAGE +
  2dup h@ = if
    2drop
  else
    $08000000 - hflash!
  then ;

: settings-read ( addr -- value )
  SETTINGS_PAGE + h@ ;

: settings-erase ( -- )
  SETTINGS_PAGE $08000000 - flashpageerase ;

Пример сохранения двух значений:

0 constant CFG_PWM_FREQ
2 constant CFG_ADC_THRESH

: 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 ;

Управление стандартным сервоприводом с ШИМ 50 Гц:

: servo-init
  50 IO3 pwm-init ;

: servo-set ( angle -- )
  180 min 0 max
  500 * 180 /
  500 +
  IO3 pwm ;

: servo-test
  servo-init
  0 servo-set 1000 ms-delay
  90 servo-set 1000 ms-delay
  180 servo-set 1000 ms-delay
  90 servo-set ;

Здесь углу 0…180° соответствует импульс 1…2 мс: при частоте 50 Гц это 5…10 % периода, или 500…1000 в шкале команды pwm. Не расширяйте диапазон без проверки документации конкретного сервопривода.

Перед подключением сервопривода используйте отдельный источник питания, рассчитанный на его пусковой ток, и объедините GND источника с GND контроллера.

Пороговый сигнал по АЦП:

: threshold-alert
  IMODE-ADC IO4 io-mode!
  OMODE-PP IO7 io-mode!
  adc-init
  begin
    IO4 adc-mv dup . ." мВ "
    2000 > if
      ." ТРЕВОГА!" cr 1 IO7 io!
    else
      cr 0 IO7 io!
    then
    500 ms-delay
  key? until
  adc-deinit ;

Идентификаторы микроконтроллера и объём флеш-памяти:

: show-device-info
  ." Chip ID: " chipid drop drop drop .
  ." Hardware ID: " hwid .
  ." Flash size: " flash-kb . ." KB" ;

Ограничения

  • При автономной работе обеспечьте стабильное питание 5 В. При пропадании USB или переходе компьютера в спящий режим USB-периферия может быть приостановлена.
  • ШИМ доступна только на четырёх выводах TIM2, перечисленных выше.
  • Перед записью во флеш-память полностью проверьте программу в оперативной памяти и сохраните исходник на компьютере.
  • Слова могут различаться между версиями прошивки. Если команда из примера не определена, проверьте список слов командой words и обратитесь в поддержку, указав версию устройства.