NFLic

STM8 с нуля.

Инструменты. Первая программа (Статья 1)

Для начала необходимо скачать комплект программ для сборки [stm8_asm] и поместить их в каталог "D:\stm\_toolchain\stm8_asm". Если файлы расположить в другой папке, то соответствующий путь необходимо прописать в пакетном файле, предназначенном для запуска этих программ [build_main.bat] . Можно также выгрузить описание к этим программам [UM0144 User Manual. ST Assembler-Linker.pdf] [RN005 Release note. ST Assembler-Linker. ASM 4.52, LYN 3.19, OBSEND 2.15.pdf] . Потребуются файлы STM8S103F.inc и STM8S103F.asm их необходимо поместить в каталог "D:\stm\_toolchain\stm8_asm\include" .

В память FLASH и EEPROM микрокотроллера необходимо программатром олнократно прошить код начального загрузчика [bootFE_rev0D_5A]. Для последующего помещения содержимого файла прошивки в память микроконтроллера STM8 потребуется только загрузчик [STM8uLoader] . Файлы загрузчика можно поместить в отдельной папке. Рядом с этими файлами следует расположить наш будущий файл прошивки в формате Intel HEX (расширение ".hex") или Motorola S-record S19 (расширение ".s19").

В вашей рабочей папке должно быть минимум 2 текстовых файла: файл с исходным кодом (расширение ".asm") и пакетный файл для запуска программ для сборки (расширение ".bat"). Не обязательно, но мы расположим в папке с исходным кодом еще три папки "bin", "list", "obj" и пропишем соответствующие пути к этим папкам в пакетном файле.

Кодировка в текстовых файлах должна быть ASCII или UTF-8 без BOM.

Схема подключения. В этой статье достаточно обратить внимание на подключение преобразователя USB-TTL(UART) и светодиода к порту PB5 микроконтроллера.

 

;                 5V        _ _ _ _ _ _ _ _ _ _ _ _  _ _ _ _ _ _ _ _ _ _ _ _
;USB-UART 5V  ->>-'      __|                       \/                       |__ 
;USB-UART VCC ->>-,     |__| PD4 (HS) TIM2_CH1            TIM2_CH2 (HS) PD3 |__|----------------,   /|
;USB-UART 3V3 ->>-'      1 |    UART1_CK  BEEP            AIN4   ADC_ETR    |20                 |  / | 
;USB-UART TXD ->>----,   __|                                                |__               ,---/  | 
;USB-UART RXD ->>----|--|__| PD5 (HS) AIN5                AIN3     (HS) PD2 |__|              |   |  | 
;USB-UART GND ->>-.  |   2 |    UART1_TX                  [TIM2_CH3]        |19               HCM1212A 
;                GND |   __|                                                |__               |   |  | 
;                    '--|__| PD6 (HS) AIN6                SWIM     (HS) PD1 |__|--- SWIM      |   |  | 
;                        3 |    UART1_RX                                    |18               '---\  | 
;                        __|                                                |__                 |  \ | 
;               NRST ---|__| NRST                         SPI_MISO (HS) PC7 |__|----------------'   \| 
;                        4 |                              [TIM1_CH2]        |17 
;                        __|                                                |__ 
;                       |__| PA1  OSCIN                   SPI_MOSI (HS) PC6 |__|           
;                        5 |                              [TIM1_CH1]        |16               3V3        3V3
;                        __|                                                |__                |          |
;                       |__| PA2  OSCOUT                   SPI_SCK (HS) PC5 |__|               |          |
;                        6 |                              [TIM2_CH1]        |15               ---        ---
;                        __|                                                |__              |   |      |   |
;                GND ---|__| Vss                     AIN2  CLK_CCO (HS) PC4 |__|             |   |      |   |
;                        7 |                        [TIM1_CH2N]  TIM1_CH4   |14              |   |      |   |
;                        __|                                                |__               ---        --- 
;                       |__| Vcap                         TIM1_CH3 (HS) PC3 |__|               |  RED     | BLUE
;                        8 |                              [TIM1_CH1N] [TLI] |13              -----LED   -----LED
;                        __|                                                |__              \   / ->   \   / ->  
;                3V3 ---|__| Vdd                  [ADC_ETR] I2C_SCL (T) PB4 |__|              \ /  ->    \ /  ->  
;                        9 |                                                |12              -----      -----
;                        __|    [SPI_NSS]                 [TIM1_BKN]        |__                |          |
;                       |__| PA3 (HS) TIM_CH3             I2C_SDA   (T) PB5 |__|---------------'         GND
;                        10|_ _ _ _ _ _ _ _ _ _ _ __ _ _ _ _ _ _ _ _ _ _ _ _|11 
;                                             STM8S103F3P6   

 

