From 5066fcf3c2e508a12e522f00d95dbed72695ccf6 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Thu, 12 Jan 2023 23:29:30 +0300 Subject: [PATCH] start with RTC for G0 --- G0:G070/RTC/Makefile | 164 ++++++++++++++++++++++ G0:G070/RTC/README | 10 ++ G0:G070/RTC/main.c | 71 ++++++++++ G0:G070/RTC/openocd.cfg | 89 ++++++++++++ G0:G070/RTC/proto.c | 83 ++++++++++++ G0:G070/RTC/proto.h | 22 +++ G0:G070/RTC/rtc.bin | Bin 0 -> 2716 bytes G0:G070/RTC/rtc.c | 61 +++++++++ G0:G070/RTC/rtc.cflags | 1 + G0:G070/RTC/rtc.config | 3 + G0:G070/RTC/rtc.creator | 1 + G0:G070/RTC/rtc.creator.user | 171 +++++++++++++++++++++++ G0:G070/RTC/rtc.cxxflags | 1 + G0:G070/RTC/rtc.files | 11 ++ G0:G070/RTC/rtc.h | 36 +++++ G0:G070/RTC/rtc.includes | 4 + G0:G070/RTC/strfunc.c | 255 +++++++++++++++++++++++++++++++++++ G0:G070/RTC/strfunc.h | 29 ++++ G0:G070/RTC/usart.c | 177 ++++++++++++++++++++++++ G0:G070/RTC/usart.h | 32 +++++ 20 files changed, 1221 insertions(+) create mode 100644 G0:G070/RTC/Makefile create mode 100644 G0:G070/RTC/README create mode 100644 G0:G070/RTC/main.c create mode 100644 G0:G070/RTC/openocd.cfg create mode 100644 G0:G070/RTC/proto.c create mode 100644 G0:G070/RTC/proto.h create mode 100755 G0:G070/RTC/rtc.bin create mode 100644 G0:G070/RTC/rtc.c create mode 100644 G0:G070/RTC/rtc.cflags create mode 100644 G0:G070/RTC/rtc.config create mode 100644 G0:G070/RTC/rtc.creator create mode 100644 G0:G070/RTC/rtc.creator.user create mode 100644 G0:G070/RTC/rtc.cxxflags create mode 100644 G0:G070/RTC/rtc.files create mode 100644 G0:G070/RTC/rtc.h create mode 100644 G0:G070/RTC/rtc.includes create mode 100644 G0:G070/RTC/strfunc.c create mode 100644 G0:G070/RTC/strfunc.h create mode 100644 G0:G070/RTC/usart.c create mode 100644 G0:G070/RTC/usart.h diff --git a/G0:G070/RTC/Makefile b/G0:G070/RTC/Makefile new file mode 100644 index 0000000..5e36ec3 --- /dev/null +++ b/G0:G070/RTC/Makefile @@ -0,0 +1,164 @@ +BINARY = rtc +BOOTPORT ?= /dev/ttyUSB0 +BOOTSPEED ?= 115200 +# MCU FAMILY +FAMILY = G0 +# MCU code +MCU = G070xx +#DEFS = -DEBUG -g3 +# change this linking script depending on particular MCU model, +# for example, if you have STM32F103VBT6, you should write: +LDSCRIPT = stm32g070xb.ld + +INDEPENDENT_HEADERS= + +FP_FLAGS ?= -msoft-float +ASM_FLAGS = -mthumb -mcpu=cortex-m0plus -march=armv6-m -mtune=cortex-m0plus +ARCH_FLAGS = $(ASM_FLAGS) $(FP_FLAGS) + +# autoincremental version & build date +VERSION_FILE = version.inc +ifeq ($(shell test -e $(VERSION_FILE) && echo -n yes), yes) + NEXTVER := $(shell expr $$(awk '/#define BUILD_NUMBER/' $(VERSION_FILE) | tr -cd "[0-9]") + 1) +else + NEXTVER := "1" +endif + +BUILDDATE := $(shell date +%Y-%m-%d) + +############################################################################### +# Executables +PREFIX ?= /opt/bin/arm-none-eabi + +RM := rm -f +RMDIR := rmdir +SIZE := $(PREFIX)-size +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)/Fx -I$(INC_DIR)/cm +LIB_DIR := $(INC_DIR)/ld + +############################################################################### +# C flags +CFLAGS += -O2 -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 -flto + +############################################################################### +# Linker flags +LDFLAGS += --static -nostartfiles --specs=nano.specs -flto +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 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) $(ARCH_FLAGS) -o $@ -c $< + +$(VERSION_FILE): *.[ch] + [ -f $(VERSION_FILE) ] || echo -e "#define BUILD_NUMBER \"0\"\n#define BUILD_DATE \"none\"" > $(VERSION_FILE) + @echo " Generate version: $(NEXTVER) for date $(BUILDDATE)" + @sed -i "s/#define BUILD_NUMBER.*/#define BUILD_NUMBER \"$(NEXTVER)\"/" $(VERSION_FILE) + @sed -i "s/#define BUILD_DATE.*/#define BUILD_DATE \"$(BUILDDATE)\"/" $(VERSION_FILE) + +# Uncomment and rename file, which includes version.inc +#$(OBJDIR)/proto.o: proto.c $(VERSION_FILE) + +$(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 + +size: $(ELF) + $(SIZE) -Ax $(ELF) + +flash: $(BIN) + @echo " FLASH $(BIN)" + $(STFLASH) write $(BIN) 0x8000000 + +boot: $(BIN) + @echo " LOAD $(BIN) through bootloader" + $(STBOOT) -b$(BOOTSPEED) $(BOOTPORT) -w $(BIN) + +openocd: + openocd -f openocd.cfg +dbg: + arm-none-eabi-gdb $(ELF) -ex 'target extended-remote localhost:3333' -ex 'monitor reset halt' + + +.PHONY: clean flash boot size openocd dbg diff --git a/G0:G070/RTC/README b/G0:G070/RTC/README new file mode 100644 index 0000000..351b779 --- /dev/null +++ b/G0:G070/RTC/README @@ -0,0 +1,10 @@ +Simplest work with RTC + +Proto: + +t - print current Tms +T - print current Time like 'Mon Jan 1 00:05:19 2001' + + +Button press - print current time @ usart3 + diff --git a/G0:G070/RTC/main.c b/G0:G070/RTC/main.c new file mode 100644 index 0000000..e680532 --- /dev/null +++ b/G0:G070/RTC/main.c @@ -0,0 +1,71 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 + +#include "proto.h" +#include "rtc.h" +#include "strfunc.h" +#include "usart.h" + +// KEY (intpullup->0) - PC0 +// LED - PC8 + +volatile uint32_t Tms = 0; + +/* Called when systick fires */ +void sys_tick_handler(void){ + ++Tms; +} + +static void gpio_setup(void){ + RCC->IOPENR |= RCC_IOPENR_GPIOCEN; // enable PC + // set PC8 as opendrain output, PC0 is pullup input, other as default (AIN) + GPIOC->MODER = (0xffffffff & ~(GPIO_MODER_MODE8 | GPIO_MODER_MODE0)) | GPIO_MODER_MODER8_O; + GPIOC->PUPDR = GPIO_PUPDR0_PU; // pullup + GPIOC->OTYPER = GPIO_OTYPER_OT8; // open drain +} + +int main(void){ + StartHSE(); + rtc_setup(); + SysTick_Config(8000); // 1ms counter + gpio_setup(); + usart3_setup(); + uint32_t T = 0; + int sent = 0; + /* Do nothing in main loop */ + while (1){ + if(Tms - T > 499){ // blink LED + T = Tms; + pin_toggle(GPIOC, 1<<8); + usart3_sendbuf(); + } + if(pin_read(GPIOC, 1<<0) == 0){ // key pressed - send time over USART + if(!sent){ + print_curtime(); + sent = 1; + } + }else sent = 0; + int wasbo = 0; + char *rcv = usart3_getline(&wasbo); + if(wasbo) usart3_sendstr("Buffer overflow occured @ last message\n"); + if(rcv) rcv = parse_cmd(rcv); + if(rcv) usart3_sendstr(rcv); + } +} diff --git a/G0:G070/RTC/openocd.cfg b/G0:G070/RTC/openocd.cfg new file mode 100644 index 0000000..fb036da --- /dev/null +++ b/G0:G070/RTC/openocd.cfg @@ -0,0 +1,89 @@ +# script for stm32g0x family + +# +# stm32g0 devices support SWD transports only. +# +source [find interface/stlink.cfg] +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32g0x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# Smallest proposed target has 8kB ram, use 4kB by default to avoid surprises +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # Section 37.5.5 - corresponds to Cortex-M0+ + set _CPUTAPID 0x0bc11477 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME + +# reasonable default +adapter speed 2000 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +proc stm32g0x_default_reset_start {} { + # Reset clock is HSI16 (16 MHz) + adapter speed 2000 +} + +proc stm32g0x_default_examine_end {} { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0x40015804 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0x40015808 0x00001800 0 +} + +proc stm32g0x_default_reset_init {} { + # Increase clock to 64 Mhz + mmw 0x40022000 0x00000002 0x00000005 ;# FLASH_ACR: Latency = 2 + mww 0x4002100C 0x30000802 ;# RCC_PLLCFGR = PLLR=/2, PLLN=8, PLLM=/1, PLLSRC=0x2 + mmw 0x40021000 0x01000000 0x00000000 ;# RCC_CR |= PLLON + mmw 0x40021008 0x00000002 0x00000005 ;# RCC_CFGR: SW=PLLRCLK + + # Boost JTAG frequency + adapter speed 4000 +} + +# Default hooks +$_TARGETNAME configure -event examine-end { stm32g0x_default_examine_end } +$_TARGETNAME configure -event reset-start { stm32g0x_default_reset_start } +$_TARGETNAME configure -event reset-init { stm32g0x_default_reset_init } diff --git a/G0:G070/RTC/proto.c b/G0:G070/RTC/proto.c new file mode 100644 index 0000000..dca5aac --- /dev/null +++ b/G0:G070/RTC/proto.c @@ -0,0 +1,83 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 +#include + +#include "rtc.h" +#include "strfunc.h" +#include "usart.h" + +extern volatile uint32_t Tms; + +const char *helpstring = + "t - print current Tms\n" + "T - print current Time\n" +; + +TRUE_INLINE void putch(char x){ + usart3_send(&x, 1); +} + +static const char *weekdays[] = {"Mon", "Tue", "Wed", "Thur", "Fri", "Sat", "Sun"}; +static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"}; + +static void prezero(uint8_t x){ + if(x < 10){ putch('0'); putch('0' + x);} + else USND(u2str(x)); +} + +void print_curtime(){ + rtc_t t; + get_curtime(&t); + USND(weekdays[t.day - 1]); + putch(' '); + USND(months[t.month - 1]); + putch(' '); + USND(u2str(t.day)); + putch(' '); + prezero(t.hour); + putch(':'); + prezero(t.minute); + putch(':'); + prezero(t.second); + USND(" 20"); prezero(t.year); + putch('\n'); +} + +char *parse_cmd(char *buf){ + // "long" commands +/* switch(*buf){ + }*/ + // "short" commands + if(buf[1]) return buf; // echo wrong data + switch(*buf){ + case 't': + USND("T="); + USND(u2str(Tms)); + putch('\n'); + break; + case 'T': + print_curtime(); + break; + default: // help + USND(helpstring); + break; + } + return NULL; +} diff --git a/G0:G070/RTC/proto.h b/G0:G070/RTC/proto.h new file mode 100644 index 0000000..a39fa1f --- /dev/null +++ b/G0:G070/RTC/proto.h @@ -0,0 +1,22 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 + +char *parse_cmd(char *buf); +void print_curtime(); diff --git a/G0:G070/RTC/rtc.bin b/G0:G070/RTC/rtc.bin new file mode 100755 index 0000000000000000000000000000000000000000..10bc3baf35a73a2a9b3e07706aef224b3562d685 GIT binary patch literal 2716 zcmaJ@eQXow8Gr61LZa||7E+Rjxgd7FlmNmHE_!n^0a z07YxnNWZ+l_j#Y^_df4E?}y=PNCL=Jnofdm1NtjGA&fKSB2ermF73bnHrzSUDJ`lv@c?)x?A=10q0UZ zdWLtQeZQo(_^t7buS=)#Yk(DB1K{ik2!n|F+y%Z`t26u(YchcQ1_X4wDhacz4vP`E|9qN7owtI^kKZhUu}i0kx?f)!v2(Vc(~DvJ3qg z+ZS$*2~VhA{RwSNKWwfsf%iw5Mt`4IT`)4toUckN=pw(O$?$G1BKi9~GfZF?*By-* zDSyFQr?7Y)o?4hsEF>=jMOk`d5i+u&Ot~GhVzU*wMyp>SiT^kY_AeanoCFOb2 z0GpGfe3RHNhh|7wCZxPTmP(7+_mmfu=auJ_Vm7RO?=seIwev=s%5iLwX@*TUb5@x* z9MY0mRWG)?j4wH#6yE^i6W}}G6^YO57Q{)Y^LbpH*o*DLl}W{0xnirS;L(=xsm8*U zFFMzYQ_3Z{jgf;GdE4i8kt?^atP%5exarzj74TNNEv1?Ymld^eWrNC0B-UkMvTIx+ zlt)RA5(3(f<2p(C#ywIVKwESDinWJ?QQ<`r zg01M&K}75wz2DnSwqZn!RD?-6LYPTXK1f_b2%6AyCs}oQ`~CV|!V1nRSPbzVA#lzK zj&~3)&E1}sR?p!%KFKutl1$T-^xvFAbEp%NeGUS(Xqk}iuWPTj`;B7OCHnOgUu%rpPhYN<9A>s1EAcFBq?Pa)9%(6;;(wt<*jmFS-}hwE zFL&wx{mhhbQSDuoOSt8HEX7~c#)0~G_s;><{m~=-UHw#dQhP-$SaV1054G)7`}`xm zRu1O4I-yk?KM1>JHsHmWvswhEbi2XJEcR|C=75z8F@`V13xibQwED?@x;4n)e)_KP zvRcRH1~I$%H9i$cX+3=}HTU!ta9stxU_@{qj;i9bkHi@?E)^KjM%B@w6Ng!6o;^2GnNEF9LV}ZF^~mmOqe8q8aM}Vgsjt@eAAMEc--3MHQoAp|H5PHjSdBZohE;DLtm^P zg6-zv=m*A>0-IQ~4fpLw%V9;9x>|N>DdrVLZ#YNVJrvuLx!FvU6LlIxoeV!r|cYPV)E?Fi}0s9D9B=r5D?;<@v4fo%Y zdTi+%W_Pfn15qiW*88Y|wj!QU2cEYI1PGq&v;;ZN%wG=tp_6G^DuM9(156Wax|8c# zmuv%GcBG}@yv>=GzLmGR(o$>Q=1xlud0RzVs>~DK$=3XaayDO6<7DF|9j(nn(doL1 zjLBcO&H5uPr!AhgxNLFF;?$eTyDfed)zP1|{4JigxNLFF;xq&FxA zr!6j9T(daM93w1#71x6PVEJ1-ZE?CrCa+n%#Se3g5^3?^?-f#FviSBau3lp4J-4xJ zj+T;b^j$rP-|l5Z3ULPUeZ)D$dBk>vh-gKG5xWul5M2lzaR@PhNFs(2Tw@5Nk;8}M zL)`Jv_|V~j<1cZ?W3iE;_#sZ@2BIg1xxx5}6VW4a7j*6b80NNc$)WyZ!yNhy#j))i zJmKp6w6%W_BLLLsF;L=tuqQeMEy*ElPk}meERI9i4xFNG%g7Pvh$n|B-y0i-=Z}v< lYdi*fjvs^0kvO~%KLnk|$PgV@hWeo+It(2n$AH29{{W&}Z~y=R literal 0 HcmV?d00001 diff --git a/G0:G070/RTC/rtc.c b/G0:G070/RTC/rtc.c new file mode 100644 index 0000000..541d103 --- /dev/null +++ b/G0:G070/RTC/rtc.c @@ -0,0 +1,61 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 + +#include "rtc.h" + +#ifndef WAITWHILE +#define WAITWHILE(x) do{register uint32_t StartUpCounter = 0; while((x) && (++StartUpCounter < 0xffffff)){nop();}}while(0) +#endif + +void rtc_setup(){ + PWR->CR1 |= PWR_CR1_DBP; // disable RTC write protection + // turn on LSE and switch RTC to it + RCC->APBENR1 |= RCC_APBENR1_RTCAPBEN; + RCC->BDCR = RCC_BDCR_LSEON; + WAITWHILE(!(RCC->BDCR & RCC_BDCR_LSERDY)); + RCC->BDCR |= RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_0; + // unlock RCC + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + RTC->ICSR |= RTC_ICSR_INIT; + WAITWHILE(!(RTC->ICSR & RTC_ICSR_INITF)); + RTC->PRER = (0x7f << RTC_PRER_PREDIV_A_Pos) | 0xff; // prediv_a = 127, prediv_s = 255 + // here we can init starting time: monday of 1 jan 2001, 00:00:00 +// RTC->DR = 1 << RTC_DR_YU_Pos | 1 << RTC_DR_WDU_Pos | 1 << RTC_DR_MU_Pos | 1 << RTC_DR_DU_Pos; +// RTC->TR = 0; + // RTC->CR is default - 0 + // now turn off INIT bit, RTC will go on + RTC->ICSR &= ~RTC_ICSR_INIT; +} + +void get_curtime(rtc_t *t){ + WAITWHILE(!(RTC->ICSR & RTC_ICSR_RSF)); + register uint32_t r = RTC->TR; + #define BCDu(shift) ((r >> shift) & 0xf) + t->second = BCDu(RTC_TR_SU_Pos) + 10 * BCDu(RTC_TR_ST_Pos); + t->minute = BCDu(RTC_TR_MNU_Pos) + 10 * BCDu(RTC_TR_MNT_Pos); + t->hour = BCDu(RTC_TR_HU_Pos) + 10 * BCDu(RTC_TR_HT_Pos); + r = RTC->DR; + t->day = BCDu(RTC_DR_DU_Pos) + 10 * BCDu(RTC_DR_DT_Pos); + t->month = BCDu(RTC_DR_MU_Pos); + if(r & RTC_DR_MT) t->month += 10; + t->weekday = (r >> RTC_DR_WDU_Pos) & 0x7; + t->year = BCDu(RTC_DR_YU_Pos) + 10 * BCDu(RTC_DR_YT_Pos); +} diff --git a/G0:G070/RTC/rtc.cflags b/G0:G070/RTC/rtc.cflags new file mode 100644 index 0000000..68d5165 --- /dev/null +++ b/G0:G070/RTC/rtc.cflags @@ -0,0 +1 @@ +-std=c17 \ No newline at end of file diff --git a/G0:G070/RTC/rtc.config b/G0:G070/RTC/rtc.config new file mode 100644 index 0000000..e94e3ae --- /dev/null +++ b/G0:G070/RTC/rtc.config @@ -0,0 +1,3 @@ +#define EBUG +#define STM32G0 +#define STM32G070xx diff --git a/G0:G070/RTC/rtc.creator b/G0:G070/RTC/rtc.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/G0:G070/RTC/rtc.creator @@ -0,0 +1 @@ +[General] diff --git a/G0:G070/RTC/rtc.creator.user b/G0:G070/RTC/rtc.creator.user new file mode 100644 index 0000000..0255582 --- /dev/null +++ b/G0:G070/RTC/rtc.creator.user @@ -0,0 +1,171 @@ + + + + + + EnvironmentId + {7bd84e39-ca37-46d3-be9d-99ebea85bc0d} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + KOI8-R + false + 4 + false + 80 + true + true + 1 + false + true + false + 0 + true + true + 0 + 8 + true + false + 1 + true + false + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + + 0 + true + + true + true + Builtin.DefaultTidyAndClazy + 2 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + Desktop + {65a14f9e-e008-4c1b-89df-4eaa4774b6e3} + 0 + 0 + 0 + + /Big/Data/00__Electronics/STM32/G0-nolib/rtc + + + + all + + true + GenericProjectManager.GenericMakeStep + + 1 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + GenericProjectManager.GenericMakeStep + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + По умолчанию + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Развёртывание + Развёртывание + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + 2 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + true + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/G0:G070/RTC/rtc.cxxflags b/G0:G070/RTC/rtc.cxxflags new file mode 100644 index 0000000..6435dfc --- /dev/null +++ b/G0:G070/RTC/rtc.cxxflags @@ -0,0 +1 @@ +-std=c++17 \ No newline at end of file diff --git a/G0:G070/RTC/rtc.files b/G0:G070/RTC/rtc.files new file mode 100644 index 0000000..412b6a9 --- /dev/null +++ b/G0:G070/RTC/rtc.files @@ -0,0 +1,11 @@ +main.c +rtc.c +rtc.h +usart.c +usart.h +strfunc.c +strfunc.h +proto.c +proto.h +i2c.c +i2c.h diff --git a/G0:G070/RTC/rtc.h b/G0:G070/RTC/rtc.h new file mode 100644 index 0000000..e5f8c8c --- /dev/null +++ b/G0:G070/RTC/rtc.h @@ -0,0 +1,36 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 + +#include + +// time, day of week (1 - monday), and date (1 - january) +typedef struct{ + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t weekday; + uint8_t day; + uint8_t month; + uint8_t year; +} rtc_t; + +void rtc_setup(); + +void get_curtime(rtc_t *t); diff --git a/G0:G070/RTC/rtc.includes b/G0:G070/RTC/rtc.includes new file mode 100644 index 0000000..641fd56 --- /dev/null +++ b/G0:G070/RTC/rtc.includes @@ -0,0 +1,4 @@ +. +../inc +../inc/Fx +../inc/cm diff --git a/G0:G070/RTC/strfunc.c b/G0:G070/RTC/strfunc.c new file mode 100644 index 0000000..c52785e --- /dev/null +++ b/G0:G070/RTC/strfunc.c @@ -0,0 +1,255 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 + +/** + * @brief hexdump - dump hex array by 16 bytes in string + * @param sendfun - function to send data + * @param arr - array to dump + * @param len - length of `arr` + */ +void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len){ + char buf[52], *bptr = buf; + for(uint16_t l = 0; l < len; ++l, ++arr){ + for(int16_t j = 1; j > -1; --j){ + register uint8_t half = (*arr >> (4*j)) & 0x0f; + if(half < 10) *bptr++ = half + '0'; + else *bptr++ = half - 10 + 'a'; + } + if(l % 16 == 15){ + *bptr++ = '\n'; + *bptr = 0; + sendfun(buf); + bptr = buf; + }else *bptr++ = ' '; + } + if(bptr != buf){ + *bptr++ = '\n'; + *bptr = 0; + sendfun(buf); + } +} + +/** + * @brief _2str - convert value into string buffer + * @param val - |value| + * @param minus - ==0 if value > 0 + * @return buffer with number + */ +static char *_2str(uint32_t val, uint8_t minus){ + static char strbuf[12]; + char *bufptr = &strbuf[11]; + *bufptr = 0; + if(!val){ + *(--bufptr) = '0'; + }else{ + while(val){ + *(--bufptr) = val % 10 + '0'; + val /= 10; + } + } + if(minus) *(--bufptr) = '-'; + return bufptr; +} + +// return string with number `val` +char *u2str(uint32_t val){ + return _2str(val, 0); +} +char *i2str(int32_t i){ + uint8_t minus = 0; + uint32_t val; + if(i < 0){ + minus = 1; + val = -i; + }else val = i; + return _2str(val, minus); +} + +/** + * @brief uhex2str - print 32bit unsigned int as hex + * @param val - value + * @return string with number + */ +char *uhex2str(uint32_t val){ + static char buf[12] = "0x"; + int npos = 2; + uint8_t *ptr = (uint8_t*)&val + 3; + int8_t i, j, z=1; + for(i = 0; i < 4; ++i, --ptr){ + if(*ptr == 0){ // omit leading zeros + if(i == 3) z = 0; + if(z) continue; + } + else z = 0; + for(j = 1; j > -1; --j){ + uint8_t half = (*ptr >> (4*j)) & 0x0f; + if(half < 10) buf[npos++] = half + '0'; + else buf[npos++] = half - 10 + 'a'; + } + } + buf[npos] = 0; + return buf; +} + +/** + * @brief omit_spaces - eliminate leading spaces and other trash in string + * @param buf - string + * @return - pointer to first character in `buf` > ' ' + */ +char *omit_spaces(const char *buf){ + while(*buf){ + if(*buf > ' ') break; + ++buf; + } + return (char*)buf; +} + +/** + * @brief getdec - read decimal number & return pointer to next non-number symbol + * @param buf - string + * @param N - number read + * @return Next non-number symbol. In case of overflow return `buf` and N==0xffffffff + */ +static char *getdec(const char *buf, uint32_t *N){ + char *start = (char*)buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '9'){ + break; + } + if(num > 429496729 || (num == 429496729 && c > '5')){ // overflow + *N = 0xffffff; + return start; + } + num *= 10; + num += c - '0'; + ++buf; + } + *N = num; + return (char*)buf; +} +// read hexadecimal number (without 0x prefix!) +static char *gethex(const char *buf, uint32_t *N){ + char *start = (char*)buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + uint8_t M = 0; + if(c >= '0' && c <= '9'){ + M = '0'; + }else if(c >= 'A' && c <= 'F'){ + M = 'A' - 10; + }else if(c >= 'a' && c <= 'f'){ + M = 'a' - 10; + } + if(M){ + if(num & 0xf0000000){ // overflow + *N = 0xffffff; + return start; + } + num <<= 4; + num += c - M; + }else{ + break; + } + ++buf; + } + *N = num; + return (char*)buf; +} +// read octal number (without 0 prefix!) +static char *getoct(const char *buf, uint32_t *N){ + char *start = (char*)buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '7'){ + break; + } + if(num & 0xe0000000){ // overflow + *N = 0xffffff; + return start; + } + num <<= 3; + num += c - '0'; + ++buf; + } + *N = num; + return (char*)buf; +} +// read binary number (without b prefix!) +static char *getbin(const char *buf, uint32_t *N){ + char *start = (char*)buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '1'){ + break; + } + if(num & 0x80000000){ // overflow + *N = 0xffffff; + return start; + } + num <<= 1; + if(c == '1') num |= 1; + ++buf; + } + *N = num; + return (char*)buf; +} + +/** + * @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111) + * @param buf - buffer with number and so on + * @param N - the number read + * @return pointer to first non-number symbol in buf + * (if it is == buf, there's no number or if *N==0xffffffff there was overflow) + */ +char *getnum(const char *txt, uint32_t *N){ + char *nxt = NULL; + char *s = omit_spaces(txt); + if(*s == '0'){ // hex, oct or 0 + if(s[1] == 'x' || s[1] == 'X'){ // hex + nxt = gethex(s+2, N); + if(nxt == s+2) nxt = (char*)txt; + }else if(s[1] > '0'-1 && s[1] < '8'){ // oct + nxt = getoct(s+1, N); + if(nxt == s+1) nxt = (char*)txt; + }else{ // 0 + nxt = s+1; + *N = 0; + } + }else if(*s == 'b' || *s == 'B'){ + nxt = getbin(s+1, N); + if(nxt == s+1) nxt = (char*)txt; + }else{ + nxt = getdec(s, N); + if(nxt == s) nxt = (char*)txt; + } + return nxt; +} + +/* +void mymemcpy(char *dest, const char *src, int len){ + if(len < 1) return; + while(len--) *dest++ = *src++; +} +*/ diff --git a/G0:G070/RTC/strfunc.h b/G0:G070/RTC/strfunc.h new file mode 100644 index 0000000..a6662d5 --- /dev/null +++ b/G0:G070/RTC/strfunc.h @@ -0,0 +1,29 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 + +#include + +void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len); +char *u2str(uint32_t val); +char *i2str(int32_t i); +char *uhex2str(uint32_t val); +char *getnum(const char *txt, uint32_t *N); +char *omit_spaces(const char *buf); +//void mymemcpy(char *dest, const char *src, int len); diff --git a/G0:G070/RTC/usart.c b/G0:G070/RTC/usart.c new file mode 100644 index 0000000..367d1bf --- /dev/null +++ b/G0:G070/RTC/usart.c @@ -0,0 +1,177 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 +#include + +#include "usart.h" + +// RX/TX DMA->CCR without EN flag +#define DMARXCCR (DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE) +#define DMATXCCR (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_TEIE) + +volatile int u3txrdy = 1, u3rxrdy = 0; // transmission done, next line received +static volatile int bufovr = 0, wasbufovr = 0; // Rx buffer overflow or error flag -> delete next line +static volatile int rbufno = 0, tbufno = 0; // current buf number +static volatile char rbuf[2][UARTBUFSZ], tbuf[2][UARTBUFSZ]; // receive & transmit buffers +static volatile int rxlen[2] = {0}, txlen[2] = {0}; + +char *usart3_getline(int *wasbo){ + if(wasbo) *wasbo = wasbufovr; + wasbufovr = 0; + if(!u3rxrdy) return NULL; + u3rxrdy = 0; // clear ready flag + return (char*)rbuf[!rbufno]; // current buffer is in filling stage, return old - filled - buffer +} + +#define USART_BRR(speed) ((64000000 + speed/2) / speed) + +// USART3 @ PD8 (Tx) and PD9 (Rx) - both AF0 +void usart3_setup(){ + RCC->IOPENR |= RCC_IOPENR_GPIODEN; // enable PD + RCC->AHBENR |= RCC_AHBENR_DMA1EN; // enable DMA1 + // set PD8 and PD9 as AF + GPIOD->MODER = (GPIOD->MODER & ~(GPIO_MODER_MODE8 | GPIO_MODER_MODE9)) + | GPIO_MODER_MODER8_AF | GPIO_MODER_MODER9_AF; + // AF0 for USART3 @ PD8/PD9 + GPIOD->AFR[1] = GPIOD->AFR[1] & ~(GPIO_AFRH_AFSEL8 | GPIO_AFRH_AFSEL9); + // enable USART3 clocking + RCC->APBENR1 |= RCC_APBENR1_USART3EN; + // baudrate 115200 + USART3->BRR = USART_BRR(115200); + // eol character: '/n' + USART3->CR2 = USART_CR2_ADD_VAL('\n'); + // enable DMA transmission + USART3->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; + // set up DMA channels: 2 - Tx, 3 - Rx + // Tx channel: mem++, mem->periph, 8bit, compl.&err. irq + DMA1_Channel2->CCR = DMATXCCR; + DMA1_Channel2->CPAR = (uint32_t) &USART3->TDR; // peripherial address + // Rx channel: mem++, periph->mem, 8bit, compl.&err. irq + DMA1_Channel3->CCR = DMARXCCR; + DMA1_Channel3->CPAR = (uint32_t) &USART3->RDR; // peripherial address + DMA1_Channel3->CNDTR = UARTBUFSZ; + DMA1_Channel3->CMAR = (uint32_t)&rbuf[rbufno]; + // set up DMAMUX channels: 55 - USART3_TX, 54 - USART3_RX + // enumeration of DMAMUX starts from 0 (DMA - from 1)! + DMAMUX1_Channel1->CCR = 55; + DMAMUX1_Channel2->CCR = 54; + // charmatch interrupt, enable transmitter and receiver, enable usart + USART3->CR1 = USART_CR1_CMIE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; + USART3->ICR = 0xffffffff; // clear all flags + DMA1_Channel3->CCR = DMARXCCR | DMA_CCR_EN; // start receiving right now + NVIC_EnableIRQ(USART3_4_IRQn); + NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); +} + +static int usart3_sendN(const char *str, int len){ + int rest = UARTBUFSZ - txlen[tbufno]; + if(rest == 0 && !u3txrdy) return 0; // buffer is full while transmission in process + if(len < rest) rest = len; + memcpy((char*)(tbuf[tbufno] + txlen[tbufno]), str, rest); + txlen[tbufno] += rest; + if(!u3txrdy) return rest; + if(txlen[tbufno] == UARTBUFSZ) usart3_sendbuf(); + if(rest == len) return len; + len -= rest; + // now fill another - empty - buffer + if(len > UARTBUFSZ) len = UARTBUFSZ; + memcpy((char*)tbuf[tbufno], str + rest, len); + txlen[tbufno] = len; + return rest + len; +} + +void usart3_send(const char *str, int len){ + while(len){ + int sent = usart3_sendN(str, len); + str += sent; + len -= sent; + } +} + +void usart3_sendstr(const char *str){ + int l = strlen(str); + usart3_send(str, l); +} + +/** + * @brief usart3_sendbuf - send current buffer + */ +void usart3_sendbuf(){ + if(!u3txrdy || txlen[tbufno] == 0) return; + // set up DMA + DMA1_Channel2->CCR = DMATXCCR; + DMA1_Channel2->CMAR = (uint32_t)&tbuf[tbufno]; + DMA1_Channel2->CNDTR = txlen[tbufno]; + USART3->ICR = USART_ICR_TCCF; // clear TC flag + u3txrdy = 0; + // activate DMA + DMA1_Channel2->CCR = DMATXCCR | DMA_CCR_EN; + tbufno = !tbufno; // swap buffers + txlen[tbufno] = 0; +} + +// return amount of bytes sents +int usart3_send_blocking(const char *str, int len){ + if(!u3txrdy) return 0; + USART3->CR1 |= USART_CR1_TE; + for(int i = 0; i < len; ++i){ + while(!(USART3->ISR & USART_ISR_TXE_TXFNF)); + USART3->TDR = *str++; + } + return len; +} + +// interrupt by '\n' +void usart3_4_isr(){ + if(USART3->ISR & USART_ISR_CMF){ // got '\n' @ USART3 + DMA1_Channel3->CCR = DMARXCCR; + if(!bufovr){ // forget about broken line @ buffer overflow + u3rxrdy = 1; + int l = UARTBUFSZ - DMA1_Channel3->CNDTR - 1; // strlen + rxlen[rbufno] = l; + rbuf[rbufno][l] = 0; + rbufno = !rbufno; + }else{ + bufovr = 0; + wasbufovr = 1; + } + // reload DMA Rx with next buffer + DMA1_Channel3->CMAR = (uint32_t)&rbuf[rbufno]; + DMA1_Channel3->CNDTR = UARTBUFSZ; + DMA1_Channel3->CCR = DMARXCCR | DMA_CCR_EN; + } + USART3->ICR = 0xffffffff; // clear all flags +} + +// ch2 - Tx, ch3 - Rx +void dma1_channel2_3_isr(){ + uint32_t isr = DMA1->ISR; + if(isr & (DMA_ISR_TCIF2 | DMA_ISR_TEIF2)){ // transfer complete or error + u3txrdy = 1; + } + if(isr & (DMA_ISR_TCIF3 | DMA_ISR_TEIF3)){ // receive complete or error -> buffer overflow + if(rbuf[rbufno][UARTBUFSZ-1] != '\n'){ // last symbol is not a newline + bufovr = 1; + DMA1_Channel3->CCR = DMARXCCR; + DMA1_Channel3->CNDTR = UARTBUFSZ; + DMA1_Channel3->CCR = DMARXCCR | DMA_CCR_EN; + } + } + DMA1->IFCR = 0xff0; // clear all flags for 2&3 +} diff --git a/G0:G070/RTC/usart.h b/G0:G070/RTC/usart.h new file mode 100644 index 0000000..eb1eace --- /dev/null +++ b/G0:G070/RTC/usart.h @@ -0,0 +1,32 @@ +/* + * This file is part of the rtc project. + * Copyright 2023 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 + +#define UARTBUFSZ (64) + +#define USND(t) do{usart3_sendstr(t);}while(0) + +extern volatile int u3txrdy, u3rxrdy; + +void usart3_setup(); +int usart3_send_blocking(const char *str, int len); +void usart3_send(const char *str, int len); +void usart3_sendbuf(); +char *usart3_getline(int *wasbo); +void usart3_sendstr(const char *str);