Add Morze

This commit is contained in:
eddyem 2017-02-14 22:16:58 +03:00
parent d827cd385d
commit 5c5bd9468e
10 changed files with 739 additions and 0 deletions

9
F0-nolib/Readme.md Normal file
View File

@ -0,0 +1,9 @@
Samples for STM32F042-nucleo and chinese STM32F030-based devboard
=================================
This directory contains examples for F0 without any library
- blink - simple LED blink
- uart - USART over DMA with hardware end-of-string detection
- uart_blink - code for STM32F030F4, echo data on USART1 and blink LEDS on PA4 and PA5
- morze - for STM32F030, echo data from USART1 on TIM3CH1 (PA6) as Morze code

137
F0-nolib/morze/Makefile Normal file
View File

@ -0,0 +1,137 @@
BINARY = morze
BOOTPORT ?= /dev/ttyUSB0
BOOTSPEED ?= 115200
# MCU FAMILY
FAMILY = F0
# MCU code
MCU = F030x4
DEFS = -DEBUG
# change this linking script depending on particular MCU model,
# for example, if you have STM32F103VBT6, you should write:
LDSCRIPT = ld/stm32f030f.ld
INDEPENDENT_HEADERS=
FP_FLAGS ?= -msoft-float
ASM_FLAGS = -mthumb -mcpu=cortex-m0 -march=armv6-m -mtune=cortex-m0
ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS)
###############################################################################
# Executables
PREFIX ?= /opt/bin/arm-none-eabi
RM := rm -f
RMDIR := rmdir
CC := $(PREFIX)-gcc
LD := $(PREFIX)-gcc
AR := $(PREFIX)-ar
AS := $(PREFIX)-as
OBJCOPY := $(PREFIX)-objcopy
OBJDUMP := $(PREFIX)-objdump
GDB := $(PREFIX)-gdb
STFLASH := $(shell which st-flash)
STBOOT := $(shell which stm32flash)
###############################################################################
# Source files
OBJDIR = mk
LDSCRIPT ?= $(BINARY).ld
SRC := $(wildcard *.c)
OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o))
STARTUP = $(OBJDIR)/startup.o
OBJS += $(STARTUP)
DEPS := $(OBJS:.o=.d)
INC_DIR ?= ../inc
INCLUDE := -I$(INC_DIR)/F0 -I$(INC_DIR)/cm
LIB_DIR := $(INC_DIR)/ld
###############################################################################
# C flags
CFLAGS += -O2 -g -MD -D__thumb2__=1
CFLAGS += -Wall -Werror -Wextra -Wshadow -Wimplicit-function-declaration
CFLAGS += -Wredundant-decls $(INCLUDE)
# -Wmissing-prototypes -Wstrict-prototypes
CFLAGS += -fno-common -ffunction-sections -fdata-sections
###############################################################################
# Linker flags
LDFLAGS += --static -nostartfiles
#--specs=nano.specs
LDFLAGS += -L$(LIB_DIR)
LDFLAGS += -T$(LDSCRIPT)
LDFLAGS += -Wl,-Map=$(OBJDIR)/$(BINARY).map
LDFLAGS += -Wl,--gc-sections
###############################################################################
# Used libraries
LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group
LDLIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU)
#.SUFFIXES: .elf .bin .hex .srec .list .map .images
#.SECONDEXPANSION:
#.SECONDARY:
ELF := $(OBJDIR)/$(BINARY).elf
LIST := $(OBJDIR)/$(BINARY).list
BIN := $(BINARY).bin
HEX := $(BINARY).hex
all: bin list
elf: $(ELF)
bin: $(BIN)
hex: $(HEX)
list: $(LIST)
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
$(OBJDIR):
mkdir $(OBJDIR)
$(STARTUP): $(INC_DIR)/startup/vector.c
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $<
$(OBJDIR)/%.o: %.c
@echo " CC $<"
$(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $<
#$(OBJDIR)/%.d: %.c $(OBJDIR)
# $(CC) -MM -MG $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@
$(BIN): $(ELF)
@echo " OBJCOPY $(BIN)"
$(OBJCOPY) -Obinary $(ELF) $(BIN)
$(HEX): $(ELF)
@echo " OBJCOPY $(HEX)"
$(OBJCOPY) -Oihex $(ELF) $(HEX)
$(LIST): $(ELF)
@echo " OBJDUMP $(LIST)"
$(OBJDUMP) -S $(ELF) > $(LIST)
$(ELF): $(OBJDIR) $(OBJS)
@echo " LD $(ELF)"
$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(ELF)
clean:
@echo " CLEAN"
$(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map
@rmdir $(OBJDIR) 2>/dev/null || true
flash: $(BIN)
@echo " FLASH $(BIN)"
$(STFLASH) write $(BIN) 0x8000000
boot: $(BIN)
@echo " LOAD $(BIN) through bootloader"
$(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN)
.PHONY: clean flash boot

8
F0-nolib/morze/Readme.md Normal file
View File

@ -0,0 +1,8 @@
Code for STM32F030F4 chinese board
Echo received by USART data as morze code (@ PA6, TIM3CH1)
USART Rx by interrupts, Tx by DMA, Morze by timer3 with DMA @ each letter
- Toggle onboard green LED once per second.
- Echo received by USART1 data (not more than 64 bytes including '\n') on B115200
- Morze text by dimmer

View File

@ -0,0 +1,12 @@
/* Linker script for STM32F030f4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
}
/* Include the common ld script. */
INCLUDE stm32f0.ld

122
F0-nolib/morze/main.c Normal file
View File

@ -0,0 +1,122 @@
/*
* main.c
*
* Copyright 2017 Edward V. Emelianoff <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <string.h>
#include "stm32f0.h"
#include "usart.h"
#include "morse.h"
volatile uint32_t Tms = 0;
/* Called when systick fires */
void sys_tick_handler(void){
++Tms;
}
static void gpio_setup(void){
/* Enable clocks to the GPIO subsystems (A&B) */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
/* Set green leds (PA4 & PA6) as output; AF1 to enable timer on PA6 */
GPIOA->MODER = GPIO_MODER_MODER4_O | GPIO_MODER_MODER6_AF;
GPIOA->AFR[0] |= 1<<24; // AF1
GPIOA->OTYPER = 1 << 6; // PA6 - opendrain, PA4 - pushpull
}
// Tim3_ch1 - PA6, 48MHz -> 1kHz
static void tim3_setup(){
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // enable clocking
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
TIM3->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // PWM mode 1: acive->inactive, preload enable
TIM3->PSC = 47999; // 1kHz
TIM3->ARR = WRD_GAP;
TIM3->CCR1 = 0;
TIM3->CCER = TIM_CCER_CC1P | TIM_CCER_CC1E; // turn it on, active low
TIM3->EGR |= TIM_EGR_UG;
// DMA ch3 - TIM3_UP
DMA1_Channel3->CPAR = (uint32_t)(&(TIM3->DMAR)); // TIM3_ch1
DMA1_Channel3->CMAR = (uint32_t)(mbuff);
DMA1_Channel3->CNDTR = 0;
// memsiz 16bit, psiz 32bit, memincrement, from memory
DMA1_Channel3->CCR |= DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_1
| DMA_CCR_MINC | DMA_CCR_DIR;
TIM3->DCR = (2 << 8) // three bytes
+ (((uint32_t)&TIM3->ARR - (uint32_t)&TIM3->CR1) >> 2);
TIM3->DIER = TIM_DIER_UDE; // enable DMA requests
DMA1_Channel3->CCR |= DMA_CCR_TCIE; // enable TC interrupt
}
char buftoping[256] = {0}, *nxtltr = buftoping;
int main(void){
uint32_t lastT = 0; // last time counter value
int L = 0; // length
char *txt;
sysreset();
SysTick_Config(6000, 1);
gpio_setup();
tim3_setup();
USART1_config();
int first = 1; // first letter in phrase
while (1){
if(dmaflag){
dmaflag = 0;
if(*nxtltr){
DMA1_Channel3->CCR &= ~DMA_CCR_EN;
while(ALL_OK != usart1_send(nxtltr, 1));
uint8_t x;
nxtltr = fillbuffer(nxtltr, &x);
if(x){
DMA1_Channel3->CNDTR = 3 * x;
DMA1_Channel3->CCR |= DMA_CCR_EN;
//x += '0';
//while(ALL_OK != usart1_send((char*)&x, 1));
if(first){ // first letter in message
first = 0;
TIM3->CR1 |= TIM_CR1_CEN;
TIM3->EGR |= TIM_EGR_UG; // force update generation
}
}
}else{
TIM3->CR1 &= ~TIM_CR1_CEN; // turn timer off
first = 1;
}
}
if(lastT > Tms || Tms - lastT > 499){
pin_toggle(GPIOA, 1<<4); // blink by onboard LED once per second
lastT = Tms;
}
if(usart1rx()){ // usart1 received data, store in in buffer
L = usart1_getline(&txt);
if(L < 256 && !*nxtltr){
memcpy(buftoping, txt, L);
buftoping[L] = 0;
nxtltr = buftoping;
dmaflag = 1; //
usart1_send("Send ", 5);
while(ALL_OK != usart1_send(txt, L));
}else usart1_send("Please, wait\n", 13);
}
/* if(L){ // text waits for sending
if(ALL_OK == usart1_send(txt, L)){
L = 0;
}
}*/
}
}

188
F0-nolib/morze/morse.c Normal file
View File

@ -0,0 +1,188 @@
/*
* geany_encoding=koi8-r
* morse.c
*
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include "stm32f0.h"
#include "morse.h"
#define MAXPINGS (8)
uint16_t mbuff[3*MAXPINGS];
/*
32 (0x20) - 64 (0x40) - @ 96 (0x60) - ` 128 (0x80) - 160 (0xa0) -   192 (0xc0) - À 224 (0xe0) - à
33 (0x21) - ! 65 (0x41) - A 97 (0x61) - a 129 (0x81) - <EFBFBD> 161 (0xa1) - ¡ 193 (0xc1) - Á 225 (0xe1) - á
34 (0x22) - " 66 (0x42) - B 98 (0x62) - b 130 (0x82) - 162 (0xa2) - ¢ 194 (0xc2) - Â 226 (0xe2) - â
35 (0x23) - # 67 (0x43) - C 99 (0x63) - c 131 (0x83) - ƒ 163 (0xa3) - £ 195 (0xc3) - Ã 227 (0xe3) - ã
36 (0x24) - $ 68 (0x44) - D 100 (0x64) - d 132 (0x84) - 164 (0xa4) - ¤ 196 (0xc4) - Ä 228 (0xe4) - ä
37 (0x25) - % 69 (0x45) - E 101 (0x65) - e 133 (0x85) - 165 (0xa5) - ¥ 197 (0xc5) - Å 229 (0xe5) - å
38 (0x26) - & 70 (0x46) - F 102 (0x66) - f 134 (0x86) - 166 (0xa6) - ¦ 198 (0xc6) - Æ 230 (0xe6) - æ
39 (0x27) - ' 71 (0x47) - G 103 (0x67) - g 135 (0x87) - 167 (0xa7) - § 199 (0xc7) - Ç 231 (0xe7) - ç
40 (0x28) - ( 72 (0x48) - H 104 (0x68) - h 136 (0x88) - ˆ 168 (0xa8) - ¨ 200 (0xc8) - È 232 (0xe8) - è
41 (0x29) - ) 73 (0x49) - I 105 (0x69) - i 137 (0x89) - 169 (0xa9) - © 201 (0xc9) - É 233 (0xe9) - é
42 (0x2a) - * 74 (0x4a) - J 106 (0x6a) - j 138 (0x8a) - Š 170 (0xaa) - ª 202 (0xca) - Ê 234 (0xea) - ê
43 (0x2b) - + 75 (0x4b) - K 107 (0x6b) - k 139 (0x8b) - 171 (0xab) - « 203 (0xcb) - Ë 235 (0xeb) - ë
44 (0x2c) - , 76 (0x4c) - L 108 (0x6c) - l 140 (0x8c) - Œ 172 (0xac) - ¬ 204 (0xcc) - Ì 236 (0xec) - ì
45 (0x2d) - - 77 (0x4d) - M 109 (0x6d) - m 141 (0x8d) - <EFBFBD> 173 (0xad) - ­ 205 (0xcd) - Í 237 (0xed) - í
46 (0x2e) - . 78 (0x4e) - N 110 (0x6e) - n 142 (0x8e) - Ž 174 (0xae) - ® 206 (0xce) - Î 238 (0xee) - î
47 (0x2f) - / 79 (0x4f) - O 111 (0x6f) - o 143 (0x8f) - <EFBFBD> 175 (0xaf) - ¯ 207 (0xcf) - Ï 239 (0xef) - ï
48 (0x30) - 0 80 (0x50) - P 112 (0x70) - p 144 (0x90) - <EFBFBD> 176 (0xb0) - ° 208 (0xd0) - Ð 240 (0xf0) - ð
49 (0x31) - 1 81 (0x51) - Q 113 (0x71) - q 145 (0x91) - 177 (0xb1) - ± 209 (0xd1) - Ñ 241 (0xf1) - ñ
50 (0x32) - 2 82 (0x52) - R 114 (0x72) - r 146 (0x92) - 178 (0xb2) - ² 210 (0xd2) - Ò 242 (0xf2) - ò
51 (0x33) - 3 83 (0x53) - S 115 (0x73) - s 147 (0x93) - 179 (0xb3) - ³ 211 (0xd3) - Ó 243 (0xf3) - ó
52 (0x34) - 4 84 (0x54) - T 116 (0x74) - t 148 (0x94) - 180 (0xb4) - ´ 212 (0xd4) - Ô 244 (0xf4) - ô
53 (0x35) - 5 85 (0x55) - U 117 (0x75) - u 149 (0x95) - 181 (0xb5) - µ 213 (0xd5) - Õ 245 (0xf5) - õ
54 (0x36) - 6 86 (0x56) - V 118 (0x76) - v 150 (0x96) - 182 (0xb6) - 214 (0xd6) - Ö 246 (0xf6) - ö
55 (0x37) - 7 87 (0x57) - W 119 (0x77) - w 151 (0x97) - 183 (0xb7) - · 215 (0xd7) - × 247 (0xf7) - ÷
56 (0x38) - 8 88 (0x58) - X 120 (0x78) - x 152 (0x98) - ˜ 184 (0xb8) - ¸ 216 (0xd8) - Ø 248 (0xf8) - ø
57 (0x39) - 9 89 (0x59) - Y 121 (0x79) - y 153 (0x99) - 185 (0xb9) - ¹ 217 (0xd9) - Ù 249 (0xf9) - ù
58 (0x3a) - : 90 (0x5a) - Z 122 (0x7a) - z 154 (0x9a) - š 186 (0xba) - º 218 (0xda) - Ú 250 (0xfa) - ú
59 (0x3b) - ; 91 (0x5b) - [ 123 (0x7b) - { 155 (0x9b) - 187 (0xbb) - » 219 (0xdb) - Û 251 (0xfb) - û
60 (0x3c) - < 92 (0x5c) - \ 124 (0x7c) - | 156 (0x9c) - œ 188 (0xbc) - ¼ 220 (0xdc) - Ü 252 (0xfc) - ü
61 (0x3d) - = 93 (0x5d) - ] 125 (0x7d) - } 157 (0x9d) - <EFBFBD> 189 (0xbd) - ½ 221 (0xdd) - Ý 253 (0xfd) - ý
62 (0x3e) - > 94 (0x5e) - ^ 126 (0x7e) - ~ 158 (0x9e) - ž 190 (0xbe) - ¾ 222 (0xde) - Þ 254 (0xfe) - þ
63 (0x3f) - ? 95 (0x5f) - _ 127 (0x7f) - 159 (0x9f) - Ÿ 191 (0xbf) - ¿ 223 (0xdf) - ß 255 (0xff) - ÿ
*/
// 1 - len in pings, 2 - pings (0 - dot, 1 - dash), reverse order
static const uint8_t ascii[] = { // sarting from space+1
6, 53, // ! -*-*--
6, 18, // " *-**-*
5, 29, // # [no] -*---
7, 72, // $ ***-**-
8, 86, // % [pc] *--*-*-*
5, 2, // & *-***
6, 30, // ' *----*
5, 13, // ( -*--*
6, 45, // ) -*--*-
7, 40, // * [str] ***-*-*
5, 10, // + *-*-*
6, 51, // , --**--
6, 33, // - -****-
6, 42, // . *-*-*-
5, 9, // / -**-*
5, 31, // 0 -----
5, 30, // 1 *----
5, 28, // 2 **---
5, 24, // 3 ***--
5, 16, // 4 ****-
5, 0, // 5 *****
5, 1, // 6 -****
5, 3, // 7 --***
5, 7, // 8 ---**
5, 15, // 9 ----*
6, 7, // : ---***
6, 21, // ; -*-*-*
7, 2, // < [ls] *-*****
5, 17, // = -***-
6, 3, // > [gs] --****
6, 12, // ? **--**
6, 22, // @ *--*-*
2, 2, // a *-
4, 1, // b -***
4, 5, // c -*-*
3, 1, // d -**
1, 0, // e *
4, 4, // f **-*
3, 3, // g --*
4, 0, // h ****
2, 0, // i **
4, 14, // j *---
3, 5, // k -*-
4, 2, // l *-**
2, 3, // m --
2, 1, // n -*
3, 7, // o ---
4, 6, // p *--*
4, 11, // q --*-
3, 2, // r *-*
3, 0, // s ***
1, 1, // t -
3, 4, // u **-
4, 8, // v ***-
3, 6, // w *--
4, 9, // x -**-
4, 13, // y -*--
4, 3, // z --**
5, 13, // [ [(]
6, 40, // \ [End of work] ***-*- //
6, 45, // ] [)]
7, 96, // ^ [hat] *****--
6, 44, // _ **--*-
6, 30, // ` [']
2, 2, // a *-
4, 1, // b -***
4, 5, // c -*-*
3, 1, // d -**
1, 0, // e *
4, 4, // f **-*
3, 3, // g --*
4, 0, // h ****
2, 0, // i **
4, 14, // j *---
3, 5, // k -*-
4, 2, // l *-**
2, 3, // m --
2, 1, // n -*
3, 7, // o ---
4, 6, // p *--*
4, 11, // q --*-
3, 2, // r *-*
3, 0, // s ***
1, 1, // t -
3, 4, // u **-
4, 8, // v ***-
3, 6, // w *--
4, 9, // x -**-
4, 13, // y -*--
4, 3, // z --**
5, 13, // { [(]
6, 30, // | [']
6, 45, // } [)]
8, 37, // ~ [tld] -*-**-**
};
/*
* I was too lazy
static const uint8_t koi8[] = {
};*/
/**
* return next character in word
* @param str (i) - string to send
* @param len (o) - length of buffer/3
*/
char *fillbuffer(char *str, uint8_t *len){
const uint8_t *arr = NULL;
char ltr = *str++;
if(ltr > ' ' && ltr < 127){ arr = ascii; ltr -= '!'; };
if(!arr){*len = 1; mbuff[0] = WRD_GAP+DASH_LEN; mbuff[2] = 0; return str;};
ltr *= 2;
uint8_t i, N = arr[(uint8_t)ltr], code = arr[(uint8_t)ltr+1];
uint16_t *ptr = mbuff;
for(i = 0; i < N; ++i){
uint16_t L = DOT_LEN;
if(code & 1) L = DASH_LEN;
*ptr++ = L + SHRT_GAP; *ptr++ = 0; *ptr++ = L;
code >>= 1;
}
ptr[-3] += LTR_GAP;
*len = N;
return str;
}

51
F0-nolib/morze/morse.h Normal file
View File

@ -0,0 +1,51 @@
/*
* geany_encoding=koi8-r
* morse.h
*
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#pragma once
#ifndef __MORSE_H__
#define __MORSE_H__
#include <stdint.h>
/*
International Morse code is composed of five elements:
short mark, dot or "dit" (Œ): "dot duration" is one time unit long == 50ms
longer mark, dash or "dah" (ŒŒŒ): three time units long == 150ms
inter-element gap between the dots and dashes within a character: one dot duration or one unit long == 50ms
short gap (between letters): three time units long == 150ms
medium gap (between words): seven time units long == 350ms
*/
// base timing (in ms)
#define DOT_LEN (75)
#define DASH_LEN (3*DOT_LEN)
#define SHRT_GAP (DOT_LEN)
// minus shr gap
#define LTR_GAP (2*DOT_LEN)
// minus ltr gap
#define WRD_GAP (4*DOT_LEN)
extern uint16_t mbuff[];
char *fillbuffer(char *ltr, uint8_t *len);
#endif // __MORSE_H__

BIN
F0-nolib/morze/morze.bin Executable file

Binary file not shown.

161
F0-nolib/morze/usart.c Normal file
View File

@ -0,0 +1,161 @@
/*
* usart.c
*
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include "usart.h"
#include <string.h> // memcpy
extern volatile uint32_t Tms;
static int datalen[2] = {0,0}; // received data line length (including '\n')
int linerdy = 0, // received data ready
dlen = 0, // length of data (including '\n') in current buffer
bufovr = 0, // input buffer overfull
txrdy = 1, // transmission done
dmaflag = 0
;
static int rbufno = 0; // current rbuf number
static char rbuf[2][UARTBUFSZ], tbuf[UARTBUFSZ]; // receive & transmit buffers
static char *recvdata = NULL;
void USART1_config(){
/* Enable the peripheral clock of GPIOA */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
/* GPIO configuration for USART1 signals */
/* (1) Select AF mode (10) on PA9 and PA10 */
/* (2) AF1 for USART1 signals */
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9|GPIO_MODER_MODER10))\
| (GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1); /* (1) */
GPIOA->AFR[1] = (GPIOA->AFR[1] &~ (GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2))\
| (1 << (1 * 4)) | (1 << (2 * 4)); /* (2) */
/* Enable the peripheral clock USART1 */
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
/* Configure USART1 */
/* (1) oversampling by 16, 115200 baud */
/* (2) 8 data bit, 1 start bit, 1 stop bit, no parity */
USART1->BRR = 480000 / 1152; /* (1) */
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; /* (2) */
/* polling idle frame Transmission */
while(!(USART1->ISR & USART_ISR_TC)){}
USART1->ICR |= USART_ICR_TCCF; /* clear TC flag */
USART1->CR1 |= USART_CR1_RXNEIE; /* enable TC, TXE & RXNE interrupt */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel2->CPAR = (uint32_t) &(USART1->TDR); // periph
DMA1_Channel2->CMAR = (uint32_t) tbuf; // mem
DMA1_Channel2->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq
USART1->CR3 = USART_CR3_DMAT;
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 3);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
/* Configure IT */
/* (3) Set priority for USART1_IRQn */
/* (4) Enable USART1_IRQn */
NVIC_SetPriority(USART1_IRQn, 0); /* (3) */
NVIC_EnableIRQ(USART1_IRQn); /* (4) */
}
void usart1_isr(){
#ifdef CHECK_TMOUT
static uint32_t tmout = 0;
#endif
if(USART1->ISR & USART_ISR_RXNE){ // RX not emty - receive next char
#ifdef CHECK_TMOUT
if(tmout && Tms >= tmout){ // set overflow flag
bufovr = 1;
datalen[rbufno] = 0;
}
tmout = Tms + TIMEOUT_MS;
if(!tmout) tmout = 1; // prevent 0
#endif
// read RDR clears flag
uint8_t rb = USART1->RDR;
if(datalen[rbufno] < UARTBUFSZ){ // put next char into buf
rbuf[rbufno][datalen[rbufno]++] = rb;
if(rb == '\n'){ // got newline - line ready
linerdy = 1;
dlen = datalen[rbufno];
recvdata = rbuf[rbufno];
// prepare other buffer
rbufno = !rbufno;
datalen[rbufno] = 0;
#ifdef CHECK_TMOUT
// clear timeout at line end
tmout = 0;
#endif
}
}else{ // buffer overrun
bufovr = 1;
datalen[rbufno] = 0;
#ifdef CHECK_TMOUT
tmout = 0;
#endif
}
}
}
// both timer and usart DMA
void dma1_channel2_3_isr(){
if(DMA1->ISR & DMA_ISR_TCIF2){ // Tx
DMA1->IFCR |= DMA_IFCR_CTCIF2; // clear TC flag
txrdy = 1;
}
if(DMA1->ISR & DMA_ISR_TCIF3){ // TIM3_UPd
DMA1_Channel3->CCR &= ~DMA_CCR_EN;
DMA1->IFCR |= DMA_IFCR_CTCIF3; // clear TC flag
dmaflag = 1;
}
}
/**
* return length of received data (without trailing zero
*/
int usart1_getline(char **line){
if(bufovr){
bufovr = 0;
linerdy = 0;
return 0;
}
*line = recvdata;
linerdy = 0;
return dlen;
}
TXstatus usart1_send(const char *str, int len){
if(!txrdy) return LINE_BUSY;
if(len > UARTBUFSZ) return STR_TOO_LONG;
txrdy = 0;
DMA1_Channel2->CCR &= ~DMA_CCR_EN;
memcpy(tbuf, str, len);
DMA1_Channel2->CNDTR = len;
DMA1_Channel2->CCR |= DMA_CCR_EN; // start transmission
return ALL_OK;
}
TXstatus usart1_send_blocking(const char *str, int len){
if(!txrdy) return LINE_BUSY;
int i;
for(i = 0; i < len; ++i){
USART1->TDR = *str++;
while(!(USART1->ISR & USART_ISR_TXE));
}
txrdy = 1;
return ALL_OK;
}

51
F0-nolib/morze/usart.h Normal file
View File

@ -0,0 +1,51 @@
/*
* usart.h
*
* Copyright 2017 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#pragma once
#ifndef __USART_H__
#define __USART_H__
#include "stm32f0.h"
// input and output buffers size
#define UARTBUFSZ (64)
// timeout between data bytes
#define TIMEOUT_MS (1500)
// check timeout
#define CHECK_TMOUT
typedef enum{
ALL_OK,
LINE_BUSY,
STR_TOO_LONG
} TXstatus;
#define usart1rx() (linerdy)
#define usart1ovr() (bufovr)
extern int linerdy, bufovr, txrdy, dmaflag;
void USART1_config();
int usart1_getline(char **line);
TXstatus usart1_send(const char *str, int len);
TXstatus usart1_send_blocking(const char *str, int len);
#endif // __USART_H__