Compare commits
136 Commits
Author | SHA1 | Date | |
---|---|---|---|
2e917bed9e | |||
0fc51b9422 | |||
03a7872bb9 | |||
d3fbf75b36 | |||
c98e82fedf | |||
3ba5b95061 | |||
666ae736ef | |||
1aa498d5bc | |||
c9dfb09ace | |||
16cb734f6f | |||
97818981fb | |||
3370e35dc5 | |||
611f5f6683 | |||
6bb7e001aa | |||
9c340c6a41 | |||
ebaf30a25f | |||
f4b02de076 | |||
d4e081a280 | |||
11c8cee3ee | |||
f603b1398e | |||
436c925038 | |||
3959eabb84 | |||
734be00a82 | |||
577e5511a2 | |||
a4d881df29 | |||
86fd05f52c | |||
2cccdd4d6e | |||
165f545310 | |||
0047fb8fea | |||
64706680c2 | |||
eb4946e7ad | |||
423a0ec90b | |||
89856091c7 | |||
ce9d927a5b | |||
caed09f4db | |||
bb15fdc634 | |||
0ad8e037cf | |||
df2dfe0cb4 | |||
d55dbc34b2 | |||
da626f7780 | |||
c67c9a73ef | |||
4dc895d793 | |||
48c1b5800e | |||
370c7960fb | |||
b3cf0d0302 | |||
3a6a64928d | |||
99d66f4e4e | |||
66521e1981 | |||
210fab8eae | |||
7318d70dcd | |||
0010c5e046 | |||
6b3b55839e | |||
6bed3ab0fb | |||
9a7c51f80e | |||
7a74f9709f | |||
fa29cfc29f | |||
2248ba1762 | |||
ac255816a1 | |||
95b63a06f5 | |||
7656c699bf | |||
c6a4f58b93 | |||
b82520fa9b | |||
25fcf8fe0b | |||
01eaa5cfab | |||
793611d629 | |||
ad52abc26b | |||
b0f5f127f6 | |||
a449b9b7ff | |||
4c6e9a4fda | |||
789b36fc21 | |||
c8861f40c4 | |||
77415cb41f | |||
11f5bc9771 | |||
8526dc084b | |||
fea286914b | |||
cfcc8a1bb6 | |||
510c82d00f | |||
26f6de3015 | |||
a9461b53f5 | |||
d7b6300a50 | |||
d0bd71b266 | |||
a46b6a1630 | |||
b100c4ae13 | |||
a0f9b4a530 | |||
e32e27100d | |||
5b0523f751 | |||
d6cac41b78 | |||
adc62ebb9a | |||
d9a15f2daa | |||
c4af940975 | |||
c58d27cf2e | |||
c3d7711258 | |||
78cb85421a | |||
ff5fbc847d | |||
51e0bfd188 | |||
c411d552a1 | |||
ceff33ea0e | |||
68955ddfec | |||
40ee01ce67 | |||
0b2bbf8c97 | |||
87af738378 | |||
e4ce622f15 | |||
dbd0ea4d27 | |||
a878a1ad9c | |||
aff4275478 | |||
609188d74e | |||
63a2e5e5ff | |||
ac1bea1d45 | |||
7b7f26ee47 | |||
3d00bdf3c0 | |||
319a02d2b4 | |||
cc8be1f278 | |||
e255573b1e | |||
0fe7e1fd39 | |||
2249f460e3 | |||
aae4009fbe | |||
a9284b7154 | |||
777fd7afb9 | |||
31079d95dd | |||
ced714129c | |||
4fcfd29d2b | |||
06de8d0be9 | |||
de36c7f3a2 | |||
8918b97618 | |||
0bb2be3727 | |||
a781fc5b3b | |||
00ef5d9344 | |||
9fbf5b4aad | |||
46083bdf5e | |||
8a165c4d71 | |||
9db9ea9dc1 | |||
4b514c6801 | |||
6a34352914 | |||
35c441355d | |||
9751880813 | |||
e58614002c |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,4 +1,5 @@
|
||||
[submodule "libopencm3"]
|
||||
path = libopencm3
|
||||
url = https://github.com/libopencm3/libopencm3
|
||||
url = https://github.com/manuelbl/libopencm3
|
||||
ignore = all
|
||||
branch = no-vbus-sensing
|
||||
|
213
README.md
213
README.md
@ -1,4 +1,4 @@
|
||||
This firmware template is designed for development boards based around [STM32 F1 series micro-controller](http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1031).
|
||||
firmware is for the I/O finder.
|
||||
|
||||
project
|
||||
=======
|
||||
@ -6,50 +6,172 @@ project
|
||||
summary
|
||||
-------
|
||||
|
||||
*describe project purpose*
|
||||
this tools allow to identify if channels (e.g. lines) are inputs or outputs.
|
||||
up to 16 channels can be identified at once.
|
||||
it also allows to monitor the channel activity, identify UART TX and RX signals.
|
||||
|
||||
usage
|
||||
-----
|
||||
|
||||
connect the pins or test points of the target device to the I/O finder channels pins on the connector.
|
||||
select the first and last channel to probe using the `start <CH>` ans `stop <CH>` commands.
|
||||
this prevents false activity monitoring alerts.
|
||||
it will also make the scan faster.
|
||||
|
||||
also connect the target voltage pin to the SWJ finder in order to use the right signal voltage level.
|
||||
alternatively, the SWJ finder can supply 3.3V to the target voltage pin using the `voltage 3` command.
|
||||
to revert to using the externally provided target voltage, use the `voltage 0` command.
|
||||
to measure the target voltage, use the `voltage` command.
|
||||
|
||||
to find out what type of I/O is connected to the channel, use the `type` command.
|
||||
it will measure the voltage while applying a pull-up and pull-down.
|
||||
if the voltage changes, the channel is likely an input (or floating).
|
||||
it will also show what value of pull-up/down is already on the channel.
|
||||
if the voltage does not change, the channel is likely an output (or GND/power supply rail).
|
||||
be aware that this is just the result at the testing type, as the target can change its configuration.
|
||||
|
||||
to monitor the activity of the channels, use the `monitor` command.
|
||||
provide no argument to not pull the channels.
|
||||
provide the 0 argument to pull the channels low using the internal 40 kOhm resistor.
|
||||
provide the 3 argument to pull the channels high to 3.3V using the internal 40 kOhm resistor.
|
||||
pulling the channels may reduce the noise, in case the channel is floating.
|
||||
the activity and current state (with time stamp) of the pin will be displayed (up to 0.1s speed).
|
||||
if the channel is switch fast, an 'X' will appear in from of the current level.
|
||||
to stop monitoring, press any key.
|
||||
|
||||
to monitor the activity of a single channel, use the `monitor_single` command.
|
||||
provide as argument the channel you want to monitor.
|
||||
this works like the `monitor` command, but has the advantage to detect high voltages down to 1.5V (ideal for 1.8V logic).
|
||||
it will also show the (maximum) frequency of the signal (useful to clock and baud rate measurement).
|
||||
|
||||
to detect the configuration of a UART stream, use the `uart_tx` command.
|
||||
provide as argument the channel you want to monitor.
|
||||
as data comes it, it will figure out the baud rate, data bits, and parity of the stream.
|
||||
the configuration is displayed as it finds a better match.
|
||||
it will also show the decoded data.
|
||||
this mainly works for ASCII based communication (e.g. human readable debug logs), and might not give correct results for binary communication.
|
||||
|
||||
to find the corresponding UART RX pin (e.g. once UART TX pin has been identified using the `uart_tx` command), use the `uart_rx` commands.
|
||||
provide as argument the channel for the UART TX pin, and the UART baud rate and frame settings (e.g. 115200 8N1).
|
||||
data will be transmitted on the channels to probe and if we received the echo back on the TX, we found the RX.
|
||||
this detection method only works if the target echoes back the data (e.g. on login prompts).
|
||||
|
||||
you can also reset the target board if you connected to target reset pin to the SWJ finder.
|
||||
you can select of to drive the reset pin (OD for open-drain, PP for push-pull) and active level (H for high, L for low) using the `reset [ODL|ODH|PPL|PPH]` command.
|
||||
to assert or release the reset, us the `reset 1` or `reset 0` commands.
|
||||
alternatively, pressing/releasing the button on the SWJ finder asserts/releases the reset signal
|
||||
|
||||
use the `help` command to list all commands.
|
||||
this will also list the shortcuts for the commands.
|
||||
|
||||
technology
|
||||
----------
|
||||
|
||||
*described electronic details*
|
||||
to figure out the type of I/O a channel is, it:
|
||||
- selects the channel on a analog multiplexer
|
||||
- measures the voltage while applying a 2 kOhm pull-down (to ground)
|
||||
- measures the voltage while applying a 2 kOhm pull-up (to target voltage)
|
||||
- calculate the resistance on the channel (since it known the resistor values of the voltage divided used to measure the channel voltage)
|
||||
|
||||
to monitor the activity, it directly reads the level of all 16 channels in parallel.
|
||||
no voltage shifter is used (the input have a high impedance to not affect the channels).
|
||||
any voltage above 3.3*0.7=2.3V is detected as high, else it is low.
|
||||
|
||||
limitation
|
||||
----------
|
||||
|
||||
the target voltage should not be higher than 5.5V (board I/O-pins limitation).
|
||||
the channel voltage level need to be above 2.3V for activity to be detected reliably when multiple channels are monitored.
|
||||
the channel voltage level need to be above 1.5V for activity to be detected reliably when a single channel is monitored.
|
||||
|
||||
the reset pin has no inline protection resistor and can sink up to 25 mA.
|
||||
in open drain mode, an external pull-up resistor is required, most often provide by the target device.
|
||||
in push-pull mode it can only source 3.3V up to 25 mA.
|
||||
|
||||
board
|
||||
=====
|
||||
|
||||
The current implementation uses a [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board).
|
||||
|
||||
The underlying template also supports following board:
|
||||
|
||||
- [Maple Mini](http://leaflabs.com/docs/hardware/maple-mini.html), based on a STM32F103CBT6
|
||||
- [System Board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#system_board), based on a STM32F103C8T6
|
||||
- [blue pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#blue_pill), based on a STM32F103C8T6
|
||||
- [black pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#black_pill), based on a STM32F103C8T6
|
||||
- [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board), based on a STM32F103C8T6
|
||||
- [ST-LINK V2 mini](https://wiki.cuvoodoo.info/doku.php?id=jtag#mini_st-link_v2), a ST-LINK/V2 clone based on a STM32F101C8T6
|
||||
- [USB-Blaster](https://wiki.cuvoodoo.info/doku.php?id=jtag#armjishu_usb-blaster), an Altera USB-Blaster clone based on a STM32F101C8T6
|
||||
|
||||
**Which board is used is defined in the Makefile**.
|
||||
This is required to map the user LED and button provided on the board
|
||||
|
||||
The ST-LINK V2 mini clone has SWD test points on the board.
|
||||
Because read protection is enabled, you will first need to remove the protection to be able to flash the firmware.
|
||||
To remove the read protection (and erase flash), run `rake remove_protection` while a SWD adapter is connected.
|
||||
|
||||
The Altera USB-Blaster clone has a pin header for SWD and UART1 on the board.
|
||||
SWD is disabled in the main firmware, and it has read protection.
|
||||
To be able to flash using SWD (or the serial port), the BOOT0 pin must be set to 1 to boot the system memory install of the flash memory.
|
||||
To set BOOT0 to 1, apply 3.3 V on R11, between the resistor and the reference designator, when powering the device.
|
||||
The red LED should stay off while the green LED is on.
|
||||
Now you can remove the read protection (and erase flash), run `rake remove_protection` while a SWD adapter is connected.
|
||||
the underlying hardware uses a [WeAct MiniF4](https://github.com/WeActTC/MiniF4-STM32F4x1) board, based on a STM32F401CCU6.
|
||||
the bi-directional level shifter are BSS138 n-channel MOSFET based.
|
||||
switching the target voltage are done using BSS84 p-channel MOSFET.
|
||||
|
||||
connections
|
||||
===========
|
||||
|
||||
Connect the peripherals the following way (STM32F10X signal; STM32F10X pin; peripheral pin; peripheral signal; comment):
|
||||
remove LED on C13 on MiniF4 board so we can reuse the pin.
|
||||
|
||||
- *list board to peripheral pin connections*
|
||||
IDC 2x10 connector:
|
||||
|
||||
All pins are configured using `define`s in the corresponding source code.
|
||||
01. GND, connect to ground
|
||||
02. VTRG, target voltage, see below for connection
|
||||
03. RST, to reset the target board, connect to PA0
|
||||
04. 3V3, connected to 3.3V
|
||||
05. CH00, connect to PB10
|
||||
06. CH01, connect to PB9
|
||||
07. CH02, connect to PB8
|
||||
08. CH03, connect to PB7
|
||||
09. CH04, connect to PB6
|
||||
10. CH05, connect to PB5
|
||||
11. CH06, connect to PB4
|
||||
12. CH07, connect to PB3
|
||||
13. CH08, connect to PA15
|
||||
14. CH09, connect to PA10
|
||||
15. CH10, connect to PA9
|
||||
16. CH11, connect to PA8
|
||||
17. CH12, connect to PB15
|
||||
18. CH13, connect to PB14
|
||||
19. CH14, connect to PB13
|
||||
20. CH15, connect to PB12
|
||||
|
||||
ADC, used to measure target voltage (up to 6.6V):
|
||||
|
||||
- connect VTRG to 22 kOhm resistor R1
|
||||
- connect PA6 (ADC1_IN6) to other side of resistor R1
|
||||
- connect PA6 to 22 kOhm resistor R2
|
||||
- connect GND to other side of resistor R2, forming a voltage divided
|
||||
|
||||
analog multiplexer, 16-channel, HP4067, to probe individual channels:
|
||||
|
||||
- channels: C0-C15 to CH0-CH15
|
||||
- select: S3 to PB2, S2 to PB1, S1 to PB0, S0 to PA7
|
||||
- enable: EN to PC15, pulled up to VCC
|
||||
- signal: S to see below
|
||||
- VCC: to 5V (for better switching, the select line can still be operated at 3.3V)
|
||||
- GND: to ground
|
||||
|
||||
ADC for signal, using BSS84 p-channel MOSFET Q5:
|
||||
|
||||
- connect signal S to PA1/ADC1_IN1 through 1 KOhm resistor (first part of voltage divider)
|
||||
- connect 1 kOhm between PA1 and PA4, creating second part of voltage divider (PA4 can ground it)
|
||||
- Q5 source: to VTRG
|
||||
- Q5 gate: to PA5, pulled up to VTRG using 10-100 kOhm resistor
|
||||
- Q5 drain: to PA4 (PA5 can set connect voltage divider to high side)
|
||||
|
||||
UART, with level shifter, to scan for UART port:
|
||||
|
||||
- short PA3 (RX) and PA2 (TX), making it a half-duplex UART (sufficient for testing most UARTs)
|
||||
- connect PA2/PA3 to 150 Ohm in-line resistor R3 (used as protection to limit sink current)
|
||||
- pull up R3 to 5V using 10 kOhm ressitor, this is necessary for the voltage shifter to operate up to 5V
|
||||
- connect R3 to source of BSS138 n-channel MOSFET Q1, used as bi-directional level shifter
|
||||
- connect gate of Q1 to Q2 drain
|
||||
- connect source of Q1 to signal S
|
||||
|
||||
level shifter control, using BSS84 p-channel MOSFET Q2:
|
||||
|
||||
- gate: to PC14, pulled up to VTRG using 10-100 kOhm resistor
|
||||
- source: VTRG
|
||||
- drain: to signal S through 10 kOhm (this creates a pull-up resistor for the low side level shifter)
|
||||
|
||||
target voltage supply control, using BSS84 p-channel MOSFET Q3 (to provide 3.3V) and BSS138 n-channel MOSFET Q4 (to prevent feed back into 3.3V):
|
||||
|
||||
- Q3 gate: PC13, pulled up to 3.3V using 10-100 kOhm resistor
|
||||
- Q3 source: 3.3V
|
||||
- Q3 drain: Q4 source, 3.3V output for target
|
||||
- Q4 source: Q3 drain, forward 3.3V to target (through body diode and because gate is on)
|
||||
- Q4 gate: to 5V, enabling transition until 5V from target is present on drain
|
||||
- Q4 drain: VTRG
|
||||
|
||||
all pins are configured using `define`s in the corresponding source code.
|
||||
|
||||
code
|
||||
====
|
||||
@ -81,15 +203,20 @@ The `bootloader` is started first and immediately jumps to the `application` if
|
||||
The `application` image is the main application and is implemented in `application.c`.
|
||||
It is up to the application to advertise USB DFU support (i.e. as does the provided USB CDC ACM example).
|
||||
|
||||
The `bootloader` image will be flashed using SWD (Serial Wire Debug).
|
||||
The simplest way do flash the `bootloader` image is using the embedded bootloader.
|
||||
By pressing the BOOT0 button (setting the pin low) while powering or resetting the device, the micro-controller boot its embedded UART/USB DFU bootloader.
|
||||
Connect a USB cable and run `rake dfu_bootloader`.
|
||||
|
||||
Once the `bootloader` is flashed, it is possible to flash the `application` over USB using the DFU protocol by running `rake flash` (equivalent to `rake dfu_application`.
|
||||
To force the bootloader to start the DFU mode press the user button or short a pin, depending on the board.
|
||||
Note: I use my own DFU bootloader instead of the embedded bootloader because I was not able to start the embedded USB DFU bootloader from the application.
|
||||
|
||||
The images can also be flash using SWD (Serial Wire Debug) in case the firmware gets stuck and does not provide USB functionalities.
|
||||
For that you need an SWD adapter.
|
||||
The `Makefile` uses a ST-Link V2 programmer along OpenOCD software (default), or Black Magic Probe.
|
||||
To flash the `booltoader` using SWD run `rake flash_booloader`.
|
||||
If the development board uses the CKS32 chip STM32 alternative, use `CPUTAPID=0x2ba01477 rake flash_booloader`.
|
||||
|
||||
Once the `bootloader` is flashed it is possible to flash the `application` over USB using the DFU protocol by running `rake flash`.
|
||||
To force the bootloader to start the DFU mode press the user button or short a pin, depending on the board.
|
||||
It is also possible to flash the `application` image using SWD by running `rake flash_application`.
|
||||
To flash the `bootloader` using SWD run `rake swd_bootloader` (this will also erase the application).
|
||||
To flash the `application` using SWD run `rake swd_application` (or `rake swd`).
|
||||
To erase all memory and unlock read/write protection, run `rake remove_protection`.
|
||||
|
||||
debug
|
||||
-----
|
||||
@ -100,4 +227,12 @@ To start the debugging session run `rake debug`.
|
||||
USB
|
||||
---
|
||||
|
||||
The firmware offers serial communication over USART1 and USB (using the CDC ACM device class).
|
||||
The firmware offers serial communication over USB (using the CDC ACM device class).
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
add monitor single channel to support 1.8V voltage.
|
||||
measure frequency of single channel.
|
||||
decode single channel as RX.
|
||||
probe UART using TX than RX.
|
||||
|
95
Rakefile
95
Rakefile
@ -1,8 +1,8 @@
|
||||
# encoding: utf-8
|
||||
# ruby: 2.4.2
|
||||
=begin
|
||||
Rakefile to manage compile CuVoodoo STM32F1 firmware.
|
||||
the firmware is for development board based around a STM32F1xx micro-controller.
|
||||
Rakefile to manage compiling CuVoodoo STM32F4 firmware.
|
||||
the firmware is for development boards based around a STM32F4xx micro-controller.
|
||||
the firmware uses the libopencm3 library providing support for this micro-controller.
|
||||
=end
|
||||
require 'rake'
|
||||
@ -14,15 +14,26 @@ APPLICATION = "application"
|
||||
FIRMWARES = [BOOTLOADER, APPLICATION]
|
||||
|
||||
# which development board is used
|
||||
# supported are: SYSTEM_BOARD, MAPLE_MINI, BLUE_PILL, BLACK_PILL, CORE_BOARD, STLINKV2, BLASTER, BUSVOODOO
|
||||
BOARD = ENV["BOARD"] || "BLUE_PILL"
|
||||
# supported are: WeAct MiniF4 with STM32F401
|
||||
BOARD = ENV["BOARD"] || "MINIF401"
|
||||
# get MCU from board
|
||||
DEVICE = case BOARD
|
||||
when "MINIF401"
|
||||
"stm32f401cc"
|
||||
else
|
||||
raise "unknown MCU for board #{BOARD}"
|
||||
end
|
||||
|
||||
# libopencm3 definitions
|
||||
LIBOPENCM3_DIR = "libopencm3"
|
||||
LIBOPENCM3_INC = LIBOPENCM3_DIR+"/include"
|
||||
LIBOPENCM3_LIB = LIBOPENCM3_DIR+"/lib"
|
||||
# STM32F1 library used for this project provided by libopencm3
|
||||
STM32F1_LIB = "opencm3_stm32f1"
|
||||
LIBOPENCM3_LIBS = LIBOPENCM3_DIR+"/lib"
|
||||
# get libopencm3
|
||||
unless File.file?("./#{LIBOPENCM3_DIR}/scripts/genlink.py") then
|
||||
sh "git submodule init"
|
||||
sh "git submodule update"
|
||||
end
|
||||
LIBOPENCM3_LIB = "opencm3_" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} FAMILY`
|
||||
|
||||
# source code used by the firmware
|
||||
SRC_DIRS = [".", "lib"]
|
||||
@ -43,7 +54,7 @@ cflags = [ENV["CFLAGS"]]
|
||||
# optimize for size
|
||||
cflags << "-Os"
|
||||
# add debug symbols (remove for smaller release)
|
||||
cflags << "-ggdb"
|
||||
cflags << "-ggdb3"
|
||||
# use C99 (supported by most an sufficient)
|
||||
cflags << "-std=c99"
|
||||
# have strict warning (for better code)
|
||||
@ -59,7 +70,8 @@ cflags += SRC_DIRS.collect {|srd_dir| "-I #{srd_dir}"}
|
||||
# include libopencm3 library
|
||||
cflags << "-I #{LIBOPENCM3_INC}"
|
||||
# add defines for micro-controller and board
|
||||
cflags << "-DSTM32F1 -D#{BOARD}"
|
||||
cflags << "-D#{BOARD}"
|
||||
cflags << `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} CPPFLAGS`
|
||||
# render cflags
|
||||
cflags = cflags.compact*' '
|
||||
|
||||
@ -76,14 +88,17 @@ ldflags_linker = ["--gc-sections"]
|
||||
# show memory usage
|
||||
ldflags_linker << "--print-memory-usage"
|
||||
# add libopencm3 libraries
|
||||
library_paths = [LIBOPENCM3_LIB]
|
||||
library_paths = [LIBOPENCM3_LIBS]
|
||||
# project libraries
|
||||
ldlibs = [STM32F1_LIB]
|
||||
ldlibs = [LIBOPENCM3_LIB]
|
||||
# general libraries (gcc provides the ARM ABI)
|
||||
ldlibs_linker = ["m", "c", "nosys", "gcc"]
|
||||
|
||||
# target micro-controller information (ARM Cortex-M3 supports thumb and thumb2, but does not include a floating point unit)
|
||||
archflags = "-mthumb -mcpu=cortex-m3 -msoft-float"
|
||||
# target micro-controller information (ARM Cortex-M4 supports thumb and thumb2, but does not include a floating point unit)
|
||||
archflags = "-mthumb"
|
||||
archflags += " -mcpu=" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} CPU`
|
||||
archflags += " -mfloat-abi=" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} FPU`.split("-")[0]
|
||||
archflags += " -mfpu=" + `./#{LIBOPENCM3_DIR}/scripts/genlink.py #{LIBOPENCM3_DIR}/ld/devices.data #{DEVICE} FPU`.split("-")[1..-1]*"-"
|
||||
|
||||
desc "compile firmwares"
|
||||
task :default => FIRMWARES
|
||||
@ -101,17 +116,17 @@ end
|
||||
|
||||
# get dependencies of a file
|
||||
# done is a list of already known dependencies
|
||||
def dependencies(source, done=[])
|
||||
def dependencies(source, done = [])
|
||||
d_path = source.ext("d") # get the dependency file
|
||||
Rake::Task[d_path].invoke # ensure the dependency file exists
|
||||
d_file = IO.read(d_path) # read the dependencies from dependency file
|
||||
d_file = d_file.split(': ')[1].gsub("\n",'').gsub('\\ ','').gsub(/\s+/,' ').split(' ') # get a list of dependencies
|
||||
d_file = d_file.split(': ')[1].gsub("\n", '').gsub('\\ ', '').gsub(/\s+/, ' ').split(' ') # get a list of dependencies
|
||||
d_list = [] # list of dependencies
|
||||
# only save dependencies which are in our source directories
|
||||
d_file.each do |d|
|
||||
SRC_DIRS.each do |dir|
|
||||
if File.dirname(d)==dir then
|
||||
d_list << d
|
||||
if File.dirname(d) == dir then
|
||||
d_list << d unless d.end_with?(".inc")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -127,14 +142,8 @@ def dependencies(source, done=[])
|
||||
return done
|
||||
end
|
||||
|
||||
desc "get libopencm3"
|
||||
file LIBOPENCM3_DIR+"/Makefile" do
|
||||
sh "git submodule init"
|
||||
sh "git submodule update"
|
||||
end
|
||||
|
||||
desc "compile libopencm3"
|
||||
file "#{LIBOPENCM3_LIB}/lib#{STM32F1_LIB}.a" => LIBOPENCM3_DIR+"/Makefile" do
|
||||
file "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a" do
|
||||
sh "make --directory #{LIBOPENCM3_DIR}"
|
||||
end
|
||||
|
||||
@ -143,17 +152,17 @@ task :doc => ["Doxyfile", "README.md"] do |t|
|
||||
end
|
||||
|
||||
desc "compile source into object"
|
||||
rule '.o' => ['.c', proc{|f| File.file?(f.ext("h")) ? f.ext("h") : []}, proc{|f| dependencies(f).collect{|d| File.file?(d.ext("h")) ? d.ext("h") : []}}, "#{LIBOPENCM3_LIB}/lib#{STM32F1_LIB}.a"] do |t|
|
||||
rule '.o' => ['.c', proc{|f| File.file?(f.ext("h")) ? f.ext("h") : []}, proc{|f| dependencies(f).collect{|d| File.file?(d.ext("h")) ? d.ext("h") : []}}, "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a"] do |t|
|
||||
sh "#{CC} #{cflags} #{archflags} -o #{t.name} -c #{t.prerequisites[0]}"
|
||||
end
|
||||
|
||||
desc "generate dependencies"
|
||||
rule '.d' => ['.c', "#{LIBOPENCM3_LIB}/lib#{STM32F1_LIB}.a"] do |t|
|
||||
rule '.d' => ['.c', "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a"] do |t|
|
||||
sh "#{CC} #{cflags} #{archflags} -MM -MF #{t.name} -c #{t.prerequisites[0]}"
|
||||
end
|
||||
|
||||
desc "link binary"
|
||||
rule '.elf' => ['.o', proc{|f| dependencies(f)}, '.ld', "#{LIBOPENCM3_LIB}/lib#{STM32F1_LIB}.a"] do |t|
|
||||
rule '.elf' => ['.o', proc{|f| dependencies(f)}, '.ld', "#{LIBOPENCM3_LIBS}/lib#{LIBOPENCM3_LIB}.a"] do |t|
|
||||
sh "#{LD} #{archflags} #{ldflags.join(' ')} #{t.prerequisites[0..-3].join(' ')} -T#{t.name.ext('ld')} #{ldflags_linker.collect{|flag| "-Wl,"+flag}.join(' ')} #{library_paths.collect{|path| "-L"+path}.join(' ')} #{ldlibs.collect{|lib| "-l"+lib}.join(' ')} -Wl,--start-group #{ldlibs_linker.collect{|lib| "-l"+lib}.join(' ')} -Wl,--end-group --output #{t.name}"
|
||||
end
|
||||
|
||||
@ -190,42 +199,50 @@ OOCD = ENV["OOCD"] || "openocd"
|
||||
# openOCD adapted name
|
||||
OOCD_INTERFACE = ENV["OOCD_INTERFACE"] || (SWD_ADAPTER=="STLINKV2" ? "stlink" : "")
|
||||
# openOCD target for the micro-controller
|
||||
OOCD_TARGET = "stm32f1x"
|
||||
OOCD_TARGET = "stm32f4x"
|
||||
# Black Magic Probe port
|
||||
BMP_PORT = ENV["BMP_PORT"] || "/dev/ttyACM0"
|
||||
# set CPUTAPID (0x1ba01477 for STM32, 0x2ba01477 for CKS32/APM32)
|
||||
CPUTAPID = ENV["CPUTAPID"] || "0x1ba01477"
|
||||
|
||||
desc "flash application"
|
||||
task :flash => :dfu_application
|
||||
|
||||
desc "flash application using USB DFU"
|
||||
task :flash => APPLICATION+".bin" do |t|
|
||||
task :dfu_application => APPLICATION+".bin" do |t|
|
||||
sh "dfu-util --device 1209:4356 --download #{t.source}"
|
||||
end
|
||||
|
||||
desc "remove STM32F1 protection using SWD"
|
||||
desc "flash application using USB DFU"
|
||||
task :dfu_bootloader => BOOTLOADER+".bin" do |t|
|
||||
sh "dfu-util --device 0483:df11 --cfg 1 --intf 0 --alt 0 --dfuse-address 0x08000000 --download #{t.source} --reset"
|
||||
end
|
||||
|
||||
desc "remove STM32F4 protection using SWD"
|
||||
task :remove_protection do
|
||||
case SWD_ADAPTER
|
||||
when "STLINKV2"
|
||||
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --command 'set CPUTAPID #{CPUTAPID}' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'stm32f1x unlock 0' --command 'reset init' --command 'flash protect 0 0 last off' --command 'reset init' --command 'stm32f1x options_write 0 SWWDG NORSTSTNDBY NORSTSTOP' --command 'reset init' --command 'stm32f1x mass_erase 0' --command 'shutdown'"
|
||||
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'stm32f2x unlock 0' --command 'reset init' --command 'flash protect 0 0 last off' --command 'reset init' --command 'stm32f2x mass_erase 0' --command 'shutdown'"
|
||||
when "BMP"
|
||||
sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='set confirm off' --eval-command='monitor swdp_scan' --eval-command='attach 1' --eval-command='monitor option erase' --eval-command='monitor erase_mass' --eval-command='kill' --eval-command='quit'"
|
||||
end
|
||||
end
|
||||
|
||||
desc "flash bootloader using SWD"
|
||||
task :flash_bootloader => BOOTLOADER+".hex" do |t|
|
||||
task :swd_bootloader => BOOTLOADER+".hex" do |t|
|
||||
case SWD_ADAPTER
|
||||
when "STLINKV2"
|
||||
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --command 'set CPUTAPID #{CPUTAPID}' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'flash erase_sector 0 0 last' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
|
||||
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'flash erase_sector 0 0 last' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
|
||||
when "BMP"
|
||||
sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='set confirm off' --eval-command='monitor swdp_scan' --eval-command='attach 1' --eval-command='monitor erase_mass' --eval-command='load' --eval-command='kill' --eval-command='quit' #{t.source}"
|
||||
end
|
||||
end
|
||||
|
||||
task :swd => :swd_application
|
||||
|
||||
desc "flash application using SWD"
|
||||
task :flash_application => APPLICATION+".hex" do |t|
|
||||
task :swd_application => APPLICATION+".hex" do |t|
|
||||
case SWD_ADAPTER
|
||||
when "STLINKV2"
|
||||
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --command 'set CPUTAPID #{CPUTAPID}' --file target/#{OOCD_TARGET}.cfg --command 'adapter speed 100' --command 'init' --command 'halt' --command 'reset init' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
|
||||
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --file target/#{OOCD_TARGET}.cfg --command 'adapter speed 100' --command 'init' --command 'halt' --command 'reset init' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
|
||||
when "BMP"
|
||||
sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='set confirm off' --eval-command='monitor swdp_scan' --eval-command='attach 1' --eval-command='load' --eval-command='kill' --eval-command='quit' #{t.source}"
|
||||
end
|
||||
@ -237,7 +254,7 @@ task :debug => APPLICATION+".elf" do |t|
|
||||
case SWD_ADAPTER
|
||||
when "STLINKV2"
|
||||
# for GDB to work with openOCD the firmware needs to be reloaded
|
||||
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --command \"set CPUTAPID #{CPUTAPID}\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' #{t.source}")
|
||||
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' #{t.source}")
|
||||
when "BMP"
|
||||
exec("#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}")
|
||||
end
|
||||
@ -249,7 +266,7 @@ task :debug_bootloader => BOOTLOADER+".elf" do |t|
|
||||
case SWD_ADAPTER
|
||||
when "STLINKV2"
|
||||
# for GDB to work with openOCD the firmware needs to be reloaded
|
||||
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --command \"set CPUTAPID #{CPUTAPID}\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset init' #{t.source}")
|
||||
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset init' #{t.source}")
|
||||
when "BMP"
|
||||
exec("#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}")
|
||||
end
|
||||
|
1594
application.c
1594
application.c
File diff suppressed because it is too large
Load Diff
@ -1,28 +1,16 @@
|
||||
/* linker script for application running on STM32F103x8 micro-controller
|
||||
* the STM32F103x8 has 64 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
|
||||
* the STM32F103xB has 128 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
|
||||
* STM32F103x8 most often have if fact 128 KB, instead of the specified and advertised 64 KB, like the STM32F103xB
|
||||
* you can define the desired flash size here.
|
||||
* the USB DFU bootloader will take the first 8 KB of flash, followed by the application
|
||||
/* linker script for application running on STM32F401xC micro-controller
|
||||
* the STM32F401xC has 256 KB of flash starting at 0x0800 0000, and 64 KB of RAM starting at 0x2000 0000
|
||||
* the USB DFU bootloader will use the first sector, which is 16 KB large.
|
||||
* this is followed by the application.
|
||||
* the first 4 bytes of the RAM is reserved for the DFU magic word (DFU! to start DFU bootloader)
|
||||
*/
|
||||
|
||||
/* define memory regions. */
|
||||
MEMORY
|
||||
{
|
||||
rom (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 64K - 8K
|
||||
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 20K - 4
|
||||
rom (rx) : ORIGIN = 0x08000000 + 16K, LENGTH = 256K - 16K
|
||||
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 64K - 4
|
||||
}
|
||||
PROVIDE(__application_beginning = ORIGIN(rom));
|
||||
/* if you want the firmware to use the flash size advertised by the micro-controller itself, use the following:
|
||||
PROVIDE(__application_end = 0);
|
||||
PROVIDE(__flash_end = 0);
|
||||
if you want to enforce a flash size, because there is more flash than advertized by the micro-controller, use to following:
|
||||
PROVIDE(__application_end = ORIGIN(rom) + LENGTH(rom));
|
||||
PROVIDE(__flash_end = ORIGIN(rom) + LENGTH(rom));
|
||||
*/
|
||||
PROVIDE(__application_end = 0);
|
||||
PROVIDE(__flash_end = 0);
|
||||
/* RAM location reserved so application can talk to bootloader and tell to start DFU */
|
||||
PROVIDE(__dfu_magic = ORIGIN(ram) - 4);
|
||||
|
||||
|
41
bootloader.c
41
bootloader.c
@ -2,7 +2,7 @@
|
||||
* @file
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* @date 2017-2019
|
||||
* @date 2017-2020
|
||||
*/
|
||||
/* standard libraries */
|
||||
#include <stdint.h> // standard integer types
|
||||
@ -17,6 +17,11 @@
|
||||
#include "global.h" // board definitions
|
||||
#include "usb_dfu.h" // USB DFU utilities
|
||||
|
||||
/** symbol for beginning of the application
|
||||
* @note this symbol will be provided by the bootloader linker script
|
||||
*/
|
||||
extern char __application_beginning;
|
||||
|
||||
/** bootloader entry point */
|
||||
void main(void);
|
||||
void main(void)
|
||||
@ -31,38 +36,20 @@ void main(void)
|
||||
__dfu_magic[1] = 0;
|
||||
__dfu_magic[2] = 0;
|
||||
__dfu_magic[3] = 0;
|
||||
} else if (0 == (RCC_CSR & 0xfc000000)) { // no reset flag present -> this was a soft reset using scb_reset_core() after clearing the flags using RCC_CSR_RMVF, this was the legacy way to start the DFU mode
|
||||
dfu_force = true;
|
||||
} else { // check if the force DFU mode input is set
|
||||
// disable SWJ pin to use as GPIO
|
||||
#if (defined(DFU_FORCE_PIN) && defined(DFU_FORCE_VALUE))
|
||||
#if ((GPIO(B) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(4) == GPIO_PIN(DFU_FORCE_PIN)))
|
||||
// JNTRST pin is used as DFU pin
|
||||
rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function domain
|
||||
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_JNTRST, 0); // keep SWJ enable bit don't use JNTRST
|
||||
#elif ((GPIO(B) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(3) == GPIO_PIN(DFU_FORCE_PIN))) || ((GPIO(A) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(15) == GPIO_PIN(DFU_FORCE_PIN)))
|
||||
// JTAG but not SWD pin used as DFU pin
|
||||
rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function domain
|
||||
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); // disable JTAG but keep SWD
|
||||
#elif ((GPIO(A) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(14) == GPIO_PIN(DFU_FORCE_PIN))) || ((GPIO(A) == GPIO_PORT(DFU_FORCE_PIN)) && (GPIO(13) == GPIO_PIN(DFU_FORCE_PIN)))
|
||||
// JTAG and SWD pin used as DFU pin
|
||||
rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function domain
|
||||
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_OFF, 0); // disable JTAG and SWD
|
||||
#endif // DFU_FORCE_PIN
|
||||
rcc_periph_clock_enable(GPIO_RCC(DFU_FORCE_PIN)); // enable clock for GPIO domain
|
||||
gpio_set_mode(GPIO_PORT(DFU_FORCE_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(DFU_FORCE_PIN)); // set GPIO to input
|
||||
// pull on the opposite of the expected value
|
||||
rcc_periph_clock_enable(GPIO_RCC(DFU_FORCE_PIN)); // enable clock for button
|
||||
#if (DFU_FORCE_VALUE == 1)
|
||||
gpio_clear(GPIO_PORT(DFU_FORCE_PIN), GPIO_PIN(DFU_FORCE_PIN)); // pull down to be able to detect when tied to high
|
||||
gpio_mode_setup(GPIO_PORT(DFU_FORCE_PIN), GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN(DFU_FORCE_PIN)); // set GPIO to input
|
||||
if (gpio_get(GPIO_PORT(DFU_FORCE_PIN), GPIO_PIN(DFU_FORCE_PIN))) { // check if output is set to the value to force DFU mode
|
||||
#else
|
||||
gpio_set(GPIO_PORT(DFU_FORCE_PIN), GPIO_PIN(DFU_FORCE_PIN)); // pull up to be able to detect when tied to low
|
||||
gpio_mode_setup(GPIO_PORT(DFU_FORCE_PIN), GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN(DFU_FORCE_PIN)); // set GPIO to input
|
||||
if (0 == gpio_get(GPIO_PORT(DFU_FORCE_PIN), GPIO_PIN(DFU_FORCE_PIN))) { // check if output is set to the value to force DFU mode
|
||||
#endif // DFU_FORCE_VALUE
|
||||
dfu_force = true; // DFU mode forced
|
||||
}
|
||||
#endif // defined(DFU_FORCE_PIN)
|
||||
rcc_periph_clock_disable(RCC_AFIO); // disable alternate function domain to put it back to default
|
||||
rcc_periph_reset_pulse(GPIO_RST(DFU_FORCE_PIN)); // reset pin GPIO domain
|
||||
rcc_periph_clock_disable(GPIO_RCC(DFU_FORCE_PIN)); // disable pin GPIO domain
|
||||
}
|
||||
@ -71,24 +58,20 @@ void main(void)
|
||||
/* the application starts with the vector table
|
||||
* the first entry in the vector table is the initial stack pointer (SP) address
|
||||
* the stack will be placed in RAM
|
||||
* on STM32F1xx SRAM begins at 0x2000 0000, and on STM32F103xx there is up to 96 KB of RAM (0x18000).
|
||||
* since the stack grown "downwards" it should start at the end of the RAM: max 0x2001 8000
|
||||
* on STM32F4 SRAM begins at 0x2000 0000, and on STM32F4xx there is up to 384 KiB of RAM (0x60000).
|
||||
* since the stack grown "downwards" it should start at the end of the RAM: max 0x2006 0000
|
||||
* if the SP is not in this range (e.g. flash has been erased) there is no valid application
|
||||
* the second entry in the vector table is the reset address, corresponding to the application start
|
||||
*/
|
||||
volatile uint32_t* application = (uint32_t*)&__application_beginning; // get the value of the application address symbol (use a register instead on the stack since the stack pointer will be changed)
|
||||
if (!dfu_force && (((*application) & 0xFFFE0000) == 0x20000000)) { // application at address seems valid
|
||||
if (!dfu_force && (((*application) & 0xFFF80000) == 0x20000000)) { // application at address seems valid
|
||||
SCB_VTOR = (volatile uint32_t)(application); // set vector table to application vector table (store at the beginning of the application)
|
||||
__asm__ volatile ("MSR msp,%0" : :"r"(*application)); // set stack pointer to address provided in the beginning of the application (loaded into a register first)
|
||||
(*(void(**)(void))((uint32_t)application + 4))(); // start application (by jumping to the reset function which address is stored as second entry of the vector table)
|
||||
}
|
||||
|
||||
rcc_clock_setup_in_hse_8mhz_out_72mhz(); // start main clock
|
||||
board_setup(); // setup board to control LED
|
||||
led_on(); // indicate bootloader started
|
||||
#if defined(BUSVOODOO)
|
||||
led_toggle(); // switch from blue to red LED
|
||||
#endif
|
||||
usb_dfu_setup(); // setup USB DFU for firmware upload
|
||||
usb_dfu_start(); // run DFU mode
|
||||
}
|
||||
|
@ -1,28 +1,18 @@
|
||||
/* linker script for application running on STM32F103x8 micro-controller
|
||||
* the STM32F103x8 has 64 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
|
||||
* the STM32F103xB has 128 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000
|
||||
* STM32F103x8 most often have if fact 128 KB, instead of the specified and advertised 64 KB, like the STM32F103xB
|
||||
* you can define the desired flash size here.
|
||||
* the USB DFU bootloader will take the first 8 KB of flash, followed by the application
|
||||
/* linker script for application running on STM32F401xC micro-controller
|
||||
* the STM32F401xC has 256 KB of flash starting at 0x0800 0000, and 64 KB of RAM starting at 0x2000 0000
|
||||
* the USB DFU bootloader will use the first sector, which is 16 KB large.
|
||||
* this is followed by the application.
|
||||
* the first 4 bytes of the RAM is reserved for the DFU magic word (DFU! to start DFU bootloader)
|
||||
*/
|
||||
|
||||
/* define memory regions. */
|
||||
MEMORY
|
||||
{
|
||||
rom (rx) : ORIGIN = 0x08000000, LENGTH = 8K
|
||||
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 20K - 4
|
||||
rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
|
||||
ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 64K - 4
|
||||
}
|
||||
/* where the main application starts */
|
||||
PROVIDE(__application_beginning = ORIGIN(rom) + LENGTH(rom));
|
||||
/* if you want the firmware to use the flash size advertised by the micro-controller itself, use the following:
|
||||
PROVIDE(__application_end = 0);
|
||||
PROVIDE(__flash_end = 0);
|
||||
if you want to enforce a flash size, because there is more flash than advertized by the micro-controller, use to following:
|
||||
PROVIDE(__application_end = ORIGIN(rom) + LENGTH(rom));
|
||||
PROVIDE(__flash_end = ORIGIN(rom) + LENGTH(rom));
|
||||
*/
|
||||
PROVIDE(__application_end = 0);
|
||||
PROVIDE(__flash_end = 0);
|
||||
/* RAM location reserved so application can talk to bootloader and tell to start DFU */
|
||||
PROVIDE(__dfu_magic = ORIGIN(ram) - 4);
|
||||
|
||||
|
110
global.c
110
global.c
@ -16,6 +16,8 @@
|
||||
#include <libopencm3/stm32/rcc.h> // real-time control clock library
|
||||
#include <libopencm3/stm32/gpio.h> // general purpose input output library
|
||||
#include <libopencm3/stm32/exti.h> // external interrupt defines
|
||||
#include <libopencm3/stm32/syscfg.h> // system definitions
|
||||
#include <libopencm3/usb/dwc/otg_fs.h> // USB OTG utilities
|
||||
|
||||
#include "global.h" // common methods
|
||||
|
||||
@ -132,9 +134,6 @@ char* b2s(uint64_t binary, uint8_t rjust)
|
||||
inline void led_on(void)
|
||||
{
|
||||
#if defined(LED_PIN)
|
||||
#if defined(BUSVOODOO)
|
||||
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_PIN)); // set LED pin push-pull
|
||||
#endif // BUSVOODOO
|
||||
#if defined(LED_ON) && LED_ON
|
||||
gpio_set(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
|
||||
#else
|
||||
@ -147,14 +146,10 @@ inline void led_on(void)
|
||||
inline void led_off(void)
|
||||
{
|
||||
#if defined(LED_PIN)
|
||||
#if defined(BUSVOODOO)
|
||||
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LED_PIN)); // set LED pin to floating to disable LEDs
|
||||
#else
|
||||
#if defined(LED_ON) && LED_ON
|
||||
gpio_clear(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
|
||||
#else
|
||||
gpio_set(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
|
||||
#endif // BUSVOODOO
|
||||
#endif // LED_ON
|
||||
#endif // LED_PIN
|
||||
}
|
||||
@ -163,21 +158,18 @@ inline void led_off(void)
|
||||
inline void led_toggle(void)
|
||||
{
|
||||
#if defined(LED_PIN)
|
||||
#if defined(BUSVOODOO)
|
||||
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_PIN)); // set LED pin to push-pull
|
||||
#endif // BUSVOODOO
|
||||
gpio_toggle(GPIO_PORT(LED_PIN), GPIO_PIN(LED_PIN));
|
||||
#endif // LED_PIN
|
||||
}
|
||||
|
||||
void sleep_us(uint32_t duration)
|
||||
{
|
||||
if (duration <= 5) { // less than the setup time
|
||||
for (volatile uint32_t nop = 0; nop < 5 * duration; nop++); // busy loop, approximate, hand tuned for 72 MHz system clock
|
||||
if (duration <= 4) { // less than the setup time
|
||||
for (volatile uint32_t nop = 0; nop < 5 * duration; nop++); // busy loop, approximate
|
||||
return;
|
||||
}
|
||||
|
||||
duration -= 5; // subtract setup time
|
||||
duration -= 4; // subtract setup time
|
||||
systick_counter_disable(); // disable SysTick to reconfigure it
|
||||
if (!systick_set_frequency(1000000, rcc_ahb_frequency)) { // set SysTick frequency to microseconds
|
||||
while (true); // unhandled error
|
||||
@ -249,33 +241,41 @@ void user_input_store(char c)
|
||||
|
||||
void board_setup(void)
|
||||
{
|
||||
#if defined(LED_PIN)
|
||||
// setup main clock
|
||||
#if defined(MINIF401)
|
||||
rcc_clock_setup_pll(&rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_84MHZ]); // the MINIF401 uses an STM32F401 which can go up to 84 MHz, and the board has a 25 MHz crystal
|
||||
#else
|
||||
rcc_clock_setup_pll(&rcc_hsi_configs[RCC_CLOCK_3V3_84MHZ]); // use HSI which is present on all boards, and limit to 84MHz (supported by all STM32F4
|
||||
#endif
|
||||
|
||||
#if defined(LED_PIN) && defined(LED_ON)
|
||||
// setup LED
|
||||
rcc_periph_clock_enable(GPIO_RCC(LED_PIN)); // enable clock for LED
|
||||
#if defined(BUSVOODOO)
|
||||
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(LED_PIN)); // set LED pin to floating to disable LEDs
|
||||
#else
|
||||
gpio_set_mode(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(LED_PIN)); // set LED pin to output push-pull do drive LED
|
||||
gpio_mode_setup(GPIO_PORT(LED_PIN), GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN(LED_PIN)); // set LED pin as output
|
||||
#if LED_ON // LED is on when sourcing
|
||||
gpio_set_output_options(GPIO_PORT(LED_PIN), GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN(LED_PIN)); // set LED pin output as push-pull
|
||||
#else // LED is on when sinking
|
||||
gpio_set_output_options(GPIO_PORT(LED_PIN), GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_PIN(LED_PIN)); // set LED pin output as open-drain
|
||||
#endif
|
||||
led_off(); // switch off LED per default
|
||||
#endif // LED_PIN
|
||||
|
||||
// setup button
|
||||
#if defined(BUTTON_PIN)
|
||||
/*
|
||||
#if defined(BUTTON_PIN) && defined(BUTTON_PRESSED)
|
||||
rcc_periph_clock_enable(GPIO_RCC(BUTTON_PIN)); // enable clock for button
|
||||
gpio_set_mode(GPIO_PORT(BUTTON_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(BUTTON_PIN)); // set button pin to input
|
||||
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
|
||||
exti_select_source(GPIO_EXTI(BUTTON_PIN), GPIO_PORT(BUTTON_PIN)); // mask external interrupt of this pin only for this port
|
||||
#if defined(BUTTON_PRESSED) && BUTTON_PRESSED
|
||||
gpio_clear(GPIO_PORT(BUTTON_PIN), GPIO_PIN(BUTTON_PIN)); // pull down to be able to detect button push (go high)
|
||||
#if BUTTON_PRESSED // level goes high when pressed
|
||||
gpio_mode_setup(GPIO_PORT(BUTTON_PIN), GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN(BUTTON_PIN)); // set GPIO to input and pull down
|
||||
exti_set_trigger(GPIO_EXTI(BUTTON_PIN), EXTI_TRIGGER_RISING); // trigger when button is pressed
|
||||
#else
|
||||
gpio_set(GPIO_PORT(BUTTON_PIN), GPIO_PIN(BUTTON_PIN)); // pull up to be able to detect button push (go low)
|
||||
#else // level goes low when pressed
|
||||
gpio_mode_setup(GPIO_PORT(BUTTON_PIN), GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN(BUTTON_PIN)); // set GPIO to input and pull up
|
||||
exti_set_trigger(GPIO_EXTI(BUTTON_PIN), EXTI_TRIGGER_FALLING); // trigger when button is pressed
|
||||
#endif
|
||||
exti_enable_request(GPIO_EXTI(BUTTON_PIN)); // enable external interrupt
|
||||
nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(BUTTON_PIN)); // enable interrupt
|
||||
#endif
|
||||
*/
|
||||
|
||||
// reset user input buffer
|
||||
user_input_available = false;
|
||||
@ -283,6 +283,66 @@ void board_setup(void)
|
||||
user_input_used = 0;
|
||||
}
|
||||
|
||||
/** disconnect USB by sending a reset condition */
|
||||
static void usb_disconnect(void)
|
||||
{
|
||||
if (OTG_FS_GUSBCFG & OTG_GUSBCFG_FDMOD) { // USB configured as device
|
||||
// pull USB D+ low for a short while
|
||||
OTG_FS_DCTL |= OTG_DCTL_SDIS; // disconnect DP pull-up to simulate a disconnect
|
||||
// in case there is an external pull-up resistor, pull DP low
|
||||
// I have no idea why, but once USB is configured, I can't use PA12/DP back as GPIO
|
||||
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO12); // be sure the D+ pin can be used as GPIO output
|
||||
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO12); // use push-pull output
|
||||
gpio_clear(GPIOA, GPIO12); // pull D+ low
|
||||
for (volatile uint32_t i = 0; i < 0x2000; i++); // USB disconnected must be at least 10 ms long, at most 100 ms
|
||||
}
|
||||
}
|
||||
|
||||
void system_memory(void)
|
||||
{
|
||||
usb_disconnect(); // disconnect from USB (if necessary)
|
||||
|
||||
// for more details, see https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/
|
||||
|
||||
// deinit RCC (according to STM32CubeF4 source code)
|
||||
RCC_CR |= RCC_CR_HSION; // enable high speed internal clock
|
||||
while (!(RCC_CR & RCC_CR_HSIRDY)); // wait until clock is ready
|
||||
RCC_CR |= (0x10U << RCC_CR_HSITRIM_SHIFT); // set HSITRIM[4:0] bits to the reset value
|
||||
RCC_CFGR = 0;// reset CFGR register
|
||||
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_HSI); // wait it till clock switch is ready
|
||||
RCC_CR &= ~(RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON); // clear HSEON, HSEBYP and CSSON bits
|
||||
while (RCC_CR & RCC_CR_HSERDY); // wait till HSE is disabled
|
||||
RCC_CR &= ~RCC_CR_PLLON; // Clear PLLON bit
|
||||
while (RCC_CR & RCC_CR_PLLRDY); // wait till PLL is disabled
|
||||
//RCC_PLLCFGR = 0x24003010; // reset PLLCFGR register to default value (value for STM32F401)
|
||||
RCC_CIR &= ~(RCC_CIR_LSIRDYIE | RCC_CIR_LSERDYIE | RCC_CIR_HSIRDYIE | RCC_CIR_HSERDYIE | RCC_CIR_PLLRDYIE); // disable all interrupts
|
||||
RCC_CIR |= (RCC_CIR_LSIRDYC | RCC_CIR_LSERDYC | RCC_CIR_HSIRDYC | RCC_CIR_HSERDYC | RCC_CIR_PLLRDYC | RCC_CIR_CSSC); // clear all interrupt flags
|
||||
RCC_CR &= ~RCC_CSR_LSION; // clear LSION bit
|
||||
RCC_CSR |= RCC_CSR_RMVF; // reset all CSR flags
|
||||
|
||||
// switch to system memory
|
||||
RCC_APB2ENR = RCC_APB2ENR_SYSCFGEN; // enable system configure clock (all others are not required)
|
||||
cm_disable_interrupts(); // disable all interrupts
|
||||
SYSCFG_MEMRM = 1; // map system memory to 0x0000 0000 (this bypasses the BOOT0 pin)
|
||||
const uint32_t address = 0x1FFF0000; // system memory address
|
||||