initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
on:
|
||||
push:
|
||||
|
||||
name: generate executables
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
name: windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: repo
|
||||
uses: actions/checkout@v2.3.1
|
||||
with:
|
||||
path: svl
|
||||
fetch-depth: 0
|
||||
|
||||
- name: python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.7'
|
||||
|
||||
- name: git
|
||||
run: |
|
||||
git config --global user.email "apollo3-uploader-builder@sparkfun.com"
|
||||
git config --global user.name "apollo3-uploader-builder"
|
||||
git config --global pull.ff only
|
||||
cd svl
|
||||
git status
|
||||
git pull
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install -r svl/requirements.txt
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
pyinstaller --onefile svl/svl.py
|
||||
|
||||
- name: copy
|
||||
run: |
|
||||
Remove-Item -Recurse -Force svl\dist\windows
|
||||
mkdir svl\dist\windows
|
||||
Move-Item -Path dist\svl.exe -Destination svl\dist\windows\svl.exe
|
||||
|
||||
- name: commit
|
||||
run: |
|
||||
cd svl
|
||||
git add dist\windows\*
|
||||
git commit -m "generated windows executable"
|
||||
git push
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
linux:
|
||||
name: linux
|
||||
needs: windows
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- name: repo
|
||||
uses: actions/checkout@v2.3.1
|
||||
with:
|
||||
path: svl
|
||||
fetch-depth: 0
|
||||
|
||||
- name: python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.7'
|
||||
|
||||
- name: git
|
||||
run: |
|
||||
git config --global user.email "apollo3-uploader-builder@sparkfun.com"
|
||||
git config --global user.name "apollo3-uploader-builder"
|
||||
git config --global pull.ff only
|
||||
cd svl
|
||||
git pull
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install -r svl/requirements.txt
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
pyinstaller --onefile svl/svl.py
|
||||
|
||||
- name: copy
|
||||
run: |
|
||||
rm -rf ./svl/dist/linux
|
||||
mkdir -p ./svl/dist/linux
|
||||
mv ./dist/svl ./svl/dist/linux/svl
|
||||
|
||||
- name: permit
|
||||
run: |
|
||||
chmod +x ./svl/dist/linux/svl
|
||||
|
||||
- name: commit
|
||||
run: |
|
||||
cd ./svl
|
||||
git add ./dist/linux/*
|
||||
git commit -m "generated linux executable"
|
||||
git push
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
macosx:
|
||||
name: macosx
|
||||
needs: linux
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: repo
|
||||
uses: actions/checkout@v2.3.1
|
||||
with:
|
||||
path: svl
|
||||
fetch-depth: 0
|
||||
|
||||
- name: python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.7'
|
||||
|
||||
- name: git
|
||||
run: |
|
||||
git config --global user.email "apollo3-uploader-builder@sparkfun.com"
|
||||
git config --global user.name "apollo3-uploader-builder"
|
||||
git config --global pull.ff only
|
||||
cd svl
|
||||
git pull
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install -r svl/requirements.txt
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
echo "Build disabled until github environment supports Big Sur"
|
||||
# pyinstaller --onefile svl/svl.py
|
||||
|
||||
- name: copy
|
||||
run: |
|
||||
echo "Build disabled until github environment supports Big Sur"
|
||||
# rm -rf ./svl/dist/macosx
|
||||
# mkdir -p ./svl/dist/macosx
|
||||
# mv ./dist/svl ./svl/dist/macosx/svl
|
||||
|
||||
- name: permit
|
||||
run: |
|
||||
echo "Build disabled until github environment supports Big Sur"
|
||||
# chmod +x ./svl/dist/macosx/svl
|
||||
|
||||
- name: commit
|
||||
run: |
|
||||
echo "Build disabled until github environment supports Big Sur"
|
||||
# cd ./svl
|
||||
# git add ./dist/macosx/*
|
||||
# git commit -m "generated macosx executable"
|
||||
# git push
|
||||
# cd ${GITHUB_WORKSPACE}
|
||||
@@ -0,0 +1,134 @@
|
||||
# intermediate blobs
|
||||
*intermediate_*OTA_blob.bin
|
||||
|
||||
# macosx
|
||||
.DS_Store
|
||||
|
||||
# gcc build artifacts
|
||||
*.o
|
||||
*.d
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
@@ -0,0 +1,108 @@
|
||||
ENTRY(Reset_Handler)
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 0x000F0000
|
||||
RAM_NVIC (rwx) : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||
RAM (rwx) : ORIGIN = (0x10000000 + 0x100), LENGTH = (384K - (0x100))
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_stext = .;
|
||||
KEEP(*(.isr_vector))
|
||||
KEEP(*(.ble_patch))
|
||||
*(.text)
|
||||
*(.text*)
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.fini))
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
. = ALIGN(4);
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
KEEP(*(.eh_frame*))
|
||||
. = ALIGN(4);
|
||||
} > FLASH
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
__etext = ALIGN(8);
|
||||
.data : AT (__etext)
|
||||
{
|
||||
__data_start__ = .;
|
||||
*(.data*)
|
||||
. = ALIGN(8);
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
. = ALIGN(8);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
. = ALIGN(8);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
KEEP(*(.fini_array))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
KEEP(*(.jcr*))
|
||||
. = ALIGN(8);
|
||||
__data_end__ = .;
|
||||
} > RAM
|
||||
.uninitialized (NOLOAD):
|
||||
{
|
||||
. = ALIGN(32);
|
||||
__uninitialized_start = .;
|
||||
*(.uninitialized)
|
||||
KEEP(*(.keep.uninitialized))
|
||||
. = ALIGN(32);
|
||||
__uninitialized_end = .;
|
||||
} > RAM
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
_sbss = .;
|
||||
__bss_start__ = .;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(8);
|
||||
_ebss = .;
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
.heap (NOLOAD):
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__end__ = .;
|
||||
PROVIDE( end = . );
|
||||
_sheap = .;
|
||||
. = ORIGIN(RAM) + LENGTH(RAM) - 0x400 -8;
|
||||
__HeapLimit = .;
|
||||
} >RAM
|
||||
.stack_dummy (NOLOAD):
|
||||
{
|
||||
. = ALIGN(8);
|
||||
*(.stack*)
|
||||
} > RAM
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM)-8;
|
||||
__StackLimit = __StackTop - 0x400;
|
||||
PROVIDE(__stack = __StackTop);
|
||||
PROVIDE(_sstack = __StackTop);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||

|
||||
|
||||
# Apollo3 Uploader - SparkFun Variable Loader (SVL)
|
||||
|
||||
The ```svl``` bootloader is the default bootloader on Artemis module--based boards. This repo contains both the Python programs that are used to send code to a board and the source code for the program that receives code on an Artemis module.
|
||||
|
||||
The bootloader for the Artemis can be upgraded via Arduino using [these instructions](https://learn.sparkfun.com/tutorials/designing-with-the-sparkfun-artemis/all#troubleshooting). It can also be upgraded using the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI).
|
||||
|
||||
Artemis SVL Versions:
|
||||
|
||||
* v5 - Speed and reliability increases
|
||||
* v4 - Added peripheral deinitialization to deliver the Apollo3 closer to the initial reset state.
|
||||
* v3 - Initial version
|
||||
|
||||
# Usage
|
||||
|
||||
* prerequisites
|
||||
* board has the SparkFun Variable Loader installed
|
||||
* source code is located in ```bootlaoder/src```
|
||||
* precompiled binaries and a makefile are located in ```bootloader/gcc```
|
||||
(the artemis module target is suitable for all current SparkFun products)
|
||||
* Python is installed on your computer
|
||||
* your program is compiled + linked to support the SVL (binary offset ```0x10000```)
|
||||
* use the SVL loader script to upload to the board
|
||||
|
||||
```python svl.py [flags] port```
|
||||
|
||||
* ```-b``` **baud rate**: 115200, 921600, or other desired common baud rate (57600, 115200, 230400, 460800, 921600)
|
||||
* ```-f``` **filepath**: path to the binary image of your program to upload
|
||||
* ```port``` **serial port**: the serial port to connect over (*/dev/\** on \*nix or *COMX* on windows)
|
||||
* ```-v``` **verbose**: turn on verbose output
|
||||
@@ -0,0 +1,405 @@
|
||||
#******************************************************************************
|
||||
#
|
||||
# Makefile - Rules for building the libraries, examples and docs.
|
||||
#
|
||||
# Copyright (c) 2019, Ambiq Micro
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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 the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# Third party software included in this distribution is subject to the
|
||||
# additional license terms as defined in the /docs/licenses directory.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# This is part of revision 2.1.0 of the AmbiqSuite Development Package.
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# This is an example makefile for SparkFun Apollo3 boards as used in the
|
||||
# AmbiqSuite SDK.
|
||||
#
|
||||
# Recommended usage
|
||||
# make
|
||||
# make bootload_svl (uses the SparkFun Variable Loader to upload code)
|
||||
# make bootload_asb (uses the Ambiq Secure Bootlaoder to upload code)
|
||||
# make clean
|
||||
#
|
||||
# Filepaths
|
||||
# You can relocate this makefile easily by providing the path to the root of
|
||||
# the AmbiqSuite SDK. If that path is not specified then this file will
|
||||
# assume that it is located in
|
||||
# <AmbiqSDKRoot>/boards/<your_board>/examples/<your_example>/gcc
|
||||
# and use relative paths
|
||||
#
|
||||
# User Configuration
|
||||
# You must also specify which COM_PORT to use if you want to use the
|
||||
# 'bootlaoder' targets.
|
||||
# Windows example: COM_PORT=COM4
|
||||
# *nix example: COM_PORT=/dev/usbserialxxxx
|
||||
#
|
||||
# Python vs. Executable
|
||||
# For simplicity the upload tools are called as Python scripts by default.
|
||||
# Make sure PYTHON is set to the appropriate command to run Python3 from the
|
||||
# command line.
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# User Options
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
# You can override these values on the command line e.g. make bootload COM_PORT=/dev/cu***
|
||||
# COM_PORT is the serial port to use for uploading. For example COM#### on Windows or /dev/cu.usbserial-#### on *nix
|
||||
COM_PORT ?=
|
||||
# ASB_UPLOAD_BAUD is the baud rate setting of the Ambiq Secue Bootloader (ASB) as it is configured on the Apollo3. Defautls to 115200 if unset
|
||||
ASB_UPLOAD_BAUD ?=
|
||||
# SVL_UPLOAD_BAUD is the baud rate setting of the SparkFun Variable Loader (SVL). Defaults to 921600 if unset
|
||||
SVL_UPLOAD_BAUD ?=
|
||||
# PYTHON3 should evaluate to a call to the Python3 executable on your machine
|
||||
PYTHON3 ?=
|
||||
|
||||
# *Optionally* specify absolute paths to the SDK and the BSP
|
||||
# You can do this on the command line - e.g. make bootload SDKPATH=~/$AMBIQ_SDK_ROOT_PATH
|
||||
# Make sure to use / instead of \ when on Windows
|
||||
SDKPATH ?=# Set as the path to the SDK root if not located at ../../../../..
|
||||
COMMONPATH ?=# Set as the path to the BSP common folder if not located at ../../../../common
|
||||
BOARDPATH ?=# Set as the path to the board if not located at ../../..
|
||||
PROJECTPATH ?=# Set as the path to the project if not located at ..
|
||||
BOARD ?=# If using a SparkFun board you can simply provide the name e.g. redboard_artemis_atp
|
||||
|
||||
### Project Settings
|
||||
TARGET := svl
|
||||
COMPILERNAME := gcc
|
||||
PROJECT := $(TARGET)_gcc
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Warning Messages
|
||||
#
|
||||
#******************************************************************************
|
||||
ifeq ($(BOARD),)
|
||||
$(warning warning: no BOARD specified, will fall back to BOARDPATH for arbitrary bsp locations)
|
||||
else
|
||||
BOARDPATH=../../../../$(BOARD)
|
||||
$(warning Using BOARD=$(BOARD) at $(BOARDPATH))
|
||||
endif
|
||||
|
||||
ifeq ($(COM_PORT),)
|
||||
COM_PORT=COM4
|
||||
$(warning warning: you have not defined COM_PORT. Assuming it is COM4)
|
||||
endif
|
||||
ifeq ($(PYTHON3),)
|
||||
PYTHON3=python3
|
||||
$(warning warning: you have not defined PYTHON3. assuming it is accessible by 'python3')
|
||||
endif
|
||||
ifeq ($(ASB_UPLOAD_BAUD),)
|
||||
ASB_UPLOAD_BAUD=115200
|
||||
$(warning defaulting to 115200 baud for ASB)
|
||||
endif
|
||||
ifeq ($(SVL_UPLOAD_BAUD),)
|
||||
SVL_UPLOAD_BAUD=921600
|
||||
$(warning defaulting to 921600 baud for SVL)
|
||||
endif
|
||||
|
||||
ifeq ($(SDKPATH),)
|
||||
SDKPATH =../../../../..
|
||||
$(warning warning: you have not defined SDKPATH so will continue assuming that the SDK root is at $(SDKPATH))
|
||||
else
|
||||
# When the SDKPATH is given export it
|
||||
export SDKPATH
|
||||
endif
|
||||
|
||||
ifeq ($(COMMONPATH),)
|
||||
COMMONPATH =../../../../common
|
||||
$(warning warning: you have not defined COMMONPATH so will continue assuming that the COMMON root is at $(COMMONPATH))
|
||||
else
|
||||
# When the COMMONPATH is given export it
|
||||
export COMMONPATH
|
||||
endif
|
||||
|
||||
ifeq ($(BOARDPATH),)
|
||||
$(error Error: BOARDPATH must be provided)
|
||||
else
|
||||
# Ensure that boardpath does not include a trailing '/'
|
||||
ifeq ($(notdir $(BOARDPATH)),)
|
||||
override BOARDPATH:=$(patsubst %/, %,$(BOARDPATH))
|
||||
$(warning BOARDPATH had a trivial 'notdir' so we tried changing it to: $(BOARDPATH))
|
||||
endif
|
||||
BOARD=$(notdir $(BOARDPATH))
|
||||
# When the BOARDPATH is given export it
|
||||
export BOARDPATH
|
||||
endif
|
||||
|
||||
ifeq ($(PROJECTPATH),)
|
||||
PROJECTPATH =..
|
||||
$(warning warning: you have not defined PROJECTPATH so will continue assuming that the PROJECT root is at $(PROJECTPATH))
|
||||
else
|
||||
# When the PROJECTPATH is given export it
|
||||
export PROJECTPATH
|
||||
endif
|
||||
|
||||
CONFIG := $(PROJECTPATH)/gcc/$(BOARD)/bin
|
||||
$(warning CONFIG=$(CONFIG))
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# User Defines / Includes / Sources / Libraries
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
# Global Defines
|
||||
DEFINES= -DPART_$(PART)
|
||||
DEFINES+= -DAM_CUSTOM_BDADDR
|
||||
DEFINES+= -DAM_PACKAGE_BGA
|
||||
DEFINES+= -DWSF_TRACE_ENABLED
|
||||
DEFINES+= -DAM_DEBUG_PRINTF
|
||||
DEFINES+= -DAM_PART_APOLLO3
|
||||
DEFINES+=
|
||||
|
||||
# Includes (Add paths to where example header files are located)
|
||||
INCLUDES=
|
||||
INCLUDES+= -I$(PROJECTPATH)/src
|
||||
INCLUDES+= -I$(BOARDPATH)/bsp
|
||||
INCLUDES+= -I$(SDKPATH)
|
||||
INCLUDES+= -I$(SDKPATH)/utils
|
||||
INCLUDES+= -I$(SDKPATH)/devices
|
||||
INCLUDES+= -I$(SDKPATH)/mcu/apollo3
|
||||
INCLUDES+= -I$(SDKPATH)/CMSIS/AmbiqMicro/Include
|
||||
INCLUDES+= -I$(SDKPATH)/CMSIS/ARM/Include
|
||||
INCLUDES+= -I$(PROJECTPATH)/src/svl_packet
|
||||
INCLUDES+= -I$(PROJECTPATH)/src/svl_ringbuf
|
||||
INCLUDES+= -I$(PROJECTPATH)/src/svl_uart
|
||||
INCLUDES+= -I$(PROJECTPATH)/src/svl_utils
|
||||
INCLUDES+=
|
||||
|
||||
# Compilation Units (Add all the .c files you need to compile)
|
||||
SRC=
|
||||
SRC+= main.c
|
||||
SRC+= am_util_delay.c
|
||||
SRC+= am_util_stdio.c
|
||||
SRC+= startup_gcc.c
|
||||
SRC+= svl_packet.c
|
||||
SRC+= svl_ringbuf.c
|
||||
SRC+= svl_uart.c
|
||||
SRC+= svl_utils.c
|
||||
SRC+=
|
||||
|
||||
# VPATH (Add paths to where your source files are located)
|
||||
VPATH=
|
||||
VPATH+= $(PROJECTPATH)/src
|
||||
VPATH+= $(SDKPATH)/utils
|
||||
VPATH+= $(COMMONPATH)/tools_sfe/templates
|
||||
VPATH+= $(PROJECTPATH)/src
|
||||
VPATH+= $(PROJECTPATH)/src/svl_packet
|
||||
VPATH+= $(PROJECTPATH)/src/svl_ringbuf
|
||||
VPATH+= $(PROJECTPATH)/src/svl_uart
|
||||
VPATH+= $(PROJECTPATH)/src/svl_utils
|
||||
VPATH+=
|
||||
|
||||
# LIBS (Precompiled libraries to include in the linker step)
|
||||
LIBS=
|
||||
LIBS+= $(BOARDPATH)/bsp/gcc/bin/libam_bsp.a
|
||||
LIBS+= $(SDKPATH)/mcu/apollo3/hal/gcc/bin/libam_hal.a
|
||||
LIBS+=
|
||||
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Warning Messages
|
||||
#
|
||||
#******************************************************************************
|
||||
### Bootloader Tools
|
||||
ASB_UPLOADER=$(PYTHON3) $(COMMONPATH)/tools_sfe/asb/asb.py
|
||||
SVL_UPLOADER=$(PYTHON3) $(COMMONPATH)/tools_sfe/svl/svl.py
|
||||
|
||||
|
||||
SHELL:=/bin/bash
|
||||
#### Setup ####
|
||||
|
||||
TOOLCHAIN ?= arm-none-eabi
|
||||
PART = apollo3
|
||||
CPU = cortex-m4
|
||||
FPU = fpv4-sp-d16
|
||||
# Default to FPU hardware calling convention. However, some customers and/or
|
||||
# applications may need the software calling convention.
|
||||
#FABI = softfp
|
||||
FABI = hard
|
||||
|
||||
STARTUP_FILE := ./startup_$(COMPILERNAME).c
|
||||
|
||||
#### Required Executables ####
|
||||
CC = $(TOOLCHAIN)-gcc
|
||||
GCC = $(TOOLCHAIN)-gcc
|
||||
CPP = $(TOOLCHAIN)-cpp
|
||||
CXX = $(TOOLCHAIN)-g++
|
||||
LD = $(TOOLCHAIN)-ld
|
||||
CP = $(TOOLCHAIN)-objcopy
|
||||
OD = $(TOOLCHAIN)-objdump
|
||||
RD = $(TOOLCHAIN)-readelf
|
||||
AR = $(TOOLCHAIN)-ar
|
||||
SIZE = $(TOOLCHAIN)-size
|
||||
RM = $(shell which rm 2>/dev/null)
|
||||
|
||||
EXECUTABLES = CC LD CP OD AR RD SIZE GCC CXX
|
||||
K := $(foreach exec,$(EXECUTABLES),\
|
||||
$(if $(shell which $($(exec)) 2>/dev/null),,\
|
||||
$(info $(exec) not found on PATH ($($(exec))).)$(exec)))
|
||||
$(if $(strip $(value K)),$(info Required Program(s) $(strip $(value K)) not found))
|
||||
|
||||
ifneq ($(strip $(value K)),)
|
||||
all clean:
|
||||
$(info Tools $(TOOLCHAIN)-$(COMPILERNAME) not installed.)
|
||||
$(RM) -rf bin
|
||||
else
|
||||
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Machinery
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
XSRC = $(filter %.cpp,$(SRC))
|
||||
ZSRC = $(filter %.cc,$(SRC))
|
||||
CSRC = $(filter %.c,$(SRC))
|
||||
ASRC = $(filter %.s,$(SRC))
|
||||
|
||||
OBJS = $(XSRC:%.cpp=$(CONFIG)/%.o)
|
||||
OBJS+= $(ZSRC:%.cc=$(CONFIG)/%.o)
|
||||
OBJS+= $(CSRC:%.c=$(CONFIG)/%.o)
|
||||
OBJS+= $(ASRC:%.s=$(CONFIG)/%.o)
|
||||
|
||||
DEPS = $(XSRC:%.cpp=$(CONFIG)/%.d)
|
||||
DEPS+= $(ZSRC:%.cc=$(CONFIG)/%.d)
|
||||
DEPS+= $(CSRC:%.c=$(CONFIG)/%.d)
|
||||
DEPS+= $(ASRC:%.s=$(CONFIG)/%.d)
|
||||
|
||||
CSTD = -std=c99
|
||||
|
||||
CFLAGS = -mthumb -mcpu=$(CPU) -mfpu=$(FPU) -mfloat-abi=$(FABI)
|
||||
CFLAGS+= -ffunction-sections -fdata-sections
|
||||
CFLAGS+= -MMD -MP $(CSTD) -Wall -g
|
||||
CFLAGS+= -O0
|
||||
CFLAGS+= $(DEFINES)
|
||||
CFLAGS+= $(INCLUDES)
|
||||
CFLAGS+=
|
||||
|
||||
XSTD = -std=gnu++11
|
||||
|
||||
XFLAGS = $(CFLAGS)
|
||||
XFLAGS+= -fno-exceptions
|
||||
|
||||
LFLAGS = -mthumb -mcpu=$(CPU) -mfpu=$(FPU) -mfloat-abi=$(FABI)
|
||||
LFLAGS+= -nostartfiles -static
|
||||
LFLAGS+= -Wl,--gc-sections,--entry,Reset_Handler,-Map,$(CONFIG)/$(TARGET).map
|
||||
LFLAGS+= -Wl,--start-group -lm -lc -lgcc $(LIBS) -Wl,--end-group
|
||||
LFLAGS+=
|
||||
|
||||
# Additional user specified CFLAGS
|
||||
CFLAGS+=$(EXTRA_CFLAGS)
|
||||
|
||||
CPFLAGS = -Obinary
|
||||
|
||||
ODFLAGS = -S
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Targets / Rules
|
||||
#
|
||||
#******************************************************************************
|
||||
all: asb
|
||||
asb: directories $(CONFIG)/$(TARGET).bin
|
||||
|
||||
directories:
|
||||
@mkdir -p $(CONFIG)
|
||||
|
||||
$(CONFIG)/%.o: %.cpp $(CONFIG)/%.d
|
||||
@echo " Compiling $(COMPILERNAME) $<" ;\
|
||||
$(CXX) -c $(XSTD) $(XFLAGS) $< -o $@
|
||||
|
||||
$(CONFIG)/%.o: %.cc $(CONFIG)/%.d
|
||||
@echo " Compiling $(COMPILERNAME) $<" ;\
|
||||
$(CXX) -c $(XSTD) $(XFLAGS) $< -o $@
|
||||
|
||||
$(CONFIG)/%.o: %.c $(CONFIG)/%.d
|
||||
@echo " Compiling $(COMPILERNAME) $<" ;\
|
||||
$(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
$(CONFIG)/%.o: %.s $(CONFIG)/%.d
|
||||
@echo " Assembling $(COMPILERNAME) $<" ;\
|
||||
$(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
$(CONFIG)/$(TARGET).axf: LINKER_FILE = $(COMMONPATH)/tools_sfe/templates/asb_linker.ld
|
||||
$(CONFIG)/$(TARGET).axf: $(OBJS) $(LIBS)
|
||||
@echo " Linking $(COMPILERNAME) $@ with script $(LINKER_FILE)";\
|
||||
$(CC) -Wl,-T,$(LINKER_FILE) -o $@ $(OBJS) $(LFLAGS)
|
||||
|
||||
$(CONFIG)/$(TARGET).bin: $(CONFIG)/$(TARGET).axf
|
||||
@echo " Copying $(COMPILERNAME) $@..." ;\
|
||||
$(CP) $(CPFLAGS) $< $@ ;\
|
||||
$(OD) $(ODFLAGS) $< > $(CONFIG)/$(TARGET).lst
|
||||
|
||||
bootload_asb: directories $(CONFIG)/$(TARGET).bin
|
||||
$(AMBIQ_BIN2BOARD) --bin $(CONFIG)/$(TARGET).bin --load-address-blob 0x20000 --magic-num 0xCB -o $(CONFIG)/$(TARGET) --version 0x0 --load-address-wired 0xC000 -i 6 --options 0x1 -b $(ASB_UPLOAD_BAUD) -port $(COM_PORT) -r 2 -v
|
||||
|
||||
bootload_svl: directories $(CONFIG)/$(TARGET)_svl.bin
|
||||
$(ARTEMIS_SVL) $(COM_PORT) -f $(CONFIG)/$(TARGET)_svl.bin -b $(SVL_UPLOAD_BAUD) -v
|
||||
|
||||
bootload: bootload_svl
|
||||
|
||||
clean:
|
||||
@echo "Cleaning..." ;\
|
||||
$(RM) -f $(OBJS) $(DEPS) \
|
||||
$(CONFIG)/$(TARGET).bin $(CONFIG)/$(TARGET).axf \
|
||||
$(CONFIG)/$(TARGET).lst $(CONFIG)/$(TARGET).map \
|
||||
$(CONFIG)/$(TARGET)_svl.bin $(CONFIG)/$(TARGET)_svl.axf \
|
||||
$(CONFIG)/$(TARGET)_svl.lst $(CONFIG)/$(TARGET)_svl.map \
|
||||
$(CONFIG)/$(TARGET)_asb.bin $(CONFIG)/$(TARGET)_asb.axf \
|
||||
$(CONFIG)/$(TARGET)_asb.lst $(CONFIG)/$(TARGET)_asb.map
|
||||
|
||||
$(CONFIG)/%.d: ;
|
||||
|
||||
$(SDKPATH)/mcu/apollo3/hal/gcc/bin/libam_hal.a:
|
||||
$(MAKE) -C $(SDKPATH)/mcu/apollo3/hal/gcc
|
||||
|
||||
$(SDKPATH)/third_party/uecc/gcc/bin/lib_uecc.a:
|
||||
$(MAKE) -C $(SDKPATH)/third_party/uecc
|
||||
|
||||
$(BOARDPATH)/bsp/gcc/bin/libam_bsp.a:
|
||||
$(MAKE) -C $(BOARDPATH)/bsp/gcc
|
||||
|
||||
# Automatically include any generated dependencies
|
||||
-include $(DEPS)
|
||||
endif
|
||||
.PHONY: all clean directories bootload bootload_asb bootload_svl
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,763 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file main.c
|
||||
//!
|
||||
//! @brief A variable-baud rate bootloader for Apollo3 / Artemis module
|
||||
//!
|
||||
//! Purpose:
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
/*
|
||||
Copyright (c) 2020 SparkFun Electronics
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Authors:
|
||||
Owen Lyke, Nathan Seidle
|
||||
|
||||
Modified: Juy 22 2019
|
||||
|
||||
*/
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Includes
|
||||
//
|
||||
//*****************************************************************************
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#include "svl_ringbuf.h"
|
||||
#include "svl_packet.h"
|
||||
#include "svl_uart.h"
|
||||
#include "svl_utils.h"
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Defines
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define SVL_VERSION_NUMBER 0x05
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Bootloader Options
|
||||
//
|
||||
// ****************************************
|
||||
#define BL_UART_BUF_LEN (2048 + 512) // must be larger than maximum frame transmission length for guaranteed performance
|
||||
#define BL_UART_INST 0 // which UART peripheral to use for BL data
|
||||
#define BL_RX_PAD 49 // RX pad for BL_UART_INST
|
||||
#define BL_TX_PAD 48 // TX pad for BL_UART_INST
|
||||
#define USERCODE_OFFSET (0xC000 + 0x4000) // location in flash to begin storing user's code (Linker script needs to be adjusted to offset user's flash to this address)
|
||||
#define FRAME_BUFFER_SIZE 512 // maximum number of 4-byte words that can be transmitted in a single frame packet
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Debug Options
|
||||
//
|
||||
// ****************************************
|
||||
|
||||
//#define DEBUG 1 // uncomment to enable debug output
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_BAUD_RATE 921600 // debug output baud rate
|
||||
#define DEBUG_UART_INST 1 // debug UART peripheral instance (should not be the same as BL_UART_INST)
|
||||
#define DEBUG_RX_PAD 25 // RX pad for
|
||||
#define DEBUG_TX_PAD 24
|
||||
#define DEBUG_UART_BUF_LEN 256
|
||||
#define DEBUG_PRINT_APP 1 // undefine to not print app pages
|
||||
#define APP_PRINT_NUM_PAGE 1
|
||||
#undef APP_PRINT_PRETTY // define APP_PRINT_PRETTY for the alternate app data print format
|
||||
uint8_t debug_buffer[DEBUG_UART_BUF_LEN] = {0};
|
||||
#endif // DEBUG
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Bootloader Commands
|
||||
//
|
||||
// ****************************************
|
||||
#define CMD_VERSION (0x01)
|
||||
#define CMD_BLMODE (0x02)
|
||||
#define CMD_NEXT (0x03)
|
||||
#define CMD_FRAME (0x04)
|
||||
#define CMD_RETRY (0x05)
|
||||
#define CMD_DONE (0x06)
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Macros
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define UART_GPIO_PINCONFIG_INNER(INST, TXRX, PAD) \
|
||||
{ \
|
||||
.uFuncSel = AM_HAL_PIN_##PAD##_UART##INST##TXRX, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA \
|
||||
}
|
||||
#define UART_GPIO_PINCONFIG(INST, TXRX, PAD) UART_GPIO_PINCONFIG_INNER(INST, TXRX, PAD)
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Forward Declarations
|
||||
//
|
||||
//*****************************************************************************
|
||||
void setup(void);
|
||||
bool detect_baud_rate(uint32_t *baud);
|
||||
void start_uart_bl(uint32_t baud);
|
||||
void enter_bootload(void);
|
||||
uint8_t handle_frame_packet(svl_packet_t *packet, uint32_t *p_frame_address, uint16_t *p_last_page_erased);
|
||||
void app_start(void);
|
||||
void debug_printf(char *fmt, ...);
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
//*****************************************************************************
|
||||
art_svl_ringbuf_t bl_rx_ringbuf = {
|
||||
.buf = NULL,
|
||||
.len = 0,
|
||||
.r_offset = 0,
|
||||
.w_offset = 0,
|
||||
};
|
||||
void *hUART_bl = NULL; // pointer to handle for bootloader UART
|
||||
void *hUART_debug = NULL; // pointer to handle for debug UART
|
||||
|
||||
#define BL_BAUD_SAMPLES (5)
|
||||
volatile uint8_t bl_baud_ticks_index = 0x00;
|
||||
volatile uint32_t bl_baud_ticks[BL_BAUD_SAMPLES] = {0};
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Main
|
||||
//
|
||||
//*****************************************************************************
|
||||
int main(void)
|
||||
{
|
||||
|
||||
bool baud_valid = false;
|
||||
uint32_t bl_baud = 0x00;
|
||||
uint8_t bl_buffer[BL_UART_BUF_LEN] = {0};
|
||||
|
||||
#define PLLEN_VER 1
|
||||
uint8_t packet_ver_buf[PLLEN_VER] = {SVL_VERSION_NUMBER};
|
||||
svl_packet_t svl_packet_version = {CMD_VERSION, packet_ver_buf, PLLEN_VER, PLLEN_VER};
|
||||
svl_packet_t svl_packet_blmode = {CMD_BLMODE, NULL, 0, 0};
|
||||
|
||||
art_svl_ringbuf_init(&bl_rx_ringbuf, bl_buffer, BL_UART_BUF_LEN);
|
||||
setup();
|
||||
|
||||
debug_printf("\n\nArtemis SVL Bootloader - DEBUG\n\n");
|
||||
|
||||
baud_valid = detect_baud_rate(&bl_baud); // Detects the baud rate. Returns true if a valid baud rate was found
|
||||
if (baud_valid == false)
|
||||
{
|
||||
app_start(); // w/o valid baud rate jump t the app
|
||||
}
|
||||
|
||||
start_uart_bl(bl_baud); // This will create a 23 us wide low 'blip' on the TX line (until possibly fixed)
|
||||
am_util_delay_us(200); // At the minimum baud rate of 115200 one byte (10 bits with start/stop) takes 10/115200 or 87 us. 87+23 = 100, double to be safe
|
||||
|
||||
debug_printf("phase:\tconfirm bootloading entry\n");
|
||||
debug_printf("\tsending Artemis SVL version packet\n");
|
||||
svl_packet_send(&svl_packet_version); // when baud rate is determined send the version packet
|
||||
|
||||
debug_printf("\twaiting for bootloader confirmation\n");
|
||||
if (svl_packet_wait(&svl_packet_blmode) != 0)
|
||||
{ // wait for the bootloader to confirm bootloader mode entry
|
||||
debug_printf("\tno confirmation received\n");
|
||||
app_start(); // break to app
|
||||
}
|
||||
debug_printf("\tentering bootloader\n\n");
|
||||
|
||||
enter_bootload(); // Now we are locked in
|
||||
am_util_delay_ms(10);
|
||||
|
||||
am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI, 0); //Cause a system Power On Init to release as much of the stack as possible
|
||||
|
||||
debug_printf("ERROR - runoff");
|
||||
while (1)
|
||||
{ // Loop forever while sleeping.
|
||||
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Go to Deep Sleep.
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Function definitions below
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifdef DEBUG
|
||||
void start_uart_debug(void)
|
||||
{
|
||||
const am_hal_gpio_pincfg_t debug_uart_tx_pinconfig = UART_GPIO_PINCONFIG(DEBUG_UART_INST, TX, DEBUG_TX_PAD);
|
||||
const am_hal_gpio_pincfg_t debug_uart_rx_pinconfig = UART_GPIO_PINCONFIG(DEBUG_UART_INST, RX, DEBUG_RX_PAD);
|
||||
const am_hal_uart_config_t debug_uart_config = {
|
||||
// Standard UART settings: 115200-8-N-1
|
||||
.ui32BaudRate = DEBUG_BAUD_RATE,
|
||||
.ui32DataBits = AM_HAL_UART_DATA_BITS_8,
|
||||
.ui32Parity = AM_HAL_UART_PARITY_NONE,
|
||||
.ui32StopBits = AM_HAL_UART_ONE_STOP_BIT,
|
||||
.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
|
||||
|
||||
// Set TX and RX FIFOs to interrupt at half-full.
|
||||
.ui32FifoLevels = (AM_HAL_UART_TX_FIFO_1_2 |
|
||||
AM_HAL_UART_RX_FIFO_1_2),
|
||||
|
||||
// Buffers
|
||||
.pui8TxBuffer = NULL,
|
||||
.ui32TxBufferSize = 0,
|
||||
.pui8RxBuffer = NULL,
|
||||
.ui32RxBufferSize = 0,
|
||||
};
|
||||
|
||||
// Initialize the printf interface for UART output.
|
||||
am_hal_uart_initialize(DEBUG_UART_INST, &hUART_debug);
|
||||
am_hal_uart_power_control(hUART_debug, AM_HAL_SYSCTRL_WAKE, false);
|
||||
am_hal_uart_configure(hUART_debug, &debug_uart_config);
|
||||
|
||||
// Disable that pesky FIFO
|
||||
UARTn(DEBUG_UART_INST)->LCRH_b.FEN = 0;
|
||||
|
||||
// Enable the UART pins.
|
||||
am_hal_gpio_pinconfig(DEBUG_TX_PAD, debug_uart_tx_pinconfig);
|
||||
am_hal_gpio_pinconfig(DEBUG_RX_PAD, debug_uart_rx_pinconfig);
|
||||
|
||||
// Enable interrupts.
|
||||
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + DEBUG_UART_INST));
|
||||
am_hal_uart_interrupt_enable(hUART_debug, (AM_HAL_UART_INT_RX));
|
||||
}
|
||||
|
||||
void stop_uart_debug(void)
|
||||
{
|
||||
// Deinitialize the UART printf interface.
|
||||
am_hal_uart_power_control(hUART_debug, AM_HAL_SYSCTRL_DEEPSLEEP, false);
|
||||
am_hal_uart_deinitialize(hUART_debug);
|
||||
|
||||
// Re-enable that pesky FIFO
|
||||
UARTn(DEBUG_UART_INST)->LCRH_b.FEN = 1;
|
||||
|
||||
// Disable the UART pins.
|
||||
am_hal_gpio_pinconfig(DEBUG_TX_PAD, g_AM_HAL_GPIO_DISABLE);
|
||||
am_hal_gpio_pinconfig(DEBUG_RX_PAD, g_AM_HAL_GPIO_DISABLE);
|
||||
|
||||
// Disable interrupts.
|
||||
NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + DEBUG_UART_INST));
|
||||
am_hal_uart_interrupt_disable(hUART_debug, (AM_HAL_UART_INT_RX));
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Setup
|
||||
//
|
||||
//*****************************************************************************
|
||||
void setup(void)
|
||||
{
|
||||
// Set the clock frequency.
|
||||
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
|
||||
|
||||
// Set the default cache configuration
|
||||
am_hal_cachectrl_config(&am_hal_cachectrl_defaults);
|
||||
am_hal_cachectrl_enable();
|
||||
|
||||
// Configure the stimer
|
||||
am_hal_stimer_int_enable(AM_HAL_STIMER_INT_OVERFLOW);
|
||||
NVIC_EnableIRQ(STIMER_IRQn);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);
|
||||
|
||||
#ifdef DEBUG
|
||||
start_uart_debug();
|
||||
#endif
|
||||
|
||||
// Enable interrupts.
|
||||
am_hal_interrupt_master_enable();
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Un-set-up
|
||||
//
|
||||
//*****************************************************************************
|
||||
void unsetup(void)
|
||||
{
|
||||
disable_burst_mode();
|
||||
|
||||
// Deconfigure the stimer
|
||||
am_hal_stimer_int_disable(AM_HAL_STIMER_INT_OVERFLOW);
|
||||
NVIC_DisableIRQ(STIMER_IRQn);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_NO_CLK);
|
||||
|
||||
#ifdef DEBUG
|
||||
stop_uart_debug();
|
||||
#endif
|
||||
|
||||
// Disable interrupts.
|
||||
am_hal_interrupt_master_disable();
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Baud Rate Detect Phase
|
||||
//
|
||||
// ****************************************
|
||||
bool detect_baud_rate(uint32_t *baud)
|
||||
{
|
||||
uint32_t bl_entry_timeout_ms = 200;
|
||||
uint32_t bl_entry_timeout_start = millis();
|
||||
bool baud_is_valid = false;
|
||||
bool timed_out = true;
|
||||
|
||||
debug_printf("phase:\tdetect baud rate\n");
|
||||
|
||||
enable_burst_mode();
|
||||
|
||||
am_hal_gpio_pinconfig(BL_RX_PAD, g_AM_HAL_GPIO_INPUT_PULLUP);
|
||||
|
||||
ap3_gpio_enable_interrupts(BL_RX_PAD, AM_HAL_GPIO_PIN_INTDIR_LO2HI);
|
||||
am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
am_hal_gpio_interrupt_enable(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
NVIC_EnableIRQ(GPIO_IRQn);
|
||||
|
||||
while ((millis() - bl_entry_timeout_start) < bl_entry_timeout_ms)
|
||||
{
|
||||
// try to detect baud rate
|
||||
|
||||
// debug_printf("\ttime (ms):\t%d\n", millis());
|
||||
|
||||
if (bl_baud_ticks_index == BL_BAUD_SAMPLES)
|
||||
{
|
||||
|
||||
// compute differences between samples
|
||||
for (uint8_t indi = 0; indi < (BL_BAUD_SAMPLES - 1); indi++)
|
||||
{
|
||||
bl_baud_ticks[indi] = bl_baud_ticks[indi + 1] - bl_baud_ticks[indi];
|
||||
}
|
||||
|
||||
float mean = 0.0;
|
||||
for (uint8_t indi = 0; indi < (BL_BAUD_SAMPLES - 1); indi++)
|
||||
{
|
||||
mean += bl_baud_ticks[indi];
|
||||
}
|
||||
mean /= (BL_BAUD_SAMPLES - 1);
|
||||
|
||||
if (mean < 3)
|
||||
{
|
||||
// invalid
|
||||
}
|
||||
else if ((mean >= 4) && (mean <= 8))
|
||||
{
|
||||
*baud = 921600;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 10) && (mean <= 14))
|
||||
{
|
||||
*baud = 460800;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 25) && (mean <= 30))
|
||||
{
|
||||
*baud = 230400;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 45) && (mean <= 55))
|
||||
{
|
||||
*baud = 115200;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 91) && (mean <= 111))
|
||||
{
|
||||
*baud = 57600;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid
|
||||
}
|
||||
|
||||
if (baud_is_valid)
|
||||
{
|
||||
timed_out = false;
|
||||
}
|
||||
|
||||
break; // exit the timeout loop
|
||||
}
|
||||
}
|
||||
|
||||
am_hal_gpio_interrupt_disable(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
NVIC_DisableIRQ(GPIO_IRQn);
|
||||
|
||||
disable_burst_mode();
|
||||
|
||||
#ifdef DEBUG
|
||||
// show differences for debugging purposes
|
||||
debug_printf("\ttiming differences: { ");
|
||||
for (uint8_t indi = 0; indi < (BL_BAUD_SAMPLES - 1); indi++)
|
||||
{
|
||||
debug_printf("%d", bl_baud_ticks[indi]);
|
||||
if (indi < (BL_BAUD_SAMPLES - 2))
|
||||
{
|
||||
debug_printf(", ");
|
||||
}
|
||||
}
|
||||
debug_printf("}\n");
|
||||
#endif // DEBUG
|
||||
|
||||
if (!baud_is_valid)
|
||||
{
|
||||
debug_printf("\tbaud rate not detected.\n\t\trising edges:\t%d\n\t\ttimed out:\t%d\n\n", bl_baud_ticks_index, timed_out);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("\tdetected valid baud rate:\t%d\n\n", *baud);
|
||||
}
|
||||
|
||||
return baud_is_valid;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Start BL UART at desired baud
|
||||
//
|
||||
//*****************************************************************************
|
||||
void start_uart_bl(uint32_t baud)
|
||||
{
|
||||
const am_hal_gpio_pincfg_t bl_uart_tx_pinconfig = UART_GPIO_PINCONFIG(BL_UART_INST, TX, BL_TX_PAD);
|
||||
const am_hal_gpio_pincfg_t bl_uart_rx_pinconfig = UART_GPIO_PINCONFIG(BL_UART_INST, RX, BL_RX_PAD);
|
||||
am_hal_uart_config_t bl_uart_config =
|
||||
{
|
||||
// Standard UART settings: 115200-8-N-1
|
||||
.ui32BaudRate = baud,
|
||||
.ui32DataBits = AM_HAL_UART_DATA_BITS_8,
|
||||
.ui32Parity = AM_HAL_UART_PARITY_NONE,
|
||||
.ui32StopBits = AM_HAL_UART_ONE_STOP_BIT,
|
||||
.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
|
||||
|
||||
// Set TX and RX FIFOs to interrupt at half-full.
|
||||
.ui32FifoLevels = (AM_HAL_UART_TX_FIFO_1_2 |
|
||||
AM_HAL_UART_RX_FIFO_1_2),
|
||||
|
||||
// Buffers
|
||||
.pui8TxBuffer = NULL,
|
||||
.ui32TxBufferSize = 0,
|
||||
.pui8RxBuffer = NULL,
|
||||
.ui32RxBufferSize = 0,
|
||||
};
|
||||
|
||||
// Initialize the printf interface for UART output.
|
||||
am_hal_uart_initialize(BL_UART_INST, &hUART_bl);
|
||||
am_hal_uart_power_control(hUART_bl, AM_HAL_SYSCTRL_WAKE, false);
|
||||
am_hal_uart_configure(hUART_bl, &bl_uart_config);
|
||||
|
||||
// Disable that pesky FIFO
|
||||
UARTn(BL_UART_INST)->LCRH_b.FEN = 0;
|
||||
|
||||
// Enable the UART pins.
|
||||
am_hal_gpio_pinconfig(BL_TX_PAD, bl_uart_tx_pinconfig);
|
||||
am_hal_gpio_pinconfig(BL_RX_PAD, bl_uart_rx_pinconfig);
|
||||
|
||||
// Enable interrupts.
|
||||
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + BL_UART_INST));
|
||||
am_hal_uart_interrupt_enable(hUART_bl, (AM_HAL_UART_INT_RX));
|
||||
|
||||
// Provide SVL Packet interfaces
|
||||
svl_packet_link_read_fn(art_svl_ringbuf_read, &bl_rx_ringbuf);
|
||||
svl_packet_link_avail_fn(art_svl_ringbuf_available, &bl_rx_ringbuf);
|
||||
svl_packet_link_millis_fn(millis);
|
||||
svl_packet_link_write_fn(svl_uart_write_byte, hUART_bl);
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Bootload phase
|
||||
//
|
||||
// ****************************************
|
||||
void enter_bootload(void)
|
||||
{
|
||||
enable_burst_mode();
|
||||
bool done = false;
|
||||
uint32_t frame_address = 0;
|
||||
uint16_t last_page_erased = 0;
|
||||
uint8_t retransmit = 0;
|
||||
static uint32_t frame_buffer[FRAME_BUFFER_SIZE];
|
||||
|
||||
svl_packet_t svl_packet_incoming_frame = {CMD_FRAME, (uint8_t *)frame_buffer, sizeof(frame_buffer) / sizeof(uint8_t), sizeof(frame_buffer) / sizeof(uint8_t)};
|
||||
svl_packet_t svl_packet_retry = {CMD_RETRY, NULL, 0, 0};
|
||||
svl_packet_t svl_packet_next = {CMD_NEXT, NULL, 0, 0};
|
||||
|
||||
debug_printf("phase:\tbootload\n");
|
||||
|
||||
while (!done)
|
||||
{
|
||||
|
||||
if (retransmit != 0)
|
||||
{
|
||||
debug_printf("\trequesting retransmission\n");
|
||||
svl_packet_send((svl_packet_t *)&svl_packet_retry); // Ask to retransmit
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("\trequesting next app frame\n");
|
||||
svl_packet_send((svl_packet_t *)&svl_packet_next); // Ask for the next frame packet
|
||||
}
|
||||
retransmit = 0;
|
||||
|
||||
uint8_t stat = svl_packet_wait(&svl_packet_incoming_frame);
|
||||
if (stat != 0)
|
||||
{ // wait for either a frame or the done command
|
||||
debug_printf("\t\terror receiving packet (%d)\n", stat);
|
||||
retransmit = 1;
|
||||
am_util_delay_us(177000); //Worst case: wait 177ms for 2048 byte transfer at 115200bps to complete
|
||||
|
||||
//Flush the buffers to remove any inbound or outbound garbage
|
||||
bl_rx_ringbuf.r_offset = 0;
|
||||
bl_rx_ringbuf.w_offset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// debug_printf("Successfully received incoming frame packet (todo: add extra details in debug)\n", stat);
|
||||
|
||||
if (svl_packet_incoming_frame.cmd == CMD_FRAME)
|
||||
{
|
||||
debug_printf("\t\treceived an app frame\n");
|
||||
if (handle_frame_packet(&svl_packet_incoming_frame, &frame_address, &last_page_erased) != 0)
|
||||
{
|
||||
// debug_printf("\t\t\tbootload error - packet could not be handled\n");
|
||||
retransmit = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (svl_packet_incoming_frame.cmd == CMD_DONE)
|
||||
{
|
||||
debug_printf("\t\treceived done signal!\n\n");
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("bootload error - unknown command\n");
|
||||
retransmit = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// finish bootloading
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Handle a frame packet
|
||||
//
|
||||
// ****************************************
|
||||
uint8_t handle_frame_packet(svl_packet_t *packet, uint32_t *p_frame_address, uint16_t *p_last_page_erased)
|
||||
{
|
||||
// debug_printf("\t\thandling frame\n");
|
||||
uint32_t num_words = (packet->pl_len / 4);
|
||||
|
||||
debug_printf("\t\tframe_address = 0x%08X, num_words = %d\n", *(p_frame_address), num_words);
|
||||
|
||||
// Check payload length is multiple of words
|
||||
if ((packet->pl_len % 4))
|
||||
{
|
||||
debug_printf("Error: frame packet not integer multiple of words (4 bytes per word)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t i32ReturnCode = 0;
|
||||
uint32_t offset_address = (*(p_frame_address) + USERCODE_OFFSET);
|
||||
if ((*p_last_page_erased) < AM_HAL_FLASH_ADDR2PAGE(offset_address))
|
||||
{ // Prevent erasing partially-filled pages
|
||||
// debug_printf("Erasing instance %d, page %d\n\r", AM_HAL_FLASH_ADDR2INST( offset_address ), AM_HAL_FLASH_ADDR2PAGE(offset_address) );
|
||||
|
||||
//Erase the 8k page for this address
|
||||
i32ReturnCode = am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, AM_HAL_FLASH_ADDR2INST(offset_address), AM_HAL_FLASH_ADDR2PAGE(offset_address));
|
||||
*(p_last_page_erased) = AM_HAL_FLASH_ADDR2PAGE(offset_address);
|
||||
|
||||
if (i32ReturnCode)
|
||||
{
|
||||
debug_printf("FLASH_MASS_ERASE i32ReturnCode = 0x%x.\n\r", i32ReturnCode);
|
||||
}
|
||||
}
|
||||
|
||||
//Record the array
|
||||
//debug_printf("Recording %d words (%d bytes) to memory\n", num_words, 4 * num_words);
|
||||
i32ReturnCode = am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY, (uint32_t *)packet->pl, (uint32_t *)(*(p_frame_address) + USERCODE_OFFSET), num_words);
|
||||
if (i32ReturnCode)
|
||||
{
|
||||
debug_printf("FLASH_WRITE error = 0x%x.\n\r", i32ReturnCode);
|
||||
return 1;
|
||||
}
|
||||
*(p_frame_address) += num_words * 4;
|
||||
|
||||
// debug_printf("Array recorded to flash\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Jump to the application
|
||||
//
|
||||
// ****************************************
|
||||
void app_start(void)
|
||||
{
|
||||
// debug_printf("\n\t-- app start --\n");
|
||||
// #ifdef DEBUG
|
||||
// #ifdef DEBUG_PRINT_APP
|
||||
// uint32_t start_address = USERCODE_OFFSET; // Print a section of flash
|
||||
// debug_printf("Printing page starting at offset 0x%04X\n", start_address);
|
||||
// #ifdef APP_PRINT_PRETTY
|
||||
// for (uint16_t x = 0; x < 512*APP_PRINT_NUM_PAGE; x++){
|
||||
// if (x % 8 == 0){
|
||||
// debug_printf("\nAdr: 0x%04X", start_address + (x * 4));
|
||||
// }
|
||||
// debug_printf(" 0x%08X", *(uint32_t *)(start_address + (x * 4)));
|
||||
// }
|
||||
// debug_printf("\n");
|
||||
// #else
|
||||
// for (uint16_t x = 0; x < 512*APP_PRINT_NUM_PAGE; x++){
|
||||
// if (x % 4 == 0){
|
||||
// debug_printf("\n");
|
||||
// }
|
||||
// uint32_t wor = *(uint32_t *)(start_address + (x * 4));
|
||||
// debug_printf("%02x%02x %02x%02x", (wor & 0x000000FF), (wor & 0x0000FF00) >> 8, (wor & 0x00FF0000) >> 16, (wor & 0xFF000000) >> 24 );
|
||||
// if( (x%4) != 3 ){
|
||||
// debug_printf(" ");
|
||||
// }
|
||||
// }
|
||||
// debug_printf("\n");
|
||||
// #endif // APP_PRINT_PRETTY
|
||||
// #endif // DEBUG_PRINT_APP
|
||||
// #endif // DEBUG
|
||||
|
||||
void *entryPoint = (void *)(*((uint32_t *)(USERCODE_OFFSET + 4)));
|
||||
debug_printf("\nJump to App at 0x%08X\n\n", (uint32_t)entryPoint);
|
||||
am_util_delay_ms(10); // Wait for prints to complete
|
||||
unsetup(); // Undoes configuration to provide users with a clean slate
|
||||
goto *entryPoint; // Jump to start of user code
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Debug printf function
|
||||
//
|
||||
// ****************************************
|
||||
void debug_printf(char *fmt, ...)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
char debug_buffer[DEBUG_UART_BUF_LEN];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(debug_buffer, DEBUG_UART_BUF_LEN, (const char *)fmt, args);
|
||||
va_end(args);
|
||||
|
||||
svl_uart_print(hUART_debug, debug_buffer);
|
||||
#endif //DEBUG
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART interrupt handlers
|
||||
//
|
||||
//*****************************************************************************
|
||||
void am_uart_isr(void)
|
||||
{
|
||||
// Service the FIFOs as necessary, and clear the interrupts.
|
||||
#if BL_UART_INST == 0
|
||||
uint32_t ui32Status, ui32Idle;
|
||||
am_hal_uart_interrupt_status_get(hUART_bl, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_bl, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_bl, ui32Status, &ui32Idle);
|
||||
if (ui32Status & AM_HAL_UART_INT_RX)
|
||||
{
|
||||
uint8_t c = 0x00;
|
||||
if (svl_uart_read(hUART_bl, (char *)&c, 1) != 0)
|
||||
{
|
||||
art_svl_ringbuf_write(&bl_rx_ringbuf, c);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
am_hal_uart_interrupt_status_get(hUART_debug, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_debug, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_debug, ui32Status, &ui32Idle);
|
||||
#endif // DEBUG
|
||||
#endif // BL_UART_INST == 0
|
||||
}
|
||||
|
||||
void am_uart1_isr(void)
|
||||
{
|
||||
// Service the FIFOs as necessary, and clear the interrupts.
|
||||
#if BL_UART_INST == 1
|
||||
uint32_t ui32Status, ui32Idle;
|
||||
am_hal_uart_interrupt_status_get(hUART_bl, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_bl, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_bl, ui32Status, &ui32Idle);
|
||||
if (ui32Status & AM_HAL_UART_INT_RX)
|
||||
{
|
||||
uint8_t c = 0x00;
|
||||
if (read(hUART_bl, &c, 1) != 0)
|
||||
{
|
||||
art_svl_ringbuf_write(&bl_rx_ringbuf, c);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
uint32_t ui32Status, ui32Idle;
|
||||
am_hal_uart_interrupt_status_get(hUART_debug, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_debug, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_debug, ui32Status, &ui32Idle);
|
||||
#endif // DEBUG
|
||||
#endif // BL_UART_INST == 0
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// GPIO interrupt handler
|
||||
//
|
||||
//*****************************************************************************
|
||||
void am_gpio_isr(void)
|
||||
{
|
||||
am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
if (bl_baud_ticks_index < BL_BAUD_SAMPLES)
|
||||
{
|
||||
bl_baud_ticks[bl_baud_ticks_index++] = CTIMER->STTMR;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// STimer interrupt handler
|
||||
//
|
||||
//*****************************************************************************
|
||||
void am_stimer_isr(void)
|
||||
{
|
||||
am_hal_stimer_int_clear(AM_HAL_STIMER_INT_OVERFLOW);
|
||||
ap3_stimer_overflows += 1;
|
||||
// At the fastest rate (3MHz) the 64 bits of the stimer
|
||||
// along with this overflow counter can keep track of
|
||||
// the time for ~ 195,000 years without wrapping to 0
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
#include "svl_packet.h"
|
||||
|
||||
void *read_param = NULL;
|
||||
void *write_param = NULL;
|
||||
void *avail_param = NULL;
|
||||
|
||||
svl_packet_read_byte_fn_t read_fn = NULL;
|
||||
svl_packet_write_byte_fn_t write_fn = NULL;
|
||||
svl_packet_avail_bytes_fn_t avail_fn = NULL;
|
||||
svl_packet_millis_fn_t millis_fn = NULL;
|
||||
|
||||
uint8_t CRCL, CRCH;
|
||||
|
||||
uint16_t CRC_Table[8 * 32] = {
|
||||
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
|
||||
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
|
||||
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
|
||||
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
|
||||
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
|
||||
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
|
||||
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
|
||||
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
|
||||
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
|
||||
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
|
||||
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
|
||||
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
|
||||
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
|
||||
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
|
||||
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
|
||||
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
|
||||
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
|
||||
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
|
||||
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
|
||||
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202};
|
||||
|
||||
//Update CRC with given byte
|
||||
inline __attribute__((always_inline)) void updateCRC(uint8_t num)
|
||||
{
|
||||
uint16_t tableAddr = (num ^ CRCH);
|
||||
CRCH = (CRC_Table[tableAddr] >> 8) ^ CRCL;
|
||||
CRCL = (CRC_Table[tableAddr] & 0x00FF);
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_read_byte(uint8_t *c)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (read_fn != NULL)
|
||||
{
|
||||
retval = read_fn(read_param, c);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_write_byte(uint8_t c)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (write_fn != NULL)
|
||||
{
|
||||
retval = write_fn(write_param, c);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_avail_bytes(void)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (avail_fn != NULL)
|
||||
{
|
||||
retval = avail_fn(avail_param);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_millis(void)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (millis_fn != NULL)
|
||||
{
|
||||
retval = millis_fn();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void svl_packet_link_read_fn(svl_packet_read_byte_fn_t fn, void *param)
|
||||
{
|
||||
read_param = param;
|
||||
read_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_link_write_fn(svl_packet_write_byte_fn_t fn, void *param)
|
||||
{
|
||||
write_param = param;
|
||||
write_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_link_avail_fn(svl_packet_avail_bytes_fn_t fn, void *param)
|
||||
{
|
||||
avail_param = param;
|
||||
avail_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_link_millis_fn(svl_packet_millis_fn_t fn)
|
||||
{
|
||||
millis_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_send(svl_packet_t *packet)
|
||||
{
|
||||
CRCL = 0;
|
||||
CRCH = 0;
|
||||
updateCRC(packet->cmd); //Add this byte to CRC
|
||||
for (uint32_t x = 0; x < packet->pl_len; x++)
|
||||
{
|
||||
updateCRC(*(packet->pl + x)); //Add this byte to CRC
|
||||
}
|
||||
|
||||
svl_packet_write_byte(((packet->pl_len + 3) >> 8)); // len high byte (including command and CRC bytes)
|
||||
svl_packet_write_byte(((packet->pl_len + 3) & 0xFF)); // len low byte (including command and CRC bytes)
|
||||
|
||||
svl_packet_write_byte((packet->cmd)); // command byte
|
||||
|
||||
if ((packet->pl != NULL) && (packet->pl_len != 0))
|
||||
{
|
||||
for (uint16_t indi = 0; indi < packet->pl_len; indi++)
|
||||
{ // payload
|
||||
svl_packet_write_byte(*(packet->pl + indi));
|
||||
}
|
||||
}
|
||||
|
||||
svl_packet_write_byte(CRCH); // CRC H
|
||||
svl_packet_write_byte(CRCL); // CRC L
|
||||
}
|
||||
|
||||
uint8_t svl_packet_wait(svl_packet_t *packet)
|
||||
{
|
||||
|
||||
// wait for 2 bytes (the length bytes)
|
||||
// wait for length bytes to come in
|
||||
// make sure that 'length' bytes are enough to satisfy the desired payload length
|
||||
|
||||
if (packet == NULL)
|
||||
{
|
||||
return (SVL_PACKET_ERR);
|
||||
}
|
||||
|
||||
const uint8_t num_bytes_length = 2;
|
||||
if (svl_packet_wait_bytes(num_bytes_length))
|
||||
{
|
||||
return (SVL_PACKET_ERR_TIMEOUT | SVL_PACKET_LEN);
|
||||
}
|
||||
uint16_t len = svl_packet_get_uint16_t();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return (SVL_PACKET_ERR_ZLP);
|
||||
}
|
||||
if ((len - 3) > packet->max_pl_len)
|
||||
{
|
||||
return (SVL_PACKET_ERR_MEM | SVL_PACKET_PL);
|
||||
}
|
||||
|
||||
//Wait for entire packet to come in
|
||||
if (svl_packet_wait_bytes(len))
|
||||
return (SVL_PACKET_ERR_TIMEOUT | SVL_PACKET_PL);
|
||||
|
||||
uint8_t incoming;
|
||||
CRCL = 0;
|
||||
CRCH = 0;
|
||||
|
||||
//Get command byte
|
||||
svl_packet_read_byte(&incoming);
|
||||
packet->cmd = incoming;
|
||||
updateCRC(incoming); //Add this byte to CRC
|
||||
|
||||
packet->pl_len = (len - 3);
|
||||
|
||||
//Now read the data coming in
|
||||
if ((packet->pl != NULL) && (packet->max_pl_len != 0))
|
||||
{
|
||||
for (uint32_t x = 0; x < packet->pl_len; x++)
|
||||
{
|
||||
svl_packet_read_byte(&incoming);
|
||||
|
||||
updateCRC(incoming); //Add this byte to CRC
|
||||
|
||||
*(packet->pl + x) = incoming; //Fill payload with data
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t crc = svl_packet_get_uint16_t(); //Read final two bytes into CRC
|
||||
|
||||
uint16_t check = ((uint16_t)CRCH << 8) | CRCL;
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
return (SVL_PACKET_ERR_CRC);
|
||||
}
|
||||
|
||||
return (SVL_PACKET_OK);
|
||||
}
|
||||
|
||||
uint16_t svl_packet_get_uint16_t(void)
|
||||
{
|
||||
uint8_t h = 0x00;
|
||||
uint8_t l = 0x00;
|
||||
svl_packet_read_byte(&h);
|
||||
svl_packet_read_byte(&l);
|
||||
return (((uint16_t)h << 8) | (l & 0xFF));
|
||||
}
|
||||
|
||||
uint8_t svl_packet_wait_bytes(uint32_t num)
|
||||
{
|
||||
uint32_t timeout_ms = 500;
|
||||
uint32_t start = svl_packet_millis();
|
||||
uint32_t avail = 0;
|
||||
|
||||
while ((svl_packet_millis() - start) < timeout_ms)
|
||||
{
|
||||
avail = svl_packet_avail_bytes();
|
||||
if (avail >= num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// debug_printf("only got %d bytes...\n",avail);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef _SVL_PACKET_H_
|
||||
#define _SVL_PACKET_H_
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
typedef struct _svl_packet_t
|
||||
{ // An SVL3 packet consists of 5+N bytes. N is the length of the data payload, and there are 5 bytes that are always transmitted
|
||||
// len // 2 - length of the remainder of the packet (pllen + 3) (note, this is automatically calculated)
|
||||
uint8_t cmd; // 1 - The command
|
||||
uint8_t *pl; // N - The payload (pointer)
|
||||
uint16_t pl_len; // - Length of the payload in bytes (note, this is not transmitted across the line, just used internally)
|
||||
// crc // 2 - CRC16 on the command and the payload. poly = 0x8005, nothing extra or fancy. Byte order MSB first, bit order MSB first
|
||||
uint16_t max_pl_len; // - This is the number of bytes pointed to by 'pl'
|
||||
} svl_packet_t;
|
||||
|
||||
enum
|
||||
{
|
||||
SVL_PACKET_OK = 0x00,
|
||||
SVL_PACKET_ERR = 0x01, // general error
|
||||
SVL_PACKET_ERR_TIMEOUT = 0x02, // timeout
|
||||
SVL_PACKET_ERR_ZLP = 0x04, // zero length packet
|
||||
SVL_PACKET_ERR_MEM = 0x08, // not enough space to receive packet
|
||||
SVL_PACKET_ERR_CRC = 0x10, // crc mismatch
|
||||
|
||||
SVL_PACKET_LEN = 0x80, // flag indicating 'len' header
|
||||
SVL_PACKET_PL = 0x40, // flag indicating payload
|
||||
};
|
||||
|
||||
typedef size_t (*svl_packet_read_byte_fn_t)(void *, uint8_t *);
|
||||
typedef size_t (*svl_packet_write_byte_fn_t)(void *, uint8_t);
|
||||
typedef size_t (*svl_packet_avail_bytes_fn_t)(void *);
|
||||
typedef size_t (*svl_packet_millis_fn_t)(void);
|
||||
|
||||
void svl_packet_link_read_fn(svl_packet_read_byte_fn_t fn, void *param);
|
||||
void svl_packet_link_write_fn(svl_packet_write_byte_fn_t fn, void *param);
|
||||
void svl_packet_link_avail_fn(svl_packet_avail_bytes_fn_t fn, void *param);
|
||||
void svl_packet_link_millis_fn(svl_packet_millis_fn_t fn);
|
||||
|
||||
void svl_packet_send(svl_packet_t *packet);
|
||||
uint8_t svl_packet_wait(svl_packet_t *packet);
|
||||
|
||||
uint16_t svl_packet_get_uint16_t(void);
|
||||
uint8_t svl_packet_wait_bytes(uint32_t num);
|
||||
|
||||
#endif // _SVL_PACKET_H_
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "svl_ringbuf.h"
|
||||
|
||||
size_t art_svl_ringbuf_init( void* vrb, uint8_t* buf, size_t len ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
rb->buf = buf;
|
||||
rb->len = len;
|
||||
rb->r_offset = 0;
|
||||
rb->w_offset = 0;
|
||||
|
||||
return rb->len;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_available( void* vrb ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
size_t avail = 0x00;
|
||||
if((rb->w_offset) >= (rb->r_offset)){
|
||||
avail = rb->w_offset - rb->r_offset;
|
||||
}else{
|
||||
avail = rb->len - (rb->r_offset - rb->w_offset);
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_bytes_free( void* vrb ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
size_t friegh = 0x00;
|
||||
if((rb->w_offset) >= (rb->r_offset)){
|
||||
friegh = rb->len - rb->w_offset + rb->r_offset -1;
|
||||
}else{
|
||||
friegh = rb->r_offset - rb->w_offset - 1;
|
||||
}
|
||||
return friegh;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_write( void* vrb, uint8_t c ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
if(art_svl_ringbuf_bytes_free(rb) > 0){
|
||||
*(rb->buf + rb->w_offset) = c;
|
||||
rb->w_offset++;
|
||||
if(rb->w_offset >= rb->len){
|
||||
rb->w_offset = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_read( void* vrb, uint8_t* c ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
if(art_svl_ringbuf_available(rb) > 0){
|
||||
*c = *(rb->buf + rb->r_offset);
|
||||
rb->r_offset++;
|
||||
if(rb->r_offset >= rb->len){
|
||||
rb->r_offset = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef _SVL_RINGBUF_H_
|
||||
#define _SVL_RINGBUF_H_
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
typedef struct _art_svl_ringbuf_t {
|
||||
uint8_t* buf;
|
||||
size_t len;
|
||||
volatile size_t r_offset;
|
||||
volatile size_t w_offset;
|
||||
}art_svl_ringbuf_t;
|
||||
|
||||
size_t art_svl_ringbuf_init ( void* rb, uint8_t* buf, size_t len );
|
||||
size_t art_svl_ringbuf_available ( void* rb );
|
||||
size_t art_svl_ringbuf_bytes_free ( void* rb );
|
||||
size_t art_svl_ringbuf_write ( void* rb, uint8_t c );
|
||||
size_t art_svl_ringbuf_read ( void* rb, uint8_t* c );
|
||||
|
||||
|
||||
#endif // _SVL_RINGBUF_H_
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "svl_uart.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART read buffer
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_read(void *pHandle, char* buf, size_t len){
|
||||
uint32_t ui32BytesRead = 0x00;
|
||||
am_hal_uart_transfer_t sRead = {
|
||||
.ui32Direction = AM_HAL_UART_READ,
|
||||
.pui8Data = (uint8_t*)buf,
|
||||
.ui32NumBytes = len,
|
||||
.ui32TimeoutMs = 0,
|
||||
.pui32BytesTransferred = &ui32BytesRead,
|
||||
};
|
||||
am_hal_uart_transfer(pHandle, &sRead);
|
||||
return ui32BytesRead;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART write buffer
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_write(void *pHandle, char* buf, size_t len){
|
||||
uint32_t ui32BytesWritten = 0;
|
||||
const am_hal_uart_transfer_t sUartWrite =
|
||||
{
|
||||
.ui32Direction = AM_HAL_UART_WRITE,
|
||||
.pui8Data = (uint8_t*) buf,
|
||||
.ui32NumBytes = len,
|
||||
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
|
||||
.pui32BytesTransferred = &ui32BytesWritten,
|
||||
};
|
||||
|
||||
am_hal_uart_transfer(pHandle, &sUartWrite);
|
||||
|
||||
return ui32BytesWritten;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART write byte
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_write_byte(void *pHandle, uint8_t c){
|
||||
return svl_uart_write(pHandle, (char*)&c, 1);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART send string
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_print(void *pHandle, char* str){
|
||||
uint32_t ui32StrLen = 0;
|
||||
while (str[ui32StrLen] != 0){ ui32StrLen++; } // Measure the length of the string.
|
||||
return svl_uart_write( pHandle, str, ui32StrLen);
|
||||
|
||||
// uint16_t indi = 0;
|
||||
// while((*(debug_buffer+indi)!='\0') && (indi < DEBUG_UART_BUF_LEN)){
|
||||
// svl_uart_write(hUART_debug, debug_buffer+indi, 1);
|
||||
// indi++;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _SVL_UART_H_
|
||||
#define _SVL_UART_H_
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
|
||||
|
||||
size_t svl_uart_read (void *pHandle, char* buf, size_t len);
|
||||
size_t svl_uart_write (void *pHandle, char* buf, size_t len);
|
||||
size_t svl_uart_write_byte (void *pHandle, uint8_t c);
|
||||
size_t svl_uart_print (void *pHandle, char* str);
|
||||
|
||||
|
||||
#endif // _SVL_UART_H_
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "svl_utils.h"
|
||||
|
||||
#define AP3_STIMER_FREQ_HZ (3000000)
|
||||
#define AP3_STIMER_FREQ_KHZ (AP3_STIMER_FREQ_HZ / 1000)
|
||||
#define AP3_STIMER_FREQ_MHZ (AP3_STIMER_FREQ_HZ / 1000000)
|
||||
|
||||
volatile uint32_t ap3_stimer_overflows = 0x00;
|
||||
uint64_t ticks = 0;
|
||||
|
||||
void _fill_ticks(void)
|
||||
{
|
||||
ticks = ap3_stimer_overflows;
|
||||
ticks <<= 32;
|
||||
ticks |= (am_hal_stimer_counter_get() & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
size_t millis(void){
|
||||
_fill_ticks();
|
||||
return (uint32_t)(ticks / AP3_STIMER_FREQ_KHZ);
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Burst mode
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool enable_burst_mode(void)
|
||||
{
|
||||
// Check that the Burst Feature is available.
|
||||
am_hal_burst_avail_e eBurstModeAvailable;
|
||||
if (AM_HAL_STATUS_SUCCESS != am_hal_burst_mode_initialize(&eBurstModeAvailable))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Put the MCU into "Burst" mode.
|
||||
am_hal_burst_mode_e eBurstMode;
|
||||
if (AM_HAL_STATUS_SUCCESS != am_hal_burst_mode_enable(&eBurstMode))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
//Turns main processor from 96MHz to 48MHz
|
||||
//Returns false if disable fails
|
||||
bool disable_burst_mode(void)
|
||||
{
|
||||
am_hal_burst_mode_e eBurstMode;
|
||||
if (AM_HAL_STATUS_SUCCESS == am_hal_burst_mode_disable(&eBurstMode))
|
||||
{
|
||||
if (AM_HAL_NORMAL_MODE != eBurstMode)
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// Local defines. Copied from am_hal_gpio.c
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Generally define GPIO PADREG and GPIOCFG bitfields
|
||||
//
|
||||
#define PADREG_FLD_76_S 6
|
||||
#define PADREG_FLD_FNSEL_S 3
|
||||
#define PADREG_FLD_DRVSTR_S 2
|
||||
#define PADREG_FLD_INPEN_S 1
|
||||
#define PADREG_FLD_PULLUP_S 0
|
||||
|
||||
#define GPIOCFG_FLD_INTD_S 3
|
||||
#define GPIOCFG_FLD_OUTCFG_S 1
|
||||
#define GPIOCFG_FLD_INCFG_S 0
|
||||
|
||||
uint32_t ap3_gpio_enable_interrupts(uint32_t ui32Pin, uint32_t eIntDir){
|
||||
uint32_t ui32Padreg, ui32AltPadCfg, ui32GPCfg;
|
||||
bool bClearEnable = false;
|
||||
|
||||
|
||||
ui32GPCfg = ui32Padreg = ui32AltPadCfg = 0;
|
||||
ui32GPCfg |= (((eIntDir >> 0) & 0x1) << GPIOCFG_FLD_INTD_S) | (((eIntDir >> 1) & 0x1) << GPIOCFG_FLD_INCFG_S);
|
||||
|
||||
uint32_t ui32GPCfgAddr;
|
||||
uint32_t ui32GPCfgClearMask;
|
||||
uint32_t ui32GPCfgShft;
|
||||
|
||||
ui32GPCfgShft = ((ui32Pin & 0x7) << 2);
|
||||
|
||||
ui32GPCfgAddr = AM_REGADDR(GPIO, CFGA) + ((ui32Pin >> 1) & ~0x3);
|
||||
ui32GPCfgClearMask = ~((uint32_t)0xF << ui32GPCfgShft);
|
||||
|
||||
ui32GPCfg <<= ui32GPCfgShft;
|
||||
|
||||
AM_CRITICAL_BEGIN
|
||||
|
||||
if (bClearEnable)
|
||||
{
|
||||
am_hal_gpio_output_tristate_disable(ui32Pin);
|
||||
}
|
||||
|
||||
GPIO->PADKEY = GPIO_PADKEY_PADKEY_Key;
|
||||
|
||||
// Here's where the magic happens
|
||||
AM_REGVAL(ui32GPCfgAddr) = (AM_REGVAL(ui32GPCfgAddr) & ui32GPCfgClearMask) | ui32GPCfg;
|
||||
|
||||
GPIO->PADKEY = 0;
|
||||
|
||||
AM_CRITICAL_END
|
||||
|
||||
return AM_HAL_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _SVL_UTILS_H_
|
||||
#define _SVL_UTILS_H_
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
void _fill_ticks(void);
|
||||
size_t millis(void);
|
||||
bool enable_burst_mode(void);
|
||||
bool disable_burst_mode(void);
|
||||
uint32_t ap3_gpio_enable_interrupts(uint32_t ui32Pin, uint32_t eIntDir);
|
||||
|
||||
extern volatile uint32_t ap3_stimer_overflows;
|
||||
|
||||
#endif // _SVL_UTILS_H_
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
###### Requirements without Version Specifiers ######`
|
||||
pyinstaller == 3.6
|
||||
pyserial
|
||||
@@ -0,0 +1,421 @@
|
||||
#!/usr/bin/env python
|
||||
# SparkFun Variable Loader
|
||||
# Variable baud rate bootloader for Artemis Apollo3 modules
|
||||
|
||||
# Immediately upon reset the Artemis module will search for the timing character
|
||||
# to auto-detect the baud rate. If a valid baud rate is found the Artemis will
|
||||
# respond with the bootloader version packet
|
||||
# If the computer receives a well-formatted version number packet at the desired
|
||||
# baud rate it will send a command to begin bootloading. The Artemis shall then
|
||||
# respond with the a command asking for the next frame.
|
||||
# The host will then send a frame packet. If the CRC is OK the Artemis will write
|
||||
# that to memory and request the next frame. If the CRC fails the Artemis will
|
||||
# discard that data and send a request to re-send the previous frame.
|
||||
# This cycle repeats until the Artemis receives a done command in place of the
|
||||
# requested frame data command.
|
||||
# The initial baud rate determination must occur within some small timeout. Once
|
||||
# baud rate detection has completed all additional communication will have a
|
||||
# universal timeout value. Once the Artemis has begun requesting data it may no
|
||||
# no longer exit the bootloader. If the host detects a timeout at any point it
|
||||
# will stop bootloading.
|
||||
|
||||
# Notes about PySerial timeout:
|
||||
# The timeout operates on whole functions - that is to say that a call to
|
||||
# ser.read(10) will return after ser.timeout, just as will ser.read(1) (assuming
|
||||
# that the necessary bytes were not found)
|
||||
# If there are no incoming bytes (on the line or in the buffer) then two calls to
|
||||
# ser.read(n) will time out after 2*ser.timeout
|
||||
# Incoming UART data is buffered behind the scenes, probably by the OS.
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Imports
|
||||
#
|
||||
# ***********************************************************************************
|
||||
|
||||
import argparse
|
||||
import serial
|
||||
import serial.tools.list_ports as list_ports
|
||||
import sys
|
||||
import time
|
||||
import math
|
||||
import os.path
|
||||
from sys import exit
|
||||
|
||||
SCRIPT_VERSION_MAJOR = "1"
|
||||
SCRIPT_VERSION_MINOR = "7"
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Commands
|
||||
#
|
||||
# ***********************************************************************************
|
||||
SVL_CMD_VER = 0x01 # version
|
||||
SVL_CMD_BL = 0x02 # enter bootload mode
|
||||
SVL_CMD_NEXT = 0x03 # request next chunk
|
||||
SVL_CMD_FRAME = 0x04 # indicate app data frame
|
||||
SVL_CMD_RETRY = 0x05 # request re-send frame
|
||||
SVL_CMD_DONE = 0x06 # finished - all data sent
|
||||
|
||||
barWidthInCharacters = 50 # Width of progress bar, ie [###### % complete
|
||||
|
||||
crcTable = (
|
||||
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
|
||||
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
|
||||
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
|
||||
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
|
||||
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
|
||||
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
|
||||
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
|
||||
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
|
||||
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
|
||||
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
|
||||
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
|
||||
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
|
||||
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
|
||||
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
|
||||
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
|
||||
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
|
||||
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
|
||||
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
|
||||
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
|
||||
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202)
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Compute CRC on a byte array
|
||||
#
|
||||
# ***********************************************************************************
|
||||
|
||||
|
||||
def get_crc16(data):
|
||||
|
||||
# Table and code ported from Artemis SVL bootloader
|
||||
crc = 0x0000
|
||||
data = bytearray(data)
|
||||
for ch in data:
|
||||
tableAddr = ch ^ (crc >> 8)
|
||||
CRCH = (crcTable[tableAddr] >> 8) ^ (crc & 0xFF)
|
||||
CRCL = crcTable[tableAddr] & 0x00FF
|
||||
crc = CRCH << 8 | CRCL
|
||||
return crc
|
||||
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Wait for a packet
|
||||
#
|
||||
# ***********************************************************************************
|
||||
def wait_for_packet(ser):
|
||||
|
||||
packet = {'len': 0, 'cmd': 0, 'data': 0, 'crc': 1, 'timeout': 1}
|
||||
|
||||
n = ser.read(2) # get the number of bytes
|
||||
if(len(n) < 2):
|
||||
return packet
|
||||
|
||||
packet['len'] = int.from_bytes(n, byteorder='big', signed=False) #
|
||||
payload = ser.read(packet['len'])
|
||||
|
||||
if(len(payload) != packet['len']):
|
||||
return packet
|
||||
|
||||
# all bytes received, so timeout is not true
|
||||
packet['timeout'] = 0
|
||||
# cmd is the first byte of the payload
|
||||
packet['cmd'] = payload[0]
|
||||
# the data is the part of the payload that is not cmd or crc
|
||||
packet['data'] = payload[1:packet['len']-2]
|
||||
# performing the crc on the whole payload should return 0
|
||||
packet['crc'] = get_crc16(payload)
|
||||
|
||||
return packet
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Send a packet
|
||||
#
|
||||
# ***********************************************************************************
|
||||
|
||||
|
||||
def send_packet(ser, cmd, data):
|
||||
data = bytearray(data)
|
||||
num_bytes = 3 + len(data)
|
||||
payload = bytearray(cmd.to_bytes(1, 'big'))
|
||||
payload.extend(data)
|
||||
crc = get_crc16(payload)
|
||||
payload.extend(bytearray(crc.to_bytes(2, 'big')))
|
||||
|
||||
ser.write(num_bytes.to_bytes(2, 'big'))
|
||||
ser.write(bytes(payload))
|
||||
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Setup: signal baud rate, get version, and command BL enter
|
||||
#
|
||||
# ***********************************************************************************
|
||||
def phase_setup(ser):
|
||||
|
||||
baud_detect_byte = b'U'
|
||||
|
||||
verboseprint('\nPhase:\tSetup')
|
||||
|
||||
# Handle the serial startup blip
|
||||
ser.reset_input_buffer()
|
||||
verboseprint('\tCleared startup blip')
|
||||
|
||||
ser.write(baud_detect_byte) # send the baud detection character
|
||||
|
||||
packet = wait_for_packet(ser)
|
||||
if(packet['timeout'] or packet['crc']):
|
||||
return False # failed to enter bootloader
|
||||
|
||||
twopartprint('\t', 'Got SVL Bootloader Version: ' +
|
||||
str(int.from_bytes(packet['data'], 'big')))
|
||||
verboseprint('\tSending \'enter bootloader\' command')
|
||||
|
||||
send_packet(ser, SVL_CMD_BL, b'')
|
||||
|
||||
return True
|
||||
|
||||
# Now enter the bootload phase
|
||||
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Bootloader phase (Artemis is locked in)
|
||||
#
|
||||
# ***********************************************************************************
|
||||
def phase_bootload(ser):
|
||||
|
||||
startTime = time.time()
|
||||
frame_size = 512*4
|
||||
|
||||
resend_max = 4
|
||||
resend_count = 0
|
||||
|
||||
verboseprint('\nPhase:\tBootload')
|
||||
|
||||
with open(args.binfile, mode='rb') as binfile:
|
||||
application = binfile.read()
|
||||
total_len = len(application)
|
||||
|
||||
total_frames = math.ceil(total_len/frame_size)
|
||||
curr_frame = 0
|
||||
progressChars = 0
|
||||
|
||||
if (not args.verbose):
|
||||
print("[", end='')
|
||||
|
||||
verboseprint('\thave ' + str(total_len) +
|
||||
' bytes to send in ' + str(total_frames) + ' frames')
|
||||
|
||||
bl_done = False
|
||||
bl_succeeded = True
|
||||
while((bl_done == False) and (bl_succeeded == True)):
|
||||
|
||||
# wait for indication by Artemis
|
||||
packet = wait_for_packet(ser)
|
||||
if(packet['timeout'] or packet['crc']):
|
||||
verboseprint('\n\tError receiving packet')
|
||||
verboseprint(packet)
|
||||
verboseprint('\n')
|
||||
bl_succeeded = False
|
||||
bl_done = True
|
||||
|
||||
if(packet['cmd'] == SVL_CMD_NEXT):
|
||||
# verboseprint('\tgot frame request')
|
||||
curr_frame += 1
|
||||
resend_count = 0
|
||||
elif(packet['cmd'] == SVL_CMD_RETRY):
|
||||
verboseprint('\t\tRetrying...')
|
||||
resend_count += 1
|
||||
if(resend_count >= resend_max):
|
||||
bl_succeeded = False
|
||||
bl_done = True
|
||||
else:
|
||||
print('Timeout or unknown error')
|
||||
bl_succeeded = False
|
||||
bl_done = True
|
||||
|
||||
if(curr_frame <= total_frames):
|
||||
frame_data = application[(
|
||||
(curr_frame-1)*frame_size):((curr_frame-1+1)*frame_size)]
|
||||
if(args.verbose):
|
||||
verboseprint('\tSending frame #'+str(curr_frame) +
|
||||
', length: '+str(len(frame_data)))
|
||||
else:
|
||||
percentComplete = curr_frame * 100 / total_frames
|
||||
percentCompleteInChars = math.ceil(
|
||||
percentComplete / 100 * barWidthInCharacters)
|
||||
while(progressChars < percentCompleteInChars):
|
||||
progressChars = progressChars + 1
|
||||
print('#', end='', flush=True)
|
||||
if (percentComplete == 100):
|
||||
print("]", end='')
|
||||
|
||||
send_packet(ser, SVL_CMD_FRAME, frame_data)
|
||||
|
||||
else:
|
||||
send_packet(ser, SVL_CMD_DONE, b'')
|
||||
bl_done = True
|
||||
|
||||
if(bl_succeeded == True):
|
||||
twopartprint('\n\t', 'Upload complete')
|
||||
endTime = time.time()
|
||||
bps = total_len / (endTime - startTime)
|
||||
verboseprint('\n\tNominal bootload bps: ' + str(round(bps, 2)))
|
||||
else:
|
||||
twopartprint('\n\t', 'Upload failed')
|
||||
|
||||
return bl_succeeded
|
||||
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Help if serial port could not be opened
|
||||
#
|
||||
# ***********************************************************************************
|
||||
def phase_serial_port_help():
|
||||
devices = list_ports.comports()
|
||||
|
||||
# First check to see if user has the given port open
|
||||
for dev in devices:
|
||||
if(dev.device.upper() == args.port.upper()):
|
||||
print(dev.device + " is currently open. Please close any other terminal programs that may be using " +
|
||||
dev.device + " and try again.")
|
||||
exit()
|
||||
|
||||
# otherwise, give user a list of possible com ports
|
||||
print(args.port.upper() +
|
||||
" not found but we detected the following serial ports:")
|
||||
for dev in devices:
|
||||
if 'CH340' in dev.description:
|
||||
print(
|
||||
dev.description + ": Likely an Arduino or derivative. Try " + dev.device + ".")
|
||||
elif 'FTDI' in dev.description:
|
||||
print(
|
||||
dev.description + ": Likely an Arduino or derivative. Try " + dev.device + ".")
|
||||
elif 'USB Serial Device' in dev.description:
|
||||
print(
|
||||
dev.description + ": Possibly an Arduino or derivative.")
|
||||
else:
|
||||
print(dev.description)
|
||||
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Main function
|
||||
#
|
||||
# ***********************************************************************************
|
||||
def main():
|
||||
try:
|
||||
num_tries = 3
|
||||
|
||||
print('\n\nArtemis SVL Bootloader')
|
||||
|
||||
verboseprint("Script version " + SCRIPT_VERSION_MAJOR +
|
||||
"." + SCRIPT_VERSION_MINOR)
|
||||
|
||||
if not os.path.exists(args.binfile):
|
||||
print("Bin file {} does not exist.".format(args.binfile))
|
||||
exit()
|
||||
|
||||
bl_success = False
|
||||
entered_bootloader = False
|
||||
|
||||
for _ in range(num_tries):
|
||||
|
||||
with serial.Serial(args.port, args.baud, timeout=args.timeout) as ser:
|
||||
|
||||
# startup time for Artemis bootloader (experimentally determined - 0.095 sec min delay)
|
||||
t_su = 0.15
|
||||
|
||||
time.sleep(t_su) # Allow Artemis to come out of reset
|
||||
|
||||
# Perform baud rate negotiation
|
||||
entered_bootloader = phase_setup(ser)
|
||||
|
||||
if(entered_bootloader == True):
|
||||
bl_success = phase_bootload(ser)
|
||||
if(bl_success == True): # Bootload
|
||||
#print("Bootload complete!")
|
||||
break
|
||||
else:
|
||||
verboseprint("Failed to enter bootload phase")
|
||||
|
||||
if(bl_success == True):
|
||||
break
|
||||
|
||||
if(entered_bootloader == False):
|
||||
print(
|
||||
"Target failed to enter bootload mode. Verify the right COM port is selected and that your board has the SVL bootloader.")
|
||||
|
||||
except serial.SerialException:
|
||||
phase_serial_port_help()
|
||||
|
||||
exit()
|
||||
|
||||
|
||||
# ******************************************************************************
|
||||
#
|
||||
# Main program flow
|
||||
#
|
||||
# ******************************************************************************
|
||||
if __name__ == '__main__':
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='SparkFun Serial Bootloader for Artemis')
|
||||
|
||||
parser.add_argument('port', help='Serial COMx Port')
|
||||
|
||||
parser.add_argument('-b', dest='baud', default=115200, type=int,
|
||||
help='Baud Rate (default is 115200)')
|
||||
|
||||
parser.add_argument('-f', dest='binfile', default='',
|
||||
help='Binary file to program into the target device')
|
||||
|
||||
parser.add_argument("-v", "--verbose", default=0, help="Enable verbose output",
|
||||
action="store_true")
|
||||
|
||||
parser.add_argument("-t", "--timeout", default=0.50, help="Communication timeout in seconds (default 0.5)",
|
||||
type=float)
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("No port selected. Detected Serial Ports:")
|
||||
devices = list_ports.comports()
|
||||
for dev in devices:
|
||||
print(dev.description)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Create print function for verbose output if caller deems it: https://stackoverflow.com/questions/5980042/how-to-implement-the-verbose-or-v-option-into-a-script
|
||||
if args.verbose:
|
||||
def verboseprint(*args):
|
||||
# Print each argument separately so caller doesn't need to
|
||||
# stuff everything to be printed into a single string
|
||||
for arg in args:
|
||||
print(arg, end='', flush=True),
|
||||
print()
|
||||
else:
|
||||
verboseprint = lambda *a: None # do-nothing function
|
||||
|
||||
def twopartprint(verbosestr, printstr):
|
||||
if args.verbose:
|
||||
print(verbosestr, end='')
|
||||
|
||||
print(printstr)
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user