initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
Vendored
+161
@@ -0,0 +1,161 @@
|
||||
on:
|
||||
push:
|
||||
|
||||
name: generate executables
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
name: windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: repo
|
||||
uses: actions/checkout@v2.3.1
|
||||
with:
|
||||
path: asb
|
||||
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 asb
|
||||
git status
|
||||
git pull
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip --version
|
||||
pip install -r asb/requirements.txt
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
cd asb
|
||||
pyinstaller --onefile asb.py
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: copy
|
||||
run: |
|
||||
Remove-Item -Recurse -Force asb\dist\windows
|
||||
mkdir asb\dist\windows
|
||||
Move-Item -Path asb\dist\asb.exe -Destination asb\dist\windows\asb.exe
|
||||
|
||||
- name: commit
|
||||
run: |
|
||||
cd asb
|
||||
git add dist\windows\*
|
||||
git commit -m "generated windows executable"
|
||||
git push
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
linux:
|
||||
name: linux
|
||||
needs: windows
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: repo
|
||||
uses: actions/checkout@v2.3.1
|
||||
with:
|
||||
path: asb
|
||||
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 asb
|
||||
git pull
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip --version
|
||||
pip install -r asb/requirements.txt
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
cd asb
|
||||
pyinstaller --onefile asb.py
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: copy
|
||||
run: |
|
||||
rm -rf ./asb/dist/linux
|
||||
mkdir -p ./asb/dist/linux
|
||||
mv ./asb/dist/asb ./asb/dist/linux/asb
|
||||
|
||||
- name: commit
|
||||
run: |
|
||||
cd ./asb
|
||||
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: asb
|
||||
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 asb
|
||||
git pull
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: install
|
||||
run: |
|
||||
python --version
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip --version
|
||||
pip install -r asb/requirements.txt
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
cd asb
|
||||
pyinstaller --onefile asb.py
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: copy
|
||||
run: |
|
||||
rm -rf ./asb/dist/macosx
|
||||
mkdir -p ./asb/dist/macosx
|
||||
mv ./asb/dist/asb ./asb/dist/macosx/asb
|
||||
|
||||
- name: commit
|
||||
run: |
|
||||
cd ./asb
|
||||
git add ./dist/macosx/*
|
||||
git commit -m "generated macosx executable"
|
||||
git push
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
@@ -0,0 +1,127 @@
|
||||
# macosx
|
||||
.DS_Store
|
||||
|
||||
# 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,3 @@
|
||||

|
||||
|
||||
# Apollo3 Uploader - Ambiq Secure Bootloader (SVL)
|
||||
@@ -0,0 +1,527 @@
|
||||
#!/usr/bin/env python3
|
||||
# Utility functioins
|
||||
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Signature import PKCS1_v1_5
|
||||
from Crypto.Hash import SHA256
|
||||
import array
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import binascii
|
||||
|
||||
|
||||
ivVal0 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
|
||||
FLASH_PAGE_SIZE = 0x2000 # 8K
|
||||
MAX_DOWNLOAD_SIZE = 0x48000 # 288K
|
||||
AM_SECBOOT_DEFAULT_NONSECURE_MAIN = 0xC000
|
||||
|
||||
AM_SECBOOT_AESCBC_BLOCK_SIZE_WORDS = 4
|
||||
AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES = 4*AM_SECBOOT_AESCBC_BLOCK_SIZE_WORDS
|
||||
|
||||
AM_SECBOOT_MIN_KEYIDX_INFO0 = 8 ## KeyIdx 8 - 15
|
||||
AM_SECBOOT_MAX_KEYIDX_INFO0 = 15
|
||||
AM_SECBOOT_MIN_KEYIDX_INFO1 = 0 ## KeyIdx 0 - 7
|
||||
AM_SECBOOT_MAX_KEYIDX_INFO1 = 7
|
||||
AM_SECBOOT_KEYIDX_BYTES = 16
|
||||
|
||||
# Encryption Algorithm
|
||||
AM_SECBOOT_ENC_ALGO_NONE = 0
|
||||
AM_SECBOOT_ENC_ALGO_AES128 = 1
|
||||
AM_SECBOOT_ENC_ALGO_MAX = AM_SECBOOT_ENC_ALGO_AES128
|
||||
# String constants
|
||||
helpEncAlgo = 'Encryption Algo? (0(default) = none, 1 = AES128)'
|
||||
|
||||
# Authentication Algorithm
|
||||
AM_SECBOOT_AUTH_ALGO_NONE = 0
|
||||
AM_SECBOOT_AUTH_ALGO_SHA256HMAC = 1
|
||||
AM_SECBOOT_AUTH_ALGO_MAX = AM_SECBOOT_AUTH_ALGO_SHA256HMAC
|
||||
# String constants
|
||||
helpAuthAlgo = 'Authentication Algo? (0(default) = none, 1 = SHA256)'
|
||||
|
||||
|
||||
FLASH_INVALID = 0xFFFFFFFF
|
||||
|
||||
# KeyWrap Mode
|
||||
AM_SECBOOT_KEYWRAP_NONE = 0
|
||||
AM_SECBOOT_KEYWRAP_XOR = 1
|
||||
AM_SECBOOT_KEYWRAP_AES128 = 2
|
||||
AM_SECBOOT_KEYWRAP_MAX = AM_SECBOOT_KEYWRAP_AES128
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Magic Numbers
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_IMAGE_MAGIC_MAIN = 0xC0
|
||||
AM_IMAGE_MAGIC_CHILD = 0xCC
|
||||
AM_IMAGE_MAGIC_NONSECURE = 0xCB
|
||||
AM_IMAGE_MAGIC_INFO0 = 0xCF
|
||||
|
||||
# Dummy for creating images for customer - not understood by SBL
|
||||
# This could be any value from the definition:
|
||||
# #define AM_IMAGE_MAGIC_CUST(x) ((((x) & 0xF0) == 0xC0) && ((x) != 0xC0) && ((x) != 0xCC) && ((x) != 0xCB) && ((x) != 0xCF))
|
||||
AM_IMAGE_MAGIC_CUSTPATCH = 0xC1
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Image Types
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_SBL = 0
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_AM3P = 1
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_PATCH = 2
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_MAIN = 3
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_CHILD = 4
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH = 5
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE = 6
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_INFO0 = 7
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA = 32
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_INVALID = 0xFF
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Wired Message Types
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_WIRED_MSGTYPE_HELLO = 0
|
||||
AM_SECBOOT_WIRED_MSGTYPE_STATUS = 1
|
||||
AM_SECBOOT_WIRED_MSGTYPE_OTADESC = 2
|
||||
AM_SECBOOT_WIRED_MSGTYPE_UPDATE = 3
|
||||
AM_SECBOOT_WIRED_MSGTYPE_ABORT = 4
|
||||
AM_SECBOOT_WIRED_MSGTYPE_RECOVER = 5
|
||||
AM_SECBOOT_WIRED_MSGTYPE_RESET = 6
|
||||
AM_SECBOOT_WIRED_MSGTYPE_ACK = 7
|
||||
AM_SECBOOT_WIRED_MSGTYPE_DATA = 8
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Wired Message ACK Status
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_SUCCESS = 0
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_FAILURE = 1
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_INFO0 = 2
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_CRC = 3
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_SEC = 4
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_MSG_TOO_BIG = 5
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_UNKNOWN_MSGTYPE = 6
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_ADDR = 7
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_OPERATION = 8
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_PARAM = 9
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_SEQ = 10
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_TOO_MUCH_DATA = 11
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Definitions related to Image Headers
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_HMAC_SIG_SIZE = 32
|
||||
AM_KEK_SIZE = 16
|
||||
AM_CRC_SIZE = 4
|
||||
|
||||
AM_MAX_UART_MSG_SIZE = 8192 # 8K buffer in SBL
|
||||
|
||||
# Wiredupdate Image Header
|
||||
AM_WU_IMAGEHDR_OFFSET_SIG = 16
|
||||
AM_WU_IMAGEHDR_OFFSET_IV = 48
|
||||
AM_WU_IMAGEHDR_OFFSET_KEK = 64
|
||||
AM_WU_IMAGEHDR_OFFSET_IMAGETYPE = (AM_WU_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_WU_IMAGEHDR_OFFSET_OPTIONS = (AM_WU_IMAGEHDR_OFFSET_IMAGETYPE + 1)
|
||||
AM_WU_IMAGEHDR_OFFSET_KEY = (AM_WU_IMAGEHDR_OFFSET_IMAGETYPE + 4)
|
||||
AM_WU_IMAGEHDR_OFFSET_ADDR = (AM_WU_IMAGEHDR_OFFSET_KEY + 4)
|
||||
AM_WU_IMAGEHDR_OFFSET_SIZE = (AM_WU_IMAGEHDR_OFFSET_ADDR + 4)
|
||||
|
||||
AM_WU_IMAGEHDR_START_HMAC = (AM_WU_IMAGEHDR_OFFSET_SIG + AM_HMAC_SIG_SIZE)
|
||||
AM_WU_IMAGEHDR_START_ENCRYPT = (AM_WU_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_WU_IMAGEHDR_SIZE = (AM_WU_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE + 16)
|
||||
|
||||
|
||||
# Image Header
|
||||
AM_IMAGEHDR_SIZE_MAIN = 256
|
||||
AM_IMAGEHDR_SIZE_AUX = (112 + AM_KEK_SIZE)
|
||||
|
||||
AM_IMAGEHDR_OFFSET_CRC = 4
|
||||
AM_IMAGEHDR_OFFSET_SIG = 16
|
||||
AM_IMAGEHDR_OFFSET_IV = 48
|
||||
AM_IMAGEHDR_OFFSET_KEK = 64
|
||||
AM_IMAGEHDR_OFFSET_SIGCLR = (AM_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_IMAGEHDR_START_CRC = (AM_IMAGEHDR_OFFSET_CRC + AM_CRC_SIZE)
|
||||
AM_IMAGEHDR_START_HMAC_INST = (AM_IMAGEHDR_OFFSET_SIG + AM_HMAC_SIG_SIZE)
|
||||
AM_IMAGEHDR_START_ENCRYPT = (AM_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_IMAGEHDR_START_HMAC = (AM_IMAGEHDR_OFFSET_SIGCLR + AM_HMAC_SIG_SIZE)
|
||||
AM_IMAGEHDR_OFFSET_ADDR = AM_IMAGEHDR_START_HMAC
|
||||
AM_IMAGEHDR_OFFSET_VERKEY = (AM_IMAGEHDR_OFFSET_ADDR + 4)
|
||||
AM_IMAGEHDR_OFFSET_CHILDPTR = (AM_IMAGEHDR_OFFSET_VERKEY + 4)
|
||||
|
||||
# Recover message
|
||||
AM_WU_RECOVERY_HDR_SIZE = 44
|
||||
AM_WU_RECOVERY_HDR_OFFSET_CUSTID = 8
|
||||
AM_WU_RECOVERY_HDR_OFFSET_RECKEY = (AM_WU_RECOVERY_HDR_OFFSET_CUSTID + 4)
|
||||
AM_WU_RECOVERY_HDR_OFFSET_NONCE = (AM_WU_RECOVERY_HDR_OFFSET_RECKEY + 16)
|
||||
AM_WU_RECOVERY_HDR_OFFSET_RECBLOB = (AM_WU_RECOVERY_HDR_OFFSET_NONCE + 16)
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# INFOSPACE related definitions
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED0 = 0x48EAAD88
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED1 = 0xC9705737
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED2 = 0x0A6B8458
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED3 = 0xE41A9D74
|
||||
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT0 = 0x5B75A5FA
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT1 = 0x7B9C8674
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT2 = 0x869A96FE
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT3 = 0xAEC90860
|
||||
|
||||
INFO_SIZE_BYTES = (8 * 1024)
|
||||
INFO_MAX_AUTH_KEY_WORDS = 32
|
||||
INFO_MAX_ENC_KEY_WORDS = 32
|
||||
|
||||
INFO_MAX_AUTH_KEYS = (INFO_MAX_AUTH_KEY_WORDS*4//AM_SECBOOT_KEYIDX_BYTES)
|
||||
INFO_MAX_ENC_KEYS = (INFO_MAX_ENC_KEY_WORDS*4//AM_SECBOOT_KEYIDX_BYTES)
|
||||
|
||||
INFO0_SIGNATURE0_O = 0x00000000
|
||||
INFO0_SIGNATURE1_O = 0x00000004
|
||||
INFO0_SIGNATURE2_O = 0x00000008
|
||||
INFO0_SIGNATURE3_O = 0x0000000c
|
||||
INFO0_SECURITY_O = 0x00000010
|
||||
INFO0_CUSTOMER_TRIM_O = 0x00000014
|
||||
INFO0_CUSTOMER_TRIM2_O = 0x00000018
|
||||
INFO0_SECURITY_OVR_O = 0x00000020
|
||||
INFO0_SECURITY_WIRED_CFG_O = 0x00000024
|
||||
INFO0_SECURITY_WIRED_IFC_CFG0_O = 0x00000028
|
||||
INFO0_SECURITY_WIRED_IFC_CFG1_O = 0x0000002C
|
||||
INFO0_SECURITY_WIRED_IFC_CFG2_O = 0x00000030
|
||||
INFO0_SECURITY_WIRED_IFC_CFG3_O = 0x00000034
|
||||
INFO0_SECURITY_WIRED_IFC_CFG4_O = 0x00000038
|
||||
INFO0_SECURITY_WIRED_IFC_CFG5_O = 0x0000003C
|
||||
INFO0_SECURITY_VERSION_O = 0x00000040
|
||||
INFO0_SECURITY_SRAM_RESV_O = 0x00000050
|
||||
AM_REG_INFO0_SECURITY_SRAM_RESV_SRAM_RESV_M = 0x0000FFFF
|
||||
INFO0_WRITE_PROTECT_L_O = 0x000001f8
|
||||
INFO0_WRITE_PROTECT_H_O = 0x000001fc
|
||||
INFO0_COPY_PROTECT_L_O = 0x00000200
|
||||
INFO0_COPY_PROTECT_H_O = 0x00000204
|
||||
INFO0_WRITE_PROTECT_SBL_L_O = 0x000009f8
|
||||
INFO0_WRITE_PROTECT_SBL_H_O = 0x000009fc
|
||||
INFO0_COPY_PROTECT_SBL_L_O = 0x00000A00
|
||||
INFO0_COPY_PROTECT_SBL_H_O = 0x00000A04
|
||||
INFO0_MAIN_PTR1_O = 0x00000C00
|
||||
INFO0_MAIN_PTR2_O = 0x00000C04
|
||||
INFO0_KREVTRACK_O = 0x00000C08
|
||||
INFO0_AREVTRACK_O = 0x00000C0C
|
||||
INFO0_MAIN_CNT0_O = 0x00000FF8
|
||||
INFO0_MAIN_CNT1_O = 0x00000FFC
|
||||
|
||||
INFO0_CUST_KEK_W0_O = 0x00001800
|
||||
INFO0_CUST_KEK_W1_O = 0x00001804
|
||||
INFO0_CUST_KEK_W2_O = 0x00001808
|
||||
INFO0_CUST_KEK_W3_O = 0x0000180c
|
||||
INFO0_CUST_KEK_W4_O = 0x00001810
|
||||
INFO0_CUST_KEK_W5_O = 0x00001814
|
||||
INFO0_CUST_KEK_W6_O = 0x00001818
|
||||
INFO0_CUST_KEK_W7_O = 0x0000181c
|
||||
INFO0_CUST_KEK_W8_O = 0x00001820
|
||||
INFO0_CUST_KEK_W9_O = 0x00001824
|
||||
INFO0_CUST_KEK_W10_O = 0x00001828
|
||||
INFO0_CUST_KEK_W11_O = 0x0000182c
|
||||
INFO0_CUST_KEK_W12_O = 0x00001830
|
||||
INFO0_CUST_KEK_W13_O = 0x00001834
|
||||
INFO0_CUST_KEK_W14_O = 0x00001838
|
||||
INFO0_CUST_KEK_W15_O = 0x0000183c
|
||||
INFO0_CUST_KEK_W16_O = 0x00001840
|
||||
INFO0_CUST_KEK_W17_O = 0x00001844
|
||||
INFO0_CUST_KEK_W18_O = 0x00001848
|
||||
INFO0_CUST_KEK_W19_O = 0x0000184c
|
||||
INFO0_CUST_KEK_W20_O = 0x00001850
|
||||
INFO0_CUST_KEK_W21_O = 0x00001854
|
||||
INFO0_CUST_KEK_W22_O = 0x00001858
|
||||
INFO0_CUST_KEK_W23_O = 0x0000185c
|
||||
INFO0_CUST_KEK_W24_O = 0x00001860
|
||||
INFO0_CUST_KEK_W25_O = 0x00001864
|
||||
INFO0_CUST_KEK_W26_O = 0x00001868
|
||||
INFO0_CUST_KEK_W27_O = 0x0000186c
|
||||
INFO0_CUST_KEK_W28_O = 0x00001870
|
||||
INFO0_CUST_KEK_W29_O = 0x00001874
|
||||
INFO0_CUST_KEK_W30_O = 0x00001878
|
||||
INFO0_CUST_KEK_W31_O = 0x0000187c
|
||||
INFO0_CUST_AUTH_W0_O = 0x00001880
|
||||
INFO0_CUST_AUTH_W1_O = 0x00001884
|
||||
INFO0_CUST_AUTH_W2_O = 0x00001888
|
||||
INFO0_CUST_AUTH_W3_O = 0x0000188c
|
||||
INFO0_CUST_AUTH_W4_O = 0x00001890
|
||||
INFO0_CUST_AUTH_W5_O = 0x00001894
|
||||
INFO0_CUST_AUTH_W6_O = 0x00001898
|
||||
INFO0_CUST_AUTH_W7_O = 0x0000189c
|
||||
INFO0_CUST_AUTH_W8_O = 0x000018a0
|
||||
INFO0_CUST_AUTH_W9_O = 0x000018a4
|
||||
INFO0_CUST_AUTH_W10_O = 0x000018a8
|
||||
INFO0_CUST_AUTH_W11_O = 0x000018ac
|
||||
INFO0_CUST_AUTH_W12_O = 0x000018b0
|
||||
INFO0_CUST_AUTH_W13_O = 0x000018b4
|
||||
INFO0_CUST_AUTH_W14_O = 0x000018b8
|
||||
INFO0_CUST_AUTH_W15_O = 0x000018bc
|
||||
INFO0_CUST_AUTH_W16_O = 0x000018c0
|
||||
INFO0_CUST_AUTH_W17_O = 0x000018c4
|
||||
INFO0_CUST_AUTH_W18_O = 0x000018c8
|
||||
INFO0_CUST_AUTH_W19_O = 0x000018cc
|
||||
INFO0_CUST_AUTH_W20_O = 0x000018d0
|
||||
INFO0_CUST_AUTH_W21_O = 0x000018d4
|
||||
INFO0_CUST_AUTH_W22_O = 0x000018d8
|
||||
INFO0_CUST_AUTH_W23_O = 0x000018dc
|
||||
INFO0_CUST_AUTH_W24_O = 0x000018e0
|
||||
INFO0_CUST_AUTH_W25_O = 0x000018e4
|
||||
INFO0_CUST_AUTH_W26_O = 0x000018e8
|
||||
INFO0_CUST_AUTH_W27_O = 0x000018ec
|
||||
INFO0_CUST_AUTH_W28_O = 0x000018f0
|
||||
INFO0_CUST_AUTH_W29_O = 0x000018f4
|
||||
INFO0_CUST_AUTH_W30_O = 0x000018f8
|
||||
INFO0_CUST_AUTH_W31_O = 0x000018fc
|
||||
INFO0_CUST_PUBKEY_W0_O = 0x00001900
|
||||
INFO0_CUST_PUBKEY_W1_O = 0x00001904
|
||||
INFO0_CUST_PUBKEY_W2_O = 0x00001908
|
||||
INFO0_CUST_PUBKEY_W3_O = 0x0000190c
|
||||
INFO0_CUST_PUBKEY_W4_O = 0x00001910
|
||||
INFO0_CUST_PUBKEY_W5_O = 0x00001914
|
||||
INFO0_CUST_PUBKEY_W6_O = 0x00001918
|
||||
INFO0_CUST_PUBKEY_W7_O = 0x0000191c
|
||||
INFO0_CUST_PUBKEY_W8_O = 0x00001920
|
||||
INFO0_CUST_PUBKEY_W9_O = 0x00001924
|
||||
INFO0_CUST_PUBKEY_W10_O = 0x00001928
|
||||
INFO0_CUST_PUBKEY_W11_O = 0x0000192c
|
||||
INFO0_CUST_PUBKEY_W12_O = 0x00001930
|
||||
INFO0_CUST_PUBKEY_W13_O = 0x00001934
|
||||
INFO0_CUST_PUBKEY_W14_O = 0x00001938
|
||||
INFO0_CUST_PUBKEY_W15_O = 0x0000193c
|
||||
INFO0_CUST_PUBKEY_W16_O = 0x00001940
|
||||
INFO0_CUST_PUBKEY_W17_O = 0x00001944
|
||||
INFO0_CUST_PUBKEY_W18_O = 0x00001948
|
||||
INFO0_CUST_PUBKEY_W19_O = 0x0000194c
|
||||
INFO0_CUST_PUBKEY_W20_O = 0x00001950
|
||||
INFO0_CUST_PUBKEY_W21_O = 0x00001954
|
||||
INFO0_CUST_PUBKEY_W22_O = 0x00001958
|
||||
INFO0_CUST_PUBKEY_W23_O = 0x0000195c
|
||||
INFO0_CUST_PUBKEY_W24_O = 0x00001960
|
||||
INFO0_CUST_PUBKEY_W25_O = 0x00001964
|
||||
INFO0_CUST_PUBKEY_W26_O = 0x00001968
|
||||
INFO0_CUST_PUBKEY_W27_O = 0x0000196c
|
||||
INFO0_CUST_PUBKEY_W28_O = 0x00001970
|
||||
INFO0_CUST_PUBKEY_W29_O = 0x00001974
|
||||
INFO0_CUST_PUBKEY_W30_O = 0x00001978
|
||||
INFO0_CUST_PUBKEY_W31_O = 0x0000197c
|
||||
INFO0_CUST_PUBKEY_W32_O = 0x00001980
|
||||
INFO0_CUST_PUBKEY_W33_O = 0x00001984
|
||||
INFO0_CUST_PUBKEY_W34_O = 0x00001988
|
||||
INFO0_CUST_PUBKEY_W35_O = 0x0000198c
|
||||
INFO0_CUST_PUBKEY_W36_O = 0x00001990
|
||||
INFO0_CUST_PUBKEY_W37_O = 0x00001994
|
||||
INFO0_CUST_PUBKEY_W38_O = 0x00001998
|
||||
INFO0_CUST_PUBKEY_W39_O = 0x0000199c
|
||||
INFO0_CUST_PUBKEY_W40_O = 0x000019a0
|
||||
INFO0_CUST_PUBKEY_W41_O = 0x000019a4
|
||||
INFO0_CUST_PUBKEY_W42_O = 0x000019a8
|
||||
INFO0_CUST_PUBKEY_W43_O = 0x000019ac
|
||||
INFO0_CUST_PUBKEY_W44_O = 0x000019b0
|
||||
INFO0_CUST_PUBKEY_W45_O = 0x000019b4
|
||||
INFO0_CUST_PUBKEY_W46_O = 0x000019b8
|
||||
INFO0_CUST_PUBKEY_W47_O = 0x000019bc
|
||||
INFO0_CUST_PUBKEY_W48_O = 0x000019c0
|
||||
INFO0_CUST_PUBKEY_W49_O = 0x000019c4
|
||||
INFO0_CUST_PUBKEY_W50_O = 0x000019c8
|
||||
INFO0_CUST_PUBKEY_W51_O = 0x000019cc
|
||||
INFO0_CUST_PUBKEY_W52_O = 0x000019d0
|
||||
INFO0_CUST_PUBKEY_W53_O = 0x000019d4
|
||||
INFO0_CUST_PUBKEY_W54_O = 0x000019d8
|
||||
INFO0_CUST_PUBKEY_W55_O = 0x000019dc
|
||||
INFO0_CUST_PUBKEY_W56_O = 0x000019e0
|
||||
INFO0_CUST_PUBKEY_W57_O = 0x000019e4
|
||||
INFO0_CUST_PUBKEY_W58_O = 0x000019e8
|
||||
INFO0_CUST_PUBKEY_W59_O = 0x000019ec
|
||||
INFO0_CUST_PUBKEY_W60_O = 0x000019f0
|
||||
INFO0_CUST_PUBKEY_W61_O = 0x000019f4
|
||||
INFO0_CUST_PUBKEY_W62_O = 0x000019f8
|
||||
INFO0_CUST_PUBKEY_W63_O = 0x000019fc
|
||||
INFO0_CUSTOMER_KEY0_O = 0x00001a00
|
||||
INFO0_CUSTOMER_KEY1_O = 0x00001a04
|
||||
INFO0_CUSTOMER_KEY2_O = 0x00001a08
|
||||
INFO0_CUSTOMER_KEY3_O = 0x00001a0c
|
||||
INFO0_CUST_PUBHASH_W0_O = 0x00001a10
|
||||
INFO0_CUST_PUBHASH_W1_O = 0x00001a14
|
||||
INFO0_CUST_PUBHASH_W2_O = 0x00001a18
|
||||
INFO0_CUST_PUBHASH_W3_O = 0x00001a1c
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC using ethernet poly, as used by Corvette hardware for validation
|
||||
#
|
||||
#******************************************************************************
|
||||
def crc32(L):
|
||||
return (binascii.crc32(L) & 0xFFFFFFFF)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Pad the text to the block_size. bZeroPad determines how to handle text which
|
||||
# is already multiple of block_size
|
||||
#
|
||||
#******************************************************************************
|
||||
def pad_to_block_size(text, block_size, bZeroPad):
|
||||
text_length = len(text)
|
||||
amount_to_pad = block_size - (text_length % block_size)
|
||||
if (amount_to_pad == block_size):
|
||||
if (bZeroPad == 0):
|
||||
amount_to_pad = 0
|
||||
for i in range(0, amount_to_pad, 1):
|
||||
text += bytes(chr(amount_to_pad), 'ascii')
|
||||
return text
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# AES CBC encryption
|
||||
#
|
||||
#******************************************************************************
|
||||
def encrypt_app_aes(cleartext, encKey, iv):
|
||||
key = array.array('B', encKey).tostring()
|
||||
ivVal = array.array('B', iv).tostring()
|
||||
plaintext = array.array('B', cleartext).tostring()
|
||||
|
||||
encryption_suite = AES.new(key, AES.MODE_CBC, ivVal)
|
||||
cipher_text = encryption_suite.encrypt(plaintext)
|
||||
|
||||
return cipher_text
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# AES 128 CBC encryption
|
||||
#
|
||||
#******************************************************************************
|
||||
def encrypt_app_aes128(cleartext, encKey, iv):
|
||||
key = array.array('B', encKey).tostring()
|
||||
ivVal = array.array('B', iv).tostring()
|
||||
plaintext = array.array('B', cleartext).tostring()
|
||||
|
||||
encryption_suite = AES.new(key, AES.MODE_CBC, ivVal)
|
||||
cipher_text = encryption_suite.encrypt(plaintext)
|
||||
|
||||
return cipher_text
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# SHA256 HMAC
|
||||
#
|
||||
#******************************************************************************
|
||||
def compute_hmac(key, data):
|
||||
sig = hmac.new(array.array('B', key).tostring(), array.array('B', data).tostring(), hashlib.sha256).digest()
|
||||
return sig
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# RSA PKCS1_v1_5 sign
|
||||
#
|
||||
#******************************************************************************
|
||||
def compute_rsa_sign(prvKeyFile, data):
|
||||
key = open(prvKeyFile, "r").read()
|
||||
rsakey = RSA.importKey(key)
|
||||
signer = PKCS1_v1_5.new(rsakey)
|
||||
digest = SHA256.new()
|
||||
digest.update(bytes(data))
|
||||
sign = signer.sign(digest)
|
||||
return sign
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# RSA PKCS1_v1_5 sign verification
|
||||
#
|
||||
#******************************************************************************
|
||||
def verify_rsa_sign(pubKeyFile, data, sign):
|
||||
key = open(pubKeyFile, "r").read()
|
||||
rsakey = RSA.importKey(key)
|
||||
#print(hex(rsakey.n))
|
||||
verifier = PKCS1_v1_5.new(rsakey)
|
||||
digest = SHA256.new()
|
||||
digest.update(bytes(data))
|
||||
return verifier.verify(digest, sign)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Fill one word in bytearray
|
||||
#
|
||||
#******************************************************************************
|
||||
def fill_word(barray, offset, w):
|
||||
barray[offset + 0] = (w >> 0) & 0x000000ff;
|
||||
barray[offset + 1] = (w >> 8) & 0x000000ff;
|
||||
barray[offset + 2] = (w >> 16) & 0x000000ff;
|
||||
barray[offset + 3] = (w >> 24) & 0x000000ff;
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Turn a 32-bit number into a series of bytes for transmission.
|
||||
#
|
||||
# This command will split a 32-bit integer into an array of bytes, ordered
|
||||
# LSB-first for transmission over the UART.
|
||||
#
|
||||
#******************************************************************************
|
||||
def int_to_bytes(n):
|
||||
A = [n & 0xFF,
|
||||
(n >> 8) & 0xFF,
|
||||
(n >> 16) & 0xFF,
|
||||
(n >> 24) & 0xFF]
|
||||
|
||||
return A
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Extract a word from a byte array
|
||||
#
|
||||
#******************************************************************************
|
||||
def word_from_bytes(B, n):
|
||||
return (B[n] + (B[n + 1] << 8) + (B[n + 2] << 16) + (B[n + 3] << 24))
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# automatically figure out the integer format (base 10 or 16)
|
||||
#
|
||||
#******************************************************************************
|
||||
def auto_int(x):
|
||||
return int(x, 0)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# User controllable Prints control
|
||||
#
|
||||
#******************************************************************************
|
||||
# Defined print levels
|
||||
AM_PRINT_LEVEL_MIN = 0
|
||||
AM_PRINT_LEVEL_NONE = AM_PRINT_LEVEL_MIN
|
||||
AM_PRINT_LEVEL_ERROR = 1
|
||||
AM_PRINT_LEVEL_INFO = 2
|
||||
AM_PRINT_LEVEL_VERBOSE = 4
|
||||
AM_PRINT_LEVEL_DEBUG = 5
|
||||
AM_PRINT_LEVEL_MAX = AM_PRINT_LEVEL_DEBUG
|
||||
|
||||
# Global variable to control the prints
|
||||
AM_PRINT_VERBOSITY = AM_PRINT_LEVEL_INFO
|
||||
|
||||
helpPrintLevel = 'Set Log Level (0: None), (1: Error), (2: INFO), (4: Verbose), (5: Debug) [Default = Info]'
|
||||
|
||||
def am_set_print_level(level):
|
||||
global AM_PRINT_VERBOSITY
|
||||
AM_PRINT_VERBOSITY = level
|
||||
|
||||
def am_print(*args, level=AM_PRINT_LEVEL_INFO, **kwargs):
|
||||
global AM_PRINT_VERBOSITY
|
||||
if (AM_PRINT_VERBOSITY >= level):
|
||||
print(*args, **kwargs)
|
||||
@@ -0,0 +1,899 @@
|
||||
#!/usr/bin/env python3
|
||||
# Combination of the three steps to take an 'application.bin' file and run it on a SparkFun Artemis module
|
||||
|
||||
# Information:
|
||||
# This script performs the three main tasks:
|
||||
# 1. Convert 'application.bin' to an OTA update blob
|
||||
# 2. Convert the OTA blob into a wired update blob
|
||||
# 3. Push the wired update blob into the Artemis module
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
import array
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import binascii
|
||||
import serial
|
||||
import serial.tools.list_ports as list_ports
|
||||
import time
|
||||
# from sf_am_defines import *
|
||||
from sys import exit
|
||||
|
||||
from am_defines import *
|
||||
from keys_info import keyTblAes, keyTblHmac, minAesKeyIdx, maxAesKeyIdx, minHmacKeyIdx, maxHmacKeyIdx, INFO_KEY, FLASH_KEY
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Global Variables
|
||||
#
|
||||
#******************************************************************************
|
||||
loadTries = 0 #If we fail, try again. Tracks the number of tries we've attempted
|
||||
loadSuccess = False
|
||||
blob2wiredfile = ''
|
||||
uploadbinfile = ''
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Generate the image blob as per command line parameters
|
||||
#
|
||||
#******************************************************************************
|
||||
def bin2blob_process(loadaddress, appFile, magicNum, crcI, crcB, authI, authB, protection, authKeyIdx, output, encKeyIdx, version, erasePrev, child0, child1, authalgo, encalgo):
|
||||
|
||||
global blob2wiredfile
|
||||
|
||||
app_binarray = bytearray()
|
||||
# Open the file, and read it into an array of integers.
|
||||
with appFile as f_app:
|
||||
app_binarray.extend(f_app.read())
|
||||
f_app.close()
|
||||
|
||||
encVal = 0
|
||||
if (encalgo != 0):
|
||||
encVal = 1
|
||||
if ((encKeyIdx < minAesKeyIdx) or (encKeyIdx > maxAesKeyIdx)):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
if (encalgo == 2):
|
||||
if (encKeyIdx & 0x1):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
keySize = 32
|
||||
else:
|
||||
keySize = 16
|
||||
if (authalgo != 0):
|
||||
if ((authKeyIdx < minHmacKeyIdx) or (authKeyIdx > maxHmacKeyIdx) or (authKeyIdx & 0x1)):
|
||||
am_print("Invalid authKey Idx ", authKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
|
||||
if (magicNum == AM_IMAGE_MAGIC_MAIN):
|
||||
hdr_length = AM_IMAGEHDR_SIZE_MAIN; #fixed header length
|
||||
elif ((magicNum == AM_IMAGE_MAGIC_CHILD) or (magicNum == AM_IMAGE_MAGIC_CUSTPATCH) or (magicNum == AM_IMAGE_MAGIC_NONSECURE) or (magicNum == AM_IMAGE_MAGIC_INFO0)):
|
||||
hdr_length = AM_IMAGEHDR_SIZE_AUX; #fixed header length
|
||||
else:
|
||||
am_print("magic number", hex(magicNum), " not supported", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
am_print("Header Size = ", hex(hdr_length))
|
||||
|
||||
#generate mutable byte array for the header
|
||||
hdr_binarray = bytearray([0x00]*hdr_length);
|
||||
|
||||
orig_app_length = (len(app_binarray))
|
||||
am_print("original app_size ",hex(orig_app_length), "(",orig_app_length,")")
|
||||
|
||||
am_print("load_address ",hex(loadaddress), "(",loadaddress,")")
|
||||
if (loadaddress & 0x3):
|
||||
am_print("load address needs to be word aligned", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
if (magicNum == AM_IMAGE_MAGIC_INFO0):
|
||||
if (orig_app_length & 0x3):
|
||||
am_print("INFO0 blob length needs to be multiple of 4", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
if ((loadaddress + orig_app_length) > INFO_SIZE_BYTES):
|
||||
am_print("INFO0 Offset and length exceed size", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
if (encVal == 1):
|
||||
block_size = AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES
|
||||
app_binarray = pad_to_block_size(app_binarray, block_size, 1)
|
||||
else:
|
||||
# Add Padding
|
||||
app_binarray = pad_to_block_size(app_binarray, 4, 0)
|
||||
|
||||
app_length = (len(app_binarray))
|
||||
am_print("app_size ",hex(app_length), "(",app_length,")")
|
||||
|
||||
# Create Image blobs
|
||||
|
||||
# w0
|
||||
blobLen = hdr_length + app_length
|
||||
w0 = (magicNum << 24) | ((encVal & 0x1) << 23) | blobLen
|
||||
|
||||
am_print("w0 =", hex(w0))
|
||||
fill_word(hdr_binarray, 0, w0)
|
||||
|
||||
# w2
|
||||
securityVal = ((authI << 1) | crcI) << 4 | (authB << 1) | crcB
|
||||
am_print("Security Value ", hex(securityVal))
|
||||
w2 = ((securityVal << 24) & 0xff000000) | ((authalgo) & 0xf) | ((authKeyIdx << 4) & 0xf0) | ((encalgo << 8) & 0xf00) | ((encKeyIdx << 12) & 0xf000)
|
||||
fill_word(hdr_binarray, 8, w2)
|
||||
am_print("w2 = ",hex(w2))
|
||||
|
||||
|
||||
if (magicNum == AM_IMAGE_MAGIC_INFO0):
|
||||
# Insert the INFO0 size and offset
|
||||
addrWord = ((orig_app_length>>2) << 16) | ((loadaddress>>2) & 0xFFFF)
|
||||
versionKeyWord = INFO_KEY
|
||||
else:
|
||||
# Insert the application binary load address.
|
||||
addrWord = loadaddress | (protection & 0x3)
|
||||
# Initialize versionKeyWord
|
||||
versionKeyWord = (version & 0x7FFF) | ((erasePrev & 0x1) << 15)
|
||||
|
||||
am_print("addrWord = ",hex(addrWord))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_ADDR, addrWord)
|
||||
|
||||
am_print("versionKeyWord = ",hex(versionKeyWord))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_VERKEY, versionKeyWord)
|
||||
|
||||
# Initialize child (Child Ptr/ Feature key)
|
||||
am_print("child0/feature = ",hex(child0))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_CHILDPTR, child0)
|
||||
am_print("child1 = ",hex(child1))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_CHILDPTR + 4, child1)
|
||||
|
||||
authKeyIdx = authKeyIdx - minHmacKeyIdx
|
||||
if (authB != 0): # Authentication needed
|
||||
am_print("Boot Authentication Enabled")
|
||||
# am_print("Key used for HMAC")
|
||||
# am_print([hex(keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, AM_HMAC_SIG_SIZE)])
|
||||
# Initialize the clear image HMAC
|
||||
sigClr = compute_hmac(keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES:(authKeyIdx*AM_SECBOOT_KEYIDX_BYTES+AM_HMAC_SIG_SIZE)], (hdr_binarray[AM_IMAGEHDR_START_HMAC:hdr_length] + app_binarray))
|
||||
am_print("HMAC Clear")
|
||||
am_print([hex(n) for n in sigClr])
|
||||
# Fill up the HMAC
|
||||
for x in range(0, AM_HMAC_SIG_SIZE):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_SIGCLR + x] = sigClr[x]
|
||||
|
||||
# All the header fields part of the encryption are now final
|
||||
if (encVal == 1):
|
||||
am_print("Encryption Enabled")
|
||||
encKeyIdx = encKeyIdx - minAesKeyIdx
|
||||
ivValAes = os.urandom(AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES)
|
||||
am_print("Initialization Vector")
|
||||
am_print([hex(ivValAes[n]) for n in range (0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES)])
|
||||
keyAes = os.urandom(keySize)
|
||||
am_print("AES Key used for encryption")
|
||||
am_print([hex(keyAes[n]) for n in range (0, keySize)])
|
||||
# Encrypted Part
|
||||
am_print("Encrypting blob of size " , (hdr_length - AM_IMAGEHDR_START_ENCRYPT + app_length))
|
||||
enc_binarray = encrypt_app_aes((hdr_binarray[AM_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray), keyAes, ivValAes)
|
||||
# am_print("Key used for encrypting AES Key")
|
||||
# am_print([hex(keyTblAes[encKeyIdx*keySize + n]) for n in range (0, keySize)])
|
||||
# Encrypted Key
|
||||
enc_key = encrypt_app_aes(keyAes, keyTblAes[encKeyIdx*keySize:encKeyIdx*keySize + keySize], ivVal0)
|
||||
am_print("Encrypted Key")
|
||||
am_print([hex(enc_key[n]) for n in range (0, keySize)])
|
||||
# Fill up the IV
|
||||
for x in range(0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_IV + x] = ivValAes[x]
|
||||
# Fill up the Encrypted Key
|
||||
for x in range(0, keySize):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_KEK + x] = enc_key[x]
|
||||
else:
|
||||
enc_binarray = hdr_binarray[AM_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray
|
||||
|
||||
|
||||
if (authI != 0): # Install Authentication needed
|
||||
am_print("Install Authentication Enabled")
|
||||
# am_print("Key used for HMAC")
|
||||
# am_print([hex(keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, AM_HMAC_SIG_SIZE)])
|
||||
# Initialize the top level HMAC
|
||||
sig = compute_hmac(keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES:(authKeyIdx*AM_SECBOOT_KEYIDX_BYTES+AM_HMAC_SIG_SIZE)], (hdr_binarray[AM_IMAGEHDR_START_HMAC_INST:AM_IMAGEHDR_START_ENCRYPT] + enc_binarray))
|
||||
am_print("Generated Signature")
|
||||
am_print([hex(n) for n in sig])
|
||||
# Fill up the HMAC
|
||||
for x in range(0, AM_HMAC_SIG_SIZE):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_SIG + x] = sig[x]
|
||||
# compute the CRC for the blob - this is done on a clear image
|
||||
crc = crc32(hdr_binarray[AM_IMAGEHDR_START_CRC:hdr_length] + app_binarray)
|
||||
am_print("crc = ",hex(crc));
|
||||
w1 = crc
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_CRC, w1)
|
||||
|
||||
# now output all three binary arrays in the proper order
|
||||
output = output + '_OTA_blob.bin'
|
||||
blob2wiredfile = output # save the output of bin2blob for use by blob2wired
|
||||
am_print("Writing to file ", output)
|
||||
with open(output, mode = 'wb') as out:
|
||||
out.write(hdr_binarray[0:AM_IMAGEHDR_START_ENCRYPT])
|
||||
out.write(enc_binarray)
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Generate the image blob as per command line parameters
|
||||
#
|
||||
#******************************************************************************
|
||||
def blob2wired_process(appFile, imagetype, loadaddress, authalgo, encalgo, authKeyIdx, encKeyIdx, optionsVal, maxSize, output):
|
||||
global uploadbinfile
|
||||
|
||||
app_binarray = bytearray()
|
||||
# Open the file, and read it into an array of integers.
|
||||
print('testing: ' + appFile )
|
||||
with open(appFile,'rb') as f_app:
|
||||
app_binarray.extend(f_app.read())
|
||||
f_app.close()
|
||||
|
||||
# Make sure it is page multiple
|
||||
if ((maxSize & (FLASH_PAGE_SIZE - 1)) != 0):
|
||||
am_print ("split needs to be multiple of flash page size", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
if (encalgo != 0):
|
||||
if ((encKeyIdx < minAesKeyIdx) or (encKeyIdx > maxAesKeyIdx)):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
if (encalgo == 2):
|
||||
if (encKeyIdx & 0x1):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
keySize = 32
|
||||
else:
|
||||
keySize = 16
|
||||
if (authalgo != 0):
|
||||
if ((authKeyIdx < minHmacKeyIdx) or (authKeyIdx > maxHmacKeyIdx) or (authKeyIdx & 0x1)):
|
||||
am_print("Invalid authKey Idx ", authKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
|
||||
hdr_length = AM_WU_IMAGEHDR_SIZE; #fixed header length
|
||||
am_print("Header Size = ", hex(hdr_length))
|
||||
|
||||
orig_app_length = (len(app_binarray))
|
||||
|
||||
if (encalgo != 0):
|
||||
block_size = keySize
|
||||
app_binarray = pad_to_block_size(app_binarray, block_size, 1)
|
||||
else:
|
||||
# Add Padding
|
||||
app_binarray = pad_to_block_size(app_binarray, 4, 0)
|
||||
|
||||
app_length = (len(app_binarray))
|
||||
am_print("app_size ",hex(app_length), "(",app_length,")")
|
||||
|
||||
if (app_length + hdr_length > maxSize):
|
||||
am_print("Image size bigger than max - Creating Split image")
|
||||
|
||||
start = 0
|
||||
# now output all three binary arrays in the proper order
|
||||
output = output + '_Wired_OTA_blob.bin'
|
||||
uploadbinfile = output; # save the name of the output from blob2wired
|
||||
out = open(output, mode = 'wb')
|
||||
|
||||
while (start < app_length):
|
||||
#generate mutable byte array for the header
|
||||
hdr_binarray = bytearray([0x00]*hdr_length);
|
||||
|
||||
if (app_length - start > maxSize):
|
||||
end = start + maxSize
|
||||
else:
|
||||
end = app_length
|
||||
|
||||
if (imagetype == AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA):
|
||||
key = INFO_KEY
|
||||
# word offset
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_ADDR, loadaddress>>2)
|
||||
else:
|
||||
key = FLASH_KEY
|
||||
# load address
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_ADDR, loadaddress)
|
||||
# Create imageType & options
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_IMAGETYPE] = imagetype
|
||||
# Set the options only for the first block
|
||||
if (start == 0):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_OPTIONS] = optionsVal
|
||||
else:
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_OPTIONS] = 0
|
||||
|
||||
# Create Info0 Update Blob for wired update
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_KEY, key)
|
||||
# update size
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_SIZE, end-start)
|
||||
|
||||
w0 = ((authalgo & 0xf) | ((authKeyIdx << 8) & 0xf00) | ((encalgo << 16) & 0xf0000) | ((encKeyIdx << 24) & 0x0f000000))
|
||||
|
||||
fill_word(hdr_binarray, 0, w0)
|
||||
|
||||
if (encalgo != 0):
|
||||
keyIdx = encKeyIdx - minAesKeyIdx
|
||||
ivValAes = os.urandom(AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES)
|
||||
am_print("Initialization Vector")
|
||||
am_print([hex(n) for n in ivValAes])
|
||||
keyAes = os.urandom(keySize)
|
||||
am_print("AES Key used for encryption")
|
||||
am_print([hex(keyAes[n]) for n in range (0, keySize)])
|
||||
# Encrypted Part - after security header
|
||||
enc_binarray = encrypt_app_aes((hdr_binarray[AM_WU_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray[start:end]), keyAes, ivValAes)
|
||||
# am_print("Key used for encrypting AES Key")
|
||||
# am_print([hex(keyTblAes[keyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, keySize)])
|
||||
# Encrypted Key
|
||||
enc_key = encrypt_app_aes(keyAes, keyTblAes[keyIdx*AM_SECBOOT_KEYIDX_BYTES:(keyIdx*AM_SECBOOT_KEYIDX_BYTES + keySize)], ivVal0)
|
||||
am_print("Encrypted Key")
|
||||
am_print([hex(enc_key[n]) for n in range (0, keySize)])
|
||||
# Fill up the IV
|
||||
for x in range(0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_IV + x] = ivValAes[x]
|
||||
# Fill up the Encrypted Key
|
||||
for x in range(0, keySize):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_KEK + x] = enc_key[x]
|
||||
else:
|
||||
enc_binarray = hdr_binarray[AM_WU_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray[start:end]
|
||||
|
||||
|
||||
if (authalgo != 0): # Authentication needed
|
||||
keyIdx = authKeyIdx - minHmacKeyIdx
|
||||
# am_print("Key used for HMAC")
|
||||
# am_print([hex(keyTblHmac[keyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, AM_HMAC_SIG_SIZE)])
|
||||
# Initialize the HMAC - Sign is computed on image following the signature
|
||||
sig = compute_hmac(keyTblHmac[keyIdx*AM_SECBOOT_KEYIDX_BYTES:(keyIdx*AM_SECBOOT_KEYIDX_BYTES+AM_HMAC_SIG_SIZE)], hdr_binarray[AM_WU_IMAGEHDR_START_HMAC:AM_WU_IMAGEHDR_START_ENCRYPT] + enc_binarray)
|
||||
am_print("HMAC")
|
||||
am_print([hex(n) for n in sig])
|
||||
# Fill up the HMAC
|
||||
for x in range(0, AM_HMAC_SIG_SIZE):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_SIG + x] = sig[x]
|
||||
|
||||
am_print("Writing to file ", output)
|
||||
am_print("Image from ", str(hex(start)), " to ", str(hex(end)), " will be loaded at", str(hex(loadaddress)))
|
||||
out.write(hdr_binarray[0:AM_WU_IMAGEHDR_START_ENCRYPT])
|
||||
out.write(enc_binarray)
|
||||
|
||||
# Reset start for next chunk
|
||||
start = end
|
||||
loadaddress = loadaddress + maxSize
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function
|
||||
#
|
||||
#******************************************************************************
|
||||
def upload(args, verboseprint):
|
||||
|
||||
global loadTries
|
||||
global loadSuccess
|
||||
|
||||
# Open a serial port, and communicate with Device
|
||||
#
|
||||
# Max flashing time depends on the amount of SRAM available.
|
||||
# For very large images, the flashing happens page by page.
|
||||
# However if the image can fit in the free SRAM, it could take a long time
|
||||
# for the whole image to be flashed at the end.
|
||||
# The largest image which can be stored depends on the max SRAM.
|
||||
# Assuming worst case ~100 ms/page of flashing time, and allowing for the
|
||||
# image to be close to occupying full SRAM (256K) which is 128 pages.
|
||||
|
||||
connection_timeout = 5
|
||||
|
||||
print('Connecting over serial port {}...'.format(args.port), flush=True)
|
||||
|
||||
#Check to see if the com port is available
|
||||
try:
|
||||
with serial.Serial(args.port, args.baud, timeout=connection_timeout) as ser:
|
||||
pass
|
||||
except:
|
||||
|
||||
#Show a list of com ports and recommend one
|
||||
print("Detected Serial Ports:")
|
||||
devices = list_ports.comports()
|
||||
port = None
|
||||
for dev in devices:
|
||||
print(dev.description)
|
||||
# The SparkFun BlackBoard has CH340 in the description
|
||||
if 'CH340' in dev.description:
|
||||
print("The port you selected was not found. But we did detect a CH340 on " + dev.device + " so you might try again on that port.")
|
||||
break
|
||||
elif 'FTDI' in dev.description:
|
||||
print("The port you selected was not found. But we did detect an FTDI on " + dev.device + " so you might try again on that port.")
|
||||
break
|
||||
elif 'USB Serial Device' in dev.description:
|
||||
print("The port you selected was not found. But we did detect a USB Serial Device on " + dev.device + " so you might try again on that port.")
|
||||
break
|
||||
else:
|
||||
print("Com Port not found - Did you select the right one?")
|
||||
|
||||
exit()
|
||||
|
||||
#Begin talking over com port
|
||||
|
||||
#The auto-bootload sequence is good but not fullproof. The bootloader
|
||||
#fails to correctly catch the BOOT signal about 1 out of ten times.
|
||||
#Auto-retry this number of times before we give up.
|
||||
|
||||
while loadTries < 3:
|
||||
loadSuccess = False
|
||||
|
||||
with serial.Serial(args.port, args.baud, timeout=connection_timeout) as ser:
|
||||
#DTR is driven low when serial port open. DTR has now pulled RST low.
|
||||
|
||||
time.sleep(0.005) #3ms and 10ms work well. Not 50, and not 0.
|
||||
|
||||
#Setting RTS/DTR high causes the bootload pin to go high, then fall across 100ms
|
||||
ser.setDTR(0) #Set DTR high
|
||||
ser.setRTS(0) #Set RTS high - support the CH340E
|
||||
|
||||
#Give bootloader a chance to run and check bootload pin before communication begins. But must initiate com before bootloader timeout of 250ms.
|
||||
time.sleep(0.100) #100ms works well
|
||||
|
||||
ser.reset_input_buffer() # reset the input bufer to discard any UART traffic that the device may have generated
|
||||
|
||||
connect_device(ser, args, verboseprint)
|
||||
|
||||
if(loadSuccess == True):
|
||||
print("Tries =", loadTries)
|
||||
print('Upload complete!')
|
||||
exit()
|
||||
else:
|
||||
print("Fail")
|
||||
|
||||
loadTries = loadTries + 1
|
||||
|
||||
print("Tries =", loadTries)
|
||||
print("Upload failed")
|
||||
exit()
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Communicate with Device
|
||||
#
|
||||
# Given a serial port, connects to the target device using the
|
||||
# UART.
|
||||
#
|
||||
#******************************************************************************
|
||||
def connect_device(ser, args, verboseprint):
|
||||
|
||||
global loadSuccess
|
||||
|
||||
# Send Hello
|
||||
#generate mutable byte array for the header
|
||||
hello = bytearray([0x00]*4)
|
||||
fill_word(hello, 0, ((8 << 16) | AM_SECBOOT_WIRED_MSGTYPE_HELLO))
|
||||
verboseprint('Sending Hello.')
|
||||
response = send_command(hello, 88, ser, verboseprint)
|
||||
|
||||
#Check if response failed
|
||||
if response == False:
|
||||
verboseprint("Failed to respond")
|
||||
return
|
||||
|
||||
verboseprint("Received response for Hello")
|
||||
word = word_from_bytes(response, 4)
|
||||
if ((word & 0xFFFF) == AM_SECBOOT_WIRED_MSGTYPE_STATUS):
|
||||
# Received Status
|
||||
print("Bootloader connected")
|
||||
|
||||
verboseprint("Received Status")
|
||||
verboseprint("length = ", hex((word >> 16)))
|
||||
verboseprint("version = ", hex(word_from_bytes(response, 8)))
|
||||
verboseprint("Max Storage = ", hex(word_from_bytes(response, 12)))
|
||||
verboseprint("Status = ", hex(word_from_bytes(response, 16)))
|
||||
verboseprint("State = ", hex(word_from_bytes(response, 20)))
|
||||
verboseprint("AMInfo = ")
|
||||
for x in range(24, 88, 4):
|
||||
verboseprint(hex(word_from_bytes(response, x)))
|
||||
|
||||
abort = args.abort
|
||||
if (abort != -1):
|
||||
# Send OTA Desc
|
||||
verboseprint('Sending Abort command.')
|
||||
abortMsg = bytearray([0x00]*8);
|
||||
fill_word(abortMsg, 0, ((12 << 16) | AM_SECBOOT_WIRED_MSGTYPE_ABORT))
|
||||
fill_word(abortMsg, 4, abort)
|
||||
if send_ackd_command(abortMsg, ser, verboseprint) == False:
|
||||
verboseprint("Failed to ack command")
|
||||
return
|
||||
|
||||
|
||||
otadescaddr = args.otadesc
|
||||
if (otadescaddr != 0xFFFFFFFF):
|
||||
# Send OTA Desc
|
||||
verboseprint('Sending OTA Descriptor = ', hex(otadescaddr))
|
||||
otaDesc = bytearray([0x00]*8);
|
||||
fill_word(otaDesc, 0, ((12 << 16) | AM_SECBOOT_WIRED_MSGTYPE_OTADESC))
|
||||
fill_word(otaDesc, 4, otadescaddr)
|
||||
if send_ackd_command(otaDesc, ser, verboseprint) == False:
|
||||
verboseprint("Failed to ack command")
|
||||
return
|
||||
|
||||
|
||||
imageType = args.imagetype
|
||||
if (uploadbinfile != ''):
|
||||
|
||||
# Read the binary file from the command line.
|
||||
with open(uploadbinfile, mode='rb') as binfile:
|
||||
application = binfile.read()
|
||||
# Gather the important binary metadata.
|
||||
totalLen = len(application)
|
||||
# Send Update command
|
||||
verboseprint('Sending Update Command.')
|
||||
|
||||
# It is assumed that maxSize is 256b multiple
|
||||
maxImageSize = args.split
|
||||
if ((maxImageSize & (FLASH_PAGE_SIZE - 1)) != 0):
|
||||
verboseprint ("split needs to be multiple of flash page size")
|
||||
return
|
||||
|
||||
# Each Block of image consists of AM_WU_IMAGEHDR_SIZE Bytes Image header and the Image blob
|
||||
maxUpdateSize = AM_WU_IMAGEHDR_SIZE + maxImageSize
|
||||
numUpdates = (totalLen + maxUpdateSize - 1) // maxUpdateSize # Integer division
|
||||
verboseprint("number of updates needed = ", numUpdates)
|
||||
|
||||
end = totalLen
|
||||
for numUpdates in range(numUpdates, 0 , -1):
|
||||
start = (numUpdates-1)*maxUpdateSize
|
||||
crc = crc32(application[start:end])
|
||||
applen = end - start
|
||||
verboseprint("Sending block of size ", str(hex(applen)), " from ", str(hex(start)), " to ", str(hex(end)))
|
||||
end = end - applen
|
||||
|
||||
update = bytearray([0x00]*16);
|
||||
fill_word(update, 0, ((20 << 16) | AM_SECBOOT_WIRED_MSGTYPE_UPDATE))
|
||||
fill_word(update, 4, applen)
|
||||
fill_word(update, 8, crc)
|
||||
# Size = 0 => We're not piggybacking any data to IMAGE command
|
||||
fill_word(update, 12, 0)
|
||||
|
||||
if send_ackd_command(update, ser, verboseprint) == False:
|
||||
verboseprint("Failed to ack command")
|
||||
return
|
||||
|
||||
# Loop over the bytes in the image, and send them to the target.
|
||||
resp = 0
|
||||
# Max chunk size is AM_MAX_UART_MSG_SIZE adjusted for the header for Data message
|
||||
maxChunkSize = AM_MAX_UART_MSG_SIZE - 12
|
||||
for x in range(0, applen, maxChunkSize):
|
||||
# Split the application into chunks of maxChunkSize bytes.
|
||||
# This is the max chunk size supported by the UART bootloader
|
||||
if ((x + maxChunkSize) > applen):
|
||||
chunk = application[start+x:start+applen]
|
||||
# print(str(hex(start+x)), " to ", str(hex(applen)))
|
||||
else:
|
||||
chunk = application[start+x:start+x+maxChunkSize]
|
||||
# print(str(hex(start+x)), " to ", str(hex(start + x + maxChunkSize)))
|
||||
|
||||
chunklen = len(chunk)
|
||||
|
||||
# Build a data packet with a "data command" a "length" and the actual
|
||||
# payload bytes, and send it to the target.
|
||||
dataMsg = bytearray([0x00]*8);
|
||||
fill_word(dataMsg, 0, (((chunklen + 12) << 16) | AM_SECBOOT_WIRED_MSGTYPE_DATA))
|
||||
# seqNo
|
||||
fill_word(dataMsg, 4, x)
|
||||
|
||||
verboseprint("Sending Data Packet of length ", chunklen)
|
||||
if send_ackd_command(dataMsg + chunk, ser, verboseprint) == False:
|
||||
verboseprint("Failed to ack command")
|
||||
return
|
||||
|
||||
if (args.raw != ''):
|
||||
|
||||
# Read the binary file from the command line.
|
||||
with open(args.raw, mode='rb') as rawfile:
|
||||
blob = rawfile.read()
|
||||
# Send Raw command
|
||||
verboseprint('Sending Raw Command.')
|
||||
ser.write(blob)
|
||||
|
||||
if (args.reset != 0):
|
||||
# Send reset
|
||||
verboseprint('Sending Reset Command.')
|
||||
resetmsg = bytearray([0x00]*8);
|
||||
fill_word(resetmsg, 0, ((12 << 16) | AM_SECBOOT_WIRED_MSGTYPE_RESET))
|
||||
# options
|
||||
fill_word(resetmsg, 4, args.reset)
|
||||
if send_ackd_command(resetmsg, ser, verboseprint) == False:
|
||||
verboseprint("Failed to ack command")
|
||||
return
|
||||
|
||||
|
||||
#Success! We're all done
|
||||
loadSuccess = True
|
||||
else:
|
||||
# Received Wrong message
|
||||
verboseprint("Received Unknown Message")
|
||||
word = word_from_bytes(response, 4)
|
||||
verboseprint("msgType = ", hex(word & 0xFFFF))
|
||||
verboseprint("Length = ", hex(word >> 16))
|
||||
verboseprint([hex(n) for n in response])
|
||||
#print("!!!Wired Upgrade Unsuccessful!!!....Terminating the script")
|
||||
|
||||
#exit()
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send ACK'd command
|
||||
#
|
||||
# Sends a command, and waits for an ACK.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_ackd_command(command, ser, verboseprint):
|
||||
|
||||
response = send_command(command, 20, ser, verboseprint)
|
||||
|
||||
#Check if response failed
|
||||
if response == False:
|
||||
verboseprint("Response not valid")
|
||||
return False #Return error
|
||||
|
||||
word = word_from_bytes(response, 4)
|
||||
if ((word & 0xFFFF) == AM_SECBOOT_WIRED_MSGTYPE_ACK):
|
||||
# Received ACK
|
||||
if (word_from_bytes(response, 12) != AM_SECBOOT_WIRED_ACK_STATUS_SUCCESS):
|
||||
verboseprint("Received NACK")
|
||||
verboseprint("msgType = ", hex(word_from_bytes(response, 8)))
|
||||
verboseprint("error = ", hex(word_from_bytes(response, 12)))
|
||||
verboseprint("seqNo = ", hex(word_from_bytes(response, 16)))
|
||||
#print("!!!Wired Upgrade Unsuccessful!!!....Terminating the script")
|
||||
verboseprint("Upload failed: No ack to command")
|
||||
|
||||
return False #Return error
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send command
|
||||
#
|
||||
# Sends a command, and waits for the response.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_command(params, response_len, ser, verboseprint):
|
||||
|
||||
# Compute crc
|
||||
crc = crc32(params)
|
||||
# print([hex(n) for n in int_to_bytes(crc)])
|
||||
# print([hex(n) for n in params])
|
||||
# send crc first
|
||||
ser.write(int_to_bytes(crc))
|
||||
|
||||
# Next, send the parameters.
|
||||
ser.write(params)
|
||||
|
||||
response = ''
|
||||
response = ser.read(response_len)
|
||||
|
||||
# Make sure we got the number of bytes we asked for.
|
||||
if len(response) != response_len:
|
||||
verboseprint('No response for command 0x{:08X}'.format(word_from_bytes(params, 0) & 0xFFFF))
|
||||
n = len(response)
|
||||
if (n != 0):
|
||||
verboseprint("received bytes ", len(response))
|
||||
verboseprint([hex(n) for n in response])
|
||||
return False
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send a command that uses an array of bytes as its parameters.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_bytewise_command(command, params, response_len, ser):
|
||||
# Send the command first.
|
||||
ser.write(int_to_bytes(command))
|
||||
|
||||
# Next, send the parameters.
|
||||
ser.write(params)
|
||||
|
||||
response = ''
|
||||
response = ser.read(response_len)
|
||||
|
||||
# Make sure we got the number of bytes we asked for.
|
||||
if len(response) != response_len:
|
||||
print("Upload failed: No reponse to command")
|
||||
verboseprint('No response for command 0x{:08X}'.format(command))
|
||||
exit()
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Errors
|
||||
#
|
||||
#******************************************************************************
|
||||
class BootError(Exception):
|
||||
pass
|
||||
|
||||
class NoAckError(BootError):
|
||||
pass
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Combination script to upload application binaries to Artemis module. Includes:\n\t\'- bin2blob: create OTA blob from binary image\'\n\t\'- blob2wired: create wired update image from OTA blob\'\n\t\'- upload: send wired update image to Apollo3 Artemis module via serial port\'\n\nThere are many command-line arguments. They have been labeled by which steps they apply to\n')
|
||||
|
||||
parser.add_argument('-a', dest = 'abort', default=-1, type=int, choices = [0,1,-1],
|
||||
help = 'upload: Should it send abort command? (0 = abort, 1 = abort and quit, -1 = no abort) (default is -1)')
|
||||
|
||||
parser.add_argument('--authalgo', dest = 'authalgo', type=auto_int, default=0, choices=range(0, AM_SECBOOT_AUTH_ALGO_MAX+1),
|
||||
help = 'bin2blob, blob2wired: ' + str(helpAuthAlgo))
|
||||
|
||||
parser.add_argument('--authI', dest = 'authI', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'bin2blob: Install Authentication check enabled (Default = N)?')
|
||||
|
||||
parser.add_argument('--authB', dest = 'authB', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'bin2blob: Boot Authentication check enabled (Default = N)?')
|
||||
|
||||
parser.add_argument('--authkey', dest = 'authkey', type=auto_int, default=(minHmacKeyIdx), choices = range(minHmacKeyIdx, maxHmacKeyIdx + 1),
|
||||
help = 'bin2blob, blob2wired: Authentication Key Idx? (' + str(minHmacKeyIdx) + ' to ' + str(maxHmacKeyIdx) + ')')
|
||||
|
||||
parser.add_argument('-b', dest='baud', default=115200, type=int,
|
||||
help = 'upload: Baud Rate (default is 115200)')
|
||||
|
||||
parser.add_argument('--bin', dest='appFile', type=argparse.FileType('rb'),
|
||||
help='bin2blob: binary file (blah.bin)')
|
||||
|
||||
parser.add_argument('-clean', dest='clean', default=0, type=int,
|
||||
help = 'All: whether or not to remove intermediate files')
|
||||
|
||||
parser.add_argument('--child0', dest = 'child0', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'bin2blob: child (blobPtr#0 for Main / feature key for AM3P)')
|
||||
|
||||
parser.add_argument('--child1', dest = 'child1', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'bin2blob: child (blobPtr#1 for Main)')
|
||||
|
||||
parser.add_argument('--crcI', dest = 'crcI', type=auto_int, default=1, choices=[0,1],
|
||||
help = 'bin2blob: Install CRC check enabled (Default = Y)?')
|
||||
|
||||
parser.add_argument('--crcB', dest = 'crcB', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'bin2blob: Boot CRC check enabled (Default = N)?')
|
||||
|
||||
parser.add_argument('--encalgo', dest = 'encalgo', type=auto_int, default=0, choices = range(0, AM_SECBOOT_ENC_ALGO_MAX+1),
|
||||
help = 'bin2blob, blob2wired: ' + str(helpEncAlgo))
|
||||
|
||||
parser.add_argument('--erasePrev', dest = 'erasePrev', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'bin2blob: erasePrev (Valid only for main)')
|
||||
|
||||
# parser.add_argument('-f', dest='binfile', default='',
|
||||
# help = 'upload: Binary file to program into the target device')
|
||||
|
||||
parser.add_argument('-i', dest = 'imagetype', default=AM_SECBOOT_WIRED_IMAGETYPE_INVALID, type=auto_int,
|
||||
choices = [
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_SBL),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_AM3P),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_PATCH),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_MAIN),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_CHILD),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INFO0),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INVALID)
|
||||
],
|
||||
help = 'blob2wired, upload: ImageType ('
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_SBL) + ': SBL, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_AM3P) + ': AM3P, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_PATCH) + ': Patch, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_MAIN) + ': Main, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_CHILD) + ': Child, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH) + ': CustOTA, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE) + ': NonSecure, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INFO0) + ': Info0 '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA) + ': Info0_NOOTA) '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INVALID) + ': Invalid) '
|
||||
'- default[Invalid]')
|
||||
|
||||
parser.add_argument('--kek', dest = 'kek', type=auto_int, default=(minAesKeyIdx), choices = range(minAesKeyIdx, maxAesKeyIdx+1),
|
||||
help = 'KEK index? (' + str(minAesKeyIdx) + ' to ' + str(maxAesKeyIdx) + ')')
|
||||
|
||||
parser.add_argument('--load-address-wired', dest='loadaddress_blob', type=auto_int, default=hex(0x60000),
|
||||
help='blob2wired: Load address of the binary - Where in flash the blob will be stored (could be different than install address of binary within).')
|
||||
|
||||
parser.add_argument('--load-address-blob', dest='loadaddress_image', type=auto_int, default=hex(AM_SECBOOT_DEFAULT_NONSECURE_MAIN),
|
||||
help='bin2blob: Load address of the binary.')
|
||||
|
||||
parser.add_argument('--loglevel', dest='loglevel', type=auto_int, default=AM_PRINT_LEVEL_INFO,
|
||||
choices = range(AM_PRINT_LEVEL_MIN, AM_PRINT_LEVEL_MAX+1),
|
||||
help='bin2blob, blob2wired: ' + str(helpPrintLevel))
|
||||
|
||||
parser.add_argument('--magic-num', dest='magic_num', default=hex(AM_IMAGE_MAGIC_NONSECURE),
|
||||
type=lambda x: x.lower(),
|
||||
# type = str.lower,
|
||||
choices = [
|
||||
hex(AM_IMAGE_MAGIC_MAIN),
|
||||
hex(AM_IMAGE_MAGIC_CHILD),
|
||||
hex(AM_IMAGE_MAGIC_CUSTPATCH),
|
||||
hex(AM_IMAGE_MAGIC_NONSECURE),
|
||||
hex(AM_IMAGE_MAGIC_INFO0)
|
||||
],
|
||||
help = 'bin2blob: Magic Num ('
|
||||
+ str(hex(AM_IMAGE_MAGIC_MAIN)) + ': Main, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_CHILD)) + ': Child, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_CUSTPATCH)) + ': CustOTA, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_NONSECURE)) + ': NonSecure, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_INFO0)) + ': Info0) '
|
||||
'- default[Main]'
|
||||
)
|
||||
|
||||
parser.add_argument('-o', dest = 'output', default='wuimage',
|
||||
help = 'all: Output filename (without the extension) [also used for intermediate filenames]')
|
||||
|
||||
parser.add_argument('-ota', dest = 'otadesc', type=auto_int, default=0xFE000,
|
||||
help = 'upload: OTA Descriptor Page address (hex) - (Default is 0xFE000 - at the end of main flash) - enter 0xFFFFFFFF to instruct SBL to skip OTA')
|
||||
|
||||
parser.add_argument('--options', dest = 'options', type=auto_int, default=0x1,
|
||||
help = 'blob2wired: Options (16b hex value) - bit0 instructs to perform OTA of the image after wired download (set to 0 if only downloading & skipping OTA flow)')
|
||||
|
||||
parser.add_argument('-p', dest = 'protection', type=auto_int, default=0, choices = [0x0, 0x1, 0x2, 0x3],
|
||||
help = 'bin2blob: protection info 2 bit C W')
|
||||
|
||||
parser.add_argument('-port', dest = 'port', help = 'upload: Serial COMx Port')
|
||||
|
||||
parser.add_argument('-r', dest = 'reset', default=1, type=auto_int, choices = [0,1,2],
|
||||
help = 'upload: Should it send reset command after image download? (0 = no reset, 1 = POI, 2 = POR) (default is 1)')
|
||||
|
||||
parser.add_argument('--raw', dest='raw', default='',
|
||||
help = 'upload: Binary file for raw message')
|
||||
|
||||
parser.add_argument('--split', dest='split', type=auto_int, default=hex(MAX_DOWNLOAD_SIZE),
|
||||
help='blob2wired, upload: Specify the max block size if the image will be downloaded in pieces')
|
||||
|
||||
parser.add_argument('--version', dest = 'version', type=auto_int, default=0,
|
||||
help = 'bin2blob: version (15 bit)')
|
||||
|
||||
parser.add_argument("-v", "--verbose", default=0, help="All: Enable verbose output",
|
||||
action="store_true")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
args.magic_num = int(args.magic_num, 16)
|
||||
|
||||
|
||||
return args
|
||||
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
# example calling:
|
||||
# python artemis_bin_to_board.py --bin application.bin --load-address-blob 0x20000 --magic-num 0xCB -o application --version 0x0 --load-address-wired 0xC000 -i 6 --options 0x1 -b 921600 -port COM4 -r 1 -v
|
||||
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
am_set_print_level(args.loglevel)
|
||||
|
||||
global blob2wiredfile
|
||||
|
||||
bin2blob_process(args.loadaddress_blob, args.appFile, args.magic_num, args.crcI, args.crcB, args.authI, args.authB, args.protection, args.authkey, args.output, args.kek, args.version, args.erasePrev, args.child0, args.child1, args.authalgo, args.encalgo)
|
||||
blob2wired_process( blob2wiredfile, args.imagetype, args.loadaddress_image, args.authalgo, args.encalgo, args.authkey, args.kek, args.options, args.split, args.output)
|
||||
|
||||
# todo: link the bin2blob step with the blob2wired step by input/output files
|
||||
|
||||
|
||||
#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=''),
|
||||
print()
|
||||
else:
|
||||
verboseprint = lambda *a: None # do-nothing function
|
||||
|
||||
upload(args, verboseprint)
|
||||
|
||||
if(args.clean == 1):
|
||||
print('Cleaning up intermediate files') # todo: why isnt this showing w/ -clean option?
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
Binary file not shown.
Vendored
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
from am_defines import *
|
||||
|
||||
minAesKeyIdx = 8
|
||||
maxAesKeyIdx = 15
|
||||
minHmacKeyIdx = 8
|
||||
maxHmacKeyIdx = 15
|
||||
|
||||
###### Following are just dummy keys - Should be substituted with real keys #######
|
||||
keyTblAes = [
|
||||
# Info0 Keys - Starting at index 8
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
keyTblHmac = [
|
||||
# Info0 Keys - Starting at index 8
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
custKey = [
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
# These are dummy values. Contact AMBIQ to get the real Recovery Key
|
||||
recoveryKey = [
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
###################################################################################
|
||||
|
||||
wrapKey = custKey
|
||||
minWrapMode = AM_SECBOOT_KEYWRAP_NONE
|
||||
|
||||
INFO_KEY = 0xd894e09e
|
||||
FLASH_KEY = 0x12344321
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
###### Requirements ######`
|
||||
pyinstaller == 3.6
|
||||
pycryptodome
|
||||
pyserial
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
//connect to device
|
||||
device AMA3B1KK-KBR
|
||||
si SWD
|
||||
speed 1000
|
||||
r
|
||||
sleep 10
|
||||
|
||||
//set C runtime environment
|
||||
wreg MSP, 0x10000100
|
||||
|
||||
// erase info0
|
||||
w4 0x10000000 0 // flash info instance
|
||||
w4 0x10000004 0xd894e09e // info 0 key
|
||||
w4 0x10000008 0xFFFFFFFF // clear return value
|
||||
setPC 0x08000085 // call the ROM helper function flash_info_erase_from_sram
|
||||
g
|
||||
sleep 50
|
||||
mem32 0x10000008 1 // dump return value for check
|
||||
|
||||
// program info0
|
||||
w4 0x10000000 0 // flash info instance
|
||||
w4 0x10000004 0 // offset
|
||||
w4 0x10000008 0x800 // length in words
|
||||
w4 0x1000000C 0xd894e09e // info 0 key
|
||||
w4 0x10000010 0xFFFFFFFF // clear return value
|
||||
loadbin info0_artemis_47_115200.bin 0x10001000 //load the info0 binary into sram
|
||||
setPC 0x08000061 // call the ROM helper function flash_program_info_area_from_sram
|
||||
g
|
||||
sleep 50
|
||||
mem32 0x10000010 1 // dump return value for check
|
||||
|
||||
loadbin artemis_svl.bin 0x0000C000 //load SVL into 0xC000 (end of Ambiq bootloader)
|
||||
|
||||
loadbin example1_blink.ino.bin 0x00010000 //load Blink after SVL
|
||||
|
||||
// perform software POI
|
||||
w4 0x40000004 0x1B
|
||||
|
||||
// quit
|
||||
qc
|
||||
@@ -0,0 +1,25 @@
|
||||
Artemis Bootloader
|
||||
==========================
|
||||
|
||||
The Artemis module is loaded with two bootloaders: the ASB and SVL. The Ambiq Secure Boot Loader (ASB) resides from 0x00 to 0xC000. This bootloader is physically part of the IC and is configured using the info0 registers. At power up, if the ASB is not activated, it jumps to 0xC000. The SparkFun Variable Bootloader (SVL) resides at 0xC000 and will wait for an incoming serial character. If a character is received, the baud rate will be auto-detected, the SVL will load new code, then jump to the new user code starting at 0x10000. The SVL times out after 50ms.
|
||||
|
||||
This directory contains the various binaries that are programmed onto each Artemis module:
|
||||
|
||||
* info0_artemis_47_115200.bin - Sets the Ambiq Secure Bootloader (ASB) to 115200bps with boot pin on 47
|
||||
* artemis_svl.bin - the SparkFun Variable Loader (SVL), starts at 0xC000
|
||||
* example1_blink.ino.bin - An example sketch to blink the LED. This shows code has been loaded but will be overwritten with new sketches.
|
||||
|
||||
For more information on the Artemis Bootloader see the Artemis Bootloader in the [Arduino_Apollo3 repo](https://github.com/sparkfun/Arduino_Apollo3/tree/master/bootloaders/artemis/!artemis_svl).
|
||||
|
||||
The ASB is configured based on the documents from Ambiq (Ambiq calls it the secure bootloader or SBL). See \AmbiqSuite-Rel2.x.x\docs\secure_bootloader\ for how to modify the info0 image.
|
||||
|
||||
* Run the bootloader at 921600bps: --u0 0x1C299c0
|
||||
* Currently pin 47 is used for BOOTLOAD: --gpio 0x2f
|
||||
* Bootloader to check if BOOTLOAD pin is high (not low): --gpiolvl 1
|
||||
* Trim timeout to 2500ms: --wTO 2500
|
||||
|
||||
This was used for Artemis v10 module that used pin 47 for boot:
|
||||
|
||||
create_info0.py --valid 1 info0_artemis_47 --pl 1 --u0 0x1C200c0 --u1 0xFFFF3031 --u2 0x2 --u3 0x0 --u4 0x0 --u5 0x0 --main 0xC000 --gpio 0x2f --version 0 --wTO 2500 --gpiolvl 1
|
||||
|
||||
We load a conservative 115200bps image into the Ambiq ASB section so that future updates can be applied. The SparkFun Variable Loader is a variable bootloader capable of operating from 9600bps to 921600bps.
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
# requires:
|
||||
# make
|
||||
|
||||
# example usage
|
||||
# locations:
|
||||
# from bsp repo root:
|
||||
# common/bsp_pinconfig/scripts/regen_bsp_libs.sh
|
||||
# from remote location: (requires $AMSDK environment variable -- {boards_sfe} can be whatever you named the root of the bsp repo )
|
||||
# $AMSDK/{boards_sfe}/common/bsp_pinconfig/scripts/regen_bsp_libs.sh -r $AMSDK/{boards_sfe}
|
||||
# arguments:
|
||||
# [-r $BSP_ROOT] path to bsp root optional -- defaults to the current directory
|
||||
# (should be specified when calling script remotely)
|
||||
# [-b $BOARDS_FILE] path to boards file optional -- defaults to all supported bsp boards
|
||||
# (for now boards must still have source files located in the bsp repo)
|
||||
|
||||
# setup
|
||||
set -e
|
||||
set -o errexit
|
||||
echo "" 1>&2
|
||||
|
||||
# get enclosing directory
|
||||
DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
|
||||
# defaults
|
||||
BSP_ROOT=.
|
||||
BOARDS_FILE=$DIR/configuration/boards.sh
|
||||
|
||||
# handle arguments
|
||||
while getopts ":r:b:" opt; do
|
||||
case $opt in
|
||||
r) BSP_ROOT="$OPTARG"
|
||||
;;
|
||||
b) BOARDS_FILE="$OPTARG"
|
||||
;;
|
||||
\?) echo "Invalid option -$OPTARG" 1>&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# verify bsp root
|
||||
echo "Using \$BSP_ROOT=$BSP_ROOT" 1>&2
|
||||
VFILE=$BSP_ROOT/README.md
|
||||
if [ -f "$VFILE" ];
|
||||
then
|
||||
echo "\$BSP_ROOT verification passed" 1>&2
|
||||
else
|
||||
echo "\$BSP_ROOT verification failed" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# load in boards to handle
|
||||
echo "Using \$BOARDS_FILE=$BOARDS_FILE" 1>&2
|
||||
source $BOARDS_FILE
|
||||
|
||||
echo "" 1>&2
|
||||
for value in $BOARDS
|
||||
do
|
||||
echo "Cleaning all examples for: $value" 1>&2
|
||||
|
||||
# https://unix.stackexchange.com/questions/86722/how-do-i-loop-through-only-directories-in-bash
|
||||
# https://stackoverflow.com/questions/4515866/iterate-through-subdirectories-in-bash
|
||||
# https://stackoverflow.com/questions/9018723/what-is-the-simplest-way-to-remove-a-trailing-slash-from-each-parameter
|
||||
# shopt -s nullglob
|
||||
for f in $BSP_ROOT/$value/examples/*/; do
|
||||
if [[ "$f" = "*" ]]; then continue; fi # protect from empty directories
|
||||
if [[ -d "$f" && ! -L "$f" ]]; then
|
||||
# # $f is a directory and is not a symlink
|
||||
# echo "Removing: $f/gcc/bin"
|
||||
# rm -rf $f/gcc/bin
|
||||
echo "cleaning ${f%/}"
|
||||
make -f ${f%/}/gcc/Makefile clean PROJECTPATH=${f%/}
|
||||
fi
|
||||
done
|
||||
done
|
||||
+1
@@ -0,0 +1 @@
|
||||
export BOARDS="edge edge2 artemis_module artemis_thing_plus redboard_artemis redboard_artemis_atp redboard_artemis_nano artemis_dk"
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"copy": [
|
||||
{
|
||||
"from": "devices",
|
||||
"to": "targets/TARGET_Ambiq_Micro/sdk/devices",
|
||||
"ignore": [
|
||||
"am_devices_da14581.c",
|
||||
"am_devices_da14581.h",
|
||||
"am_devices_em9304.c",
|
||||
"am_devices_em9304.h",
|
||||
"am_devices_fireball.c",
|
||||
"am_devices_fireball.h",
|
||||
"am_devices_mb85rc256v.c",
|
||||
"am_devices_mb85rc256v.h",
|
||||
"am_devices_mb85rs1mt.c",
|
||||
"am_devices_mb85rs1mt.h",
|
||||
"am_devices_mspi_atxp032.c",
|
||||
"am_devices_mspi_atxp032.h",
|
||||
"am_devices_mspi_psram_aps6404l.c",
|
||||
"am_devices_mspi_psram_aps6404l.h",
|
||||
"am_devices_mspi_rm67162.c",
|
||||
"am_devices_mspi_rm67162.h",
|
||||
"am_devices_mspi_s25fs064s.c",
|
||||
"am_devices_mspi_s25fs064s.h",
|
||||
"am_devices_spiflash.c",
|
||||
"am_devices_spiflash.h"
|
||||
]
|
||||
},
|
||||
{
|
||||
"from": "utils",
|
||||
"to": "targets/TARGET_Ambiq_Micro/sdk/utils",
|
||||
"ignore": [
|
||||
"am_util_faultisr.c",
|
||||
"am_util_regdump.c"
|
||||
]
|
||||
},
|
||||
{
|
||||
"from": "mcu",
|
||||
"to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/sdk/mcu",
|
||||
"ignore": [
|
||||
"apollo",
|
||||
"apollo2",
|
||||
"apollo3p",
|
||||
"Makefile",
|
||||
"gcc",
|
||||
"iar",
|
||||
"keil"
|
||||
]
|
||||
},
|
||||
{
|
||||
"from": "CMSIS",
|
||||
"to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/sdk/CMSIS",
|
||||
"ignore": [
|
||||
"apollo1.h",
|
||||
"apollo2.h",
|
||||
"apollo3p.h",
|
||||
"system_apollo1.h",
|
||||
"system_apollo2.h",
|
||||
"system_apollo3p.h",
|
||||
"system_apollo1.c",
|
||||
"system_apollo2.c",
|
||||
"system_apollo3p.c",
|
||||
"startup_apollo1.s",
|
||||
"startup_apollo2.s",
|
||||
"startup_apollo3.s",
|
||||
"startup_apollo3p.s",
|
||||
"arm_math.h",
|
||||
"cmsis_armcc.h",
|
||||
"cmsis_armclang.h",
|
||||
"cmsis_compiler.h",
|
||||
"cmsis_gcc.h",
|
||||
"cmsis_iccarm.h",
|
||||
"cmsis_version.h",
|
||||
"core_cm4.h",
|
||||
"mpu_armv7.h",
|
||||
"arm_cortexM4l_math.lib",
|
||||
"arm_cortexM4lf_math.lib",
|
||||
"iar_cortexM4l_math.a",
|
||||
"iar_cortexM4lf_math.a",
|
||||
"libarm_cortexM4l_math.a"
|
||||
]
|
||||
},
|
||||
|
||||
{"from": "boards_sfe/artemis_dk/bsp", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_DK/bsp", "ignore": ["gcc", "bsp_pins.src"]},
|
||||
{"from": "boards_sfe/artemis_thing_plus/bsp", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_THING_PLUS/bsp", "ignore": ["gcc", "bsp_pins.src"]},
|
||||
{"from": "boards_sfe/edge/bsp", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_EDGE/bsp", "ignore": ["gcc", "bsp_pins.src"]},
|
||||
{"from": "boards_sfe/edge2/bsp", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_EDGE2/bsp", "ignore": ["gcc", "bsp_pins.src"]},
|
||||
{"from": "boards_sfe/redboard_artemis/bsp", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/bsp", "ignore": ["gcc", "bsp_pins.src"]},
|
||||
{"from": "boards_sfe/redboard_artemis_atp/bsp", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_ATP/bsp", "ignore": ["gcc", "bsp_pins.src"]},
|
||||
{"from": "boards_sfe/redboard_artemis_nano/bsp", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_NANO/bsp", "ignore": ["gcc", "bsp_pins.src"]},
|
||||
|
||||
{"from": "boards_sfe/common/third_party/hm01b0", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/COMPONENT_hm01b0/hm01b0", "ignore": []},
|
||||
{"from": "boards_sfe/common/third_party/lis2dh12", "to": "targets/TARGET_Ambiq_Micro/TARGET_Apollo3/COMPONENT_lis2dh12/lis2dh12", "ignore": []}
|
||||
],
|
||||
|
||||
"generate": {
|
||||
"pincfgs": {
|
||||
"peripherals": {
|
||||
"src": "{_sdk}/boards_sfe/common/support/apollo3/peripherals/pins.src",
|
||||
"dest": "{_mbed}/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralPinConfigs",
|
||||
"guard": "_APOLLO3_PERIPHERAL_PIN_CONFIGS_H_",
|
||||
"bgaguard": "AM_PACKAGE_BGA",
|
||||
"prefix": "AP3_PER"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
# requires:
|
||||
# - 'make' available at the command line
|
||||
# - 'arm-none-eabi-xxx' available at the command line (preferred version is q4-2018-major)
|
||||
|
||||
# example usage
|
||||
# locations:
|
||||
# from bsp repo root:
|
||||
# common/bsp_pinconfig/scripts/regen_bsp_libs.sh
|
||||
# from remote location: (requires $AMSDK environment variable -- {boards_sfe} can be whatever you named the root of the bsp repo )
|
||||
# $AMSDK/{boards_sfe}/common/bsp_pinconfig/scripts/regen_bsp_libs.sh -r $AMSDK/{boards_sfe}
|
||||
# arguments:
|
||||
# [-r $BSP_ROOT] path to bsp root optional -- defaults to the current directory
|
||||
# (should be specified when calling script remotely)
|
||||
# [-b $BOARDS_FILE] path to boards file optional -- defaults to all supported bsp boards
|
||||
# (for now boards must still have source files located in the bsp repo)
|
||||
|
||||
# setup
|
||||
set -e
|
||||
set -o errexit
|
||||
echo "" 1>&2
|
||||
|
||||
# get enclosing directory
|
||||
DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
|
||||
# defaults
|
||||
BSP_ROOT=.
|
||||
BOARDS_FILE=$DIR/configuration/boards.sh
|
||||
|
||||
# handle arguments
|
||||
while getopts ":r:b:" opt; do
|
||||
case $opt in
|
||||
r) BSP_ROOT="$OPTARG"
|
||||
;;
|
||||
b) BOARDS_FILE="$OPTARG"
|
||||
;;
|
||||
\?) echo "Invalid option -$OPTARG" 1>&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# verify bsp root
|
||||
echo "Using \$BSP_ROOT=$BSP_ROOT" 1>&2
|
||||
VFILE=$BSP_ROOT/README.md
|
||||
if [ -f "$VFILE" ];
|
||||
then
|
||||
echo "\$BSP_ROOT verification passed" 1>&2
|
||||
else
|
||||
echo "\$BSP_ROOT verification failed" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# load in boards to handle
|
||||
echo "Using \$BOARDS_FILE=$BOARDS_FILE" 1>&2
|
||||
source $BOARDS_FILE
|
||||
|
||||
echo "" 1>&2
|
||||
for value in $BOARDS
|
||||
do
|
||||
echo "Regenerating bsp library for: $value" 1>&2
|
||||
make -C $BSP_ROOT/$value/bsp/gcc
|
||||
done
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# requires:
|
||||
# - python3 available at the command line
|
||||
|
||||
# example usage
|
||||
# locations:
|
||||
# from bsp repo root:
|
||||
# common/bsp_pinconfig/scripts/regen_bsp_pins.sh
|
||||
# from remote location: (requires $AMSDK environment variable -- {boards_sfe} can be whatever you named the root of the bsp repo )
|
||||
# $AMSDK/{boards_sfe}/common/bsp_pinconfig/scripts/regen_bsp_pins.sh -r $AMSDK/{boards_sfe}
|
||||
# arguments:
|
||||
# [-r $BSP_ROOT] path to bsp root optional -- defaults to the current directory
|
||||
# (should be specified when calling script remotely)
|
||||
# [-b $BOARDS_FILE] path to boards file optional -- defaults to all supported bsp boards
|
||||
# (for now boards must still have source files located in the bsp repo)
|
||||
|
||||
# setup
|
||||
set -e
|
||||
set -o errexit
|
||||
echo "" 1>&2
|
||||
|
||||
# get enclosing directory
|
||||
DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
|
||||
# defaults
|
||||
BSP_ROOT=.
|
||||
BOARDS_FILE=$DIR/configuration/boards.sh
|
||||
|
||||
# handle arguments
|
||||
while getopts ":r:b:" opt; do
|
||||
case $opt in
|
||||
r) BSP_ROOT="$OPTARG"
|
||||
;;
|
||||
b) BOARDS_FILE="$OPTARG"
|
||||
;;
|
||||
\?) echo "Invalid option -$OPTARG" 1>&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# verify bsp root
|
||||
echo "Using \$BSP_ROOT=$BSP_ROOT" 1>&2
|
||||
VFILE=$BSP_ROOT/README.md
|
||||
if [ -f "$VFILE" ];
|
||||
then
|
||||
echo "\$BSP_ROOT verification passed" 1>&2
|
||||
else
|
||||
echo "\$BSP_ROOT verification failed" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# load in boards to handle
|
||||
echo "Using \$BOARDS_FILE=$BOARDS_FILE" 1>&2
|
||||
source $BOARDS_FILE
|
||||
|
||||
# generate bsp files for every board
|
||||
echo "" 1>&2
|
||||
for value in $BOARDS
|
||||
do
|
||||
echo "Regenerating bsp_pins files for: $value" 1>&2
|
||||
$BSP_ROOT/common/bsp_pinconfig/pinconfig.py $BSP_ROOT/$value/bsp/bsp_pins.src h > $BSP_ROOT/$value/bsp/am_bsp_pins.h
|
||||
$BSP_ROOT/common/bsp_pinconfig/pinconfig.py $BSP_ROOT/$value/bsp/bsp_pins.src c > $BSP_ROOT/$value/bsp/am_bsp_pins.c
|
||||
done
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# requires:
|
||||
# - see requirements of source scripts
|
||||
|
||||
# example usage
|
||||
# locations:
|
||||
# from bsp repo root:
|
||||
# common/bsp_pinconfig/scripts/regen_bsps.sh
|
||||
# from remote location: (requires $AMSDK environment variable -- {boards_sfe} can be whatever you named the root of the bsp repo )
|
||||
# $AMSDK/{boards_sfe}/common/bsp_pinconfig/scripts/regen_bsps.sh -r $AMSDK/{boards_sfe}
|
||||
# arguments:
|
||||
# [-r $BSP_ROOT] path to bsp root optional -- defaults to the current directory
|
||||
# (should be specified when calling script remotely)
|
||||
# [-b $BOARDS_FILE] path to boards file optional -- defaults to all supported bsp boards
|
||||
# (for now boards must still have source files located in the bsp repo)
|
||||
|
||||
# setup
|
||||
set -e
|
||||
set -o errexit
|
||||
echo "" 1>&2
|
||||
|
||||
# get enclosing directory
|
||||
DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
|
||||
|
||||
# defaults
|
||||
BSP_ROOT=.
|
||||
BOARDS_FILE=$BSP_ROOT/common/tools_sfe/scripts/configuration/boards.sh
|
||||
|
||||
# handle arguments
|
||||
while getopts ":r:b:" opt; do
|
||||
case $opt in
|
||||
r) BSP_ROOT="$OPTARG"
|
||||
;;
|
||||
b) BOARDS_FILE="$OPTARG"
|
||||
;;
|
||||
\?) echo "Invalid option -$OPTARG" 1>&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# regen pins and libs
|
||||
$BSP_ROOT/common/tools_sfe/scripts/regen_bsp_pins.sh -r $BSP_ROOT -b $BOARDS_FILE # regenerates source (.h and .c) files from the bsp_pins.src files
|
||||
$BSP_ROOT/common/tools_sfe/scripts/regen_bsp_libs.sh -r $BSP_ROOT -b $BOARDS_FILE # regenerates library archive files from bsp source (.h and .c) files
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3.8
|
||||
|
||||
# requires python3.8
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import shutil
|
||||
import os
|
||||
import subprocess
|
||||
from braceexpand import braceexpand as expand
|
||||
|
||||
# ***********************************************************************************
|
||||
#
|
||||
# Main function
|
||||
#
|
||||
# ***********************************************************************************
|
||||
def main():
|
||||
|
||||
# load configuration
|
||||
with open(args.config, 'r') as fin:
|
||||
config = json.loads(fin.read())
|
||||
|
||||
# handle copy steps
|
||||
for step in config['copy']:
|
||||
src_path = os.path.join(args.sdk, step['from'])
|
||||
dest_path = os.path.join(args.mbed, step['to'])
|
||||
ignore_patterns = step['ignore']
|
||||
print("copy")
|
||||
print("from '" + src_path + "'")
|
||||
print("to '" + dest_path + "'")
|
||||
print("\texcluding:")
|
||||
print(ignore_patterns)
|
||||
print()
|
||||
shutil.rmtree(dest_path, ignore_errors=True)
|
||||
shutil.copytree(src_path, dest_path, ignore=shutil.ignore_patterns(*ignore_patterns), dirs_exist_ok=True)
|
||||
|
||||
# handle pincfg generation
|
||||
print('generate pincfgs:')
|
||||
def absolutify(path):
|
||||
new_path = path
|
||||
new_path = new_path.replace('{_mbed}', args.mbed)
|
||||
new_path = new_path.replace('{_sdk}', args.sdk)
|
||||
return new_path
|
||||
|
||||
selectors = ['c', 'h']
|
||||
for name, job in config['generate']['pincfgs'].items():
|
||||
print('\t', name)
|
||||
for selector in selectors:
|
||||
results = subprocess.run( [
|
||||
'python',
|
||||
absolutify('{_sdk}/boards_sfe/common/bsp_pinconfig/pinconfig.py'),
|
||||
absolutify(job['src']), selector,
|
||||
'-g', job['guard'],
|
||||
'-p', job['prefix'],
|
||||
'-b', job['bgaguard']
|
||||
],
|
||||
capture_output=True)
|
||||
|
||||
with open(absolutify(job['dest']) + '.' + selector, 'wb') as fout:
|
||||
fout.write(results.stdout)
|
||||
errors = str(results.stderr)
|
||||
if errors != "b''":
|
||||
print('error: ', str(results.stderr))
|
||||
|
||||
exit()
|
||||
|
||||
|
||||
|
||||
# ******************************************************************************
|
||||
#
|
||||
# Main program flow
|
||||
#
|
||||
# ******************************************************************************
|
||||
if __name__ == '__main__':
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Utility to generate GCC flag and symbol files from mbed build profiles')
|
||||
|
||||
parser.add_argument('-m', '--mbed', dest='mbed', required=True, help='path to root of mbed')
|
||||
parser.add_argument('-c', '--config', dest='config', required=False, default='./boards_sfe/common/tools_sfe/scripts/configuration/mbed-config.json', help='path to the json configuration file')
|
||||
parser.add_argument('-s', '--sdk', dest='sdk', required=False, default='.', help='path to root of AmbiqSuiteSDK')
|
||||
parser.add_argument('-v', '--verbose', default=0, help='enable verbose output', action='store_true')
|
||||
|
||||
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()
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# requires:
|
||||
|
||||
# a script to aid in upgrading the AmbiqSuite SDK
|
||||
|
||||
# # get enclosing directory
|
||||
# DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")") # can handle symlinks but fails on mac
|
||||
DIR=$(dirname -- "$BASH_SOURCE") # assumes no symlinks.... (for mac compatibility)
|
||||
|
||||
# import sh-realpath
|
||||
source $DIR/utility/sh-realpath/realpath.sh
|
||||
|
||||
# defaults
|
||||
SDK_ROOT=$DIR/../../../..
|
||||
UPGRADE_ROOT=
|
||||
|
||||
# handle arguments
|
||||
while getopts ":r:u:" opt; do
|
||||
case $opt in
|
||||
r) SDK_ROOT="$OPTARG"
|
||||
;;
|
||||
u) UPGRADE_ROOT="$OPTARG"
|
||||
;;
|
||||
\?) echo "Invalid option -$OPTARG" 1>&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ensure user provided -u option
|
||||
if [ -z "$UPGRADE_ROOT" ]
|
||||
then
|
||||
echo "User must provide -u option (path to upgrade sdk directory)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# make a temporary directory to hold the old sdk
|
||||
TMP_DIR=$(mktemp -d -t ambiqsuite_sdk_upgrade_tmp)
|
||||
echo "created temporary directory $TMP_DIR"
|
||||
|
||||
# get the sdk folder name (and verify)
|
||||
SDK_ROOT=$(realpath $SDK_ROOT)
|
||||
SDK_NAME=$(basename $SDK_ROOT)
|
||||
echo "Got SDK name: $SDK_NAME"
|
||||
VFILE=$SDK_ROOT/VERSION.txt
|
||||
if [ -f "$VFILE" ];
|
||||
then
|
||||
echo "\$SDK_ROOT verification passed" 1>&2
|
||||
else
|
||||
echo "\$SDK_ROOT verification failed" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# get the upgrade folder (and verify)
|
||||
UPGRADE_ROOT=$(realpath $UPGRADE_ROOT)
|
||||
echo "Got upgrade SDK path: $UPGRADE_ROOT"
|
||||
VFILE=$UPGRADE_ROOT/VERSION.txt
|
||||
if [ -f "$VFILE" ];
|
||||
then
|
||||
echo "\$UPGRADE_ROOT verification passed" 1>&2
|
||||
else
|
||||
echo "\$UPGRADE_ROOT verification failed" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# copy sdk to temporary dir (being sure to keep hidden files)
|
||||
cp -r $SDK_ROOT/. $TMP_DIR
|
||||
|
||||
# remove old directory
|
||||
rm -rf $SDK_ROOT
|
||||
|
||||
# copy the upgrade to the SDK_ROOT
|
||||
cp -r $UPGRADE_ROOT $SDK_ROOT
|
||||
|
||||
# copy important directories from the old SDK to the upgrade
|
||||
cp -r $TMP_DIR/.git* $SDK_ROOT
|
||||
cp -r $TMP_DIR/README.md $SDK_ROOT
|
||||
cp -r $TMP_DIR/boards_sfe $SDK_ROOT
|
||||
|
||||
# clean up temporary folder
|
||||
rm -rf $TMP_DIR
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
# this script relies on the environment variable $AMSDK being set to the root of your AmbiqSuite SDK
|
||||
# use it when you have a pre-built binary file to upload onto a board
|
||||
|
||||
# default variables
|
||||
BINFILE=.
|
||||
ASB_UPLOAD_BAUD=115200
|
||||
PORT=COM4
|
||||
|
||||
# immutables
|
||||
COMMONPATH=$AMSDK/boards_sfe/common
|
||||
PYTHON3=python3
|
||||
AMBIQ_BIN2BOARD=$COMMONPATH/tools_sfe/asb/asb.py
|
||||
BINPATH=temp_
|
||||
|
||||
# handle arguments
|
||||
while getopts ":p:f:b:u:" opt; do
|
||||
case $opt in
|
||||
p) PORT="$OPTARG"
|
||||
;;
|
||||
f) BINFILE="$OPTARG"
|
||||
;;
|
||||
b) ASB_UPLOAD_BAUD="$OPTARG"
|
||||
;;
|
||||
u) UPLOADER="$OPTARG"
|
||||
;;
|
||||
\?) echo "Invalid option -$OPTARG" >&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
printf "Uploading file with Ambiq Secure Bootloader:\n%s\n\n" "$BINFILE"
|
||||
|
||||
$PYTHON3 $AMBIQ_BIN2BOARD --bin $BINFILE --load-address-blob 0x20000 --magic-num 0xCB -o $BINPATH --version 0x0 --load-address-wired 0xC000 -i 6 --options 0x1 -b $ASB_UPLOAD_BAUD -port $PORT -r 2 -v
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Michael Kropat
|
||||
|
||||
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.
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
.PHONY: test
|
||||
test: lint unit-test
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
-shellcheck realpath.sh
|
||||
-checkbashisms realpath.sh
|
||||
|
||||
.PHONY: unit-test
|
||||
unit-test: t/*
|
||||
|
||||
t/%: force
|
||||
bash "$@"
|
||||
dash "$@"
|
||||
|
||||
.PHONY: force
|
||||
force: ;
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
# sh-realpath
|
||||
|
||||
*A portable, pure shell implementation of realpath*
|
||||
|
||||
Copy the functions in [realpath.sh](realpath.sh) into your shell script to
|
||||
avoid introducing a dependency on either `realpath` or `readlink -f`, since:
|
||||
|
||||
* `realpath` does not come installed by default
|
||||
* `readlink -f` **is not portable** to OS-X ([relevant man page](https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man1/readlink.1.html))
|
||||
|
||||
## Usage
|
||||
|
||||
$ source ./realpath.sh
|
||||
$ realpath /proc/self
|
||||
/proc/2772
|
||||
|
||||
Or we can get tricky:
|
||||
|
||||
$ cd /tmp
|
||||
$ mkdir -p somedir/targetdir somedir/anotherdir
|
||||
$ ln -s somedir somedirlink
|
||||
$ ln -s somedir/anotherdir/../anotherlink somelink
|
||||
$ ln -s targetdir/targetpath somedir/anotherlink
|
||||
$ realpath .///somedirlink/././anotherdir/../../somelink
|
||||
/tmp/somedir/targetdir/targetpath
|
||||
|
||||
## API
|
||||
|
||||
Note: unlike `realpath(1)`, these functions take no options; **do not** use `--` to escape any arguments
|
||||
|
||||
| Function | Description
|
||||
| --------------------------------- | -------------
|
||||
| <pre>realpath PATH</pre> | Resolve all symlinks to `PATH`, then output the canonicalized result
|
||||
| <pre>resolve_symlinks PATH</pre> | If `PATH` is a symlink, follow it as many times as possible; output the path of the first non-symlink found
|
||||
| <pre>canonicalize_path PATH</pre> | Output absolute path that `PATH` refers to, resolving any relative directories (`.`, `..`) in `PATH` and any symlinks in `PATH`'s ancestor directories
|
||||
|
||||
### readlink Emulation
|
||||
|
||||
`realpath.sh` includes optional readlink emulation. It exposes a `readlink`
|
||||
function that calls the system `readlink(1)` if it exists. Otherwise it uses
|
||||
`stat(1)` to emulate the same functionality. In contrast to the functions in
|
||||
the previous section, you may pass `--` as the first argument, since you may be
|
||||
calling the system `readlink(1)`.
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
#!/bin/sh
|
||||
|
||||
realpath() {
|
||||
canonicalize_path "$(resolve_symlinks "$1")"
|
||||
}
|
||||
|
||||
resolve_symlinks() {
|
||||
_resolve_symlinks "$1"
|
||||
}
|
||||
|
||||
_resolve_symlinks() {
|
||||
_assert_no_path_cycles "$@" || return
|
||||
|
||||
local dir_context path
|
||||
path=$(readlink -- "$1")
|
||||
if [ $? -eq 0 ]; then
|
||||
dir_context=$(dirname -- "$1")
|
||||
_resolve_symlinks "$(_prepend_dir_context_if_necessary "$dir_context" "$path")" "$@"
|
||||
else
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
_prepend_dir_context_if_necessary() {
|
||||
if [ "$1" = . ]; then
|
||||
printf '%s\n' "$2"
|
||||
else
|
||||
_prepend_path_if_relative "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_prepend_path_if_relative() {
|
||||
case "$2" in
|
||||
/* ) printf '%s\n' "$2" ;;
|
||||
* ) printf '%s\n' "$1/$2" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_assert_no_path_cycles() {
|
||||
local target path
|
||||
|
||||
target=$1
|
||||
shift
|
||||
|
||||
for path in "$@"; do
|
||||
if [ "$path" = "$target" ]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
canonicalize_path() {
|
||||
if [ -d "$1" ]; then
|
||||
_canonicalize_dir_path "$1"
|
||||
else
|
||||
_canonicalize_file_path "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
_canonicalize_dir_path() {
|
||||
(cd "$1" 2>/dev/null && pwd -P)
|
||||
}
|
||||
|
||||
_canonicalize_file_path() {
|
||||
local dir file
|
||||
dir=$(dirname -- "$1")
|
||||
file=$(basename -- "$1")
|
||||
(cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
|
||||
}
|
||||
|
||||
# Optionally, you may also want to include:
|
||||
|
||||
### readlink emulation ###
|
||||
|
||||
readlink() {
|
||||
if _has_command readlink; then
|
||||
_system_readlink "$@"
|
||||
else
|
||||
_emulated_readlink "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
_has_command() {
|
||||
hash -- "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
_system_readlink() {
|
||||
command readlink "$@"
|
||||
}
|
||||
|
||||
_emulated_readlink() {
|
||||
if [ "$1" = -- ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
_gnu_stat_readlink "$@" || _bsd_stat_readlink "$@"
|
||||
}
|
||||
|
||||
_gnu_stat_readlink() {
|
||||
local output
|
||||
output=$(stat -c %N -- "$1" 2>/dev/null) &&
|
||||
|
||||
printf '%s\n' "$output" |
|
||||
sed "s/^‘[^’]*’ -> ‘\(.*\)’/\1/
|
||||
s/^'[^']*' -> '\(.*\)'/\1/"
|
||||
# FIXME: handle newlines
|
||||
}
|
||||
|
||||
_bsd_stat_readlink() {
|
||||
stat -f %Y -- "$1" 2>/dev/null
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
#!/bin/sh
|
||||
|
||||
. ./realpath.sh
|
||||
|
||||
setUp() {
|
||||
_test_previousdir=$PWD
|
||||
_test_workingdir=$(mktemp -d -t sh-realpath.XXXXXX)
|
||||
cd -P -- "$_test_workingdir"
|
||||
}
|
||||
|
||||
tearDown() {
|
||||
cd -- "$_test_previousdir"
|
||||
rm -rf -- "$_test_workingdir"
|
||||
}
|
||||
|
||||
it_outputs_pwd_when_passed_zero_args() {
|
||||
local output
|
||||
|
||||
output=$(canonicalize_path)
|
||||
|
||||
assertTrue '`canonicalize_path` succeeds' $?
|
||||
assertEquals 'outputs $PWD' "$PWD/" "$output"
|
||||
}
|
||||
|
||||
it_outputs_absolute_path_to_target_when_passed_the_name_of_a_non_existent_file() {
|
||||
local output
|
||||
|
||||
output=$(canonicalize_path non_existent_file)
|
||||
|
||||
assertTrue '`canonicalize_path non_existent_file` succeeds' $?
|
||||
assertEquals 'output is "$PWD/non_existent_file"' "$PWD/non_existent_file" "$output"
|
||||
}
|
||||
|
||||
it_returns_an_error_when_passed_a_path_in_a_non_existent_dir() {
|
||||
local output
|
||||
|
||||
output=$(canonicalize_path non_existent_dir/somepath 2>&1)
|
||||
|
||||
assertFalse '`canonicalize_path non_existent_dir/somepath` fails' $?
|
||||
assertNull 'no output' "$output"
|
||||
}
|
||||
|
||||
it_outputs_absolute_path_when_passed_the_name_of_a_path_in_a_subdir() {
|
||||
local output
|
||||
mkdir somedir
|
||||
|
||||
output=$(canonicalize_path somedir/somepath)
|
||||
|
||||
assertTrue '`canonicalize_path somedir/somepath` succeeds' $?
|
||||
assertEquals 'output is "$PWD/somedir/somepath"' "$PWD/somedir/somepath" "$output"
|
||||
}
|
||||
|
||||
it_returns_an_error_when_passed_a_path_in_a_symlink_to_nowhere() {
|
||||
ln -s non/existent/dir somelink
|
||||
|
||||
canonicalize_path somelink/somepath
|
||||
|
||||
assertFalse '`canonicalize_path somelink/somepath` fails' $?
|
||||
}
|
||||
|
||||
it_returns_the_target_dir_when_passed_a_symlink_to_another_dir() {
|
||||
local output
|
||||
mkdir somedir
|
||||
ln -s somedir somelink
|
||||
|
||||
output=$(canonicalize_path somelink)
|
||||
|
||||
assertTrue '`canonicalize_path somelink` succeeds' $?
|
||||
assertEquals 'output is "$PWD/somedir"' "$PWD/somedir" "$output"
|
||||
}
|
||||
|
||||
it_returns_absolute_path_of_target_directory_when_passed_a_path_in_a_symlink_to_another_dir() {
|
||||
local output
|
||||
mkdir somedir
|
||||
ln -s somedir somelink
|
||||
|
||||
output=$(canonicalize_path somelink/somepath)
|
||||
|
||||
assertTrue '`canonicalize_path somelink/somepath` succeeds' $?
|
||||
assertEquals 'output is "$PWD/somedir/somepath"' "$PWD/somedir/somepath" "$output"
|
||||
}
|
||||
|
||||
it_collapses_current_dir_references() {
|
||||
local output
|
||||
|
||||
output=$(canonicalize_path ././somepath)
|
||||
|
||||
assertTrue '`canonicalize_path ././somepath` succeeds' $?
|
||||
assertEquals 'output is "$PWD/somepath"' "$PWD/somepath" "$output"
|
||||
}
|
||||
|
||||
it_collapses_extra_slashes() {
|
||||
local output
|
||||
|
||||
output=$(canonicalize_path .///somepath)
|
||||
|
||||
assertTrue '`canonicalize_path .///somepath` succeeds' $?
|
||||
assertEquals 'output is "$PWD/somepath"' "$PWD/somepath" "$output"
|
||||
}
|
||||
|
||||
it_collapses_parent_dir_references() {
|
||||
local output
|
||||
mkdir -p somedir/anotherdir
|
||||
|
||||
output=$(canonicalize_path somedir/anotherdir/../../somepath)
|
||||
|
||||
assertTrue '`canonicalize_path somedir/anotherdir/../../somepath` succeeds' $?
|
||||
assertEquals 'output is "$PWD/somepath"' "$PWD/somepath" "$output"
|
||||
}
|
||||
|
||||
|
||||
##### Test Harness #####
|
||||
|
||||
# suite() -- find and register tests to be run
|
||||
# Derived from Gary Bernhardt's screencast #68
|
||||
# (https://www.destroyallsoftware.com/screencasts/catalog/test-driving-shell-scripts)
|
||||
suite() {
|
||||
local name tests
|
||||
tests=$(grep ^it_ "$0" | cut -d '(' -f 1)
|
||||
for name in $tests; do
|
||||
suite_addTest "$name"
|
||||
done
|
||||
}
|
||||
|
||||
if hash shunit2 2>/dev/null; then
|
||||
. shunit2
|
||||
else
|
||||
echo 'Error: shunit2(1) could not be located. Please install it on your $PATH.' >&2
|
||||
exit 1
|
||||
fi
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
|
||||
. ./realpath.sh
|
||||
|
||||
setUp() {
|
||||
unset _system_readlink _gnu_stat_readlink _bsd_stat_readlink
|
||||
|
||||
_has_command() {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
it_calls_system_readlink_when_has_command_readlink_is_true() {
|
||||
_has_command() {
|
||||
test "$1" = readlink
|
||||
}
|
||||
|
||||
local readlink_arg1 readlink_arg2
|
||||
_system_readlink() {
|
||||
readlink_arg1="$1"
|
||||
readlink_arg2="$2"
|
||||
}
|
||||
|
||||
readlink -- some/path
|
||||
|
||||
assertEquals -- "$readlink_arg1"
|
||||
assertEquals some/path "$readlink_arg2"
|
||||
}
|
||||
|
||||
it_calls__gnu_stat_readlink_when_has_command_readlink_is_false() {
|
||||
local called
|
||||
_gnu_stat_readlink() {
|
||||
called=1
|
||||
}
|
||||
|
||||
readlink -- some/path
|
||||
|
||||
assertNotNull "_gnu_stat_readlink called" "$called"
|
||||
}
|
||||
|
||||
it_passes_actual_arg_to__gnu_stat_readlink() {
|
||||
local arg
|
||||
_gnu_stat_readlink() {
|
||||
arg="$1"
|
||||
}
|
||||
|
||||
readlink -- some/path
|
||||
|
||||
assertEquals some/path "$arg"
|
||||
}
|
||||
|
||||
it_passes_first_arg_to__gnu_stat_readlink_when_no_dashes() {
|
||||
local arg
|
||||
_gnu_stat_readlink() {
|
||||
arg="$1"
|
||||
}
|
||||
|
||||
readlink some/path
|
||||
|
||||
assertEquals some/path "$arg"
|
||||
}
|
||||
|
||||
it_doesnt_call__bsd_stat_readlink_when__gnu_stat_readlink_returns_true() {
|
||||
_gnu_stat_readlink() {
|
||||
return 0
|
||||
}
|
||||
|
||||
local called
|
||||
_bsd_stat_readlink() {
|
||||
called=1
|
||||
}
|
||||
|
||||
readlink -- some/path
|
||||
|
||||
assertNull "_bsd_stat_readlink not called" "$called"
|
||||
}
|
||||
|
||||
it_calls__bsd_stat_readlink_when__gnu_stat_readlink_returns_false() {
|
||||
_gnu_stat_readlink() {
|
||||
return 1
|
||||
}
|
||||
|
||||
local called
|
||||
_bsd_stat_readlink() {
|
||||
called=1
|
||||
}
|
||||
|
||||
readlink -- some/path
|
||||
|
||||
assertNotNull "_bsd_stat_readlink called" "$called"
|
||||
}
|
||||
|
||||
it_passes_actual_arg_to__bsd_stat_readlink() {
|
||||
_gnu_stat_readlink() {
|
||||
return 1
|
||||
}
|
||||
|
||||
local arg
|
||||
_bsd_stat_readlink() {
|
||||
arg="$1"
|
||||
}
|
||||
|
||||
readlink -- some/path
|
||||
|
||||
assertEquals some/path "$arg"
|
||||
}
|
||||
|
||||
##### Test Harness #####
|
||||
|
||||
# suite() -- find and register tests to be run
|
||||
# Derived from Gary Bernhardt's screencast #68
|
||||
# (https://www.destroyallsoftware.com/screencasts/catalog/test-driving-shell-scripts)
|
||||
suite() {
|
||||
local name tests
|
||||
tests=$(grep ^it_ "$0" | cut -d '(' -f 1)
|
||||
for name in $tests; do
|
||||
suite_addTest "$name"
|
||||
done
|
||||
}
|
||||
|
||||
if hash shunit2 2>/dev/null; then
|
||||
. shunit2
|
||||
else
|
||||
echo 'Error: shunit2(1) could not be located. Please install it on your $PATH.' >&2
|
||||
exit 1
|
||||
fi
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
#!/bin/sh
|
||||
|
||||
. ./realpath.sh
|
||||
|
||||
setUp() {
|
||||
_test_previousdir=$PWD
|
||||
_test_workingdir=$(mktemp -d -t sh-realpath.XXXXXX)
|
||||
cd -P -- "$_test_workingdir"
|
||||
}
|
||||
|
||||
tearDown() {
|
||||
cd -- "$_test_previousdir"
|
||||
rm -rf -- "$_test_workingdir"
|
||||
}
|
||||
|
||||
it_outputs_pwd_when_passed_zero_args() {
|
||||
local output
|
||||
|
||||
output=$(realpath)
|
||||
|
||||
assertTrue '`realpath` succeeds' $?
|
||||
assertEquals 'outputs "$PWD/"' "$PWD/" "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_canonical_path_of_crazy_paths() {
|
||||
local output
|
||||
mkdir -p somedir/targetdir somedir/anotherdir
|
||||
ln -s somedir somedirlink
|
||||
ln -s somedir/anotherdir/../anotherlink somelink
|
||||
ln -s targetdir/targetpath somedir/anotherlink
|
||||
|
||||
output=$(realpath .///somedirlink/././anotherdir/../../somelink)
|
||||
|
||||
assertTrue '`realpath .///somedirlink/././anotherdir/../../somelink` succeeds' $?
|
||||
assertEquals 'outputs "$PWD/somedir/targetdir/targetpath"' "$PWD/somedir/targetdir/targetpath" "$output"
|
||||
}
|
||||
|
||||
##### Test Harness #####
|
||||
|
||||
# suite() -- find and register tests to be run
|
||||
# Derived from Gary Bernhardt's screencast #68
|
||||
# (https://www.destroyallsoftware.com/screencasts/catalog/test-driving-shell-scripts)
|
||||
suite() {
|
||||
local name tests
|
||||
tests=$(grep ^it_ "$0" | cut -d '(' -f 1)
|
||||
for name in $tests; do
|
||||
suite_addTest "$name"
|
||||
done
|
||||
}
|
||||
|
||||
if hash shunit2 2>/dev/null; then
|
||||
. shunit2
|
||||
else
|
||||
echo 'Error: shunit2(1) could not be located. Please install it on your $PATH.' >&2
|
||||
exit 1
|
||||
fi
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
#!/bin/sh
|
||||
|
||||
. ./realpath.sh
|
||||
|
||||
setUp() {
|
||||
_test_previousdir=$PWD
|
||||
_test_workingdir=$(mktemp -d -t sh-realpath.XXXXXX)
|
||||
cd -P -- "$_test_workingdir"
|
||||
}
|
||||
|
||||
tearDown() {
|
||||
cd -- "$_test_previousdir"
|
||||
rm -rf -- "$_test_workingdir"
|
||||
}
|
||||
|
||||
it_outputs_nothing_when_passed_nothing() {
|
||||
local output
|
||||
output=$(resolve_symlinks)
|
||||
|
||||
assertTrue '`resolve_symlinks` succeeds' $?
|
||||
assertNull 'there is no output' "$output"
|
||||
}
|
||||
|
||||
it_outputs_filename_when_passed_a_nonexistent_filename() {
|
||||
local output
|
||||
output=$(resolve_symlinks non_existent_file)
|
||||
|
||||
assertTrue '`resolve_symlinks non_existent_file` succeeds' $?
|
||||
assertEquals 'output is "non_existent_file"' non_existent_file "$output"
|
||||
}
|
||||
|
||||
it_outputs_filename_when_passed_a_file_that_exists() {
|
||||
: >|somefile
|
||||
|
||||
output=$(resolve_symlinks somefile)
|
||||
|
||||
assertTrue '`resolve_symlinks somefile` succeeds' $?
|
||||
assertEquals 'output is "somefile"' somefile "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_target_when_passed_a_symlink_to_a_file_that_doesnt_exist() {
|
||||
local output
|
||||
ln -s non_existent_file somelink
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "non_existent_file"' non_existent_file "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_target_when_passed_a_symlink_to_a_file_that_exists() {
|
||||
local output
|
||||
ln -s somefile somelink
|
||||
: >|somefile
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "somefile"' somefile "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_target_when_passed_a_symlink_in_a_child_dir() {
|
||||
local output
|
||||
mkdir somedir
|
||||
ln -s somepath somedir/somelink
|
||||
|
||||
output=$(resolve_symlinks somedir/somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somedir/somelink` succeeds' $?
|
||||
assertEquals 'output is "somedir/somepath"' somedir/somepath "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_final_target_when_passed_a_symlink_to_a_symlink_to_a_file() {
|
||||
local output
|
||||
ln -s anotherlink somelink
|
||||
ln -s somepath anotherlink
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "somepath"' somepath "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_final_target_with_path_when_passed_a_symlink_to_a_file_in_another_dir() {
|
||||
local output
|
||||
ln -s somedir/somepath somelink
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "somedir/somepath"' somedir/somepath "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_final_target_with_path_when_passed_a_symlink_to_a_symlink_in_another_dir() {
|
||||
local output
|
||||
ln -s somedir/anotherlink somelink
|
||||
mkdir somedir
|
||||
ln -s somepath somedir/anotherlink
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "somedir/somepath"' somedir/somepath "$output"
|
||||
}
|
||||
|
||||
it_outputs_a_valid_path_to_the_current_dir_when_passed_a_symlink_that_has_trailing_dots() {
|
||||
local output
|
||||
ln -s somepath/.. somelink
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "somepath/.."' somepath/.. "$output"
|
||||
}
|
||||
|
||||
it_outputs_a_valid_path_to_the_final_target_when_passed_a_symlink_that_references_the_parent_dir() {
|
||||
local output
|
||||
mkdir somedir
|
||||
ln -s ../somepath somedir/somelink
|
||||
|
||||
output=$(resolve_symlinks somedir/somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somedir/somelink` succeeds' $?
|
||||
assertEquals 'output is "somedir/../somepath"' somedir/../somepath "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_absolute_path_when_passed_a_symlink_to_an_absolute_path() {
|
||||
local output
|
||||
ln -s /some/absolute/path somelink
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "/some/absolute/path"' /some/absolute/path "$output"
|
||||
}
|
||||
|
||||
it_outputs_the_final_target_when_passed_a_symlink_to_an_absolute_path_symlink() {
|
||||
local output
|
||||
ln -s $PWD/anotherlink somelink
|
||||
ln -s somepath anotherlink
|
||||
|
||||
output=$(resolve_symlinks somelink)
|
||||
|
||||
assertTrue '`resolve_symlinks somelink` succeeds' $?
|
||||
assertEquals 'output is "$PWD/somepath"' $PWD/somepath "$output"
|
||||
}
|
||||
|
||||
it_returns_an_error_when_passed_a_symlink_to_a_symlink_to_a_symlink_that_points_to_the_first_symlink() {
|
||||
ln -s anotherlink somelink
|
||||
ln -s circularlink anotherlink
|
||||
ln -s somelink circularlink
|
||||
|
||||
resolve_symlinks somelink
|
||||
|
||||
assertFalse '`resolve_symlinks somelink` fails' $?
|
||||
}
|
||||
|
||||
|
||||
##### Test Harness #####
|
||||
|
||||
# suite() -- find and register tests to be run
|
||||
# Derived from Gary Bernhardt's screencast #68
|
||||
# (https://www.destroyallsoftware.com/screencasts/catalog/test-driving-shell-scripts)
|
||||
suite() {
|
||||
local name tests
|
||||
tests=$(grep ^it_ "$0" | cut -d '(' -f 1)
|
||||
for name in $tests; do
|
||||
suite_addTest "$name"
|
||||
done
|
||||
}
|
||||
|
||||
if hash shunit2 2>/dev/null; then
|
||||
. shunit2
|
||||
else
|
||||
echo 'Error: shunit2(1) could not be located. Please install it on your $PATH.' >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
Vendored
+152
@@ -0,0 +1,152 @@
|
||||
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-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: |
|
||||
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: 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: |
|
||||
pyinstaller --onefile svl/svl.py
|
||||
|
||||
- name: copy
|
||||
run: |
|
||||
rm -rf ./svl/dist/macosx
|
||||
mkdir -p ./svl/dist/macosx
|
||||
mv ./dist/svl ./svl/dist/macosx/svl
|
||||
|
||||
- name: commit
|
||||
run: |
|
||||
cd ./svl
|
||||
git add ./dist/macosx/*
|
||||
git commit -m "generated macosx executable"
|
||||
git push
|
||||
cd ${GITHUB_WORKSPACE}
|
||||
@@ -0,0 +1,131 @@
|
||||
# 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,3 @@
|
||||

|
||||
|
||||
# Apollo3 Uploader - SparkFun Variable Loader (SVL)
|
||||
+405
@@ -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
|
||||
+763
@@ -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
|
||||
}
|
||||
+240
@@ -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;
|
||||
}
|
||||
+47
@@ -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_
|
||||
+69
@@ -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;
|
||||
}
|
||||
+20
@@ -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_
|
||||
+70
@@ -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++;
|
||||
// }
|
||||
}
|
||||
+15
@@ -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_
|
||||
+119
@@ -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;
|
||||
}
|
||||
+18
@@ -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.
Vendored
Executable
BIN
Binary file not shown.
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()
|
||||
@@ -0,0 +1,91 @@
|
||||
/* stack: dynamic */
|
||||
/* heap: dynamic */
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash (rx) : ORIGIN = 0x0000C000, LENGTH = 960K
|
||||
sram (rwx) : ORIGIN = 0x10000000, LENGTH = 384K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* text: executable code */
|
||||
/* located in _flash_ */
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_stext = .;
|
||||
KEEP(*(.isr_vector))
|
||||
KEEP(*(.ble_patch))
|
||||
*(.text)
|
||||
*(.text*)
|
||||
|
||||
__init_array_start = .;
|
||||
KEEP(*(.init_array*))
|
||||
__init_array_end = .;
|
||||
|
||||
/* .rodata */
|
||||
. = ALIGN(4);
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
} > flash
|
||||
|
||||
/* data: uniquely initialized symbols */
|
||||
/* loaded into flash region, copied to sram region at startup */
|
||||
/* VMA appears in sram region, LMA is in flash region for initialization */
|
||||
/* _init_data used by startup to locate flash region copy of data */
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
*(.data)
|
||||
*(.data*)
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} > sram AT>flash
|
||||
_init_data = LOADADDR(.data); /* used by startup to initialize data */
|
||||
|
||||
/* bss: zero-initialized symbols */
|
||||
/* don't require flash memory to remember their value */
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} > sram
|
||||
|
||||
/* heap: RAM memory that can be dynamically allocated in the upward direction (increasing memory addresses) */
|
||||
/* _sheap is used to identify the beginning of available dynamic memory */
|
||||
.heap (NOLOAD):
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__end__ = .;
|
||||
PROVIDE( end = . );
|
||||
_sheap = .;
|
||||
} >sram
|
||||
|
||||
/* dmz: the no-mans-land between the stack and the heap */
|
||||
/* purpose is to place padding between initial (empty) stack and heap */
|
||||
.dmz (NOLOAD):
|
||||
{
|
||||
. = ORIGIN(sram) + LENGTH(sram) - 8; /* Automatically give the rest of the space in sram to the stack */
|
||||
. = ALIGN(8);
|
||||
}
|
||||
|
||||
/* stack: RAM memory that can be dynamically allocated in the downward direction (decreasing memory addresses) */
|
||||
/* _sstack is used to set the initial stack pointer */
|
||||
.stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(8);
|
||||
_sstack = .;
|
||||
} >sram
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/* stack: dynamic */
|
||||
/* heap: dynamic */
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash (rx) : ORIGIN = 0x00010000, LENGTH = 960K /*Modified from 0xC000 to work with SparkFun SVL*/
|
||||
sram (rwx) : ORIGIN = 0x10000000, LENGTH = 384K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* text: executable code */
|
||||
/* located in _flash_ */
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_stext = .;
|
||||
KEEP(*(.isr_vector))
|
||||
KEEP(*(.ble_patch))
|
||||
*(.text)
|
||||
*(.text*)
|
||||
|
||||
__init_array_start = .;
|
||||
KEEP(*(.init_array*))
|
||||
__init_array_end = .;
|
||||
|
||||
/* .rodata */
|
||||
. = ALIGN(4);
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
} > flash
|
||||
|
||||
/* data: uniquely initialized symbols */
|
||||
/* loaded into flash region, copied to sram region at startup */
|
||||
/* VMA appears in sram region, LMA is in flash region for initialization */
|
||||
/* _init_data used by startup to locate flash region copy of data */
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
*(.data)
|
||||
*(.data*)
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} > sram AT>flash
|
||||
_init_data = LOADADDR(.data); /* used by startup to initialize data */
|
||||
|
||||
/* bss: zero-initialized symbols */
|
||||
/* don't require flash memory to remember their value */
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} > sram
|
||||
|
||||
/* heap: RAM memory that can be dynamically allocated in the upward direction (increasing memory addresses) */
|
||||
/* _sheap is used to identify the beginning of available dynamic memory */
|
||||
.heap (NOLOAD):
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__end__ = .;
|
||||
PROVIDE( end = . );
|
||||
_sheap = .;
|
||||
} >sram
|
||||
|
||||
/* dmz: the no-mans-land between the stack and the heap */
|
||||
/* purpose is to place padding between initial (empty) stack and heap */
|
||||
.dmz (NOLOAD):
|
||||
{
|
||||
. = ORIGIN(sram) + LENGTH(sram) - 8; /* Automatically give the rest of the space in sram to the stack */
|
||||
. = ALIGN(8);
|
||||
}
|
||||
|
||||
/* stack: RAM memory that can be dynamically allocated in the downward direction (decreasing memory addresses) */
|
||||
/* _sstack is used to set the initial stack pointer */
|
||||
.stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(8);
|
||||
_sstack = .;
|
||||
} >sram
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// A starting point for projects with the Ambiqsuite SDK
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Main
|
||||
//
|
||||
//*****************************************************************************
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
// Startup boilerplate
|
||||
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0); // Set the clock frequency.
|
||||
am_hal_cachectrl_config(&am_hal_cachectrl_defaults); // Set the default cache configuration
|
||||
am_hal_cachectrl_enable();
|
||||
am_bsp_low_power_init(); // Configure the board for low power operation.
|
||||
|
||||
|
||||
// Loop forever while sleeping.
|
||||
while (1)
|
||||
{
|
||||
// Go to Deep Sleep.
|
||||
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
|
||||
}
|
||||
}
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
#******************************************************************************
|
||||
#
|
||||
# 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 := example
|
||||
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+=
|
||||
|
||||
# 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+=
|
||||
|
||||
# VPATH (Add paths to where your source files are located)
|
||||
VPATH=
|
||||
VPATH+= $(PROJECTPATH)/src
|
||||
VPATH+= $(SDKPATH)/utils
|
||||
VPATH+= $(COMMONPATH)/tools_sfe/templates
|
||||
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)_asb.bin
|
||||
svl: directories $(CONFIG)/$(TARGET)_svl.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)_asb.axf: LINKER_FILE = $(COMMONPATH)/tools_sfe/templates/asb_linker.ld
|
||||
$(CONFIG)/$(TARGET)_asb.axf: $(OBJS) $(LIBS)
|
||||
@echo " Linking $(COMPILERNAME) $@ with script $(LINKER_FILE)";\
|
||||
$(CC) -Wl,-T,$(LINKER_FILE) -o $@ $(OBJS) $(LFLAGS)
|
||||
|
||||
$(CONFIG)/$(TARGET)_svl.axf: LINKER_FILE = $(COMMONPATH)/tools_sfe/templates/asb_svl_linker.ld
|
||||
$(CONFIG)/$(TARGET)_svl.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)_asb.bin
|
||||
$(ASB_UPLOADER) --bin $(CONFIG)/$(TARGET)_asb.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
|
||||
$(SVL_UPLOADER) $(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
|
||||
@@ -0,0 +1,361 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file startup_gcc.c
|
||||
//!
|
||||
//! @brief Definitions for interrupt handlers, the vector table, and the stack.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// 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 v2.2.0-7-g63f7c2ba1 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Forward declaration of interrupt handlers.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern void Reset_Handler(void) __attribute ((naked));
|
||||
extern void NMI_Handler(void) __attribute ((weak));
|
||||
extern void HardFault_Handler(void) __attribute ((weak));
|
||||
extern void MemManage_Handler(void) __attribute ((weak, alias ("HardFault_Handler")));
|
||||
extern void BusFault_Handler(void) __attribute ((weak, alias ("HardFault_Handler")));
|
||||
extern void UsageFault_Handler(void) __attribute ((weak, alias ("HardFault_Handler")));
|
||||
extern void SecureFault_Handler(void) __attribute ((weak));
|
||||
extern void SVC_Handler(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void DebugMon_Handler(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void PendSV_Handler(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void SysTick_Handler(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
|
||||
extern void am_brownout_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_watchdog_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_rtc_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_vcomp_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_ioslave_ios_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_ioslave_acc_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_iomaster0_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_iomaster1_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_iomaster2_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_iomaster3_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_iomaster4_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_iomaster5_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_ble_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_gpio_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_ctimer_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_uart_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_uart1_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_scard_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_adc_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_pdm0_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_mspi0_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_software0_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr0_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr1_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr2_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr3_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr4_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr5_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr6_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_stimer_cmpr7_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
extern void am_clkgen_isr(void) __attribute ((weak, alias ("am_default_isr")));
|
||||
|
||||
extern void am_default_isr(void) __attribute ((weak));
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// The entry point for the application.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern int main(void);
|
||||
|
||||
// '_sstack' accesses the linker-provided address for the start of the stack
|
||||
// (which is a high address - stack goes top to bottom)
|
||||
extern void* _sstack;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// The vector table. Note that the proper constructs must be placed on this to
|
||||
// ensure that it ends up at physical address 0x0000.0000.
|
||||
//
|
||||
// Note: Aliasing and weakly exporting am_mpufault_isr, am_busfault_isr, and
|
||||
// am_usagefault_isr does not work if am_fault_isr is defined externally.
|
||||
// Therefore, we'll explicitly use am_fault_isr in the table for those vectors.
|
||||
//
|
||||
//*****************************************************************************
|
||||
__attribute__ ((section(".isr_vector")))
|
||||
void (* const g_am_pfnVectors[])(void) =
|
||||
{
|
||||
(void (*)(void))(&_sstack), // The initial stack pointer (provided by linker script)
|
||||
Reset_Handler, // The reset handler
|
||||
NMI_Handler, // The NMI handler
|
||||
HardFault_Handler, // The hard fault handler
|
||||
MemManage_Handler, // The MemManage_Handler
|
||||
BusFault_Handler, // The BusFault_Handler
|
||||
UsageFault_Handler, // The UsageFault_Handler
|
||||
SecureFault_Handler, // The SecureFault_Handler
|
||||
0, // Reserved
|
||||
0, // Reserved
|
||||
0, // Reserved
|
||||
SVC_Handler, // SVCall handler
|
||||
DebugMon_Handler, // Debug monitor handler
|
||||
0, // Reserved
|
||||
PendSV_Handler, // The PendSV handler
|
||||
SysTick_Handler, // The SysTick handler
|
||||
|
||||
//
|
||||
// Peripheral Interrupts
|
||||
//
|
||||
am_brownout_isr, // 0: Brownout (rstgen)
|
||||
am_watchdog_isr, // 1: Watchdog
|
||||
am_rtc_isr, // 2: RTC
|
||||
am_vcomp_isr, // 3: Voltage Comparator
|
||||
am_ioslave_ios_isr, // 4: I/O Slave general
|
||||
am_ioslave_acc_isr, // 5: I/O Slave access
|
||||
am_iomaster0_isr, // 6: I/O Master 0
|
||||
am_iomaster1_isr, // 7: I/O Master 1
|
||||
am_iomaster2_isr, // 8: I/O Master 2
|
||||
am_iomaster3_isr, // 9: I/O Master 3
|
||||
am_iomaster4_isr, // 10: I/O Master 4
|
||||
am_iomaster5_isr, // 11: I/O Master 5
|
||||
am_ble_isr, // 12: BLEIF
|
||||
am_gpio_isr, // 13: GPIO
|
||||
am_ctimer_isr, // 14: CTIMER
|
||||
am_uart_isr, // 15: UART0
|
||||
am_uart1_isr, // 16: UART1
|
||||
am_scard_isr, // 17: SCARD
|
||||
am_adc_isr, // 18: ADC
|
||||
am_pdm0_isr, // 19: PDM
|
||||
am_mspi0_isr, // 20: MSPI0
|
||||
am_software0_isr, // 21: SOFTWARE0
|
||||
am_stimer_isr, // 22: SYSTEM TIMER
|
||||
am_stimer_cmpr0_isr, // 23: SYSTEM TIMER COMPARE0
|
||||
am_stimer_cmpr1_isr, // 24: SYSTEM TIMER COMPARE1
|
||||
am_stimer_cmpr2_isr, // 25: SYSTEM TIMER COMPARE2
|
||||
am_stimer_cmpr3_isr, // 26: SYSTEM TIMER COMPARE3
|
||||
am_stimer_cmpr4_isr, // 27: SYSTEM TIMER COMPARE4
|
||||
am_stimer_cmpr5_isr, // 28: SYSTEM TIMER COMPARE5
|
||||
am_stimer_cmpr6_isr, // 29: SYSTEM TIMER COMPARE6
|
||||
am_stimer_cmpr7_isr, // 30: SYSTEM TIMER COMPARE7
|
||||
am_clkgen_isr, // 31: CLKGEN
|
||||
};
|
||||
|
||||
//******************************************************************************
|
||||
//
|
||||
// Place code immediately following vector table.
|
||||
//
|
||||
//******************************************************************************
|
||||
//******************************************************************************
|
||||
//
|
||||
// The Patch table.
|
||||
//
|
||||
// The patch table should pad the vector table size to a total of 64 entries
|
||||
// (16 core + 48 periph) such that code begins at offset 0x100.
|
||||
//
|
||||
//******************************************************************************
|
||||
__attribute__ ((section(".ble_patch")))
|
||||
uint32_t const __Patchable[] =
|
||||
{
|
||||
0, // 32
|
||||
0, // 33
|
||||
0, // 34
|
||||
0, // 35
|
||||
0, // 36
|
||||
0, // 37
|
||||
0, // 38
|
||||
0, // 39
|
||||
0, // 40
|
||||
0, // 41
|
||||
0, // 42
|
||||
0, // 43
|
||||
0, // 44
|
||||
0, // 45
|
||||
0, // 46
|
||||
0, // 47
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// The following are constructs created by the linker, indicating where the
|
||||
// the "data" and "bss" segments reside in memory. The initializers for the
|
||||
// "data" segment resides immediately following the "text" segment.
|
||||
//
|
||||
//*****************************************************************************
|
||||
extern uint32_t _etext;
|
||||
extern uint32_t _sdata;
|
||||
extern uint32_t _edata;
|
||||
extern uint32_t _sbss;
|
||||
extern uint32_t _ebss;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// This is the code that gets called when the processor first starts execution
|
||||
// following a reset event. Only the absolutely necessary set is performed,
|
||||
// after which the application supplied entry() routine is called.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#if defined(__GNUC_STDC_INLINE__)
|
||||
void
|
||||
Reset_Handler(void)
|
||||
{
|
||||
//
|
||||
// Set the vector table pointer.
|
||||
//
|
||||
__asm(" ldr r0, =0xE000ED08\n"
|
||||
" ldr r1, =g_am_pfnVectors\n"
|
||||
" str r1, [r0]");
|
||||
|
||||
//
|
||||
// Set the stack pointer.
|
||||
//
|
||||
__asm(" ldr sp, [r1]");
|
||||
|
||||
#ifndef NOFPU
|
||||
//
|
||||
// Enable the FPU.
|
||||
//
|
||||
__asm("ldr r0, =0xE000ED88\n"
|
||||
"ldr r1,[r0]\n"
|
||||
"orr r1,#(0xF << 20)\n"
|
||||
"str r1,[r0]\n"
|
||||
"dsb\n"
|
||||
"isb\n");
|
||||
#endif
|
||||
//
|
||||
// Copy the data segment initializers from flash to SRAM.
|
||||
//
|
||||
__asm(" ldr r0, =_init_data\n"
|
||||
" ldr r1, =_sdata\n"
|
||||
" ldr r2, =_edata\n"
|
||||
"copy_loop:\n"
|
||||
" cmp r1, r2\n"
|
||||
" beq copy_end\n"
|
||||
" ldr r3, [r0], #4\n"
|
||||
" str r3, [r1], #4\n"
|
||||
" b copy_loop\n"
|
||||
"copy_end:\n");
|
||||
|
||||
//
|
||||
// Zero fill the bss segment.
|
||||
//
|
||||
__asm(" ldr r0, =_sbss\n"
|
||||
" ldr r1, =_ebss\n"
|
||||
" mov r2, #0\n"
|
||||
"zero_loop:\n"
|
||||
" cmp r0, r1\n"
|
||||
" it lt\n"
|
||||
" strlt r2, [r0], #4\n"
|
||||
" blt zero_loop");
|
||||
|
||||
//
|
||||
// Call Global Static Constructors for C++ support
|
||||
//
|
||||
extern void (*__init_array_start)(void); // symbols must be
|
||||
extern void (*__init_array_end)(void); // provided by linker
|
||||
for (void (**p)() = &__init_array_start; p < &__init_array_end; ++p) {
|
||||
(*p)(); // Call each function in the list
|
||||
}
|
||||
|
||||
//
|
||||
// Call the application's entry point.
|
||||
//
|
||||
main();
|
||||
|
||||
//
|
||||
// If main returns then execute a break point instruction
|
||||
//
|
||||
__asm(" bkpt ");
|
||||
}
|
||||
#else
|
||||
#error GNU STDC inline not supported.
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// This is the code that gets called when the processor receives a NMI. This
|
||||
// simply enters an infinite loop, preserving the system state for examination
|
||||
// by a debugger.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
NMI_Handler(void)
|
||||
{
|
||||
//
|
||||
// Go into an infinite loop.
|
||||
//
|
||||
while(1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// This is the code that gets called when the processor receives a fault
|
||||
// interrupt. This simply enters an infinite loop, preserving the system state
|
||||
// for examination by a debugger.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
HardFault_Handler(void)
|
||||
{
|
||||
//
|
||||
// Go into an infinite loop.
|
||||
//
|
||||
while(1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//*****************************************************************************
|
||||
void
|
||||
am_default_isr(void)
|
||||
{
|
||||
//
|
||||
// Go into an infinite loop.
|
||||
//
|
||||
while(1)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// system function calls
|
||||
|
||||
#include <sys/types.h> // provides caddr_t /* for caddr_t (typedef char * caddr_t;) */s
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Excellent insight from Martin T. https://embdev.net/topic/linker-error-undefined-reference-to-_sbrk */
|
||||
static unsigned char* _eheap = NULL; // our heap management tracks the end of the heap with this var
|
||||
extern unsigned char _sheap; // Provided by linker
|
||||
caddr_t _sbrk ( int incr ){
|
||||
unsigned char* prev_heap;
|
||||
unsigned char local;
|
||||
|
||||
// Initialize the heap pointer
|
||||
if (_eheap == NULL) {
|
||||
_eheap = (unsigned char*)&_sheap;
|
||||
}
|
||||
prev_heap = _eheap;
|
||||
|
||||
// Check that the requested amount of memory is available (w/ margin)
|
||||
if( ((&local)-(_eheap)) >= (incr + 128) ){
|
||||
_eheap += incr;
|
||||
}else{
|
||||
// set errno to ENOMEM
|
||||
prev_heap = (unsigned char*)-1;
|
||||
}
|
||||
|
||||
// Return the previous heap (or the error code)
|
||||
return (caddr_t) prev_heap;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user