Compare commits

...

142 Commits
master ... dev

Author SHA1 Message Date
daf5920814 Merge pull request 'tim' (#6) from tim into dev
Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/6
2024-11-03 12:07:39 +00:00
70e6cd2d19 Replace wfi by wfe for faster wakeup time 2024-11-03 13:01:12 +01:00
3303bf6435 Document RTC calibration functions 2024-11-03 13:00:46 +01:00
ec9f5f85fb Remove debug statement left in the code 2024-10-21 17:13:03 +02:00
bd15878cb5 Add missing variable name to dma's function 2024-10-21 17:07:02 +02:00
5ddcf4b15e Fix dual LF at the end of debug lines 2024-10-21 17:05:49 +02:00
05e3397d95 Implement rtc's LSI calibration 2024-10-21 17:05:26 +02:00
ae9cdc3582 Fix majors bugs in tim module 2024-10-21 17:04:45 +02:00
a0dadf166d Fix rcc's timer frequency being 10x too low 2024-10-21 17:03:03 +02:00
a1028b29b8 Fix bkp regs missing a field 2024-10-21 17:02:16 +02:00
449ec77f9f Implement backup domain's data registers access 2024-09-01 22:43:14 +02:00
92085aabb0 Fix rtc prescaler computation 2024-09-01 19:32:38 +02:00
6ab59f1545 Add timer clocks to rcc's clock frequencies 2024-08-30 22:23:24 +02:00
edb59d7e6b Validate basic use case for tim 2 to 4
tim 2, 3 and 4 work as expected in continuous upcounting with IRQ. tim 1
doesn't seem to work at all (no IRQ), though the issue as not be found
yet
2024-08-28 23:11:18 +02:00
d7da7618e3 Define tim's first API iteration
This API is subject to changes and lacks DMA management
2024-08-28 22:06:20 +02:00
3cbc836fe5 Setup tim's module backbone 2024-08-07 21:37:44 +02:00
93f1b5a992 Define tim module's registers 2024-08-04 23:18:38 +02:00
6d95bce6df Merge pull request 'task' (#5) from task into dev
Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/5
2024-08-04 18:30:15 +00:00
ebc7ad4235 Fix compilation warning in task module 2024-08-04 20:18:45 +02:00
bc4bab4704 Fix include issue in afio module 2024-08-04 20:17:52 +02:00
a4ca0d30c3 Force the use of system's reset in openocd
Using the system's reset avoids the debug getting stuck when the chip
enters low power. Hopefully this works all the time
2024-08-04 20:14:34 +02:00
89c81b8c42 Integrate the RTC to the task module 2024-08-04 20:14:24 +02:00
24e412446d Implement bkp's rtc alarm configuration
Since the alarm must be set each time it is to be used, a separated
function is a better fit
2024-08-04 20:12:28 +02:00
7ab6622908 Rework exti module to use a simpler API
The "specific" lines configuration would not work due to index error in
the callback configuration. While fixing the error, simplifying the API
by moving the afio calls to the calling context seemed a cleaner way to
do things
2024-08-04 19:38:24 +02:00
ba9bc57a49 Add openocd configuration
The target's debug would sometime get stuck while in low-power, making
it difficult to resume communications, even after hardware resets. Some
peripherals were also kept running when halted. This config should fix
these issues
2024-08-04 15:52:24 +02:00
947df53ecb Add missing file documentation 2024-07-27 22:19:29 +02:00
80c027370b Document BKP module 2024-07-27 22:13:46 +02:00
b1d25561b4 Temporarily fix warning 2024-07-27 21:57:53 +02:00
507f1e6863 Move rtc control to new BKP module
RCC's BCDR register has been moved to the BKP module since it is part of
the backup circuit and thus also aboeys some restrictions access-wise
2024-07-27 20:11:51 +02:00
3e3d4d2bff Implement RTC module's basic functionnalities
FUnctions need a cleanup and some details need be ironned, like the
clock management since the whole backup domain must be reset to
configure them
2024-07-27 16:41:36 +02:00
b37eb1dd6e Add RTC configuration to RCC module 2024-07-27 14:17:58 +02:00
0b483c535b Ensure PWR is enabled before configuration 2024-07-27 14:15:55 +02:00
a02bcecaec Implement RTC module's registers 2024-07-16 22:21:05 +02:00
699569ec99 Add LSI configuration function to RCC 2024-07-16 21:50:01 +02:00
3e97d4fe7e Implement sleep modes 2024-07-14 19:17:20 +02:00
5c89df4324 Fix typo in PWR registers 2024-07-13 21:35:42 +02:00
1741d47546 Implement SCB module 2024-07-13 21:35:22 +02:00
97dad53621 Define SCB module's registers 2024-07-13 21:14:44 +02:00
9681755168 Define PWR module's registers 2024-07-13 13:19:17 +02:00
5e4d87474a Fix major reg bitfield issue
A while back, macros had to be put in place to avoid letting the
compiler directly use the bitfields. This was necessary because the
compiler used strb instruction which only write bytes. On the AHB bus,
byte writes are transformed into word writes by repeating the byte,
which caused mayhem in the registers. After a lot of research, turns out
the packed attribute stops the compiler from does optimal (word) writes
and isn't needed anyway. Removing them fixes the issue
2024-07-10 23:16:49 +02:00
d5c70a3a04 Document the task module 2024-07-10 21:54:23 +02:00
93b383be49 Add API to access task's system time 2024-07-09 22:07:35 +02:00
dd1756221d Fix typo in task macros 2024-07-09 21:46:15 +02:00
173e16eb2e Add back task features in a simplified way 2024-07-09 11:53:05 +02:00
b7951f2211 Simplify task module 2024-07-06 22:43:50 +02:00
7cb33f65a5 Create new delay module 2024-05-14 15:03:18 +02:00
c09d2cda67 Remove priority parameter from tasks
In the end, priorities are only usefull in preemptive systems. Here, it would
only garentee the execution order, which we don't care about most of the time
2024-05-14 14:53:51 +02:00
34fb4dac76 Make stk_read function usable
This function used to return the raw current value, but that exposes the
prescaling used internaly
2024-04-30 20:17:58 +02:00
432310a52d Implement task module
For now, most code is temporary to validate that the system can work as
envisionned. Optimisations and cleaning will be done shortly
2024-04-30 20:15:58 +02:00
7e69bfd89c Document systick module 2024-04-28 22:11:37 +02:00
ddd05da6eb Implement systick module 2024-04-28 22:04:10 +02:00
7ba9063d02 Define systick's registers 2024-04-28 19:43:37 +02:00
fb1c11132f Write first API macros 2024-04-28 19:14:28 +02:00
Steins7
cbe6409f69 Merge pull request 'rework' (#4) from rework into dev
Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/4
2024-04-20 18:20:22 +00:00
Steins7
64e1a0c83d Merge pull request 'assert' (#3) from assert into rework
Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/3
2024-04-20 13:47:12 +00:00
47a06a2a39 Add asserts in existing code 2024-04-20 15:45:51 +02:00
a20acf4031 Implement error header 2024-04-20 15:20:18 +02:00
Steins7
eb0ca60aa1 Merge pull request 'debug' (#2) from debug into rework
Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/2
2024-04-20 11:15:31 +00:00
26f2b4d545 Document format module 2024-04-20 11:57:02 +02:00
12800818ce Document debug module 2024-04-20 11:44:56 +02:00
84deb788a0 Improve debug module architecture 2024-04-20 11:37:11 +02:00
254fec4f00 Disable zero padding for signed integers
zero padding is mostly used with unsiged integers, and is quite difficult to
properly implement for signed integers. Disbaling iti n that case seems like a
good compromise
2024-04-15 23:10:31 +02:00
0088322ee7 Fix warning 2024-04-15 23:10:19 +02:00
e477055e6e Implement right-justified padding 2024-04-15 22:56:49 +02:00
3bcb9c7df4 Add error handling 2024-04-15 17:17:23 +02:00
075d9e17a6 Changed internal functions to static 2024-04-15 17:17:05 +02:00
727aadaba9 Implement signed integer formating 2024-04-15 17:04:35 +02:00
3dc548332f Implement basic string formatting 2024-04-15 16:54:54 +02:00
0d5deffa58 Update debug service to use new dma_mbuf 2024-04-07 16:47:34 +02:00
Steins7
c26b1cd703 Merge pull request 'usart' (#1) from usart into rework
Reviewed-on: https://git.steins7.ovh/Steins7/stm32f1xx_HBL/pulls/1
2024-04-06 21:05:00 +00:00
cf077d2e51 Fix unwanted changes 2024-04-06 23:02:08 +02:00
4eec301d17 Optimize USART driver's code size
Using tables reduces code size while also improving lisibility. That is a
win-win
2024-04-06 22:56:28 +02:00
c6da4e11d8 Document USART driver 2024-04-06 22:19:19 +02:00
85e7ad5ef1 Document DMA driver 2024-04-06 17:26:56 +02:00
a1ae904239 Document dma_cbuf service 2024-04-06 16:59:57 +02:00
5e961b15fc Document dma_mbuf service 2024-04-06 16:57:36 +02:00
fd33003e26 Rework DMA buffer to work properly
DMA buffers now work reliably with USART. The DMA api has changed to make it
more efficient code-size-wise. This may, however, complicate things when
implementating powersaving features
2024-04-06 16:29:45 +02:00
7a19ae9223 Clean minor issues in startup.s 2024-04-06 16:28:08 +02:00
ccf36ac400 Simplify dma buffers and adjust usart
The dma buffer should be services that are used on top of peripherals. As such,
the usart driver should'nt directly use them, this is up to the user. The
multi-buffer has also been simplified since I was not satisfied with the
previous implementation
2024-04-03 22:03:15 +02:00
e1097048a6 RAM initialisation fixed in 086f915 2023-09-24 22:04:38 +02:00
b992e2b8fb First implementation of debug service
For now, only basic traces are implemented. The rest will follow once a printf
function is implemented
2023-09-24 22:02:20 +02:00
cc54ca7ca8 Improve mbuf fix
Byte index is now stored on 2 bytes. Macros have been made cleaner
2023-09-24 21:59:29 +02:00
0628c4c07c Use TC instead of TXE
Transfer Complete is preferable to TX Empty when using a DMA since we could be
polling the bit between transfers. TXE would be 1 but the DMA would be
transfering another at the same time. TC takes the DMA into account
2023-09-24 18:35:36 +02:00
dbfba20520 Temporary fix for mbuf's byte index
Each buffer should use its own byte index since the value would otherwise be
overwritten when writing to other buffers
2023-09-24 18:33:20 +02:00
a7099d5dfd Rename drivers folder to drv 2023-09-21 20:42:16 +02:00
086f9155f7 Fix RAM initialisation
The reset handler is responsible for loading the variables default values. This
includes variables initialized to 0, although they are handed through bss and
not data
2023-09-18 11:45:12 +02:00
4464156981 Move DMA config to buffers
Control over most parameters is not needed since they cannot change for the
buffer to work as expected. Only the priority should be adjustable
2023-09-17 17:52:14 +02:00
d84d9cef83 Move DMA's rx buffer to a separate module 2023-09-17 17:36:24 +02:00
e2adf48f82 Document dma multibuffer module 2023-09-17 00:04:06 +02:00
256e3f30ab Make USART writes non-blocking
The application should be the one to decide if a write should be blocking or not
2023-09-16 23:50:13 +02:00
7a660c29d2 Implement and validate all USARTs 2023-09-16 23:40:36 +02:00
dac751e466 Move DMA's tx buffer to a separate module 2023-09-16 18:53:50 +02:00
9f2b337abf Add additionnal param to DMA callbacks
This parameter is necessary for DMA tools to be implemented with minimal flash
usage as it allow the use of a single callback function for all purposes instead
of the need to add separate callback functions
2023-09-16 18:15:44 +02:00
b9285f2ab9 Document USART's private functions 2023-09-16 17:38:13 +02:00
fdc5f381f8 Got USART's TX via DMA working as intended
For now, USART's writes are blocking. This should be left to the application to
decide
2023-09-16 17:15:49 +02:00
a66e5733e1 First try at implementing USART's TX
Unbuffered writes are working as intented. Buffering still needs work
2023-09-13 21:57:13 +02:00
6269cf969a Add critical section functions for DMAs 2023-09-13 21:56:30 +02:00
f89fe12298 Add circular rx buffer management 2023-07-11 11:44:54 +02:00
46776ebfd3 Configure usart's rx with dma 2023-07-10 11:30:51 +02:00
c571343de1 Fix usart's regs typo 2023-07-10 11:29:43 +02:00
43cdb55c48 Cleanup dma's configuration code 2023-07-10 11:29:07 +02:00
12c0b16b39 Cosmetic fixes 2023-07-10 11:14:46 +02:00
45452ce49e Implement dma's basic functions 2023-07-10 11:13:36 +02:00
6ddc2266e1 Create dma's register map 2023-07-10 11:13:05 +02:00
dfccfd9591 Replace flash's bitfields with macros 2023-07-07 17:46:04 +02:00
ebe30a4a7a Replace exti's bitfields with macros 2023-07-07 17:41:18 +02:00
26bb798b79 Add usart's read function 2023-07-05 23:05:03 +02:00
073be3f980 Fix macro parameter 2023-07-05 22:51:31 +02:00
c8040cf62f Implement usart's basic function
This code doesn't work quite right yet, must most of the control system is in
place
2023-07-05 22:24:02 +02:00
9706979028 Apply new mask system to usart's regs 2023-07-05 22:23:53 +02:00
c1b3f0d073 Replace rcc's bitfields with macros
Bitfields can use byte acces, which the bus doesn't permit. When that happens,
the bus adds extra bytes to form a word, modifying fields that shouldn't be.
Bitfields can be kept for debug and read, but writes must be done though masks
2023-07-05 22:23:28 +02:00
aeba78cfcc Create usart's register map 2023-05-18 13:49:53 +02:00
3b4536bea2 Upddate module documentation 2023-05-13 15:50:13 +02:00
db5180d3e7 Document afio function 2023-05-13 15:48:07 +02:00
245b9238e9 Finish exti's implementation 2023-05-13 15:42:59 +02:00
3906a79315 Implement afio's control functions 2023-05-13 15:42:38 +02:00
9052aac1b3 Create afio's register map 2023-05-13 15:42:11 +02:00
c7deded9b2 Implement exti's control functions 2023-05-13 14:17:32 +02:00
a99b4ad0de Create exti's register map 2023-05-13 14:17:03 +02:00
8dc58b6747 Add peripheral-wide reset function for gpios 2023-05-13 13:27:51 +02:00
d9170ee902 Updated module documentation 2023-05-08 21:28:30 +02:00
f0da0cd05c Fix gpio configuration mask not properly applied 2023-05-08 21:19:46 +02:00
0034dea774 Make gpio writes atomic 2023-05-08 21:03:52 +02:00
c44dc87f43 Implement gpio's control functions 2023-05-08 21:01:31 +02:00
2f40111dbb Create gpio's register map 2023-05-08 20:53:30 +02:00
16fbf892ba Fix bitwise negations using the boolean operator 2023-05-08 20:52:18 +02:00
1d8ccfdfca Fix rcc enum 2023-05-07 19:28:01 +02:00
661f4a0ae5 Implement nvic's control functions 2023-04-27 21:12:05 +02:00
691b360eb1 Create nvic's register map 2023-04-27 21:12:00 +02:00
8ff2cabeab Add cortex_m3 doc 2023-04-27 21:03:25 +02:00
c10ef4d2f1 Merge peripheral control functions
The functions are very simple and their number complicates the API more
than anything, so we better merge them
2023-03-31 23:32:43 +02:00
2d83ce9f05 Implement AHB peripherals control functions 2023-03-31 23:22:11 +02:00
2b689c4335 Cleanup repository 2023-03-31 14:18:48 +02:00
ca935a7650 Rework comments
Avoid repitions between comments and code. Additionnal usage information
can be added as header comment and additionnal technical information can
be added in the source file
2023-03-31 14:17:39 +02:00
a101f07009 Implement peripheral control functions 2023-03-31 14:04:36 +02:00
3a768d9190 Implement Flash configuration 2023-03-26 21:07:37 +02:00
7f7cb077dc Create flash register map 2023-03-24 19:05:43 +01:00
dd6d5fbdd1 Implement RCC's clock configuration
For now, flash configuration is hard-coded. This will fixed in future
commits
2023-03-22 23:30:29 +01:00
50dc10b76e Create RCC register map 2023-03-19 21:57:37 +01:00
c2aec8e9ed Rewrite linker and startup files
The files previously used were from StmCubeMx and Mbed but they contain
a lots off things that we don't need, like a heap and a space for
special debug symbols
2023-03-13 11:45:37 +01:00
d1e73a55c6 Update .gitignore 2023-02-11 21:57:21 +01:00
4a12fa7a3d Reorganize repository to be used as a library
Project was organized as an application, wich makes it less practical
to include in other projects. A template project may be added back to
make up for the missing files
2023-02-11 21:55:32 +01:00
110 changed files with 7631 additions and 13378 deletions

View File

@ -1,27 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: Steins7
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Code
2. Specific Hardware used
3. OS and toolchain
4. Conditions for the bug to appear
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE]"
labels: enhancement
assignees: Steins7
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ bin
.gdb_history
*tags
*.taghl
.cache

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Steins7
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

189
Makefile
View File

@ -1,189 +0,0 @@
#-------------------------------------------------------------------------------
# this GNU-makefile relies on the GCC toolchain
# --- control global project settings
# RELEASE=1 -> enable optimisation, then disable debug
# RELEASE=0 -> disable optimisation, then enable debug
RELEASE=0
# --- project architecture
# program name
EXE_PREFIX=main
# project folders, This Makefile should be in the same folder as the SRC folder
SRC=src
BIN=bin
INC=include
LIB=lib
OBJ=${BIN}/obj
DEP=${BIN}/dep
# code folders, in the SRC folder
SUBFOLDERS=drivers target
# Define linker script file here
LDSCRIPT=${SRC}/target/STM32F103XB.ld
# --- advanced config
# List all user C define here
UDEFS=
# Define ASM defines here
UADEFS=
# --- toolchain configuration
TARGET=arm-none-eabi-
CC=${TARGET}gcc
CPP=${TARGET}g++
OBJCOPY=${TARGET}objcopy
AS=${TARGET}gcc -x assembler-with-cpp -c
SIZE=${TARGET}size
OBJDUMP=${TARGET}objdump
# --- hardware settings
ARCH=armv7-m
FLOAT-ABI=soft #no FPU on stm32f103
CPU=cortex-m3
CPUFLAGS=-mthumb
FPU=fpv4-sp-d16 #"FLOAT-ABI=soft" disable that
#-------------------------------------------------------------------------------
# --- makefile pre-incantation
# List all de:fault C defines here, like -D_DEBUG=1
DDEFS=-march=${ARCH} -mfloat-abi=${FLOAT-ABI} -mcpu=${CPU} -mfpu=${FPU} $\
${CPUFLAGS}
# List all default ASM defines here, like -D_DEBUG=1
DADEFS=-D__ASSEMBLY__
# --- deduce file names
MAIN_C_FILES=${wildcard ${SRC}/${strip ${EXE_PREFIX}}*.c}
MAIN_CPP_FILES=${wildcard ${SRC}/${strip ${EXE_PREFIX}}*.cpp}
COMMON_C_FILES=${filter-out ${MAIN_C_FILES},${wildcard ${SRC}/*.c}}
COMMON_C_FILES+=${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.c}}
COMMON_CPP_FILES=${filter-out ${MAIN_CPP_FILES},${wildcard ${SRC}/*.cpp}}
COMMON_CPP_FILES+=${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.cpp}}
COMMON_ASM_FILES=${foreach dir,${SUBFOLDERS},${wildcard ${SRC}/${dir}/*.s}}
MAIN_OBJECT_FILES=${sort ${patsubst ${src}/%.c,${obj}/%.o,${MAIN_C_FILES}} \
${patsubst ${src}/%.cpp,${obj}/%.o,${MAIN_CPP_FILES}}}
COMMON_OBJECT_FILES=${sort \
${patsubst ${SRC}/%.c,${OBJ}/%.o,${COMMON_C_FILES}} \
${patsubst ${SRC}/%.cpp,${OBJ}/%.o,${COMMON_CPP_FILES}} \
${patsubst ${SRC}/%s,${OBJ}/%o,${COMMON_ASM_FILES}}}
LIBRARIES=${foreach dir,${wildcard ${LIB}/*},${wildcard ${LIB}/${dir}/*.a}}
OBJECT_FILES=${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES}
DEPEND_FILES=${OBJECT_FILES:%.o,%.d}
#-------------------------------------------------------------------------------
# --- makefile incantation
# down here is black magic, you probably don't want to modify anything
DEFS=${DDEFS} ${UDEFS}
ADEFS=${DADEFS} ${UADEFS}
# --- otpimisation
ifeq (${strip ${RELEASE}},0)
CFLAGS=-g3 -O0
else
CFLAGS=-O3
endif
# --- c/cpp
ifneq (${strip ${MAIN_CPP_FILES} ${COMMON_CPP_FILES}},)
CC:=${CPP}
CFLAGS+=-std=c++17
else
CFLAGS+=-std=c17
endif
ASFLAGS=${LIB} $(DEFS) -Wa,--gdwarf2 $(ADEFS)
CFLAGS+=-Wall ${DEFS} -Wextra -Warray-bounds -Wno-unused-parameter $\
-fomit-frame-pointer
LDFLAGS=-T ${LDSCRIPT} -lc -lgcc -lgcov -lm -Wl,-Map=$@.map,--gc-sections $\
--specs=nosys.specs
INCLUDE=-I ${INC}
# --- Generate dependency information
CFLAGS+=-MD -MP -MF ${patsubst %o,%d,$@}
ASFLAGS+=#-MD -MP -MF ${patsubst %o,%d,$@}
# --- folder tree
DIR_GUARD=@mkdir -p ${@D}
#-------------------------------------------------------------------------------
# --- make rules
all: ${BIN}/${EXE_PREFIX}.elf ${BIN}/${EXE_PREFIX}.hex ${BIN}/${EXE_PREFIX}.bin
rebuild : clean all
.SUFFIXES:
.SECONDARY:
.PHONY: all clean rebuild
# --- compiler command for elf file
${BIN}/%.elf : ${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES}
@echo -e '\e[32;1m ==== linking $@ ====\e[0m'
@echo ${COMMON_OBJECT_FILES}
@echo
${DIR_GUARD}
${CC} ${INCLUDE} ${CFLAGS} -o $@ $^ ${LIBRARIES} ${LDFLAGS}
${OBJDUMP} -h $@
${SIZE} $@
@echo
# --- compiler commands for uploadable files
${BIN}/%.hex : ${BIN}/%.elf
@echo -e '\e[33;1m ==== translating $< ====\e[0m'
${OBJCOPY} -O ihex $< $@
@echo
${BIN}/%.bin : ${BIN}/%.elf
@echo -e '\e[33;1m ==== translating $< ====\e[0m'
${OBJCOPY} -O binary $< $@
@echo
# --- compiler commands for every source file
${OBJ}/%.o : ${SRC}/%.cpp
@echo -e '\e[36;1m ==== compiling $< ====\e[0m'
${DIR_GUARD}
${CPP} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
@echo
${BIN}/%.o : ${SRC}/%.cpp
@echo -e '\e[36;1m ==== compiling $< ====\e[0m'
${DIR_GUARD}
${CPP} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
@echo
${OBJ}/%.o : ${SRC}/%.c
@echo -e '\e[34;1m ==== compiling $< ====\e[0m'
${DIR_GUARD}
${CC} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
@echo
${BIN}/%.o : ${SRC}/%.c
@echo -e '\e[34;1m ==== compiling $< ====\e[0m'
${DIR_GUARD}
${CC} ${INCLUDE} -c ${CFLAGS} $< -o $@ ${LIBRARIES}
@echo
${OBJ}/%.o : ${SRC}/%.s
@echo -e '\e[35;1m ==== compiling $^ ====\e[0m'
${DIR_GUARD}
${AS} -o ${ASFLAGS} $< -o $@ ${LIBRARIES}
@echo
${BIN}/%.o : ${SRC}/%.s
@echo -e '\e[35;1m ==== compiling $^ ====\e[0m'
${DIR_GUARD}
${AS} -o ${ASFLAGS} $< -o $@ ${LIBRARIES}
@echo
# --- remove generated files
clean:
-rm -rf ${BIN}/*
-include ${DEPEND_FILES}

View File

@ -1,2 +0,0 @@
# stm32f1xx_HBL
simplified HAL for stm32f1 microcontrollers, designed to be easily customized

BIN
doc/cortex_m3.pdf Normal file

Binary file not shown.

331
doc/modules.drawio Normal file
View File

@ -0,0 +1,331 @@
<mxfile host="Electron" modified="2023-05-13T13:49:29.284Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.2.1 Chrome/106.0.5249.199 Electron/21.4.4 Safari/537.36" etag="hag9Pts7i5T_KBibxpc9" version="21.2.1" type="device">
<diagram name="Page-1" id="nh8f32euryOmsLCMibi_">
<mxGraphModel dx="1420" dy="1695" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="v3HUPI7M600Mln0mNnSE-29" value="&lt;p style=&quot;margin:0px;margin-top:4px;text-align:center;&quot;&gt;&lt;b&gt;Drivers&lt;/b&gt;&lt;/p&gt;&lt;hr size=&quot;1&quot;&gt;&lt;div style=&quot;height:2px;&quot;&gt;&lt;/div&gt;" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;shadow=0;" parent="1" vertex="1">
<mxGeometry x="100" y="-690" width="1460" height="740" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-13" value="RCC" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;fillColor=#6d8764;strokeColor=#3A5431;labelBackgroundColor=none;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="150" y="-620" width="310" height="164" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-14" value="- regs : struct" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-13" vertex="1">
<mxGeometry y="26" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-15" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;" parent="v3HUPI7M600Mln0mNnSE-13" vertex="1">
<mxGeometry y="52" width="310" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-8" value="+ rcc_configure (preset: enum)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-13" vertex="1">
<mxGeometry y="60" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-6" value="+ rcc_enable (mask: ahb, mask: apb1, mask: apb2)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-13" vertex="1">
<mxGeometry y="86" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-17" value="+ rcc_disable (mask: ahb, mask: apb1, mask: apb2)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-13" vertex="1">
<mxGeometry y="112" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-20" value="+ rcc_reset (mask: apb1, mask: apb2)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-13" vertex="1">
<mxGeometry y="138" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-30" value="TIM" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#e51400;strokeColor=#B20000;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="1370" y="-619" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-31" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-30" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-32" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-30" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-33" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-30" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-34" value="GPIO" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#6d8764;strokeColor=#3A5431;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="500" y="-620" width="360" height="204" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-35" value="- regs : struct" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-34" vertex="1">
<mxGeometry y="26" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-36" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-34" vertex="1">
<mxGeometry y="52" width="360" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-37" value="+ gpio_configure (enum: port, mask: pin, enum: mode, &#xa;    enum: config): void&#xa;&#xa;&#xa;" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-34" vertex="1">
<mxGeometry y="60" width="360" height="40" as="geometry" />
</mxCell>
<mxCell id="ClqF0cL-BW29ZjaMUesU-8" value="+ gpio_reset (enum: port, mask: pin) " style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-34" vertex="1">
<mxGeometry y="100" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="ClqF0cL-BW29ZjaMUesU-5" value="+ gpio_read (enum: port, mask: pin): bool&#xa;&#xa;&#xa;" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-34" vertex="1">
<mxGeometry y="126" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="ClqF0cL-BW29ZjaMUesU-6" value="+ gpio_write (enum: port, mask: pin, bool: val) " style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-34" vertex="1">
<mxGeometry y="152" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="DX46o3M0sBaZfG6b8Zif-7" value="+ gpio_reset_peripheral () " style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="v3HUPI7M600Mln0mNnSE-34">
<mxGeometry y="178" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-38" value="ADC" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#e51400;strokeColor=#B20000;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="1370" y="-399" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-39" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-38" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-40" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-38" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-41" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-38" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-42" value="BKP" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1000" y="-620" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-43" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-42" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-44" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-42" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-45" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-42" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-46" value="SPI" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1000" y="-400" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-47" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-46" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-48" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-46" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-49" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-46" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-50" value="I2C" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1190" y="-289" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-51" value="+ field: type" style="text;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-50" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-52" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-50" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-53" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-50" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-54" value="USART" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#fa6800;strokeColor=#C73500;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1370" y="-509" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-55" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-54" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-56" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-54" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-57" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-54" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-58" value="CAN ?" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1190" y="-179" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-59" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-58" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-60" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-58" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-61" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-58" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-62" value="WDG" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1000" y="-510" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-63" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-62" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-64" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-62" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-65" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-62" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-66" value="DMA" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#fa6800;strokeColor=#C73500;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1190" y="-399" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-67" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-66" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-68" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-66" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-69" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-66" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-70" value="PWR" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1190" y="-509" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-71" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-70" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-72" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-70" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-73" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-70" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-74" value="NVIC" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#6d8764;strokeColor=#3A5431;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="150" y="-424" width="310" height="242" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-75" value="- regs : struct" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="26" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-76" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="52" width="310" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-77" value="+ nvic_enable (int: interrupt)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="60" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="o2IW8Z8pTP8tj_kMgO3k-2" value="+ nvic_disable (int: interrupt)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="86" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="o2IW8Z8pTP8tj_kMgO3k-3" value="+ nvic_clear_pending (int: interrupt)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="112" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="o2IW8Z8pTP8tj_kMgO3k-4" value="+ nvic_set_priority (int: interrupt, int: priority)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="138" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="o2IW8Z8pTP8tj_kMgO3k-6" value="+ nvic_set_pending (int: interrupt)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="164" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="o2IW8Z8pTP8tj_kMgO3k-8" value="+ nvic_is_pending (int interrupt): bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="190" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="o2IW8Z8pTP8tj_kMgO3k-7" value="+ nvic_is_active (int interrupt): bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-74" vertex="1">
<mxGeometry y="216" width="310" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-78" value="FLASH" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1370" y="-289" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-79" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-78" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-80" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-78" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-81" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-78" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-82" value="CRC" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="1000" y="-290" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-83" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-82" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-84" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-82" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-85" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-82" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-86" value="&lt;p style=&quot;margin:0px;margin-top:4px;text-align:center;&quot;&gt;&lt;b&gt;Services&lt;/b&gt;&lt;/p&gt;&lt;hr size=&quot;1&quot;&gt;&lt;div style=&quot;height:2px;&quot;&gt;&lt;/div&gt;" style="verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;shadow=0;" parent="1" vertex="1">
<mxGeometry x="100" y="160" width="810" height="280" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-87" value="Task" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#e51400;strokeColor=#B20000;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="320" y="210" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-88" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-87" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-89" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-87" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-90" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-87" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-91" value="Debug" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="140" y="210" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-92" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-91" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-93" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-91" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-94" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-91" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-95" value="Eeprom ?" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="140" y="320" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-96" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-95" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-97" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-95" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-98" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-95" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-99" value="Display" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="680" y="210" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-100" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-99" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-101" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-99" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-102" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-99" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-103" value="Input" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#f0a30a;strokeColor=#BD7000;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="500" y="210" width="160" height="86" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-104" value="+ field: type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-103" vertex="1">
<mxGeometry y="26" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-105" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="v3HUPI7M600Mln0mNnSE-103" vertex="1">
<mxGeometry y="52" width="160" height="8" as="geometry" />
</mxCell>
<mxCell id="v3HUPI7M600Mln0mNnSE-106" value="+ method(type): type" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="v3HUPI7M600Mln0mNnSE-103" vertex="1">
<mxGeometry y="60" width="160" height="26" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-1" value="EXTI" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#e3c800;strokeColor=#B09500;fontColor=#000000;" parent="1" vertex="1">
<mxGeometry x="500" y="-385" width="360" height="190" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-2" value="- regs : struct" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="BL1kyMswEt5U9iN2dzKQ-1" vertex="1">
<mxGeometry y="26" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-3" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="BL1kyMswEt5U9iN2dzKQ-1" vertex="1">
<mxGeometry y="52" width="360" height="8" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-4" value="+ exti_configure (mask: line, enum: port, func: callback)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="BL1kyMswEt5U9iN2dzKQ-1" vertex="1">
<mxGeometry y="60" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="DX46o3M0sBaZfG6b8Zif-1" value="+ exti_reset (mask: line)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="BL1kyMswEt5U9iN2dzKQ-1">
<mxGeometry y="86" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="DX46o3M0sBaZfG6b8Zif-5" value="+ exti_configure_specific (mask: line, func: callback)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="BL1kyMswEt5U9iN2dzKQ-1">
<mxGeometry y="112" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="DX46o3M0sBaZfG6b8Zif-6" value="+ exti_reset_specific (mask: line)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="BL1kyMswEt5U9iN2dzKQ-1">
<mxGeometry y="138" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="DX46o3M0sBaZfG6b8Zif-8" value="+ exti_reset_peripheral () " style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" vertex="1" parent="BL1kyMswEt5U9iN2dzKQ-1">
<mxGeometry y="164" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-10" value="AFIO" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;shadow=0;fillColor=#6d8764;strokeColor=#3A5431;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="500" y="-160" width="360" height="86" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-11" value="- regs : struct" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="BL1kyMswEt5U9iN2dzKQ-10" vertex="1">
<mxGeometry y="26" width="360" height="26" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-12" value="" style="line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;strokeColor=inherit;shadow=0;" parent="BL1kyMswEt5U9iN2dzKQ-10" vertex="1">
<mxGeometry y="52" width="360" height="8" as="geometry" />
</mxCell>
<mxCell id="BL1kyMswEt5U9iN2dzKQ-13" value="+ afio_map_exti (mask: line,  enum: port)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;" parent="BL1kyMswEt5U9iN2dzKQ-10" vertex="1">
<mxGeometry y="60" width="360" height="26" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

63
drv/afio.c Normal file
View File

@ -0,0 +1,63 @@
/** @file afio.c
* Module handling Alternate Functions for Inputs/Outputs
*
* The module provides functions to remap ios to diverse peripherals
*/
//--includes--------------------------------------------------------------------
#include "afio.h"
#include "afio_regs.h"
#include "rcc.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct AFIO* regs = (struct AFIO*)AFIO_BASE_ADDRESS;
//--public functions------------------------------------------------------------
void afio_map_exti(enum ExtiLine line_mask, enum GpioPort port)
{
//ensure afio peripheral is enabled
rcc_enable(RCC_AHB_NONE, RCC_APB1_NONE, RCC_APB2_AFIO);
for (uint8_t i = 0; i < 4; ++i) {
if (line_mask & (0x1 << i)) {
regs->EXTICR1.word &= ~(0xF << (4 * i));
regs->EXTICR1.word |= (port << (4 * i));
}
}
line_mask = line_mask >> 4;
for (uint8_t i = 0; i < 4; ++i) {
if (line_mask & (0x1 << i)) {
regs->EXTICR2.word &= ~(0xF << (4 * i));
regs->EXTICR2.word |= (port << (4 * i));
}
}
line_mask = line_mask >> 4;
for (uint8_t i = 0; i < 4; ++i) {
if (line_mask & (0x1 << i)) {
regs->EXTICR3.word &= ~(0xF << (4 * i));
regs->EXTICR3.word |= (port << (4 * i));
}
}
line_mask = line_mask >> 4;
for (uint8_t i = 0; i < 4; ++i) {
if (line_mask & (0x1 << i)) {
regs->EXTICR4.word &= ~(0xF << (4 * i));
regs->EXTICR4.word |= (port << (4 * i));
}
}
}
//--local functions-------------------------------------------------------------

31
drv/afio.h Normal file
View File

@ -0,0 +1,31 @@
/** @file afio.h
* Module handling Alternate Functions for Inputs/Outputs
*
* The module provides functions to remap ios to diverse peripherals
*/
#ifndef _AFIO_H_
#define _AFIO_H_
//--includes--------------------------------------------------------------------
#include "exti.h"
#include "gpio.h"
//--type definitions------------------------------------------------------------
//--functions-------------------------------------------------------------------
/**
* Maps the exti lines to gpio ports. The ExtiLine enum can be used as a
* mask to configure multiple lines at the same time. This function is used by
* the exti module to configure its line and calling it directly should should
* thus normaly not be needed. It could however still be usefull when wanting to
* change the port linked to an exti without reconfiguring it entirely
*/
void afio_map_exti(enum ExtiLine line_mask, enum GpioPort port);
#endif //_AFIO_H_

125
drv/afio_regs.h Normal file
View File

@ -0,0 +1,125 @@
/** @file afio_regs.h
* Module defining the AFIO registers.
*
* Mainly made to be used by the afio module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _AFIO_REGS_H_
#define _AFIO_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define AFIO_BASE_ADDRESS 0x40010000
union EVCR {
struct {
uint32_t PIN:4;
uint32_t PORT:3;
uint32_t EVOE:1;
uint32_t reserved1:24;
};
uint32_t word;
};
union MAPR {
struct {
uint32_t SPI1_REMAP:1;
uint32_t I2C1_REMAP:1;
uint32_t USART1_REMAP:1;
uint32_t USART2_REMAP:1;
uint32_t USART3_REMAP:2;
uint32_t TIM1_REMAP:2;
uint32_t TIM2_REMAP:2;
uint32_t TIM3_REMAP:2;
uint32_t TIM4_REMAP:1;
uint32_t CAN_REMAP:2;
uint32_t PD01_REMAP:1;
uint32_t TIM5CH4_REMAP:1;
uint32_t ADC1_ETRGINJ_REMAP:1;
uint32_t ADC1_ETRGREG_REMAP:1;
uint32_t ADC2_ETRGINJ_REMAP:1;
uint32_t ADC2_ETRGREG_REMAP:1;
uint32_t reserved1:3;
uint32_t SWJ_CFG:3;
uint32_t reserved2:5;
};
uint32_t word;
};
union EXTICR1 {
struct {
uint32_t EXTI0:4;
uint32_t EXTI1:4;
uint32_t EXTI2:4;
uint32_t EXTI3:4;
uint32_t reserved1:16;
};
uint32_t word;
};
union EXTICR2 {
struct {
uint32_t EXTI4:4;
uint32_t EXTI5:4;
uint32_t EXTI6:4;
uint32_t EXTI7:4;
uint32_t reserved1:16;
};
uint32_t word;
};
union EXTICR3 {
struct {
uint32_t EXTI8:4;
uint32_t EXTI9:4;
uint32_t EXTI10:4;
uint32_t EXTI11:4;
uint32_t reserved1:16;
};
uint32_t word;
};
union EXTICR4 {
struct {
uint32_t EXTI12:4;
uint32_t EXTI13:4;
uint32_t EXTI14:4;
uint32_t EXTI15:4;
uint32_t reserved1:16;
};
uint32_t word;
};
union MAPR2 {
struct {
uint32_t reserved1:5;
uint32_t TIM9_REMAP:1;
uint32_t TIM10_REMAP:1;
uint32_t TIM11_REMAP:1;
uint32_t TIM13_REMAP:1;
uint32_t TIM14_REMAP:1;
uint32_t FSMC_NADV:1;
uint32_t reserved2:21;
};
uint32_t word;
};
struct AFIO {
union EVCR EVCR;
union MAPR MAPR;
union EXTICR1 EXTICR1;
union EXTICR2 EXTICR2;
union EXTICR3 EXTICR3;
union EXTICR4 EXTICR4;
union MAPR2 MAPR2;
};
#endif //_AFIO_REGS_H_

222
drv/bkp.c Normal file
View File

@ -0,0 +1,222 @@
/** @file bkp.c
* Module handling the Backup (BKP) domain functionalities.
*
* This module includes management of the Real Time Clock (RTC), Tamper
* protection system and a limited space (20 bytes) for persistent data storage
*
* All features present in this module stay running in standby mode / when
* no-longer powered, so long as VBAT is maintained
*/
//--includes--------------------------------------------------------------------
#include "bkp.h"
#include "bkp_regs.h"
#include "rcc.h"
#include "nvic.h"
//--local definitions-----------------------------------------------------------
static uint32_t compute_prescaler(uint32_t period_ms,
enum BkpRtcClockSrc clock_src);
static void lsi_calib_callback(enum TimIRQSource src);
//--local variables-------------------------------------------------------------
static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS;
static volatile struct RCC* rcc_regs = (struct RCC*)RCC_BASE_ADDRESS;
static volatile struct RTC* rtc_regs = (struct RTC*)RTC_BASE_ADDRESS;
static BkpRtcCallback rtc_callback;
//--public functions------------------------------------------------------------
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, BkpRtcCallback callback)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
//start RTC
rcc_regs->BDCR.RTCSEL = clock_src + 1;
rcc_regs->BDCR.RTCEN = 1;
uint32_t prescaler = compute_prescaler(period_ms, clock_src);
//wait for registers to synchronize
rtc_regs->CRL.RSF = 0;
while (rtc_regs->CRL.RSF != 1) {}
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
//enable core configuration
rtc_regs->CRL.CNF = 1;
//configure core registers
rtc_regs->PRLH.PRL = prescaler >> 16;
rtc_regs->PRLL.PRL = prescaler;
//apply irq config
rtc_regs->CRH.word |= irq_mask & 0x7;
//disable/apply core configuration
rtc_regs->CRL.CNF = 0;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
if (callback) {
rtc_callback = callback;
nvic_enable(NVIC_IRQ_RTC);
}
}
void bkp_set_rtc_alam(uint32_t offset)
{
uint32_t alarm = bkp_read_rtc() + offset;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
//enable core configuration
rtc_regs->CRL.CNF = 1;
//write alarm value
rtc_regs->ALRH.RTC_ALR = alarm >> 16;
rtc_regs->ALRL.RTC_ALR = alarm;
//disable/apply core configuration
rtc_regs->CRL.CNF = 0;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
}
uint32_t bkp_read_rtc(void)
{
//wait for core registers to be synchronized, immediate most of the time
while (rtc_regs->CRL.RSF != 1) {}
uint32_t time = rtc_regs->CNTH.RTC_CNT << 16;
time |= rtc_regs->CNTL.RTC_CNT << 0;
return time;
}
uint32_t bkp_read_rtc_div(void)
{
//wait for core registers to be synchronized, immediate most of the time
while (rtc_regs->CRL.RSF != 1) {}
uint32_t div = rtc_regs->DIVH.RTC_DIV << 16;
div |= rtc_regs->DIVL.RTC_DIV << 0;
return div;
}
void bkp_reset(void)
{
rcc_regs->BDCR.BDRST = 1;
rcc_regs->BDCR.BDRST = 0;
}
void bkp_write_data(enum BkpData data_index, uint16_t data)
{
bkp_regs->DR[data_index].D = data;
}
uint16_t bkp_read_data(enum BkpData data_index)
{
return bkp_regs->DR[data_index].D;
}
void bkp_calibrate_lsi(enum TimPeriph timer)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
//do not calibrate if already calibrated
if (bkp_read_data(BKP_DATA_LSI_CALIB) != 0) {
return;
}
//configure timer to count 1s exactly
struct RccClocks clocks;
rcc_get_clocks(&clocks);
tim_set_prescaler(timer, (clocks.tim_freq / 10000)); //10000 to avoid
//prescaler overflow
tim_set_auto_reload(timer, 10000);
tim_configure_master(timer, TIM_CONFIG_ONE_SHOT
| TIM_CONFIG_DIR_UP, TIM_MASTER_CONFIG_MODE_RESET,
lsi_calib_callback);
//configure rtc to tick every 2s so the div value isn't reset during the
//timer's delay if the clock is too fast
bkp_configure_rtc(2000, BKP_RTC_CLOCK_SRC_LSI, BKP_RTC_IRQ_NONE, nullptr);
tim_start(timer);
while (bkp_read_data(BKP_DATA_LSI_CALIB) == 0) {}
//TODO reset timer
}
//--local functions-------------------------------------------------------------
/**
* Computes the prescaler value based on the clock source and the required
* period
*/
static uint32_t compute_prescaler(uint32_t period_ms,
enum BkpRtcClockSrc clock_src)
{
uint32_t prescaler;
switch (clock_src) {
case BKP_RTC_CLOCK_SRC_LSE:
prescaler = 32768; //32.768kHz
break;
case BKP_RTC_CLOCK_SRC_LSI:
prescaler = bkp_read_data(BKP_DATA_LSI_CALIB);
if (prescaler == 0) {
prescaler = 40000; //40khz
}
break;
case BKP_RTC_CLOCK_SRC_HSE:
prescaler = 62500; //8Mhz / 128
break;
default:
return 0;
}
return (period_ms * prescaler) / 1000;
}
/**
* LSI callibration callback. Measures the LSI deviation from its theorical
* frequency using the RTC and stores the effective frequency for calibration
* purposes
*/
static void lsi_calib_callback(enum TimIRQSource src)
{
if (src == TIM_IRQ_SOURCE_UPDATE) {
//div is decremented from 40kHz * programmed delay (in s)
uint32_t lsi_freq = (40000 * 2) - bkp_read_rtc_div();
bkp_write_data(BKP_DATA_LSI_CALIB, lsi_freq);
}
}
//--ISRs------------------------------------------------------------------------
void hdr_rtc(void)
{
nvic_clear_pending(NVIC_IRQ_RTC);
//copy and clear and pass along src flags
enum BkpRtcIrq src = rtc_regs->CRL.word & 0x7;
rtc_regs->CRL.word &= ~(0x7);
rtc_callback(src);
}

137
drv/bkp.h Normal file
View File

@ -0,0 +1,137 @@
/** @file bkp.h
* Module handling the Backup (BKP) domain functionalities.
*
* This module includes management of the Real Time Clock (RTC), Tamper
* protection system and a limited space (20 bytes) for persistent data storage
*
* All features present in this module stay running in standby mode / when
* no-longer powered, so long as VBAT is maintained
*/
#ifndef _BKP_H_
#define _BKP_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
#include "tim.h"
//--type definitions------------------------------------------------------------
/**
* Available clock sources for the RTC. See bkp_configure_rtc() for more
* information
*/
enum BkpRtcClockSrc {
BKP_RTC_CLOCK_SRC_LSE = 0x0,
BKP_RTC_CLOCK_SRC_LSI = 0x1,
BKP_RTC_CLOCK_SRC_HSE = 0x2,
};
/**
* Available IRQ sources. This enum is passed to the RTC callback to allow
* differentiating IRQ sources
*/
enum BkpRtcIrq {
BKP_RTC_IRQ_NONE = 0,
BKP_RTC_IRQ_SECOND = 0x1 << 0,
BKP_RTC_IRQ_ALARM = 0x1 << 1,
BKP_RTC_IRQ_OVERFLOW = 0x1 << 2,
};
enum BkpData {
BKP_DATA_LSI_CALIB,
BKP_DATA_1,
BKP_DATA_2,
BKP_DATA_3,
BKP_DATA_4,
BKP_DATA_5,
BKP_DATA_6,
BKP_DATA_7,
BKP_DATA_8,
BKP_DATA_9,
};
/**
* Prototype of the IRQ callbacks that the applicative code can provide
*/
typedef void (*BkpRtcCallback)(enum BkpRtcIrq src);
//--functions-------------------------------------------------------------------
/**
* Configures the RTC, starting it immediately. Configuration is saved between
* boots as long as VBAT is present
*
* The RTC can run on a period of up to 1s and using one of 3 clocks. Clock
* choice is a question of compromise :
* - LSE consumes the less energy and continues to run in standby mode, but
* requires an extra oscillator circuit
* - LSI consumes little but isn't very accurate and requires extra calibration
* (see bkp_callibrate_lsi). The calibration value is automatically used if
* present when calling this function.
* - HSE consumes the most.
* WARNING : once configured, the clock source can only changed by reseting the
* whole backup domain via bkp_reset()
* Clocks must be enabled prior to calling this function
*
* Mulitple IRQs can be enabled and redirected to single callback. The alarm
* IRQ, triggered at the tick value specified by bkp_set_rtc_alam() can be
* rerouted to an exti line for wakeup from stop and standby, in wich case it
* doesn't need to be enabled here.
*
* Ensure backup domain writes are enabled (see pwr_configure_bkp_write()) while
* calling this function
*/
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, BkpRtcCallback callback);
/**
* Configure the alarm to trigger after the specified time in ticks, which can
* be viewed as an offset to the current time value. This offset is only precise
* to the tick and thus if the tick changes right after this function is
* called, the observed offset will be close to 1 tick short
*/
void bkp_set_rtc_alam(uint32_t offset);
/**
* Returns the current counter value of the RTC
*/
uint32_t bkp_read_rtc(void);
uint32_t bkp_read_rtc_div(void);
/**
* Resets the entire backup domain, composed of everything configured through
* this module
*/
void bkp_reset(void);
/**
* Writes data to the specified backup domain index. The data will persist as
* long as VBAT is present
*/
void bkp_write_data(enum BkpData data_index, uint16_t data);
/**
* Writes data from the specified backup domain data index. The data will
* persist as long as VBAT is present
*/
uint16_t bkp_read_data(enum BkpData data_index);
/**
* Calibrate the LSI oscillator using the specified timer for accurate RTC
* timings and store the calibration value at backup domain index
* BKP_DATA_LSI_CALIB. This function has no effect if a calibration value is
* already present
*/
void bkp_calibrate_lsi(enum TimPeriph timer);
//unimplemented functions
void bkp_configure_tamper();
void bkp_configure_lse(bool enable);
#endif //_BKP_H_

197
drv/bkp_regs.h Normal file
View File

@ -0,0 +1,197 @@
/** @file bkp_regs.h
* Module defining the Backup (bkp) domain registers.
*
* Mainly made to be used by the bkp module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _BKP_REGS_H_
#define _BKP_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define BKP_BASE_ADDRESS 0x40006C00
#define RCC_BASE_ADDRESS 0x40021020
#define RTC_BASE_ADDRESS 0x40002800
union BKP_DR {
struct {
uint32_t D:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union BKP_RTCCR {
struct {
uint32_t CAL:7;
uint32_t CCO:1;
uint32_t ASOE:1;
uint32_t ASOS:1;
uint32_t reserved1:22;
};
uint32_t word;
};
union BKP_CR {
struct {
uint32_t TPE:1;
uint32_t TPAL:1;
uint32_t reserved1:30;
};
uint32_t word;
};
union BKP_CSR {
struct {
uint32_t CTE:1;
uint32_t CTI:1;
uint32_t TPIE:1;
uint32_t reserved1:5;
uint32_t TEF:1;
uint32_t TIF:1;
uint32_t reserved2:22;
};
uint32_t word;
};
struct BKP {
uint32_t reserved1;
union BKP_DR DR[20];
union BKP_RTCCR RTCCR;
union BKP_CR CR;
union BKP_CSR CSR;
};
union RCC_BDCR {
struct {
uint32_t LSEON:1;
uint32_t LSERDY:1;
uint32_t LSEBYP:1;
uint32_t reserved1:5;
uint32_t RTCSEL:2;
uint32_t reserved2:5;
uint32_t RTCEN:1;
uint32_t BDRST:1;
uint32_t reserved3:15;
};
uint32_t word;
};
struct RCC {
union RCC_BDCR BDCR;
};
union RTC_CRH {
struct {
uint32_t SECIE:1;
uint32_t ALRIE:1;
uint32_t OWIE:1;
uint32_t reserved1:29;
};
uint32_t word;
};
union RTC_CRL {
struct {
uint32_t SECF:1;
uint32_t ALRF:1;
uint32_t OWF:1;
uint32_t RSF:1;
uint32_t CNF:1;
uint32_t RTOFF:1;
uint32_t reserved1:26;
};
uint32_t word;
};
union RTC_PRLH {
struct {
uint32_t PRL:4;
uint32_t reserved1:28;
};
uint32_t word;
};
union RTC_PRLL {
struct {
uint32_t PRL:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_DIVH {
struct {
uint32_t RTC_DIV:4;
uint32_t reserved1:28;
};
uint32_t word;
};
union RTC_DIVL {
struct {
uint32_t RTC_DIV:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_CNTH {
struct {
uint32_t RTC_CNT:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_CNTL {
struct {
uint32_t RTC_CNT:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_ALRH {
struct {
uint32_t RTC_ALR:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union RTC_ALRL {
struct {
uint32_t RTC_ALR:16;
uint32_t reserved1:16;
};
uint32_t word;
};
struct RTC {
union RTC_CRH CRH;
union RTC_CRL CRL;
union RTC_PRLH PRLH;
union RTC_PRLL PRLL;
union RTC_DIVH DIVH;
union RTC_DIVL DIVL;
union RTC_CNTH CNTH;
union RTC_CNTL CNTL;
union RTC_ALRH ALRH;
union RTC_ALRL ALRL;
};
//--functions-------------------------------------------------------------------
#endif //_BKP_REGS_H_

335
drv/dma.c Normal file
View File

@ -0,0 +1,335 @@
/** @file dma.h
* Module handling Direct Memory Access controller
*
* The module provides functions to configure the dma channels and controller
* transfers
*/
//--includes--------------------------------------------------------------------
#include "dma.h"
#include "dma_regs.h"
#include "nvic.h"
#include "rcc.h"
#include "stddef.h"
//--local definitions-----------------------------------------------------------
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph);
static void start_dma(volatile struct DMA* dma, enum DmaChannel channel,
volatile void* mem, uint16_t size);
//--local variables-------------------------------------------------------------
static volatile struct DMA* const dma1 = (struct DMA*)DMA1_BASE_ADDRESS;
static volatile struct DMA* const dma2 = (struct DMA*)DMA2_BASE_ADDRESS;
static DmaCallback dma1_callbacks[7];
static volatile void* dma1_cb_params[7];
static DmaCallback dma2_callbacks[5];
static volatile void* dma2_cb_params[5];
//--public functions------------------------------------------------------------
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph,
DmaCallback callback, volatile void* cb_param)
{
//reset peripheral first, to ensure proper configuration
dma_reset(dma, channel);
switch (dma) {
case DMA_PERIPH_1:
rcc_enable(RCC_AHB_DMA1, RCC_APB1_NONE, RCC_APB2_NONE);
configure_dma(dma1, channel, config_mask, periph);
if (callback) {
dma1_callbacks[channel] = callback;
dma1_cb_params[channel] = cb_param;
nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
}
break;
case DMA_PERIPH_2:
rcc_enable(RCC_AHB_DMA2, RCC_APB1_NONE, RCC_APB2_NONE);
configure_dma(dma2, channel, config_mask, periph);
if (callback) {
dma2_callbacks[channel] = callback;
dma2_cb_params[channel] = cb_param;
nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
}
break;
default:
break;
}
}
void dma_reset(enum DmaPeriph dma, enum DmaChannel channel)
{
volatile struct DMA* periph;
//first, disable IRQs
switch (dma) {
case DMA_PERIPH_1:
periph = dma1;
dma1_callbacks[channel] = NULL;
nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
break;
case DMA_PERIPH_2:
periph = dma2;
dma2_callbacks[channel] = NULL;
nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
break;
default:
return;
break;
}
//then, set all registers to reset value
volatile struct DMA_CHANNEL* regs = &periph->CHANNELS[channel];
regs->CCR.word = 0;
regs->CNDTR.word = 0;
regs->CMAR = 0;
regs->CPAR = 0;
}
void dma_start(enum DmaPeriph dma, enum DmaChannel channel,
volatile void* mem, uint16_t size)
{
switch (dma) {
case DMA_PERIPH_1:
if (dma1_callbacks[channel]) {
nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
}
start_dma(dma1, channel, mem, size);
break;
case DMA_PERIPH_2:
if (dma2_callbacks[channel]) {
nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
}
start_dma(dma2, channel, mem, size);
break;
default:
return;
break;
}
}
void dma_stop(enum DmaPeriph dma, enum DmaChannel channel)
{
switch (dma) {
case DMA_PERIPH_1:
dma1->CHANNELS[channel].CCR.EN = 0;
if (dma1_callbacks[channel]) {
nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
}
break;
case DMA_PERIPH_2:
dma2->CHANNELS[channel].CCR.EN;
if (dma2_callbacks[channel]) {
nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
}
break;
default:
return;
break;
}
}
void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel)
{
switch (dma) {
case DMA_PERIPH_1:
nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
break;
case DMA_PERIPH_2:
nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
break;
default:
return;
break;
}
}
void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel)
{
switch (dma) {
case DMA_PERIPH_1:
nvic_enable(NVIC_IRQ_DMA1_CHANNEL1 + channel);
break;
case DMA_PERIPH_2:
nvic_enable(NVIC_IRQ_DMA2_CHANNEL1 + channel);
break;
default:
return;
break;
}
}
uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channel)
{
switch (dma) {
case DMA_PERIPH_1:
return dma1->CHANNELS[channel].CNDTR.NDT;
break;
case DMA_PERIPH_2:
return dma2->CHANNELS[channel].CNDTR.NDT;
break;
default:
return 0;
break;
}
}
//--local functions-------------------------------------------------------------
/**
* Applies the given configuration mask to the given DMA channel
*/
static void configure_dma(volatile struct DMA* dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph)
{
volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel];
//registers should already be at reset value, apply new config
regs->CCR.word = config_mask;
regs->CPAR = (uint32_t)periph;
}
/**
* Starts the given DMA channel using the given parameters
*/
static void start_dma(volatile struct DMA* dma, enum DmaChannel channel,
volatile void* mem, uint16_t size)
{
volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel];
//registers should already be configured, apply transfer config
regs->CNDTR.NDT = size;
regs->CMAR = (uint32_t)mem;
//only start transfer when everything is configured
regs->CCR.EN = 1;
}
//--ISRs------------------------------------------------------------------------
void hdr_dma1_channel1(void)
{
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL1);
enum DmaIRQSource src = (dma1->IFCR.word >> 1) & 0x7;
dma1->IFCR.CGIF1 = 1;
dma1_callbacks[0](src, dma1_cb_params[0]);
}
void hdr_dma1_channel2(void)
{
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL2);
enum DmaIRQSource src = (dma1->IFCR.word >> 5) & 0x7;
dma1->IFCR.CGIF2 = 1;
dma1_callbacks[1](src, dma1_cb_params[1]);
}
void hdr_dma1_channel3(void)
{
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL3);
enum DmaIRQSource src = (dma1->IFCR.word >> 9) & 0x7;
dma1->IFCR.CGIF3 = 1;
dma1_callbacks[2](src, dma1_cb_params[2]);
}
void hdr_dma1_channel4(void)
{
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL4);
enum DmaIRQSource src = (dma1->IFCR.word >> 13) & 0x7;
dma1->IFCR.CGIF4 = 1;
dma1_callbacks[3](src, dma1_cb_params[3]);
}
void hdr_dma1_channel5(void)
{
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL5);
enum DmaIRQSource src = (dma1->IFCR.word >> 17) & 0x7;
dma1->IFCR.CGIF5 = 1;
dma1_callbacks[4](src, dma1_cb_params[4]);
}
void hdr_dma1_channel6(void)
{
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL6);
enum DmaIRQSource src = (dma1->IFCR.word >> 21) & 0x7;
dma1->IFCR.CGIF6 = 1;
dma1_callbacks[5](src, dma1_cb_params[5]);
}
void hdr_dma1_channel7(void)
{
nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL7);
enum DmaIRQSource src = (dma1->IFCR.word >> 25) & 0x7;
dma1->IFCR.CGIF7 = 1;
dma1_callbacks[6](src, dma1_cb_params[6]);
}
void hdr_dma2_channel1(void)
{
nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL1);
enum DmaIRQSource src = (dma2->IFCR.word >> 1) & 0x7;
dma2->IFCR.CGIF1 = 1;
dma2_callbacks[0](src, dma2_cb_params[0]);
}
void hdr_dma2_channel2(void)
{
nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL2);
enum DmaIRQSource src = (dma2->IFCR.word >> 5) & 0x7;
dma2->IFCR.CGIF2 = 1;
dma2_callbacks[1](src, dma2_cb_params[1]);
}
void hdr_dma2_channel3(void)
{
nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL3);
enum DmaIRQSource src = (dma2->IFCR.word >> 9) & 0x7;
dma2->IFCR.CGIF3 = 1;
dma2_callbacks[2](src, dma2_cb_params[2]);
}
void hdr_dma2_channel4_5(void)
{
nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL4_5);
enum DmaIRQSource src = (dma2->IFCR.word >> 13) & 0x7;
if (src != 0) {
dma2->IFCR.CGIF4 = 1;
dma1_callbacks[3](src, dma2_cb_params[3]);
}
src = (dma2->IFCR.word >> 17) & 0x7;
if (src != 0) {
dma2->IFCR.CGIF5 = 1;
dma1_callbacks[4](src, dma2_cb_params[4]);
}
}