Исходный и пакетный файл [main.zip].

 

Исходный файл "mainRAM.asm" :

 

stm8/ TITLE “mainRAM.asm”

    #include "STM8S103F3P.inc"
    MOTOROLA
    WORDS
	
    segment byte at 0100 'some_RAM_segment'
start:
    bset    PB_DDR,#5   ; [72 1A 50 07]
    bset    PB_CR1,#5   ; [72 1A 50 08]
cycle:
    jra     cycle       ; [20 FE]
;    jra     *           ; [20 FE] 

    end
; mainRAM.asm

 

Разберем исходный файл.

 

stm8/ TITLE “mainRAM.asm”

Выражение "stm8/" сообщает ассемблеру (asm.exe) о нашем намерении использовать набор команд STM8, который описан в "table" файле "stm8.tab". Файл "stm8.tab" должен находиться в одной папке с файлом "asm.exe". Существуют также другие наборы команд (напр. ST7 и соответствующее выражение "st7/" и "table" файл "st7.tab"). Выражение "stm8/" обязательно должно находиться в начале первой строки исходного файла. Поместите перед выражением "stm8/" пробел или переместите его на вторую строчку получите ошибку от ассемблера "Couldn't open table file 'D:\stm\_toolchain\stm8_asm\ stm8.tab'.

Директивы и команды ассемблера в свою очередь не могут располагаться в начале строки. Директива ассемблера "TITLE" здесь прекрасно уживается с выражением "stm8/" в одной строке. Директива ассемблера "TITLE" никак не влияет на генерируемый код. Результат директивы "TITLE" можно увидеть если открыть "listing" файл "mainRAM.lsr" в папке "list".

 

   #include "STM8S103F3P.inc"

Директива ассемблера "#include" подключает "include" файл "STM8S103F3P.inc" в котором директива ассемблера "#include" подключает "include" файл "STM8S103F.inc" который в свою очередь содержит символьные имена регистров ввода-вывода. Благодаря этой директиве ассемблер способен заменить используемые нами символьные имена регистров на реальные адреса.

Линковщих (lyn.exe) работает с объектными файлами и не видит директив ассемблера. Поэтому дополнительно приходиться собирать файл "STM8S103F.asm" в объектный файл "STM8S103F3P.obj" для линковщика. В результате линковщик также сможет сопоставить символьные имена с их числовыми значениями.

 

   MOTOROLA

Директива ассемблера "MOTOROLA" как и директивы ассемблера "INTEL", "TEXAS", "ZILOG" устанавливают требуемый формат представления числовых данных при помощи соответствуюших префиксом и суффиксов:

;                                   MOTOROLA,     INTEL,     TEXAS,        ZILOG
; десятичные числа                        17         17         17            17
; шестнадцатиричные чиcла                $11       011h        >11           %11
; восьмиричные числа                     ~21   21o(21q)        ~21        %(8)21
; двоичные числа                   %00010001  00010001b  ?00010001  %(2)00010001
; текущее значение счетчика команд         *          $          $             $        

Действие директивы распростаняется на весь исходный файл. Если директивы в исходном файле отсутствуют, ассемблер принимает формат MOTOROLA. На сайте nflic.ru также принят формат MOTOROLA.

Здесь следует обратить внимание, что ассемблер приведенные выше числовые данные будет считать адресами ячеек памяти. Для того, чтобы ассемблер воспринимал данные как числа необходимо добавить дополнительно префикс # (решетка) вне зависимости от принятого формата представления числовых данных.

; в индексный регистр X помещается число, 
; расположенное в ячейках памяти $8054 (старший байт) и $8055 (младший байт)
    ldw   X, $8054 
; в индексный регистр X помещается число $8054
    ldw   X, #$8054   

Префикс # (решетка) применим также к названиям меток.

     WORDS
; в индексный регистр X помещается число $3321 из таблицы
    ldw   X, table 
; в индексный регистр X помещается адрес $8200 первой ячейки таблицы
    ldw   X, #table
    segment byte at 8200 'table_to_copy'
table:
     dc.b    $33, $21, $65, $79

