From d01e40e17405e469afc6aa3001e707c7fccc14da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 12 May 2016 01:32:35 +0200 Subject: [PATCH] blinkenlights working w sonar --- Makefile | 5 +- f103.pro | 200 +++-- f103.pro.user | 223 ++---- openocd.cfg | 157 ++++ parsemap.php | 21 + project/bus/event_handler.c | 159 ++++ project/bus/event_handler.h | 48 ++ project/bus/event_queue.c | 66 ++ project/bus/event_queue.h | 75 ++ project/colorled.c | 66 ++ project/colorled.h | 79 ++ project/com/com_fileio.c | 96 +++ project/com/com_fileio.h | 23 + project/com/com_iface.c | 179 +++++ project/com/com_iface.h | 168 ++++ project/com/datalink.c | 48 ++ project/com/datalink.h | 26 + project/com/debug.c | 108 +++ project/com/debug.h | 73 ++ project/com/iface_noop.c | 91 +++ project/com/iface_noop.h | 14 + project/com/iface_usart.c | 328 ++++++++ project/com/iface_usart.h | 19 + project/display.c | 94 +++ project/display.h | 11 + project/hw_init.c | 125 +++ project/hw_init.h | 6 + project/main.c | 70 +- project/main.h | 18 + project/malloc_safe.c | 40 + project/malloc_safe.h | 17 + project/spl_assert.c | 24 + project/stm32f10x_it.c | 2 + project/syscalls.c | 32 + project/system_stm32f10x.c | 1429 +++++++++++++++++------------------ project/utils/circbuf.c | 161 ++++ project/utils/circbuf.h | 93 +++ project/utils/debounce.c | 171 +++++ project/utils/debounce.h | 62 ++ project/utils/matcher.c | 33 + project/utils/matcher.h | 39 + project/utils/meanbuf.c | 70 ++ project/utils/meanbuf.h | 33 + project/utils/minmax.h | 4 + project/utils/str_utils.c | 286 +++++++ project/utils/str_utils.h | 75 ++ project/utils/timebase.c | 331 ++++++++ project/utils/timebase.h | 159 ++++ 48 files changed, 4666 insertions(+), 991 deletions(-) create mode 100644 openocd.cfg create mode 100755 parsemap.php create mode 100644 project/bus/event_handler.c create mode 100644 project/bus/event_handler.h create mode 100644 project/bus/event_queue.c create mode 100644 project/bus/event_queue.h create mode 100644 project/colorled.c create mode 100644 project/colorled.h create mode 100644 project/com/com_fileio.c create mode 100644 project/com/com_fileio.h create mode 100644 project/com/com_iface.c create mode 100644 project/com/com_iface.h create mode 100644 project/com/datalink.c create mode 100644 project/com/datalink.h create mode 100644 project/com/debug.c create mode 100644 project/com/debug.h create mode 100644 project/com/iface_noop.c create mode 100644 project/com/iface_noop.h create mode 100644 project/com/iface_usart.c create mode 100644 project/com/iface_usart.h create mode 100644 project/display.c create mode 100644 project/display.h create mode 100644 project/hw_init.c create mode 100644 project/hw_init.h create mode 100644 project/main.h create mode 100644 project/malloc_safe.c create mode 100644 project/malloc_safe.h create mode 100644 project/spl_assert.c create mode 100644 project/syscalls.c create mode 100644 project/utils/circbuf.c create mode 100644 project/utils/circbuf.h create mode 100644 project/utils/debounce.c create mode 100644 project/utils/debounce.h create mode 100644 project/utils/matcher.c create mode 100644 project/utils/matcher.h create mode 100644 project/utils/meanbuf.c create mode 100644 project/utils/meanbuf.h create mode 100644 project/utils/minmax.h create mode 100644 project/utils/str_utils.c create mode 100644 project/utils/str_utils.h create mode 100644 project/utils/timebase.c create mode 100644 project/utils/timebase.h diff --git a/Makefile b/Makefile index ac35875..2d97754 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ ARCH_FLAGS = -msoft-float -mfloat-abi=soft ARCH_FLAGS += -mthumb -mcpu=cortex-m3 # Clock speed constants -DEFS += -DF_CPU=8000000UL +DEFS += -DF_CPU=72000000UL DEFS += -DSTM32F10X_MD DEFS += -DARM_MATH_CM3 @@ -113,7 +113,7 @@ LIB_CFLAGS = -Wno-shadow -Wno-float-equal -Wno-inline -Wno-unused-parameter -W ############################################################################### # Linker flags -LDFLAGS += --static -lm -lc -nostartfiles +LDFLAGS += --static -lm -lc -nostartfiles -specs=nano.specs LDFLAGS += -Llib LDFLAGS += -T$(LDSCRIPT) LDFLAGS += -Wl,-Map=$(*).map @@ -181,6 +181,7 @@ size: $(BINARY).elf %.elf %.map: libcheck $(OBJS) $(HEADERS) $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(*).elf + $(Q)./parsemap.php $(Q)$(SIZE) $(*).elf %.o: %.c diff --git a/f103.pro b/f103.pro index a160381..bdfeca4 100644 --- a/f103.pro +++ b/f103.pro @@ -11,7 +11,7 @@ INCLUDEPATH += \ /usr/arm-none-eabi/include \ /usr/lib/gcc/arm-none-eabi/5.3.0/include/ -DEFINES += F_CPU=8000000UL \ +DEFINES += F_CPU=72000000UL \ STM32F10X_MD \ USE_STDPERIPH_DRIVER \ __null=0 \ @@ -21,87 +21,127 @@ DEFINES += F_CPU=8000000UL \ __CORTEX_M=3 \ VERBOSE_LOGGING=1 -HEADERS += \ - lib/cmsis/core_cm3.h \ - lib/cmsis/stm32f10x.h \ - lib/sbmp/library/crc32.h \ - lib/sbmp/library/payload_builder.h \ - lib/sbmp/library/payload_parser.h \ - lib/sbmp/library/sbmp.h \ - lib/sbmp/library/sbmp_bulk.h \ - lib/sbmp/library/sbmp_checksum.h \ - lib/sbmp/library/sbmp_config.example.h \ - lib/sbmp/library/sbmp_datagram.h \ - lib/sbmp/library/sbmp_frame.h \ - lib/sbmp/library/sbmp_session.h \ - lib/sbmp/library/type_coerce.h \ - lib/spl/inc/misc.h \ - lib/spl/inc/stm32f10x_adc.h \ - lib/spl/inc/stm32f10x_bkp.h \ - lib/spl/inc/stm32f10x_can.h \ - lib/spl/inc/stm32f10x_cec.h \ - lib/spl/inc/stm32f10x_crc.h \ - lib/spl/inc/stm32f10x_dac.h \ - lib/spl/inc/stm32f10x_dbgmcu.h \ - lib/spl/inc/stm32f10x_dma.h \ - lib/spl/inc/stm32f10x_exti.h \ - lib/spl/inc/stm32f10x_flash.h \ - lib/spl/inc/stm32f10x_fsmc.h \ - lib/spl/inc/stm32f10x_gpio.h \ - lib/spl/inc/stm32f10x_i2c.h \ - lib/spl/inc/stm32f10x_iwdg.h \ - lib/spl/inc/stm32f10x_pwr.h \ - lib/spl/inc/stm32f10x_rcc.h \ - lib/spl/inc/stm32f10x_rtc.h \ - lib/spl/inc/stm32f10x_sdio.h \ - lib/spl/inc/stm32f10x_spi.h \ - lib/spl/inc/stm32f10x_tim.h \ - lib/spl/inc/stm32f10x_usart.h \ - lib/spl/inc/stm32f10x_wwdg.h \ - project/stm32f10x_conf.h \ - project/stm32f10x_it.h \ - project/system_stm32f10x.h \ - project/sbmp_config.h +HEADERS += \ + lib/cmsis/core_cm3.h \ + lib/cmsis/stm32f10x.h \ + lib/sbmp/library/crc32.h \ + lib/sbmp/library/payload_builder.h \ + lib/sbmp/library/payload_parser.h \ + lib/sbmp/library/sbmp.h \ + lib/sbmp/library/sbmp_bulk.h \ + lib/sbmp/library/sbmp_checksum.h \ + lib/sbmp/library/sbmp_config.example.h \ + lib/sbmp/library/sbmp_datagram.h \ + lib/sbmp/library/sbmp_frame.h \ + lib/sbmp/library/sbmp_session.h \ + lib/sbmp/library/type_coerce.h \ + lib/spl/inc/misc.h \ + lib/spl/inc/stm32f10x_adc.h \ + lib/spl/inc/stm32f10x_bkp.h \ + lib/spl/inc/stm32f10x_can.h \ + lib/spl/inc/stm32f10x_cec.h \ + lib/spl/inc/stm32f10x_crc.h \ + lib/spl/inc/stm32f10x_dac.h \ + lib/spl/inc/stm32f10x_dbgmcu.h \ + lib/spl/inc/stm32f10x_dma.h \ + lib/spl/inc/stm32f10x_exti.h \ + lib/spl/inc/stm32f10x_flash.h \ + lib/spl/inc/stm32f10x_fsmc.h \ + lib/spl/inc/stm32f10x_gpio.h \ + lib/spl/inc/stm32f10x_i2c.h \ + lib/spl/inc/stm32f10x_iwdg.h \ + lib/spl/inc/stm32f10x_pwr.h \ + lib/spl/inc/stm32f10x_rcc.h \ + lib/spl/inc/stm32f10x_rtc.h \ + lib/spl/inc/stm32f10x_sdio.h \ + lib/spl/inc/stm32f10x_spi.h \ + lib/spl/inc/stm32f10x_tim.h \ + lib/spl/inc/stm32f10x_usart.h \ + lib/spl/inc/stm32f10x_wwdg.h \ + project/stm32f10x_conf.h \ + project/stm32f10x_it.h \ + project/system_stm32f10x.h \ + project/sbmp_config.h \ + project/com/com_fileio.h \ + project/com/com_iface.h \ + project/com/datalink.h \ + project/com/debug.h \ + project/com/iface_noop.h \ + project/com/iface_usart.h \ + project/utils/circbuf.h \ + project/utils/minmax.h \ + project/utils/timebase.h \ + project/colorled.h \ + project/malloc_safe.h \ + project/hw_init.h \ + project/utils/debounce.h \ + project/bus/event_handler.h \ + project/bus/event_queue.h \ + project/utils/str_utils.h \ + project/main.h \ + project/utils/matcher.h \ + project/utils/meanbuf.h \ + project/display.h -SOURCES += \ - lib/cmsis/core_cm3.c \ - lib/sbmp/library/crc32.c \ - lib/sbmp/library/payload_builder.c \ - lib/sbmp/library/payload_parser.c \ - lib/sbmp/library/sbmp_bulk.c \ - lib/sbmp/library/sbmp_checksum.c \ - lib/sbmp/library/sbmp_datagram.c \ - lib/sbmp/library/sbmp_frame.c \ - lib/sbmp/library/sbmp_session.c \ - lib/spl/src/misc.c \ - lib/spl/src/stm32f10x_adc.c \ - lib/spl/src/stm32f10x_bkp.c \ - lib/spl/src/stm32f10x_can.c \ - lib/spl/src/stm32f10x_cec.c \ - lib/spl/src/stm32f10x_crc.c \ - lib/spl/src/stm32f10x_dac.c \ - lib/spl/src/stm32f10x_dbgmcu.c \ - lib/spl/src/stm32f10x_dma.c \ - lib/spl/src/stm32f10x_exti.c \ - lib/spl/src/stm32f10x_flash.c \ - lib/spl/src/stm32f10x_fsmc.c \ - lib/spl/src/stm32f10x_gpio.c \ - lib/spl/src/stm32f10x_i2c.c \ - lib/spl/src/stm32f10x_iwdg.c \ - lib/spl/src/stm32f10x_pwr.c \ - lib/spl/src/stm32f10x_rcc.c \ - lib/spl/src/stm32f10x_rtc.c \ - lib/spl/src/stm32f10x_sdio.c \ - lib/spl/src/stm32f10x_spi.c \ - lib/spl/src/stm32f10x_tim.c \ - lib/spl/src/stm32f10x_usart.c \ - lib/spl/src/stm32f10x_wwdg.c \ - project/main.c \ - project/stm32f10x_it.c \ - project/system_stm32f10x.c +SOURCES += \ + lib/cmsis/core_cm3.c \ + lib/sbmp/library/crc32.c \ + lib/sbmp/library/payload_builder.c \ + lib/sbmp/library/payload_parser.c \ + lib/sbmp/library/sbmp_bulk.c \ + lib/sbmp/library/sbmp_checksum.c \ + lib/sbmp/library/sbmp_datagram.c \ + lib/sbmp/library/sbmp_frame.c \ + lib/sbmp/library/sbmp_session.c \ + lib/spl/src/misc.c \ + lib/spl/src/stm32f10x_adc.c \ + lib/spl/src/stm32f10x_bkp.c \ + lib/spl/src/stm32f10x_can.c \ + lib/spl/src/stm32f10x_cec.c \ + lib/spl/src/stm32f10x_crc.c \ + lib/spl/src/stm32f10x_dac.c \ + lib/spl/src/stm32f10x_dbgmcu.c \ + lib/spl/src/stm32f10x_dma.c \ + lib/spl/src/stm32f10x_exti.c \ + lib/spl/src/stm32f10x_flash.c \ + lib/spl/src/stm32f10x_fsmc.c \ + lib/spl/src/stm32f10x_gpio.c \ + lib/spl/src/stm32f10x_i2c.c \ + lib/spl/src/stm32f10x_iwdg.c \ + lib/spl/src/stm32f10x_pwr.c \ + lib/spl/src/stm32f10x_rcc.c \ + lib/spl/src/stm32f10x_rtc.c \ + lib/spl/src/stm32f10x_sdio.c \ + lib/spl/src/stm32f10x_spi.c \ + lib/spl/src/stm32f10x_tim.c \ + lib/spl/src/stm32f10x_usart.c \ + lib/spl/src/stm32f10x_wwdg.c \ + project/main.c \ + project/stm32f10x_it.c \ + project/system_stm32f10x.c \ + project/com/com_fileio.c \ + project/com/com_iface.c \ + project/com/datalink.c \ + project/com/debug.c \ + project/com/iface_noop.c \ + project/com/iface_usart.c \ + project/utils/circbuf.c \ + project/utils/debounce.c \ + project/utils/timebase.c \ + project/colorled.c \ + project/hw_init.c \ + project/malloc_safe.c \ + project/spl_assert.c \ + project/syscalls.c \ + project/bus/event_handler.c \ + project/bus/event_queue.c \ + project/utils/str_utils.c \ + project/utils/matcher.c \ + project/utils/meanbuf.c \ + project/display.c DISTFILES += \ style.astylerc \ Makefile \ - lib/cmsis/startup_stm32f10x_md.s \ - lib/cmsis/stm32_flash.ld + lib/cmsis/startup_stm32f10x_md.s \ + lib/cmsis/stm32_flash.ld diff --git a/f103.pro.user b/f103.pro.user index 82c316d..0c9e824 100644 --- a/f103.pro.user +++ b/f103.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -53,7 +53,12 @@ ProjectExplorer.Project.PluginSettings - + + + + 1 + + ProjectExplorer.Project.Target.0 @@ -63,22 +68,11 @@ {15262c8f-05de-48ee-9452-3d289b21ba3e} 0 -1 - 0 + 2 - /home/ondra/devel/build-f103-STLINK-Debug + /home/ondra/devel/f103 - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - false - false - - true Make @@ -88,10 +82,10 @@ -r false - + -B -j 4 - 2 + 1 Build ProjectExplorer.BuildSteps.Build @@ -119,132 +113,12 @@ false Debug - + Main Qt4ProjectManager.Qt4BuildConfiguration 2 true - - /home/ondra/devel/build-f103-STLINK-Release - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - - /home/ondra/devel/build-f103-STLINK-Profile - - - true - qmake - - QtProjectManager.QMakeBuildStep - true - - false - true - false - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Profile - - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 3 + 1 0 @@ -288,11 +162,11 @@ 2 - - + flash + /usr/bin/make %{buildDir} - Custom Executable - + Run /usr/bin/make + make flash ProjectExplorer.CustomExecutableRunConfiguration 3768 false @@ -340,13 +214,66 @@ 13 14 - - Run on GDB server or hardware debugger + f103 (via GDB server or hardware debugger) - BareMetal.CustomRunConfig + BareMetal/home/ondra/devel/f103/f103.pro - + f103.pro + 3768 + false + true + false + false + true + + + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + /home/ondra/devel/f103/main.elf + /home/ondra/devel/f103 + Run /home/ondra/devel/f103/main.elf + + ProjectExplorer.CustomExecutableRunConfiguration 3768 false true @@ -354,7 +281,7 @@ false true - 2 + 3 diff --git a/openocd.cfg b/openocd.cfg new file mode 100644 index 0000000..9f463ae --- /dev/null +++ b/openocd.cfg @@ -0,0 +1,157 @@ +#daemon configuration +telnet_port 4444 +gdb_port 3333 + +#interface +#cat /usr/lib/openocd/interface/olimex-arm-usb-ocd.cfg >> openocd.cfg + + + +# +# STMicroelectronics ST-LINK/V2 in-circuit debugger/programmer +# + +interface hla +hla_layout stlink +hla_device_desc "ST-LINK/V2" +hla_vid_pid 0x0483 0x3748 + +# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 +# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 +# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial +# number reset issues. +# eg. +#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" + + + +# target configuration +# cat /usr/lib/openocd/target/stm32.cfg >> openocd.cfg + +# script for stm32f3x family + +# +# stm32 devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32f3x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz +# +# Since we may be running of an RC oscilator, we crank down the speed a +# bit more to be on the safe side. Perhaps superstition, but if are +# running off a crystal, we can run closer to the limit. Note +# that there can be a pretty wide band where things are more or less stable. +adapter_khz 1000 + +adapter_nsrst_delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + # See STM Document RM0316 + # Section 29.6.3 - corresponds to Cortex-M4 r0p1 + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +if { [info exists BSTAPID] } { + set _BSTAPID $BSTAPID +} else { + # STM Document RM0316 rev 5 for STM32F302/303 B/C size + set _BSTAPID1 0x06422041 + # STM Document RM0313 rev 3 for STM32F37x + set _BSTAPID2 0x06432041 + # STM Document RM364 rev 1 for STM32F334 + set _BSTAPID3 0x06438041 + # STM Document RM316 rev 5 for STM32F303 6/8 size + # STM Document RM365 rev 3 for STM32F302 6/8 size + # STM Document RM366 rev 2 for STM32F301 6/8 size + set _BSTAPID4 0x06439041 + # STM Document RM016 rev 5 for STM32F303 D/E size + set _BSTAPID5 0x06446041 +} + +if {[using_jtag]} { + swj_newdap $_CHIPNAME bs -irlen 5 -expected-id $_BSTAPID1 \ + -expected-id $_BSTAPID2 -expected-id $_BSTAPID3 \ + -expected-id $_BSTAPID4 -expected-id $_BSTAPID5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME + +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 stm32f3x_default_reset_start {} { + # Reset clock is HSI (8 MHz) + adapter_khz 1000 +} + +proc stm32f3x_default_examine_end {} { + # Enable debug during low power modes (uses more power) + mmw 0xe0042004 0x00000007 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + + # Stop watchdog counters during halt + mww 0xe0042008 0x00001800 ;# DBGMCU_APB1_FZ = DBG_IWDG_STOP | DBG_WWDG_STOP +} + +proc stm32f3x_default_reset_init {} { + # Configure PLL to boost clock to HSI x 8 (64 MHz) + mww 0x40021004 0x00380400 ;# RCC_CFGR = PLLMUL[3:1] | PPRE1[2] + mmw 0x40021000 0x01000000 0 ;# RCC_CR |= PLLON + mww 0x40022000 0x00000012 ;# FLASH_ACR = PRFTBE | LATENCY[1] + sleep 10 ;# Wait for PLL to lock + mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] + + # Boost JTAG frequency + adapter_khz 8000 +} + +# Default hooks +$_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end } +$_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start } +$_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init } + +$_TARGETNAME configure -event trace-config { + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0xe0042004 0x00000020 0 +} diff --git a/parsemap.php b/parsemap.php new file mode 100755 index 0000000..4dbfa6e --- /dev/null +++ b/parsemap.php @@ -0,0 +1,21 @@ +#!/usr/bin/env php +handler = handler; + slot->type = type; + slot->handler_id = make_pid(); + slot->used = true; + slot->chained_handler = 0; + slot->user_data = user_data; + + return slot->handler_id; + } + + error("Failed to register event handler for type %d", type); + + return 0; // fail +} + +/** Chain for common destruction */ +bool chain_event_handler(uint32_t from, uint32_t to, bool reci) +{ + uint8_t cnt = 0; + + for (int i = 0; i < EH_SLOT_COUNT; i++) { + EventHandlerSlot *slot = &eh_slots[i]; + + if (!slot->used) continue; + + if (slot->handler_id == from) { + slot->chained_handler = to; + cnt++; + } + + // link back in two-handler reciprocal link + if (reci && slot->handler_id == to) { + slot->chained_handler = from; + cnt++; + } + + if (cnt == (reci ? 2 : 1)) { + return true; + } + } + + return false; +} + +/** + * @brief check if exists + */ +bool event_handler_exists(uint32_t handler_id) +{ + for (int i = 0; i < EH_SLOT_COUNT; i++) { + EventHandlerSlot *slot = &eh_slots[i]; + if (!slot->used) continue; + if (slot->handler_id == handler_id) { + return true; + } + } + + return false; +} + +/** + * @brief Remove event handler by handler ID + * @param handler_id : handler ID, obtained when registering or in the callback. + * @return number of removed handlers + */ +int remove_event_handler(uint32_t handler_id) +{ + int cnt = 0; + while (handler_id != 0) { // outer loop because of chained handlers + bool suc = false; + for (int i = 0; i < EH_SLOT_COUNT; i++) { + if (!eh_slots[i].used) { + continue; // skip empty slot + } + + // Free slot found + EventHandlerSlot *slot = &eh_slots[i]; + if (slot->handler_id == handler_id) { + slot->used = false; + slot->user_data = NULL; + suc = true; + cnt++; + + handler_id = slot->chained_handler; // continue with the chained handler. + break; + } + } + if (!suc) break; + } + return cnt; +} + +/** Handle an event */ +void run_event_handler(Event *evt) +{ + bool handled = false; + + for (int i = 0; i < EH_SLOT_COUNT; i++) { + EventHandlerSlot *slot = &eh_slots[i]; + + if (!slot->used) continue; // unused + + if (slot->type != evt->type) continue; // wrong type + + handled = slot->handler(slot->handler_id, evt, &slot->user_data); + if (handled) break; + } + + if (!handled) { + warn("Unhandled event, type %d", evt->type); + } +} diff --git a/project/bus/event_handler.h b/project/bus/event_handler.h new file mode 100644 index 0000000..e128d0b --- /dev/null +++ b/project/bus/event_handler.h @@ -0,0 +1,48 @@ +#pragma once +#include "main.h" +#include "event_queue.h" + +typedef bool (*EventHandlerCallback) (uint32_t hdlr_id, Event *evt, void **user_data); + +/** + * @brief Register an event handler for event type + * @param type : handled event type + * @param handler : the handler func + * @return handler ID. Can be used to remove the handler. + */ +uint32_t register_event_handler(EventType type, EventHandlerCallback handler, void *user_data); + +/** + * @brief Remove event handler by handler ID + * @param handler_id : handler ID, obtained when registering or in the callback. + * @return number of removed handlers + */ +int remove_event_handler(uint32_t handler_id); + +/** + * @brief Handle an event + * @param event : pointer to the event to handle + */ +void run_event_handler(Event *event); + +/** + * @brief Check if hansler exists + * @param handler_id : handler + * @return exists + */ +bool event_handler_exists(uint32_t handler_id); + +/** + * @brief Create a link between two handlers (one direction). + * + * If handler A is linked to handler B, and handler A is removed, + * both handlers will perish. + * + * Make a circle if you need to chain more than two handlers. + * + * @param from : handler A + * @param to : handler B + * @param reciprocal : link also from B to A + * @return + */ +bool chain_event_handler(uint32_t from, uint32_t to, bool reciprocal); diff --git a/project/bus/event_queue.c b/project/bus/event_queue.c new file mode 100644 index 0000000..e364ace --- /dev/null +++ b/project/bus/event_queue.c @@ -0,0 +1,66 @@ +#include "event_queue.h" +#include "com/debug.h" + +/** Task queue */ +static CircBuf *tq; + +/** Event queue */ +static CircBuf *eq; + + +void queues_init(size_t tq_size, size_t eq_size) +{ + tq = cbuf_create(tq_size, sizeof(QueuedTask)); + eq = cbuf_create(eq_size, sizeof(Event)); +} + + +bool tq_post(void (*handler)(void*), void *arg) +{ + QueuedTask task; + task.handler = handler; + task.arg = arg; + + bool suc = cbuf_append(tq, &task); + if (!suc) error("TQ overflow"); + return suc; +} + + +bool eq_post(const Event *event) +{ + bool suc = cbuf_append(eq, event); + if (!suc) { + error("EQ overflow, evt %d", event->type); + } + return suc; +} + + +bool tq_poll_one(void) +{ + QueuedTask task; + + // serve all tasks + bool suc = cbuf_pop(tq, &task); + + if (suc) { + task.handler(task.arg); + } + + return suc; +} + + +void tq_poll(void) +{ + // serve all tasks + while (tq_poll_one()); +} + + +bool eq_take(Event *dest) +{ + bool suc = cbuf_pop(eq, dest); + return suc; +} diff --git a/project/bus/event_queue.h b/project/bus/event_queue.h new file mode 100644 index 0000000..dedf08b --- /dev/null +++ b/project/bus/event_queue.h @@ -0,0 +1,75 @@ +#pragma once + +#include "main.h" +#include "utils/circbuf.h" + +#define TASK_QUEUE_SIZE 64 +#define EVENT_QUEUE_SIZE 64 + + +/** Application events */ +typedef enum { + EVENT_ONE // placeholder + +} EventType; + + +/** Event Queue entry */ +typedef struct { + EventType type; + void *data; +} Event; + +typedef struct { + void (*handler)(void*); + void* arg; +} QueuedTask; + + +/** + * @brief Set up the task and event queues + * @param tq_size : number of slots in the task queue + * @param eq_size : number of slots in the event queue + */ +void queues_init(size_t tq_size, size_t eq_size); + + +/** + * @brief Post a task on the task queue, with arg. + * + * @see tq_post() + * + * @param handler : task function + * @param arg : argument for the handler + * @return success + */ +bool tq_post(void (*handler)(void *), void *arg); + + +/** + * @brief Post an event on the event queue + * @param event : pointer to an event to post; will be copied. + * @return success + */ +bool eq_post(const Event *event); + + +/** + * @brief Run all pending tasks on the task queue + */ +void tq_poll(void); + + +/** + * @brief Run one pending task on the task queue + * @return true if a task was run. + */ +bool tq_poll_one(void); + + +/** + * @brief Take one event off the event queue. + * @param dest : pointer to a destination event variable. + * @return success + */ +bool eq_take(Event *dest); diff --git a/project/colorled.c b/project/colorled.c new file mode 100644 index 0000000..43e648b --- /dev/null +++ b/project/colorled.c @@ -0,0 +1,66 @@ +#include "colorled.h" +#include "utils/timebase.h" + +#define LONG_DELAY() for (volatile uint32_t __j = 4; __j > 0; __j--) +#define SHORT_DELAY() for (volatile uint32_t __j = 1; __j > 0; __j--) + +static inline +__attribute__((always_inline)) +void colorled_byte(uint8_t b) +{ + for (register volatile uint8_t i = 0; i < 8; i++) { + COLORLED_GPIO->BSRR = COLORLED_PIN; // set pin high + + // duty cycle determines bit value + if (b & 0x80) { + LONG_DELAY(); + COLORLED_GPIO->BRR = COLORLED_PIN; // set pin low + SHORT_DELAY(); + } else { + SHORT_DELAY(); + COLORLED_GPIO->BRR = COLORLED_PIN; // set pin low + LONG_DELAY(); + } + + b <<= 1; // shift to next bit + } +} + + +/** Set one RGB LED color */ +void colorled_set(uint32_t rgb) +{ + __disable_irq(); // SysTick interrupt when sending data would break the timing + + colorled_byte((rgb & 0x00FF00) >> 8); + colorled_byte((rgb & 0xFF0000) >> 16); + colorled_byte(rgb & 0x0000FF); + + __enable_irq(); + + delay_us(50); // show +} + + +/** Set many RGBs */ +void colorled_set_many(uint32_t *rgbs, int count) +{ + __disable_irq(); + + for (int i = 0; i < count; i++) { + uint32_t rgb = *rgbs++; + colorled_byte((rgb & 0x00FF00) >> 8); + colorled_byte((rgb & 0xFF0000) >> 16); + colorled_byte(rgb & 0x0000FF); + } + + __enable_irq(); + + delay_us(50); // show +} + + +void colorled_off(void) +{ + colorled_set(RGB_BLACK); +} diff --git a/project/colorled.h b/project/colorled.h new file mode 100644 index 0000000..5c36eb0 --- /dev/null +++ b/project/colorled.h @@ -0,0 +1,79 @@ +#pragma once + +/* Includes ------------------------------------------------------------------*/ + +#include "main.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +// PB8 - WS2812B data line +#define COLORLED_GPIO GPIOB +#define COLORLED_PIN GPIO_Pin_12 + +#define RGB_RED rgb(255, 0, 0) +#define RGB_ORANGE rgb(255, 110, 0) +#define RGB_YELLOW rgb(255, 255, 0) +#define RGB_LIME rgb(160, 255, 0) +#define RGB_GREEN rgb( 0, 255, 0) +#define RGB_CYAN rgb( 0, 255, 120) +#define RGB_BLUE rgb( 0, 0, 255) +#define RGB_MAGENTA rgb(255, 0, 255) +#define RGB_WHITE rgb(255, 255, 255) +#define RGB_BLACK rgb( 0, 0, 0) + +/** + * @brief Struct for easy manipulation of RGB colors. + * + * Set components in the xrgb.r (etc.) and you will get + * the hex in xrgb.num. + */ +typedef union { + + /** Struct for access to individual color components */ + struct __attribute__((packed)) { + uint8_t b; + uint8_t g; + uint8_t r; + }; + + /** RGB color as a single uint32_t */ + uint32_t num; + +} ws2812_rgb_t; + +/* Exported macros -----------------------------------------------------------*/ + +/** + * @brief Compose an RGB color. + * @param r, g, b - components 0xFF + * @returns integer 0xRRGGBB + */ +#define rgb(r, g, b) (((0xFF & (r)) << 16) | ((0xFF & (g)) << 8) | (0xFF & (b))) + +/* Get components */ +#define rgb_r(rgb) (((rgb) >> 16) & 0xFF) +#define rgb_g(rgb) (((rgb) >> 8) & 0xFF) +#define rgb_b(rgb) ((rgb) & 0xFF) + +/* Exported functions --------------------------------------------------------*/ + +/** + * @brief Turn OFF the rgb LED + */ +void colorled_off(void); + + +/** + * @brief Set color of a WS2812B + * @param rgb - color 0xRRGGBB + */ +void colorled_set(uint32_t rgb); + + +/** + * @brief Set color of multiple chained RGB leds + * @param rgbs - array of colors (0xRRGGBB) + * @param count - number of LEDs + */ +void colorled_set_many(uint32_t *rgbs, int count); diff --git a/project/com/com_fileio.c b/project/com/com_fileio.c new file mode 100644 index 0000000..c6cfd9c --- /dev/null +++ b/project/com/com_fileio.c @@ -0,0 +1,96 @@ +#include "main.h" + +#include "com_fileio.h" +#include "com_iface.h" +#include "utils/str_utils.h" + +// Holding fields for ifaces +ComIface *debug_iface = NULL; +ComIface *data_iface = NULL; + + +// --- File descriptor names ------------------------------ + +struct name_fd { + const char *name; + const int fd; +}; + +#define NAME_FD_MAP_LEN 1 + +/** pre-assigned file descriptors for names */ +static const struct name_fd name_fd_map[NAME_FD_MAP_LEN] = { + {FNAME_DLNK, FD_DLNK} +}; + + +// --- Syscalls ------------------------------------------- + +/** + * @brief Write to a file by file descriptor. + * + * @param fd : open file descriptor + * @param buf : data to write + * @param len : buffer size + * @return number of written bytes + */ +int _write(int fd, const char *buf, int len) +{ + switch (fd) { + case FD_STDOUT: return (int)com_tx_block(debug_iface, buf, (size_t)len); + case FD_STDERR: return (int)com_tx_block(debug_iface, buf, (size_t)len); + case FD_DLNK: return (int)com_tx_block(data_iface, buf, (size_t)len); + default: + return 0; + } +} + + +// For some reason, reading does not work. +#if 0 +/** + * @brief Read from a file descriptor + * + * @param fd : file descriptor + * @param buf : destination buffer + * @param len : number of bytes to read + * @return actual number of read bytes + */ +int _read(int fd, char *buf, int len) +{ + switch (fd) { + case FD_STDIN: return com_rx_block(debug_iface, buf, len); + case FD_ESP: return com_rx_block(esp_iface, buf, len); + default: + return 0; + } +} +#endif + + +/** + * @brief Open a file by name. + * + * This stub is called by newlib when fopen is used. + * It returns a pre-assigned file descriptor based + * on the name. + * + * @note + * stdout, stderr, stdin are open implicitly + * + * @param name : file name + * @param flags : file flags (ignored) + * @return file descriptor + */ +int _open(const char *name, int flags, ...) +{ + (void)flags; + + for (int i = 0; i < NAME_FD_MAP_LEN; i++) { + if (streq(name_fd_map[i].name, name)) { + return name_fd_map[i].fd; + } + } + + return -1; +} diff --git a/project/com/com_fileio.h b/project/com/com_fileio.h new file mode 100644 index 0000000..f1159ec --- /dev/null +++ b/project/com/com_fileio.h @@ -0,0 +1,23 @@ +#pragma once + +#include "com_iface.h" + +/** Debug USART iface */ +extern ComIface *debug_iface; + +/** ESP8266 com iface */ +extern ComIface *data_iface; + +/** Do-nothing iface */ +extern ComIface *com_iface_noop; + + +/** File descriptors for use with built-in "files" */ +enum { + FD_STDIN = 0, + FD_STDOUT = 1, + FD_STDERR = 2, + FD_DLNK = 3, +}; + +#define FNAME_DLNK "dlnk" diff --git a/project/com/com_iface.c b/project/com/com_iface.c new file mode 100644 index 0000000..20df6c7 --- /dev/null +++ b/project/com/com_iface.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include + +#include "com_iface.h" +#include "utils/timebase.h" + +// ---- accessor methods ---------------------- + +bool com_rx_rdy(ComIface *iface) +{ + return iface->rx_rdy(iface); +} + + +bool com_tx_rdy(ComIface *iface) +{ + return iface->tx_rdy(iface); +} + + +bool com_tx_done(ComIface *iface) +{ + return iface->tx_done(iface); +} + +bool com_tx(ComIface *iface, uint8_t b) +{ + return iface->tx(iface, b); +} + + +bool com_rx(ComIface *iface, uint8_t *b) +{ + return iface->rx(iface, (uint8_t*) b); +} + + +bool com_unrx(ComIface *iface, uint8_t b) +{ + if (!iface->unrx) { + return false; // not all may have it implemented + } + return iface->unrx(iface, b); +} + + +size_t com_tx_block(ComIface *iface, const void *blob, size_t size) +{ + return iface->txb(iface, blob, size); +} + + +size_t com_rx_block(ComIface *iface, void *buf, size_t length) +{ + return iface->rxb(iface, buf, length); +} + + +void com_poll(ComIface *iface) +{ + iface->poll(iface); +} + + +bool com_rx_char(ComIface *iface, char * c) +{ + return iface->rx(iface, (uint8_t*) c); +} + + +bool com_tx_char(ComIface *iface, const char c) +{ + return iface->tx(iface, (uint8_t)c); +} + + +/** Read string, terminate with \0. Returns real read size. */ +size_t com_rx_str(ComIface *iface, char* buf, size_t buflen) +{ + size_t len = iface->rxb(iface, buf, buflen); + buf[len] = 0; // zero terminator + return len; +} + + +size_t com_tx_str(ComIface *iface, const char * string) +{ + return iface->txb(iface, string, strlen(string)); +} + + +/** Wait for incoming byte */ +bool com_rx_wait(ComIface *iface, uint16_t timeout) +{ + until_timeout(timeout) { + if (iface->rx_rdy(iface)) return true; + } + + return false; +} + + +/** Wait for tx buf ready */ +bool com_tx_rdy_wait(ComIface *iface, uint16_t timeout) +{ + until_timeout(timeout) { + if (iface->tx_rdy(iface)) return true; + } + + return false; +} + + +/** Wait for tx complete */ +bool com_tx_done_wait(ComIface *iface, uint16_t timeout) +{ + until_timeout(timeout) { + if (iface->tx_done(iface)) return true; + } + + return false; +} + + +void com_printf(ComIface *iface, const char *fmt, ...) +{ + if (iface->file == NULL) { + com_tx_str(iface, "com_printf(), no iface file!\r\n"); + return; + } + + // use the file descriptor attached + + va_list va; + va_start(va, fmt); + vfprintf(iface->file, fmt, va); + va_end(va); +} + + +void com_vprintf(ComIface *iface, const char *fmt, va_list va) +{ + if (iface->file == NULL) { + com_tx_str(iface, "com_vprintf(), no iface file!\r\n"); + com_tx_str(iface, fmt); // poor mans fallback + return; + } + + // use the file descriptor attached + vfprintf(iface->file, fmt, va); +} + + +void com_v100_attr_(ComIface *iface, uint8_t count, ...) +{ + va_list va; + va_start(va, count); + + com_tx_char(iface, 27); + com_tx_char(iface, '['); + + for (int i = 0; i < count; i++) { + int attr = va_arg(va, int); + + // comma + if (i > 0) com_tx_char(iface, ';'); + + // number + com_printf(iface, "%d", attr); + } + + com_tx_char(iface, 'm'); + + va_end(va); +} diff --git a/project/com/com_iface.h b/project/com/com_iface.h new file mode 100644 index 0000000..6900684 --- /dev/null +++ b/project/com/com_iface.h @@ -0,0 +1,168 @@ +#pragma once + +#include +#include +#include +#include +#include + +// Implementation-independent UI (command handler) + +typedef struct ComIface_struct ComIface; + +struct ComIface_struct { + // --- Variables --- + + /** Implementation-specific data object */ + void *opts; + + /** File descriptor for this stream */ + FILE *file; + + /** + * User callback for data ready, triggered on poll(). + * Can be null. + */ + void (*rx_callback)(ComIface *iface); + + // --- Interface methods --- + + /** Data ready to be read (RX buffer Not Empty) */ + bool (*rx_rdy)(ComIface *iface); + + /** Free space in TX buffer */ + bool (*tx_rdy)(ComIface *iface); + + /** Everything sent */ + bool (*tx_done)(ComIface *iface); + + /** Send 1 byte. Blocking, timeout after some time. */ + bool (*tx)(ComIface *iface, uint8_t b); + + /** Read one byte. False on failure. Blocking, timeout after some time. */ + bool (*rx)(ComIface *iface, uint8_t *b); + + /** Unreceive one byte. False on failure. */ + bool (*unrx)(ComIface *iface, uint8_t b); + + /** Send a binary block. False on failure. */ + size_t (*txb)(ComIface *iface, const void *blob, size_t size); + + /** Read a binary block. Returns real read length. Blocking, timeout after some time. */ + size_t (*rxb)(ComIface *iface, void *buf, size_t length); + + /** Poll for changes */ + void (*poll)(ComIface *iface); +}; + + +// ---- Functions for working with iface -------------- + +/** Wait for incoming byte */ +bool com_rx_wait(ComIface *iface, uint16_t timeout); + +/** Wait for free space in tx buffer */ +bool com_tx_rdy_wait(ComIface *iface, uint16_t timeout); + +/** Wait for tx complete */ +bool com_tx_done_wait(ComIface *iface, uint16_t timeout); + +/** Check if there's data in the receive buffer */ +bool com_rx_rdy(ComIface *iface); + +/** Check if transmit buffer can accept data */ +bool com_tx_rdy(ComIface *iface); + +/** Check if transmit buffer is empty */ +bool com_tx_done(ComIface *iface); + +/** Send 1 byte */ +bool com_tx(ComIface *iface, uint8_t b); + +/** Read one byte. False on failure. Fails on timeout. */ +bool com_rx(ComIface *iface, uint8_t *b); + +/** Unrx one byte. False on failure. */ +bool com_unrx(ComIface *iface, uint8_t b); + +/** Send a binary blob. False on failure. Fails on timeout. */ +size_t com_tx_block(ComIface *iface, const void *blob, size_t size); + +/** Read a blob. Returns real read length. Stops on timeout. */ +size_t com_rx_block(ComIface *iface, void *buf, size_t length); + +/** Poll for changes */ +void com_poll(ComIface *iface); + +/** Send 1 char */ +bool com_tx_char(ComIface *iface, char c); + +/** Read one char. False on failure. Fails on timeout. */ +bool com_rx_char(ComIface *iface, char *c); + +/** Send a string. False on failure. */ +size_t com_tx_str(ComIface *iface, const char *str); + +/** Read a string. Returns real read length. Stops on timeout. */ +size_t com_rx_str(ComIface *iface, char *buf, size_t length); + + +/** + * Printf to a serial interface. + * Max length is 255 chars. + */ +void com_printf(ComIface *iface, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + + +/** + * Printf to a serial interface, with va_list. + */ +void com_vprintf(ComIface *iface, const char *fmt, va_list va); + + +// ---- VT100/ANSI color support ------------- + +/** ANSI formatting attributes */ +typedef enum { + // Non-colour Attributes + FMT_RESET = 0, // Reset all attributes + FMT_BRIGHT = 1, // Bright + FMT_DIM = 2, // Dim + FMT_UNDER = 4, // Underscore + FMT_BLINK = 5, // Blink + FMT_INVERS = 7, // Reverse + FMT_HIDDEN = 8, // Hidden + FMT_ITALIC = 16, // Italic font + FMT_FAINT = 32, // Faint color + + // Foreground Colours + FMT_BLACK = 30, // Black + FMT_RED = 31, // Red + FMT_GREEN = 32, // Green + FMT_YELLOW = 33, // Yellow + FMT_BLUE = 34, // Blue + FMT_MAGENTA = 35, // Magenta + FMT_CYAN = 36, // Cyan + FMT_WHITE = 37, // White + + // Background Colours + FMT_BLACK_BG = 40, // Black + FMT_RED_BG = 41, // Red + FMT_GREEN_BG = 42, // Green + FMT_YELLOW_BG = 43, // Yellow + FMT_BLUE_BG = 44, // Blue + FMT_MAGENTA_BG = 45, // Magenta + FMT_CYAN_BG = 46, // Cyan + FMT_WHITE_BG = 47, // White +} ANSI_attr_t; + +#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1) +#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N + +#define com_v100_attr(iface, ...) com_v100_attr_(iface, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__) + +/** + * Send formatting code to a com interface + */ +void com_v100_attr_(ComIface *iface, uint8_t count, ...); diff --git a/project/com/datalink.c b/project/com/datalink.c new file mode 100644 index 0000000..8c35417 --- /dev/null +++ b/project/com/datalink.c @@ -0,0 +1,48 @@ +#include "datalink.h" +#include "com_fileio.h" +#include "debug.h" +#include "com_fileio.h" + +SBMP_Endpoint *dlnk_ep; + +static void dlnk_tx(uint8_t b); +static void dlnk_rx_bridge(ComIface *iface); + +/** Set up the datalink */ +void dlnk_init(void) +{ + // Allocate & setup the endpoint + dlnk_ep = sbmp_ep_init(NULL, NULL, 100, dlnk_rx, dlnk_tx); + sbmp_ep_seed_session(dlnk_ep, 0x3FFF); // just in case arbitration fails + sbmp_ep_enable(dlnk_ep, true); + + sbmp_ep_init_listeners(dlnk_ep, NULL, 4); // really don' need many here.. + + data_iface->rx_callback = dlnk_rx_bridge; +} + +/** + * Bridge between USART subsystem's Rx buffer, and the SBMP driver + * + * Called if bytes are received in the USART buffer, + * and the USART subsystem is polled. + */ +static void dlnk_rx_bridge(ComIface *iface) +{ + uint8_t b; + while (com_rx(iface, &b)) { + SBMP_RxStatus st = sbmp_ep_receive(dlnk_ep, b); + + // If byte was not accepted, try to put it back into the buffer + if (st == SBMP_RX_BUSY || st == SBMP_RX_DISABLED) { + com_unrx(iface, b); + break; + } + } +} + +/** Datalink Tx func */ +static void dlnk_tx(uint8_t b) +{ + com_tx(data_iface, b); +} diff --git a/project/com/datalink.h b/project/com/datalink.h new file mode 100644 index 0000000..a09f259 --- /dev/null +++ b/project/com/datalink.h @@ -0,0 +1,26 @@ +#pragma once + +/** + * SBMP setup & funcs + */ + +#include "main.h" +#include + +#define DG_REQUEST_RAW 40 // request raw vector. Sample count [u16], Frequency [u32] +#define DG_REQUEST_FFT 41 // request fft vector. Sample count [u16], Frequency [u32]. Result - count/2 bins. Count must be 2^n, 16..2048 +#define DG_REQUEST_STORE_REF 42 // calculate signal signature & store for comparing +#define DG_REQUEST_COMPARE_REF 43 +// wifi status & control +#define DG_SETMODE_AP 44 // request AP mode (AP button pressed) +#define DG_WPS_START 45 // start WPS +#define DG_WIFI_STATUS 46 // WiFi status report +#define DG_REQUEST_STM_VERSION 47 // Get acquisition module firmware version + + +extern SBMP_Endpoint *dlnk_ep; + +void dlnk_init(void); + +/** Received datagram handler */ +extern void dlnk_rx(SBMP_Datagram *dg); diff --git a/project/com/debug.c b/project/com/debug.c new file mode 100644 index 0000000..dc1f00e --- /dev/null +++ b/project/com/debug.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +#include "com_iface.h" + +#include "utils/timebase.h" + +#include "debug.h" + + +void dbg_printf(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + com_vprintf(debug_iface, fmt, va); // vsnprintf(strbuf, DBG_BUF_LEN, fmt, va); + va_end(va); +} + + +void dbg_va_base(const char *fmt, const char *tag, va_list va) +{ + ms_time_t now = ms_now(); + uint32_t secs = now / 1000; + uint32_t ms = now % 1000; + + com_printf(debug_iface, "%4"PRIu32".%03"PRIu32" ", secs, ms); + + dbg_raw(tag); + + com_vprintf(debug_iface, fmt, va); + dbg_raw(DEBUG_EOL); +} + +/** Print a log message with an INFO tag and newline (ONLY FOR BANNER - always shown) */ +void banner_info(const char *fmt, ...) +{ + com_v100_attr(debug_iface, FMT_GREEN); + + va_list va; + va_start(va, fmt); + dbg_va_base(fmt, DEBUG_TAG_INFO, va); + va_end(va); + + com_v100_attr(debug_iface, FMT_RESET); +} + + +#if VERBOSE_LOGGING + +/** Print a log message with a DEBUG tag and newline */ +void dbg(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + dbg_va_base(fmt, DEBUG_TAG_BASE, va); + va_end(va); +} + + +/** Print a log message with an INFO tag and newline */ +void info(const char *fmt, ...) __attribute__((alias("banner_info"))); + +#endif + + + +/** Print a log message with an INFO tag and newline */ +void banner(const char *fmt, ...) +{ + com_v100_attr(debug_iface, FMT_GREEN, FMT_BRIGHT); + + va_list va; + va_start(va, fmt); + dbg_va_base(fmt, DEBUG_TAG_INFO, va); + va_end(va); + + com_v100_attr(debug_iface, FMT_RESET); +} + + +/** Print a log message with a warning tag and newline */ +void warn(const char *fmt, ...) +{ + com_v100_attr(debug_iface, FMT_YELLOW, FMT_BRIGHT); + + va_list va; + va_start(va, fmt); + dbg_va_base(fmt, DEBUG_TAG_WARN, va); + va_end(va); + + com_v100_attr(debug_iface, FMT_RESET); +} + + +/** Print a log message with an ERROR tag and newline */ +void error(const char *fmt, ...) +{ + com_v100_attr(debug_iface, FMT_RED, FMT_BRIGHT); + + va_list va; + va_start(va, fmt); + dbg_va_base(fmt, DEBUG_TAG_ERROR, va); + va_end(va); + + com_v100_attr(debug_iface, FMT_RESET); +} diff --git a/project/com/debug.h b/project/com/debug.h new file mode 100644 index 0000000..7f97d2f --- /dev/null +++ b/project/com/debug.h @@ -0,0 +1,73 @@ +#pragma once + +#include "main.h" +#include "com_iface.h" +#include "com_fileio.h" + +#include "bus/event_queue.h" + +// helper to mark printf functions +#define PRINTF_LIKE __attribute__((format(printf, 1, 2))) + +#define DBG_BUF_LEN 256 + +#define ESCAPE_DEBUG_MESSAGES 1 + + +// formatting symbols +#define DEBUG_EOL "\r\n" +#define DEBUG_TAG_WARN "[W] " +#define DEBUG_TAG_ERROR "[E] " +#define DEBUG_TAG_BASE "[ ] " +#define DEBUG_TAG_INFO "[i] " + + +/** Print a log message with no tag and no newline */ +void dbg_printf(const char *fmt, ...) PRINTF_LIKE; + +/** Print via va_list */ +void dbg_va_base(const char *fmt, const char *tag, va_list va); + +/** Print a string to the debug interface (length not limited) */ +static inline void dbg_raw(const char *str) +{ + com_tx_str(debug_iface, str); +} + + +/** Print a char to the debug interface */ +static inline void dbg_raw_c(char c) +{ + com_tx(debug_iface, (uint8_t)c); +} + + +#if VERBOSE_LOGGING + +/** Print a log message with a "debug" tag and newline */ +void dbg(const char *fmt, ...) PRINTF_LIKE; + + +/** Print a log message with an "info" tag and newline */ +void info(const char *fmt, ...) PRINTF_LIKE; + +#else + +#define dbg(fmt, ...) +#define info(fmt, ...) + +#endif + + +/** Print a log message with an "info" tag and newline */ +void banner_info(const char *fmt, ...) PRINTF_LIKE; + +/** Print a log message with a "banner" tag and newline */ +void banner(const char *fmt, ...) PRINTF_LIKE; + +/** Print a log message with a "warning" tag and newline */ +void warn(const char *fmt, ...) PRINTF_LIKE; + + +/** Print a log message with an "error" tag and newline */ +void error(const char *fmt, ...) PRINTF_LIKE; diff --git a/project/com/iface_noop.c b/project/com/iface_noop.c new file mode 100644 index 0000000..4c69415 --- /dev/null +++ b/project/com/iface_noop.c @@ -0,0 +1,91 @@ +#include + +#include "iface_noop.h" +#include "com_fileio.h" +#include "malloc_safe.h" + +// ==== NOOP com driver ==== + +static bool if_rx_rdy(ComIface *iface) +{ + (void)iface; + return false; +} + +static bool if_tx_rdy(ComIface *iface) +{ + (void)iface; + return true; +} + +static bool if_tx_done(ComIface *iface) +{ + (void)iface; + return true; +} + +static bool if_rx(ComIface *iface, uint8_t *b) +{ + (void)iface; + (void)b; + return false; +} + +static bool if_unrx(ComIface *iface, uint8_t b) +{ + (void)iface; + (void)b; + return false; +} + +static bool if_tx(ComIface *iface, uint8_t b) +{ + (void)iface; + (void)b; + return true; +} + +static size_t if_rxb(ComIface *iface, void *buf, size_t buflen) +{ + (void)iface; + (void)buf; + (void)buflen; + return 0; +} + +static size_t if_txb(ComIface *iface, const void *blob, size_t size) +{ + (void)iface; + (void)blob; + + return size; +} + +static void if_poll(ComIface *iface) +{ + (void)iface; +} + +ComIface *com_noop_init(void) +{ + ComIface *iface = malloc_s(sizeof(ComIface)); + + iface->rx_rdy = if_rx_rdy; + iface->tx_rdy = if_tx_rdy; + iface->tx_done = if_tx_done; + + iface->rx = if_rx; + iface->unrx = if_unrx; + iface->tx = if_tx; + + iface->rxb = if_rxb; + iface->txb = if_txb; + + iface->poll = if_poll; + iface->rx_callback = NULL; + + return iface; +} + + + diff --git a/project/com/iface_noop.h b/project/com/iface_noop.h new file mode 100644 index 0000000..08819ac --- /dev/null +++ b/project/com/iface_noop.h @@ -0,0 +1,14 @@ +#pragma once + +/** + * NOOP iface works like /dev/null + */ + +#include "com_iface.h" + +/** + * @brief Initialize a do-nothing interface. + * @param iface : iface pointer. If NULL, it'll be allocated. + * @return the iface pointer. + */ +ComIface *com_noop_init(void); diff --git a/project/com/iface_usart.c b/project/com/iface_usart.c new file mode 100644 index 0000000..8dec78e --- /dev/null +++ b/project/com/iface_usart.c @@ -0,0 +1,328 @@ +#include "main.h" +#include "malloc_safe.h" +#include "iface_usart.h" + +#include "utils/timebase.h" +#include "utils/circbuf.h" + +#include "com/com_fileio.h" +#include "com/debug.h" + +#include "bus/event_queue.h" + + +#define DEF_WAIT_TO_MS 5 + + +typedef struct { + uint16_t wait_timeout; + USART_TypeDef *dev; + CircBuf *rxbuf; // allocated receive buffer + CircBuf *txbuf; // allocated transmit buffer, can be NULL -> no buffer +} usart_opts; + +#define opts(iface) ((usart_opts *)(iface)->opts) + +// ---- Instances ---- +// (needed for async rx/tx with interrupts) + +static ComIface *usart1_iface = NULL; +static ComIface *usart2_iface = NULL; +static ComIface *usart3_iface = NULL; + +// ------------------- + + +/** Check if data is ready for reading */ +static bool if_rx_rdy(ComIface *iface) +{ + CircBuf *buf = opts(iface)->rxbuf; + + return !cbuf_empty(buf); +} + + +/** Check if sending is done */ +static bool if_tx_rdy(ComIface *iface) +{ + CircBuf *buf = opts(iface)->txbuf; + + if (buf == NULL) { + // non-buffered mode + USART_TypeDef* USARTx = opts(iface)->dev; + return (USARTx->SR & USART_SR_TXE); + } + + return !cbuf_full(buf); +} + + +/** Check if sending is done */ +static bool if_tx_done(ComIface *iface) +{ + CircBuf *buf = opts(iface)->txbuf; + USART_TypeDef* USARTx = opts(iface)->dev; + + // NULL buffer is considered empty + return cbuf_empty(buf) && (USARTx->SR & USART_SR_TC); +} + + +/** Read one byte (wait for it). False on error. */ +static bool if_rx(ComIface *iface, uint8_t *b) +{ + // wait for data in the buffer + if (!com_rx_wait(iface, opts(iface)->wait_timeout) || b == NULL) { + return false; + } + + // read from buffer + cbuf_pop(opts(iface)->rxbuf, b); + + return true; +} + + +/** Try to unreceive a byte. False on error. */ +static bool if_unrx(ComIface *iface, uint8_t b) +{ + // push back + return cbuf_push(opts(iface)->rxbuf, &b); +} + + +/** Send one byte (waits for tx) */ +static bool if_tx(ComIface *iface, uint8_t b) +{ + usart_opts *uopts = opts(iface); + USART_TypeDef* USARTx = uopts->dev; + + if (uopts->txbuf == NULL) { + + // Blocking tx mode + until_timeout(uopts->wait_timeout) { + if (USARTx->SR & USART_SR_TXE) { + USARTx->DR = b; + return true; // success + } + } + + return false; + + } else { + + // Buffered mode + + // wait for free space in the buffer + bool ready = com_tx_rdy_wait(iface, uopts->wait_timeout); + + if (ready) { + // append to the buffer + cbuf_append(uopts->txbuf, &b); + } + + // regardless ready state, start Tx if there are bytes + // (should fix a bug where full buffer was never emptied) + + // If TXE (send buffer empty), start sending the buffer + // Otherwise, IRQ chain is in progress. + if (USARTx->SR & USART_SR_TXE) { + USART_ITConfig(USARTx, USART_IT_TXE, ENABLE); // start tx chain + } + + return ready; + } +} + + +/** Read a blob. Returns real read size */ +static size_t if_rxb(ComIface *iface, void *buf, size_t buflen) +{ + if (buf == NULL) return false; + //if (!com_rx_wait(iface, opts(iface)->wait_timeout)) return 0; + + uint8_t* byteptr = (uint8_t*)buf; + for (size_t i = 0; i < buflen; i++) { + if (!if_rx(iface, byteptr++)) return i; + } + + return buflen; +} + + +/** Send a binary blob. False on error. */ +static size_t if_txb(ComIface *iface, const void *blob, size_t size) +{ + if (blob == NULL) return false; + //if (!com_tx_rdy_wait(iface, opts(iface)->wait_timeout)) return false; + + const uint8_t* byteptr = (const uint8_t*)blob; + for (size_t i = 0; i < size; i++) { + if (!if_tx(iface, *byteptr++)) return i; + } + + return size; +} + + +/** Check for incoming data */ +static void if_poll(ComIface *iface) +{ + if (if_rx_rdy(iface)) { + // call user cb + if (iface->rx_callback) { + iface->rx_callback(iface); + } + } +} + + +// ---- Init interface ---- + +//void usart_iface_set_baudrate(ComIface *iface, uint32_t baud) +//{ +// USART_TypeDef* USARTx = opts(iface)->dev; +// +// USART_SetBaudrate(USARTx, baud); +//} + + +/* public */ +ComIface *usart_iface_init(USART_TypeDef* USARTx, uint32_t baud, size_t rxbuf_len, size_t txbuf_len) +{ + assert_param(IS_USART_BAUDRATE(baud)); + assert_param(rxbuf_len > 0); + + ComIface *iface = malloc_s(sizeof(ComIface)); + + // --- setup device specific iface data --- + + // Allocate the opts config object + iface->opts = malloc_s(sizeof(usart_opts)); + + // Set device ID + opts(iface)->dev = USARTx; + opts(iface)->wait_timeout = DEF_WAIT_TO_MS; + + // Initialize the rx/tx buffers (malloc's the array) + opts(iface)->rxbuf = cbuf_create(rxbuf_len, 1); + + // zero-length TX buffer -> blocking Tx + opts(iface)->txbuf = (txbuf_len == 0) ? NULL : cbuf_create(txbuf_len, 1); + + // --- driver instance --- + + iface->rx_rdy = if_rx_rdy; + iface->tx_rdy = if_tx_rdy; + iface->tx_done = if_tx_done; + + iface->rx = if_rx; + iface->unrx = if_unrx; + iface->tx = if_tx; + + iface->txb = if_txb; + iface->rxb = if_rxb; + + iface->poll = if_poll; + + iface->rx_callback = NULL; // user can replace + + + /* enable peripehral clock, assign to holder var, enable IRQ */ + IRQn_Type irqn; + + if (USARTx == USART1) { + // USART1 + usart1_iface = iface; + irqn = USART1_IRQn; + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + + } else if (USARTx == USART2) { + // USART2 + usart2_iface = iface; + irqn = USART2_IRQn; + RCC->APB1ENR |= RCC_APB1ENR_USART2EN; + + } else { + // USART3 + usart3_iface = iface; + irqn = USART3_IRQn; + RCC->APB1ENR |= RCC_APB1ENR_USART3EN; + } + + // Enable IRQ + NVIC_EnableIRQ(irqn); + + // lower priority than SysTick, but high + NVIC_SetPriority(irqn, 1); // function does the shifting + + + /* Setup UART parameters. */ + USART_InitTypeDef usart; + USART_StructInit(&usart); + usart.USART_BaudRate = baud; + USART_Init(USARTx, &usart); + + /* Enable */ + USART_Cmd(USARTx, ENABLE); + + // Enable Rx interrupt + USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE); // disable IRQ + + return iface; +} + + +// ---- IRQ handlers for chained writing and rx ---- + + +/** + * @brief Common USART irq handler + * @param iface the interface at which the event occured + */ +static void usart_iface_irq_base(ComIface* iface) +{ + USART_TypeDef* USARTx = opts(iface)->dev; + + if (USARTx->SR & USART_SR_RXNE) { + // Byte received. + uint8_t rxb = USARTx->DR & 0xFF; + if (!cbuf_append(opts(iface)->rxbuf, &rxb)) { + // Buffer overflow + // Can't print debug msg, can cause deadlock + } + } + + if (USARTx->SR & USART_SR_TXE) { + // Byte sent. + uint8_t txb; + + // Send next byte (if buffer is NULL, cbuf_pop also returns false) + if (cbuf_pop(opts(iface)->txbuf, &txb)) { + USARTx->DR = txb; // send data + } else { + USART_ITConfig(USARTx, USART_IT_TXE, DISABLE); // disable IRQ + } + } + + // Clear ORE flag if set + USART_ClearFlag(USARTx, USART_FLAG_ORE); +} + + +void USART1_IRQHandler(void) +{ + usart_iface_irq_base(usart1_iface); +} + + +void USART2_IRQHandler(void) +{ + usart_iface_irq_base(usart2_iface); +} + + +void USART3_IRQHandler(void) +{ + usart_iface_irq_base(usart3_iface); +} diff --git a/project/com/iface_usart.h b/project/com/iface_usart.h new file mode 100644 index 0000000..7dcf525 --- /dev/null +++ b/project/com/iface_usart.h @@ -0,0 +1,19 @@ +#pragma once + +#include "main.h" +#include "com_iface.h" + +// Hardware USART. + +/** + * @brief Init an USART interface. Caller must configure GPIO's & AF manually. + * @param USARTx device + * @param baud baud rate (ex.: 9600) + * @param rxbuf_len receive buffer size, must be > 0 + * @param txbuf_len send buffer size. If 0, tx is blocking. + * @return the iface structure + */ +ComIface *usart_iface_init(USART_TypeDef* USARTx, uint32_t baud, size_t rxbuf_len, size_t txbuf_len); + +///** Set baud rate */ +//void usart_iface_set_baudrate(ComIface *iface, uint32_t baud); diff --git a/project/display.c b/project/display.c new file mode 100644 index 0000000..d0ae1d3 --- /dev/null +++ b/project/display.c @@ -0,0 +1,94 @@ +#include "display.h" +#include "com/debug.h" +#include "utils/timebase.h" +#include "utils/meanbuf.h" + +#include + +#define PIXEL_COUNT 30 + +static ws2812_rgb_t pixels[PIXEL_COUNT] = {}; + +static MeanBuf *mb; + +void display_show(void) +{ + colorled_set_many((uint32_t*) pixels, PIXEL_COUNT); +} + + +static void handle_sonar_value(float mm) +{ + for (int i = PIXEL_COUNT-1; i > 0; i--) { + pixels[i].num = pixels[i-1].num; + } + + float x = mm/5.0f; + if (x>255) x = 255; + + pixels[0].r = 255-x; + pixels[0].b = x; + + display_show(); +} + + +static void show(void*arg) +{ + (void)arg; + + handle_sonar_value(meanbuf_current(mb)); +} + + +static void sonar(void* arg) +{ + (void)arg; + + info("Sonar"); + + GPIOB->BSRR = GPIO_Pin_13; + delay_us(10); + GPIOB->BRR = GPIO_Pin_13; + + // wait for response + + bool suc = false; + until_timeout(50) { + if((GPIOB->IDR & (1 << 14)) != 0) { + suc = true; + break; + } + } + + if (!suc) { + dbg("Not suc"); + return; + } + + uint32_t cnt = 0; + until_timeout(50) { + if((GPIOB->IDR & (1 << 14)) == 0) break; + cnt++; + } + + float t = cnt / 11.2f; + + meanbuf_add(mb, t); +} + + +void display_init(void) +{ + mb = meanbuf_create(10); + + for (int i = 0; i < PIXEL_COUNT; i++) { + pixels[i].num = rgb(0, 0, 255); + } + + display_show(); + + add_periodic_task(sonar, NULL, 50, true); + + add_periodic_task(show, NULL, 50, true); +} diff --git a/project/display.h b/project/display.h new file mode 100644 index 0000000..a60afb5 --- /dev/null +++ b/project/display.h @@ -0,0 +1,11 @@ +#ifndef DISPLAY_H +#define DISPLAY_H + +#include "main.h" +#include "colorled.h" + +void display_show(void); + +void display_init(void); + +#endif // DISPLAY_H diff --git a/project/hw_init.c b/project/hw_init.c new file mode 100644 index 0000000..2e9b194 --- /dev/null +++ b/project/hw_init.c @@ -0,0 +1,125 @@ +#include "hw_init.h" + +#include "com/iface_usart.h" +#include "com/com_fileio.h" +#include "com/datalink.h" + +#include "utils/debounce.h" +#include "utils/timebase.h" + +#include "bus/event_queue.h" + +// ---- Private prototypes -------- + +static void conf_gpio(void); +static void conf_usart(void); +static void conf_systick(void); +static void conf_subsystems(void); +static void conf_irq_prios(void); + +// ---- Public functions ---------- + +/** + * @brief Initialize hardware resources + */ +void hw_init(void) +{ + conf_gpio(); + conf_usart(); + conf_systick(); + conf_irq_prios(); + conf_subsystems(); +} + + +// ---- Private functions --------- + + + +static void conf_irq_prios(void) +{ + NVIC_SetPriorityGrouping(0); // 0 bits for sub-priority + + // SysTick - highest prio, used for timeouts + NVIC_SetPriority(SysTick_IRQn, 0); // SysTick - for timeouts + NVIC_SetPriority(USART2_IRQn, 6); // USART - datalink + NVIC_SetPriority(USART1_IRQn, 10); // USART - debug + + // FIXME check , probably bad ports +} + + +/** + * @brief Configure SW subsystems + */ +static void conf_subsystems(void) +{ + // task scheduler subsystem + timebase_init(15, 15); + + // event and task queues + queues_init(15, 15); + + // initialize SBMP for ESP8266 + dlnk_init(); +} + + +/** + * @brief Configure GPIOs + */ +static void conf_gpio(void) +{ + GPIO_InitTypeDef gpio_cnf; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); + + // Red LED + gpio_cnf.GPIO_Pin = GPIO_Pin_13; + gpio_cnf.GPIO_Mode = GPIO_Mode_Out_PP; + gpio_cnf.GPIO_Speed = GPIO_Speed_10MHz; + GPIO_Init(GPIOC, &gpio_cnf); + + // colorled | sonar trig + gpio_cnf.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; + gpio_cnf.GPIO_Mode = GPIO_Mode_Out_PP; + gpio_cnf.GPIO_Speed = GPIO_Speed_10MHz; + GPIO_Init(GPIOB, &gpio_cnf); + + gpio_cnf.GPIO_Pin = GPIO_Pin_14; + gpio_cnf.GPIO_Mode = GPIO_Mode_IPD; + gpio_cnf.GPIO_Speed = GPIO_Speed_10MHz; + GPIO_Init(GPIOB, &gpio_cnf); + + // A0-sonar trig | UART2 - debug, UART1 - esp + gpio_cnf.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_9 | GPIO_Pin_10; + gpio_cnf.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_Init(GPIOA, &gpio_cnf); +} + + +/** + * @brief Configure USARTs + */ +static void conf_usart(void) +{ + // Debug interface, working as stdout/stderr. + debug_iface = usart_iface_init(USART2, 115200, 256, 256); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + debug_iface->file = stdout; + + // Datalink iface + data_iface = usart_iface_init(USART1, 460800, 256, 256); +} + + +/** + * @brief Configure 1 kHz SysTick w/ interrupt + */ +static void conf_systick(void) +{ + SysTick_Config(F_CPU / 1000); +} diff --git a/project/hw_init.h b/project/hw_init.h new file mode 100644 index 0000000..cfe42ca --- /dev/null +++ b/project/hw_init.h @@ -0,0 +1,6 @@ +#pragma once + +#include "main.h" + +void hw_init(void); + diff --git a/project/main.c b/project/main.c index 4daaec6..d2a0395 100644 --- a/project/main.c +++ b/project/main.c @@ -1,25 +1,69 @@ -/* Includes ------------------------------------------------------------------*/ -#include "stm32f10x.h" -#include +#include "main.h" +#include "hw_init.h" + +#include "com/debug.h" +#include "com/com_fileio.h" +#include "com/com_iface.h" +#include "bus/event_queue.h" +#include "bus/event_handler.h" +#include "utils/timebase.h" + +#include "colorled.h" +#include "display.h" +#include +#include + +void poll_subsystems(void) +{ + // poll serial buffers (runs callback) + com_poll(debug_iface); + com_poll(data_iface); + + // run queued tasks + tq_poll(); + + // handle queued events + Event evt; + + until_timeout(2) { // take 2 ms max + if (eq_take(&evt)) { + run_event_handler(&evt); + } else { + break; + } + } +} + + + +void blinky(void* arg) +{ + (void)arg; + GPIOC->ODR ^= 1<<13; +} + + int main(void) { - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + hw_init(); + display_init(); - GPIO_InitTypeDef gpio_cnf; - gpio_cnf.GPIO_Pin = GPIO_Pin_13; - gpio_cnf.GPIO_Mode = GPIO_Mode_Out_PP; - gpio_cnf.GPIO_Speed = GPIO_Speed_2MHz; + banner("*** STM32F103K8T6 RGB LED demo ***"); + banner_info("(c) Ondrej Hruska, 2016"); + banner_info("Katedra mereni K338, CVUT FEL"); - GPIO_Init(GPIOC, &gpio_cnf); + add_periodic_task(blinky, NULL, 500, false); while (1) { - GPIOC->ODR ^= GPIO_Pin_13; - - // delay - for (int i = 0; i < 1000000; i++); + poll_subsystems(); } } + +void dlnk_rx(SBMP_Datagram *dg) +{ + dbg("Rx dg type %d", dg->type); +} diff --git a/project/main.h b/project/main.h new file mode 100644 index 0000000..ad6719a --- /dev/null +++ b/project/main.h @@ -0,0 +1,18 @@ +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include +#include +#include +#include + +#include + +#define MIN(a,b) ((a)>(b)?(b):(a)) +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +#endif // MAIN_H diff --git a/project/malloc_safe.c b/project/malloc_safe.c new file mode 100644 index 0000000..2f3919c --- /dev/null +++ b/project/malloc_safe.c @@ -0,0 +1,40 @@ +#include "com/debug.h" + +#include +#include +#include + +static void reset_when_done(void) +{ + for (uint32_t i = 0; i < 20000; i++) { + if (com_tx_done(debug_iface)) break; + } + + NVIC_SystemReset(); +} + + +void *malloc_safe_do(size_t size, const char* file, uint32_t line) +{ + void *mem = malloc(size); + if (mem == NULL) { + // malloc failed + error("Malloc failed in file %s on line %"PRIu32, file, line); + reset_when_done(); + } + + return mem; +} + + +void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line) +{ + void *mem = calloc(size, nmemb); + if (mem == NULL) { + // malloc failed + error("Malloc failed in file %s on line %"PRIu32, file, line); + reset_when_done(); + } + + return mem; +} diff --git a/project/malloc_safe.h b/project/malloc_safe.h new file mode 100644 index 0000000..9e6e6dc --- /dev/null +++ b/project/malloc_safe.h @@ -0,0 +1,17 @@ +#ifndef MALLOC_SAFE_H +#define MALLOC_SAFE_H + +/** + * Malloc that prints error and restarts the system on failure. + */ + +#include +#include + +void *malloc_safe_do(size_t size, const char* file, uint32_t line); +void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line); + +#define malloc_s(size) malloc_safe_do(size, __FILE__, __LINE__) +#define calloc_s(nmemb, size) calloc_safe_do(nmemb, size, __FILE__, __LINE__) + +#endif // MALLOC_SAFE_H diff --git a/project/spl_assert.c b/project/spl_assert.c new file mode 100644 index 0000000..1378626 --- /dev/null +++ b/project/spl_assert.c @@ -0,0 +1,24 @@ +#include "main.h" +#include "utils/timebase.h" +#include "com/debug.h" + +#ifdef USE_FULL_ASSERT + +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @return None + */ +void __attribute__((noreturn)) +assert_failed(uint8_t* file, uint32_t line) +{ + error("Assert failed in file %s, line %"PRIu32".", file, line); + + /* Infinite loop */ + while (1); +} + +#endif + diff --git a/project/stm32f10x_it.c b/project/stm32f10x_it.c index d2a19dc..1938e00 100644 --- a/project/stm32f10x_it.c +++ b/project/stm32f10x_it.c @@ -23,6 +23,7 @@ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_it.h" +#include "utils/timebase.h" /** @addtogroup STM32F10x_StdPeriph_Template * @{ @@ -138,6 +139,7 @@ void PendSV_Handler(void) */ void SysTick_Handler(void) { + timebase_ms_cb(); } /******************************************************************************/ diff --git a/project/syscalls.c b/project/syscalls.c new file mode 100644 index 0000000..72cb6be --- /dev/null +++ b/project/syscalls.c @@ -0,0 +1,32 @@ +#include +#include + +register char * stack_ptr asm("sp"); + +caddr_t _sbrk(int incr) +{ + extern char end __asm("end"); + static char *heap_end; + char *prev_heap_end; + + if (heap_end == 0) + heap_end = &end; + + prev_heap_end = heap_end; + if (heap_end + incr > stack_ptr) + { +// write(1, "Heap and stack collision\n", 25); +// abort(); + errno = ENOMEM; + return (caddr_t) -1; + } + + heap_end += incr; + + return (caddr_t) prev_heap_end; +} + + +// Other systcalls are defined in +// - com/com_fileio.c +// - hw_utils/reset.h diff --git a/project/system_stm32f10x.c b/project/system_stm32f10x.c index d6875a3..343f166 100644 --- a/project/system_stm32f10x.c +++ b/project/system_stm32f10x.c @@ -5,19 +5,19 @@ * @version V3.5.0 * @date 08-April-2011 * @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Source File. - * - * 1. This file provides two functions and one global variable to be called from + * + * 1. This file provides two functions and one global variable to be called from * user application: * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier - * factors, AHB/APBx prescalers and Flash settings). - * This function is called at startup just after reset and + * factors, AHB/APBx prescalers and Flash settings). + * This function is called at startup just after reset and * before branch to main program. This call is made inside * the "startup_stm32f10x_xx.s" file. * * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used - * by the user application to setup the SysTick + * by the user application to setup the SysTick * timer or configure other parameters. - * + * * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must * be called whenever the core clock is changed * during program execution. @@ -27,15 +27,15 @@ * configure the system clock before to branch to main program. * * 3. If the system clock source selected by user fails to startup, the SystemInit() - * function will do nothing and HSI still used as system clock source. User can + * function will do nothing and HSI still used as system clock source. User can * add some code to deal with this issue inside the SetSysClock() function. * * 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depedning on - * the product used), refer to "HSE_VALUE" define in "stm32f10x.h" file. + * the product used), refer to "HSE_VALUE" define in "stm32f10x.h" file. * When HSE is used as system clock source, directly or through PLL, and you * are using different crystal you have to adapt the HSE value to your own * configuration. - * + * ****************************************************************************** * @attention * @@ -56,8 +56,8 @@ /** @addtogroup stm32f10x_system * @{ - */ - + */ + /** @addtogroup STM32F10x_System_Private_Includes * @{ */ @@ -82,33 +82,33 @@ /*!< Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after reset the HSI is used as SYSCLK source) - + IMPORTANT NOTE: - ============== + ============== 1. After each device reset the HSI is used as System clock source. 2. Please make sure that the selected System clock doesn't exceed your device's - maximum frequency. - + maximum frequency. + 3. If none of the define below is enabled, the HSI is used as System clock - source. + source. 4. The System clock configuration functions provided within this file assume that: - - For Low, Medium and High density Value line devices an external 8MHz - crystal is used to drive the System clock. - - For Low, Medium and High density devices an external 8MHz crystal is - used to drive the System clock. - - For Connectivity line devices an external 25MHz crystal is used to drive - the System clock. - If you are using different crystal you have to adapt those functions accordingly. - */ - + - For Low, Medium and High density Value line devices an external 8MHz + crystal is used to drive the System clock. + - For Low, Medium and High density devices an external 8MHz crystal is + used to drive the System clock. + - For Connectivity line devices an external 25MHz crystal is used to drive + the System clock. + If you are using different crystal you have to adapt those functions accordingly. + */ + #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) /* #define SYSCLK_FREQ_HSE HSE_VALUE */ - #define SYSCLK_FREQ_24MHz 24000000 +#define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ -/* #define SYSCLK_FREQ_24MHz 24000000 */ +/* #define SYSCLK_FREQ_24MHz 24000000 */ /* #define SYSCLK_FREQ_36MHz 36000000 */ /* #define SYSCLK_FREQ_48MHz 48000000 */ /* #define SYSCLK_FREQ_56MHz 56000000 */ @@ -116,17 +116,17 @@ #endif /*!< Uncomment the following line if you need to use external SRAM mounted - on STM3210E-EVAL board (STM32 High density and XL-density devices) or on - STM32100E-EVAL board (STM32 High-density value line devices) as data memory */ + on STM3210E-EVAL board (STM32 High density and XL-density devices) or on + STM32100E-EVAL board (STM32 High-density value line devices) as data memory */ #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL) /* #define DATA_IN_ExtSRAM */ #endif /*!< Uncomment the following line if you need to relocate your vector Table in - Internal SRAM. */ + Internal SRAM. */ /* #define VECT_TAB_SRAM */ -#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. - This value must be a multiple of 0x200. */ +#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ /** @@ -149,22 +149,22 @@ * Clock Definitions *******************************************************************************/ #ifdef SYSCLK_FREQ_HSE - uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */ +uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */ #elif defined SYSCLK_FREQ_24MHz - uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */ +uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */ #elif defined SYSCLK_FREQ_36MHz - uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */ +uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */ #elif defined SYSCLK_FREQ_48MHz - uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */ +uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */ #elif defined SYSCLK_FREQ_56MHz - uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */ +uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */ #elif defined SYSCLK_FREQ_72MHz - uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */ +uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */ #else /*!< HSI Selected as System Clock source */ - uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */ +uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */ #endif -__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +static __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; /** * @} */ @@ -176,21 +176,21 @@ __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9} static void SetSysClock(void); #ifdef SYSCLK_FREQ_HSE - static void SetSysClockToHSE(void); +static void SetSysClockToHSE(void); #elif defined SYSCLK_FREQ_24MHz - static void SetSysClockTo24(void); +static void SetSysClockTo24(void); #elif defined SYSCLK_FREQ_36MHz - static void SetSysClockTo36(void); +static void SetSysClockTo36(void); #elif defined SYSCLK_FREQ_48MHz - static void SetSysClockTo48(void); +static void SetSysClockTo48(void); #elif defined SYSCLK_FREQ_56MHz - static void SetSysClockTo56(void); +static void SetSysClockTo56(void); #elif defined SYSCLK_FREQ_72MHz - static void SetSysClockTo72(void); +static void SetSysClockTo72(void); #endif #ifdef DATA_IN_ExtSRAM - static void SystemInit_ExtMemCtl(void); +static void SystemInit_ExtMemCtl(void); #endif /* DATA_IN_ExtSRAM */ /** @@ -203,69 +203,69 @@ static void SetSysClock(void); /** * @brief Setup the microcontroller system - * Initialize the Embedded Flash Interface, the PLL and update the + * Initialize the Embedded Flash Interface, the PLL and update the * SystemCoreClock variable. * @note This function should be used only after reset. * @param None * @retval None */ -void SystemInit (void) +void SystemInit(void) { - /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ - /* Set HSION bit */ - RCC->CR |= (uint32_t)0x00000001; + /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001; - /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */ + /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */ #ifndef STM32F10X_CL - RCC->CFGR &= (uint32_t)0xF8FF0000; + RCC->CFGR &= (uint32_t)0xF8FF0000; #else - RCC->CFGR &= (uint32_t)0xF0FF0000; -#endif /* STM32F10X_CL */ - - /* Reset HSEON, CSSON and PLLON bits */ - RCC->CR &= (uint32_t)0xFEF6FFFF; + RCC->CFGR &= (uint32_t)0xF0FF0000; +#endif /* STM32F10X_CL */ - /* Reset HSEBYP bit */ - RCC->CR &= (uint32_t)0xFFFBFFFF; + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFF; - /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ - RCC->CFGR &= (uint32_t)0xFF80FFFF; + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ + RCC->CFGR &= (uint32_t)0xFF80FFFF; #ifdef STM32F10X_CL - /* Reset PLL2ON and PLL3ON bits */ - RCC->CR &= (uint32_t)0xEBFFFFFF; + /* Reset PLL2ON and PLL3ON bits */ + RCC->CR &= (uint32_t)0xEBFFFFFF; - /* Disable all interrupts and clear pending bits */ - RCC->CIR = 0x00FF0000; + /* Disable all interrupts and clear pending bits */ + RCC->CIR = 0x00FF0000; - /* Reset CFGR2 register */ - RCC->CFGR2 = 0x00000000; + /* Reset CFGR2 register */ + RCC->CFGR2 = 0x00000000; #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) - /* Disable all interrupts and clear pending bits */ - RCC->CIR = 0x009F0000; + /* Disable all interrupts and clear pending bits */ + RCC->CIR = 0x009F0000; - /* Reset CFGR2 register */ - RCC->CFGR2 = 0x00000000; + /* Reset CFGR2 register */ + RCC->CFGR2 = 0x00000000; #else - /* Disable all interrupts and clear pending bits */ - RCC->CIR = 0x009F0000; + /* Disable all interrupts and clear pending bits */ + RCC->CIR = 0x009F0000; #endif /* STM32F10X_CL */ - + #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL) - #ifdef DATA_IN_ExtSRAM - SystemInit_ExtMemCtl(); - #endif /* DATA_IN_ExtSRAM */ -#endif +#ifdef DATA_IN_ExtSRAM + SystemInit_ExtMemCtl(); +#endif /* DATA_IN_ExtSRAM */ +#endif - /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */ - /* Configure the Flash Latency cycles and enable prefetch buffer */ - SetSysClock(); + /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */ + /* Configure the Flash Latency cycles and enable prefetch buffer */ + SetSysClock(); #ifdef VECT_TAB_SRAM - SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ #else - SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ -#endif + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ +#endif } /** @@ -273,142 +273,130 @@ void SystemInit (void) * The SystemCoreClock variable contains the core clock (HCLK), it can * be used by the user application to setup the SysTick timer or configure * other parameters. - * + * * @note Each time the core clock (HCLK) changes, this function must be called * to update SystemCoreClock variable value. Otherwise, any configuration - * based on this variable will be incorrect. - * - * @note - The system frequency computed by this function is not the real - * frequency in the chip. It is calculated based on the predefined + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined * constant and the selected clock source: - * + * * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) - * + * * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) - * - * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) * or HSI_VALUE(*) multiplied by the PLL factors. - * + * * (*) HSI_VALUE is a constant defined in stm32f1xx.h file (default value * 8 MHz) but the real value may vary depending on the variations - * in voltage and temperature. - * + * in voltage and temperature. + * * (**) HSE_VALUE is a constant defined in stm32f1xx.h file (default value * 8 MHz or 25 MHz, depedning on the product used), user has to ensure * that HSE_VALUE is same as the real frequency of the crystal used. * Otherwise, this function may have wrong result. - * + * * - The result of this function could be not correct when using fractional * value for HSE crystal. * @param None * @retval None */ -void SystemCoreClockUpdate (void) +void SystemCoreClockUpdate(void) { - uint32_t tmp = 0, pllmull = 0, pllsource = 0; + uint32_t tmp = 0, pllmull = 0, pllsource = 0; #ifdef STM32F10X_CL - uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0; + uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0; #endif /* STM32F10X_CL */ #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) - uint32_t prediv1factor = 0; + uint32_t prediv1factor = 0; #endif /* STM32F10X_LD_VL or STM32F10X_MD_VL or STM32F10X_HD_VL */ - - /* Get SYSCLK source -------------------------------------------------------*/ - tmp = RCC->CFGR & RCC_CFGR_SWS; - - switch (tmp) - { - case 0x00: /* HSI used as system clock */ - SystemCoreClock = HSI_VALUE; - break; - case 0x04: /* HSE used as system clock */ - SystemCoreClock = HSE_VALUE; - break; - case 0x08: /* PLL used as system clock */ - - /* Get PLL clock source and multiplication factor ----------------------*/ - pllmull = RCC->CFGR & RCC_CFGR_PLLMULL; - pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; - -#ifndef STM32F10X_CL - pllmull = ( pllmull >> 18) + 2; - - if (pllsource == 0x00) - { - /* HSI oscillator clock divided by 2 selected as PLL clock entry */ - SystemCoreClock = (HSI_VALUE >> 1) * pllmull; - } - else - { - #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) - prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; - /* HSE oscillator clock selected as PREDIV1 clock entry */ - SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; - #else - /* HSE selected as PLL clock entry */ - if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET) - {/* HSE oscillator clock divided by 2 */ - SystemCoreClock = (HSE_VALUE >> 1) * pllmull; - } - else - { - SystemCoreClock = HSE_VALUE * pllmull; - } - #endif - } + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) { + case 0x00: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock */ + SystemCoreClock = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock */ + + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmull = RCC->CFGR & RCC_CFGR_PLLMULL; + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + +#ifndef STM32F10X_CL + pllmull = (pllmull >> 18) + 2; + + if (pllsource == 0x00) { + /* HSI oscillator clock divided by 2 selected as PLL clock entry */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + } else { +#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) + prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; + /* HSE oscillator clock selected as PREDIV1 clock entry */ + SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; +#else + /* HSE selected as PLL clock entry */ + if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET) { + /* HSE oscillator clock divided by 2 */ + SystemCoreClock = (HSE_VALUE >> 1) * pllmull; + } else { + SystemCoreClock = HSE_VALUE * pllmull; + } +#endif + } #else - pllmull = pllmull >> 18; - - if (pllmull != 0x0D) - { - pllmull += 2; - } - else - { /* PLL multiplication factor = PLL input clock * 6.5 */ - pllmull = 13 / 2; - } - - if (pllsource == 0x00) - { - /* HSI oscillator clock divided by 2 selected as PLL clock entry */ - SystemCoreClock = (HSI_VALUE >> 1) * pllmull; - } - else - {/* PREDIV1 selected as PLL clock entry */ - - /* Get PREDIV1 clock source and division factor */ - prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC; - prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; - - if (prediv1source == 0) - { - /* HSE oscillator clock selected as PREDIV1 clock entry */ - SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; - } - else - {/* PLL2 clock selected as PREDIV1 clock entry */ - - /* Get PREDIV2 division factor and PLL2 multiplication factor */ - prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1; - pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8 ) + 2; - SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull; - } - } -#endif /* STM32F10X_CL */ - break; - - default: - SystemCoreClock = HSI_VALUE; - break; - } - - /* Compute HCLK clock frequency ----------------*/ - /* Get HCLK prescaler */ - tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; - /* HCLK clock frequency */ - SystemCoreClock >>= tmp; + pllmull = pllmull >> 18; + + if (pllmull != 0x0D) { + pllmull += 2; + } else { + /* PLL multiplication factor = PLL input clock * 6.5 */ + pllmull = 13 / 2; + } + + if (pllsource == 0x00) { + /* HSI oscillator clock divided by 2 selected as PLL clock entry */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + } else { + /* PREDIV1 selected as PLL clock entry */ + + /* Get PREDIV1 clock source and division factor */ + prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC; + prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; + + if (prediv1source == 0) { + /* HSE oscillator clock selected as PREDIV1 clock entry */ + SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; + } else { + /* PLL2 clock selected as PREDIV1 clock entry */ + + /* Get PREDIV2 division factor and PLL2 multiplication factor */ + prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1; + pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8) + 2; + SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull; + } + } +#endif /* STM32F10X_CL */ + break; + + default: + SystemCoreClock = HSI_VALUE; + break; + } + + /* Compute HCLK clock frequency ----------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; } /** @@ -419,73 +407,73 @@ void SystemCoreClockUpdate (void) static void SetSysClock(void) { #ifdef SYSCLK_FREQ_HSE - SetSysClockToHSE(); + SetSysClockToHSE(); #elif defined SYSCLK_FREQ_24MHz - SetSysClockTo24(); + SetSysClockTo24(); #elif defined SYSCLK_FREQ_36MHz - SetSysClockTo36(); + SetSysClockTo36(); #elif defined SYSCLK_FREQ_48MHz - SetSysClockTo48(); + SetSysClockTo48(); #elif defined SYSCLK_FREQ_56MHz - SetSysClockTo56(); + SetSysClockTo56(); #elif defined SYSCLK_FREQ_72MHz - SetSysClockTo72(); + SetSysClockTo72(); #endif - - /* If none of the define above is enabled, the HSI is used as System clock - source (default after reset) */ + + /* If none of the define above is enabled, the HSI is used as System clock + source (default after reset) */ } /** - * @brief Setup the external memory controller. Called in startup_stm32f10x.s + * @brief Setup the external memory controller. Called in startup_stm32f10x.s * before jump to __main * @param None * @retval None - */ + */ #ifdef DATA_IN_ExtSRAM /** - * @brief Setup the external memory controller. + * @brief Setup the external memory controller. * Called in startup_stm32f10x_xx.s/.c before jump to main. - * This function configures the external SRAM mounted on STM3210E-EVAL + * This function configures the external SRAM mounted on STM3210E-EVAL * board (STM32 High density devices). This SRAM will be used as program * data memory (including heap and stack). * @param None * @retval None - */ -void SystemInit_ExtMemCtl(void) + */ +void SystemInit_ExtMemCtl(void) { -/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is - required, then adjust the Register Addresses */ - - /* Enable FSMC clock */ - RCC->AHBENR = 0x00000114; - - /* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */ - RCC->APB2ENR = 0x000001E0; - -/* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/ -/*---------------- SRAM Address lines configuration -------------------------*/ -/*---------------- NOE and NWE configuration --------------------------------*/ -/*---------------- NE3 configuration ----------------------------------------*/ -/*---------------- NBL0, NBL1 configuration ---------------------------------*/ - - GPIOD->CRL = 0x44BB44BB; - GPIOD->CRH = 0xBBBBBBBB; - - GPIOE->CRL = 0xB44444BB; - GPIOE->CRH = 0xBBBBBBBB; - - GPIOF->CRL = 0x44BBBBBB; - GPIOF->CRH = 0xBBBB4444; - - GPIOG->CRL = 0x44BBBBBB; - GPIOG->CRH = 0x44444B44; - -/*---------------- FSMC Configuration ---------------------------------------*/ -/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/ - - FSMC_Bank1->BTCR[4] = 0x00001011; - FSMC_Bank1->BTCR[5] = 0x00000200; + /*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is + required, then adjust the Register Addresses */ + + /* Enable FSMC clock */ + RCC->AHBENR = 0x00000114; + + /* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */ + RCC->APB2ENR = 0x000001E0; + + /* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/ + /*---------------- SRAM Address lines configuration -------------------------*/ + /*---------------- NOE and NWE configuration --------------------------------*/ + /*---------------- NE3 configuration ----------------------------------------*/ + /*---------------- NBL0, NBL1 configuration ---------------------------------*/ + + GPIOD->CRL = 0x44BB44BB; + GPIOD->CRH = 0xBBBBBBBB; + + GPIOE->CRL = 0xB44444BB; + GPIOE->CRH = 0xBBBBBBBB; + + GPIOF->CRL = 0x44BBBBBB; + GPIOF->CRH = 0xBBBB4444; + + GPIOG->CRL = 0x44BBBBBB; + GPIOG->CRH = 0x44444B44; + + /*---------------- FSMC Configuration ---------------------------------------*/ + /*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/ + + FSMC_Bank1->BTCR[4] = 0x00001011; + FSMC_Bank1->BTCR[5] = 0x00000200; } #endif /* DATA_IN_ExtSRAM */ @@ -499,78 +487,68 @@ void SystemInit_ExtMemCtl(void) */ static void SetSysClockToHSE(void) { - __IO uint32_t StartUpCounter = 0, HSEStatus = 0; - - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { #if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL - /* Enable Prefetch Buffer */ - FLASH->ACR |= FLASH_ACR_PRFTBE; + /* Enable Prefetch Buffer */ + FLASH->ACR |= FLASH_ACR_PRFTBE; - /* Flash 0 wait state */ - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); + /* Flash 0 wait state */ + FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); #ifndef STM32F10X_CL - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; #else - if (HSE_VALUE <= 24000000) - { - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; - } - else - { - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; - } + if (HSE_VALUE <= 24000000) { + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; + } else { + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; + } #endif /* STM32F10X_CL */ #endif - - /* HCLK = SYSCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; - - /* PCLK1 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; - - /* Select HSE as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSE; - - /* Wait till HSE is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x04) - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } + + /* HCLK = SYSCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; + + /* Select HSE as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSE; + + /* Wait till HSE is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x04) { + } + } else { + /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } } #elif defined SYSCLK_FREQ_24MHz /** - * @brief Sets System clock frequency to 24MHz and configure HCLK, PCLK2 + * @brief Sets System clock frequency to 24MHz and configure HCLK, PCLK2 * and PCLK1 prescalers. * @note This function should be used only after reset. * @param None @@ -578,505 +556,460 @@ static void SetSysClockToHSE(void) */ static void SetSysClockTo24(void) { - __IO uint32_t StartUpCounter = 0, HSEStatus = 0; - - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { -#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL - /* Enable Prefetch Buffer */ - FLASH->ACR |= FLASH_ACR_PRFTBE; - - /* Flash 0 wait state */ - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { +#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL + /* Enable Prefetch Buffer */ + FLASH->ACR |= FLASH_ACR_PRFTBE; + + /* Flash 0 wait state */ + FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; #endif - - /* HCLK = SYSCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; - - /* PCLK1 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; - + + /* HCLK = SYSCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; + #ifdef STM32F10X_CL - /* Configure PLLs ------------------------------------------------------*/ - /* PLL configuration: PLLCLK = PREDIV1 * 6 = 24 MHz */ - RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | - RCC_CFGR_PLLMULL6); - - /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ - /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 10 = 4 MHz */ - RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | - RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); - RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | - RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV10); - - /* Enable PLL2 */ - RCC->CR |= RCC_CR_PLL2ON; - /* Wait till PLL2 is ready */ - while((RCC->CR & RCC_CR_PLL2RDY) == 0) - { - } + /* Configure PLLs ------------------------------------------------------*/ + /* PLL configuration: PLLCLK = PREDIV1 * 6 = 24 MHz */ + RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | + RCC_CFGR_PLLMULL6); + + /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ + /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 10 = 4 MHz */ + RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | + RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); + RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | + RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV10); + + /* Enable PLL2 */ + RCC->CR |= RCC_CR_PLL2ON; + /* Wait till PLL2 is ready */ + while ((RCC->CR & RCC_CR_PLL2RDY) == 0) { + } #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL) - /* PLL configuration: = (HSE / 2) * 6 = 24 MHz */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1_Div2 | RCC_CFGR_PLLMULL6); -#else - /* PLL configuration: = (HSE / 2) * 6 = 24 MHz */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL6); + /* PLL configuration: = (HSE / 2) * 6 = 24 MHz */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1_Div2 | RCC_CFGR_PLLMULL6); +#else + /* PLL configuration: = (HSE / 2) * 6 = 24 MHz */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL6); #endif /* STM32F10X_CL */ - /* Enable PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Select PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; - - /* Wait till PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while ((RCC->CR & RCC_CR_PLLRDY) == 0) { + } + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { + } + } else { + /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } } #elif defined SYSCLK_FREQ_36MHz /** - * @brief Sets System clock frequency to 36MHz and configure HCLK, PCLK2 - * and PCLK1 prescalers. + * @brief Sets System clock frequency to 36MHz and configure HCLK, PCLK2 + * and PCLK1 prescalers. * @note This function should be used only after reset. * @param None * @retval None */ static void SetSysClockTo36(void) { - __IO uint32_t StartUpCounter = 0, HSEStatus = 0; - - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { - /* Enable Prefetch Buffer */ - FLASH->ACR |= FLASH_ACR_PRFTBE; - - /* Flash 1 wait state */ - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; - - /* HCLK = SYSCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; - - /* PCLK1 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; - + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { + /* Enable Prefetch Buffer */ + FLASH->ACR |= FLASH_ACR_PRFTBE; + + /* Flash 1 wait state */ + FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; + + /* HCLK = SYSCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1; + #ifdef STM32F10X_CL - /* Configure PLLs ------------------------------------------------------*/ - - /* PLL configuration: PLLCLK = PREDIV1 * 9 = 36 MHz */ - RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | - RCC_CFGR_PLLMULL9); - - /*!< PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ - /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 10 = 4 MHz */ - - RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | - RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); - RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | - RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV10); - - /* Enable PLL2 */ - RCC->CR |= RCC_CR_PLL2ON; - /* Wait till PLL2 is ready */ - while((RCC->CR & RCC_CR_PLL2RDY) == 0) - { - } - -#else - /* PLL configuration: PLLCLK = (HSE / 2) * 9 = 36 MHz */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL9); + /* Configure PLLs ------------------------------------------------------*/ + + /* PLL configuration: PLLCLK = PREDIV1 * 9 = 36 MHz */ + RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | + RCC_CFGR_PLLMULL9); + + /*!< PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ + /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 10 = 4 MHz */ + + RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | + RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); + RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | + RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV10); + + /* Enable PLL2 */ + RCC->CR |= RCC_CR_PLL2ON; + /* Wait till PLL2 is ready */ + while ((RCC->CR & RCC_CR_PLL2RDY) == 0) { + } + +#else + /* PLL configuration: PLLCLK = (HSE / 2) * 9 = 36 MHz */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL9); #endif /* STM32F10X_CL */ - /* Enable PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Select PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; - - /* Wait till PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while ((RCC->CR & RCC_CR_PLLRDY) == 0) { + } + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { + } + } else { + /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } } #elif defined SYSCLK_FREQ_48MHz /** - * @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 - * and PCLK1 prescalers. + * @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 + * and PCLK1 prescalers. * @note This function should be used only after reset. * @param None * @retval None */ static void SetSysClockTo48(void) { - __IO uint32_t StartUpCounter = 0, HSEStatus = 0; - - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { - /* Enable Prefetch Buffer */ - FLASH->ACR |= FLASH_ACR_PRFTBE; - - /* Flash 1 wait state */ - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; - - /* HCLK = SYSCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; - - /* PCLK1 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; - + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { + /* Enable Prefetch Buffer */ + FLASH->ACR |= FLASH_ACR_PRFTBE; + + /* Flash 1 wait state */ + FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; + + /* HCLK = SYSCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; + #ifdef STM32F10X_CL - /* Configure PLLs ------------------------------------------------------*/ - /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ - /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */ - - RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | - RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); - RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | - RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); - - /* Enable PLL2 */ - RCC->CR |= RCC_CR_PLL2ON; - /* Wait till PLL2 is ready */ - while((RCC->CR & RCC_CR_PLL2RDY) == 0) - { - } - - - /* PLL configuration: PLLCLK = PREDIV1 * 6 = 48 MHz */ - RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | - RCC_CFGR_PLLMULL6); -#else - /* PLL configuration: PLLCLK = HSE * 6 = 48 MHz */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); + /* Configure PLLs ------------------------------------------------------*/ + /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ + /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */ + + RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | + RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); + RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | + RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); + + /* Enable PLL2 */ + RCC->CR |= RCC_CR_PLL2ON; + /* Wait till PLL2 is ready */ + while ((RCC->CR & RCC_CR_PLL2RDY) == 0) { + } + + + /* PLL configuration: PLLCLK = PREDIV1 * 6 = 48 MHz */ + RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | + RCC_CFGR_PLLMULL6); +#else + /* PLL configuration: PLLCLK = HSE * 6 = 48 MHz */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); #endif /* STM32F10X_CL */ - /* Enable PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Select PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; - - /* Wait till PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while ((RCC->CR & RCC_CR_PLLRDY) == 0) { + } + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { + } + } else { + /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } } #elif defined SYSCLK_FREQ_56MHz /** - * @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 - * and PCLK1 prescalers. + * @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 + * and PCLK1 prescalers. * @note This function should be used only after reset. * @param None * @retval None */ static void SetSysClockTo56(void) { - __IO uint32_t StartUpCounter = 0, HSEStatus = 0; - - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { - /* Enable Prefetch Buffer */ - FLASH->ACR |= FLASH_ACR_PRFTBE; - - /* Flash 2 wait state */ - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; - - /* HCLK = SYSCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; - - /* PCLK1 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { + /* Enable Prefetch Buffer */ + FLASH->ACR |= FLASH_ACR_PRFTBE; + + /* Flash 2 wait state */ + FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; + + /* HCLK = SYSCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; #ifdef STM32F10X_CL - /* Configure PLLs ------------------------------------------------------*/ - /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ - /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */ - - RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | - RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); - RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | - RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); - - /* Enable PLL2 */ - RCC->CR |= RCC_CR_PLL2ON; - /* Wait till PLL2 is ready */ - while((RCC->CR & RCC_CR_PLL2RDY) == 0) - { - } - - - /* PLL configuration: PLLCLK = PREDIV1 * 7 = 56 MHz */ - RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | - RCC_CFGR_PLLMULL7); -#else - /* PLL configuration: PLLCLK = HSE * 7 = 56 MHz */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL7); + /* Configure PLLs ------------------------------------------------------*/ + /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ + /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */ + + RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | + RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); + RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | + RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); + + /* Enable PLL2 */ + RCC->CR |= RCC_CR_PLL2ON; + /* Wait till PLL2 is ready */ + while ((RCC->CR & RCC_CR_PLL2RDY) == 0) { + } + + + /* PLL configuration: PLLCLK = PREDIV1 * 7 = 56 MHz */ + RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | + RCC_CFGR_PLLMULL7); +#else + /* PLL configuration: PLLCLK = HSE * 7 = 56 MHz */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL7); #endif /* STM32F10X_CL */ - /* Enable PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Select PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; - - /* Wait till PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while ((RCC->CR & RCC_CR_PLLRDY) == 0) { + } + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { + } + } else { + /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } } #elif defined SYSCLK_FREQ_72MHz /** - * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 - * and PCLK1 prescalers. + * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 + * and PCLK1 prescalers. * @note This function should be used only after reset. * @param None * @retval None */ static void SetSysClockTo72(void) { - __IO uint32_t StartUpCounter = 0, HSEStatus = 0; - - /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ - /* Enable HSE */ - RCC->CR |= ((uint32_t)RCC_CR_HSEON); - - /* Wait till HSE is ready and if Time out is reached exit */ - do - { - HSEStatus = RCC->CR & RCC_CR_HSERDY; - StartUpCounter++; - } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); - - if ((RCC->CR & RCC_CR_HSERDY) != RESET) - { - HSEStatus = (uint32_t)0x01; - } - else - { - HSEStatus = (uint32_t)0x00; - } - - if (HSEStatus == (uint32_t)0x01) - { - /* Enable Prefetch Buffer */ - FLASH->ACR |= FLASH_ACR_PRFTBE; - - /* Flash 2 wait state */ - FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); - FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; - - - /* HCLK = SYSCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; - - /* PCLK2 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; - - /* PCLK1 = HCLK */ - RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { + /* Enable Prefetch Buffer */ + FLASH->ACR |= FLASH_ACR_PRFTBE; + + /* Flash 2 wait state */ + FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); + FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; + + + /* HCLK = SYSCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; #ifdef STM32F10X_CL - /* Configure PLLs ------------------------------------------------------*/ - /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ - /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */ - - RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | - RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); - RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | - RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); - - /* Enable PLL2 */ - RCC->CR |= RCC_CR_PLL2ON; - /* Wait till PLL2 is ready */ - while((RCC->CR & RCC_CR_PLL2RDY) == 0) - { - } - - - /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ - RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | - RCC_CFGR_PLLMULL9); -#else - /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | - RCC_CFGR_PLLMULL)); - RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); + /* Configure PLLs ------------------------------------------------------*/ + /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */ + /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */ + + RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | + RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); + RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 | + RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); + + /* Enable PLL2 */ + RCC->CR |= RCC_CR_PLL2ON; + /* Wait till PLL2 is ready */ + while ((RCC->CR & RCC_CR_PLL2RDY) == 0) { + } + + + /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ + RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | + RCC_CFGR_PLLMULL9); +#else + /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | + RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); #endif /* STM32F10X_CL */ - /* Enable PLL */ - RCC->CR |= RCC_CR_PLLON; - - /* Wait till PLL is ready */ - while((RCC->CR & RCC_CR_PLLRDY) == 0) - { - } - - /* Select PLL as system clock source */ - RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); - RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; - - /* Wait till PLL is used as system clock source */ - while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) - { - } - } - else - { /* If HSE fails to start-up, the application will have wrong clock - configuration. User can add here some code to deal with this error */ - } + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while ((RCC->CR & RCC_CR_PLLRDY) == 0) { + } + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { + } + } else { + /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } } #endif @@ -1087,8 +1020,8 @@ static void SetSysClockTo72(void) /** * @} */ - + /** * @} - */ + */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/project/utils/circbuf.c b/project/utils/circbuf.c new file mode 100644 index 0000000..6d0ed51 --- /dev/null +++ b/project/utils/circbuf.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include + +#include "circbuf.h" +#include "malloc_safe.h" + +// --- Circbuf data structure ---- + +/** Offset in void* buffer */ +#define PV_OFFS(pvBuf, elem_size, index) ((uint8_t*)(pvBuf) + ((elem_size)*(index))) + + +// Instance structure +struct circbuf_struct { + void *buf; + size_t elem_size; + size_t cap; + size_t lr; // last read pos + size_t nw; // next write pos +}; + + +/** + * @brief Write data to a CircBuf slot + * @param cb : circbuf + * @param index : slot index + * @param source : data source + */ +static void write_buffer(CircBuf *cb, size_t index, const void *source) +{ + memcpy(PV_OFFS(cb->buf, cb->elem_size, index), source, cb->elem_size); +} + + +/** + * @brief Copy data from a CircBuf slot to a buffer + * @param cb : circbuf + * @param index : slot index + * @param dest : destination buffer + */ +static void read_buffer(const CircBuf *cb, size_t index, void *dest) +{ + memcpy(dest, PV_OFFS(cb->buf, cb->elem_size, index), cb->elem_size); +} + + +/** Create a cbuf */ +CircBuf *cbuf_create(size_t capacity, size_t elem_size) +{ + // add one, because one is always unused. + capacity++; + + // Allocate the structure + CircBuf *cb = malloc_s(sizeof(CircBuf)); + + // allocate the buffer + cb->buf = malloc_s(capacity * elem_size); + + // set capacity, clear state + cb->elem_size = elem_size; + cb->cap = capacity; + cbuf_clear(cb); + + return cb; +} + + +/** Release cbuf memory */ +void cbuf_destroy(CircBuf *cb) +{ + if (cb != NULL) { + if (cb->buf != NULL) { + free(cb->buf); + } + + free(cb); + } +} + + +/** Check if cbuf is full */ +bool cbuf_full(const CircBuf *cb) +{ + if (cb == NULL) return false; + + return (cb->lr == cb->nw); +} + + +/** Check if cbuf is empty */ +bool cbuf_empty(const CircBuf *cb) +{ + if (cb == NULL) return true; + + return ((cb->lr + 1) % cb->cap) == cb->nw; +} + + +/** Write a byte to the buffer, if space left */ +bool cbuf_append(CircBuf *cb, const void *source) +{ + if (cb == NULL) return false; + if (source == NULL) return false; + if (cbuf_full(cb)) return false; + + write_buffer(cb, cb->nw, source); + + // increment + cb->nw++; + if (cb->nw == cb->cap) cb->nw = 0; + + return true; +} + + +/** Push value to the end, like a stack. */ +bool cbuf_push(CircBuf *cb, const void *source) +{ + if (cb == NULL) return false; + if (source == NULL) return false; + if (cbuf_full(cb)) return false; + + write_buffer(cb, cb->lr, source); + + // move lr back + if (cb->lr == 0) { + cb->lr = cb->cap - 1; // wrap to the end + } else { + cb->lr--; + } + + return true; +} + + +/** Read one byte, if not empty. */ +bool cbuf_pop(CircBuf *cb, void *dest) +{ + if (cb == NULL || dest == NULL) return false; + if (cbuf_empty(cb)) return false; + + // increment + cb->lr++; + if (cb->lr == cb->cap) cb->lr = 0; + + read_buffer(cb, cb->lr, dest); + + return true; +} + + +/** Clear a cbuf */ +void cbuf_clear(CircBuf *cb) +{ + if (cb == NULL) return; + + cb->lr = cb->cap - 1; + cb->nw = 0; +} diff --git a/project/utils/circbuf.h b/project/utils/circbuf.h new file mode 100644 index 0000000..4e73f59 --- /dev/null +++ b/project/utils/circbuf.h @@ -0,0 +1,93 @@ +/** + * @file circbuf.h + * @author Ondřej Hruška, 2016 + * + * Circular buffer / queue / stack. + * Slots are pre-allocated, values are copied into the buffer. + * + * The buffer may be used as a stack, event queue or a simple buffer. + * + * ------------------------------------- + * + * NW LR + * append -> [][][][] -> pop + * <- push + * + * NW - next write pointer (stack base) + * LR - last read position (stack top) + * + * ------------------------------------- + * + * MIT license + */ + +#pragma once + +#include +#include +#include + + +typedef struct circbuf_struct CircBuf; + + +/** + * @brief Initialize a circular buffer. The buffer is malloc'd. + * @param capacity : buffer capacity + * @param elem_size : size of one element + * @return pointer to the buffer instance + */ +CircBuf *cbuf_create(size_t capacity, size_t elem_size); + + +/** + * @brief Destroy a buffer, freeing used memory. + * + * @attention + * If the buffer items have malloc'd members, you have + * to free them manually to avoid a memory leak. + * + * @param cb : buffer + */ +void cbuf_destroy(CircBuf *cb); + + +/** Test for full buffer */ +bool cbuf_full(const CircBuf *cb); + + +/** Test for empty buffer */ +bool cbuf_empty(const CircBuf *cb); + + +/** + * @brief Append a value to the buffer (FIFO) + * @param cb : buffer + * @param source : pointer to a value (will be copied) + * @return success + */ +bool cbuf_append(CircBuf *cb, const void *source); + + +/** + * @brief Push a value into the circbuf (LIFO). + * + * @param cb : buffer + * @param source : pointer to a value (will be copied) + * @return success + */ +bool cbuf_push(CircBuf *cb, const void *source); + + +/** + * @brief Read a value from the buffer, return susccess. + * + * @param cb : buffer + * @param dest : read destionation. If NULL, value is discarded. + * @return success + */ +bool cbuf_pop(CircBuf *cb, void *dest); + + +/** @brief Remove all data from buffer */ +void cbuf_clear(CircBuf *cb); diff --git a/project/utils/debounce.c b/project/utils/debounce.c new file mode 100644 index 0000000..0834d0a --- /dev/null +++ b/project/utils/debounce.c @@ -0,0 +1,171 @@ +#include "main.h" +#include "debounce.h" +#include "timebase.h" +#include "malloc_safe.h" + +// ms debounce time + +#define DEF_DEBO_TIME 20 + +typedef struct { + GPIO_TypeDef *GPIOx; ///< GPIO base + uint16_t pin; ///< bit mask + bool state; ///< current state + bool invert; ///< invert pin + debo_id_t id; ///< pin ID + ms_time_t debo_time; ///< debouncing time (ms) + ms_time_t counter_0; ///< counter for falling edge (ms) + ms_time_t counter_1; ///< counter for rising edge (ms) + void (*falling_cb)(void); + void (*rising_cb)(void); +} debo_slot_t; + + +/** Number of allocated slots */ +static size_t debo_slot_count = 0; + +/** Slots array */ +static debo_slot_t *debo_slots; + +/** Next free pin ID for make_id() */ +static debo_id_t next_pin_id = 1; + + +/** + * @brief Get a valid free pin ID for a new entry. + * @return the ID. + */ +static debo_id_t make_id(void) +{ + debo_id_t id = next_pin_id++; + + // make sure no task is given PID 0 + if (next_pin_id == DEBO_PIN_NONE) { + next_pin_id++; + } + + return id; +} + + +/** Init the debouncer */ +void debounce_init(size_t slot_count) +{ + debo_slots = calloc_s(slot_count, sizeof(debo_slot_t)); + debo_slot_count = slot_count; +} + + +/** Register a pin */ +debo_id_t debo_register_pin(debo_init_t *init) +{ + assert_param(IS_GPIO_ALL_PERIPH(init->GPIOx)); + assert_param(IS_GET_GPIO_PIN(init->pin)); + + for (size_t i = 0; i < debo_slot_count; i++) { + debo_slot_t *slot = &debo_slots[i]; + + if (slot->id != DEBO_PIN_NONE) continue; // slot is used + + slot->GPIOx = init->GPIOx; + slot->pin = init->pin; + slot->falling_cb = init->falling_cb; + slot->rising_cb = init->rising_cb; + slot->invert = init->invert; + slot->counter_0 = 0; + slot->counter_1 = 0; + slot->debo_time = (init->debo_time == 0) ? DEF_DEBO_TIME : init->debo_time; + + bool state = GPIO_ReadInputDataBit(slot->GPIOx, slot->pin); + if (slot->invert) state = !state; + slot->state = state; + + slot->id = make_id(); + + return slot->id; + } + + return DEBO_PIN_NONE; +} + + +/** Callback that must be called every 1 ms */ +void debo_periodic_task(void) +{ + for (size_t i = 0; i < debo_slot_count; i++) { + debo_slot_t *slot = &debo_slots[i]; + if (slot->id == DEBO_PIN_NONE) continue; // unused + + bool state = GPIO_ReadInputDataBit(slot->GPIOx, slot->pin); + if (slot->invert) state = !state; + + if (slot->state != state) { + if (state == 0) { + // falling + + if (slot->counter_0++ == slot->debo_time) { + slot->state = 0; + + if (slot->falling_cb != NULL) { + slot->falling_cb(); + } + } + } else { + // rising + + if (slot->counter_1++ == slot->debo_time) { + slot->state = 1; + + if (slot->rising_cb != NULL) { + slot->rising_cb(); + } + } + } + } else { + // reset counters + slot->counter_0 = 0; + slot->counter_1 = 0; + } + } +} + + +/** + * @brief Check if a pin is high + * @param pin_id : Slot ID + * @return true if the pin is registered and is HIGH + */ +bool debo_pin_state(debo_id_t pin_id) +{ + if (pin_id == DEBO_PIN_NONE) return false; + + for (size_t i = 0; i < debo_slot_count; i++) { + debo_slot_t *slot = &debo_slots[i]; + if (slot->id != pin_id) continue; + + return slot->state; + } + + return false; +} + + +/** + * @brief Remove a pin entry from the debouncer. + * @param pin_id : Slot ID + * @return true if task found & removed. + */ +bool debo_remove_pin(debo_id_t pin_id) +{ + if (pin_id == DEBO_PIN_NONE) return false; + + for (size_t i = 0; i < debo_slot_count; i++) { + debo_slot_t *slot = &debo_slots[i]; + if (slot->id != pin_id) continue; + + slot->id = DEBO_PIN_NONE; + return true; + } + + return false; +} diff --git a/project/utils/debounce.h b/project/utils/debounce.h new file mode 100644 index 0000000..ecc17e9 --- /dev/null +++ b/project/utils/debounce.h @@ -0,0 +1,62 @@ +#pragma once +#include "main.h" +#include "utils/timebase.h" + +// Debouncer requires that you setup SysTick first. + +/** Debounced pin ID - used for state readout */ +typedef uint32_t debo_id_t; + +/** debo_id_t indicating unused slot */ +#define DEBO_PIN_NONE 0 + + +/** + * @brief Initialize the debouncer. + * + * You have to also register the periodic task to timebase. + * + * @param pin_count : number of pin slots to allocate + */ +void debounce_init(size_t pin_count); + + +/** + * @brief 1 ms periodic callback for debouncer. Must be registered to timebase. + */ +void debo_periodic_task(void); + + +typedef struct { + GPIO_TypeDef *GPIOx; ///< GPIO base + uint16_t pin; ///< pin mask + ms_time_t debo_time; ///< debounce time in ms, 0 = default (20 ms) + bool invert; ///< invert value read from GPIO (button to ground) + void (*rising_cb)(void); ///< callback when the pin goes HIGH + void (*falling_cb)(void); ///< callback when the pin goes LOW +} debo_init_t; + + +/** + * @brief Add a pin for debouncing. + * + * The pin state will be checked with the configured hysteresis + * and callbacks will be called when a state change is detected. + */ +debo_id_t debo_register_pin(debo_init_t *init_struct); + + +/** + * @brief Check if a pin is high + * @param pin_id : Slot ID + * @return true if the pin is registered and is HIGH + */ +bool debo_pin_state(debo_id_t pin_id); + + +/** + * @brief Remove a pin entry from the debouncer. + * @param pin_id : Slot ID + * @return true if task found & removed. + */ +bool debo_remove_pin(debo_id_t pin_id); diff --git a/project/utils/matcher.c b/project/utils/matcher.c new file mode 100644 index 0000000..558d3c2 --- /dev/null +++ b/project/utils/matcher.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +#include "matcher.h" + +void matcher_reset(matcher_t *m) +{ + m->cursor = 0; +} + + +/** Handle incoming char. Returns true if this char completed the match. */ +bool matcher_test(matcher_t * m, uint8_t b) +{ + // If mismatch, rewind (and check at 0) + if (m->pattern[m->cursor] != b) { + m->cursor = 0; + } + + // Check for match + if (m->pattern[m->cursor] == b) { + // Good char + m->cursor++; + if (m->pattern[m->cursor] == 0) { // end of pattern + m->cursor = 0; // rewind + return true; // indicate success + } + } + + return false; +} diff --git a/project/utils/matcher.h b/project/utils/matcher.h new file mode 100644 index 0000000..4d71468 --- /dev/null +++ b/project/utils/matcher.h @@ -0,0 +1,39 @@ +/** + * @file matcher.h + * @author Ondřej Hruška, 2016 + * + * String matching utility. + * + * Matcher can be used for detecting a pattern in a stream of characters. + * With each incoming character, call matcher_test(). + * + * It will return true if the character completed a match. + * + * MIT license + */ + +#pragma once + +#include +#include +#include + +typedef struct { + const char *pattern; + size_t cursor; +} matcher_t; + + +/** reset match progress */ +void matcher_reset(matcher_t *m); + + +/** + * Consume an incoming character. + * If this char was the last char of the pattern, returns true and resets matcher. + * + * If the char is not in the pattern, resets matcher. + * + * @returns true if the char concluded the expected pattern. + */ +bool matcher_test(matcher_t * mb, uint8_t b); diff --git a/project/utils/meanbuf.c b/project/utils/meanbuf.c new file mode 100644 index 0000000..a9dd5f8 --- /dev/null +++ b/project/utils/meanbuf.c @@ -0,0 +1,70 @@ +#include +#include + +#include "meanbuf.h" +#include "malloc_safe.h" + + +struct meanbuf_struct { + float * buf; // buffer (allocated at init) + size_t cap; // capacity + size_t nw; // next write index + float mean; // updated on write +}; + + +/** Init a buffer */ +MeanBuf *meanbuf_create(size_t size) +{ + MeanBuf *mb = malloc_s(sizeof(MeanBuf)); + + if (size < 1) size = 1; + + mb->buf = calloc_s(size, sizeof(float)); // calloc, so it starts with zeros. + mb->cap = size; + mb->nw = 0; + mb->mean = 0; + + // clean buffer + for (uint16_t i = 0; i < size; i++) { + mb->buf[i] = 0; + } + + return mb; +} + + +void meanbuf_destroy(MeanBuf *mb) +{ + if (mb == NULL) return; + + if (mb->buf != NULL) { + free(mb->buf); + } + + free(mb); +} + + +/** Add a value to the buffer. Returns current mean. */ +float meanbuf_add(MeanBuf *mb, float f) +{ + // add sample + mb->buf[mb->nw++] = f; + if (mb->nw == mb->cap) mb->nw = 0; + + // calculate average + float acc = 0; + for (size_t i = 0; i < mb->cap; i++) { + acc += mb->buf[i]; + } + + acc /= mb->cap; + + return mb->mean = acc; +} + +float meanbuf_current(MeanBuf *mb) +{ + return mb->mean; +} diff --git a/project/utils/meanbuf.h b/project/utils/meanbuf.h new file mode 100644 index 0000000..4d8f690 --- /dev/null +++ b/project/utils/meanbuf.h @@ -0,0 +1,33 @@ +/** + * @file meanbuf.h + * @author Ondřej Hruška, 2016 + * + * Averaging float buffer. (You can adjust it to use doubles, if you prefer.) + * + * The meanbuf_create() function allocates a buffer. + * + * You can then call meanbuf_add() to add a new value into the buffer (and remove the oldest). + * This function returns the current average value. + * + * This buffer can be used for signal smoothing (such as from an analogue sensor). + * + * MIT license + */ + + +#pragma once +#include +#include + +typedef struct meanbuf_struct MeanBuf; + +/** Init a buffer */ +MeanBuf *meanbuf_create(size_t size); + +/** Deinit a buffer (free buffer array) */ +void meanbuf_destroy(MeanBuf *mb); + +/** Add a value to the buffer. Returns current mean. */ +float meanbuf_add(MeanBuf *mb, float f); + +float meanbuf_current(MeanBuf *bm); diff --git a/project/utils/minmax.h b/project/utils/minmax.h new file mode 100644 index 0000000..8593abd --- /dev/null +++ b/project/utils/minmax.h @@ -0,0 +1,4 @@ +#pragma once + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) diff --git a/project/utils/str_utils.c b/project/utils/str_utils.c new file mode 100644 index 0000000..25b6453 --- /dev/null +++ b/project/utils/str_utils.c @@ -0,0 +1,286 @@ +#include "str_utils.h" +#include "matcher.h" +#include "malloc_safe.h" + +#include +#include +#include +#include + +// Lot of this stuff is actually not needed anymore, +// it was written for the ESP AT firmware, which is no longer used. + +/** + * Escape a char. + * @returns what to put after backslash, or '\0' for no escape. + */ +static char escape_char(char c) +{ + switch (c) { + case '\r': return 'r'; + case '\n': return 'n'; + case '\t': return 't'; + case '\\': return '\\'; + default: return 0; + } +} + + +/** + * Escape string in place + */ +void str_escape_ip(char * buf, size_t buf_len) +{ + size_t i = 0; + + // string length (updated when escapes are performed) + size_t slen = strlen(buf); + + for (; i < buf_len - 1 && buf[i] != 0; i++) { + char replace = escape_char(buf[i]); + + // Escape, shift trailing chars + if (replace != 0) { + if (i >= buf_len - 2) { + break; // discard the char, escape wouldn't fit. + } + + // (could be faster if moved starting at the end) + + char m = buf[i + 1]; // remember next char + + buf[i] = '\\'; + buf[i + 1] = replace; + + slen++; // account for the added backslash + + // shift trailing chars + for (size_t j = i + 2; j <= slen; j++) { + char n = buf[j]; + buf[j] = m; + m = n; + } + + i++; // skip the insterted slash + } + } + + buf[i] = 0; // add terminator (in case end of string was reached) +} + + +void str_escape(char *dest, const char *src, size_t dest_len) +{ + size_t di = 0, si = 0; + + for (; src[si] != 0 && di < dest_len - 1; si++) { + char orig = src[si]; + char replace = escape_char(orig); + + if (replace == 0) { + dest[di++] = orig; + } else { + if (di >= dest_len - 2) { + break; // out of space + } + + dest[di++] = '\\'; + dest[di++] = replace; + } + } + + dest[di] = 0; // append terminator +} + + + +int32_t strpos(const char *haystack, const char *needle) +{ + const char *p = strstr(haystack, needle); + if (p) return (p - haystack); + return -1; // Not found = -1. +} + + +int32_t strpos_upto(const char *haystack, const char *needle, size_t limit) +{ + if (limit <= 0) return strpos(haystack, needle); + + matcher_t m = {needle, 0}; + char c; + + for (size_t i = 0; i < limit; i++, haystack++) { + c = *haystack; + if (c == 0) break; + + if (matcher_test(&m, (uint8_t)c)) { + return i - strlen(needle) + 1; // match occured on the last needle char + } + } + + return -1; +} + + +int32_t strpos_upto_match(const char *haystack, const char *needle, const char *endmatch) +{ + if (endmatch == NULL) return strpos(haystack, needle); + + matcher_t matcher_needle = {needle, 0}; + matcher_t matcher_end = {endmatch, 0}; + char c; + + for (int i = 0;; i++, haystack++) { + c = *haystack; + if (c == 0) break; + + // match + if (matcher_test(&matcher_needle, (uint8_t)c)) { + return i - strlen(needle) + 1; // match occured on the last needle char + } + + // end + if (matcher_test(&matcher_end, (uint8_t)c)) { + return -1; + } + } + + return -1; +} + +size_t str_copy(char * dest, const char *src) +{ + char c; + size_t i = 0; + while ((c = *src++) != 0) { + *dest++ = c; + i++; + } + return i; +} + + +/** + * Decode URL-encoded string in place. + */ +void urldecode_ip(char *str) +{ + unsigned int x; + + for (size_t i = 0; str[i] != 0; i++) { + char c = str[i]; + if (c == '+') { + str[i] = ' '; + } else if (c == '%') { + // decode the byte + sscanf(&str[i + 1], "%02x", &x); + str[i] = (char)x; + + // shift following chars + for (size_t a = i + 3, b = i + 1;; a++, b++) { + str[b] = str[a]; // move + if (str[a] == 0) break; + } + } + } +} + + +/** + * url-decode string, put output in a buffer. + */ +void urldecode(char *dest, const char *src) +{ + unsigned int x; + size_t si = 0, di = 0; + + for (; src[si] != 0; si++) { + char c = src[si]; + if (c == '+') { + dest[di++] = ' '; + } else if (c == '%') { + // decode the byte + sscanf(&src[si + 1], "%02x", &x); + dest[di++] = (char)x; + + si += 2; + } else { + dest[di++] = c; + } + } + + // add terminator + dest[di] = 0; +} + + + +/** + * url-decode string, put output in a buffer. + * Limit operation to N chars in input string + */ +void urldecode_n(char *dest, const char *src, size_t count) +{ + unsigned int x; + size_t si = 0, di = 0; + + for (; src[si] != 0 && si < count; si++) { + char c = src[si]; + if (c == '+') { + dest[di++] = ' '; + } else if (c == '%') { + // decode the byte + sscanf(&src[si + 1], "%02x", &x); + dest[di++] = (char)x; + + si += 2; + } else { + dest[di++] = c; + } + } + + // add terminator + dest[di] = 0; +} + + +bool get_query_value(char *buffer, const char *querystring, const char *key, size_t buf_len) +{ + bool retval; + + size_t qs_len = strlen(querystring); + + char *ptrn = malloc_s(strlen(key) + 3); // &key=\0 + sprintf(ptrn, "&%s=", key); + matcher_t m = {ptrn, 1}; // pretend ampersand was already matched + + for (size_t i = 0; i < qs_len; i++) { + char c = querystring[i]; + if (matcher_test(&m, (uint8_t)c)) { + // found the match + i++; // advance past the equals sign + + size_t seg_end = i; + while (seg_end < qs_len && querystring[seg_end] != '&') { + seg_end++; + } + + if (seg_end - i > buf_len) seg_end = i + buf_len; + + if (seg_end == i) { + buffer[0] = 0; // strncpy behaves strange with length 0 + } else { + urldecode_n(buffer, querystring + i, seg_end - i); + } + + retval = true; + goto done; + } + } + + // not found + retval = false; +done: + free(ptrn); + return retval; +} diff --git a/project/utils/str_utils.h b/project/utils/str_utils.h new file mode 100644 index 0000000..79a2e4b --- /dev/null +++ b/project/utils/str_utils.h @@ -0,0 +1,75 @@ +#pragma once +#include +#include +#include + +#define streq(a, b) (strcmp((a), (b)) == 0) +#define streqi(a, b) (strcasecmp((a), (b)) == 0) + +/** + * Escape string, storing result in a buffer. + */ +void str_escape(char *dest, const char *src, size_t dest_len); + + +/** + * Escape special chars in a string, IN PLACE. + * + * If string is too long after escaping, last chars are dropped. + * + * @param buf the buffer, containing 0-terminated string. + * @param buflen buffer length + */ +void str_escape_ip(char *buf, size_t buf_len); + + +/** + * Get position of needle in a haystack. + * -1 if not found. + */ +int32_t strpos(const char *haystack, const char *needle); + + +/** + * Find substring position, ending at index 'limit'. + * Limit <= 0 means no limit. + * Returns index of the first character of needle in haystack. + */ +int32_t strpos_upto(const char *haystack, const char *needle, size_t limit); + + +/** + * Find substring position, ending when endmatch is encountered. (Substring within endmatch *can* be reported). + * Returns index of the first character of needle in haystack. + */ +int32_t strpos_upto_match(const char *haystack, const char *needle, const char *endmatch); + + +/** + * Like sprintf, except without formatting + */ +size_t str_copy(char * dest, const char *src); + + +/** + * Decode url-encoded string, store result in dest. + */ +void urldecode(char *dest, const char *src); + + +/** + * Decode url-encoded string in place. + */ +void urldecode_ip(char *str); + + +/** + * Retrieve & url-decode a query string value by name. + * + * @param buffer - target buffer + * @param querystring - string (foo=bar&baz=moi) + * @param key - key to retrieve + * @param buf_len - length of the target buffer + * @return true if found. + */ +bool get_query_value(char *buffer, const char *querystring, const char *key, size_t buf_len); diff --git a/project/utils/timebase.c b/project/utils/timebase.c new file mode 100644 index 0000000..f18a06b --- /dev/null +++ b/project/utils/timebase.c @@ -0,0 +1,331 @@ +#include "timebase.h" +#include "bus/event_queue.h" +#include "com/debug.h" +#include "malloc_safe.h" + +// Time base +static volatile ms_time_t SystemTime_ms = 0; + + +typedef struct { + /** User callback with arg */ + void (*callback)(void *); + /** Arg for the arg callback */ + void *cb_arg; + /** Callback interval */ + ms_time_t interval_ms; + /** Counter, when reaches interval_ms, is cleared and callback is called. */ + ms_time_t countup; + /** Unique task ID (for cancelling / modification) */ + task_pid_t pid; + /** Enable flag - disabled tasks still count, but CB is not run */ + bool enabled; + /** Marks that the task is due to be run */ + bool enqueue; +} periodic_task_t; + + +typedef struct { + /** User callback with arg */ + void (*callback)(void *); + /** Arg for the arg callback */ + void *cb_arg; + /** Counter, when reaches 0ms, callback is called and the task is removed */ + ms_time_t countdown_ms; + /** Unique task ID (for cancelling / modification) */ + task_pid_t pid; + /** Whether this task is long and needs posting on the queue */ + bool enqueue; +} future_task_t; + + +static size_t periodic_slot_count = 0; +static size_t future_slot_count = 0; + +static periodic_task_t *periodic_tasks; +static future_task_t *future_tasks; + + +/** Init timebase */ +void timebase_init(size_t periodic, size_t future) +{ + periodic_slot_count = periodic; + future_slot_count = future; + + periodic_tasks = calloc_s(periodic, sizeof(periodic_task_t)); + future_tasks = calloc_s(future, sizeof(future_task_t)); +} + + +static task_pid_t next_task_pid = 1; // 0 (PID_NONE) is reserved + + +/** Get a valid free PID for a new task. */ +static task_pid_t make_pid(void) +{ + task_pid_t pid = next_task_pid++; + + // make sure no task is given PID 0 + if (next_task_pid == PID_NONE) { + next_task_pid++; + } + + return pid; +} + + +/** Take an empty periodic task slot and populate the basics. */ +static periodic_task_t* claim_periodic_task_slot(ms_time_t interval, bool enqueue) +{ + for (size_t i = 0; i < periodic_slot_count; i++) { + periodic_task_t *task = &periodic_tasks[i]; + if (task->pid != PID_NONE) continue; // task is used + + task->countup = 0; + task->interval_ms = interval - 1; + task->enqueue = enqueue; + task->pid = make_pid(); + task->enabled = true; + return task; + } + + error("Periodic task table full."); + + return NULL; +} + + +/** Take an empty future task slot and populate the basics. */ +static future_task_t* claim_future_task_slot(ms_time_t delay, bool enqueue) +{ + for (size_t i = 0; i < future_slot_count; i++) { + future_task_t *task = &future_tasks[i]; + if (task->pid != PID_NONE) continue; // task is used + + task->countdown_ms = delay; + task->enqueue = enqueue; + task->pid = make_pid(); + return task; + } + + error("Future task table full."); + + return NULL; +} + +/** Add a periodic task with an arg. */ +task_pid_t add_periodic_task(void (*callback)(void*), void* arg, ms_time_t interval, bool enqueue) +{ + periodic_task_t *task = claim_periodic_task_slot(interval, enqueue); + + if (task == NULL) return PID_NONE; + + task->callback = callback; + task->cb_arg = arg; + + return task->pid; +} + + +/** Schedule a future task, with uint32_t argument. */ +task_pid_t schedule_task(void (*callback)(void*), void *arg, ms_time_t delay, bool enqueue) +{ + future_task_t *task = claim_future_task_slot(delay, enqueue); + + if (task == NULL) return PID_NONE; + + task->callback = callback; + task->cb_arg = arg; + + return task->pid; +} + + +/** Enable or disable a periodic task. */ +bool enable_periodic_task(task_pid_t pid, FunctionalState enable) +{ + if (pid == PID_NONE) return false; + + for (size_t i = 0; i < periodic_slot_count; i++) { + periodic_task_t *task = &periodic_tasks[i]; + if (task->pid != pid) continue; + + task->enabled = (enable == ENABLE); + return true; + } + + return false; +} + + +/** Check if a periodic task is enabled */ +bool is_periodic_task_enabled(task_pid_t pid) +{ + if (pid == PID_NONE) return false; + + for (size_t i = 0; i < periodic_slot_count; i++) { + periodic_task_t *task = &periodic_tasks[i]; + if (task->pid != pid) continue; + + return task->enabled; + } + + return false; +} + +bool reset_periodic_task(task_pid_t pid) +{ + if (pid == PID_NONE) return false; + + for (size_t i = 0; i < periodic_slot_count; i++) { + periodic_task_t *task = &periodic_tasks[i]; + if (task->pid != pid) continue; + + task->countup = 0; + return true; + } + + return false; +} + + +/** Remove a periodic task. */ +bool remove_periodic_task(task_pid_t pid) +{ + if (pid == PID_NONE) return false; + + for (size_t i = 0; i < periodic_slot_count; i++) { + periodic_task_t *task = &periodic_tasks[i]; + if (task->pid != pid) continue; + + task->pid = PID_NONE; // mark unused + return true; + } + + return false; +} + + +/** Abort a scheduled task. */ +bool abort_scheduled_task(task_pid_t pid) +{ + if (pid == PID_NONE) return false; + + for (size_t i = 0; i < future_slot_count; i++) { + future_task_t *task = &future_tasks[i]; + if (task->pid != pid) continue; + + task->pid = PID_NONE; // mark unused + return true; + } + + return false; +} + + +/** Run a periodic task */ +static void run_periodic_task(periodic_task_t *task) +{ + if (!task->enabled) return; + + if (task->enqueue) { + // queued task + tq_post(task->callback, task->cb_arg); + } else { + // immediate task + task->callback(task->cb_arg); + } +} + + +/** Run a future task */ +static void run_future_task(future_task_t *task) +{ + if (task->enqueue) { + // queued task + tq_post(task->callback, task->cb_arg); + } else { + // immediate task + task->callback(task->cb_arg); + } +} + + +/** + * @brief Millisecond callback, should be run in the SysTick handler. + */ +void timebase_ms_cb(void) +{ + // increment global time + SystemTime_ms++; + + // run periodic tasks + for (size_t i = 0; i < periodic_slot_count; i++) { + periodic_task_t *task = &periodic_tasks[i]; + if (task->pid == PID_NONE) continue; // unused + + if (task->countup++ >= task->interval_ms) { + // run if enabled + run_periodic_task(task); + // restart counter + task->countup = 0; + } + } + + // run planned future tasks + for (size_t i = 0; i < future_slot_count; i++) { + future_task_t *task = &future_tasks[i]; + if (task->pid == PID_NONE) continue; // unused + + if (task->countdown_ms-- == 0) { + // run + run_future_task(task); + // release the slot + task->pid = PID_NONE; + } + } +} + + + +/** Seconds delay */ +void delay_s(uint32_t s) +{ + while (s-- != 0) { + delay_ms(1000); + } +} + + +/** Delay N ms */ +void delay_ms(ms_time_t ms) +{ + ms_time_t start = SystemTime_ms; + while ((SystemTime_ms - start) < ms); // overrun solved by unsigned arithmetic +} + + +/** Get milliseconds elapsed since start timestamp */ +ms_time_t ms_elapsed(ms_time_t start) +{ + return SystemTime_ms - start; +} + + +/** Get current timestamp. */ +ms_time_t ms_now(void) +{ + return SystemTime_ms; +} + + +/** Helper for looping with periodic branches */ +bool ms_loop_elapsed(ms_time_t *start, ms_time_t duration) +{ + if (SystemTime_ms - *start >= duration) { + *start = SystemTime_ms; + return true; + } + + return false; +} diff --git a/project/utils/timebase.h b/project/utils/timebase.h new file mode 100644 index 0000000..00c618c --- /dev/null +++ b/project/utils/timebase.h @@ -0,0 +1,159 @@ +#pragma once + +/** + * To use the Timebase functionality, + * set up SysTick to 1 kHz and call + * timebase_ms_cb() in the IRQ. + * + * If you plan to use pendable future tasks, + * also make sure you call run_pending_tasks() + * in your main loop. + * + * This is not needed for non-pendable tasks. + */ + +#include "main.h" + + +/** Task PID. */ +typedef uint32_t task_pid_t; + +/** Time value in ms */ +typedef uint32_t ms_time_t; + +// PID value that can be used to indicate no task +#define PID_NONE 0 + +/** Loop until timeout - use in place of while() or for(). break and continue work too! */ +#define until_timeout(to_ms) for(uint32_t _utmeo = ms_now(); ms_elapsed(_utmeo) < (to_ms);) + +/** Retry a call until a timeout. Variable 'suc' is set to the return value. Must be defined. */ +#define retry_TO(to_ms, call) \ + until_timeout(to_ms) { \ + suc = call; \ + if (suc) break; \ + } + +/** Init timebase, allocate slots for tasks. */ +void timebase_init(size_t periodic_count, size_t future_count); + +/** Must be called every 1 ms */ +void timebase_ms_cb(void); + + +// --- Periodic ----------------------------------------------- + + +/** + * @brief Add a periodic task with an arg. + * @param callback : task callback + * @param arg : callback argument + * @param interval : task interval (ms) + * @param enqueue : put on the task queue when due + * @return task PID + */ +task_pid_t add_periodic_task(void (*callback)(void *), void *arg, ms_time_t interval, bool enqueue); + + +/** Destroy a periodic task. */ +bool remove_periodic_task(task_pid_t pid); + +/** Enable or disable a periodic task. Returns true on success. */ +bool enable_periodic_task(task_pid_t pid, FunctionalState cmd); + +/** Check if a periodic task exists and is enabled. */ +bool is_periodic_task_enabled(task_pid_t pid); + +/** Reset timer for a task */ +bool reset_periodic_task(task_pid_t pid); + + +// --- Future ------------------------------------------------- + + +/** + * @brief Schedule a future task, with uint32_t argument. + * @param callback : task callback + * @param arg : callback argument + * @param delay : task delay (ms) + * @param enqueue : put on the task queue when due + * @return task PID + */ +task_pid_t schedule_task(void (*callback_arg)(void *), void *arg, ms_time_t delay, bool enqueue); + + +/** Abort a scheduled task. */ +bool abort_scheduled_task(task_pid_t pid); + + +// --- Waiting functions -------------------------------------- + +/** Get milliseconds elapsed since start timestamp */ +ms_time_t ms_elapsed(ms_time_t start); + + +/** Get current timestamp. */ +ms_time_t ms_now(void); + + +/** Delay using SysTick */ +void delay_ms(ms_time_t ms); + + +/** Delay N seconds */ +void delay_s(uint32_t s); + + +inline __attribute__((always_inline)) +void delay_cycles(uint32_t n) +{ + uint32_t l = n >> 2; + + __asm volatile( + "0: mov r0,r0;" + "subs %[count], #1;" + "bne 0b;" + : [count] "+r"(l) + ); +} + + +inline __attribute__((always_inline)) +void delay_ns(uint32_t ns) +{ + delay_cycles(ns / 24); +} + + +/** + * @brief Microsecond delay. + * @param us + */ +inline __attribute__((always_inline)) +void delay_us(uint32_t us) +{ + delay_ns(us * 1150); +} + + +/** + * @brief Check if time since `start` elapsed. + * + * If so, sets the *start variable to the current time. + * + * Example: + * + * ms_time_t s = ms_now(); + * + * while(1) { + * if (ms_loop_elapsed(&s, 100)) { + * // this is called every 100 ms + * } + * // ... rest of the loop ... + * } + * + * @param start start time variable + * @param duration delay length + * @return delay elapsed; start was updated. + */ +bool ms_loop_elapsed(ms_time_t *start, ms_time_t duration);