180
drv/dma.h Normal file
View File

@ -0,0 +1,180 @@
/** @file dma.h
* Module handling Direct Memory Access controller
*
* The module provides functions to configure the dma channels and controller
* transfers
*/
#ifndef _DMA_H_
#define _DMA_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
/**
* Available DMA peripherals. Note that some of these peripherals may not be
* available on all chips
*/
enum DmaPeriph {
DMA_PERIPH_1,
DMA_PERIPH_2,
};
/**
* Available DMA channels. Note that some of these channels may not be
* available on all chips and all DMA peripheral
*/
enum DmaChannel {
DMA_CHANNEL_1 = 0,
DMA_CHANNEL_2,
DMA_CHANNEL_3,
DMA_CHANNEL_4,
DMA_CHANNEL_5,
DMA_CHANNEL_6, //not available for DMA 2
DMA_CHANNEL_7, //not available for DMA 2
};
/**
* Configuration options for memory-to-peripheral transfers
*/
enum DmaConfig {
DMA_CONFIG_IRQ_COMPLETE = (0x1 << 1),
DMA_CONFIG_IRQ_HALF = (0x1 << 2),
DMA_CONFIG_IRQ_ERROR = (0x1 << 3),
DMA_CONFIG_FROM_MEM = (0x1 << 4),
DMA_CONFIG_FROM_PERIPH = (0x0 << 4),
DMA_CONFIG_CIRCULAR = (0x1 << 5),
DMA_CONFIG_INC_PERIPH = (0x1 << 6),
DMA_CONFIG_INC_MEM = (0x1 << 7),
DMA_CONFIG_PSIZE_8BITS = (0x0 << 8),
DMA_CONFIG_PSIZE_16BITS = (0x1 << 8),
DMA_CONFIG_PSIZE_32BITS = (0x2 << 8),
DMA_CONFIG_MSIZE_8BITS = (0x0 << 10),
DMA_CONFIG_MSIZE_16BITS = (0x1 << 10),
DMA_CONFIG_MSIZE_32BITS = (0x2 << 10),
DMA_CONFIG_PRIO_LOW = (0x0 << 12),
DMA_CONFIG_PRIO_MEDIUM = (0x1 << 12),
DMA_CONFIG_PRIO_HIGH = (0x2 << 12),
DMA_CONFIG_PRIO_VHIGH = (0x3 << 12),
};
/**
* Configuration options for memory-to-memory transfers
*/
enum DmaConfigM2M {
DMA_CONFIG_M2M_IRQ_COMPLETE = (0x1 << 1),
DMA_CONFIG_M2M_IRQ_HALF = (0x1 << 2),
DMA_CONFIG_M2M_IRQ_ERROR = (0x1 << 3),
DMA_CONFIG_M2M_INC_SRC = (0x1 << 6),
DMA_CONFIG_M2M_INC_DEST = (0x1 << 7),
DMA_CONFIG_M2M_SSIZE_8BITS = (0x0 << 8),
DMA_CONFIG_M2M_SSIZE_16BITS = (0x1 << 8),
DMA_CONFIG_M2M_SSIZE_32BITS = (0x2 << 8),
DMA_CONFIG_M2M_DSIZE_8BITS = (0x0 << 10),
DMA_CONFIG_M2M_DSIZE_16BITS = (0x1 << 10),
DMA_CONFIG_M2M_DSIZE_32BITS = (0x2 << 10),
DMA_CONFIG_M2M_PRIO_LOW = (0x0 << 12),
DMA_CONFIG_M2M_PRIO_MEDIUM = (0x1 << 12),
DMA_CONFIG_M2M_PRIO_HIGH = (0x2 << 12),
DMA_CONFIG_M2M_PRIO_VHIGH = (0x3 << 12),
};
/**
* Available sources for a DMA IRQ. These sources can be enabled independently
* in the DMA configuration.
*/
enum DmaIRQSource {
DMA_IRQ_SOURCE_COMPLETE = (0x1 << 1),
DMA_IRQ_SOURCE_HALF = (0x1 << 2),
DMA_IQR_SOURCE_ERROR = (0x2 << 3),
};
/**
* Prototype of the IRQ callbacks that the applicative code can provide
*/
typedef void (*DmaCallback)(enum DmaIRQSource src, volatile void* param);
/**
* Generic struct used to share DAM configs between peripheral drivers and
* services providing DMA interfaces
*/
struct DmaParam {
void* periph;
enum DmaConfig config; //DMA config, must correspond to peripheral
enum DmaPeriph dma; //DMA peripheral, must correspond to peripheral
enum DmaChannel channel; //DMA channel, must correspond to peripheral
};
//--functions-------------------------------------------------------------------
/**
* Configures the given DMA channel with the provided configuration, to perform
* a transfer to or from the given peripheral register. The specified callback,
* if any, will be called on the enabled IRQ sources, with the specified
* parameter, if any.
*
* This function doesn't initiate transfers, use dma_start() for that
*/
void dma_configure(enum DmaPeriph dma, enum DmaChannel channel,
enum DmaConfig config_mask, volatile void* periph,
DmaCallback callback, volatile void* cb_param);
/**
* Unimplemented
*/
void dma_configure_mem2mem(enum DmaPeriph dma, enum DmaChannel channel,
enum DmaConfigM2M config_mask, const void* src, void* dest,
uint16_t size, DmaCallback callback, void* cb_param);
/**
* Resets the given DMA channel, restoring the default configuration and
* disabling it
*/
void dma_reset(enum DmaPeriph dma, enum DmaChannel channel);
/**
* Initiate a transfer on the given DMA channel, to or from the given memory
* address, and of the specified size.
*
* Should only be used after the channel has been configured through
* dma_configure()
* All transfers started must be eventually stopped, or the channel reset, for
* proper IRQ behavior.
*/
void dma_start(enum DmaPeriph dma, enum DmaChannel channel,
volatile void* mem, uint16_t size);
/**
* Stops a transfer on the given DMA channel. If the transfer has already
* ended, properly shutdown the channel. Configuration is not lost after calling
* this function and dma_start() may be called again
*/
void dma_stop(enum DmaPeriph dma, enum DmaChannel channel);
/**
* Enters a DMA critical section, disabling the given channel's IRQs until
* dma_exit_critical() is called
*/
void dma_enter_critical(enum DmaPeriph dma, enum DmaChannel channel);
/**
* Exists a DMA critical section previously entered through
* dma_enter_critical(). Reenables the given channel's IRQs
*/
void dma_exit_critical(enum DmaPeriph dma, enum DmaChannel channel);
/**
* Returns the remaining number of bytes to be transmitted while a transfer is
* running. When no transfer is running, returns the number of bytes to transfer
* next
*/
uint16_t dma_get_remaining(enum DmaPeriph dma, enum DmaChannel channe);
#endif //_DMA_H_