Отсутствие решетки или лишняя решетка можно считать причиной номер один почему ваша программа собирается но не работает так как вы от нее ожидали.

 

   WORDS

Директива ассемблера "WORDS" как и директивы ассемблера "BYTES", "LONGS" устанавливают размерность меток соответственно 16-, 8-, 24-разрядная адресация. Действие директивы распростаняется на весь исходный файл или до следующей директивы. С помощью суффиксов .b, .w, .l можно переопределить размерность метки на 8-, 16-, 24-разрядную адресацию. Если директивы в исходном файле отсутствуют, ассемблер принимает размерность WORDS.

 

    segment byte at 0100 'some_RAM_segment'

Конструкция объявляет сегмент с кодом/данными с начальным адресом $0100 (шестнадцатиричные цифры без префикса). Имя/класс сегмента "some_RAM_segment". Ассемблер ничего не знает об областях памяти RAM, EEPROM, FLASH, OPTION Bytes, HW Registers. Ваша забота назначать адреса сегментов, располагая код/данные в необходимой вам области памяти.

byte означает, что код расположится в памяти начиная с того адреса, который вы указали в объявлении сегмента (без выравнивания начального адреса).

В нашем случае мы указали адрес $0100 и код расположился начиная именно с этого адреса (см. вторую строку):

S00600004844521B
S10D0100721A5007721A500820FE0C
S9030000FC

Если мы заменим byte на word и объявим невыровненный по word начальный адрес $0101:

    segment word at 0101 'some_RAM_segment'

Код расположится со следующего выровненного по word адреса $0102 (см. вторую строку):

S00600004844521B
S10D0102721A5007721A500820FE0A
S9030000FC

Поддерживаются следующие правила(маски) выравнивания начального адреса сегмента:

; byte - (1 байт) без выравнивания начального адреса сегмента
; word - (2 байта) по маске $xxx0, $xxx2, $xxx4, $xxx6, $xxx8, $xxxB, $xxxC, $xxxE 
; long - (4 байта) по маске $xxx0, $xxx4, $xxx8, $xxxC 
; para - (16 байт) по маске $xxx0 
; 64   - (64 байта) по маске $xx00, $xx40, $xx80, $xxC0
; 128  - (128 байт) по маске $xx00, $xx80
; page - (256 байт) по маске $xx00
; 1k -   (1024 байт) по маске $x000, $x400, $x800, $xC00
; 4k -   (4096 байт) по маске $xx0000, $xx4000, $xx8000, $xxC000

Мы будем применять byte и назначать произвольный начальный адрес сегмента.

В объявлении сегмента можно также указать конечный адрес:

    segment byte at 0100-01FF 'some_RAM_segment'

 

start:

Имя метки. Метка может быть расположена тольков в начале строки. Метка может не оканчиваться двоеточием. Метка имеет размерность (по умолчанию 16-разрядный адрес) может оканчиваться суффиксом .b , .w или .l. При сборке ассемлер и линковщик заменяет метки реальными адресами. До сборки ни мы ни ассемблер ни линкер не знают адресов поэтому пользуемся метками. В одной строке возможны и метка и команда ассемблера, между ними должен быть хотябы один пробел.

 

    bset 	PB_DDR,#5    ; [72 1A 50 07]
    bset 	PB_CR1,#5    ; [72 1A 50 07]

Здесь команды ассемблера установки бита №5 (всего битов 8 от 0 до 7) в регистре направления и управления порта PB. В результате на ножке PB5 фиксируется активный "0", катод светодиода притягивается к минусу питания, светодиод начинает светиться.

Точка с запятой - начало комментария. Все, что после символа ";" и вплоть до конца строки игнорируется ассемблером. Здесь в комментариях расположили машинный код соответствующих команд ассемблера. Благодаря подключению файла "STM8S103F3P.inc" (и соответственно файла "STM8S103F3P.asm" для ассемблера или файла "STM8S103F3P.obj" для линковщика ) возможно использовать символьные имена регистров вместо их адресов:

    bset 	$5007,#5     ; [72 1A 50 07]
    bset 	$5007,#5     ; [72 1A 50 07]

 

cycle:
    jra     cycle       ; [20 FE]

"Бесконечный" цикл. Безусловный относительный переход на метку "cycle". Безусловный - переход будет выполнен без проверки каких либо условий. Относительный - в коде команды отсутствует абсолютный адрес (как у команд безусловных переходов "jp", "jpf"), но содержится небольшое смещение (в пределах от -128 до +127) от текущего адреса (здесь смещение $FE = -2). После дешифровки текущей команды (в том числе и до ее выполнения) в счетчике команд PC находится адрес следующей команды. В результате выполнения команды счетчик команд возвращается на 2 байта (длина команды).

