diff --git a/F0/Readme.md b/F0/Readme.md index 24d1c95..bfc4cb1 100644 --- a/F0/Readme.md +++ b/F0/Readme.md @@ -3,3 +3,4 @@ Samples for STM32F042-nucleo and chinese STM32F030-based devboard - 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 diff --git a/F0/uart_blink/Makefile b/F0/uart_blink/Makefile new file mode 100644 index 0000000..f652305 --- /dev/null +++ b/F0/uart_blink/Makefile @@ -0,0 +1,137 @@ +BINARY = uartblink +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 diff --git a/F0/uart_blink/Readme.md b/F0/uart_blink/Readme.md new file mode 100644 index 0000000..38e7a49 --- /dev/null +++ b/F0/uart_blink/Readme.md @@ -0,0 +1,6 @@ +Code for STM32F030F4 chinese board +- Toggle onboard green LED once per second. +- Echo received by USART1 data (not more than 64 bytes including '\n') on B115200: + - if PA6 not connected to ground echo text directly + - otherwice echo it reversly +- Light up LED on PA5 (opendrain) when receive data and turn it off when send. diff --git a/F0/uart_blink/ld/stm32f030f.ld b/F0/uart_blink/ld/stm32f030f.ld new file mode 100644 index 0000000..f8b61f1 --- /dev/null +++ b/F0/uart_blink/ld/stm32f030f.ld @@ -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 + diff --git a/F0/uart_blink/main.c b/F0/uart_blink/main.c new file mode 100644 index 0000000..b01102c --- /dev/null +++ b/F0/uart_blink/main.c @@ -0,0 +1,84 @@ +/* + * main.c + * + * Copyright 2017 Edward V. Emelianoff + * + * 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 "usart.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 (PA5 & PA4) as output */ + GPIOA->MODER = GPIO_MODER_MODER4_O | GPIO_MODER_MODER5_O; + GPIOA->OTYPER = 1 << 5; // PA5 - opendrain, PA4 - pushpull + /* PA6 - switch blink rate (pullup input) */ + GPIOA->PUPDR = GPIO_PUPDR_PUPDR6_0; +} + +/** + * reverce line + */ +char *rline(char *in, int L){ + static char out[UARTBUFSZ]; + if(L > UARTBUFSZ - 1) return in; + char *optr = out, *iptr = &in[L-1]; + for(; L > 0; --L) *optr++ = *iptr--; + *optr = '\n'; + return out; +} + +int main(void){ + uint32_t lastT = 0; + int L = 0; + char *txt; + sysreset(); + SysTick_Config(6000, 1); + gpio_setup(); + USART1_config(); + //StartHSE(); + pin_set(GPIOA, 1<<5); // clear extern LED + /* Do nothing in main loop */ + while (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(!pin_read(GPIOA, 1<<6)){ // there's a jumper: reverse string + txt = rline(txt, L); + } + pin_clear(GPIOA, 1<<5); // set extern LED + } + if(L){ // text waits for sending + if(ALL_OK == usart1_send(txt, L)){ + L = 0; + pin_set(GPIOA, 1<<5); // clear extern LED + } + } + } +} diff --git a/F0/uart_blink/uartblink.bin b/F0/uart_blink/uartblink.bin new file mode 100755 index 0000000..589e867 Binary files /dev/null and b/F0/uart_blink/uartblink.bin differ diff --git a/F0/uart_blink/usart.c b/F0/uart_blink/usart.c new file mode 100644 index 0000000..826c1a4 --- /dev/null +++ b/F0/uart_blink/usart.c @@ -0,0 +1,153 @@ +/* + * usart.c + * + * Copyright 2017 Edward V. Emelianov + * + * 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 // 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 + txdlen = 0 // length of transmitted data +; + +static int rbufno = 0, // current rbuf number + txnum = 0; // current number of transmitted symbol in tbuf +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_TCIE | USART_CR1_TXEIE | USART_CR1_RXNEIE;/* enable TC, TXE & RXNE interrupt */ + /* 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_TC){ // Transmission complete + USART1->ICR |= USART_ICR_TCCF; /* Clear transfer complete flag */ + txrdy = 1; + } + if(USART1->ISR & USART_ISR_TXE){ // TX emty - send next char + // clear by writing to TDR + if(txnum < txdlen){ + USART1->TDR = tbuf[txnum++]; + }else + USART1->CR1 &= ~USART_CR1_TXEIE; // turn off interrupt + } + 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 + } + } +} + +/** + * 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; + txdlen = len; + memcpy(tbuf, str, len); + txnum = 0; + USART1->CR1 |= USART_CR1_TXEIE; // allow IRQ + 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; +} diff --git a/F0/uart_blink/usart.h b/F0/uart_blink/usart.h new file mode 100644 index 0000000..ee27f42 --- /dev/null +++ b/F0/uart_blink/usart.h @@ -0,0 +1,51 @@ +/* + * usart.h + * + * Copyright 2017 Edward V. Emelianov + * + * 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; + +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__