137
drv/dma_regs.h Normal file
View File

@ -0,0 +1,137 @@
/** @file dma_regs.h
* Module defining the DMA registers.
*
* Mainly made to be used by the dma module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _DMA_REGS_H_
#define _DMA_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define DMA1_BASE_ADDRESS 0x40020000
#define DMA2_BASE_ADDRESS 0x40020400
union DMA_ISR {
struct {
uint32_t GIF1:1;
uint32_t TCIF1:1;
uint32_t HTIF1:1;
uint32_t TEIF1:1;
uint32_t GIF2:1;
uint32_t TCIF2:1;
uint32_t HTIF2:1;
uint32_t TEIF2:1;
uint32_t GIF3:1;
uint32_t TCIF3:1;
uint32_t HTIF3:1;
uint32_t TEIF3:1;
uint32_t GIF4:1;
uint32_t TCIF4:1;
uint32_t HTIF4:1;
uint32_t TEIF4:1;
uint32_t GIF5:1;
uint32_t TCIF5:1;
uint32_t HTIF5:1;
uint32_t TEIF5:1;
uint32_t GIF6:1;
uint32_t TCIF6:1;
uint32_t HTIF6:1;
uint32_t TEIF6:1;
uint32_t GIF7:1;
uint32_t TCIF7:1;
uint32_t HTIF7:1;
uint32_t TEIF7:1;
uint32_t reserved1:4;
};
uint32_t word;
};
union DMA_IFCR {
struct {
uint32_t CGIF1:1;
uint32_t CTCIF1:1;
uint32_t CHTIF1:1;
uint32_t CTEIF1:1;
uint32_t CGIF2:1;
uint32_t CTCIF2:1;
uint32_t CHTIF2:1;
uint32_t CTEIF2:1;
uint32_t CGIF3:1;
uint32_t CTCIF3:1;
uint32_t CHTIF3:1;
uint32_t CTEIF3:1;
uint32_t CGIF4:1;
uint32_t CTCIF4:1;
uint32_t CHTIF4:1;
uint32_t CTEIF4:1;
uint32_t CGIF5:1;
uint32_t CTCIF5:1;
uint32_t CHTIF5:1;
uint32_t CTEIF5:1;
uint32_t CGIF6:1;
uint32_t CTCIF6:1;
uint32_t CHTIF6:1;
uint32_t CTEIF6:1;
uint32_t CGIF7:1;
uint32_t CTCIF7:1;
uint32_t CHTIF7:1;
uint32_t CTEIF7:1;
uint32_t reserved1:4;
};
uint32_t word;
};
union DMA_CCR {
struct {
uint32_t EN:1;
uint32_t TCIE:1;
uint32_t HTIE:1;
uint32_t TEIE:1;
uint32_t DIR:1;
uint32_t CIRC:1;
uint32_t PINC:1;
uint32_t MINC:1;
uint32_t PSIZE:2;
uint32_t MSIZE:2;
uint32_t PL:2;
uint32_t MEM2MEM:1;
uint32_t reserved1:17;
};
uint32_t word;
};
union DMA_CNDTR {
struct {
uint32_t NDT:16;
uint32_t reserved1:16;
};
uint32_t word;
};
struct DMA_CHANNEL {
union DMA_CCR CCR;
union DMA_CNDTR CNDTR;
uint32_t CPAR;
uint32_t CMAR;
uint32_t reserved1;
};
struct DMA {
union DMA_ISR ISR;
union DMA_IFCR IFCR;
struct DMA_CHANNEL CHANNELS[7];
};
//--functions-------------------------------------------------------------------
#endif //_DMA_REGS_H_

225
drv/exti.c Normal file
View File

@ -0,0 +1,225 @@
/** @file exti.c
* Module handling EXTernal Interrupt lines
*
* The module provides functions to configure the exti lines to generate events
* or interrupts
*/
//--includes--------------------------------------------------------------------
#include "exti.h"
#include "exti_regs.h"
#include "nvic.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct EXTI* regs = (struct EXTI*)EXTI_BASE_ADDRESS;
static ExtiCallback callbacks[19];
//--public functions------------------------------------------------------------
void exti_configure(enum ExtiLine line_mask, enum ExtiConfig config_mask,
ExtiCallback callback)
{
exti_reset(line_mask);
//configure edge detections
if (config_mask & EXTI_CONFIG_RISING_EDGE) {
regs->RTSR.word |= line_mask;
} else {
regs->RTSR.word &= ~line_mask;
}
if (config_mask & EXTI_CONFIG_FALLING_EDGE) {
regs->FTSR.word |= line_mask;
} else {
regs->FTSR.word &= ~line_mask;
}
//reconfigure events/irqs
regs->EMR.word |= line_mask;
if (callback) {
//register callbacks for each line selected
for (uint8_t i = 0; i < 19; ++i) {
if (line_mask & (0x1 << i)) {
callbacks[i] = callback;
}
}
//enable interrupts lines in nvic
for (uint8_t i = 0; i < 5; ++i) {
if (line_mask & (0x1 << i)) {
nvic_enable(NVIC_IRQ_EXTI0 + i);
}
}
if (line_mask & 0x3e0) {
nvic_enable(NVIC_IRQ_EXTI9_5);
}
if (line_mask & 0x7c00) {
nvic_enable(NVIC_IRQ_EXTI15_10);
}
if (line_mask & EXTI_LINE_PVD) {
nvic_enable(NVIC_IRQ_PVD);
}
if (line_mask & EXTI_LINE_RTC) {
nvic_enable(NVIC_IRQ_RTC_ALARM);
}
if (line_mask & EXTI_LINE_USB) {
nvic_enable(NVIC_IRQ_USB_WAKEUP);
}
//enable irqs in last to avoid triggers during config
regs->IMR.word |= line_mask;
}
}
void exti_reset(enum ExtiLine line_mask)
{
//disable events/irqs
regs->IMR.word &= ~line_mask;
regs->EMR.word &= ~line_mask;
//clear any pending bits
regs->PR.word |= line_mask;
//disable interrupts lines in nvic
for (uint8_t i = 0; i < 5; ++i) {
if (line_mask & (0x1 << i)) {
nvic_disable(NVIC_IRQ_EXTI0 + i);
}
}
if (line_mask & 0x3e0) {
nvic_disable(NVIC_IRQ_EXTI9_5);
}
if (line_mask & 0x7c00) {
nvic_disable(NVIC_IRQ_EXTI15_10);
}
//disable events/irqs
regs->IMR.word &= ~line_mask;
regs->EMR.word &= ~line_mask;
//clear any pending bits
regs->PR.word |= line_mask;
//disable interrupts lines in nvic
if (line_mask & EXTI_LINE_PVD) {
nvic_disable(NVIC_IRQ_PVD);
}
if (line_mask & EXTI_LINE_RTC) {
nvic_disable(NVIC_IRQ_RTC_ALARM);
}
if (line_mask & EXTI_LINE_USB) {
nvic_disable(NVIC_IRQ_USB_WAKEUP);
}
}
void exti_reset_peripheral(void)
{
//reset peripheral config
regs->IMR.word = 0;
regs->EMR.word = 0;
regs->RTSR.word = 0;
regs->FTSR.word = 0;
regs->SWIER.word = 0;
regs->PR.word = 0;
//disable interrupts in nvic
for (uint8_t i = 0; i < 5; ++i) {
nvic_enable(NVIC_IRQ_EXTI0 + i);
}
nvic_enable(NVIC_IRQ_EXTI9_5);
nvic_enable(NVIC_IRQ_EXTI15_10);
nvic_disable(NVIC_IRQ_PVD);
nvic_disable(NVIC_IRQ_RTC_ALARM);
nvic_disable(NVIC_IRQ_USB_WAKEUP);
}
//--local functions-------------------------------------------------------------
//--ISRs------------------------------------------------------------------------
void hdr_exti0(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI0);
regs->PR.PR0 = 1;
callbacks[0]();
}
void hdr_exti1(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI1);
regs->PR.PR1 = 1;
callbacks[1]();
}
void hdr_exti2(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI2);
regs->PR.PR2 = 1;
callbacks[2]();
}
void hdr_exti3(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI3);
regs->PR.PR3 = 1;
callbacks[3]();
}
void hdr_exti4(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI4);
regs->PR.PR4 = 1;
callbacks[4]();
}
void hdr_exti9_5(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI9_5);
for (uint8_t i = 5; i < 10; ++i) {
if (regs->PR.word & (0x1 << i)) {
regs->PR.word |= 0x1 << i;
callbacks[i]();
}
}
}
void hdr_exti15_10(void)
{
nvic_clear_pending(NVIC_IRQ_EXTI15_10);
for (uint8_t i = 10; i < 16; ++i) {
if (regs->PR.word & (0x1 << i)) {
regs->PR.word |= 0x1 << i;
callbacks[i]();
}
}
}
void hdr_pvd(void)
{
nvic_clear_pending(NVIC_IRQ_PVD);
regs->PR.PR16 = 1;
callbacks[16]();
}
void hdr_rtc_alarm(void)
{
nvic_clear_pending(NVIC_IRQ_RTC_ALARM);
regs->PR.PR17 = 1;
callbacks[17]();
}
void hdr_usb_wakeup(void)
{
nvic_clear_pending(NVIC_IRQ_USB_WAKEUP);
regs->PR.PR18 = 1;
callbacks[18]();
}

88
drv/exti.h Normal file
View File

@ -0,0 +1,88 @@
/** @file exti.h
* Module handling EXTernal Interrupt lines
*
* The module provides functions to configure the exti lines to generate events
* or interrupts
*/
#ifndef _EXTI_H_
#define _EXTI_H_
//--includes--------------------------------------------------------------------
//--type definitions------------------------------------------------------------
/**
* Available exti lines. The numbered lines correspond to gpios while the
* remaining are directly mapped to peripherals
*/
enum ExtiLine {
EXTI_LINE_0 = (0x1 << 0),
EXTI_LINE_1 = (0x1 << 1),
EXTI_LINE_2 = (0x1 << 2),
EXTI_LINE_3 = (0x1 << 3),
EXTI_LINE_4 = (0x1 << 4),
EXTI_LINE_5 = (0x1 << 5),
EXTI_LINE_6 = (0x1 << 6),
EXTI_LINE_7 = (0x1 << 7),
EXTI_LINE_8 = (0x1 << 8),
EXTI_LINE_9 = (0x1 << 9),
EXTI_LINE_10 = (0x1 << 10),
EXTI_LINE_11 = (0x1 << 11),
EXTI_LINE_12 = (0x1 << 12),
EXTI_LINE_13 = (0x1 << 13),
EXTI_LINE_14 = (0x1 << 14),
EXTI_LINE_15 = (0x1 << 15),
EXTI_LINE_PVD = (0x1 << 16),
EXTI_LINE_RTC = (0x1 << 17),
EXTI_LINE_USB = (0x1 << 18),
};
/**
* Available configurations for exti lines. These configurations apply to both
* regular and specific lines and can be used together on a single line
*/
enum ExtiConfig {
EXTI_CONFIG_RISING_EDGE = (0x1 << 0),
EXTI_CONFIG_FALLING_EDGE = (0x1 << 1),
};
typedef void (*ExtiCallback)(void);
//--functions-------------------------------------------------------------------
/**
* Configure lines to call a single callback. The ExtiLine enum can be used as a
* mask to configure multiple lines at the same time.
*
* Every numbered line must be linked to a gpio port using afio_map_exti(). Each
* line is linked to the pins of the same id (ex : pin 1 for exti 1). When
* possible, it is recommended to use the lowest id possible for better
* performance. Each pin must be configured independently through the gpio
* driver module
*
* The remaining lines are linked to specific peripherals which must be
* configured independently through the corresponding driver module.
*
* The ExtiConfig enum can be used as mask. If no callback is specified, the
* interrupt won't be enabled, but an event will still be sent to wake the cpu
* up.
*/
void exti_configure(enum ExtiLine line_mask, enum ExtiConfig config_mask,
ExtiCallback callback);
/**
* Resets lines. The ExtiLine enum can be used as a mask to reset multiple lines
* at the same time
*/
void exti_reset(enum ExtiLine line_mask);
/**
* Resets all lines. The exti peripheral is returned to its reset configuration
*/
void exti_reset_peripheral(void);
#endif //_EXTI_H_

190
drv/exti_regs.h Normal file
View File

@ -0,0 +1,190 @@
/** @file exti_regs.h
* Module defining the EXTI registers
*
* Mainly made to be used by the exti module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _EXTI_REGS_H_
#define _EXTI_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define EXTI_BASE_ADDRESS 0x40010400
union EXTI_IMR {
struct {
uint32_t MR0:1;
uint32_t MR1:1;
uint32_t MR2:1;
uint32_t MR3:1;
uint32_t MR4:1;
uint32_t MR5:1;
uint32_t MR6:1;
uint32_t MR7:1;
uint32_t MR8:1;
uint32_t MR9:1;
uint32_t MR10:1;
uint32_t MR11:1;
uint32_t MR12:1;
uint32_t MR13:1;
uint32_t MR14:1;
uint32_t MR15:1;
uint32_t MR16:1;
uint32_t MR17:1;
uint32_t MR18:1;
uint32_t reserved1:13;
};
uint32_t word;
};
union EXTI_EMR {
struct {
uint32_t MR0:1;
uint32_t MR1:1;
uint32_t MR2:1;
uint32_t MR3:1;
uint32_t MR4:1;
uint32_t MR5:1;
uint32_t MR6:1;
uint32_t MR7:1;
uint32_t MR8:1;
uint32_t MR9:1;
uint32_t MR10:1;
uint32_t MR11:1;
uint32_t MR12:1;
uint32_t MR13:1;
uint32_t MR14:1;
uint32_t MR15:1;
uint32_t MR16:1;
uint32_t MR17:1;
uint32_t MR18:1;
uint32_t reserved1:13;
};
uint32_t word;
};
union EXTI_RTSR {
struct {
uint32_t TR0:1;
uint32_t TR1:1;
uint32_t TR2:1;
uint32_t TR3:1;
uint32_t TR4:1;
uint32_t TR5:1;
uint32_t TR6:1;
uint32_t TR7:1;
uint32_t TR8:1;
uint32_t TR9:1;
uint32_t TR10:1;
uint32_t TR11:1;
uint32_t TR12:1;
uint32_t TR13:1;
uint32_t TR14:1;
uint32_t TR15:1;
uint32_t TR16:1;
uint32_t TR17:1;
uint32_t TR18:1;
uint32_t reserved1:13;
};
uint32_t word;
};
union EXTI_FTSR {
struct {
uint32_t TR0:1;
uint32_t TR1:1;
uint32_t TR2:1;
uint32_t TR3:1;
uint32_t TR4:1;
uint32_t TR5:1;
uint32_t TR6:1;
uint32_t TR7:1;
uint32_t TR8:1;
uint32_t TR9:1;
uint32_t TR10:1;
uint32_t TR11:1;
uint32_t TR12:1;
uint32_t TR13:1;
uint32_t TR14:1;
uint32_t TR15:1;
uint32_t TR16:1;
uint32_t TR17:1;
uint32_t TR18:1;
uint32_t reserved1:13;
};
uint32_t word;
};
union EXTI_SWIER {
struct {
uint32_t SWIER0:1;
uint32_t SWIER1:1;
uint32_t SWIER2:1;
uint32_t SWIER3:1;
uint32_t SWIER4:1;
uint32_t SWIER5:1;
uint32_t SWIER6:1;
uint32_t SWIER7:1;
uint32_t SWIER8:1;
uint32_t SWIER9:1;
uint32_t SWIER10:1;
uint32_t SWIER11:1;
uint32_t SWIER12:1;
uint32_t SWIER13:1;
uint32_t SWIER14:1;
uint32_t SWIER15:1;
uint32_t SWIER16:1;
uint32_t SWIER17:1;
uint32_t SWIER18:1;
uint32_t reserved1:13;
};
uint32_t word;
};
union EXTI_PR {
struct {
uint32_t PR0:1;
uint32_t PR1:1;
uint32_t PR2:1;
uint32_t PR3:1;
uint32_t PR4:1;
uint32_t PR5:1;
uint32_t PR6:1;
uint32_t PR7:1;
uint32_t PR8:1;
uint32_t PR9:1;
uint32_t PR10:1;
uint32_t PR11:1;
uint32_t PR12:1;
uint32_t PR13:1;
uint32_t PR14:1;
uint32_t PR15:1;
uint32_t PR16:1;
uint32_t PR17:1;
uint32_t PR18:1;
uint32_t reserved1:13;
};
uint32_t word;
};
struct EXTI {
union EXTI_IMR IMR;
union EXTI_EMR EMR;
union EXTI_RTSR RTSR;
union EXTI_FTSR FTSR;
union EXTI_SWIER SWIER;
union EXTI_PR PR;
};
//--functions-------------------------------------------------------------------
#endif //_EXTI_REGS_H_

52
drv/flash.c Normal file
View File

@ -0,0 +1,52 @@
/** @file flash.c
* Module handling flash memory interface registers.
*
* The module provides functions to configure the flash and perform read and
* writes
*/
//--includes--------------------------------------------------------------------
#include "flash.h"
#include "flash_regs.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct FLASH* regs = (struct FLASH*)FLASH_BASE_ADDRESS;
//--public functions------------------------------------------------------------
/**
* Sets the correct latency to compensate the core's clock speed. Latency must
* never be too low or the system will crash due to errors when accessing the
* flash, hence the warning in the header
*/
void flash_configure(enum FlashPreset preset)
{
//restore default configuration
regs->ACR.word &= ~0x3f;
regs->ACR.word |= 0x30;
//apply new configuration
switch (preset) {
case FLASH_PRESET_LOW_CLOCK_SPEED:
regs->ACR.HLFCYA = 1; //half cycle for power saving
break;
case FLASH_PRESET_MEDIUM_CLOCK_SPEED:
regs->ACR.LATENCY = 0x1;
break;
case FLASH_PRESET_HIGH_CLOCK_SPEED:
regs->ACR.LATENCY = 0x2;
break;
default:
break;
}
}
//--local functions-------------------------------------------------------------

39
drv/flash.h Normal file
View File

@ -0,0 +1,39 @@
/** @file flash.h
* Module handling flash memory interface registers.
*
* The module provides functions to configure the flash and perform read and
* writes
*/
#ifndef _FLASH_H_
#define _FLASH_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
/**
* Available flash configuration presets
*/
enum FlashPreset {
FLASH_PRESET_LOW_CLOCK_SPEED, //for 0 < clock <= 24Mz
FLASH_PRESET_MEDIUM_CLOCK_SPEED, //for 24MHz < clock <= 48MHz
FLASH_PRESET_HIGH_CLOCK_SPEED, //for 48MHz < clock <= 72MHz
};
//--functions-------------------------------------------------------------------
/**
* Configure the flash according to the given preset. Warning: calling this
* function with a sysclk higher than 24Mhz may cause the system to crash,
* please lower the clocks first
*/
void flash_configure(enum FlashPreset preset);
#endif //_FLASH_H_

97
drv/flash_regs.h Normal file
View File

@ -0,0 +1,97 @@
/** @file flash_regs.h
* Module defining flash memory interface registers.
*
* Mainly made to be used by the rcc module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _FLASH_REGS_H_
#define _FLASH_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define FLASH_BASE_ADDRESS 0x40022000
union FLASH_ACR {
struct {
uint32_t LATENCY:3;
uint32_t HLFCYA:1;
uint32_t PRFTBE:1;
uint32_t PRFTBS:1;
uint32_t reserved1:26;
};
uint32_t word;
};
union FLASH_KEYR {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_OPTKEYR {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_SR {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_CR {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_AR {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_OBR {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
union FLASH_WRPR {
struct {
uint32_t reserved1; //TODO
};
uint32_t word;
};
struct FLASH {
union FLASH_ACR ACR;
union FLASH_KEYR KEYR;
union FLASH_OPTKEYR OPTKEYR;
union FLASH_SR SR;
union FLASH_CR CR;
union FLASH_AR AR;
uint32_t reserved1;
union FLASH_OBR OBR;
union FLASH_WRPR WRPR;
};
//--functions-------------------------------------------------------------------
#endif //_FLASH_REGS_H_

95
drv/gpio.c Normal file
View File

@ -0,0 +1,95 @@
/** @file gpio.c
* Module handling General Purpose Input/Output (GPIO) pins
*
* The module provides functions to configure the gpio pins and read from/
* write to them
*/
//--includes--------------------------------------------------------------------
#include "gpio.h"
#include "gpio_regs.h"
#include "rcc.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct GPIO* regs = (struct GPIO*)GPIO_BASE_ADDRESS;
//--public functions------------------------------------------------------------
/**
* Use the provided mask to generate its equivalent with 3 bits of padding
* between each initial bit. This new mask matches the registers layout and
* allow for direct application of the mode and config. Outputs are disabled
* prior to confiiguration to avoid any glitches. The relevant clocks are
* automatically enabled for the ports used
*/
void gpio_configure(enum GpioPort port, enum GpioPin pin_mask,
enum GpioMode mode, enum GpioConfig config)
{
//ensure gpio port is enabled
rcc_enable(RCC_AHB_NONE, RCC_APB1_NONE, RCC_APB2_IOPA << port);
//reset outputs before configuring anything
regs->PORTS[port].BRR.word = pin_mask;
//clear config for selected port, then apply new config, 8 first pins
uint32_t mask = 0;
for (uint8_t i=0; i<8; ++i)
{
if (pin_mask & (0x1 << i))
{
mask |= 0x1 << (i * 4);
}
}
regs->PORTS[port].CRL.word &= ~(0xF * mask);
regs->PORTS[port].CRL.word |= ((config << 2) | (mode << 0)) * mask;
//clear config for selected port, then apply new config, 8 last pins
mask = 0;
pin_mask = pin_mask >> 8;
for (uint8_t i=0; i<8; ++i)
{
if (pin_mask & (0x1 << i))
{
mask |= 0x1 << (i * 4);
}
}
regs->PORTS[port].CRH.word &= ~(0xF * mask);
regs->PORTS[port].CRH.word |= ((config << 2) | (mode << 0)) * mask;
}
void gpio_reset(enum GpioPort port, enum GpioPin pin_mask)
{
gpio_configure(port, pin_mask, GPIO_MODE_INPUT, GPIO_CONFIG_IN_FLOATING);
}
void gpio_write(enum GpioPort port, enum GpioPin pin_mask, bool value)
{
if (value) {
regs->PORTS[port].BSRR.word = pin_mask;
} else {
regs->PORTS[port].BRR.word = pin_mask;
}
}
bool gpio_read(enum GpioPort port, enum GpioPin pin_mask)
{
return (regs->PORTS[port].IDR.word & pin_mask) == pin_mask;
}
void gpio_reset_peripheral(void)
{
rcc_disable(RCC_AHB_NONE, RCC_APB1_NONE, RCC_APB2_IOPA | RCC_APB2_IOPB
| RCC_APB2_IOPC | RCC_APB2_IOPD | RCC_APB2_IOPE | RCC_APB2_IOPF
| RCC_APB2_IOPG);
}
//--local functions-------------------------------------------------------------

125
drv/gpio.h Normal file
View File

