UART (Universal Asynchronous Receiver-Transmitter) - основное средство для общения с нашим загрузчиком/терминалом.
Здесь рассмотрим только настройки 9600/8N1. Сигнал передается по двум проводам, третий общий. С обоих сторон выводы TXD, RXD, GND. Формат передачи данных по обеим линиям одинаков. Сигнал распространяется последовательно от выхода TXD до входа RXD. Дежурное состояние линии "1". Все интервалы одинаковы и для нашей скорости 9600 равны 1000000/9600 = 104 мксек.
; Start Stop ; TXD "1" ---------- ----- ----- ----- ----- ----- ----- ----- ----- ----- ------- RXD ; | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ; GND "0" ----- ----- ----- ----- ----- ----- ----- ----- ----- GND ; time - >
Первым идет сигнал Start - уровень "0" длительностью интервал. От начала сигнала Start идет отсчет временных интервалов.
Далее следуют начиная с младшего все биты длительностью интервал каждый передаваемого байта.
Последним следует сигнал Stop - уровень "1" длительностью не менее интервал.
После сигнала Stop сразу может последовать сигнал Start либо неопределенное время дежурное состояние линии "1".
Схема подключения для STM8S103F3P6:
; 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
Уровень сигнала с обоих сторон должен быть одинаков (в нашем случае 3,3В).
Рассмотрим настройку UART без использования прерываний. В STM8 несколько UART. Выбираем UART1.
Принятые настройки 8N1 (8 бит данных, нет контроля четности, 1 стоповый бит) приняты по умолчанию в STM8.
Первым делом необходимо включить тактирование UART1 (для STM8L) установкой в "1" бита PCKEN13(#3) в регистре CLK_PCKENR1. В STM8S103F3 при сбросе периферия уже тактируется.
bset CLK_PCKENR1, #3 ; для STM8L
Следом надо настроить скорость UART. При сбросе STM8 стартует от внутреннего генератора частотой 16 МГц с подключенным делителем 1/8. Итого на вход UART1 приходит частота 2 МГц. Необходимо посчитать величину UART_DIV и загрузить ее в регистры UART1_BRR1 и UART1_BRR2. В документации дается формула:
Tx/Rx baud rate = Fmaster / UART_DIV
По которой UART_DIV = 2000000 / 9600 = 208 = $D0. Вот это число и надо загрузить сначало в регистр UART2_BRR2 потом в регистр UART1_BRR1 и не наоборот. Разряды значения UART_DIV по регистрам UART2_BRR2 и UART2_BRR1 распределяются следующим образом:
; 7 6 5 4 3 2 1 0 ; ----- ----- ----- ----- ----- ----- ----- ----- ; | 15 | 14 | 13 | 12 | 3 | 2 | 1 | 0 | UART2_BRR2 ; ----- ----- ----- ----- ----- ----- ----- ----- ; | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | UART2_BRR1 ; ----- ----- ----- ----- ----- ----- ----- -----
Получается $0 надо записать в регистр UART2_BRR2, а $D надо записать в регистр UART2_BRR1:
mov UART1_BRR2, #$0 ; [35 00 52 33] для Fmaster=16/8=2МГц и 96000 mov UART1_BRR1, #$D ; [35 0D 52 32] для Fmaster=16/8=2МГц и 96000
Ввиду того, что регистры UART2_BRR2 и UART2_BRR1 при сбросе инициализируются величиной $00, первую команду можно было бы опустить.
Теперь необходимо разрешить прием и передачу установкой в "1" соответственно битов REN (#2) и TEN (#3) в регистре UART1_CR2:
mov UART1_CR2, #%00001100 ; [35 0C 52 35] UART1_CR2.TEN <- 1 UART1_CR2.REN <- 1 разрешаем передачу/прием
Для того, чтобы отправить байт по UART необходимо поместить требуемый байт в регистр UART1_DR и опрашивая бит TXE (#7) регистра UART1_SR убедиться, что освободился регистр с данными для передачи:
mov UART1_DR, #$FA wait_tx_byte: btjf UART1_SR, #7, wait_tx_byte ; skip if UART1_SR.TXE = 0 Transmit data register empty
Для того, чтобы принять байт по UART необходимо опрашивая бит RXNE (#5) регистра UART1_SR убедиться, что регистр с данными для приема не пустой и прочитать содержимое регистра UART1_DR:
wait_rx_byte: btjf UART1_SR, #5, wait_rx_byte ; skip if UART1_SR.RXNE = 0 Read data register not empty ld A, UART1_DR
Набросаем программу которая будет принимать байт по UART, инвертировать и отправлять по UART:
stm8/ TITLE “mainRAM_echo.asm” #include "STM8S103F3P.inc" MOTOROLA WORDS ; define following addresses as long segment byte at 0100 'some_RAM_segment' start: ; настраиваем UART 9600/8N1 mov UART1_BRR2, #$0 ; [35 00 52 33] для Fmaster=16/8=2МГц и 96000 mov UART1_BRR1, #$D ; [35 0D 52 32] для Fmaster=16/8=2МГц и 96000 ; разрешаем передачу/прием mov UART1_CR2, #%00001100 ; [35 0C 52 35] UART1_CR2.TEN <- 1 UART1_CR2.REN <- 1 cycle: ; ожидаем получения байта из UART wait_rx_byte: btjf UART1_SR, #5, wait_rx_byte ; [72 0B 52 30 FB] ; включаем светодиод bset PB_DDR,#5 ; [72 1A 50 07] bset PB_CR1,#5 ; [72 1A 50 08] ; принимаем, инвертируем и отправляем байт по UART cpl UART1_DR ; [72 53 52 31] ; ожидаем передачи байта по UART wait_tx_byte: btjf UART1_SR, #7, wait_tx_byte ; [72 0F 52 30 FB] ; выключаем светодиод bres PB_DDR,#5 ; [72 1B 50 07] bres PB_CR1,#5 ; [72 1B 50 08] jra cycle ; [20 E0] end ; mainRAM_echo.asm
Команда "mov longmem, #byte" помещает byte в ячейку памяти с адресом longmem.
Команда "btjf longmem, #bit, ssoff" проверяет разряд с номером #bit в ячейке памяти с адресом longmem и если разряд равен "0"(false) осуществляет переход со смещением ssoff (-128...+127).
Команда "cpl longmem" инвертирует содержимое ячейки памяти с адресом longmem.
Команда "bset longmem, #bit" устанавливает в "1" разряд с номером #bit содержимого ячейки памяти с адресом longmem.
Команда "bres longmem, #bit" сбрасывает в "0" разряд с номером #bit содержимого ячейки памяти с адресом longmem.
Выгружаем файл [mainRAM_echo] запускаем файл [run_STM8uLoader.bat], нажимаем кнопку сброса на плате STM8, нажимая последовательно две клавиши из набора 0..9, A..F отправляем байт прикладной программе, на что программа отвечает инверсным значение байта:
Следующая программа будет принимать старший байт начального адреса, отправлять этот байт обратно, потом принимать младший байт начального адреса и отправлять содержимое блока памяти (64 байт) начиная с адреса принятого двумя предыдущмим байтами.
stm8/ TITLE “mainRAM_ReadBlock.asm” .NOLIST #include "STM8S103F3P.inc" .LIST MOTOROLA WORDS ; define following addresses as long segment byte at 0100 'some_RAM_segment' start: ; настраиваем UART 9600/8N1 mov UART1_BRR2, #$0 ; [35 00 52 33] для Fmaster=16/8=2МГц и 96000 mov UART1_BRR1, #$D ; [35 0D 52 32] для Fmaster=16/8=2МГц и 96000 ; разрешаем передачу/прием mov UART1_CR2, #%00001100 ; [35 0C 52 35] UART1_CR2.TEN <- 1 UART1_CR2.REN <- 1 cycle: ; ожидаем получения старшего байта начального адреса блока wait_rx_byte_XH: btjf UART1_SR, #5, wait_rx_byte_XH ; [72 0B 52 30 FB] ld A, UART1_DR ; [C6 52 31] ld XH, A ; [95] ; отправляем эхо старшего байта начального адреса блока ld UART1_DR, A ; [C7 52 31] wait_tx_byte_XH: btjf UART1_SR, #7, wait_tx_byte_XH ; [72 0F 52 30 FB] ; ожидаем получения младшего байта начального адреса блока wait_rx_byte_XL: btjf UART1_SR, #5, wait_rx_byte_XL ; [72 0B 52 30 FB] ld A, UART1_DR ; [C6 52 31] ld XL, A ; [97] ; в индексный регистр Y количество байт в блоке ldw Y, #64 ; [90 AE 00 40] ; включаем светодиод bset PB_DDR,#5 ; [72 1A 50 07] bset PB_CR1,#5 ; [72 1A 50 08] read_block; ld A, (X) ld UART1_DR, A wait_tx_block: btjf UART1_SR, #7, wait_tx_block ; [72 0F 52 30 FB] incw X ; [5C] decw Y ; [90 5A] jrne read_block ; [26 F2] ; выключаем светодиод bres PB_DDR,#5 ; [72 1B 50 07] bres PB_CR1,#5 ; [72 1B 50 08] jra cycle ; [20 E0] end ; mainRAM_ReadBlock.asm
Выгружаем файл [mainRAM_ReadBlock] запускаем файл [run_STM8uLoader.bat], нажимаем кнопку сброса на плате STM8, нажимая последовательно четыре клавиши из набора 0..9, A..F отправляем начальный адрес требуемого блока (64 байт) памяти, на что прикладная программа читает содержимое блока с начальным адресом и отправляет в UART:
Машинные коды STM8 и команды ассемблера здесь. Адресное пространство STM8S103F3 тут.