diff --git a/F303-nolib/Readme.md b/F303-nolib/Readme.md new file mode 100644 index 0000000..7128e4d --- /dev/null +++ b/F303-nolib/Readme.md @@ -0,0 +1,8 @@ +Samples for STM32F303 +================================= + +Most of these samples works with [my non-solder devboard](https://github.com/eddyem/stm32samples/tree/master/F0_F1_F3-LQFP48_testboard) + +- blink - simple LEDs blink on PB0 and PB1 +- usart1 - read data from USART1 and send it back (blocking sending) +- usarts - work with all three USARTs, send to USART1 data read from other, you can send "2\n" or "3\n" to USART1 for tests of USART2/USART3 diff --git a/F303-nolib/blink/blink.bin b/F303-nolib/blink/blink.bin index 35409ea..45bc3be 100755 Binary files a/F303-nolib/blink/blink.bin and b/F303-nolib/blink/blink.bin differ diff --git a/F303-nolib/inc/Fx/stm32f3.h b/F303-nolib/inc/Fx/stm32f3.h index af491d3..1e6bc81 100644 --- a/F303-nolib/inc/Fx/stm32f3.h +++ b/F303-nolib/inc/Fx/stm32f3.h @@ -109,7 +109,7 @@ TRUE_INLINE int StartHSE(){ // system bus 72MHz from PLL #define WAITWHILE(x) do{StartUpCounter = 0; while((x) && (++StartUpCounter < 0xffffff)){nop();}; if(x) return 0;}while(0) RCC->CR = (RCC->CR & ~RCC_CR_PLLON) | RCC_CR_HSEON; // disable PLL to reconfigure, enable HSE WAITWHILE(!(RCC->CR & RCC_CR_HSERDY)); - // Enable Prefetch Buffer. Flash 2 wait states for 48..72MHz + // Enable Prefetch Buffer. Flash 4 wait states for 48..72MHz FLASH->ACR = (FLASH->ACR & ~(FLASH_ACR_LATENCY)) | FLASH_ACR_LATENCY_2 | FLASH_ACR_PRFTBE; // HCLK = SYSCLK (AHB prescaler = 1), PCLK1 = HCLK (APB1 prescaler = 1), PCLK2 = HCLK (APB2 prescaler = 1) diff --git a/F303-nolib/inc/ld/stm32f3.ld b/F303-nolib/inc/ld/stm32f3.ld index 56de5de..bffa48e 100644 --- a/F303-nolib/inc/ld/stm32f3.ld +++ b/F303-nolib/inc/ld/stm32f3.ld @@ -49,6 +49,10 @@ SECTIONS { _stext = .; *(.text*) *(.rodata*) + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + KEEP (*(.init)) + KEEP (*(.fini)) . = ALIGN(4); _etext = .; } >rom @@ -61,7 +65,7 @@ SECTIONS { .ARM : { *(.ARM.exidx*) } >rom - + .data : { . = ALIGN(4); @@ -74,11 +78,22 @@ SECTIONS { .myvars : { . = ALIGN(2048); + __varsstart = ABSOLUTE(.); KEEP(*(.myvars)) } > rom _ldata = LOADADDR(.data); + .ccmram : + { + . = ALIGN(4); + _sccmram = .; + *(.ccmram) + *(.ccmram*) + . = ALIGN(4); + _eccmram = .; + } >ccmram AT> rom + .bss : { . = ALIGN(4); diff --git a/F303-nolib/usart1/Makefile b/F303-nolib/usart1/Makefile new file mode 100644 index 0000000..7b02a34 --- /dev/null +++ b/F303-nolib/usart1/Makefile @@ -0,0 +1,146 @@ +BINARY = usart1 +BOOTPORT ?= /dev/ttyUSB0 +BOOTSPEED ?= 115200 +# MCU FAMILY +FAMILY ?= F3 +# MCU code +MCU ?= F303xb +# or __ARM_ARCH_7EM__ +ARMARCH = __ARM_ARCH_7M__ +# change this linking script depending on particular MCU model, +LDSCRIPT ?= stm32f303xB.ld +# debug +#DEFS = -DEBUG + +INDEPENDENT_HEADERS= + +FP_FLAGS ?= -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant +ASM_FLAGS ?= -mthumb -mcpu=cortex-m4 +ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS) -D $(ARMARCH) + +############################################################################### +# Executables +#PREFIX ?= arm-none-eabi +# gcc from arm web site +PREFIX ?= /opt/bin/arm-none-eabi +TOOLCHLIB ?= /opt/arm-none-eabi/lib +RM := rm -f +RMDIR := rmdir +CC := $(PREFIX)-gcc +# don't replace ld with gcc: the binary size would be much greater!! +LD := $(PREFIX)-ld +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +SIZE := $(PREFIX)-size +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH := $(shell which st-flash) +STBOOT := $(shell which stm32flash) +DFUUTIL := $(shell which dfu-util) + +############################################################################### +# Source files +OBJDIR := mk +SRC := $(wildcard *.c) +OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o)) +STARTUP := $(OBJDIR)/startup.o +MAP := $(OBJDIR)/$(BINARY).map +OBJS += $(STARTUP) +# dependencies: we need them to recompile files if their headers-dependencies changed +DEPS := $(OBJS:.o=.d) + +INC_DIR ?= ../inc + +INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm +LIB_DIR := $(INC_DIR)/ld + +############################################################################### +# C flags +CFLAGS += -g -gdwarf-2 +CFLAGS += -O2 -D__thumb2__=1 -MD +CFLAGS += -Wall -Werror -Wextra -Wshadow +CFLAGS += -fshort-enums -ffunction-sections -fdata-sections +#CFLAGS += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector +CFLAGS += $(ARCH_FLAGS) + +############################################################################### +# Linker flags +#LDFLAGS += -nostartfiles --static -nostdlib -specs=nosys.specs -specs=nano.specs +LDFLAGS += $(ARCH_FLAGS) +LDFLAGS += -specs=nosys.specs -specs=nano.specs +LDFLAGS += -L$(LIB_DIR) +#LDFLAGS += -L$(TOOLCHLIB) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(MAP),--cref -Wl,--gc-sections + +############################################################################### +# Used libraries +#LDLIBS += -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) + +ELF := $(OBJDIR)/$(BINARY).elf +LIST := $(OBJDIR)/$(BINARY).list +BIN := $(BINARY).bin +HEX := $(BINARY).hex + +all: bin list size + +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) -o $@ -c $< + +$(OBJDIR)/%.o: %.c + @echo " CC $<" + $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $< + +$(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)" + $(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF) + +size: $(ELF) + $(SIZE) $(ELF) + +clean: + @echo " CLEAN" + $(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(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) + +dfuboot: $(BIN) + @echo " LOAD $(BIN) THROUGH DFU" + $(DFUUTIL) -a0 -D $(BIN) -s 0x08000000 + +.PHONY: clean flash boot diff --git a/F303-nolib/usart1/hardware.c b/F303-nolib/usart1/hardware.c new file mode 100644 index 0000000..2f09270 --- /dev/null +++ b/F303-nolib/usart1/hardware.c @@ -0,0 +1,32 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#include "hardware.h" +#include "usart.h" + +static inline void gpio_setup(){ + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // for USART and LEDs + for(int i = 0; i < 10000; ++i) nop(); + GPIOB->MODER = GPIO_MODER_MODER0_O | GPIO_MODER_MODER1_O; + GPIOB->ODR = 1; +} + +void hw_setup(){ + gpio_setup(); +} + diff --git a/F303-nolib/usart1/hardware.h b/F303-nolib/usart1/hardware.h new file mode 100644 index 0000000..b7ebcd6 --- /dev/null +++ b/F303-nolib/usart1/hardware.h @@ -0,0 +1,27 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#pragma once +#ifndef __HARDWARE_H__ +#define __HARDWARE_H__ + +#include "stm32f3.h" + +void hw_setup(); + +#endif // __HARDWARE_H__ diff --git a/F303-nolib/usart1/main.c b/F303-nolib/usart1/main.c new file mode 100644 index 0000000..a3af972 --- /dev/null +++ b/F303-nolib/usart1/main.c @@ -0,0 +1,52 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#include "stm32f3.h" +#include "hardware.h" +#include "usart.h" + + +volatile uint32_t Tms = 0; + +void sys_tick_handler(void){ + ++Tms; +} + +int main(void){ + if(!StartHSE()) StartHSI(); + SysTick_Config((uint32_t)72000); // 1ms + hw_setup(); + usart_setup(); + uint32_t ctr = Tms; + while(1){ + if(Tms - ctr > 499){ + ctr = Tms; + pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0 + } + if(bufovr){ + bufovr = 0; + usart_send("bufovr\n"); + } + char *txt = NULL; + if(usart_getline(&txt)){ + usart_send("Get by USART1: "); + usart_send(txt); + usart_putchar('\n'); + } + } +} diff --git a/F303-nolib/usart1/usart.c b/F303-nolib/usart1/usart.c new file mode 100644 index 0000000..ee8fc03 --- /dev/null +++ b/F303-nolib/usart1/usart.c @@ -0,0 +1,106 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#include "stm32f3.h" +#include "hardware.h" +#include "usart.h" +#include + +static volatile int idatalen = 0; // received data line length (including '\n') + +volatile int linerdy = 0, // received data ready + dlen = 0, // length of data (including '\n') in current buffer + bufovr = 0; // input buffer overfull + +static volatile int rbufno = 0; // current rbuf number +static char rbuf[2][UARTBUFSZ]; // receive buffers +static volatile char *recvdata = NULL; + +/** + * return length of received data (without trailing zero) + */ +int usart_getline(char **line){ + if(bufovr){ + bufovr = 0; + linerdy = 0; + return 0; + } + if(!linerdy) return 0; + *line = (char*)recvdata; + linerdy = 0; + return dlen; +} + +void usart_putchar(const char ch){ + while(!(USART1->ISR & USART_ISR_TXE)); + USART1->TDR = ch; +} +void usart_sendn(const char *str, int L){ + if(!str) return; + for(int i = 0; i < L; ++i){ + usart_putchar(str[i]); + } +} +void usart_send(const char *str){ + if(!str) return; + int L = 0; + const char *ptr = str; + while(*ptr++) ++L; + usart_sendn(str, L); +} + +void usart_setup(){ + // USART1: Rx - PA10 (AF7), Tx - PA9 (AF7) + // setup pins: + GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10)) | + GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF; + GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) | + 7 << (1 * 4) | 7 << (2 * 4); // PA9, PA10 + // clock + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + USART1->ICR = 0xffffffff; // clear all flags + USART1->BRR = 720000 / 1152; + USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; // 1start,8data,nstop; enable Rx,Tx,USART + uint32_t tmout = 16000000; + while(!(USART1->ISR & USART_ISR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission + USART1->ICR = 0xffffffff; // clear all flags again + NVIC_SetPriority(USART1_IRQn, 0); + NVIC_EnableIRQ(USART1_IRQn); +} + +void usart1_exti25_isr(){ + if(USART1->ISR & USART_ISR_RXNE){ // RX not emty - receive next char + // read RDR clears flag + uint8_t rb = USART1->RDR; + if(idatalen < UARTBUFSZ){ // put next char into buf + rbuf[rbufno][idatalen++] = rb; + if(rb == '\n'){ // got newline - line ready + linerdy = 1; + dlen = idatalen; + recvdata = rbuf[rbufno]; + recvdata[dlen-1] = 0; + // prepare other buffer + rbufno = !rbufno; + idatalen = 0; + } + }else{ // buffer overrun + bufovr = 1; + idatalen = 0; + } + } +} diff --git a/F303-nolib/usart1/usart.h b/F303-nolib/usart1/usart.h new file mode 100644 index 0000000..f252029 --- /dev/null +++ b/F303-nolib/usart1/usart.h @@ -0,0 +1,36 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#pragma once +#ifndef __USART_H__ +#define __USART_H__ + +#include "hardware.h" + +// input buffers size +#define UARTBUFSZ (80) + +extern volatile int linerdy, bufovr; + +void usart_setup(); +int usart_getline(char **line); +void usart_send(const char *str); +void usart_sendn(const char *str, int L); +void usart_putchar(const char ch); + +#endif // __USART_H__ diff --git a/F303-nolib/usart1/usart1.bin b/F303-nolib/usart1/usart1.bin new file mode 100755 index 0000000..b224843 Binary files /dev/null and b/F303-nolib/usart1/usart1.bin differ diff --git a/F303-nolib/usarts/Makefile b/F303-nolib/usarts/Makefile new file mode 100644 index 0000000..7ddce2f --- /dev/null +++ b/F303-nolib/usarts/Makefile @@ -0,0 +1,146 @@ +BINARY = usart +BOOTPORT ?= /dev/ttyUSB0 +BOOTSPEED ?= 115200 +# MCU FAMILY +FAMILY ?= F3 +# MCU code +MCU ?= F303xb +# or __ARM_ARCH_7EM__ +ARMARCH = __ARM_ARCH_7M__ +# change this linking script depending on particular MCU model, +LDSCRIPT ?= stm32f303xB.ld +# debug +#DEFS = -DEBUG + +INDEPENDENT_HEADERS= + +FP_FLAGS ?= -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant +ASM_FLAGS ?= -mthumb -mcpu=cortex-m4 +ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS) -D $(ARMARCH) + +############################################################################### +# Executables +#PREFIX ?= arm-none-eabi +# gcc from arm web site +PREFIX ?= /opt/bin/arm-none-eabi +TOOLCHLIB ?= /opt/arm-none-eabi/lib +RM := rm -f +RMDIR := rmdir +CC := $(PREFIX)-gcc +# don't replace ld with gcc: the binary size would be much greater!! +LD := $(PREFIX)-ld +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +SIZE := $(PREFIX)-size +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH := $(shell which st-flash) +STBOOT := $(shell which stm32flash) +DFUUTIL := $(shell which dfu-util) + +############################################################################### +# Source files +OBJDIR := mk +SRC := $(wildcard *.c) +OBJS := $(addprefix $(OBJDIR)/, $(SRC:%.c=%.o)) +STARTUP := $(OBJDIR)/startup.o +MAP := $(OBJDIR)/$(BINARY).map +OBJS += $(STARTUP) +# dependencies: we need them to recompile files if their headers-dependencies changed +DEPS := $(OBJS:.o=.d) + +INC_DIR ?= ../inc + +INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm +LIB_DIR := $(INC_DIR)/ld + +############################################################################### +# C flags +CFLAGS += -g -gdwarf-2 +CFLAGS += -O2 -D__thumb2__=1 -MD +CFLAGS += -Wall -Werror -Wextra -Wshadow +CFLAGS += -fshort-enums -ffunction-sections -fdata-sections +#CFLAGS += -fno-common -ffunction-sections -fdata-sections -fno-stack-protector +CFLAGS += $(ARCH_FLAGS) + +############################################################################### +# Linker flags +#LDFLAGS += -nostartfiles --static -nostdlib -specs=nosys.specs -specs=nano.specs +LDFLAGS += $(ARCH_FLAGS) +LDFLAGS += -specs=nosys.specs -specs=nano.specs +LDFLAGS += -L$(LIB_DIR) +#LDFLAGS += -L$(TOOLCHLIB) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(MAP),--cref -Wl,--gc-sections + +############################################################################### +# Used libraries +#LDLIBS += -lc $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +DEFS += -DSTM32$(FAMILY) -DSTM32$(MCU) + +ELF := $(OBJDIR)/$(BINARY).elf +LIST := $(OBJDIR)/$(BINARY).list +BIN := $(BINARY).bin +HEX := $(BINARY).hex + +all: bin list size + +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) -o $@ -c $< + +$(OBJDIR)/%.o: %.c + @echo " CC $<" + $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) -o $@ -c $< + +$(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)" + $(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF) + +size: $(ELF) + $(SIZE) $(ELF) + +clean: + @echo " CLEAN" + $(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(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) + +dfuboot: $(BIN) + @echo " LOAD $(BIN) THROUGH DFU" + $(DFUUTIL) -a0 -D $(BIN) -s 0x08000000 + +.PHONY: clean flash boot diff --git a/F303-nolib/usarts/hardware.c b/F303-nolib/usarts/hardware.c new file mode 100644 index 0000000..3979f54 --- /dev/null +++ b/F303-nolib/usarts/hardware.c @@ -0,0 +1,32 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#include "hardware.h" +#include "usart.h" + +static inline void gpio_setup(){ + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // for USART and LEDs + for(int i = 0; i < 10; ++i) nop(); // don't know why, but next line won't work without a little delay + GPIOB->MODER = GPIO_MODER_MODER0_O | GPIO_MODER_MODER1_O; + GPIOB->ODR = 1; +} + +void hw_setup(){ + gpio_setup(); +} + diff --git a/F303-nolib/usarts/hardware.h b/F303-nolib/usarts/hardware.h new file mode 100644 index 0000000..b7ebcd6 --- /dev/null +++ b/F303-nolib/usarts/hardware.h @@ -0,0 +1,27 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#pragma once +#ifndef __HARDWARE_H__ +#define __HARDWARE_H__ + +#include "stm32f3.h" + +void hw_setup(); + +#endif // __HARDWARE_H__ diff --git a/F303-nolib/usarts/main.c b/F303-nolib/usarts/main.c new file mode 100644 index 0000000..ef82493 --- /dev/null +++ b/F303-nolib/usarts/main.c @@ -0,0 +1,60 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#include "stm32f3.h" +#include "hardware.h" +#include "usart.h" + + +volatile uint32_t Tms = 0; + +void sys_tick_handler(void){ + ++Tms; +} + +int main(void){ + if(!StartHSE()) StartHSI(); + SysTick_Config((uint32_t)72000); // 1ms + hw_setup(); + usart_setup(); + uint32_t ctr = Tms; + while(1){ + if(Tms - ctr > 499){ + ctr = Tms; + pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0 + // usart_send(1, "test\n"); + // transmit_tbuf(); + } + for(int n = 1; n <= USARTNUM; ++n){ + if(usartrx(n)){ // usart1 received data, store in in buffer + char *txt = NULL; + int r = usart_getline(n, &txt); + if(r){ + txt[r] = 0; + usart_send(1, "Got by USART"); + char u[] = "0 : "; u[0] = '0' + n; + usart_send(1, u); + usart_send(1, txt); + if(txt[0] == '2') usart_send(2, "Test for USART2\n"); + else if(txt[0] == '3') usart_send(3, "Test for USART3\n"); + transmit_tbuf(); + } + } + } + } +} diff --git a/F303-nolib/usarts/usart.bin b/F303-nolib/usarts/usart.bin new file mode 100755 index 0000000..88b01dd Binary files /dev/null and b/F303-nolib/usarts/usart.bin differ diff --git a/F303-nolib/usarts/usart.c b/F303-nolib/usarts/usart.c new file mode 100644 index 0000000..8b15eba --- /dev/null +++ b/F303-nolib/usarts/usart.c @@ -0,0 +1,242 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#include "stm32f3.h" +#include "hardware.h" +#include "usart.h" +#include + +extern volatile uint32_t Tms; +// USART tx DMA 1: DMA1_Channel4, 2: DMA1_Channel7, 3: DMA1_Channel2 +static DMA_Channel_TypeDef *USARTDMA[USARTNUM] = { + DMA1_Channel4, DMA1_Channel7, DMA1_Channel2 +}; +static const uint32_t dmatcifs[USARTNUM] = { + DMA_ISR_TCIF4, DMA_ISR_TCIF7, DMA_ISR_TCIF2 +}; +static const uint32_t dmactcifs[USARTNUM] = { + DMA_IFCR_CTCIF4, DMA_IFCR_CTCIF7, DMA_IFCR_CTCIF2 +}; +static USART_TypeDef *USARTs[USARTNUM] = { + USART1, USART2, USART3 +}; + +static volatile int idatalen[USARTNUM][2] = {0}; // received data line length (including '\n') +static volatile int odatalen[USARTNUM][2] = {0}; + +volatile int linerdy[USARTNUM] = {0}, // received data ready + dlen[USARTNUM] = {0}, // length of data (including '\n') in current buffer + bufovr[USARTNUM] = {0}, // input buffer overfull + txrdy[USARTNUM] = {1,1,1}; // transmission done + + +int rbufno[USARTNUM] = {0}, tbufno[USARTNUM] = {0}; // current rbuf/tbuf numbers +static char rbuf[USARTNUM][2][UARTBUFSZI], tbuf[USARTNUM][2][UARTBUFSZO]; // receive & transmit buffers +static char *recvdata[USARTNUM] = {0}; + +/** + * return length of received data (without trailing zero + * usartno: 1, 2 or 3 + */ +int usart_getline(int usartno, char **line){ + --usartno; + if(bufovr[usartno]){ + bufovr[usartno] = 0; + linerdy[usartno] = 0; + return 0; + } + *line = recvdata[usartno]; + linerdy[usartno] = 0; + return dlen[usartno]; +} + +// transmit current tbuf for all USARTs and swap buffers +void transmit_tbuf(){ + for(int usartno = 0; usartno < USARTNUM; ++usartno){ + uint32_t p = 1000000; + while(!txrdy[usartno] && --p); + if(!txrdy[usartno]) continue; + register int l = odatalen[usartno][tbufno[usartno]]; + if(!l) continue; + txrdy[usartno] = 0; + odatalen[usartno][tbufno[usartno]] = 0; + USARTDMA[usartno]->CCR &= ~DMA_CCR_EN; + USARTDMA[usartno]->CMAR = (uint32_t) tbuf[usartno][tbufno[usartno]]; // mem + USARTDMA[usartno]->CNDTR = l; + USARTDMA[usartno]->CCR |= DMA_CCR_EN; + tbufno[usartno] = !tbufno[usartno]; + } +} + +void usart_putchar(int usartno, const char ch){ + --usartno; + if(odatalen[usartno][tbufno[usartno]] == UARTBUFSZO) transmit_tbuf(); + tbuf[usartno][tbufno[usartno]][odatalen[usartno][tbufno[usartno]]++] = ch; +} + +void usart_send(int usartno, const char *str){ + --usartno; + while(*str){ + if(odatalen[usartno][tbufno[usartno]] == UARTBUFSZO) transmit_tbuf(); + tbuf[usartno][tbufno[usartno]][odatalen[usartno][tbufno[usartno]]++] = *str++; + } +} + +void usart_sendn(int usartno, const char *str, uint32_t L){ + --usartno; + for(uint32_t i = 0; i < L; ++i){ + if(odatalen[usartno][tbufno[usartno]] == UARTBUFSZO) transmit_tbuf(); + tbuf[usartno][tbufno[usartno]][odatalen[usartno][tbufno[usartno]]++] = *str++; + } +} + +void newline(int usartno){ + usart_putchar(usartno, '\n'); + transmit_tbuf(); +} + + +void usart_setup(){ + // USART1: Rx - PA10 (AF7), Tx - PA9 (AF7) + // USART2: Rx - PA3 (AF7), Tx - PA2 (AF7) + // USART3: Rx - PB11 (AF7), Tx - PB10 (AF7) + // setup pins: + GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER2|GPIO_MODER_MODER3|GPIO_MODER_MODER9 | GPIO_MODER_MODER10)) | + GPIO_MODER_MODER2_AF | GPIO_MODER_MODER3_AF | GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF; + GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(GPIO_AFRL_AFRL2 | GPIO_AFRL_AFRL3)) | + 7 << (2 * 4) | 7 << (3 * 4); // PA2,3 + GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) | + 7 << (1 * 4) | 7 << (2 * 4); // PA9, PA10 + GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER10 | GPIO_MODER_MODER11)) | + GPIO_MODER_MODER10_AF | GPIO_MODER_MODER11_AF; + GPIOB->AFR[1] = (GPIOB->AFR[1] & ~(GPIO_AFRH_AFRH2 | GPIO_AFRH_AFRH3)) | + 7 << (2 * 4) | 7 << (3 * 4); // PB10, PB11 + // clock + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + RCC->APB1ENR |= RCC_APB1ENR_USART2EN; + RCC->APB1ENR |= RCC_APB1ENR_USART3EN; + RCC->AHBENR |= RCC_AHBENR_DMA1EN; + for(int i = 0; i < USARTNUM; ++i){ + USARTs[i]->ICR = 0xffffffff; // clear all flags + // USARTX Tx DMA + USARTDMA[i]->CCR &= ~DMA_CCR_EN; + USARTDMA[i]->CPAR = (uint32_t) &USARTs[i]->TDR; // periph + USARTDMA[i]->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq + // setup usarts + USARTs[i]->BRR = 720000 / 1152; + USARTs[i]->CR3 = USART_CR3_DMAT; // enable DMA Tx + USARTs[i]->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; // 1start,8data,nstop; enable Rx,Tx,USART + uint32_t tmout = 16000000; + while(!(USARTs[i]->ISR & USART_ISR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission + USARTs[i]->ICR = 0xffffffff; // clear all flags again + } + NVIC_SetPriority(DMA1_Channel2_IRQn, 3); + NVIC_EnableIRQ(DMA1_Channel2_IRQn); + NVIC_SetPriority(USART1_IRQn, 0); + NVIC_EnableIRQ(USART1_IRQn); + NVIC_SetPriority(DMA1_Channel4_IRQn, 3); + NVIC_EnableIRQ(DMA1_Channel4_IRQn); + NVIC_SetPriority(USART2_IRQn, 0); + NVIC_EnableIRQ(USART2_IRQn); + NVIC_SetPriority(DMA1_Channel7_IRQn, 3); + NVIC_EnableIRQ(DMA1_Channel7_IRQn); + NVIC_SetPriority(USART3_IRQn, 0); + NVIC_EnableIRQ(USART3_IRQn); +} + +void usart_stop(){ + RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN; + RCC->APB1ENR &= ~RCC_APB1ENR_USART2EN; + RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN; +} + +static void usart_IRQ(int usartno){ + USART_TypeDef *USARTX = USARTs[usartno]; + //USND("USART"); USB_sendstr(u2str(usartno+1)); USND(" IRQ, ISR="); + //USB_sendstr(uhex2str(USARTX->ISR)); USND("\n"); + #ifdef CHECK_TMOUT + static uint32_t tmout[USARTNUM] = {0}; + #endif + if(USARTX->ISR & USART_ISR_RXNE){ // RX not emty - receive next char + #ifdef CHECK_TMOUT + if(tmout[usartno] && Tms >= tmout[usartno]){ // set overflow flag + bufovr[usartno] = 1; + idatalen[usartno][rbufno[usartno]] = 0; + } + tmout[usartno] = Tms + TIMEOUT_MS; + if(!tmout[usartno]) tmout[usartno] = 1; // prevent 0 + #endif + // read RDR clears flag + uint8_t rb = USARTX->RDR; + //USND("RB="); USB_sendstr(uhex2str(rb)); USND("\n"); + if(idatalen[usartno][rbufno[usartno]] < UARTBUFSZI){ // put next char into buf + rbuf[usartno][rbufno[usartno]][idatalen[usartno][rbufno[usartno]]++] = rb; + if(rb == '\n'){ // got newline - line ready + //USND("Newline\n"); + linerdy[usartno] = 1; + dlen[usartno] = idatalen[usartno][rbufno[usartno]]; + recvdata[usartno] = rbuf[usartno][rbufno[usartno]]; + // prepare other buffer + rbufno[usartno] = !rbufno[usartno]; + idatalen[usartno][rbufno[usartno]] = 0; + #ifdef CHECK_TMOUT + // clear timeout at line end + tmout[usartno] = 0; + #endif + } + }else{ // buffer overrun + bufovr[usartno] = 1; + idatalen[usartno][rbufno[usartno]] = 0; + #ifdef CHECK_TMOUT + tmout[usartno] = 0; + #endif + } + } +} + +static void usart_dma_IRQ(int usartno){ + if(DMA1->ISR & dmatcifs[usartno]){ + DMA1->IFCR |= dmactcifs[usartno]; + txrdy[usartno] = 1; + } +} + +// USART1 Rx +void usart1_exti25_isr(){ + usart_IRQ(0); +} +// USART2 Rx +void usart2_exti26_isr(){ + usart_IRQ(1); +} +// USART3 Rx +void usart3_exti28_isr(){ + usart_IRQ(2); +} +// USART1 Tx +void dma1_channel4_isr(){ + usart_dma_IRQ(0); +} +// USART2 Tx +void dma1_channel7_isr(){ + usart_dma_IRQ(1); +} +// USART3 Tx +void dma1_channel2_isr(){ + usart_dma_IRQ(2); +} diff --git a/F303-nolib/usarts/usart.h b/F303-nolib/usarts/usart.h new file mode 100644 index 0000000..f6a4f7c --- /dev/null +++ b/F303-nolib/usarts/usart.h @@ -0,0 +1,52 @@ +/* + * This file is part of the F303usart project. + * Copyright 2021 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 3 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, see . + */ + +#pragma once +#ifndef __USART_H__ +#define __USART_H__ + +#include "hardware.h" + +#define USARTNUM (3) + +// input and output buffers size +#define UARTBUFSZI (80) +#define UARTBUFSZO (80) +// timeout between data bytes +#ifndef TIMEOUT_MS +#define TIMEOUT_MS (1500) +#endif + +// macro for static strings +#define SEND(n, str) usart_send(n, str) + +#define usartrx(n) (linerdy[n-1]) +#define usartovr(n) (bufovr[n-1]) + +extern volatile int linerdy[], bufovr[], txrdy[]; + +void transmit_tbuf(); +void usart_setup(); +int usart_getline(int usartno, char **line); +void usart_send(int usartno, const char *str); +void usart_sendn(int usartno, const char *str, uint32_t L); +void newline(int usartno); +void usart_putchar(int usartno, const char ch); +void usart_stop(); + +#endif // __USART_H__