@ -0,0 +1,125 @@
/** @file gpio.h
* Module handling General Purpose Input/Output (GPIO) pins
*
* The module provides functions to configure the gpio pins and read from/
* write to them
*/
#ifndef _GPIO_H_
#define _GPIO_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
#include "stdbool.h"
//--type definitions------------------------------------------------------------
/**
* Available GPIO ports. Note that not all ports may be available for a
* particular chip
*/
enum GpioPort {
GPIO_PORT_A = 0,
GPIO_PORT_B,
GPIO_PORT_C,
GPIO_PORT_D,
GPIO_PORT_E,
GPIO_PORT_F,
GPIO_PORT_G,
};
/**
* Availables pin for a particular port. Note that all ports available may not
* have all the pins listed here and that some pins may be used by defaut (jtag,
* ...)
*/
enum GpioPin {
GPIO_PIN_0 = (0x1 << 0),
GPIO_PIN_1 = (0x1 << 1),
GPIO_PIN_2 = (0x1 << 2),
GPIO_PIN_3 = (0x1 << 3),
GPIO_PIN_4 = (0x1 << 4),
GPIO_PIN_5 = (0x1 << 5),
GPIO_PIN_6 = (0x1 << 6),
GPIO_PIN_7 = (0x1 << 7),
GPIO_PIN_8 = (0x1 << 8),
GPIO_PIN_9 = (0x1 << 9),
GPIO_PIN_10 = (0x1 << 10),
GPIO_PIN_11 = (0x1 << 11),
GPIO_PIN_12 = (0x1 << 12),
GPIO_PIN_13 = (0x1 << 13),
GPIO_PIN_14 = (0x1 << 14),
GPIO_PIN_15 = (0x1 << 15),
};
/**
* Available modes for a pin. To have a pin in both modes simultaneously, use
* push-pull configuration in input mode but note that the power may be
* limited
*/
enum GpioMode {
GPIO_MODE_INPUT = 0,
GPIO_MODE_OUTPUT, //10MHz max
GPIO_MODE_OUTPUT_SLOW, //2MHz max
GPIO_MODE_OUTPUT_FAST, //50MHz max
};
/**
* Available configurations for a pin. Some configurations only apply in input
* mode (denoted "IN") while others only apply in output mode (denoted "OUT")
*/
enum GpioConfig {
GPIO_CONFIG_IN_ANALOG = 0,
GPIO_CONFIG_IN_FLOATING,
GPIO_CONFIG_IN_PUSH_PULL, //use gpio_write() to configure pull_up/down
GPIO_CONFIG_OUT_PUSH_PULL = 0,
GPIO_CONFIG_OUT_OPEN_DRAIN,
GPIO_CONFIG_OUT_ALT_PUSH_PULL,
GPIO_CONFIG_OUT_ALT_OPEN_DRAIN,
};
//--functions-------------------------------------------------------------------
/**
* Configures gpio pins on a single port. The GpioPin enum can be used as mask
* to configure multiple pins at the same time. Before configuring a pin, make
* sure it isn't used somewhere else (peripherals, jtag, ...). After
* configuration, the selected output pins are set to output 0V
*/
void gpio_configure(enum GpioPort port, enum GpioPin pin_mask,
enum GpioMode mode, enum GpioConfig config);
/**
* Resets gpio pins on a single port. The GpioPin enum can be used as mask
* to reset multiple pins at the same time. This is a simple wrapper over
* gpio_configure(), setting the selected ports as floating input
*/
void gpio_reset(enum GpioPort port, enum GpioPin pin_mask);
/**
* Write a value to output gpios on a single port. The GpioPin enum can be used
* as mask to reset multiple pins at the same time. In push-pull input mode,
* configure the pull up/down. Has no effect otherwise. Writes are atomic
* operations
*/
void gpio_write(enum GpioPort port, enum GpioPin pin_mask, bool value);
/**
* Reads the value of gpios on a single port. The GpioPin enum can be used
* as mask to read multiple pins at the same time. For output pins, reads the
* pin state. Returns true if all selected ports are high
*/
bool gpio_read(enum GpioPort port, enum GpioPin pin_mask);
/**
* Resets all gpios and disable all ports. The gpio peripherals are returned to
* their reset configuration and their respective clocks disabled
*/
void gpio_reset_peripheral(void);
#endif //_GPIO_H_

215
drv/gpio_regs.h Normal file
View File

@ -0,0 +1,215 @@
/** @file gpio_regs.h
* Module defining the GPIO registers.
*
* Mainly made to be used by the gpio module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _GPIO_REGS_H_
#define _GPIO_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define GPIO_BASE_ADDRESS 0x40010800
union GPIO_CRL {
struct {
uint32_t MODE0:2;
uint32_t CNF0:2;
uint32_t MODE1:2;
uint32_t CNF1:2;
uint32_t MODE2:2;
uint32_t CNF2:2;
uint32_t MODE3:2;
uint32_t CNF3:2;
uint32_t MODE4:2;
uint32_t CNF4:2;
uint32_t MODE5:2;
uint32_t CNF5:2;
uint32_t MODE6:2;
uint32_t CNF6:2;
uint32_t MODE7:2;
uint32_t CNF7:2;
};
uint32_t word;
};
union GPIO_CRH {
struct {
uint32_t MODE8:2;
uint32_t CNF8:2;
uint32_t MODE9:2;
uint32_t CNF9:2;
uint32_t MODE10:2;
uint32_t CNF10:2;
uint32_t MODE11:2;
uint32_t CNF11:2;
uint32_t MODE12:2;
uint32_t CNF12:2;
uint32_t MODE13:2;
uint32_t CNF13:2;
uint32_t MODE14:2;
uint32_t CNF14:2;
uint32_t MODE15:2;
uint32_t CNF15:2;
};
uint32_t word;
};
union GPIO_IDR {
struct {
uint32_t IDR0:1;
uint32_t IDR1:1;
uint32_t IDR2:1;
uint32_t IDR3:1;
uint32_t IDR4:1;
uint32_t IDR5:1;
uint32_t IDR6:1;
uint32_t IDR7:1;
uint32_t IDR8:1;
uint32_t IDR9:1;
uint32_t IDR10:1;
uint32_t IDR11:1;
uint32_t IDR12:1;
uint32_t IDR13:1;
uint32_t IDR14:1;
uint32_t IDR15:1;
uint32_t reserved1:16;
};
uint32_t word;
};
union GPIO_ODR {
struct {
uint32_t ODR0:1;
uint32_t ODR1:1;
uint32_t ODR2:1;
uint32_t ODR3:1;
uint32_t ODR4:1;
uint32_t ODR5:1;
uint32_t ODR6:1;
uint32_t ODR7:1;
uint32_t ODR8:1;
uint32_t ODR9:1;
uint32_t ODR10:1;
uint32_t ODR11:1;
uint32_t ODR12:1;
uint32_t ODR13:1;
uint32_t ODR14:1;
uint32_t ODR15:1;
uint32_t reserved1:16;
};
uint32_t word;
};
union GPIO_BSRR {
struct {
uint32_t BS0:1;
uint32_t BS1:1;
uint32_t BS2:1;
uint32_t BS3:1;
uint32_t BS4:1;
uint32_t BS5:1;
uint32_t BS6:1;
uint32_t BS7:1;
uint32_t BS8:1;
uint32_t BS9:1;
uint32_t BS10:1;
uint32_t BS11:1;
uint32_t BS12:1;
uint32_t BS13:1;
uint32_t BS14:1;
uint32_t BS15:1;
uint32_t BR0:1;
uint32_t BR1:1;
uint32_t BR2:1;
uint32_t BR3:1;
uint32_t BR4:1;
uint32_t BR5:1;
uint32_t BR6:1;
uint32_t BR7:1;
uint32_t BR8:1;
uint32_t BR9:1;
uint32_t BR10:1;
uint32_t BR11:1;
uint32_t BR12:1;
uint32_t BR13:1;
uint32_t BR14:1;
uint32_t BR15:1;
};
uint32_t word;
};
union GPIO_BRR {
struct {
uint32_t BR0:1;
uint32_t BR1:1;
uint32_t BR2:1;
uint32_t BR3:1;
uint32_t BR4:1;
uint32_t BR5:1;
uint32_t BR6:1;
uint32_t BR7:1;
uint32_t BR8:1;
uint32_t BR9:1;
uint32_t BR10:1;
uint32_t BR11:1;
uint32_t BR12:1;
uint32_t BR13:1;
uint32_t BR14:1;
uint32_t BR15:1;
uint32_t reserved1:16;
};
uint32_t word;
};
union GPIO_LCKK {
struct {
uint32_t LCK0:1;
uint32_t LCK1:1;
uint32_t LCK2:1;
uint32_t LCK3:1;
uint32_t LCK4:1;
uint32_t LCK5:1;
uint32_t LCK6:1;
uint32_t LCK7:1;
uint32_t LCK8:1;
uint32_t LCK9:1;
uint32_t LCK10:1;
uint32_t LCK11:1;
uint32_t LCK12:1;
uint32_t LCK13:1;
uint32_t LCK14:1;
uint32_t LCK15:1;
uint32_t LCKK:1;
uint32_t reserved1:15;
};
uint32_t word;
};
struct GPIO_PORT {
union GPIO_CRL CRL;
union GPIO_CRH CRH;
union GPIO_IDR IDR;
union GPIO_ODR ODR;
union GPIO_BSRR BSRR;
union GPIO_BRR BRR;
union GPIO_LCKK LCKK;
uint32_t reserved1[249];
};
struct GPIO {
struct GPIO_PORT PORTS[7];
};
//--functions-------------------------------------------------------------------
#endif //_GPIO_REGS_H_

87
drv/nvic.c Normal file
View File

@ -0,0 +1,87 @@
/** @file nvic.c
* Module handling the Nested Vector Interrupt Controller (NVIC)
*
* The module provides functions to configure the different interrupts and
* their priority suiing the NVIC's interface
*/
//--includes--------------------------------------------------------------------
#include "nvic.h"
#include "nvic_regs.h"
//--local definitions-----------------------------------------------------------
/**
* NVIC's register are only accessible by 32 bits words, and data is stored
* accors 3 consecutive registers. This macro sets the right bit from the
* right register based on the IRQ number
*/
#define set_bit(reg, irq) \
do { \
uint8_t n = irq / 32; \
uint8_t r = irq - n * 32; \
regs->reg[n] |= (0x1 << r); \
} while (0)
/**
* NVIC's register are only accessible by 32 bits words, and data is stored
* accors 3 consecutive registers. This macro fetches the right bit from the
* right register based on the IRQ number
*/
#define get_bit(reg, irq, res) \
do { \
uint8_t n = irq / 32; \
uint8_t r = irq - n * 32; \
res = 0 != (regs->reg[n] | (0x1 << r)); \
} while (0)
//--local variables-------------------------------------------------------------
static volatile struct NVIC1* regs = (struct NVIC1*)NVIC1_BASE_ADDRESS;
//--public functions------------------------------------------------------------
void nvic_enable(enum NvicIrq irq)
{
set_bit(ISERX, irq);
}
void nvic_disable(enum NvicIrq irq)
{
set_bit(ICERX, irq);
}
void nvic_clear_pending(enum NvicIrq irq)
{
set_bit(ICPRX, irq);
}
void nvic_set_priority(enum NvicIrq irq, uint8_t priority)
{
uint8_t n = irq / 4;
uint8_t r = (irq - n * 4); //get the division's reminder
r *= 8; //mul by 8 since each 'slot' is 8 bits
r += 4; //add 4 since we only write to the upper 4 bits
regs->IPRX[n] &= ~(0x0F << r);
regs->IPRX[n] |= (priority & 0x0F) << r;
}
void nvic_set_pending(enum NvicIrq irq)
{
set_bit(ISPRX, irq);
}
bool nvic_is_pending(enum NvicIrq irq)
{
bool res = false;
get_bit(ISPRX, irq, res);
return res;
}
//--local functions-------------------------------------------------------------

125
drv/nvic.h Normal file
View File

@ -0,0 +1,125 @@
/** @file nvic.h
* Module handling the Nested Vector Interrupt Controller (NVIC)
*
* The module provides functions to configure the different interrupts and
* their priority suiing the NVIC's interface
*/
#ifndef _NVIC_H_
#define _NVIC_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
#include "stdbool.h"
//--type definitions------------------------------------------------------------
/**
* Available System IRQs. This does not include CPU's IRQs
*/
enum NvicIrq {
NVIC_IRQ_WWDG = 0,
NVIC_IRQ_PVD,
NVIC_IRQ_TAMPER,
NVIC_IRQ_RTC,
NVIC_IRQ_FLASH,
NVIC_IRQ_RCC,
NVIC_IRQ_EXTI0,
NVIC_IRQ_EXTI1,
NVIC_IRQ_EXTI2,
NVIC_IRQ_EXTI3,
NVIC_IRQ_EXTI4,
NVIC_IRQ_DMA1_CHANNEL1,
NVIC_IRQ_DMA1_CHANNEL2,
NVIC_IRQ_DMA1_CHANNEL3,
NVIC_IRQ_DMA1_CHANNEL4,
NVIC_IRQ_DMA1_CHANNEL5,
NVIC_IRQ_DMA1_CHANNEL6,
NVIC_IRQ_DMA1_CHANNEL7,
NVIC_IRQ_ADC1_2,
NVIC_IRQ_HP_CAN_TX,
NVIC_IRQ_LP_CAN_RX0,
NVIC_IRQ_CAN_RX1,
NVIC_IRQ_CAN_SCE,
NVIC_IRQ_EXTI9_5,
NVIC_IRQ_TIM1_BRK,
NVIC_IRQ_TIM1_UP,
NVIC_IRQ_TIM1_TRG_COM,
NVIC_IRQ_TIM1_CC,
NVIC_IRQ_TIM2,
NVIC_IRQ_TIM3,
NVIC_IRQ_TIM4,
NVIC_IRQ_I2C1_EVENT,
NVIC_IRQ_I2C1_ERROR,
NVIC_IRQ_I2C2_EVENT,
NVIC_IRQ_I2C2_ERROR,
NVIC_IRQ_SPI1,
NVIC_IRQ_SPI2,
NVIC_IRQ_USART1,
NVIC_IRQ_USART2,
NVIC_IRQ_USART3,
NVIC_IRQ_EXTI15_10,
NVIC_IRQ_RTC_ALARM,
NVIC_IRQ_USB_WAKEUP,
NVIC_IRQ_TIM8_BRK,
NVIC_IRQ_TIM8_UP,
NVIC_IRQ_TIM8_TRG_COM,
NVIC_IRQ_TIM8_CC,
NVIC_IRQ_ADC3,
NVIC_IRQ_FSMC,
NVIC_IRQ_SDIO,
NVIC_IRQ_TIM5,
NVIC_IRQ_SPI3,
NVIC_IRQ_UART4,
NVIC_IRQ_UART5,
NVIC_IRQ_TIM6,
NVIC_IRQ_TIM7,
NVIC_IRQ_DMA2_CHANNEL1,
NVIC_IRQ_DMA2_CHANNEL2,
NVIC_IRQ_DMA2_CHANNEL3,
NVIC_IRQ_DMA2_CHANNEL4_5,
};
//--functions-------------------------------------------------------------------
/**
* Enables the selected IRQ
*/
void nvic_enable(enum NvicIrq irq);
/**
* Disables the selected IRQ
*/
void nvic_disable(enum NvicIrq irq);
/**
* Clears the pending state of an IRQ. Should be called when reaching an IRQ
* handler so that the IRQ isn't triggered again when exiting the handler
*/
void nvic_clear_pending(enum NvicIrq irq);
/**
* Sets the priority for the selected IRQ. The lower the priority value, the
* higher the effective priority. Valid priority values range from 0 to 15. Any
* higher value will be ignored. When multiple IRQs with the same priority are
* triggered, they will be serviced from the lowest ID to the highest
*/
void nvic_set_priority(enum NvicIrq irq, uint8_t priority);
/**
* Sets the selected IRQ's pending state. If the IRQ is active, it will be
* triggered
*/
void nvic_set_pending(enum NvicIrq irq);
/**
* Returns wether the selected IRQ is currently pending or not
*/
bool nvic_is_pending(enum NvicIrq irq);
#endif //_RCC_H_

39
drv/nvic_regs.h Normal file
View File

@ -0,0 +1,39 @@
/** @file nvic_regs.h
* Module defining the Nested Vector Interrupt Controller (NVIC) registers.
*
* Mainly made to be used by the nvic module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _NVIC_REGS_H_
#define _NVIC_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define NVIC1_BASE_ADDRESS 0xE000E100
#define NVIC2_BASE_ADDRESS 0xE000EF00
struct NVIC1 {
uint32_t ISERX[3];
uint32_t ICERX[3];
uint32_t ISPRX[3];
uint32_t ICPRX[3];
uint32_t IABRX[3];
uint32_t IPRX[20];
};
struct NVIC2 {
uint32_t INTID;
};
//--functions-------------------------------------------------------------------
#endif //_NVIC_REGS_H_

61
drv/pwr.c Normal file
View File

@ -0,0 +1,61 @@
/** @file pwr.c
* Module handling the power management's control
*
* The module provides functions to enter the different sleep states, control
* and filter wakeup events (WKUP and RTC) and configure power voltage
* detection
*/
//--includes--------------------------------------------------------------------
#include "pwr.h"
#include "pwr_regs.h"
#include "scb.h"
#include "rcc.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct PWR* regs = (struct PWR*)PWR_BASE_ADDRESS;
//--public functions------------------------------------------------------------
void pwr_sleep(void)
{
scb_configure_deepsleep(false);
__asm("wfe");
}
void pwr_stop(enum PwrWakeupSpeed speed)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE);
scb_configure_deepsleep(true);
regs->CR.PDDS = 0;
regs->CR.LPDS = speed;
__asm("wfe");
rcc_configure(RCC_PRESET_SPEED);
}
void pwr_standby(void)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE);
scb_configure_deepsleep(true);
regs->CR.PDDS = 1;
__asm("wfe");
rcc_configure(RCC_PRESET_SPEED);
}
void pwr_configure_bkp_write(bool enable)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE);
regs->CR.DBP = enable;
}
//--local functions-------------------------------------------------------------
//--ISRs------------------------------------------------------------------------

51
drv/pwr.h Normal file
View File

@ -0,0 +1,51 @@
/** @file pwr.h
* Module handling the power management's control
*
* The module provides functions to enter the different sleep states, control
* and filter wakeup events (WKUP and RTC) and configure power voltage
* detection
*/
#ifndef _PWR_H_
#define _PWR_H_
//--includes--------------------------------------------------------------------
//--type definitions------------------------------------------------------------
enum PwrWakeupSpeed {
PWR_WAKEUP_SPEED_FAST, //faster wakeup, higher consumption in stop mode
PWR_WAKEUP_SPEED_SLOW, //slower wakeup, lower consumption in stop mode
};
enum PwrPvdThreshold {
PWR_PVD_THRESHOLD_2_2V,
PWR_PVD_THRESHOLD_2_3V,
PWR_PVD_THRESHOLD_2_4V,
PWR_PVD_THRESHOLD_2_5V,
PWR_PVD_THRESHOLD_2_6V,
PWR_PVD_THRESHOLD_2_7V,
PWR_PVD_THRESHOLD_2_8V,
PWR_PVD_THRESHOLD_2_9V,
};
typedef void (*PwrPvdCallback)(void);
//--functions-------------------------------------------------------------------
void pwr_sleep(void);
void pwr_stop(enum PwrWakeupSpeed speed);
void pwr_standby(void);
bool pwr_wakeup_event(void);
bool pwr_standby_exit(void);
void pwr_configure_bkp_write(bool enable);
void pwr_configure_wakeup_pin(bool enable);
void pwr_configure_pvd(enum PwrPvdThreshold treshold);
#endif //_PWR_H_

56
drv/pwr_regs.h Normal file
View File

@ -0,0 +1,56 @@
/** @file pwr_regs.h
* Module defining Power control (PWR) registers.
*
* Mainly made to be used by the pwr module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _PWR_REGS_H_
#define _PWR_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define PWR_BASE_ADDRESS 0x40007000
union PWR_CR {
struct {
uint32_t LPDS:1;
uint32_t PDDS:1;
uint32_t CWUF:1;
uint32_t CSBF:1;
uint32_t PVDE:1;
uint32_t PLS:3;
uint32_t DBP:1;
uint32_t reserved1:23;
};
uint32_t word;
};
union PWR_CSR {
struct {
uint32_t WUF:1;
uint32_t SBF:1;
uint32_t PVDO:1;
uint32_t reserved1:5;
uint32_t EWUP:1;
uint32_t reserved2:23;
};
uint32_t word;
};
struct PWR {
union PWR_CR CR;
union PWR_CSR CSR;
};
//--functions-------------------------------------------------------------------
#endif //_PWR_REGS_H_

196
drv/rcc.c Normal file
View File

@ -0,0 +1,196 @@
/** @file rcc.c
* Module handling Reset and Clocks Control (RCC).
*
* The module provides functions to configure clocks according to presets as
* well as to enable/disable/reset peripherals.
*/
//--includes--------------------------------------------------------------------
#include "rcc.h"
#include "rcc_regs.h"
#include "flash.h"
//--local definitions-----------------------------------------------------------
#define AHB_MASK 0x00000557
#define APB1_MASK 0x3afec9ff
#define APB2_MASK 0x0038fffd
static void apply_default_preset(void);
static void apply_speed_preset(void);
//--local variables-------------------------------------------------------------
static volatile struct RCC* regs = (struct RCC*)RCC_BASE_ADDRESS;
static enum RccPreset current_preset = RCC_PRESET_DEFAULT;
//--public functions------------------------------------------------------------
/**
* Configures the clock sources, PLL, prescalers, etc. All peripherals are
* disabled prior to any modifications to avoid unwanted side effects.
*/
void rcc_configure(enum RccPreset preset)
{
//disable all peripherals during clock configuration
union RCC_APB1ENR apb1_enr = regs->APB1ENR;
regs->APB1ENR.word = 0x0;
union RCC_APB2ENR apb2_enr = regs->APB2ENR;
regs->APB2ENR.word = 0x0;
switch (preset) {
case RCC_PRESET_DEFAULT:
apply_default_preset();
current_preset = RCC_PRESET_DEFAULT;
break;
case RCC_PRESET_SPEED:
apply_speed_preset();
current_preset = RCC_PRESET_SPEED;
break;
default:
break;
}
//re-enable peripherals
regs->APB1ENR = apb1_enr;
regs->APB2ENR = apb2_enr;
}
void rcc_configure_lsi(bool enable)
{
regs->CSR.LSION = enable;
//ensure LSI is enabled
if (enable) {
while (regs->CSR.LSIRDY != 0x1) {}
}
}
void rcc_enable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask,
enum RccApb2 apb2_mask)
{
regs->AHBENR.word |= ahb_mask & AHB_MASK;
regs->APB1ENR.word |= apb1_mask & APB1_MASK;
regs->APB2ENR.word |= apb2_mask & APB2_MASK;
}
void rcc_disable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask,
enum RccApb2 apb2_mask)
{
regs->AHBENR.word &= !(ahb_mask & AHB_MASK);
regs->APB1ENR.word &= !(apb1_mask & APB1_MASK);
regs->APB2ENR.word &= !(apb2_mask & APB2_MASK);
}
void rcc_reset(enum RccApb1 apb1_mask, enum RccApb2 apb2_mask)
{
regs->APB1RSTR.word &= !(apb1_mask & APB1_MASK);
regs->APB2RSTR.word &= !(apb2_mask & APB2_MASK);
}
void rcc_get_clocks(struct RccClocks* clocks)
{
clocks->ahb_freq = 0;
switch (current_preset)
{
case RCC_PRESET_DEFAULT:
clocks->ahb_freq = 8000000;
clocks->apb1_freq = 8000000;
clocks->apb2_freq = 8000000;
clocks->tim_freq = 8000000;
break;
case RCC_PRESET_SPEED:
clocks->ahb_freq = 72000000;
clocks->apb1_freq = 36000000;
clocks->apb2_freq = 72000000;
clocks->tim_freq = 72000000;
break;
default:
//TODO hardfault
break;
}
}
//--local functions-------------------------------------------------------------
/**
* Apply the default clock preset, using HSI whithout PLL or prescalers. This is
* similar to the reset configuration. Most buses run at 8Mhz, except ADCs wich
* run at 4Mhz, and Systick wich only reaches 1Mhz.
*/
static void apply_default_preset(void)
{
//ensures HSI is enabled
regs->CR.HSION = 1;
while (regs->CR.HSIRDY != 0x1);
//set HSI as main clock source and disable prescalers
regs->CFGR.word &= ~0x077fff3;
//disable all options
regs->CR.HSITRIM = 0;
regs->CR.HSITRIM = 0x10;
regs->CR.HSEON = 0;
regs->CR.HSEBYP = 0;
regs->CR.CCSON = 0;
regs->CR.PLLON = 0;
//disable all interrupts
regs->CIR.LSIRDYIE = 0;
regs->CIR.LSERDYIE = 0;
regs->CIR.HSIRDYIE = 0;
regs->CIR.HSERDYIE = 0;
regs->CIR.PLLRDYIE = 0;
//reconfigure flash
flash_configure(FLASH_PRESET_LOW_CLOCK_SPEED);
}
/**
* Apply the speed preset, using HSE with PLL to achieve 72MHz on AHB, APB2 and
* timer buses. APB1 is limited to its maximum clock of 36Mhz and the ADCs run
* at 12MHz. Systick runs at 9Mhz.
*/
static void apply_speed_preset(void)
{
//restore sane values
apply_default_preset();
//try enabling HSE, fallback to HSI if HSE fails
regs->CR.HSEON = 1;
for (uint32_t i=0; i<1000; ++i) {
__asm__("nop");
}
if (regs->CR.HSERDY == 0x1) {
regs->CFGR.PLLSCR = 1;
} else {
regs->CR.HSEON = 0;
}
//configure PLL, fallback to HSI if PLL fails
regs->CFGR.PLLMUL = 0x7; //PLL x9
regs->CR.PLLON = 1;
for (uint32_t i=0; i<1000; ++i) {
__asm__("nop");
}
if (regs->CR.PLLRDY != 0x1) {
regs->CR.PLLON = 0;
return; //clock low enough, no need for prescalers
}
//configure prescalers
regs->CFGR.PPRE1 = 0x4; // /2
regs->CFGR.ADCPRE = 0x2; // /6
//reconfigure flash
flash_configure(FLASH_PRESET_HIGH_CLOCK_SPEED);
//switch to PLL output
regs->CFGR.SW = 0x2;
}

156
drv/rcc.h Normal file
View File

@ -0,0 +1,156 @@
/** @file rcc.h
* Module handling Reset and Clocks Control (RCC).
*
* The module provides functions to configure clocks according to presets as
* well as to enable/disable/reset peripherals.
*/
#ifndef _RCC_H_
#define _RCC_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
/**
* Available clock configuration presets
*/
enum RccPreset {
RCC_PRESET_DEFAULT, //sane values, identical to reset config
RCC_PRESET_SPEED, //highest clocks, uses 8MHz HSE if available
};
/**
* Available peripherals on the AHB bus. Note that some of these peripherals
* may not be availables on all chips
*/
enum RccAhb {
RCC_AHB_NONE = 0,
RCC_AHB_DMA1 = (0x1 << 0),
RCC_AHB_DMA2 = (0x1 << 1),
RCC_AHB_SRAM = (0x1 << 2),
RCC_AHB_FLITF = (0x1 << 4),
RCC_AHB_CRC = (0x1 << 6),
RCC_AHB_FSMC = (0x1 << 8),
RCC_AHB_SDIO = (0x1 << 10),
};
/**
* Available peripherals on the APB1 bus. Note that some of these peripherals
* may not be availables on all chips
*/
enum RccApb1 {
RCC_APB1_NONE = 0,
RCC_APB1_TIM2 = (0x1 << 0),
RCC_APB1_TIM3 = (0x1 << 1),
RCC_APB1_TIM4 = (0x1 << 2),
RCC_APB1_TIM5 = (0x1 << 3),
RCC_APB1_TIM6 = (0x1 << 4),
RCC_APB1_TIM7 = (0x1 << 5),
RCC_APB1_TIM12 = (0x1 << 6),
RCC_APB1_TIM13 = (0x1 << 7),
RCC_APB1_TIM14 = (0x1 << 8),
RCC_APB1_WWDG = (0x1 << 11),
RCC_APB1_SPI2 = (0x1 << 14),
RCC_APB1_SPI3 = (0x1 << 15),
RCC_APB1_USART2 = (0x1 << 17),
RCC_APB1_USART3 = (0x1 << 18),
RCC_APB1_UART4 = (0x1 << 19),
RCC_APB1_UART5 = (0x1 << 20),
RCC_APB1_I2C1 = (0x1 << 21),
RCC_APB1_I2C2 = (0x1 << 22),
RCC_APB1_USB = (0x1 << 23),
RCC_APB1_CAN = (0x1 << 25),
RCC_APB1_BKP = (0x1 << 27),
RCC_APB1_PWR = (0x1 << 28),
RCC_APB1_DAC = (0x1 << 29),
};
/**
* Available peripherals on the APB2 bus. Note that some of these peripherals
* may not be available on all chips
*/
enum RccApb2 {
RCC_APB2_NONE = 0,
RCC_APB2_AFIO = (0x1 << 0),
RCC_APB2_IOPA = (0x1 << 2),
RCC_APB2_IOPB = (0x1 << 3),
RCC_APB2_IOPC = (0x1 << 4),
RCC_APB2_IOPD = (0x1 << 5),
RCC_APB2_IOPE = (0x1 << 6),
RCC_APB2_IOPF = (0x1 << 7),
RCC_APB2_IOPG = (0x1 << 8),
RCC_APB2_ADC1 = (0x1 << 9),
RCC_APB2_ADC2 = (0x1 << 10),
RCC_APB2_TIM1 = (0x1 << 11),
RCC_APB2_SPI1 = (0x1 << 12),
RCC_APB2_TIM8 = (0x1 << 13),
RCC_APB2_USART = (0x1 << 14),
RCC_APB2_ADC3 = (0x1 << 15),
RCC_APB2_TIM9 = (0x1 << 19),
RCC_APB2_TIM10 = (0x1 << 20),
RCC_APB2_TIM11 = (0x1 << 21),
};
enum RccRtcClockSrc {
RCC_RTC_CLOCK_SRC_NONE = 0x0,
RCC_RTC_CLOCK_SRC_LSE = 0x1,
RCC_RTC_CLOCK_SRC_LSI = 0x2,
RCC_RTC_CLOCK_SRC_HSE = 0x3,
};
struct RccClocks {
uint32_t ahb_freq;
uint32_t apb1_freq;
uint32_t apb2_freq;
uint32_t tim_freq;
};
//--functions-------------------------------------------------------------------
/**
* Configures the clocks and buses according to the given preset. Peripheral
* states are kept during the change and additional reconfiguration are
* handled automatically for peripherals that rely on a clock timings (timers,
* watchdogs, ...)
*/
void rcc_configure(enum RccPreset preset);
/**
* Configures the Low Speed Internal (LSI) oscillator for low power
* applications.
*/
void rcc_configure_lsi(bool enable);
/**
* Enables peripherals on the different buses. The enums values can used as
* masks to enable multiple peripherals at the same time. Invalid values will be
* ignored.
*/
void rcc_enable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask,
enum RccApb2 apb2_mask);
/**
* Disables peripherals on the different buses. The enums values can used as
* masks to disable multiple peripherals at the same time. Invalid values will
* be ignored.
*/
void rcc_disable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask,
enum RccApb2 apb2_mask);
/**
* Resets peripherals on the different buses. The enums values can used as
* masks to reset multiple peripherals at the same time. Invalid values will
* be ignored.
*/
void rcc_reset(enum RccApb1 apb1_mask, enum RccApb2 apb2_mask);
void rcc_get_clocks(struct RccClocks* clocks);
#endif //_RCC_H_

