├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── examples ├── adc_dma │ └── adc_dma_main.c ├── adc_interrupt │ └── adc_interrupt_main.c ├── benchmark_arithmetic │ └── benchmark_arithmetic_main.c ├── blink │ └── blink_main.c ├── hello_world │ └── hello_world_main.c ├── led_from_mic │ └── led_from_mic_main.c └── timer_counter │ └── timer_counter_main.c ├── include ├── adc.h ├── cmsis_predefs.h ├── core_stm32.h ├── debug_log.h ├── led.h ├── stm32_specifics.h ├── strings.h └── timers.h ├── openocd.cfg ├── source ├── boot.s └── timers.c └── stm32_linker_layout.lds /.gitignore: -------------------------------------------------------------------------------- 1 | gen 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Pete Warden. All rights reserved. 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "[]" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright 2017, The TensorFlow Authors. 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for all the examples in the STM32 Bare Library. 2 | 3 | # Override this if you want to store temporary files outside of the source folder. 4 | GENDIR := ./gen/ 5 | 6 | # Sub-directories holding generated files. 7 | OBJDIR := $(GENDIR)/obj/ 8 | ELFDIR := $(GENDIR)/elf/ 9 | BINDIR := $(GENDIR)/bin/ 10 | DEPDIR := $(GENDIR)/dep/ 11 | 12 | # The cross-compilation toolchain prefix to use for gcc binaries. 13 | CROSS_PREFIX := arm-none-eabi 14 | AS := $(CROSS_PREFIX)-as 15 | CC := $(CROSS_PREFIX)-gcc 16 | LD := $(CROSS_PREFIX)-ld.bfd 17 | OBJCOPY := $(CROSS_PREFIX)-objcopy 18 | 19 | # Debug symbols are enabled with -g, but since we compile ELFs down to bin files, these don't 20 | # affect the code size on-device. 21 | CCFLAGS := -mcpu=cortex-m3 -mthumb -g 22 | 23 | # Used to rebuild when headers used by a source file change. 24 | DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td 25 | 26 | # We rely on headers from Arm's CMSIS library for things like device register layouts. To 27 | # download the library, use `git clone https://github.com/ARM-software/CMSIS_5` in the parent 28 | # folder of the one this Makefile is in (not this folder, but the one above). 29 | CMSIS_DIR :=../CMSIS_5/ 30 | ifeq ($(shell test -d $(CMSIS_DIR) ; echo $$?), 1) 31 | $(error "CMSIS not found at '$(CMSIS_DIR)' - try 'git clone https://github.com/ARM-software/CMSIS_5 $(CMSIS_DIR)'") 32 | endif 33 | 34 | # Allow CMSIS core headers, and ones from this library. 35 | INCLUDES := \ 36 | -isystem$(CMSIS_DIR)/CMSIS/Core/Include/ \ 37 | -I./include 38 | 39 | ASFLAGS := 40 | 41 | # Defines the offsets used when linking binaries for the STM32. 42 | LDFLAGS := -T stm32_linker_layout.lds 43 | 44 | 45 | # Library source files. 46 | # The order of boot.s is important, since it needs to be first in linking 47 | # order, since it has to be at the start of flash memory when the chip is reset 48 | LIBRARY_SRCS := \ 49 | $(wildcard source/boot.s) \ 50 | $(wildcard source/*.c) 51 | LIBRARY_OBJS := $(addprefix $(OBJDIR), \ 52 | $(patsubst %.c,%.o,$(patsubst %.s,%.o,$(LIBRARY_SRCS)))) 53 | 54 | EXAMPLES_FOLDERS := $(wildcard examples/*) 55 | EXAMPLES_NAMES := $(notdir $(EXAMPLES_FOLDERS)) 56 | EXAMPLES_BINS := $(patsubst %, $(BINDIR)/examples/%.bin, $(EXAMPLES_NAMES)) 57 | 58 | # Rule used when no target is specified. 59 | all: $(EXAMPLES_BINS) 60 | 61 | clean: 62 | rm -rf $(GENDIR) 63 | 64 | # Generic rules for generating different file types. 65 | $(OBJDIR)%.o: %.c 66 | @mkdir -p $(dir $@) 67 | @mkdir -p $(dir $(DEPDIR)$*) 68 | $(CC) $(CCFLAGS) $(INCLUDES) $(DEPFLAGS) -c $< -o $@ 69 | @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d 70 | 71 | $(OBJDIR)%.o: %.s 72 | @mkdir -p $(dir $@) 73 | $(AS) $(ASFLAGS) $< -o $@ 74 | 75 | $(BINDIR)/%.bin: $(ELFDIR)/%.elf 76 | @mkdir -p $(dir $@) 77 | $(OBJCOPY) $< $@ -O binary 78 | 79 | # Loop through all of the example folders and create a rule to build each .elf 80 | # file automatically. 81 | define BUILD_EXAMPLE_ELF 82 | $(1): $(2) 83 | @mkdir -p $(dir $(1)) 84 | $(LD) $(LDFLAGS) -o $(1) $(2) 85 | endef 86 | $(foreach name,$(EXAMPLES_NAMES),\ 87 | $(eval $(call BUILD_EXAMPLE_ELF,\ 88 | $(ELFDIR)/examples/$(name).elf,\ 89 | $(LIBRARY_OBJS) $(patsubst %.c,$(OBJDIR)%.o,$(wildcard examples/$(name)/*.c))))) 90 | 91 | # Include dependency tracking rules. 92 | $(DEPDIR)/%.d: ; 93 | .PRECIOUS: $(DEPDIR)/%.d 94 | ALL_SRCS := \ 95 | $(wildcard examples/*/*.c) \ 96 | $(wildcard source/*.c) 97 | -include $(patsubst %,$(DEPDIR)/%.d,$(basename $(ALL_SRCS))) 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # STM32 Bare Library 2 | 3 | System functions and example code for programming the "Blue Pill" STM32-compatible micro-controller boards. 4 | 5 | ## Introduction 6 | 7 | You can now buy "Blue Pill" development boards individually for less than $2. These devices have ARM Cortex M3 CPUs running at 72MHz, 20KB of SRAM, and 64KB of flash, and consume far less energy than standard ARM processors. They offer an amazing amount of computing power for a cheap package that can be run on a battery for a long time. They are perfect for prototyping running compute-intensive algorithms like machine learning on embedded systems. 8 | 9 | Unfortunately, though their price point makes them very accessible, there are other barriers to getting started with the boards. They require separate hardware to program, and some basic wiring skills. The system software that you need to do anything useful with them is also often proprietary and confusing. This framework tackles all those problems by standardizing a work flow based on open software and hardware, providing step-by-step guides for the small amount of wiring needed, and offering self-contained system functions and examples in plain C. 10 | 11 | ## What You Need 12 | 13 | Before you get started, you'll need to have a few pieces of hardware available. No soldering or tools are required though, you should be able to assemble everything you need by hand. My thanks go to [Andy Selle](http://www.andyselle.com/) who pioneered the approach that I've documented below. 14 | 15 | - **Blue Pill Board**. You can usually find these by [searching on Ebay](https://www.google.com/search?q=site%3Aebay.com+blue+pill+board) or Aliexpress. They come with free shipping, but be aware that can take several weeks, so I often choose a faster option. I also recommend picking up several boards at once, since they're cheap and spares will come in handy in case one is damaged. 16 | 17 | - [**Raspberry Pi 3**](https://www.adafruit.com/product/3055). The Blue Pill boards have a CPU and RAM, but don't come with any software pre-installed. To do anything useful with them, you have to use an external hardware device to program code into their flash memory. You can buy commercial tools to do this, but I prefer to use a Pi. They have external IO pins that can be controlled directly from software, so they can communicate directly to the Blue Pill's pin using the SWD protocol to program, control, and even debug the chip's execution. 18 | 19 | - [**Female-to-Female Jumper Wires**](https://www.adafruit.com/product/266). We need these to connect the Pi's output pins to the Blue Pill's inputs. Any electrical connection will do, but this type of wire will slot snugly onto the pins at either end. 20 | 21 | ## Install OpenOCD on your Pi 22 | 23 | These steps assume you have a Raspberry Pi 3 running a recent version of Raspbian. There's nothing that I know definitely won't work on a Pi 2 (or a Pi Zero/One with an adjustment to the OpenOCD scripts), but I've not tested any other combinations. The approach I'm using came from [a great AdaFruit guide](https://learn.adafruit.com/programming-microcontrollers-using-openocd-on-raspberry-pi), which I recommend checking out for more background on what we're doing. 24 | 25 | The main piece of software we need to install is [OpenOCD](http://openocd.org), the Open On-Chip Debugger. Despite its name, this tool also handles flashing micro-controller flash memory with new programs, as well as displaying debug information from the chip. It does this through the Serial Wire Debug protocol, communicating through dedicated pins on the Blue Pill board. 26 | 27 | OpenOCD doesn't have a binary package for the Pi, but it is easy to compile. To build it, run these commands in the terminal on your Pi: 28 | 29 | ``` 30 | sudo apt-get update 31 | sudo apt-get install git autoconf libtool make pkg-config libusb-1.0-0 libusb-1.0-0-dev 32 | git clone git://git.code.sf.net/p/openocd/code openocd-code 33 | cd openocd-code 34 | ./bootstrap 35 | ./configure --enable-sysfsgpio --enable-bcm2835gpio 36 | make 37 | sudo make install 38 | ``` 39 | 40 | ## Wiring up your Blue Pill 41 | 42 | The four pins at the thin end of the Blue Pill board are dedicate to the SWD protocol, and need to be connected to the right pins on the Pi's header, which OpenOCD will then control to program the chip. 43 | 44 | Here's a diagram showing how the wires should be attached between the Pi and the board: 45 | 46 | ![Blue Pill Wiring](https://storage.googleapis.com/download.tensorflow.org/example_images/blue_pill_wiring.png) 47 | 48 | This is based on the wiring recommended by the AdaFruit tutorial, where ground and power (3.3V) can be driven by any of the multiple pins on the Pi that supply them, SWDIO (the data pin) is on pin 24, and SWDCLK (the clock pin) is on pin 25. I'm leaving the reset pin unconnected, since it's optional. 49 | 50 | ![AdaFruit Diagram](https://cdn-learn.adafruit.com/assets/assets/000/031/318/large1024/raspberry_pi_SWDPinoutPi2.png) 51 | 52 | Here are some photos of my actual setup: 53 | 54 | ![Blue Pill Wiring](https://storage.googleapis.com/download.tensorflow.org/example_images/blue_pill_0.jpg) 55 | 56 | ![Pi Wiring](https://storage.googleapis.com/download.tensorflow.org/example_images/blue_pill_1.jpg) 57 | 58 | ![Complete Picture of Wiring](https://storage.googleapis.com/download.tensorflow.org/example_images/blue_pill_2.jpg) 59 | 60 | If you're using female-to-female jumper wires, you should be able to just push the connectors at each end onto the corresponding pins, and they should fit snugly with a small amount of force. 61 | 62 | There are also two yellow plastic jumper switches on the board. Normally they will both in position furthest away from the SWD pins, and closest to the small USB port. This is the recommended position for our workflow, but if they're in a different place when you get your board, you may need to move them back. 63 | 64 | Once you've wired in the ground and power (3.3v) connections, you should see a red LED on the board light up. If it doesn't, check your wiring, or try another board in case there's a defect. 65 | 66 | ## Building the Examples 67 | 68 | Now you should be ready to build some example programs for the Blue Pill board. To do this, you'll need to clone [ARM's CMSIS 5 micro-controller library](https://github.com/ARM-software/CMSIS_5) from GitHub and get this repository too. You'll also need to install the cross-compilation toolchain for ARM. 69 | 70 | ``` 71 | cd ~ 72 | git clone https://github.com/ARM-software/CMSIS_5 73 | git clone https://github.com/petewarden/stm32_bare_lib 74 | sudo apt-get install -y gcc-arm-none-eabi 75 | ``` 76 | 77 | Now you should just be able to build the library and examples by running: 78 | 79 | ``` 80 | cd ~/stm32_bare_lib 81 | make 82 | ``` 83 | 84 | If this doesn't produce an error you should have binary files ready to be flashed to the Blue Pill in `gen/bin/examples/blink.bin`, `gen/bin/examples/hello_world.bin`, and so on. 85 | 86 | These are not quite like normal executables, they're just exact copies of the bytes that need to be copied into flash memory on the device. They don't contain any debug symbols, and the very start of flash has to be a table of function pointers, so making sure that `boot.s` is first in linking order is important. You don't need to worry about that for these examples, because the makefile takes care of all that, but once you start building your own programs you'll need to be careful. 87 | 88 | ## Testing OpenOCD 89 | 90 | Once you've got this library's repository from GitHub, you can start testing your wiring connection. There are a lot of settings you need to pass to OpenOCD to make a successful link, so to make things easier these are included in [opened.cfg](https://github.com/petewarden/stm32_bare_lib/blob/master/openocd.cfg) in the root of the source tree. To try out OpenOCD, run: 91 | 92 | ``` 93 | cd ~/stm32_bare_lib 94 | sudo openocd -f openocd.cfg 95 | ``` 96 | 97 | If it's working correctly, you should see output like this: 98 | 99 | ``` 100 | Open On-Chip Debugger 0.10.0+dev-00299-g6d390e1b (2018-02-17-00:10) 101 | Licensed under GNU GPL v2 102 | For bug reports, read 103 | http://openocd.org/doc/doxygen/bugs.html 104 | BCM2835 GPIO config: tck = 11, tms = 25, tdi = 10, tdo = 9 105 | BCM2835 GPIO nums: swclk = 11, swdio = 25 106 | BCM2835 GPIO nums: swclk = 25, swdio = 24 107 | adapter speed: 1000 kHz 108 | adapter_nsrst_delay: 100 109 | none separate 110 | cortex_m reset_config sysresetreq 111 | none separate 112 | Info : BCM2835 GPIO JTAG/SWD bitbang driver 113 | Info : JTAG and SWD modes enabled 114 | Info : clock speed 1001 kHz 115 | Info : SWD DPIDR 0x1ba01477 116 | Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints 117 | Info : Listening on port 3333 for gdb connections 118 | semihosting is enabled 119 | Info : Listening on port 6666 for tcl connections 120 | Info : Listening on port 4444 for telnet connections 121 | ``` 122 | 123 | If you see `Error: Could not initialize the debug port` instead, that's a sign that's something is wrong with the connection. Check your wiring, and if that's okay make sure that you have the correct pins on your Pi hooked up. 124 | 125 | ## Running Examples 126 | 127 | With OpenOCD running in one terminal, open up a new window and type: 128 | 129 | ``` 130 | telnet localhost 4444 131 | ``` 132 | 133 | This should bring you to a command console for OpenOCD that looks something like this: 134 | 135 | ``` 136 | Trying ::1... 137 | Trying 127.0.0.1... 138 | Connected to localhost. 139 | Escape character is '^]'. 140 | Open On-Chip Debugger 141 | > 142 | ``` 143 | 144 | This is the place where you can execute commands to control the Blue Pill board. The first thing we need is to stop the chip so we can program it. We do that by running the `reset halt` command, which means restart the CPU and then stop before executing any instructions. 145 | 146 | ``` 147 | > reset halt 148 | target halted due to debug-request, current mode: Thread 149 | xPSR: 0x01000000 pc: 0x00000052 msp: 0x20005000, semihosting 150 | > 151 | ``` 152 | 153 | Next we will upload one of the binary example programs we've built with `flash write_image erase gen/bin/examples/blink.bin 0x08000000`. This is telling OpenOCD to write the data in the file, starting at address `0x08000000`, which is where flash is mapped to on the Blue Pill. 154 | 155 | ``` 156 | > flash write_image erase gen/bin/examples/blink.bin 0x08000000 157 | auto erase enabled 158 | device id = 0x20036410 159 | flash size = 128kbytes 160 | wrote 1024 bytes from file gen/bin/examples/blink.bin in 0.096076s (10.408 KiB/s) 161 | > 162 | ``` 163 | 164 | If it complains that the file isn't found, make sure that the examples built correctly in the earlier step, and that the `openocd` command was run from the stm32_bare_lib source folder. 165 | 166 | Finally we need to restart the chip again, at which point it should try to execute the program we've just uploaded to flash. We do this with the plain `reset` command, which with no arguments restarts the chip and begins execution. 167 | 168 | ``` 169 | > reset 170 | > 171 | ``` 172 | 173 | If you look at the board, you should see a green LED just below the red power LED flashing a couple of times a second. Congratulations, you've run your first micro-controller program! 174 | 175 | ## Debug Output 176 | 177 | Blinking LEDs is fun, but to be at all productive on complex programs we need to be able to easily pass information back to the host computer for debugging purposes. The [Hello World example](https://github.com/petewarden/stm32_bare_lib/blob/master/examples/hello_world/hello_world_main.c) shows how to use [`DebugLog()`](https://github.com/petewarden/stm32_bare_lib/blob/master/include/debug_log.h#L24) to do this. To run it, execute these commands in the OpenOCD command console: 178 | 179 | ``` 180 | reset halt 181 | flash write_image erase gen/bin/examples/hello_world.bin 0x08000000 182 | reset 183 | ``` 184 | 185 | If you switch back to the first terminal that you started the `openocd` command in (not the console you just used), you should see the line "Hello World!" at the bottom. 186 | 187 | The `DebugLog()` function can take several hundred milliseconds to execute, since it has to call back to the host machine, so it shouldn't be used in performance-critical code, but it is handy when you're trying to track down issues. 188 | 189 | ## Debugging with GDB 190 | 191 | The standard Gnu debugger `gdb` works reasonably well with this setup. To install it, run: 192 | 193 | ``` 194 | sudo apt-get install -y gdb-arm-none-eabi 195 | ``` 196 | 197 | You can then debug a program by executing: 198 | 199 | ``` 200 | cd ~/stm32_bare_lib/ 201 | arm-none-eabi-gdb --eval-command="target remote localhost:3333" gen/elf/examples/blink.elf 202 | ``` 203 | 204 | You should see a gdb prompt, and you can execute commands to inspect variables: 205 | 206 | ``` 207 | (gdb) info locals 208 | shift = 536891384 209 | old_config = 2101681877 210 | cleared_config = 172 211 | ``` 212 | 213 | If the program has crashed, you should also be able to inspect the call stack. I haven't found it easy to step through programs or continue execution though. 214 | 215 | ## Using the Library 216 | 217 | If you want to create your own programs using this framework, you should start off by copying one of the examples and expanding it. You'll need to: 218 | 219 | - Add new makefile rules for your program. 220 | - Link against the output of [boot.s](https://github.com/petewarden/stm32_bare_lib/blob/master/source/boot.s) as the first object in the linking stage. This should happen automatically when you use the makefile rules, but it's important since this assembly contains the table of function pointers used to call our program code and it has to be at the start. 221 | - Link using `-T stm32_linker_layout.lds`, so the linker knows where program and data memory start on the Blue Pill. 222 | - Instead of a `main()` function, provide `OnReset()`. This is called when the chip starts up. 223 | - Be aware that global variables aren't set up by default, so you need to do all initialization explicitly at the start of your `OnReset()` call. 224 | 225 | When you need to call more advanced capabilities on the micro-controller, there are a couple of different approaches. Arm's CMSIS library defines a lot of device registers in [`core_cm3.h`](https://github.com/ARM-software/CMSIS/blob/master/CMSIS/Include/core_cm3.h). It can't be called without some extra definitions beforehand though, so stm32_bare_lib's [`core_stm32.h`](https://github.com/petewarden/stm32_bare_lib/blob/master/include/core_stm32.h) header handles setting those up for the Blue Pill. 226 | 227 | Device manufacturers typically also release a header file that defines registers for peripherals that are not standard across all particular CPUs but that exist only on their boards. Since Blue Pill SoCs are STM32-compatible, these would normally be in something like stm32f*.h, but this is only available as part of proprietary products from ST. Instead, the [`core_stm32.h`](https://github.com/petewarden/stm32_bare_lib/blob/master/include/core_stm32.h) header includes a few of the most commonly-used device registers, as defined by [ST's reference guide to the processor](http://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf 228 | ). These definitions are used to set up and control the LEDs for example. 229 | 230 | ## Further Reading 231 | 232 | Looking through the [examples folder](https://github.com/petewarden/stm32_bare_lib/tree/master/examples) should give you some ideas on the sort of things that are possible. 233 | 234 | [STM32duino](http://wiki.stm32duino.com/index.php?title=Blue_Pill) has a wealth of information on Blue Pill boards, and the name even comes from [a thread on their forums](http://www.stm32duino.com/viewtopic.php?f=28&t=117&hilit=blue+pill). 235 | 236 | [Thomas Trebisky has some fantastic examples](https://github.com/trebisky/stm32f103) of bare-metal STM32 programming, and I've found them very useful to reference as I've been working on this. 237 | 238 | [David Welch has also made available great sample code](https://github.com/dwelch67/stm32_samples/tree/master/STM32F103C8T6) for the STM32. 239 | 240 | [Reference Manual](http://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf) - The ultimate resource for understanding what the micro-controller can do. 241 | -------------------------------------------------------------------------------- /examples/adc_dma/adc_dma_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // This example shows how to read an ADC using DMA. For a simpler but slower 14 | // version, see examples/adc_interrupt. 15 | 16 | #include "adc.h" 17 | #include "debug_log.h" 18 | 19 | #define DMA_BUFFER_SIZE (1024) 20 | uint16_t g_dma_buffer[DMA_BUFFER_SIZE]; 21 | 22 | int32_t g_error_count; 23 | int32_t g_half_count; 24 | int32_t g_complete_count; 25 | int32_t g_current_volume; 26 | 27 | void OnReset(void) { 28 | g_error_count = 0; 29 | g_half_count = 0; 30 | g_complete_count = 0; 31 | g_current_volume = 0; 32 | 33 | // Start up the clock system. 34 | RccInitForAdc(); 35 | 36 | // TODO: At the moment, only port A0 seems to be working. 37 | AdcInit(GPIOA, 0, 0); 38 | DmaInit(); 39 | AdcDmaOn(g_dma_buffer, DMA_BUFFER_SIZE); 40 | //AdcOn(); 41 | while (1) { 42 | const int32_t adc_log_length = 256; 43 | char adc_log[adc_log_length]; 44 | StrCpy(adc_log, adc_log_length, "DMA: "); 45 | StrCatInt32(adc_log, adc_log_length, g_current_volume, 10); 46 | StrCatStr(adc_log, adc_log_length, " volume, "); 47 | StrCatInt32(adc_log, adc_log_length, g_error_count, 10); 48 | StrCatStr(adc_log, adc_log_length, " errors, "); 49 | StrCatInt32(adc_log, adc_log_length, g_half_count, 10); 50 | StrCatStr(adc_log, adc_log_length, " half, "); 51 | StrCatInt32(adc_log, adc_log_length, g_complete_count, 10); 52 | StrCatStr(adc_log, adc_log_length, " complete\n"); 53 | DebugLog(adc_log); 54 | } 55 | AdcOff(); 56 | } 57 | 58 | void ProcessDmaBuffer(const uint16_t* buffer, int start_index, int end_index) { 59 | const uint16_t* start = (buffer + start_index); 60 | const uint16_t* current; 61 | const uint16_t* const end = (buffer + end_index); 62 | int32_t total = 0; 63 | for (current = start; current != end; ++current) { 64 | total += *current; 65 | } 66 | const int count = (end_index - start_index); 67 | const int32_t mean = (total / count); 68 | uint32_t total_volume = 0; 69 | for (current = start; current != end; ++current) { 70 | const uint16_t current_value = *current; 71 | const int32_t delta = (current_value - mean); 72 | int32_t abs_delta; 73 | if (delta < 0) { 74 | abs_delta = - delta; 75 | } else { 76 | abs_delta = delta; 77 | } 78 | total_volume += abs_delta; 79 | } 80 | g_current_volume = (total_volume / count); 81 | } 82 | 83 | void OnDma1Channel1Interrupt() { 84 | if (DMA1->ISR & DMA_ISR_TEIF1) { 85 | ++g_error_count; 86 | DMA1->IFCR |= DMA_IFCR_CTEIF1; 87 | return; 88 | } 89 | if (DMA1->ISR & DMA_ISR_HTIF1) { 90 | ++g_half_count; 91 | DMA1->IFCR |= DMA_IFCR_CHTIF1; 92 | ProcessDmaBuffer(g_dma_buffer, 0, (DMA_BUFFER_SIZE / 2)); 93 | return; 94 | } 95 | if (DMA1->ISR & DMA_ISR_TCIF1) { 96 | ++g_complete_count; 97 | DMA1->IFCR |= DMA_IFCR_CTCIF1; 98 | ProcessDmaBuffer(g_dma_buffer, (DMA_BUFFER_SIZE / 2), DMA_BUFFER_SIZE); 99 | return; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /examples/adc_interrupt/adc_interrupt_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // This example shows how to read an ADC using interrupts. This is slower than 14 | // continuously DMA-ing the data into a buffer, but simpler. 15 | 16 | #include "adc.h" 17 | #include "debug_log.h" 18 | 19 | // You need a function named "OnReset" in your program to act like "main" in 20 | // traditional C. This will be called when the processor starts up. 21 | void OnReset(void) { 22 | // Start up the clock system. 23 | RccInitForAdc(); 24 | 25 | // TODO: At the moment, only port A0 seems to be working. 26 | AdcInit(GPIOA, 0, 1); 27 | while (1) { 28 | // Calls to AdcOn() cause the interrupt to be called back once 29 | // a value is available. 30 | AdcOn(); 31 | } 32 | AdcOff(); 33 | } 34 | 35 | // If you have a function named OnAdcInterrupt() in your program, this will be 36 | // called once an ADC value is available, if you've set up the system as shown 37 | // in the OnReset() function above. 38 | void OnAdcInterrupt() { 39 | // We're expecting an EOC signal to be marked in the status register. 40 | if (!(ADC1->SR & ADC_SR_EOC)) { 41 | DebugLog("ADC Interrupt called outside of an End Of Conversion event.\n"); 42 | return; 43 | } 44 | // Read the value from the data register and output it to the debug log. 45 | const int32_t adc_value = ADC1->DR; 46 | const int32_t adc_log_length = 256; 47 | char adc_log[adc_log_length]; 48 | StrCpy(adc_log, adc_log_length, "ADC: "); 49 | StrCatInt32(adc_log, adc_log_length, adc_value, 10); 50 | StrCatStr(adc_log, adc_log_length, "\n"); 51 | DebugLog(adc_log); 52 | } 53 | -------------------------------------------------------------------------------- /examples/benchmark_arithmetic/benchmark_arithmetic_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Tests the speed of arithmetic operations and outputs the results to the 14 | // debugger logs. 15 | 16 | #include "core_stm32.h" 17 | #include "debug_log.h" 18 | #include "timers.h" 19 | 20 | // The function that's called when the chip is started. 21 | void OnReset(void) { 22 | // Set up SysTick to call back every millisecond. 23 | g_tick_count = 0; 24 | SysTick_Config(CLOCK_RATE / 10000); 25 | DebugLog("Benchmarking started\n"); 26 | 27 | volatile int32_t a = 42; 28 | volatile int32_t b = 23; 29 | volatile int32_t total = 0; 30 | const int iters = 10000; 31 | const int32_t start_time = g_tick_count; 32 | for (int i = 0; i < iters; ++i) { 33 | total += a * b; 34 | } 35 | const int32_t end_time = g_tick_count; 36 | const int32_t duration = end_time - start_time; 37 | 38 | DebugLog("Multiply-add of "); 39 | DebugLogInt32(iters); 40 | DebugLog(" elements took "); 41 | DebugLogInt32(duration); 42 | DebugLog("ms\n"); 43 | } 44 | -------------------------------------------------------------------------------- /examples/blink/blink_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // This example shows how to write a minimal "Blue Pill" program that blinks the 14 | // LED continuously. 15 | 16 | #include "led.h" 17 | #include "timers.h" 18 | 19 | // You need a function named "OnReset" in your program to act like "main" in 20 | // traditional C. This will be called when the processor starts up. 21 | void OnReset(void) { 22 | // Before the LED can be accessed, the device registers need to be set up. 23 | LedInit(); 24 | // We'll keep looping forever, turning the LED on and off. 25 | while (1) { 26 | LedOn(); 27 | // This delay function is inefficient because it has the processor spin in 28 | // a loop executing no-ops, rather than going to sleep and saving power. 29 | // It's simpler to call though, so we'll use it for this example. 30 | BusyWaitMicroseconds(200 * 1000); 31 | LedOff(); 32 | BusyWaitMicroseconds(200 * 1000); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/hello_world/hello_world_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // An example of writing a string to a connected debug system using Arm's 14 | // semihosting system. If you have openocd running and 'arm semihosting enable' 15 | // has been run, you should see "Hello World!" in the openocd console logs. 16 | 17 | #include "debug_log.h" 18 | 19 | // The function that's called when the chip is started. 20 | void OnReset(void) { 21 | // Output "Hello World!" to the OpenOCD console. 22 | // This call can take hundreds of milliseconds, so don't use it in 23 | // performance-critical code! 24 | DebugLog("Hello World!\n"); 25 | } 26 | -------------------------------------------------------------------------------- /examples/led_from_mic/led_from_mic_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // This example shows how to read an ADC using DMA. For a simpler but slower 14 | // version, see examples/adc_interrupt. 15 | 16 | #include "adc.h" 17 | #include "debug_log.h" 18 | #include "led.h" 19 | 20 | #define DMA_BUFFER_SIZE (1024) 21 | uint16_t g_dma_buffer[DMA_BUFFER_SIZE]; 22 | 23 | int32_t g_error_count; 24 | int32_t g_half_count; 25 | int32_t g_complete_count; 26 | int32_t g_current_volume; 27 | 28 | void OnReset(void) { 29 | g_error_count = 0; 30 | g_half_count = 0; 31 | g_complete_count = 0; 32 | g_current_volume = 0; 33 | 34 | // Start up the clock system. 35 | RccInitForAdc(); 36 | 37 | // TODO: At the moment, only port A0 seems to be working. 38 | AdcInit(GPIOA, 0, 0); 39 | DmaInit(); 40 | AdcDmaOn(g_dma_buffer, DMA_BUFFER_SIZE); 41 | LedInit(); 42 | //AdcOn(); 43 | while (1) { 44 | if (g_current_volume > 10) { 45 | LedOn(); 46 | } else { 47 | LedOff(); 48 | } 49 | } 50 | AdcOff(); 51 | } 52 | 53 | void ProcessDmaBuffer(const uint16_t* buffer, int start_index, int end_index) { 54 | const uint16_t* start = (buffer + start_index); 55 | const uint16_t* current; 56 | const uint16_t* const end = (buffer + end_index); 57 | int32_t total = 0; 58 | for (current = start; current != end; ++current) { 59 | total += *current; 60 | } 61 | const int count = (end_index - start_index); 62 | const int32_t mean = (total / count); 63 | uint32_t total_volume = 0; 64 | for (current = start; current != end; ++current) { 65 | const uint16_t current_value = *current; 66 | const int32_t delta = (current_value - mean); 67 | int32_t abs_delta; 68 | if (delta < 0) { 69 | abs_delta = - delta; 70 | } else { 71 | abs_delta = delta; 72 | } 73 | total_volume += abs_delta; 74 | } 75 | g_current_volume = (total_volume / count); 76 | } 77 | 78 | void OnDma1Channel1Interrupt() { 79 | if (DMA1->ISR & DMA_ISR_TEIF1) { 80 | ++g_error_count; 81 | DMA1->IFCR |= DMA_IFCR_CTEIF1; 82 | return; 83 | } 84 | if (DMA1->ISR & DMA_ISR_HTIF1) { 85 | ++g_half_count; 86 | DMA1->IFCR |= DMA_IFCR_CHTIF1; 87 | ProcessDmaBuffer(g_dma_buffer, 0, (DMA_BUFFER_SIZE / 2)); 88 | return; 89 | } 90 | if (DMA1->ISR & DMA_ISR_TCIF1) { 91 | ++g_complete_count; 92 | DMA1->IFCR |= DMA_IFCR_CTCIF1; 93 | ProcessDmaBuffer(g_dma_buffer, (DMA_BUFFER_SIZE / 2), DMA_BUFFER_SIZE); 94 | return; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /examples/timer_counter/timer_counter_main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Shows how to set up and read a simple timer counter. 14 | 15 | #include "adc.h" 16 | #include "debug_log.h" 17 | 18 | void OnReset(void) { 19 | // Start up the clock system. 20 | RccInitForAdc(); 21 | 22 | TimerInit(TIMERID_TIM1); 23 | const uint16_t start_time = TimerGetCounter(TIMERID_TIM1); 24 | while (1) { 25 | const uint16_t current_time = TimerGetCounter(TIMERID_TIM1) - start_time; 26 | const int32_t seconds = current_time / 1000; 27 | const int32_t milliseconds = current_time - (seconds * 1000); 28 | const int32_t adc_log_length = 256; 29 | char adc_log[adc_log_length]; 30 | StrCpy(adc_log, adc_log_length, "Time: "); 31 | StrCatInt32(adc_log, adc_log_length, seconds, 10); 32 | StrCatStr(adc_log, adc_log_length, "."); 33 | StrCatInt32(adc_log, adc_log_length, milliseconds, 10); 34 | StrCatStr(adc_log, adc_log_length, "s\n"); 35 | DebugLog(adc_log); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /include/adc.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // ADC utility functions. 14 | 15 | #ifndef INCLUDE_ADC_H 16 | #define INCLUDE_ADC_H 17 | 18 | #include "core_stm32.h" 19 | #include "timers.h" 20 | 21 | // Sets the mode bits for the GPIO port. See GPIO_MODE_INPUT_* for values. 22 | static inline void SetGpioMode(GPIO_t* gpio, int port, int mode) { 23 | __IO uint32_t* cr; 24 | if (port < 8) { 25 | cr = &(gpio->CRL); 26 | } else { 27 | cr = &(gpio->CRH); 28 | } 29 | 30 | // Set up speed and configuration. 31 | const int shift = (port % 8) * 4; 32 | const uint32_t old_config = *cr; 33 | const uint32_t cleared_config = (old_config & ~(0xf << shift)); 34 | *cr = cleared_config | (mode << shift); 35 | } 36 | 37 | static inline void EnableNvic(int irq) { 38 | NVIC->ISER[irq/32] = 1 << (irq%32); 39 | } 40 | 41 | // Sets up the clock control system for ADC access. 42 | static inline void RccInitForAdc(void) { 43 | // Here we're asking the chip to run at 72 MHz. The PLL controls the 44 | // main chip's speed, so to get 72MHz we set the source of the PLL to 45 | // be the HSE clock, which is 8MHz, with a multiplier of x9. 46 | RCC->CFGR = 47 | RCC_CFGR_PLLSRC_HSE | 48 | RCC_CFGR_PLLMUL_9 | 49 | RCC_CFGR_SW_HSI | 50 | RCC_CFGR_PPRE1_DIV_2; 51 | RCC->CR = 52 | RCC_CR_HSION | 53 | RCC_CR_HSEON | 54 | RCC_CR_PLLON; 55 | while (!(RCC->CR & RCC_CR_PLLRDY)) { 56 | } 57 | 58 | // Configure flash to work with the new speed, with prefetching enabled 59 | // and a two-clock wait for access. 60 | *FLASH_ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2; 61 | 62 | // The ADC clock speed is: 63 | // SYSCLOCK / AHB Prescaler / APB2 Prescaler / ADC Prescaler. 64 | // In this case, we want 16KHz for the ADC, so: 65 | // 72MHz / 2 (HPRE_DIV_2) / 4 (PPRE2_DIV_4) / 8 (ADCPRE_DIV_8) 66 | // = 1.125MHz 67 | // Total conversion time = Sampling time + 12.5 cycles 68 | // So, if we pick a sampling time of 55.5, total is 68. 69 | // 1.125MHz / 68 = 16.5KHz. 70 | // We need to set the sampling time in the ADC registers. This is done 71 | // in the ADC initialization routine below. 72 | RCC->CFGR = 73 | RCC_CFGR_PLLSRC_HSE | 74 | RCC_CFGR_PLLMUL_9 | 75 | RCC_CFGR_SW_PLL | 76 | RCC_CFGR_PPRE2_DIV_4 | 77 | RCC_CFGR_ADCPRE_DIV_8 | 78 | RCC_CFGR_HPRE_DIV_2; 79 | 80 | RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; 81 | 82 | RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; 83 | RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; 84 | RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; 85 | RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; 86 | RCC->APB2ENR |= RCC_APB2ENR_ADC2EN; 87 | RCC->APB2ENR |= RCC_APB2ENR_USART1EN; 88 | } 89 | 90 | // This needs to be called before the ADC can be accessed. 91 | static inline void AdcInit(GPIO_t* gpio, int port, int do_interrupt) { 92 | if (do_interrupt) { 93 | EnableNvic(ADC_IRQ_NUMBER); 94 | } 95 | if (do_interrupt) { 96 | // Trigger an interrupt at the end of a conversion. 97 | ADC1->CR1 |= ADC_CR1_EOCIE; 98 | } else { 99 | ADC1->CR2 |= ADC_CR2_CONT; 100 | ADC1->CR2 |= ADC_CR2_DMA; 101 | ADC1->CR2 |= ADC_CR2_SWSTART | ADC_CR2_EXTTRIG; 102 | } 103 | 104 | ADC1->CR2 |= ADC_CR2_ADON | ADC_CR2_TSVREFE; 105 | BusyWaitMicroseconds(30 * 1000); 106 | ADC1->CR2 |= ADC_CR2_CAL; 107 | while (ADC1->CR2 & ADC_CR2_CAL) { 108 | } 109 | 110 | // TODO - I'm assuming the ADC is on channel 0 here. 111 | ADC1->SMPR2 = ADC_SMPR2_SMP0_55_5_CYCLES; 112 | 113 | ADC1->CR2 |= ADC_CR2_ADON; 114 | 115 | SetGpioMode(gpio, port, GPIO_MODE_INPUT_ANALOG); 116 | } 117 | 118 | static inline void DmaInit() { 119 | EnableNvic(DMA1_Channel1_IRQn); 120 | RCC->AHBENR |= RCC_AHBENR_DMA1EN; 121 | volatile uint32_t read_value = RCC->AHBENR; 122 | } 123 | 124 | static inline void AdcDmaOn(void* dma_buffer, int dma_buffer_count) { 125 | DMA1->CPAR1 = (uint32_t)(&ADC1->DR); 126 | DMA1->CMAR1 = (uint32_t)(dma_buffer); 127 | DMA1->CNDTR1 = dma_buffer_count; 128 | DMA1->CCR1 = 129 | DMA_CCR_TCIE | 130 | DMA_CCR_HTIE | 131 | DMA_CCR_TEIE | 132 | DMA_CCR_DIR_FROM_PERIPHERAL | 133 | DMA_CCR_CIRC | 134 | DMA_CCR_MINC | 135 | DMA_CCR_PSIZE_16 | 136 | DMA_CCR_MSIZE_16 | 137 | DMA_CCR_PL_LOW; 138 | DMA1->CCR1 |= DMA_CCR_EN; 139 | } 140 | 141 | static inline void AdcOn(void) { 142 | ADC1->CR2 |= ADC_CR2_ADON; 143 | } 144 | 145 | static inline void AdcOff(void) { 146 | ADC1->CR2 &= ~ADC_CR2_ADON; 147 | } 148 | 149 | #endif // INCLUDE_LED_H 150 | -------------------------------------------------------------------------------- /include/cmsis_predefs.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Should not be included separately, only contains type and macro definitions 14 | // that are needed before including the CMSIS M3 header. Include "core_stm32.h" 15 | // instead. 16 | #ifndef INCLUDE_CMSIS_PREDEFS_H 17 | #define INCLUDE_CMSIS_PREDEFS_H 18 | 19 | // We need a couple of STM32-specific definitions before we include the main M3 20 | // header file. 21 | typedef enum IRQn { 22 | NonMaskableInt_IRQn = -14, 23 | MemoryManagement_IRQn = -12, 24 | BusFault_IRQn = -11, 25 | UsageFault_IRQn = -10, 26 | SVCall_IRQn = -5, 27 | DebugMonitor_IRQn = -4, 28 | PendSV_IRQn = -2, 29 | SysTick_IRQn = -1, 30 | WWDG_IRQn = 0, 31 | PVD_IRQn = 1, 32 | TAMPER_IRQn = 2, 33 | RTC_IRQn = 3, 34 | FLASH_IRQn = 4, 35 | RCC_IRQn = 5, 36 | EXTI0_IRQn = 6, 37 | EXTI1_IRQn = 7, 38 | EXTI2_IRQn = 8, 39 | EXTI3_IRQn = 9, 40 | EXTI4_IRQn = 10, 41 | DMA1_Channel1_IRQn = 11, 42 | DMA1_Channel2_IRQn = 12, 43 | DMA1_Channel3_IRQn = 13, 44 | DMA1_Channel4_IRQn = 14, 45 | DMA1_Channel5_IRQn = 15, 46 | DMA1_Channel6_IRQn = 16, 47 | DMA1_Channel7_IRQn = 17, 48 | } IRQn_Type; 49 | #define __NVIC_PRIO_BITS (2) 50 | 51 | // We want to use the standard ARM SysTick implementation, so indicate there's 52 | // no manufacturer-supplied version. 53 | #define __Vendor_SysTickConfig (0) 54 | 55 | #endif // INCLUDE_CMSIS_PREDEFS_H 56 | -------------------------------------------------------------------------------- /include/core_stm32.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Provides useful definitions for access to system components of the STM32 14 | // chip, including both standard Arm and vendor-specific parts. 15 | // This is the main header you want to include to access devices. 16 | 17 | #ifndef INCLUDE_CORE_STM32_H 18 | #define INCLUDE_CORE_STM32_H 19 | 20 | // These define some STM32-specific properties that are needed before the main 21 | // CMSIS library header is included. 22 | #include "cmsis_predefs.h" 23 | 24 | // Include the CMSIS Arm Cortex M3 header, which defines useful functions and 25 | // constants for system components that are common across all M3 chips. 26 | // This include relies on CMSIS being downloaded. See README for details. 27 | #include 28 | 29 | // Defines manufacturer-specific parts of the STM32 system. 30 | #include "stm32_specifics.h" 31 | 32 | #endif // INCLUDE_CORE_STM32_H 33 | -------------------------------------------------------------------------------- /include/debug_log.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Output strings to a debug console, using semihosting. 14 | // You'll need to enable this option in the OpenOCD configuration using: 15 | // arm semihosting enable 16 | 17 | #ifndef INCLUDE_DEBUG_LOG_H 18 | #define INCLUDE_DEBUG_LOG_H 19 | 20 | #include 21 | 22 | #include "strings.h" 23 | 24 | // Writes a string to the OpenOCD debug console. This can take hundreds of 25 | // milliseconds, so don't call this in performance-intensive code. 26 | static inline void DebugLog(char* s) { 27 | asm("mov r0, #0x04\n" // SYS_WRITE0 28 | "mov r1, %[str]\n" 29 | "bkpt #0xAB\n" 30 | : 31 | : [str] "r"(s) 32 | : "r0", "r1"); 33 | } 34 | 35 | // Writes out a signed 32-bit number to the debug console. 36 | static inline void DebugLogInt32(int32_t i) { 37 | char number_string[kFastToBufferSize]; 38 | number_string[0] = 'b'; 39 | number_string[1] = 0; 40 | FastInt32ToBufferLeft(i, number_string, 10); 41 | DebugLog(number_string); 42 | } 43 | 44 | // Writes out an unsigned 32-bit number to the debug console. 45 | static inline void DebugLogUInt32(uint32_t i) { 46 | char number_string[kFastToBufferSize]; 47 | FastUInt32ToBufferLeft(i, number_string, 10); 48 | DebugLog(number_string); 49 | } 50 | 51 | // Writes out an unsigned 32-bit number to the debug console as hex. 52 | static inline void DebugLogHex(uint32_t i) { 53 | char number_string[kFastToBufferSize]; 54 | FastUInt32ToBufferLeft(i, number_string, 16); 55 | DebugLog(number_string); 56 | } 57 | 58 | #endif // INCLUDE_DEBUG_LOG_H 59 | -------------------------------------------------------------------------------- /include/led.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Control the LED on a "Blue Pill" STM32-compatible board. 14 | 15 | #ifndef INCLUDE_LED_H 16 | #define INCLUDE_LED_H 17 | 18 | #include "core_stm32.h" 19 | 20 | // Known location of the LED on the "Blue Pill" STM32 SoCs. 21 | #define LED_PORT (13) 22 | 23 | // This needs to be called before the LED can be accessed. 24 | static inline void LedInit() { 25 | // Enable GPIOC. 26 | RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; 27 | 28 | // Set up speed and configuration. 29 | const int shift = (LED_PORT - 8) * 4; 30 | const uint32_t old_config = GPIOC->CRH; 31 | const uint32_t cleared_config = (old_config & ~(0xf << shift)); 32 | GPIOC->CRH = cleared_config | ((GPIO_MODE_OUT_2 | GPIO_CONF_GP_OD) << shift); 33 | } 34 | 35 | // LedInit() must be called before these will work. 36 | static inline void LedOn() { GPIOC->BSRR = (1 << (LED_PORT + 16)); } 37 | static inline void LedOff() { GPIOC->BSRR = (1 << LED_PORT); } 38 | 39 | #endif // INCLUDE_LED_H 40 | -------------------------------------------------------------------------------- /include/stm32_specifics.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Provides useful definitions for processor-specific parts of the STM32 14 | // platform, such as device register locations. 15 | 16 | #ifndef INCLUDE_STM32_SPECIFICS_H 17 | #define INCLUDE_STM32_SPECIFICS_H 18 | 19 | // Now define some device-specific structures. For more information, see 20 | // http://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf 21 | 22 | // Reset and Clock Control Layout. 23 | typedef struct { 24 | __IO uint32_t CR; // Clock Control. 25 | __IO uint32_t CFGR; // Clock Configuration #1. 26 | __IO uint32_t CIR; // Clock Interrupt. 27 | __IO uint32_t APB2RSTR; // APB2 Peripheral Reset. 28 | __IO uint32_t APB1RSTR; // APB1 Peripheral Reset. 29 | __IO uint32_t AHBENR; // AHB Peripheral Clock. 30 | __IO uint32_t APB2ENR; // APB2 Peripheral Clock Enable. 31 | __IO uint32_t APB1ENR; // APB1 Peripheral Clock Enable. 32 | __IO uint32_t BDCR; // Backup Domain Control. 33 | __IO uint32_t CSR; // Clock Control and status. 34 | __IO uint32_t AHBRSTR; // AHB Peripheral Reset. 35 | __IO uint32_t CFGR2; // Clock Configuration #2. 36 | __IO uint32_t CFGR3; // Clock Configuration #3. 37 | } RCC_t; 38 | 39 | // GPIO Control Layout. 40 | typedef struct { 41 | __IO uint32_t CRL; // Control Low. 42 | __IO uint32_t CRH; // Control High. 43 | __IO uint16_t IDR; // Port Input Data. 44 | __IO uint16_t UNUSED1; // Unused. 45 | __IO uint16_t ODR; // Output data register. 46 | __IO uint16_t UNUSED2; // Unused. 47 | __IO uint32_t BSRR; // Port Bit Set/Reset. 48 | __IO uint16_t BRR; // Bit Reset. 49 | __IO uint16_t UNUSED3; // Unused. 50 | __IO uint32_t LCKR; // Port Configuration Lock. 51 | } GPIO_t; 52 | 53 | // SysTick control. 54 | typedef struct { 55 | __IO uint32_t CTRL; // Control and Status. 56 | __IOM uint32_t LOAD; // Reload Value. 57 | __IOM uint32_t VAL; // Current Value. 58 | __IM uint32_t CALIB; // Calibration. 59 | } SysTick_t; 60 | 61 | // ADC register layout. 62 | typedef struct { 63 | __IO uint32_t SR; 64 | __IO uint32_t CR1; 65 | __IO uint32_t CR2; 66 | __IO uint32_t SMPR1; 67 | __IO uint32_t SMPR2; 68 | __IO uint32_t JOFR1; 69 | __IO uint32_t JOFR2; 70 | __IO uint32_t JOFR3; 71 | __IO uint32_t JOFR4; 72 | __IO uint32_t HTR; 73 | __IO uint32_t LTR; 74 | __IO uint32_t SQR1; 75 | __IO uint32_t SQR2; 76 | __IO uint32_t SQR3; 77 | __IO uint32_t JSQR; 78 | __IO uint32_t JDR1; 79 | __IO uint32_t JDR2; 80 | __IO uint32_t JDR3; 81 | __IO uint32_t JDR4; 82 | __IO uint32_t DR; 83 | } ADC_t; 84 | 85 | // DMA register layout. 86 | typedef struct { 87 | __IO uint32_t ISR; 88 | __IO uint32_t IFCR; 89 | __IO uint32_t CCR1; 90 | __IO uint32_t CNDTR1; 91 | __IO uint32_t CPAR1; 92 | __IO uint32_t CMAR1; 93 | __IO uint32_t UNUSED1; 94 | __IO uint32_t CCR2; 95 | __IO uint32_t CNDTR2; 96 | __IO uint32_t CPAR2; 97 | __IO uint32_t CMAR2; 98 | __IO uint32_t UNUSED2; 99 | __IO uint32_t CCR3; 100 | __IO uint32_t CNDTR3; 101 | __IO uint32_t CPAR3; 102 | __IO uint32_t CMAR3; 103 | __IO uint32_t UNUSED3; 104 | __IO uint32_t CCR4; 105 | __IO uint32_t CNDTR4; 106 | __IO uint32_t CPAR4; 107 | __IO uint32_t CMAR4; 108 | __IO uint32_t UNUSED4; 109 | __IO uint32_t CCR5; 110 | __IO uint32_t CNDTR5; 111 | __IO uint32_t CPAR5; 112 | __IO uint32_t CMAR5; 113 | __IO uint32_t UNUSED5; 114 | __IO uint32_t CCR6; 115 | __IO uint32_t CNDTR6; 116 | __IO uint32_t CPAR6; 117 | __IO uint32_t CMAR6; 118 | __IO uint32_t UNUSED6; 119 | __IO uint32_t CCR7; 120 | __IO uint32_t CNDTR7; 121 | __IO uint32_t CPAR7; 122 | __IO uint32_t CMAR7; 123 | __IO uint32_t UNUSED7; 124 | } DMA_t; 125 | 126 | // Timer register layout. 127 | typedef struct { 128 | __IO uint32_t CR1; 129 | __IO uint32_t CR2; 130 | __IO uint32_t SMCR; 131 | __IO uint32_t DIER; 132 | __IO uint32_t SR; 133 | __IO uint32_t EGR; 134 | __IO uint32_t CCMR1; 135 | __IO uint32_t CCMR2; 136 | __IO uint32_t CCER; 137 | __IO uint32_t CNT; 138 | __IO uint32_t PSC; 139 | __IO uint32_t ARR; 140 | __IO uint32_t RCR; 141 | __IO uint32_t CCR1; 142 | __IO uint32_t CCR2; 143 | __IO uint32_t CCR3; 144 | __IO uint32_t CCR4; 145 | __IO uint32_t CDTR; 146 | __IO uint32_t DCR; 147 | __IO uint32_t DMAR; 148 | } TIM_t; 149 | 150 | // Addresses of peripherals. 151 | #define RCC_BASE ((uint32_t)0x40021000) 152 | #define GPIOA_BASE ((uint32_t)0x40010800) 153 | #define GPIOB_BASE ((uint32_t)0x40010C00) 154 | #define GPIOC_BASE ((uint32_t)0x40011000) 155 | #define ADC1_BASE ((uint32_t)0x40012400) 156 | #define ADC2_BASE ((uint32_t)0x40012800) 157 | #define TIM1_BASE ((uint32_t)0x40012C00) 158 | #define TIM2_BASE ((uint32_t)0x40000000) 159 | #define TIM3_BASE ((uint32_t)0x40000400) 160 | #define TIM4_BASE ((uint32_t)0x40000800) 161 | #define TIM5_BASE ((uint32_t)0x40000c00) 162 | #define TIM6_BASE ((uint32_t)0x40001000) 163 | #define TIM7_BASE ((uint32_t)0x40001400) 164 | #define FLASH_ACR_BASE ((uint32_t)0x40022000) 165 | #define DMA1_BASE ((uint32_t)0x40020000) 166 | #define DMA2_BASE ((uint32_t)0x40020400) 167 | 168 | // Globals for accessing peripherals. 169 | #define RCC ((RCC_t*)RCC_BASE) 170 | #define GPIOA ((GPIO_t*)GPIOA_BASE) 171 | #define GPIOB ((GPIO_t*)GPIOB_BASE) 172 | #define GPIOC ((GPIO_t*)GPIOC_BASE) 173 | #define ADC1 ((ADC_t*)ADC1_BASE) 174 | #define ADC2 ((ADC_t*)ADC2_BASE) 175 | #define FLASH_ACR ((volatile uint32_t*)FLASH_ACR_BASE) 176 | #define DMA1 ((DMA_t*)DMA1_BASE) 177 | #define DMA2 ((DMA_t*)DMA2_BASE) 178 | #define TIM1 ((TIM_t*)TIM1_BASE) 179 | #define TIM2 ((TIM_t*)TIM2_BASE) 180 | #define TIM3 ((TIM_t*)TIM3_BASE) 181 | #define TIM4 ((TIM_t*)TIM4_BASE) 182 | #define TIM5 ((TIM_t*)TIM5_BASE) 183 | #define TIM6 ((TIM_t*)TIM6_BASE) 184 | #define TIM7 ((TIM_t*)TIM7_BASE) 185 | 186 | // GPIO settings. 187 | #define GPIO_MODE_OUT_2 (0x2) 188 | #define GPIO_CONF_GP_UD (0x0) 189 | #define GPIO_CONF_GP_OD (0x4) 190 | 191 | #define GPIO_MODE_INPUT_ANALOG (0x0) 192 | #define GPIO_MODE_INPUT_FLOAT (0x4) 193 | #define GPIO_MODE_INPUT_PUPD (0x8) 194 | 195 | // ADC interrupt number. 196 | #define ADC_IRQ_NUMBER (18) 197 | 198 | // ADC Status Register flag values. 199 | #define ADC_SR_AWD (1 << 0) 200 | #define ADC_SR_EOC (1 << 1) 201 | #define ADC_SR_JEOC (1 << 2) 202 | #define ADC_SR_JSTRT (1 << 3) 203 | #define ADC_SR_STRT (1 << 4) 204 | 205 | // ADC Control Register #1 flag values. 206 | #define ADC_CR1_EOCIE (1 << 5) 207 | #define ADC_CR1_AWDIE (1 << 6) 208 | #define ADC_CR1_JEOCIE (1 << 7) 209 | #define ADC_CR1_SCAN (1 << 8) 210 | #define ADC_CR1_AWDSGL (1 << 9) 211 | #define ADC_CR1_JAUTO (1 << 10) 212 | #define ADC_CR1_DISCEN (1 << 11) 213 | #define ADC_CR1_JDISCEN (1 << 12) 214 | #define ADC_CR1_JAWDEN (1 << 22) 215 | #define ADC_CR1_AWDEN (1 << 23) 216 | 217 | // ADC Control Register #2 flag values. 218 | #define ADC_CR2_ADON (1 << 0) 219 | #define ADC_CR2_CONT (1 << 1) 220 | #define ADC_CR2_CAL (1 << 2) 221 | #define ADC_CR2_RSTCAL (1 << 3) 222 | #define ADC_CR2_DMA (1 << 8) 223 | #define ADC_CR2_ALIGN (1 << 11) 224 | #define ADC_CR2_JEXTTRIG (1 << 15) 225 | #define ADC_CR2_EXTTRIG (1 << 20) 226 | #define ADC_CR2_JSWSTART (1 << 21) 227 | #define ADC_CR2_SWSTART (1 << 22) 228 | #define ADC_CR2_TSVREFE (1 << 23) 229 | 230 | // ADC Sample Time Register #1 flag values. 231 | #define ADC_SMPR1_SMP10_1_5_CYCLES (0 << 0) 232 | #define ADC_SMPR1_SMP10_7_5_CYCLES (1 << 0) 233 | #define ADC_SMPR1_SMP10_13_5_CYCLES (2 << 0) 234 | #define ADC_SMPR1_SMP10_28_5_CYCLES (3 << 0) 235 | #define ADC_SMPR1_SMP10_41_5_CYCLES (4 << 0) 236 | #define ADC_SMPR1_SMP10_55_5_CYCLES (5 << 0) 237 | #define ADC_SMPR1_SMP10_71_5_CYCLES (6 << 0) 238 | #define ADC_SMPR1_SMP10_239_5_CYCLES (7 << 0) 239 | #define ADC_SMPR1_SMP11_1_5_CYCLES (0 << 3) 240 | #define ADC_SMPR1_SMP11_7_5_CYCLES (1 << 3) 241 | #define ADC_SMPR1_SMP11_13_5_CYCLES (2 << 3) 242 | #define ADC_SMPR1_SMP11_28_5_CYCLES (3 << 3) 243 | #define ADC_SMPR1_SMP11_41_5_CYCLES (4 << 3) 244 | #define ADC_SMPR1_SMP11_55_5_CYCLES (5 << 3) 245 | #define ADC_SMPR1_SMP11_71_5_CYCLES (6 << 3) 246 | #define ADC_SMPR1_SMP11_239_5_CYCLES (7 << 3) 247 | #define ADC_SMPR1_SMP12_1_5_CYCLES (0 << 6) 248 | #define ADC_SMPR1_SMP12_7_5_CYCLES (1 << 6) 249 | #define ADC_SMPR1_SMP12_13_5_CYCLES (2 << 6) 250 | #define ADC_SMPR1_SMP12_28_5_CYCLES (3 << 6) 251 | #define ADC_SMPR1_SMP12_41_5_CYCLES (4 << 6) 252 | #define ADC_SMPR1_SMP12_55_5_CYCLES (5 << 6) 253 | #define ADC_SMPR1_SMP12_71_5_CYCLES (6 << 6) 254 | #define ADC_SMPR1_SMP12_239_5_CYCLES (7 << 6) 255 | #define ADC_SMPR1_SMP13_1_5_CYCLES (0 << 9) 256 | #define ADC_SMPR1_SMP13_7_5_CYCLES (1 << 9) 257 | #define ADC_SMPR1_SMP13_13_5_CYCLES (2 << 9) 258 | #define ADC_SMPR1_SMP13_28_5_CYCLES (3 << 9) 259 | #define ADC_SMPR1_SMP13_41_5_CYCLES (4 << 9) 260 | #define ADC_SMPR1_SMP13_55_5_CYCLES (5 << 9) 261 | #define ADC_SMPR1_SMP13_71_5_CYCLES (6 << 9) 262 | #define ADC_SMPR1_SMP13_239_5_CYCLES (7 << 9) 263 | #define ADC_SMPR1_SMP14_1_5_CYCLES (0 << 12) 264 | #define ADC_SMPR1_SMP14_7_5_CYCLES (1 << 12) 265 | #define ADC_SMPR1_SMP14_13_5_CYCLES (2 << 12) 266 | #define ADC_SMPR1_SMP14_28_5_CYCLES (3 << 12) 267 | #define ADC_SMPR1_SMP14_41_5_CYCLES (4 << 12) 268 | #define ADC_SMPR1_SMP14_55_5_CYCLES (5 << 12) 269 | #define ADC_SMPR1_SMP14_71_5_CYCLES (6 << 12) 270 | #define ADC_SMPR1_SMP14_239_5_CYCLES (7 << 12) 271 | #define ADC_SMPR1_SMP15_1_5_CYCLES (0 << 15) 272 | #define ADC_SMPR1_SMP15_7_5_CYCLES (1 << 15) 273 | #define ADC_SMPR1_SMP15_13_5_CYCLES (2 << 15) 274 | #define ADC_SMPR1_SMP15_28_5_CYCLES (3 << 15) 275 | #define ADC_SMPR1_SMP15_41_5_CYCLES (4 << 15) 276 | #define ADC_SMPR1_SMP15_55_5_CYCLES (5 << 15) 277 | #define ADC_SMPR1_SMP15_71_5_CYCLES (6 << 15) 278 | #define ADC_SMPR1_SMP15_239_5_CYCLES (7 << 15) 279 | #define ADC_SMPR1_SMP16_1_5_CYCLES (0 << 18) 280 | #define ADC_SMPR1_SMP16_7_5_CYCLES (1 << 18) 281 | #define ADC_SMPR1_SMP16_13_5_CYCLES (2 << 18) 282 | #define ADC_SMPR1_SMP16_28_5_CYCLES (3 << 18) 283 | #define ADC_SMPR1_SMP16_41_5_CYCLES (4 << 18) 284 | #define ADC_SMPR1_SMP16_55_5_CYCLES (5 << 18) 285 | #define ADC_SMPR1_SMP16_71_5_CYCLES (6 << 18) 286 | #define ADC_SMPR1_SMP16_239_5_CYCLES (7 << 18) 287 | #define ADC_SMPR1_SMP17_1_5_CYCLES (0 << 21) 288 | #define ADC_SMPR1_SMP17_7_5_CYCLES (1 << 21) 289 | #define ADC_SMPR1_SMP17_13_5_CYCLES (2 << 21) 290 | #define ADC_SMPR1_SMP17_28_5_CYCLES (3 << 21) 291 | #define ADC_SMPR1_SMP17_41_5_CYCLES (4 << 21) 292 | #define ADC_SMPR1_SMP17_55_5_CYCLES (5 << 21) 293 | #define ADC_SMPR1_SMP17_71_5_CYCLES (6 << 21) 294 | #define ADC_SMPR1_SMP17_239_5_CYCLES (7 << 21) 295 | 296 | // ADC Sample Time Register #2 flag values. 297 | #define ADC_SMPR2_SMP0_1_5_CYCLES (0 << 0) 298 | #define ADC_SMPR2_SMP0_7_5_CYCLES (1 << 0) 299 | #define ADC_SMPR2_SMP0_13_5_CYCLES (2 << 0) 300 | #define ADC_SMPR2_SMP0_28_5_CYCLES (3 << 0) 301 | #define ADC_SMPR2_SMP0_41_5_CYCLES (4 << 0) 302 | #define ADC_SMPR2_SMP0_55_5_CYCLES (5 << 0) 303 | #define ADC_SMPR2_SMP0_71_5_CYCLES (6 << 0) 304 | #define ADC_SMPR2_SMP0_239_5_CYCLES (7 << 0) 305 | #define ADC_SMPR2_SMP1_1_5_CYCLES (0 << 3) 306 | #define ADC_SMPR2_SMP1_7_5_CYCLES (1 << 3) 307 | #define ADC_SMPR2_SMP1_13_5_CYCLES (2 << 3) 308 | #define ADC_SMPR2_SMP1_28_5_CYCLES (3 << 3) 309 | #define ADC_SMPR2_SMP1_41_5_CYCLES (4 << 3) 310 | #define ADC_SMPR2_SMP1_55_5_CYCLES (5 << 3) 311 | #define ADC_SMPR2_SMP1_71_5_CYCLES (6 << 3) 312 | #define ADC_SMPR2_SMP1_239_5_CYCLES (7 << 3) 313 | #define ADC_SMPR2_SMP2_1_5_CYCLES (0 << 6) 314 | #define ADC_SMPR2_SMP2_7_5_CYCLES (1 << 6) 315 | #define ADC_SMPR2_SMP2_13_5_CYCLES (2 << 6) 316 | #define ADC_SMPR2_SMP2_28_5_CYCLES (3 << 6) 317 | #define ADC_SMPR2_SMP2_41_5_CYCLES (4 << 6) 318 | #define ADC_SMPR2_SMP2_55_5_CYCLES (5 << 6) 319 | #define ADC_SMPR2_SMP2_71_5_CYCLES (6 << 6) 320 | #define ADC_SMPR2_SMP2_239_5_CYCLES (7 << 6) 321 | #define ADC_SMPR2_SMP3_1_5_CYCLES (0 << 9) 322 | #define ADC_SMPR2_SMP3_7_5_CYCLES (1 << 9) 323 | #define ADC_SMPR2_SMP3_13_5_CYCLES (2 << 9) 324 | #define ADC_SMPR2_SMP3_28_5_CYCLES (3 << 9) 325 | #define ADC_SMPR2_SMP3_41_5_CYCLES (4 << 9) 326 | #define ADC_SMPR2_SMP3_55_5_CYCLES (5 << 9) 327 | #define ADC_SMPR2_SMP3_71_5_CYCLES (6 << 9) 328 | #define ADC_SMPR2_SMP3_239_5_CYCLES (7 << 9) 329 | #define ADC_SMPR2_SMP4_1_5_CYCLES (0 << 12) 330 | #define ADC_SMPR2_SMP4_7_5_CYCLES (1 << 12) 331 | #define ADC_SMPR2_SMP4_13_5_CYCLES (2 << 12) 332 | #define ADC_SMPR2_SMP4_28_5_CYCLES (3 << 12) 333 | #define ADC_SMPR2_SMP4_41_5_CYCLES (4 << 12) 334 | #define ADC_SMPR2_SMP4_55_5_CYCLES (5 << 12) 335 | #define ADC_SMPR2_SMP4_71_5_CYCLES (6 << 12) 336 | #define ADC_SMPR2_SMP4_239_5_CYCLES (7 << 12) 337 | #define ADC_SMPR2_SMP5_1_5_CYCLES (0 << 15) 338 | #define ADC_SMPR2_SMP5_7_5_CYCLES (1 << 15) 339 | #define ADC_SMPR2_SMP5_13_5_CYCLES (2 << 15) 340 | #define ADC_SMPR2_SMP5_28_5_CYCLES (3 << 15) 341 | #define ADC_SMPR2_SMP5_41_5_CYCLES (4 << 15) 342 | #define ADC_SMPR2_SMP5_55_5_CYCLES (5 << 15) 343 | #define ADC_SMPR2_SMP5_71_5_CYCLES (6 << 15) 344 | #define ADC_SMPR2_SMP5_239_5_CYCLES (7 << 15) 345 | #define ADC_SMPR2_SMP6_1_5_CYCLES (0 << 18) 346 | #define ADC_SMPR2_SMP6_7_5_CYCLES (1 << 18) 347 | #define ADC_SMPR2_SMP6_13_5_CYCLES (2 << 18) 348 | #define ADC_SMPR2_SMP6_28_5_CYCLES (3 << 18) 349 | #define ADC_SMPR2_SMP6_41_5_CYCLES (4 << 18) 350 | #define ADC_SMPR2_SMP6_55_5_CYCLES (5 << 18) 351 | #define ADC_SMPR2_SMP6_71_5_CYCLES (6 << 18) 352 | #define ADC_SMPR2_SMP6_239_5_CYCLES (7 << 18) 353 | #define ADC_SMPR2_SMP7_1_5_CYCLES (0 << 21) 354 | #define ADC_SMPR2_SMP7_7_5_CYCLES (1 << 21) 355 | #define ADC_SMPR2_SMP7_13_5_CYCLES (2 << 21) 356 | #define ADC_SMPR2_SMP7_28_5_CYCLES (3 << 21) 357 | #define ADC_SMPR2_SMP7_41_5_CYCLES (4 << 21) 358 | #define ADC_SMPR2_SMP7_55_5_CYCLES (5 << 21) 359 | #define ADC_SMPR2_SMP7_71_5_CYCLES (6 << 21) 360 | #define ADC_SMPR2_SMP7_239_5_CYCLES (7 << 21) 361 | #define ADC_SMPR2_SMP8_1_5_CYCLES (0 << 24) 362 | #define ADC_SMPR2_SMP8_7_5_CYCLES (1 << 24) 363 | #define ADC_SMPR2_SMP8_13_5_CYCLES (2 << 24) 364 | #define ADC_SMPR2_SMP8_28_5_CYCLES (3 << 24) 365 | #define ADC_SMPR2_SMP8_41_5_CYCLES (4 << 24) 366 | #define ADC_SMPR2_SMP8_55_5_CYCLES (5 << 24) 367 | #define ADC_SMPR2_SMP8_71_5_CYCLES (6 << 24) 368 | #define ADC_SMPR2_SMP8_239_5_CYCLES (7 << 24) 369 | #define ADC_SMPR2_SMP9_1_5_CYCLES (0 << 27) 370 | #define ADC_SMPR2_SMP9_7_5_CYCLES (1 << 27) 371 | #define ADC_SMPR2_SMP9_13_5_CYCLES (2 << 27) 372 | #define ADC_SMPR2_SMP9_28_5_CYCLES (3 << 27) 373 | #define ADC_SMPR2_SMP9_41_5_CYCLES (4 << 27) 374 | #define ADC_SMPR2_SMP9_55_5_CYCLES (5 << 27) 375 | #define ADC_SMPR2_SMP9_71_5_CYCLES (6 << 27) 376 | #define ADC_SMPR2_SMP9_239_5_CYCLES (7 << 27) 377 | 378 | // Flash Access Control Register flag values. 379 | #define FLASH_ACR_LATENCY_0 (0) 380 | #define FLASH_ACR_LATENCY_1 (1) 381 | #define FLASH_ACR_LATENCY_2 (2) 382 | #define FLASH_ACR_HLFCYA (1 << 3) 383 | #define FLASH_ACR_PRFTBE (1 << 4) 384 | #define FLASH_ACR_PRFTBS (1 << 5) 385 | 386 | // Reset and Clock Control Control Register flag values. 387 | #define RCC_CR_HSION (1 << 0) 388 | #define RCC_CR_HSIRDY (1 << 1) 389 | #define RCC_CR_HSEON (1 << 16) 390 | #define RCC_CR_HSERDY (1 << 17) 391 | #define RCC_CR_HSEBYP (1 <<18) 392 | #define RCC_CR_CSSON (1 << 19) 393 | #define RCC_CR_PLLON (1 << 24) 394 | #define RCC_CR_PLLRDY (1 << 25) 395 | 396 | // Reset and Clock Control Configuration Register flag values. 397 | #define RCC_CFGR_SW_HSI (0 << 0) 398 | #define RCC_CFGR_SW_HSE (1 << 0) 399 | #define RCC_CFGR_SW_PLL (2 << 0) 400 | #define RCC_CFGR_HPRE_DIV_NONE (0 << 4) 401 | #define RCC_CFGR_HPRE_DIV_2 ((1 << 7) | (0 << 4)) 402 | #define RCC_CFGR_HPRE_DIV_4 ((1 << 7) | (1 << 4)) 403 | #define RCC_CFGR_HPRE_DIV_8 ((1 << 7) | (2 << 4)) 404 | #define RCC_CFGR_HPRE_DIV_16 ((1 << 7) | (3 << 4)) 405 | #define RCC_CFGR_HPRE_DIV_64 ((1 << 7) | (4 << 4)) 406 | #define RCC_CFGR_HPRE_DIV_128 ((1 << 7) | (5 << 4)) 407 | #define RCC_CFGR_HPRE_DIV_256 ((1 << 7) | (6 << 4)) 408 | #define RCC_CFGR_HPRE_DIV_512 ((1 << 7) | (7 << 4)) 409 | #define RCC_CFGR_PPRE1_DIV_NONE (0 << 8) 410 | #define RCC_CFGR_PPRE1_DIV_2 ((1 << 10) | (0 << 8)) 411 | #define RCC_CFGR_PPRE1_DIV_4 ((1 << 10) | (1 << 8)) 412 | #define RCC_CFGR_PPRE1_DIV_8 ((1 << 10) | (2 << 8)) 413 | #define RCC_CFGR_PPRE1_DIV_16 ((1 << 10) | (3 << 8)) 414 | #define RCC_CFGR_PPRE2_DIV_NONE (0 << 11) 415 | #define RCC_CFGR_PPRE2_DIV_2 ((1 << 13) | (0 << 11)) 416 | #define RCC_CFGR_PPRE2_DIV_4 ((1 << 13) | (1 << 11)) 417 | #define RCC_CFGR_PPRE2_DIV_8 ((1 << 13) | (2 << 11)) 418 | #define RCC_CFGR_PPRE2_DIV_16 ((1 << 13) | (3 << 11)) 419 | #define RCC_CFGR_ADCPRE_DIV_2 (0 << 14) 420 | #define RCC_CFGR_ADCPRE_DIV_4 (1 << 14) 421 | #define RCC_CFGR_ADCPRE_DIV_6 (2 << 14) 422 | #define RCC_CFGR_ADCPRE_DIV_8 (3 << 14) 423 | #define RCC_CFGR_PLLSRC_HSE (1 << 16) 424 | #define RCC_CFGR_PLLXTPRE (1 << 17) 425 | #define RCC_CFGR_PLLMUL_2 (0 << 18) 426 | #define RCC_CFGR_PLLMUL_3 (1 << 18) 427 | #define RCC_CFGR_PLLMUL_4 (2 << 18) 428 | #define RCC_CFGR_PLLMUL_5 (3 << 18) 429 | #define RCC_CFGR_PLLMUL_6 (4 << 18) 430 | #define RCC_CFGR_PLLMUL_7 (5 << 18) 431 | #define RCC_CFGR_PLLMUL_8 (6 << 18) 432 | #define RCC_CFGR_PLLMUL_9 (7 << 18) 433 | #define RCC_CFGR_PLLMUL_10 (8 << 18) 434 | #define RCC_CFGR_PLLMUL_11 (9 << 18) 435 | #define RCC_CFGR_PLLMUL_12 (10 << 18) 436 | #define RCC_CFGR_PLLMUL_13 (11 << 18) 437 | #define RCC_CFGR_PLLMUL_14 (12 << 18) 438 | #define RCC_CFGR_PLLMUL_15 (13 << 18) 439 | #define RCC_CFGR_PLLMUL_16 (14 << 18) 440 | #define RCC_CFGR_USBPRE (1 << 22) 441 | #define RCC_CFGR_MCO_NO_CLOCK (0 << 24) 442 | #define RCC_CFGR_MCO_SYS_CLOCK ((1 << 26) | (1 << 24)) 443 | #define RCC_CFGR_MCO_HSI_CLOCK ((1 << 26) | (2 << 24)) 444 | #define RCC_CFGR_MCO_PLL_CLOCK ((1 << 26) | (3 << 24)) 445 | 446 | // Reset and Clock Control AHB Peripheral Clock Enable Register flag values. 447 | #define RCC_AHBENR_DMA1EN (1 << 0) 448 | #define RCC_AHBENR_DMA2EN (1 << 1) 449 | #define RCC_AHBENR_SRAMEN (1 << 2) 450 | #define RCC_AHBENR_FLITFEN (1 << 4) 451 | #define RCC_AHBENR_CRCEN (1 << 6) 452 | #define RCC_AHBENR_FSMCEN (1 << 8) 453 | #define RCC_AHBENR_SDIOEN (1 << 10) 454 | 455 | // Reset and Clock Control APB1 Peripheral Clock Enable Register flag values. 456 | #define RCC_APB1ENR_TIM2EN (1 << 0) 457 | #define RCC_APB1ENR_TIM3EN (1 << 1) 458 | #define RCC_APB1ENR_TIM4EN (1 << 2) 459 | #define RCC_APB1ENR_TIM5EN (1 << 3) 460 | #define RCC_APB1ENR_TIM6EN (1 << 4) 461 | #define RCC_APB1ENR_TIM7EN (1 << 5) 462 | #define RCC_APB1ENR_TIM12EN (1 << 6) 463 | #define RCC_APB1ENR_TIM13EN (1 << 7) 464 | #define RCC_APB1ENR_TIM14EN (1 << 8) 465 | #define RCC_APB1ENR_WWDGEN (1 << 11) 466 | #define RCC_APB1ENR_SPI2EN (1 << 14) 467 | #define RCC_APB1ENR_SPI3EN (1 << 15) 468 | #define RCC_APB1ENR_USART2EN (1 << 17) 469 | #define RCC_APB1ENR_USART3EN (1 << 18) 470 | #define RCC_APB1ENR_USART4EN (1 << 19) 471 | #define RCC_APB1ENR_USART5EN (1 << 20) 472 | #define RCC_APB1ENR_I2C1EN (1 << 21) 473 | #define RCC_APB1ENR_I2C2EN (1 << 22) 474 | #define RCC_APB1ENR_USBEN (1 << 23) 475 | #define RCC_APB1ENR_CANEN (1 << 25) 476 | #define RCC_APB1ENR_BKPEN (1 << 27) 477 | #define RCC_APB1ENR_PWREN (1 << 28) 478 | #define RCC_APB1ENR_DACEN (1 << 29) 479 | 480 | // Reset and Clock Control APB2 Peripheral Clock Enable Register flag values. 481 | #define RCC_APB2ENR_AFIOEN (1 << 0) 482 | #define RCC_APB2ENR_IOPAEN (1 << 2) 483 | #define RCC_APB2ENR_IOPBEN (1 << 3) 484 | #define RCC_APB2ENR_IOPCEN (1 << 4) 485 | #define RCC_APB2ENR_IOPDEN (1 << 5) 486 | #define RCC_APB2ENR_IOPEEN (1 << 6) 487 | #define RCC_APB2ENR_IOPFEN (1 << 7) 488 | #define RCC_APB2ENR_IOPGEN (1 << 8) 489 | #define RCC_APB2ENR_ADC1EN (1 << 9) 490 | #define RCC_APB2ENR_ADC2EN (1 << 10) 491 | #define RCC_APB2ENR_TIM1EN (1 << 11) 492 | #define RCC_APB2ENR_SPI1EN (1 << 12) 493 | #define RCC_APB2ENR_TIM8EN (1 << 13) 494 | #define RCC_APB2ENR_USART1EN (1 << 14) 495 | #define RCC_APB2ENR_ADC3EN (1 << 15) 496 | #define RCC_APB2ENR_TIM9EN (1 << 19) 497 | #define RCC_APB2ENR_TIM10EN (1 << 20) 498 | #define RCC_APB2ENR_TIM11EN (1 << 21) 499 | 500 | // DMA Configuration Register flag values. 501 | #define DMA_CCR_EN (1 << 0) 502 | #define DMA_CCR_TCIE (1 << 1) 503 | #define DMA_CCR_HTIE (1 << 2) 504 | #define DMA_CCR_TEIE (1 << 3) 505 | #define DMA_CCR_DIR_FROM_PERIPHERAL (0 << 4) 506 | #define DMA_CCR_DIR_FROM_MEMORY (1 << 4) 507 | #define DMA_CCR_CIRC (1 << 5) 508 | #define DMA_CCR_PINC (1 << 6) 509 | #define DMA_CCR_MINC (1 << 7) 510 | #define DMA_CCR_PSIZE_8 (0 << 8) 511 | #define DMA_CCR_PSIZE_16 (1 << 8) 512 | #define DMA_CCR_PSIZE_32 (2 << 8) 513 | #define DMA_CCR_MSIZE_8 (0 << 10) 514 | #define DMA_CCR_MSIZE_16 (1 << 10) 515 | #define DMA_CCR_MSIZE_32 (2 << 10) 516 | #define DMA_CCR_PL_LOW (0 << 12) 517 | #define DMA_CCR_PL_MEDIUM (1 << 12) 518 | #define DMA_CCR_PL_HIGH (2 << 12) 519 | #define DMA_CCR_PL_VERY_HIGH (3 << 12) 520 | #define DMA_CCR_MEM2MEM (1 << 14) 521 | 522 | // DMA Interrupt Status Register flag values. 523 | #define DMA_ISR_GIF1 (1 << 0) 524 | #define DMA_ISR_TCIF1 (1 << 1) 525 | #define DMA_ISR_HTIF1 (1 << 2) 526 | #define DMA_ISR_TEIF1 (1 << 3) 527 | #define DMA_ISR_GIF2 (1 << 4) 528 | #define DMA_ISR_TCIF2 (1 << 5) 529 | #define DMA_ISR_HTIF2 (1 << 6) 530 | #define DMA_ISR_TEIF2 (1 << 7) 531 | #define DMA_ISR_GIF3 (1 << 8) 532 | #define DMA_ISR_TCIF3 (1 << 9) 533 | #define DMA_ISR_HTIF3 (1 << 10) 534 | #define DMA_ISR_TEIF3 (1 << 11) 535 | #define DMA_ISR_GIF4 (1 << 12) 536 | #define DMA_ISR_TCIF4 (1 << 13) 537 | #define DMA_ISR_HTIF4 (1 << 14) 538 | #define DMA_ISR_TEIF4 (1 << 15) 539 | #define DMA_ISR_GIF5 (1 << 16) 540 | #define DMA_ISR_TCIF5 (1 << 17) 541 | #define DMA_ISR_HTIF5 (1 << 18) 542 | #define DMA_ISR_TEIF5 (1 << 19) 543 | #define DMA_ISR_GIF6 (1 << 20) 544 | #define DMA_ISR_TCIF6 (1 << 21) 545 | #define DMA_ISR_HTIF6 (1 << 22) 546 | #define DMA_ISR_TEIF6 (1 << 23) 547 | #define DMA_ISR_GIF7 (1 << 24) 548 | #define DMA_ISR_TCIF7 (1 << 25) 549 | #define DMA_ISR_HTIF7 (1 << 26) 550 | #define DMA_ISR_TEIF7 (1 << 27) 551 | 552 | // DMA Interrupt Clear Register flag values. 553 | #define DMA_IFCR_CGIF1 (1 << 0) 554 | #define DMA_IFCR_CTCIF1 (1 << 1) 555 | #define DMA_IFCR_CHTIF1 (1 << 2) 556 | #define DMA_IFCR_CTEIF1 (1 << 3) 557 | #define DMA_IFCR_CGIF2 (1 << 4) 558 | #define DMA_IFCR_CTCIF2 (1 << 5) 559 | #define DMA_IFCR_CHTIF2 (1 << 6) 560 | #define DMA_IFCR_CTEIF2 (1 << 7) 561 | #define DMA_IFCR_CGIF3 (1 << 8) 562 | #define DMA_IFCR_CTCIF3 (1 << 9) 563 | #define DMA_IFCR_CHTIF3 (1 << 10) 564 | #define DMA_IFCR_CTEIF3 (1 << 11) 565 | #define DMA_IFCR_CGIF4 (1 << 12) 566 | #define DMA_IFCR_CTCIF4 (1 << 13) 567 | #define DMA_IFCR_CHTIF4 (1 << 14) 568 | #define DMA_IFCR_CTEIF4 (1 << 15) 569 | #define DMA_IFCR_CGIF5 (1 << 16) 570 | #define DMA_IFCR_CTCIF5 (1 << 17) 571 | #define DMA_IFCR_CHTIF5 (1 << 18) 572 | #define DMA_IFCR_CTEIF5 (1 << 19) 573 | #define DMA_IFCR_CGIF6 (1 << 20) 574 | #define DMA_IFCR_CTCIF6 (1 << 21) 575 | #define DMA_IFCR_CHTIF6 (1 << 22) 576 | #define DMA_IFCR_CTEIF6 (1 << 23) 577 | #define DMA_IFCR_CGIF7 (1 << 24) 578 | #define DMA_IFCR_CTCIF7 (1 << 25) 579 | #define DMA_IFCR_CHTIF7 (1 << 26) 580 | #define DMA_IFCR_CTEIF7 (1 << 27) 581 | 582 | // Timer Control Register #1 flag values. 583 | #define TIM_CR1_CEN (1 << 0) 584 | #define TIM_CR1_UDIS (1 << 1) 585 | #define TIM_CR1_URS (1 << 2) 586 | #define TIM_CR1_OPM (1 << 3) 587 | #define TIM_CR1_DIR_UP (0 << 4) 588 | #define TIM_CR1_DIR_DOWN (0 << 4) 589 | #define TIM_CR1_CMS_EDGE (0 << 5) 590 | #define TIM_CR1_CMS_MODE1 (1 << 5) 591 | #define TIM_CR1_CMS_MODE2 (2 << 5) 592 | #define TIM_CR1_CMS_MODE3 (3 << 5) 593 | #define TIM_CR1_ARPE (1 << 7) 594 | #define TIM_CR1_CKD_DIV1 (0 << 8) 595 | #define TIM_CR1_CKD_DIV2 (1 << 8) 596 | #define TIM_CR1_CKD_DIV4 (2 << 8) 597 | 598 | // Timer Control Register #2 flag values. 599 | #define TIM_CR2_CCPC (1 << 0) 600 | #define TIM_CR2_CCUS (1 << 2) 601 | #define TIM_CR2_CCDS (1 << 3) 602 | #define TIM_CR2_MMS_RESET (0 << 4) 603 | #define TIM_CR2_MMS_ENABLE (1 << 4) 604 | #define TIM_CR2_MMS_UPDATE (2 << 4) 605 | #define TIM_CR2_MMS_COMPARE_PULSE (3 << 4) 606 | #define TIM_CR2_MMS_COMPARE_OC1 (4 << 4) 607 | #define TIM_CR2_MMS_COMPARE_OC2 (5 << 4) 608 | #define TIM_CR2_MMS_COMPARE_OC3 (6 << 4) 609 | #define TIM_CR2_MMS_COMPARE_OC4 (7 << 4) 610 | #define TIM_CR2_MMS_TI1S (1 << 7) 611 | #define TIM_CR2_MMS_OIS1 (1 << 8) 612 | #define TIM_CR2_MMS_OIS1N (1 << 9) 613 | #define TIM_CR2_MMS_OIS2 (1 << 10) 614 | #define TIM_CR2_MMS_OIS2N (1 << 11) 615 | #define TIM_CR2_MMS_OIS3 (1 << 12) 616 | #define TIM_CR2_MMS_OIS3N (1 << 13) 617 | #define TIM_CR2_MMS_OIS4 (1 << 14) 618 | 619 | // Timer Status Register flag values. 620 | #define TIM_SR_UIF (1 << 0) 621 | #define TIM_SR_CC1IF (1 << 1) 622 | #define TIM_SR_CC2IF (1 << 2) 623 | #define TIM_SR_CC3IF (1 << 3) 624 | #define TIM_SR_CC4IF (1 << 4) 625 | #define TIM_SR_COMIF (1 << 5) 626 | #define TIM_SR_TIF (1 << 6) 627 | #define TIM_SR_BIF (1 << 7) 628 | #define TIM_SR_CC1OF (1 << 9) 629 | #define TIM_SR_CC2OF (1 << 9) 630 | #define TIM_SR_CC3OF (1 << 9) 631 | #define TIM_SR_CC4OF (1 << 9) 632 | 633 | #endif // INCLUDE_STM32_SPECIFICS_H 634 | -------------------------------------------------------------------------------- /include/strings.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Simple string functions. 14 | 15 | #ifndef INCLUDE_STRINGS_H 16 | #define INCLUDE_STRINGS_H 17 | 18 | #include 19 | 20 | // Reverses a zero-terminated string in-place. 21 | static inline char* ReverseStringInPlace(char* start, char* end) { 22 | char *p1 = start; 23 | char *p2 = end - 1; 24 | while (p1 < p2) { 25 | char tmp = *p1; 26 | *p1++ = *p2; 27 | *p2-- = tmp; 28 | } 29 | return start; 30 | } 31 | 32 | // Populates the provided buffer with an ASCII representation of the number. 33 | static inline char* FastUInt32ToBufferLeft(uint32_t i, char* buffer, int base) { 34 | char* start = buffer; 35 | do { 36 | *buffer++ = ((i % base) + '0'); 37 | i /= base; 38 | } while (i > 0); 39 | *buffer = 0; 40 | ReverseStringInPlace(start, buffer); 41 | return buffer; 42 | } 43 | 44 | // All input buffers to the number conversion functions must be this long. 45 | static const int kFastToBufferSize = 48; 46 | 47 | // Populates the provided buffer with an ASCII representation of the number. 48 | static inline char* FastInt32ToBufferLeft(int32_t i, char* buffer, int base) { 49 | uint32_t u = i; 50 | if (i < 0) { 51 | *buffer++ = '-'; 52 | u = -u; 53 | } 54 | return FastUInt32ToBufferLeft(u, buffer, base); 55 | } 56 | 57 | // Appends a string to a string, in-place. You need to pass in the maximum string 58 | // length as the second argument. 59 | static inline char* StrCatStr(char* main, int main_max_length, char* to_append) { 60 | char* current = main; 61 | while (*current != 0) { 62 | ++current; 63 | } 64 | const int current_length = current - main; 65 | char* current_end = current + (main_max_length - 1); 66 | while ((*to_append != 0) && (current < current_end)) { 67 | *current = *to_append; 68 | ++current; 69 | ++to_append; 70 | } 71 | *current = 0; 72 | } 73 | 74 | // Converts a number to a string and appends it to another. 75 | static inline char* StrCatInt32(char* main, int main_max_length, int32_t number, int base) { 76 | char number_string[kFastToBufferSize]; 77 | FastInt32ToBufferLeft(number, number_string, base); 78 | StrCatStr(main, main_max_length, number_string); 79 | } 80 | 81 | // Converts a number to a string and appends it to another. 82 | static inline char* StrCatUInt32(char* main, int main_max_length, uint32_t number, int base) { 83 | char number_string[kFastToBufferSize]; 84 | FastUInt32ToBufferLeft(number, number_string, base); 85 | StrCatStr(main, main_max_length, number_string); 86 | } 87 | 88 | static inline void StrCpy(char* main, int main_max_length, const char* source) { 89 | char* current = main; 90 | char* current_end = main + (main_max_length - 1); 91 | while ((*source != 0) && (current < current_end)) { 92 | *current = *source; 93 | ++current; 94 | ++source; 95 | } 96 | *current = 0; 97 | } 98 | 99 | #endif // INCLUDE_STRINGS_H 100 | -------------------------------------------------------------------------------- /include/timers.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Timer utilities for the "Blue Pill" STM32 board. 14 | 15 | #ifndef INCLUDE_TIMERS_H 16 | #define INCLUDE_TIMERS_H 17 | 18 | #include 19 | 20 | #include "core_stm32.h" 21 | 22 | // We know the "Blue Pill" STM32 board runs at 72 MHz. 23 | #define CLOCK_RATE (72 * 1000 * 1000) 24 | 25 | // There's a default SysTick handler function defined in source/timers.c that 26 | // just increments the g_tick_count variable by default. Optionally, you can 27 | // set g_tick_callback and it will call into a user-defined function too. 28 | // To control the frequency, you'll need to call the CMSIS SysTick_Config(). 29 | extern uint32_t g_tick_count; 30 | typedef void (*OnSysTickCallback)(int tick_count); 31 | extern OnSysTickCallback g_tick_callback; 32 | 33 | // Spin in a loop for roughly the specified number of microseconds. This is 34 | // using instruction timing, so it's not precise, and the processor will be 35 | // consuming power while this is running. 36 | static inline void BusyWaitMicroseconds(int32_t us) { 37 | // Each loop takes very roughly one microsecond on a Blue Pill. 38 | volatile int32_t count = us; 39 | for (; count > 0; --count) 40 | ; 41 | } 42 | 43 | // Indexes for the different timers. 44 | #define TIMERID_TIM1 (0) 45 | #define TIMERID_TIM2 (1) 46 | #define TIMERID_TIM3 (2) 47 | #define TIMERID_TIM4 (3) 48 | #define TIMERID_TIM5 (4) 49 | #define TIMERID_TIM6 (5) 50 | #define TIMERID_TIM7 (6) 51 | #define TIMERID_TIM8 (7) 52 | #define TIMERID_TIM9 (8) 53 | #define TIMERID_TIM10 (9) 54 | #define TIMERID_TIM11 (10) 55 | #define TIMERID_TIM12 (11) 56 | #define TIMERID_TIM13 (12) 57 | #define TIMERID_TIM14 (13) 58 | 59 | // Converts from a logical time index defined above, to the actual area of 60 | // memory holding the device control registers. These are in order, so we 61 | // have to do a lookup. 62 | static inline TIM_t* TimerIdToStruct(int timer_id) { 63 | static TIM_t* const id_to_struct_lookup[] = { 64 | TIM1, 65 | TIM2, 66 | TIM3, 67 | TIM4, 68 | TIM5, 69 | TIM6, 70 | TIM7, 71 | }; 72 | return id_to_struct_lookup[timer_id]; 73 | } 74 | 75 | // Initializes the given timer to count up every millisecond. 76 | static inline void TimerInit(int timer_id) { 77 | // We need different flags to turn on the different timers, so look them up 78 | // from a table and apply them to the correct register. 79 | static const uint32_t id_to_flag_lookup[] = { 80 | RCC_APB2ENR_TIM1EN, 81 | RCC_APB1ENR_TIM2EN, 82 | RCC_APB1ENR_TIM3EN, 83 | RCC_APB1ENR_TIM4EN, 84 | RCC_APB1ENR_TIM5EN, 85 | RCC_APB1ENR_TIM6EN, 86 | RCC_APB1ENR_TIM7EN, 87 | RCC_APB2ENR_TIM8EN, 88 | RCC_APB2ENR_TIM9EN, 89 | RCC_APB2ENR_TIM10EN, 90 | RCC_APB2ENR_TIM11EN, 91 | RCC_APB1ENR_TIM12EN, 92 | RCC_APB1ENR_TIM13EN, 93 | RCC_APB1ENR_TIM14EN, 94 | }; 95 | const uint32_t flag = id_to_flag_lookup[timer_id]; 96 | if ((timer_id == TIMERID_TIM1) || (timer_id > TIMERID_TIM7)) { 97 | RCC->APB2ENR |= flag; 98 | } else { 99 | RCC->APB1ENR |= flag; 100 | } 101 | 102 | // Now we do some math to determine how fast the counter increments. 103 | // The prescale (PSC) value is what the timer clock is divided by, and 104 | // the timer clock is derived from the the system clock either divided 105 | // by 1, 2, or 4 (set by the TIM_CR1_CKD_DIV* flag). 106 | TIM_t* tim = TimerIdToStruct(timer_id); 107 | // Prescaled is 72,000 /4. 108 | tim->PSC = 18000; 109 | tim->ARR = 0xffff; 110 | tim->CR1 = 111 | TIM_CR1_DIR_UP | 112 | TIM_CR1_CMS_EDGE | 113 | TIM_CR1_CKD_DIV4; 114 | // Once everything's set up, turn the timer on. 115 | tim->CR1 |= TIM_CR1_CEN; 116 | } 117 | 118 | // Returns the current value of a timer's counter. This is only 16 bits, so it 119 | // will overflow quickly (for example after 65 seconds, with the default setup 120 | // above of incrementing every millisecond). 121 | static inline uint16_t TimerGetCounter(int timer_id) { 122 | TIM_t* tim = TimerIdToStruct(timer_id); 123 | return tim->CNT; 124 | } 125 | 126 | #endif // INCLUDE_TIMERS_H 127 | -------------------------------------------------------------------------------- /openocd.cfg: -------------------------------------------------------------------------------- 1 | # ********************************************************************************************* 2 | # This script has the settings for using a RaspberryPi 2/3 as a SWD controller for a Blue Pill 3 | # microcontroller. To use it, run openocd in this directory as: 4 | # 5 | # sudo openocd -f openocd.cfg 6 | # 7 | # Once you've run that command, you can then open another shell on the Pi, and run: 8 | # 9 | # telnet localhost 4444 10 | # 11 | # This will drop you into an OpenOCD command shell. There you can stop, run, and flash the 12 | # chip, using commands like: 13 | # 14 | # reset halt 15 | # 16 | # This restarts the chip, and stops at the first instruction. You need to do this before you 17 | # flash a new program. 18 | # 19 | # flash write_image erase gen_blink_main.bin 0x08000000 20 | # 21 | # Writes the program into flash, so that it's run at next restart. 22 | # 23 | # reset 24 | # 25 | # Restarts the chip, and runs whatever's in flash. 26 | # ********************************************************************************************* 27 | 28 | # Should be installed by OpenOCD as one of its bundled scripts. 29 | source [find interface/raspberrypi2-native.cfg] 30 | 31 | # Because we're following the GPIO pin wiring suggested by AdaFruit in their article 32 | # https://learn.adafruit.com/programming-microcontrollers-using-openocd-on-raspberry-pi/wiring-and-test 33 | # we need to change port numbers from the defaults used in the OpenOCD script. 34 | bcm2835gpio_swd_nums 25 24 35 | 36 | transport select swd 37 | 38 | set CHIPNAME stm32f1x 39 | # Another script that OCD installs, containing information on the STM32 we're using. 40 | source [find target/stm32f1x.cfg] 41 | 42 | reset_config srst_nogate 43 | init 44 | # Enable logging output from the device to OpenOCD's console stream. See LogString() in 45 | # include/log.h for an example of using this. 46 | arm semihosting enable 47 | -------------------------------------------------------------------------------- /source/boot.s: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | // Initialization parameters that are read when the STM32 processor boots. 14 | // 15 | // The first 32-bit word defines the starting address of the top of the stack, 16 | // and the next is the address of the function that's called when the 17 | // processor is first started. In this example, the rest of the possible vectors 18 | // are left as infinite loops, but these could be replaced with useful routines 19 | // if needed. For more examples, see: 20 | // https://github.com/trebisky/stm32f103/blob/master/blink1/locore.s 21 | // https://github.com/leaflabs/maple-bootloader/blob/master/stm32_lib/c_only_startup.s 22 | // 23 | // The .o output of this file must be linked as the first object file, so that 24 | // .bin has this table of vectors right at the start. If you don't ensure this, 25 | // you'll see weird hangs when you reset the device. 26 | 27 | .cpu cortex-m3 28 | .thumb 29 | 30 | .word 0x20005000 // Stack start address, at the top of SRAM. 31 | .word _on_reset_asm // Reset. 32 | .word _infinite_loop // NMI. 33 | .word _infinite_loop // Hard Fault. 34 | .word _infinite_loop // MM Fault. 35 | .word _infinite_loop // Bus Fault. 36 | .word _infinite_loop // Usage Fault. 37 | .word _infinite_loop // Unused. 38 | .word _infinite_loop // Unused. 39 | .word _infinite_loop // Unused. 40 | .word _infinite_loop // Unused. 41 | .word _infinite_loop // SV call. 42 | .word _infinite_loop // Unused. 43 | .word _infinite_loop // Unused. 44 | .word _infinite_loop // PendSV. 45 | .word OnSysTick // SysTick. 46 | .word _infinite_loop // IRQ0. 47 | .word _infinite_loop // IRQ1. 48 | .word _infinite_loop // IRQ2. 49 | .word _infinite_loop // IRQ3. 50 | .word _infinite_loop // IRQ4. 51 | .word _infinite_loop // IRQ5. 52 | .word _infinite_loop // IRQ6. 53 | .word _infinite_loop // IRQ7. 54 | .word _infinite_loop // IRQ8. 55 | .word _infinite_loop // IRQ9. 56 | .word _infinite_loop // IRQ10. 57 | .word OnDma1Channel1Interrupt // IRQ11. 58 | .word OnDma1Channel2Interrupt // IRQ12. 59 | .word OnDma1Channel3Interrupt // IRQ13. 60 | .word OnDma1Channel4Interrupt // IRQ14. 61 | .word OnDma1Channel5Interrupt // IRQ15. 62 | .word OnDma1Channel6Interrupt // IRQ16. 63 | .word OnDma1Channel7Interrupt // IRQ17. 64 | .word OnAdcInterrupt // IRQ18. 65 | .word _infinite_loop // IRQ19. 66 | .word _infinite_loop // IRQ20. 67 | .word _infinite_loop // IRQ21. 68 | .word _infinite_loop // IRQ22. 69 | .word _infinite_loop // IRQ23. 70 | .word _infinite_loop // IRQ24. 71 | .word _infinite_loop // IRQ25. 72 | .word _infinite_loop // IRQ26. 73 | .word _infinite_loop // IRQ27. 74 | .word _infinite_loop // IRQ28. 75 | .word _infinite_loop // IRQ29. 76 | .word _infinite_loop // IRQ30. 77 | .word _infinite_loop // IRQ31. 78 | .word _infinite_loop // IRQ32. 79 | .word _infinite_loop // IRQ33. 80 | .word _infinite_loop // IRQ34. 81 | .word _infinite_loop // IRQ35. 82 | .word _infinite_loop // IRQ36. 83 | .word _infinite_loop // IRQ37. 84 | .word _infinite_loop // IRQ38. 85 | .word _infinite_loop // IRQ39. 86 | .word _infinite_loop // IRQ40. 87 | .word _infinite_loop // IRQ41. 88 | .word _infinite_loop // IRQ42. 89 | .word _infinite_loop // IRQ43. 90 | .word _infinite_loop // IRQ44. 91 | .word _infinite_loop // IRQ45. 92 | .word _infinite_loop // IRQ46. 93 | .word _infinite_loop // IRQ47. 94 | .word _infinite_loop // IRQ48. 95 | .word _infinite_loop // IRQ49. 96 | .word _infinite_loop // IRQ50. 97 | .word _infinite_loop // IRQ51. 98 | .word _infinite_loop // IRQ52. 99 | 100 | _infinite_loop: b _infinite_loop 101 | 102 | .thumb_func 103 | _on_reset_asm: 104 | // OnReset() should be a C-linkage function symbol that's defined elsewhere in 105 | // your program. It works like main() in a non-embedded context, but with no 106 | // arguments. 107 | bl OnReset 108 | b . 109 | 110 | .weak OnAdcInterrupt 111 | .thumb_set OnAdcInterrupt, _infinite_loop 112 | 113 | .weak OnDma1Channel1Interrupt 114 | .thumb_set OnDma1Channel1, _infinite_loop 115 | 116 | .weak OnDma1Channel2Interrupt 117 | .thumb_set OnDma1Channel2, _infinite_loop 118 | 119 | .weak OnDma1Channel3Interrupt 120 | .thumb_set OnDma1Channel3, _infinite_loop 121 | 122 | .weak OnDma1Channel4Interrupt 123 | .thumb_set OnDma1Channel4, _infinite_loop 124 | 125 | .weak OnDma1Channel5Interrupt 126 | .thumb_set OnDma1Channel5, _infinite_loop 127 | 128 | .weak OnDma1Channel6Interrupt 129 | .thumb_set OnDma1Channel6, _infinite_loop 130 | 131 | .weak OnDma1Channel7Interrupt 132 | .thumb_set OnDma1Channel7, _infinite_loop 133 | -------------------------------------------------------------------------------- /source/timers.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Pete Warden. All Rights Reserved. 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | Unless required by applicable law or agreed to in writing, software 7 | distributed under the License is distributed on an "AS IS" BASIS, 8 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and 10 | limitations under the License. 11 | ==============================================================================*/ 12 | 13 | #include "timers.h" 14 | 15 | #include "debug_log.h" 16 | 17 | uint32_t g_tick_count = 0; 18 | OnSysTickCallback g_tick_callback = 0; 19 | 20 | // We've set up boot.s to call this function when there's a systick event. 21 | // The frequency can be controlled by SysTick_Config. 22 | void OnSysTick() { 23 | g_tick_count += 1; 24 | //DebugLog("Foo\n"); 25 | //*(char*)(0) = 23; 26 | //if (g_tick_callback) { 27 | // g_tick_callback(g_tick_count); 28 | //} 29 | } 30 | -------------------------------------------------------------------------------- /stm32_linker_layout.lds: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | * Memory layout for STM32 linking 3 | * 4 | * Defines where to access the flash and sram for linking purposes. Here's the overall 5 | * layout (from https://github.com/trebisky/stm32f103/blob/master/blink1/blink.lds). 6 | * 7 | * 0x00000000 - 0x07ffffff - aliased to flash or sys memory depending on BOOT jumpers. 8 | * 0x08000000 - 0x0800ffff - Flash. 9 | * 0x1ffff000 - 0x1ffff7ff - Boot firmware in system memory. 10 | * 0x1ffff800 - 0x1fffffff - Option bytes. 11 | * 0x20000000 - 0x20004fff - SRAM. 12 | * 0x40000000 - 0x40023400 - Peripherals 13 | */ 14 | 15 | MEMORY { 16 | flash(RX) : ORIGIN = 0x00000000, LENGTH = 64K 17 | sram(WAIL) : ORIGIN = 0x20000000, LENGTH = 20K 18 | } 19 | 20 | SECTIONS { 21 | .text : { *(.text*) } > flash 22 | .bss : { *(.bss*) } > sram 23 | } 24 | --------------------------------------------------------------------------------