Альтернативное написание этой же команды в формате MOTOROLA:

    jra     *           ; [20 FE] 

В формате INTEL, TEXAS, ZILOG:

    jra     $           ; [20 FE] 

 

    end

Директива "end" означает конец исходного кода. Я бы назвал последняя строка с исходным кодом в этом файле. Все начиная со следующей строки игнорируется ассемблером. Есть очень важное ограничение - обязательно должна быть хотя бы одна строка после строки с директивой "end" иначе ассемблер выдаст ошибку " Fatal 4: Illegal Source EOF 'EOF' ".

 

Тестовый пакетный файл "build_main.bat":

 

set STM8ASM_DIR=D:\stm\_toolchain\stm8_asm
set STM8ASM_INCLUDE_DIR=D:\stm\_toolchain\stm8_asm\include
set PATH=%STM8ASM_DIR%;%STM8ASM_INCLUDE_DIR%
@echo on
:: Сборка файла STM8S103F3P.asm...
asm -sym -li=list\STM8S103F3P.lsr %STM8ASM_INCLUDE_DIR%\STM8S103F3P.asm -I=%STM8ASM_INCLUDE_DIR%  -obj=obj\STM8S103F3P.obj
:: Сборка файла Assembling mainRAM.asm...
asm -sym -li=list\mainRAM.lsr mainRAM.asm -I=%STM8ASM_INCLUDE_DIR%  -obj=obj\mainRAM.obj
:: Линковка файлов STM8S103F3P.obj и mainRAM.obj в файл mainRAM.cod
lyn obj\STM8S103F3P.obj+obj\mainRAM.obj, bin\mainRAM.cod, ; 
:: Создание файлов прошивки mainRAM.hex и mainRAM.s19
obsend bin\mainRAM.cod,f,bin\mainRAM.hex,ix
obsend bin\mainRAM.cod,f,bin\mainRAM.s19,s
pause

Здесь необходимо обратить внимание на строки начинающиеся с "asm", "lyn", "obsend". Ассемблер (asm.exe) собирает каждый исходный файл (расширение .asm) по отдельности в объектный файл (расширение .obj). Линкер (lyn.exe) компонует все объектные файлы в бинарный файл с "чистым" кодом (расширение .cod). obsend.exe создает из файла с кодом файлы прошивки в необходимом формате.

 

Запускаем файл build_mainRAM.bat. Наблюдаем непрерывное свечение светодиода на плате STM8 и консольное окно с тремя "No errors".

Первый "No errors" результат работы программы asm.exe - удачная сборка файла STM8S103F3P.asm в бинарный объектный файл STM8S103F3P.obj (см. папку "obj").

Второй "No errors" результат работы программы asm.exe - удачная сборка файла main.asm в бинарный объектный файл main.obj (см. папку "obj").

Третий "No Errors" результат работы программы lyn.exe - удачная компоновка файлов STM8S103F3P.obj и main.obj в бинарный файл с "чистым" кодом main.cod (см. папку "bin").

Результат работы программы obsend.exe - текстовые файлы "main.hex" и "main.s19" с кодом для записи в микроконтроллер (см. папку "bin").

 

 

Текстовый файл прошивки "mainRAM.hex" в формате Intel HEX. Здесь:

0100 начальный адрес сегмента с кодом,

721A5007 машинный код команды "bset PB_DDR,#5",

721A5008 машинный код команды "bset PB_CR1,#5",

20F6 машинный код команды "jra cycle".

 

:020000040000FA
:0A010000721A5007721A500820FE10
:00000001FF

 

Текстовый файл прошивки "mainRAM.s19" в формате Motorola S-record (S19). Здесь:

0100 начальный адрес сегмента с кодом,

721A5007 машинный код команды "bset PB_DDR,#5",

721A5008 машинный код команды "bset PB_CR1,#5",

20F6 машинный код команды "jra cycle".

 

S00600004844521B
S10D0100721A5007721A500820FE0C
S9030000FC

 

Машинные коды STM8 и команды ассемблера здесь. Адресное пространство STM8S103F3 тут.

 

[Оглавление.] [Адресное простанство и регистры STM8 (Статья 2)]