262
drv/rcc_regs.h Normal file
View File

@ -0,0 +1,262 @@
/** @file rcc_regs.h
* Module defining Reset and Clocks Control (RCC) registers.
*
* Mainly made to be used by the rcc module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _RCC_REGS_H_
#define _RCC_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define RCC_BASE_ADDRESS 0x40021000
union RCC_CR {
struct {
uint32_t HSION:1;
uint32_t HSIRDY:1;
uint32_t reserved1:1;
uint32_t HSITRIM:5;
uint32_t HSICAL:8;
uint32_t HSEON:1;
uint32_t HSERDY:1;
uint32_t HSEBYP:1;
uint32_t CCSON:1;
uint32_t reserved2:4;
uint32_t PLLON:1;
uint32_t PLLRDY:1;
uint32_t reserved3:6;
};
uint32_t word;
};
union RCC_CFGR {
struct {
uint32_t SW:2;
uint32_t SWS:2;
uint32_t HPRE:4;
uint32_t PPRE1:3;
uint32_t PPRE2:3;
uint32_t ADCPRE:2;
uint32_t PLLSCR:1;
uint32_t PLLXTPRE:1;
uint32_t PLLMUL:4;
uint32_t USBPRE:1;
uint32_t reserved1:1;
uint32_t MCO:3;
uint32_t reserved2:5;
};
uint32_t word;
};
union RCC_CIR {
struct {
uint32_t LSIRDYF:1;
uint32_t LSERDYF:1;
uint32_t HSIRDYF:1;
uint32_t HSERDYF:1;
uint32_t PLLRDYF:1;
uint32_t reserved1:2;
uint32_t CSSF:1;
uint32_t LSIRDYIE:1;
uint32_t LSERDYIE:1;
uint32_t HSIRDYIE:1;
uint32_t HSERDYIE:1;
uint32_t PLLRDYIE:1;
uint32_t RSE2:3;
uint32_t LSIRDYC:1;
uint32_t LSERDYC:1;
uint32_t HSIRDYC:1;
uint32_t HSERDYC:1;
uint32_t PLLRDYC:1;
uint32_t reserved3:2;
uint32_t CSSC:1;
uint32_t reserved4:8;
};
uint32_t word;
};
union RCC_APB2RSTR {
struct {
uint32_t AFIORST:1;
uint32_t reserved1:1;
uint32_t IOPARST:1;
uint32_t IOPBRST:1;
uint32_t IOPCRST:1;
uint32_t IOPDRST:1;
uint32_t IOPERST:1;
uint32_t IOPFRST:1;
uint32_t IOPGRST:1;
uint32_t ADC1RST:1;
uint32_t ACD2RST:1;
uint32_t TIM1RST:1;
uint32_t SPI1RST:1;
uint32_t TIM8RST:1;
uint32_t USART1RST:1;
uint32_t ADC3RST:1;
uint32_t reserved2:3;
uint32_t TIM9RST:1;
uint32_t TIM10RST:1;
uint32_t TIM11RST:1;
uint32_t reserved3:10;
};
uint32_t word;
};
union RCC_APB1RSTR {
struct {
uint32_t TIM2RST:1;
uint32_t TIM3RST:1;
uint32_t TIM4RST:1;
uint32_t TIM5RST:1;
uint32_t TIM6RST:1;
uint32_t TIM7RST:1;
uint32_t TIM12RST:1;
uint32_t TIM13RST:1;
uint32_t TIM14RST:1;
uint32_t reserved1:2;
uint32_t WWDGRST:1;
uint32_t reserved2:2;
uint32_t SPI2RST:1;
uint32_t SPI3RST:1;
uint32_t reserved3:1;
uint32_t USART2RST:1;
uint32_t USART3RST:1;
uint32_t UART4RST:1;
uint32_t UART5RST:1;
uint32_t I2C12RST:1;
uint32_t I2C2RST:1;
uint32_t USB2RST:1;
uint32_t reserved4:1;
uint32_t CANRST:1;
uint32_t reserved5:1;
uint32_t BKPRST:1;
uint32_t PWRRST:1;
uint32_t DACRST:1;
uint32_t reserved6:2;
};
uint32_t word;
};
union RCC_AHBENR {
struct {
uint32_t DMA1EN:1;
uint32_t DMA2EN:1;
uint32_t SRAMEN:1;
uint32_t reserved1:1;
uint32_t FLITFEN:1;
uint32_t reserved2:1;
uint32_t CRCEN:1;
uint32_t reserved3:1;
uint32_t FSMCEN:1;
uint32_t reserved4:1;
uint32_t SDIOEN:1;
uint32_t reserved5:21;
};
uint32_t word;
};
union RCC_APB2ENR {
struct {
uint32_t AFIOEN:1;
uint32_t reserved1:1;
uint32_t IOPAEN:1;
uint32_t IOPBEN:1;
uint32_t IOPCEN:1;
uint32_t IOPDEN:1;
uint32_t IOPEEN:1;
uint32_t IOPFEN:1;
uint32_t IOPGEN:1;
uint32_t ADC1EN:1;
uint32_t ACD2EN:1;
uint32_t TIM1EN:1;
uint32_t SPI1EN:1;
uint32_t TIM8EN:1;
uint32_t USART1EN:1;
uint32_t ADC3EN:1;
uint32_t reserved2:3;
uint32_t TIM9EN:1;
uint32_t TIM10EN:1;
uint32_t TIM11EN:1;
uint32_t reserved3:10;
};
uint32_t word;
};
union RCC_APB1ENR {
struct {
uint32_t TIM2EN:1;
uint32_t TIM3EN:1;
uint32_t TIM4EN:1;
uint32_t TIM5EN:1;
uint32_t TIM6EN:1;
uint32_t TIM7EN:1;
uint32_t TIM12EN:1;
uint32_t TIM13EN:1;
uint32_t TIM14EN:1;
uint32_t reserved1:2;
uint32_t WWDGEN:1;
uint32_t reserved2:2;
uint32_t SPI2EN:1;
uint32_t SPI3EN:1;
uint32_t reserved3:1;
uint32_t USART2EN:1;
uint32_t USART3EN:1;
uint32_t UART4EN:1;
uint32_t UART5EN:1;
uint32_t I2C12EN:1;
uint32_t I2C2EN:1;
uint32_t USB2EN:1;
uint32_t reserved4:1;
uint32_t CANEN:1;
uint32_t reserved5:1;
uint32_t BKPEN:1;
uint32_t PWREN:1;
uint32_t DACEN:1;
uint32_t reserved6:2;
};
uint32_t word;
};
union RCC_CSR {
struct {
uint32_t LSION:1;
uint32_t LSIRDY:1;
uint32_t reserved1:22;
uint32_t RMVF:1;
uint32_t reserved2:1;
uint32_t PINRSTF:1;
uint32_t PORRSTF:1;
uint32_t SFTRSTF:1;
uint32_t IWDGRSTF:1;
uint32_t WWDGRSTF:1;
uint32_t LPWRSTF:1;
};
uint32_t word;
};
struct RCC {
union RCC_CR CR;
union RCC_CFGR CFGR;
union RCC_CIR CIR;
union RCC_APB2RSTR APB2RSTR;
union RCC_APB1RSTR APB1RSTR;
union RCC_AHBENR AHBENR;
union RCC_APB2ENR APB2ENR;
union RCC_APB1ENR APB1ENR;
uint32_t reserved1;
union RCC_CSR CSR;
};
//--functions-------------------------------------------------------------------
#endif //_RCC_REGS_H_

64
drv/scb.c Normal file
View File

@ -0,0 +1,64 @@
/** @file scb.c
* Module handling the System Control Block
*
* The module provides functions to configure miscelaneous options of the cortex
* m3, including sleep behavior, event handler priorities, resets and fault
* handlers
*/
//--includes--------------------------------------------------------------------
#include "scb.h"
#include "scb_regs.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct SCB* regs = (struct SCB*)SCB_BASE_ADDRESS;
//--public functions------------------------------------------------------------
uint16_t scb_pending_exception(void)
{
return regs->ICSR.VECTPENDING;
}
uint16_t scb_active_exception(void)
{
return regs->ICSR.VECTACTIVE;
}
void scb_configure_vector_table(uint32_t offset)
{
//TODO check that last LSB is 0 (alignement restrictions)
regs->VTOR.TABLEOFF = offset & 0x1FFFFF;
}
void scb_reset_system(void)
{
regs->AIRCR.SYSRESETREQ = 1;
}
void scb_configure_deepsleep(bool enable)
{
regs->SCR.SLEEPDEEP = enable;
}
void scb_configure_div0_fault(bool enable)
{
regs->CCR.DIV_0_TRP = enable;
}
void scb_configure_unalign_fault(bool enable)
{
regs->CCR.UNALIGN_TRP = enable;
}
//--local functions-------------------------------------------------------------
//--ISRs------------------------------------------------------------------------

32
drv/scb.h Normal file
View File

@ -0,0 +1,32 @@
/** @file scb.h
* Module handling the System Control Block
*
* The module provides functions to configure miscelaneous options of the cortex
* m3, including sleep behavior, event handler priorities, resets and fault
* handlers
*/
#ifndef _SCB_H_
#define _SCB_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
//--functions-------------------------------------------------------------------
uint16_t scb_pending_exception(void);
uint16_t scb_active_exception(void);
void scb_configure_vector_table(uint32_t offset);
void scb_reset_system(void);
void scb_configure_deepsleep(bool enable);
void scb_configure_div0_fault(bool enable);
void scb_configure_unalign_fault(bool enable);
#endif //_SCB_H_

192
drv/scb_regs.h Normal file
View File

@ -0,0 +1,192 @@
/** @file scb_regs.h
* Module defining System Control Block (SCB) registers.
*
* Mainly made to be used by the scb module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _SCB_REGS_H_
#define _SCB_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define SCB_BASE_ADDRESS 0xE000ED00
union SCB_CPUID {
struct {
uint32_t revision:4;
uint32_t part_no:12;
uint32_t constant:4;
uint32_t variant:4;
uint32_t implementer:8;
};
uint32_t word;
};
union SCB_ICSR {
struct {
uint32_t VECTACTIVE:9;
uint32_t reserved1:2;
uint32_t RETOBASE:1;
uint32_t VECTPENDING:10;
uint32_t ISRPENDING:1;
uint32_t reserved2:2;
uint32_t PENDSTCLR:1;
uint32_t PENDSTSET:1;
uint32_t PENDSVCRL:1;
uint32_t PENDSVSET:1;
uint32_t reserved3:2;
uint32_t NMIPENDSET:1;
};
uint32_t word;
};
union SCB_VTOR {
struct {
uint32_t reserved1:9;
uint32_t TABLEOFF:21;
uint32_t reserved2:2;
};
uint32_t word;
};
union SCB_AIRCR {
struct {
uint32_t VECTRESET:1;
uint32_t VECTCRLACTIVE:1;
uint32_t SYSRESETREQ:1;
uint32_t reserved1:5;
uint32_t PRIGROUP:3;
uint32_t reserved2:4;
uint32_t ENDIANESS:1;
uint32_t VECTKEY:16;
};
uint32_t word;
};
union SCB_SCR {
struct {
uint32_t reserved1:1;
uint32_t SLEEPONEXIT:1;
uint32_t SLEEPDEEP:1;
uint32_t reserved2:1;
uint32_t SEVONPEND:1;
uint32_t reserved3:27;
};
uint32_t word;
};
union SCB_CCR {
struct {
uint32_t NONBASETHRDEN:1;
uint32_t USERSETMPEND:1;
uint32_t reserved1:1;
uint32_t UNALIGN_TRP:1;
uint32_t DIV_0_TRP:1;
uint32_t reserved2:3;
uint32_t BFHFNIGN:1;
uint32_t STKALIGN:1;
uint32_t reserved3:22;
};
uint32_t word;
};
union SCB_SHPR1 {
struct {
uint32_t PRI4:8;
uint32_t PRI5:8;
uint32_t PRI6:8;
uint32_t reserved1:8;
};
uint32_t word;
};
union SCB_SHPR2 {
struct {
uint32_t reserved1:24;
uint32_t PRI11:8;
};
uint32_t word;
};
union SCB_SHPR3 {
struct {
uint32_t reserved1:16;
uint32_t PRI14:8;
uint32_t PRI15:8;
};
uint32_t word;
};
union SCB_SHCRS {
struct {
uint32_t MEMFAULTACT:1;
uint32_t BUSFAULTACT:1;
uint32_t reserved1:1;
uint32_t USGFAULTACT:1;
uint32_t reserved2:3;
uint32_t SVCALLACT:1;
uint32_t MONITORACT:1;
uint32_t reserved3:1;
uint32_t PENDSVACT:1;
uint32_t SYSTICKACT:1;
uint32_t USGFAULTPENDED:1;
uint32_t MEMFAULTPENDED:1;
uint32_t BUSFAULTPENDED:1;
uint32_t SVCALLPENDED:1;
uint32_t MEMFAULTENA:1;
uint32_t BUSFAULTENA:1;
uint32_t USGFAULTENA:1;
uint32_t reserved4:13;
};
uint32_t word;
};
union SCB_CFSR {
struct {
uint32_t MMFSR:8;
uint32_t BFSR:8;
uint32_t UFSR:16;
};
uint32_t word;
};
union SCB_HFSR {
struct {
uint32_t reserved1:1;
uint32_t VECTTBL:1;
uint32_t reserved2:28;
uint32_t FORCED:1;
uint32_t DEBUG_VT:1;
};
uint32_t word;
};
struct SCB {
union SCB_CPUID CPUID;
union SCB_ICSR ICSR;
union SCB_VTOR VTOR;
union SCB_AIRCR AIRCR;
union SCB_SCR SCR;
union SCB_CCR CCR;
union SCB_SHPR1 SHPR1;
union SCB_SHPR2 SHPR2;
union SCB_SHPR3 SHPR3;
union SCB_SHCRS SHCRS;
union SCB_CFSR CFSR;
union SCB_HFSR HFSR;
uint32_t MMAR;
uint32_t BFAR;
};
//--functions-------------------------------------------------------------------
#endif //_PWR_REGS_H_

90
drv/stk.c Normal file
View File

@ -0,0 +1,90 @@
/** @file stk.c
* Module handling the system timer (systick or STK for short)
*
* The module provides functions to configure and use the system timer embedded
* in the cortex m core
*/
//--includes--------------------------------------------------------------------
#include "stk.h"
#include "stk_regs.h"
#include "rcc.h"
//--local definitions-----------------------------------------------------------
static volatile struct STK* regs = (struct STK*)STK_BASE_ADDRESS;
//--local variables-------------------------------------------------------------
static StkCallback callback;
static uint32_t prescaler;
//--public functions------------------------------------------------------------
uint32_t stk_configure(uint32_t period_us, StkCallback cb)
{
stk_reset();
struct RccClocks clocks;
rcc_get_clocks(&clocks);
uint32_t prescaler = (clocks.ahb_freq / 1000000 / 8);
uint32_t reload = period_us * prescaler;
if (reload < 1) {
//period is too small, try using the non-prescaled clock
prescaler *= 8;
reload = period_us * prescaler;
if (reload < 1) {
//period is still too small
return 1;
}
regs->CTRL.CLKSOURCE = 1;
}
regs->LOAD.RELOAD = reload;
regs->CTRL.TICKINT = 1;
callback = cb;
return 0;
}
void stk_reset(void)
{
regs->CTRL.ENABLE = 0;
regs->CTRL.TICKINT = 0;
regs->CTRL.CLKSOURCE = 0;
regs->CTRL.COUNTFLAG = 0;
regs->LOAD.RELOAD = 0;
regs->VAL.CURRENT = 0;
}
void stk_start(void)
{
regs->CTRL.ENABLE = 1;
}
void stk_stop(void)
{
regs->CTRL.ENABLE = 0;
}
uint32_t stk_read_us(void)
{
return (regs->VAL.word & 0x00FFFFFF) / prescaler;
}
//--local functions-------------------------------------------------------------
void hdr_sys_tick(void)
{
//clearing the pending bit in SCB_ICSR isn't needed, though I don't know why
callback();
}

55
drv/stk.h Normal file
View File

@ -0,0 +1,55 @@
/** @file stk.h
* Module handling the system timer (systick or STK for short)
*
* The module provides functions to configure and use the system timer embedded
* in the cortex m core
*/
#ifndef _STK_H_
#define _STK_H_
//--includes--------------------------------------------------------------------
#include <stdint.h>
//--type definitions------------------------------------------------------------
typedef void (*StkCallback)(void);
//--functions-------------------------------------------------------------------
/**
* Configures the system timer to run at the specified period in µs and call the
* given callback when said period is reached. Due to the limited configuration
* options, 1.8s is the maximum period when running in speed preset (see rcc
* module). The maximum period can be substantially increased by reducing the
* core clock
*/
uint32_t stk_configure(uint32_t period_us, StkCallback cb);
/**
* Resets the system timer configuration, restoring the default configuration
* and stopping it
*/
void stk_reset(void);
/**
* Starts the system timer. The timer will run until stopped
*/
void stk_start(void);
/**
* Stops the system timer
*/
void stk_stop(void);
/**
* Read the current value of the timer's counter in µs
*/
uint32_t stk_read_us(void);
#endif //_STK_H_

70
drv/stk_regs.h Normal file
View File

@ -0,0 +1,70 @@
/** @file stk_regs.h
* Module defining systick (STK) registers.
*
* Mainly made to be used by the stk module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _STK_REGS_H_
#define _STK_REGS_H_
//--includes--------------------------------------------------------------------
#include <stdint.h>
//--type definitions------------------------------------------------------------
#define STK_BASE_ADDRESS 0xE000E010
union STK_CTRL {
struct {
uint32_t ENABLE:1;
uint32_t TICKINT:1;
uint32_t CLKSOURCE:1;
uint32_t reserved1:13;
uint32_t COUNTFLAG:1;
uint32_t reserved2:15;
};
uint32_t word;
};
union STK_LOAD {
struct {
uint32_t RELOAD:24;
uint32_t reserved1:8;
};
uint32_t word;
};
union STK_VAL {
struct {
uint32_t CURRENT:24;
uint32_t reserved1:8;
};
uint32_t word;
};
union STK_CALIB {
struct {
uint32_t TENMS:24;
uint32_t reserved1:6;
uint32_t SKEW:1;
uint32_t NOREF:1;
};
uint32_t word;
};
struct STK {
union STK_CTRL CTRL;
union STK_LOAD LOAD;
union STK_VAL VAL;
union STK_CALIB CALIB;
};
//--functions-------------------------------------------------------------------
#endif //_STK_REGS_H_

183
drv/tim.c Normal file
View File

@ -0,0 +1,183 @@
/** @file tim.c
* Module handling general purpose and advances TIMers
*/
//--includes--------------------------------------------------------------------
#include "tim.h"
#include "tim_regs.h"
#include "nvic.h"
#include "../srv/error.h"
//--local definitions-----------------------------------------------------------
static volatile struct TIM* regs[] = {
(struct TIM*)TIM1_BASE_ADDRESS,
(struct TIM*)TIM2_BASE_ADDRESS,
(struct TIM*)TIM3_BASE_ADDRESS,
(struct TIM*)TIM4_BASE_ADDRESS,
};
static enum TimIRQSource computeIRQSource(enum TimPeriph periph);
//--local variables-------------------------------------------------------------
static TimCallback callbacks[4];
//--public functions------------------------------------------------------------
void tim_configure_master(enum TimPeriph periph, enum TimConfig config_mask,
enum TimMasterConfig master_config_mask, TimCallback callback)
{
error_assert(periph <= TIM_PERIPH_4);
//apply config mask directly while masking reserved areas. Masking is
//important here since advanced timer may have additionnal config bits
regs[periph]->cr1.word |= config_mask & 0x3FF;
regs[periph]->cr2.word |= (config_mask >> 16) & 0x88;
regs[periph]->cr2.word |= master_config_mask & 0x70;
//if callback specified, configure IRQ
if (callback != nullptr) {
callbacks[periph] = callback;
regs[periph]->dier.TIE = 1;
regs[periph]->dier.UIE = 0;
enum NvicIrq irq = 0;
switch (periph) {
case TIM_PERIPH_1:
irq = NVIC_IRQ_TIM1_UP;
break;
case TIM_PERIPH_2:
irq = NVIC_IRQ_TIM2;
break;
case TIM_PERIPH_3:
irq = NVIC_IRQ_TIM3;
break;
case TIM_PERIPH_4:
irq = NVIC_IRQ_TIM4;
break;
}
nvic_enable(irq);
}
//trigger update to force application of the config
regs[periph]->egr.UG = 1;
while (regs[periph]->sr.UIF == 0) {}
regs[periph]->sr.UIF = 0;
if (callback != nullptr) {
regs[periph]->dier.UIE = 1;
}
}
void tim_start(enum TimPeriph periph)
{
error_assert(periph <= TIM_PERIPH_4);
regs[periph]->cr1.CEN = 1;
}
void tim_stop(enum TimPeriph periph)
{
error_assert(periph <= TIM_PERIPH_4);
regs[periph]->cr1.CEN = 0;
}
void tim_update(enum TimPeriph periph)
{
error_assert(periph <= TIM_PERIPH_4);
regs[periph]->egr.UG = 1;
}
void tim_set_auto_reload(enum TimPeriph periph, uint16_t auto_reload)
{
error_assert(periph <= TIM_PERIPH_4);
regs[periph]->arr.ARR = auto_reload;
}
void tim_set_prescaler(enum TimPeriph periph, uint16_t prescaler)
{
error_assert(periph <= TIM_PERIPH_4);
regs[periph]->psc.PSC = prescaler;
}
void tim_set_counter(enum TimPeriph periph, uint16_t counter)
{
error_assert(periph <= TIM_PERIPH_4);
regs[periph]->cnt.CNT = counter;
}
uint16_t tim_get_auto_reload(enum TimPeriph periph)
{
error_assert(periph <= TIM_PERIPH_4);
return regs[periph]->arr.ARR;
}
uint16_t tim_get_prescaler(enum TimPeriph periph)
{
error_assert(periph <= TIM_PERIPH_4);
return regs[periph]->psc.PSC;
}
uint16_t tim_get_counter(enum TimPeriph periph)
{
error_assert(periph <= TIM_PERIPH_4);
return regs[periph]->cnt.CNT;
}
//--local functions-------------------------------------------------------------
static enum TimIRQSource computeIRQSource(enum TimPeriph periph)
{
enum TimIRQSource src =
(TIM_IRQ_SOURCE_TRIGGER & regs[periph]->sr.TIF)
| (TIM_IRQ_SOURCE_UPDATE & regs[periph]->sr.UIF);
regs[periph]->sr.TIF = 0;
regs[periph]->sr.UIF = 0;
return src;
}
//--ISRs------------------------------------------------------------------------
void hdr_tim1_up(void)
{
nvic_clear_pending(NVIC_IRQ_TIM1_UP);
enum TimIRQSource src = computeIRQSource(TIM_PERIPH_1);
callbacks[TIM_PERIPH_1](src);
}
void hdr_tim2(void)
{
nvic_clear_pending(NVIC_IRQ_TIM2);
enum TimIRQSource src = computeIRQSource(TIM_PERIPH_2);
callbacks[TIM_PERIPH_2](src);
}
void hdr_tim3(void)
{
nvic_clear_pending(NVIC_IRQ_TIM3);
enum TimIRQSource src = computeIRQSource(TIM_PERIPH_3);
callbacks[TIM_PERIPH_3](src);
}
void hdr_tim4(void)
{
nvic_clear_pending(NVIC_IRQ_TIM4);
enum TimIRQSource src = computeIRQSource(TIM_PERIPH_4);
callbacks[TIM_PERIPH_4](src);
}

163
drv/tim.h Normal file
View File

@ -0,0 +1,163 @@
/** @file tim.h
* Module handling general purpose and advances TIMers
*/
#ifndef _TIM_H_
#define _TIM_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
enum TimPeriph {
TIM_PERIPH_1,
TIM_PERIPH_2,
TIM_PERIPH_3,
TIM_PERIPH_4,
};
enum TimChannel {
TIM_CHANNEL_1,
TIM_CHANNEL_2,
TIM_CHANNEL_3,
TIM_CHANNEL_4,
};
enum TimConfig {
TIM_CONFIG_DISABLE_UPDATES = (0x1 << 1),
TIM_CONFIG_LIMIT_UPDATE_SRC = (0x1 << 2),
TIM_CONFIG_CONTINUOUS = (0x0 << 3),
TIM_CONFIG_ONE_SHOT = (0x1 << 3),
TIM_CONFIG_DIR_UP = (0x0 << 4),
TIM_CONFIG_DIR_DOWN = (0x1 << 4),
TIM_CONFIG_CENTER_ALIGNED_1 = (0x1 << 5),
TIM_CONFIG_CENTER_ALIGNED_2 = (0x2 << 5),
TIM_CONFIG_CENTER_ALIGNED_3 = (0x3 << 5),
TIM_CONFIG_BUFFERED_ARR = (0x1 << 7),
TIM_CONFIG_FILTER_CLOCK_DIV_1 = (0x0 << 8),
TIM_CONFIG_FILTER_CLOCK_DIV_2 = (0x1 << 8),
TIM_CONFIG_FILTER_CLOCK_DIV_4 = (0x2 << 8),
TIM_CONFIG_DMA_ON_CC_EVENT = (0x0 << 19),
TIM_CONFIG_DMA_ON_UPDATE = (0x1 << 19),
TIM_CONFIG_XOR_TI1 = (0x1 << 23),
};
enum TimMasterConfig {
TIM_MASTER_CONFIG_MODE_RESET = (0x0 << 4),
TIM_MASTER_CONFIG_MODE_ENABLE = (0x1 << 4),
TIM_MASTER_CONFIG_MODE_UPDATE = (0x2 << 4),
TIM_MASTER_CONFIG_MODE_COMP_PULSE = (0x3 << 4),
TIM_MASTER_CONFIG_MODE_COMP_1 = (0x4 << 4),
TIM_MASTER_CONFIG_MODE_COMP_2 = (0x5 << 4),
TIM_MASTER_CONFIG_MODE_COMP_3 = (0x6 << 4),
TIM_MASTER_CONFIG_MODE_COMP_4 = (0x7 << 4),
};
enum TimSlaveConfig {
TIM_SLAVE_CONFIG_MODE_ENCODER_1 = (0x1 << 0),
TIM_SLAVE_CONFIG_MODE_ENCODER_2 = (0x2 << 0),
TIM_SLAVE_CONFIG_MODE_ENCODER_3 = (0x3 << 0),
TIM_SLAVE_CONFIG_MODE_RESET = (0x4 << 0),
TIM_SLAVE_CONFIG_MODE_GATED = (0x5 << 0),
TIM_SLAVE_CONFIG_MODE_TRIGGER = (0x6 << 0),
TIM_SLAVE_CONFIG_MODE_EXT_CLK = (0x7 << 0),
TIM_SLAVE_CONFIG_TRIG_INTERNAL_1 = (0x0 << 4),
TIM_SLAVE_CONFIG_TRIG_INTERNAL_2 = (0x1 << 4),
TIM_SLAVE_CONFIG_TRIG_INTERNAL_3 = (0x2 << 4),
TIM_SLAVE_CONFIG_TRIG_INTERNAL_4 = (0x3 << 4),
TIM_SLAVE_CONFIG_TRIG_EDGE_DETECT = (0x4 << 4),
TIM_SLAVE_CONFIG_TRIG_FILTERED_1 = (0x5 << 4),
TIM_SLAVE_CONFIG_TRIG_FILTERED_2 = (0x6 << 4),
TIM_SLAVE_CONFIG_TRIG_EXT = (0x7 << 4),
};
enum TimExtConfig {
TIM_EXT_CONFIG_FILTER_1 = (0x1 << 8),
TIM_EXT_CONFIG_FILTER_2 = (0x2 << 8),
TIM_EXT_CONFIG_FILTER_3 = (0x3 << 8),
TIM_EXT_CONFIG_FILTER_4 = (0x4 << 8),
TIM_EXT_CONFIG_FILTER_5 = (0x5 << 8),
TIM_EXT_CONFIG_FILTER_6 = (0x6 << 8),
TIM_EXT_CONFIG_FILTER_7 = (0x7 << 8),
TIM_EXT_CONFIG_FILTER_8 = (0x8 << 8),
TIM_EXT_CONFIG_FILTER_9 = (0x9 << 8),
TIM_EXT_CONFIG_FILTER_10 = (0xA << 8),
TIM_EXT_CONFIG_FILTER_11 = (0xB << 8),
TIM_EXT_CONFIG_FILTER_12 = (0xC << 8),
TIM_EXT_CONFIG_FILTER_13 = (0xD << 8),
TIM_EXT_CONFIG_FILTER_14 = (0xE << 8),
TIM_EXT_CONFIG_FILTER_15 = (0xF << 8),
TIM_EXT_CONFIG_PRESCALER_DIV_1 = (0x0 << 12),
TIM_EXT_CONFIG_PRESCALER_DIV_2 = (0x1 << 12),
TIM_EXT_CONFIG_PRESCALER_DIV_4 = (0x2 << 12),
TIM_EXT_CONFIG_PRESCALER_DIV_8 = (0x3 << 12),
TIM_EXT_CONFIG_USE_AS_CLK = (0x3 << 14),
TIM_EXT_CONFIG_INVERT = (0x3 << 15),
};
enum TimOutputConfig {
TIM_OUTPUT_CONFIG_FAST_MODE = (0x1 << 2),
TIM_OUTPUT_CONFIG_PRELOAD_EN = (0x1 << 3),
TIM_OUTPUT_CONFIG_MODE_FROZEN = (0x0 << 4),
TIM_OUTPUT_CONFIG_MODE_ACTIVE = (0x1 << 4),
TIM_OUTPUT_CONFIG_MODE_INACTIVE = (0x2 << 4),
TIM_OUTPUT_CONFIG_MODE_TOGGLE = (0x3 << 4),
TIM_OUTPUT_CONFIG_MODE_FORCE_ACTIVE = (0x4 << 4),
TIM_OUTPUT_CONFIG_MODE_FORCE_INACTIVE = (0x5 << 4),
TIM_OUTPUT_CONFIG_MODE_PWM_1 = (0x6 << 4),
TIM_OUTPUT_CONFIG_MODE_PWM_2 = (0x7 << 4),
TIM_OUTPUT_CONFIG_CLEAR_ON_EXT_TRIG = (0x1 << 7),
};
enum TimIntputConfig {
TIM_INPUT_CONFIG_ALTERNATE_TRIGGER = (0x2 << 0),
TIM_INPUT_CONFIG_INTERNAL_TRIGGER = (0x3 << 0),
TIM_INPUT_CONFIG_PRESCALER_1 = (0x0 << 2),
TIM_INPUT_CONFIG_PRESCALER_2 = (0x1 << 2),
TIM_INPUT_CONFIG_PRESCALER_4 = (0x2 << 2),
TIM_INPUT_CONFIG_PRESCALER_8 = (0x3 << 2),
};
enum TimIRQSource {
TIM_IRQ_SOURCE_TRIGGER,
TIM_IRQ_SOURCE_UPDATE,
};
typedef void (*TimCallback)(enum TimIRQSource src);
//--functions-------------------------------------------------------------------
void tim_configure_master(enum TimPeriph periph, enum TimConfig config_mask,
enum TimMasterConfig master_config_mask, TimCallback callback);
void tim_configure_slave(enum TimPeriph periph, enum TimConfig config_mask,
enum TimSlaveConfig slave_config_mask, TimCallback callback);
void tim_start(enum TimPeriph periph);
void tim_stop(enum TimPeriph periph);
void tim_update(enum TimPeriph periph);
void tim_set_auto_reload(enum TimPeriph periph, uint16_t auto_reload);
void tim_set_prescaler(enum TimPeriph periph, uint16_t prescaler);
void tim_set_counter(enum TimPeriph periph, uint16_t counter);
uint16_t tim_get_auto_reload(enum TimPeriph periph);
uint16_t tim_get_prescaler(enum TimPeriph periph);
uint16_t tim_get_counter(enum TimPeriph periph);
void tim_configure_output_channel(enum TimPeriph periph,
enum TimChannel channel_mask, enum TimOutputConfig config_mask,
uint16_t value);
void tim_configure_input_channel(enum TimPeriph periph,
enum TimChannel channel_mask, enum TimInputConfig config_mask,
uint16_t value);
void tim_configure_ext_trigger(enum TimPeriph periph,
enum TimExtConfig ext_config_mask);
#endif //_TIM_H_

