summaryrefslogtreecommitdiff
path: root/gm_platform/fw
diff options
context:
space:
mode:
authorjaseg <git@jaseg.net>2020-01-23 14:38:36 +0100
committerjaseg <git@jaseg.net>2020-01-23 14:38:36 +0100
commit410e38651052038e34843b17269d61e75720f0ba (patch)
tree987d1853c55b152d5e1362af4420fa52fcd56a81 /gm_platform/fw
parent6a49b8399fb156d427b5d15746de877ac933ba3d (diff)
downloadmaster-thesis-410e38651052038e34843b17269d61e75720f0ba.tar.gz
master-thesis-410e38651052038e34843b17269d61e75720f0ba.tar.bz2
master-thesis-410e38651052038e34843b17269d61e75720f0ba.zip
board bringup: adc, usart working
Diffstat (limited to 'gm_platform/fw')
-rw-r--r--gm_platform/fw/Makefile111
-rw-r--r--gm_platform/fw/Scope.ipynb906
-rw-r--r--gm_platform/fw/adc.c125
-rw-r--r--gm_platform/fw/adc.h28
-rw-r--r--gm_platform/fw/base.c25
-rw-r--r--gm_platform/fw/cmsis_exports.c48
-rw-r--r--gm_platform/fw/cobs.c293
-rw-r--r--gm_platform/fw/cobs.h23
-rw-r--r--gm_platform/fw/global.h52
-rwxr-xr-xgm_platform/fw/main.binbin0 -> 6552 bytes
-rw-r--r--gm_platform/fw/main.c175
-rw-r--r--gm_platform/fw/main.c.bak162
-rwxr-xr-xgm_platform/fw/main.elfbin0 -> 180992 bytes
-rw-r--r--gm_platform/fw/main.hex414
-rw-r--r--gm_platform/fw/main.lst4459
-rw-r--r--gm_platform/fw/main.map457
-rw-r--r--gm_platform/fw/openocd.cfg17
-rw-r--r--gm_platform/fw/packet_interface.c46
-rw-r--r--gm_platform/fw/packet_interface.h6
-rw-r--r--gm_platform/fw/scope.gdb12
-rw-r--r--gm_platform/fw/serial.c139
-rw-r--r--gm_platform/fw/serial.h44
-rw-r--r--gm_platform/fw/startup_stm32f030x6.s273
-rw-r--r--gm_platform/fw/stm32_flash.ld136
-rw-r--r--gm_platform/fw/system_stm32f0xx.c336
-rw-r--r--gm_platform/fw/tools/gen_cmsis_exports.py30
26 files changed, 8317 insertions, 0 deletions
diff --git a/gm_platform/fw/Makefile b/gm_platform/fw/Makefile
new file mode 100644
index 0000000..ea874eb
--- /dev/null
+++ b/gm_platform/fw/Makefile
@@ -0,0 +1,111 @@
+# Megumin LED display firmware
+# Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+CUBE_PATH ?= $(wildcard ~)/resource/STM32CubeF0
+CMSIS_PATH ?= $(CUBE_PATH)/Drivers/CMSIS
+CMSIS_DEV_PATH ?= $(CMSIS_PATH)/Device/ST/STM32F0xx
+HAL_PATH ?= $(CUBE_PATH)/Drivers/STM32F0xx_HAL_Driver
+
+MAC_ADDR ?= 0xdeadbeef
+
+CC := arm-none-eabi-gcc
+LD := arm-none-eabi-ld
+OBJCOPY := arm-none-eabi-objcopy
+OBJDUMP := arm-none-eabi-objdump
+SIZE := arm-none-eabi-size
+
+CFLAGS = -g -Wall -Wextra -std=gnu11 -O0 -fdump-rtl-expand
+CFLAGS += -mlittle-endian -mcpu=cortex-m0 -march=armv6-m -mthumb
+#CFLAGS += -ffunction-sections -fdata-sections
+LDFLAGS = -nostartfiles
+#LDFLAGS += -specs=rdimon.specs -DSEMIHOSTING
+LDFLAGS += -Wl,-Map=main.map -nostdlib
+#LDFLAGS += -Wl,--gc-sections
+LIBS = -lgcc
+#LIBS += -lrdimon
+
+# Technically we're using an STM32F030F4, but apart from the TSSOP20 package that one is largely identical to the
+# STM32F030*6 and there is no separate device header provided for it, so we're faking a *6 device here. This is
+# even documented in stm32f0xx.h. Thanks ST!
+CFLAGS += -DSTM32F030x6 -DHSE_VALUE=8000000
+
+LDFLAGS += -Tstm32_flash.ld
+CFLAGS += -I$(CMSIS_DEV_PATH)/Include -I$(CMSIS_PATH)/Include -I$(HAL_PATH)/Inc -Iconfig -Wno-unused -I../common
+LDFLAGS += -L$(CMSIS_PATH)/Lib/GCC -larm_cortexM0l_math
+
+###################################################
+
+.PHONY: program clean
+
+all: main.elf
+
+.clang:
+ echo flags = $(CFLAGS) > .clang
+
+cmsis_exports.c: $(CMSIS_DEV_PATH)/Include/stm32f030x6.h $(CMSIS_PATH)/Include/core_cm0.h
+ python3 tools/gen_cmsis_exports.py $^ > $@
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) -o $@ $^
+# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^
+
+%.o: %.s
+ $(CC) -c $(CFLAGS) -o $@ $^
+# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^
+
+%.dot: %.elf
+ r2 -a arm -qc 'aa;agC' $< 2>/dev/null >$@
+
+sources.tar.xz: main.c Makefile
+ tar -caf $@ $^
+
+# don't ask...
+sources.tar.xz.zip: sources.tar.xz
+ zip $@ $^
+
+sources.c: sources.tar.xz.zip
+ xxd -i $< | head -n -1 | sed 's/=/__attribute__((section(".source_tarball"))) =/' > $@
+
+main.elf: main.c adc.c serial.c cobs.c startup_stm32f030x6.s system_stm32f0xx.c $(HAL_PATH)/Src/stm32f0xx_ll_utils.c base.c cmsis_exports.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(OBJCOPY) -O ihex $@ $(@:.elf=.hex)
+ $(OBJCOPY) -O binary $@ $(@:.elf=.bin)
+ $(OBJDUMP) -St $@ >$(@:.elf=.lst)
+ $(SIZE) $@
+
+program: main.elf openocd.cfg
+ openocd -f openocd.cfg -c "program $< verify reset exit"
+
+8b10b_test_encode: 8b10b_test_encode.c 8b10b.c
+ gcc -o $@ $^
+
+8b10b_test_decode: 8b10b_test_decode.c 8b10b.c
+ gcc -o $@ $^
+
+protocol_test: protocol.c protocol_test.c
+ gcc -o $@ -O0 -Wall -Wextra -g -I../common $^
+
+clean:
+ rm -f **.o
+ rm -f main.elf main.hex main.bin main.map main.lst
+ rm -f **.expand
+ rm -f cmsis_exports.c
+ rm -f sources.tar.xz
+ rm -f sources.tar.xz.zip
+ rm -f sources.c
+ rm -f *.dot
+ rm -f protocol_test
+
diff --git a/gm_platform/fw/Scope.ipynb b/gm_platform/fw/Scope.ipynb
new file mode 100644
index 0000000..1022e56
--- /dev/null
+++ b/gm_platform/fw/Scope.ipynb
@@ -0,0 +1,906 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from matplotlib import pyplot as plt\n",
+ "%matplotlib notebook\n",
+ "import numpy as np\n",
+ "import struct\n",
+ "import math"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def plot_data(offx=0, end=-1, signed=False, channels=1):\n",
+ " with open('/tmp/scope_dump.bin', 'rb') as f:\n",
+ " raw_data = f.read()\n",
+ " data = struct.unpack(f'<{len(raw_data)//2}{\"h\" if signed else \"H\"}', raw_data)\n",
+ " \n",
+ " fig, axs = plt.subplots(channels*2, 1, squeeze=False, sharex=True, figsize=(10, 5))\n",
+ " axs = axs.flatten()\n",
+ " for i, (ax_t, ax_f) in enumerate(zip(axs[0::2], axs[1::2])):\n",
+ " le_slice = data[offx:][:end][i::channels]\n",
+ " ax_t.plot(np.linspace(0, len(le_slice)/1000, len(le_slice)),\n",
+ " [math.nan if x==-255 else x for x in le_slice])\n",
+ " ax_t.grid() \n",
+ " \n",
+ " ax_f.specgram(le_slice, Fs=1000)\n",
+ " ax_f.grid()\n",
+ " \n",
+ " return data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "/* Put everything inside the global mpl namespace */\n",
+ "window.mpl = {};\n",
+ "\n",
+ "\n",
+ "mpl.get_websocket_type = function() {\n",
+ " if (typeof(WebSocket) !== 'undefined') {\n",
+ " return WebSocket;\n",
+ " } else if (typeof(MozWebSocket) !== 'undefined') {\n",
+ " return MozWebSocket;\n",
+ " } else {\n",
+ " alert('Your browser does not have WebSocket support.' +\n",
+ " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
+ " 'Firefox 4 and 5 are also supported but you ' +\n",
+ " 'have to enable WebSockets in about:config.');\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
+ " this.id = figure_id;\n",
+ "\n",
+ " this.ws = websocket;\n",
+ "\n",
+ " this.supports_binary = (this.ws.binaryType != undefined);\n",
+ "\n",
+ " if (!this.supports_binary) {\n",
+ " var warnings = document.getElementById(\"mpl-warnings\");\n",
+ " if (warnings) {\n",
+ " warnings.style.display = 'block';\n",
+ " warnings.textContent = (\n",
+ " \"This browser does not support binary websocket messages. \" +\n",
+ " \"Performance may be slow.\");\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " this.imageObj = new Image();\n",
+ "\n",
+ " this.context = undefined;\n",
+ " this.message = undefined;\n",
+ " this.canvas = undefined;\n",
+ " this.rubberband_canvas = undefined;\n",
+ " this.rubberband_context = undefined;\n",
+ " this.format_dropdown = undefined;\n",
+ "\n",
+ " this.image_mode = 'full';\n",
+ "\n",
+ " this.root = $('<div/>');\n",
+ " this._root_extra_style(this.root)\n",
+ " this.root.attr('style', 'display: inline-block');\n",
+ "\n",
+ " $(parent_element).append(this.root);\n",
+ "\n",
+ " this._init_header(this);\n",
+ " this._init_canvas(this);\n",
+ " this._init_toolbar(this);\n",
+ "\n",
+ " var fig = this;\n",
+ "\n",
+ " this.waiting = false;\n",
+ "\n",
+ " this.ws.onopen = function () {\n",
+ " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
+ " fig.send_message(\"send_image_mode\", {});\n",
+ " if (mpl.ratio != 1) {\n",
+ " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
+ " }\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " }\n",
+ "\n",
+ " this.imageObj.onload = function() {\n",
+ " if (fig.image_mode == 'full') {\n",
+ " // Full images could contain transparency (where diff images\n",
+ " // almost always do), so we need to clear the canvas so that\n",
+ " // there is no ghosting.\n",
+ " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
+ " }\n",
+ " fig.context.drawImage(fig.imageObj, 0, 0);\n",
+ " };\n",
+ "\n",
+ " this.imageObj.onunload = function() {\n",
+ " fig.ws.close();\n",
+ " }\n",
+ "\n",
+ " this.ws.onmessage = this._make_on_message_function(this);\n",
+ "\n",
+ " this.ondownload = ondownload;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_header = function() {\n",
+ " var titlebar = $(\n",
+ " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
+ " 'ui-helper-clearfix\"/>');\n",
+ " var titletext = $(\n",
+ " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
+ " 'text-align: center; padding: 3px;\"/>');\n",
+ " titlebar.append(titletext)\n",
+ " this.root.append(titlebar);\n",
+ " this.header = titletext[0];\n",
+ "}\n",
+ "\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_canvas = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var canvas_div = $('<div/>');\n",
+ "\n",
+ " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
+ "\n",
+ " function canvas_keyboard_event(event) {\n",
+ " return fig.key_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " canvas_div.keydown('key_press', canvas_keyboard_event);\n",
+ " canvas_div.keyup('key_release', canvas_keyboard_event);\n",
+ " this.canvas_div = canvas_div\n",
+ " this._canvas_extra_style(canvas_div)\n",
+ " this.root.append(canvas_div);\n",
+ "\n",
+ " var canvas = $('<canvas/>');\n",
+ " canvas.addClass('mpl-canvas');\n",
+ " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
+ "\n",
+ " this.canvas = canvas[0];\n",
+ " this.context = canvas[0].getContext(\"2d\");\n",
+ "\n",
+ " var backingStore = this.context.backingStorePixelRatio ||\n",
+ "\tthis.context.webkitBackingStorePixelRatio ||\n",
+ "\tthis.context.mozBackingStorePixelRatio ||\n",
+ "\tthis.context.msBackingStorePixelRatio ||\n",
+ "\tthis.context.oBackingStorePixelRatio ||\n",
+ "\tthis.context.backingStorePixelRatio || 1;\n",
+ "\n",
+ " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
+ "\n",
+ " var rubberband = $('<canvas/>');\n",
+ " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
+ "\n",
+ " var pass_mouse_events = true;\n",
+ "\n",
+ " canvas_div.resizable({\n",
+ " start: function(event, ui) {\n",
+ " pass_mouse_events = false;\n",
+ " },\n",
+ " resize: function(event, ui) {\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " stop: function(event, ui) {\n",
+ " pass_mouse_events = true;\n",
+ " fig.request_resize(ui.size.width, ui.size.height);\n",
+ " },\n",
+ " });\n",
+ "\n",
+ " function mouse_event_fn(event) {\n",
+ " if (pass_mouse_events)\n",
+ " return fig.mouse_event(event, event['data']);\n",
+ " }\n",
+ "\n",
+ " rubberband.mousedown('button_press', mouse_event_fn);\n",
+ " rubberband.mouseup('button_release', mouse_event_fn);\n",
+ " // Throttle sequential mouse events to 1 every 20ms.\n",
+ " rubberband.mousemove('motion_notify', mouse_event_fn);\n",
+ "\n",
+ " rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
+ " rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
+ "\n",
+ " canvas_div.on(\"wheel\", function (event) {\n",
+ " event = event.originalEvent;\n",
+ " event['data'] = 'scroll'\n",
+ " if (event.deltaY < 0) {\n",
+ " event.step = 1;\n",
+ " } else {\n",
+ " event.step = -1;\n",
+ " }\n",
+ " mouse_event_fn(event);\n",
+ " });\n",
+ "\n",
+ " canvas_div.append(canvas);\n",
+ " canvas_div.append(rubberband);\n",
+ "\n",
+ " this.rubberband = rubberband;\n",
+ " this.rubberband_canvas = rubberband[0];\n",
+ " this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
+ " this.rubberband_context.strokeStyle = \"#000000\";\n",
+ "\n",
+ " this._resize_canvas = function(width, height) {\n",
+ " // Keep the size of the canvas, canvas container, and rubber band\n",
+ " // canvas in synch.\n",
+ " canvas_div.css('width', width)\n",
+ " canvas_div.css('height', height)\n",
+ "\n",
+ " canvas.attr('width', width * mpl.ratio);\n",
+ " canvas.attr('height', height * mpl.ratio);\n",
+ " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
+ "\n",
+ " rubberband.attr('width', width);\n",
+ " rubberband.attr('height', height);\n",
+ " }\n",
+ "\n",
+ " // Set the figure to an initial 600x600px, this will subsequently be updated\n",
+ " // upon first draw.\n",
+ " this._resize_canvas(600, 600);\n",
+ "\n",
+ " // Disable right mouse context menu.\n",
+ " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
+ " return false;\n",
+ " });\n",
+ "\n",
+ " function set_focus () {\n",
+ " canvas.focus();\n",
+ " canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " window.setTimeout(set_focus, 100);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('<div/>')\n",
+ " nav_element.attr('style', 'width: 100%');\n",
+ " this.root.append(nav_element);\n",
+ "\n",
+ " // Define a callback function for later on.\n",
+ " function toolbar_event(event) {\n",
+ " return fig.toolbar_button_onclick(event['data']);\n",
+ " }\n",
+ " function toolbar_mouse_event(event) {\n",
+ " return fig.toolbar_button_onmouseover(event['data']);\n",
+ " }\n",
+ "\n",
+ " for(var toolbar_ind in mpl.toolbar_items) {\n",
+ " var name = mpl.toolbar_items[toolbar_ind][0];\n",
+ " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
+ " var image = mpl.toolbar_items[toolbar_ind][2];\n",
+ " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
+ "\n",
+ " if (!name) {\n",
+ " // put a spacer in here.\n",
+ " continue;\n",
+ " }\n",
+ " var button = $('<button/>');\n",
+ " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
+ " 'ui-button-icon-only');\n",
+ " button.attr('role', 'button');\n",
+ " button.attr('aria-disabled', 'false');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ "\n",
+ " var icon_img = $('<span/>');\n",
+ " icon_img.addClass('ui-button-icon-primary ui-icon');\n",
+ " icon_img.addClass(image);\n",
+ " icon_img.addClass('ui-corner-all');\n",
+ "\n",
+ " var tooltip_span = $('<span/>');\n",
+ " tooltip_span.addClass('ui-button-text');\n",
+ " tooltip_span.html(tooltip);\n",
+ "\n",
+ " button.append(icon_img);\n",
+ " button.append(tooltip_span);\n",
+ "\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " var fmt_picker_span = $('<span/>');\n",
+ "\n",
+ " var fmt_picker = $('<select/>');\n",
+ " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
+ " fmt_picker_span.append(fmt_picker);\n",
+ " nav_element.append(fmt_picker_span);\n",
+ " this.format_dropdown = fmt_picker[0];\n",
+ "\n",
+ " for (var ind in mpl.extensions) {\n",
+ " var fmt = mpl.extensions[ind];\n",
+ " var option = $(\n",
+ " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
+ " fmt_picker.append(option)\n",
+ " }\n",
+ "\n",
+ " // Add hover states to the ui-buttons\n",
+ " $( \".ui-button\" ).hover(\n",
+ " function() { $(this).addClass(\"ui-state-hover\");},\n",
+ " function() { $(this).removeClass(\"ui-state-hover\");}\n",
+ " );\n",
+ "\n",
+ " var status_bar = $('<span class=\"mpl-message\"/>');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
+ " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
+ " // which will in turn request a refresh of the image.\n",
+ " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_message = function(type, properties) {\n",
+ " properties['type'] = type;\n",
+ " properties['figure_id'] = this.id;\n",
+ " this.ws.send(JSON.stringify(properties));\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.send_draw_message = function() {\n",
+ " if (!this.waiting) {\n",
+ " this.waiting = true;\n",
+ " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " var format_dropdown = fig.format_dropdown;\n",
+ " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
+ " fig.ondownload(fig, format);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
+ " var size = msg['size'];\n",
+ " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
+ " fig._resize_canvas(size[0], size[1]);\n",
+ " fig.send_message(\"refresh\", {});\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
+ " var x0 = msg['x0'] / mpl.ratio;\n",
+ " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
+ " var x1 = msg['x1'] / mpl.ratio;\n",
+ " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
+ " x0 = Math.floor(x0) + 0.5;\n",
+ " y0 = Math.floor(y0) + 0.5;\n",
+ " x1 = Math.floor(x1) + 0.5;\n",
+ " y1 = Math.floor(y1) + 0.5;\n",
+ " var min_x = Math.min(x0, x1);\n",
+ " var min_y = Math.min(y0, y1);\n",
+ " var width = Math.abs(x1 - x0);\n",
+ " var height = Math.abs(y1 - y0);\n",
+ "\n",
+ " fig.rubberband_context.clearRect(\n",
+ " 0, 0, fig.canvas.width, fig.canvas.height);\n",
+ "\n",
+ " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
+ " // Updates the figure title.\n",
+ " fig.header.textContent = msg['label'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
+ " var cursor = msg['cursor'];\n",
+ " switch(cursor)\n",
+ " {\n",
+ " case 0:\n",
+ " cursor = 'pointer';\n",
+ " break;\n",
+ " case 1:\n",
+ " cursor = 'default';\n",
+ " break;\n",
+ " case 2:\n",
+ " cursor = 'crosshair';\n",
+ " break;\n",
+ " case 3:\n",
+ " cursor = 'move';\n",
+ " break;\n",
+ " }\n",
+ " fig.rubberband_canvas.style.cursor = cursor;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
+ " fig.message.textContent = msg['message'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
+ " // Request the server to send over a new figure.\n",
+ " fig.send_draw_message();\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
+ " fig.image_mode = msg['mode'];\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Called whenever the canvas gets updated.\n",
+ " this.send_message(\"ack\", {});\n",
+ "}\n",
+ "\n",
+ "// A function to construct a web socket function for onmessage handling.\n",
+ "// Called in the figure constructor.\n",
+ "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
+ " return function socket_on_message(evt) {\n",
+ " if (evt.data instanceof Blob) {\n",
+ " /* FIXME: We get \"Resource interpreted as Image but\n",
+ " * transferred with MIME type text/plain:\" errors on\n",
+ " * Chrome. But how to set the MIME type? It doesn't seem\n",
+ " * to be part of the websocket stream */\n",
+ " evt.data.type = \"image/png\";\n",
+ "\n",
+ " /* Free the memory for the previous frames */\n",
+ " if (fig.imageObj.src) {\n",
+ " (window.URL || window.webkitURL).revokeObjectURL(\n",
+ " fig.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
+ " evt.data);\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
+ " fig.imageObj.src = evt.data;\n",
+ " fig.updated_canvas_event();\n",
+ " fig.waiting = false;\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var msg = JSON.parse(evt.data);\n",
+ " var msg_type = msg['type'];\n",
+ "\n",
+ " // Call the \"handle_{type}\" callback, which takes\n",
+ " // the figure and JSON message as its only arguments.\n",
+ " try {\n",
+ " var callback = fig[\"handle_\" + msg_type];\n",
+ " } catch (e) {\n",
+ " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " if (callback) {\n",
+ " try {\n",
+ " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
+ " callback(fig, msg);\n",
+ " } catch (e) {\n",
+ " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
+ " }\n",
+ " }\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
+ "mpl.findpos = function(e) {\n",
+ " //this section is from http://www.quirksmode.org/js/events_properties.html\n",
+ " var targ;\n",
+ " if (!e)\n",
+ " e = window.event;\n",
+ " if (e.target)\n",
+ " targ = e.target;\n",
+ " else if (e.srcElement)\n",
+ " targ = e.srcElement;\n",
+ " if (targ.nodeType == 3) // defeat Safari bug\n",
+ " targ = targ.parentNode;\n",
+ "\n",
+ " // jQuery normalizes the pageX and pageY\n",
+ " // pageX,Y are the mouse positions relative to the document\n",
+ " // offset() returns the position of the element relative to the document\n",
+ " var x = e.pageX - $(targ).offset().left;\n",
+ " var y = e.pageY - $(targ).offset().top;\n",
+ "\n",
+ " return {\"x\": x, \"y\": y};\n",
+ "};\n",
+ "\n",
+ "/*\n",
+ " * return a copy of an object with only non-object keys\n",
+ " * we need this to avoid circular references\n",
+ " * http://stackoverflow.com/a/24161582/3208463\n",
+ " */\n",
+ "function simpleKeys (original) {\n",
+ " return Object.keys(original).reduce(function (obj, key) {\n",
+ " if (typeof original[key] !== 'object')\n",
+ " obj[key] = original[key]\n",
+ " return obj;\n",
+ " }, {});\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.mouse_event = function(event, name) {\n",
+ " var canvas_pos = mpl.findpos(event)\n",
+ "\n",
+ " if (name === 'button_press')\n",
+ " {\n",
+ " this.canvas.focus();\n",
+ " this.canvas_div.focus();\n",
+ " }\n",
+ "\n",
+ " var x = canvas_pos.x * mpl.ratio;\n",
+ " var y = canvas_pos.y * mpl.ratio;\n",
+ "\n",
+ " this.send_message(name, {x: x, y: y, button: event.button,\n",
+ " step: event.step,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ "\n",
+ " /* This prevents the web browser from automatically changing to\n",
+ " * the text insertion cursor when the button is pressed. We want\n",
+ " * to control all of the cursor setting manually through the\n",
+ " * 'cursor' event from matplotlib */\n",
+ " event.preventDefault();\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " // Handle any extra behaviour associated with a key event\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.key_event = function(event, name) {\n",
+ "\n",
+ " // Prevent repeat events\n",
+ " if (name == 'key_press')\n",
+ " {\n",
+ " if (event.which === this._key)\n",
+ " return;\n",
+ " else\n",
+ " this._key = event.which;\n",
+ " }\n",
+ " if (name == 'key_release')\n",
+ " this._key = null;\n",
+ "\n",
+ " var value = '';\n",
+ " if (event.ctrlKey && event.which != 17)\n",
+ " value += \"ctrl+\";\n",
+ " if (event.altKey && event.which != 18)\n",
+ " value += \"alt+\";\n",
+ " if (event.shiftKey && event.which != 16)\n",
+ " value += \"shift+\";\n",
+ "\n",
+ " value += 'k';\n",
+ " value += event.which.toString();\n",
+ "\n",
+ " this._key_event_extra(event, name);\n",
+ "\n",
+ " this.send_message(name, {key: value,\n",
+ " guiEvent: simpleKeys(event)});\n",
+ " return false;\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
+ " if (name == 'download') {\n",
+ " this.handle_save(this, null);\n",
+ " } else {\n",
+ " this.send_message(\"toolbar_button\", {name: name});\n",
+ " }\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
+ " this.message.textContent = tooltip;\n",
+ "};\n",
+ "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
+ "\n",
+ "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
+ "\n",
+ "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
+ " // Create a \"websocket\"-like object which calls the given IPython comm\n",
+ " // object with the appropriate methods. Currently this is a non binary\n",
+ " // socket, so there is still some room for performance tuning.\n",
+ " var ws = {};\n",
+ "\n",
+ " ws.close = function() {\n",
+ " comm.close()\n",
+ " };\n",
+ " ws.send = function(m) {\n",
+ " //console.log('sending', m);\n",
+ " comm.send(m);\n",
+ " };\n",
+ " // Register the callback with on_msg.\n",
+ " comm.on_msg(function(msg) {\n",
+ " //console.log('receiving', msg['content']['data'], msg);\n",
+ " // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
+ " ws.onmessage(msg['content']['data'])\n",
+ " });\n",
+ " return ws;\n",
+ "}\n",
+ "\n",
+ "mpl.mpl_figure_comm = function(comm, msg) {\n",
+ " // This is the function which gets called when the mpl process\n",
+ " // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
+ "\n",
+ " var id = msg.content.data.id;\n",
+ " // Get hold of the div created by the display call when the Comm\n",
+ " // socket was opened in Python.\n",
+ " var element = $(\"#\" + id);\n",
+ " var ws_proxy = comm_websocket_adapter(comm)\n",
+ "\n",
+ " function ondownload(figure, format) {\n",
+ " window.open(figure.imageObj.src);\n",
+ " }\n",
+ "\n",
+ " var fig = new mpl.figure(id, ws_proxy,\n",
+ " ondownload,\n",
+ " element.get(0));\n",
+ "\n",
+ " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
+ " // web socket which is closed, not our websocket->open comm proxy.\n",
+ " ws_proxy.onopen();\n",
+ "\n",
+ " fig.parent_element = element.get(0);\n",
+ " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
+ " if (!fig.cell_info) {\n",
+ " console.error(\"Failed to find cell for figure\", id, fig);\n",
+ " return;\n",
+ " }\n",
+ "\n",
+ " var output_index = fig.cell_info[2]\n",
+ " var cell = fig.cell_info[0];\n",
+ "\n",
+ "};\n",
+ "\n",
+ "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
+ " var width = fig.canvas.width/mpl.ratio\n",
+ " fig.root.unbind('remove')\n",
+ "\n",
+ " // Update the output cell to use the data from the current canvas.\n",
+ " fig.push_to_output();\n",
+ " var dataURL = fig.canvas.toDataURL();\n",
+ " // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
+ " // the notebook keyboard shortcuts fail.\n",
+ " IPython.keyboard_manager.enable()\n",
+ " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
+ " fig.close_ws(fig, msg);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.close_ws = function(fig, msg){\n",
+ " fig.send_message('closing', msg);\n",
+ " // fig.ws.close()\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
+ " // Turn the data on the canvas into data in the output cell.\n",
+ " var width = this.canvas.width/mpl.ratio\n",
+ " var dataURL = this.canvas.toDataURL();\n",
+ " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.updated_canvas_event = function() {\n",
+ " // Tell IPython that the notebook contents must change.\n",
+ " IPython.notebook.set_dirty(true);\n",
+ " this.send_message(\"ack\", {});\n",
+ " var fig = this;\n",
+ " // Wait a second, then push the new image to the DOM so\n",
+ " // that it is saved nicely (might be nice to debounce this).\n",
+ " setTimeout(function () { fig.push_to_output() }, 1000);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._init_toolbar = function() {\n",
+ " var fig = this;\n",
+ "\n",
+ " var nav_element = $('<div/>')\n",
+ " nav_element.attr('style', 'width: 100%');\n",
+ " this.root.append(nav_element);\n",
+ "\n",
+ " // Define a callback function for later on.\n",
+ " function toolbar_event(event) {\n",
+ " return fig.toolbar_button_onclick(event['data']);\n",
+ " }\n",
+ " function toolbar_mouse_event(event) {\n",
+ " return fig.toolbar_button_onmouseover(event['data']);\n",
+ " }\n",
+ "\n",
+ " for(var toolbar_ind in mpl.toolbar_items){\n",
+ " var name = mpl.toolbar_items[toolbar_ind][0];\n",
+ " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
+ " var image = mpl.toolbar_items[toolbar_ind][2];\n",
+ " var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
+ "\n",
+ " if (!name) { continue; };\n",
+ "\n",
+ " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
+ " button.click(method_name, toolbar_event);\n",
+ " button.mouseover(tooltip, toolbar_mouse_event);\n",
+ " nav_element.append(button);\n",
+ " }\n",
+ "\n",
+ " // Add the status bar.\n",
+ " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
+ " nav_element.append(status_bar);\n",
+ " this.message = status_bar[0];\n",
+ "\n",
+ " // Add the close button to the window.\n",
+ " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
+ " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
+ " button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
+ " button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
+ " buttongrp.append(button);\n",
+ " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
+ " titlebar.prepend(buttongrp);\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._root_extra_style = function(el){\n",
+ " var fig = this\n",
+ " el.on(\"remove\", function(){\n",
+ "\tfig.close_ws(fig, {});\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._canvas_extra_style = function(el){\n",
+ " // this is important to make the div 'focusable\n",
+ " el.attr('tabindex', 0)\n",
+ " // reach out to IPython and tell the keyboard manager to turn it's self\n",
+ " // off when our div gets focus\n",
+ "\n",
+ " // location in version 3\n",
+ " if (IPython.notebook.keyboard_manager) {\n",
+ " IPython.notebook.keyboard_manager.register_events(el);\n",
+ " }\n",
+ " else {\n",
+ " // location in version 2\n",
+ " IPython.keyboard_manager.register_events(el);\n",
+ " }\n",
+ "\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
+ " var manager = IPython.notebook.keyboard_manager;\n",
+ " if (!manager)\n",
+ " manager = IPython.keyboard_manager;\n",
+ "\n",
+ " // Check for shift+enter\n",
+ " if (event.shiftKey && event.which == 13) {\n",
+ " this.canvas_div.blur();\n",
+ " event.shiftKey = false;\n",
+ " // Send a \"J\" for go to next cell\n",
+ " event.which = 74;\n",
+ " event.keyCode = 74;\n",
+ " manager.command_mode();\n",
+ " manager.handle_keydown(event);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
+ " fig.ondownload(fig, null);\n",
+ "}\n",
+ "\n",
+ "\n",
+ "mpl.find_output_cell = function(html_output) {\n",
+ " // Return the cell and output element which can be found *uniquely* in the notebook.\n",
+ " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
+ " // IPython event is triggered only after the cells have been serialised, which for\n",
+ " // our purposes (turning an active figure into a static one), is too late.\n",
+ " var cells = IPython.notebook.get_cells();\n",
+ " var ncells = cells.length;\n",
+ " for (var i=0; i<ncells; i++) {\n",
+ " var cell = cells[i];\n",
+ " if (cell.cell_type === 'code'){\n",
+ " for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
+ " var data = cell.output_area.outputs[j];\n",
+ " if (data.data) {\n",
+ " // IPython >= 3 moved mimebundle to data attribute of output\n",
+ " data = data.data;\n",
+ " }\n",
+ " if (data['text/html'] == html_output) {\n",
+ " return [cell, data, j];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Register the function which deals with the matplotlib target/channel.\n",
+ "// The kernel may be null if the page has been refreshed.\n",
+ "if (IPython.notebook.kernel != null) {\n",
+ " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
+ "}\n"
+ ],
+ "text/plain": [
+ "<IPython.core.display.Javascript object>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "<img src=\"data:image/png;base64,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\" width=\"1000\">"
+ ],
+ "text/plain": [
+ "<IPython.core.display.HTML object>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "data = plot_data(offx=4, signed=True, channels=1)\n",
+ "#print(''.join(str(x) for x in data[4:][3::4]))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "ename": "FileNotFoundError",
+ "evalue": "[Errno 2] No such file or directory: '/tmp/foo'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m<ipython-input-32-d8e3fa510bf1>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0mplotdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvals\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mdelta\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0mdelta\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdelta\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplotdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mplot_avg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m<ipython-input-32-d8e3fa510bf1>\u001b[0m in \u001b[0;36mplot_avg\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mplot_avg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'/tmp/foo'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'rb'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mvals\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrombuffer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'uint16'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/tmp/foo'"
+ ]
+ }
+ ],
+ "source": [
+ "import random, struct, numpy as np\n",
+ "\n",
+ "def plot_avg():\n",
+ " with open('/tmp/foo', 'rb') as f:\n",
+ " vals = np.frombuffer(f.read(), dtype='uint16')\n",
+ " \n",
+ " vals = vals.copy()\n",
+ " idx = 1\n",
+ " vals &= 1<<idx\n",
+ " vals >>= idx\n",
+ " \n",
+ " delta = 10000\n",
+ " plotdata = [sum(vals[i:i+delta])/delta for i in range(0, len(vals), delta)]\n",
+ " plt.plot(plotdata)\n",
+ "plot_avg()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.7.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/gm_platform/fw/adc.c b/gm_platform/fw/adc.c
new file mode 100644
index 0000000..547089b
--- /dev/null
+++ b/gm_platform/fw/adc.c
@@ -0,0 +1,125 @@
+/* Megumin LED display firmware
+ * Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "adc.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+volatile uint16_t adc_buf[ADC_BUFSIZE];
+
+static void adc_dma_init(int burstlen);
+static void adc_timer_init(int psc, int ivl);
+
+
+/* Mode that can be used for debugging */
+void adc_configure_scope_mode(int sampling_interval_ns) {
+ adc_dma_init(sizeof(adc_buf)/sizeof(adc_buf[0]));
+
+ /* Clock from PCLK/4 instead of the internal exclusive high-speed RC oscillator. */
+ ADC1->CFGR2 = (2<<ADC_CFGR2_CKMODE_Pos); /* Use PCLK/4=12MHz */
+ /* Sampling time 239.5 ADC clock cycles -> total conversion time 38.5us*/
+ ADC1->SMPR = (7<<ADC_SMPR_SMP_Pos);
+
+ /* Setup DMA and triggering */
+ /* Trigger from TIM1 TRGO */
+ ADC1->CFGR1 = ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | (2<<ADC_CFGR1_EXTEN_Pos) | (1<<ADC_CFGR1_EXTSEL_Pos);
+ ADC1->CHSELR = ADC_CHSELR_CHSEL2;
+ /* Perform self-calibration */
+ ADC1->CR |= ADC_CR_ADCAL;
+ while (ADC1->CR & ADC_CR_ADCAL)
+ ;
+ /* Enable conversion */
+ ADC1->CR |= ADC_CR_ADEN;
+ ADC1->CR |= ADC_CR_ADSTART;
+
+ /* An ADC conversion takes 1.1667us, so to be sure we don't get data overruns we limit sampling to every 1.5us.
+ Since we don't have a spare PLL to generate the ADC sample clock and re-configuring the system clock just for this
+ would be overkill we round to 250ns increments. The minimum sampling rate is about 60Hz due to timer resolution. */
+ int cycles = sampling_interval_ns > 1500 ? sampling_interval_ns/250 : 6;
+ if (cycles > 0xffff)
+ cycles = 0xffff;
+ adc_timer_init(12/*250ns/tick*/, cycles);
+}
+
+/* FIXME figure out the proper place to configure this. */
+#define ADC_TIMER_INTERVAL_US 20
+
+static void adc_dma_init(int burstlen) {
+ /* Configure DMA 1 Channel 1 to get rid of all the data */
+ DMA1_Channel1->CPAR = (unsigned int)&ADC1->DR;
+ DMA1_Channel1->CMAR = (unsigned int)&adc_buf;
+ DMA1_Channel1->CNDTR = burstlen;
+ DMA1_Channel1->CCR = (0<<DMA_CCR_PL_Pos);
+ DMA1_Channel1->CCR |=
+ DMA_CCR_CIRC /* circular mode so we can leave it running indefinitely */
+ | (1<<DMA_CCR_MSIZE_Pos) /* 16 bit */
+ | (1<<DMA_CCR_PSIZE_Pos) /* 16 bit */
+ | DMA_CCR_MINC
+ | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */
+
+ /* triggered on transfer completion. We use this to process the ADC data */
+ NVIC_EnableIRQ(DMA1_Channel1_IRQn);
+ NVIC_SetPriority(DMA1_Channel1_IRQn, 2<<5);
+
+ DMA1_Channel1->CCR |= DMA_CCR_EN; /* Enable channel */
+}
+
+static void adc_timer_init(int psc, int ivl) {
+ TIM1->BDTR = TIM_BDTR_MOE; /* MOE is needed even though we only "output" a chip-internal signal TODO: Verify this. */
+ TIM1->CCMR2 = (6<<TIM_CCMR2_OC4M_Pos); /* PWM Mode 1 to get a clean trigger signal */
+ TIM1->CCER = TIM_CCER_CC4E; /* Enable capture/compare unit 4 connected to ADC */
+ TIM1->CCR4 = 1; /* Trigger at start of timer cycle */
+ /* Set prescaler and interval */
+ TIM1->PSC = psc-1;
+ TIM1->ARR = ivl-1;
+ /* Preload all values */
+ TIM1->EGR |= TIM_EGR_UG;
+ TIM1->CR1 = TIM_CR1_ARPE;
+ /* And... go! */
+ TIM1->CR1 |= TIM_CR1_CEN;
+}
+
+/* This acts as a no-op that provides a convenient point to set a breakpoint for the debug scope logic */
+static void gdb_dump(void) {
+}
+
+void DMA1_Channel1_IRQHandler(void) {
+ /* Clear the interrupt flag */
+ DMA1->IFCR |= DMA_IFCR_CGIF1;
+ gdb_dump();
+
+ /*
+ static int debug_buf_pos = 0;
+ if (st->sync) {
+ if (debug_buf_pos < NCH) {
+ debug_buf_pos = NCH;
+ } else {
+ adc_buf[debug_buf_pos++] = symbol;
+
+ if (debug_buf_pos >= sizeof(adc_buf)/sizeof(adc_buf[0])) {
+ debug_buf_pos = 0;
+ st->sync = 0;
+ gdb_dump();
+ for (int i=0; i<sizeof(adc_buf)/sizeof(adc_buf[0]); i++)
+ adc_buf[i] = -255;
+ }
+ }
+ }
+ */
+}
+
diff --git a/gm_platform/fw/adc.h b/gm_platform/fw/adc.h
new file mode 100644
index 0000000..c526858
--- /dev/null
+++ b/gm_platform/fw/adc.h
@@ -0,0 +1,28 @@
+/* Megumin LED display firmware
+ * Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ADC_H__
+#define __ADC_H__
+
+#include "global.h"
+
+extern volatile uint16_t adc_buf[ADC_BUFSIZE];
+
+void adc_init(void);
+void adc_configure_scope_mode(int sampling_interval_ns);
+
+#endif/*__ADC_H__*/
diff --git a/gm_platform/fw/base.c b/gm_platform/fw/base.c
new file mode 100644
index 0000000..8e7c03b
--- /dev/null
+++ b/gm_platform/fw/base.c
@@ -0,0 +1,25 @@
+
+#include <unistd.h>
+#include <stdbool.h>
+
+int __errno = 0;
+void *_impure_ptr = NULL;
+
+void __sinit(void) {
+}
+
+void *memset(void *s, int c, size_t n) {
+ char *end = (char *)s + n;
+ for (char *p = (char *)s; p < end; p++)
+ *p = (char)c;
+ return s;
+}
+
+size_t strlen(const char *s) {
+ const char *start = s;
+ while (*s++);
+ return s - start - 1;
+}
+
+void __assert_func(bool value) {
+}
diff --git a/gm_platform/fw/cmsis_exports.c b/gm_platform/fw/cmsis_exports.c
new file mode 100644
index 0000000..39874b5
--- /dev/null
+++ b/gm_platform/fw/cmsis_exports.c
@@ -0,0 +1,48 @@
+#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__
+#define __GENERATED_CMSIS_HEADER_EXPORTS__
+
+#include <stm32f030x6.h>
+
+/* stm32f030x6.h */
+TIM_TypeDef *tim3 = TIM3;
+TIM_TypeDef *tim14 = TIM14;
+RTC_TypeDef *rtc = RTC;
+WWDG_TypeDef *wwdg = WWDG;
+IWDG_TypeDef *iwdg = IWDG;
+I2C_TypeDef *i2c1 = I2C1;
+PWR_TypeDef *pwr = PWR;
+SYSCFG_TypeDef *syscfg = SYSCFG;
+EXTI_TypeDef *exti = EXTI;
+ADC_TypeDef *adc1 = ADC1;
+ADC_Common_TypeDef *adc1_common = ADC1_COMMON;
+ADC_Common_TypeDef *adc = ADC;
+TIM_TypeDef *tim1 = TIM1;
+SPI_TypeDef *spi1 = SPI1;
+USART_TypeDef *usart1 = USART1;
+TIM_TypeDef *tim16 = TIM16;
+TIM_TypeDef *tim17 = TIM17;
+DBGMCU_TypeDef *dbgmcu = DBGMCU;
+DMA_TypeDef *dma1 = DMA1;
+DMA_Channel_TypeDef *dma1_channel1 = DMA1_Channel1;
+DMA_Channel_TypeDef *dma1_channel2 = DMA1_Channel2;
+DMA_Channel_TypeDef *dma1_channel3 = DMA1_Channel3;
+DMA_Channel_TypeDef *dma1_channel4 = DMA1_Channel4;
+DMA_Channel_TypeDef *dma1_channel5 = DMA1_Channel5;
+FLASH_TypeDef *flash = FLASH;
+OB_TypeDef *ob = OB;
+RCC_TypeDef *rcc = RCC;
+CRC_TypeDef *crc = CRC;
+GPIO_TypeDef *gpioa = GPIOA;
+GPIO_TypeDef *gpiob = GPIOB;
+GPIO_TypeDef *gpioc = GPIOC;
+GPIO_TypeDef *gpiod = GPIOD;
+GPIO_TypeDef *gpiof = GPIOF;
+
+#include <core_cm0.h>
+
+/* core_cm0.h */
+SCB_Type *scb = SCB;
+SysTick_Type *systick = SysTick;
+NVIC_Type *nvic = NVIC;
+
+#endif//__GENERATED_CMSIS_HEADER_EXPORTS__
diff --git a/gm_platform/fw/cobs.c b/gm_platform/fw/cobs.c
new file mode 100644
index 0000000..22dcac0
--- /dev/null
+++ b/gm_platform/fw/cobs.c
@@ -0,0 +1,293 @@
+
+#include "serial.h"
+#include "cobs.h"
+
+/*@ requires \valid(dst + (0..dstlen-1));
+ @ requires \valid_read(src + (0..srclen-1));
+ @ requires \separated(dst + (0..dstlen-1), src + (0..srclen-1));
+ @
+ @ behavior valid:
+ @ assumes 0 <= srclen <= 254;
+ @ assumes 0 <= dstlen <= 65535;
+ @ assumes dstlen >= srclen+2;
+ @ assigns dst[0..srclen+1];
+ @ ensures \forall integer i; (0 <= i < srclen && \old(src[i]) != 0) ==> dst[i+1] == src[i];
+ @ ensures \result == srclen+2;
+ @ ensures \forall integer i; 0 <= i <= srclen ==> dst[i] != 0;
+ @ ensures dst[srclen+1] == 0;
+ @
+ @ behavior invalid:
+ @ assumes srclen < 0 || srclen > 254
+ @ || dstlen < 0 || dstlen > 65535
+ @ || dstlen < srclen+2;
+ @ assigns \nothing;
+ @ ensures \result == -1;
+ @
+ @ complete behaviors;
+ @ disjoint behaviors;
+ @*/
+ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen) {
+ if (dstlen > 65535 || srclen > 254)
+ return -1;
+ //@ assert 0 <= dstlen <= 65535 && 0 <= srclen <= 254;
+
+ if (dstlen < srclen+2)
+ return -1;
+ //@ assert 0 <= srclen < srclen+2 <= dstlen;
+
+ size_t p = 0;
+ /*@ loop invariant 0 <= p <= srclen+1;
+ @ loop invariant \forall integer i; 0 <= i < p ==> dst[i] != 0;
+ @ loop invariant \forall integer i; 0 < i < p ==> (src[i-1] != 0 ==> dst[i] == src[i-1]);
+ @ loop assigns p, dst[0..srclen+1];
+ @ loop variant srclen-p+1;
+ @*/
+ while (p <= srclen) {
+
+ char val;
+ if (p != 0 && src[p-1] != 0) {
+ val = src[p-1];
+
+ } else {
+ size_t q = p;
+ /*@ loop invariant 0 <= p <= q <= srclen;
+ @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0;
+ @ loop assigns q;
+ @ loop variant srclen-q;
+ @*/
+ while (q < srclen && src[q] != 0)
+ q++;
+ //@ assert q == srclen || src[q] == 0;
+ //@ assert q <= srclen <= 254;
+ val = (char)q-p+1;
+ //@ assert val != 0;
+ }
+
+ dst[p] = val;
+ p++;
+ }
+
+ dst[p] = 0;
+ //@ assert p == srclen+1;
+
+ return srclen+2;
+}
+
+int cobs_encode_usart(char *src, size_t srclen) {
+ if (srclen > 254)
+ return -1;
+ //@ assert 0 <= srclen <= 254;
+
+ size_t p = 0;
+ /*@ loop invariant 0 <= p <= srclen+1;
+ @ loop assigns p;
+ @ loop variant srclen-p+1;
+ @*/
+ while (p <= srclen) {
+
+ char val;
+ if (p != 0 && src[p-1] != 0) {
+ val = src[p-1];
+
+ } else {
+ size_t q = p;
+ /*@ loop invariant 0 <= p <= q <= srclen;
+ @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0;
+ @ loop assigns q;
+ @ loop variant srclen-q;
+ @*/
+ while (q < srclen && src[q] != 0)
+ q++;
+ //@ assert q == srclen || src[q] == 0;
+ //@ assert q <= srclen <= 254;
+ val = (char)q-p+1;
+ //@ assert val != 0;
+ }
+
+ usart_putc(val);
+ p++;
+ }
+
+ usart_putc(0);
+ //@ assert p == srclen+1;
+
+ return 0;
+}
+
+/*@ requires \valid(dst + (0..dstlen-1));
+ @ requires \valid_read(src + (0..srclen-1));
+ @ requires \separated(dst + (0..dstlen-1), src + (0..srclen-1));
+ @
+ @ behavior maybe_valid_frame:
+ @ assumes 1 <= srclen <= dstlen <= 65535;
+ @ assumes \exists integer j; j > 0 && \forall integer i; 0 <= i < j ==> src[i] != 0;
+ @ assumes \exists integer i; 0 <= i < srclen && src[i] == 0;
+ @ assigns dst[0..dstlen-1];
+ @ ensures \result >= 0 || \result == -3;
+ @ ensures \result >= 0 ==> src[\result+1] == 0;
+ @ ensures \result >= 0 ==> (\forall integer i; 0 <= i < \result ==> src[i] != 0);
+ @
+ @ behavior invalid_frame:
+ @ assumes 1 <= srclen <= dstlen <= 65535;
+ @ assumes src[0] == 0 || \forall integer i; 0 <= i < srclen ==> src[i] != 0;
+ @ assigns dst[0..dstlen-1];
+ @ ensures \result == -2;
+ @
+ @ behavior invalid_buffers:
+ @ assumes dstlen < 0 || dstlen > 65535
+ @ || srclen < 1 || srclen > 65535
+ @ || dstlen < srclen;
+ @ assigns \nothing;
+ @ ensures \result == -1;
+ @
+ @ complete behaviors;
+ @ disjoint behaviors;
+ @*/
+ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen) {
+ if (dstlen > 65535 || srclen > 65535)
+ return -1;
+
+ if (srclen < 1)
+ return -1;
+
+ if (dstlen < srclen)
+ return -1;
+
+ size_t p = 1;
+ size_t c = (unsigned char)src[0];
+ //@ assert 0 <= c < 256;
+ //@ assert 0 <= c;
+ //@ assert c < 256;
+ if (c == 0)
+ return -2; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
+ //@ assert c >= 0;
+ //@ assert c != 0;
+ //@ assert c <= 257;
+ //@ assert c > 0;
+ //@ assert c >= 0 && c != 0 ==> c > 0;
+
+ /*@ //loop invariant \forall integer i; 0 <= i <= p ==> (i == srclen || src[i] != 0);
+ @ loop invariant \forall integer i; 1 <= i < p ==> src[i] != 0;
+ @ loop invariant c > 0;
+ @ loop invariant 1 <= p <= srclen <= dstlen <= 65535;
+ @ loop invariant \separated(dst + (0..dstlen-1), src + (0..srclen-1));
+ @ loop invariant \valid_read(src + (0..srclen-1));
+ @ loop invariant \forall integer i; 1 <= i <= srclen ==> \valid(dst + i - 1);
+ @ loop assigns dst[0..dstlen-1], p, c;
+ @ loop variant srclen-p;
+ @*/
+ while (p < srclen && src[p]) {
+ char val;
+ c--;
+
+ //@ assert src[p] != 0;
+ if (c == 0) {
+ c = (unsigned char)src[p];
+ val = 0;
+ } else {
+ val = src[p];
+ }
+
+ //@ assert 0 <= p-1 <= dstlen-1;
+ dst[p-1] = val;
+ p++;
+ }
+
+ if (p == srclen)
+ return -2; /* Invalid framing. The terminating null byte should always be present in the input buffer. */
+
+ if (c != 1)
+ return -3; /* Invalid framing. The skip counter does not hit the end of the frame. */
+
+ //@ assert 0 < p <= srclen <= 65535;
+ //@ assert src[p] == 0;
+ //@ assert \forall integer i; 1 <= i < p ==> src[i] != 0;
+ return p-1;
+}
+
+void cobs_decode_incremental_initialize(struct cobs_decode_state *state) {
+ state->p = 0;
+ state->c = 0;
+}
+
+int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src) {
+ if (state->p == 0) {
+ if (src == 0)
+ goto empty_errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
+ state->c = (unsigned char)src;
+ state->p++;
+ return 0;
+ }
+
+ if (!src) {
+ if (state->c != 1)
+ goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */
+ int rv = state->p-1;
+ cobs_decode_incremental_initialize(state);
+ return rv;
+ }
+
+ char val;
+ state->c--;
+
+ if (state->c == 0) {
+ state->c = (unsigned char)src;
+ val = 0;
+ } else {
+ val = src;
+ }
+
+ size_t pos = state->p-1;
+ if (pos >= dstlen)
+ return -2; /* output buffer too small */
+ dst[pos] = val;
+ state->p++;
+ return 0;
+
+errout:
+ cobs_decode_incremental_initialize(state);
+ return -1;
+
+empty_errout:
+ cobs_decode_incremental_initialize(state);
+ return -3;
+}
+
+#ifdef VALIDATION
+/*@
+ @ requires 0 <= d < 256;
+ @ assigns \nothing;
+ @*/
+size_t test(char foo, unsigned int d) {
+ unsigned int c = (unsigned char)foo;
+ if (c != 0) {
+ //@ assert c < 256;
+ //@ assert c >= 0;
+ //@ assert c != 0;
+ //@ assert c > 0;
+ }
+ if (d != 0) {
+ //@ assert d >= 0;
+ //@ assert d != 0;
+ //@ assert d > 0;
+ }
+ return c + d;
+}
+
+#include <__fc_builtin.h>
+
+void main(void) {
+ char inbuf[254];
+ char cobsbuf[256];
+ char outbuf[256];
+
+ size_t range = Frama_C_interval(0, sizeof(inbuf));
+ Frama_C_make_unknown((char *)inbuf, range);
+
+ cobs_encode(cobsbuf, sizeof(cobsbuf), inbuf, sizeof(inbuf));
+ cobs_decode(outbuf, sizeof(outbuf), cobsbuf, sizeof(cobsbuf));
+
+ //@ assert \forall integer i; 0 <= i < sizeof(inbuf) ==> outbuf[i] == inbuf[i];
+}
+#endif//VALIDATION
+
diff --git a/gm_platform/fw/cobs.h b/gm_platform/fw/cobs.h
new file mode 100644
index 0000000..40f7955
--- /dev/null
+++ b/gm_platform/fw/cobs.h
@@ -0,0 +1,23 @@
+#ifndef __COBS_H__
+#define __COBS_H__
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+
+struct cobs_decode_state {
+ size_t p;
+ size_t c;
+};
+
+
+ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen);
+ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen);
+
+int cobs_encode_usart(char *src, size_t srclen);
+
+void cobs_decode_incremental_initialize(struct cobs_decode_state *state);
+int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src);
+
+#endif//__COBS_H__
diff --git a/gm_platform/fw/global.h b/gm_platform/fw/global.h
new file mode 100644
index 0000000..5fedde7
--- /dev/null
+++ b/gm_platform/fw/global.h
@@ -0,0 +1,52 @@
+/* Megumin LED display firmware
+ * Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GLOBAL_H__
+#define __GLOBAL_H__
+
+/* Workaround for sub-par ST libraries */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#include <stm32f0xx.h>
+#include <stm32f0xx_ll_utils.h>
+#include <stm32f0xx_ll_spi.h>
+#pragma GCC diagnostic pop
+
+#include <system_stm32f0xx.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Microcontroller part number: STM32F030F4P6 */
+
+/* Things used for module status reporting. */
+#define FIRMWARE_VERSION 1
+#define HARDWARE_VERSION 0
+
+#define TS_CAL1 (*(uint16_t *)0x1FFFF7B8)
+#define VREFINT_CAL (*(uint16_t *)0x1FFFF7BA)
+
+#define ADC_BUFSIZE 1024
+
+extern volatile unsigned int sys_time;
+extern volatile unsigned int sys_time_seconds;
+
+#define UNUSED(var) ((void)var)
+
+#endif/*__GLOBAL_H__*/
diff --git a/gm_platform/fw/main.bin b/gm_platform/fw/main.bin
new file mode 100755
index 0000000..e2b0cdc
--- /dev/null
+++ b/gm_platform/fw/main.bin
Binary files differ
diff --git a/gm_platform/fw/main.c b/gm_platform/fw/main.c
new file mode 100644
index 0000000..d2bc33c
--- /dev/null
+++ b/gm_platform/fw/main.c
@@ -0,0 +1,175 @@
+/* Megumin LED display firmware
+ * Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "global.h"
+#include "adc.h"
+#include "serial.h"
+
+
+volatile unsigned int sys_time_seconds = 0;
+
+void update_leds() {
+
+}
+
+volatile union {
+ struct {
+ unsigned int usb, ocxo, error, _nc1, _nc2, _nc3, pps, sd_card;
+ };
+ unsigned int arr[0];
+} leds;
+
+int main(void) {
+ RCC->CR |= RCC_CR_HSEON;
+ while (!(RCC->CR&RCC_CR_HSERDY));
+ RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk;
+ RCC->CFGR |= ((6-2)<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x6 -> 48.0MHz */
+ RCC->CR |= RCC_CR_PLLON;
+ while (!(RCC->CR&RCC_CR_PLLRDY));
+ RCC->CFGR |= (2<<RCC_CFGR_SW_Pos);
+ SystemCoreClockUpdate();
+ SysTick_Config(SystemCoreClock/10); /* 100ms interval */
+ NVIC_EnableIRQ(SysTick_IRQn);
+ NVIC_SetPriority(SysTick_IRQn, 3<<5);
+
+ /* Turn on lots of neat things */
+ RCC->AHBENR |= RCC_AHBENR_DMAEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_FLITFEN;
+ RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_DBGMCUEN |\
+ RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN | RCC_APB2ENR_USART1EN;
+ RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
+
+ GPIOA->MODER |=
+ (3<<GPIO_MODER_MODER2_Pos) /* PA2 - LINE_MEAS */
+ | (1<<GPIO_MODER_MODER3_Pos) /* PA3 - LED_STB */
+ | (1<<GPIO_MODER_MODER4_Pos) /* PA4 - SD_CS */
+ | (2<<GPIO_MODER_MODER5_Pos) /* PA5 - SCK */
+ | (2<<GPIO_MODER_MODER6_Pos) /* PA6 - MISO */
+ | (2<<GPIO_MODER_MODER7_Pos) /* PA7 - MOSI */
+ | (2<<GPIO_MODER_MODER9_Pos) /* PA9 - HOST_RX */
+ | (2<<GPIO_MODER_MODER10_Pos);/* PA10 - HOST_TX */
+
+ /* Set shift register IO GPIO output speed */
+ GPIOA->OSPEEDR |=
+ (2<<GPIO_OSPEEDR_OSPEEDR3_Pos) /* LED_STB */
+ | (2<<GPIO_OSPEEDR_OSPEEDR4_Pos) /* SD_CS */
+ | (2<<GPIO_OSPEEDR_OSPEEDR5_Pos) /* SCK */
+ | (2<<GPIO_OSPEEDR_OSPEEDR7_Pos) /* MOSI */
+ | (2<<GPIO_OSPEEDR_OSPEEDR9_Pos); /* HOST_RX */
+
+ GPIOA->AFR[0] = (0<<GPIO_AFRL_AFRL5_Pos) | (0<<GPIO_AFRL_AFRL6_Pos) | (0<<GPIO_AFRL_AFRL7_Pos);
+ GPIOA->AFR[1] = (1<<8) | (1<<4);
+
+ GPIOB->MODER |=
+ (0<<GPIO_MODER_MODER1_Pos); /* PB0 - LINE_POL */
+
+ SPI1->CR1 =
+ SPI_CR1_SSM
+ | SPI_CR1_SSI
+ | (4<<SPI_CR1_BR_Pos) /* /32 ~1.5MHz */
+ | SPI_CR1_MSTR;
+ SPI1->CR2 = (7<<SPI_CR2_DS_Pos);
+ SPI1->CR1 |= SPI_CR1_SPE;
+
+ NVIC_EnableIRQ(SPI1_IRQn);
+ NVIC_SetPriority(SPI1_IRQn, 2<<5);
+
+ TIM16->CR2 = 0;
+ TIM16->DIER = TIM_DIER_UIE;
+ TIM16->PSC = 48-1; /* 1us */
+ TIM16->ARR = 1000-1; /* 1ms */
+ TIM16->CR1 = TIM_CR1_CEN;
+
+ NVIC_EnableIRQ(TIM16_IRQn);
+ NVIC_SetPriority(TIM16_IRQn, 2<<5);
+
+ adc_configure_scope_mode(1000000);
+
+ usart_dma_init();
+
+ while (42) {
+ char *data = "FOOBAR\n";
+ usart_send_packet((uint8_t*)data, 8);
+ for (int i=0; i<100000; i++);
+ //int pol = GPIOB->IDR & (1<<1); /* Sample current polarity */
+ //leds.error = pol ? 100 : 0;
+ //for (int i=0; i<10000; i++) ;
+ //leds.error = 100;
+ }
+}
+
+void SPI1_IRQHandler(void) {
+ if (SPI1->SR & SPI_SR_TXE) {
+ /* LED_STB */
+ GPIOA->BSRR = 1<<3;
+ SPI1->CR2 &= ~SPI_CR2_TXEIE;
+ }
+}
+
+void TIM16_IRQHandler(void) {
+ static int leds_update_counter = 0;
+ if (TIM16->SR & TIM_SR_UIF) {
+ TIM16->SR &= ~TIM_SR_UIF;
+
+ uint8_t bits = 0, mask = 1;
+ for (size_t i=0; i<sizeof(leds)/sizeof(leds.arr[0]); i++) {
+ if (leds.arr[i]) {
+ leds.arr[i]--;
+ bits |= mask;
+ }
+ mask <<= 1;
+ }
+
+ if (leds_update_counter++ == 10) {
+ leds_update_counter = 0;
+
+ /* Workaround for SPI hardware bug: Even if configured to 8-bit mode, the SPI will do a 16-bit transfer if the
+ * data register is accessed through a 16-bit write. Unfortunately, the STMCube register defs define DR as an
+ * uint16_t, so we have to do some magic here to force an 8-bit write. */
+ *((volatile uint8_t*)&(SPI1->DR)) = bits;
+ SPI1->CR2 |= SPI_CR2_TXEIE;
+ GPIOA->BRR = 1<<3;
+ }
+ }
+}
+
+void NMI_Handler(void) {
+ asm volatile ("bkpt");
+}
+
+void HardFault_Handler(void) __attribute__((naked));
+void HardFault_Handler() {
+ asm volatile ("bkpt");
+}
+
+void SVC_Handler(void) {
+ asm volatile ("bkpt");
+}
+
+
+void PendSV_Handler(void) {
+ asm volatile ("bkpt");
+}
+
+void SysTick_Handler(void) {
+ static int n = 0;
+ if (n++ == 10) {
+ n = 0;
+ sys_time_seconds++;
+ leds.pps = 100; /* ms */
+ }
+}
+
diff --git a/gm_platform/fw/main.c.bak b/gm_platform/fw/main.c.bak
new file mode 100644
index 0000000..07d065d
--- /dev/null
+++ b/gm_platform/fw/main.c.bak
@@ -0,0 +1,162 @@
+/* Megumin LED display firmware
+ * Copyright (C) 2018 Sebastian Götte <code@jaseg.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "global.h"
+
+#include "adc.h"
+
+volatile unsigned int sys_time = 0;
+volatile unsigned int sys_time_seconds = 0;
+
+void TIM1_BRK_UP_TRG_COM_Handler() {
+ TIM1->SR &= ~TIM_SR_UIF_Msk;
+}
+
+int main(void) {
+ RCC->CR |= RCC_CR_HSEON;
+ while (!(RCC->CR&RCC_CR_HSERDY));
+ RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk;
+ RCC->CFGR |= ((6-2)<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x6 -> 48.0MHz */
+ RCC->CR |= RCC_CR_PLLON;
+ while (!(RCC->CR&RCC_CR_PLLRDY));
+ RCC->CFGR |= (2<<RCC_CFGR_SW_Pos);
+ SystemCoreClockUpdate();
+ SysTick_Config(SystemCoreClock/1000); /* 1ms interval */
+
+ /* Turn on lots of neat things */
+ RCC->AHBENR |= RCC_AHBENR_DMAEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_FLITFEN;
+ RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN| RCC_APB2ENR_DBGMCUEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM1EN;;
+ RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
+
+ GPIOA->MODER |=
+ (3<<GPIO_MODER_MODER0_Pos) /* PA0 - Vmeas_A to ADC */
+ | (3<<GPIO_MODER_MODER1_Pos) /* PA1 - Vmeas_B to ADC */
+ | (1<<GPIO_MODER_MODER2_Pos) /* PA2 - LOAD */
+ | (1<<GPIO_MODER_MODER3_Pos) /* PA3 - CH0 */
+ | (1<<GPIO_MODER_MODER4_Pos) /* PA4 - CH3 */
+ | (0<<GPIO_MODER_MODER5_Pos) /* PA5 - TP1 */
+ | (1<<GPIO_MODER_MODER6_Pos) /* PA6 - CH2 */
+ | (1<<GPIO_MODER_MODER7_Pos) /* PA7 - CH1 */
+ | (0<<GPIO_MODER_MODER9_Pos) /* PA9 - TP2 */
+ | (0<<GPIO_MODER_MODER10_Pos);/* PA10 - TP3 */
+
+ /* Set shift register IO GPIO output speed */
+ GPIOA->OSPEEDR |=
+ (2<<GPIO_OSPEEDR_OSPEEDR2_Pos) /* LOAD */
+ | (2<<GPIO_OSPEEDR_OSPEEDR3_Pos) /* CH0 */
+ | (2<<GPIO_OSPEEDR_OSPEEDR4_Pos) /* CH3 */
+ | (2<<GPIO_OSPEEDR_OSPEEDR6_Pos) /* CH2 */
+ | (2<<GPIO_OSPEEDR_OSPEEDR7_Pos); /* CH1 */
+
+ /* Setup CC1 and CC2. CC2 generates the LED drivers' STROBE, CC1 triggers the IRQ handler */
+ TIM1->BDTR = TIM_BDTR_MOE;
+ TIM1->CCMR2 = (6<<TIM_CCMR2_OC4M_Pos); /* PWM Mode 1 */
+ TIM1->CCER = TIM_CCER_CC4E;
+ TIM1->CCR4 = 1;
+ TIM1->DIER = TIM_DIER_UIE;
+
+ TIM1->PSC = SystemCoreClock/500000 - 1; /* 0.5us/tick */
+ TIM1->ARR = 25-1;
+ /* Preload all values */
+ TIM1->EGR |= TIM_EGR_UG;
+ TIM1->CR1 = TIM_CR1_ARPE;
+ /* And... go! */
+ TIM1->CR1 |= TIM_CR1_CEN;
+
+ void set_outputs(uint8_t val) {
+ int a=!!(val&1), b=!!(val&2), c=!!(val&4), d=!!(val&8);
+ GPIOA->ODR &= ~(!a<<3 | !b<<7 | c<<6 | d<<4);
+ GPIOA->ODR |= a<<3 | b<<7 | !c<<6 | !d<<4;
+ }
+ set_outputs(0);
+
+ adc_init();
+
+ uint8_t out_state = 0x01;
+#define DEBOUNCE 100
+ int debounce_ctr = 0;
+ int val_last = 0;
+ int ctr = 0;
+#define RESET 1000
+ int reset_ctr = 0;
+ while (42) {
+#define FOO 500000
+ if (reset_ctr)
+ reset_ctr--;
+ else
+ set_outputs(0);
+
+ if (debounce_ctr) {
+ debounce_ctr--;
+ } else {
+ int val = !!(GPIOA->IDR & 1);
+ debounce_ctr = DEBOUNCE;
+
+ if (val != val_last) {
+ if (val)
+ set_outputs(out_state & 0xf);
+ else
+ set_outputs(out_state >> 4);
+ reset_ctr = RESET;
+ val_last = val;
+ ctr++;
+
+ if (ctr == 100) {
+ ctr = 0;
+ out_state = out_state<<1 | out_state>>7;
+ }
+ }
+ }
+ /*
+ for (int i=0; i<FOO; i++) ;
+ set_outputs(0x1);
+ for (int i=0; i<FOO; i++) ;
+ set_outputs(0x2);
+ for (int i=0; i<FOO; i++) ;
+ set_outputs(0x4);
+ for (int i=0; i<FOO; i++) ;
+ set_outputs(0x8);
+ */
+ //for (int i=0; i<8*FOO; i++) ;
+ //GPIOA->ODR ^= 4;
+ }
+}
+
+void NMI_Handler(void) {
+}
+
+void HardFault_Handler(void) __attribute__((naked));
+void HardFault_Handler() {
+ asm volatile ("bkpt");
+}
+
+void SVC_Handler(void) {
+}
+
+
+void PendSV_Handler(void) {
+}
+
+void SysTick_Handler(void) {
+ static int n = 0;
+ sys_time++;
+ if (n++ == 1000) {
+ n = 0;
+ sys_time_seconds++;
+ }
+}
+
diff --git a/gm_platform/fw/main.elf b/gm_platform/fw/main.elf
new file mode 100755
index 0000000..f23985f
--- /dev/null
+++ b/gm_platform/fw/main.elf
Binary files differ
diff --git a/gm_platform/fw/main.hex b/gm_platform/fw/main.hex
new file mode 100644
index 0000000..c23d980
--- /dev/null
+++ b/gm_platform/fw/main.hex
@@ -0,0 +1,414 @@
+:020000040800F2
+:100000000010002095180008B1040008BD04000885
+:1000100000000000000000000000000000000000E0
+:10002000000000000000000000000000C104000803
+:100030000000000000000000CD040008D904000802
+:10004000E118000800000000E1180008E1180008AD
+:10005000E1180008E1180008E1180008E11800089C
+:1000600000000000930700085D0A0008E11800087E
+:10007000E1180008E1180008E1180008000000007D
+:10008000E11800080000000000000000E11800086E
+:1000900000000000F5030008E1180008E11800085E
+:1000A00000000000C903000800000000E11800087B
+:1000B0000000000000000000000000000000000040
+:1000C00080B582B000AF0200FB1D1A70FB1D1B78CB
+:1000D0001A001F231A40044B012191400A001A60A4
+:1000E000C046BD4602B080BD00E100E090B583B0DF
+:1000F00000AF02003960FB1D1A70FB1D1B787F2BBF
+:1001000032D92F4AFB1D1B7819000F230B40083BE7
+:100110009B0806339B00D31804331B68FA1D127822
+:10012000110003220A40D200FF2191400A00D2436D
+:100130001A4011003B689B01FF221A40FB1D1B78EF
+:10014000180003230340DB009A401D48FB1D1B7869
+:100150001C000F232340083B9B080A4306339B00E7
+:10016000C31804331A6027E0164AFB1D1B785BB2E4
+:100170009B08C0339B009B58FA1D12781100032284
+:100180000A40D200FF2191400A00D2431A401100D8
+:100190003B689B01FF221A40FB1D1B7818000323BC
+:1001A0000340DB009A400748FB1D1B785BB29B08AD
+:1001B0000A43C0339B001A50C046BD4603B090BDF1
+:1001C00000ED00E000E100E080B582B000AF7860B3
+:1001D0007B685A1E80235B049A4201D3012310E0FE
+:1001E0000A4B7A68013A5A6001235B4203211800E6
+:1001F000FFF77CFF054B00229A60044B07221A6030
+:1002000000231800BD4602B080BDC04610E000E0EB
+:1002100080B500AFC046BD4680BD80B582B000AF9E
+:100220005B4B1A685A4B802149020A431A60C04648
+:10023000574B1A6880239B021340F9D0544B5A68DD
+:10024000534B54490A405A60514B5A68504B8821CD
+:1002500049030A435A604E4B1A684D4B80214904AA
+:100260000A431A60C0464A4B1A6880239B04134015
+:10027000F9D0474B5A68464B02210A435A6000F0B6
+:1002800011FE454B1B680A21180001F08DF903008F
+:100290001800FFF799FF01235B421800FFF710FFDA
+:1002A00001235B4260211800FFF720FF384B5A6999
+:1002B000374B3A490A435A61354B9A69344B3849AE
+:1002C0000A439A61324BDA69314B02210A43DA61FF
+:1002D0009023DB051A689023DB0532490A431A6034
+:1002E0009023DB059A689023DB052F490A439A6027
+:1002F0009023DB0500221A629023DB05882252003E
+:100300005A622A4A294B12681A60294BC922920064
+:100310001A60274BE022D2005A60254B1A68244B02
+:1003200040210A431A601920FFF7CAFE4021192014
+:10033000FFF7DCFE1F4B00225A601E4B0122DA60E1
+:100340001C4B2F229A621B4B1B4ADA62194B01226B
+:100350001A601520FFF7B4FE40211520FFF7C6FEF6
+:10036000164B180000F05AF900F0BEFA144B3B602F
+:100370003B680821180000F091FB00237B6002E03D
+:100380007B6801337B607B680E4A9342F8DDEDE7C2
+:10039000001002400CF8C3FF00000020110006000E
+:1003A000015A420070A92800808A08000004004811
+:1003B0000030014000440140E703000040420F00CC
+:1003C000E41800089F86010080B500AF084B9B68C9
+:1003D0000222134009D09023DB0508229A61044BC6
+:1003E0005A68034B80218A435A60C046BD4680BD8F
+:1003F0000030014080B582B000AF284B1B6901225C
+:10040000134047D0254B1A69244B01218A431A61B6
+:10041000FB1D00221A70BB1D01221A7000233B60D5
+:100420001DE01F4B3A689200D358002B0FD01C4B95
+:100430003A689200D358591E194B3A689200D1502D
+:10044000FB1DF91DBA1D097812780A431A70BA1DEE
+:10045000BB1D1B78DB1813703B6801333B603B68A6
+:10046000072BDED90F4B1B68591C0E4A11600A2B53
+:1004700010D10C4B00221A600B4AFB1D1B78137025
+:100480000A4B5A68094B80210A435A609023DB05C6
+:1004900008229A62C046BD4602B080BD00440140B9
+:1004A000A8000020980000200C30014000300140DE
+:1004B00080B500AF00BEC046BD4680BD00BEC04690
+:1004C00080B500AF00BEC046BD4680BD80B500AF60
+:1004D00000BEC046BD4680BD80B500AF0A4B1B685C
+:1004E000591C094A11600A2B0AD1074B00221A60D5
+:1004F000064B1B685A1C054B1A60054B64229A6117
+:10050000C046BD4680BDC0469C000020940000202F
+:10051000A800002080B582B000AF0200FB1D1A7059
+:10052000FB1D1B781A001F231A40044B0121914028
+:100530000A001A60C046BD4602B080BD00E100E07E
+:1005400090B583B000AF02003960FB1D1A70FB1D2F
+:100550001B787F2B32D92F4AFB1D1B7819000F23E4
+:100560000B40083B9B0806339B00D31804331B68E1
+:10057000FA1D1278110003220A40D200FF21914097
+:100580000A00D2431A4011003B689B01FF221A4027
+:10059000FB1D1B78180003230340DB009A401D4815
+:1005A000FB1D1B781C000F232340083B9B080A43BC
+:1005B00006339B00C31804331A6027E0164AFB1D5C
+:1005C0001B785BB29B08C0339B009B58FA1D1278C6
+:1005D000110003220A40D200FF2191400A00D243B9
+:1005E0001A4011003B689B01FF221A40FB1D1B783B
+:1005F000180003230340DB009A400748FB1D1B78CB
+:100600005BB29B080A43C0339B001A50C046BD46EC
+:1006100003B090BD00ED00E000E100E080B584B0E3
+:1006200000AF78608023DB00180000F04BF8214B0E
+:10063000802212061A611F4B07225A611D4B1E4A67
+:10064000DA601C4B04229A621A4B9A68194B80217B
+:1006500009060A439A60C046164B9B68002BFBDBD9
+:10066000144B9A68134B01210A439A60114B9A6804
+:10067000104B04210A439A607B68104A934206DDBE
+:100680007B68FA21180001F019F8030000E0062346
+:10069000FB60FA6880235B029A4201DB084BFB6037
+:1006A000FB6819000C2000F03DF8C046BD4604B0C0
+:1006B00080BDC0460024014043080000DC05000066
+:1006C000FFFF000080B582B000AF7860114B124A86
+:1006D0009A60104B114ADA600E4B7A685A600D4BE3
+:1006E00000221A600B4B1A680A4B0D490A431A6024
+:1006F0000920FFF70FFF40210920FFF721FF054BDD
+:100700001A68044B01210A431A60C046BD4602B074
+:1007100080BDC0460800024040240140C8000020BF
+:10072000A205000080B582B000AF78603960154B3B
+:10073000802212025A64134BC022D201DA61114B9B
+:10074000802252011A620F4B01221A647B685A1EE2
+:100750000C4B9A623B685A1E0A4BDA62094B5A6983
+:10076000084B01210A435A61064B80221A60054B4F
+:100770001A68044B01210A431A60C046BD4602B004
+:1007800080BDC046002C014080B500AFC046BD46CC
+:1007900080BD80B500AF054B5A68044B01210A4368
+:1007A0005A60FFF7F1FFC046BD4680BD0000024021
+:1007B00080B582B000AF0200FB1D1A70FB1D1B78D4
+:1007C0001A001F231A40044B012191400A001A60AD
+:1007D000C046BD4602B080BD00E100E080B582B0F9
+:1007E00000AF0200FB1D1A70FB1D1B781A001F23AF
+:1007F0001340054901229A40130080228B50C046C5
+:10080000BD4602B080BDC04600E100E090B583B0B7
+:1008100000AF02003960FB1D1A70FB1D1B787F2B97
+:1008200032D92F4AFB1D1B7819000F230B40083BC0
+:100830009B0806339B00D31804331B68FA1D1278FB
+:10084000110003220A40D200FF2191400A00D24346
+:100850001A4011003B689B01FF221A40FB1D1B78C8
+:10086000180003230340DB009A401D48FB1D1B7842
+:100870001C000F232340083B9B080A4306339B00C0
+:10088000C31804331A6027E0164AFB1D1B785BB2BD
+:100890009B08C0339B009B58FA1D1278110003225D
+:1008A0000A40D200FF2191400A00D2431A401100B1
+:1008B0003B689B01FF221A40FB1D1B781800032395
+:1008C0000340DB009A400748FB1D1B785BB29B0886
+:1008D0000A43C0339B001A50C046BD4603B090BDCA
+:1008E00000ED00E000E100E080B500AF174B012211
+:1008F00052421A60154B00225A60144B00229A6033
+:10090000134B144A9A60124B92221A600A20FFF786
+:100910004FFF20210A20FFF779FF0F4B0F4A1A6083
+:100920000D4B3022DA600C4BC02292025A600A4B07
+:100930009A68094B80210A439A60074B1A68064B54
+:1009400001210A431A60C046BD4680BDC808002088
+:100950001C00024028380140003801402C200000D3
+:1009600080B584B000AF194BBB60BB685B687B602F
+:10097000BB689B687A689A4205D2BB689A687B68B4
+:10098000D31AFB6004E07B6880225200D31AFB601C
+:10099000BB687A681A607A68FB68D318FF221A402D
+:1009A000BB685A60BB680C331A007B68D218084BCE
+:1009B000DA60074BFA685A60054B1A68044B01214C
+:1009C0000A431A60C046BD4604B080BDC808002076
+:1009D0001C00024080B582B000AF78600A00FB1CAA
+:1009E0001A700A20FFF7FAFE7B689A687B681B681A
+:1009F0009A4205D10A20FFF7DBFE10235B4211E08B
+:100A00007B689B687A68D318FA1C12781A737B6823
+:100A10009B680133FF221A407B689A600A20FFF727
+:100A2000C7FE00231800BD4602B080BD80B582B06D
+:100A300000AF0200FB1D1A70C046FB1D1A78064B62
+:100A400011001800FFF7C6FF03001033F5D0C046B1
+:100A5000C046BD4602B080BDC808002080B500AFCA
+:100A60000B4B5A680A4B20210A435A60094B1A68FB
+:100A7000084B01218A431A60074B9A68064B5B6852
+:100A80009A4201D0FFF76CFFC046BD4680BDC0460C
+:100A9000000002401C000240C808002080B582B05F
+:100AA00000AF786039603A687B681100180000F088
+:100AB00070F8054B1B680122134001D1FFF750FF6E
+:100AC000C046BD4602B080BD1C00024080B588B063
+:100AD00000AFF860B9607A603B60BA6880235B025F
+:100AE0009A4202D23B68FE2B02D901235B424CE0C2
+:100AF0003B680233BA689A4202D201235B4244E067
+:100B00000023FB6136E0FB69002B0FD0FB69013B42
+:100B10007A68D3181B78002B08D0FB69013B7A68F0
+:100B2000D2181B23FB1812781A7019E0FB697B613D
+:100B300002E07B6901337B617A693B689A4205D2A6
+:100B40007A687B69D3181B78002BF2D17B69DAB203
+:100B5000FB69DBB2D31ADAB21B23FB1801321A701D
+:100B6000FA68FB69D3181B22BA1812781A70FB694D
+:100B70000133FB61FA693B689A42C4D9FA68FB69A0
+:100B8000D31800221A703B6802331800BD4608B023
+:100B900080BD80B586B000AF786039603B68FE2BC1
+:100BA00002D901235B4240E000237B6135E07B6991
+:100BB000002B0FD07B69013B7A68D3181B78002B80
+:100BC00008D07B69013B7A68D2181323FB1812788E
+:100BD0001A7019E07B69FB6002E0FB680133FB607F
+:100BE000FA683B689A4205D27A68FB68D3181B788A
+:100BF000002BF2D1FB68DAB27B69DBB2D31ADAB22E
+:100C00001323FB1801321A701323FB181B781800EA
+:100C1000FFF70CFF7B6901337B617A693B689A427D
+:100C2000C5D90020FFF702FF00231800BD4606B01B
+:100C300080BD80B588B000AFF860B9607A603B6075
+:100C4000BA6880235B029A4204D23A6880235B022E
+:100C50009A4202D301235B4252E03B68002B02D14F
+:100C600001235B424CE0BA683B689A4202D20123FE
+:100C70005B4245E00123FB617B681B78BB61BB697C
+:100C8000002B24D102235B423AE0BB69013BBB61EC
+:100C9000BB69002B09D17A68FB69D3181B78BB614B
+:100CA0001723FB1800221A7006E07A68FB69D21835
+:100CB0001723FB1812781A70FB69013BFA68D318E6
+:100CC0001722BA1812781A70FB690133FB61FA69AE
+:100CD0003B689A4205D27A68FB69D3181B78002BCF
+:100CE000D3D1FA693B689A4202D102235B4207E002
+:100CF000BB69012B02D003235B4201E0FB69013B8E
+:100D00001800BD4608B080BD80B582B000AF7860E5
+:100D10007B6800221A607B6800225A60C046BD468C
+:100D200002B080BD80B588B000AFF860B9607A606D
+:100D30001A00FB1C1A70FB681B68002B0ED1FB1CF1
+:100D40001B78002B54D0FB1C1A78FB685A60FB6898
+:100D50001B685A1CFB681A60002350E0FB1C1B78C0
+:100D6000002B0DD1FB685B68012B39D1FB681B6838
+:100D7000013B7B61FB681800FFF7C6FF7B693EE023
+:100D8000FB685B685A1EFB685A60FB685B68002B57
+:100D900008D1FB1C1A78FB685A601F23FB1800223D
+:100DA0001A7004E01F23FB18FA1C12781A70FB68F3
+:100DB0001B68013BBB61BA697B689A4202D302237C
+:100DC0005B421CE0BA68BB69D3181F22BA181278BC
+:100DD0001A70FB681B685A1CFB681A6000230EE03F
+:100DE000C046FB681800FFF78FFF01235B4206E057
+:100DF000C046FB681800FFF787FF03235B4218001B
+:100E0000BD4608B080BD0419000800000020940011
+:100E1000002094000020D4090020000080B500AF1D
+:100E20001A4B1A68194B01210A431A60174B5A686A
+:100E3000164B17490A405A60144B1A68134B154950
+:100E40000A401A60114B1A68104B13490A401A6085
+:100E50000E4B5A680D4B11490A405A600B4BDA6A27
+:100E60000A4B0F218A43DA62084B1A6B074B0C4975
+:100E70000A401A63054B5A6B044B01218A435A639B
+:100E8000024B00229A60C046BD4680BD0010024061
+:100E90000CB8FF08FFFFF6FEFFFFFBFFFFFFC0FFE0
+:100EA000ECFEFFFF80B584B000AF0023FB600023A1
+:100EB000BB6000237B6000233B60314B5B680C22EE
+:100EC0001340FB60FB68082B11D0FB68082B41D84E
+:100ED000FB68002B03D0FB68042B04D03AE0294BBD
+:100EE000294A1A603AE0274B274A1A6036E0244B19
+:100EF0005A68F0239B031340BB60214B5A68802340
+:100F00005B0213407B60BB689B0C0233BB601C4BD5
+:100F1000DB6A0F22134001333B607A6880235B0257
+:100F20009A420AD13968184800F03EFB03001A00C3
+:100F3000BB685A43134B1A6010E0B9680A005201AB
+:100F4000521A93019B1ADB005B181B021A000D4B0F
+:100F50001A6003E00B4B0C4A1A60C046084B5B68F2
+:100F60001B090F221340094AD35CFB60054B1A682A
+:100F7000FB68DA40034B1A60C046BD4604B080BD32
+:100F8000001002400000002000127A00EC18000857
+:100F900080B500AF044B1A68034B8021C9020A4395
+:100FA0001A60C046BD4680BD0010024080B500AF4B
+:100FB000044B1A68034B04490A401A60C046BD46F8
+:100FC00080BDC04600100240FFFFFBFF80B500AFB0
+:100FD000044B1A68034B802149020A431A60C04639
+:100FE000BD4680BD0010024080B500AF064B1A68B8
+:100FF00080239B021340054A944663445A4253415E
+:10100000DBB21800BD4680BD001002400000FEFFAC
+:1010100080B500AF044B1A68034B01210A431A60E4
+:10102000C046BD4680BDC0460010024080B500AF3E
+:10103000054B1B6802221340023B5A425341DBB26C
+:101040001800BD4680BDC0460010024080B582B089
+:1010500000AF7860064B5B68032293431900044B92
+:101060007A680A435A60C046BD4602B080BDC04699
+:101070000010024080B500AF034B5B680C221340A8
+:101080001800BD4680BDC0460010024080B582B049
+:1010900000AF7860064B5B68F02293431900044B65
+:1010A0007A680A435A60C046BD4602B080BDC04659
+:1010B0000010024080B582B000AF7860064B5B68DC
+:1010C000064A13401900044B7A680A435A60C04626
+:1010D000BD4602B080BDC04600100240FFF8FFFFD1
+:1010E00080B500AF044B1A68034B802149040A43C2
+:1010F0001A60C046BD4680BD0010024080B500AFFA
+:10110000074B1A6880239B041340FE221206944664
+:1011100063445A425341DBB21800BD4680BDC0460D
+:101120000010024080B582B000AF786039600E4B8D
+:101130005B680E4A134019007A6880235B021A40EC
+:101140003B681A43084B0A435A60074BDB6A0F227D
+:10115000934319007B680F221A40034B0A43DA625B
+:10116000C046BD4602B080BD00100240FFFFC2FF76
+:1011700080B582B000AF786039603968786800F077
+:1011800013FA03001A00064B013A5A60044B00227E
+:101190009A60034B05221A60C046BD4602B080BD6E
+:1011A00010E000E080B582B000AF7860064B1B68AD
+:1011B000012293431900044B7A680A431A60C0461F
+:1011C000BD4602B080BDC0460020024080B500AFE1
+:1011D000034B1B68012213401800BD4680BDC0466A
+:1011E0000020024080B582B000AF7860FA239A00F8
+:1011F0007B6811001800FFF7BBFFC046BD4602B078
+:1012000080BD80B584B000AF78600E4B1B68FB607A
+:10121000FB687B6801330CD07B6801337B6008E09E
+:10122000084B1A6880235B02134002D07B68013BA5
+:101230007B607B68002BF3D1C046C046BD4604B03E
+:1012400080BDC04610E000E080B582B000AF78609D
+:10125000034B7A681A60C046BD4602B080BDC046E6
+:101260000000002090B585B000AF786039600F2392
+:10127000FB1801221A700023BB6000F0D4F80300B1
+:10128000012B28D17B6801225A607B68174A19001C
+:10129000100000F0ABF80300BB60FFF7C7FE0300CF
+:1012A000012B07D0FFF7B4FEC046FFF7BFFE0300D7
+:1012B000012BFAD17B681B6819000020FFF732FF71
+:1012C0000F23FC183A68BB681100180000F0BEF844
+:1012D0000300237003E00F23FB1800221A700F2372
+:1012E000FB181B781800BD4605B090BD00127A00AF
+:1012F00090B587B000AFF860B9607A603B601723A3
+:10130000FB1801221A7000233B6100F08CF80300E7
+:10131000012B32D17A68FB681100180000F066F8E2
+:1013200003003B61FFF760FE0300012B0FD0BB6899
+:10133000012B02D1FFF72CFE01E0FFF737FEFFF78C
+:1013400045FEC046FFF750FE0300012BFAD17B6833
+:101350005B68802252021A437B681B6819001000E8
+:10136000FFF7E0FE1723FC183A683B6911001800EC
+:1013700000F06CF80300237003E01723FB18002231
+:101380001A701723FB181B781800BD4607B090BDD4
+:1013900080B584B000AF78600F217B1801221A70ED
+:1013A0000023BB607B68002B03D17B1800221A70DE
+:1013B00013E07B680C4A934201D90123BB60BB68F0
+:1013C0001800FFF7EFFEFFF701FF0200BB68934232
+:1013D00003D00F23FB1800221A700F23FB181B7871
+:1013E0001800BD4604B080BD00366E0180B584B0E3
+:1013F00000AF786039600023FB603B685B680133B5
+:101400001900786800F0D0F8030019003B681B68E9
+:101410009B0C0F22134002334B43FB60FB68180008
+:10142000BD4604B080BD80B582B000AFFB1D012277
+:101430001A70FFF763FE031E02D0FB1D00221A7014
+:10144000FB1D1B781800BD4602B080BD90B585B06D
+:1014500000AF786039600F203B1801221A7000231A
+:10146000BB602E4B1A683B681B681B090F210B40A1
+:101470002B49CB5C9A401300BB60BA687B689A42E8
+:1014800006D23C187B681800FFF782FF0300237028
+:101490000F23FB181B78012B1AD1FFF721FEC04642
+:1014A000FFF72CFE0300012BFAD13B681B681800E4
+:1014B000FFF7ECFD0220FFF7C9FDC046FFF7DAFD9C
+:1014C0000300082BFAD13B685B681800FFF7F2FDB8
+:1014D000BA687B689A4207D90F23FC187B6818000A
+:1014E000FFF756FF030023700F23FB181B78012B17
+:1014F0000CD13B681B681B090F221340084AD35CC0
+:101500001A007B68D3401800FFF79EFE0F23FB18DC
+:101510001B781800BD4605B090BDC04600000020F5
+:10152000EC18000880B500AFC046BD4680BD80B550
+:1015300086B000AFF860B9607A60FA687B68D3184B
+:101540003B61FB687B6106E0BB68DAB27B691A70BD
+:101550007B6901337B617A693B699A42F4D3FB680A
+:101560001800BD4606B080BD80B584B000AF78607D
+:101570007B68FB60C0467B685A1C7A601B78002B36
+:10158000F9D17A68FB68D31A013B1800BD4604B054
+:1015900080BD80B582B000AF0200FB1D1A70C0464E
+:1015A000BD4602B080BD0000002243088B4274D3C8
+:1015B00003098B425FD3030A8B4244D3030B8B4254
+:1015C00028D3030C8B420DD3FF22090212BA030C5D
+:1015D0008B4202D31212090265D0030B8B4219D33E
+:1015E00000E0090AC30B8B4201D3CB03C01A52415E
+:1015F000830B8B4201D38B03C01A5241430B8B42A6
+:1016000001D34B03C01A5241030B8B4201D30B038E
+:10161000C01A5241C30A8B4201D3CB02C01A5241B5
+:10162000830A8B4201D38B02C01A5241430A8B4278
+:1016300001D34B02C01A5241030A8B4201D30B0261
+:10164000C01A5241CDD2C3098B4201D3CB01C01A7B
+:10165000524183098B4201D38B01C01A5241430985
+:101660008B4201D34B01C01A524103098B4201D373
+:101670000B01C01A5241C3088B4201D3CB00C01AE0
+:10168000524183088B4201D38B00C01A5241430858
+:101690008B4201D34B00C01A5241411A00D201467D
+:1016A000524110467047FFE701B5002000F0F0F806
+:1016B00002BDC0460029F7D076E7704703460B43CA
+:1016C0007FD4002243088B4274D303098B425FD33B
+:1016D000030A8B4244D3030B8B4228D3030C8B4267
+:1016E0000DD3FF22090212BA030C8B4202D312124D
+:1016F000090265D0030B8B4219D300E0090AC30B22
+:101700008B4201D3CB03C01A5241830B8B4201D3CE
+:101710008B03C01A5241430B8B4201D34B03C01AB7
+:101720005241030B8B4201D30B03C01A5241C30A2F
+:101730008B4201D3CB02C01A5241830A8B4201D3A0
+:101740008B02C01A5241430A8B4201D34B02C01A8A
+:101750005241030A8B4201D30B02C01A5241CDD22F
+:10176000C3098B4201D3CB01C01A524183098B427A
+:1017700001D38B01C01A524143098B4201D34B0163
+:10178000C01A524103098B4201D30B01C01A5241C6
+:10179000C3088B4201D3CB00C01A524183088B424D
+:1017A00001D38B00C01A524143088B4201D34B0036
+:1017B000C01A5241411A00D20146524110467047A8
+:1017C0005DE0CA0F00D04942031000D340425340AD
+:1017D00000229C4603098B422DD3030A8B4212D36D
+:1017E000FC22890112BA030A8B420CD3890192119F
+:1017F0008B4208D3890192118B4204D389013AD0DC
+:10180000921100E08909C3098B4201D3CB01C01AB0
+:10181000524183098B4201D38B01C01A52414309C3
+:101820008B4201D34B01C01A524103098B4201D3B1
+:101830000B01C01A5241C3088B4201D3CB00C01A1E
+:10184000524183088B4201D38B00C01A5241D9D236
+:1018500043088B4201D34B00C01A5241411A00D2B7
+:101860000146634652415B10104601D34042002BB3
+:1018700000D54942704763465B1000D3404201B532
+:10188000002000F005F802BD0029F8D016E77047E7
+:101890007047C0460C488546002103E00B4B5B585F
+:1018A000435004310A480B4B42189A42F6D30A4A75
+:1018B00002E0002313600432084B9A42F9D3FFF789
+:1018C000ADFAFEF7AAFCFEE700100020041900089C
+:1018D000000000209400002094000020D409002083
+:1018E000FEE70000464F4F4241520A000000000050
+:1018F00000000000010203040607080900000000C0
+:0419000001020304D9
+:1019040000127A000004004000200040002800403B
+:10191400002C0040003000400054004000700040A3
+:101924000000014000040140002401400827014058
+:1019340008270140002C01400030014000380140DC
+:1019440000440140004801400058014000000240AA
+:10195400080002401C0002403000024044000240E3
+:10196400580002400020024000F8FF1F001002400F
+:10197400003002400000004800040048000800480D
+:10198400000C00480014004800ED00E010E000E006
+:0419940000E100E08E
+:040000050800189542
+:00000001FF
diff --git a/gm_platform/fw/main.lst b/gm_platform/fw/main.lst
new file mode 100644
index 0000000..5be6e7e
--- /dev/null
+++ b/gm_platform/fw/main.lst
@@ -0,0 +1,4459 @@
+
+main.elf: file format elf32-littlearm
+
+SYMBOL TABLE:
+08000000 l d .isr_vector 00000000 .isr_vector
+080000c0 l d .text 00000000 .text
+20000000 l d .data 00000000 .data
+20000094 l d .bss 00000000 .bss
+00000000 l d .comment 00000000 .comment
+00000000 l d .ARM.attributes 00000000 .ARM.attributes
+00000000 l d .debug_aranges 00000000 .debug_aranges
+00000000 l d .debug_info 00000000 .debug_info
+00000000 l d .debug_abbrev 00000000 .debug_abbrev
+00000000 l d .debug_line 00000000 .debug_line
+00000000 l d .debug_frame 00000000 .debug_frame
+00000000 l d .debug_str 00000000 .debug_str
+00000000 l d .debug_ranges 00000000 .debug_ranges
+00000000 l df *ABS* 00000000 /tmp/ccTaPb5k.o
+080018a4 l .text 00000000 LoopCopyDataInit
+0800189c l .text 00000000 CopyDataInit
+080018b8 l .text 00000000 LoopFillZerobss
+080018b2 l .text 00000000 FillZerobss
+080018c6 l .text 00000000 LoopForever
+080018e0 l .text 00000000 Infinite_Loop
+00000000 l df *ABS* 00000000 main.c
+080000c0 l F .text 0000002c NVIC_EnableIRQ
+080000ec l F .text 000000dc NVIC_SetPriority
+080001c8 l F .text 00000048 SysTick_Config
+20000098 l .bss 00000004 leds_update_counter.5785
+2000009c l .bss 00000004 n.5808
+00000000 l df *ABS* 00000000 adc.c
+08000514 l F .text 0000002c NVIC_EnableIRQ
+08000540 l F .text 000000dc NVIC_SetPriority
+080006c4 l F .text 00000060 adc_dma_init
+08000724 l F .text 00000064 adc_timer_init
+08000788 l F .text 0000000a gdb_dump
+00000000 l df *ABS* 00000000 serial.c
+080007b0 l F .text 0000002c NVIC_EnableIRQ
+080007dc l F .text 00000030 NVIC_DisableIRQ
+0800080c l F .text 000000dc NVIC_SetPriority
+08000960 l F .text 00000074 usart_schedule_dma
+00000000 l df *ABS* 00000000 cobs.c
+00000000 l df *ABS* 00000000 system_stm32f0xx.c
+00000000 l df *ABS* 00000000 stm32f0xx_ll_utils.c
+08000f90 l F .text 0000001c LL_RCC_HSE_EnableBypass
+08000fac l F .text 00000020 LL_RCC_HSE_DisableBypass
+08000fcc l F .text 0000001c LL_RCC_HSE_Enable
+08000fe8 l F .text 00000028 LL_RCC_HSE_IsReady
+08001010 l F .text 0000001c LL_RCC_HSI_Enable
+0800102c l F .text 00000020 LL_RCC_HSI_IsReady
+0800104c l F .text 00000028 LL_RCC_SetSysClkSource
+08001074 l F .text 00000018 LL_RCC_GetSysClkSource
+0800108c l F .text 00000028 LL_RCC_SetAHBPrescaler
+080010b4 l F .text 0000002c LL_RCC_SetAPB1Prescaler
+080010e0 l F .text 0000001c LL_RCC_PLL_Enable
+080010fc l F .text 00000028 LL_RCC_PLL_IsReady
+08001124 l F .text 0000004c LL_RCC_PLL_ConfigDomain_SYS
+08001170 l F .text 00000034 LL_InitTick
+080011a4 l F .text 00000028 LL_FLASH_SetLatency
+080011cc l F .text 00000018 LL_FLASH_GetLatency
+08001426 l F .text 00000026 UTILS_PLL_IsBusy
+080013ec l F .text 0000003a UTILS_GetPLLOutputFrequency
+0800144c l F .text 000000d8 UTILS_EnablePLLAndSwitchSystem
+08001390 l F .text 0000005c UTILS_SetFlashLatency
+00000000 l df *ABS* 00000000 base.c
+00000000 l df *ABS* 00000000 cmsis_exports.c
+00000000 l df *ABS* 00000000 _udivsi3.o
+080015a8 l .text 00000000 .udivsi3_skip_div0_test
+00000000 l df *ABS* 00000000 _divsi3.o
+080016bc l .text 00000000 .divsi3_skip_div0_test
+00000000 l df *ABS* 00000000 _dvmd_tls.o
+080018fc g O .text 00000008 APBPrescTable
+20000044 g O .data 00000004 tim17
+2000007c g O .data 00000004 gpioc
+20000088 g O .data 00000004 scb
+08001202 g F .text 00000046 LL_mDelay
+08000a9c g F .text 00000030 usart_send_packet
+080018e0 w F .text 00000002 TIM1_CC_IRQHandler
+08001524 g F .text 0000000a __sinit
+080004bc g F .text 00000004 HardFault_Handler
+2000006c g O .data 00000004 rcc
+080004d8 g F .text 0000003c SysTick_Handler
+08001904 g .text 00000000 _sidata
+080004cc g F .text 0000000c PendSV_Handler
+20000020 g O .data 00000004 syscfg
+080004b0 g F .text 0000000c NMI_Handler
+200009d4 g .bss 00000000 __exidx_end
+08001264 g F .text 0000008c LL_PLL_ConfigSystemClock_HSI
+080018e0 w F .text 00000002 I2C1_IRQHandler
+08001248 g F .text 0000001c LL_SetSystemCoreClock
+200000a0 g O .bss 00000004 __errno
+20000008 g O .data 00000004 tim14
+20000048 g O .data 00000004 dbgmcu
+2000003c g O .data 00000004 usart1
+08001904 g .text 00000000 _etext
+20000094 g .bss 00000000 _sbss
+08000c32 g F .text 000000d6 cobs_decode
+200008c8 g O .bss 0000010c usart_tx_buf
+20000094 g O .bss 00000004 sys_time_seconds
+20000000 g O .data 00000004 SystemCoreClock
+2000001c g O .data 00000004 pwr
+080015a8 g F .text 0000010a .hidden __udivsi3
+08001592 g F .text 00000014 __assert_func
+20000000 g .data 00000000 _sdata
+080003c8 g F .text 0000002c SPI1_IRQHandler
+20000060 g O .data 00000004 dma1_channel5
+20000058 g O .data 00000004 dma1_channel3
+200009d4 g .bss 00000000 __exidx_start
+080011e4 g F .text 0000001e LL_Init1msTick
+20000054 g O .data 00000004 dma1_channel2
+080018e0 w F .text 00000002 EXTI2_3_IRQHandler
+080018e0 w F .text 00000002 ADC1_IRQHandler
+08000d24 g F .text 000000e2 cobs_decode_incremental
+2000004c g O .data 00000004 dma1
+080018e0 w F .text 00000002 TIM17_IRQHandler
+080018e0 w F .text 00000002 RTC_IRQHandler
+200009d4 g .bss 00000000 _ebss
+2000002c g O .data 00000004 adc1_common
+08001894 w F .text 00000034 Reset_Handler
+20000070 g O .data 00000004 crc
+20000024 g O .data 00000004 exti
+08000210 g F .text 0000000a update_leds
+20000028 g O .data 00000004 adc1
+080016bc g F .text 00000000 .hidden __aeabi_idiv
+08000acc g F .text 000000c6 cobs_encode
+200000a8 g O .bss 00000020 leds
+20000074 g O .data 00000004 gpioa
+080003f4 g F .text 000000bc TIM16_IRQHandler
+080018e0 w F .text 00000002 TIM3_IRQHandler
+080018e0 w F .text 00000002 EXTI4_15_IRQHandler
+080018e0 w F .text 00000002 RCC_IRQHandler
+20000094 g .bss 00000000 _bss
+08000792 g F .text 0000001e DMA1_Channel1_IRQHandler
+080018e0 g .text 00000002 Default_Handler
+080018ec g O .text 00000010 AHBPrescTable
+08000b92 g F .text 000000a0 cobs_encode_usart
+20000010 g O .data 00000004 wwdg
+080018e0 w F .text 00000002 TIM14_IRQHandler
+080018e0 w F .text 00000002 DMA1_Channel4_5_IRQHandler
+20000030 g O .data 00000004 adc
+08000a2c g F .text 00000030 usart_putc
+080018e0 w F .text 00000002 EXTI0_1_IRQHandler
+08001890 w F .text 00000002 .hidden __aeabi_ldiv0
+20000004 g O .data 00000004 tim3
+2000000c g O .data 00000004 rtc
+080008e8 g F .text 00000078 usart_dma_init
+0800152e g F .text 0000003a memset
+0800021a g F .text 000001ae main
+20000064 g O .data 00000004 flash
+080015a8 g F .text 00000000 .hidden __aeabi_uidiv
+080004c0 g F .text 0000000c SVC_Handler
+20000018 g O .data 00000004 i2c1
+20000050 g O .data 00000004 dma1_channel1
+080016bc g F .text 000001cc .hidden __divsi3
+20000090 g O .data 00000004 nvic
+08000e1c g F .text 00000088 SystemInit
+200000a4 g O .bss 00000004 _impure_ptr
+080018e0 w F .text 00000002 WWDG_IRQHandler
+20000000 g .data 00000000 _data
+20000084 g O .data 00000004 gpiof
+08000a5c g F .text 00000040 DMA1_Channel2_3_IRQHandler
+200000c8 g O .bss 00000800 adc_buf
+20000080 g O .data 00000004 gpiod
+20001000 g *ABS* 00000000 _estack
+080016b4 g F .text 00000008 .hidden __aeabi_uidivmod
+20000068 g O .data 00000004 ob
+20000094 g .data 00000000 _edata
+20000038 g O .data 00000004 spi1
+080009d4 g F .text 00000058 usart_dma_fifo_push
+2000005c g O .data 00000004 dma1_channel4
+08000000 g O .isr_vector 00000000 g_pfnVectors
+08000ea4 g F .text 000000ec SystemCoreClockUpdate
+080012f0 g F .text 000000a0 LL_PLL_ConfigSystemClock_HSE
+08001890 w F .text 00000002 .hidden __aeabi_idiv0
+20000014 g O .data 00000004 iwdg
+080018e0 w F .text 00000002 FLASH_IRQHandler
+08000d08 g F .text 0000001c cobs_decode_incremental_initialize
+080018e0 w F .text 00000002 USART1_IRQHandler
+0800061c g F .text 000000a8 adc_configure_scope_mode
+08001568 g F .text 0000002a strlen
+080018e0 w F .text 00000002 TIM1_BRK_UP_TRG_COM_IRQHandler
+20000078 g O .data 00000004 gpiob
+20000034 g O .data 00000004 tim1
+2000008c g O .data 00000004 systick
+08001888 g F .text 00000008 .hidden __aeabi_idivmod
+20000040 g O .data 00000004 tim16
+
+
+
+Disassembly of section .text:
+
+080000c0 <NVIC_EnableIRQ>:
+ \brief Enable External Interrupt
+ \details Enables a device-specific interrupt in the NVIC interrupt controller.
+ \param [in] IRQn External interrupt number. Value cannot be negative.
+ */
+__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
+{
+ 80000c0: b580 push {r7, lr}
+ 80000c2: b082 sub sp, #8
+ 80000c4: af00 add r7, sp, #0
+ 80000c6: 0002 movs r2, r0
+ 80000c8: 1dfb adds r3, r7, #7
+ 80000ca: 701a strb r2, [r3, #0]
+ NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
+ 80000cc: 1dfb adds r3, r7, #7
+ 80000ce: 781b ldrb r3, [r3, #0]
+ 80000d0: 001a movs r2, r3
+ 80000d2: 231f movs r3, #31
+ 80000d4: 401a ands r2, r3
+ 80000d6: 4b04 ldr r3, [pc, #16] ; (80000e8 <NVIC_EnableIRQ+0x28>)
+ 80000d8: 2101 movs r1, #1
+ 80000da: 4091 lsls r1, r2
+ 80000dc: 000a movs r2, r1
+ 80000de: 601a str r2, [r3, #0]
+}
+ 80000e0: 46c0 nop ; (mov r8, r8)
+ 80000e2: 46bd mov sp, r7
+ 80000e4: b002 add sp, #8
+ 80000e6: bd80 pop {r7, pc}
+ 80000e8: e000e100 .word 0xe000e100
+
+080000ec <NVIC_SetPriority>:
+ \note The priority cannot be set for every core interrupt.
+ \param [in] IRQn Interrupt number.
+ \param [in] priority Priority to set.
+ */
+__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
+{
+ 80000ec: b590 push {r4, r7, lr}
+ 80000ee: b083 sub sp, #12
+ 80000f0: af00 add r7, sp, #0
+ 80000f2: 0002 movs r2, r0
+ 80000f4: 6039 str r1, [r7, #0]
+ 80000f6: 1dfb adds r3, r7, #7
+ 80000f8: 701a strb r2, [r3, #0]
+ if ((int32_t)(IRQn) < 0)
+ 80000fa: 1dfb adds r3, r7, #7
+ 80000fc: 781b ldrb r3, [r3, #0]
+ 80000fe: 2b7f cmp r3, #127 ; 0x7f
+ 8000100: d932 bls.n 8000168 <NVIC_SetPriority+0x7c>
+ {
+ SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 8000102: 4a2f ldr r2, [pc, #188] ; (80001c0 <NVIC_SetPriority+0xd4>)
+ 8000104: 1dfb adds r3, r7, #7
+ 8000106: 781b ldrb r3, [r3, #0]
+ 8000108: 0019 movs r1, r3
+ 800010a: 230f movs r3, #15
+ 800010c: 400b ands r3, r1
+ 800010e: 3b08 subs r3, #8
+ 8000110: 089b lsrs r3, r3, #2
+ 8000112: 3306 adds r3, #6
+ 8000114: 009b lsls r3, r3, #2
+ 8000116: 18d3 adds r3, r2, r3
+ 8000118: 3304 adds r3, #4
+ 800011a: 681b ldr r3, [r3, #0]
+ 800011c: 1dfa adds r2, r7, #7
+ 800011e: 7812 ldrb r2, [r2, #0]
+ 8000120: 0011 movs r1, r2
+ 8000122: 2203 movs r2, #3
+ 8000124: 400a ands r2, r1
+ 8000126: 00d2 lsls r2, r2, #3
+ 8000128: 21ff movs r1, #255 ; 0xff
+ 800012a: 4091 lsls r1, r2
+ 800012c: 000a movs r2, r1
+ 800012e: 43d2 mvns r2, r2
+ 8000130: 401a ands r2, r3
+ 8000132: 0011 movs r1, r2
+ (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
+ 8000134: 683b ldr r3, [r7, #0]
+ 8000136: 019b lsls r3, r3, #6
+ 8000138: 22ff movs r2, #255 ; 0xff
+ 800013a: 401a ands r2, r3
+ 800013c: 1dfb adds r3, r7, #7
+ 800013e: 781b ldrb r3, [r3, #0]
+ 8000140: 0018 movs r0, r3
+ 8000142: 2303 movs r3, #3
+ 8000144: 4003 ands r3, r0
+ 8000146: 00db lsls r3, r3, #3
+ 8000148: 409a lsls r2, r3
+ SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 800014a: 481d ldr r0, [pc, #116] ; (80001c0 <NVIC_SetPriority+0xd4>)
+ 800014c: 1dfb adds r3, r7, #7
+ 800014e: 781b ldrb r3, [r3, #0]
+ 8000150: 001c movs r4, r3
+ 8000152: 230f movs r3, #15
+ 8000154: 4023 ands r3, r4
+ 8000156: 3b08 subs r3, #8
+ 8000158: 089b lsrs r3, r3, #2
+ 800015a: 430a orrs r2, r1
+ 800015c: 3306 adds r3, #6
+ 800015e: 009b lsls r3, r3, #2
+ 8000160: 18c3 adds r3, r0, r3
+ 8000162: 3304 adds r3, #4
+ 8000164: 601a str r2, [r3, #0]
+ else
+ {
+ NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
+ }
+}
+ 8000166: e027 b.n 80001b8 <NVIC_SetPriority+0xcc>
+ NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 8000168: 4a16 ldr r2, [pc, #88] ; (80001c4 <NVIC_SetPriority+0xd8>)
+ 800016a: 1dfb adds r3, r7, #7
+ 800016c: 781b ldrb r3, [r3, #0]
+ 800016e: b25b sxtb r3, r3
+ 8000170: 089b lsrs r3, r3, #2
+ 8000172: 33c0 adds r3, #192 ; 0xc0
+ 8000174: 009b lsls r3, r3, #2
+ 8000176: 589b ldr r3, [r3, r2]
+ 8000178: 1dfa adds r2, r7, #7
+ 800017a: 7812 ldrb r2, [r2, #0]
+ 800017c: 0011 movs r1, r2
+ 800017e: 2203 movs r2, #3
+ 8000180: 400a ands r2, r1
+ 8000182: 00d2 lsls r2, r2, #3
+ 8000184: 21ff movs r1, #255 ; 0xff
+ 8000186: 4091 lsls r1, r2
+ 8000188: 000a movs r2, r1
+ 800018a: 43d2 mvns r2, r2
+ 800018c: 401a ands r2, r3
+ 800018e: 0011 movs r1, r2
+ (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
+ 8000190: 683b ldr r3, [r7, #0]
+ 8000192: 019b lsls r3, r3, #6
+ 8000194: 22ff movs r2, #255 ; 0xff
+ 8000196: 401a ands r2, r3
+ 8000198: 1dfb adds r3, r7, #7
+ 800019a: 781b ldrb r3, [r3, #0]
+ 800019c: 0018 movs r0, r3
+ 800019e: 2303 movs r3, #3
+ 80001a0: 4003 ands r3, r0
+ 80001a2: 00db lsls r3, r3, #3
+ 80001a4: 409a lsls r2, r3
+ NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 80001a6: 4807 ldr r0, [pc, #28] ; (80001c4 <NVIC_SetPriority+0xd8>)
+ 80001a8: 1dfb adds r3, r7, #7
+ 80001aa: 781b ldrb r3, [r3, #0]
+ 80001ac: b25b sxtb r3, r3
+ 80001ae: 089b lsrs r3, r3, #2
+ 80001b0: 430a orrs r2, r1
+ 80001b2: 33c0 adds r3, #192 ; 0xc0
+ 80001b4: 009b lsls r3, r3, #2
+ 80001b6: 501a str r2, [r3, r0]
+}
+ 80001b8: 46c0 nop ; (mov r8, r8)
+ 80001ba: 46bd mov sp, r7
+ 80001bc: b003 add sp, #12
+ 80001be: bd90 pop {r4, r7, pc}
+ 80001c0: e000ed00 .word 0xe000ed00
+ 80001c4: e000e100 .word 0xe000e100
+
+080001c8 <SysTick_Config>:
+ \note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
+ function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
+ must contain a vendor-specific implementation of this function.
+ */
+__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
+{
+ 80001c8: b580 push {r7, lr}
+ 80001ca: b082 sub sp, #8
+ 80001cc: af00 add r7, sp, #0
+ 80001ce: 6078 str r0, [r7, #4]
+ if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
+ 80001d0: 687b ldr r3, [r7, #4]
+ 80001d2: 1e5a subs r2, r3, #1
+ 80001d4: 2380 movs r3, #128 ; 0x80
+ 80001d6: 045b lsls r3, r3, #17
+ 80001d8: 429a cmp r2, r3
+ 80001da: d301 bcc.n 80001e0 <SysTick_Config+0x18>
+ {
+ return (1UL); /* Reload value impossible */
+ 80001dc: 2301 movs r3, #1
+ 80001de: e010 b.n 8000202 <SysTick_Config+0x3a>
+ }
+
+ SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
+ 80001e0: 4b0a ldr r3, [pc, #40] ; (800020c <SysTick_Config+0x44>)
+ 80001e2: 687a ldr r2, [r7, #4]
+ 80001e4: 3a01 subs r2, #1
+ 80001e6: 605a str r2, [r3, #4]
+ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
+ 80001e8: 2301 movs r3, #1
+ 80001ea: 425b negs r3, r3
+ 80001ec: 2103 movs r1, #3
+ 80001ee: 0018 movs r0, r3
+ 80001f0: f7ff ff7c bl 80000ec <NVIC_SetPriority>
+ SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
+ 80001f4: 4b05 ldr r3, [pc, #20] ; (800020c <SysTick_Config+0x44>)
+ 80001f6: 2200 movs r2, #0
+ 80001f8: 609a str r2, [r3, #8]
+ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
+ 80001fa: 4b04 ldr r3, [pc, #16] ; (800020c <SysTick_Config+0x44>)
+ 80001fc: 2207 movs r2, #7
+ 80001fe: 601a str r2, [r3, #0]
+ SysTick_CTRL_TICKINT_Msk |
+ SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
+ return (0UL); /* Function successful */
+ 8000200: 2300 movs r3, #0
+}
+ 8000202: 0018 movs r0, r3
+ 8000204: 46bd mov sp, r7
+ 8000206: b002 add sp, #8
+ 8000208: bd80 pop {r7, pc}
+ 800020a: 46c0 nop ; (mov r8, r8)
+ 800020c: e000e010 .word 0xe000e010
+
+08000210 <update_leds>:
+#include "serial.h"
+
+
+volatile unsigned int sys_time_seconds = 0;
+
+void update_leds() {
+ 8000210: b580 push {r7, lr}
+ 8000212: af00 add r7, sp, #0
+
+}
+ 8000214: 46c0 nop ; (mov r8, r8)
+ 8000216: 46bd mov sp, r7
+ 8000218: bd80 pop {r7, pc}
+
+0800021a <main>:
+ unsigned int usb, ocxo, error, _nc1, _nc2, _nc3, pps, sd_card;
+ };
+ unsigned int arr[0];
+} leds;
+
+int main(void) {
+ 800021a: b580 push {r7, lr}
+ 800021c: b082 sub sp, #8
+ 800021e: af00 add r7, sp, #0
+ RCC->CR |= RCC_CR_HSEON;
+ 8000220: 4b5b ldr r3, [pc, #364] ; (8000390 <main+0x176>)
+ 8000222: 681a ldr r2, [r3, #0]
+ 8000224: 4b5a ldr r3, [pc, #360] ; (8000390 <main+0x176>)
+ 8000226: 2180 movs r1, #128 ; 0x80
+ 8000228: 0249 lsls r1, r1, #9
+ 800022a: 430a orrs r2, r1
+ 800022c: 601a str r2, [r3, #0]
+ while (!(RCC->CR&RCC_CR_HSERDY));
+ 800022e: 46c0 nop ; (mov r8, r8)
+ 8000230: 4b57 ldr r3, [pc, #348] ; (8000390 <main+0x176>)
+ 8000232: 681a ldr r2, [r3, #0]
+ 8000234: 2380 movs r3, #128 ; 0x80
+ 8000236: 029b lsls r3, r3, #10
+ 8000238: 4013 ands r3, r2
+ 800023a: d0f9 beq.n 8000230 <main+0x16>
+ RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk;
+ 800023c: 4b54 ldr r3, [pc, #336] ; (8000390 <main+0x176>)
+ 800023e: 685a ldr r2, [r3, #4]
+ 8000240: 4b53 ldr r3, [pc, #332] ; (8000390 <main+0x176>)
+ 8000242: 4954 ldr r1, [pc, #336] ; (8000394 <main+0x17a>)
+ 8000244: 400a ands r2, r1
+ 8000246: 605a str r2, [r3, #4]
+ RCC->CFGR |= ((6-2)<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x6 -> 48.0MHz */
+ 8000248: 4b51 ldr r3, [pc, #324] ; (8000390 <main+0x176>)
+ 800024a: 685a ldr r2, [r3, #4]
+ 800024c: 4b50 ldr r3, [pc, #320] ; (8000390 <main+0x176>)
+ 800024e: 2188 movs r1, #136 ; 0x88
+ 8000250: 0349 lsls r1, r1, #13
+ 8000252: 430a orrs r2, r1
+ 8000254: 605a str r2, [r3, #4]
+ RCC->CR |= RCC_CR_PLLON;
+ 8000256: 4b4e ldr r3, [pc, #312] ; (8000390 <main+0x176>)
+ 8000258: 681a ldr r2, [r3, #0]
+ 800025a: 4b4d ldr r3, [pc, #308] ; (8000390 <main+0x176>)
+ 800025c: 2180 movs r1, #128 ; 0x80
+ 800025e: 0449 lsls r1, r1, #17
+ 8000260: 430a orrs r2, r1
+ 8000262: 601a str r2, [r3, #0]
+ while (!(RCC->CR&RCC_CR_PLLRDY));
+ 8000264: 46c0 nop ; (mov r8, r8)
+ 8000266: 4b4a ldr r3, [pc, #296] ; (8000390 <main+0x176>)
+ 8000268: 681a ldr r2, [r3, #0]
+ 800026a: 2380 movs r3, #128 ; 0x80
+ 800026c: 049b lsls r3, r3, #18
+ 800026e: 4013 ands r3, r2
+ 8000270: d0f9 beq.n 8000266 <main+0x4c>
+ RCC->CFGR |= (2<<RCC_CFGR_SW_Pos);
+ 8000272: 4b47 ldr r3, [pc, #284] ; (8000390 <main+0x176>)
+ 8000274: 685a ldr r2, [r3, #4]
+ 8000276: 4b46 ldr r3, [pc, #280] ; (8000390 <main+0x176>)
+ 8000278: 2102 movs r1, #2
+ 800027a: 430a orrs r2, r1
+ 800027c: 605a str r2, [r3, #4]
+ SystemCoreClockUpdate();
+ 800027e: f000 fe11 bl 8000ea4 <SystemCoreClockUpdate>
+ SysTick_Config(SystemCoreClock/10); /* 100ms interval */
+ 8000282: 4b45 ldr r3, [pc, #276] ; (8000398 <main+0x17e>)
+ 8000284: 681b ldr r3, [r3, #0]
+ 8000286: 210a movs r1, #10
+ 8000288: 0018 movs r0, r3
+ 800028a: f001 f98d bl 80015a8 <__udivsi3>
+ 800028e: 0003 movs r3, r0
+ 8000290: 0018 movs r0, r3
+ 8000292: f7ff ff99 bl 80001c8 <SysTick_Config>
+ NVIC_EnableIRQ(SysTick_IRQn);
+ 8000296: 2301 movs r3, #1
+ 8000298: 425b negs r3, r3
+ 800029a: 0018 movs r0, r3
+ 800029c: f7ff ff10 bl 80000c0 <NVIC_EnableIRQ>
+ NVIC_SetPriority(SysTick_IRQn, 3<<5);
+ 80002a0: 2301 movs r3, #1
+ 80002a2: 425b negs r3, r3
+ 80002a4: 2160 movs r1, #96 ; 0x60
+ 80002a6: 0018 movs r0, r3
+ 80002a8: f7ff ff20 bl 80000ec <NVIC_SetPriority>
+
+ /* Turn on lots of neat things */
+ RCC->AHBENR |= RCC_AHBENR_DMAEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_FLITFEN;
+ 80002ac: 4b38 ldr r3, [pc, #224] ; (8000390 <main+0x176>)
+ 80002ae: 695a ldr r2, [r3, #20]
+ 80002b0: 4b37 ldr r3, [pc, #220] ; (8000390 <main+0x176>)
+ 80002b2: 493a ldr r1, [pc, #232] ; (800039c <main+0x182>)
+ 80002b4: 430a orrs r2, r1
+ 80002b6: 615a str r2, [r3, #20]
+ RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_DBGMCUEN |\
+ 80002b8: 4b35 ldr r3, [pc, #212] ; (8000390 <main+0x176>)
+ 80002ba: 699a ldr r2, [r3, #24]
+ 80002bc: 4b34 ldr r3, [pc, #208] ; (8000390 <main+0x176>)
+ 80002be: 4938 ldr r1, [pc, #224] ; (80003a0 <main+0x186>)
+ 80002c0: 430a orrs r2, r1
+ 80002c2: 619a str r2, [r3, #24]
+ RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN | RCC_APB2ENR_USART1EN;
+ RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
+ 80002c4: 4b32 ldr r3, [pc, #200] ; (8000390 <main+0x176>)
+ 80002c6: 69da ldr r2, [r3, #28]
+ 80002c8: 4b31 ldr r3, [pc, #196] ; (8000390 <main+0x176>)
+ 80002ca: 2102 movs r1, #2
+ 80002cc: 430a orrs r2, r1
+ 80002ce: 61da str r2, [r3, #28]
+
+ GPIOA->MODER |=
+ 80002d0: 2390 movs r3, #144 ; 0x90
+ 80002d2: 05db lsls r3, r3, #23
+ 80002d4: 681a ldr r2, [r3, #0]
+ 80002d6: 2390 movs r3, #144 ; 0x90
+ 80002d8: 05db lsls r3, r3, #23
+ 80002da: 4932 ldr r1, [pc, #200] ; (80003a4 <main+0x18a>)
+ 80002dc: 430a orrs r2, r1
+ 80002de: 601a str r2, [r3, #0]
+ | (2<<GPIO_MODER_MODER7_Pos) /* PA7 - MOSI */
+ | (2<<GPIO_MODER_MODER9_Pos) /* PA9 - HOST_RX */
+ | (2<<GPIO_MODER_MODER10_Pos);/* PA10 - HOST_TX */
+
+ /* Set shift register IO GPIO output speed */
+ GPIOA->OSPEEDR |=
+ 80002e0: 2390 movs r3, #144 ; 0x90
+ 80002e2: 05db lsls r3, r3, #23
+ 80002e4: 689a ldr r2, [r3, #8]
+ 80002e6: 2390 movs r3, #144 ; 0x90
+ 80002e8: 05db lsls r3, r3, #23
+ 80002ea: 492f ldr r1, [pc, #188] ; (80003a8 <main+0x18e>)
+ 80002ec: 430a orrs r2, r1
+ 80002ee: 609a str r2, [r3, #8]
+ | (2<<GPIO_OSPEEDR_OSPEEDR4_Pos) /* SD_CS */
+ | (2<<GPIO_OSPEEDR_OSPEEDR5_Pos) /* SCK */
+ | (2<<GPIO_OSPEEDR_OSPEEDR7_Pos) /* MOSI */
+ | (2<<GPIO_OSPEEDR_OSPEEDR9_Pos); /* HOST_RX */
+
+ GPIOA->AFR[0] = (0<<GPIO_AFRL_AFRL5_Pos) | (0<<GPIO_AFRL_AFRL6_Pos) | (0<<GPIO_AFRL_AFRL7_Pos);
+ 80002f0: 2390 movs r3, #144 ; 0x90
+ 80002f2: 05db lsls r3, r3, #23
+ 80002f4: 2200 movs r2, #0
+ 80002f6: 621a str r2, [r3, #32]
+ GPIOA->AFR[1] = (1<<8) | (1<<4);
+ 80002f8: 2390 movs r3, #144 ; 0x90
+ 80002fa: 05db lsls r3, r3, #23
+ 80002fc: 2288 movs r2, #136 ; 0x88
+ 80002fe: 0052 lsls r2, r2, #1
+ 8000300: 625a str r2, [r3, #36] ; 0x24
+
+ GPIOB->MODER |=
+ 8000302: 4a2a ldr r2, [pc, #168] ; (80003ac <main+0x192>)
+ 8000304: 4b29 ldr r3, [pc, #164] ; (80003ac <main+0x192>)
+ 8000306: 6812 ldr r2, [r2, #0]
+ 8000308: 601a str r2, [r3, #0]
+ (0<<GPIO_MODER_MODER1_Pos); /* PB0 - LINE_POL */
+
+ SPI1->CR1 =
+ 800030a: 4b29 ldr r3, [pc, #164] ; (80003b0 <main+0x196>)
+ 800030c: 22c9 movs r2, #201 ; 0xc9
+ 800030e: 0092 lsls r2, r2, #2
+ 8000310: 601a str r2, [r3, #0]
+ SPI_CR1_SSM
+ | SPI_CR1_SSI
+ | (4<<SPI_CR1_BR_Pos) /* /32 ~1.5MHz */
+ | SPI_CR1_MSTR;
+ SPI1->CR2 = (7<<SPI_CR2_DS_Pos);
+ 8000312: 4b27 ldr r3, [pc, #156] ; (80003b0 <main+0x196>)
+ 8000314: 22e0 movs r2, #224 ; 0xe0
+ 8000316: 00d2 lsls r2, r2, #3
+ 8000318: 605a str r2, [r3, #4]
+ SPI1->CR1 |= SPI_CR1_SPE;
+ 800031a: 4b25 ldr r3, [pc, #148] ; (80003b0 <main+0x196>)
+ 800031c: 681a ldr r2, [r3, #0]
+ 800031e: 4b24 ldr r3, [pc, #144] ; (80003b0 <main+0x196>)
+ 8000320: 2140 movs r1, #64 ; 0x40
+ 8000322: 430a orrs r2, r1
+ 8000324: 601a str r2, [r3, #0]
+
+ NVIC_EnableIRQ(SPI1_IRQn);
+ 8000326: 2019 movs r0, #25
+ 8000328: f7ff feca bl 80000c0 <NVIC_EnableIRQ>
+ NVIC_SetPriority(SPI1_IRQn, 2<<5);
+ 800032c: 2140 movs r1, #64 ; 0x40
+ 800032e: 2019 movs r0, #25
+ 8000330: f7ff fedc bl 80000ec <NVIC_SetPriority>
+
+ TIM16->CR2 = 0;
+ 8000334: 4b1f ldr r3, [pc, #124] ; (80003b4 <main+0x19a>)
+ 8000336: 2200 movs r2, #0
+ 8000338: 605a str r2, [r3, #4]
+ TIM16->DIER = TIM_DIER_UIE;
+ 800033a: 4b1e ldr r3, [pc, #120] ; (80003b4 <main+0x19a>)
+ 800033c: 2201 movs r2, #1
+ 800033e: 60da str r2, [r3, #12]
+ TIM16->PSC = 48-1; /* 1us */
+ 8000340: 4b1c ldr r3, [pc, #112] ; (80003b4 <main+0x19a>)
+ 8000342: 222f movs r2, #47 ; 0x2f
+ 8000344: 629a str r2, [r3, #40] ; 0x28
+ TIM16->ARR = 1000-1; /* 1ms */
+ 8000346: 4b1b ldr r3, [pc, #108] ; (80003b4 <main+0x19a>)
+ 8000348: 4a1b ldr r2, [pc, #108] ; (80003b8 <main+0x19e>)
+ 800034a: 62da str r2, [r3, #44] ; 0x2c
+ TIM16->CR1 = TIM_CR1_CEN;
+ 800034c: 4b19 ldr r3, [pc, #100] ; (80003b4 <main+0x19a>)
+ 800034e: 2201 movs r2, #1
+ 8000350: 601a str r2, [r3, #0]
+
+ NVIC_EnableIRQ(TIM16_IRQn);
+ 8000352: 2015 movs r0, #21
+ 8000354: f7ff feb4 bl 80000c0 <NVIC_EnableIRQ>
+ NVIC_SetPriority(TIM16_IRQn, 2<<5);
+ 8000358: 2140 movs r1, #64 ; 0x40
+ 800035a: 2015 movs r0, #21
+ 800035c: f7ff fec6 bl 80000ec <NVIC_SetPriority>
+
+ adc_configure_scope_mode(1000000);
+ 8000360: 4b16 ldr r3, [pc, #88] ; (80003bc <main+0x1a2>)
+ 8000362: 0018 movs r0, r3
+ 8000364: f000 f95a bl 800061c <adc_configure_scope_mode>
+
+ usart_dma_init();
+ 8000368: f000 fabe bl 80008e8 <usart_dma_init>
+
+ while (42) {
+ char *data = "FOOBAR\n";
+ 800036c: 4b14 ldr r3, [pc, #80] ; (80003c0 <main+0x1a6>)
+ 800036e: 603b str r3, [r7, #0]
+ usart_send_packet((uint8_t*)data, 8);
+ 8000370: 683b ldr r3, [r7, #0]
+ 8000372: 2108 movs r1, #8
+ 8000374: 0018 movs r0, r3
+ 8000376: f000 fb91 bl 8000a9c <usart_send_packet>
+ for (int i=0; i<100000; i++);
+ 800037a: 2300 movs r3, #0
+ 800037c: 607b str r3, [r7, #4]
+ 800037e: e002 b.n 8000386 <main+0x16c>
+ 8000380: 687b ldr r3, [r7, #4]
+ 8000382: 3301 adds r3, #1
+ 8000384: 607b str r3, [r7, #4]
+ 8000386: 687b ldr r3, [r7, #4]
+ 8000388: 4a0e ldr r2, [pc, #56] ; (80003c4 <main+0x1aa>)
+ 800038a: 4293 cmp r3, r2
+ 800038c: ddf8 ble.n 8000380 <main+0x166>
+ while (42) {
+ 800038e: e7ed b.n 800036c <main+0x152>
+ 8000390: 40021000 .word 0x40021000
+ 8000394: ffc3f80c .word 0xffc3f80c
+ 8000398: 20000000 .word 0x20000000
+ 800039c: 00060011 .word 0x00060011
+ 80003a0: 00425a01 .word 0x00425a01
+ 80003a4: 0028a970 .word 0x0028a970
+ 80003a8: 00088a80 .word 0x00088a80
+ 80003ac: 48000400 .word 0x48000400
+ 80003b0: 40013000 .word 0x40013000
+ 80003b4: 40014400 .word 0x40014400
+ 80003b8: 000003e7 .word 0x000003e7
+ 80003bc: 000f4240 .word 0x000f4240
+ 80003c0: 080018e4 .word 0x080018e4
+ 80003c4: 0001869f .word 0x0001869f
+
+080003c8 <SPI1_IRQHandler>:
+ //for (int i=0; i<10000; i++) ;
+ //leds.error = 100;
+ }
+}
+
+void SPI1_IRQHandler(void) {
+ 80003c8: b580 push {r7, lr}
+ 80003ca: af00 add r7, sp, #0
+ if (SPI1->SR & SPI_SR_TXE) {
+ 80003cc: 4b08 ldr r3, [pc, #32] ; (80003f0 <SPI1_IRQHandler+0x28>)
+ 80003ce: 689b ldr r3, [r3, #8]
+ 80003d0: 2202 movs r2, #2
+ 80003d2: 4013 ands r3, r2
+ 80003d4: d009 beq.n 80003ea <SPI1_IRQHandler+0x22>
+ /* LED_STB */
+ GPIOA->BSRR = 1<<3;
+ 80003d6: 2390 movs r3, #144 ; 0x90
+ 80003d8: 05db lsls r3, r3, #23
+ 80003da: 2208 movs r2, #8
+ 80003dc: 619a str r2, [r3, #24]
+ SPI1->CR2 &= ~SPI_CR2_TXEIE;
+ 80003de: 4b04 ldr r3, [pc, #16] ; (80003f0 <SPI1_IRQHandler+0x28>)
+ 80003e0: 685a ldr r2, [r3, #4]
+ 80003e2: 4b03 ldr r3, [pc, #12] ; (80003f0 <SPI1_IRQHandler+0x28>)
+ 80003e4: 2180 movs r1, #128 ; 0x80
+ 80003e6: 438a bics r2, r1
+ 80003e8: 605a str r2, [r3, #4]
+ }
+}
+ 80003ea: 46c0 nop ; (mov r8, r8)
+ 80003ec: 46bd mov sp, r7
+ 80003ee: bd80 pop {r7, pc}
+ 80003f0: 40013000 .word 0x40013000
+
+080003f4 <TIM16_IRQHandler>:
+
+void TIM16_IRQHandler(void) {
+ 80003f4: b580 push {r7, lr}
+ 80003f6: b082 sub sp, #8
+ 80003f8: af00 add r7, sp, #0
+ static int leds_update_counter = 0;
+ if (TIM16->SR & TIM_SR_UIF) {
+ 80003fa: 4b28 ldr r3, [pc, #160] ; (800049c <TIM16_IRQHandler+0xa8>)
+ 80003fc: 691b ldr r3, [r3, #16]
+ 80003fe: 2201 movs r2, #1
+ 8000400: 4013 ands r3, r2
+ 8000402: d047 beq.n 8000494 <TIM16_IRQHandler+0xa0>
+ TIM16->SR &= ~TIM_SR_UIF;
+ 8000404: 4b25 ldr r3, [pc, #148] ; (800049c <TIM16_IRQHandler+0xa8>)
+ 8000406: 691a ldr r2, [r3, #16]
+ 8000408: 4b24 ldr r3, [pc, #144] ; (800049c <TIM16_IRQHandler+0xa8>)
+ 800040a: 2101 movs r1, #1
+ 800040c: 438a bics r2, r1
+ 800040e: 611a str r2, [r3, #16]
+
+ uint8_t bits = 0, mask = 1;
+ 8000410: 1dfb adds r3, r7, #7
+ 8000412: 2200 movs r2, #0
+ 8000414: 701a strb r2, [r3, #0]
+ 8000416: 1dbb adds r3, r7, #6
+ 8000418: 2201 movs r2, #1
+ 800041a: 701a strb r2, [r3, #0]
+ for (size_t i=0; i<sizeof(leds)/sizeof(leds.arr[0]); i++) {
+ 800041c: 2300 movs r3, #0
+ 800041e: 603b str r3, [r7, #0]
+ 8000420: e01d b.n 800045e <TIM16_IRQHandler+0x6a>
+ if (leds.arr[i]) {
+ 8000422: 4b1f ldr r3, [pc, #124] ; (80004a0 <TIM16_IRQHandler+0xac>)
+ 8000424: 683a ldr r2, [r7, #0]
+ 8000426: 0092 lsls r2, r2, #2
+ 8000428: 58d3 ldr r3, [r2, r3]
+ 800042a: 2b00 cmp r3, #0
+ 800042c: d00f beq.n 800044e <TIM16_IRQHandler+0x5a>
+ leds.arr[i]--;
+ 800042e: 4b1c ldr r3, [pc, #112] ; (80004a0 <TIM16_IRQHandler+0xac>)
+ 8000430: 683a ldr r2, [r7, #0]
+ 8000432: 0092 lsls r2, r2, #2
+ 8000434: 58d3 ldr r3, [r2, r3]
+ 8000436: 1e59 subs r1, r3, #1
+ 8000438: 4b19 ldr r3, [pc, #100] ; (80004a0 <TIM16_IRQHandler+0xac>)
+ 800043a: 683a ldr r2, [r7, #0]
+ 800043c: 0092 lsls r2, r2, #2
+ 800043e: 50d1 str r1, [r2, r3]
+ bits |= mask;
+ 8000440: 1dfb adds r3, r7, #7
+ 8000442: 1df9 adds r1, r7, #7
+ 8000444: 1dba adds r2, r7, #6
+ 8000446: 7809 ldrb r1, [r1, #0]
+ 8000448: 7812 ldrb r2, [r2, #0]
+ 800044a: 430a orrs r2, r1
+ 800044c: 701a strb r2, [r3, #0]
+ }
+ mask <<= 1;
+ 800044e: 1dba adds r2, r7, #6
+ 8000450: 1dbb adds r3, r7, #6
+ 8000452: 781b ldrb r3, [r3, #0]
+ 8000454: 18db adds r3, r3, r3
+ 8000456: 7013 strb r3, [r2, #0]
+ for (size_t i=0; i<sizeof(leds)/sizeof(leds.arr[0]); i++) {
+ 8000458: 683b ldr r3, [r7, #0]
+ 800045a: 3301 adds r3, #1
+ 800045c: 603b str r3, [r7, #0]
+ 800045e: 683b ldr r3, [r7, #0]
+ 8000460: 2b07 cmp r3, #7
+ 8000462: d9de bls.n 8000422 <TIM16_IRQHandler+0x2e>
+ }
+
+ if (leds_update_counter++ == 10) {
+ 8000464: 4b0f ldr r3, [pc, #60] ; (80004a4 <TIM16_IRQHandler+0xb0>)
+ 8000466: 681b ldr r3, [r3, #0]
+ 8000468: 1c59 adds r1, r3, #1
+ 800046a: 4a0e ldr r2, [pc, #56] ; (80004a4 <TIM16_IRQHandler+0xb0>)
+ 800046c: 6011 str r1, [r2, #0]
+ 800046e: 2b0a cmp r3, #10
+ 8000470: d110 bne.n 8000494 <TIM16_IRQHandler+0xa0>
+ leds_update_counter = 0;
+ 8000472: 4b0c ldr r3, [pc, #48] ; (80004a4 <TIM16_IRQHandler+0xb0>)
+ 8000474: 2200 movs r2, #0
+ 8000476: 601a str r2, [r3, #0]
+
+ /* Workaround for SPI hardware bug: Even if configured to 8-bit mode, the SPI will do a 16-bit transfer if the
+ * data register is accessed through a 16-bit write. Unfortunately, the STMCube register defs define DR as an
+ * uint16_t, so we have to do some magic here to force an 8-bit write. */
+ *((volatile uint8_t*)&(SPI1->DR)) = bits;
+ 8000478: 4a0b ldr r2, [pc, #44] ; (80004a8 <TIM16_IRQHandler+0xb4>)
+ 800047a: 1dfb adds r3, r7, #7
+ 800047c: 781b ldrb r3, [r3, #0]
+ 800047e: 7013 strb r3, [r2, #0]
+ SPI1->CR2 |= SPI_CR2_TXEIE;
+ 8000480: 4b0a ldr r3, [pc, #40] ; (80004ac <TIM16_IRQHandler+0xb8>)
+ 8000482: 685a ldr r2, [r3, #4]
+ 8000484: 4b09 ldr r3, [pc, #36] ; (80004ac <TIM16_IRQHandler+0xb8>)
+ 8000486: 2180 movs r1, #128 ; 0x80
+ 8000488: 430a orrs r2, r1
+ 800048a: 605a str r2, [r3, #4]
+ GPIOA->BRR = 1<<3;
+ 800048c: 2390 movs r3, #144 ; 0x90
+ 800048e: 05db lsls r3, r3, #23
+ 8000490: 2208 movs r2, #8
+ 8000492: 629a str r2, [r3, #40] ; 0x28
+ }
+ }
+}
+ 8000494: 46c0 nop ; (mov r8, r8)
+ 8000496: 46bd mov sp, r7
+ 8000498: b002 add sp, #8
+ 800049a: bd80 pop {r7, pc}
+ 800049c: 40014400 .word 0x40014400
+ 80004a0: 200000a8 .word 0x200000a8
+ 80004a4: 20000098 .word 0x20000098
+ 80004a8: 4001300c .word 0x4001300c
+ 80004ac: 40013000 .word 0x40013000
+
+080004b0 <NMI_Handler>:
+
+void NMI_Handler(void) {
+ 80004b0: b580 push {r7, lr}
+ 80004b2: af00 add r7, sp, #0
+ asm volatile ("bkpt");
+ 80004b4: be00 bkpt 0x0000
+}
+ 80004b6: 46c0 nop ; (mov r8, r8)
+ 80004b8: 46bd mov sp, r7
+ 80004ba: bd80 pop {r7, pc}
+
+080004bc <HardFault_Handler>:
+
+void HardFault_Handler(void) __attribute__((naked));
+void HardFault_Handler() {
+ asm volatile ("bkpt");
+ 80004bc: be00 bkpt 0x0000
+}
+ 80004be: 46c0 nop ; (mov r8, r8)
+
+080004c0 <SVC_Handler>:
+
+void SVC_Handler(void) {
+ 80004c0: b580 push {r7, lr}
+ 80004c2: af00 add r7, sp, #0
+ asm volatile ("bkpt");
+ 80004c4: be00 bkpt 0x0000
+}
+ 80004c6: 46c0 nop ; (mov r8, r8)
+ 80004c8: 46bd mov sp, r7
+ 80004ca: bd80 pop {r7, pc}
+
+080004cc <PendSV_Handler>:
+
+
+void PendSV_Handler(void) {
+ 80004cc: b580 push {r7, lr}
+ 80004ce: af00 add r7, sp, #0
+ asm volatile ("bkpt");
+ 80004d0: be00 bkpt 0x0000
+}
+ 80004d2: 46c0 nop ; (mov r8, r8)
+ 80004d4: 46bd mov sp, r7
+ 80004d6: bd80 pop {r7, pc}
+
+080004d8 <SysTick_Handler>:
+
+void SysTick_Handler(void) {
+ 80004d8: b580 push {r7, lr}
+ 80004da: af00 add r7, sp, #0
+ static int n = 0;
+ if (n++ == 10) {
+ 80004dc: 4b0a ldr r3, [pc, #40] ; (8000508 <SysTick_Handler+0x30>)
+ 80004de: 681b ldr r3, [r3, #0]
+ 80004e0: 1c59 adds r1, r3, #1
+ 80004e2: 4a09 ldr r2, [pc, #36] ; (8000508 <SysTick_Handler+0x30>)
+ 80004e4: 6011 str r1, [r2, #0]
+ 80004e6: 2b0a cmp r3, #10
+ 80004e8: d10a bne.n 8000500 <SysTick_Handler+0x28>
+ n = 0;
+ 80004ea: 4b07 ldr r3, [pc, #28] ; (8000508 <SysTick_Handler+0x30>)
+ 80004ec: 2200 movs r2, #0
+ 80004ee: 601a str r2, [r3, #0]
+ sys_time_seconds++;
+ 80004f0: 4b06 ldr r3, [pc, #24] ; (800050c <SysTick_Handler+0x34>)
+ 80004f2: 681b ldr r3, [r3, #0]
+ 80004f4: 1c5a adds r2, r3, #1
+ 80004f6: 4b05 ldr r3, [pc, #20] ; (800050c <SysTick_Handler+0x34>)
+ 80004f8: 601a str r2, [r3, #0]
+ leds.pps = 100; /* ms */
+ 80004fa: 4b05 ldr r3, [pc, #20] ; (8000510 <SysTick_Handler+0x38>)
+ 80004fc: 2264 movs r2, #100 ; 0x64
+ 80004fe: 619a str r2, [r3, #24]
+ }
+}
+ 8000500: 46c0 nop ; (mov r8, r8)
+ 8000502: 46bd mov sp, r7
+ 8000504: bd80 pop {r7, pc}
+ 8000506: 46c0 nop ; (mov r8, r8)
+ 8000508: 2000009c .word 0x2000009c
+ 800050c: 20000094 .word 0x20000094
+ 8000510: 200000a8 .word 0x200000a8
+
+08000514 <NVIC_EnableIRQ>:
+{
+ 8000514: b580 push {r7, lr}
+ 8000516: b082 sub sp, #8
+ 8000518: af00 add r7, sp, #0
+ 800051a: 0002 movs r2, r0
+ 800051c: 1dfb adds r3, r7, #7
+ 800051e: 701a strb r2, [r3, #0]
+ NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
+ 8000520: 1dfb adds r3, r7, #7
+ 8000522: 781b ldrb r3, [r3, #0]
+ 8000524: 001a movs r2, r3
+ 8000526: 231f movs r3, #31
+ 8000528: 401a ands r2, r3
+ 800052a: 4b04 ldr r3, [pc, #16] ; (800053c <NVIC_EnableIRQ+0x28>)
+ 800052c: 2101 movs r1, #1
+ 800052e: 4091 lsls r1, r2
+ 8000530: 000a movs r2, r1
+ 8000532: 601a str r2, [r3, #0]
+}
+ 8000534: 46c0 nop ; (mov r8, r8)
+ 8000536: 46bd mov sp, r7
+ 8000538: b002 add sp, #8
+ 800053a: bd80 pop {r7, pc}
+ 800053c: e000e100 .word 0xe000e100
+
+08000540 <NVIC_SetPriority>:
+{
+ 8000540: b590 push {r4, r7, lr}
+ 8000542: b083 sub sp, #12
+ 8000544: af00 add r7, sp, #0
+ 8000546: 0002 movs r2, r0
+ 8000548: 6039 str r1, [r7, #0]
+ 800054a: 1dfb adds r3, r7, #7
+ 800054c: 701a strb r2, [r3, #0]
+ if ((int32_t)(IRQn) < 0)
+ 800054e: 1dfb adds r3, r7, #7
+ 8000550: 781b ldrb r3, [r3, #0]
+ 8000552: 2b7f cmp r3, #127 ; 0x7f
+ 8000554: d932 bls.n 80005bc <NVIC_SetPriority+0x7c>
+ SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 8000556: 4a2f ldr r2, [pc, #188] ; (8000614 <NVIC_SetPriority+0xd4>)
+ 8000558: 1dfb adds r3, r7, #7
+ 800055a: 781b ldrb r3, [r3, #0]
+ 800055c: 0019 movs r1, r3
+ 800055e: 230f movs r3, #15
+ 8000560: 400b ands r3, r1
+ 8000562: 3b08 subs r3, #8
+ 8000564: 089b lsrs r3, r3, #2
+ 8000566: 3306 adds r3, #6
+ 8000568: 009b lsls r3, r3, #2
+ 800056a: 18d3 adds r3, r2, r3
+ 800056c: 3304 adds r3, #4
+ 800056e: 681b ldr r3, [r3, #0]
+ 8000570: 1dfa adds r2, r7, #7
+ 8000572: 7812 ldrb r2, [r2, #0]
+ 8000574: 0011 movs r1, r2
+ 8000576: 2203 movs r2, #3
+ 8000578: 400a ands r2, r1
+ 800057a: 00d2 lsls r2, r2, #3
+ 800057c: 21ff movs r1, #255 ; 0xff
+ 800057e: 4091 lsls r1, r2
+ 8000580: 000a movs r2, r1
+ 8000582: 43d2 mvns r2, r2
+ 8000584: 401a ands r2, r3
+ 8000586: 0011 movs r1, r2
+ (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
+ 8000588: 683b ldr r3, [r7, #0]
+ 800058a: 019b lsls r3, r3, #6
+ 800058c: 22ff movs r2, #255 ; 0xff
+ 800058e: 401a ands r2, r3
+ 8000590: 1dfb adds r3, r7, #7
+ 8000592: 781b ldrb r3, [r3, #0]
+ 8000594: 0018 movs r0, r3
+ 8000596: 2303 movs r3, #3
+ 8000598: 4003 ands r3, r0
+ 800059a: 00db lsls r3, r3, #3
+ 800059c: 409a lsls r2, r3
+ SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 800059e: 481d ldr r0, [pc, #116] ; (8000614 <NVIC_SetPriority+0xd4>)
+ 80005a0: 1dfb adds r3, r7, #7
+ 80005a2: 781b ldrb r3, [r3, #0]
+ 80005a4: 001c movs r4, r3
+ 80005a6: 230f movs r3, #15
+ 80005a8: 4023 ands r3, r4
+ 80005aa: 3b08 subs r3, #8
+ 80005ac: 089b lsrs r3, r3, #2
+ 80005ae: 430a orrs r2, r1
+ 80005b0: 3306 adds r3, #6
+ 80005b2: 009b lsls r3, r3, #2
+ 80005b4: 18c3 adds r3, r0, r3
+ 80005b6: 3304 adds r3, #4
+ 80005b8: 601a str r2, [r3, #0]
+}
+ 80005ba: e027 b.n 800060c <NVIC_SetPriority+0xcc>
+ NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 80005bc: 4a16 ldr r2, [pc, #88] ; (8000618 <NVIC_SetPriority+0xd8>)
+ 80005be: 1dfb adds r3, r7, #7
+ 80005c0: 781b ldrb r3, [r3, #0]
+ 80005c2: b25b sxtb r3, r3
+ 80005c4: 089b lsrs r3, r3, #2
+ 80005c6: 33c0 adds r3, #192 ; 0xc0
+ 80005c8: 009b lsls r3, r3, #2
+ 80005ca: 589b ldr r3, [r3, r2]
+ 80005cc: 1dfa adds r2, r7, #7
+ 80005ce: 7812 ldrb r2, [r2, #0]
+ 80005d0: 0011 movs r1, r2
+ 80005d2: 2203 movs r2, #3
+ 80005d4: 400a ands r2, r1
+ 80005d6: 00d2 lsls r2, r2, #3
+ 80005d8: 21ff movs r1, #255 ; 0xff
+ 80005da: 4091 lsls r1, r2
+ 80005dc: 000a movs r2, r1
+ 80005de: 43d2 mvns r2, r2
+ 80005e0: 401a ands r2, r3
+ 80005e2: 0011 movs r1, r2
+ (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
+ 80005e4: 683b ldr r3, [r7, #0]
+ 80005e6: 019b lsls r3, r3, #6
+ 80005e8: 22ff movs r2, #255 ; 0xff
+ 80005ea: 401a ands r2, r3
+ 80005ec: 1dfb adds r3, r7, #7
+ 80005ee: 781b ldrb r3, [r3, #0]
+ 80005f0: 0018 movs r0, r3
+ 80005f2: 2303 movs r3, #3
+ 80005f4: 4003 ands r3, r0
+ 80005f6: 00db lsls r3, r3, #3
+ 80005f8: 409a lsls r2, r3
+ NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 80005fa: 4807 ldr r0, [pc, #28] ; (8000618 <NVIC_SetPriority+0xd8>)
+ 80005fc: 1dfb adds r3, r7, #7
+ 80005fe: 781b ldrb r3, [r3, #0]
+ 8000600: b25b sxtb r3, r3
+ 8000602: 089b lsrs r3, r3, #2
+ 8000604: 430a orrs r2, r1
+ 8000606: 33c0 adds r3, #192 ; 0xc0
+ 8000608: 009b lsls r3, r3, #2
+ 800060a: 501a str r2, [r3, r0]
+}
+ 800060c: 46c0 nop ; (mov r8, r8)
+ 800060e: 46bd mov sp, r7
+ 8000610: b003 add sp, #12
+ 8000612: bd90 pop {r4, r7, pc}
+ 8000614: e000ed00 .word 0xe000ed00
+ 8000618: e000e100 .word 0xe000e100
+
+0800061c <adc_configure_scope_mode>:
+static void adc_dma_init(int burstlen);
+static void adc_timer_init(int psc, int ivl);
+
+
+/* Mode that can be used for debugging */
+void adc_configure_scope_mode(int sampling_interval_ns) {
+ 800061c: b580 push {r7, lr}
+ 800061e: b084 sub sp, #16
+ 8000620: af00 add r7, sp, #0
+ 8000622: 6078 str r0, [r7, #4]
+ adc_dma_init(sizeof(adc_buf)/sizeof(adc_buf[0]));
+ 8000624: 2380 movs r3, #128 ; 0x80
+ 8000626: 00db lsls r3, r3, #3
+ 8000628: 0018 movs r0, r3
+ 800062a: f000 f84b bl 80006c4 <adc_dma_init>
+
+ /* Clock from PCLK/4 instead of the internal exclusive high-speed RC oscillator. */
+ ADC1->CFGR2 = (2<<ADC_CFGR2_CKMODE_Pos); /* Use PCLK/4=12MHz */
+ 800062e: 4b21 ldr r3, [pc, #132] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 8000630: 2280 movs r2, #128 ; 0x80
+ 8000632: 0612 lsls r2, r2, #24
+ 8000634: 611a str r2, [r3, #16]
+ /* Sampling time 239.5 ADC clock cycles -> total conversion time 38.5us*/
+ ADC1->SMPR = (7<<ADC_SMPR_SMP_Pos);
+ 8000636: 4b1f ldr r3, [pc, #124] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 8000638: 2207 movs r2, #7
+ 800063a: 615a str r2, [r3, #20]
+
+ /* Setup DMA and triggering */
+ /* Trigger from TIM1 TRGO */
+ ADC1->CFGR1 = ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | (2<<ADC_CFGR1_EXTEN_Pos) | (1<<ADC_CFGR1_EXTSEL_Pos);
+ 800063c: 4b1d ldr r3, [pc, #116] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 800063e: 4a1e ldr r2, [pc, #120] ; (80006b8 <adc_configure_scope_mode+0x9c>)
+ 8000640: 60da str r2, [r3, #12]
+ ADC1->CHSELR = ADC_CHSELR_CHSEL2;
+ 8000642: 4b1c ldr r3, [pc, #112] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 8000644: 2204 movs r2, #4
+ 8000646: 629a str r2, [r3, #40] ; 0x28
+ /* Perform self-calibration */
+ ADC1->CR |= ADC_CR_ADCAL;
+ 8000648: 4b1a ldr r3, [pc, #104] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 800064a: 689a ldr r2, [r3, #8]
+ 800064c: 4b19 ldr r3, [pc, #100] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 800064e: 2180 movs r1, #128 ; 0x80
+ 8000650: 0609 lsls r1, r1, #24
+ 8000652: 430a orrs r2, r1
+ 8000654: 609a str r2, [r3, #8]
+ while (ADC1->CR & ADC_CR_ADCAL)
+ 8000656: 46c0 nop ; (mov r8, r8)
+ 8000658: 4b16 ldr r3, [pc, #88] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 800065a: 689b ldr r3, [r3, #8]
+ 800065c: 2b00 cmp r3, #0
+ 800065e: dbfb blt.n 8000658 <adc_configure_scope_mode+0x3c>
+ ;
+ /* Enable conversion */
+ ADC1->CR |= ADC_CR_ADEN;
+ 8000660: 4b14 ldr r3, [pc, #80] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 8000662: 689a ldr r2, [r3, #8]
+ 8000664: 4b13 ldr r3, [pc, #76] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 8000666: 2101 movs r1, #1
+ 8000668: 430a orrs r2, r1
+ 800066a: 609a str r2, [r3, #8]
+ ADC1->CR |= ADC_CR_ADSTART;
+ 800066c: 4b11 ldr r3, [pc, #68] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 800066e: 689a ldr r2, [r3, #8]
+ 8000670: 4b10 ldr r3, [pc, #64] ; (80006b4 <adc_configure_scope_mode+0x98>)
+ 8000672: 2104 movs r1, #4
+ 8000674: 430a orrs r2, r1
+ 8000676: 609a str r2, [r3, #8]
+
+ /* An ADC conversion takes 1.1667us, so to be sure we don't get data overruns we limit sampling to every 1.5us.
+ Since we don't have a spare PLL to generate the ADC sample clock and re-configuring the system clock just for this
+ would be overkill we round to 250ns increments. The minimum sampling rate is about 60Hz due to timer resolution. */
+ int cycles = sampling_interval_ns > 1500 ? sampling_interval_ns/250 : 6;
+ 8000678: 687b ldr r3, [r7, #4]
+ 800067a: 4a10 ldr r2, [pc, #64] ; (80006bc <adc_configure_scope_mode+0xa0>)
+ 800067c: 4293 cmp r3, r2
+ 800067e: dd06 ble.n 800068e <adc_configure_scope_mode+0x72>
+ 8000680: 687b ldr r3, [r7, #4]
+ 8000682: 21fa movs r1, #250 ; 0xfa
+ 8000684: 0018 movs r0, r3
+ 8000686: f001 f819 bl 80016bc <__divsi3>
+ 800068a: 0003 movs r3, r0
+ 800068c: e000 b.n 8000690 <adc_configure_scope_mode+0x74>
+ 800068e: 2306 movs r3, #6
+ 8000690: 60fb str r3, [r7, #12]
+ if (cycles > 0xffff)
+ 8000692: 68fa ldr r2, [r7, #12]
+ 8000694: 2380 movs r3, #128 ; 0x80
+ 8000696: 025b lsls r3, r3, #9
+ 8000698: 429a cmp r2, r3
+ 800069a: db01 blt.n 80006a0 <adc_configure_scope_mode+0x84>
+ cycles = 0xffff;
+ 800069c: 4b08 ldr r3, [pc, #32] ; (80006c0 <adc_configure_scope_mode+0xa4>)
+ 800069e: 60fb str r3, [r7, #12]
+ adc_timer_init(12/*250ns/tick*/, cycles);
+ 80006a0: 68fb ldr r3, [r7, #12]
+ 80006a2: 0019 movs r1, r3
+ 80006a4: 200c movs r0, #12
+ 80006a6: f000 f83d bl 8000724 <adc_timer_init>
+}
+ 80006aa: 46c0 nop ; (mov r8, r8)
+ 80006ac: 46bd mov sp, r7
+ 80006ae: b004 add sp, #16
+ 80006b0: bd80 pop {r7, pc}
+ 80006b2: 46c0 nop ; (mov r8, r8)
+ 80006b4: 40012400 .word 0x40012400
+ 80006b8: 00000843 .word 0x00000843
+ 80006bc: 000005dc .word 0x000005dc
+ 80006c0: 0000ffff .word 0x0000ffff
+
+080006c4 <adc_dma_init>:
+
+/* FIXME figure out the proper place to configure this. */
+#define ADC_TIMER_INTERVAL_US 20
+
+static void adc_dma_init(int burstlen) {
+ 80006c4: b580 push {r7, lr}
+ 80006c6: b082 sub sp, #8
+ 80006c8: af00 add r7, sp, #0
+ 80006ca: 6078 str r0, [r7, #4]
+ /* Configure DMA 1 Channel 1 to get rid of all the data */
+ DMA1_Channel1->CPAR = (unsigned int)&ADC1->DR;
+ 80006cc: 4b11 ldr r3, [pc, #68] ; (8000714 <adc_dma_init+0x50>)
+ 80006ce: 4a12 ldr r2, [pc, #72] ; (8000718 <adc_dma_init+0x54>)
+ 80006d0: 609a str r2, [r3, #8]
+ DMA1_Channel1->CMAR = (unsigned int)&adc_buf;
+ 80006d2: 4b10 ldr r3, [pc, #64] ; (8000714 <adc_dma_init+0x50>)
+ 80006d4: 4a11 ldr r2, [pc, #68] ; (800071c <adc_dma_init+0x58>)
+ 80006d6: 60da str r2, [r3, #12]
+ DMA1_Channel1->CNDTR = burstlen;
+ 80006d8: 4b0e ldr r3, [pc, #56] ; (8000714 <adc_dma_init+0x50>)
+ 80006da: 687a ldr r2, [r7, #4]
+ 80006dc: 605a str r2, [r3, #4]
+ DMA1_Channel1->CCR = (0<<DMA_CCR_PL_Pos);
+ 80006de: 4b0d ldr r3, [pc, #52] ; (8000714 <adc_dma_init+0x50>)
+ 80006e0: 2200 movs r2, #0
+ 80006e2: 601a str r2, [r3, #0]
+ DMA1_Channel1->CCR |=
+ 80006e4: 4b0b ldr r3, [pc, #44] ; (8000714 <adc_dma_init+0x50>)
+ 80006e6: 681a ldr r2, [r3, #0]
+ 80006e8: 4b0a ldr r3, [pc, #40] ; (8000714 <adc_dma_init+0x50>)
+ 80006ea: 490d ldr r1, [pc, #52] ; (8000720 <adc_dma_init+0x5c>)
+ 80006ec: 430a orrs r2, r1
+ 80006ee: 601a str r2, [r3, #0]
+ | (1<<DMA_CCR_PSIZE_Pos) /* 16 bit */
+ | DMA_CCR_MINC
+ | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */
+
+ /* triggered on transfer completion. We use this to process the ADC data */
+ NVIC_EnableIRQ(DMA1_Channel1_IRQn);
+ 80006f0: 2009 movs r0, #9
+ 80006f2: f7ff ff0f bl 8000514 <NVIC_EnableIRQ>
+ NVIC_SetPriority(DMA1_Channel1_IRQn, 2<<5);
+ 80006f6: 2140 movs r1, #64 ; 0x40
+ 80006f8: 2009 movs r0, #9
+ 80006fa: f7ff ff21 bl 8000540 <NVIC_SetPriority>
+
+ DMA1_Channel1->CCR |= DMA_CCR_EN; /* Enable channel */
+ 80006fe: 4b05 ldr r3, [pc, #20] ; (8000714 <adc_dma_init+0x50>)
+ 8000700: 681a ldr r2, [r3, #0]
+ 8000702: 4b04 ldr r3, [pc, #16] ; (8000714 <adc_dma_init+0x50>)
+ 8000704: 2101 movs r1, #1
+ 8000706: 430a orrs r2, r1
+ 8000708: 601a str r2, [r3, #0]
+}
+ 800070a: 46c0 nop ; (mov r8, r8)
+ 800070c: 46bd mov sp, r7
+ 800070e: b002 add sp, #8
+ 8000710: bd80 pop {r7, pc}
+ 8000712: 46c0 nop ; (mov r8, r8)
+ 8000714: 40020008 .word 0x40020008
+ 8000718: 40012440 .word 0x40012440
+ 800071c: 200000c8 .word 0x200000c8
+ 8000720: 000005a2 .word 0x000005a2
+
+08000724 <adc_timer_init>:
+
+static void adc_timer_init(int psc, int ivl) {
+ 8000724: b580 push {r7, lr}
+ 8000726: b082 sub sp, #8
+ 8000728: af00 add r7, sp, #0
+ 800072a: 6078 str r0, [r7, #4]
+ 800072c: 6039 str r1, [r7, #0]
+ TIM1->BDTR = TIM_BDTR_MOE; /* MOE is needed even though we only "output" a chip-internal signal TODO: Verify this. */
+ 800072e: 4b15 ldr r3, [pc, #84] ; (8000784 <adc_timer_init+0x60>)
+ 8000730: 2280 movs r2, #128 ; 0x80
+ 8000732: 0212 lsls r2, r2, #8
+ 8000734: 645a str r2, [r3, #68] ; 0x44
+ TIM1->CCMR2 = (6<<TIM_CCMR2_OC4M_Pos); /* PWM Mode 1 to get a clean trigger signal */
+ 8000736: 4b13 ldr r3, [pc, #76] ; (8000784 <adc_timer_init+0x60>)
+ 8000738: 22c0 movs r2, #192 ; 0xc0
+ 800073a: 01d2 lsls r2, r2, #7
+ 800073c: 61da str r2, [r3, #28]
+ TIM1->CCER = TIM_CCER_CC4E; /* Enable capture/compare unit 4 connected to ADC */
+ 800073e: 4b11 ldr r3, [pc, #68] ; (8000784 <adc_timer_init+0x60>)
+ 8000740: 2280 movs r2, #128 ; 0x80
+ 8000742: 0152 lsls r2, r2, #5
+ 8000744: 621a str r2, [r3, #32]
+ TIM1->CCR4 = 1; /* Trigger at start of timer cycle */
+ 8000746: 4b0f ldr r3, [pc, #60] ; (8000784 <adc_timer_init+0x60>)
+ 8000748: 2201 movs r2, #1
+ 800074a: 641a str r2, [r3, #64] ; 0x40
+ /* Set prescaler and interval */
+ TIM1->PSC = psc-1;
+ 800074c: 687b ldr r3, [r7, #4]
+ 800074e: 1e5a subs r2, r3, #1
+ 8000750: 4b0c ldr r3, [pc, #48] ; (8000784 <adc_timer_init+0x60>)
+ 8000752: 629a str r2, [r3, #40] ; 0x28
+ TIM1->ARR = ivl-1;
+ 8000754: 683b ldr r3, [r7, #0]
+ 8000756: 1e5a subs r2, r3, #1
+ 8000758: 4b0a ldr r3, [pc, #40] ; (8000784 <adc_timer_init+0x60>)
+ 800075a: 62da str r2, [r3, #44] ; 0x2c
+ /* Preload all values */
+ TIM1->EGR |= TIM_EGR_UG;
+ 800075c: 4b09 ldr r3, [pc, #36] ; (8000784 <adc_timer_init+0x60>)
+ 800075e: 695a ldr r2, [r3, #20]
+ 8000760: 4b08 ldr r3, [pc, #32] ; (8000784 <adc_timer_init+0x60>)
+ 8000762: 2101 movs r1, #1
+ 8000764: 430a orrs r2, r1
+ 8000766: 615a str r2, [r3, #20]
+ TIM1->CR1 = TIM_CR1_ARPE;
+ 8000768: 4b06 ldr r3, [pc, #24] ; (8000784 <adc_timer_init+0x60>)
+ 800076a: 2280 movs r2, #128 ; 0x80
+ 800076c: 601a str r2, [r3, #0]
+ /* And... go! */
+ TIM1->CR1 |= TIM_CR1_CEN;
+ 800076e: 4b05 ldr r3, [pc, #20] ; (8000784 <adc_timer_init+0x60>)
+ 8000770: 681a ldr r2, [r3, #0]
+ 8000772: 4b04 ldr r3, [pc, #16] ; (8000784 <adc_timer_init+0x60>)
+ 8000774: 2101 movs r1, #1
+ 8000776: 430a orrs r2, r1
+ 8000778: 601a str r2, [r3, #0]
+}
+ 800077a: 46c0 nop ; (mov r8, r8)
+ 800077c: 46bd mov sp, r7
+ 800077e: b002 add sp, #8
+ 8000780: bd80 pop {r7, pc}
+ 8000782: 46c0 nop ; (mov r8, r8)
+ 8000784: 40012c00 .word 0x40012c00
+
+08000788 <gdb_dump>:
+
+/* This acts as a no-op that provides a convenient point to set a breakpoint for the debug scope logic */
+static void gdb_dump(void) {
+ 8000788: b580 push {r7, lr}
+ 800078a: af00 add r7, sp, #0
+}
+ 800078c: 46c0 nop ; (mov r8, r8)
+ 800078e: 46bd mov sp, r7
+ 8000790: bd80 pop {r7, pc}
+
+08000792 <DMA1_Channel1_IRQHandler>:
+
+void DMA1_Channel1_IRQHandler(void) {
+ 8000792: b580 push {r7, lr}
+ 8000794: af00 add r7, sp, #0
+ /* Clear the interrupt flag */
+ DMA1->IFCR |= DMA_IFCR_CGIF1;
+ 8000796: 4b05 ldr r3, [pc, #20] ; (80007ac <DMA1_Channel1_IRQHandler+0x1a>)
+ 8000798: 685a ldr r2, [r3, #4]
+ 800079a: 4b04 ldr r3, [pc, #16] ; (80007ac <DMA1_Channel1_IRQHandler+0x1a>)
+ 800079c: 2101 movs r1, #1
+ 800079e: 430a orrs r2, r1
+ 80007a0: 605a str r2, [r3, #4]
+ gdb_dump();
+ 80007a2: f7ff fff1 bl 8000788 <gdb_dump>
+ adc_buf[i] = -255;
+ }
+ }
+ }
+ */
+}
+ 80007a6: 46c0 nop ; (mov r8, r8)
+ 80007a8: 46bd mov sp, r7
+ 80007aa: bd80 pop {r7, pc}
+ 80007ac: 40020000 .word 0x40020000
+
+080007b0 <NVIC_EnableIRQ>:
+{
+ 80007b0: b580 push {r7, lr}
+ 80007b2: b082 sub sp, #8
+ 80007b4: af00 add r7, sp, #0
+ 80007b6: 0002 movs r2, r0
+ 80007b8: 1dfb adds r3, r7, #7
+ 80007ba: 701a strb r2, [r3, #0]
+ NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
+ 80007bc: 1dfb adds r3, r7, #7
+ 80007be: 781b ldrb r3, [r3, #0]
+ 80007c0: 001a movs r2, r3
+ 80007c2: 231f movs r3, #31
+ 80007c4: 401a ands r2, r3
+ 80007c6: 4b04 ldr r3, [pc, #16] ; (80007d8 <NVIC_EnableIRQ+0x28>)
+ 80007c8: 2101 movs r1, #1
+ 80007ca: 4091 lsls r1, r2
+ 80007cc: 000a movs r2, r1
+ 80007ce: 601a str r2, [r3, #0]
+}
+ 80007d0: 46c0 nop ; (mov r8, r8)
+ 80007d2: 46bd mov sp, r7
+ 80007d4: b002 add sp, #8
+ 80007d6: bd80 pop {r7, pc}
+ 80007d8: e000e100 .word 0xe000e100
+
+080007dc <NVIC_DisableIRQ>:
+{
+ 80007dc: b580 push {r7, lr}
+ 80007de: b082 sub sp, #8
+ 80007e0: af00 add r7, sp, #0
+ 80007e2: 0002 movs r2, r0
+ 80007e4: 1dfb adds r3, r7, #7
+ 80007e6: 701a strb r2, [r3, #0]
+ NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
+ 80007e8: 1dfb adds r3, r7, #7
+ 80007ea: 781b ldrb r3, [r3, #0]
+ 80007ec: 001a movs r2, r3
+ 80007ee: 231f movs r3, #31
+ 80007f0: 4013 ands r3, r2
+ 80007f2: 4905 ldr r1, [pc, #20] ; (8000808 <NVIC_DisableIRQ+0x2c>)
+ 80007f4: 2201 movs r2, #1
+ 80007f6: 409a lsls r2, r3
+ 80007f8: 0013 movs r3, r2
+ 80007fa: 2280 movs r2, #128 ; 0x80
+ 80007fc: 508b str r3, [r1, r2]
+}
+ 80007fe: 46c0 nop ; (mov r8, r8)
+ 8000800: 46bd mov sp, r7
+ 8000802: b002 add sp, #8
+ 8000804: bd80 pop {r7, pc}
+ 8000806: 46c0 nop ; (mov r8, r8)
+ 8000808: e000e100 .word 0xe000e100
+
+0800080c <NVIC_SetPriority>:
+{
+ 800080c: b590 push {r4, r7, lr}
+ 800080e: b083 sub sp, #12
+ 8000810: af00 add r7, sp, #0
+ 8000812: 0002 movs r2, r0
+ 8000814: 6039 str r1, [r7, #0]
+ 8000816: 1dfb adds r3, r7, #7
+ 8000818: 701a strb r2, [r3, #0]
+ if ((int32_t)(IRQn) < 0)
+ 800081a: 1dfb adds r3, r7, #7
+ 800081c: 781b ldrb r3, [r3, #0]
+ 800081e: 2b7f cmp r3, #127 ; 0x7f
+ 8000820: d932 bls.n 8000888 <NVIC_SetPriority+0x7c>
+ SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 8000822: 4a2f ldr r2, [pc, #188] ; (80008e0 <NVIC_SetPriority+0xd4>)
+ 8000824: 1dfb adds r3, r7, #7
+ 8000826: 781b ldrb r3, [r3, #0]
+ 8000828: 0019 movs r1, r3
+ 800082a: 230f movs r3, #15
+ 800082c: 400b ands r3, r1
+ 800082e: 3b08 subs r3, #8
+ 8000830: 089b lsrs r3, r3, #2
+ 8000832: 3306 adds r3, #6
+ 8000834: 009b lsls r3, r3, #2
+ 8000836: 18d3 adds r3, r2, r3
+ 8000838: 3304 adds r3, #4
+ 800083a: 681b ldr r3, [r3, #0]
+ 800083c: 1dfa adds r2, r7, #7
+ 800083e: 7812 ldrb r2, [r2, #0]
+ 8000840: 0011 movs r1, r2
+ 8000842: 2203 movs r2, #3
+ 8000844: 400a ands r2, r1
+ 8000846: 00d2 lsls r2, r2, #3
+ 8000848: 21ff movs r1, #255 ; 0xff
+ 800084a: 4091 lsls r1, r2
+ 800084c: 000a movs r2, r1
+ 800084e: 43d2 mvns r2, r2
+ 8000850: 401a ands r2, r3
+ 8000852: 0011 movs r1, r2
+ (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
+ 8000854: 683b ldr r3, [r7, #0]
+ 8000856: 019b lsls r3, r3, #6
+ 8000858: 22ff movs r2, #255 ; 0xff
+ 800085a: 401a ands r2, r3
+ 800085c: 1dfb adds r3, r7, #7
+ 800085e: 781b ldrb r3, [r3, #0]
+ 8000860: 0018 movs r0, r3
+ 8000862: 2303 movs r3, #3
+ 8000864: 4003 ands r3, r0
+ 8000866: 00db lsls r3, r3, #3
+ 8000868: 409a lsls r2, r3
+ SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 800086a: 481d ldr r0, [pc, #116] ; (80008e0 <NVIC_SetPriority+0xd4>)
+ 800086c: 1dfb adds r3, r7, #7
+ 800086e: 781b ldrb r3, [r3, #0]
+ 8000870: 001c movs r4, r3
+ 8000872: 230f movs r3, #15
+ 8000874: 4023 ands r3, r4
+ 8000876: 3b08 subs r3, #8
+ 8000878: 089b lsrs r3, r3, #2
+ 800087a: 430a orrs r2, r1
+ 800087c: 3306 adds r3, #6
+ 800087e: 009b lsls r3, r3, #2
+ 8000880: 18c3 adds r3, r0, r3
+ 8000882: 3304 adds r3, #4
+ 8000884: 601a str r2, [r3, #0]
+}
+ 8000886: e027 b.n 80008d8 <NVIC_SetPriority+0xcc>
+ NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 8000888: 4a16 ldr r2, [pc, #88] ; (80008e4 <NVIC_SetPriority+0xd8>)
+ 800088a: 1dfb adds r3, r7, #7
+ 800088c: 781b ldrb r3, [r3, #0]
+ 800088e: b25b sxtb r3, r3
+ 8000890: 089b lsrs r3, r3, #2
+ 8000892: 33c0 adds r3, #192 ; 0xc0
+ 8000894: 009b lsls r3, r3, #2
+ 8000896: 589b ldr r3, [r3, r2]
+ 8000898: 1dfa adds r2, r7, #7
+ 800089a: 7812 ldrb r2, [r2, #0]
+ 800089c: 0011 movs r1, r2
+ 800089e: 2203 movs r2, #3
+ 80008a0: 400a ands r2, r1
+ 80008a2: 00d2 lsls r2, r2, #3
+ 80008a4: 21ff movs r1, #255 ; 0xff
+ 80008a6: 4091 lsls r1, r2
+ 80008a8: 000a movs r2, r1
+ 80008aa: 43d2 mvns r2, r2
+ 80008ac: 401a ands r2, r3
+ 80008ae: 0011 movs r1, r2
+ (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
+ 80008b0: 683b ldr r3, [r7, #0]
+ 80008b2: 019b lsls r3, r3, #6
+ 80008b4: 22ff movs r2, #255 ; 0xff
+ 80008b6: 401a ands r2, r3
+ 80008b8: 1dfb adds r3, r7, #7
+ 80008ba: 781b ldrb r3, [r3, #0]
+ 80008bc: 0018 movs r0, r3
+ 80008be: 2303 movs r3, #3
+ 80008c0: 4003 ands r3, r0
+ 80008c2: 00db lsls r3, r3, #3
+ 80008c4: 409a lsls r2, r3
+ NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
+ 80008c6: 4807 ldr r0, [pc, #28] ; (80008e4 <NVIC_SetPriority+0xd8>)
+ 80008c8: 1dfb adds r3, r7, #7
+ 80008ca: 781b ldrb r3, [r3, #0]
+ 80008cc: b25b sxtb r3, r3
+ 80008ce: 089b lsrs r3, r3, #2
+ 80008d0: 430a orrs r2, r1
+ 80008d2: 33c0 adds r3, #192 ; 0xc0
+ 80008d4: 009b lsls r3, r3, #2
+ 80008d6: 501a str r2, [r3, r0]
+}
+ 80008d8: 46c0 nop ; (mov r8, r8)
+ 80008da: 46bd mov sp, r7
+ 80008dc: b003 add sp, #12
+ 80008de: bd90 pop {r4, r7, pc}
+ 80008e0: e000ed00 .word 0xe000ed00
+ 80008e4: e000e100 .word 0xe000e100
+
+080008e8 <usart_dma_init>:
+
+volatile struct dma_tx_buf usart_tx_buf;
+
+static void usart_schedule_dma();
+
+void usart_dma_init() {
+ 80008e8: b580 push {r7, lr}
+ 80008ea: af00 add r7, sp, #0
+ usart_tx_buf.xfr_start = -1,
+ 80008ec: 4b17 ldr r3, [pc, #92] ; (800094c <usart_dma_init+0x64>)
+ 80008ee: 2201 movs r2, #1
+ 80008f0: 4252 negs r2, r2
+ 80008f2: 601a str r2, [r3, #0]
+ usart_tx_buf.xfr_end = 0,
+ 80008f4: 4b15 ldr r3, [pc, #84] ; (800094c <usart_dma_init+0x64>)
+ 80008f6: 2200 movs r2, #0
+ 80008f8: 605a str r2, [r3, #4]
+ usart_tx_buf.wr_pos = 0,
+ 80008fa: 4b14 ldr r3, [pc, #80] ; (800094c <usart_dma_init+0x64>)
+ 80008fc: 2200 movs r2, #0
+ 80008fe: 609a str r2, [r3, #8]
+
+ /* Configure DMA 1 Channel 2 to handle uart transmission */
+ DMA1_Channel2->CPAR = (unsigned int)&(USART1->TDR);
+ 8000900: 4b13 ldr r3, [pc, #76] ; (8000950 <usart_dma_init+0x68>)
+ 8000902: 4a14 ldr r2, [pc, #80] ; (8000954 <usart_dma_init+0x6c>)
+ 8000904: 609a str r2, [r3, #8]
+ DMA1_Channel2->CCR = (0<<DMA_CCR_PL_Pos)
+ 8000906: 4b12 ldr r3, [pc, #72] ; (8000950 <usart_dma_init+0x68>)
+ 8000908: 2292 movs r2, #146 ; 0x92
+ 800090a: 601a str r2, [r3, #0]
+ | (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */
+ | DMA_CCR_MINC
+ | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */
+
+ /* triggered on transfer completion. We use this to process the ADC data */
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ 800090c: 200a movs r0, #10
+ 800090e: f7ff ff4f bl 80007b0 <NVIC_EnableIRQ>
+ NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1<<5);
+ 8000912: 2120 movs r1, #32
+ 8000914: 200a movs r0, #10
+ 8000916: f7ff ff79 bl 800080c <NVIC_SetPriority>
+
+ USART1->CR1 = /* 8-bit -> M1, M0 clear */
+ 800091a: 4b0f ldr r3, [pc, #60] ; (8000958 <usart_dma_init+0x70>)
+ 800091c: 4a0f ldr r2, [pc, #60] ; (800095c <usart_dma_init+0x74>)
+ 800091e: 601a str r2, [r3, #0]
+ | USART_CR1_RXNEIE /* Enable receive interrupt */
+ /* other interrupts clear */
+ | USART_CR1_TE
+ | USART_CR1_RE;
+ /* Set divider for 1MBd @48MHz system clock. */
+ USART1->BRR = 48;
+ 8000920: 4b0d ldr r3, [pc, #52] ; (8000958 <usart_dma_init+0x70>)
+ 8000922: 2230 movs r2, #48 ; 0x30
+ 8000924: 60da str r2, [r3, #12]
+
+ USART1->CR2 = USART_CR2_TXINV | USART_CR2_RXINV;
+ 8000926: 4b0c ldr r3, [pc, #48] ; (8000958 <usart_dma_init+0x70>)
+ 8000928: 22c0 movs r2, #192 ; 0xc0
+ 800092a: 0292 lsls r2, r2, #10
+ 800092c: 605a str r2, [r3, #4]
+
+ USART1->CR3 |= USART_CR3_DMAT; /* TX DMA enable */
+ 800092e: 4b0a ldr r3, [pc, #40] ; (8000958 <usart_dma_init+0x70>)
+ 8000930: 689a ldr r2, [r3, #8]
+ 8000932: 4b09 ldr r3, [pc, #36] ; (8000958 <usart_dma_init+0x70>)
+ 8000934: 2180 movs r1, #128 ; 0x80
+ 8000936: 430a orrs r2, r1
+ 8000938: 609a str r2, [r3, #8]
+ /* Enable receive interrupt */
+ //NVIC_EnableIRQ(USART1_IRQn);
+ //NVIC_SetPriority(USART1_IRQn, 1);
+
+ /* And... go! */
+ USART1->CR1 |= USART_CR1_UE;
+ 800093a: 4b07 ldr r3, [pc, #28] ; (8000958 <usart_dma_init+0x70>)
+ 800093c: 681a ldr r2, [r3, #0]
+ 800093e: 4b06 ldr r3, [pc, #24] ; (8000958 <usart_dma_init+0x70>)
+ 8000940: 2101 movs r1, #1
+ 8000942: 430a orrs r2, r1
+ 8000944: 601a str r2, [r3, #0]
+}
+ 8000946: 46c0 nop ; (mov r8, r8)
+ 8000948: 46bd mov sp, r7
+ 800094a: bd80 pop {r7, pc}
+ 800094c: 200008c8 .word 0x200008c8
+ 8000950: 4002001c .word 0x4002001c
+ 8000954: 40013828 .word 0x40013828
+ 8000958: 40013800 .word 0x40013800
+ 800095c: 0000202c .word 0x0000202c
+
+08000960 <usart_schedule_dma>:
+
+void usart_schedule_dma() {
+ 8000960: b580 push {r7, lr}
+ 8000962: b084 sub sp, #16
+ 8000964: af00 add r7, sp, #0
+ /* This function is only called when the DMA channel is disabled. This means we don't have to guard it in IRQ
+ * disables. */
+ volatile struct dma_tx_buf *buf = &usart_tx_buf;
+ 8000966: 4b19 ldr r3, [pc, #100] ; (80009cc <usart_schedule_dma+0x6c>)
+ 8000968: 60bb str r3, [r7, #8]
+
+ size_t xfr_len, xfr_start = buf->xfr_end;
+ 800096a: 68bb ldr r3, [r7, #8]
+ 800096c: 685b ldr r3, [r3, #4]
+ 800096e: 607b str r3, [r7, #4]
+ if (buf->wr_pos > xfr_start) /* no wraparound */
+ 8000970: 68bb ldr r3, [r7, #8]
+ 8000972: 689b ldr r3, [r3, #8]
+ 8000974: 687a ldr r2, [r7, #4]
+ 8000976: 429a cmp r2, r3
+ 8000978: d205 bcs.n 8000986 <usart_schedule_dma+0x26>
+ xfr_len = buf->wr_pos - xfr_start;
+ 800097a: 68bb ldr r3, [r7, #8]
+ 800097c: 689a ldr r2, [r3, #8]
+ 800097e: 687b ldr r3, [r7, #4]
+ 8000980: 1ad3 subs r3, r2, r3
+ 8000982: 60fb str r3, [r7, #12]
+ 8000984: e004 b.n 8000990 <usart_schedule_dma+0x30>
+ else /* wraparound */
+ xfr_len = sizeof(buf->data) - xfr_start; /* schedule transfer until end of buffer */
+ 8000986: 687b ldr r3, [r7, #4]
+ 8000988: 2280 movs r2, #128 ; 0x80
+ 800098a: 0052 lsls r2, r2, #1
+ 800098c: 1ad3 subs r3, r2, r3
+ 800098e: 60fb str r3, [r7, #12]
+
+ buf->xfr_start = xfr_start;
+ 8000990: 68bb ldr r3, [r7, #8]
+ 8000992: 687a ldr r2, [r7, #4]
+ 8000994: 601a str r2, [r3, #0]
+ buf->xfr_end = (xfr_start + xfr_len) % sizeof(buf->data); /* handle wraparound */
+ 8000996: 687a ldr r2, [r7, #4]
+ 8000998: 68fb ldr r3, [r7, #12]
+ 800099a: 18d3 adds r3, r2, r3
+ 800099c: 22ff movs r2, #255 ; 0xff
+ 800099e: 401a ands r2, r3
+ 80009a0: 68bb ldr r3, [r7, #8]
+ 80009a2: 605a str r2, [r3, #4]
+
+ /* initiate transmission of new buffer */
+ DMA1_Channel2->CMAR = (uint32_t)(buf->data + xfr_start);
+ 80009a4: 68bb ldr r3, [r7, #8]
+ 80009a6: 330c adds r3, #12
+ 80009a8: 001a movs r2, r3
+ 80009aa: 687b ldr r3, [r7, #4]
+ 80009ac: 18d2 adds r2, r2, r3
+ 80009ae: 4b08 ldr r3, [pc, #32] ; (80009d0 <usart_schedule_dma+0x70>)
+ 80009b0: 60da str r2, [r3, #12]
+ DMA1_Channel2->CNDTR = xfr_len;
+ 80009b2: 4b07 ldr r3, [pc, #28] ; (80009d0 <usart_schedule_dma+0x70>)
+ 80009b4: 68fa ldr r2, [r7, #12]
+ 80009b6: 605a str r2, [r3, #4]
+ DMA1_Channel2->CCR |= DMA_CCR_EN;
+ 80009b8: 4b05 ldr r3, [pc, #20] ; (80009d0 <usart_schedule_dma+0x70>)
+ 80009ba: 681a ldr r2, [r3, #0]
+ 80009bc: 4b04 ldr r3, [pc, #16] ; (80009d0 <usart_schedule_dma+0x70>)
+ 80009be: 2101 movs r1, #1
+ 80009c0: 430a orrs r2, r1
+ 80009c2: 601a str r2, [r3, #0]
+}
+ 80009c4: 46c0 nop ; (mov r8, r8)
+ 80009c6: 46bd mov sp, r7
+ 80009c8: b004 add sp, #16
+ 80009ca: bd80 pop {r7, pc}
+ 80009cc: 200008c8 .word 0x200008c8
+ 80009d0: 4002001c .word 0x4002001c
+
+080009d4 <usart_dma_fifo_push>:
+
+int usart_dma_fifo_push(volatile struct dma_tx_buf *buf, char c) {
+ 80009d4: b580 push {r7, lr}
+ 80009d6: b082 sub sp, #8
+ 80009d8: af00 add r7, sp, #0
+ 80009da: 6078 str r0, [r7, #4]
+ 80009dc: 000a movs r2, r1
+ 80009de: 1cfb adds r3, r7, #3
+ 80009e0: 701a strb r2, [r3, #0]
+ /* This function must be guarded by IRQ disable since the IRQ may schedule a new transfer and charge pos/start. */
+ NVIC_DisableIRQ(DMA1_Channel2_3_IRQn);
+ 80009e2: 200a movs r0, #10
+ 80009e4: f7ff fefa bl 80007dc <NVIC_DisableIRQ>
+
+ if (buf->wr_pos == buf->xfr_start) {
+ 80009e8: 687b ldr r3, [r7, #4]
+ 80009ea: 689a ldr r2, [r3, #8]
+ 80009ec: 687b ldr r3, [r7, #4]
+ 80009ee: 681b ldr r3, [r3, #0]
+ 80009f0: 429a cmp r2, r3
+ 80009f2: d105 bne.n 8000a00 <usart_dma_fifo_push+0x2c>
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ 80009f4: 200a movs r0, #10
+ 80009f6: f7ff fedb bl 80007b0 <NVIC_EnableIRQ>
+ return -EBUSY;
+ 80009fa: 2310 movs r3, #16
+ 80009fc: 425b negs r3, r3
+ 80009fe: e011 b.n 8000a24 <usart_dma_fifo_push+0x50>
+ }
+
+ buf->data[buf->wr_pos] = c;
+ 8000a00: 687b ldr r3, [r7, #4]
+ 8000a02: 689b ldr r3, [r3, #8]
+ 8000a04: 687a ldr r2, [r7, #4]
+ 8000a06: 18d3 adds r3, r2, r3
+ 8000a08: 1cfa adds r2, r7, #3
+ 8000a0a: 7812 ldrb r2, [r2, #0]
+ 8000a0c: 731a strb r2, [r3, #12]
+ buf->wr_pos = (buf->wr_pos + 1) % sizeof(buf->data);
+ 8000a0e: 687b ldr r3, [r7, #4]
+ 8000a10: 689b ldr r3, [r3, #8]
+ 8000a12: 3301 adds r3, #1
+ 8000a14: 22ff movs r2, #255 ; 0xff
+ 8000a16: 401a ands r2, r3
+ 8000a18: 687b ldr r3, [r7, #4]
+ 8000a1a: 609a str r2, [r3, #8]
+
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ 8000a1c: 200a movs r0, #10
+ 8000a1e: f7ff fec7 bl 80007b0 <NVIC_EnableIRQ>
+ return 0;
+ 8000a22: 2300 movs r3, #0
+}
+ 8000a24: 0018 movs r0, r3
+ 8000a26: 46bd mov sp, r7
+ 8000a28: b002 add sp, #8
+ 8000a2a: bd80 pop {r7, pc}
+
+08000a2c <usart_putc>:
+
+void usart_putc(char c) {
+ 8000a2c: b580 push {r7, lr}
+ 8000a2e: b082 sub sp, #8
+ 8000a30: af00 add r7, sp, #0
+ 8000a32: 0002 movs r2, r0
+ 8000a34: 1dfb adds r3, r7, #7
+ 8000a36: 701a strb r2, [r3, #0]
+ /* push char to fifo, busy-loop if stalled to wait for USART to empty fifo via DMA */
+ while (usart_dma_fifo_push(&usart_tx_buf, c) == -EBUSY) {
+ 8000a38: 46c0 nop ; (mov r8, r8)
+ 8000a3a: 1dfb adds r3, r7, #7
+ 8000a3c: 781a ldrb r2, [r3, #0]
+ 8000a3e: 4b06 ldr r3, [pc, #24] ; (8000a58 <usart_putc+0x2c>)
+ 8000a40: 0011 movs r1, r2
+ 8000a42: 0018 movs r0, r3
+ 8000a44: f7ff ffc6 bl 80009d4 <usart_dma_fifo_push>
+ 8000a48: 0003 movs r3, r0
+ 8000a4a: 3310 adds r3, #16
+ 8000a4c: d0f5 beq.n 8000a3a <usart_putc+0xe>
+ /* idle */
+ }
+}
+ 8000a4e: 46c0 nop ; (mov r8, r8)
+ 8000a50: 46c0 nop ; (mov r8, r8)
+ 8000a52: 46bd mov sp, r7
+ 8000a54: b002 add sp, #8
+ 8000a56: bd80 pop {r7, pc}
+ 8000a58: 200008c8 .word 0x200008c8
+
+08000a5c <DMA1_Channel2_3_IRQHandler>:
+
+void DMA1_Channel2_3_IRQHandler(void) {
+ 8000a5c: b580 push {r7, lr}
+ 8000a5e: af00 add r7, sp, #0
+ /* Transfer complete */
+ DMA1->IFCR |= DMA_IFCR_CTCIF2;
+ 8000a60: 4b0b ldr r3, [pc, #44] ; (8000a90 <DMA1_Channel2_3_IRQHandler+0x34>)
+ 8000a62: 685a ldr r2, [r3, #4]
+ 8000a64: 4b0a ldr r3, [pc, #40] ; (8000a90 <DMA1_Channel2_3_IRQHandler+0x34>)
+ 8000a66: 2120 movs r1, #32
+ 8000a68: 430a orrs r2, r1
+ 8000a6a: 605a str r2, [r3, #4]
+
+ DMA1_Channel2->CCR &= ~DMA_CCR_EN;
+ 8000a6c: 4b09 ldr r3, [pc, #36] ; (8000a94 <DMA1_Channel2_3_IRQHandler+0x38>)
+ 8000a6e: 681a ldr r2, [r3, #0]
+ 8000a70: 4b08 ldr r3, [pc, #32] ; (8000a94 <DMA1_Channel2_3_IRQHandler+0x38>)
+ 8000a72: 2101 movs r1, #1
+ 8000a74: 438a bics r2, r1
+ 8000a76: 601a str r2, [r3, #0]
+ if (usart_tx_buf.wr_pos != usart_tx_buf.xfr_end) /* buffer not empty */
+ 8000a78: 4b07 ldr r3, [pc, #28] ; (8000a98 <DMA1_Channel2_3_IRQHandler+0x3c>)
+ 8000a7a: 689a ldr r2, [r3, #8]
+ 8000a7c: 4b06 ldr r3, [pc, #24] ; (8000a98 <DMA1_Channel2_3_IRQHandler+0x3c>)
+ 8000a7e: 685b ldr r3, [r3, #4]
+ 8000a80: 429a cmp r2, r3
+ 8000a82: d001 beq.n 8000a88 <DMA1_Channel2_3_IRQHandler+0x2c>
+ usart_schedule_dma();
+ 8000a84: f7ff ff6c bl 8000960 <usart_schedule_dma>
+}
+ 8000a88: 46c0 nop ; (mov r8, r8)
+ 8000a8a: 46bd mov sp, r7
+ 8000a8c: bd80 pop {r7, pc}
+ 8000a8e: 46c0 nop ; (mov r8, r8)
+ 8000a90: 40020000 .word 0x40020000
+ 8000a94: 4002001c .word 0x4002001c
+ 8000a98: 200008c8 .word 0x200008c8
+
+08000a9c <usart_send_packet>:
+
+void usart_send_packet(const uint8_t *data, size_t len) {
+ 8000a9c: b580 push {r7, lr}
+ 8000a9e: b082 sub sp, #8
+ 8000aa0: af00 add r7, sp, #0
+ 8000aa2: 6078 str r0, [r7, #4]
+ 8000aa4: 6039 str r1, [r7, #0]
+ /* ignore return value as putf is blocking and always succeeds */
+ (void)cobs_encode_usart((char *)data, len);
+ 8000aa6: 683a ldr r2, [r7, #0]
+ 8000aa8: 687b ldr r3, [r7, #4]
+ 8000aaa: 0011 movs r1, r2
+ 8000aac: 0018 movs r0, r3
+ 8000aae: f000 f870 bl 8000b92 <cobs_encode_usart>
+
+ /* If the DMA stream is idle right now, schedule a transfer */
+ if (!(DMA1_Channel2->CCR & DMA_CCR_EN))
+ 8000ab2: 4b05 ldr r3, [pc, #20] ; (8000ac8 <usart_send_packet+0x2c>)
+ 8000ab4: 681b ldr r3, [r3, #0]
+ 8000ab6: 2201 movs r2, #1
+ 8000ab8: 4013 ands r3, r2
+ 8000aba: d101 bne.n 8000ac0 <usart_send_packet+0x24>
+ usart_schedule_dma();
+ 8000abc: f7ff ff50 bl 8000960 <usart_schedule_dma>
+}
+ 8000ac0: 46c0 nop ; (mov r8, r8)
+ 8000ac2: 46bd mov sp, r7
+ 8000ac4: b002 add sp, #8
+ 8000ac6: bd80 pop {r7, pc}
+ 8000ac8: 4002001c .word 0x4002001c
+
+08000acc <cobs_encode>:
+ @ ensures \result == -1;
+ @
+ @ complete behaviors;
+ @ disjoint behaviors;
+ @*/
+ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen) {
+ 8000acc: b580 push {r7, lr}
+ 8000ace: b088 sub sp, #32
+ 8000ad0: af00 add r7, sp, #0
+ 8000ad2: 60f8 str r0, [r7, #12]
+ 8000ad4: 60b9 str r1, [r7, #8]
+ 8000ad6: 607a str r2, [r7, #4]
+ 8000ad8: 603b str r3, [r7, #0]
+ if (dstlen > 65535 || srclen > 254)
+ 8000ada: 68ba ldr r2, [r7, #8]
+ 8000adc: 2380 movs r3, #128 ; 0x80
+ 8000ade: 025b lsls r3, r3, #9
+ 8000ae0: 429a cmp r2, r3
+ 8000ae2: d202 bcs.n 8000aea <cobs_encode+0x1e>
+ 8000ae4: 683b ldr r3, [r7, #0]
+ 8000ae6: 2bfe cmp r3, #254 ; 0xfe
+ 8000ae8: d902 bls.n 8000af0 <cobs_encode+0x24>
+ return -1;
+ 8000aea: 2301 movs r3, #1
+ 8000aec: 425b negs r3, r3
+ 8000aee: e04c b.n 8000b8a <cobs_encode+0xbe>
+ //@ assert 0 <= dstlen <= 65535 && 0 <= srclen <= 254;
+
+ if (dstlen < srclen+2)
+ 8000af0: 683b ldr r3, [r7, #0]
+ 8000af2: 3302 adds r3, #2
+ 8000af4: 68ba ldr r2, [r7, #8]
+ 8000af6: 429a cmp r2, r3
+ 8000af8: d202 bcs.n 8000b00 <cobs_encode+0x34>
+ return -1;
+ 8000afa: 2301 movs r3, #1
+ 8000afc: 425b negs r3, r3
+ 8000afe: e044 b.n 8000b8a <cobs_encode+0xbe>
+ //@ assert 0 <= srclen < srclen+2 <= dstlen;
+
+ size_t p = 0;
+ 8000b00: 2300 movs r3, #0
+ 8000b02: 61fb str r3, [r7, #28]
+ @ loop invariant \forall integer i; 0 <= i < p ==> dst[i] != 0;
+ @ loop invariant \forall integer i; 0 < i < p ==> (src[i-1] != 0 ==> dst[i] == src[i-1]);
+ @ loop assigns p, dst[0..srclen+1];
+ @ loop variant srclen-p+1;
+ @*/
+ while (p <= srclen) {
+ 8000b04: e036 b.n 8000b74 <cobs_encode+0xa8>
+
+ char val;
+ if (p != 0 && src[p-1] != 0) {
+ 8000b06: 69fb ldr r3, [r7, #28]
+ 8000b08: 2b00 cmp r3, #0
+ 8000b0a: d00f beq.n 8000b2c <cobs_encode+0x60>
+ 8000b0c: 69fb ldr r3, [r7, #28]
+ 8000b0e: 3b01 subs r3, #1
+ 8000b10: 687a ldr r2, [r7, #4]
+ 8000b12: 18d3 adds r3, r2, r3
+ 8000b14: 781b ldrb r3, [r3, #0]
+ 8000b16: 2b00 cmp r3, #0
+ 8000b18: d008 beq.n 8000b2c <cobs_encode+0x60>
+ val = src[p-1];
+ 8000b1a: 69fb ldr r3, [r7, #28]
+ 8000b1c: 3b01 subs r3, #1
+ 8000b1e: 687a ldr r2, [r7, #4]
+ 8000b20: 18d2 adds r2, r2, r3
+ 8000b22: 231b movs r3, #27
+ 8000b24: 18fb adds r3, r7, r3
+ 8000b26: 7812 ldrb r2, [r2, #0]
+ 8000b28: 701a strb r2, [r3, #0]
+ 8000b2a: e019 b.n 8000b60 <cobs_encode+0x94>
+
+ } else {
+ size_t q = p;
+ 8000b2c: 69fb ldr r3, [r7, #28]
+ 8000b2e: 617b str r3, [r7, #20]
+ /*@ loop invariant 0 <= p <= q <= srclen;
+ @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0;
+ @ loop assigns q;
+ @ loop variant srclen-q;
+ @*/
+ while (q < srclen && src[q] != 0)
+ 8000b30: e002 b.n 8000b38 <cobs_encode+0x6c>
+ q++;
+ 8000b32: 697b ldr r3, [r7, #20]
+ 8000b34: 3301 adds r3, #1
+ 8000b36: 617b str r3, [r7, #20]
+ while (q < srclen && src[q] != 0)
+ 8000b38: 697a ldr r2, [r7, #20]
+ 8000b3a: 683b ldr r3, [r7, #0]
+ 8000b3c: 429a cmp r2, r3
+ 8000b3e: d205 bcs.n 8000b4c <cobs_encode+0x80>
+ 8000b40: 687a ldr r2, [r7, #4]
+ 8000b42: 697b ldr r3, [r7, #20]
+ 8000b44: 18d3 adds r3, r2, r3
+ 8000b46: 781b ldrb r3, [r3, #0]
+ 8000b48: 2b00 cmp r3, #0
+ 8000b4a: d1f2 bne.n 8000b32 <cobs_encode+0x66>
+ //@ assert q == srclen || src[q] == 0;
+ //@ assert q <= srclen <= 254;
+ val = (char)q-p+1;
+ 8000b4c: 697b ldr r3, [r7, #20]
+ 8000b4e: b2da uxtb r2, r3
+ 8000b50: 69fb ldr r3, [r7, #28]
+ 8000b52: b2db uxtb r3, r3
+ 8000b54: 1ad3 subs r3, r2, r3
+ 8000b56: b2da uxtb r2, r3
+ 8000b58: 231b movs r3, #27
+ 8000b5a: 18fb adds r3, r7, r3
+ 8000b5c: 3201 adds r2, #1
+ 8000b5e: 701a strb r2, [r3, #0]
+ //@ assert val != 0;
+ }
+
+ dst[p] = val;
+ 8000b60: 68fa ldr r2, [r7, #12]
+ 8000b62: 69fb ldr r3, [r7, #28]
+ 8000b64: 18d3 adds r3, r2, r3
+ 8000b66: 221b movs r2, #27
+ 8000b68: 18ba adds r2, r7, r2
+ 8000b6a: 7812 ldrb r2, [r2, #0]
+ 8000b6c: 701a strb r2, [r3, #0]
+ p++;
+ 8000b6e: 69fb ldr r3, [r7, #28]
+ 8000b70: 3301 adds r3, #1
+ 8000b72: 61fb str r3, [r7, #28]
+ while (p <= srclen) {
+ 8000b74: 69fa ldr r2, [r7, #28]
+ 8000b76: 683b ldr r3, [r7, #0]
+ 8000b78: 429a cmp r2, r3
+ 8000b7a: d9c4 bls.n 8000b06 <cobs_encode+0x3a>
+ }
+
+ dst[p] = 0;
+ 8000b7c: 68fa ldr r2, [r7, #12]
+ 8000b7e: 69fb ldr r3, [r7, #28]
+ 8000b80: 18d3 adds r3, r2, r3
+ 8000b82: 2200 movs r2, #0
+ 8000b84: 701a strb r2, [r3, #0]
+ //@ assert p == srclen+1;
+
+ return srclen+2;
+ 8000b86: 683b ldr r3, [r7, #0]
+ 8000b88: 3302 adds r3, #2
+}
+ 8000b8a: 0018 movs r0, r3
+ 8000b8c: 46bd mov sp, r7
+ 8000b8e: b008 add sp, #32
+ 8000b90: bd80 pop {r7, pc}
+
+08000b92 <cobs_encode_usart>:
+
+int cobs_encode_usart(char *src, size_t srclen) {
+ 8000b92: b580 push {r7, lr}
+ 8000b94: b086 sub sp, #24
+ 8000b96: af00 add r7, sp, #0
+ 8000b98: 6078 str r0, [r7, #4]
+ 8000b9a: 6039 str r1, [r7, #0]
+ if (srclen > 254)
+ 8000b9c: 683b ldr r3, [r7, #0]
+ 8000b9e: 2bfe cmp r3, #254 ; 0xfe
+ 8000ba0: d902 bls.n 8000ba8 <cobs_encode_usart+0x16>
+ return -1;
+ 8000ba2: 2301 movs r3, #1
+ 8000ba4: 425b negs r3, r3
+ 8000ba6: e040 b.n 8000c2a <cobs_encode_usart+0x98>
+ //@ assert 0 <= srclen <= 254;
+
+ size_t p = 0;
+ 8000ba8: 2300 movs r3, #0
+ 8000baa: 617b str r3, [r7, #20]
+ /*@ loop invariant 0 <= p <= srclen+1;
+ @ loop assigns p;
+ @ loop variant srclen-p+1;
+ @*/
+ while (p <= srclen) {
+ 8000bac: e035 b.n 8000c1a <cobs_encode_usart+0x88>
+
+ char val;
+ if (p != 0 && src[p-1] != 0) {
+ 8000bae: 697b ldr r3, [r7, #20]
+ 8000bb0: 2b00 cmp r3, #0
+ 8000bb2: d00f beq.n 8000bd4 <cobs_encode_usart+0x42>
+ 8000bb4: 697b ldr r3, [r7, #20]
+ 8000bb6: 3b01 subs r3, #1
+ 8000bb8: 687a ldr r2, [r7, #4]
+ 8000bba: 18d3 adds r3, r2, r3
+ 8000bbc: 781b ldrb r3, [r3, #0]
+ 8000bbe: 2b00 cmp r3, #0
+ 8000bc0: d008 beq.n 8000bd4 <cobs_encode_usart+0x42>
+ val = src[p-1];
+ 8000bc2: 697b ldr r3, [r7, #20]
+ 8000bc4: 3b01 subs r3, #1
+ 8000bc6: 687a ldr r2, [r7, #4]
+ 8000bc8: 18d2 adds r2, r2, r3
+ 8000bca: 2313 movs r3, #19
+ 8000bcc: 18fb adds r3, r7, r3
+ 8000bce: 7812 ldrb r2, [r2, #0]
+ 8000bd0: 701a strb r2, [r3, #0]
+ 8000bd2: e019 b.n 8000c08 <cobs_encode_usart+0x76>
+
+ } else {
+ size_t q = p;
+ 8000bd4: 697b ldr r3, [r7, #20]
+ 8000bd6: 60fb str r3, [r7, #12]
+ /*@ loop invariant 0 <= p <= q <= srclen;
+ @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0;
+ @ loop assigns q;
+ @ loop variant srclen-q;
+ @*/
+ while (q < srclen && src[q] != 0)
+ 8000bd8: e002 b.n 8000be0 <cobs_encode_usart+0x4e>
+ q++;
+ 8000bda: 68fb ldr r3, [r7, #12]
+ 8000bdc: 3301 adds r3, #1
+ 8000bde: 60fb str r3, [r7, #12]
+ while (q < srclen && src[q] != 0)
+ 8000be0: 68fa ldr r2, [r7, #12]
+ 8000be2: 683b ldr r3, [r7, #0]
+ 8000be4: 429a cmp r2, r3
+ 8000be6: d205 bcs.n 8000bf4 <cobs_encode_usart+0x62>
+ 8000be8: 687a ldr r2, [r7, #4]
+ 8000bea: 68fb ldr r3, [r7, #12]
+ 8000bec: 18d3 adds r3, r2, r3
+ 8000bee: 781b ldrb r3, [r3, #0]
+ 8000bf0: 2b00 cmp r3, #0
+ 8000bf2: d1f2 bne.n 8000bda <cobs_encode_usart+0x48>
+ //@ assert q == srclen || src[q] == 0;
+ //@ assert q <= srclen <= 254;
+ val = (char)q-p+1;
+ 8000bf4: 68fb ldr r3, [r7, #12]
+ 8000bf6: b2da uxtb r2, r3
+ 8000bf8: 697b ldr r3, [r7, #20]
+ 8000bfa: b2db uxtb r3, r3
+ 8000bfc: 1ad3 subs r3, r2, r3
+ 8000bfe: b2da uxtb r2, r3
+ 8000c00: 2313 movs r3, #19
+ 8000c02: 18fb adds r3, r7, r3
+ 8000c04: 3201 adds r2, #1
+ 8000c06: 701a strb r2, [r3, #0]
+ //@ assert val != 0;
+ }
+
+ usart_putc(val);
+ 8000c08: 2313 movs r3, #19
+ 8000c0a: 18fb adds r3, r7, r3
+ 8000c0c: 781b ldrb r3, [r3, #0]
+ 8000c0e: 0018 movs r0, r3
+ 8000c10: f7ff ff0c bl 8000a2c <usart_putc>
+ p++;
+ 8000c14: 697b ldr r3, [r7, #20]
+ 8000c16: 3301 adds r3, #1
+ 8000c18: 617b str r3, [r7, #20]
+ while (p <= srclen) {
+ 8000c1a: 697a ldr r2, [r7, #20]
+ 8000c1c: 683b ldr r3, [r7, #0]
+ 8000c1e: 429a cmp r2, r3
+ 8000c20: d9c5 bls.n 8000bae <cobs_encode_usart+0x1c>
+ }
+
+ usart_putc(0);
+ 8000c22: 2000 movs r0, #0
+ 8000c24: f7ff ff02 bl 8000a2c <usart_putc>
+ //@ assert p == srclen+1;
+
+ return 0;
+ 8000c28: 2300 movs r3, #0
+}
+ 8000c2a: 0018 movs r0, r3
+ 8000c2c: 46bd mov sp, r7
+ 8000c2e: b006 add sp, #24
+ 8000c30: bd80 pop {r7, pc}
+
+08000c32 <cobs_decode>:
+ @ ensures \result == -1;
+ @
+ @ complete behaviors;
+ @ disjoint behaviors;
+ @*/
+ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen) {
+ 8000c32: b580 push {r7, lr}
+ 8000c34: b088 sub sp, #32
+ 8000c36: af00 add r7, sp, #0
+ 8000c38: 60f8 str r0, [r7, #12]
+ 8000c3a: 60b9 str r1, [r7, #8]
+ 8000c3c: 607a str r2, [r7, #4]
+ 8000c3e: 603b str r3, [r7, #0]
+ if (dstlen > 65535 || srclen > 65535)
+ 8000c40: 68ba ldr r2, [r7, #8]
+ 8000c42: 2380 movs r3, #128 ; 0x80
+ 8000c44: 025b lsls r3, r3, #9
+ 8000c46: 429a cmp r2, r3
+ 8000c48: d204 bcs.n 8000c54 <cobs_decode+0x22>
+ 8000c4a: 683a ldr r2, [r7, #0]
+ 8000c4c: 2380 movs r3, #128 ; 0x80
+ 8000c4e: 025b lsls r3, r3, #9
+ 8000c50: 429a cmp r2, r3
+ 8000c52: d302 bcc.n 8000c5a <cobs_decode+0x28>
+ return -1;
+ 8000c54: 2301 movs r3, #1
+ 8000c56: 425b negs r3, r3
+ 8000c58: e052 b.n 8000d00 <cobs_decode+0xce>
+
+ if (srclen < 1)
+ 8000c5a: 683b ldr r3, [r7, #0]
+ 8000c5c: 2b00 cmp r3, #0
+ 8000c5e: d102 bne.n 8000c66 <cobs_decode+0x34>
+ return -1;
+ 8000c60: 2301 movs r3, #1
+ 8000c62: 425b negs r3, r3
+ 8000c64: e04c b.n 8000d00 <cobs_decode+0xce>
+
+ if (dstlen < srclen)
+ 8000c66: 68ba ldr r2, [r7, #8]
+ 8000c68: 683b ldr r3, [r7, #0]
+ 8000c6a: 429a cmp r2, r3
+ 8000c6c: d202 bcs.n 8000c74 <cobs_decode+0x42>
+ return -1;
+ 8000c6e: 2301 movs r3, #1
+ 8000c70: 425b negs r3, r3
+ 8000c72: e045 b.n 8000d00 <cobs_decode+0xce>
+
+ size_t p = 1;
+ 8000c74: 2301 movs r3, #1
+ 8000c76: 61fb str r3, [r7, #28]
+ size_t c = (unsigned char)src[0];
+ 8000c78: 687b ldr r3, [r7, #4]
+ 8000c7a: 781b ldrb r3, [r3, #0]
+ 8000c7c: 61bb str r3, [r7, #24]
+ //@ assert 0 <= c < 256;
+ //@ assert 0 <= c;
+ //@ assert c < 256;
+ if (c == 0)
+ 8000c7e: 69bb ldr r3, [r7, #24]
+ 8000c80: 2b00 cmp r3, #0
+ 8000c82: d124 bne.n 8000cce <cobs_decode+0x9c>
+ return -2; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
+ 8000c84: 2302 movs r3, #2
+ 8000c86: 425b negs r3, r3
+ 8000c88: e03a b.n 8000d00 <cobs_decode+0xce>
+ @ loop assigns dst[0..dstlen-1], p, c;
+ @ loop variant srclen-p;
+ @*/
+ while (p < srclen && src[p]) {
+ char val;
+ c--;
+ 8000c8a: 69bb ldr r3, [r7, #24]
+ 8000c8c: 3b01 subs r3, #1
+ 8000c8e: 61bb str r3, [r7, #24]
+
+ //@ assert src[p] != 0;
+ if (c == 0) {
+ 8000c90: 69bb ldr r3, [r7, #24]
+ 8000c92: 2b00 cmp r3, #0
+ 8000c94: d109 bne.n 8000caa <cobs_decode+0x78>
+ c = (unsigned char)src[p];
+ 8000c96: 687a ldr r2, [r7, #4]
+ 8000c98: 69fb ldr r3, [r7, #28]
+ 8000c9a: 18d3 adds r3, r2, r3
+ 8000c9c: 781b ldrb r3, [r3, #0]
+ 8000c9e: 61bb str r3, [r7, #24]
+ val = 0;
+ 8000ca0: 2317 movs r3, #23
+ 8000ca2: 18fb adds r3, r7, r3
+ 8000ca4: 2200 movs r2, #0
+ 8000ca6: 701a strb r2, [r3, #0]
+ 8000ca8: e006 b.n 8000cb8 <cobs_decode+0x86>
+ } else {
+ val = src[p];
+ 8000caa: 687a ldr r2, [r7, #4]
+ 8000cac: 69fb ldr r3, [r7, #28]
+ 8000cae: 18d2 adds r2, r2, r3
+ 8000cb0: 2317 movs r3, #23
+ 8000cb2: 18fb adds r3, r7, r3
+ 8000cb4: 7812 ldrb r2, [r2, #0]
+ 8000cb6: 701a strb r2, [r3, #0]
+ }
+
+ //@ assert 0 <= p-1 <= dstlen-1;
+ dst[p-1] = val;
+ 8000cb8: 69fb ldr r3, [r7, #28]
+ 8000cba: 3b01 subs r3, #1
+ 8000cbc: 68fa ldr r2, [r7, #12]
+ 8000cbe: 18d3 adds r3, r2, r3
+ 8000cc0: 2217 movs r2, #23
+ 8000cc2: 18ba adds r2, r7, r2
+ 8000cc4: 7812 ldrb r2, [r2, #0]
+ 8000cc6: 701a strb r2, [r3, #0]
+ p++;
+ 8000cc8: 69fb ldr r3, [r7, #28]
+ 8000cca: 3301 adds r3, #1
+ 8000ccc: 61fb str r3, [r7, #28]
+ while (p < srclen && src[p]) {
+ 8000cce: 69fa ldr r2, [r7, #28]
+ 8000cd0: 683b ldr r3, [r7, #0]
+ 8000cd2: 429a cmp r2, r3
+ 8000cd4: d205 bcs.n 8000ce2 <cobs_decode+0xb0>
+ 8000cd6: 687a ldr r2, [r7, #4]
+ 8000cd8: 69fb ldr r3, [r7, #28]
+ 8000cda: 18d3 adds r3, r2, r3
+ 8000cdc: 781b ldrb r3, [r3, #0]
+ 8000cde: 2b00 cmp r3, #0
+ 8000ce0: d1d3 bne.n 8000c8a <cobs_decode+0x58>
+ }
+
+ if (p == srclen)
+ 8000ce2: 69fa ldr r2, [r7, #28]
+ 8000ce4: 683b ldr r3, [r7, #0]
+ 8000ce6: 429a cmp r2, r3
+ 8000ce8: d102 bne.n 8000cf0 <cobs_decode+0xbe>
+ return -2; /* Invalid framing. The terminating null byte should always be present in the input buffer. */
+ 8000cea: 2302 movs r3, #2
+ 8000cec: 425b negs r3, r3
+ 8000cee: e007 b.n 8000d00 <cobs_decode+0xce>
+
+ if (c != 1)
+ 8000cf0: 69bb ldr r3, [r7, #24]
+ 8000cf2: 2b01 cmp r3, #1
+ 8000cf4: d002 beq.n 8000cfc <cobs_decode+0xca>
+ return -3; /* Invalid framing. The skip counter does not hit the end of the frame. */
+ 8000cf6: 2303 movs r3, #3
+ 8000cf8: 425b negs r3, r3
+ 8000cfa: e001 b.n 8000d00 <cobs_decode+0xce>
+
+ //@ assert 0 < p <= srclen <= 65535;
+ //@ assert src[p] == 0;
+ //@ assert \forall integer i; 1 <= i < p ==> src[i] != 0;
+ return p-1;
+ 8000cfc: 69fb ldr r3, [r7, #28]
+ 8000cfe: 3b01 subs r3, #1
+}
+ 8000d00: 0018 movs r0, r3
+ 8000d02: 46bd mov sp, r7
+ 8000d04: b008 add sp, #32
+ 8000d06: bd80 pop {r7, pc}
+
+08000d08 <cobs_decode_incremental_initialize>:
+
+void cobs_decode_incremental_initialize(struct cobs_decode_state *state) {
+ 8000d08: b580 push {r7, lr}
+ 8000d0a: b082 sub sp, #8
+ 8000d0c: af00 add r7, sp, #0
+ 8000d0e: 6078 str r0, [r7, #4]
+ state->p = 0;
+ 8000d10: 687b ldr r3, [r7, #4]
+ 8000d12: 2200 movs r2, #0
+ 8000d14: 601a str r2, [r3, #0]
+ state->c = 0;
+ 8000d16: 687b ldr r3, [r7, #4]
+ 8000d18: 2200 movs r2, #0
+ 8000d1a: 605a str r2, [r3, #4]
+}
+ 8000d1c: 46c0 nop ; (mov r8, r8)
+ 8000d1e: 46bd mov sp, r7
+ 8000d20: b002 add sp, #8
+ 8000d22: bd80 pop {r7, pc}
+
+08000d24 <cobs_decode_incremental>:
+
+int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src) {
+ 8000d24: b580 push {r7, lr}
+ 8000d26: b088 sub sp, #32
+ 8000d28: af00 add r7, sp, #0
+ 8000d2a: 60f8 str r0, [r7, #12]
+ 8000d2c: 60b9 str r1, [r7, #8]
+ 8000d2e: 607a str r2, [r7, #4]
+ 8000d30: 001a movs r2, r3
+ 8000d32: 1cfb adds r3, r7, #3
+ 8000d34: 701a strb r2, [r3, #0]
+ if (state->p == 0) {
+ 8000d36: 68fb ldr r3, [r7, #12]
+ 8000d38: 681b ldr r3, [r3, #0]
+ 8000d3a: 2b00 cmp r3, #0
+ 8000d3c: d10e bne.n 8000d5c <cobs_decode_incremental+0x38>
+ if (src == 0)
+ 8000d3e: 1cfb adds r3, r7, #3
+ 8000d40: 781b ldrb r3, [r3, #0]
+ 8000d42: 2b00 cmp r3, #0
+ 8000d44: d054 beq.n 8000df0 <cobs_decode_incremental+0xcc>
+ goto empty_errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
+ state->c = (unsigned char)src;
+ 8000d46: 1cfb adds r3, r7, #3
+ 8000d48: 781a ldrb r2, [r3, #0]
+ 8000d4a: 68fb ldr r3, [r7, #12]
+ 8000d4c: 605a str r2, [r3, #4]
+ state->p++;
+ 8000d4e: 68fb ldr r3, [r7, #12]
+ 8000d50: 681b ldr r3, [r3, #0]
+ 8000d52: 1c5a adds r2, r3, #1
+ 8000d54: 68fb ldr r3, [r7, #12]
+ 8000d56: 601a str r2, [r3, #0]
+ return 0;
+ 8000d58: 2300 movs r3, #0
+ 8000d5a: e050 b.n 8000dfe <cobs_decode_incremental+0xda>
+ }
+
+ if (!src) {
+ 8000d5c: 1cfb adds r3, r7, #3
+ 8000d5e: 781b ldrb r3, [r3, #0]
+ 8000d60: 2b00 cmp r3, #0
+ 8000d62: d10d bne.n 8000d80 <cobs_decode_incremental+0x5c>
+ if (state->c != 1)
+ 8000d64: 68fb ldr r3, [r7, #12]
+ 8000d66: 685b ldr r3, [r3, #4]
+ 8000d68: 2b01 cmp r3, #1
+ 8000d6a: d139 bne.n 8000de0 <cobs_decode_incremental+0xbc>
+ goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */
+ int rv = state->p-1;
+ 8000d6c: 68fb ldr r3, [r7, #12]
+ 8000d6e: 681b ldr r3, [r3, #0]
+ 8000d70: 3b01 subs r3, #1
+ 8000d72: 617b str r3, [r7, #20]
+ cobs_decode_incremental_initialize(state);
+ 8000d74: 68fb ldr r3, [r7, #12]
+ 8000d76: 0018 movs r0, r3
+ 8000d78: f7ff ffc6 bl 8000d08 <cobs_decode_incremental_initialize>
+ return rv;
+ 8000d7c: 697b ldr r3, [r7, #20]
+ 8000d7e: e03e b.n 8000dfe <cobs_decode_incremental+0xda>
+ }
+
+ char val;
+ state->c--;
+ 8000d80: 68fb ldr r3, [r7, #12]
+ 8000d82: 685b ldr r3, [r3, #4]
+ 8000d84: 1e5a subs r2, r3, #1
+ 8000d86: 68fb ldr r3, [r7, #12]
+ 8000d88: 605a str r2, [r3, #4]
+
+ if (state->c == 0) {
+ 8000d8a: 68fb ldr r3, [r7, #12]
+ 8000d8c: 685b ldr r3, [r3, #4]
+ 8000d8e: 2b00 cmp r3, #0
+ 8000d90: d108 bne.n 8000da4 <cobs_decode_incremental+0x80>
+ state->c = (unsigned char)src;
+ 8000d92: 1cfb adds r3, r7, #3
+ 8000d94: 781a ldrb r2, [r3, #0]
+ 8000d96: 68fb ldr r3, [r7, #12]
+ 8000d98: 605a str r2, [r3, #4]
+ val = 0;
+ 8000d9a: 231f movs r3, #31
+ 8000d9c: 18fb adds r3, r7, r3
+ 8000d9e: 2200 movs r2, #0
+ 8000da0: 701a strb r2, [r3, #0]
+ 8000da2: e004 b.n 8000dae <cobs_decode_incremental+0x8a>
+ } else {
+ val = src;
+ 8000da4: 231f movs r3, #31
+ 8000da6: 18fb adds r3, r7, r3
+ 8000da8: 1cfa adds r2, r7, #3
+ 8000daa: 7812 ldrb r2, [r2, #0]
+ 8000dac: 701a strb r2, [r3, #0]
+ }
+
+ size_t pos = state->p-1;
+ 8000dae: 68fb ldr r3, [r7, #12]
+ 8000db0: 681b ldr r3, [r3, #0]
+ 8000db2: 3b01 subs r3, #1
+ 8000db4: 61bb str r3, [r7, #24]
+ if (pos >= dstlen)
+ 8000db6: 69ba ldr r2, [r7, #24]
+ 8000db8: 687b ldr r3, [r7, #4]
+ 8000dba: 429a cmp r2, r3
+ 8000dbc: d302 bcc.n 8000dc4 <cobs_decode_incremental+0xa0>
+ return -2; /* output buffer too small */
+ 8000dbe: 2302 movs r3, #2
+ 8000dc0: 425b negs r3, r3
+ 8000dc2: e01c b.n 8000dfe <cobs_decode_incremental+0xda>
+ dst[pos] = val;
+ 8000dc4: 68ba ldr r2, [r7, #8]
+ 8000dc6: 69bb ldr r3, [r7, #24]
+ 8000dc8: 18d3 adds r3, r2, r3
+ 8000dca: 221f movs r2, #31
+ 8000dcc: 18ba adds r2, r7, r2
+ 8000dce: 7812 ldrb r2, [r2, #0]
+ 8000dd0: 701a strb r2, [r3, #0]
+ state->p++;
+ 8000dd2: 68fb ldr r3, [r7, #12]
+ 8000dd4: 681b ldr r3, [r3, #0]
+ 8000dd6: 1c5a adds r2, r3, #1
+ 8000dd8: 68fb ldr r3, [r7, #12]
+ 8000dda: 601a str r2, [r3, #0]
+ return 0;
+ 8000ddc: 2300 movs r3, #0
+ 8000dde: e00e b.n 8000dfe <cobs_decode_incremental+0xda>
+ goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */
+ 8000de0: 46c0 nop ; (mov r8, r8)
+
+errout:
+ cobs_decode_incremental_initialize(state);
+ 8000de2: 68fb ldr r3, [r7, #12]
+ 8000de4: 0018 movs r0, r3
+ 8000de6: f7ff ff8f bl 8000d08 <cobs_decode_incremental_initialize>
+ return -1;
+ 8000dea: 2301 movs r3, #1
+ 8000dec: 425b negs r3, r3
+ 8000dee: e006 b.n 8000dfe <cobs_decode_incremental+0xda>
+ goto empty_errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */
+ 8000df0: 46c0 nop ; (mov r8, r8)
+
+empty_errout:
+ cobs_decode_incremental_initialize(state);
+ 8000df2: 68fb ldr r3, [r7, #12]
+ 8000df4: 0018 movs r0, r3
+ 8000df6: f7ff ff87 bl 8000d08 <cobs_decode_incremental_initialize>
+ return -3;
+ 8000dfa: 2303 movs r3, #3
+ 8000dfc: 425b negs r3, r3
+}
+ 8000dfe: 0018 movs r0, r3
+ 8000e00: 46bd mov sp, r7
+ 8000e02: b008 add sp, #32
+ 8000e04: bd80 pop {r7, pc}
+ 8000e06: 1904 .short 0x1904
+ 8000e08: 00000800 .word 0x00000800
+ 8000e0c: 00942000 .word 0x00942000
+ 8000e10: 00942000 .word 0x00942000
+ 8000e14: 09d42000 .word 0x09d42000
+ 8000e18: 00002000 .word 0x00002000
+
+08000e1c <SystemInit>:
+ * Initialize the default HSI clock source, vector table location and the PLL configuration is reset.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ 8000e1c: b580 push {r7, lr}
+ 8000e1e: af00 add r7, sp, #0
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001U;
+ 8000e20: 4b1a ldr r3, [pc, #104] ; (8000e8c <SystemInit+0x70>)
+ 8000e22: 681a ldr r2, [r3, #0]
+ 8000e24: 4b19 ldr r3, [pc, #100] ; (8000e8c <SystemInit+0x70>)
+ 8000e26: 2101 movs r1, #1
+ 8000e28: 430a orrs r2, r1
+ 8000e2a: 601a str r2, [r3, #0]
+#if defined (STM32F051x8) || defined (STM32F058x8)
+ /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */
+ RCC->CFGR &= (uint32_t)0xF8FFB80CU;
+#else
+ /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits */
+ RCC->CFGR &= (uint32_t)0x08FFB80CU;
+ 8000e2c: 4b17 ldr r3, [pc, #92] ; (8000e8c <SystemInit+0x70>)
+ 8000e2e: 685a ldr r2, [r3, #4]
+ 8000e30: 4b16 ldr r3, [pc, #88] ; (8000e8c <SystemInit+0x70>)
+ 8000e32: 4917 ldr r1, [pc, #92] ; (8000e90 <SystemInit+0x74>)
+ 8000e34: 400a ands r2, r1
+ 8000e36: 605a str r2, [r3, #4]
+#endif /* STM32F051x8 or STM32F058x8 */
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFFU;
+ 8000e38: 4b14 ldr r3, [pc, #80] ; (8000e8c <SystemInit+0x70>)
+ 8000e3a: 681a ldr r2, [r3, #0]
+ 8000e3c: 4b13 ldr r3, [pc, #76] ; (8000e8c <SystemInit+0x70>)
+ 8000e3e: 4915 ldr r1, [pc, #84] ; (8000e94 <SystemInit+0x78>)
+ 8000e40: 400a ands r2, r1
+ 8000e42: 601a str r2, [r3, #0]
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFFU;
+ 8000e44: 4b11 ldr r3, [pc, #68] ; (8000e8c <SystemInit+0x70>)
+ 8000e46: 681a ldr r2, [r3, #0]
+ 8000e48: 4b10 ldr r3, [pc, #64] ; (8000e8c <SystemInit+0x70>)
+ 8000e4a: 4913 ldr r1, [pc, #76] ; (8000e98 <SystemInit+0x7c>)
+ 8000e4c: 400a ands r2, r1
+ 8000e4e: 601a str r2, [r3, #0]
+
+ /* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
+ RCC->CFGR &= (uint32_t)0xFFC0FFFFU;
+ 8000e50: 4b0e ldr r3, [pc, #56] ; (8000e8c <SystemInit+0x70>)
+ 8000e52: 685a ldr r2, [r3, #4]
+ 8000e54: 4b0d ldr r3, [pc, #52] ; (8000e8c <SystemInit+0x70>)
+ 8000e56: 4911 ldr r1, [pc, #68] ; (8000e9c <SystemInit+0x80>)
+ 8000e58: 400a ands r2, r1
+ 8000e5a: 605a str r2, [r3, #4]
+
+ /* Reset PREDIV[3:0] bits */
+ RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U;
+ 8000e5c: 4b0b ldr r3, [pc, #44] ; (8000e8c <SystemInit+0x70>)
+ 8000e5e: 6ada ldr r2, [r3, #44] ; 0x2c
+ 8000e60: 4b0a ldr r3, [pc, #40] ; (8000e8c <SystemInit+0x70>)
+ 8000e62: 210f movs r1, #15
+ 8000e64: 438a bics r2, r1
+ 8000e66: 62da str r2, [r3, #44] ; 0x2c
+#elif defined (STM32F091xC) || defined (STM32F098xx)
+ /* Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFF0FEACU;
+#elif defined (STM32F030x6) || defined (STM32F030x8) || defined (STM32F031x6) || defined (STM32F038xx) || defined (STM32F030xC)
+ /* Reset USART1SW[1:0], I2C1SW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFEECU;
+ 8000e68: 4b08 ldr r3, [pc, #32] ; (8000e8c <SystemInit+0x70>)
+ 8000e6a: 6b1a ldr r2, [r3, #48] ; 0x30
+ 8000e6c: 4b07 ldr r3, [pc, #28] ; (8000e8c <SystemInit+0x70>)
+ 8000e6e: 490c ldr r1, [pc, #48] ; (8000ea0 <SystemInit+0x84>)
+ 8000e70: 400a ands r2, r1
+ 8000e72: 631a str r2, [r3, #48] ; 0x30
+#else
+ #warning "No target selected"
+#endif
+
+ /* Reset HSI14 bit */
+ RCC->CR2 &= (uint32_t)0xFFFFFFFEU;
+ 8000e74: 4b05 ldr r3, [pc, #20] ; (8000e8c <SystemInit+0x70>)
+ 8000e76: 6b5a ldr r2, [r3, #52] ; 0x34
+ 8000e78: 4b04 ldr r3, [pc, #16] ; (8000e8c <SystemInit+0x70>)
+ 8000e7a: 2101 movs r1, #1
+ 8000e7c: 438a bics r2, r1
+ 8000e7e: 635a str r2, [r3, #52] ; 0x34
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000U;
+ 8000e80: 4b02 ldr r3, [pc, #8] ; (8000e8c <SystemInit+0x70>)
+ 8000e82: 2200 movs r2, #0
+ 8000e84: 609a str r2, [r3, #8]
+
+}
+ 8000e86: 46c0 nop ; (mov r8, r8)
+ 8000e88: 46bd mov sp, r7
+ 8000e8a: bd80 pop {r7, pc}
+ 8000e8c: 40021000 .word 0x40021000
+ 8000e90: 08ffb80c .word 0x08ffb80c
+ 8000e94: fef6ffff .word 0xfef6ffff
+ 8000e98: fffbffff .word 0xfffbffff
+ 8000e9c: ffc0ffff .word 0xffc0ffff
+ 8000ea0: fffffeec .word 0xfffffeec
+
+08000ea4 <SystemCoreClockUpdate>:
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate (void)
+{
+ 8000ea4: b580 push {r7, lr}
+ 8000ea6: b084 sub sp, #16
+ 8000ea8: af00 add r7, sp, #0
+ uint32_t tmp = 0, pllmull = 0, pllsource = 0, predivfactor = 0;
+ 8000eaa: 2300 movs r3, #0
+ 8000eac: 60fb str r3, [r7, #12]
+ 8000eae: 2300 movs r3, #0
+ 8000eb0: 60bb str r3, [r7, #8]
+ 8000eb2: 2300 movs r3, #0
+ 8000eb4: 607b str r3, [r7, #4]
+ 8000eb6: 2300 movs r3, #0
+ 8000eb8: 603b str r3, [r7, #0]
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+ 8000eba: 4b31 ldr r3, [pc, #196] ; (8000f80 <SystemCoreClockUpdate+0xdc>)
+ 8000ebc: 685b ldr r3, [r3, #4]
+ 8000ebe: 220c movs r2, #12
+ 8000ec0: 4013 ands r3, r2
+ 8000ec2: 60fb str r3, [r7, #12]
+
+ switch (tmp)
+ 8000ec4: 68fb ldr r3, [r7, #12]
+ 8000ec6: 2b08 cmp r3, #8
+ 8000ec8: d011 beq.n 8000eee <SystemCoreClockUpdate+0x4a>
+ 8000eca: 68fb ldr r3, [r7, #12]
+ 8000ecc: 2b08 cmp r3, #8
+ 8000ece: d841 bhi.n 8000f54 <SystemCoreClockUpdate+0xb0>
+ 8000ed0: 68fb ldr r3, [r7, #12]
+ 8000ed2: 2b00 cmp r3, #0
+ 8000ed4: d003 beq.n 8000ede <SystemCoreClockUpdate+0x3a>
+ 8000ed6: 68fb ldr r3, [r7, #12]
+ 8000ed8: 2b04 cmp r3, #4
+ 8000eda: d004 beq.n 8000ee6 <SystemCoreClockUpdate+0x42>
+ 8000edc: e03a b.n 8000f54 <SystemCoreClockUpdate+0xb0>
+ {
+ case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
+ SystemCoreClock = HSI_VALUE;
+ 8000ede: 4b29 ldr r3, [pc, #164] ; (8000f84 <SystemCoreClockUpdate+0xe0>)
+ 8000ee0: 4a29 ldr r2, [pc, #164] ; (8000f88 <SystemCoreClockUpdate+0xe4>)
+ 8000ee2: 601a str r2, [r3, #0]
+ break;
+ 8000ee4: e03a b.n 8000f5c <SystemCoreClockUpdate+0xb8>
+ case RCC_CFGR_SWS_HSE: /* HSE used as system clock */
+ SystemCoreClock = HSE_VALUE;
+ 8000ee6: 4b27 ldr r3, [pc, #156] ; (8000f84 <SystemCoreClockUpdate+0xe0>)
+ 8000ee8: 4a27 ldr r2, [pc, #156] ; (8000f88 <SystemCoreClockUpdate+0xe4>)
+ 8000eea: 601a str r2, [r3, #0]
+ break;
+ 8000eec: e036 b.n 8000f5c <SystemCoreClockUpdate+0xb8>
+ case RCC_CFGR_SWS_PLL: /* PLL used as system clock */
+ /* Get PLL clock source and multiplication factor ----------------------*/
+ pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
+ 8000eee: 4b24 ldr r3, [pc, #144] ; (8000f80 <SystemCoreClockUpdate+0xdc>)
+ 8000ef0: 685a ldr r2, [r3, #4]
+ 8000ef2: 23f0 movs r3, #240 ; 0xf0
+ 8000ef4: 039b lsls r3, r3, #14
+ 8000ef6: 4013 ands r3, r2
+ 8000ef8: 60bb str r3, [r7, #8]
+ pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
+ 8000efa: 4b21 ldr r3, [pc, #132] ; (8000f80 <SystemCoreClockUpdate+0xdc>)
+ 8000efc: 685a ldr r2, [r3, #4]
+ 8000efe: 2380 movs r3, #128 ; 0x80
+ 8000f00: 025b lsls r3, r3, #9
+ 8000f02: 4013 ands r3, r2
+ 8000f04: 607b str r3, [r7, #4]
+ pllmull = ( pllmull >> 18) + 2;
+ 8000f06: 68bb ldr r3, [r7, #8]
+ 8000f08: 0c9b lsrs r3, r3, #18
+ 8000f0a: 3302 adds r3, #2
+ 8000f0c: 60bb str r3, [r7, #8]
+ predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
+ 8000f0e: 4b1c ldr r3, [pc, #112] ; (8000f80 <SystemCoreClockUpdate+0xdc>)
+ 8000f10: 6adb ldr r3, [r3, #44] ; 0x2c
+ 8000f12: 220f movs r2, #15
+ 8000f14: 4013 ands r3, r2
+ 8000f16: 3301 adds r3, #1
+ 8000f18: 603b str r3, [r7, #0]
+
+ if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV)
+ 8000f1a: 687a ldr r2, [r7, #4]
+ 8000f1c: 2380 movs r3, #128 ; 0x80
+ 8000f1e: 025b lsls r3, r3, #9
+ 8000f20: 429a cmp r2, r3
+ 8000f22: d10a bne.n 8000f3a <SystemCoreClockUpdate+0x96>
+ {
+ /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */
+ SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull;
+ 8000f24: 6839 ldr r1, [r7, #0]
+ 8000f26: 4818 ldr r0, [pc, #96] ; (8000f88 <SystemCoreClockUpdate+0xe4>)
+ 8000f28: f000 fb3e bl 80015a8 <__udivsi3>
+ 8000f2c: 0003 movs r3, r0
+ 8000f2e: 001a movs r2, r3
+ 8000f30: 68bb ldr r3, [r7, #8]
+ 8000f32: 435a muls r2, r3
+ 8000f34: 4b13 ldr r3, [pc, #76] ; (8000f84 <SystemCoreClockUpdate+0xe0>)
+ 8000f36: 601a str r2, [r3, #0]
+ SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+#endif /* STM32F042x6 || STM32F048xx || STM32F070x6 ||
+ STM32F071xB || STM32F072xB || STM32F078xx || STM32F070xB ||
+ STM32F091xC || STM32F098xx || STM32F030xC */
+ }
+ break;
+ 8000f38: e010 b.n 8000f5c <SystemCoreClockUpdate+0xb8>
+ SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+ 8000f3a: 68b9 ldr r1, [r7, #8]
+ 8000f3c: 000a movs r2, r1
+ 8000f3e: 0152 lsls r2, r2, #5
+ 8000f40: 1a52 subs r2, r2, r1
+ 8000f42: 0193 lsls r3, r2, #6
+ 8000f44: 1a9b subs r3, r3, r2
+ 8000f46: 00db lsls r3, r3, #3
+ 8000f48: 185b adds r3, r3, r1
+ 8000f4a: 021b lsls r3, r3, #8
+ 8000f4c: 001a movs r2, r3
+ 8000f4e: 4b0d ldr r3, [pc, #52] ; (8000f84 <SystemCoreClockUpdate+0xe0>)
+ 8000f50: 601a str r2, [r3, #0]
+ break;
+ 8000f52: e003 b.n 8000f5c <SystemCoreClockUpdate+0xb8>
+ default: /* HSI used as system clock */
+ SystemCoreClock = HSI_VALUE;
+ 8000f54: 4b0b ldr r3, [pc, #44] ; (8000f84 <SystemCoreClockUpdate+0xe0>)
+ 8000f56: 4a0c ldr r2, [pc, #48] ; (8000f88 <SystemCoreClockUpdate+0xe4>)
+ 8000f58: 601a str r2, [r3, #0]
+ break;
+ 8000f5a: 46c0 nop ; (mov r8, r8)
+ }
+ /* Compute HCLK clock frequency ----------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ 8000f5c: 4b08 ldr r3, [pc, #32] ; (8000f80 <SystemCoreClockUpdate+0xdc>)
+ 8000f5e: 685b ldr r3, [r3, #4]
+ 8000f60: 091b lsrs r3, r3, #4
+ 8000f62: 220f movs r2, #15
+ 8000f64: 4013 ands r3, r2
+ 8000f66: 4a09 ldr r2, [pc, #36] ; (8000f8c <SystemCoreClockUpdate+0xe8>)
+ 8000f68: 5cd3 ldrb r3, [r2, r3]
+ 8000f6a: 60fb str r3, [r7, #12]
+ /* HCLK clock frequency */
+ SystemCoreClock >>= tmp;
+ 8000f6c: 4b05 ldr r3, [pc, #20] ; (8000f84 <SystemCoreClockUpdate+0xe0>)
+ 8000f6e: 681a ldr r2, [r3, #0]
+ 8000f70: 68fb ldr r3, [r7, #12]
+ 8000f72: 40da lsrs r2, r3
+ 8000f74: 4b03 ldr r3, [pc, #12] ; (8000f84 <SystemCoreClockUpdate+0xe0>)
+ 8000f76: 601a str r2, [r3, #0]
+}
+ 8000f78: 46c0 nop ; (mov r8, r8)
+ 8000f7a: 46bd mov sp, r7
+ 8000f7c: b004 add sp, #16
+ 8000f7e: bd80 pop {r7, pc}
+ 8000f80: 40021000 .word 0x40021000
+ 8000f84: 20000000 .word 0x20000000
+ 8000f88: 007a1200 .word 0x007a1200
+ 8000f8c: 080018ec .word 0x080018ec
+
+08000f90 <LL_RCC_HSE_EnableBypass>:
+ * @brief Enable HSE external oscillator (HSE Bypass)
+ * @rmtoll CR HSEBYP LL_RCC_HSE_EnableBypass
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_HSE_EnableBypass(void)
+{
+ 8000f90: b580 push {r7, lr}
+ 8000f92: af00 add r7, sp, #0
+ SET_BIT(RCC->CR, RCC_CR_HSEBYP);
+ 8000f94: 4b04 ldr r3, [pc, #16] ; (8000fa8 <LL_RCC_HSE_EnableBypass+0x18>)
+ 8000f96: 681a ldr r2, [r3, #0]
+ 8000f98: 4b03 ldr r3, [pc, #12] ; (8000fa8 <LL_RCC_HSE_EnableBypass+0x18>)
+ 8000f9a: 2180 movs r1, #128 ; 0x80
+ 8000f9c: 02c9 lsls r1, r1, #11
+ 8000f9e: 430a orrs r2, r1
+ 8000fa0: 601a str r2, [r3, #0]
+}
+ 8000fa2: 46c0 nop ; (mov r8, r8)
+ 8000fa4: 46bd mov sp, r7
+ 8000fa6: bd80 pop {r7, pc}
+ 8000fa8: 40021000 .word 0x40021000
+
+08000fac <LL_RCC_HSE_DisableBypass>:
+ * @brief Disable HSE external oscillator (HSE Bypass)
+ * @rmtoll CR HSEBYP LL_RCC_HSE_DisableBypass
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_HSE_DisableBypass(void)
+{
+ 8000fac: b580 push {r7, lr}
+ 8000fae: af00 add r7, sp, #0
+ CLEAR_BIT(RCC->CR, RCC_CR_HSEBYP);
+ 8000fb0: 4b04 ldr r3, [pc, #16] ; (8000fc4 <LL_RCC_HSE_DisableBypass+0x18>)
+ 8000fb2: 681a ldr r2, [r3, #0]
+ 8000fb4: 4b03 ldr r3, [pc, #12] ; (8000fc4 <LL_RCC_HSE_DisableBypass+0x18>)
+ 8000fb6: 4904 ldr r1, [pc, #16] ; (8000fc8 <LL_RCC_HSE_DisableBypass+0x1c>)
+ 8000fb8: 400a ands r2, r1
+ 8000fba: 601a str r2, [r3, #0]
+}
+ 8000fbc: 46c0 nop ; (mov r8, r8)
+ 8000fbe: 46bd mov sp, r7
+ 8000fc0: bd80 pop {r7, pc}
+ 8000fc2: 46c0 nop ; (mov r8, r8)
+ 8000fc4: 40021000 .word 0x40021000
+ 8000fc8: fffbffff .word 0xfffbffff
+
+08000fcc <LL_RCC_HSE_Enable>:
+ * @brief Enable HSE crystal oscillator (HSE ON)
+ * @rmtoll CR HSEON LL_RCC_HSE_Enable
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_HSE_Enable(void)
+{
+ 8000fcc: b580 push {r7, lr}
+ 8000fce: af00 add r7, sp, #0
+ SET_BIT(RCC->CR, RCC_CR_HSEON);
+ 8000fd0: 4b04 ldr r3, [pc, #16] ; (8000fe4 <LL_RCC_HSE_Enable+0x18>)
+ 8000fd2: 681a ldr r2, [r3, #0]
+ 8000fd4: 4b03 ldr r3, [pc, #12] ; (8000fe4 <LL_RCC_HSE_Enable+0x18>)
+ 8000fd6: 2180 movs r1, #128 ; 0x80
+ 8000fd8: 0249 lsls r1, r1, #9
+ 8000fda: 430a orrs r2, r1
+ 8000fdc: 601a str r2, [r3, #0]
+}
+ 8000fde: 46c0 nop ; (mov r8, r8)
+ 8000fe0: 46bd mov sp, r7
+ 8000fe2: bd80 pop {r7, pc}
+ 8000fe4: 40021000 .word 0x40021000
+
+08000fe8 <LL_RCC_HSE_IsReady>:
+ * @brief Check if HSE oscillator Ready
+ * @rmtoll CR HSERDY LL_RCC_HSE_IsReady
+ * @retval State of bit (1 or 0).
+ */
+__STATIC_INLINE uint32_t LL_RCC_HSE_IsReady(void)
+{
+ 8000fe8: b580 push {r7, lr}
+ 8000fea: af00 add r7, sp, #0
+ return (READ_BIT(RCC->CR, RCC_CR_HSERDY) == (RCC_CR_HSERDY));
+ 8000fec: 4b06 ldr r3, [pc, #24] ; (8001008 <LL_RCC_HSE_IsReady+0x20>)
+ 8000fee: 681a ldr r2, [r3, #0]
+ 8000ff0: 2380 movs r3, #128 ; 0x80
+ 8000ff2: 029b lsls r3, r3, #10
+ 8000ff4: 4013 ands r3, r2
+ 8000ff6: 4a05 ldr r2, [pc, #20] ; (800100c <LL_RCC_HSE_IsReady+0x24>)
+ 8000ff8: 4694 mov ip, r2
+ 8000ffa: 4463 add r3, ip
+ 8000ffc: 425a negs r2, r3
+ 8000ffe: 4153 adcs r3, r2
+ 8001000: b2db uxtb r3, r3
+}
+ 8001002: 0018 movs r0, r3
+ 8001004: 46bd mov sp, r7
+ 8001006: bd80 pop {r7, pc}
+ 8001008: 40021000 .word 0x40021000
+ 800100c: fffe0000 .word 0xfffe0000
+
+08001010 <LL_RCC_HSI_Enable>:
+ * @brief Enable HSI oscillator
+ * @rmtoll CR HSION LL_RCC_HSI_Enable
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_HSI_Enable(void)
+{
+ 8001010: b580 push {r7, lr}
+ 8001012: af00 add r7, sp, #0
+ SET_BIT(RCC->CR, RCC_CR_HSION);
+ 8001014: 4b04 ldr r3, [pc, #16] ; (8001028 <LL_RCC_HSI_Enable+0x18>)
+ 8001016: 681a ldr r2, [r3, #0]
+ 8001018: 4b03 ldr r3, [pc, #12] ; (8001028 <LL_RCC_HSI_Enable+0x18>)
+ 800101a: 2101 movs r1, #1
+ 800101c: 430a orrs r2, r1
+ 800101e: 601a str r2, [r3, #0]
+}
+ 8001020: 46c0 nop ; (mov r8, r8)
+ 8001022: 46bd mov sp, r7
+ 8001024: bd80 pop {r7, pc}
+ 8001026: 46c0 nop ; (mov r8, r8)
+ 8001028: 40021000 .word 0x40021000
+
+0800102c <LL_RCC_HSI_IsReady>:
+ * @brief Check if HSI clock is ready
+ * @rmtoll CR HSIRDY LL_RCC_HSI_IsReady
+ * @retval State of bit (1 or 0).
+ */
+__STATIC_INLINE uint32_t LL_RCC_HSI_IsReady(void)
+{
+ 800102c: b580 push {r7, lr}
+ 800102e: af00 add r7, sp, #0
+ return (READ_BIT(RCC->CR, RCC_CR_HSIRDY) == (RCC_CR_HSIRDY));
+ 8001030: 4b05 ldr r3, [pc, #20] ; (8001048 <LL_RCC_HSI_IsReady+0x1c>)
+ 8001032: 681b ldr r3, [r3, #0]
+ 8001034: 2202 movs r2, #2
+ 8001036: 4013 ands r3, r2
+ 8001038: 3b02 subs r3, #2
+ 800103a: 425a negs r2, r3
+ 800103c: 4153 adcs r3, r2
+ 800103e: b2db uxtb r3, r3
+}
+ 8001040: 0018 movs r0, r3
+ 8001042: 46bd mov sp, r7
+ 8001044: bd80 pop {r7, pc}
+ 8001046: 46c0 nop ; (mov r8, r8)
+ 8001048: 40021000 .word 0x40021000
+
+0800104c <LL_RCC_SetSysClkSource>:
+ *
+ * (*) value not defined in all devices
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_SetSysClkSource(uint32_t Source)
+{
+ 800104c: b580 push {r7, lr}
+ 800104e: b082 sub sp, #8
+ 8001050: af00 add r7, sp, #0
+ 8001052: 6078 str r0, [r7, #4]
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, Source);
+ 8001054: 4b06 ldr r3, [pc, #24] ; (8001070 <LL_RCC_SetSysClkSource+0x24>)
+ 8001056: 685b ldr r3, [r3, #4]
+ 8001058: 2203 movs r2, #3
+ 800105a: 4393 bics r3, r2
+ 800105c: 0019 movs r1, r3
+ 800105e: 4b04 ldr r3, [pc, #16] ; (8001070 <LL_RCC_SetSysClkSource+0x24>)
+ 8001060: 687a ldr r2, [r7, #4]
+ 8001062: 430a orrs r2, r1
+ 8001064: 605a str r2, [r3, #4]
+}
+ 8001066: 46c0 nop ; (mov r8, r8)
+ 8001068: 46bd mov sp, r7
+ 800106a: b002 add sp, #8
+ 800106c: bd80 pop {r7, pc}
+ 800106e: 46c0 nop ; (mov r8, r8)
+ 8001070: 40021000 .word 0x40021000
+
+08001074 <LL_RCC_GetSysClkSource>:
+ * @arg @ref LL_RCC_SYS_CLKSOURCE_STATUS_HSI48 (*)
+ *
+ * (*) value not defined in all devices
+ */
+__STATIC_INLINE uint32_t LL_RCC_GetSysClkSource(void)
+{
+ 8001074: b580 push {r7, lr}
+ 8001076: af00 add r7, sp, #0
+ return (uint32_t)(READ_BIT(RCC->CFGR, RCC_CFGR_SWS));
+ 8001078: 4b03 ldr r3, [pc, #12] ; (8001088 <LL_RCC_GetSysClkSource+0x14>)
+ 800107a: 685b ldr r3, [r3, #4]
+ 800107c: 220c movs r2, #12
+ 800107e: 4013 ands r3, r2
+}
+ 8001080: 0018 movs r0, r3
+ 8001082: 46bd mov sp, r7
+ 8001084: bd80 pop {r7, pc}
+ 8001086: 46c0 nop ; (mov r8, r8)
+ 8001088: 40021000 .word 0x40021000
+
+0800108c <LL_RCC_SetAHBPrescaler>:
+ * @arg @ref LL_RCC_SYSCLK_DIV_256
+ * @arg @ref LL_RCC_SYSCLK_DIV_512
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_SetAHBPrescaler(uint32_t Prescaler)
+{
+ 800108c: b580 push {r7, lr}
+ 800108e: b082 sub sp, #8
+ 8001090: af00 add r7, sp, #0
+ 8001092: 6078 str r0, [r7, #4]
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, Prescaler);
+ 8001094: 4b06 ldr r3, [pc, #24] ; (80010b0 <LL_RCC_SetAHBPrescaler+0x24>)
+ 8001096: 685b ldr r3, [r3, #4]
+ 8001098: 22f0 movs r2, #240 ; 0xf0
+ 800109a: 4393 bics r3, r2
+ 800109c: 0019 movs r1, r3
+ 800109e: 4b04 ldr r3, [pc, #16] ; (80010b0 <LL_RCC_SetAHBPrescaler+0x24>)
+ 80010a0: 687a ldr r2, [r7, #4]
+ 80010a2: 430a orrs r2, r1
+ 80010a4: 605a str r2, [r3, #4]
+}
+ 80010a6: 46c0 nop ; (mov r8, r8)
+ 80010a8: 46bd mov sp, r7
+ 80010aa: b002 add sp, #8
+ 80010ac: bd80 pop {r7, pc}
+ 80010ae: 46c0 nop ; (mov r8, r8)
+ 80010b0: 40021000 .word 0x40021000
+
+080010b4 <LL_RCC_SetAPB1Prescaler>:
+ * @arg @ref LL_RCC_APB1_DIV_8
+ * @arg @ref LL_RCC_APB1_DIV_16
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_SetAPB1Prescaler(uint32_t Prescaler)
+{
+ 80010b4: b580 push {r7, lr}
+ 80010b6: b082 sub sp, #8
+ 80010b8: af00 add r7, sp, #0
+ 80010ba: 6078 str r0, [r7, #4]
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE, Prescaler);
+ 80010bc: 4b06 ldr r3, [pc, #24] ; (80010d8 <LL_RCC_SetAPB1Prescaler+0x24>)
+ 80010be: 685b ldr r3, [r3, #4]
+ 80010c0: 4a06 ldr r2, [pc, #24] ; (80010dc <LL_RCC_SetAPB1Prescaler+0x28>)
+ 80010c2: 4013 ands r3, r2
+ 80010c4: 0019 movs r1, r3
+ 80010c6: 4b04 ldr r3, [pc, #16] ; (80010d8 <LL_RCC_SetAPB1Prescaler+0x24>)
+ 80010c8: 687a ldr r2, [r7, #4]
+ 80010ca: 430a orrs r2, r1
+ 80010cc: 605a str r2, [r3, #4]
+}
+ 80010ce: 46c0 nop ; (mov r8, r8)
+ 80010d0: 46bd mov sp, r7
+ 80010d2: b002 add sp, #8
+ 80010d4: bd80 pop {r7, pc}
+ 80010d6: 46c0 nop ; (mov r8, r8)
+ 80010d8: 40021000 .word 0x40021000
+ 80010dc: fffff8ff .word 0xfffff8ff
+
+080010e0 <LL_RCC_PLL_Enable>:
+ * @brief Enable PLL
+ * @rmtoll CR PLLON LL_RCC_PLL_Enable
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_PLL_Enable(void)
+{
+ 80010e0: b580 push {r7, lr}
+ 80010e2: af00 add r7, sp, #0
+ SET_BIT(RCC->CR, RCC_CR_PLLON);
+ 80010e4: 4b04 ldr r3, [pc, #16] ; (80010f8 <LL_RCC_PLL_Enable+0x18>)
+ 80010e6: 681a ldr r2, [r3, #0]
+ 80010e8: 4b03 ldr r3, [pc, #12] ; (80010f8 <LL_RCC_PLL_Enable+0x18>)
+ 80010ea: 2180 movs r1, #128 ; 0x80
+ 80010ec: 0449 lsls r1, r1, #17
+ 80010ee: 430a orrs r2, r1
+ 80010f0: 601a str r2, [r3, #0]
+}
+ 80010f2: 46c0 nop ; (mov r8, r8)
+ 80010f4: 46bd mov sp, r7
+ 80010f6: bd80 pop {r7, pc}
+ 80010f8: 40021000 .word 0x40021000
+
+080010fc <LL_RCC_PLL_IsReady>:
+ * @brief Check if PLL Ready
+ * @rmtoll CR PLLRDY LL_RCC_PLL_IsReady
+ * @retval State of bit (1 or 0).
+ */
+__STATIC_INLINE uint32_t LL_RCC_PLL_IsReady(void)
+{
+ 80010fc: b580 push {r7, lr}
+ 80010fe: af00 add r7, sp, #0
+ return (READ_BIT(RCC->CR, RCC_CR_PLLRDY) == (RCC_CR_PLLRDY));
+ 8001100: 4b07 ldr r3, [pc, #28] ; (8001120 <LL_RCC_PLL_IsReady+0x24>)
+ 8001102: 681a ldr r2, [r3, #0]
+ 8001104: 2380 movs r3, #128 ; 0x80
+ 8001106: 049b lsls r3, r3, #18
+ 8001108: 4013 ands r3, r2
+ 800110a: 22fe movs r2, #254 ; 0xfe
+ 800110c: 0612 lsls r2, r2, #24
+ 800110e: 4694 mov ip, r2
+ 8001110: 4463 add r3, ip
+ 8001112: 425a negs r2, r3
+ 8001114: 4153 adcs r3, r2
+ 8001116: b2db uxtb r3, r3
+}
+ 8001118: 0018 movs r0, r3
+ 800111a: 46bd mov sp, r7
+ 800111c: bd80 pop {r7, pc}
+ 800111e: 46c0 nop ; (mov r8, r8)
+ 8001120: 40021000 .word 0x40021000
+
+08001124 <LL_RCC_PLL_ConfigDomain_SYS>:
+ * @arg @ref LL_RCC_PLL_MUL_15
+ * @arg @ref LL_RCC_PLL_MUL_16
+ * @retval None
+ */
+__STATIC_INLINE void LL_RCC_PLL_ConfigDomain_SYS(uint32_t Source, uint32_t PLLMul)
+{
+ 8001124: b580 push {r7, lr}
+ 8001126: b082 sub sp, #8
+ 8001128: af00 add r7, sp, #0
+ 800112a: 6078 str r0, [r7, #4]
+ 800112c: 6039 str r1, [r7, #0]
+ MODIFY_REG(RCC->CFGR, RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL, (Source & RCC_CFGR_PLLSRC) | PLLMul);
+ 800112e: 4b0e ldr r3, [pc, #56] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>)
+ 8001130: 685b ldr r3, [r3, #4]
+ 8001132: 4a0e ldr r2, [pc, #56] ; (800116c <LL_RCC_PLL_ConfigDomain_SYS+0x48>)
+ 8001134: 4013 ands r3, r2
+ 8001136: 0019 movs r1, r3
+ 8001138: 687a ldr r2, [r7, #4]
+ 800113a: 2380 movs r3, #128 ; 0x80
+ 800113c: 025b lsls r3, r3, #9
+ 800113e: 401a ands r2, r3
+ 8001140: 683b ldr r3, [r7, #0]
+ 8001142: 431a orrs r2, r3
+ 8001144: 4b08 ldr r3, [pc, #32] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>)
+ 8001146: 430a orrs r2, r1
+ 8001148: 605a str r2, [r3, #4]
+ MODIFY_REG(RCC->CFGR2, RCC_CFGR2_PREDIV, (Source & RCC_CFGR2_PREDIV));
+ 800114a: 4b07 ldr r3, [pc, #28] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>)
+ 800114c: 6adb ldr r3, [r3, #44] ; 0x2c
+ 800114e: 220f movs r2, #15
+ 8001150: 4393 bics r3, r2
+ 8001152: 0019 movs r1, r3
+ 8001154: 687b ldr r3, [r7, #4]
+ 8001156: 220f movs r2, #15
+ 8001158: 401a ands r2, r3
+ 800115a: 4b03 ldr r3, [pc, #12] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>)
+ 800115c: 430a orrs r2, r1
+ 800115e: 62da str r2, [r3, #44] ; 0x2c
+}
+ 8001160: 46c0 nop ; (mov r8, r8)
+ 8001162: 46bd mov sp, r7
+ 8001164: b002 add sp, #8
+ 8001166: bd80 pop {r7, pc}
+ 8001168: 40021000 .word 0x40021000
+ 800116c: ffc2ffff .word 0xffc2ffff
+
+08001170 <LL_InitTick>:
+ * configuration by calling this function, for a delay use rather osDelay RTOS service.
+ * @param Ticks Number of ticks
+ * @retval None
+ */
+__STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks)
+{
+ 8001170: b580 push {r7, lr}
+ 8001172: b082 sub sp, #8
+ 8001174: af00 add r7, sp, #0
+ 8001176: 6078 str r0, [r7, #4]
+ 8001178: 6039 str r1, [r7, #0]
+ /* Configure the SysTick to have interrupt in 1ms time base */
+ SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */
+ 800117a: 6839 ldr r1, [r7, #0]
+ 800117c: 6878 ldr r0, [r7, #4]
+ 800117e: f000 fa13 bl 80015a8 <__udivsi3>
+ 8001182: 0003 movs r3, r0
+ 8001184: 001a movs r2, r3
+ 8001186: 4b06 ldr r3, [pc, #24] ; (80011a0 <LL_InitTick+0x30>)
+ 8001188: 3a01 subs r2, #1
+ 800118a: 605a str r2, [r3, #4]
+ SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
+ 800118c: 4b04 ldr r3, [pc, #16] ; (80011a0 <LL_InitTick+0x30>)
+ 800118e: 2200 movs r2, #0
+ 8001190: 609a str r2, [r3, #8]
+ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
+ 8001192: 4b03 ldr r3, [pc, #12] ; (80011a0 <LL_InitTick+0x30>)
+ 8001194: 2205 movs r2, #5
+ 8001196: 601a str r2, [r3, #0]
+ SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */
+}
+ 8001198: 46c0 nop ; (mov r8, r8)
+ 800119a: 46bd mov sp, r7
+ 800119c: b002 add sp, #8
+ 800119e: bd80 pop {r7, pc}
+ 80011a0: e000e010 .word 0xe000e010
+
+080011a4 <LL_FLASH_SetLatency>:
+ * @arg @ref LL_FLASH_LATENCY_0
+ * @arg @ref LL_FLASH_LATENCY_1
+ * @retval None
+ */
+__STATIC_INLINE void LL_FLASH_SetLatency(uint32_t Latency)
+{
+ 80011a4: b580 push {r7, lr}
+ 80011a6: b082 sub sp, #8
+ 80011a8: af00 add r7, sp, #0
+ 80011aa: 6078 str r0, [r7, #4]
+ MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, Latency);
+ 80011ac: 4b06 ldr r3, [pc, #24] ; (80011c8 <LL_FLASH_SetLatency+0x24>)
+ 80011ae: 681b ldr r3, [r3, #0]
+ 80011b0: 2201 movs r2, #1
+ 80011b2: 4393 bics r3, r2
+ 80011b4: 0019 movs r1, r3
+ 80011b6: 4b04 ldr r3, [pc, #16] ; (80011c8 <LL_FLASH_SetLatency+0x24>)
+ 80011b8: 687a ldr r2, [r7, #4]
+ 80011ba: 430a orrs r2, r1
+ 80011bc: 601a str r2, [r3, #0]
+}
+ 80011be: 46c0 nop ; (mov r8, r8)
+ 80011c0: 46bd mov sp, r7
+ 80011c2: b002 add sp, #8
+ 80011c4: bd80 pop {r7, pc}
+ 80011c6: 46c0 nop ; (mov r8, r8)
+ 80011c8: 40022000 .word 0x40022000
+
+080011cc <LL_FLASH_GetLatency>:
+ * @retval Returned value can be one of the following values:
+ * @arg @ref LL_FLASH_LATENCY_0
+ * @arg @ref LL_FLASH_LATENCY_1
+ */
+__STATIC_INLINE uint32_t LL_FLASH_GetLatency(void)
+{
+ 80011cc: b580 push {r7, lr}
+ 80011ce: af00 add r7, sp, #0
+ return (uint32_t)(READ_BIT(FLASH->ACR, FLASH_ACR_LATENCY));
+ 80011d0: 4b03 ldr r3, [pc, #12] ; (80011e0 <LL_FLASH_GetLatency+0x14>)
+ 80011d2: 681b ldr r3, [r3, #0]
+ 80011d4: 2201 movs r2, #1
+ 80011d6: 4013 ands r3, r2
+}
+ 80011d8: 0018 movs r0, r3
+ 80011da: 46bd mov sp, r7
+ 80011dc: bd80 pop {r7, pc}
+ 80011de: 46c0 nop ; (mov r8, r8)
+ 80011e0: 40022000 .word 0x40022000
+
+080011e4 <LL_Init1msTick>:
+ * @param HCLKFrequency HCLK frequency in Hz
+ * @note HCLK frequency can be calculated thanks to RCC helper macro or function @ref LL_RCC_GetSystemClocksFreq
+ * @retval None
+ */
+void LL_Init1msTick(uint32_t HCLKFrequency)
+{
+ 80011e4: b580 push {r7, lr}
+ 80011e6: b082 sub sp, #8
+ 80011e8: af00 add r7, sp, #0
+ 80011ea: 6078 str r0, [r7, #4]
+ /* Use frequency provided in argument */
+ LL_InitTick(HCLKFrequency, 1000U);
+ 80011ec: 23fa movs r3, #250 ; 0xfa
+ 80011ee: 009a lsls r2, r3, #2
+ 80011f0: 687b ldr r3, [r7, #4]
+ 80011f2: 0011 movs r1, r2
+ 80011f4: 0018 movs r0, r3
+ 80011f6: f7ff ffbb bl 8001170 <LL_InitTick>
+}
+ 80011fa: 46c0 nop ; (mov r8, r8)
+ 80011fc: 46bd mov sp, r7
+ 80011fe: b002 add sp, #8
+ 8001200: bd80 pop {r7, pc}
+
+08001202 <LL_mDelay>:
+ * will configure Systick to 1ms
+ * @param Delay specifies the delay time length, in milliseconds.
+ * @retval None
+ */
+void LL_mDelay(uint32_t Delay)
+{
+ 8001202: b580 push {r7, lr}
+ 8001204: b084 sub sp, #16
+ 8001206: af00 add r7, sp, #0
+ 8001208: 6078 str r0, [r7, #4]
+ __IO uint32_t tmp = SysTick->CTRL; /* Clear the COUNTFLAG first */
+ 800120a: 4b0e ldr r3, [pc, #56] ; (8001244 <LL_mDelay+0x42>)
+ 800120c: 681b ldr r3, [r3, #0]
+ 800120e: 60fb str r3, [r7, #12]
+ /* Add this code to indicate that local variable is not used */
+ ((void)tmp);
+ 8001210: 68fb ldr r3, [r7, #12]
+
+ /* Add a period to guaranty minimum wait */
+ if (Delay < LL_MAX_DELAY)
+ 8001212: 687b ldr r3, [r7, #4]
+ 8001214: 3301 adds r3, #1
+ 8001216: d00c beq.n 8001232 <LL_mDelay+0x30>
+ {
+ Delay++;
+ 8001218: 687b ldr r3, [r7, #4]
+ 800121a: 3301 adds r3, #1
+ 800121c: 607b str r3, [r7, #4]
+ }
+
+ while (Delay)
+ 800121e: e008 b.n 8001232 <LL_mDelay+0x30>
+ {
+ if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0U)
+ 8001220: 4b08 ldr r3, [pc, #32] ; (8001244 <LL_mDelay+0x42>)
+ 8001222: 681a ldr r2, [r3, #0]
+ 8001224: 2380 movs r3, #128 ; 0x80
+ 8001226: 025b lsls r3, r3, #9
+ 8001228: 4013 ands r3, r2
+ 800122a: d002 beq.n 8001232 <LL_mDelay+0x30>
+ {
+ Delay--;
+ 800122c: 687b ldr r3, [r7, #4]
+ 800122e: 3b01 subs r3, #1
+ 8001230: 607b str r3, [r7, #4]
+ while (Delay)
+ 8001232: 687b ldr r3, [r7, #4]
+ 8001234: 2b00 cmp r3, #0
+ 8001236: d1f3 bne.n 8001220 <LL_mDelay+0x1e>
+ }
+ }
+}
+ 8001238: 46c0 nop ; (mov r8, r8)
+ 800123a: 46c0 nop ; (mov r8, r8)
+ 800123c: 46bd mov sp, r7
+ 800123e: b004 add sp, #16
+ 8001240: bd80 pop {r7, pc}
+ 8001242: 46c0 nop ; (mov r8, r8)
+ 8001244: e000e010 .word 0xe000e010
+
+08001248 <LL_SetSystemCoreClock>:
+ * @note Variable can be calculated also through SystemCoreClockUpdate function.
+ * @param HCLKFrequency HCLK frequency in Hz (can be calculated thanks to RCC helper macro)
+ * @retval None
+ */
+void LL_SetSystemCoreClock(uint32_t HCLKFrequency)
+{
+ 8001248: b580 push {r7, lr}
+ 800124a: b082 sub sp, #8
+ 800124c: af00 add r7, sp, #0
+ 800124e: 6078 str r0, [r7, #4]
+ /* HCLK clock frequency */
+ SystemCoreClock = HCLKFrequency;
+ 8001250: 4b03 ldr r3, [pc, #12] ; (8001260 <LL_SetSystemCoreClock+0x18>)
+ 8001252: 687a ldr r2, [r7, #4]
+ 8001254: 601a str r2, [r3, #0]
+}
+ 8001256: 46c0 nop ; (mov r8, r8)
+ 8001258: 46bd mov sp, r7
+ 800125a: b002 add sp, #8
+ 800125c: bd80 pop {r7, pc}
+ 800125e: 46c0 nop ; (mov r8, r8)
+ 8001260: 20000000 .word 0x20000000
+
+08001264 <LL_PLL_ConfigSystemClock_HSI>:
+ * - SUCCESS: Max frequency configuration done
+ * - ERROR: Max frequency configuration not done
+ */
+ErrorStatus LL_PLL_ConfigSystemClock_HSI(LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct,
+ LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
+{
+ 8001264: b590 push {r4, r7, lr}
+ 8001266: b085 sub sp, #20
+ 8001268: af00 add r7, sp, #0
+ 800126a: 6078 str r0, [r7, #4]
+ 800126c: 6039 str r1, [r7, #0]
+ ErrorStatus status = SUCCESS;
+ 800126e: 230f movs r3, #15
+ 8001270: 18fb adds r3, r7, r3
+ 8001272: 2201 movs r2, #1
+ 8001274: 701a strb r2, [r3, #0]
+ uint32_t pllfreq = 0U;
+ 8001276: 2300 movs r3, #0
+ 8001278: 60bb str r3, [r7, #8]
+
+ /* Check if one of the PLL is enabled */
+ if (UTILS_PLL_IsBusy() == SUCCESS)
+ 800127a: f000 f8d4 bl 8001426 <UTILS_PLL_IsBusy>
+ 800127e: 0003 movs r3, r0
+ 8001280: 2b01 cmp r3, #1
+ 8001282: d128 bne.n 80012d6 <LL_PLL_ConfigSystemClock_HSI+0x72>
+#if defined(RCC_PLLSRC_PREDIV1_SUPPORT)
+ /* Check PREDIV value */
+ assert_param(IS_LL_UTILS_PREDIV_VALUE(UTILS_PLLInitStruct->PLLDiv));
+#else
+ /* Force PREDIV value to 2 */
+ UTILS_PLLInitStruct->Prediv = LL_RCC_PREDIV_DIV_2;
+ 8001284: 687b ldr r3, [r7, #4]
+ 8001286: 2201 movs r2, #1
+ 8001288: 605a str r2, [r3, #4]
+#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/
+
+ /* Calculate the new PLL output frequency */
+ pllfreq = UTILS_GetPLLOutputFrequency(HSI_VALUE, UTILS_PLLInitStruct);
+ 800128a: 687b ldr r3, [r7, #4]
+ 800128c: 4a17 ldr r2, [pc, #92] ; (80012ec <LL_PLL_ConfigSystemClock_HSI+0x88>)
+ 800128e: 0019 movs r1, r3
+ 8001290: 0010 movs r0, r2
+ 8001292: f000 f8ab bl 80013ec <UTILS_GetPLLOutputFrequency>
+ 8001296: 0003 movs r3, r0
+ 8001298: 60bb str r3, [r7, #8]
+
+ /* Enable HSI if not enabled */
+ if (LL_RCC_HSI_IsReady() != 1U)
+ 800129a: f7ff fec7 bl 800102c <LL_RCC_HSI_IsReady>
+ 800129e: 0003 movs r3, r0
+ 80012a0: 2b01 cmp r3, #1
+ 80012a2: d007 beq.n 80012b4 <LL_PLL_ConfigSystemClock_HSI+0x50>
+ {
+ LL_RCC_HSI_Enable();
+ 80012a4: f7ff feb4 bl 8001010 <LL_RCC_HSI_Enable>
+ while (LL_RCC_HSI_IsReady() != 1U)
+ 80012a8: 46c0 nop ; (mov r8, r8)
+ 80012aa: f7ff febf bl 800102c <LL_RCC_HSI_IsReady>
+ 80012ae: 0003 movs r3, r0
+ 80012b0: 2b01 cmp r3, #1
+ 80012b2: d1fa bne.n 80012aa <LL_PLL_ConfigSystemClock_HSI+0x46>
+
+ /* Configure PLL */
+#if defined(RCC_PLLSRC_PREDIV1_SUPPORT)
+ LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, UTILS_PLLInitStruct->PLLMul, UTILS_PLLInitStruct->PLLDiv);
+#else
+ LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, UTILS_PLLInitStruct->PLLMul);
+ 80012b4: 687b ldr r3, [r7, #4]
+ 80012b6: 681b ldr r3, [r3, #0]
+ 80012b8: 0019 movs r1, r3
+ 80012ba: 2000 movs r0, #0
+ 80012bc: f7ff ff32 bl 8001124 <LL_RCC_PLL_ConfigDomain_SYS>
+#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/
+
+ /* Enable PLL and switch system clock to PLL */
+ status = UTILS_EnablePLLAndSwitchSystem(pllfreq, UTILS_ClkInitStruct);
+ 80012c0: 230f movs r3, #15
+ 80012c2: 18fc adds r4, r7, r3
+ 80012c4: 683a ldr r2, [r7, #0]
+ 80012c6: 68bb ldr r3, [r7, #8]
+ 80012c8: 0011 movs r1, r2
+ 80012ca: 0018 movs r0, r3
+ 80012cc: f000 f8be bl 800144c <UTILS_EnablePLLAndSwitchSystem>
+ 80012d0: 0003 movs r3, r0
+ 80012d2: 7023 strb r3, [r4, #0]
+ 80012d4: e003 b.n 80012de <LL_PLL_ConfigSystemClock_HSI+0x7a>
+ }
+ else
+ {
+ /* Current PLL configuration cannot be modified */
+ status = ERROR;
+ 80012d6: 230f movs r3, #15
+ 80012d8: 18fb adds r3, r7, r3
+ 80012da: 2200 movs r2, #0
+ 80012dc: 701a strb r2, [r3, #0]
+ }
+
+ return status;
+ 80012de: 230f movs r3, #15
+ 80012e0: 18fb adds r3, r7, r3
+ 80012e2: 781b ldrb r3, [r3, #0]
+}
+ 80012e4: 0018 movs r0, r3
+ 80012e6: 46bd mov sp, r7
+ 80012e8: b005 add sp, #20
+ 80012ea: bd90 pop {r4, r7, pc}
+ 80012ec: 007a1200 .word 0x007a1200
+
+080012f0 <LL_PLL_ConfigSystemClock_HSE>:
+ * - SUCCESS: Max frequency configuration done
+ * - ERROR: Max frequency configuration not done
+ */
+ErrorStatus LL_PLL_ConfigSystemClock_HSE(uint32_t HSEFrequency, uint32_t HSEBypass,
+ LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
+{
+ 80012f0: b590 push {r4, r7, lr}
+ 80012f2: b087 sub sp, #28
+ 80012f4: af00 add r7, sp, #0
+ 80012f6: 60f8 str r0, [r7, #12]
+ 80012f8: 60b9 str r1, [r7, #8]
+ 80012fa: 607a str r2, [r7, #4]
+ 80012fc: 603b str r3, [r7, #0]
+ ErrorStatus status = SUCCESS;
+ 80012fe: 2317 movs r3, #23
+ 8001300: 18fb adds r3, r7, r3
+ 8001302: 2201 movs r2, #1
+ 8001304: 701a strb r2, [r3, #0]
+ uint32_t pllfreq = 0U;
+ 8001306: 2300 movs r3, #0
+ 8001308: 613b str r3, [r7, #16]
+ /* Check the parameters */
+ assert_param(IS_LL_UTILS_HSE_FREQUENCY(HSEFrequency));
+ assert_param(IS_LL_UTILS_HSE_BYPASS(HSEBypass));
+
+ /* Check if one of the PLL is enabled */
+ if (UTILS_PLL_IsBusy() == SUCCESS)
+ 800130a: f000 f88c bl 8001426 <UTILS_PLL_IsBusy>
+ 800130e: 0003 movs r3, r0
+ 8001310: 2b01 cmp r3, #1
+ 8001312: d132 bne.n 800137a <LL_PLL_ConfigSystemClock_HSE+0x8a>
+#else
+ assert_param(IS_LL_UTILS_PREDIV_VALUE(UTILS_PLLInitStruct->Prediv));
+#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/
+
+ /* Calculate the new PLL output frequency */
+ pllfreq = UTILS_GetPLLOutputFrequency(HSEFrequency, UTILS_PLLInitStruct);
+ 8001314: 687a ldr r2, [r7, #4]
+ 8001316: 68fb ldr r3, [r7, #12]
+ 8001318: 0011 movs r1, r2
+ 800131a: 0018 movs r0, r3
+ 800131c: f000 f866 bl 80013ec <UTILS_GetPLLOutputFrequency>
+ 8001320: 0003 movs r3, r0
+ 8001322: 613b str r3, [r7, #16]
+
+ /* Enable HSE if not enabled */
+ if (LL_RCC_HSE_IsReady() != 1U)
+ 8001324: f7ff fe60 bl 8000fe8 <LL_RCC_HSE_IsReady>
+ 8001328: 0003 movs r3, r0
+ 800132a: 2b01 cmp r3, #1
+ 800132c: d00f beq.n 800134e <LL_PLL_ConfigSystemClock_HSE+0x5e>
+ {
+ /* Check if need to enable HSE bypass feature or not */
+ if (HSEBypass == LL_UTILS_HSEBYPASS_ON)
+ 800132e: 68bb ldr r3, [r7, #8]
+ 8001330: 2b01 cmp r3, #1
+ 8001332: d102 bne.n 800133a <LL_PLL_ConfigSystemClock_HSE+0x4a>
+ {
+ LL_RCC_HSE_EnableBypass();
+ 8001334: f7ff fe2c bl 8000f90 <LL_RCC_HSE_EnableBypass>
+ 8001338: e001 b.n 800133e <LL_PLL_ConfigSystemClock_HSE+0x4e>
+ }
+ else
+ {
+ LL_RCC_HSE_DisableBypass();
+ 800133a: f7ff fe37 bl 8000fac <LL_RCC_HSE_DisableBypass>
+ }
+
+ /* Enable HSE */
+ LL_RCC_HSE_Enable();
+ 800133e: f7ff fe45 bl 8000fcc <LL_RCC_HSE_Enable>
+ while (LL_RCC_HSE_IsReady() != 1U)
+ 8001342: 46c0 nop ; (mov r8, r8)
+ 8001344: f7ff fe50 bl 8000fe8 <LL_RCC_HSE_IsReady>
+ 8001348: 0003 movs r3, r0
+ 800134a: 2b01 cmp r3, #1
+ 800134c: d1fa bne.n 8001344 <LL_PLL_ConfigSystemClock_HSE+0x54>
+
+ /* Configure PLL */
+#if defined(RCC_PLLSRC_PREDIV1_SUPPORT)
+ LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, UTILS_PLLInitStruct->PLLMul, UTILS_PLLInitStruct->PLLDiv);
+#else
+ LL_RCC_PLL_ConfigDomain_SYS((RCC_CFGR_PLLSRC_HSE_PREDIV | UTILS_PLLInitStruct->Prediv), UTILS_PLLInitStruct->PLLMul);
+ 800134e: 687b ldr r3, [r7, #4]
+ 8001350: 685b ldr r3, [r3, #4]
+ 8001352: 2280 movs r2, #128 ; 0x80
+ 8001354: 0252 lsls r2, r2, #9
+ 8001356: 431a orrs r2, r3
+ 8001358: 687b ldr r3, [r7, #4]
+ 800135a: 681b ldr r3, [r3, #0]
+ 800135c: 0019 movs r1, r3
+ 800135e: 0010 movs r0, r2
+ 8001360: f7ff fee0 bl 8001124 <LL_RCC_PLL_ConfigDomain_SYS>
+#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/
+
+ /* Enable PLL and switch system clock to PLL */
+ status = UTILS_EnablePLLAndSwitchSystem(pllfreq, UTILS_ClkInitStruct);
+ 8001364: 2317 movs r3, #23
+ 8001366: 18fc adds r4, r7, r3
+ 8001368: 683a ldr r2, [r7, #0]
+ 800136a: 693b ldr r3, [r7, #16]
+ 800136c: 0011 movs r1, r2
+ 800136e: 0018 movs r0, r3
+ 8001370: f000 f86c bl 800144c <UTILS_EnablePLLAndSwitchSystem>
+ 8001374: 0003 movs r3, r0
+ 8001376: 7023 strb r3, [r4, #0]
+ 8001378: e003 b.n 8001382 <LL_PLL_ConfigSystemClock_HSE+0x92>
+ }
+ else
+ {
+ /* Current PLL configuration cannot be modified */
+ status = ERROR;
+ 800137a: 2317 movs r3, #23
+ 800137c: 18fb adds r3, r7, r3
+ 800137e: 2200 movs r2, #0
+ 8001380: 701a strb r2, [r3, #0]
+ }
+
+ return status;
+ 8001382: 2317 movs r3, #23
+ 8001384: 18fb adds r3, r7, r3
+ 8001386: 781b ldrb r3, [r3, #0]
+}
+ 8001388: 0018 movs r0, r3
+ 800138a: 46bd mov sp, r7
+ 800138c: b007 add sp, #28
+ 800138e: bd90 pop {r4, r7, pc}
+
+08001390 <UTILS_SetFlashLatency>:
+ * @retval An ErrorStatus enumeration value:
+ * - SUCCESS: Latency has been modified
+ * - ERROR: Latency cannot be modified
+ */
+static ErrorStatus UTILS_SetFlashLatency(uint32_t Frequency)
+{
+ 8001390: b580 push {r7, lr}
+ 8001392: b084 sub sp, #16
+ 8001394: af00 add r7, sp, #0
+ 8001396: 6078 str r0, [r7, #4]
+ ErrorStatus status = SUCCESS;
+ 8001398: 210f movs r1, #15
+ 800139a: 187b adds r3, r7, r1
+ 800139c: 2201 movs r2, #1
+ 800139e: 701a strb r2, [r3, #0]
+
+ uint32_t latency = LL_FLASH_LATENCY_0; /* default value 0WS */
+ 80013a0: 2300 movs r3, #0
+ 80013a2: 60bb str r3, [r7, #8]
+
+ /* Frequency cannot be equal to 0 */
+ if (Frequency == 0U)
+ 80013a4: 687b ldr r3, [r7, #4]
+ 80013a6: 2b00 cmp r3, #0
+ 80013a8: d103 bne.n 80013b2 <UTILS_SetFlashLatency+0x22>
+ {
+ status = ERROR;
+ 80013aa: 187b adds r3, r7, r1
+ 80013ac: 2200 movs r2, #0
+ 80013ae: 701a strb r2, [r3, #0]
+ 80013b0: e013 b.n 80013da <UTILS_SetFlashLatency+0x4a>
+ }
+ else
+ {
+ if (Frequency > UTILS_LATENCY1_FREQ)
+ 80013b2: 687b ldr r3, [r7, #4]
+ 80013b4: 4a0c ldr r2, [pc, #48] ; (80013e8 <UTILS_SetFlashLatency+0x58>)
+ 80013b6: 4293 cmp r3, r2
+ 80013b8: d901 bls.n 80013be <UTILS_SetFlashLatency+0x2e>
+ {
+ /* 24 < SYSCLK <= 48 => 1WS (2 CPU cycles) */
+ latency = LL_FLASH_LATENCY_1;
+ 80013ba: 2301 movs r3, #1
+ 80013bc: 60bb str r3, [r7, #8]
+ }
+ /* else SYSCLK < 24MHz default LL_FLASH_LATENCY_0 0WS */
+
+ LL_FLASH_SetLatency(latency);
+ 80013be: 68bb ldr r3, [r7, #8]
+ 80013c0: 0018 movs r0, r3
+ 80013c2: f7ff feef bl 80011a4 <LL_FLASH_SetLatency>
+
+ /* Check that the new number of wait states is taken into account to access the Flash
+ memory by reading the FLASH_ACR register */
+ if (LL_FLASH_GetLatency() != latency)
+ 80013c6: f7ff ff01 bl 80011cc <LL_FLASH_GetLatency>
+ 80013ca: 0002 movs r2, r0
+ 80013cc: 68bb ldr r3, [r7, #8]
+ 80013ce: 4293 cmp r3, r2
+ 80013d0: d003 beq.n 80013da <UTILS_SetFlashLatency+0x4a>
+ {
+ status = ERROR;
+ 80013d2: 230f movs r3, #15
+ 80013d4: 18fb adds r3, r7, r3
+ 80013d6: 2200 movs r2, #0
+ 80013d8: 701a strb r2, [r3, #0]
+ }
+ }
+ return status;
+ 80013da: 230f movs r3, #15
+ 80013dc: 18fb adds r3, r7, r3
+ 80013de: 781b ldrb r3, [r3, #0]
+}
+ 80013e0: 0018 movs r0, r3
+ 80013e2: 46bd mov sp, r7
+ 80013e4: b004 add sp, #16
+ 80013e6: bd80 pop {r7, pc}
+ 80013e8: 016e3600 .word 0x016e3600
+
+080013ec <UTILS_GetPLLOutputFrequency>:
+ * @param UTILS_PLLInitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains
+ * the configuration information for the PLL.
+ * @retval PLL output frequency (in Hz)
+ */
+static uint32_t UTILS_GetPLLOutputFrequency(uint32_t PLL_InputFrequency, LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct)
+{
+ 80013ec: b580 push {r7, lr}
+ 80013ee: b084 sub sp, #16
+ 80013f0: af00 add r7, sp, #0
+ 80013f2: 6078 str r0, [r7, #4]
+ 80013f4: 6039 str r1, [r7, #0]
+ uint32_t pllfreq = 0U;
+ 80013f6: 2300 movs r3, #0
+ 80013f8: 60fb str r3, [r7, #12]
+ /* The application software must set correctly the PLL multiplication factor to
+ be in the range 16-48MHz */
+#if defined(RCC_PLLSRC_PREDIV1_SUPPORT)
+ pllfreq = __LL_RCC_CALC_PLLCLK_FREQ(PLL_InputFrequency, UTILS_PLLInitStruct->PLLMul, UTILS_PLLInitStruct->PLLDiv);
+#else
+ pllfreq = __LL_RCC_CALC_PLLCLK_FREQ(PLL_InputFrequency / (UTILS_PLLInitStruct->Prediv + 1U), UTILS_PLLInitStruct->PLLMul);
+ 80013fa: 683b ldr r3, [r7, #0]
+ 80013fc: 685b ldr r3, [r3, #4]
+ 80013fe: 3301 adds r3, #1
+ 8001400: 0019 movs r1, r3
+ 8001402: 6878 ldr r0, [r7, #4]
+ 8001404: f000 f8d0 bl 80015a8 <__udivsi3>
+ 8001408: 0003 movs r3, r0
+ 800140a: 0019 movs r1, r3
+ 800140c: 683b ldr r3, [r7, #0]
+ 800140e: 681b ldr r3, [r3, #0]
+ 8001410: 0c9b lsrs r3, r3, #18
+ 8001412: 220f movs r2, #15
+ 8001414: 4013 ands r3, r2
+ 8001416: 3302 adds r3, #2
+ 8001418: 434b muls r3, r1
+ 800141a: 60fb str r3, [r7, #12]
+#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/
+ assert_param(IS_LL_UTILS_PLL_FREQUENCY(pllfreq));
+
+ return pllfreq;
+ 800141c: 68fb ldr r3, [r7, #12]
+}
+ 800141e: 0018 movs r0, r3
+ 8001420: 46bd mov sp, r7
+ 8001422: b004 add sp, #16
+ 8001424: bd80 pop {r7, pc}
+
+08001426 <UTILS_PLL_IsBusy>:
+ * @retval An ErrorStatus enumeration value:
+ * - SUCCESS: PLL modification can be done
+ * - ERROR: PLL is busy
+ */
+static ErrorStatus UTILS_PLL_IsBusy(void)
+{
+ 8001426: b580 push {r7, lr}
+ 8001428: b082 sub sp, #8
+ 800142a: af00 add r7, sp, #0
+ ErrorStatus status = SUCCESS;
+ 800142c: 1dfb adds r3, r7, #7
+ 800142e: 2201 movs r2, #1
+ 8001430: 701a strb r2, [r3, #0]
+
+ /* Check if PLL is busy*/
+ if (LL_RCC_PLL_IsReady() != 0U)
+ 8001432: f7ff fe63 bl 80010fc <LL_RCC_PLL_IsReady>
+ 8001436: 1e03 subs r3, r0, #0
+ 8001438: d002 beq.n 8001440 <UTILS_PLL_IsBusy+0x1a>
+ {
+ /* PLL configuration cannot be modified */
+ status = ERROR;
+ 800143a: 1dfb adds r3, r7, #7
+ 800143c: 2200 movs r2, #0
+ 800143e: 701a strb r2, [r3, #0]
+ }
+
+
+ return status;
+ 8001440: 1dfb adds r3, r7, #7
+ 8001442: 781b ldrb r3, [r3, #0]
+}
+ 8001444: 0018 movs r0, r3
+ 8001446: 46bd mov sp, r7
+ 8001448: b002 add sp, #8
+ 800144a: bd80 pop {r7, pc}
+
+0800144c <UTILS_EnablePLLAndSwitchSystem>:
+ * @retval An ErrorStatus enumeration value:
+ * - SUCCESS: No problem to switch system to PLL
+ * - ERROR: Problem to switch system to PLL
+ */
+static ErrorStatus UTILS_EnablePLLAndSwitchSystem(uint32_t SYSCLK_Frequency, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct)
+{
+ 800144c: b590 push {r4, r7, lr}
+ 800144e: b085 sub sp, #20
+ 8001450: af00 add r7, sp, #0
+ 8001452: 6078 str r0, [r7, #4]
+ 8001454: 6039 str r1, [r7, #0]
+ ErrorStatus status = SUCCESS;
+ 8001456: 200f movs r0, #15
+ 8001458: 183b adds r3, r7, r0
+ 800145a: 2201 movs r2, #1
+ 800145c: 701a strb r2, [r3, #0]
+ uint32_t sysclk_frequency_current = 0U;
+ 800145e: 2300 movs r3, #0
+ 8001460: 60bb str r3, [r7, #8]
+
+ assert_param(IS_LL_UTILS_SYSCLK_DIV(UTILS_ClkInitStruct->AHBCLKDivider));
+ assert_param(IS_LL_UTILS_APB1_DIV(UTILS_ClkInitStruct->APB1CLKDivider));
+
+ /* Calculate current SYSCLK frequency */
+ sysclk_frequency_current = (SystemCoreClock << AHBPrescTable[(UTILS_ClkInitStruct->AHBCLKDivider & RCC_CFGR_HPRE) >> RCC_POSITION_HPRE]);
+ 8001462: 4b2e ldr r3, [pc, #184] ; (800151c <UTILS_EnablePLLAndSwitchSystem+0xd0>)
+ 8001464: 681a ldr r2, [r3, #0]
+ 8001466: 683b ldr r3, [r7, #0]
+ 8001468: 681b ldr r3, [r3, #0]
+ 800146a: 091b lsrs r3, r3, #4
+ 800146c: 210f movs r1, #15
+ 800146e: 400b ands r3, r1
+ 8001470: 492b ldr r1, [pc, #172] ; (8001520 <UTILS_EnablePLLAndSwitchSystem+0xd4>)
+ 8001472: 5ccb ldrb r3, [r1, r3]
+ 8001474: 409a lsls r2, r3
+ 8001476: 0013 movs r3, r2
+ 8001478: 60bb str r3, [r7, #8]
+
+ /* Increasing the number of wait states because of higher CPU frequency */
+ if (sysclk_frequency_current < SYSCLK_Frequency)
+ 800147a: 68ba ldr r2, [r7, #8]
+ 800147c: 687b ldr r3, [r7, #4]
+ 800147e: 429a cmp r2, r3
+ 8001480: d206 bcs.n 8001490 <UTILS_EnablePLLAndSwitchSystem+0x44>
+ {
+ /* Set FLASH latency to highest latency */
+ status = UTILS_SetFlashLatency(SYSCLK_Frequency);
+ 8001482: 183c adds r4, r7, r0
+ 8001484: 687b ldr r3, [r7, #4]
+ 8001486: 0018 movs r0, r3
+ 8001488: f7ff ff82 bl 8001390 <UTILS_SetFlashLatency>
+ 800148c: 0003 movs r3, r0
+ 800148e: 7023 strb r3, [r4, #0]
+ }
+
+ /* Update system clock configuration */
+ if (status == SUCCESS)
+ 8001490: 230f movs r3, #15
+ 8001492: 18fb adds r3, r7, r3
+ 8001494: 781b ldrb r3, [r3, #0]
+ 8001496: 2b01 cmp r3, #1
+ 8001498: d11a bne.n 80014d0 <UTILS_EnablePLLAndSwitchSystem+0x84>
+ {
+ /* Enable PLL */
+ LL_RCC_PLL_Enable();
+ 800149a: f7ff fe21 bl 80010e0 <LL_RCC_PLL_Enable>
+ while (LL_RCC_PLL_IsReady() != 1U)
+ 800149e: 46c0 nop ; (mov r8, r8)
+ 80014a0: f7ff fe2c bl 80010fc <LL_RCC_PLL_IsReady>
+ 80014a4: 0003 movs r3, r0
+ 80014a6: 2b01 cmp r3, #1
+ 80014a8: d1fa bne.n 80014a0 <UTILS_EnablePLLAndSwitchSystem+0x54>
+ {
+ /* Wait for PLL ready */
+ }
+
+ /* Sysclk activation on the main PLL */
+ LL_RCC_SetAHBPrescaler(UTILS_ClkInitStruct->AHBCLKDivider);
+ 80014aa: 683b ldr r3, [r7, #0]
+ 80014ac: 681b ldr r3, [r3, #0]
+ 80014ae: 0018 movs r0, r3
+ 80014b0: f7ff fdec bl 800108c <LL_RCC_SetAHBPrescaler>
+ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
+ 80014b4: 2002 movs r0, #2
+ 80014b6: f7ff fdc9 bl 800104c <LL_RCC_SetSysClkSource>
+ while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
+ 80014ba: 46c0 nop ; (mov r8, r8)
+ 80014bc: f7ff fdda bl 8001074 <LL_RCC_GetSysClkSource>
+ 80014c0: 0003 movs r3, r0
+ 80014c2: 2b08 cmp r3, #8
+ 80014c4: d1fa bne.n 80014bc <UTILS_EnablePLLAndSwitchSystem+0x70>
+ {
+ /* Wait for system clock switch to PLL */
+ }
+
+ /* Set APB1 & APB2 prescaler*/
+ LL_RCC_SetAPB1Prescaler(UTILS_ClkInitStruct->APB1CLKDivider);
+ 80014c6: 683b ldr r3, [r7, #0]
+ 80014c8: 685b ldr r3, [r3, #4]
+ 80014ca: 0018 movs r0, r3
+ 80014cc: f7ff fdf2 bl 80010b4 <LL_RCC_SetAPB1Prescaler>
+ }
+
+ /* Decreasing the number of wait states because of lower CPU frequency */
+ if (sysclk_frequency_current > SYSCLK_Frequency)
+ 80014d0: 68ba ldr r2, [r7, #8]
+ 80014d2: 687b ldr r3, [r7, #4]
+ 80014d4: 429a cmp r2, r3
+ 80014d6: d907 bls.n 80014e8 <UTILS_EnablePLLAndSwitchSystem+0x9c>
+ {
+ /* Set FLASH latency to lowest latency */
+ status = UTILS_SetFlashLatency(SYSCLK_Frequency);
+ 80014d8: 230f movs r3, #15
+ 80014da: 18fc adds r4, r7, r3
+ 80014dc: 687b ldr r3, [r7, #4]
+ 80014de: 0018 movs r0, r3
+ 80014e0: f7ff ff56 bl 8001390 <UTILS_SetFlashLatency>
+ 80014e4: 0003 movs r3, r0
+ 80014e6: 7023 strb r3, [r4, #0]
+ }
+
+ /* Update SystemCoreClock variable */
+ if (status == SUCCESS)
+ 80014e8: 230f movs r3, #15
+ 80014ea: 18fb adds r3, r7, r3
+ 80014ec: 781b ldrb r3, [r3, #0]
+ 80014ee: 2b01 cmp r3, #1
+ 80014f0: d10c bne.n 800150c <UTILS_EnablePLLAndSwitchSystem+0xc0>
+ {
+ LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ(SYSCLK_Frequency, UTILS_ClkInitStruct->AHBCLKDivider));
+ 80014f2: 683b ldr r3, [r7, #0]
+ 80014f4: 681b ldr r3, [r3, #0]
+ 80014f6: 091b lsrs r3, r3, #4
+ 80014f8: 220f movs r2, #15
+ 80014fa: 4013 ands r3, r2
+ 80014fc: 4a08 ldr r2, [pc, #32] ; (8001520 <UTILS_EnablePLLAndSwitchSystem+0xd4>)
+ 80014fe: 5cd3 ldrb r3, [r2, r3]
+ 8001500: 001a movs r2, r3
+ 8001502: 687b ldr r3, [r7, #4]
+ 8001504: 40d3 lsrs r3, r2
+ 8001506: 0018 movs r0, r3
+ 8001508: f7ff fe9e bl 8001248 <LL_SetSystemCoreClock>
+ }
+
+ return status;
+ 800150c: 230f movs r3, #15
+ 800150e: 18fb adds r3, r7, r3
+ 8001510: 781b ldrb r3, [r3, #0]
+}
+ 8001512: 0018 movs r0, r3
+ 8001514: 46bd mov sp, r7
+ 8001516: b005 add sp, #20
+ 8001518: bd90 pop {r4, r7, pc}
+ 800151a: 46c0 nop ; (mov r8, r8)
+ 800151c: 20000000 .word 0x20000000
+ 8001520: 080018ec .word 0x080018ec
+
+08001524 <__sinit>:
+#include <stdbool.h>
+
+int __errno = 0;
+void *_impure_ptr = NULL;
+
+void __sinit(void) {
+ 8001524: b580 push {r7, lr}
+ 8001526: af00 add r7, sp, #0
+}
+ 8001528: 46c0 nop ; (mov r8, r8)
+ 800152a: 46bd mov sp, r7
+ 800152c: bd80 pop {r7, pc}
+
+0800152e <memset>:
+
+void *memset(void *s, int c, size_t n) {
+ 800152e: b580 push {r7, lr}
+ 8001530: b086 sub sp, #24
+ 8001532: af00 add r7, sp, #0
+ 8001534: 60f8 str r0, [r7, #12]
+ 8001536: 60b9 str r1, [r7, #8]
+ 8001538: 607a str r2, [r7, #4]
+ char *end = (char *)s + n;
+ 800153a: 68fa ldr r2, [r7, #12]
+ 800153c: 687b ldr r3, [r7, #4]
+ 800153e: 18d3 adds r3, r2, r3
+ 8001540: 613b str r3, [r7, #16]
+ for (char *p = (char *)s; p < end; p++)
+ 8001542: 68fb ldr r3, [r7, #12]
+ 8001544: 617b str r3, [r7, #20]
+ 8001546: e006 b.n 8001556 <memset+0x28>
+ *p = (char)c;
+ 8001548: 68bb ldr r3, [r7, #8]
+ 800154a: b2da uxtb r2, r3
+ 800154c: 697b ldr r3, [r7, #20]
+ 800154e: 701a strb r2, [r3, #0]
+ for (char *p = (char *)s; p < end; p++)
+ 8001550: 697b ldr r3, [r7, #20]
+ 8001552: 3301 adds r3, #1
+ 8001554: 617b str r3, [r7, #20]
+ 8001556: 697a ldr r2, [r7, #20]
+ 8001558: 693b ldr r3, [r7, #16]
+ 800155a: 429a cmp r2, r3
+ 800155c: d3f4 bcc.n 8001548 <memset+0x1a>
+ return s;
+ 800155e: 68fb ldr r3, [r7, #12]
+}
+ 8001560: 0018 movs r0, r3
+ 8001562: 46bd mov sp, r7
+ 8001564: b006 add sp, #24
+ 8001566: bd80 pop {r7, pc}
+
+08001568 <strlen>:
+
+size_t strlen(const char *s) {
+ 8001568: b580 push {r7, lr}
+ 800156a: b084 sub sp, #16
+ 800156c: af00 add r7, sp, #0
+ 800156e: 6078 str r0, [r7, #4]
+ const char *start = s;
+ 8001570: 687b ldr r3, [r7, #4]
+ 8001572: 60fb str r3, [r7, #12]
+ while (*s++);
+ 8001574: 46c0 nop ; (mov r8, r8)
+ 8001576: 687b ldr r3, [r7, #4]
+ 8001578: 1c5a adds r2, r3, #1
+ 800157a: 607a str r2, [r7, #4]
+ 800157c: 781b ldrb r3, [r3, #0]
+ 800157e: 2b00 cmp r3, #0
+ 8001580: d1f9 bne.n 8001576 <strlen+0xe>
+ return s - start - 1;
+ 8001582: 687a ldr r2, [r7, #4]
+ 8001584: 68fb ldr r3, [r7, #12]
+ 8001586: 1ad3 subs r3, r2, r3
+ 8001588: 3b01 subs r3, #1
+}
+ 800158a: 0018 movs r0, r3
+ 800158c: 46bd mov sp, r7
+ 800158e: b004 add sp, #16
+ 8001590: bd80 pop {r7, pc}
+
+08001592 <__assert_func>:
+
+void __assert_func(bool value) {
+ 8001592: b580 push {r7, lr}
+ 8001594: b082 sub sp, #8
+ 8001596: af00 add r7, sp, #0
+ 8001598: 0002 movs r2, r0
+ 800159a: 1dfb adds r3, r7, #7
+ 800159c: 701a strb r2, [r3, #0]
+}
+ 800159e: 46c0 nop ; (mov r8, r8)
+ 80015a0: 46bd mov sp, r7
+ 80015a2: b002 add sp, #8
+ 80015a4: bd80 pop {r7, pc}
+ ...
+
+080015a8 <__udivsi3>:
+ 80015a8: 2200 movs r2, #0
+ 80015aa: 0843 lsrs r3, r0, #1
+ 80015ac: 428b cmp r3, r1
+ 80015ae: d374 bcc.n 800169a <__udivsi3+0xf2>
+ 80015b0: 0903 lsrs r3, r0, #4
+ 80015b2: 428b cmp r3, r1
+ 80015b4: d35f bcc.n 8001676 <__udivsi3+0xce>
+ 80015b6: 0a03 lsrs r3, r0, #8
+ 80015b8: 428b cmp r3, r1
+ 80015ba: d344 bcc.n 8001646 <__udivsi3+0x9e>
+ 80015bc: 0b03 lsrs r3, r0, #12
+ 80015be: 428b cmp r3, r1
+ 80015c0: d328 bcc.n 8001614 <__udivsi3+0x6c>
+ 80015c2: 0c03 lsrs r3, r0, #16
+ 80015c4: 428b cmp r3, r1
+ 80015c6: d30d bcc.n 80015e4 <__udivsi3+0x3c>
+ 80015c8: 22ff movs r2, #255 ; 0xff
+ 80015ca: 0209 lsls r1, r1, #8
+ 80015cc: ba12 rev r2, r2
+ 80015ce: 0c03 lsrs r3, r0, #16
+ 80015d0: 428b cmp r3, r1
+ 80015d2: d302 bcc.n 80015da <__udivsi3+0x32>
+ 80015d4: 1212 asrs r2, r2, #8
+ 80015d6: 0209 lsls r1, r1, #8
+ 80015d8: d065 beq.n 80016a6 <__udivsi3+0xfe>
+ 80015da: 0b03 lsrs r3, r0, #12
+ 80015dc: 428b cmp r3, r1
+ 80015de: d319 bcc.n 8001614 <__udivsi3+0x6c>
+ 80015e0: e000 b.n 80015e4 <__udivsi3+0x3c>
+ 80015e2: 0a09 lsrs r1, r1, #8
+ 80015e4: 0bc3 lsrs r3, r0, #15
+ 80015e6: 428b cmp r3, r1
+ 80015e8: d301 bcc.n 80015ee <__udivsi3+0x46>
+ 80015ea: 03cb lsls r3, r1, #15
+ 80015ec: 1ac0 subs r0, r0, r3
+ 80015ee: 4152 adcs r2, r2
+ 80015f0: 0b83 lsrs r3, r0, #14
+ 80015f2: 428b cmp r3, r1
+ 80015f4: d301 bcc.n 80015fa <__udivsi3+0x52>
+ 80015f6: 038b lsls r3, r1, #14
+ 80015f8: 1ac0 subs r0, r0, r3
+ 80015fa: 4152 adcs r2, r2
+ 80015fc: 0b43 lsrs r3, r0, #13
+ 80015fe: 428b cmp r3, r1
+ 8001600: d301 bcc.n 8001606 <__udivsi3+0x5e>
+ 8001602: 034b lsls r3, r1, #13
+ 8001604: 1ac0 subs r0, r0, r3
+ 8001606: 4152 adcs r2, r2
+ 8001608: 0b03 lsrs r3, r0, #12
+ 800160a: 428b cmp r3, r1
+ 800160c: d301 bcc.n 8001612 <__udivsi3+0x6a>
+ 800160e: 030b lsls r3, r1, #12
+ 8001610: 1ac0 subs r0, r0, r3
+ 8001612: 4152 adcs r2, r2
+ 8001614: 0ac3 lsrs r3, r0, #11
+ 8001616: 428b cmp r3, r1
+ 8001618: d301 bcc.n 800161e <__udivsi3+0x76>
+ 800161a: 02cb lsls r3, r1, #11
+ 800161c: 1ac0 subs r0, r0, r3
+ 800161e: 4152 adcs r2, r2
+ 8001620: 0a83 lsrs r3, r0, #10
+ 8001622: 428b cmp r3, r1
+ 8001624: d301 bcc.n 800162a <__udivsi3+0x82>
+ 8001626: 028b lsls r3, r1, #10
+ 8001628: 1ac0 subs r0, r0, r3
+ 800162a: 4152 adcs r2, r2
+ 800162c: 0a43 lsrs r3, r0, #9
+ 800162e: 428b cmp r3, r1
+ 8001630: d301 bcc.n 8001636 <__udivsi3+0x8e>
+ 8001632: 024b lsls r3, r1, #9
+ 8001634: 1ac0 subs r0, r0, r3
+ 8001636: 4152 adcs r2, r2
+ 8001638: 0a03 lsrs r3, r0, #8
+ 800163a: 428b cmp r3, r1
+ 800163c: d301 bcc.n 8001642 <__udivsi3+0x9a>
+ 800163e: 020b lsls r3, r1, #8
+ 8001640: 1ac0 subs r0, r0, r3
+ 8001642: 4152 adcs r2, r2
+ 8001644: d2cd bcs.n 80015e2 <__udivsi3+0x3a>
+ 8001646: 09c3 lsrs r3, r0, #7
+ 8001648: 428b cmp r3, r1
+ 800164a: d301 bcc.n 8001650 <__udivsi3+0xa8>
+ 800164c: 01cb lsls r3, r1, #7
+ 800164e: 1ac0 subs r0, r0, r3
+ 8001650: 4152 adcs r2, r2
+ 8001652: 0983 lsrs r3, r0, #6
+ 8001654: 428b cmp r3, r1
+ 8001656: d301 bcc.n 800165c <__udivsi3+0xb4>
+ 8001658: 018b lsls r3, r1, #6
+ 800165a: 1ac0 subs r0, r0, r3
+ 800165c: 4152 adcs r2, r2
+ 800165e: 0943 lsrs r3, r0, #5
+ 8001660: 428b cmp r3, r1
+ 8001662: d301 bcc.n 8001668 <__udivsi3+0xc0>
+ 8001664: 014b lsls r3, r1, #5
+ 8001666: 1ac0 subs r0, r0, r3
+ 8001668: 4152 adcs r2, r2
+ 800166a: 0903 lsrs r3, r0, #4
+ 800166c: 428b cmp r3, r1
+ 800166e: d301 bcc.n 8001674 <__udivsi3+0xcc>
+ 8001670: 010b lsls r3, r1, #4
+ 8001672: 1ac0 subs r0, r0, r3
+ 8001674: 4152 adcs r2, r2
+ 8001676: 08c3 lsrs r3, r0, #3
+ 8001678: 428b cmp r3, r1
+ 800167a: d301 bcc.n 8001680 <__udivsi3+0xd8>
+ 800167c: 00cb lsls r3, r1, #3
+ 800167e: 1ac0 subs r0, r0, r3
+ 8001680: 4152 adcs r2, r2
+ 8001682: 0883 lsrs r3, r0, #2
+ 8001684: 428b cmp r3, r1
+ 8001686: d301 bcc.n 800168c <__udivsi3+0xe4>
+ 8001688: 008b lsls r3, r1, #2
+ 800168a: 1ac0 subs r0, r0, r3
+ 800168c: 4152 adcs r2, r2
+ 800168e: 0843 lsrs r3, r0, #1
+ 8001690: 428b cmp r3, r1
+ 8001692: d301 bcc.n 8001698 <__udivsi3+0xf0>
+ 8001694: 004b lsls r3, r1, #1
+ 8001696: 1ac0 subs r0, r0, r3
+ 8001698: 4152 adcs r2, r2
+ 800169a: 1a41 subs r1, r0, r1
+ 800169c: d200 bcs.n 80016a0 <__udivsi3+0xf8>
+ 800169e: 4601 mov r1, r0
+ 80016a0: 4152 adcs r2, r2
+ 80016a2: 4610 mov r0, r2
+ 80016a4: 4770 bx lr
+ 80016a6: e7ff b.n 80016a8 <__udivsi3+0x100>
+ 80016a8: b501 push {r0, lr}
+ 80016aa: 2000 movs r0, #0
+ 80016ac: f000 f8f0 bl 8001890 <__aeabi_idiv0>
+ 80016b0: bd02 pop {r1, pc}
+ 80016b2: 46c0 nop ; (mov r8, r8)
+
+080016b4 <__aeabi_uidivmod>:
+ 80016b4: 2900 cmp r1, #0
+ 80016b6: d0f7 beq.n 80016a8 <__udivsi3+0x100>
+ 80016b8: e776 b.n 80015a8 <__udivsi3>
+ 80016ba: 4770 bx lr
+
+080016bc <__divsi3>:
+ 80016bc: 4603 mov r3, r0
+ 80016be: 430b orrs r3, r1
+ 80016c0: d47f bmi.n 80017c2 <__divsi3+0x106>
+ 80016c2: 2200 movs r2, #0
+ 80016c4: 0843 lsrs r3, r0, #1
+ 80016c6: 428b cmp r3, r1
+ 80016c8: d374 bcc.n 80017b4 <__divsi3+0xf8>
+ 80016ca: 0903 lsrs r3, r0, #4
+ 80016cc: 428b cmp r3, r1
+ 80016ce: d35f bcc.n 8001790 <__divsi3+0xd4>
+ 80016d0: 0a03 lsrs r3, r0, #8
+ 80016d2: 428b cmp r3, r1
+ 80016d4: d344 bcc.n 8001760 <__divsi3+0xa4>
+ 80016d6: 0b03 lsrs r3, r0, #12
+ 80016d8: 428b cmp r3, r1
+ 80016da: d328 bcc.n 800172e <__divsi3+0x72>
+ 80016dc: 0c03 lsrs r3, r0, #16
+ 80016de: 428b cmp r3, r1
+ 80016e0: d30d bcc.n 80016fe <__divsi3+0x42>
+ 80016e2: 22ff movs r2, #255 ; 0xff
+ 80016e4: 0209 lsls r1, r1, #8
+ 80016e6: ba12 rev r2, r2
+ 80016e8: 0c03 lsrs r3, r0, #16
+ 80016ea: 428b cmp r3, r1
+ 80016ec: d302 bcc.n 80016f4 <__divsi3+0x38>
+ 80016ee: 1212 asrs r2, r2, #8
+ 80016f0: 0209 lsls r1, r1, #8
+ 80016f2: d065 beq.n 80017c0 <__divsi3+0x104>
+ 80016f4: 0b03 lsrs r3, r0, #12
+ 80016f6: 428b cmp r3, r1
+ 80016f8: d319 bcc.n 800172e <__divsi3+0x72>
+ 80016fa: e000 b.n 80016fe <__divsi3+0x42>
+ 80016fc: 0a09 lsrs r1, r1, #8
+ 80016fe: 0bc3 lsrs r3, r0, #15
+ 8001700: 428b cmp r3, r1
+ 8001702: d301 bcc.n 8001708 <__divsi3+0x4c>
+ 8001704: 03cb lsls r3, r1, #15
+ 8001706: 1ac0 subs r0, r0, r3
+ 8001708: 4152 adcs r2, r2
+ 800170a: 0b83 lsrs r3, r0, #14
+ 800170c: 428b cmp r3, r1
+ 800170e: d301 bcc.n 8001714 <__divsi3+0x58>
+ 8001710: 038b lsls r3, r1, #14
+ 8001712: 1ac0 subs r0, r0, r3
+ 8001714: 4152 adcs r2, r2
+ 8001716: 0b43 lsrs r3, r0, #13
+ 8001718: 428b cmp r3, r1
+ 800171a: d301 bcc.n 8001720 <__divsi3+0x64>
+ 800171c: 034b lsls r3, r1, #13
+ 800171e: 1ac0 subs r0, r0, r3
+ 8001720: 4152 adcs r2, r2
+ 8001722: 0b03 lsrs r3, r0, #12
+ 8001724: 428b cmp r3, r1
+ 8001726: d301 bcc.n 800172c <__divsi3+0x70>
+ 8001728: 030b lsls r3, r1, #12
+ 800172a: 1ac0 subs r0, r0, r3
+ 800172c: 4152 adcs r2, r2
+ 800172e: 0ac3 lsrs r3, r0, #11
+ 8001730: 428b cmp r3, r1
+ 8001732: d301 bcc.n 8001738 <__divsi3+0x7c>
+ 8001734: 02cb lsls r3, r1, #11
+ 8001736: 1ac0 subs r0, r0, r3
+ 8001738: 4152 adcs r2, r2
+ 800173a: 0a83 lsrs r3, r0, #10
+ 800173c: 428b cmp r3, r1
+ 800173e: d301 bcc.n 8001744 <__divsi3+0x88>
+ 8001740: 028b lsls r3, r1, #10
+ 8001742: 1ac0 subs r0, r0, r3
+ 8001744: 4152 adcs r2, r2
+ 8001746: 0a43 lsrs r3, r0, #9
+ 8001748: 428b cmp r3, r1
+ 800174a: d301 bcc.n 8001750 <__divsi3+0x94>
+ 800174c: 024b lsls r3, r1, #9
+ 800174e: 1ac0 subs r0, r0, r3
+ 8001750: 4152 adcs r2, r2
+ 8001752: 0a03 lsrs r3, r0, #8
+ 8001754: 428b cmp r3, r1
+ 8001756: d301 bcc.n 800175c <__divsi3+0xa0>
+ 8001758: 020b lsls r3, r1, #8
+ 800175a: 1ac0 subs r0, r0, r3
+ 800175c: 4152 adcs r2, r2
+ 800175e: d2cd bcs.n 80016fc <__divsi3+0x40>
+ 8001760: 09c3 lsrs r3, r0, #7
+ 8001762: 428b cmp r3, r1
+ 8001764: d301 bcc.n 800176a <__divsi3+0xae>
+ 8001766: 01cb lsls r3, r1, #7
+ 8001768: 1ac0 subs r0, r0, r3
+ 800176a: 4152 adcs r2, r2
+ 800176c: 0983 lsrs r3, r0, #6
+ 800176e: 428b cmp r3, r1
+ 8001770: d301 bcc.n 8001776 <__divsi3+0xba>
+ 8001772: 018b lsls r3, r1, #6
+ 8001774: 1ac0 subs r0, r0, r3
+ 8001776: 4152 adcs r2, r2
+ 8001778: 0943 lsrs r3, r0, #5
+ 800177a: 428b cmp r3, r1
+ 800177c: d301 bcc.n 8001782 <__divsi3+0xc6>
+ 800177e: 014b lsls r3, r1, #5
+ 8001780: 1ac0 subs r0, r0, r3
+ 8001782: 4152 adcs r2, r2
+ 8001784: 0903 lsrs r3, r0, #4
+ 8001786: 428b cmp r3, r1
+ 8001788: d301 bcc.n 800178e <__divsi3+0xd2>
+ 800178a: 010b lsls r3, r1, #4
+ 800178c: 1ac0 subs r0, r0, r3
+ 800178e: 4152 adcs r2, r2
+ 8001790: 08c3 lsrs r3, r0, #3
+ 8001792: 428b cmp r3, r1
+ 8001794: d301 bcc.n 800179a <__divsi3+0xde>
+ 8001796: 00cb lsls r3, r1, #3
+ 8001798: 1ac0 subs r0, r0, r3
+ 800179a: 4152 adcs r2, r2
+ 800179c: 0883 lsrs r3, r0, #2
+ 800179e: 428b cmp r3, r1
+ 80017a0: d301 bcc.n 80017a6 <__divsi3+0xea>
+ 80017a2: 008b lsls r3, r1, #2
+ 80017a4: 1ac0 subs r0, r0, r3
+ 80017a6: 4152 adcs r2, r2
+ 80017a8: 0843 lsrs r3, r0, #1
+ 80017aa: 428b cmp r3, r1
+ 80017ac: d301 bcc.n 80017b2 <__divsi3+0xf6>
+ 80017ae: 004b lsls r3, r1, #1
+ 80017b0: 1ac0 subs r0, r0, r3
+ 80017b2: 4152 adcs r2, r2
+ 80017b4: 1a41 subs r1, r0, r1
+ 80017b6: d200 bcs.n 80017ba <__divsi3+0xfe>
+ 80017b8: 4601 mov r1, r0
+ 80017ba: 4152 adcs r2, r2
+ 80017bc: 4610 mov r0, r2
+ 80017be: 4770 bx lr
+ 80017c0: e05d b.n 800187e <__divsi3+0x1c2>
+ 80017c2: 0fca lsrs r2, r1, #31
+ 80017c4: d000 beq.n 80017c8 <__divsi3+0x10c>
+ 80017c6: 4249 negs r1, r1
+ 80017c8: 1003 asrs r3, r0, #32
+ 80017ca: d300 bcc.n 80017ce <__divsi3+0x112>
+ 80017cc: 4240 negs r0, r0
+ 80017ce: 4053 eors r3, r2
+ 80017d0: 2200 movs r2, #0
+ 80017d2: 469c mov ip, r3
+ 80017d4: 0903 lsrs r3, r0, #4
+ 80017d6: 428b cmp r3, r1
+ 80017d8: d32d bcc.n 8001836 <__divsi3+0x17a>
+ 80017da: 0a03 lsrs r3, r0, #8
+ 80017dc: 428b cmp r3, r1
+ 80017de: d312 bcc.n 8001806 <__divsi3+0x14a>
+ 80017e0: 22fc movs r2, #252 ; 0xfc
+ 80017e2: 0189 lsls r1, r1, #6
+ 80017e4: ba12 rev r2, r2
+ 80017e6: 0a03 lsrs r3, r0, #8
+ 80017e8: 428b cmp r3, r1
+ 80017ea: d30c bcc.n 8001806 <__divsi3+0x14a>
+ 80017ec: 0189 lsls r1, r1, #6
+ 80017ee: 1192 asrs r2, r2, #6
+ 80017f0: 428b cmp r3, r1
+ 80017f2: d308 bcc.n 8001806 <__divsi3+0x14a>
+ 80017f4: 0189 lsls r1, r1, #6
+ 80017f6: 1192 asrs r2, r2, #6
+ 80017f8: 428b cmp r3, r1
+ 80017fa: d304 bcc.n 8001806 <__divsi3+0x14a>
+ 80017fc: 0189 lsls r1, r1, #6
+ 80017fe: d03a beq.n 8001876 <__divsi3+0x1ba>
+ 8001800: 1192 asrs r2, r2, #6
+ 8001802: e000 b.n 8001806 <__divsi3+0x14a>
+ 8001804: 0989 lsrs r1, r1, #6
+ 8001806: 09c3 lsrs r3, r0, #7
+ 8001808: 428b cmp r3, r1
+ 800180a: d301 bcc.n 8001810 <__divsi3+0x154>
+ 800180c: 01cb lsls r3, r1, #7
+ 800180e: 1ac0 subs r0, r0, r3
+ 8001810: 4152 adcs r2, r2
+ 8001812: 0983 lsrs r3, r0, #6
+ 8001814: 428b cmp r3, r1
+ 8001816: d301 bcc.n 800181c <__divsi3+0x160>
+ 8001818: 018b lsls r3, r1, #6
+ 800181a: 1ac0 subs r0, r0, r3
+ 800181c: 4152 adcs r2, r2
+ 800181e: 0943 lsrs r3, r0, #5
+ 8001820: 428b cmp r3, r1
+ 8001822: d301 bcc.n 8001828 <__divsi3+0x16c>
+ 8001824: 014b lsls r3, r1, #5
+ 8001826: 1ac0 subs r0, r0, r3
+ 8001828: 4152 adcs r2, r2
+ 800182a: 0903 lsrs r3, r0, #4
+ 800182c: 428b cmp r3, r1
+ 800182e: d301 bcc.n 8001834 <__divsi3+0x178>
+ 8001830: 010b lsls r3, r1, #4
+ 8001832: 1ac0 subs r0, r0, r3
+ 8001834: 4152 adcs r2, r2
+ 8001836: 08c3 lsrs r3, r0, #3
+ 8001838: 428b cmp r3, r1
+ 800183a: d301 bcc.n 8001840 <__divsi3+0x184>
+ 800183c: 00cb lsls r3, r1, #3
+ 800183e: 1ac0 subs r0, r0, r3
+ 8001840: 4152 adcs r2, r2
+ 8001842: 0883 lsrs r3, r0, #2
+ 8001844: 428b cmp r3, r1
+ 8001846: d301 bcc.n 800184c <__divsi3+0x190>
+ 8001848: 008b lsls r3, r1, #2
+ 800184a: 1ac0 subs r0, r0, r3
+ 800184c: 4152 adcs r2, r2
+ 800184e: d2d9 bcs.n 8001804 <__divsi3+0x148>
+ 8001850: 0843 lsrs r3, r0, #1
+ 8001852: 428b cmp r3, r1
+ 8001854: d301 bcc.n 800185a <__divsi3+0x19e>
+ 8001856: 004b lsls r3, r1, #1
+ 8001858: 1ac0 subs r0, r0, r3
+ 800185a: 4152 adcs r2, r2
+ 800185c: 1a41 subs r1, r0, r1
+ 800185e: d200 bcs.n 8001862 <__divsi3+0x1a6>
+ 8001860: 4601 mov r1, r0
+ 8001862: 4663 mov r3, ip
+ 8001864: 4152 adcs r2, r2
+ 8001866: 105b asrs r3, r3, #1
+ 8001868: 4610 mov r0, r2
+ 800186a: d301 bcc.n 8001870 <__divsi3+0x1b4>
+ 800186c: 4240 negs r0, r0
+ 800186e: 2b00 cmp r3, #0
+ 8001870: d500 bpl.n 8001874 <__divsi3+0x1b8>
+ 8001872: 4249 negs r1, r1
+ 8001874: 4770 bx lr
+ 8001876: 4663 mov r3, ip
+ 8001878: 105b asrs r3, r3, #1
+ 800187a: d300 bcc.n 800187e <__divsi3+0x1c2>
+ 800187c: 4240 negs r0, r0
+ 800187e: b501 push {r0, lr}
+ 8001880: 2000 movs r0, #0
+ 8001882: f000 f805 bl 8001890 <__aeabi_idiv0>
+ 8001886: bd02 pop {r1, pc}
+
+08001888 <__aeabi_idivmod>:
+ 8001888: 2900 cmp r1, #0
+ 800188a: d0f8 beq.n 800187e <__divsi3+0x1c2>
+ 800188c: e716 b.n 80016bc <__divsi3>
+ 800188e: 4770 bx lr
+
+08001890 <__aeabi_idiv0>:
+ 8001890: 4770 bx lr
+ 8001892: 46c0 nop ; (mov r8, r8)
+
+08001894 <Reset_Handler>:
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr r0, =_estack
+ 8001894: 480c ldr r0, [pc, #48] ; (80018c8 <LoopForever+0x2>)
+ mov sp, r0 /* set stack pointer */
+ 8001896: 4685 mov sp, r0
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ 8001898: 2100 movs r1, #0
+ b LoopCopyDataInit
+ 800189a: e003 b.n 80018a4 <LoopCopyDataInit>
+
+0800189c <CopyDataInit>:
+
+CopyDataInit:
+ ldr r3, =_sidata
+ 800189c: 4b0b ldr r3, [pc, #44] ; (80018cc <LoopForever+0x6>)
+ ldr r3, [r3, r1]
+ 800189e: 585b ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ 80018a0: 5043 str r3, [r0, r1]
+ adds r1, r1, #4
+ 80018a2: 3104 adds r1, #4
+
+080018a4 <LoopCopyDataInit>:
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ 80018a4: 480a ldr r0, [pc, #40] ; (80018d0 <LoopForever+0xa>)
+ ldr r3, =_edata
+ 80018a6: 4b0b ldr r3, [pc, #44] ; (80018d4 <LoopForever+0xe>)
+ adds r2, r0, r1
+ 80018a8: 1842 adds r2, r0, r1
+ cmp r2, r3
+ 80018aa: 429a cmp r2, r3
+ bcc CopyDataInit
+ 80018ac: d3f6 bcc.n 800189c <CopyDataInit>
+ ldr r2, =_sbss
+ 80018ae: 4a0a ldr r2, [pc, #40] ; (80018d8 <LoopForever+0x12>)
+ b LoopFillZerobss
+ 80018b0: e002 b.n 80018b8 <LoopFillZerobss>
+
+080018b2 <FillZerobss>:
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ 80018b2: 2300 movs r3, #0
+ str r3, [r2]
+ 80018b4: 6013 str r3, [r2, #0]
+ adds r2, r2, #4
+ 80018b6: 3204 adds r2, #4
+
+080018b8 <LoopFillZerobss>:
+
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ 80018b8: 4b08 ldr r3, [pc, #32] ; (80018dc <LoopForever+0x16>)
+ cmp r2, r3
+ 80018ba: 429a cmp r2, r3
+ bcc FillZerobss
+ 80018bc: d3f9 bcc.n 80018b2 <FillZerobss>
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+ 80018be: f7ff faad bl 8000e1c <SystemInit>
+/* Call static constructors */
+// bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+ 80018c2: f7fe fcaa bl 800021a <main>
+
+080018c6 <LoopForever>:
+
+LoopForever:
+ b LoopForever
+ 80018c6: e7fe b.n 80018c6 <LoopForever>
+ ldr r0, =_estack
+ 80018c8: 20001000 .word 0x20001000
+ ldr r3, =_sidata
+ 80018cc: 08001904 .word 0x08001904
+ ldr r0, =_sdata
+ 80018d0: 20000000 .word 0x20000000
+ ldr r3, =_edata
+ 80018d4: 20000094 .word 0x20000094
+ ldr r2, =_sbss
+ 80018d8: 20000094 .word 0x20000094
+ ldr r3, = _ebss
+ 80018dc: 200009d4 .word 0x200009d4
+
+080018e0 <ADC1_IRQHandler>:
+ * @retval : None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ 80018e0: e7fe b.n 80018e0 <ADC1_IRQHandler>
+ 80018e2: 0000 movs r0, r0
+ 80018e4: 424f4f46 .word 0x424f4f46
+ 80018e8: 000a5241 .word 0x000a5241
+
+080018ec <AHBPrescTable>:
+ ...
+ 80018f4: 04030201 09080706 ........
+
+080018fc <APBPrescTable>:
+ 80018fc: 00000000 04030201 ........
diff --git a/gm_platform/fw/main.map b/gm_platform/fw/main.map
new file mode 100644
index 0000000..ecbce31
--- /dev/null
+++ b/gm_platform/fw/main.map
@@ -0,0 +1,457 @@
+Archive member included to satisfy reference by file (symbol)
+
+/usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ /tmp/cchCmUnQ.o (__aeabi_uidiv)
+/usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ /tmp/cczzmF2c.o (__aeabi_idiv)
+/usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+ /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) (__aeabi_idiv0)
+
+Allocating common symbols
+Common symbol size file
+
+usart_tx_buf 0x10c /tmp/cc4OHQ7z.o
+leds 0x20 /tmp/cchCmUnQ.o
+adc_buf 0x800 /tmp/cczzmF2c.o
+
+Memory Configuration
+
+Name Origin Length Attributes
+FLASH 0x0000000008000000 0x0000000000003c00 xr
+CONFIGFLASH 0x0000000008003c00 0x0000000000000400 rw
+RAM 0x0000000020000000 0x0000000000001000 xrw
+*default* 0x0000000000000000 0xffffffffffffffff
+
+Linker script and memory map
+
+LOAD /home/user/resource/STM32CubeF0/Drivers/CMSIS/Lib/GCC/libarm_cortexM0l_math.a
+LOAD /tmp/cchCmUnQ.o
+LOAD /tmp/cczzmF2c.o
+LOAD /tmp/cc4OHQ7z.o
+LOAD /tmp/cc0OqFzX.o
+LOAD /tmp/ccTaPb5k.o
+LOAD /tmp/cc6XVkRI.o
+LOAD /tmp/ccvZIDd7.o
+LOAD /tmp/ccTEVTRv.o
+LOAD /tmp/ccvICuLU.o
+LOAD /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a
+ 0x0000000020001000 _estack = 0x20001000
+
+.isr_vector 0x0000000008000000 0xc0
+ 0x0000000008000000 . = ALIGN (0x4)
+ *(.isr_vector)
+ .isr_vector 0x0000000008000000 0xc0 /tmp/ccTaPb5k.o
+ 0x0000000008000000 g_pfnVectors
+ 0x00000000080000c0 . = ALIGN (0x4)
+
+.text 0x00000000080000c0 0x1844
+ 0x00000000080000c0 . = ALIGN (0x4)
+ *(.text)
+ .text 0x00000000080000c0 0x454 /tmp/cchCmUnQ.o
+ 0x0000000008000210 update_leds
+ 0x000000000800021a main
+ 0x00000000080003c8 SPI1_IRQHandler
+ 0x00000000080003f4 TIM16_IRQHandler
+ 0x00000000080004b0 NMI_Handler
+ 0x00000000080004bc HardFault_Handler
+ 0x00000000080004c0 SVC_Handler
+ 0x00000000080004cc PendSV_Handler
+ 0x00000000080004d8 SysTick_Handler
+ .text 0x0000000008000514 0x29c /tmp/cczzmF2c.o
+ 0x000000000800061c adc_configure_scope_mode
+ 0x0000000008000792 DMA1_Channel1_IRQHandler
+ .text 0x00000000080007b0 0x31c /tmp/cc4OHQ7z.o
+ 0x00000000080008e8 usart_dma_init
+ 0x00000000080009d4 usart_dma_fifo_push
+ 0x0000000008000a2c usart_putc
+ 0x0000000008000a5c DMA1_Channel2_3_IRQHandler
+ 0x0000000008000a9c usart_send_packet
+ .text 0x0000000008000acc 0x33a /tmp/cc0OqFzX.o
+ 0x0000000008000acc cobs_encode
+ 0x0000000008000b92 cobs_encode_usart
+ 0x0000000008000c32 cobs_decode
+ 0x0000000008000d08 cobs_decode_incremental_initialize
+ 0x0000000008000d24 cobs_decode_incremental
+ .text 0x0000000008000e06 0x14 /tmp/ccTaPb5k.o
+ *fill* 0x0000000008000e1a 0x2
+ .text 0x0000000008000e1c 0x174 /tmp/cc6XVkRI.o
+ 0x0000000008000e1c SystemInit
+ 0x0000000008000ea4 SystemCoreClockUpdate
+ .text 0x0000000008000f90 0x594 /tmp/ccvZIDd7.o
+ 0x00000000080011e4 LL_Init1msTick
+ 0x0000000008001202 LL_mDelay
+ 0x0000000008001248 LL_SetSystemCoreClock
+ 0x0000000008001264 LL_PLL_ConfigSystemClock_HSI
+ 0x00000000080012f0 LL_PLL_ConfigSystemClock_HSE
+ .text 0x0000000008001524 0x82 /tmp/ccTEVTRv.o
+ 0x0000000008001524 __sinit
+ 0x000000000800152e memset
+ 0x0000000008001568 strlen
+ 0x0000000008001592 __assert_func
+ .text 0x00000000080015a6 0x0 /tmp/ccvICuLU.o
+ *fill* 0x00000000080015a6 0x2
+ .text 0x00000000080015a8 0x114 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ 0x00000000080015a8 __udivsi3
+ 0x00000000080015a8 __aeabi_uidiv
+ 0x00000000080016b4 __aeabi_uidivmod
+ .text 0x00000000080016bc 0x1d4 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ 0x00000000080016bc __aeabi_idiv
+ 0x00000000080016bc __divsi3
+ 0x0000000008001888 __aeabi_idivmod
+ .text 0x0000000008001890 0x4 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+ 0x0000000008001890 __aeabi_ldiv0
+ 0x0000000008001890 __aeabi_idiv0
+ *(.text.*)
+ .text.Reset_Handler
+ 0x0000000008001894 0x4c /tmp/ccTaPb5k.o
+ 0x0000000008001894 Reset_Handler
+ .text.Default_Handler
+ 0x00000000080018e0 0x2 /tmp/ccTaPb5k.o
+ 0x00000000080018e0 TIM1_CC_IRQHandler
+ 0x00000000080018e0 I2C1_IRQHandler
+ 0x00000000080018e0 EXTI2_3_IRQHandler
+ 0x00000000080018e0 ADC1_IRQHandler
+ 0x00000000080018e0 TIM17_IRQHandler
+ 0x00000000080018e0 RTC_IRQHandler
+ 0x00000000080018e0 TIM3_IRQHandler
+ 0x00000000080018e0 EXTI4_15_IRQHandler
+ 0x00000000080018e0 RCC_IRQHandler
+ 0x00000000080018e0 Default_Handler
+ 0x00000000080018e0 TIM14_IRQHandler
+ 0x00000000080018e0 DMA1_Channel4_5_IRQHandler
+ 0x00000000080018e0 EXTI0_1_IRQHandler
+ 0x00000000080018e0 WWDG_IRQHandler
+ 0x00000000080018e0 FLASH_IRQHandler
+ 0x00000000080018e0 USART1_IRQHandler
+ 0x00000000080018e0 TIM1_BRK_UP_TRG_COM_IRQHandler
+ *(.rodata)
+ *fill* 0x00000000080018e2 0x2
+ .rodata 0x00000000080018e4 0x8 /tmp/cchCmUnQ.o
+ .rodata 0x00000000080018ec 0x18 /tmp/cc6XVkRI.o
+ 0x00000000080018ec AHBPrescTable
+ 0x00000000080018fc APBPrescTable
+ *(.rodata*)
+ *(.glue_7)
+ .glue_7 0x0000000008001904 0x0 linker stubs
+ *(.glue_7t)
+ .glue_7t 0x0000000008001904 0x0 linker stubs
+ *(.source_tarball)
+ *(.init)
+ *(.fini)
+ *(.source_tarball)
+ 0x0000000008001904 . = ALIGN (0x4)
+ 0x0000000008001904 _etext = .
+ 0x0000000008001904 _sidata = _etext
+
+.vfp11_veneer 0x0000000008001904 0x0
+ .vfp11_veneer 0x0000000008001904 0x0 linker stubs
+
+.v4_bx 0x0000000008001904 0x0
+ .v4_bx 0x0000000008001904 0x0 linker stubs
+
+.iplt 0x0000000008001904 0x0
+ .iplt 0x0000000008001904 0x0 /tmp/cchCmUnQ.o
+
+.rel.dyn 0x0000000008001904 0x0
+ .rel.iplt 0x0000000008001904 0x0 /tmp/cchCmUnQ.o
+
+.data 0x0000000020000000 0x94 load address 0x0000000008001904
+ 0x0000000020000000 . = ALIGN (0x4)
+ 0x0000000020000000 _sdata = .
+ 0x0000000020000000 _data = .
+ *(.data)
+ .data 0x0000000020000000 0x0 /tmp/cchCmUnQ.o
+ .data 0x0000000020000000 0x0 /tmp/cczzmF2c.o
+ .data 0x0000000020000000 0x0 /tmp/cc4OHQ7z.o
+ .data 0x0000000020000000 0x0 /tmp/cc0OqFzX.o
+ .data 0x0000000020000000 0x0 /tmp/ccTaPb5k.o
+ .data 0x0000000020000000 0x4 /tmp/cc6XVkRI.o
+ 0x0000000020000000 SystemCoreClock
+ .data 0x0000000020000004 0x0 /tmp/ccvZIDd7.o
+ .data 0x0000000020000004 0x0 /tmp/ccTEVTRv.o
+ .data 0x0000000020000004 0x90 /tmp/ccvICuLU.o
+ 0x0000000020000004 tim3
+ 0x0000000020000008 tim14
+ 0x000000002000000c rtc
+ 0x0000000020000010 wwdg
+ 0x0000000020000014 iwdg
+ 0x0000000020000018 i2c1
+ 0x000000002000001c pwr
+ 0x0000000020000020 syscfg
+ 0x0000000020000024 exti
+ 0x0000000020000028 adc1
+ 0x000000002000002c adc1_common
+ 0x0000000020000030 adc
+ 0x0000000020000034 tim1
+ 0x0000000020000038 spi1
+ 0x000000002000003c usart1
+ 0x0000000020000040 tim16
+ 0x0000000020000044 tim17
+ 0x0000000020000048 dbgmcu
+ 0x000000002000004c dma1
+ 0x0000000020000050 dma1_channel1
+ 0x0000000020000054 dma1_channel2
+ 0x0000000020000058 dma1_channel3
+ 0x000000002000005c dma1_channel4
+ 0x0000000020000060 dma1_channel5
+ 0x0000000020000064 flash
+ 0x0000000020000068 ob
+ 0x000000002000006c rcc
+ 0x0000000020000070 crc
+ 0x0000000020000074 gpioa
+ 0x0000000020000078 gpiob
+ 0x000000002000007c gpioc
+ 0x0000000020000080 gpiod
+ 0x0000000020000084 gpiof
+ 0x0000000020000088 scb
+ 0x000000002000008c systick
+ 0x0000000020000090 nvic
+ .data 0x0000000020000094 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .data 0x0000000020000094 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .data 0x0000000020000094 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+ *(.data.*)
+ *(.RAMtext)
+ 0x0000000020000094 . = ALIGN (0x4)
+ 0x0000000020000094 _edata = .
+
+.igot.plt 0x0000000020000094 0x0 load address 0x0000000008001998
+ .igot.plt 0x0000000020000094 0x0 /tmp/cchCmUnQ.o
+
+.bss 0x0000000020000094 0x940 load address 0x0000000008001998
+ 0x0000000020000094 . = ALIGN (0x4)
+ 0x0000000020000094 _sbss = .
+ 0x0000000020000094 _bss = .
+ *(.bss)
+ .bss 0x0000000020000094 0xc /tmp/cchCmUnQ.o
+ 0x0000000020000094 sys_time_seconds
+ .bss 0x00000000200000a0 0x0 /tmp/cczzmF2c.o
+ .bss 0x00000000200000a0 0x0 /tmp/cc4OHQ7z.o
+ .bss 0x00000000200000a0 0x0 /tmp/cc0OqFzX.o
+ .bss 0x00000000200000a0 0x0 /tmp/ccTaPb5k.o
+ .bss 0x00000000200000a0 0x0 /tmp/cc6XVkRI.o
+ .bss 0x00000000200000a0 0x0 /tmp/ccvZIDd7.o
+ .bss 0x00000000200000a0 0x8 /tmp/ccTEVTRv.o
+ 0x00000000200000a0 __errno
+ 0x00000000200000a4 _impure_ptr
+ .bss 0x00000000200000a8 0x0 /tmp/ccvICuLU.o
+ .bss 0x00000000200000a8 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .bss 0x00000000200000a8 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .bss 0x00000000200000a8 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+ *(.bss.*)
+ *(COMMON)
+ COMMON 0x00000000200000a8 0x20 /tmp/cchCmUnQ.o
+ 0x00000000200000a8 leds
+ COMMON 0x00000000200000c8 0x800 /tmp/cczzmF2c.o
+ 0x00000000200000c8 adc_buf
+ COMMON 0x00000000200008c8 0x10c /tmp/cc4OHQ7z.o
+ 0x00000000200008c8 usart_tx_buf
+ 0x00000000200009d4 . = ALIGN (0x4)
+ 0x00000000200009d4 _ebss = .
+ [!provide] PROVIDE (end = _ebss)
+ [!provide] PROVIDE (_end = _ebss)
+ 0x00000000200009d4 __exidx_start = .
+ 0x00000000200009d4 __exidx_end = .
+
+.stab
+ *(.stab)
+
+.stabstr
+ *(.stabstr)
+
+.stab.excl
+ *(.stab.excl)
+
+.stab.exclstr
+ *(.stab.exclstr)
+
+.stab.index
+ *(.stab.index)
+
+.stab.indexstr
+ *(.stab.indexstr)
+
+.comment 0x0000000000000000 0x21
+ *(.comment)
+ .comment 0x0000000000000000 0x21 /tmp/cchCmUnQ.o
+ 0x22 (size before relaxing)
+ .comment 0x0000000000000021 0x22 /tmp/cczzmF2c.o
+ .comment 0x0000000000000021 0x22 /tmp/cc4OHQ7z.o
+ .comment 0x0000000000000021 0x22 /tmp/cc0OqFzX.o
+ .comment 0x0000000000000021 0x22 /tmp/cc6XVkRI.o
+ .comment 0x0000000000000021 0x22 /tmp/ccvZIDd7.o
+ .comment 0x0000000000000021 0x22 /tmp/ccTEVTRv.o
+ .comment 0x0000000000000021 0x22 /tmp/ccvICuLU.o
+
+.ARM.attributes
+ 0x0000000000000000 0x2f
+ .ARM.attributes
+ 0x0000000000000000 0x2b /tmp/cchCmUnQ.o
+ .ARM.attributes
+ 0x000000000000002b 0x2b /tmp/cczzmF2c.o
+ .ARM.attributes
+ 0x0000000000000056 0x2b /tmp/cc4OHQ7z.o
+ .ARM.attributes
+ 0x0000000000000081 0x2b /tmp/cc0OqFzX.o
+ .ARM.attributes
+ 0x00000000000000ac 0x21 /tmp/ccTaPb5k.o
+ .ARM.attributes
+ 0x00000000000000cd 0x2b /tmp/cc6XVkRI.o
+ .ARM.attributes
+ 0x00000000000000f8 0x2b /tmp/ccvZIDd7.o
+ .ARM.attributes
+ 0x0000000000000123 0x2b /tmp/ccTEVTRv.o
+ .ARM.attributes
+ 0x000000000000014e 0x31 /tmp/ccvICuLU.o
+ .ARM.attributes
+ 0x000000000000017f 0x1e /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .ARM.attributes
+ 0x000000000000019d 0x1e /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .ARM.attributes
+ 0x00000000000001bb 0x1e /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+
+.debug
+ *(.debug)
+
+.line
+ *(.line)
+
+.debug_srcinfo
+ *(.debug_srcinfo)
+
+.debug_sfnames
+ *(.debug_sfnames)
+
+.debug_aranges 0x0000000000000000 0x180
+ *(.debug_aranges)
+ .debug_aranges
+ 0x0000000000000000 0x20 /tmp/cchCmUnQ.o
+ .debug_aranges
+ 0x0000000000000020 0x20 /tmp/cczzmF2c.o
+ .debug_aranges
+ 0x0000000000000040 0x20 /tmp/cc4OHQ7z.o
+ .debug_aranges
+ 0x0000000000000060 0x20 /tmp/cc0OqFzX.o
+ .debug_aranges
+ 0x0000000000000080 0x28 /tmp/ccTaPb5k.o
+ .debug_aranges
+ 0x00000000000000a8 0x20 /tmp/cc6XVkRI.o
+ .debug_aranges
+ 0x00000000000000c8 0x20 /tmp/ccvZIDd7.o
+ .debug_aranges
+ 0x00000000000000e8 0x20 /tmp/ccTEVTRv.o
+ .debug_aranges
+ 0x0000000000000108 0x18 /tmp/ccvICuLU.o
+ .debug_aranges
+ 0x0000000000000120 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .debug_aranges
+ 0x0000000000000140 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .debug_aranges
+ 0x0000000000000160 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+
+.debug_pubnames
+ *(.debug_pubnames)
+
+.debug_info 0x0000000000000000 0x5d8a
+ *(.debug_info .gnu.linkonce.wi.*)
+ .debug_info 0x0000000000000000 0x136b /tmp/cchCmUnQ.o
+ .debug_info 0x000000000000136b 0x105f /tmp/cczzmF2c.o
+ .debug_info 0x00000000000023ca 0x1019 /tmp/cc4OHQ7z.o
+ .debug_info 0x00000000000033e3 0xcb1 /tmp/cc0OqFzX.o
+ .debug_info 0x0000000000004094 0x22 /tmp/ccTaPb5k.o
+ .debug_info 0x00000000000040b6 0x263 /tmp/cc6XVkRI.o
+ .debug_info 0x0000000000004319 0x795 /tmp/ccvZIDd7.o
+ .debug_info 0x0000000000004aae 0x1e9 /tmp/ccTEVTRv.o
+ .debug_info 0x0000000000004c97 0x1081 /tmp/ccvICuLU.o
+ .debug_info 0x0000000000005d18 0x26 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .debug_info 0x0000000000005d3e 0x26 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .debug_info 0x0000000000005d64 0x26 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+
+.debug_abbrev 0x0000000000000000 0x1204
+ *(.debug_abbrev)
+ .debug_abbrev 0x0000000000000000 0x357 /tmp/cchCmUnQ.o
+ .debug_abbrev 0x0000000000000357 0x320 /tmp/cczzmF2c.o
+ .debug_abbrev 0x0000000000000677 0x319 /tmp/cc4OHQ7z.o
+ .debug_abbrev 0x0000000000000990 0x287 /tmp/cc0OqFzX.o
+ .debug_abbrev 0x0000000000000c17 0x12 /tmp/ccTaPb5k.o
+ .debug_abbrev 0x0000000000000c29 0x113 /tmp/cc6XVkRI.o
+ .debug_abbrev 0x0000000000000d3c 0x23c /tmp/ccvZIDd7.o
+ .debug_abbrev 0x0000000000000f78 0x117 /tmp/ccTEVTRv.o
+ .debug_abbrev 0x000000000000108f 0x139 /tmp/ccvICuLU.o
+ .debug_abbrev 0x00000000000011c8 0x14 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .debug_abbrev 0x00000000000011dc 0x14 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .debug_abbrev 0x00000000000011f0 0x14 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+
+.debug_line 0x0000000000000000 0x17b1
+ *(.debug_line)
+ .debug_line 0x0000000000000000 0x3ec /tmp/cchCmUnQ.o
+ .debug_line 0x00000000000003ec 0x33d /tmp/cczzmF2c.o
+ .debug_line 0x0000000000000729 0x36e /tmp/cc4OHQ7z.o
+ .debug_line 0x0000000000000a97 0x2f9 /tmp/cc0OqFzX.o
+ .debug_line 0x0000000000000d90 0x77 /tmp/ccTaPb5k.o
+ .debug_line 0x0000000000000e07 0x1ab /tmp/cc6XVkRI.o
+ .debug_line 0x0000000000000fb2 0x466 /tmp/ccvZIDd7.o
+ .debug_line 0x0000000000001418 0xf4 /tmp/ccTEVTRv.o
+ .debug_line 0x000000000000150c 0x148 /tmp/ccvICuLU.o
+ .debug_line 0x0000000000001654 0x76 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .debug_line 0x00000000000016ca 0x7d /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .debug_line 0x0000000000001747 0x6a /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+
+.debug_frame 0x0000000000000000 0x848
+ *(.debug_frame)
+ .debug_frame 0x0000000000000000 0x168 /tmp/cchCmUnQ.o
+ .debug_frame 0x0000000000000168 0xe8 /tmp/cczzmF2c.o
+ .debug_frame 0x0000000000000250 0x128 /tmp/cc4OHQ7z.o
+ .debug_frame 0x0000000000000378 0xb0 /tmp/cc0OqFzX.o
+ .debug_frame 0x0000000000000428 0x4c /tmp/cc6XVkRI.o
+ .debug_frame 0x0000000000000474 0x308 /tmp/ccvZIDd7.o
+ .debug_frame 0x000000000000077c 0x8c /tmp/ccTEVTRv.o
+ .debug_frame 0x0000000000000808 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ .debug_frame 0x0000000000000828 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+
+.debug_str 0x0000000000000000 0x12b2
+ *(.debug_str)
+ .debug_str 0x0000000000000000 0x965 /tmp/cchCmUnQ.o
+ 0xa11 (size before relaxing)
+ .debug_str 0x0000000000000965 0xdf /tmp/cczzmF2c.o
+ 0x8fc (size before relaxing)
+ .debug_str 0x0000000000000a44 0xa7 /tmp/cc4OHQ7z.o
+ 0x904 (size before relaxing)
+ .debug_str 0x0000000000000aeb 0xa2 /tmp/cc0OqFzX.o
+ 0x658 (size before relaxing)
+ .debug_str 0x0000000000000b8d 0x22 /tmp/ccTaPb5k.o
+ 0x57 (size before relaxing)
+ .debug_str 0x0000000000000baf 0x53 /tmp/cc6XVkRI.o
+ 0x219 (size before relaxing)
+ .debug_str 0x0000000000000c02 0x3ae /tmp/ccvZIDd7.o
+ 0x5bf (size before relaxing)
+ .debug_str 0x0000000000000fb0 0x39 /tmp/ccTEVTRv.o
+ 0x1b7 (size before relaxing)
+ .debug_str 0x0000000000000fe9 0x227 /tmp/ccvICuLU.o
+ 0x5ca (size before relaxing)
+ .debug_str 0x0000000000001210 0xa2 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o)
+ 0xae (size before relaxing)
+ .debug_str 0x00000000000012b2 0xae /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o)
+ .debug_str 0x00000000000012b2 0xae /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o)
+
+.debug_loc
+ *(.debug_loc)
+
+.debug_macinfo
+ *(.debug_macinfo)
+
+.debug_weaknames
+ *(.debug_weaknames)
+
+.debug_funcnames
+ *(.debug_funcnames)
+
+.debug_typenames
+ *(.debug_typenames)
+
+.debug_varnames
+ *(.debug_varnames)
+OUTPUT(main.elf elf32-littlearm)
+
+.debug_ranges 0x0000000000000000 0x38
+ .debug_ranges 0x0000000000000000 0x18 /tmp/cc0OqFzX.o
+ .debug_ranges 0x0000000000000018 0x20 /tmp/ccTaPb5k.o
diff --git a/gm_platform/fw/openocd.cfg b/gm_platform/fw/openocd.cfg
new file mode 100644
index 0000000..ce164b7
--- /dev/null
+++ b/gm_platform/fw/openocd.cfg
@@ -0,0 +1,17 @@
+telnet_port 4445
+gdb_port 3334
+tcl_port 6667
+
+source [find interface/stlink-v2.cfg]
+#interface jlink
+#interface stlink-v2
+#adapter_khz 10000
+#transport select swd
+
+#source /usr/share/openocd/scripts/target/stm32f0x.cfg
+source [find target/stm32f0x_stlink.cfg]
+
+init
+arm semihosting enable
+
+#flash bank sysflash.alias stm32f0x 0x00000000 0 0 0 $_TARGETNAME
diff --git a/gm_platform/fw/packet_interface.c b/gm_platform/fw/packet_interface.c
new file mode 100644
index 0000000..099993b
--- /dev/null
+++ b/gm_platform/fw/packet_interface.c
@@ -0,0 +1,46 @@
+
+#include "packet_interface.h"
+#include "cobs.h"
+
+void usart2_isr(void) {
+ TRACING_SET(TR_HOST_IF_USART_IRQ);
+ static struct cobs_decode_state host_cobs_state = {0};
+ if (USART2_SR & USART_SR_ORE) { /* Overrun handling */
+ LOG_PRINTF("USART2 data register overrun\n");
+ /* Clear interrupt flag */
+ (void)USART2_DR; /* FIXME make sure this read is not optimized out */
+ host_packet_length = -1;
+ TRACING_CLEAR(TR_HOST_IF_USART_IRQ);
+ return;
+ }
+
+ uint8_t data = USART2_DR; /* This automatically acknowledges the IRQ */
+
+ if (host_packet_length) {
+ LOG_PRINTF("USART2 COBS buffer overrun\n");
+ host_packet_length = -1;
+ TRACING_CLEAR(TR_HOST_IF_USART_IRQ);
+ return;
+ }
+
+ ssize_t rv = cobs_decode_incremental(&host_cobs_state, (char *)host_packet_buf, sizeof(host_packet_buf), data);
+ if (rv == -2) {
+ LOG_PRINTF("Host interface COBS packet too large\n");
+ host_packet_length = -1;
+ } else if (rv == -3) {
+ LOG_PRINTF("Got double null byte from host\n");
+ } else if (rv < 0) {
+ LOG_PRINTF("Host interface COBS framing error\n");
+ host_packet_length = -1;
+ } else if (rv > 0) {
+ host_packet_length = rv;
+ } /* else just return and wait for next byte */
+ TRACING_CLEAR(TR_HOST_IF_USART_IRQ);
+}
+
+void send_packet(struct dma_usart_file *f, const uint8_t *data, size_t len) {
+ /* ignore return value as putf is blocking and always succeeds */
+ (void)cobs_encode_incremental(f, putf, (char *)data, len);
+ flush(f);
+}
+
diff --git a/gm_platform/fw/packet_interface.h b/gm_platform/fw/packet_interface.h
new file mode 100644
index 0000000..dbace62
--- /dev/null
+++ b/gm_platform/fw/packet_interface.h
@@ -0,0 +1,6 @@
+#ifndef __PACKET_INTERFACE_H__
+#define __PACKET_INTERFACE_H__
+
+void send_packet(struct dma_usart_file *f, const uint8_t *data, size_t len);
+
+#endif
diff --git a/gm_platform/fw/scope.gdb b/gm_platform/fw/scope.gdb
new file mode 100644
index 0000000..01366fa
--- /dev/null
+++ b/gm_platform/fw/scope.gdb
@@ -0,0 +1,12 @@
+target remote 192.168.178.103:3334
+set pagination off
+file main.elf
+load
+
+break gdb_dump
+command 1
+ dump binary value /tmp/scope_dump.bin adc_buf
+ continue
+end
+
+continue
diff --git a/gm_platform/fw/serial.c b/gm_platform/fw/serial.c
new file mode 100644
index 0000000..ae639c0
--- /dev/null
+++ b/gm_platform/fw/serial.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "global.h"
+#include "serial.h"
+#include "cobs.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+volatile struct dma_tx_buf usart_tx_buf;
+
+static void usart_schedule_dma();
+
+void usart_dma_init() {
+ usart_tx_buf.xfr_start = -1,
+ usart_tx_buf.xfr_end = 0,
+ usart_tx_buf.wr_pos = 0,
+
+ /* Configure DMA 1 Channel 2 to handle uart transmission */
+ DMA1_Channel2->CPAR = (unsigned int)&(USART1->TDR);
+ DMA1_Channel2->CCR = (0<<DMA_CCR_PL_Pos)
+ | DMA_CCR_DIR
+ | (0<<DMA_CCR_MSIZE_Pos) /* 8 bit */
+ | (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */
+ | DMA_CCR_MINC
+ | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */
+
+ /* triggered on transfer completion. We use this to process the ADC data */
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1<<5);
+
+ USART1->CR1 = /* 8-bit -> M1, M0 clear */
+ /* OVER8 clear. Use default 16x oversampling */
+ /* CMIF clear */
+ USART_CR1_MME
+ /* WAKE clear */
+ /* PCE, PS clear */
+ | USART_CR1_RXNEIE /* Enable receive interrupt */
+ /* other interrupts clear */
+ | USART_CR1_TE
+ | USART_CR1_RE;
+ /* Set divider for 1MBd @48MHz system clock. */
+ USART1->BRR = 48;
+
+ USART1->CR2 = USART_CR2_TXINV | USART_CR2_RXINV;
+
+ USART1->CR3 |= USART_CR3_DMAT; /* TX DMA enable */
+
+ /* Enable receive interrupt */
+ //NVIC_EnableIRQ(USART1_IRQn);
+ //NVIC_SetPriority(USART1_IRQn, 1);
+
+ /* And... go! */
+ USART1->CR1 |= USART_CR1_UE;
+}
+
+void usart_schedule_dma() {
+ /* This function is only called when the DMA channel is disabled. This means we don't have to guard it in IRQ
+ * disables. */
+ volatile struct dma_tx_buf *buf = &usart_tx_buf;
+
+ size_t xfr_len, xfr_start = buf->xfr_end;
+ if (buf->wr_pos > xfr_start) /* no wraparound */
+ xfr_len = buf->wr_pos - xfr_start;
+ else /* wraparound */
+ xfr_len = sizeof(buf->data) - xfr_start; /* schedule transfer until end of buffer */
+
+ buf->xfr_start = xfr_start;
+ buf->xfr_end = (xfr_start + xfr_len) % sizeof(buf->data); /* handle wraparound */
+
+ /* initiate transmission of new buffer */
+ DMA1_Channel2->CMAR = (uint32_t)(buf->data + xfr_start);
+ DMA1_Channel2->CNDTR = xfr_len;
+ DMA1_Channel2->CCR |= DMA_CCR_EN;
+}
+
+int usart_dma_fifo_push(volatile struct dma_tx_buf *buf, char c) {
+ /* This function must be guarded by IRQ disable since the IRQ may schedule a new transfer and charge pos/start. */
+ NVIC_DisableIRQ(DMA1_Channel2_3_IRQn);
+
+ if (buf->wr_pos == buf->xfr_start) {
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ return -EBUSY;
+ }
+
+ buf->data[buf->wr_pos] = c;
+ buf->wr_pos = (buf->wr_pos + 1) % sizeof(buf->data);
+
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ return 0;
+}
+
+void usart_putc(char c) {
+ /* push char to fifo, busy-loop if stalled to wait for USART to empty fifo via DMA */
+ while (usart_dma_fifo_push(&usart_tx_buf, c) == -EBUSY) {
+ /* idle */
+ }
+}
+
+void DMA1_Channel2_3_IRQHandler(void) {
+ /* Transfer complete */
+ DMA1->IFCR |= DMA_IFCR_CTCIF2;
+
+ DMA1_Channel2->CCR &= ~DMA_CCR_EN;
+ if (usart_tx_buf.wr_pos != usart_tx_buf.xfr_end) /* buffer not empty */
+ usart_schedule_dma();
+}
+
+void usart_send_packet(const uint8_t *data, size_t len) {
+ /* ignore return value as putf is blocking and always succeeds */
+ (void)cobs_encode_usart((char *)data, len);
+
+ /* If the DMA stream is idle right now, schedule a transfer */
+ if (!(DMA1_Channel2->CCR & DMA_CCR_EN))
+ usart_schedule_dma();
+}
+
diff --git a/gm_platform/fw/serial.h b/gm_platform/fw/serial.h
new file mode 100644
index 0000000..55eac9e
--- /dev/null
+++ b/gm_platform/fw/serial.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __SERIAL_H__
+#define __SERIAL_H__
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <errno.h>
+
+struct dma_tx_buf {
+ size_t xfr_start; /* Start index of running DMA transfer */
+ size_t xfr_end; /* End index of running DMA transfer plus one */
+ size_t wr_pos; /* Next index to be written */
+ uint8_t data[256];
+};
+
+extern volatile struct dma_tx_buf usart_tx_buf;
+
+void usart_dma_init(void);
+int usart_dma_fifo_push(volatile struct dma_tx_buf *buf, char c);
+void usart_putc(char c);
+void usart_send_packet(const uint8_t *data, size_t len);
+
+#endif // __SERIAL_H__
diff --git a/gm_platform/fw/startup_stm32f030x6.s b/gm_platform/fw/startup_stm32f030x6.s
new file mode 100644
index 0000000..2f0eb42
--- /dev/null
+++ b/gm_platform/fw/startup_stm32f030x6.s
@@ -0,0 +1,273 @@
+/**
+ ******************************************************************************
+ * @file startup_stm32f030x6.s
+ * copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates/gcc
+ * @author MCD Application Team
+ * @version V2.3.1
+ * @date 04-November-2016
+ * @brief STM32F030x4/STM32F030x6 devices vector table for Atollic TrueSTUDIO toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M0 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m0
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr r0, =_estack
+ mov sp, r0 /* set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2]
+ adds r2, r2, #4
+
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+// bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+
+LoopForever:
+ b LoopForever
+
+
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ *
+ * @param None
+ * @retval : None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M0. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word 0
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word 0 /* Reserved */
+ .word RTC_IRQHandler /* RTC through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
+ .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
+ .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
+ .word 0 /* Reserved */
+ .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
+ .word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */
+ .word DMA1_Channel4_5_IRQHandler /* DMA1 Channel 4 and Channel 5 */
+ .word ADC1_IRQHandler /* ADC1 */
+ .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word 0 /* Reserved */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word TIM14_IRQHandler /* TIM14 */
+ .word 0 /* Reserved */
+ .word TIM16_IRQHandler /* TIM16 */
+ .word TIM17_IRQHandler /* TIM17 */
+ .word I2C1_IRQHandler /* I2C1 */
+ .word 0 /* Reserved */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word 0 /* Reserved */
+ .word USART1_IRQHandler /* USART1 */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak RTC_IRQHandler
+ .thumb_set RTC_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_1_IRQHandler
+ .thumb_set EXTI0_1_IRQHandler,Default_Handler
+
+ .weak EXTI2_3_IRQHandler
+ .thumb_set EXTI2_3_IRQHandler,Default_Handler
+
+ .weak EXTI4_15_IRQHandler
+ .thumb_set EXTI4_15_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel1_IRQHandler
+ .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel2_3_IRQHandler
+ .thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel4_5_IRQHandler
+ .thumb_set DMA1_Channel4_5_IRQHandler,Default_Handler
+
+ .weak ADC1_IRQHandler
+ .thumb_set ADC1_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_UP_TRG_COM_IRQHandler
+ .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM14_IRQHandler
+ .thumb_set TIM14_IRQHandler,Default_Handler
+
+ .weak TIM16_IRQHandler
+ .thumb_set TIM16_IRQHandler,Default_Handler
+
+ .weak TIM17_IRQHandler
+ .thumb_set TIM17_IRQHandler,Default_Handler
+
+ .weak I2C1_IRQHandler
+ .thumb_set I2C1_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/gm_platform/fw/stm32_flash.ld b/gm_platform/fw/stm32_flash.ld
new file mode 100644
index 0000000..cba7577
--- /dev/null
+++ b/gm_platform/fw/stm32_flash.ld
@@ -0,0 +1,136 @@
+
+ENTRY(Reset_Handler)
+
+MEMORY {
+ FLASH (rx): ORIGIN = 0x08000000, LENGTH = 0x3C00
+ CONFIGFLASH (rw): ORIGIN = 0x08003C00, LENGTH = 0x400
+ RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K
+}
+
+/* highest address of the user mode stack */
+_estack = 0x20001000;
+
+SECTIONS {
+ /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */
+ .isr_vector : {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* the program code is stored in the .text section, which goes to Flash */
+ .text : {
+ . = ALIGN(4);
+
+ *(.text) /* normal code */
+ *(.text.*) /* -ffunction-sections code */
+ *(.rodata) /* read-only data (constants) */
+ *(.rodata*) /* -fdata-sections read only data */
+ *(.glue_7) /* TBD - needed ? */
+ *(.glue_7t) /* TBD - needed ? */
+
+ *(.source_tarball)
+
+ /* Necessary KEEP sections (see http://sourceware.org/ml/newlib/2005/msg00255.html) */
+ KEEP (*(.init))
+ KEEP (*(.fini))
+ KEEP (*(.source_tarball))
+
+ . = ALIGN(4);
+ _etext = .;
+ /* This is used by the startup in order to initialize the .data section */
+ _sidata = _etext;
+ } >FLASH
+
+ /*
+ .configflash : {
+ . = ALIGN(0x400);
+ *(.configdata)
+ _econfig = .;
+ } >FLASH
+ */
+
+ /* This is the initialized data section
+ The program executes knowing that the data is in the RAM
+ but the loader puts the initial values in the FLASH (inidata).
+ It is one task of the startup to copy the initial values from FLASH to RAM. */
+ .data : AT ( _sidata ) {
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .data secion */
+ _sdata = . ;
+ _data = . ;
+
+ *(.data)
+ *(.data.*)
+ *(.RAMtext)
+
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .data secion */
+ _edata = . ;
+ } >RAM
+
+ /* This is the uninitialized data section */
+ .bss : {
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .;
+ _bss = .;
+
+ *(.bss)
+ *(.bss.*) /* patched by elias - allows the use of -fdata-sections */
+ *(COMMON)
+
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .bss secion */
+ _ebss = . ;
+ } >RAM
+
+ PROVIDE ( end = _ebss);
+ PROVIDE (_end = _ebss);
+
+ __exidx_start = .;
+ __exidx_end = .;
+
+ /* after that it's only debugging information. */
+
+ /* remove the debugging information from the standard libraries */
+/* /DISCARD/ : {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }*/
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+}
diff --git a/gm_platform/fw/system_stm32f0xx.c b/gm_platform/fw/system_stm32f0xx.c
new file mode 100644
index 0000000..a43c3d6
--- /dev/null
+++ b/gm_platform/fw/system_stm32f0xx.c
@@ -0,0 +1,336 @@
+/**
+ ******************************************************************************
+ * @file system_stm32f0xx.c
+ * copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates
+ * @author MCD Application Team
+ * @version V2.3.1
+ * @date 04-November-2016
+ * @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File.
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f0xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (8 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f0xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. This file configures the system clock as follows:
+ *=============================================================================
+ * Supported STM32F0xx device
+ *-----------------------------------------------------------------------------
+ * System Clock source | HSI
+ *-----------------------------------------------------------------------------
+ * SYSCLK(Hz) | 8000000
+ *-----------------------------------------------------------------------------
+ * HCLK(Hz) | 8000000
+ *-----------------------------------------------------------------------------
+ * AHB Prescaler | 1
+ *-----------------------------------------------------------------------------
+ * APB1 Prescaler | 1
+ *-----------------------------------------------------------------------------
+ *=============================================================================
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f0xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f0xx.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Defines
+ * @{
+ */
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz.
+ This value can be provided and adapted by the user application. */
+#endif /* HSE_VALUE */
+
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz.
+ This value can be provided and adapted by the user application. */
+#endif /* HSI_VALUE */
+
+#if !defined (HSI48_VALUE)
+#define HSI48_VALUE ((uint32_t)48000000) /*!< Default value of the HSI48 Internal oscillator in Hz.
+ This value can be provided and adapted by the user application. */
+#endif /* HSI48_VALUE */
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Variables
+ * @{
+ */
+ /* This variable is updated in three ways:
+ 1) by calling CMSIS function SystemCoreClockUpdate()
+ 2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+ 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
+ Note: If you use this function to configure the system clock there is no need to
+ call the 2 first functions listed above, since SystemCoreClock variable is
+ updated automatically.
+ */
+uint32_t SystemCoreClock = 8000000;
+
+const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system.
+ * Initialize the default HSI clock source, vector table location and the PLL configuration is reset.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001U;
+
+#if defined (STM32F051x8) || defined (STM32F058x8)
+ /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */
+ RCC->CFGR &= (uint32_t)0xF8FFB80CU;
+#else
+ /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits */
+ RCC->CFGR &= (uint32_t)0x08FFB80CU;
+#endif /* STM32F051x8 or STM32F058x8 */
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFFU;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFFU;
+
+ /* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
+ RCC->CFGR &= (uint32_t)0xFFC0FFFFU;
+
+ /* Reset PREDIV[3:0] bits */
+ RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U;
+
+#if defined (STM32F072xB) || defined (STM32F078xx)
+ /* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU;
+#elif defined (STM32F071xB)
+ /* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFCEACU;
+#elif defined (STM32F091xC) || defined (STM32F098xx)
+ /* Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFF0FEACU;
+#elif defined (STM32F030x6) || defined (STM32F030x8) || defined (STM32F031x6) || defined (STM32F038xx) || defined (STM32F030xC)
+ /* Reset USART1SW[1:0], I2C1SW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFEECU;
+#elif defined (STM32F051x8) || defined (STM32F058xx)
+ /* Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFEACU;
+#elif defined (STM32F042x6) || defined (STM32F048xx)
+ /* Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU;
+#elif defined (STM32F070x6) || defined (STM32F070xB)
+ /* Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU;
+ /* Set default USB clock to PLLCLK, since there is no HSI48 */
+ RCC->CFGR3 |= (uint32_t)0x00000080U;
+#else
+ #warning "No target selected"
+#endif
+
+ /* Reset HSI14 bit */
+ RCC->CR2 &= (uint32_t)0xFFFFFFFEU;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000U;
+
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f0xx_hal.h file (default value
+ * 8 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f0xx_hal.h file (default value
+ * 8 MHz), user has to ensure that HSE_VALUE is same as the real
+ * frequency of the crystal used. Otherwise, this function may
+ * have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate (void)
+{
+ uint32_t tmp = 0, pllmull = 0, pllsource = 0, predivfactor = 0;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case RCC_CFGR_SWS_HSE: /* HSE used as system clock */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case RCC_CFGR_SWS_PLL: /* PLL used as system clock */
+ /* Get PLL clock source and multiplication factor ----------------------*/
+ pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
+ pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
+ pllmull = ( pllmull >> 18) + 2;
+ predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
+
+ if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV)
+ {
+ /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */
+ SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull;
+ }
+#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx)
+ else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV)
+ {
+ /* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */
+ SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull;
+ }
+#endif /* STM32F042x6 || STM32F048xx || STM32F072xB || STM32F078xx || STM32F091xC || STM32F098xx */
+ else
+ {
+#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \
+ || defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \
+ || defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC)
+ /* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */
+ SystemCoreClock = (HSI_VALUE/predivfactor) * pllmull;
+#else
+ /* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */
+ SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+#endif /* STM32F042x6 || STM32F048xx || STM32F070x6 ||
+ STM32F071xB || STM32F072xB || STM32F078xx || STM32F070xB ||
+ STM32F091xC || STM32F098xx || STM32F030xC */
+ }
+ break;
+ default: /* HSI used as system clock */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK clock frequency ----------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK clock frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/gm_platform/fw/tools/gen_cmsis_exports.py b/gm_platform/fw/tools/gen_cmsis_exports.py
new file mode 100644
index 0000000..ba3422b
--- /dev/null
+++ b/gm_platform/fw/tools/gen_cmsis_exports.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+import re
+import os
+
+if __name__ == '__main__':
+ import argparse
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('cmsis_device_header', nargs='+', type=argparse.FileType('rb'))
+ args = parser.parse_args()
+
+ print('#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__')
+ print('#define __GENERATED_CMSIS_HEADER_EXPORTS__')
+ print()
+ for header in args.cmsis_device_header:
+ lines = header.readlines()
+ name = os.path.basename(header.name)
+ print('#include <{}>'.format(name))
+ print()
+
+ print('/* {} */'.format(name))
+ for l in lines:
+ match = re.match(b'^#define (\w+)\s+\W*(\w+_TypeDef|\w+_Type).*$', l)
+ if match:
+ inst, typedef = match.groups()
+ inst, typedef = inst.decode(), typedef.decode()
+ print('{} *{} = {};'.format(typedef, inst.lower(), inst))
+ print()
+ print('#endif//__GENERATED_CMSIS_HEADER_EXPORTS__')
+