455
drv/tim_regs.h Normal file
View File

@ -0,0 +1,455 @@
/** @file tim_regs.h
* Module defining the TIMers registers.
*
* Mainly made to be used by the tim module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _TIM_REGS_H_
#define _TIM_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define TIM1_BASE_ADDRESS 0x40012C00
#define TIM2_BASE_ADDRESS 0x40000000
#define TIM3_BASE_ADDRESS 0x40000400
#define TIM4_BASE_ADDRESS 0x40000800
union TIM_CR1 {
struct {
uint32_t CEN:1;
uint32_t UDIS:1;
uint32_t URS:1;
uint32_t OPM:1;
uint32_t DIR:1;
uint32_t CMS:2;
uint32_t ARPE:1;
uint32_t CKD:2;
uint32_t reserved1:22;
};
uint32_t word;
};
union TIM_CR2 {
struct {
uint32_t reserved1:3;
uint32_t CCDS:1;
uint32_t MMS:3;
uint32_t TI1S:1;
uint32_t reserved2:24;
};
uint32_t word;
};
union TIM_ADV_CR2 {
struct {
uint32_t CCPC:1;
uint32_t reserved1:1;
uint32_t CCUS:1;
uint32_t CCDS:1;
uint32_t MMS:3;
uint32_t TI1S:1;
uint32_t OI1S:1;
uint32_t OIS1N:1;
uint32_t OIS2:1;
uint32_t OIS2N:1;
uint32_t OIS3:1;
uint32_t OIS3N:1;
uint32_t OIS4:1;
uint32_t reserved2:17;
};
uint32_t word;
};
union TIM_SMCR {
struct {
uint32_t SMS:3;
uint32_t reserved1:1;
uint32_t TS:3;
uint32_t MSM:1;
uint32_t ETF:4;
uint32_t ETPS:2;
uint32_t ECE:1;
uint32_t ETP:1;
uint32_t reserved2:16;
};
uint32_t word;
};
union TIM_DIER {
struct {
uint32_t UIE:1;
uint32_t CC1IE:1;
uint32_t CC2IE:1;
uint32_t CC3IE:1;
uint32_t CC4IE:1;
uint32_t reserved1:1;
uint32_t TIE:1;
uint32_t reserved2:1;
uint32_t UDE:1;
uint32_t CC1DE:1;
uint32_t CC2DE:1;
uint32_t CC3DE:1;
uint32_t CC4DE:1;
uint32_t COMDE:1;
uint32_t TDE:1;
uint32_t reserved3:17;
};
uint32_t word;
};
union TIM_ADV_DIER {
struct {
uint32_t UIE:1;
uint32_t CC1IE:1;
uint32_t CC2IE:1;
uint32_t CC3IE:1;
uint32_t CC4IE:1;
uint32_t COMIE:1;
uint32_t TIE:1;
uint32_t BIE:1;
uint32_t UDE:1;
uint32_t CC1DE:1;
uint32_t CC2DE:1;
uint32_t CC3DE:1;
uint32_t CC4DE:1;
uint32_t COMDE:1;
uint32_t TDE:1;
uint32_t reserved1:17;
};
uint32_t word;
};
union TIM_SR {
struct {
uint32_t UIF:1;
uint32_t CC1IF:1;
uint32_t CC2IF:1;
uint32_t CC3IF:1;
uint32_t CC4IF:1;
uint32_t reserved1:1;
uint32_t TIF:1;
uint32_t reserved2:2;
uint32_t CC1OF:1;
uint32_t CC2OF:1;
uint32_t CC3OF:1;
uint32_t CC4OF:1;
uint32_t reserved3:19;
};
uint32_t word;
};
union TIM_ADV_SR {
struct {
uint32_t UIF:1;
uint32_t CC1IF:1;
uint32_t CC2IF:1;
uint32_t CC3IF:1;
uint32_t CC4IF:1;
uint32_t COMIF:1;
uint32_t TIF:1;
uint32_t BIF:1;
uint32_t reserved1:1;
uint32_t CC1OF:1;
uint32_t CC2OF:1;
uint32_t CC3OF:1;
uint32_t CC4OF:1;
uint32_t reserved2:19;
};
uint32_t word;
};
union TIM_EGR {
struct {
uint32_t UG:1;
uint32_t CC1G:1;
uint32_t CC2G:1;
uint32_t CC3G:1;
uint32_t CC4G:1;
uint32_t reserved1:1;
uint32_t TG:1;
uint32_t reserved2:25;
};
uint32_t word;
};
union TIM_ADV_EGR {
struct {
uint32_t UG:1;
uint32_t CC1G:1;
uint32_t CC2G:1;
uint32_t CC3G:1;
uint32_t CC4G:1;
uint32_t COMG:1;
uint32_t TG:1;
uint32_t BG:1;
uint32_t reserved1:24;
};
uint32_t word;
};
union TIM_CCMR1_INPUT {
struct {
uint32_t CC1S:2;
uint32_t OC1FE:1;
uint32_t OC1PE:1;
uint32_t OC1M:3;
uint32_t OC1CE:1;
uint32_t CC2S:2;
uint32_t OC2FE:1;
uint32_t OC2PE:1;
uint32_t OC2M:3;
uint32_t OC2CE:1;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_CCMR1_OUTPUT {
struct {
uint32_t CC1S:2;
uint32_t IC1PSC:2;
uint32_t IC1F:4;
uint32_t CC2S:2;
uint32_t IC2PSC:2;
uint32_t IC2F:4;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_CCMR1 {
union TIM_CCMR1_INPUT input;
union TIM_CCMR1_OUTPUT output;
};
union TIM_CCMR2_INPUT {
struct {
uint32_t CC3S:2;
uint32_t OC3FE:1;
uint32_t OC3PE:1;
uint32_t OC3M:3;
uint32_t OC3CE:1;
uint32_t CC4S:2;
uint32_t OC4FE:1;
uint32_t OC4PE:1;
uint32_t OC4M:3;
uint32_t OC4CE:1;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_CCMR2_OUTPUT {
struct {
uint32_t CC3S:2;
uint32_t IC3PSC:2;
uint32_t IC3F:4;
uint32_t CC4S:2;
uint32_t IC4PSC:2;
uint32_t IC4F:4;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_CCMR2 {
union TIM_CCMR2_INPUT input;
union TIM_CCMR2_OUTPUT output;
};
union TIM_CCER {
struct {
uint32_t CC1E:1;
uint32_t CC1P:1;
uint32_t reserved1:2;
uint32_t CC2E:1;
uint32_t CC2P:1;
uint32_t reserved2:2;
uint32_t CC3E:1;
uint32_t CC3P:1;
uint32_t reserved3:2;
uint32_t CC4E:1;
uint32_t CC4P:1;
uint32_t reserved4:18;
};
uint32_t word;
};
union TIM_ADV_CCER {
struct {
uint32_t CC1E:1;
uint32_t CC1P:1;
uint32_t CC1NE:1;
uint32_t CC1NP:1;
uint32_t CC2E:1;
uint32_t CC2P:1;
uint32_t CC2NE:1;
uint32_t CC2NP:1;
uint32_t CC3E:1;
uint32_t CC3P:1;
uint32_t CC3NE:1;
uint32_t CC3NP:1;
uint32_t CC4E:1;
uint32_t CC4P:1;
uint32_t CC4NE:1;
uint32_t CC4NP:1;
uint32_t reserved1:18;
};
uint32_t word;
};
union TIM_CNT {
struct {
uint32_t CNT:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_PSC {
struct {
uint32_t PSC:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_ARR {
struct {
uint32_t ARR:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_ADV_RCR {
struct {
uint32_t REP:8;
uint32_t reserved1:24;
};
uint32_t word;
};
union TIM_CCR1 {
struct {
uint32_t CCR1:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_CCR2 {
struct {
uint32_t CCR2:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_CCR3 {
struct {
uint32_t CCR3:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_CCR4 {
struct {
uint32_t CCR4:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_ADV_BDTR {
struct {
uint32_t DT:8;
uint32_t LOCK:2;
uint32_t OSSI:1;
uint32_t OSSR:1;
uint32_t BKE:1;
uint32_t BKP:1;
uint32_t AOE:1;
uint32_t MOE:1;
uint32_t reserved1:16;
};
uint32_t word;
};
union TIM_DCR {
struct {
uint32_t DBA:5;
uint32_t reserved1:3;
uint32_t MBL:5;
uint32_t reserved2:19;
};
uint32_t word;
};
union TIM_DMAR {
struct {
uint32_t DMAB;
};
uint32_t word;
};
struct TIM {
union TIM_CR1 cr1;
union TIM_CR2 cr2;
union TIM_SMCR smcr;
union TIM_DIER dier;
union TIM_SR sr;
union TIM_EGR egr;
union TIM_CCMR1 ccmr1;
union TIM_CCMR2 ccmr2;
union TIM_CCER ccer;
union TIM_CNT cnt;
union TIM_PSC psc;
union TIM_ARR arr;
uint32_t reserved1;
union TIM_CCR1 ccr1;
union TIM_CCR2 ccr2;
union TIM_CCR3 ccr3;
union TIM_CCR4 ccr4;
uint32_t reserved2;
union TIM_DCR dcr;
union TIM_DMAR dmar;
};
struct TIM_ADV {
union TIM_CR1 cr1;
union TIM_ADV_CR2 cr2;
union TIM_SMCR smcr;
union TIM_ADV_DIER dier;
union TIM_ADV_SR sr;
union TIM_ADV_EGR egr;
union TIM_CCMR1 ccmr1;
union TIM_CCMR2 ccmr2;
union TIM_ADV_CCER ccer;
union TIM_CNT cnt;
union TIM_PSC psc;
union TIM_ARR arr;
union TIM_ADV_RCR rcr;
union TIM_CCR1 ccr1;
union TIM_CCR2 ccr2;
union TIM_CCR3 ccr3;
union TIM_CCR4 ccr4;
union TIM_ADV_BDTR bdtr;
union TIM_DCR dcr;
union TIM_DMAR dmar;
};
//--functions-------------------------------------------------------------------
#endif //_TIM_REGS_H_

259
drv/usart.c Normal file
View File

@ -0,0 +1,259 @@
/** @file usart.c
* Module handling Universal Synchronous/Asynchronous Receiver/Transmitter
*
* The module provides functions to configure the usarts and read/write from/to
* it
*/
//--includes--------------------------------------------------------------------
#include "usart.h"
#include "usart_regs.h"
#include "rcc.h"
#include "dma.h"
#include "stddef.h"
//--local definitions-----------------------------------------------------------
static void configure_usart(volatile struct USART* regs,
enum UsartConfig config);
static void configure_baudrate(volatile struct USART* regs, uint32_t clock,
uint32_t baudrate);
#define DMA_CONFIG (DMA_CONFIG_PSIZE_8BITS)
//--local variables-------------------------------------------------------------
static volatile struct USART* const usarts[] = {
(struct USART*)USART1_BASE_ADDRESS,
(struct USART*)USART2_BASE_ADDRESS,
(struct USART*)USART3_BASE_ADDRESS,
};
static const struct DmaParam usarts_rx_param[] = {
{
(void*)&usarts[USART_PERIPH_1]->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_5,
},
{
(void*)&usarts[USART_PERIPH_2]->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_6,
},
{
(void*)&usarts[USART_PERIPH_3]->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_3,
},
};
static const struct DmaParam usarts_tx_param[] = {
{
(void*)&usarts[USART_PERIPH_1]->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_4,
},
{
(void*)&usarts[USART_PERIPH_2]->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_7,
},
{
(void*)&usarts[USART_PERIPH_3]->DR,
DMA_CONFIG,
DMA_PERIPH_1,
DMA_CHANNEL_2,
},
};
//--public functions------------------------------------------------------------
void usart_configure(enum UsartPeriph periph, enum UsartConfig config,
uint32_t baudrate)
{
struct RccClocks clocks;
rcc_get_clocks(&clocks);
switch (periph) {
case USART_PERIPH_1:
rcc_enable(RCC_AHB_NONE, RCC_APB1_NONE, RCC_APB2_USART);
configure_baudrate(usarts[USART_PERIPH_1], clocks.apb2_freq,
baudrate);
configure_usart(usarts[USART_PERIPH_1], config);
break;
case USART_PERIPH_2:
rcc_enable(RCC_AHB_NONE, RCC_APB1_USART2, RCC_APB2_NONE);
configure_baudrate(usarts[USART_PERIPH_2], clocks.apb1_freq,
baudrate);
configure_usart(usarts[USART_PERIPH_2], config);
break;
case USART_PERIPH_3:
rcc_enable(RCC_AHB_NONE, RCC_APB1_USART3, RCC_APB2_NONE);
configure_baudrate(usarts[USART_PERIPH_3], clocks.apb1_freq,
baudrate);
configure_usart(usarts[USART_PERIPH_3], config);
break;
default:
break;
}
}
uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte)
{
if (periph > USART_PERIPH_3) {
return 1;
}
if (usarts[periph]->SR.RXNE) {
*byte = usarts[periph]->DR.DR;
return 0;
} else {
return 1;
}
}
uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte)
{
if (periph > USART_PERIPH_3) {
return 1;
}
//only write data if the tx register it empty, give up otherwise
if (usarts[periph]->SR.TXE) {
usarts[periph]->DR.DR = byte;
return 0;
} else {
return 1;
}
}
const struct DmaParam* usart_configure_rx_dma(enum UsartPeriph periph)
{
if (periph > USART_PERIPH_3) {
return nullptr;
}
usarts[periph]->CR3.DMAR = 1;
return &usarts_rx_param[periph];
}
const struct DmaParam* usart_configure_tx_dma(enum UsartPeriph periph)
{
if (periph > USART_PERIPH_3) {
return nullptr;
}
usarts[periph]->CR3.DMAT = 1;
return &usarts_tx_param[periph];
}
//--local functions-------------------------------------------------------------
/**
* Apply the given configuration to the given registers. Generic version of
* usart_configure()
*/
static void configure_usart(volatile struct USART* regs,
enum UsartConfig config)
{
//configure parity
switch (config)
{
case USART_CONFIG_7E1:
case USART_CONFIG_8E1:
case USART_CONFIG_7E2:
case USART_CONFIG_8E2:
regs->CR1.PCE = 1;
regs->CR1.PS = 0;
break;
case USART_CONFIG_7O1:
case USART_CONFIG_7O2:
case USART_CONFIG_8O1:
case USART_CONFIG_8O2:
regs->CR1.PCE = 1;
regs->CR1.PS = 1;
break;
case USART_CONFIG_8N1:
case USART_CONFIG_8N2:
regs->CR1.PCE = 0;
break;
default:
break;
}
//configure bit number
switch (config)
{
case USART_CONFIG_7E1:
case USART_CONFIG_7E2:
case USART_CONFIG_7O1:
case USART_CONFIG_7O2:
case USART_CONFIG_8N1:
case USART_CONFIG_8N2:
regs->CR1.M = 0;
break;
case USART_CONFIG_8E2:
case USART_CONFIG_8E1:
case USART_CONFIG_8O1:
case USART_CONFIG_8O2:
regs->CR1.M = 1;
break;
default:
break;
}
//configure stop bits
switch (config)
{
case USART_CONFIG_7E1:
case USART_CONFIG_7O1:
case USART_CONFIG_8N1:
case USART_CONFIG_8E1:
case USART_CONFIG_8O1:
regs->CR2.STOP = 0;
break;
case USART_CONFIG_7E2:
case USART_CONFIG_7O2:
case USART_CONFIG_8N2:
case USART_CONFIG_8E2:
case USART_CONFIG_8O2:
regs->CR2.STOP = 2;
break;
default:
break;
}
//enable Rx/Tx
regs->CR1.TE = 1;
regs->CR1.RE = 1;
regs->CR1.UE = 1;
}
/**
* Configure the given registers with the given baudrate. Baudrate is dependant
* on the peripheral's clock and may not be exact due to precision errors (see
* table 192 in documentation)
*/
static void configure_baudrate(volatile struct USART* regs, uint32_t clock,
uint32_t baudrate)
{
uint32_t mantissa = clock / (baudrate * 16);
uint32_t factor = clock / baudrate;
volatile uint32_t divider = factor - (mantissa * 16);
regs->BRR.DIV_Mantissa = mantissa & 0xFFF;
regs->BRR.DIV_Fraction = divider & 0xF;
}

111
drv/usart.h Normal file
View File

@ -0,0 +1,111 @@
/** @file usart.h
* Module handling Universal Synchronous/Asynchronous Receiver/Transmitter
*
* The module provides functions to configure the usarts and read/write from/to
* it
*/
#ifndef _USART_H_
#define _USART_H_
//--includes--------------------------------------------------------------------
#include "dma.h"
#include "stdint.h"
//--type definitions------------------------------------------------------------
/**
* Available USART peripherals. Note that some of these peripherals may not be
* available on all chips
*/
enum UsartPeriph {
USART_PERIPH_1,
USART_PERIPH_2,
USART_PERIPH_3,
};
/**
* Available configuration options
*/
enum UsartConfig {
USART_CONFIG_7E1,
USART_CONFIG_7E2,
USART_CONFIG_7O1,
USART_CONFIG_7O2,
USART_CONFIG_8N1,
USART_CONFIG_8N2,
USART_CONFIG_8E1,
USART_CONFIG_8E2,
USART_CONFIG_8O1,
USART_CONFIG_8O2,
};
//--functions-------------------------------------------------------------------
/**
* Configures the given USART peripheral using the provided condiguration
* options and baudrate. The baudrate may be any value supported by the
* peripheral, though some may not be exact due to precision errors (see
* table 192 in documentation). The baudrate is dependant on the peripheral's
* clock and changes to the later after this function has been called will cause
* the effective baudrate to change
*
* This function doesn't configure the required ports. This should be done using
* the gpio driver:
* - Tx port should be using GPIO_CONFIG_OUT_ALT_PUSH_PULL with
* the appropriate output speed based on the baurate (see GpioMode)
* - Rx port should be using GPIO_CONFIG_IN_FLOATING in input mode
* Both ports do not need to be configured if not used (e.g. if only using Tx,
* the Rx port can be left unconfigured)
*/
void usart_configure(enum UsartPeriph periph, enum UsartConfig config,
uint32_t baudrate);
/**
* Resets the given USART peripheral, applying the default configuration and
* disabling it
*/
void usart_reset(enum UsartPeriph periph);
/**
* Reads a single byte to the given USART peripheral, returning 0 if
* successfull, 1 otherwise.
*
* The Rx port must be configured for this function to ever return successfully
*/
uint32_t usart_read_byte(enum UsartPeriph periph, uint8_t* byte);
/**
* Writes a single byte to the given USART peripheral, returning 0 if
* successfull, 1 otherwise.
*
* The Tx port must be configured for this function to do anything, though the
* function would still return 0
*/
uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte);
/**
* Configures the given USART peripheral for DMA Rx operations, returning the
* corresponding DMA parameters to be used.
*
* The DMA must be configured separately using the DMA driver or an existing
* service
*/
const struct DmaParam* usart_configure_rx_dma(enum UsartPeriph periph);
/**
* Configures the given USART peripheral for DMA Rx operations, returning the
* corresponding DMA parameters to be used.
*
* The DMA must be configured separately using the DMA driver or an existing
* service
*/
const struct DmaParam* usart_configure_tx_dma(enum UsartPeriph periph);
#endif //_USART_H_

137
drv/usart_regs.h Normal file
View File

@ -0,0 +1,137 @@
/** @file usart_regs.h
* Module defining the USART registers.
*
* Mainly made to be used by the usart module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _USART_REGS_H_
#define _USART_REGS_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
#define USART1_BASE_ADDRESS 0x40013800
#define USART2_BASE_ADDRESS 0x40004400
#define USART3_BASE_ADDRESS 0x40004800
union USART_SR {
struct {
uint32_t PE:1;
uint32_t FE:1;
uint32_t NE:1;
uint32_t ORE:1;
uint32_t IDLE:1;
uint32_t RXNE:1;
uint32_t TC:1;
uint32_t TXE:1;
uint32_t LBD:1;
uint32_t CTS:1;
uint32_t reserved1:22;
};
uint32_t word;
};
union USART_DR {
struct {
uint32_t DR:9;
uint32_t reserved1:23;
};
uint32_t word;
};
union USART_BRR {
struct {
uint32_t DIV_Fraction:4;
uint32_t DIV_Mantissa:12;
uint32_t reserved1:16;
};
uint32_t word;
};
union USART_CR1 {
struct {
uint32_t SBK:1;
uint32_t RWU:1;
uint32_t RE:1;
uint32_t TE:1;
uint32_t IDLEIE:1;
uint32_t RXNEIE:1;
uint32_t TCIE:1;
uint32_t TXEIE:1;
uint32_t PEI:1;
uint32_t PS:1;
uint32_t PCE:1;
uint32_t WAKE:1;
uint32_t M:1;
uint32_t UE:1;
uint32_t reserved1:18;
};
uint32_t word;
};
union USART_CR2 {
struct {
uint32_t ADD:4;
uint32_t reserved1:1;
uint32_t LBDL:1;
uint32_t LBDIE:1;
uint32_t reserved2:1;
uint32_t LBCL:1;
uint32_t CPHA:1;
uint32_t CPOL:1;
uint32_t CLKEN:1;
uint32_t STOP:2;
uint32_t LINEN:1;
uint32_t reserved3:17;
};
uint32_t word;
};
union USART_CR3 {
struct {
uint32_t EIE:1;
uint32_t IREN:1;
uint32_t IRLP:1;
uint32_t HDSEL:1;
uint32_t NACK:1;
uint32_t SCEN:1;
uint32_t DMAR:1;
uint32_t DMAT:1;
uint32_t RTSE:1;
uint32_t CTSE:1;
uint32_t CTSIE:1;
uint32_t reserved3:21;
};
uint32_t word;
};
union USART_GTPR {
struct {
uint32_t PSC:8;
uint32_t GT:8;
uint32_t reserved1:16;
};
uint32_t word;
};
struct USART {
union USART_SR SR;
union USART_DR DR;
union USART_BRR BRR;
union USART_CR1 CR1;
union USART_CR2 CR2;
union USART_CR3 CR3;
union USART_GTPR GTPR;
};
//--functions-------------------------------------------------------------------
#endif //_USART_REGS_H_

82
linker.ld Normal file
View File

@ -0,0 +1,82 @@
/** @file
* Linker to be used with the HBL.
*
* This linker file provides the basic architecture for a projet. Stack size and
* memory layout can be configured at will. Note that this file doesn't provide
* a heap space since the HBL doesn't provide or use any form of dynamic
* allocation.
*/
/*--Configuration-------------------------------------------------------------*/
/* minimal stack size */
_min_stack_size = 0x400;
/* memory layout of the chip */
MEMORY
{
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (!rx) : ORIGIN = 0x20000000, LENGTH = 20K
}
/*--Description---------------------------------------------------------------*/
ENTRY(hdr_reset)
/* end of "RAM" Ram type memory */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* ROM adress to load data from */
_sromdata = LOADADDR(.data);
SECTIONS
{
/* vector table, cpu will look for it at adress 0 on reset */
.vector_table :
{
KEEP(*(.vector_table))
} > ROM
/* program code */
.text :
{
. = ALIGN(4);
*(.text)
} > ROM
/* const data */
.rodata :
{
. = ALIGN(4);
*(.rodata)
} > ROM
/* initialized data from ROM */
.data :
{
. = ALIGN(4);
_sdata = .;
*(.data)
. = ALIGN(4);
_edata = .;
} > RAM AT > ROM
/* uninitialized data, zeroed */
.bss :
{
. = ALIGN(4);
_sbss = .;
*(.bss)
. = ALIGN(4);
_ebss = .;
} > RAM
/* memory space allocated to stack. The stack is situated at the very end of
* the RAM while this section may not, thus it is only used to enforce a
* minimal stack size */
.stack :
{
. = ALIGN(8);
. = . + _min_stack_size;
} > RAM
}

View File

@ -1,3 +0,0 @@
#!/bin/bash
openocd -f interface/stlink.cfg -f target/cs32f1x.cfg

25
openocd.cfg Normal file
View File

@ -0,0 +1,25 @@
# using a STM32f103CB wich has 128kB of flash instead of the more common 64KB
set CHIPNAME stm32f103CB
set FLASH_SIZE 0x20000
# load default configurations
source [find interface/stlink.cfg]
source [find target/stm32f1x.cfg]
# override examine-end event
$CHIPNAME.cpu configure -event examine-end {
# write DBGMCU_CR, disable all peripherals (timers, dmas, watchdogs while
# halted by debug. Trace is not affected
mmw 0xE0042004 0x7E3FFF07 0
}
reset_config srst_only srst_nogate connect_assert_srst
# inits debugging, from that point, commands can be used
init
# resets the target and halt it immediately afterward. Stops debug from being
# inacessible due to low-power states
reset halt

View File

@ -1,29 +0,0 @@
//------------------------------------------------------------------------------
/* priorities */
#define EXTI0_IRQ_PRIORITY 8
#define EXTI1_IRQ_PRIORITY 8
#define EXTI2_IRQ_PRIORITY 8
#define EXTI3_IRQ_PRIORITY 8
#define EXTI4_IRQ_PRIORITY 8
#define EXTI9_5_IRQ_PRIORITY 8
#define EXTI15_10_IRQ_PRIORITY 8
#define TIM1_IRQ_PRIORITY 4
#define TIM2_IRQ_PRIORITY 4
#define TIM3_IRQ_PRIORITY 4
#define TIM4_IRQ_PRIORITY 4
#define USART1_IRQ_PRIORITY 3
#define USART2_IRQ_PRIORITY 3
#define USART3_IRQ_PRIORITY 3
#define I2C1_IRQ_PRIORITY 2
#define I2C1_IRQERR_PRIORITY 1
#define I2C2_IRQ_PRIORITY 2
#define I2C2_IRQERR_PRIORITY 1
#define SPI1_IRQ_PRIORITY 4
#define SPI2_IRQ_PRIORITY 4
#define ADC1_2_IRQ_PRIORITY 5

View File

@ -1,41 +0,0 @@
#include "adc.h"
extern Clock_t sysclks;
int adc_init(ADC_TypeDef* adc) {
// enable adc clock
if(adc == ADC1) RCC->APB2ENR |= 0x1 << 9;
else if(adc == ADC2) RCC->APB2ENR |= 0x1 << 10;
else return -1; //no such adc
// enable adc
adc->CR2 |= 0x1;
// configure regular channels
adc->CR1 = 0; //reset value
adc->CR1 |= 0x1 << 23; //enable analog watchdog
adc->CR1 |= 0x1 << 11; //discontinuous mode
// set trigger to manual
adc->CR1 |= 0x7 << 3;
adc->SMPR2 |= 0x3FFFFFFF;
// calibrate
adc->CR2 |= 0x1 << 2;
while((adc->CR2 >> 2) & 0x1);
return 0;
}
uint16_t adc_read(ADC_TypeDef* adc, uint8_t channel) {
adc->SQR1 &= ~(0xF << 20); //one conversion only
adc->SQR3 = (adc->SQR3 & ~(0x1F)) | channel; //set channel
//adc->CR2 |= 0x1 << 22; //start convertion
adc->CR2 |= 0x1;
while(!((adc->SR >> 1) & 0x1)); //waiting for convertion
return adc->DR & 0xFFF;
}

View File

@ -1,15 +0,0 @@
#ifndef ADC_H
#define ADC_H
#include "../target/stm32f103xb.h"
#include "../config.h"
#include "rcc.h"
int adc_init(ADC_TypeDef* adc);
uint16_t adc_read(ADC_TypeDef* adc, uint8_t channel);
#endif

View File

@ -1,223 +0,0 @@
//driver header
#include "io.h"
static OnIO io_cb[16]={
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
void EXTI0_IRQHandler() {
if (io_cb[0]) (io_cb[0])();
EXTI->PR = 1<<0;
}
void EXTI1_IRQHandler() {
if (io_cb[1]) (io_cb[1])();
EXTI->PR = 1<<1;
}
void EXTI2_IRQHandler() {
if (io_cb[2]) (io_cb[2])();
EXTI->PR = 1<<2;
}
void EXTI3_IRQHandler() {
if (io_cb[3]) (io_cb[3])();
EXTI->PR = 1<<3;
}
void EXTI4_IRQHandler() {
if (io_cb[4]) (io_cb[4])();
EXTI->PR = 1<<4;
}
void EXTI9_5_IRQHandler() {
if (EXTI->PR & (1<<5)) {
if (io_cb[5]) (io_cb[5])();
EXTI->PR = 1<<5;
} else if (EXTI->PR & (1<<6)) {
if (io_cb[6]) (io_cb[6])();
EXTI->PR = 1<<6;
} else if (EXTI->PR & (1<<7)) {
if (io_cb[7]) (io_cb[7])();
EXTI->PR = 1<<7;
} else if (EXTI->PR & (1<<8)) {
if (io_cb[8]) (io_cb[8])();
EXTI->PR = 1<<8;
} else if (EXTI->PR & (1<<9)) {
if (io_cb[9]) (io_cb[9])();
EXTI->PR = 1<<9;
}
}
void EXTI15_10_IRQHandler() {
if (EXTI->PR & (1<<10)) {
if (io_cb[10]) (io_cb[10])();
EXTI->PR = 1<<10;
} else if (EXTI->PR & (1<<11)) {
if (io_cb[11]) (io_cb[11])();
EXTI->PR = 1<<11;
} else if (EXTI->PR & (1<<12)) {
if (io_cb[12]) (io_cb[12])();
EXTI->PR = 1<<12;
} else if (EXTI->PR & (1<<13)) {
if (io_cb[13]) (io_cb[13])();
EXTI->PR = 1<<13;
} else if (EXTI->PR & (1<<14)) {
if (io_cb[14]) (io_cb[14])();
EXTI->PR = 1<<14;
} else if (EXTI->PR & (1<<15)) {
if (io_cb[15]) (io_cb[15])();
EXTI->PR = 1<<15;
}
}
/* Definitions for EXTI configuration */
enum io_exti_mask {
SYSCFG_EXTI_PA_MASK = 0x0,
SYSCFG_EXTI_PB_MASK = 0x1,
SYSCFG_EXTI_PC_MASK = 0x2,
SYSCFG_EXTI_PD_MASK = 0x3,
SYSCFG_EXTI_PE_MASK = 0x4
};
int io_configure(GPIO_TypeDef *gpio, uint16_t pin, uint16_t pin_cfg, OnIO cb) {
// enable GPIOx subsystem clocking
if (gpio == GPIOA) RCC->APB2ENR |= 1<<2;
else if (gpio == GPIOB) RCC->APB2ENR |= 1<<3;
else if (gpio == GPIOC) RCC->APB2ENR |= 1<<4;
else if (gpio == GPIOD) RCC->APB2ENR |= 1<<5;
else if (gpio == GPIOE) RCC->APB2ENR |= 1<<6;
// setup pin mask for crx registers
uint64_t pin_mask = 0;
for(int i=0; i<16; ++i) {
if((pin >> i) & 0x1) pin_mask |= 0x1ll << 4*i;
}
// clear previous data
uint64_t crx = pin_mask * 0x4; //reset value is 0x4
uint16_t odr = pin;
gpio->CRH &= ~(crx >> 32);
gpio->CRL &= ~(crx & 0xFFFFFFFF);
gpio->BSRR |= odr << 16;
// set up the new configuration
crx = pin_mask * (pin_cfg & 0xF);
odr = pin * ((pin_cfg & 0x10) >> 4);
gpio->CRH |= crx >> 32;
gpio->CRL |= crx & 0xFFFFFFFF;
gpio->BSRR |= odr;
//TODO manage alternate functions
// manage IRQs //TODO allow IRQ reset
if (!cb) return 0; //no callback attached
if (pin_cfg & 0x7) return -1; //callback set, but not in input mode
RCC->APB2ENR |= 0x1; //enable AFIO clocking
// prepare mask
uint8_t port_mask = 0;
// uint32_t pin_mask = 0;
if (gpio == GPIOA) port_mask = SYSCFG_EXTI_PA_MASK;
else if (gpio == GPIOB) port_mask = SYSCFG_EXTI_PB_MASK;
else if (gpio == GPIOC) port_mask = SYSCFG_EXTI_PC_MASK;
else if (gpio == GPIOD) port_mask = SYSCFG_EXTI_PD_MASK;
else if (gpio == GPIOE) port_mask = SYSCFG_EXTI_PE_MASK;
// setup external IRQ lines
uint64_t afio_mask;
for(int i=0; i<4; ++i) {
afio_mask = ((pin_mask & (0xFFFFll << (i*16))) >> (i*16)) * port_mask;
if(afio_mask) AFIO->EXTICR[i] |= afio_mask;
}
// clear pending IRQs on concerned lines
EXTI->PR |= pin;
// configure IRQ options and masks
EXTI->IMR |= pin;
if(pin_cfg & 0x100) EXTI->RTSR |= pin;
if(pin_cfg & 0x200) EXTI->FTSR |= pin; //in case both falling and rising
//are set, both will be a trigger
// register IRQ callbacks
for(int i=0; i<16; ++i) {
if((pin >> i) & 0x1) {
io_cb[i] = cb;
// Setup NVIC
switch (i) {
case 0:
NVIC_SetPriority(EXTI0_IRQn, EXTI0_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI0_IRQn);
break;
case 1:
NVIC_SetPriority(EXTI1_IRQn, EXTI1_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI1_IRQn);
break;
case 2:
NVIC_SetPriority(EXTI2_IRQn, EXTI2_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI2_IRQn);
break;
case 3:
NVIC_SetPriority(EXTI3_IRQn, EXTI3_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI3_IRQn);
break;
case 4:
NVIC_SetPriority(EXTI4_IRQn, EXTI4_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI4_IRQn);
break;
case 5:
case 6:
case 7:
case 8:
case 9:
NVIC_SetPriority(EXTI9_5_IRQn, EXTI9_5_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI9_5_IRQn);
break;
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
NVIC_SetPriority(EXTI15_10_IRQn, EXTI15_10_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI15_10_IRQn);
break;
default:
return -1; //impossible to get there
}
}
}
return 0;
}
uint32_t io_read(GPIO_TypeDef *gpio, uint16_t mask)
{
return gpio->IDR & mask;
}
void io_write(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask)
{
gpio->BSRR = (uint32_t)(mask) << (val ? 0 : 16);
}
void io_write_n(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask)
{
gpio->BSRR = (uint32_t)(mask) << (val ? 16 : 0);
}
void io_set(GPIO_TypeDef *gpio, uint16_t mask)
{
gpio->BSRR = mask;
}
void io_clear(GPIO_TypeDef *gpio, uint16_t mask)
{
gpio->BSRR = (uint32_t)(mask) << 16;
}

View File

@ -1,132 +0,0 @@
#ifndef IO_H
#define IO_H
//std headers
#include <stdlib.h>
#include <stdint.h>
//target header
#include "../target/stm32f103xb.h"
//custom header
#include "../config.h"
//------------------------------------------------------------------------------
/* GPIO pin mask definitions */
enum io_pin {
PIN_0 = (1 << 0),
PIN_1 = (1 << 1),
PIN_2 = (1 << 2),
PIN_3 = (1 << 3),
PIN_4 = (1 << 4),
PIN_5 = (1 << 5),
PIN_6 = (1 << 6),
PIN_7 = (1 << 7),
PIN_8 = (1 << 8),
PIN_9 = (1 << 9),
PIN_10 = (1 << 10),
PIN_11 = (1 << 11),
PIN_12 = (1 << 12),
PIN_13 = (1 << 13),
PIN_14 = (1 << 14),
PIN_15 = (1 << 15),
PIN_ALL = 0xFFFF
};
//------------------------------------------------------------------------------
/* GPIO pin mode definitions */
enum io_mode {
IO_MODE_INPUT = (0x0),
IO_MODE_OUTPUT = (0x1), // 10Mhz max
IO_MODE_OUTPUT_SLOW = (0x3), // 2MHz max
IO_MODE_OUTPUT_FAST = (0x4) // 50 MHz max
};
//------------------------------------------------------------------------------
/* GPIO pin conf definitions */
enum io_conf {
IO_IN_ANALOG = (0b0 << 2),
IO_IN_FLOATING = (0b1 << 2),
IO_IN_PULL_UP = (0b110 << 2),
IO_IN_PULL_DOWN = (0b010 << 2),
IO_OUT_ALT_FNCT = (0b10 << 2),
IO_OUT_PUSH_PULL = (0b0 << 2),
IO_OUT_OPEN_DRAIN = (0b1 << 2)
};
//------------------------------------------------------------------------------
/* GPIO pin clear */
#define IO_CLEAR (0)
//------------------------------------------------------------------------------
/* alternate function selection option */
//TODO not supported for now
//enum io_alt_fnct {
// PIN_OPT_AF0 0x0,
// PIN_OPT_AF1 0x1,
// PIN_OPT_AF2 0x2,
// PIN_OPT_AF3 0x3,
// PIN_OPT_AF4 0x4,
// PIN_OPT_AF5 0x5,
// PIN_OPT_AF6 0x6,
// PIN_OPT_AF7 0x7,
// PIN_OPT_AF8 0x8,
// PIN_OPT_AF9 0x9,
// PIN_OPT_AF10 0xA,
// PIN_OPT_AF11 0xB,
// PIN_OPT_AF12 0xC,
// PIN_OPT_AF13 0xD,
// PIN_OPT_AF14 0xE,
// PIN_OPT_AF15 0xF
//};
//------------------------------------------------------------------------------
/* GPIO IRQ conf definitons */
enum io_irq_conf {
IO_IRQ_EDGE_RISE = (0x1 << 8),
IO_IRQ_EDGE_FALL = (0x2 << 8),
IO_IRQ_EDGE_BOTH = (0x3 << 8)
};
typedef void (*OnIO)();
//------------------------------------------------------------------------------
/* io_configure
*
* configure pins referenced in 'pin_mask' of specified port
* 'gpio' according to 'pin_cfg' and associate a callback
* function 'cb' if not NULL.
* returns 0 if success
*/
int io_configure(GPIO_TypeDef *gpio, uint16_t pin_mask, uint16_t pin_cfg,
OnIO cb);
/* io_read
*
* read 32 bit data from port 'gpio', filter the result with mask
*/
uint32_t io_read(GPIO_TypeDef *gpio, uint16_t mask);
/* io_write
*
* write 16 bit data filtered by mask to port 'gpio'
* '1' in val are written as HIGH level on port pins
*/
void io_write(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask);
/* io_write_n
*
* write 16 bit data filtered by mask to port 'gpio'
* '1' in val are written as LOW level on port pins
*/
void io_write_n(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask);
/* io_set/clear
*
* set or clear outputs according to bit mask
*/
void io_set(GPIO_TypeDef *gpio, uint16_t mask);
void io_clear(GPIO_TypeDef *gpio, uint16_t mask);
#endif

View File

@ -1,186 +0,0 @@
#include "lcd.h"
enum mode {
WRITE,
READ,
UNDEFINED
};
//TODO make the driver dynamic ?
static TIM_TypeDef* timer = 0;
static uint8_t mode = UNDEFINED;
static uint8_t rows = 0;
static uint8_t columns = 0;
static uint8_t rows_offset[4] = {};
//------------------------------------------------------------------------------
// internal functions
int set_mode_read(void) {
// configure pins
if(io_configure(GPIOA, PIN_8 | PIN_12 | PIN_15, IO_MODE_INPUT |
IO_IN_FLOATING, 0)) return -1;
if(io_configure(GPIOB, PIN_3 | PIN_4 | PIN_13 | PIN_14 | PIN_15,
IO_MODE_INPUT | IO_IN_FLOATING, 0)) return -1;
// put lcd in read mode
io_set(GPIOA, PIN_9); // after the pins are ready to recieve voltage
mode = READ;
return 0;
}
int set_mode_write(void) {
// put lcd in write mode
io_clear(GPIOA, PIN_9); //before the pin can send voltage
// configure pins
if(io_configure(GPIOA, PIN_8 | PIN_12 | PIN_15, IO_MODE_OUTPUT |
IO_OUT_PUSH_PULL, 0)) return -1;
if(io_configure(GPIOB, PIN_3 | PIN_4 | PIN_13 | PIN_14 | PIN_15,
IO_MODE_OUTPUT | IO_OUT_PUSH_PULL, 0)) return -1;
mode = WRITE;
return 0;
}
void wait_for_ready(void) {
//TODO debug that
// // configure the lcd
// if(mode != READ) if(set_mode_read()) return;
//
// // read D7 pin
// for(;;) {
// io_set(GPIOA, PIN_11);
// for(int i=0; i<1000; ++i); //timer_wait is overkill here
// if(!io_read(GPIOB, PIN_4)) break;
// io_clear(GPIOA, PIN_11);
// for(int i=0; i<1000; ++i); //same
// }
timer_wait_ms(timer, 2, 0); //wait max delay
}
void write_byte(uint8_t byte) {
// put the lcd bus in write mode
if(mode != WRITE) if(set_mode_write()) return;
// start tranfert
io_set(GPIOA, PIN_11);
timer_wait_us(timer, 1, 0);
// send the data
io_write(GPIOA, (byte >> 0) & 0x1, PIN_8);
io_write(GPIOA, (byte >> 1) & 0x1, PIN_12);
io_write(GPIOB, (byte >> 2) & 0x1, PIN_15);
io_write(GPIOA, (byte >> 3) & 0x1, PIN_15);
io_write(GPIOB, (byte >> 4) & 0x1, PIN_14);
io_write(GPIOB, (byte >> 5) & 0x1, PIN_3);
io_write(GPIOB, (byte >> 6) & 0x1, PIN_13);
io_write(GPIOB, (byte >> 7) & 0x1, PIN_4);
// validate data
io_clear(GPIOA, PIN_11);
}
//------------------------------------------------------------------------------
int lcd_init(TIM_TypeDef* tim, uint8_t col, uint8_t row) {
timer = tim;
columns = col;
rows = row;
rows_offset[0] = 0x00;
rows_offset[1] = 0x40;
rows_offset[2] = 0x00 + columns;
rows_offset[3] = 0x40 + columns;
// disable JTAG, as it utilise needed pins, SWD remains usable in
// synchronous mode
RCC->APB2ENR |= 0x1; //enable AFIO clocking
AFIO->MAPR = (AFIO->MAPR & ~(0x8 << 24)) | 0x2 << 24;
// configure the lcd control pins
if(io_configure(GPIOA, PIN_9 | PIN_10 | PIN_11, IO_MODE_OUTPUT |
IO_OUT_PUSH_PULL, 0)) return -1;
// put the lcd bus in write mode
if(set_mode_write()) return -1; //no check in case the pins were used
//somewhere else
// select instruction register
io_write(GPIOA, LCD_MODE_CMD, PIN_10);
// begin initialisation sequence
timer_wait_ms(timer, 15, 0);
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
timer_wait_ms(timer, 5, 0);
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
timer_wait_us(timer, 150, 0);
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
wait_for_ready();
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
wait_for_ready();
write_byte(LCD_DISP_CTRL | LCD_CTRL_DISP_OFF | LCD_CTRL_CUR_OFF |
LCD_CTRL_BLINK_OFF);
wait_for_ready();
write_byte(LCD_CLEAR);
wait_for_ready();
write_byte(LCD_ENTRY | LCD_ENTRY_LEFT | LCD_ENTRY_SHIFT_DEC);
wait_for_ready();
// post initialisation setup
write_byte(LCD_DISP_CTRL | LCD_CTRL_DISP_ON | LCD_CTRL_CUR_ON |
LCD_CTRL_BLINK_ON);
wait_for_ready();
write_byte(LCD_CLEAR);
return 0;
}
void lcd_send_cmd(uint8_t cmd) {
// wait for the screen
wait_for_ready();
// select instruction register
io_write(GPIOA, LCD_MODE_CMD, PIN_10);
// send the command
write_byte(cmd);
}
void lcd_print(const char* txt) {
// prepare data
const char* c = txt;
// wait for the screen
wait_for_ready();
// select data register
io_write(GPIOA, LCD_MODE_DATA, PIN_10);
// send the caracters until end of string
// TODO implement '\n'
while(*c != '\0') {
wait_for_ready();
write_byte(*c);
c++;
}
}
void lcd_print_c(char c) {
// wait for the screen
wait_for_ready();
// select data register
io_write(GPIOA, LCD_MODE_DATA, PIN_10);
// send the caracter
write_byte(c);
}
void lcd_set_cursor(uint8_t col, uint8_t row) {
lcd_send_cmd(LCD_DDRAM_ADDR | (col + rows_offset[row]));
}

View File

@ -1,93 +0,0 @@
#ifndef LCD_H
#define LCD_H
#include "../target/stm32f103xb.h"
#include "../config.h"
#include "timer.h"
#include "io.h"
#include <stdlib.h>
//------------------------------------------------------------------------------
/* LCD mode selection */
enum lcd_register {
LCD_MODE_CMD = 0,
LCD_MODE_DATA = 1
};
//------------------------------------------------------------------------------
/* LCD commands */
enum lcd_command {
LCD_CLEAR = 0x01,
LCD_CUR_HOME = 0x02,
LCD_ENTRY = 0x04,
LCD_DISP_CTRL = 0x08,
LCD_SHIFT = 0x10,
LCD_FUNC_SET = 0x20,
LCD_CGRAM_ADDR = 0x40,
LCD_DDRAM_ADDR = 0x80
};
//------------------------------------------------------------------------------
/* LCD_ENTRY command options */
enum lcd_entry_option {
LCD_ENTRY_RIGHT = 0x00,
LCD_ENTRY_LEFT = 0x02,
LCD_ENTRY_SHIFT_INC = 0x01,
LCD_ENTRY_SHIFT_DEC = 0x00
};
//------------------------------------------------------------------------------
/* LCD_DISP_CTRL command options */
enum lcd_ctrl_option {
LCD_CTRL_DISP_ON = 0x04,
LCD_CTRL_DISP_OFF = 0x00,
LCD_CTRL_CUR_ON = 0x02,
LCD_CTRL_CUR_OFF = 0x00,
LCD_CTRL_BLINK_ON = 0x01,
LCD_CTRL_BLINK_OFF = 0x00
};
//------------------------------------------------------------------------------
/* LCD_SHIFT command options */
enum lcd_shift_option {
LCD_SHIFT_DISP = 0x08,
LCD_SHIFT_CUR = 0x00,
LCD_SHIFT_RIGHT = 0x04,
LCD_SHIFT_LEFT = 0x00
};
//------------------------------------------------------------------------------
/* LCD_FUNC_SET command options */
enum lcd_func_option {
LCD_FUNC_8BIT = 0x10,
LCD_FUNC_4BIT = 0x00,
LCD_FUNC_2LINE = 0x08,
LCD_FUNC_1LINE = 0x00,
LCD_FUNC_5x10DOTS = 0x04,
LCD_FUNC_5x8DOTS = 0x00
};
//------------------------------------------------------------------------------
/** lcd_init
* initialise the lcd, needed before anything else can be done
* the timer is used for delays and can't be in use when lcd functions are
* called
*/
int lcd_init(TIM_TypeDef* tim, uint8_t col, uint8_t row);
/** lcd_send_cmd
* send the specified command to the lcd
*/
void lcd_send_cmd(uint8_t cmd);
/** lcd_print
* print a null-terminated string on the lcd
*/
void lcd_print(const char* txt);
void lcd_print_c(char c);
void lcd_set_cursor(uint8_t col, uint8_t row);
#endif

View File

@ -1,258 +0,0 @@
/*
==============================================================================
##### RCC specific features #####
==============================================================================
[..]
After reset the device is running from Internal High Speed oscillator
(HSI 16MHz) with Flash 0 wait state, Flash prefetch buffer, D-Cache
and I-Cache are disabled, and all peripherals are off except internal
SRAM, Flash and JTAG.
(+) There is no prescaler on High speed (AHB) and Low speed (APB) busses;
all peripherals mapped on these busses are running at HSI speed.
(+) The clock for all peripherals is switched off, except the SRAM and FLASH.
(+) All GPIOs are in input floating state, except the JTAG pins which
are assigned to be used for debug purpose.
[..]
Once the device started from reset, the user application has to:
(+) Configure the clock source to be used to drive the System clock
(if the application needs higher frequency/performance)
(+) Configure the System clock frequency and Flash settings
(+) Configure the AHB and APB busses prescalers
(+) Enable the clock for the peripheral(s) to be used
(+) Configure the clock source(s) for peripherals which clocks are not
derived from the System clock (I2S, RTC, ADC, USB OTG FS/SDIO/RNG)
##### RCC Limitations #####
==============================================================================
[..]
A delay between an RCC peripheral clock enable and the effective peripheral
enabling should be taken into account in order to manage the peripheral
read/write from/to registers.
(+) This delay depends on the peripheral mapping.
(+) If peripheral is mapped on AHB: the delay is 2 AHB clock cycle
after the clock enable bit is set on the hardware register
(+) If peripheral is mapped on APB: the delay is 2 APB clock cycle
after the clock enable bit is set on the hardware register
[..]
Possible Workarounds:
(#) Enable the peripheral clock sometimes before the peripheral read/write
register is required.
(#) For AHB peripheral, insert two dummy read to the peripheral register.
(#) For APB peripheral, insert a dummy read to the peripheral register.
*/
#include "rcc.h"
/* HPRE: AHB high-speed prescaler */
#define RCC_CFGR_HPRE_DIV_NONE 0x0
#define RCC_CFGR_HPRE_DIV_2 (0x8 + 0)
#define RCC_CFGR_HPRE_DIV_4 (0x8 + 1)
#define RCC_CFGR_HPRE_DIV_8 (0x8 + 2)
#define RCC_CFGR_HPRE_DIV_16 (0x8 + 3)
#define RCC_CFGR_HPRE_DIV_64 (0x8 + 4)
#define RCC_CFGR_HPRE_DIV_128 (0x8 + 5)
#define RCC_CFGR_HPRE_DIV_256 (0x8 + 6)
#define RCC_CFGR_HPRE_DIV_512 (0x8 + 7)
/* PPRE1/2: APB high-speed prescalers */
#define RCC_CFGR_PPRE_DIV_NONE 0x0
#define RCC_CFGR_PPRE_DIV_2 0x4
#define RCC_CFGR_PPRE_DIV_4 0x5
#define RCC_CFGR_PPRE_DIV_8 0x6
#define RCC_CFGR_PPRE_DIV_16 0x7
/* PPLMUL: PPL multiplier */
#define RCC_CFGR_PLLMUL(fac) (fac + 2)
/* ADC: ADCPRE prescalers */
#define RCC_CFGR_ADCPRE_DIV_2 0x0
#define RCC_CFGR_ADCPRE_DIV_4 0x1
#define RCC_CFGR_ADCPRE_DIV_6 0x2
#define RCC_CFGR_ADCPRE_DIV_8 0x3
enum rcc_osc {
RCC_HSI,
RCC_HSE,
RCC_PLL,
RCC_LSI,
RCC_LSE
};
struct ClockConfig_t {
uint8_t type;
uint8_t pll_src;
uint8_t pllmul;
uint8_t hpre;
uint8_t ppre1;
uint8_t ppre2;
uint8_t adcpre;
uint32_t flash_cfg;
uint32_t ahb_freq;
uint32_t apb1_freq;
uint32_t apb2_freq;
};
static struct ClockConfig_t _clock_config[] = {
{/* Performance Mode */
.type = RCC_PLL,
.pll_src = RCC_HSE, //8MHz
.pllmul = RCC_CFGR_PLLMUL(9), //freq should noot exceed 72MHz
.hpre = RCC_CFGR_HPRE_DIV_NONE,
.ppre1 = RCC_CFGR_PPRE_DIV_2, //freq should not exceed 36MHz
.ppre2 = RCC_CFGR_PPRE_DIV_NONE,
.adcpre = RCC_CFGR_ADCPRE_DIV_6, //freq should not exceed 14MHz
.flash_cfg = FLASH_ACR_LATENCY_2,
.ahb_freq = 72000000,
.apb1_freq = 36000000,
.apb2_freq = 72000000
},
{/* Powersave Mode */
.type = RCC_HSE,
.hpre = RCC_CFGR_HPRE_DIV_16,
.ppre1 = RCC_CFGR_PPRE_DIV_16,
.ppre2 = RCC_CFGR_PPRE_DIV_16,
.adcpre = RCC_CFGR_ADCPRE_DIV_2,
.flash_cfg = FLASH_ACR_LATENCY_0,
.ahb_freq = 500000,
.apb1_freq = 500000,
.apb2_freq = 500000
}
};
static void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI:
if (!(RCC->CR & RCC_CR_HSION)) {
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY)==0);
}
break;
case RCC_HSE:
if (!(RCC->CR & RCC_CR_HSEON)) {
RCC->CR |= RCC_CR_HSEON;
while ((RCC->CR & RCC_CR_HSERDY)==0);
}
break;
case RCC_PLL:
if (!(RCC->CR & RCC_CR_PLLON)) {
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY)==0);
}
break;
case RCC_LSI:
if (!(RCC->CSR & RCC_CSR_LSION)) {
RCC->CSR |= RCC_CSR_LSION;
while ((RCC->CSR & RCC_CSR_LSIRDY)==0);
}
break;
case RCC_LSE:
if (!(RCC->BDCR & RCC_BDCR_LSEON)) {
RCC->BDCR |= RCC_BDCR_LSEON;
while ((RCC->BDCR & RCC_BDCR_LSERDY)==0);
}
break;
}
}
static void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI:
RCC->CR &= ~RCC_CR_HSION;
break;
case RCC_HSE:
RCC->CR &= ~(RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON);
break;
case RCC_PLL:
RCC->CR &= ~RCC_CR_PLLON;
break;
case RCC_LSI:
RCC->CSR &= ~RCC_CSR_LSION;
break;
case RCC_LSE:
RCC->BDCR &= ~RCC_BDCR_LSEON;
break;
}
}
static void rcc_set_sysclk(enum rcc_osc osc)
{
RCC->CFGR = (RCC->CFGR & ~0x3) | (osc & 3);
while (((RCC->CFGR & 0xC)>>2) != osc);
}
void rcc_config_clock(uint32_t config, Clock_t *sysclks)
{
struct ClockConfig_t *clk;
if (config < CLOCK_CONFIG_END) {
clk=&(_clock_config[config]);
} else {
clk=&(_clock_config[CLOCK_CONFIG_PERFORMANCE]);
}
if (clk->type == RCC_HSE) { // HSE Clock
rcc_osc_on(RCC_HSE);
rcc_set_sysclk(RCC_HSE);
rcc_osc_off(RCC_PLL);
rcc_osc_off(RCC_HSI);
} else if (clk->type == RCC_PLL) {
// enable PWR module clocking
RCC->APB1ENR |= 1<<28;
if (clk->pll_src == RCC_HSE) { // HSE Clock src
rcc_osc_on(RCC_HSE);
} else { // Default: HSI Clock src
rcc_osc_on(RCC_HSI);
}
// configure prescalers for
// AHB: AHBCLK > 25MHz
// APB1: APB1CLK <= 36MHz
// APB2: APB2CLK <= 72MHz
RCC->CFGR = ( RCC->CFGR & ~((0x3F<<8) | (0xF<<4) | (0x3<<14)) ) |
((clk->hpre & 0xF) << 4) |
((clk->ppre1 & 0x7) << 8) |
((clk->ppre2 & 0x7) << 11)|
(clk->adcpre << 14);
// configure PLL
RCC->CFGR &= !(0xF<<18);
RCC->CFGR |= clk->pllmul<<18;
// enable PLL oscillator
rcc_osc_on(RCC_PLL);
// set Flash timings
FLASH->ACR &= !0x8;
FLASH->ACR |= clk->flash_cfg;
//TODO set buffer bits
// connect to PLL
rcc_set_sysclk(RCC_PLL);
// stop unused clock
if ((clk->pll_src == RCC_HSE) && (RCC->CR & RCC_CR_HSION))
rcc_osc_off(RCC_HSI);
else
rcc_osc_off(RCC_HSE);
} else { // Default: HSI Clock
rcc_osc_on(RCC_HSI);
rcc_set_sysclk(RCC_HSI);
rcc_osc_off(RCC_PLL);
rcc_osc_off(RCC_HSE);
}
sysclks->ahb_freq = clk->ahb_freq;
sysclks->apb1_freq = clk->apb1_freq;
sysclks->apb2_freq = clk->apb2_freq;
sysclks->apb1_timer_freq =
clk->ppre1==RCC_CFGR_PPRE_DIV_NONE ? clk->apb1_freq : 2*clk->apb1_freq;
sysclks->apb2_timer_freq =
clk->ppre2==RCC_CFGR_PPRE_DIV_NONE ? clk->apb2_freq : 2*clk->apb2_freq;
}

View File

@ -1,33 +0,0 @@
#ifndef _RCC_H_
#define _RCC_H_
#include "../target/stm32f103xb.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _Clock_t {
uint32_t ahb_freq;
uint32_t apb1_freq;
uint32_t apb1_timer_freq;
uint32_t apb2_freq;
uint32_t apb2_timer_freq;
} Clock_t;
enum Clock_config {
CLOCK_CONFIG_PERFORMANCE,
CLOCK_CONFIG_POWERSAVE,
CLOCK_CONFIG_END
};
//void SystemInit(void);
void rcc_config_clock(uint32_t config, Clock_t *sysclks);
#
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,311 +0,0 @@
#include "timer.h"
extern Clock_t sysclks;
//------------------------------------------------------------------------------
static OnTick callback1 = 0;
static OnTick callback2 = 0;
static OnTick callback3 = 0;
static OnTick callback4 = 0;
void TIM1_UP_IRQHandler(void) {
if (callback1) callback1();
TIM1->SR &= ~0x1F;
}
void TIM2_IRQHandler(void) {
if (callback2) callback2();
TIM2->SR &= ~0x1F;
}
void TIM3_IRQHandler(void) {
if (callback3) callback3();
TIM3->SR &= ~0x1F;
}
void TIM4_IRQHandler(void) {
if (callback4) callback4();
TIM4->SR &= ~0x1F;
}
//------------------------------------------------------------------------------
int timer_config_cb(TIM_TypeDef* tmr, uint32_t* clk, OnTick cb) {
IRQn_Type irqn;
uint32_t irq_priority;
// get clocks config
if (tmr == TIM1) {
*clk = sysclks.apb2_timer_freq;
// register callback function
callback1 = cb;
irqn = TIM1_UP_IRQn; //every update
irq_priority = TIM1_IRQ_PRIORITY;
// enable timer clocking
RCC->APB2ENR |= 1<<11;
} else if (tmr == TIM2) {
*clk = sysclks.apb1_timer_freq;
// register callback function
callback2 = cb;
irqn = TIM2_IRQn;
irq_priority = TIM2_IRQ_PRIORITY;
// enable timer clocking
RCC->APB1ENR |= 1<<0;
} else if (tmr == TIM3) {
*clk = sysclks.apb1_timer_freq;
// register callback function
callback3 = cb;
irqn = TIM3_IRQn;
irq_priority = TIM3_IRQ_PRIORITY;
// enable timer clocking
RCC->APB1ENR |= 1<<1;
} else if (tmr == TIM4) {
*clk = sysclks.apb1_timer_freq;
// register callback function
callback4 = cb;
irqn = TIM4_IRQn;
irq_priority = TIM4_IRQ_PRIORITY;
// enable timer clocking
RCC->APB1ENR |= 1<<2;
} else return -1;
// clear pending interrupts
tmr->SR &= !1;
// Enable interrupts
tmr->DIER = (1<<0);
NVIC_SetPriority(irqn,irq_priority);
NVIC_EnableIRQ(irqn);
return 0;
}
//------------------------------------------------------------------------------
int timer_wait_ms(TIM_TypeDef* tmr, uint16_t ms, OnTick cb) {
uint32_t clk = 0;
if(!cb) { //blocking
//get clocks config
if (tmr == TIM1) {
clk = sysclks.apb2_timer_freq;
RCC->APB2ENR |= 1<<11;
}
else {
clk = sysclks.apb1_timer_freq;
if (tmr == TIM2) RCC->APB1ENR |= 1<<0;
else if (tmr == TIM3) RCC->APB1ENR |= 1<<1;
else if (tmr == TIM4) RCC->APB1ENR |= 1<<2;
else return -1; // no such timer
}
// set period
tmr->ARR = 0xFFFFFFFF;
} else { //non-blocking
if(timer_config_cb(tmr, &clk, cb)) return -1;
// set period
tmr->ARR = ms-1;
}
// set mode
tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings
tmr->CR1 |= (1<<3); //one pulse mode
// set prescaler 1ms
tmr->PSC = 8*(clk/1000)-1; //PSC = clk/f - 1 | don't know why 8 times..
timer_start(tmr);
if(!cb) {
while(tmr->CNT < ms); //waiting for end of delay
}
return 0;
}
int timer_wait_us(TIM_TypeDef* tmr, uint16_t us, OnTick cb) {
uint32_t clk = 0;
if(!cb) { //blocking
//get clocks config
if (tmr == TIM1) {
clk = sysclks.apb2_timer_freq;
RCC->APB2ENR |= 1<<11;
}
else {
clk = sysclks.apb1_timer_freq;
if (tmr == TIM2) RCC->APB1ENR |= 1<<0;
else if (tmr == TIM3) RCC->APB1ENR |= 1<<1;
else if (tmr == TIM4) RCC->APB1ENR |= 1<<2;
else return -1; // no such timer
}
// set period
tmr->ARR = 0xFFFFFFFF;
} else { //non-blocking
if(timer_config_cb(tmr, &clk, cb)) return -1;
// set period
tmr->ARR = us-1;
}
// set mode
tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings
tmr->CR1 |= (1<<3); //one pulse mode
// set prescaler 1us
tmr->PSC = 8*(clk/1000000)-1; //PSC = clk/f - 1 | don't know why 8 times..
timer_start(tmr);
if(!cb) {
while(tmr->CNT < us); //waiting for end of delay
}
return 0;
}
//------------------------------------------------------------------------------
int timer_tick_init(TIM_TypeDef *tmr, uint16_t tick_ms, OnTick cb) {
IRQn_Type irqn;
uint32_t irq_priority, clk;
// get back the clock frequency
if (tmr == TIM1) {
clk = sysclks.apb2_timer_freq;
// register callback function
callback1 = cb;
irqn = TIM1_UP_IRQn; //every update
irq_priority = TIM1_IRQ_PRIORITY;
// enable timer clocking
RCC->APB2ENR |= 1<<11;
} else if (tmr == TIM2) {
clk = sysclks.apb1_timer_freq;
// register callback function
callback2 = cb;
irqn = TIM2_IRQn;
irq_priority = TIM2_IRQ_PRIORITY;
// enable timer clocking
RCC->APB1ENR |= 1<<0;
} else if (tmr == TIM3) {
clk = sysclks.apb1_timer_freq;
// register callback function
callback3 = cb;
irqn = TIM3_IRQn;
irq_priority = TIM3_IRQ_PRIORITY;
// enable timer clocking
RCC->APB1ENR |= 1<<1;
} else if (tmr == TIM4) {
clk = sysclks.apb1_timer_freq;
// register callback function
callback4 = cb;
irqn = TIM4_IRQn;
irq_priority = TIM4_IRQ_PRIORITY;
// enable timer clocking
RCC->APB1ENR |= 1<<2;
} else return -1;
// clear pending interrupts
tmr->SR &= !1;
// set mode
tmr->CR1 = (1<<7) | (1<<2); //buffering and update settings
tmr->DIER = (1<<0); //Enable interrupts
// set prescaler 1ms
tmr->PSC = 8*(clk/1000)-1; //PSC = clk/f - 1 | don't know why 8 times...
// set period
if(timer_set_period(tmr,tick_ms)) return -1;
if (cb) {
NVIC_SetPriority(irqn,irq_priority);
NVIC_EnableIRQ(irqn); //unmask IRQ
}
return 0;
}
int timer_set_period(TIM_TypeDef *tmr, uint16_t tick) {
// set period
tmr->ARR = tick-1; //tickms = (ARR+1)Tpsc
// force update to reset counter and apply prescaler
tmr->EGR |= 1;
return 0;
}
void timer_start(TIM_TypeDef *tmr) {
// force update to reset counter and prescaler
tmr->EGR |= 1;
// enable counting
tmr->CR1 |= 1;
}
void timer_stop(TIM_TypeDef *tmr) {
// disable counting
tmr->CR1 &= !1;
}
//------------------------------------------------------------------------------
int timer_enc_init(TIM_TypeDef* tmr) {
// enable timer
if (tmr == TIM1) {
RCC->APB2ENR |= 1<<11;
} else if (tmr == TIM2) {
RCC->APB1ENR |= 1<<0;
} else if (tmr == TIM3) {
RCC->APB1ENR |= 1<<1;
} else if (tmr == TIM4) {
RCC->APB1ENR |= 1<<2;
} else return -1; //no such timer
//TODO set registers at reset value
tmr->SMCR |= 0x1; //count on only one edge
tmr->ARR = (1 << 16)-1;
// map inputs
tmr->CCMR1 |= 0x9;
tmr->CCMR1 |= 0x9 << 8;
// enable input channels and invert them //TODO add an otpion for that
tmr->CCER |= 0x3;
tmr->CCER |= 0x3 << 4;
tmr->CR1 |= 0x1; //enable timer
return 0;
}

View File

@ -1,88 +0,0 @@
#ifndef TIMER_H
#define TIMER_H
#include "../target/stm32f103xb.h"
#include "../config.h"
#include "rcc.h"
typedef void (*OnTick)(void);
//------------------------------------------------------------------------------
/** timer_wait_ms
* wait for ms milliseconds function
*/
int timer_wait_ms(TIM_TypeDef *tmr, uint16_t ms, OnTick cb);
/** timer_wait_us
* wait for us microseconds function
*/
int timer_wait_us(TIM_TypeDef *tmr, uint16_t us, OnTick cb);
//------------------------------------------------------------------------------
/** timer_tick_init
* setup timer to call cb function periodically, each tick_ms
*/
int timer_tick_init(TIM_TypeDef *tmr, uint16_t tick_ms, OnTick cb);
/** timer_set_period
* change the period, in ms when called after tick_init,
* otherwise in whatever unit the timer is configured
* reset count when used
*/
int timer_set_period(TIM_TypeDef *tmr, uint16_t tick);
/** timer_start
* reset count and start counting
*/
void timer_start(TIM_TypeDef *tmr);
/** timer_stop
* stop counting
*/
void timer_stop(TIM_TypeDef *tmr);
//------------------------------------------------------------------------------
/** timer_enc_init
* setup timer to read encoder output and keep track of it's position in the
* CNT register whithout using CPU time
*/
int timer_enc_init(TIM_TypeDef* tmr);
//------------------------------------------------------------------------------
//#define PWM_CHANNEL_1 0
//#define PWM_CHANNEL_2 1
//#define PWM_CHANNEL_3 2
//#define PWM_CHANNEL_4 3
//
///** pwm_init
// * setup pwm timer period, each tick_ms
// */
//int pwm_init(TIM_TypeDef *pwm, uint32_t period_ms, OnTick cb);
//
///** pwm_channel_enable
// * set up pwm channel
// */
//int pwm_channel_enable(TIM_TypeDef *pwm, uint32_t channel, uint32_t dutycycle, uint32_t oe);
//
///** pwm_channel_disable
// * disable pwm channel
// */
//int pwm_channel_disable(TIM_TypeDef *pwm, uint32_t channel);
//
///** pwm_channel_set
// * set up dutycycle for pwm channel
// */
//int pwm_channel_set(TIM_TypeDef *pwm, uint32_t channel, uint32_t dutycycle);
//
///** pwm_start
// * start counting
// */
//#define pwm_start(pwm) timer_start(pwm)
//
///** pwm_stop
// * stop and reset counting
// */
//#define pwm_stop(pwm) timer_stop(pwm)
#endif

View File

@ -1,52 +0,0 @@
// standard headers
#include <stdint.h>
#include <stdlib.h>
// driver includes
#include "drivers/rcc.h"
#include "drivers/io.h"
Clock_t sysclks;
#include "drivers/timer.h"
extern uint32_t end;
//------------------------------------------------------------------------------
/* static variables */;
int val = 0; //debug led
//------------------------------------------------------------------------------
/* Timer IRQ */
static void timeout_cb(void) {
io_write(GPIOC, val, PIN_13);
val = !val;
}
//------------------------------------------------------------------------------
/* main function */
int main(void) {
// configure clocks (necessary before using timers)
rcc_config_clock(CLOCK_CONFIG_PERFORMANCE, &sysclks);
// configure GPIO for LED
if(io_configure(GPIOC, PIN_13, IO_MODE_OUTPUT | IO_OUT_PUSH_PULL, 0))
return -1;
io_write(GPIOC, 1, PIN_13);
// start timed interruption
timer_tick_init(TIM2, 1000, timeout_cb);
timer_start(TIM2);
uint32_t test = (uint32_t)(&end);
test++;
int* tab = (int*)malloc(10*sizeof(int));
for(int i=0; i<10; ++i) {
tab[i] = i;
}
// main loop
for(;;);
return 0;
}

View File

@ -1,177 +0,0 @@
/**
******************************************************************************
* @file LinkerScript.ld
* @author Auto-generated by STM32CubeIDE
* @brief Linker script for STM32F103C8Tx Device from STM32F1 series
* 64Kbytes FLASH
* 20Kbytes RAM
*
* Set heap size, stack size and stack location according
* to application requirements.
*
* Set memory bank area and size if external memory is used
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : {
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
.ARM : {
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
.preinit_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough "RAM" Ram type
* memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}

View File

@ -1,371 +0,0 @@
/**
*************** (C) COPYRIGHT 2016 STMicroelectronics ************************
* @file startup_stm32f103xb.s
* @author MCD Application Team
* @version V4.1.0
* @date 29-April-2016
* @brief STM32F103xB Devices vector table for Atollic toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Configure the clock system
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M3 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
*
* <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
.equ BootRAM, 0xF108F85F
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr r0, =_estack
mov sp, r0 /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
/* Call the clock system intitialization function.*/
// bl SystemInit
/* Call static constructors */
//bl __libc_init_array
/* Call the application's entry point.*/
bl main
//bl _start
LoopForever:
b LoopForever
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* @param None
* @retval : None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN1_TX_IRQHandler
.word USB_LP_CAN1_RX0_IRQHandler
.word CAN1_RX1_IRQHandler
.word CAN1_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word TIM4_IRQHandler
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word I2C2_EV_IRQHandler
.word I2C2_ER_IRQHandler
.word SPI1_IRQHandler
.word SPI2_IRQHandler
.word USART1_IRQHandler
.word USART2_IRQHandler
.word USART3_IRQHandler
.word EXTI15_10_IRQHandler
.word RTC_Alarm_IRQHandler
.word USBWakeUp_IRQHandler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word BootRAM /* @0x108. This is for boot in RAM mode for
STM32F10x Medium Density devices. */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMPER_IRQHandler
.thumb_set TAMPER_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_IRQHandler
.thumb_set DMA1_Channel2_IRQHandler,Default_Handler
.weak DMA1_Channel3_IRQHandler
.thumb_set DMA1_Channel3_IRQHandler,Default_Handler
.weak DMA1_Channel4_IRQHandler
.thumb_set DMA1_Channel4_IRQHandler,Default_Handler
.weak DMA1_Channel5_IRQHandler
.thumb_set DMA1_Channel5_IRQHandler,Default_Handler
.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler
.weak DMA1_Channel7_IRQHandler
.thumb_set DMA1_Channel7_IRQHandler,Default_Handler
.weak ADC1_2_IRQHandler
.thumb_set ADC1_2_IRQHandler,Default_Handler
.weak USB_HP_CAN1_TX_IRQHandler
.thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler
.weak USB_LP_CAN1_RX0_IRQHandler
.thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_IRQHandler
.thumb_set TIM1_BRK_IRQHandler,Default_Handler
.weak TIM1_UP_IRQHandler
.thumb_set TIM1_UP_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_IRQHandler
.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTC_Alarm_IRQHandler
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
.weak USBWakeUp_IRQHandler
.thumb_set USBWakeUp_IRQHandler,Default_Handler
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

View File

@ -1,238 +0,0 @@
/**
******************************************************************************
* @file stm32f1xx.h
* @author MCD Application Team
* @version V4.2.0
* @date 31-March-2017
* @brief CMSIS STM32F1xx Device Peripheral Access Layer Header File.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32F1xx device used in the target application
* - To use or not the peripherals drivers in application code(i.e.
* code will be based on direct access to peripherals registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f1xx
* @{
*/
#ifndef __STM32F1XX_H
#define __STM32F1XX_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32F1)
#define STM32F1
#endif /* STM32F1 */
/* Uncomment the line below according to the target STM32L device used in your
application
*/
#if !defined (STM32F100xB) && !defined (STM32F100xE) && !defined (STM32F101x6) && \
!defined (STM32F101xB) && !defined (STM32F101xE) && !defined (STM32F101xG) && !defined (STM32F102x6) && !defined (STM32F102xB) && !defined (STM32F103x6) && \
!defined (STM32F103xB) && !defined (STM32F103xE) && !defined (STM32F103xG) && !defined (STM32F105xC) && !defined (STM32F107xC)
/* #define STM32F100xB */ /*!< STM32F100C4, STM32F100R4, STM32F100C6, STM32F100R6, STM32F100C8, STM32F100R8, STM32F100V8, STM32F100CB, STM32F100RB and STM32F100VB */
/* #define STM32F100xE */ /*!< STM32F100RC, STM32F100VC, STM32F100ZC, STM32F100RD, STM32F100VD, STM32F100ZD, STM32F100RE, STM32F100VE and STM32F100ZE */
/* #define STM32F101x6 */ /*!< STM32F101C4, STM32F101R4, STM32F101T4, STM32F101C6, STM32F101R6 and STM32F101T6 Devices */
/* #define STM32F101xB */ /*!< STM32F101C8, STM32F101R8, STM32F101T8, STM32F101V8, STM32F101CB, STM32F101RB, STM32F101TB and STM32F101VB */
/* #define STM32F101xE */ /*!< STM32F101RC, STM32F101VC, STM32F101ZC, STM32F101RD, STM32F101VD, STM32F101ZD, STM32F101RE, STM32F101VE and STM32F101ZE */
/* #define STM32F101xG */ /*!< STM32F101RF, STM32F101VF, STM32F101ZF, STM32F101RG, STM32F101VG and STM32F101ZG */
/* #define STM32F102x6 */ /*!< STM32F102C4, STM32F102R4, STM32F102C6 and STM32F102R6 */
/* #define STM32F102xB */ /*!< STM32F102C8, STM32F102R8, STM32F102CB and STM32F102RB */
/* #define STM32F103x6 */ /*!< STM32F103C4, STM32F103R4, STM32F103T4, STM32F103C6, STM32F103R6 and STM32F103T6 */
#define STM32F103xB /*!< STM32F103C8, STM32F103R8, STM32F103T8, STM32F103V8, STM32F103CB, STM32F103RB, STM32F103TB and STM32F103VB */
/* #define STM32F103xE */ /*!< STM32F103RC, STM32F103VC, STM32F103ZC, STM32F103RD, STM32F103VD, STM32F103ZD, STM32F103RE, STM32F103VE and STM32F103ZE */
/* #define STM32F103xG */ /*!< STM32F103RF, STM32F103VF, STM32F103ZF, STM32F103RG, STM32F103VG and STM32F103ZG */
/* #define STM32F105xC */ /*!< STM32F105R8, STM32F105V8, STM32F105RB, STM32F105VB, STM32F105RC and STM32F105VC */
/* #define STM32F107xC */ /*!< STM32F107RB, STM32F107VB, STM32F107RC and STM32F107VC */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
//#define USE_HAL_DRIVER
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number V4.2.0
*/
#define __STM32F1_CMSIS_VERSION_MAIN (0x04) /*!< [31:24] main version */
#define __STM32F1_CMSIS_VERSION_SUB1 (0x02) /*!< [23:16] sub1 version */
#define __STM32F1_CMSIS_VERSION_SUB2 (0x00) /*!< [15:8] sub2 version */
#define __STM32F1_CMSIS_VERSION_RC (0x00) /*!< [7:0] release candidate */
#define __STM32F1_CMSIS_VERSION ((__STM32F1_CMSIS_VERSION_MAIN << 24)\
|(__STM32F1_CMSIS_VERSION_SUB1 << 16)\
|(__STM32F1_CMSIS_VERSION_SUB2 << 8 )\
|(__STM32F1_CMSIS_VERSION_RC))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32F100xB)
#include "stm32f100xb.h"
#elif defined(STM32F100xE)
#include "stm32f100xe.h"
#elif defined(STM32F101x6)
#include "stm32f101x6.h"
#elif defined(STM32F101xB)
#include "stm32f101xb.h"
#elif defined(STM32F101xE)
#include "stm32f101xe.h"
#elif defined(STM32F101xG)
#include "stm32f101xg.h"
#elif defined(STM32F102x6)
#include "stm32f102x6.h"
#elif defined(STM32F102xB)
#include "stm32f102xb.h"
#elif defined(STM32F103x6)
#include "stm32f103x6.h"
#elif defined(STM32F103xB)
#include "stm32f103xb.h"
#elif defined(STM32F103xE)
#include "stm32f103xe.h"
#elif defined(STM32F103xG)
#include "stm32f103xg.h"
#elif defined(STM32F105xC)
#include "stm32f105xc.h"
#elif defined(STM32F107xC)
#include "stm32f107xc.h"
#else
#error "Please select first the target STM32F1xx device used in your application (in stm32f1xx.h file)"
#endif
/**
* @}
*/
/** @addtogroup Exported_types
* @{
*/
typedef enum
{
RESET = 0,
SET = !RESET
} FlagStatus, ITStatus;
typedef enum
{
DISABLE = 0,
ENABLE = !DISABLE
} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum
{
ERROR = 0,
SUCCESS = !ERROR
} ErrorStatus;
/**
* @}
*/
/** @addtogroup Exported_macros
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))
/**
* @}
*/
#if defined (USE_HAL_DRIVER)
#include "stm32f1xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __STM32F1xx_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -1,109 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This file configures the system clock as follows:
*-----------------------------------------------------------------------------
* System clock source | 1- PLL_HSE_EXTC | 3- PLL_HSI
* | (external 8 MHz clock) | (internal 8 MHz)
* | 2- PLL_HSE_XTAL |
* | (external 8 MHz xtal) |
*-----------------------------------------------------------------------------
* SYSCLK(MHz) | 72 | 64
*-----------------------------------------------------------------------------
* AHBCLK (MHz) | 72 | 64
*-----------------------------------------------------------------------------
* APB1CLK (MHz) | 36 | 32
*-----------------------------------------------------------------------------
* APB2CLK (MHz) | 72 | 64
*-----------------------------------------------------------------------------
* USB capable (48 MHz precise clock) | NO | NO
*-----------------------------------------------------------------------------
******************************************************************************
*/
#include "stm32f1xx.h"
/*!< Uncomment the following line if you need to relocate your vector Table in
Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
/**
* @brief Setup the microcontroller system
* 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)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
RCC->CR |= 0x00000001U;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#if !defined(STM32F105xC) && !defined(STM32F107xC)
RCC->CFGR &= 0xF8FF0000U;
#else
RCC->CFGR &= 0xF0FF0000U;
#endif /* STM32F105xC */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= 0xFEF6FFFFU;
/* Reset HSEBYP bit */
RCC->CR &= 0xFFFBFFFFU;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= 0xFF80FFFFU;
#if defined(STM32F105xC) || defined(STM32F107xC)
/* Reset PLL2ON and PLL3ON bits */
RCC->CR &= 0xEBFFFFFFU;
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x00FF0000U;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000U;
#elif defined(STM32F100xB) || defined(STM32F100xE)
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000U;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000U;
#else
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000U;
#endif /* STM32F105xC */
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif
#ifdef VECT_TAB_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
}

View File

@ -1,118 +0,0 @@
/**
******************************************************************************
* @file system_stm32f10x.h
* @author MCD Application Team
* @version V4.2.0
* @date 31-March-2017
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Header File.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f10x_system
* @{
*/
/**
* @brief Define to prevent recursive inclusion
*/
#ifndef __SYSTEM_STM32F10X_H
#define __SYSTEM_STM32F10X_H
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup STM32F10x_System_Includes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F10x_System_Exported_types
* @{
*/
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
extern const uint8_t AHBPrescTable[16U]; /*!< AHB prescalers table values */
extern const uint8_t APBPrescTable[8U]; /*!< APB prescalers table values */
/**
* @}
*/
/** @addtogroup STM32F10x_System_Exported_Constants
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F10x_System_Exported_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F10x_System_Exported_Functions
* @{
*/
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
extern void SetSysClock(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /*__SYSTEM_STM32F10X_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

82
srv/debug.c Normal file
View File

@ -0,0 +1,82 @@
/** @file debug.c
* Module handling various debug functions
*
* The module provides a range of functions and tools to make debug more
* convenient
*/
//--includes--------------------------------------------------------------------
#include "debug.h"
#include "dma_mbuf.h"
#include "format.h"
#if DEBUG_TRACE || DEBUG_WARN || DEBUG_ERROR
//--local definitions-----------------------------------------------------------
static uint32_t write_debug(uint8_t c, void* arg);
#define BUFFER_SIZE 162 //(80 char line + \n) * 2
//--local variables-------------------------------------------------------------
static struct DmaMultiBuffer mbuf;
static uint8_t tx_buffer[BUFFER_SIZE];
//--public functions------------------------------------------------------------
void _debug_init(enum UsartPeriph usart, enum GpioPort tx_port,
enum GpioPin tx_pin)
{
gpio_configure(tx_port, tx_pin, GPIO_MODE_OUTPUT_FAST,
GPIO_CONFIG_OUT_ALT_PUSH_PULL);
usart_configure(usart, USART_CONFIG_8N1, 1000000);
dma_mbuf_configure(&mbuf,usart_configure_tx_dma(usart),
DMA_CONFIG_PRIO_LOW, tx_buffer, BUFFER_SIZE);
debug_trace("");
debug_trace("------------------------------------------------------------------------------");
debug_trace("starting debug software");
debug_trace("compiled on " __DATE__ " at " __TIME__);
debug_trace("------------------------------------------------------------------------------");
}
void _debug_print(const char* restrict header,
const char* restrict format, ...)
{
va_list va;
va_start(va, format);
format_vfctprintf(write_debug, nullptr, header, va);
format_vfctprintf(write_debug, nullptr, format, va);
va_end(va);
write_debug('\n', nullptr);
//ensure everything is written when done
while (dma_mbuf_switch(&mbuf)) {}
}
//--local functions-------------------------------------------------------------
/**
* Callback to use with format_vfctprintf() to print caracters to the debug port
*/
static uint32_t write_debug(uint8_t c, void* arg)
{
(void)arg; //unused, required because of FormatCallback
while (dma_mbuf_write_byte(&mbuf, c))
{
//buffer is full, wait until transfer started
while (dma_mbuf_switch(&mbuf)) {}
}
return 0;
}
#endif //DEBUG_TRACE || DEBUG_WARN || DEBUG_ERROR

97
srv/debug.h Normal file
View File

@ -0,0 +1,97 @@
/** @file debug.h
* Module handling various debug functions
*
* The module provides a range of functions and tools to make debug more
* convenient
*/
#ifndef _DEBUG_H_
#define _DEBUG_H_
//--includes--------------------------------------------------------------------
#include "../drv/usart.h"
#include "../drv/gpio.h"
#define DEBUG_TRACE 1
#define DEBUG_WARN 1
#define DEBUG_ERROR 1
//--type definitions------------------------------------------------------------
#if DEBUG_TRACE || DEBUG_WARN || DEBUG_ERROR
#define debug_init(usart, tx_port, tx_pin) _debug_init(usart, tx_port, tx_pin)
#else
#define debug_init(usart) do {} while (0)
#endif
#if DEBUG_TRACE
/**
* Prints a trace message on the debug port. This function should return
* immediately, provided that the message's length doesn't exceed 80 caracters
* and that it isn't called in very quick succession. Otherwise, it will block
* until the internal buffering system is ready to accept the message
*/
#define debug_trace(format, ...) _debug_print("T:", \
format __VA_OPT__(,) __VA_ARGS__)
#else
#define debug_trace(format, ...) do {} while (0)
#endif
#if DEBUG_WARN
/**
* Prints a warning message on the debug port. This function should return
* immediately, provided that the message's length doesn't exceed 80 caracters
* and that it isn't called in very quick succession. Otherwise, it will block
* until the internal buffering system is ready to accept the message
*/
#define debug_warn(format, ...) _debug_print("W:", \
format __VA_OPT__(,) __VA_ARGS__)
#else
#define debug_warn(format, ...) do {} while (0)
#endif
#if DEBUG_ERROR
/**
* Prints an error message on the debug port. This function should return
* immediately, provided that the message's length doesn't exceed 80 caracters
* and that it isn't called in very quick succession. Otherwise, it will block
* until the internal buffering system is ready to accept the message
*/
#define debug_error(format, ...) _debug_print("E:", \
format __VA_OPT__(,) __VA_ARGS__)
#else
#define debug_error(format, ...) do {} while (0)
#endif
//--functions-------------------------------------------------------------------
#if DEBUG_TRACE || DEBUG_WARN || DEBUG_ERROR
/**
* Initializes the debug system to use the given usart peripheral on the given
* tx port, printing a banner if traces are enabled.
* The usart doesn't need to be configured, neither does the tx port.
*
* This function shouldn't be called directly. Instead, use the debug_init macro
*/
void _debug_init(enum UsartPeriph usart, enum GpioPort tx_port,
enum GpioPin tx_pin);
/**
* Prints a debug message on the debug port with the given header. This function
* should return immediately, provided that the message's length doesn't exceed
* 80 caracters and that it isn't called in very quick succession. Otherwise, it
* will block until the internal buffering system is ready to accept the message
*
* This function shouldn't be called directly. Instead, use the debug macros
*/
void _debug_print(const char* restrict header,
const char* restrict format, ...);
#endif
#endif //_DEBUG_H_

23
srv/delay.c Normal file
View File

@ -0,0 +1,23 @@
/** @file delay.c
* Module handling delays definitions and operations
*
* The module provides an API to delay the code execution with the most
* accuraccy possible, putting the system in sleep whenever possible. The RTC is
* required when using delays superior to a 1.5s. Accuraccy is only garenteed up
* to the unit being used (to the millisecond when delaying in ms, to the second
* when delaying in seconds)
*/
//--includes--------------------------------------------------------------------
#include "delay.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
//--public functions------------------------------------------------------------
//--local functions-------------------------------------------------------------

23
srv/delay.h Normal file
View File

@ -0,0 +1,23 @@
/** @file delay.h
* Module handling delays definitions and operations
*
* The module provides an API to delay the code execution with the most
* accuraccy possible, putting the system in sleep whenever possible. The RTC is
* required when using delays superior to a 1.5s. Accuraccy is only garenteed up
* to the unit being used (to the millisecond when delaying in ms, to the second
* when delaying in seconds)
*/
#ifndef _DELAY_H_
#define _DELAY_H_
//--includes--------------------------------------------------------------------
//--type definitions------------------------------------------------------------
//--functions-------------------------------------------------------------------
//--internal_functions----------------------------------------------------------
#endif //_DELAY_H_

Some files were not shown because too many files have changed in this diff Show More