*
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps and configuration necessary to reproduce the behavior.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. Windows 10]
|
||||
- odrivetool Version (`odrivetool --version`)
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,47 @@
|
||||
name: 'Add version to release channel'
|
||||
description: |
|
||||
Appends the specified version to the end of the specified release channel if
|
||||
it wasn't already part of that channel.
|
||||
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Release type (firmware, gui, docs, internal-docs).'
|
||||
required: true
|
||||
channel:
|
||||
description: 'The channel on which to register this version'
|
||||
required: true
|
||||
version:
|
||||
description: 'The version name (commit hash or semantic version name)'
|
||||
required: true
|
||||
odrive_api_key:
|
||||
description: 'Key to our release index server'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
pip install aiohttp cryptography
|
||||
pip install odrive --pre
|
||||
|
||||
- name: Register on release server
|
||||
shell: python
|
||||
run: |
|
||||
import asyncio
|
||||
import sys
|
||||
import aiohttp
|
||||
|
||||
sys.path.insert(0, '${{ github.workspace }}/.github/actions/upload-release')
|
||||
from odrive.api_client import ApiClient
|
||||
from private_release_api import PrivateReleaseApi
|
||||
|
||||
async def main():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
api_client = ApiClient(session, key='${{ inputs.odrive_api_key }}')
|
||||
release_api = PrivateReleaseApi(api_client)
|
||||
await release_api.append_to_channel('${{ inputs.release_type }}', "${{ inputs.channel }}", "${{ inputs.version }}")
|
||||
await release_api.refresh_routes('${{ inputs.release_type }}')
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,135 @@
|
||||
name: 'Upload (Pre)release'
|
||||
description: |
|
||||
Pushes the specified local directory to our release file server and registers
|
||||
the new content on our release index server.
|
||||
The version will not yet be associated with a channel.
|
||||
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Release type (firmware, gui, docs, internal-docs).' # TODO: Currently only firmware and docs is supported.
|
||||
required: true
|
||||
version:
|
||||
description: 'The version name (commit hash or semantic version name)'
|
||||
required: true
|
||||
src_dir:
|
||||
description: 'The source directory on the local system.'
|
||||
required: true
|
||||
do_access_key:
|
||||
description: 'DigitalOcean access key'
|
||||
required: true
|
||||
do_secret_key:
|
||||
description: 'DigitalOcean secret key'
|
||||
required: true
|
||||
odrive_api_key:
|
||||
description: 'Key to our release index server'
|
||||
required: true
|
||||
board:
|
||||
description: 'ODrive board version triplet ("PRODUCT_LINE.VERSION.VARIANT") (for firmware releases only).'
|
||||
required: false
|
||||
app:
|
||||
description: 'Firmware app name (default, bootloader) (for firmware releases only).'
|
||||
required: false
|
||||
variant:
|
||||
description: 'Variant (public or internal).'
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Prerequisites
|
||||
shell: bash
|
||||
run: pip install aiohttp cryptography
|
||||
|
||||
- name: Install odrivetool
|
||||
shell: bash
|
||||
run: pip install odrive --pre
|
||||
|
||||
- name: Load Content Key
|
||||
id: load-content-key
|
||||
shell: python
|
||||
run: |
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
import aiohttp
|
||||
|
||||
sys.path.insert(0, '${{ github.workspace }}/.github/actions/upload-release')
|
||||
from odrive.api_client import ApiClient
|
||||
from private_release_api import PrivateReleaseApi # well not so private anymore
|
||||
from odrive.crypto import safe_b64encode
|
||||
|
||||
content_key = PrivateReleaseApi.get_content_key('${{ inputs.src_dir }}', "${{ github.sha }}")
|
||||
|
||||
async def main():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
api_client = ApiClient(session, key='${{ inputs.odrive_api_key }}')
|
||||
release_api = PrivateReleaseApi(api_client)
|
||||
manifest = await release_api.get_manifest('${{ inputs.release_type }}', content_key)
|
||||
needs_upload = manifest is None
|
||||
|
||||
print("::set-output name=content-key::" + safe_b64encode(content_key))
|
||||
print("::set-output name=needs-upload::" + ('true' if needs_upload else 'false'))
|
||||
|
||||
asyncio.run(main())
|
||||
|
||||
# This is for debugging only
|
||||
- name: Dump context
|
||||
shell: bash
|
||||
env:
|
||||
CONTEXT: ${{ toJson(steps) }}
|
||||
run: |
|
||||
echo "$CONTEXT"
|
||||
|
||||
- name: Upload to DigitalOcean
|
||||
if: steps.load-content-key.outputs.needs-upload == 'true'
|
||||
uses: BetaHuhn/do-spaces-action@v2
|
||||
with:
|
||||
access_key: ${{ inputs.do_access_key }}
|
||||
secret_key: ${{ inputs.do_secret_key }}
|
||||
space_name: odrive-cdn
|
||||
space_region: nyc3
|
||||
source: ${{ inputs.src_dir }}
|
||||
out_dir: releases/${{ inputs.release_type }}/${{ steps.load-content-key.outputs.content-key }}
|
||||
|
||||
- name: Register on release server
|
||||
shell: python
|
||||
run: |
|
||||
import asyncio
|
||||
import re
|
||||
import sys
|
||||
|
||||
import aiohttp
|
||||
|
||||
sys.path.insert(0, '${{ github.workspace }}/.github/actions/upload-release')
|
||||
from odrive.api_client import ApiClient
|
||||
from private_release_api import PrivateReleaseApi
|
||||
from odrive.crypto import safe_b64decode
|
||||
|
||||
version="${{ inputs.version }}"
|
||||
|
||||
print("Version: ", version)
|
||||
print("Content key: ", '${{ steps.load-content-key.outputs.content-key }}')
|
||||
|
||||
async def main():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
api_client = ApiClient(session, key='${{ inputs.odrive_api_key }}')
|
||||
release_api = PrivateReleaseApi(api_client)
|
||||
|
||||
qualifiers = {}
|
||||
if '${{ inputs.board }}':
|
||||
qualifiers['board'] = tuple(int(i) for i in re.match(r'^([0-9]+)\.([0-9]+).([0-9]+)$', '${{ inputs.board }}').groups())
|
||||
if '${{ inputs.app }}':
|
||||
qualifiers['app'] = '${{ inputs.app }}'
|
||||
if '${{ inputs.variant }}':
|
||||
qualifiers['variant'] = '${{ inputs.variant }}'
|
||||
|
||||
content_key = safe_b64decode('${{ steps.load-content-key.outputs.content-key }}')
|
||||
|
||||
# Content can only be registered once, afterwards the indicated_commit cannot be changed
|
||||
if "${{ steps.load-content-key.outputs.needs-upload}}" == 'true':
|
||||
await release_api.register_content('${{ inputs.release_type }}', content_key, '${{ github.sha }}')
|
||||
|
||||
# Can be called multiple times with same or different parameters. No effect if called twice with the same parameters.
|
||||
await release_api.register_version('${{ inputs.release_type }}', version, content_key, **qualifiers)
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
from odrive.api_client import ApiClient
|
||||
from odrive.crypto import b64encode
|
||||
|
||||
class PrivateReleaseApi():
|
||||
BASE_URL = '/releases'
|
||||
|
||||
@staticmethod
|
||||
def get_content_key(path: str, commit_hash: str):
|
||||
commit_hash_bytes = bytes.fromhex(commit_hash)
|
||||
|
||||
def _get_file_names(path: str, prefix: list):
|
||||
with os.scandir(os.path.join(path, *prefix)) as it:
|
||||
for entry in it:
|
||||
if entry.is_file():
|
||||
yield os.path.join(*prefix, entry.name)
|
||||
else:
|
||||
yield from _get_file_names(path, prefix + [entry.name])
|
||||
filenames = sorted(_get_file_names(path, []))
|
||||
|
||||
dir_hasher = hashlib.sha256()
|
||||
|
||||
for filename in filenames:
|
||||
with open(os.path.join(path, filename), 'rb') as fp:
|
||||
content = fp.read()
|
||||
|
||||
# Calculate commit-invariant hash of the file content
|
||||
# This means that if a new compile differs only by embedded commit hash,
|
||||
# it is considered equal.
|
||||
patched_content = content.replace(commit_hash_bytes, bytes(len(commit_hash_bytes)))
|
||||
file_hasher = hashlib.sha256()
|
||||
file_hasher.update(patched_content)
|
||||
|
||||
dir_hasher.update(filename.encode('utf-8'))
|
||||
dir_hasher.update(file_hasher.digest())
|
||||
|
||||
return dir_hasher.digest()
|
||||
|
||||
def __init__(self, api_client: 'ApiClient'):
|
||||
self._api_client = api_client
|
||||
|
||||
async def get_manifest(self, release_type: str, content_key: bytes):
|
||||
outputs = await self._api_client.call('GET', PrivateReleaseApi.BASE_URL + '/' + release_type + '/manifest', inputs={
|
||||
'content_key': b64encode(content_key),
|
||||
})
|
||||
return outputs
|
||||
|
||||
async def register_content(self, release_type: str, content_key: bytes, indicated_commit: str):
|
||||
outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/content', inputs={
|
||||
'content_key': b64encode(content_key),
|
||||
'indicated_commit': indicated_commit,
|
||||
})
|
||||
return outputs['created']
|
||||
|
||||
async def register_version(self, release_type: str, version: str, content_key: bytes, **qualifiers):
|
||||
outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/version', inputs={
|
||||
'version': version,
|
||||
'content_key': b64encode(content_key),
|
||||
**qualifiers
|
||||
})
|
||||
return outputs['created']
|
||||
|
||||
async def append_to_channel(self, release_type: str, channel: str, version: str):
|
||||
outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/channel', inputs={
|
||||
'channel': channel,
|
||||
'version': version,
|
||||
})
|
||||
return outputs['published']
|
||||
|
||||
async def refresh_routes(self, release_type: str):
|
||||
await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/refresh-routes')
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Build and publish HTML documentation website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'docs-v**' ]
|
||||
paths: ['docs/**', '.github/**']
|
||||
|
||||
jobs:
|
||||
make-html:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Get release name and channel
|
||||
id: release-info
|
||||
shell: python
|
||||
run: |
|
||||
channel = "master"
|
||||
version = "${{ github.ref }}"
|
||||
assert version.startswith("refs/heads/docs-v0.5.")
|
||||
version = version[len("refs/heads/docs-v"):]
|
||||
|
||||
print("::set-output name=channel::" + channel)
|
||||
print("::set-output name=version::" + version)
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-sphinx-sphinx-tabs-sphinx-design-sphinx_copybutton-sphinx_panels-sphinx_rtd_theme
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: pip install sphinx sphinx-tabs sphinx-design sphinx_copybutton sphinx_panels sphinx_rtd_theme myst_parser
|
||||
|
||||
- name: Build HTML docs
|
||||
run: |
|
||||
cd docs
|
||||
make html
|
||||
|
||||
- name: Upload docs
|
||||
uses: ./.github/actions/upload-release
|
||||
with:
|
||||
release_type: docs
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
src_dir: docs/_build/html
|
||||
do_access_key: ${{ secrets.DIGITALOCEAN_ACCESS_KEY }}
|
||||
do_secret_key: ${{ secrets.DIGITALOCEAN_SECRET_KEY }}
|
||||
odrive_api_key: ${{ secrets.ODRIVE_API_KEY }}
|
||||
variant: public
|
||||
|
||||
- name: Add version to release channel
|
||||
uses: ./.github/actions/add-version-to-channel
|
||||
with:
|
||||
release_type: docs
|
||||
channel: ${{ steps.release-info.outputs.channel }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
odrive_api_key: ${{ secrets.ODRIVE_API_KEY }}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, devel]
|
||||
push:
|
||||
branches: [master, devel]
|
||||
tags: ['fw-v*']
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
board_version: [v3.6-56V]
|
||||
debug: [true]
|
||||
|
||||
include:
|
||||
- {os: ubuntu-latest, board_version: v3.2, debug: false}
|
||||
- {os: ubuntu-latest, board_version: v3.3, debug: false}
|
||||
- {os: ubuntu-latest, board_version: v3.4-24V, debug: false}
|
||||
- {os: ubuntu-latest, board_version: v3.4-48V, debug: false}
|
||||
- {os: ubuntu-latest, board_version: v3.5-24V, debug: false}
|
||||
- {os: ubuntu-latest, board_version: v3.5-48V, debug: false}
|
||||
- {os: ubuntu-latest, board_version: v3.6-24V, debug: false}
|
||||
- {os: ubuntu-latest, board_version: v3.6-56V, debug: false}
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
outputs:
|
||||
channel: ${{ steps.release-info.outputs.channel }}
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # fetch entire history to get version information
|
||||
|
||||
- name: Get release name and channel
|
||||
id: release-info
|
||||
shell: python
|
||||
run: |
|
||||
if "${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/fw-v0.5.') }}" == "true":
|
||||
channel = "master"
|
||||
version = "${{ github.ref }}"[len("refs/tags/fw-v"):]
|
||||
|
||||
else:
|
||||
channel = "none"
|
||||
version = "${{ github.sha }}"
|
||||
|
||||
print("::set-output name=channel::" + channel)
|
||||
print("::set-output name=version::" + version)
|
||||
|
||||
- name: Install prerequisites (Debian)
|
||||
if: startsWith(matrix.os, 'ubuntu-')
|
||||
run: |
|
||||
DEBIAN_VERSION="$(lsb_release --release --short)"
|
||||
echo Debian version: $DEBIAN_VERSION
|
||||
if [ "$DEBIAN_VERSION" == "16.04" ]; then
|
||||
# Ubuntu 16.04 (Debian 9) is on ARM GCC 4.9 which is too old for us
|
||||
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-arm-embedded
|
||||
else
|
||||
sudo apt-get install gcc-arm-none-eabi
|
||||
fi
|
||||
|
||||
if ! (apt-cache search tup | grep "^tup - "); then
|
||||
sudo add-apt-repository ppa:jonathonf/tup
|
||||
sudo apt-get update
|
||||
fi
|
||||
|
||||
sudo apt-get install tup
|
||||
|
||||
sudo apt install python3 python3-yaml python3-jinja2 python3-jsonschema
|
||||
|
||||
- name: Install prerequisites (macOS)
|
||||
if: startsWith(matrix.os, 'macOS-')
|
||||
run: |
|
||||
brew install armmbed/formulae/arm-none-eabi-gcc
|
||||
# See https://github.com/osxfuse/osxfuse/issues/801#issuecomment-833419942
|
||||
brew install --cask macfuse
|
||||
brew install gromgit/fuse/tup-mac
|
||||
pip3 install PyYAML Jinja2 jsonschema
|
||||
|
||||
|
||||
- name: Cache chocolatey
|
||||
uses: actions/cache@v2
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
with:
|
||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey\gcc-arm-embedded
|
||||
key: ${{ runner.os }}-gcc-arm-embedded
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gcc-arm-embedded
|
||||
|
||||
- name: Install prerequisites (Windows)
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
run: |
|
||||
Invoke-WebRequest -Uri "http://gittup.org/tup/win32/tup-latest.zip" -OutFile ".\tup-latest.zip"
|
||||
Expand-Archive ".\tup-latest.zip" -DestinationPath ".\tup-latest" -Force
|
||||
echo "$(Resolve-Path .)\tup-latest" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
choco install gcc-arm-embedded # downloads https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-win32.zip
|
||||
|
||||
pip install PyYAML Jinja2 jsonschema
|
||||
|
||||
- name: Prepare Compilation
|
||||
run: |
|
||||
# for debugging
|
||||
arm-none-eabi-gcc --version
|
||||
python --version
|
||||
|
||||
cd ${{ github.workspace }}/Firmware
|
||||
echo "CONFIG_BOARD_VERSION=${{ matrix.board_version }}" >> tup.config
|
||||
echo "CONFIG_STRICT=true" >> tup.config
|
||||
echo "CONFIG_DEBUG=${{ matrix.debug }}" >> tup.config
|
||||
mkdir -p autogen
|
||||
python ../tools/odrive/version.py --output autogen/version.c
|
||||
cat autogen/version.c
|
||||
tup init
|
||||
tup generate ./tup_build.sh
|
||||
|
||||
- name: Compile (Unix)
|
||||
if: "!startsWith(matrix.os, 'windows-')"
|
||||
run: |
|
||||
cd ${{ github.workspace }}/Firmware
|
||||
bash -xe ./tup_build.sh
|
||||
|
||||
- name: Compile (Windows)
|
||||
if: startsWith(matrix.os, 'windows-')
|
||||
run: |
|
||||
cd ${{ github.workspace }}/Firmware
|
||||
mv tup_build.sh tup_build.bat # in reality this is a .bat script on windows
|
||||
.\tup_build.bat
|
||||
|
||||
- name: Upload binary as artifact
|
||||
if: ${{ matrix.os == 'ubuntu-latest' && matrix.debug == false }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware-${{ matrix.board_version }}
|
||||
path: |
|
||||
Firmware/build/ODriveFirmware.elf
|
||||
Firmware/build/ODriveFirmware.bin
|
||||
Firmware/build/ODriveFirmware.hex
|
||||
|
||||
- name: Copy firmware to temp folder
|
||||
run: |
|
||||
mkdir ${{ github.workspace }}/out
|
||||
cp ${{ github.workspace }}/Firmware/build/ODriveFirmware.elf ${{ github.workspace }}/out/firmware.elf
|
||||
|
||||
- name: Parse and format matrix.board_version
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
id: format-board-version
|
||||
run: |
|
||||
formatted_version=$(echo "${{ matrix.board_version }}" | sed 's/v\([0-9]\+\)\.\([0-9]\+\)-\([0-9]\+\)V/\1.\2.\3/')
|
||||
echo "Formatted board version: $formatted_version"
|
||||
echo "::set-output name=formatted_board_version::$formatted_version"
|
||||
|
||||
- name: Upload firmware to ODrive release system
|
||||
if: ${{ steps.release-info.outputs.channel == 'master' && matrix.os == 'ubuntu-latest' && matrix.debug == false && (startsWith(matrix.board_version, 'v3.5-') || startsWith(matrix.board_version, 'v3.6-')) }}
|
||||
uses: ./.github/actions/upload-release
|
||||
with:
|
||||
release_type: firmware
|
||||
version: ${{ steps.release-info.outputs.version }}
|
||||
src_dir: out
|
||||
do_access_key: ${{ secrets.DIGITALOCEAN_ACCESS_KEY }}
|
||||
do_secret_key: ${{ secrets.DIGITALOCEAN_SECRET_KEY }}
|
||||
odrive_api_key: ${{ secrets.ODRIVE_API_KEY }}
|
||||
board: ${{ steps.format-board-version.outputs.formatted_board_version }}
|
||||
app: default
|
||||
variant: public
|
||||
|
||||
make-release:
|
||||
needs: [compile] # require all builds to succeed before we actually make the release
|
||||
if: needs.compile.outputs.channel == 'master'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout git repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: pip install aiohttp appdirs
|
||||
|
||||
- name: Add version to release channel
|
||||
uses: ./.github/actions/add-version-to-channel
|
||||
with:
|
||||
release_type: firmware
|
||||
channel: ${{ needs.compile.outputs.channel }}
|
||||
version: ${{ needs.compile.outputs.version }}
|
||||
odrive_api_key: ${{ secrets.ODRIVE_API_KEY }}
|
||||
|
||||
code-checks:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check that we're not using std::isnan
|
||||
run: |
|
||||
cd ${{ github.workspace }}/Firmware
|
||||
|
||||
if grep 'std::isnan' -R .; then
|
||||
echo "Don't use std::isnan because it's not compatible with '-ffast-math'. Use is_nan() instead."
|
||||
return 1;
|
||||
fi
|
||||
|
||||
# TODO:
|
||||
# - check if enums.py is consistent with yaml
|
||||
# - clang-format check
|
||||
# - check if interface_generator outputs the same thing with Python 3.5 and Python 3.8
|
||||
@@ -0,0 +1,68 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
#Ipython Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# Tup
|
||||
.tup
|
||||
tup.config
|
||||
|
||||
# Sphinx documentation
|
||||
/docs/_build/
|
||||
|
||||
# Autogenerated API reference
|
||||
/docs/_api
|
||||
/docs/_includes/apiindex.html
|
||||
|
||||
# Jekyll HTML documention and artifacts
|
||||
/docs/ruby-bundle
|
||||
/docs/_site
|
||||
/docs/.bundle/config
|
||||
/docs/.jekyll-metadata
|
||||
|
||||
|
||||
*.exe
|
||||
|
||||
ODrive\.config
|
||||
|
||||
ODrive\.creator
|
||||
|
||||
ODrive\.creator\.user
|
||||
|
||||
ODrive\.files
|
||||
|
||||
ODrive\.includes
|
||||
|
||||
Firmware/Tests/bin/
|
||||
|
||||
# GUI
|
||||
GUI/dist_electron
|
||||
GUI/node_modules
|
||||
GUI/build
|
||||
|
||||
docs/reStructuredText/_build/
|
||||
tools/odrive-cansimple.ini
|
||||
@@ -0,0 +1,197 @@
|
||||
|
||||
#include <Wire.h>
|
||||
#include "odrive.h"
|
||||
|
||||
|
||||
// See odrive.h for a description
|
||||
bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length) {
|
||||
// transmit
|
||||
if (tx_buffer) {
|
||||
Wire.beginTransmission(slave_addr);
|
||||
if (Wire.write(tx_buffer, tx_length) != tx_length)
|
||||
return false;
|
||||
bool should_stop = !rx_buffer;
|
||||
if (Wire.endTransmission(should_stop) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// receive
|
||||
if (rx_buffer) {
|
||||
while(Wire.available()) Wire.read(); // flush input buffer
|
||||
if (Wire.requestFrom(slave_addr, (uint8_t)rx_length, (uint8_t)true /* stop after receiving */) != rx_length)
|
||||
return false;
|
||||
for (size_t i = 0; i < rx_length; ++i)
|
||||
rx_buffer[i] = Wire.read();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int set_and_save_configuration(uint8_t odrive_num, uint8_t axis_num) {
|
||||
bool success;
|
||||
success = odrive::clear_errors(odrive_num, axis_num);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// select hall effect mode
|
||||
bool user_config_loaded = false;
|
||||
success = odrive::read_property<odrive::USER_CONFIG_LOADED>(odrive_num, &user_config_loaded);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
if (user_config_loaded) {
|
||||
Serial.println("ODrive already configured");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// select hall effect mode
|
||||
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__MODE>(odrive_num, axis_num, 1);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// configure encoder counts per revolution (6 hall effect states * 12 pole pairs)
|
||||
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__CPR>(odrive_num, axis_num, 72);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// disable velocity integrator
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN>(odrive_num, axis_num, 0);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// select velocity control
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__CONTROL_MODE>(odrive_num, axis_num, 2);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// set velocity controller P-gain
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__CONFIG__VEL_GAIN>(odrive_num, axis_num, 0.005f);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// request state: motor calibration
|
||||
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 4);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
delay(6000);
|
||||
|
||||
// check if the axis is in idle and no errors occurred
|
||||
if (!odrive::check_axis_state(odrive_num, axis_num, 1))
|
||||
return __LINE__;
|
||||
|
||||
// ensure that the motor calibration is considered valid after power cycle
|
||||
success = odrive::write_axis_property<odrive::AXIS__MOTOR__CONFIG__PRE_CALIBRATED>(odrive_num, axis_num, true);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// request state: encoder calibration
|
||||
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 7);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
delay(12000);
|
||||
|
||||
// check if the axis is in idle and no errors occurred
|
||||
if (!odrive::check_axis_state(odrive_num, axis_num, 1))
|
||||
return __LINE__;
|
||||
|
||||
// ensure that the encoder calibration is considered valid after power cycle
|
||||
success = odrive::write_axis_property<odrive::AXIS__ENCODER__CONFIG__PRE_CALIBRATED>(odrive_num, axis_num, true);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
|
||||
// store the configuration to NVM
|
||||
// Caution: this operation is usually instantaneous but after every couple of hundred calls it will
|
||||
// take around 1 second (because a flash page needs to be erased).
|
||||
success = odrive::trigger<odrive::SAVE_CONFIGURATION>(odrive_num);
|
||||
if (!success)
|
||||
return __LINE__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
byte odrive_num = 7;
|
||||
byte axis_num = 0;
|
||||
bool do_setup = true;
|
||||
|
||||
void setup() {
|
||||
Wire.begin(); // join i2c bus (address optional for master)
|
||||
Serial.begin(9600);
|
||||
Serial.println("Hello World!");
|
||||
|
||||
if (do_setup) {
|
||||
Serial.println("Starting ODrive setup...");
|
||||
int error_line = set_and_save_configuration(odrive_num, axis_num);
|
||||
if (error_line != 0) {
|
||||
Serial.print("ODrive setup failed at line ");
|
||||
Serial.print(error_line);
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
Serial.println("ODrive setup succeeded!");
|
||||
do_setup = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
bool success;
|
||||
delay(500);
|
||||
|
||||
success = odrive::check_axis_state(odrive_num, axis_num, 8);
|
||||
if (!success) {
|
||||
Serial.println("not in closed loop control - entering closed loop control");
|
||||
|
||||
// clear previous error state
|
||||
success = odrive::clear_errors(odrive_num, axis_num);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
|
||||
// request velocity 0
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, 0);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
|
||||
// request state: closed loop control
|
||||
success = odrive::write_axis_property<odrive::AXIS__REQUESTED_STATE>(odrive_num, axis_num, 8);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
|
||||
success = odrive::check_axis_state(odrive_num, axis_num, 8);
|
||||
if (!success) {
|
||||
Serial.println("could not enter closed loop control");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, 72 * 5);
|
||||
if (!success) {
|
||||
Serial.println("error");
|
||||
return;
|
||||
}
|
||||
|
||||
delay(500);
|
||||
|
||||
success = odrive::write_axis_property<odrive::AXIS__CONTROLLER__VEL_SETPOINT>(odrive_num, axis_num, -72 * 5);
|
||||
if (!success) {
|
||||
Serial.println("error");
|
||||
return;
|
||||
}
|
||||
|
||||
// print Vbus to show liveness
|
||||
float vbus;
|
||||
success = odrive::read_property<odrive::VBUS_VOLTAGE>(odrive_num, &vbus);
|
||||
if (!success) {
|
||||
Serial.println("error");
|
||||
return;
|
||||
}
|
||||
Serial.println(vbus);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* ODrive I2C communication library
|
||||
* This file implements I2C communication with the ODrive.
|
||||
*
|
||||
* - Implement the C function I2C_transaction to provide low level I2C access.
|
||||
* - Use read_property<PropertyId>() to read properties from the ODrive.
|
||||
* - Use write_property<PropertyId>() to modify properties on the ODrive.
|
||||
* - Use trigger<PropertyId>() to trigger a function (such as reboot or save_configuration)
|
||||
* - Use endpoint_type_t<PropertyId> to retrieve the underlying type
|
||||
* of a given property.
|
||||
* - Refer to PropertyId for a list of available properties.
|
||||
*
|
||||
* To regenerate the interface definitions, flash an ODrive with
|
||||
* the new firmware, connect it to your PC via USB and then run
|
||||
* ../tools/odrivetool generate-code --output [path to odrive_endpoints.h]
|
||||
* This step can be done with any ODrive, it doesn't have to be the
|
||||
* one that you'll be controlling over I2C.
|
||||
*/
|
||||
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "odrive_endpoints.h"
|
||||
|
||||
#ifdef __AVR__
|
||||
// AVR-GCC doesn't ship with the STL, so we use our own little excerpt
|
||||
#include "type_traits.h"
|
||||
#else
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* @brief Send and receive data to/from an I2C slave
|
||||
*
|
||||
* This function carries out the following sequence:
|
||||
* 1. generate a START condition
|
||||
* 2. if the tx_buffer is not null:
|
||||
* a. send 7-bit slave address (with the LSB 0)
|
||||
* b. send all bytes in the tx_buffer
|
||||
* 3. if both tx_buffer and rx_buffer are not null, generate a REPEATED START condition
|
||||
* 4. if the rx_buffer is not null:
|
||||
* a. send 7-bit slave address (with the LSB 1)
|
||||
* b. read rx_length bytes into rx_buffer
|
||||
* 5. send STOP condition
|
||||
*
|
||||
* @param slave_addr: 7-bit slave address (the MSB is ignored)
|
||||
* @return true if all data was transmitted and received as requested by the caller, false otherwise
|
||||
*/
|
||||
bool I2C_transaction(uint8_t slave_addr, const uint8_t * tx_buffer, size_t tx_length, uint8_t * rx_buffer, size_t rx_length);
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace odrive {
|
||||
static constexpr const uint8_t i2c_addr = (0xD << 3); // write: 1101xxx0, read: 1101xxx1
|
||||
|
||||
template<typename T>
|
||||
using bit_width = std::integral_constant<unsigned int, CHAR_BIT * sizeof(T)>;
|
||||
|
||||
template<typename T>
|
||||
using byte_width = std::integral_constant<unsigned int, (bit_width<T>::value + 7) / 8>;
|
||||
|
||||
|
||||
template<unsigned int IBitSize>
|
||||
struct unsigned_int_of_size;
|
||||
|
||||
template<> struct unsigned_int_of_size<32> { typedef uint32_t type; };
|
||||
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
read_le(const uint8_t buffer[byte_width<T>::value]) {
|
||||
T value = 0;
|
||||
for (size_t i = 0; i < byte_width<T>::value; ++i)
|
||||
value |= (static_cast<T>(buffer[i]) << (i << 3));
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
read_le(const uint8_t buffer[]) {
|
||||
using T_Int = typename unsigned_int_of_size<bit_width<T>::value>::type;
|
||||
T_Int value = read_le<T_Int>(buffer);
|
||||
return *reinterpret_cast<T*>(&value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, void>::type
|
||||
write_le(uint8_t buffer[byte_width<T>::value], T value) {
|
||||
for (size_t i = 0; i < byte_width<T>::value; ++i)
|
||||
buffer[i] = (value >> (i << 3)) & 0xff;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
write_le(uint8_t buffer[byte_width<T>::value], T value) {
|
||||
using T_Int = typename unsigned_int_of_size<bit_width<T>::value>::type;
|
||||
write_le<T_Int>(buffer, *reinterpret_cast<T_Int*>(&value));
|
||||
}
|
||||
|
||||
/* @brief Read from an endpoint on the ODrive.
|
||||
* To read from an axis specific endpoint use read_axis_property() instead.
|
||||
*
|
||||
* Usage example:
|
||||
* float val;
|
||||
* success = odrive::read_property<odrive::VBUS_VOLTAGE>(0, &val);
|
||||
*
|
||||
* @param num Selects the ODrive. For instance the value 4 selects
|
||||
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
|
||||
* @return true if the I2C transaction succeeded, false otherwise
|
||||
*/
|
||||
template<int IPropertyId>
|
||||
bool read_property(uint8_t num, endpoint_type_t<IPropertyId>* value, uint16_t address = IPropertyId) {
|
||||
uint8_t i2c_tx_buffer[4];
|
||||
write_le<uint16_t>(i2c_tx_buffer, address);
|
||||
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
|
||||
uint8_t i2c_rx_buffer[byte_width<endpoint_type_t<IPropertyId>>::value];
|
||||
if (!I2C_transaction(i2c_addr + num,
|
||||
i2c_tx_buffer, sizeof(i2c_tx_buffer),
|
||||
i2c_rx_buffer, sizeof(i2c_rx_buffer)))
|
||||
return false;
|
||||
if (value)
|
||||
*value = read_le<endpoint_type_t<IPropertyId>>(i2c_rx_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* @brief Write to an endpoint on the ODrive.
|
||||
* To write to an axis specific endpoint use write_axis_property() instead.
|
||||
*
|
||||
* Usage example:
|
||||
* success = odrive::write_property<odrive::TEST_PROPERTY>(0, 42);
|
||||
*
|
||||
* @param num Selects the ODrive. For instance the value 4 selects
|
||||
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
|
||||
* @return true if the I2C transaction succeeded, false otherwise
|
||||
*/
|
||||
template<int IPropertyId>
|
||||
bool write_property(uint8_t num, endpoint_type_t<IPropertyId> value, uint16_t address = IPropertyId) {
|
||||
uint8_t i2c_tx_buffer[4 + byte_width<endpoint_type_t<IPropertyId>>::value];
|
||||
write_le<uint16_t>(i2c_tx_buffer, address);
|
||||
write_le<endpoint_type_t<IPropertyId>>(i2c_tx_buffer + 2, value);
|
||||
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
|
||||
return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0);
|
||||
}
|
||||
|
||||
/* @brief Trigger an parameter-less function on the ODrive
|
||||
*
|
||||
* Usage example:
|
||||
* success = odrive::trigger<odrive::SAVE_CONFIGURATION>(0);
|
||||
*
|
||||
* @param num Selects the ODrive. For instance the value 4 selects
|
||||
* the ODrive that has [A2, A1, A0] connected to [VCC, GND, GND].
|
||||
* @return true if the I2C transaction succeeded, false otherwise
|
||||
*/
|
||||
template<int IPropertyId,
|
||||
typename = typename std::enable_if<std::is_void<endpoint_type_t<IPropertyId>>::value>::type>
|
||||
bool trigger(uint8_t num, uint16_t address = IPropertyId) {
|
||||
uint8_t i2c_tx_buffer[4];
|
||||
write_le<uint16_t>(i2c_tx_buffer, address);
|
||||
write_le<uint16_t>(i2c_tx_buffer + sizeof(i2c_tx_buffer) - 2, json_crc);
|
||||
return I2C_transaction(i2c_addr + num, i2c_tx_buffer, sizeof(i2c_tx_buffer), nullptr, 0);
|
||||
}
|
||||
|
||||
template<int IPropertyId>
|
||||
bool read_axis_property(uint8_t num, uint8_t axis, endpoint_type_t<IPropertyId>* value) {
|
||||
return read_property<IPropertyId>(num, value, IPropertyId + axis * per_axis_offset);
|
||||
}
|
||||
|
||||
template<int IPropertyId>
|
||||
bool write_axis_property(uint8_t num, uint8_t axis, endpoint_type_t<IPropertyId> value) {
|
||||
return write_property<IPropertyId>(num, value, IPropertyId + axis * per_axis_offset);
|
||||
}
|
||||
|
||||
|
||||
/* @brief Checks if the axis is in the requested state and the error register is clear */
|
||||
bool check_axis_state(uint8_t num, uint8_t axis, uint8_t state) {
|
||||
endpoint_type_t<odrive::AXIS__CURRENT_STATE> observed_state = 0;
|
||||
endpoint_type_t<odrive::AXIS__ERROR> observed_error = 0;
|
||||
if (!read_axis_property<odrive::AXIS__CURRENT_STATE>(num, axis, &observed_state))
|
||||
return false;
|
||||
if (!read_axis_property<odrive::AXIS__ERROR>(num, axis, &observed_error))
|
||||
return false;
|
||||
return (observed_error == 0) && (observed_state == state);
|
||||
}
|
||||
|
||||
/* @brief Clears any error state of the specified axis */
|
||||
bool clear_errors(uint8_t num, uint8_t axis) {
|
||||
if (!write_axis_property<odrive::AXIS__ERROR>(num, axis, 0))
|
||||
return false;
|
||||
if (!write_axis_property<odrive::AXIS__MOTOR__ERROR>(num, axis, 0))
|
||||
return false;
|
||||
if (!write_axis_property<odrive::AXIS__ENCODER__ERROR>(num, axis, 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* This file was autogenerated using the "odrivetool generate-code" feature.
|
||||
*
|
||||
* The file matches a specific firmware version. If you add/remove/rename any
|
||||
* properties exposed by the ODrive, this file needs to be regenerated, otherwise
|
||||
* the ODrive will ignore all commands.
|
||||
*/
|
||||
|
||||
#ifndef __ODRIVE_ENDPOINTS_HPP
|
||||
#define __ODRIVE_ENDPOINTS_HPP
|
||||
|
||||
|
||||
namespace odrive {
|
||||
|
||||
static constexpr const uint16_t json_crc = 0xbe97;
|
||||
|
||||
static constexpr const uint16_t per_axis_offset = 101;
|
||||
|
||||
enum {
|
||||
VBUS_VOLTAGE = 1,
|
||||
SERIAL_NUMBER = 2,
|
||||
HW_VERSION_MAJOR = 3,
|
||||
HW_VERSION_MINOR = 4,
|
||||
HW_VERSION_VARIANT = 5,
|
||||
FW_VERSION_MAJOR = 6,
|
||||
FW_VERSION_MINOR = 7,
|
||||
FW_VERSION_REVISION = 8,
|
||||
FW_VERSION_UNRELEASED = 9,
|
||||
USER_CONFIG_LOADED = 10,
|
||||
BRAKE_RESISTOR_ARMED = 11,
|
||||
SYSTEM_STATS__UPTIME = 12,
|
||||
SYSTEM_STATS__MIN_HEAP_SPACE = 13,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_AXIS0 = 14,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_AXIS1 = 15,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_COMMS = 16,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_USB = 17,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_UART = 18,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_USB_IRQ = 19,
|
||||
SYSTEM_STATS__MIN_STACK_SPACE_STARTUP = 20,
|
||||
SYSTEM_STATS__USB__RX_CNT = 21,
|
||||
SYSTEM_STATS__USB__TX_CNT = 22,
|
||||
SYSTEM_STATS__USB__TX_OVERRUN_CNT = 23,
|
||||
SYSTEM_STATS__I2C__ADDR = 24,
|
||||
SYSTEM_STATS__I2C__ADDR_MATCH_CNT = 25,
|
||||
SYSTEM_STATS__I2C__RX_CNT = 26,
|
||||
SYSTEM_STATS__I2C__ERROR_CNT = 27,
|
||||
CONFIG__BRAKE_RESISTANCE = 28,
|
||||
CONFIG__ENABLE_UART = 29,
|
||||
CONFIG__ENABLE_I2C_INSTEAD_OF_CAN = 30,
|
||||
CONFIG__DC_BUS_UNDERVOLTAGE_TRIP_LEVEL = 31,
|
||||
CONFIG__DC_BUS_OVERVOLTAGE_TRIP_LEVEL = 32,
|
||||
TEST_PROPERTY = 235,
|
||||
ADC_GPIO1 = 242,
|
||||
ADC_GPIO2 = 243,
|
||||
SAVE_CONFIGURATION = 244,
|
||||
ERASE_CONFIGURATION = 245,
|
||||
REBOOT = 246,
|
||||
ENTER_DFU_MODE = 247,
|
||||
|
||||
// Per-Axis endpoints (to be used with read_axis_property and write_axis_property)
|
||||
AXIS__ERROR = 33,
|
||||
AXIS__ENABLE_STEP_DIR = 34,
|
||||
AXIS__CURRENT_STATE = 35,
|
||||
AXIS__REQUESTED_STATE = 36,
|
||||
AXIS__LOOP_COUNTER = 37,
|
||||
AXIS__CONFIG__STARTUP_MOTOR_CALIBRATION = 38,
|
||||
AXIS__CONFIG__STARTUP_ENCODER_INDEX_SEARCH = 39,
|
||||
AXIS__CONFIG__STARTUP_ENCODER_OFFSET_CALIBRATION = 40,
|
||||
AXIS__CONFIG__STARTUP_CLOSED_LOOP_CONTROL = 41,
|
||||
AXIS__CONFIG__STARTUP_SENSORLESS_CONTROL = 42,
|
||||
AXIS__CONFIG__ENABLE_STEP_DIR = 43,
|
||||
AXIS__CONFIG__COUNTS_PER_STEP = 44,
|
||||
AXIS__CONFIG__RAMP_UP_TIME = 45,
|
||||
AXIS__CONFIG__RAMP_UP_DISTANCE = 46,
|
||||
AXIS__CONFIG__SPIN_UP_CURRENT = 47,
|
||||
AXIS__CONFIG__SPIN_UP_ACCELERATION = 48,
|
||||
AXIS__CONFIG__SPIN_UP_TARGET_VEL = 49,
|
||||
AXIS__MOTOR__ERROR = 50,
|
||||
AXIS__MOTOR__ARMED_STATE = 51,
|
||||
AXIS__MOTOR__IS_CALIBRATED = 52,
|
||||
AXIS__MOTOR__CURRENT_MEAS_PHB = 53,
|
||||
AXIS__MOTOR__CURRENT_MEAS_PHC = 54,
|
||||
AXIS__MOTOR__DC_CALIB_PHB = 55,
|
||||
AXIS__MOTOR__DC_CALIB_PHC = 56,
|
||||
AXIS__MOTOR__PHASE_CURRENT_REV_GAIN = 57,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__P_GAIN = 58,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__I_GAIN = 59,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_D = 60,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_Q = 61,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__IBUS = 62,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_ALPHA = 63,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_BETA = 64,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__IQ_SETPOINT = 65,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__IQ_MEASURED = 66,
|
||||
AXIS__MOTOR__CURRENT_CONTROL__MAX_ALLOWED_CURRENT = 67,
|
||||
AXIS__MOTOR__GATE_DRIVER__DRV_FAULT = 68,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_GENERAL = 69,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_I = 70,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_DC = 71,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_R = 72,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_L = 73,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ENC_CALIB = 74,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_IDX_SEARCH = 75,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_VOLTAGE = 76,
|
||||
AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_CURRENT = 77,
|
||||
AXIS__MOTOR__CONFIG__PRE_CALIBRATED = 78,
|
||||
AXIS__MOTOR__CONFIG__POLE_PAIRS = 79,
|
||||
AXIS__MOTOR__CONFIG__CALIBRATION_CURRENT = 80,
|
||||
AXIS__MOTOR__CONFIG__RESISTANCE_CALIB_MAX_VOLTAGE = 81,
|
||||
AXIS__MOTOR__CONFIG__PHASE_INDUCTANCE = 82,
|
||||
AXIS__MOTOR__CONFIG__PHASE_RESISTANCE = 83,
|
||||
AXIS__MOTOR__CONFIG__DIRECTION = 84,
|
||||
AXIS__MOTOR__CONFIG__MOTOR_TYPE = 85,
|
||||
AXIS__MOTOR__CONFIG__CURRENT_LIM = 86,
|
||||
AXIS__CONTROLLER__POS_SETPOINT = 87,
|
||||
AXIS__CONTROLLER__VEL_SETPOINT = 88,
|
||||
AXIS__CONTROLLER__VEL_INTEGRATOR_CURRENT = 89,
|
||||
AXIS__CONTROLLER__CURRENT_SETPOINT = 90,
|
||||
AXIS__CONTROLLER__CONFIG__CONTROL_MODE = 91,
|
||||
AXIS__CONTROLLER__CONFIG__POS_GAIN = 92,
|
||||
AXIS__CONTROLLER__CONFIG__VEL_GAIN = 93,
|
||||
AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN = 94,
|
||||
AXIS__CONTROLLER__CONFIG__VEL_LIMIT = 95,
|
||||
AXIS__CONTROLLER__START_ANTICOGGING_CALIBRATION = 105,
|
||||
AXIS__ENCODER__ERROR = 106,
|
||||
AXIS__ENCODER__IS_READY = 107,
|
||||
AXIS__ENCODER__INDEX_FOUND = 108,
|
||||
AXIS__ENCODER__SHADOW_COUNT = 109,
|
||||
AXIS__ENCODER__COUNT_IN_CPR = 110,
|
||||
AXIS__ENCODER__OFFSET = 111,
|
||||
AXIS__ENCODER__INTERPOLATION = 112,
|
||||
AXIS__ENCODER__PHASE = 113,
|
||||
AXIS__ENCODER__POS_ESTIMATE = 114,
|
||||
AXIS__ENCODER__POS_CPR = 115,
|
||||
AXIS__ENCODER__HALL_STATE = 116,
|
||||
AXIS__ENCODER__PLL_VEL = 117,
|
||||
AXIS__ENCODER__PLL_KP = 118,
|
||||
AXIS__ENCODER__PLL_KI = 119,
|
||||
AXIS__ENCODER__CONFIG__MODE = 120,
|
||||
AXIS__ENCODER__CONFIG__USE_INDEX = 121,
|
||||
AXIS__ENCODER__CONFIG__PRE_CALIBRATED = 122,
|
||||
AXIS__ENCODER__CONFIG__IDX_SEARCH_SPEED = 123,
|
||||
AXIS__ENCODER__CONFIG__CPR = 124,
|
||||
AXIS__ENCODER__CONFIG__OFFSET = 125,
|
||||
AXIS__ENCODER__CONFIG__OFFSET_FLOAT = 126,
|
||||
AXIS__ENCODER__CONFIG__CALIB_RANGE = 127,
|
||||
AXIS__SENSORLESS_ESTIMATOR__ERROR = 128,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PHASE = 129,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_POS = 130,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_VEL = 131,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_KP = 132,
|
||||
AXIS__SENSORLESS_ESTIMATOR__PLL_KI = 133,
|
||||
};
|
||||
|
||||
template<int I>
|
||||
struct endpoint_type;
|
||||
|
||||
template<> struct endpoint_type<VBUS_VOLTAGE> { typedef float type; };
|
||||
template<> struct endpoint_type<SERIAL_NUMBER> { typedef uint64_t type; };
|
||||
template<> struct endpoint_type<HW_VERSION_MAJOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<HW_VERSION_MINOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<HW_VERSION_VARIANT> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_MAJOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_MINOR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_REVISION> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<FW_VERSION_UNRELEASED> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<USER_CONFIG_LOADED> { typedef bool type; };
|
||||
template<> struct endpoint_type<BRAKE_RESISTOR_ARMED> { typedef bool type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__UPTIME> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_HEAP_SPACE> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_AXIS0> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_AXIS1> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_COMMS> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_USB> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_UART> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_USB_IRQ> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__MIN_STACK_SPACE_STARTUP> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__USB__RX_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__USB__TX_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__USB__TX_OVERRUN_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__ADDR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__ADDR_MATCH_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__RX_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<SYSTEM_STATS__I2C__ERROR_CNT> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<CONFIG__BRAKE_RESISTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<CONFIG__ENABLE_UART> { typedef bool type; };
|
||||
template<> struct endpoint_type<CONFIG__ENABLE_I2C_INSTEAD_OF_CAN> { typedef bool type; };
|
||||
template<> struct endpoint_type<CONFIG__DC_BUS_UNDERVOLTAGE_TRIP_LEVEL> { typedef float type; };
|
||||
template<> struct endpoint_type<CONFIG__DC_BUS_OVERVOLTAGE_TRIP_LEVEL> { typedef float type; };
|
||||
template<> struct endpoint_type<TEST_PROPERTY> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<ADC_GPIO1> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<ADC_GPIO2> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<SAVE_CONFIGURATION> { typedef void type; };
|
||||
template<> struct endpoint_type<ERASE_CONFIGURATION> { typedef void type; };
|
||||
template<> struct endpoint_type<REBOOT> { typedef void type; };
|
||||
template<> struct endpoint_type<ENTER_DFU_MODE> { typedef void type; };
|
||||
|
||||
|
||||
// Per-axis endpoints
|
||||
template<> struct endpoint_type<AXIS__ERROR> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENABLE_STEP_DIR> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CURRENT_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__REQUESTED_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__LOOP_COUNTER> { typedef uint32_t type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_MOTOR_CALIBRATION> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_ENCODER_INDEX_SEARCH> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_ENCODER_OFFSET_CALIBRATION> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_CLOSED_LOOP_CONTROL> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__STARTUP_SENSORLESS_CONTROL> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__ENABLE_STEP_DIR> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__COUNTS_PER_STEP> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__RAMP_UP_TIME> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__RAMP_UP_DISTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_ACCELERATION> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONFIG__SPIN_UP_TARGET_VEL> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__ERROR> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__ARMED_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__IS_CALIBRATED> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_MEAS_PHB> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_MEAS_PHC> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__DC_CALIB_PHB> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__DC_CALIB_PHC> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__PHASE_CURRENT_REV_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__P_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__I_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_D> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__V_CURRENT_CONTROL_INTEGRAL_Q> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IBUS> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_ALPHA> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__FINAL_V_BETA> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IQ_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__IQ_MEASURED> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CURRENT_CONTROL__MAX_ALLOWED_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__GATE_DRIVER__DRV_FAULT> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_GENERAL> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_I> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ADC_CB_DC> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_R> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_MEAS_L> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_ENC_CALIB> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_IDX_SEARCH> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_VOLTAGE> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__TIMING_LOG__TIMING_LOG_FOC_CURRENT> { typedef uint16_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PRE_CALIBRATED> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__POLE_PAIRS> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__CALIBRATION_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__RESISTANCE_CALIB_MAX_VOLTAGE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PHASE_INDUCTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__PHASE_RESISTANCE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__DIRECTION> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__MOTOR_TYPE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__MOTOR__CONFIG__CURRENT_LIM> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__POS_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__VEL_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__VEL_INTEGRATOR_CURRENT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CURRENT_SETPOINT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__CONTROL_MODE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__POS_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_INTEGRATOR_GAIN> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__CONFIG__VEL_LIMIT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__CONTROLLER__START_ANTICOGGING_CALIBRATION> { typedef void type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__ERROR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__IS_READY> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__INDEX_FOUND> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__SHADOW_COUNT> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__COUNT_IN_CPR> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__OFFSET> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__INTERPOLATION> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PHASE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__POS_ESTIMATE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__POS_CPR> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__HALL_STATE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PLL_VEL> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PLL_KP> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__PLL_KI> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__MODE> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__USE_INDEX> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__PRE_CALIBRATED> { typedef bool type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__IDX_SEARCH_SPEED> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__CPR> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__OFFSET> { typedef int32_t type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__OFFSET_FLOAT> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__ENCODER__CONFIG__CALIB_RANGE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__ERROR> { typedef uint8_t type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PHASE> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_POS> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_VEL> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_KP> { typedef float type; };
|
||||
template<> struct endpoint_type<AXIS__SENSORLESS_ESTIMATOR__PLL_KI> { typedef float type; };
|
||||
|
||||
|
||||
template<int I>
|
||||
using endpoint_type_t = typename endpoint_type<I>::type;
|
||||
|
||||
}
|
||||
|
||||
#endif // __ODRIVE_ENDPOINTS_HPP
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* This file is a very small part of the GCC STL because AVR-GCC ships
|
||||
* without the STL.
|
||||
*/
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
/**
|
||||
* @defgroup metaprogramming Metaprogramming
|
||||
* @ingroup utilities
|
||||
*
|
||||
* Template utilities for compile-time introspection and modification,
|
||||
* including type classification traits, type property inspection traits
|
||||
* and type transformation traits.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// integral_constant
|
||||
template<typename _Tp, _Tp __v>
|
||||
struct integral_constant
|
||||
{
|
||||
static constexpr _Tp value = __v;
|
||||
typedef _Tp value_type;
|
||||
typedef integral_constant<_Tp, __v> type;
|
||||
constexpr operator value_type() const noexcept { return value; }
|
||||
#if __cplusplus > 201103L
|
||||
|
||||
#define __cpp_lib_integral_constant_callable 201304
|
||||
|
||||
constexpr value_type operator()() const noexcept { return value; }
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename _Tp, _Tp __v>
|
||||
constexpr _Tp integral_constant<_Tp, __v>::value;
|
||||
|
||||
/// The type used as a compile-time boolean with true value.
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
|
||||
/// The type used as a compile-time boolean with false value.
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
|
||||
template<bool __v>
|
||||
using __bool_constant = integral_constant<bool, __v>;
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
# define __cpp_lib_bool_constant 201505
|
||||
template<bool __v>
|
||||
using bool_constant = integral_constant<bool, __v>;
|
||||
#endif
|
||||
|
||||
|
||||
// Primary type categories.
|
||||
|
||||
template<typename>
|
||||
struct remove_cv;
|
||||
|
||||
template<typename>
|
||||
struct __is_void_helper
|
||||
: public false_type { };
|
||||
|
||||
template<>
|
||||
struct __is_void_helper<void>
|
||||
: public true_type { };
|
||||
|
||||
/// is_void
|
||||
template<typename _Tp>
|
||||
struct is_void
|
||||
: public __is_void_helper<typename remove_cv<_Tp>::type>::type
|
||||
{ };
|
||||
|
||||
template<typename>
|
||||
struct __is_integral_helper
|
||||
: public false_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<bool>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<char>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<signed char>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned char>
|
||||
: public true_type { };
|
||||
|
||||
#ifdef _GLIBCXX_USE_WCHAR_T
|
||||
template<>
|
||||
struct __is_integral_helper<wchar_t>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<char16_t>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<char32_t>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<short>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned short>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<int>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned int>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<long>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned long>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<long long>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned long long>
|
||||
: public true_type { };
|
||||
|
||||
// Conditionalizing on __STRICT_ANSI__ here will break any port that
|
||||
// uses one of these types for size_t.
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_0)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_0>
|
||||
: public true_type { };
|
||||
#endif
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_1)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_1>
|
||||
: public true_type { };
|
||||
#endif
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_2)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_2>
|
||||
: public true_type { };
|
||||
#endif
|
||||
#if defined(__GLIBCXX_TYPE_INT_N_3)
|
||||
template<>
|
||||
struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_integral_helper<unsigned __GLIBCXX_TYPE_INT_N_3>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
/// is_integral
|
||||
template<typename _Tp>
|
||||
struct is_integral
|
||||
: public __is_integral_helper<typename remove_cv<_Tp>::type>::type
|
||||
{ };
|
||||
|
||||
template<typename>
|
||||
struct __is_floating_point_helper
|
||||
: public false_type { };
|
||||
|
||||
template<>
|
||||
struct __is_floating_point_helper<float>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_floating_point_helper<double>
|
||||
: public true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_floating_point_helper<long double>
|
||||
: public true_type { };
|
||||
|
||||
#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128)
|
||||
template<>
|
||||
struct __is_floating_point_helper<__float128>
|
||||
: public true_type { };
|
||||
#endif
|
||||
|
||||
/// is_floating_point
|
||||
template<typename _Tp>
|
||||
struct is_floating_point
|
||||
: public __is_floating_point_helper<typename remove_cv<_Tp>::type>::type
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
||||
// Const-volatile modifications.
|
||||
|
||||
/// remove_const
|
||||
template<typename _Tp>
|
||||
struct remove_const
|
||||
{ typedef _Tp type; };
|
||||
|
||||
template<typename _Tp>
|
||||
struct remove_const<_Tp const>
|
||||
{ typedef _Tp type; };
|
||||
|
||||
/// remove_volatile
|
||||
template<typename _Tp>
|
||||
struct remove_volatile
|
||||
{ typedef _Tp type; };
|
||||
|
||||
template<typename _Tp>
|
||||
struct remove_volatile<_Tp volatile>
|
||||
{ typedef _Tp type; };
|
||||
|
||||
/// remove_cv
|
||||
template<typename _Tp>
|
||||
struct remove_cv
|
||||
{
|
||||
typedef typename
|
||||
remove_const<typename remove_volatile<_Tp>::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
// Primary template.
|
||||
/// Define a member typedef @c type only if a boolean constant is true.
|
||||
template<bool, typename _Tp = void>
|
||||
struct enable_if
|
||||
{ };
|
||||
|
||||
// Partial specialization for true.
|
||||
template<typename _Tp>
|
||||
struct enable_if<true, _Tp>
|
||||
{ typedef _Tp type; };
|
||||
|
||||
|
||||
// Type relations.
|
||||
|
||||
/// is_same
|
||||
template<typename, typename>
|
||||
struct is_same
|
||||
: public false_type { };
|
||||
|
||||
template<typename _Tp>
|
||||
struct is_same<_Tp, _Tp>
|
||||
: public true_type { };
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Oskar Weigl
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "ODriveArduino.h"
|
||||
|
||||
// Print with stream operator
|
||||
template<class T> inline Print& operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
|
||||
template<> inline Print& operator <<(Print &obj, float arg) { obj.print(arg, 4); return obj; }
|
||||
|
||||
ODriveArduino::ODriveArduino(Stream& serial)
|
||||
: serial_(serial) {}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position) {
|
||||
SetPosition(motor_number, position, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward) {
|
||||
SetPosition(motor_number, position, velocity_feedforward, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward, float current_feedforward) {
|
||||
serial_ << "p " << motor_number << " " << position << " " << velocity_feedforward << " " << current_feedforward << "\n";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetVelocity(int motor_number, float velocity) {
|
||||
SetVelocity(motor_number, velocity, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetVelocity(int motor_number, float velocity, float current_feedforward) {
|
||||
serial_ << "v " << motor_number << " " << velocity << " " << current_feedforward << "\n";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetCurrent(int motor_number, float current) {
|
||||
serial_ << "c " << motor_number << " " << current << "\n";
|
||||
}
|
||||
|
||||
void ODriveArduino::TrapezoidalMove(int motor_number, float position) {
|
||||
serial_ << "t " << motor_number << " " << position << "\n";
|
||||
}
|
||||
|
||||
float ODriveArduino::readFloat() {
|
||||
return readString().toFloat();
|
||||
}
|
||||
|
||||
float ODriveArduino::GetVelocity(int motor_number) {
|
||||
serial_<< "r axis" << motor_number << ".encoder.vel_estimate\n";
|
||||
return ODriveArduino::readFloat();
|
||||
}
|
||||
|
||||
float ODriveArduino::GetPosition(int motor_number) {
|
||||
serial_ << "r axis" << motor_number << ".encoder.pos_estimate\n";
|
||||
return ODriveArduino::readFloat();
|
||||
}
|
||||
|
||||
int32_t ODriveArduino::readInt() {
|
||||
return readString().toInt();
|
||||
}
|
||||
|
||||
bool ODriveArduino::run_state(int axis, int requested_state, bool wait_for_idle, float timeout) {
|
||||
int timeout_ctr = (int)(timeout * 10.0f);
|
||||
serial_ << "w axis" << axis << ".requested_state " << requested_state << '\n';
|
||||
if (wait_for_idle) {
|
||||
do {
|
||||
delay(100);
|
||||
serial_ << "r axis" << axis << ".current_state\n";
|
||||
} while (readInt() != AXIS_STATE_IDLE && --timeout_ctr > 0);
|
||||
}
|
||||
|
||||
return timeout_ctr > 0;
|
||||
}
|
||||
|
||||
String ODriveArduino::readString() {
|
||||
String str = "";
|
||||
static const unsigned long timeout = 1000;
|
||||
unsigned long timeout_start = millis();
|
||||
for (;;) {
|
||||
while (!serial_.available()) {
|
||||
if (millis() - timeout_start >= timeout) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
char c = serial_.read();
|
||||
if (c == '\n')
|
||||
break;
|
||||
str += c;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
#ifndef ODriveArduino_h
|
||||
#define ODriveArduino_h
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "ODriveEnums.h"
|
||||
|
||||
class ODriveArduino {
|
||||
public:
|
||||
ODriveArduino(Stream& serial);
|
||||
|
||||
// Commands
|
||||
void SetPosition(int motor_number, float position);
|
||||
void SetPosition(int motor_number, float position, float velocity_feedforward);
|
||||
void SetPosition(int motor_number, float position, float velocity_feedforward, float current_feedforward);
|
||||
void SetVelocity(int motor_number, float velocity);
|
||||
void SetVelocity(int motor_number, float velocity, float current_feedforward);
|
||||
void SetCurrent(int motor_number, float current);
|
||||
void TrapezoidalMove(int motor_number, float position);
|
||||
// Getters
|
||||
float GetVelocity(int motor_number);
|
||||
float GetPosition(int motor_number);
|
||||
// General params
|
||||
float readFloat();
|
||||
int32_t readInt();
|
||||
|
||||
// State helper
|
||||
bool run_state(int axis, int requested_state, bool wait_for_idle, float timeout = 10.0f);
|
||||
private:
|
||||
String readString();
|
||||
|
||||
Stream& serial_;
|
||||
};
|
||||
|
||||
#endif //ODriveArduino_h
|
||||
@@ -0,0 +1,203 @@
|
||||
|
||||
#ifndef ODriveEnums_h
|
||||
#define ODriveEnums_h
|
||||
|
||||
/* TODO: This file is dangerous because the enums could potentially change between API versions. Should transmit as part of the JSON.
|
||||
** To regenerate this file, nagivate to the top level of the ODrive repository and run:
|
||||
** python Firmware/interface_generator_stub.py --definitions Firmware/odrive-interface.yaml --template tools/arduino_enums_template.j2 --output Arduino/ODriveArduino/ODriveEnums.h
|
||||
*/
|
||||
|
||||
// ODrive.GpioMode
|
||||
enum GpioMode {
|
||||
GPIO_MODE_DIGITAL = 0,
|
||||
GPIO_MODE_DIGITAL_PULL_UP = 1,
|
||||
GPIO_MODE_DIGITAL_PULL_DOWN = 2,
|
||||
GPIO_MODE_ANALOG_IN = 3,
|
||||
GPIO_MODE_UART_A = 4,
|
||||
GPIO_MODE_UART_B = 5,
|
||||
GPIO_MODE_UART_C = 6,
|
||||
GPIO_MODE_CAN_A = 7,
|
||||
GPIO_MODE_I2C_A = 8,
|
||||
GPIO_MODE_SPI_A = 9,
|
||||
GPIO_MODE_PWM = 10,
|
||||
GPIO_MODE_ENC0 = 11,
|
||||
GPIO_MODE_ENC1 = 12,
|
||||
GPIO_MODE_ENC2 = 13,
|
||||
GPIO_MODE_MECH_BRAKE = 14,
|
||||
GPIO_MODE_STATUS = 15,
|
||||
};
|
||||
|
||||
// ODrive.StreamProtocolType
|
||||
enum StreamProtocolType {
|
||||
STREAM_PROTOCOL_TYPE_FIBRE = 0,
|
||||
STREAM_PROTOCOL_TYPE_ASCII = 1,
|
||||
STREAM_PROTOCOL_TYPE_STDOUT = 2,
|
||||
STREAM_PROTOCOL_TYPE_ASCII_AND_STDOUT = 3,
|
||||
};
|
||||
|
||||
// ODrive.Can.Protocol
|
||||
enum Protocol {
|
||||
PROTOCOL_SIMPLE = 0x00000001,
|
||||
};
|
||||
|
||||
// ODrive.Axis.AxisState
|
||||
enum AxisState {
|
||||
AXIS_STATE_UNDEFINED = 0,
|
||||
AXIS_STATE_IDLE = 1,
|
||||
AXIS_STATE_STARTUP_SEQUENCE = 2,
|
||||
AXIS_STATE_FULL_CALIBRATION_SEQUENCE = 3,
|
||||
AXIS_STATE_MOTOR_CALIBRATION = 4,
|
||||
AXIS_STATE_ENCODER_INDEX_SEARCH = 6,
|
||||
AXIS_STATE_ENCODER_OFFSET_CALIBRATION = 7,
|
||||
AXIS_STATE_CLOSED_LOOP_CONTROL = 8,
|
||||
AXIS_STATE_LOCKIN_SPIN = 9,
|
||||
AXIS_STATE_ENCODER_DIR_FIND = 10,
|
||||
AXIS_STATE_HOMING = 11,
|
||||
AXIS_STATE_ENCODER_HALL_POLARITY_CALIBRATION = 12,
|
||||
AXIS_STATE_ENCODER_HALL_PHASE_CALIBRATION = 13,
|
||||
};
|
||||
|
||||
// ODrive.Encoder.Mode
|
||||
enum EncoderMode {
|
||||
ENCODER_MODE_INCREMENTAL = 0,
|
||||
ENCODER_MODE_HALL = 1,
|
||||
ENCODER_MODE_SINCOS = 2,
|
||||
ENCODER_MODE_SPI_ABS_CUI = 256,
|
||||
ENCODER_MODE_SPI_ABS_AMS = 257,
|
||||
ENCODER_MODE_SPI_ABS_AEAT = 258,
|
||||
ENCODER_MODE_SPI_ABS_RLS = 259,
|
||||
ENCODER_MODE_SPI_ABS_MA732 = 260,
|
||||
};
|
||||
|
||||
// ODrive.Controller.ControlMode
|
||||
enum ControlMode {
|
||||
CONTROL_MODE_VOLTAGE_CONTROL = 0,
|
||||
CONTROL_MODE_TORQUE_CONTROL = 1,
|
||||
CONTROL_MODE_VELOCITY_CONTROL = 2,
|
||||
CONTROL_MODE_POSITION_CONTROL = 3,
|
||||
};
|
||||
|
||||
// ODrive.Controller.InputMode
|
||||
enum InputMode {
|
||||
INPUT_MODE_INACTIVE = 0,
|
||||
INPUT_MODE_PASSTHROUGH = 1,
|
||||
INPUT_MODE_VEL_RAMP = 2,
|
||||
INPUT_MODE_POS_FILTER = 3,
|
||||
INPUT_MODE_MIX_CHANNELS = 4,
|
||||
INPUT_MODE_TRAP_TRAJ = 5,
|
||||
INPUT_MODE_TORQUE_RAMP = 6,
|
||||
INPUT_MODE_MIRROR = 7,
|
||||
INPUT_MODE_TUNING = 8,
|
||||
};
|
||||
|
||||
// ODrive.Motor.MotorType
|
||||
enum MotorType {
|
||||
MOTOR_TYPE_HIGH_CURRENT = 0,
|
||||
MOTOR_TYPE_GIMBAL = 2,
|
||||
MOTOR_TYPE_ACIM = 3,
|
||||
};
|
||||
|
||||
// ODrive.Error
|
||||
enum ODriveError {
|
||||
ODRIVE_ERROR_NONE = 0x00000000,
|
||||
ODRIVE_ERROR_CONTROL_ITERATION_MISSED = 0x00000001,
|
||||
ODRIVE_ERROR_DC_BUS_UNDER_VOLTAGE = 0x00000002,
|
||||
ODRIVE_ERROR_DC_BUS_OVER_VOLTAGE = 0x00000004,
|
||||
ODRIVE_ERROR_DC_BUS_OVER_REGEN_CURRENT = 0x00000008,
|
||||
ODRIVE_ERROR_DC_BUS_OVER_CURRENT = 0x00000010,
|
||||
ODRIVE_ERROR_BRAKE_DEADTIME_VIOLATION = 0x00000020,
|
||||
ODRIVE_ERROR_BRAKE_DUTY_CYCLE_NAN = 0x00000040,
|
||||
ODRIVE_ERROR_INVALID_BRAKE_RESISTANCE = 0x00000080,
|
||||
};
|
||||
|
||||
// ODrive.Can.Error
|
||||
enum CanError {
|
||||
CAN_ERROR_NONE = 0x00000000,
|
||||
CAN_ERROR_DUPLICATE_CAN_IDS = 0x00000001,
|
||||
};
|
||||
|
||||
// ODrive.Axis.Error
|
||||
enum AxisError {
|
||||
AXIS_ERROR_NONE = 0x00000000,
|
||||
AXIS_ERROR_INVALID_STATE = 0x00000001,
|
||||
AXIS_ERROR_MOTOR_FAILED = 0x00000040,
|
||||
AXIS_ERROR_SENSORLESS_ESTIMATOR_FAILED = 0x00000080,
|
||||
AXIS_ERROR_ENCODER_FAILED = 0x00000100,
|
||||
AXIS_ERROR_CONTROLLER_FAILED = 0x00000200,
|
||||
AXIS_ERROR_WATCHDOG_TIMER_EXPIRED = 0x00000800,
|
||||
AXIS_ERROR_MIN_ENDSTOP_PRESSED = 0x00001000,
|
||||
AXIS_ERROR_MAX_ENDSTOP_PRESSED = 0x00002000,
|
||||
AXIS_ERROR_ESTOP_REQUESTED = 0x00004000,
|
||||
AXIS_ERROR_HOMING_WITHOUT_ENDSTOP = 0x00020000,
|
||||
AXIS_ERROR_OVER_TEMP = 0x00040000,
|
||||
AXIS_ERROR_UNKNOWN_POSITION = 0x00080000,
|
||||
};
|
||||
|
||||
// ODrive.Motor.Error
|
||||
enum MotorError {
|
||||
MOTOR_ERROR_NONE = 0x00000000,
|
||||
MOTOR_ERROR_PHASE_RESISTANCE_OUT_OF_RANGE = 0x00000001,
|
||||
MOTOR_ERROR_PHASE_INDUCTANCE_OUT_OF_RANGE = 0x00000002,
|
||||
MOTOR_ERROR_DRV_FAULT = 0x00000008,
|
||||
MOTOR_ERROR_CONTROL_DEADLINE_MISSED = 0x00000010,
|
||||
MOTOR_ERROR_MODULATION_MAGNITUDE = 0x00000080,
|
||||
MOTOR_ERROR_CURRENT_SENSE_SATURATION = 0x00000400,
|
||||
MOTOR_ERROR_CURRENT_LIMIT_VIOLATION = 0x00001000,
|
||||
MOTOR_ERROR_MODULATION_IS_NAN = 0x00010000,
|
||||
MOTOR_ERROR_MOTOR_THERMISTOR_OVER_TEMP = 0x00020000,
|
||||
MOTOR_ERROR_FET_THERMISTOR_OVER_TEMP = 0x00040000,
|
||||
MOTOR_ERROR_TIMER_UPDATE_MISSED = 0x00080000,
|
||||
MOTOR_ERROR_CURRENT_MEASUREMENT_UNAVAILABLE = 0x00100000,
|
||||
MOTOR_ERROR_CONTROLLER_FAILED = 0x00200000,
|
||||
MOTOR_ERROR_I_BUS_OUT_OF_RANGE = 0x00400000,
|
||||
MOTOR_ERROR_BRAKE_RESISTOR_DISARMED = 0x00800000,
|
||||
MOTOR_ERROR_SYSTEM_LEVEL = 0x01000000,
|
||||
MOTOR_ERROR_BAD_TIMING = 0x02000000,
|
||||
MOTOR_ERROR_UNKNOWN_PHASE_ESTIMATE = 0x04000000,
|
||||
MOTOR_ERROR_UNKNOWN_PHASE_VEL = 0x08000000,
|
||||
MOTOR_ERROR_UNKNOWN_TORQUE = 0x10000000,
|
||||
MOTOR_ERROR_UNKNOWN_CURRENT_COMMAND = 0x20000000,
|
||||
MOTOR_ERROR_UNKNOWN_CURRENT_MEASUREMENT = 0x40000000,
|
||||
MOTOR_ERROR_UNKNOWN_VBUS_VOLTAGE = 0x80000000,
|
||||
MOTOR_ERROR_UNKNOWN_VOLTAGE_COMMAND = 0x100000000,
|
||||
MOTOR_ERROR_UNKNOWN_GAINS = 0x200000000,
|
||||
MOTOR_ERROR_CONTROLLER_INITIALIZING = 0x400000000,
|
||||
MOTOR_ERROR_UNBALANCED_PHASES = 0x800000000,
|
||||
};
|
||||
|
||||
// ODrive.Controller.Error
|
||||
enum ControllerError {
|
||||
CONTROLLER_ERROR_NONE = 0x00000000,
|
||||
CONTROLLER_ERROR_OVERSPEED = 0x00000001,
|
||||
CONTROLLER_ERROR_INVALID_INPUT_MODE = 0x00000002,
|
||||
CONTROLLER_ERROR_UNSTABLE_GAIN = 0x00000004,
|
||||
CONTROLLER_ERROR_INVALID_MIRROR_AXIS = 0x00000008,
|
||||
CONTROLLER_ERROR_INVALID_LOAD_ENCODER = 0x00000010,
|
||||
CONTROLLER_ERROR_INVALID_ESTIMATE = 0x00000020,
|
||||
CONTROLLER_ERROR_INVALID_CIRCULAR_RANGE = 0x00000040,
|
||||
CONTROLLER_ERROR_SPINOUT_DETECTED = 0x00000080,
|
||||
};
|
||||
|
||||
// ODrive.Encoder.Error
|
||||
enum EncoderError {
|
||||
ENCODER_ERROR_NONE = 0x00000000,
|
||||
ENCODER_ERROR_UNSTABLE_GAIN = 0x00000001,
|
||||
ENCODER_ERROR_CPR_POLEPAIRS_MISMATCH = 0x00000002,
|
||||
ENCODER_ERROR_NO_RESPONSE = 0x00000004,
|
||||
ENCODER_ERROR_UNSUPPORTED_ENCODER_MODE = 0x00000008,
|
||||
ENCODER_ERROR_ILLEGAL_HALL_STATE = 0x00000010,
|
||||
ENCODER_ERROR_INDEX_NOT_FOUND_YET = 0x00000020,
|
||||
ENCODER_ERROR_ABS_SPI_TIMEOUT = 0x00000040,
|
||||
ENCODER_ERROR_ABS_SPI_COM_FAIL = 0x00000080,
|
||||
ENCODER_ERROR_ABS_SPI_NOT_READY = 0x00000100,
|
||||
ENCODER_ERROR_HALL_NOT_CALIBRATED_YET = 0x00000200,
|
||||
};
|
||||
|
||||
// ODrive.SensorlessEstimator.Error
|
||||
enum SensorlessEstimatorError {
|
||||
SENSORLESS_ESTIMATOR_ERROR_NONE = 0x00000000,
|
||||
SENSORLESS_ESTIMATOR_ERROR_UNSTABLE_GAIN = 0x00000001,
|
||||
SENSORLESS_ESTIMATOR_ERROR_UNKNOWN_CURRENT_MEASUREMENT = 0x00000002,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
# ODriveArduino
|
||||
Arduino library for the ODrive
|
||||
|
||||
To install the library, first clone this repository. In the Arduino IDE select: *Sketch -> Include Library -> Add .ZIP Library...*
|
||||
|
||||
Select the enclosing folder (e.g. ODriveArduino) to add it. Restarting the Arduino IDE may be necessary to see the examples in the *File* dropdown. Check the included example *ODriveArduinoTest* for basic usage.
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
// includes
|
||||
#include <HardwareSerial.h>
|
||||
#include <SoftwareSerial.h>
|
||||
#include <ODriveArduino.h>
|
||||
// Printing with stream operator helper functions
|
||||
template<class T> inline Print& operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
|
||||
template<> inline Print& operator <<(Print &obj, float arg) { obj.print(arg, 4); return obj; }
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// Set up serial pins to the ODrive
|
||||
////////////////////////////////
|
||||
|
||||
// Below are some sample configurations.
|
||||
// You can comment out the default Teensy one and uncomment the one you wish to use.
|
||||
// You can of course use something different if you like
|
||||
// Don't forget to also connect ODrive GND to Arduino GND.
|
||||
|
||||
// Teensy 3 and 4 (all versions) - Serial1
|
||||
// pin 0: RX - connect to ODrive TX
|
||||
// pin 1: TX - connect to ODrive RX
|
||||
// See https://www.pjrc.com/teensy/td_uart.html for other options on Teensy
|
||||
HardwareSerial& odrive_serial = Serial1;
|
||||
|
||||
// Arduino Mega or Due - Serial1
|
||||
// pin 19: RX - connect to ODrive TX
|
||||
// pin 18: TX - connect to ODrive RX
|
||||
// See https://www.arduino.cc/reference/en/language/functions/communication/serial/ for other options
|
||||
// HardwareSerial& odrive_serial = Serial1;
|
||||
|
||||
// Arduino without spare serial ports (such as Arduino UNO) have to use software serial.
|
||||
// Note that this is implemented poorly and can lead to wrong data sent or read.
|
||||
// pin 8: RX - connect to ODrive TX
|
||||
// pin 9: TX - connect to ODrive RX
|
||||
// SoftwareSerial odrive_serial(8, 9);
|
||||
|
||||
|
||||
// ODrive object
|
||||
ODriveArduino odrive(odrive_serial);
|
||||
|
||||
void setup() {
|
||||
// ODrive uses 115200 baud
|
||||
odrive_serial.begin(115200);
|
||||
|
||||
// Serial to PC
|
||||
Serial.begin(115200);
|
||||
while (!Serial) ; // wait for Arduino Serial Monitor to open
|
||||
|
||||
Serial.println("ODriveArduino");
|
||||
Serial.println("Setting parameters...");
|
||||
|
||||
// In this example we set the same parameters to both motors.
|
||||
// You can of course set them different if you want.
|
||||
// See the documentation or play around in odrivetool to see the available parameters
|
||||
for (int axis = 0; axis < 2; ++axis) {
|
||||
odrive_serial << "w axis" << axis << ".controller.config.vel_limit " << 10.0f << '\n';
|
||||
odrive_serial << "w axis" << axis << ".motor.config.current_lim " << 11.0f << '\n';
|
||||
// This ends up writing something like "w axis0.motor.config.current_lim 10.0\n"
|
||||
}
|
||||
|
||||
Serial.println("Ready!");
|
||||
Serial.println("Send the character '0' or '1' to calibrate respective motor (you must do this before you can command movement)");
|
||||
Serial.println("Send the character 's' to exectue test move");
|
||||
Serial.println("Send the character 'b' to read bus voltage");
|
||||
Serial.println("Send the character 'p' to read motor positions in a 10s loop");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
if (Serial.available()) {
|
||||
char c = Serial.read();
|
||||
|
||||
// Run calibration sequence
|
||||
if (c == '0' || c == '1') {
|
||||
int motornum = c-'0';
|
||||
int requested_state;
|
||||
|
||||
requested_state = AXIS_STATE_MOTOR_CALIBRATION;
|
||||
Serial << "Axis" << c << ": Requesting state " << requested_state << '\n';
|
||||
if(!odrive.run_state(motornum, requested_state, true)) return;
|
||||
|
||||
requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION;
|
||||
Serial << "Axis" << c << ": Requesting state " << requested_state << '\n';
|
||||
if(!odrive.run_state(motornum, requested_state, true, 25.0f)) return;
|
||||
|
||||
requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL;
|
||||
Serial << "Axis" << c << ": Requesting state " << requested_state << '\n';
|
||||
if(!odrive.run_state(motornum, requested_state, false /*don't wait*/)) return;
|
||||
}
|
||||
|
||||
// Sinusoidal test move
|
||||
if (c == 's') {
|
||||
Serial.println("Executing test move");
|
||||
for (float ph = 0.0f; ph < 6.28318530718f; ph += 0.01f) {
|
||||
float pos_m0 = 2.0f * cos(ph);
|
||||
float pos_m1 = 2.0f * sin(ph);
|
||||
odrive.SetPosition(0, pos_m0);
|
||||
odrive.SetPosition(1, pos_m1);
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Read bus voltage
|
||||
if (c == 'b') {
|
||||
odrive_serial << "r vbus_voltage\n";
|
||||
Serial << "Vbus voltage: " << odrive.readFloat() << '\n';
|
||||
}
|
||||
|
||||
// print motor positions in a 10s loop
|
||||
if (c == 'p') {
|
||||
static const unsigned long duration = 10000;
|
||||
unsigned long start = millis();
|
||||
while(millis() - start < duration) {
|
||||
for (int motor = 0; motor < 2; ++motor) {
|
||||
Serial << odrive.GetPosition(motor) << '\t';
|
||||
}
|
||||
Serial << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,525 @@
|
||||
|
||||
## [0.5.6] - Unreleased
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed race condition in homing sequence that was causing strange behaviour. Fixes [#634](https://github.com/odriverobotics/ODrive/issues/634)]
|
||||
* When using a load encoder, CAN will report the correct position and velocity.
|
||||
* When using a load encoder, homing will reset the correct linear position. Fixes [#651](https://github.com/odriverobotics/ODrive/issues/651)
|
||||
* Implemented CAN controller error message, which was previously defined but not actually implemented.
|
||||
* Get Vbus Voltage message updated to match ODrive Pro's CANSimple implementation.
|
||||
* `vel_setpoint` and `torque_setpoint` will be clamped to `vel_limit` and the active torque limit. Fixes [#647](https://github.com/odriverobotics/ODrive/issues/647)
|
||||
|
||||
### Added
|
||||
|
||||
* Added public `controller.get_anticogging_value(uint32)` fibre function to index into the the cogging map. Fixes [#690](https://github.com/odriverobotics/ODrive/issues/690)
|
||||
* Added Get ADC Voltage message to CAN (0x1C). Send the desired GPIO number in byte 1, and the ODrive will respond with the ADC voltage from that pin (if previously configured for analog)
|
||||
* Added CAN heartbeat message flags for motor, controller, and encoder error. If flag is true, fetch the corresponding error with the respective message.
|
||||
* Added scoped enums, e.g. `CONTROL_MODE_POSITION_CONTROL` can be used as `ControlMode.POSITION_CONTROL`
|
||||
* Added more cyclic messages to can. Use the `rate_ms` values in `<odrv>.<axis>.config.can` to set the cycle rate of the message in milliseconds. Set a rate to 0 to disable sending. The following variables are avaialble:
|
||||
|
||||
Command ID | Rate Variable | Message Name
|
||||
:-- | :-- | :--
|
||||
0x01 | `heartbeat_rate_ms` | Heartbeat
|
||||
0x09 | `encoder_rate_ms` | Get Encoder Estimates
|
||||
0x03 | `motor_error_rate_ms` | Get Motor Error
|
||||
0x04 | `encoder_error_rate_ms` | Get Encoder Error
|
||||
0x1D | `controller_error_rate_ms` | Get Controller Error
|
||||
0x05 | `sensorless_error_rate_ms` | Get Sensorless Error
|
||||
0x0A | `encoder_count_rate_ms` | Get Encoder Count
|
||||
0x14 | `iq_rate_ms` | Get Iq
|
||||
0x15 | `sensorless_rate_ms` | Get Sensorless Estimates
|
||||
0x17 | `bus_vi_rate_ms` | Get Bus Voltage Current
|
||||
|
||||
### Changed
|
||||
|
||||
* Improved can_generate_dbc.py file and resultant .dbc. Now supports 8 ODrive axes (0..7) natively
|
||||
* Add units and value tables to every signal in odrive-cansimple.dbc
|
||||
* Autogenerate odrive-cansimple.dbc on compile
|
||||
|
||||
## [0.5.5] - 2022-08-11
|
||||
|
||||
* CANSimple messages which previously required the rtr bit to be set will now also respond if DLC = 0
|
||||
* Ensure endstops update before being checked for errors, to prevent [#625](https://github.com/odriverobotics/ODrive/issues/625)
|
||||
* Reset trajectory_done_ during homing to ensure a new trajectory is actually computed [#634](https://github.com/odriverobotics/ODrive/issues/634)
|
||||
* Use `input_xxx` as a DC offset in tuning mode
|
||||
* Sync `steps_` with input pos.
|
||||
* Trigger reset of input_pos and pos_setpoint to estimate when changing control mode into position control
|
||||
|
||||
## [0.5.4] - 2021-10-12
|
||||
|
||||
### Fixed
|
||||
* Some ASCII protocol commands (e.g. `w axis0.requested_state 4`) resulted in `not implemented` due to an issue with the CI compiler. A workaround was made to fix this.
|
||||
* Fixed bad response of some ASCII procotol commands (e.g. `r axis0.error` returned `0d` instead of `0`).
|
||||
|
||||
### Added
|
||||
* Added `<axis>.controller.config.vel_integrator_limit`
|
||||
* Allow setting controller gains on CAN Simple
|
||||
|
||||
## [0.5.3] - 2021-09-03
|
||||
|
||||
### Fixed
|
||||
* ASCII protocol commands with multiline responses (`i`, `h`) now return the expected response (in v0.5.2 the response was corrupted)
|
||||
* odrivetool no longer shows the message `<Task pending coro=... running at ...>` when closing
|
||||
* Homing used to erroneously complete with `is_homed == True` even if it failed for some reason
|
||||
* When entering closed loop control in trapezoidal trajectory mode the axis no longer snaps to the 0 position
|
||||
* Fix python DFU firmware version prerelease status resolution to use correct attribute
|
||||
* Fixed firmware compiled-in version number
|
||||
|
||||
### Added
|
||||
* `brake_resistor_current` added to interface for reading the commanded brake resistor current
|
||||
|
||||
### Changed
|
||||
* Removed `odrivetool generate-code`. This feature was broken in 0.5.2. Use [`interface_generator.py`](https://github.com/odriverobotics/ODrive/blob/master/tools/fibre-tools/interface_generator.py) instead (see Tupfile.lua for examples).
|
||||
* Firmware boots on devices with unset OTP.
|
||||
* Changed CAN heartbeat message to include "trajectory done" flag
|
||||
|
||||
## [0.5.2] - 2021-05-21
|
||||
|
||||
### Fixed
|
||||
* spinout error is no longer sticky and doesn't trigger on static torque loads due to I^2*R electrical power
|
||||
* Step and direction mode resets position when entering closed loop just like `input_pos` does
|
||||
* CAN baud rate setting is now correctly handled
|
||||
* `odrivetool dfu` works properly when an ODrive is flashed with the `dfu` switch set to "dfu".
|
||||
* `odrivetool dfu` now erases the entire flash memory before flashing firmware. This ensures that old configuration parameters are erased.
|
||||
* ASCII and the Native Protocol do not run at the same time on a UART interface. See `odrv0.config.uart0_protocol` and the `STREAM_PROTOCOL_TYPE` enums for details.
|
||||
|
||||
### Added
|
||||
* `sc` command to ascii protocol to run `odrv.clear_errors()`
|
||||
* Added phase balance check to motor calibration and MOTOR_ERROR_UNBALANCED_PHASES to error enums
|
||||
* Added polarity and phase offset calibration for hall effect encoders
|
||||
* [Mechanical brake support](docs/mechanical-brakes.md)
|
||||
* Added periodic sending of encoder position on CAN
|
||||
* Support for UART1 on GPIO3 and GPIO4. UART0 (on GPIO1/2) and UART1 can currently not be enabled at the same time.
|
||||
* Thermistors now have a 2nd order lowpass filter applied to reduce noise
|
||||
* 2-norm current clamping is used for AC induction motors
|
||||
* Added spinout detection to detect incorrect encoder offset and CONTROLLER_ERROR_SPINOUT_DETECTED to error enums.
|
||||
* Added AARCH64 support to libfibre
|
||||
* Tuning input mode added to provide sinusoidal position, velocity, or torque stimulus. See INPUT_MODE_TUNING and the controller class for details.
|
||||
* Added torque mirroring to INPUT_MODE_MIRROR
|
||||
* `mechanical_power_bandwidth`, `electrical_power_bandwidth`, `spinout_electrical_power_threshold`, `spinout_mechanical_power_threshold` added to `controller.config` for spinout detection.
|
||||
* `mechanical_power` and `electrical_power` added to `controller`.
|
||||
* Added autogenerated enums header file [ODriveEnums.h](../Arduino/ODriveArduino/ODriveEnums.h) for Arduino use. Created Jinja template and edited Makefile to autogenerate it. Reflected change in Dockerfile and added note in developer-guide markdown file for updating ODriveEnums.h alongside enums.py.
|
||||
* Added GetPosition member function in ODriveArduino class to complement existing GetVelocity, SetVelocity, and SetPosition functions.
|
||||
|
||||
### Changed
|
||||
* Step/dir performance improved! Dual axis step rates up to 250kHz have been tested
|
||||
* Apply_config is called for encoders after a successful direction find
|
||||
* Full calibration sequence now includes hall polarity calibration if a hall effect encoder is used
|
||||
* Modified encoder offset calibration to work correctly when calib_scan_distance is not a multiple of 4pi
|
||||
* Moved thermistors from being a top level object to belonging to Motor objects. Also changed errors: thermistor errors rolled into motor errors
|
||||
* Use DMA for DRV8301 setup
|
||||
* Make NVM configuration code more dynamic so that the layout doesn't have to be known at compile time.
|
||||
* GPIO initialization logic was changed. GPIOs now need to be explicitly set to the mode corresponding to the feature that they are used by. See `<odrv>.config.gpioX_mode`.
|
||||
* Previously, if two components used the same interrupt pin (e.g. step input for axis0 and axis1) then the one that was configured later would override the other one. Now this is no longer the case (the old component remains the owner of the pin).
|
||||
* New control loop architecture:
|
||||
1. TIM8 update interrupt handler (CNT = 0) runs at a high priority and invokes the system level function `sample_cb()` to sample all timing critical inputs (currently only encoder state).
|
||||
2. TIM8 update interrupt handler (CNT = 0) raises an NVIC flag to kick off a lower priority interrupt.
|
||||
3. The control loop interrupt handler checks if all ADC measurements are ready and informs both motor objects about the current measurements.
|
||||
4. The control loop interrupt handler invokes the system level function `control_loop_cb()` which updates all components (encoders, estimators, torque controllers, etc). The data paths between the components are configured by the Axis threads based on the requested state. This replaces the previous architecture where the components were updated inside the Axis threads in `Axis::run_control_loop()`.
|
||||
5. Meanwhile the TIM1 and TIM8 updates for CNT = 3500 will have fired. The control loop interrupt handler thus reads the new ADC measurements and informs both motor objects that a DC calibration event has happened.
|
||||
6. Finally, the control loop interrupt invokes `pwm_update_cb` on both motors to make them update their PWM timing registers.
|
||||
* Components that need low level control over PWM timings are implemented by inheriting from the `PhaseControlLaw` interface. Three components currently inherit this interface: `FieldOrientedController`, `ResistanceMeasurementControlLaw` and `InductanceMeasurementControlLaw`.
|
||||
* The FOC algorithm is now found in foc.cpp and and is presumably capable of running at a different frequency than the main control tasks (not relevant for ODrive v3).
|
||||
* ACIM estimator was consolidated into a separate component `<odrv>.acim_estimator`.
|
||||
* The Automatic Output Enable (AOE) flag of TIM1/TIM8 is used to achieve glitch-free motor arming.
|
||||
* Sensorless mode was merged into closed loop control mode. Use `<axis>.enable_sensorless_mode` to disable the use of an encoder.
|
||||
* More informative profiling instrumentation was added.
|
||||
* A system-level error property was introduced.
|
||||
* Added `torque_mirror_ratio` and use it to feed-forward `controller_.torque_output` in `INPUT_MODE_MIRROR`
|
||||
* Accumulate integer steps in step/dir to avoid float precision errors
|
||||
* Circular setpoint mode must be enabled when the step/dir interface is used.
|
||||
* Replaced inline enum in ODriveArduino class by including new autogenerated ODriveEnums.h header file.
|
||||
* Changed the example ODriveArduinoTest.ino file to reflect the new GetPosition member function. Also removed the scope resolution operator to access the enums as it can now be accessed from the global namespace.
|
||||
* `save_configuration()` reboots the board.
|
||||
|
||||
### API Migration Notes
|
||||
* `axis.config.turns_per_step` changed to `axis.controller.config.steps_per_circular_range`
|
||||
* `odrive.axis.fet_thermistor`, `odrive.axis.motor_thermistor` moved to `odrive.axis.motor` object
|
||||
* `enable_uart` and `uart_baudrate` were renamed to `enable_uart0` and `uart0_baudrate`.
|
||||
* `enable_i2c_instead_of_can` was replaced by the separate settings `enable_i2c0` and `enable_can0`.
|
||||
* `<axis>.motor.gate_driver` was moved to `<axis>.gate_driver`.
|
||||
* `<axis>.min_endstop.pullup` and `<axis>.max_endstop.pullup` were removed. Use `<odrv>.config.gpioX_mode = GPIO_MODE_DIGITAL / GPIO_MODE_DIGITAL_PULL_UP / GPIO_MODE_DIGITAL_PULL_DOWN` instead.
|
||||
* `<axis>.config.can_node_id` was moved to `<axis>.config.can.node_id`
|
||||
* `<axis>.config.can_node_id_extended` was moved to `<axis>.config.can.is_extended`
|
||||
* `<axis>.config.can_heartbeat_rate_ms` was moved to `<axis>.config.can.heartbeat_rate_ms`
|
||||
* `<odrv>.get_oscilloscope_val()` was moved to `<odrv>.oscilloscope.get_val()`.
|
||||
* Several error flags from `<odrv>.<axis>.error` were removed. Some were moved to `<odrv>.error` and some are no longer relevant because implementation details changed.
|
||||
* Several error flags from `<odrv>.<axis>.motor.error` were removed. Some were moved to `<odrv>.error` and some are no longer relevant because implementation details changed.
|
||||
* `<axis>.lockin_state` was removed as the lockin implementation was replaced by a more general open loop control block (currently not exposed on the API).
|
||||
* `AXIS_STATE_SENSORLESS_CONTROL` was removed. Use `AXIS_STATE_CLOSED_LOOP_CONTROL` instead with `<odrv>.enable_sensorless_mode = True`.
|
||||
* `<axis>.config.startup_sensorless_control` was removed. Use `<axis>.config.startup_closed_loop_control` instead with `<odrv>.enable_sensorless_mode = True`.
|
||||
* `<axis>.clear_errors()` was replaced by the system-wide function `<odrv>.clear_errors()`.
|
||||
* `<axis>.armed_state` was replaced by `<axis>.is_armed`.
|
||||
* Several properties in `<axis>.motor.current_control` were changed to read-only.
|
||||
* `<axis>.motor.current_control.Ibus` was moved to `<axis>.motor.I_bus`.
|
||||
* `<axis>.motor.current_control.max_allowed_current` was moved to `<axis>.motor.max_allowed_current`.
|
||||
* `<axis>.motor.current_control.overcurrent_trip_level` was removed.
|
||||
* `<axis>.motor.current_control.acim_rotor_flux` was moved to `<axis>.acim_estimator.rotor_flux`.
|
||||
* `<axis>.motor.current_control.async_phase_vel` was moved to `<axis>.acim_estimator.stator_phase_vel`.
|
||||
* `<axis>.motor.current_control.async_phase_offset` was moved to `<axis>.acim_estimator.phase`.
|
||||
* `<axis>.motor.timing_log` was removed in favor of `<odrv>.task_times` and `<odrv>.<axis>.task_times`.
|
||||
* `<axis>.motor.config.direction` was moved to `<axis>.encoder.config.direction`.
|
||||
* `<axis>.motor.config.acim_slip_velocity` was moved to `<axis>.acim_estimator.config.slip_velocity`.
|
||||
* Several properties were changed to readonly.
|
||||
* `<axis>.encoder.config.offset` was renamed to ``<axis>.encoder.config.phase_offset`
|
||||
* `<axis>.encoder.config.offset_float` was renamed to ``<axis>.encoder.config.phase_offset_float`
|
||||
* `<odrv>.config.brake_resistance == 0.0` is no longer a valid way to disable the brake resistor. Use `<odrv>.config.enable_brake_resistor` instead. A reboot is necessary for this to take effect.
|
||||
* `<odrv>.can.set_baud_rate()` was removed. The baudrate is now automatically updated when writing to `<odrv>.can.config.baud_rate`.
|
||||
|
||||
## [0.5.1] - 2020-09-27
|
||||
### Added
|
||||
* Added motor `torque_constant`: units of torque are now [Nm] instead of just motor current.
|
||||
* Added `motor.config.torque_lim`: limit for motor torque in [Nm].
|
||||
* [Motor thermistors support](docs/thermistors.md)
|
||||
* Enable/disable of thermistor thermal limits according `setting axis.<thermistor>.enabled`.
|
||||
* Introduced `odrive-interface.yaml` as a root source for the ODrive's API. `odrivetool` connects much faster as a side effect.
|
||||
* Added torque_constant and torque_lim to motor config
|
||||
|
||||
### Changed
|
||||
* **`input_pos`, `input_vel`, `pos_estimate_linear`, `pos_estimate_circular`, are now in units of [turns] or [turns/s] instead of [counts] or [counts/s]**
|
||||
* **`pos_gain`, `vel_gain`, `vel_integrator_gain`, are now in units of [(turns/s) / turns], [Nm/(turns/s)], [Nm/(turns/s * s)] instead of [(counts/s) / counts], [A/(counts/s)], [A/((counts/s) * s)].** `pos_gain` is not affected. Old values of `vel_gain` and `vel_integrator_gain` should be multiplied by `torque_constant * encoder cpr` to convert from the old units to the new units. `torque_constant` is approximately equal to 8.27 / (motor KV).
|
||||
* `axis.motor.thermal_current_lim` has been removed. Instead a new property is available `axis.motor.effective_current_lim` which contains the effective current limit including any thermal limits.
|
||||
* `axis.motor.get_inverter_temp()`, `axis.motor.inverter_temp_limit_lower` and `axis.motor.inverter_temp_limit_upper` have been moved to seperate fet thermistor object under `axis.fet_thermistor`. `get_inverter_temp()` function has been renamed to `temp` and is now a read-only property.
|
||||
* `axis.config.counts_per_step` is now `axis.config.turns_per_step`
|
||||
* Outputs of `axis.sensorless_estimator` are now in turns/s instead of electrical rad/s
|
||||
* Fixed bug of high current during lockin-ramp caused by `motor::update()` expecting a torque command instead of current
|
||||
* Fixed bug where commanded velocity was extremely high just after sensorless ramp when using `input_mode` INPUT_MODE_VEL_RAMP caused by `vel_setpoint` and `axis.config.sensorless_ramp.vel` being in different units
|
||||
|
||||
### Fixed
|
||||
* Fixed bug of high current during lockin-ramp caused by `motor::update()` expecting a torque command instead of current
|
||||
* Fixed bug where commanded velocity was extremely high just after sensorless ramp when using `input_mode` INPUT_MODE_VEL_RAMP caused by `vel_setpoint` and `axis.config.sensorless_ramp.vel` being in different units
|
||||
|
||||
## [0.5.0] - 2020-08-03
|
||||
### Added
|
||||
* AC Induction Motor support.
|
||||
* Tracking of rotor flux through rotor time constant
|
||||
* Automatic d axis current for Maximum Torque Per Amp (MTPA)
|
||||
* ASCII "w" commands now execute write hooks.
|
||||
* Simplified control interface ("Input Filter" branch)
|
||||
* New input variables: `input_pos`, `input_vel`, and `input_current`
|
||||
* New setting `input_mode` to switch between different input behaviours
|
||||
* Passthrough
|
||||
* Velocity Ramp
|
||||
* 2nd Order Position Filter
|
||||
* Trapezoidal Trajectory Planner
|
||||
* Removed `set_xxx_setpoint()` functions and made `xxx_setpoint` variables read-only
|
||||
* [Preliminary support for Absolute Encoders](docs/encoders.md)
|
||||
* [Preliminary support for endstops and homing](docs/endstops.md)
|
||||
* [CAN Communication with CANSimple stack](can-protocol.md)
|
||||
* Gain scheduling for anti-hunt when close to 0 position error
|
||||
* Velocity Limiting in Current Control mode according to `vel_limit` and `vel_gain`
|
||||
* Regen current limiting according to `max_regen_current`, in Amps
|
||||
* DC Bus hard current limiting according to `dc_max_negative_current` and `dc_max_positive_current`
|
||||
* Brake resistor logic now attempts to clamp voltage according to `odrv.config.dc_bus_overvoltage_ramp_start` and `odrv.config.dc_bus_overvoltage_ramp_end`
|
||||
* Unit Testing with Doctest has been started for select algorithms, see [Firmware/Tests/test_runner.cpp](Firmware/Tests/test_runner.cpp)
|
||||
* Added support for Flylint VSCode Extension for static code analysis
|
||||
* Using an STM32F405 .svd file allows CortexDebug to view registers during debugging
|
||||
* Added scripts for building via docker.
|
||||
* Added ability to change uart baudrate via fibre
|
||||
|
||||
### Changed
|
||||
* Changed ratiometric `motor.config.current_lim_tolerance` to absolute `motor.config.current_lim_margin`
|
||||
* Moved `controller.vel_ramp_enable` to INPUT_MODE_VEL_RAMP.
|
||||
* Anticogging map is temporarily forced to 0.1 deg precision, but saves with the config
|
||||
* Some Encoder settings have been made read-only
|
||||
* Cleaned up VSCode C/C++ Configuration settings on Windows with recursive includePath
|
||||
* Now compiling with C++17
|
||||
* Fixed a firmware hang that could occur from unlikely but possible user input
|
||||
* Added JSON caching to Fibre. This drastically reduces the time odrivetool needs to connect to an ODrive (except for the first time or after firmware updates).
|
||||
* Fix IPython `RuntimeWarning` that would occur every time `odrivetool` was started.
|
||||
* Reboot on `erase_configuration()`. This avoids unexpected behavior of a subsequent `save_configuration()` call, since the configuration is only erased from NVM, not from RAM.
|
||||
* Change `motor.get_inverter_temp()` to use a property which was already being sampled at `motor.inverter_temp`
|
||||
* Fixed a numerical issue in the trajectory planner that could cause sudden jumps of the position setpoint
|
||||
|
||||
## [0.4.12] - 2020-05-06
|
||||
### Fixed
|
||||
* Fixed a numerical issue in the trajectory planner that could cause sudden jumps of the position setpoint
|
||||
|
||||
## [0.4.11] - 2019-07-25
|
||||
### Added
|
||||
* Separate lockin configs for sensorless, index search, and general.
|
||||
* Check current limit violation: added `ERROR_CURRENT_UNSTABLE`, `motor.config.current_lim_tolerance`.
|
||||
|
||||
### Changed
|
||||
* Ascii command for reboot changed from `sb` to `sr`.
|
||||
|
||||
## [0.4.10] - 2019-04-24
|
||||
### Fixed
|
||||
* Index search would trigger in the wrong place.
|
||||
|
||||
## [0.4.9] - 2019-04-23
|
||||
### Added
|
||||
* A release target for ODrive v3.6
|
||||
* Communication watchdog feature.
|
||||
* `encoder.set_linear_count(count)` function.
|
||||
* Configurable encoder offset calibration distance and speed:`calib_scan_distance` and `calib_scan_omega`
|
||||
* Encoder offset calibration debug variable `calib_scan_response`
|
||||
* Lock-in drive feature
|
||||
* Script to enable using a hall signal as index edge.
|
||||
|
||||
### Changed
|
||||
* Moved `traptraj.A_per_css` to `controller.inertia`
|
||||
* Refactored velocity ramp mode into the new general input filtering structure
|
||||
* Encoder index search now based on the new lock-in drive feature
|
||||
|
||||
### Fixed
|
||||
* Encoder index interrupts now disabled when not searching
|
||||
|
||||
## [0.4.8] - 2019-02-25
|
||||
### Added
|
||||
* `dump_errors()` utility function in odrivetool to dump, decode and optionally clear errors.
|
||||
* `f` command to ascii protocol to get encoder position and velocity feedback.
|
||||
* `q` command to ascii protocol. It is like the old `p` command, but velocity and current mean limits, not feed-forward.
|
||||
* `ss`, `se`, `sr` commands to ascii protocol, for save config, erase config and reboot.
|
||||
* `move_incremental` function for relative trajectory moves.
|
||||
* `encoder.config.ignore_illegal_hall_state` option.
|
||||
* `encoder.config.enable_phase_interpolation` option. Setting to false may reduce jerky pulsations at low speed when using hall sensor feedback.
|
||||
* Analog input. Used the same way as the PWM input mappings.
|
||||
* Voltage limit soft clamping instead of ERROR_MODULATION_MAGNITUDE in gimbal motor closed loop.
|
||||
* Thermal current limit with linear derating.
|
||||
|
||||
### Changed
|
||||
* Unified lockin drive modes. Current for index searching and encoder offset calibration now moved to axis.lockin.current.
|
||||
|
||||
### Fixed
|
||||
* Added required 1.5 cycle phase shift between ADC and PWM, lack thereof caused unstable current controller at high eRPM.
|
||||
|
||||
## [0.4.7] - 2018-11-28
|
||||
### Added
|
||||
* Overspeed fault
|
||||
* Current sense saturation fault.
|
||||
* Suppress startup transients by sampling encoder estimate into position setpoint when entering closed loop control.
|
||||
* Make step dir gpio pins configurable.
|
||||
* Configuration variable `encoder.config.zero_count_on_find_idx`, true by default. Set to false to leave the initial encoder count to be where the axis was at boot.
|
||||
* Circular position setpoint mode: position setpoints wrapped [0, cpr). Useful for infinite incremental position control.
|
||||
* Velocity setpoint ramping. Use velocity control mode, and set `controller.vel_ramp_enable` to true. This will ramp `controller.vel_setpoint` towards `controller.vel_ramp_target` at a ramp rate of `controller.config.vel_ramp_rate`.
|
||||
|
||||
### Changed
|
||||
* Increased switching frequency from around 8kHz to 24kHz. Control loops still run at 8kHz.
|
||||
* Renamed `axis.enable_step_dir` to `axis.step_dir_active`
|
||||
* New process for working with STM32CubeMX.
|
||||
|
||||
### Fixed
|
||||
* Would get ERROR_CONTROL_DEADLINE_MISSED along with every ERROR_PHASE_RESISTANCE_OUT_OF_RANGE.
|
||||
* ODrive tool can now run interactive nested scripts with "%run -i script.py"
|
||||
|
||||
## [0.4.6] - 2018-10-07
|
||||
### Fixed
|
||||
* Broken printing of floats on ascii protocol
|
||||
|
||||
## [0.4.5] - 2018-10-06
|
||||
### Added
|
||||
* **Trapezoidal Trajectory Planner**
|
||||
* Hook to execute protocol property written callback
|
||||
* -Wdouble-promotion warning to compilation
|
||||
|
||||
### Changed
|
||||
* Make python tools compatible with python 2.7 (so it can be used with ROS)
|
||||
* Threading API constructor can't take the daemon parameter, so all thread creation had to be expanded out.
|
||||
* `TimeoutError` isn't defined, but it makes for more readable code, so I defined it as an OSError subclass.
|
||||
* `ModuleNotFoundError` is replaced by the older ImportError.
|
||||
* Print function imported from future
|
||||
* Using new hooks to calculate:
|
||||
* `motor.config.current_control_bandwidth`
|
||||
* This deprecates `motor.set_current_control_bandwidth()`
|
||||
* `encoder.config.bandwidth`
|
||||
* Default value for `motor.resistance_calib_max_voltage` changed to 2.0
|
||||
|
||||
### Fixed
|
||||
* An issue where the axis state machine would jump in and out of idle when there is an error
|
||||
* There is a [bug](https://github.com/ARM-software/CMSIS_5/issues/267) in the arm fast math library, which gives spikes in the output of arm_cos_f32 for input values close to -pi/2. We fixed the bug locally, and hence are using "our_arm_cos_f32".
|
||||
|
||||
## [0.4.4] - 2018-09-18
|
||||
### Fixed
|
||||
* Serious reliability issue with USB communication where packets on Native and the CDC interface would collide with each other.
|
||||
|
||||
## [0.4.3] - 2018-08-30
|
||||
### Added
|
||||
* `min_endstop` and `max_endstop` objects can be configured on GPIO
|
||||
* Axes can be homed if `min_endstop` is enabled
|
||||
* Encoder position count "homed" to zero when index is found.
|
||||
|
||||
### Changed
|
||||
* We now enforce encoder offset calibration must happen after index is found (if using index)
|
||||
* Renaming of the velocity estimate `pll_vel` -> `vel_estimate`.
|
||||
* Hardcoded maximum inductance now 2500 uH.
|
||||
|
||||
### Fixed
|
||||
* Incorrect shifting of offset during index callback
|
||||
* Once you got an axis error `ERROR_INVALID_STATE` you could never clear it
|
||||
* Char to int conversion to read motornum on arduino example
|
||||
* GPIO above #5 would not be used correctly in some cases
|
||||
|
||||
## [0.4.2] - 2018-08-04
|
||||
### Added
|
||||
* Hall sensor feedback
|
||||
* Configurable RC PWM input
|
||||
* Ability to read axis FET temperature
|
||||
* Config settings for:
|
||||
* `motor.config.requested_current_range`
|
||||
* `motor.config.current_control_bandwidth` and `motor.set_current_control_bandwidth`. Latter required to invoke gain recalculation.
|
||||
* `encoder.config.bandwidth`
|
||||
* `sensorless_estimator.config.pm_flux_linkage`
|
||||
|
||||
## [0.4.1] - 2018-07-01
|
||||
### Fixed
|
||||
* Encoder errors would show up as Axis error `ERROR_MOTOR_FAILED` instead of `ERROR_ENCODER_FAILED`.
|
||||
* Various pip install dependencies
|
||||
* Ability for python tools threads to quit properly
|
||||
* dfuse error prints now python3 compatible
|
||||
|
||||
## [0.4.0] - 2018-06-10
|
||||
### Added
|
||||
* Encoder can now go forever in velocity/torque mode due to using circular encoder space.
|
||||
* Protocol supports function return values
|
||||
* bake Git-derived firmware version into firmware binary. The firmware version is exposed through the `fw_version_[...]` properties.
|
||||
* `make write_otp` command to burn the board version onto the ODrive's one-time programmable memory. If you have an ODrive v3.4 or older, you should run this once for a better firmware update user experience in the future. Run the command without any options for more details. Once set, the board version is exposed through the `hw_version_[...]` properties.
|
||||
* infrastructure to publish the python tools to PyPi. See `tools/setup.py` for details.
|
||||
* Automated test script `run_tests.py`
|
||||
* System stats (e.g. stack usage) are exposed under `<odrv>.system_stats`
|
||||
|
||||
### Changed
|
||||
* DFU script updates
|
||||
* Verify the flash after writing
|
||||
* Automatically download firmware from GitHub releases if no file is provided
|
||||
* Retain configuration during firmware updates
|
||||
* Refactor python tools
|
||||
* The scripts `explore_odrive.py`, `liveplotter.py`, `drv_status.py` and `rate_test.py` have been merged into one single `odrivetool` script. Running this script without any arguments provides the shell that `explore_odrive.py` used to provide.
|
||||
* The command line options of `odrivetool` have changed compared to the original `explore_odrive.py`. See `odrivetool --help` for more details.
|
||||
* `odrivetool` (previously `explore_odrive.py`) now supports controlling multiple ODrives concurrently (`odrv0`, `odrv1`, ...)
|
||||
* No need to restart the `odrivetool` shell when devices get disconnected and reconnected
|
||||
* ODrive accesses from within python tools are now thread-safe. That means you can read from the same remote property from multiple threads concurrently.
|
||||
* The liveplotter (`odrivetool liveplotter`, formerly `liveplotter.py`) does no longer steal focus and closes as expected
|
||||
* Add commands `odrivetool backup-config` and `odrivetool restore-config`
|
||||
* (experimental: start liveplotter from `odrivetool` shell by typing `start_liveplotter(lambda: odrv0.motor0.encoder.encoder_state)`)
|
||||
* Set thread priority of USB pump thread above protocol thread
|
||||
* GPIO3 not sensitive to edges by default
|
||||
* The device now appears as a composite device on USB. One subdevice is still a CDC device (virtual COM port), the other subdevice is a vendor specific class. This should resolve several issues that were caused by conflicting kernel drivers or OS services.
|
||||
* Add WinUSB descriptors. This will tell Windows >= 8 to automatically load winusb.sys for the ODrive (only for the vendor specific subdevice). This makes it possible to use the ODrive from userspace via WinUSB with zero configuration. The Python tool currently still uses libusb so Zadig is still required.
|
||||
* Add a configuration to enable the ASCII protocol on USB at runtime. This will only enable the ASCII protocol on the USB CDC subdevice, not the vendor specific subdevice so the python tools will still be able to talk to the ODrive.
|
||||
|
||||
### Fixed
|
||||
* Enums now transported with correct underlying type on native protocol
|
||||
* USB issue where the device would stop responding when the host script would quit abruptly or reset the device during operation
|
||||
|
||||
## [0.3.6] - 2018-03-26
|
||||
### Added
|
||||
* **Storing of configuration parameters to Non Volatile Memory**
|
||||
* **USB Bootloader**
|
||||
* `make erase_config` to erase the configuration with an STLink (the configuration can also be erased from within explore_odrive.py, using `odrv0.erase_configuration()`)
|
||||
* Travis-CI builds firmware for all board versions and deploys the binaries when a tag is pushed to master
|
||||
* General purpose ADC API. See function get_adc_voltage() in low_level.cpp for more detais.
|
||||
|
||||
### Changed
|
||||
* Most of the code from `lowlevel.c` moved to `axis.cpp`, `encoder.cpp`, `controller.cpp`, `sensorless_estimator.cpp`, `motor.cpp` and the corresponding header files
|
||||
* Refactoring of the developer-facing communication protocol interface. See e.g. `axis.hpp` or `controller.hpp` for examples on how to add your own fields and functions
|
||||
* Change of the user-facing field paths. E.g. `my_odrive.motor0.pos_setpoint` is now at `my_odrive.axis0.controller.pos_setpoint`. Names are mostly unchanged.
|
||||
* Rewrite of the top-level per-axis state-machine
|
||||
* The build is now configured using the `tup.config` file instead of editing source files. Make sure you set your board version correctly. See [here](README.md#configuring-the-build) for details.
|
||||
* The toplevel directory for tup is now `Firmware`. If you used tup before, go to `Firmware` and run `rm -rd ../.tup; rm -rd build/*; make`.
|
||||
* Update CubeMX generated STM platform code to version 1.19.0
|
||||
* Remove `UUID_0`, `UUID_1` and `UUID_2` from USB protocol. Use `serial_number` instead.
|
||||
* Freertos memory pool (task stacks, etc) now uses Core Coupled Memory.
|
||||
|
||||
### Fixed
|
||||
* malloc now fails if we run out of memory (before it would always succeed even if we are out of ram...)
|
||||
|
||||
## [0.3.5] - 2018-03-04
|
||||
### Added
|
||||
* Reporting error if your encoder CPR is incorrect
|
||||
* Ability to start anticogging calibration over USB protocol
|
||||
* Reporting of DRV status/control registers and fault codes
|
||||
* DRV status read script
|
||||
* Microsecond delay function
|
||||
* Travis-CI
|
||||
* Firmware update over USB
|
||||
|
||||
### Changed
|
||||
* Build system is now tup instead of make. Please check the [Readme](README.md#installing-prerequisites) for installation instructions.
|
||||
|
||||
## [0.3.4] - 2018-02-13
|
||||
### Fixed
|
||||
* Broken way to check for python 2. Python 2 not supported yet.
|
||||
|
||||
## [0.3.3] - 2018-02-12
|
||||
### Added
|
||||
* Liveplotter script
|
||||
* Automatic recovery of USB halt/stall condition
|
||||
|
||||
### Changed
|
||||
* Modified python code to be Python 2 compatible
|
||||
|
||||
### Fixed
|
||||
* USB CSC (USB serial) now reports a sensible baud rate
|
||||
|
||||
## [0.3.2] - 2018-02-02
|
||||
### Added
|
||||
* Gimbal motor mode
|
||||
* Encoder index pulse support
|
||||
* `resistance_calib_max_voltage` parameter
|
||||
|
||||
## [0.3.1] - 2018-01-18
|
||||
### Added
|
||||
* UUID Endpoint
|
||||
* Reporting of correct ODrive version on USB descriptor
|
||||
* Getting started instructions for VSCode
|
||||
|
||||
### Changed
|
||||
* USB Product ID to 0x0D32, as it is the only Pid we were allocated on [pid.codes](http://pid.codes/1209/0D32/)
|
||||
* Recommended method to debug firmware from VSCode now uses Cortex-Debug extension instead of native-debug.
|
||||
* Refactor IDE instructions into separate files
|
||||
|
||||
### Fixed
|
||||
* Bug where the remote function calls from Python to the ODrive were not working properly.
|
||||
|
||||
## [0.3] - 2017-12-18
|
||||
### Added
|
||||
* **New binary communication protocol**
|
||||
* This is a much richer and more efficient binary protocol than the old human-readable protocol.
|
||||
* The old protocol is still available (but will be depricated eventually). You must manually chose to fall back on this protocol if you wish to still use it.
|
||||
* Support for C++
|
||||
* Demo scripts for getting started with commanding ODrive from python
|
||||
* Protection from user setting current_lim higher than is measurable
|
||||
* Current sense shunt values for HW v3.4
|
||||
* Check DRV chip fault line
|
||||
|
||||
### Changed
|
||||
* Shunt resistance values for v3.3 and earlier to include extra resistance of PCB
|
||||
* Default HW revision to v3.4
|
||||
* Refactoring of control code:
|
||||
* Lifted top layer of low_level.c into Axis.cpp
|
||||
|
||||
## [0.2.2] - 2017-11-17
|
||||
### Fixed
|
||||
* Incorrect TIM14 interrupt mapping on board v3.2 caused hard-fault
|
||||
|
||||
### Changed
|
||||
* GPIO communication mode now defaults to NONE
|
||||
|
||||
## [0.2.1] - 2017-11-14
|
||||
### Fixed
|
||||
* USB communication deadlock
|
||||
* EXTI handler redefiniton in V3.2
|
||||
|
||||
### Changed
|
||||
* Resistance/inductance measurement now saved dispite errors, to allow debugging
|
||||
|
||||
## [0.2.0] - 2017-11-12
|
||||
### Added
|
||||
* UART communication
|
||||
* Setting to select UART or Step/dir on GIPIO 1,2
|
||||
* Basic Anti-cogging
|
||||
|
||||
## [0.1.0] - 2017-08-26
|
||||
### Added
|
||||
* Step/Dir interface
|
||||
* this Changelog
|
||||
* motor control interrupt timing diagram
|
||||
* uint16 exposed variable type
|
||||
* null termination to USB string parsing
|
||||
|
||||
### Changed
|
||||
* Fixed Resistance measurement bug
|
||||
* Simplified motor control adc triggers
|
||||
* Increased AUX bridge deadtime
|
||||
@@ -0,0 +1,37 @@
|
||||
FROM ubuntu:bionic
|
||||
|
||||
# Prepare the build environment and dependencies
|
||||
RUN \
|
||||
set -x && \
|
||||
apt-get update && \
|
||||
apt-get -y install software-properties-common && \
|
||||
add-apt-repository ppa:team-gcc-arm-embedded/ppa && \
|
||||
add-apt-repository ppa:jonathonf/tup && \
|
||||
apt-get update && \
|
||||
apt-get -y upgrade && \
|
||||
apt-get -y install gcc-arm-embedded openocd tup python3.7 python3-yaml python3-jinja2 python3-jsonschema build-essential git time && \
|
||||
# Build step below does not know about debian's python naming schemme
|
||||
ln -s /usr/bin/python3.7 /usr/bin/python && \
|
||||
mkdir -p ODrive
|
||||
|
||||
WORKDIR ODrive/Firmware
|
||||
|
||||
# Must attach the firmware tree into the container
|
||||
CMD \
|
||||
# Regenerate autogen/version.c
|
||||
mkdir -p autogen && \
|
||||
python ../tools/odrive/version.py \
|
||||
--output autogen/version.c && \
|
||||
# Regenerate python interface
|
||||
python interface_generator_stub.py \
|
||||
--definitions odrive-interface.yaml \
|
||||
--template ../tools/enums_template.j2 \
|
||||
--output ../tools/odrive/enums.py && \
|
||||
python interface_generator_stub.py \
|
||||
--definitions odrive-interface.yaml \
|
||||
--template ../tools/arduino_enums_template.j2 \
|
||||
--output ../Arduino/ODriveArduino/ODriveEnums.h && \
|
||||
# Hack around Tup's dependency on FUSE
|
||||
tup init && \
|
||||
tup generate build.sh && \
|
||||
./build.sh
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
AllowShortCaseLabelsOnASingleLine: 'true'
|
||||
IndentWidth: '4'
|
||||
ColumnLimit: '0'
|
||||
...
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
#build folder
|
||||
autogen/
|
||||
build/
|
||||
deploy/
|
||||
.dep/
|
||||
tup_build.sh
|
||||
|
||||
#markdown preview output
|
||||
README.html
|
||||
|
||||
#autogenerated project files
|
||||
.cproject
|
||||
.mxproject
|
||||
Odrive.xml
|
||||
|
||||
#Eclipse stuff
|
||||
.settings/
|
||||
.project
|
||||
|
||||
# VSCode stuff
|
||||
/.vscode/.cortex-debug.*.state.json
|
||||
|
||||
# STM32CubeMX (in case you put it in this folder, or a symlink)
|
||||
STM32CubeMX
|
||||
|
||||
#gdb log
|
||||
openocd.log
|
||||
|
||||
# OS-specific files
|
||||
.DS_Store
|
||||
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ODrive v3.6 Windows",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/ThirdParty/FreeRTOS/Source/portable/GCC/ARM_CM4F",
|
||||
"${workspaceFolder}/fibre-cpp/include"
|
||||
],
|
||||
"compilerPath": "${ARM_GCC_ROOT}/bin/arm-none-eabi-g++.exe",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"defines": [
|
||||
"__arm__",
|
||||
"STM32F405xx",
|
||||
"FPU_FPV4",
|
||||
"USE_HAL_DRIVER",
|
||||
"HW_VERSION_MAJOR=3",
|
||||
"HW_VERSION_MINOR=6",
|
||||
"HW_VERSION_VOLTAGE=56",
|
||||
"FIBRE_ENABLE_SERVER",
|
||||
"FIBRE_ENABLE_CLIENT",
|
||||
"__weak=\"__attribute__((weak))\"",
|
||||
"__packed=\"__attribute__((__packed__))\"",
|
||||
"__GNUC__"
|
||||
],
|
||||
"compilerArgs": [
|
||||
"-mthumb",
|
||||
"-mcpu=cortex-m4",
|
||||
"-mfpu=fpv4-sp-d16",
|
||||
"-mfloat-abi=hard",
|
||||
"-specs=nosys.specs",
|
||||
"-specs=nano.specs",
|
||||
"-u _printf_float",
|
||||
"-u _scanf_float"
|
||||
],
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "ODrive 3.6 Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/ThirdParty/FreeRTOS/Source/portable/GCC/ARM_CM4F",
|
||||
"${workspaceFolder}/fibre-cpp/include"
|
||||
],
|
||||
"compilerPath": "arm-none-eabi-g++",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"defines": [
|
||||
"__arm__",
|
||||
"STM32F405xx",
|
||||
"FPU_FPV4",
|
||||
"USE_HAL_DRIVER",
|
||||
"HW_VERSION_MAJOR=3",
|
||||
"HW_VERSION_MINOR=6",
|
||||
"HW_VERSION_VOLTAGE=56",
|
||||
"FIBRE_ENABLE_SERVER",
|
||||
"FIBRE_ENABLE_CLIENT",
|
||||
"__weak=\"__attribute__((weak))\"",
|
||||
"__packed=\"__attribute__((__packed__))\"",
|
||||
"__GNUC__"
|
||||
],
|
||||
"compilerArgs": [
|
||||
"-mthumb",
|
||||
"-mcpu=cortex-m4",
|
||||
"-mfpu=fpv4-sp-d16",
|
||||
"-mfloat-abi=hard",
|
||||
"-specs=nosys.specs",
|
||||
"-specs=nano.specs",
|
||||
"-u _printf_float",
|
||||
"-u _scanf_float"
|
||||
],
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "ODrive 3.6 Mac",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/ThirdParty/FreeRTOS/Source/portable/GCC/ARM_CM4F",
|
||||
"${workspaceFolder}/fibre-cpp/include"
|
||||
],
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"defines": [
|
||||
"__arm__",
|
||||
"STM32F405xx",
|
||||
"FPU_FPV4",
|
||||
"USE_HAL_DRIVER",
|
||||
"HW_VERSION_MAJOR=3",
|
||||
"HW_VERSION_MINOR=6",
|
||||
"HW_VERSION_VOLTAGE=56",
|
||||
"FIBRE_ENABLE_SERVER",
|
||||
"FIBRE_ENABLE_CLIENT",
|
||||
"__weak=\"__attribute__((weak))\"",
|
||||
"__packed=\"__attribute__((__packed__))\"",
|
||||
"__GNUC__"
|
||||
],
|
||||
"compilerArgs": [
|
||||
"-mthumb",
|
||||
"-mcpu=cortex-m4",
|
||||
"-mfpu=fpv4-sp-d16",
|
||||
"-mfloat-abi=hard",
|
||||
"-specs=nosys.specs",
|
||||
"-specs=nano.specs",
|
||||
"-u _printf_float",
|
||||
"-u _scanf_float"
|
||||
],
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// For the Cortex-Debug extension
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"request": "launch",
|
||||
"name": "Debug ODrive v3.x - ST-Link",
|
||||
"executable": "${workspaceRoot}/build/ODriveFirmware.elf",
|
||||
"configFiles": [
|
||||
"interface/stlink-v2.cfg",
|
||||
"target/stm32f4x_stlink.cfg",
|
||||
],
|
||||
"svdFile": "${workspaceRoot}/Board/v3/STM32F40x.svd",
|
||||
"cwd": "${workspaceRoot}"
|
||||
},
|
||||
{
|
||||
// For the Cortex-Debug extension
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"request": "launch",
|
||||
"name": "Debug ODrive v4.x - ST-Link",
|
||||
"executable": "${workspaceRoot}/build/ODriveFirmware.elf",
|
||||
"configFiles": [
|
||||
"interface/stlink.cfg",
|
||||
"target/stm32f7x.cfg",
|
||||
],
|
||||
"openOCDLaunchCommands": [
|
||||
"reset_config none separate"
|
||||
],
|
||||
"svdFile": "${workspaceRoot}/Private/v4/STM32F722.svd",
|
||||
"cwd": "${workspaceRoot}"
|
||||
},
|
||||
{
|
||||
// For the Cortex-Debug extension
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"request": "launch",
|
||||
"name": "Debug ODrive v3.x - ST-Link - FreeRTOS",
|
||||
"executable": "${workspaceRoot}/build/ODriveFirmware.elf",
|
||||
"rtos": "FreeRTOS",
|
||||
"configFiles": [
|
||||
"interface/stlink-v2.cfg",
|
||||
"target/stm32f4x_stlink.cfg",
|
||||
],
|
||||
"svdFile": "${workspaceRoot}/Board/v3/STM32F40x.svd",
|
||||
"cwd": "${workspaceRoot}"
|
||||
},
|
||||
{
|
||||
// For the Cortex-Debug extension
|
||||
// ssh -t odrv3 -L3333:localhost:3333 bash -c "\"openocd '-f' 'interface/stlink-v2.cfg' '-f' 'target/stm32f4x_stlink.cfg'\""
|
||||
"type": "cortex-debug",
|
||||
"servertype": "external",
|
||||
"gdbTarget": "localhost:3333",
|
||||
"preLaunchCommands": [
|
||||
"load"
|
||||
],
|
||||
"request": "launch",
|
||||
"name": "Debug ODrive v3.x - Remote",
|
||||
"executable": "${workspaceRoot}/build/ODriveFirmware.elf",
|
||||
"configFiles": [
|
||||
"interface/stlink-v2.cfg",
|
||||
"target/stm32f4x_stlink.cfg",
|
||||
],
|
||||
"svdFile": "${workspaceRoot}/Board/v3/STM32F40x.svd",
|
||||
"cwd": "${workspaceRoot}"
|
||||
},
|
||||
{
|
||||
// For the Cortex-Debug extension
|
||||
// ssh -t odrv4 -L3333:localhost:3333 bash -c "\"openocd '-f' 'interface/stlink.cfg' '-f' 'target/stm32f7x.cfg' -c 'reset_config none separate'\""
|
||||
"type": "cortex-debug",
|
||||
"servertype": "external",
|
||||
"gdbTarget": "localhost:3333",
|
||||
"preLaunchCommands": [
|
||||
"load"
|
||||
],
|
||||
"request": "launch",
|
||||
"name": "Debug ODrive v4.x - Remote",
|
||||
"executable": "${workspaceRoot}/build/ODriveFirmware.elf",
|
||||
"configFiles": [
|
||||
"interface/stlink.cfg",
|
||||
"target/stm32f7x.cfg",
|
||||
],
|
||||
"svdFile": "${workspaceRoot}/Private/v4/STM32F722.svd",
|
||||
"cwd": "${workspaceRoot}"
|
||||
},
|
||||
{
|
||||
// For the Cortex-Debug extensions
|
||||
"type": "cortex-debug",
|
||||
"servertype": "bmp",
|
||||
"request": "launch",
|
||||
"name": "Debug ODrive v3.x - Black Magic Probe",
|
||||
"executable": "${workspaceRoot}/build/ODriveFirmware.elf",
|
||||
"device": "STM32F4xx",
|
||||
"BMPGDBSerialPort": "${env:BMP_PORT}",
|
||||
"interface": "swd",
|
||||
"targetId": 1,
|
||||
"armToolchainPath": "${env:ARM_GCC_ROOT}/bin/",
|
||||
"cwd": "${workspaceRoot}"
|
||||
}
|
||||
]
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"C_Cpp.intelliSenseEngine": "Default",
|
||||
"C_Cpp.intelliSenseEngineFallback": "Disabled",
|
||||
"files.associations": {
|
||||
"memory": "cpp",
|
||||
"utility": "cpp",
|
||||
"deque": "cpp",
|
||||
"vector": "cpp",
|
||||
"array": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"exception": "cpp",
|
||||
"functional": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"algorithm": "cpp"
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "make",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"panel": "new"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "flash - ST-Link",
|
||||
"type": "shell",
|
||||
"command": "make flash",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "flash - Black Magic Probe",
|
||||
"type": "shell",
|
||||
"command": "make flashbmp",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "openocd",
|
||||
"type": "shell",
|
||||
"command": "openocd -f \"interface/stlink-v2.cfg\" -f \"target/stm32f4x_stlink.cfg\" -c \"gdb_port 3333; log_output openocd.log\"",
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
*
|
||||
* These definitions should be adjusted for your particular hardware and
|
||||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* Section where include file can be added */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Ensure stdint is only used by the compiler, and not the assembler. */
|
||||
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
||||
#include <stdint.h>
|
||||
extern uint32_t SystemCoreClock;
|
||||
#endif
|
||||
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
||||
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||
#define configMAX_PRIORITIES ( 7 )
|
||||
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
||||
#define configTOTAL_HEAP_SIZE ((size_t)65536)
|
||||
#define configMAX_TASK_NAME_LEN ( 16 )
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 1
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
|
||||
/* Co-routine definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero
|
||||
to exclude the API function. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskCleanUpResources 0
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_xTaskGetSchedulerState 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
|
||||
/* Cortex-M specific definitions. */
|
||||
#ifdef __NVIC_PRIO_BITS
|
||||
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
|
||||
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||
#else
|
||||
#define configPRIO_BITS 4
|
||||
#endif
|
||||
|
||||
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
||||
function. */
|
||||
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
||||
|
||||
/* The highest interrupt priority that can be used by any interrupt service
|
||||
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
|
||||
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
||||
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
||||
|
||||
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
|
||||
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
|
||||
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||
|
||||
/* Normal assert() semantics without relying on the provision of an assert.h
|
||||
header file. */
|
||||
/* USER CODE BEGIN 1 */
|
||||
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
||||
standard names. */
|
||||
#define vPortSVCHandler SVC_Handler
|
||||
#define xPortPendSVHandler PendSV_Handler
|
||||
|
||||
/* IMPORTANT: This define MUST be commented when used with STM32Cube firmware,
|
||||
to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
|
||||
/* #define xPortSysTickHandler SysTick_Handler */
|
||||
|
||||
/* USER CODE BEGIN Defines */
|
||||
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
|
||||
#define configAPPLICATION_ALLOCATED_HEAP 1 // ucHeap allocated in freertos.c
|
||||
/* USER CODE END Defines */
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : ADC.h
|
||||
* Description : This file provides code for the configuration
|
||||
* of the ADC instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __adc_H
|
||||
#define __adc_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern ADC_HandleTypeDef hadc1;
|
||||
extern ADC_HandleTypeDef hadc2;
|
||||
extern ADC_HandleTypeDef hadc3;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
extern void _Error_Handler(char *, int);
|
||||
|
||||
void MX_ADC1_Init(void);
|
||||
void MX_ADC2_Init(void);
|
||||
void MX_ADC3_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ adc_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* @brief Contains board specific configuration for ODrive v3.x
|
||||
*/
|
||||
|
||||
#ifndef __BOARD_CONFIG_H
|
||||
#define __BOARD_CONFIG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// STM specific includes
|
||||
#include <stm32f4xx_hal.h>
|
||||
#include <gpio.h>
|
||||
#include <spi.h>
|
||||
#include <tim.h>
|
||||
#include <can.h>
|
||||
#include <i2c.h>
|
||||
#include <usb_device.h>
|
||||
#include <main.h>
|
||||
#include "cmsis_os.h"
|
||||
|
||||
#include <arm_math.h>
|
||||
|
||||
#include <Drivers/STM32/stm32_system.h>
|
||||
|
||||
#if HW_VERSION_MINOR <= 3
|
||||
#define SHUNT_RESISTANCE (675e-6f)
|
||||
#else
|
||||
#define SHUNT_RESISTANCE (500e-6f)
|
||||
#endif
|
||||
|
||||
#define AXIS_COUNT (2)
|
||||
|
||||
// Total count of GPIOs, including encoder pins, CAN pins and a dummy GPIO0.
|
||||
// ODrive v3.4 and earlier don't have GPIOs 6, 7 and 8 but to keep the numbering
|
||||
// consistent we just leave a gap in the counting scheme.
|
||||
#define GPIO_COUNT (17)
|
||||
|
||||
#define CAN_FREQ (2000000UL)
|
||||
|
||||
#if HW_VERSION_MINOR >= 5 && HW_VERSION_VOLTAGE >= 48
|
||||
#define DEFAULT_BRAKE_RESISTANCE (2.0f) // [ohm]
|
||||
#else
|
||||
#define DEFAULT_BRAKE_RESISTANCE (0.47f) // [ohm]
|
||||
#endif
|
||||
|
||||
#define DEFAULT_ERROR_PIN 0
|
||||
#define DEFAULT_MIN_DC_VOLTAGE 8.0f
|
||||
|
||||
#define DEFAULT_GPIO_MODES \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL, \
|
||||
ODriveIntf::GPIO_MODE_UART_A, \
|
||||
ODriveIntf::GPIO_MODE_UART_A, \
|
||||
ODriveIntf::GPIO_MODE_ANALOG_IN, \
|
||||
ODriveIntf::GPIO_MODE_ANALOG_IN, \
|
||||
ODriveIntf::GPIO_MODE_ANALOG_IN, \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL, \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL, \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL, \
|
||||
ODriveIntf::GPIO_MODE_ENC0, \
|
||||
ODriveIntf::GPIO_MODE_ENC0, \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL_PULL_DOWN, \
|
||||
ODriveIntf::GPIO_MODE_ENC1, \
|
||||
ODriveIntf::GPIO_MODE_ENC1, \
|
||||
ODriveIntf::GPIO_MODE_DIGITAL_PULL_DOWN, \
|
||||
ODriveIntf::GPIO_MODE_CAN_A, \
|
||||
ODriveIntf::GPIO_MODE_CAN_A,
|
||||
|
||||
#define TIM_TIME_BASE TIM14
|
||||
|
||||
// Run control loop at the same frequency as the current measurements.
|
||||
#define CONTROL_TIMER_PERIOD_TICKS (2 * TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR + 1))
|
||||
|
||||
#define TIM1_INIT_COUNT (TIM_1_8_PERIOD_CLOCKS / 2 - 1 * 128) // TODO: explain why this offset
|
||||
|
||||
// The delta from the control loop timestamp to the current sense timestamp is
|
||||
// exactly 0 for M0 and TIM1_INIT_COUNT for M1.
|
||||
#define MAX_CONTROL_LOOP_UPDATE_TO_CURRENT_UPDATE_DELTA (TIM_1_8_PERIOD_CLOCKS / 2 + 1 * 128)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Drivers/DRV8301/drv8301.hpp>
|
||||
#include <Drivers/STM32/stm32_gpio.hpp>
|
||||
#include <Drivers/STM32/stm32_spi_arbiter.hpp>
|
||||
#include <MotorControl/pwm_input.hpp>
|
||||
#include <MotorControl/thermistor.hpp>
|
||||
|
||||
using TGateDriver = Drv8301;
|
||||
using TOpAmp = Drv8301;
|
||||
|
||||
#include <MotorControl/motor.hpp>
|
||||
#include <MotorControl/encoder.hpp>
|
||||
|
||||
extern std::array<Axis, AXIS_COUNT> axes;
|
||||
extern Motor motors[AXIS_COUNT];
|
||||
extern OnboardThermistorCurrentLimiter fet_thermistors[AXIS_COUNT];
|
||||
extern Encoder encoders[AXIS_COUNT];
|
||||
extern Stm32Gpio gpios[GPIO_COUNT];
|
||||
|
||||
struct GpioFunction { int mode = 0; uint8_t alternate_function = 0xff; };
|
||||
extern std::array<GpioFunction, 3> alternate_functions[GPIO_COUNT];
|
||||
|
||||
extern USBD_HandleTypeDef& usb_dev_handle;
|
||||
|
||||
extern Stm32SpiArbiter& ext_spi_arbiter;
|
||||
|
||||
extern UART_HandleTypeDef* uart_a;
|
||||
extern UART_HandleTypeDef* uart_b;
|
||||
extern UART_HandleTypeDef* uart_c;
|
||||
|
||||
extern PwmInput pwm0_input;
|
||||
#endif
|
||||
|
||||
// Period in [s]
|
||||
#define CURRENT_MEAS_PERIOD ( (float)2*TIM_1_8_PERIOD_CLOCKS*(TIM_1_8_RCR+1) / (float)TIM_1_8_CLOCK_HZ )
|
||||
static const float current_meas_period = CURRENT_MEAS_PERIOD;
|
||||
|
||||
// Frequency in [Hz]
|
||||
#define CURRENT_MEAS_HZ ( (float)(TIM_1_8_CLOCK_HZ) / (float)(2*TIM_1_8_PERIOD_CLOCKS*(TIM_1_8_RCR+1)) )
|
||||
static const int current_meas_hz = CURRENT_MEAS_HZ;
|
||||
|
||||
#if HW_VERSION_VOLTAGE >= 48
|
||||
#define VBUS_S_DIVIDER_RATIO 19.0f
|
||||
#elif HW_VERSION_VOLTAGE == 24
|
||||
#define VBUS_S_DIVIDER_RATIO 11.0f
|
||||
#else
|
||||
#error "unknown board voltage"
|
||||
#endif
|
||||
|
||||
// Linear range of the DRV8301 opamp output: 0.3V...5.7V. We set the upper limit
|
||||
// to 3.0V so that it's symmetric around the center point of 1.65V.
|
||||
#define CURRENT_SENSE_MIN_VOLT 0.3f
|
||||
#define CURRENT_SENSE_MAX_VOLT 3.0f
|
||||
|
||||
// This board has no board-specific user configurations
|
||||
static inline bool board_read_config() { return true; }
|
||||
static inline bool board_write_config() { return true; }
|
||||
static inline void board_clear_config() { }
|
||||
static inline bool board_apply_config() { return true; }
|
||||
|
||||
void system_init();
|
||||
bool board_init();
|
||||
void start_timers();
|
||||
|
||||
#endif // __BOARD_CONFIG_H
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : CAN.h
|
||||
* Description : This file provides code for the configuration
|
||||
* of the CAN instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __can_H
|
||||
#define __can_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern CAN_HandleTypeDef hcan1;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
extern void _Error_Handler(char *, int);
|
||||
|
||||
void MX_CAN1_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ can_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : dma.h
|
||||
* Description : This file contains all the function prototypes for
|
||||
* the dma.c file
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __dma_H
|
||||
#define __dma_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* DMA memory to memory transfer handles -------------------------------------*/
|
||||
extern void _Error_Handler(char*, int);
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_DMA_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __dma_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : gpio.h
|
||||
* Description : This file contains all the functions prototypes for
|
||||
* the gpio
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __gpio_H
|
||||
#define __gpio_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_GPIO_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ pinoutConfig_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : I2C.h
|
||||
* Description : This file provides code for the configuration
|
||||
* of the I2C instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __i2c_H
|
||||
#define __i2c_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern I2C_HandleTypeDef hi2c1;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
extern void _Error_Handler(char *, int);
|
||||
|
||||
void MX_I2C1_Init(uint8_t addr);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ i2c_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.h
|
||||
* @brief : Header for main.c file.
|
||||
* This file contains the common defines of the application.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __MAIN_H__
|
||||
#define __MAIN_H__
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \
|
||||
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2
|
||||
#include "prev_board_ver/main_V3_2.h"
|
||||
#elif HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 3 \
|
||||
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 4
|
||||
#include "prev_board_ver/main_V3_4.h"
|
||||
#else
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
#define TIM_1_8_CLOCK_HZ 168000000
|
||||
#define TIM_1_8_PERIOD_CLOCKS 3500
|
||||
#define TIM_1_8_DEADTIME_CLOCKS 20
|
||||
#define TIM_APB1_CLOCK_HZ 84000000
|
||||
#define TIM_APB1_PERIOD_CLOCKS 4096
|
||||
#define TIM_APB1_DEADTIME_CLOCKS 40
|
||||
#define TIM_1_8_RCR 2
|
||||
|
||||
#define M0_nCS_Pin GPIO_PIN_13
|
||||
#define M0_nCS_GPIO_Port GPIOC
|
||||
#define M1_nCS_Pin GPIO_PIN_14
|
||||
#define M1_nCS_GPIO_Port GPIOC
|
||||
#define M1_ENC_Z_Pin GPIO_PIN_15
|
||||
#define M1_ENC_Z_GPIO_Port GPIOC
|
||||
#define M0_IB_Pin GPIO_PIN_0
|
||||
#define M0_IB_GPIO_Port GPIOC
|
||||
#define M0_IC_Pin GPIO_PIN_1
|
||||
#define M0_IC_GPIO_Port GPIOC
|
||||
#define M1_IC_Pin GPIO_PIN_2
|
||||
#define M1_IC_GPIO_Port GPIOC
|
||||
#define M1_IB_Pin GPIO_PIN_3
|
||||
#define M1_IB_GPIO_Port GPIOC
|
||||
#define GPIO_1_Pin GPIO_PIN_0
|
||||
#define GPIO_1_GPIO_Port GPIOA
|
||||
#define GPIO_2_Pin GPIO_PIN_1
|
||||
#define GPIO_2_GPIO_Port GPIOA
|
||||
#define GPIO_3_Pin GPIO_PIN_2
|
||||
#define GPIO_3_GPIO_Port GPIOA
|
||||
#define GPIO_4_Pin GPIO_PIN_3
|
||||
#define GPIO_4_GPIO_Port GPIOA
|
||||
#define M1_TEMP_Pin GPIO_PIN_4
|
||||
#define M1_TEMP_GPIO_Port GPIOA
|
||||
#define AUX_TEMP_Pin GPIO_PIN_5
|
||||
#define AUX_TEMP_GPIO_Port GPIOA
|
||||
#define VBUS_S_Pin GPIO_PIN_6
|
||||
#define VBUS_S_GPIO_Port GPIOA
|
||||
#define M1_AL_Pin GPIO_PIN_7
|
||||
#define M1_AL_GPIO_Port GPIOA
|
||||
#define GPIO_5_Pin GPIO_PIN_4
|
||||
#define GPIO_5_GPIO_Port GPIOC
|
||||
#define M0_TEMP_Pin GPIO_PIN_5
|
||||
#define M0_TEMP_GPIO_Port GPIOC
|
||||
#define M1_BL_Pin GPIO_PIN_0
|
||||
#define M1_BL_GPIO_Port GPIOB
|
||||
#define M1_CL_Pin GPIO_PIN_1
|
||||
#define M1_CL_GPIO_Port GPIOB
|
||||
#define GPIO_6_Pin GPIO_PIN_2
|
||||
#define GPIO_6_GPIO_Port GPIOB
|
||||
#define AUX_L_Pin GPIO_PIN_10
|
||||
#define AUX_L_GPIO_Port GPIOB
|
||||
#define AUX_H_Pin GPIO_PIN_11
|
||||
#define AUX_H_GPIO_Port GPIOB
|
||||
#define EN_GATE_Pin GPIO_PIN_12
|
||||
#define EN_GATE_GPIO_Port GPIOB
|
||||
#define M0_AL_Pin GPIO_PIN_13
|
||||
#define M0_AL_GPIO_Port GPIOB
|
||||
#define M0_BL_Pin GPIO_PIN_14
|
||||
#define M0_BL_GPIO_Port GPIOB
|
||||
#define M0_CL_Pin GPIO_PIN_15
|
||||
#define M0_CL_GPIO_Port GPIOB
|
||||
#define M1_AH_Pin GPIO_PIN_6
|
||||
#define M1_AH_GPIO_Port GPIOC
|
||||
#define M1_BH_Pin GPIO_PIN_7
|
||||
#define M1_BH_GPIO_Port GPIOC
|
||||
#define M1_CH_Pin GPIO_PIN_8
|
||||
#define M1_CH_GPIO_Port GPIOC
|
||||
#define M0_ENC_Z_Pin GPIO_PIN_9
|
||||
#define M0_ENC_Z_GPIO_Port GPIOC
|
||||
#define M0_AH_Pin GPIO_PIN_8
|
||||
#define M0_AH_GPIO_Port GPIOA
|
||||
#define M0_BH_Pin GPIO_PIN_9
|
||||
#define M0_BH_GPIO_Port GPIOA
|
||||
#define M0_CH_Pin GPIO_PIN_10
|
||||
#define M0_CH_GPIO_Port GPIOA
|
||||
#define GPIO_7_Pin GPIO_PIN_15
|
||||
#define GPIO_7_GPIO_Port GPIOA
|
||||
#define nFAULT_Pin GPIO_PIN_2
|
||||
#define nFAULT_GPIO_Port GPIOD
|
||||
#define GPIO_8_Pin GPIO_PIN_3
|
||||
#define GPIO_8_GPIO_Port GPIOB
|
||||
#define M0_ENC_A_Pin GPIO_PIN_4
|
||||
#define M0_ENC_A_GPIO_Port GPIOB
|
||||
#define M0_ENC_B_Pin GPIO_PIN_5
|
||||
#define M0_ENC_B_GPIO_Port GPIOB
|
||||
#define M1_ENC_A_Pin GPIO_PIN_6
|
||||
#define M1_ENC_A_GPIO_Port GPIOB
|
||||
#define M1_ENC_B_Pin GPIO_PIN_7
|
||||
#define M1_ENC_B_GPIO_Port GPIOB
|
||||
|
||||
/* ########################## Assert Selection ############################## */
|
||||
/**
|
||||
* @brief Uncomment the line below to expanse the "assert_param" macro in the
|
||||
* HAL drivers code
|
||||
*/
|
||||
/* #define USE_FULL_ASSERT 1U */
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
#endif
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _Error_Handler(char *, int);
|
||||
|
||||
#define Error_Handler() _Error_Handler(__FILE__, __LINE__)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAIN_H__ */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : mxconstants.h
|
||||
* Description : This file contains the common defines of the application
|
||||
******************************************************************************
|
||||
*
|
||||
* COPYRIGHT(c) 2016 STMicroelectronics
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
|
||||
#define M0_nCS_Pin GPIO_PIN_13
|
||||
#define M0_nCS_GPIO_Port GPIOC
|
||||
#define M1_nCS_Pin GPIO_PIN_14
|
||||
#define M1_nCS_GPIO_Port GPIOC
|
||||
#define M1_DC_CAL_Pin GPIO_PIN_15
|
||||
#define M1_DC_CAL_GPIO_Port GPIOC
|
||||
#define M0_IB_Pin GPIO_PIN_0
|
||||
#define M0_IB_GPIO_Port GPIOC
|
||||
#define M0_IC_Pin GPIO_PIN_1
|
||||
#define M0_IC_GPIO_Port GPIOC
|
||||
#define M1_IC_Pin GPIO_PIN_2
|
||||
#define M1_IC_GPIO_Port GPIOC
|
||||
#define M1_IB_Pin GPIO_PIN_3
|
||||
#define M1_IB_GPIO_Port GPIOC
|
||||
#define VBUS_S_Pin GPIO_PIN_0
|
||||
#define VBUS_S_GPIO_Port GPIOA
|
||||
#define M1_TEMP_Pin GPIO_PIN_1
|
||||
#define M1_TEMP_GPIO_Port GPIOA
|
||||
#define AUX_I_Pin GPIO_PIN_2
|
||||
#define AUX_I_GPIO_Port GPIOA
|
||||
#define GPIO_4_Pin GPIO_PIN_3
|
||||
#define GPIO_4_GPIO_Port GPIOA
|
||||
#define GPIO_3_Pin GPIO_PIN_4
|
||||
#define GPIO_3_GPIO_Port GPIOA
|
||||
#define GPIO_2_Pin GPIO_PIN_5
|
||||
#define GPIO_2_GPIO_Port GPIOA
|
||||
#define AUX_V_Pin GPIO_PIN_6
|
||||
#define AUX_V_GPIO_Port GPIOA
|
||||
#define M1_AL_Pin GPIO_PIN_7
|
||||
#define M1_AL_GPIO_Port GPIOA
|
||||
#define AUX_TEMP_Pin GPIO_PIN_4
|
||||
#define AUX_TEMP_GPIO_Port GPIOC
|
||||
#define M0_TEMP_Pin GPIO_PIN_5
|
||||
#define M0_TEMP_GPIO_Port GPIOC
|
||||
#define M1_BL_Pin GPIO_PIN_0
|
||||
#define M1_BL_GPIO_Port GPIOB
|
||||
#define M1_CL_Pin GPIO_PIN_1
|
||||
#define M1_CL_GPIO_Port GPIOB
|
||||
#define GPIO_1_Pin GPIO_PIN_2
|
||||
#define GPIO_1_GPIO_Port GPIOB
|
||||
#define AUX_L_Pin GPIO_PIN_10
|
||||
#define AUX_L_GPIO_Port GPIOB
|
||||
#define AUX_H_Pin GPIO_PIN_11
|
||||
#define AUX_H_GPIO_Port GPIOB
|
||||
#define EN_GATE_Pin GPIO_PIN_12
|
||||
#define EN_GATE_GPIO_Port GPIOB
|
||||
#define M0_AL_Pin GPIO_PIN_13
|
||||
#define M0_AL_GPIO_Port GPIOB
|
||||
#define M0_BL_Pin GPIO_PIN_14
|
||||
#define M0_BL_GPIO_Port GPIOB
|
||||
#define M0_CL_Pin GPIO_PIN_15
|
||||
#define M0_CL_GPIO_Port GPIOB
|
||||
#define M1_AH_Pin GPIO_PIN_6
|
||||
#define M1_AH_GPIO_Port GPIOC
|
||||
#define M1_BH_Pin GPIO_PIN_7
|
||||
#define M1_BH_GPIO_Port GPIOC
|
||||
#define M1_CH_Pin GPIO_PIN_8
|
||||
#define M1_CH_GPIO_Port GPIOC
|
||||
#define M0_DC_CAL_Pin GPIO_PIN_9
|
||||
#define M0_DC_CAL_GPIO_Port GPIOC
|
||||
#define M0_AH_Pin GPIO_PIN_8
|
||||
#define M0_AH_GPIO_Port GPIOA
|
||||
#define M0_BH_Pin GPIO_PIN_9
|
||||
#define M0_BH_GPIO_Port GPIOA
|
||||
#define M0_CH_Pin GPIO_PIN_10
|
||||
#define M0_CH_GPIO_Port GPIOA
|
||||
#define M0_ENC_Z_Pin GPIO_PIN_15
|
||||
#define M0_ENC_Z_GPIO_Port GPIOA
|
||||
#define nFAULT_Pin GPIO_PIN_2
|
||||
#define nFAULT_GPIO_Port GPIOD
|
||||
#define M1_ENC_Z_Pin GPIO_PIN_3
|
||||
#define M1_ENC_Z_GPIO_Port GPIOB
|
||||
#define M0_ENC_A_Pin GPIO_PIN_4
|
||||
#define M0_ENC_A_GPIO_Port GPIOB
|
||||
#define M0_ENC_B_Pin GPIO_PIN_5
|
||||
#define M0_ENC_B_GPIO_Port GPIOB
|
||||
#define M1_ENC_A_Pin GPIO_PIN_6
|
||||
#define M1_ENC_A_GPIO_Port GPIOB
|
||||
#define M1_ENC_B_Pin GPIO_PIN_7
|
||||
#define M1_ENC_B_GPIO_Port GPIOB
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
#define TIM_1_8_CLOCK_HZ 168000000
|
||||
#define TIM_1_8_PERIOD_CLOCKS 3500
|
||||
#define TIM_1_8_DEADTIME_CLOCKS 20
|
||||
#define TIM_APB1_CLOCK_HZ 84000000
|
||||
#define TIM_APB1_PERIOD_CLOCKS 4096
|
||||
#define TIM_APB1_DEADTIME_CLOCKS 40
|
||||
#define TIM_1_8_RCR 2
|
||||
|
||||
#define M0_nCS_Pin GPIO_PIN_13
|
||||
#define M0_nCS_GPIO_Port GPIOC
|
||||
#define M1_nCS_Pin GPIO_PIN_14
|
||||
#define M1_nCS_GPIO_Port GPIOC
|
||||
#define M1_DC_CAL_Pin GPIO_PIN_15
|
||||
#define M1_DC_CAL_GPIO_Port GPIOC
|
||||
#define M0_IB_Pin GPIO_PIN_0
|
||||
#define M0_IB_GPIO_Port GPIOC
|
||||
#define M0_IC_Pin GPIO_PIN_1
|
||||
#define M0_IC_GPIO_Port GPIOC
|
||||
#define M1_IC_Pin GPIO_PIN_2
|
||||
#define M1_IC_GPIO_Port GPIOC
|
||||
#define M1_IB_Pin GPIO_PIN_3
|
||||
#define M1_IB_GPIO_Port GPIOC
|
||||
#define VBUS_S_Pin GPIO_PIN_0
|
||||
#define VBUS_S_GPIO_Port GPIOA
|
||||
#define M1_TEMP_Pin GPIO_PIN_1
|
||||
#define M1_TEMP_GPIO_Port GPIOA
|
||||
#define AUX_I_Pin GPIO_PIN_2
|
||||
#define AUX_I_GPIO_Port GPIOA
|
||||
#define GPIO_4_Pin GPIO_PIN_3
|
||||
#define GPIO_4_GPIO_Port GPIOA
|
||||
#define GPIO_3_Pin GPIO_PIN_4
|
||||
#define GPIO_3_GPIO_Port GPIOA
|
||||
#define GPIO_3_EXTI_IRQn EXTI4_IRQn
|
||||
#define GPIO_2_Pin GPIO_PIN_5
|
||||
#define GPIO_2_GPIO_Port GPIOA
|
||||
#define AUX_V_Pin GPIO_PIN_6
|
||||
#define AUX_V_GPIO_Port GPIOA
|
||||
#define M1_AL_Pin GPIO_PIN_7
|
||||
#define M1_AL_GPIO_Port GPIOA
|
||||
#define AUX_TEMP_Pin GPIO_PIN_4
|
||||
#define AUX_TEMP_GPIO_Port GPIOC
|
||||
#define M0_TEMP_Pin GPIO_PIN_5
|
||||
#define M0_TEMP_GPIO_Port GPIOC
|
||||
#define M1_BL_Pin GPIO_PIN_0
|
||||
#define M1_BL_GPIO_Port GPIOB
|
||||
#define M1_CL_Pin GPIO_PIN_1
|
||||
#define M1_CL_GPIO_Port GPIOB
|
||||
#define GPIO_1_Pin GPIO_PIN_2
|
||||
#define GPIO_1_GPIO_Port GPIOB
|
||||
#define GPIO_1_EXTI_IRQn EXTI2_IRQn
|
||||
#define AUX_L_Pin GPIO_PIN_10
|
||||
#define AUX_L_GPIO_Port GPIOB
|
||||
#define AUX_H_Pin GPIO_PIN_11
|
||||
#define AUX_H_GPIO_Port GPIOB
|
||||
#define EN_GATE_Pin GPIO_PIN_12
|
||||
#define EN_GATE_GPIO_Port GPIOB
|
||||
#define M0_AL_Pin GPIO_PIN_13
|
||||
#define M0_AL_GPIO_Port GPIOB
|
||||
#define M0_BL_Pin GPIO_PIN_14
|
||||
#define M0_BL_GPIO_Port GPIOB
|
||||
#define M0_CL_Pin GPIO_PIN_15
|
||||
#define M0_CL_GPIO_Port GPIOB
|
||||
#define M1_AH_Pin GPIO_PIN_6
|
||||
#define M1_AH_GPIO_Port GPIOC
|
||||
#define M1_BH_Pin GPIO_PIN_7
|
||||
#define M1_BH_GPIO_Port GPIOC
|
||||
#define M1_CH_Pin GPIO_PIN_8
|
||||
#define M1_CH_GPIO_Port GPIOC
|
||||
#define M0_DC_CAL_Pin GPIO_PIN_9
|
||||
#define M0_DC_CAL_GPIO_Port GPIOC
|
||||
#define M0_AH_Pin GPIO_PIN_8
|
||||
#define M0_AH_GPIO_Port GPIOA
|
||||
#define M0_BH_Pin GPIO_PIN_9
|
||||
#define M0_BH_GPIO_Port GPIOA
|
||||
#define M0_CH_Pin GPIO_PIN_10
|
||||
#define M0_CH_GPIO_Port GPIOA
|
||||
#define M0_ENC_Z_Pin GPIO_PIN_15
|
||||
#define M0_ENC_Z_GPIO_Port GPIOA
|
||||
#define nFAULT_Pin GPIO_PIN_2
|
||||
#define nFAULT_GPIO_Port GPIOD
|
||||
#define M1_ENC_Z_Pin GPIO_PIN_3
|
||||
#define M1_ENC_Z_GPIO_Port GPIOB
|
||||
#define M0_ENC_A_Pin GPIO_PIN_4
|
||||
#define M0_ENC_A_GPIO_Port GPIOB
|
||||
#define M0_ENC_B_Pin GPIO_PIN_5
|
||||
#define M0_ENC_B_GPIO_Port GPIOB
|
||||
#define M1_ENC_A_Pin GPIO_PIN_6
|
||||
#define M1_ENC_A_GPIO_Port GPIOB
|
||||
#define M1_ENC_B_Pin GPIO_PIN_7
|
||||
#define M1_ENC_B_GPIO_Port GPIOB
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
#define TIM_1_8_CLOCK_HZ 168000000
|
||||
#define TIM_1_8_PERIOD_CLOCKS 3500
|
||||
#define TIM_1_8_DEADTIME_CLOCKS 20
|
||||
#define TIM_APB1_CLOCK_HZ 84000000
|
||||
#define TIM_APB1_PERIOD_CLOCKS 4096
|
||||
#define TIM_APB1_DEADTIME_CLOCKS 40
|
||||
#define TIM_1_8_RCR 2
|
||||
|
||||
#define M0_nCS_Pin GPIO_PIN_13
|
||||
#define M0_nCS_GPIO_Port GPIOC
|
||||
#define M1_nCS_Pin GPIO_PIN_14
|
||||
#define M1_nCS_GPIO_Port GPIOC
|
||||
#define M1_DC_CAL_Pin GPIO_PIN_15
|
||||
#define M1_DC_CAL_GPIO_Port GPIOC
|
||||
#define M0_IB_Pin GPIO_PIN_0
|
||||
#define M0_IB_GPIO_Port GPIOC
|
||||
#define M0_IC_Pin GPIO_PIN_1
|
||||
#define M0_IC_GPIO_Port GPIOC
|
||||
#define M1_IC_Pin GPIO_PIN_2
|
||||
#define M1_IC_GPIO_Port GPIOC
|
||||
#define M1_IB_Pin GPIO_PIN_3
|
||||
#define M1_IB_GPIO_Port GPIOC
|
||||
#define GPIO_1_Pin GPIO_PIN_0
|
||||
#define GPIO_1_GPIO_Port GPIOA
|
||||
#define GPIO_2_Pin GPIO_PIN_1
|
||||
#define GPIO_2_GPIO_Port GPIOA
|
||||
#define GPIO_3_Pin GPIO_PIN_2
|
||||
#define GPIO_3_GPIO_Port GPIOA
|
||||
#define GPIO_3_EXTI_IRQn EXTI2_IRQn
|
||||
#define GPIO_4_Pin GPIO_PIN_3
|
||||
#define GPIO_4_GPIO_Port GPIOA
|
||||
#define M1_TEMP_Pin GPIO_PIN_4
|
||||
#define M1_TEMP_GPIO_Port GPIOA
|
||||
#define AUX_I_Pin GPIO_PIN_5
|
||||
#define AUX_I_GPIO_Port GPIOA
|
||||
#define VBUS_S_Pin GPIO_PIN_6
|
||||
#define VBUS_S_GPIO_Port GPIOA
|
||||
#define M1_AL_Pin GPIO_PIN_7
|
||||
#define M1_AL_GPIO_Port GPIOA
|
||||
#define AUX_TEMP_Pin GPIO_PIN_4
|
||||
#define AUX_TEMP_GPIO_Port GPIOC
|
||||
#define M0_TEMP_Pin GPIO_PIN_5
|
||||
#define M0_TEMP_GPIO_Port GPIOC
|
||||
#define M1_BL_Pin GPIO_PIN_0
|
||||
#define M1_BL_GPIO_Port GPIOB
|
||||
#define M1_CL_Pin GPIO_PIN_1
|
||||
#define M1_CL_GPIO_Port GPIOB
|
||||
#define GPIO_5_Pin GPIO_PIN_2
|
||||
#define GPIO_5_GPIO_Port GPIOB
|
||||
#define AUX_L_Pin GPIO_PIN_10
|
||||
#define AUX_L_GPIO_Port GPIOB
|
||||
#define AUX_H_Pin GPIO_PIN_11
|
||||
#define AUX_H_GPIO_Port GPIOB
|
||||
#define EN_GATE_Pin GPIO_PIN_12
|
||||
#define EN_GATE_GPIO_Port GPIOB
|
||||
#define M0_AL_Pin GPIO_PIN_13
|
||||
#define M0_AL_GPIO_Port GPIOB
|
||||
#define M0_BL_Pin GPIO_PIN_14
|
||||
#define M0_BL_GPIO_Port GPIOB
|
||||
#define M0_CL_Pin GPIO_PIN_15
|
||||
#define M0_CL_GPIO_Port GPIOB
|
||||
#define M1_AH_Pin GPIO_PIN_6
|
||||
#define M1_AH_GPIO_Port GPIOC
|
||||
#define M1_BH_Pin GPIO_PIN_7
|
||||
#define M1_BH_GPIO_Port GPIOC
|
||||
#define M1_CH_Pin GPIO_PIN_8
|
||||
#define M1_CH_GPIO_Port GPIOC
|
||||
#define M0_DC_CAL_Pin GPIO_PIN_9
|
||||
#define M0_DC_CAL_GPIO_Port GPIOC
|
||||
#define M0_AH_Pin GPIO_PIN_8
|
||||
#define M0_AH_GPIO_Port GPIOA
|
||||
#define M0_BH_Pin GPIO_PIN_9
|
||||
#define M0_BH_GPIO_Port GPIOA
|
||||
#define M0_CH_Pin GPIO_PIN_10
|
||||
#define M0_CH_GPIO_Port GPIOA
|
||||
#define M0_ENC_Z_Pin GPIO_PIN_15
|
||||
#define M0_ENC_Z_GPIO_Port GPIOA
|
||||
#define nFAULT_Pin GPIO_PIN_2
|
||||
#define nFAULT_GPIO_Port GPIOD
|
||||
#define M1_ENC_Z_Pin GPIO_PIN_3
|
||||
#define M1_ENC_Z_GPIO_Port GPIOB
|
||||
#define M0_ENC_A_Pin GPIO_PIN_4
|
||||
#define M0_ENC_A_GPIO_Port GPIOB
|
||||
#define M0_ENC_B_Pin GPIO_PIN_5
|
||||
#define M0_ENC_B_GPIO_Port GPIOB
|
||||
#define M1_ENC_A_Pin GPIO_PIN_6
|
||||
#define M1_ENC_A_GPIO_Port GPIOB
|
||||
#define M1_ENC_B_Pin GPIO_PIN_7
|
||||
#define M1_ENC_B_GPIO_Port GPIOB
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : SPI.h
|
||||
* Description : This file provides code for the configuration
|
||||
* of the SPI instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __spi_H
|
||||
#define __spi_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern SPI_HandleTypeDef hspi3;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
extern void _Error_Handler(char *, int);
|
||||
|
||||
void MX_SPI3_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ spi_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_hal_conf.h
|
||||
* @brief HAL configuration file.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2018 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F4xx_HAL_CONF_H
|
||||
#define __STM32F4xx_HAL_CONF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
/* ########################## Module Selection ############################## */
|
||||
/**
|
||||
* @brief This is the list of modules to be used in the HAL driver
|
||||
*/
|
||||
#define HAL_MODULE_ENABLED
|
||||
|
||||
#define HAL_ADC_MODULE_ENABLED
|
||||
/* #define HAL_CRYP_MODULE_ENABLED */
|
||||
#define HAL_CAN_MODULE_ENABLED
|
||||
/* #define HAL_CRC_MODULE_ENABLED */
|
||||
/* #define HAL_CRYP_MODULE_ENABLED */
|
||||
/* #define HAL_DAC_MODULE_ENABLED */
|
||||
/* #define HAL_DCMI_MODULE_ENABLED */
|
||||
/* #define HAL_DMA2D_MODULE_ENABLED */
|
||||
/* #define HAL_ETH_MODULE_ENABLED */
|
||||
/* #define HAL_NAND_MODULE_ENABLED */
|
||||
/* #define HAL_NOR_MODULE_ENABLED */
|
||||
/* #define HAL_PCCARD_MODULE_ENABLED */
|
||||
/* #define HAL_SRAM_MODULE_ENABLED */
|
||||
/* #define HAL_SDRAM_MODULE_ENABLED */
|
||||
/* #define HAL_HASH_MODULE_ENABLED */
|
||||
#define HAL_I2C_MODULE_ENABLED
|
||||
/* #define HAL_I2S_MODULE_ENABLED */
|
||||
/* #define HAL_IWDG_MODULE_ENABLED */
|
||||
/* #define HAL_LTDC_MODULE_ENABLED */
|
||||
/* #define HAL_RNG_MODULE_ENABLED */
|
||||
/* #define HAL_RTC_MODULE_ENABLED */
|
||||
/* #define HAL_SAI_MODULE_ENABLED */
|
||||
/* #define HAL_SD_MODULE_ENABLED */
|
||||
/* #define HAL_MMC_MODULE_ENABLED */
|
||||
#define HAL_SPI_MODULE_ENABLED
|
||||
#define HAL_TIM_MODULE_ENABLED
|
||||
#define HAL_UART_MODULE_ENABLED
|
||||
/* #define HAL_USART_MODULE_ENABLED */
|
||||
/* #define HAL_IRDA_MODULE_ENABLED */
|
||||
/* #define HAL_SMARTCARD_MODULE_ENABLED */
|
||||
/* #define HAL_WWDG_MODULE_ENABLED */
|
||||
#define HAL_PCD_MODULE_ENABLED
|
||||
/* #define HAL_HCD_MODULE_ENABLED */
|
||||
/* #define HAL_DSI_MODULE_ENABLED */
|
||||
/* #define HAL_QSPI_MODULE_ENABLED */
|
||||
/* #define HAL_QSPI_MODULE_ENABLED */
|
||||
/* #define HAL_CEC_MODULE_ENABLED */
|
||||
/* #define HAL_FMPI2C_MODULE_ENABLED */
|
||||
/* #define HAL_SPDIFRX_MODULE_ENABLED */
|
||||
/* #define HAL_DFSDM_MODULE_ENABLED */
|
||||
/* #define HAL_LPTIM_MODULE_ENABLED */
|
||||
/* #define HAL_EXTI_MODULE_ENABLED */
|
||||
#define HAL_GPIO_MODULE_ENABLED
|
||||
#define HAL_DMA_MODULE_ENABLED
|
||||
#define HAL_RCC_MODULE_ENABLED
|
||||
#define HAL_FLASH_MODULE_ENABLED
|
||||
#define HAL_PWR_MODULE_ENABLED
|
||||
#define HAL_CORTEX_MODULE_ENABLED
|
||||
|
||||
/* ########################## HSE/HSI Values adaptation ##################### */
|
||||
/**
|
||||
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSE is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSE_STARTUP_TIMEOUT)
|
||||
#define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */
|
||||
#endif /* HSE_STARTUP_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @brief Internal High Speed oscillator (HSI) value.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSI is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/**
|
||||
* @brief Internal Low Speed oscillator (LSI) value.
|
||||
*/
|
||||
#if !defined (LSI_VALUE)
|
||||
#define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/
|
||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
||||
The real value may vary depending on the variations
|
||||
in voltage and temperature.*/
|
||||
/**
|
||||
* @brief External Low Speed oscillator (LSE) value.
|
||||
*/
|
||||
#if !defined (LSE_VALUE)
|
||||
#define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz */
|
||||
#endif /* LSE_VALUE */
|
||||
|
||||
#if !defined (LSE_STARTUP_TIMEOUT)
|
||||
#define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */
|
||||
#endif /* LSE_STARTUP_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @brief External clock source for I2S peripheral
|
||||
* This value is used by the I2S HAL module to compute the I2S clock source
|
||||
* frequency, this source is inserted directly through I2S_CKIN pad.
|
||||
*/
|
||||
#if !defined (EXTERNAL_CLOCK_VALUE)
|
||||
#define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/
|
||||
#endif /* EXTERNAL_CLOCK_VALUE */
|
||||
|
||||
/* Tip: To avoid modifying this file each time you need to use different HSE,
|
||||
=== you can define the HSE value in your toolchain compiler preprocessor. */
|
||||
|
||||
/* ########################### System Configuration ######################### */
|
||||
/**
|
||||
* @brief This is the HAL system configuration section
|
||||
*/
|
||||
#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */
|
||||
#define TICK_INT_PRIORITY ((uint32_t)6U) /*!< tick interrupt priority */
|
||||
#define USE_RTOS 0U
|
||||
#define PREFETCH_ENABLE 1U
|
||||
#define INSTRUCTION_CACHE_ENABLE 1U
|
||||
#define DATA_CACHE_ENABLE 1U
|
||||
|
||||
/* ########################## Assert Selection ############################## */
|
||||
/**
|
||||
* @brief Uncomment the line below to expanse the "assert_param" macro in the
|
||||
* HAL drivers code
|
||||
*/
|
||||
/* #define USE_FULL_ASSERT 1U */
|
||||
|
||||
/* ################## Ethernet peripheral configuration ##################### */
|
||||
|
||||
/* Section 1 : Ethernet peripheral configuration */
|
||||
|
||||
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
|
||||
#define MAC_ADDR0 2U
|
||||
#define MAC_ADDR1 0U
|
||||
#define MAC_ADDR2 0U
|
||||
#define MAC_ADDR3 0U
|
||||
#define MAC_ADDR4 0U
|
||||
#define MAC_ADDR5 0U
|
||||
|
||||
/* Definition of the Ethernet driver buffers size and count */
|
||||
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
|
||||
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
|
||||
#define ETH_RXBUFNB ((uint32_t)4U) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
|
||||
#define ETH_TXBUFNB ((uint32_t)4U) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
|
||||
|
||||
/* Section 2: PHY configuration section */
|
||||
|
||||
/* DP83848_PHY_ADDRESS Address*/
|
||||
#define DP83848_PHY_ADDRESS 0x01U
|
||||
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
|
||||
#define PHY_RESET_DELAY ((uint32_t)0x000000FFU)
|
||||
/* PHY Configuration delay */
|
||||
#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFU)
|
||||
|
||||
#define PHY_READ_TO ((uint32_t)0x0000FFFFU)
|
||||
#define PHY_WRITE_TO ((uint32_t)0x0000FFFFU)
|
||||
|
||||
/* Section 3: Common PHY Registers */
|
||||
|
||||
#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */
|
||||
#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */
|
||||
|
||||
#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */
|
||||
#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */
|
||||
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */
|
||||
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */
|
||||
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */
|
||||
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */
|
||||
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */
|
||||
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */
|
||||
#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */
|
||||
#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */
|
||||
|
||||
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */
|
||||
#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */
|
||||
#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */
|
||||
|
||||
/* Section 4: Extended PHY Registers */
|
||||
#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */
|
||||
|
||||
#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */
|
||||
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */
|
||||
|
||||
/* ################## SPI peripheral configuration ########################## */
|
||||
|
||||
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
|
||||
* Activated: CRC code is present inside driver
|
||||
* Deactivated: CRC code cleaned from driver
|
||||
*/
|
||||
|
||||
#define USE_SPI_CRC 0U
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Include module's header file
|
||||
*/
|
||||
|
||||
#ifdef HAL_RCC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rcc.h"
|
||||
#endif /* HAL_RCC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_EXTI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_exti.h"
|
||||
#endif /* HAL_EXTI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_GPIO_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_gpio.h"
|
||||
#endif /* HAL_GPIO_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DMA_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dma.h"
|
||||
#endif /* HAL_DMA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CORTEX_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cortex.h"
|
||||
#endif /* HAL_CORTEX_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ADC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_adc.h"
|
||||
#endif /* HAL_ADC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CAN_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_can.h"
|
||||
#endif /* HAL_CAN_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CRC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_crc.h"
|
||||
#endif /* HAL_CRC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CRYP_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cryp.h"
|
||||
#endif /* HAL_CRYP_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DMA2D_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dma2d.h"
|
||||
#endif /* HAL_DMA2D_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DAC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dac.h"
|
||||
#endif /* HAL_DAC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DCMI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dcmi.h"
|
||||
#endif /* HAL_DCMI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ETH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_eth.h"
|
||||
#endif /* HAL_ETH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FLASH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_flash.h"
|
||||
#endif /* HAL_FLASH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SRAM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sram.h"
|
||||
#endif /* HAL_SRAM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NOR_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_nor.h"
|
||||
#endif /* HAL_NOR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NAND_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_nand.h"
|
||||
#endif /* HAL_NAND_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCCARD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pccard.h"
|
||||
#endif /* HAL_PCCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SDRAM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sdram.h"
|
||||
#endif /* HAL_SDRAM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_HASH_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_hash.h"
|
||||
#endif /* HAL_HASH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2C_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_i2c.h"
|
||||
#endif /* HAL_I2C_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2S_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_i2s.h"
|
||||
#endif /* HAL_I2S_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IWDG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_iwdg.h"
|
||||
#endif /* HAL_IWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_LTDC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_ltdc.h"
|
||||
#endif /* HAL_LTDC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PWR_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pwr.h"
|
||||
#endif /* HAL_PWR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_RNG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rng.h"
|
||||
#endif /* HAL_RNG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_RTC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_rtc.h"
|
||||
#endif /* HAL_RTC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SAI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sai.h"
|
||||
#endif /* HAL_SAI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_sd.h"
|
||||
#endif /* HAL_SD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_MMC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_mmc.h"
|
||||
#endif /* HAL_MMC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SPI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_spi.h"
|
||||
#endif /* HAL_SPI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_TIM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_tim.h"
|
||||
#endif /* HAL_TIM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_UART_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_uart.h"
|
||||
#endif /* HAL_UART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_USART_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_usart.h"
|
||||
#endif /* HAL_USART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IRDA_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_irda.h"
|
||||
#endif /* HAL_IRDA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SMARTCARD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_smartcard.h"
|
||||
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_WWDG_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_wwdg.h"
|
||||
#endif /* HAL_WWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_pcd.h"
|
||||
#endif /* HAL_PCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_HCD_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_hcd.h"
|
||||
#endif /* HAL_HCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DSI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dsi.h"
|
||||
#endif /* HAL_DSI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_QSPI_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_qspi.h"
|
||||
#endif /* HAL_QSPI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CEC_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_cec.h"
|
||||
#endif /* HAL_CEC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FMPI2C_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_fmpi2c.h"
|
||||
#endif /* HAL_FMPI2C_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SPDIFRX_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_spdifrx.h"
|
||||
#endif /* HAL_SPDIFRX_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DFSDM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_dfsdm.h"
|
||||
#endif /* HAL_DFSDM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_LPTIM_MODULE_ENABLED
|
||||
#include "stm32f4xx_hal_lptim.h"
|
||||
#endif /* HAL_LPTIM_MODULE_ENABLED */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief The assert_param macro is used for function's parameters check.
|
||||
* @param expr: If expr is false, it calls assert_failed function
|
||||
* which reports the name of the source file and the source
|
||||
* line number of the call that failed.
|
||||
* If expr is true, it returns no value.
|
||||
* @retval None
|
||||
*/
|
||||
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void assert_failed(uint8_t* file, uint32_t line);
|
||||
#else
|
||||
#define assert_param(expr) ((void)0U)
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F4xx_HAL_CONF_H */
|
||||
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_it.h
|
||||
* @brief This file contains the headers of the interrupt handlers.
|
||||
******************************************************************************
|
||||
*
|
||||
* COPYRIGHT(c) 2018 STMicroelectronics
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F4xx_IT_H
|
||||
#define __STM32F4xx_IT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
|
||||
void NMI_Handler(void);
|
||||
void HardFault_Handler(void);
|
||||
void MemManage_Handler(void);
|
||||
void BusFault_Handler(void);
|
||||
void UsageFault_Handler(void);
|
||||
void DebugMon_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
void DMA1_Stream0_IRQHandler(void);
|
||||
void DMA1_Stream2_IRQHandler(void);
|
||||
void DMA1_Stream4_IRQHandler(void);
|
||||
void DMA1_Stream5_IRQHandler(void);
|
||||
void DMA1_Stream6_IRQHandler(void);
|
||||
void DMA1_Stream7_IRQHandler(void);
|
||||
//void ADC_IRQHandler(void);
|
||||
void CAN1_TX_IRQHandler(void);
|
||||
void CAN1_RX0_IRQHandler(void);
|
||||
void CAN1_RX1_IRQHandler(void);
|
||||
void CAN1_SCE_IRQHandler(void);
|
||||
void USART2_IRQHandler(void);
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void);
|
||||
void TIM5_IRQHandler(void);
|
||||
void SPI3_IRQHandler(void);
|
||||
void UART4_IRQHandler(void);
|
||||
void OTG_FS_IRQHandler(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F4xx_IT_H */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : TIM.h
|
||||
* Description : This file provides code for the configuration
|
||||
* of the TIM instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __tim_H
|
||||
#define __tim_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern TIM_HandleTypeDef htim1;
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern TIM_HandleTypeDef htim3;
|
||||
extern TIM_HandleTypeDef htim4;
|
||||
extern TIM_HandleTypeDef htim5;
|
||||
extern TIM_HandleTypeDef htim8;
|
||||
extern TIM_HandleTypeDef htim13;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
extern void _Error_Handler(char *, int);
|
||||
|
||||
void MX_TIM1_Init(void);
|
||||
void MX_TIM2_Init(void);
|
||||
void MX_TIM3_Init(void);
|
||||
void MX_TIM4_Init(void);
|
||||
void MX_TIM5_Init(void);
|
||||
void MX_TIM8_Init(void);
|
||||
void MX_TIM13_Init(void);
|
||||
|
||||
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ tim_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : USART.h
|
||||
* Description : This file provides code for the configuration
|
||||
* of the USART instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __usart_H
|
||||
#define __usart_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern UART_HandleTypeDef huart4;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
extern void _Error_Handler(char *, int);
|
||||
|
||||
void MX_UART4_Init(void);
|
||||
void MX_USART2_UART_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ usart_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usb_device.h
|
||||
* @version : v1.0_Cube
|
||||
* @brief : Header for usb_device.c file.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __USB_DEVICE__H__
|
||||
#define __USB_DEVICE__H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx.h"
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "usbd_def.h"
|
||||
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/** @addtogroup USBD_OTG_DRIVER
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DEVICE USBD_DEVICE
|
||||
* @brief Device file for Usb otg low level driver.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DEVICE_Exported_Variables USBD_DEVICE_Exported_Variables
|
||||
* @brief Public variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** USB device core handle. */
|
||||
extern USBD_HandleTypeDef hUsbDeviceFS;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DEVICE_Exported_FunctionsPrototype USBD_DEVICE_Exported_FunctionsPrototype
|
||||
* @brief Declaration of public functions for Usb device.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** USB Device initialization function. */
|
||||
void MX_USB_DEVICE_Init(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USB_DEVICE__H__ */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usbd_cdc_if.h
|
||||
* @version : v1.0_Cube
|
||||
* @brief : Header for usbd_cdc_if.c file.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __USBD_CDC_IF_H__
|
||||
#define __USBD_CDC_IF_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usbd_cdc.h"
|
||||
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
|
||||
* @brief For Usb device.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF USBD_CDC_IF
|
||||
* @brief Usb VCP device module
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Exported_Defines USBD_CDC_IF_Exported_Defines
|
||||
* @brief Defines.
|
||||
* @{
|
||||
*/
|
||||
/* USER CODE BEGIN EXPORTED_DEFINES */
|
||||
/* Define size for the receive and transmit buffer over CDC */
|
||||
/* It's up to user to redefine and/or remove those define */
|
||||
#define USB_RX_DATA_SIZE 64
|
||||
#define USB_TX_DATA_SIZE 64
|
||||
#define APP_RX_DATA_SIZE USB_RX_DATA_SIZE
|
||||
#define APP_TX_DATA_SIZE USB_TX_DATA_SIZE
|
||||
/* USER CODE END EXPORTED_DEFINES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Exported_Types USBD_CDC_IF_Exported_Types
|
||||
* @brief Types.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_TYPES */
|
||||
/* USER CODE END EXPORTED_TYPES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Exported_Macros USBD_CDC_IF_Exported_Macros
|
||||
* @brief Aliases.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_MACRO */
|
||||
/* USER CODE END EXPORTED_MACRO */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
|
||||
* @brief Public variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** CDC Interface callback. */
|
||||
extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_VARIABLES */
|
||||
/* USER CODE END EXPORTED_VARIABLES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Exported_FunctionsPrototype USBD_CDC_IF_Exported_FunctionsPrototype
|
||||
* @brief Public functions declaration.
|
||||
* @{
|
||||
*/
|
||||
|
||||
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len, uint8_t endpoint_pair);
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_FUNCTIONS */
|
||||
/* USER CODE END EXPORTED_FUNCTIONS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USBD_CDC_IF_H__ */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usbd_conf.h
|
||||
* @version : v1.0_Cube
|
||||
* @brief : Header for usbd_conf.c file.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __USBD_CONF__H__
|
||||
#define __USBD_CONF__H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "stm32f4xx.h"
|
||||
#include "stm32f4xx_hal.h"
|
||||
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/** @addtogroup USBD_OTG_DRIVER
|
||||
* @brief Driver for Usb device.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CONF USBD_CONF
|
||||
* @brief Configuration file for Usb otg low level driver.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CONF_Exported_Variables USBD_CONF_Exported_Variables
|
||||
* @brief Public variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines
|
||||
* @brief Defines for configuration of the Usb device.
|
||||
* @{
|
||||
*/
|
||||
#define MS_VendorCode 'P'
|
||||
|
||||
/*---------- -----------*/
|
||||
#define USBD_MAX_NUM_INTERFACES 1
|
||||
/*---------- -----------*/
|
||||
#define USBD_MAX_NUM_CONFIGURATION 1
|
||||
/*---------- -----------*/
|
||||
#define USBD_MAX_STR_DESC_SIZ 512
|
||||
/*---------- -----------*/
|
||||
#define USBD_SUPPORT_USER_STRING_DESC 1
|
||||
/*---------- -----------*/
|
||||
#define USBD_DEBUG_LEVEL 0
|
||||
/*---------- -----------*/
|
||||
#define USBD_LPM_ENABLED 0
|
||||
/*---------- -----------*/
|
||||
#define USBD_SELF_POWERED 1
|
||||
|
||||
/****************************************/
|
||||
/* #define for FS and HS identification */
|
||||
#define DEVICE_FS 0
|
||||
#define DEVICE_HS 1
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CONF_Exported_Macros USBD_CONF_Exported_Macros
|
||||
* @brief Aliases.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Memory management macros */
|
||||
|
||||
/** Alias for memory allocation. */
|
||||
#define USBD_malloc malloc
|
||||
|
||||
/** Alias for memory release. */
|
||||
#define USBD_free free
|
||||
|
||||
/** Alias for memory set. */
|
||||
#define USBD_memset memset
|
||||
|
||||
/** Alias for memory copy. */
|
||||
#define USBD_memcpy memcpy
|
||||
|
||||
/** Alias for delay. */
|
||||
#define USBD_Delay HAL_Delay
|
||||
|
||||
/* DEBUG macros */
|
||||
|
||||
#if (USBD_DEBUG_LEVEL > 0)
|
||||
#define USBD_UsrLog(...) printf(__VA_ARGS__);\
|
||||
printf("\n");
|
||||
#else
|
||||
#define USBD_UsrLog(...)
|
||||
#endif
|
||||
|
||||
#if (USBD_DEBUG_LEVEL > 1)
|
||||
|
||||
#define USBD_ErrLog(...) printf("ERROR: ") ;\
|
||||
printf(__VA_ARGS__);\
|
||||
printf("\n");
|
||||
#else
|
||||
#define USBD_ErrLog(...)
|
||||
#endif
|
||||
|
||||
#if (USBD_DEBUG_LEVEL > 2)
|
||||
#define USBD_DbgLog(...) printf("DEBUG : ") ;\
|
||||
printf(__VA_ARGS__);\
|
||||
printf("\n");
|
||||
#else
|
||||
#define USBD_DbgLog(...)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CONF_Exported_Types USBD_CONF_Exported_Types
|
||||
* @brief Types.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CONF_Exported_FunctionsPrototype USBD_CONF_Exported_FunctionsPrototype
|
||||
* @brief Declaration of public functions for Usb device.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Exported functions -------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USBD_CONF__H__ */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usbd_desc.h
|
||||
* @version : v1.0_Cube
|
||||
* @brief : Header for usbd_desc.c file.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __USBD_DESC__H__
|
||||
#define __USBD_DESC__H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usbd_def.h"
|
||||
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC USBD_DESC
|
||||
* @brief Usb device descriptors module.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Exported_Defines USBD_DESC_Exported_Defines
|
||||
* @brief Defines.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_DEFINES */
|
||||
|
||||
/* USER CODE END EXPORTED_DEFINES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Exported_TypesDefinitions USBD_DESC_Exported_TypesDefinitions
|
||||
* @brief Types.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_TYPES */
|
||||
|
||||
/* USER CODE END EXPORTED_TYPES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Exported_Macros USBD_DESC_Exported_Macros
|
||||
* @brief Aliases.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_MACRO */
|
||||
|
||||
/* USER CODE END EXPORTED_MACRO */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Exported_Variables USBD_DESC_Exported_Variables
|
||||
* @brief Public variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Descriptor for the Usb device. */
|
||||
extern USBD_DescriptorsTypeDef FS_Desc;
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_VARIABLES */
|
||||
|
||||
/* USER CODE END EXPORTED_VARIABLES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Exported_FunctionsPrototype USBD_DESC_Exported_FunctionsPrototype
|
||||
* @brief Public functions declaration.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_FUNCTIONS */
|
||||
|
||||
uint8_t * USBD_UsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length);
|
||||
|
||||
/* USER CODE END EXPORTED_FUNCTIONS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USBD_DESC__H__ */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
# This file is partially autogenerated. If you let CubeMX generate the code,
|
||||
# it will edit this file to update the source and include list. This editing
|
||||
# is not very robust, so be careful with changing the format of this file.
|
||||
|
||||
######################################
|
||||
# source
|
||||
######################################
|
||||
C_SOURCES = \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c \
|
||||
Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
|
||||
Src/stm32f4xx_hal_timebase_TIM.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_can.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c \
|
||||
Src/tim.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c \
|
||||
Src/dma.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c \
|
||||
Src/freertos.c \
|
||||
Src/main.c \
|
||||
Src/usbd_conf.c \
|
||||
Src/spi.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \
|
||||
Src/usart.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
|
||||
Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
|
||||
Src/usbd_cdc_if.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c \
|
||||
Src/adc.c \
|
||||
Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/list.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c \
|
||||
Src/stm32f4xx_hal_msp.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c \
|
||||
Src/usbd_desc.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c \
|
||||
Src/stm32f4xx_it.c \
|
||||
Src/usb_device.c \
|
||||
Src/can.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/queue.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.c \
|
||||
Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c \
|
||||
Src/system_stm32f4xx.c \
|
||||
Src/gpio.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/timers.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c \
|
||||
Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c \
|
||||
Src/i2c.c \
|
||||
Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c
|
||||
|
||||
ASM_SOURCES = \
|
||||
startup_stm32f405xx.s
|
||||
|
||||
#######################################
|
||||
# Includes
|
||||
#######################################
|
||||
AS_INCLUDES =
|
||||
|
||||
C_INCLUDES = \
|
||||
-IMiddlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \
|
||||
-IMiddlewares/Third_Party/FreeRTOS/Source/include \
|
||||
-IMiddlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS \
|
||||
-IMiddlewares/ST/STM32_USB_Device_Library/Core/Inc \
|
||||
-IMiddlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \
|
||||
-IDrivers/STM32F4xx_HAL_Driver/Inc \
|
||||
-IDrivers/STM32F4xx_HAL_Driver/Inc/Legacy \
|
||||
-IDrivers/CMSIS/Device/ST/STM32F4xx/Include \
|
||||
-IDrivers/CMSIS/Include \
|
||||
-IInc
|
||||
|
||||
# CubeMX insists on this line
|
||||
Inc
|
||||
@@ -0,0 +1,698 @@
|
||||
#MicroXplorer Configuration settings - do not modify
|
||||
ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_6
|
||||
ADC1.Channel-1\#ChannelInjectedConversion=ADC_CHANNEL_6
|
||||
ADC1.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4
|
||||
ADC1.ContinuousConvMode=DISABLE
|
||||
ADC1.DMAContinuousRequests=DISABLE
|
||||
ADC1.DataAlign=ADC_DATAALIGN_RIGHT
|
||||
ADC1.DiscontinuousConvMode=DISABLE
|
||||
ADC1.EOCSelection=ADC_EOC_SINGLE_CONV
|
||||
ADC1.EnableAnalogWatchDog=false
|
||||
ADC1.ExternalTrigConv=ADC_SOFTWARE_START
|
||||
ADC1.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE
|
||||
ADC1.ExternalTrigInjecConv=ADC_EXTERNALTRIGINJECCONV_T1_TRGO
|
||||
ADC1.ExternalTrigInjecConvEdge=ADC_EXTERNALTRIGINJECCONVEDGE_RISING
|
||||
ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,master,ClockPrescaler,Resolution,DataAlign,ScanConvMode,ContinuousConvMode,DiscontinuousConvMode,DMAContinuousRequests,EOCSelection,NbrOfConversion,ExternalTrigConvEdge,InjNumberOfConversion,EnableAnalogWatchDog,Rank-1\#ChannelInjectedConversion,Channel-1\#ChannelInjectedConversion,SamplingTime-1\#ChannelInjectedConversion,InjectedOffset-1\#ChannelInjectedConversion,InjectedConvMode,ExternalTrigInjecConvEdge,ExternalTrigInjecConv,ExternalTrigConv
|
||||
ADC1.InjNumberOfConversion=1
|
||||
ADC1.InjectedConvMode=None
|
||||
ADC1.InjectedOffset-1\#ChannelInjectedConversion=0
|
||||
ADC1.NbrOfConversion=1
|
||||
ADC1.NbrOfConversionFlag=1
|
||||
ADC1.Rank-0\#ChannelRegularConversion=1
|
||||
ADC1.Rank-1\#ChannelInjectedConversion=1
|
||||
ADC1.Resolution=ADC_RESOLUTION_12B
|
||||
ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES
|
||||
ADC1.SamplingTime-1\#ChannelInjectedConversion=ADC_SAMPLETIME_3CYCLES
|
||||
ADC1.ScanConvMode=DISABLE
|
||||
ADC1.master=1
|
||||
ADC2.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_13
|
||||
ADC2.Channel-1\#ChannelInjectedConversion=ADC_CHANNEL_10
|
||||
ADC2.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4
|
||||
ADC2.ContinuousConvMode=DISABLE
|
||||
ADC2.DMAContinuousRequests=DISABLE
|
||||
ADC2.DataAlign=ADC_DATAALIGN_RIGHT
|
||||
ADC2.DiscontinuousConvMode=DISABLE
|
||||
ADC2.EOCSelection=ADC_EOC_SINGLE_CONV
|
||||
ADC2.EnableAnalogWatchDog=false
|
||||
ADC2.ExternalTrigConv=ADC_EXTERNALTRIGCONV_T8_TRGO
|
||||
ADC2.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_RISING
|
||||
ADC2.ExternalTrigInjecConv=ADC_EXTERNALTRIGINJECCONV_T1_TRGO
|
||||
ADC2.ExternalTrigInjecConvEdge=ADC_EXTERNALTRIGINJECCONVEDGE_RISING
|
||||
ADC2.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler,Resolution,DataAlign,ScanConvMode,ContinuousConvMode,DiscontinuousConvMode,DMAContinuousRequests,EOCSelection,NbrOfConversion,InjNumberOfConversion,EnableAnalogWatchDog,Rank-1\#ChannelInjectedConversion,Channel-1\#ChannelInjectedConversion,SamplingTime-1\#ChannelInjectedConversion,InjectedOffset-1\#ChannelInjectedConversion,ExternalTrigInjecConvEdge,ExternalTrigConvEdge,InjectedConvMode,ExternalTrigInjecConv,ExternalTrigConv
|
||||
ADC2.InjNumberOfConversion=1
|
||||
ADC2.InjectedConvMode=None
|
||||
ADC2.InjectedOffset-1\#ChannelInjectedConversion=0
|
||||
ADC2.NbrOfConversion=1
|
||||
ADC2.NbrOfConversionFlag=1
|
||||
ADC2.Rank-0\#ChannelRegularConversion=1
|
||||
ADC2.Rank-1\#ChannelInjectedConversion=1
|
||||
ADC2.Resolution=ADC_RESOLUTION_12B
|
||||
ADC2.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES
|
||||
ADC2.SamplingTime-1\#ChannelInjectedConversion=ADC_SAMPLETIME_3CYCLES
|
||||
ADC2.ScanConvMode=DISABLE
|
||||
ADC3.Channel-7\#ChannelRegularConversion=ADC_CHANNEL_12
|
||||
ADC3.Channel-8\#ChannelInjectedConversion=ADC_CHANNEL_11
|
||||
ADC3.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4
|
||||
ADC3.ContinuousConvMode=DISABLE
|
||||
ADC3.DMAContinuousRequests=DISABLE
|
||||
ADC3.DataAlign=ADC_DATAALIGN_RIGHT
|
||||
ADC3.DiscontinuousConvMode=DISABLE
|
||||
ADC3.EOCSelection=ADC_EOC_SINGLE_CONV
|
||||
ADC3.EnableAnalogWatchDog=false
|
||||
ADC3.ExternalTrigConv=ADC_EXTERNALTRIGCONV_T8_TRGO
|
||||
ADC3.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_RISING
|
||||
ADC3.ExternalTrigInjecConv=ADC_EXTERNALTRIGINJECCONV_T1_TRGO
|
||||
ADC3.ExternalTrigInjecConvEdge=ADC_EXTERNALTRIGINJECCONVEDGE_RISING
|
||||
ADC3.IPParameters=Rank-7\#ChannelRegularConversion,Channel-7\#ChannelRegularConversion,SamplingTime-7\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler,Resolution,DataAlign,ScanConvMode,ContinuousConvMode,DiscontinuousConvMode,DMAContinuousRequests,EOCSelection,NbrOfConversion,ExternalTrigConvEdge,InjNumberOfConversion,EnableAnalogWatchDog,Rank-8\#ChannelInjectedConversion,Channel-8\#ChannelInjectedConversion,SamplingTime-8\#ChannelInjectedConversion,InjectedOffset-8\#ChannelInjectedConversion,ExternalTrigInjecConvEdge,InjectedConvMode,ExternalTrigInjecConv,ExternalTrigConv
|
||||
ADC3.InjNumberOfConversion=1
|
||||
ADC3.InjectedConvMode=None
|
||||
ADC3.InjectedOffset-8\#ChannelInjectedConversion=0
|
||||
ADC3.NbrOfConversion=1
|
||||
ADC3.NbrOfConversionFlag=1
|
||||
ADC3.Rank-7\#ChannelRegularConversion=1
|
||||
ADC3.Rank-8\#ChannelInjectedConversion=1
|
||||
ADC3.Resolution=ADC_RESOLUTION_12B
|
||||
ADC3.SamplingTime-7\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES
|
||||
ADC3.SamplingTime-8\#ChannelInjectedConversion=ADC_SAMPLETIME_3CYCLES
|
||||
ADC3.ScanConvMode=DISABLE
|
||||
CAN1.AutoWakeUp=ENABLE
|
||||
CAN1.BS1=CAN_BS1_6TQ
|
||||
CAN1.BS2=CAN_BS2_5TQ
|
||||
CAN1.CalculateTimeBit=500
|
||||
CAN1.CalculateTimeQuantum=166.66666666666669
|
||||
CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,Prescaler,TimeSeg1,TimeSeg2,AutoWakeUp,BS1,BS2
|
||||
CAN1.Prescaler=7
|
||||
CAN1.TimeSeg1=CAN_BS1_6TQ
|
||||
CAN1.TimeSeg2=CAN_BS2_5TQ
|
||||
Dma.ADC1.2.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.ADC1.2.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.ADC1.2.Instance=DMA2_Stream0
|
||||
Dma.ADC1.2.MemDataAlignment=DMA_MDATAALIGN_HALFWORD
|
||||
Dma.ADC1.2.MemInc=DMA_MINC_ENABLE
|
||||
Dma.ADC1.2.Mode=DMA_CIRCULAR
|
||||
Dma.ADC1.2.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD
|
||||
Dma.ADC1.2.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.ADC1.2.Priority=DMA_PRIORITY_LOW
|
||||
Dma.ADC1.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.Request0=UART4_RX
|
||||
Dma.Request1=UART4_TX
|
||||
Dma.Request2=ADC1
|
||||
Dma.Request3=SPI3_TX
|
||||
Dma.Request4=SPI3_RX
|
||||
Dma.RequestsNb=5
|
||||
Dma.SPI3_RX.4.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.SPI3_RX.4.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.SPI3_RX.4.Instance=DMA1_Stream0
|
||||
Dma.SPI3_RX.4.MemDataAlignment=DMA_MDATAALIGN_HALFWORD
|
||||
Dma.SPI3_RX.4.MemInc=DMA_MINC_ENABLE
|
||||
Dma.SPI3_RX.4.Mode=DMA_NORMAL
|
||||
Dma.SPI3_RX.4.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD
|
||||
Dma.SPI3_RX.4.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.SPI3_RX.4.Priority=DMA_PRIORITY_MEDIUM
|
||||
Dma.SPI3_RX.4.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.SPI3_TX.3.Direction=DMA_MEMORY_TO_PERIPH
|
||||
Dma.SPI3_TX.3.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.SPI3_TX.3.Instance=DMA1_Stream5
|
||||
Dma.SPI3_TX.3.MemDataAlignment=DMA_MDATAALIGN_HALFWORD
|
||||
Dma.SPI3_TX.3.MemInc=DMA_MINC_ENABLE
|
||||
Dma.SPI3_TX.3.Mode=DMA_NORMAL
|
||||
Dma.SPI3_TX.3.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD
|
||||
Dma.SPI3_TX.3.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.SPI3_TX.3.Priority=DMA_PRIORITY_MEDIUM
|
||||
Dma.SPI3_TX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.UART4_RX.0.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.UART4_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.UART4_RX.0.Instance=DMA1_Stream2
|
||||
Dma.UART4_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.UART4_RX.0.MemInc=DMA_MINC_ENABLE
|
||||
Dma.UART4_RX.0.Mode=DMA_CIRCULAR
|
||||
Dma.UART4_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.UART4_RX.0.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.UART4_RX.0.Priority=DMA_PRIORITY_LOW
|
||||
Dma.UART4_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.UART4_TX.1.Direction=DMA_MEMORY_TO_PERIPH
|
||||
Dma.UART4_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.UART4_TX.1.Instance=DMA1_Stream4
|
||||
Dma.UART4_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.UART4_TX.1.MemInc=DMA_MINC_ENABLE
|
||||
Dma.UART4_TX.1.Mode=DMA_NORMAL
|
||||
Dma.UART4_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.UART4_TX.1.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.UART4_TX.1.Priority=DMA_PRIORITY_LOW
|
||||
Dma.UART4_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
FREERTOS.FootprintOK=true
|
||||
FREERTOS.INCLUDE_uxTaskGetStackHighWaterMark=1
|
||||
FREERTOS.INCLUDE_vTaskDelayUntil=1
|
||||
FREERTOS.IPParameters=Tasks01,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE,FootprintOK,configCHECK_FOR_STACK_OVERFLOW,INCLUDE_uxTaskGetStackHighWaterMark,configUSE_IDLE_HOOK
|
||||
FREERTOS.Tasks01=defaultTask,0,256,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.configCHECK_FOR_STACK_OVERFLOW=1
|
||||
FREERTOS.configTOTAL_HEAP_SIZE=65536
|
||||
FREERTOS.configUSE_IDLE_HOOK=1
|
||||
File.Version=6
|
||||
KeepUserPlacement=true
|
||||
Mcu.Family=STM32F4
|
||||
Mcu.IP0=ADC1
|
||||
Mcu.IP1=ADC2
|
||||
Mcu.IP10=TIM1
|
||||
Mcu.IP11=TIM2
|
||||
Mcu.IP12=TIM3
|
||||
Mcu.IP13=TIM4
|
||||
Mcu.IP14=TIM5
|
||||
Mcu.IP15=TIM8
|
||||
Mcu.IP16=TIM13
|
||||
Mcu.IP17=UART4
|
||||
Mcu.IP18=USB_DEVICE
|
||||
Mcu.IP19=USB_OTG_FS
|
||||
Mcu.IP2=ADC3
|
||||
Mcu.IP3=CAN1
|
||||
Mcu.IP4=DMA
|
||||
Mcu.IP5=FREERTOS
|
||||
Mcu.IP6=NVIC
|
||||
Mcu.IP7=RCC
|
||||
Mcu.IP8=SPI3
|
||||
Mcu.IP9=SYS
|
||||
Mcu.IPNb=20
|
||||
Mcu.Name=STM32F405RGTx
|
||||
Mcu.Package=LQFP64
|
||||
Mcu.Pin0=PC13-ANTI_TAMP
|
||||
Mcu.Pin1=PC14-OSC32_IN
|
||||
Mcu.Pin10=PA1
|
||||
Mcu.Pin11=PA2
|
||||
Mcu.Pin12=PA3
|
||||
Mcu.Pin13=PA4
|
||||
Mcu.Pin14=PA5
|
||||
Mcu.Pin15=PA6
|
||||
Mcu.Pin16=PA7
|
||||
Mcu.Pin17=PC4
|
||||
Mcu.Pin18=PC5
|
||||
Mcu.Pin19=PB0
|
||||
Mcu.Pin2=PC15-OSC32_OUT
|
||||
Mcu.Pin20=PB1
|
||||
Mcu.Pin21=PB2
|
||||
Mcu.Pin22=PB10
|
||||
Mcu.Pin23=PB11
|
||||
Mcu.Pin24=PB12
|
||||
Mcu.Pin25=PB13
|
||||
Mcu.Pin26=PB14
|
||||
Mcu.Pin27=PB15
|
||||
Mcu.Pin28=PC6
|
||||
Mcu.Pin29=PC7
|
||||
Mcu.Pin3=PH0-OSC_IN
|
||||
Mcu.Pin30=PC8
|
||||
Mcu.Pin31=PC9
|
||||
Mcu.Pin32=PA8
|
||||
Mcu.Pin33=PA9
|
||||
Mcu.Pin34=PA10
|
||||
Mcu.Pin35=PA11
|
||||
Mcu.Pin36=PA12
|
||||
Mcu.Pin37=PA13
|
||||
Mcu.Pin38=PA14
|
||||
Mcu.Pin39=PA15
|
||||
Mcu.Pin4=PH1-OSC_OUT
|
||||
Mcu.Pin40=PC10
|
||||
Mcu.Pin41=PC11
|
||||
Mcu.Pin42=PC12
|
||||
Mcu.Pin43=PD2
|
||||
Mcu.Pin44=PB3
|
||||
Mcu.Pin45=PB4
|
||||
Mcu.Pin46=PB5
|
||||
Mcu.Pin47=PB6
|
||||
Mcu.Pin48=PB7
|
||||
Mcu.Pin49=PB8
|
||||
Mcu.Pin5=PC0
|
||||
Mcu.Pin50=PB9
|
||||
Mcu.Pin51=VP_FREERTOS_VS_ENABLE
|
||||
Mcu.Pin52=VP_SYS_VS_tim14
|
||||
Mcu.Pin53=VP_TIM1_VS_ClockSourceINT
|
||||
Mcu.Pin54=VP_TIM1_VS_no_output4
|
||||
Mcu.Pin55=VP_TIM13_VS_ClockSourceINT
|
||||
Mcu.Pin56=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
|
||||
Mcu.Pin6=PC1
|
||||
Mcu.Pin7=PC2
|
||||
Mcu.Pin8=PC3
|
||||
Mcu.Pin9=PA0-WKUP
|
||||
Mcu.PinsNb=57
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=TIM_1_8_CLOCK_HZ,168000000;TIM_1_8_PERIOD_CLOCKS,3500;TIM_1_8_DEADTIME_CLOCKS,20;TIM_APB1_CLOCK_HZ,84000000;TIM_APB1_PERIOD_CLOCKS,4096;TIM_APB1_DEADTIME_CLOCKS,40;TIM_1_8_RCR,2
|
||||
Mcu.UserName=STM32F405RGTx
|
||||
MxCube.Version=4.27.0
|
||||
MxDb.Version=DB.4.0.270
|
||||
NVIC.ADC_IRQn=true\:5\:0\:false\:false\:true\:true\:true
|
||||
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true
|
||||
NVIC.CAN1_RX0_IRQn=true\:6\:0\:true\:false\:true\:true\:true
|
||||
NVIC.CAN1_RX1_IRQn=true\:6\:0\:true\:false\:true\:true\:true
|
||||
NVIC.CAN1_SCE_IRQn=true\:6\:0\:true\:false\:true\:true\:true
|
||||
NVIC.CAN1_TX_IRQn=true\:6\:0\:true\:false\:true\:true\:true
|
||||
NVIC.DMA1_Stream0_IRQn=true\:5\:0\:false\:false\:true\:true\:false
|
||||
NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:true
|
||||
NVIC.DMA1_Stream4_IRQn=true\:5\:0\:false\:false\:true\:true\:false
|
||||
NVIC.DMA1_Stream5_IRQn=true\:5\:0\:false\:false\:true\:true\:false
|
||||
NVIC.DMA2_Stream0_IRQn=true\:5\:0\:false\:false\:false\:true\:false
|
||||
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:true
|
||||
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true
|
||||
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:true
|
||||
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:true
|
||||
NVIC.OTG_FS_IRQn=true\:5\:0\:false\:false\:true\:true\:true
|
||||
NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:true
|
||||
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||
NVIC.SPI3_IRQn=true\:5\:0\:false\:false\:true\:true\:true
|
||||
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:true
|
||||
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:true
|
||||
NVIC.TIM1_UP_TIM10_IRQn=true\:0\:0\:false\:false\:false\:false\:true
|
||||
NVIC.TIM5_IRQn=true\:5\:0\:false\:false\:true\:true\:true
|
||||
NVIC.TIM8_TRG_COM_TIM14_IRQn=true\:0\:0\:false\:false\:true\:false\:false
|
||||
NVIC.TIM8_UP_TIM13_IRQn=true\:0\:0\:false\:false\:false\:false\:true
|
||||
NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn
|
||||
NVIC.TimeBaseIP=TIM14
|
||||
NVIC.UART4_IRQn=true\:5\:0\:false\:false\:true\:true\:true
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true
|
||||
PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PA0-WKUP.GPIO_Label=GPIO_1
|
||||
PA0-WKUP.GPIO_PuPd=GPIO_PULLDOWN
|
||||
PA0-WKUP.Locked=true
|
||||
PA0-WKUP.Signal=SharedStack_PA0
|
||||
PA0-WKUP.Stacked=true
|
||||
PA1.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PA1.GPIO_Label=GPIO_2
|
||||
PA1.GPIO_PuPd=GPIO_NOPULL
|
||||
PA1.Locked=true
|
||||
PA1.Signal=SharedStack_PA1
|
||||
PA1.Stacked=true
|
||||
PA10.GPIOParameters=GPIO_Label
|
||||
PA10.GPIO_Label=M0_CH
|
||||
PA10.Locked=true
|
||||
PA10.Signal=S_TIM1_CH3
|
||||
PA11.Mode=Device_Only
|
||||
PA11.Signal=USB_OTG_FS_DM
|
||||
PA12.Mode=Device_Only
|
||||
PA12.Signal=USB_OTG_FS_DP
|
||||
PA13.Mode=Serial_Wire
|
||||
PA13.Signal=SYS_JTMS-SWDIO
|
||||
PA14.Mode=Serial_Wire
|
||||
PA14.Signal=SYS_JTCK-SWCLK
|
||||
PA15.GPIOParameters=GPIO_Label
|
||||
PA15.GPIO_Label=GPIO_7
|
||||
PA15.Locked=true
|
||||
PA15.Signal=GPIO_Input
|
||||
PA2.GPIOParameters=GPIO_Label
|
||||
PA2.GPIO_Label=GPIO_3
|
||||
PA2.Locked=true
|
||||
PA2.Signal=S_TIM5_CH3
|
||||
PA3.GPIOParameters=GPIO_Label
|
||||
PA3.GPIO_Label=GPIO_4
|
||||
PA3.Locked=true
|
||||
PA3.Signal=S_TIM5_CH4
|
||||
PA4.GPIOParameters=GPIO_Label
|
||||
PA4.GPIO_Label=M1_TEMP
|
||||
PA4.Locked=true
|
||||
PA4.Signal=ADCx_IN4
|
||||
PA5.GPIOParameters=GPIO_Label
|
||||
PA5.GPIO_Label=AUX_TEMP
|
||||
PA5.Locked=true
|
||||
PA5.Signal=ADCx_IN5
|
||||
PA6.GPIOParameters=GPIO_Label
|
||||
PA6.GPIO_Label=VBUS_S
|
||||
PA6.Locked=true
|
||||
PA6.Signal=ADCx_IN6
|
||||
PA7.GPIOParameters=GPIO_Label
|
||||
PA7.GPIO_Label=M1_AL
|
||||
PA7.Locked=true
|
||||
PA7.Mode=PWM Generation1 CH1 CH1N
|
||||
PA7.Signal=TIM8_CH1N
|
||||
PA8.GPIOParameters=GPIO_Label
|
||||
PA8.GPIO_Label=M0_AH
|
||||
PA8.Locked=true
|
||||
PA8.Signal=S_TIM1_CH1
|
||||
PA9.GPIOParameters=GPIO_Label
|
||||
PA9.GPIO_Label=M0_BH
|
||||
PA9.Locked=true
|
||||
PA9.Signal=S_TIM1_CH2
|
||||
PB0.GPIOParameters=GPIO_Label
|
||||
PB0.GPIO_Label=M1_BL
|
||||
PB0.Locked=true
|
||||
PB0.Mode=PWM Generation2 CH2 CH2N
|
||||
PB0.Signal=TIM8_CH2N
|
||||
PB1.GPIOParameters=GPIO_Label
|
||||
PB1.GPIO_Label=M1_CL
|
||||
PB1.Locked=true
|
||||
PB1.Mode=PWM Generation3 CH3 CH3N
|
||||
PB1.Signal=TIM8_CH3N
|
||||
PB10.GPIOParameters=GPIO_Label
|
||||
PB10.GPIO_Label=AUX_L
|
||||
PB10.Locked=true
|
||||
PB10.Signal=S_TIM2_CH3
|
||||
PB11.GPIOParameters=GPIO_Label
|
||||
PB11.GPIO_Label=AUX_H
|
||||
PB11.Locked=true
|
||||
PB11.Signal=S_TIM2_CH4
|
||||
PB12.GPIOParameters=GPIO_Label
|
||||
PB12.GPIO_Label=EN_GATE
|
||||
PB12.Locked=true
|
||||
PB12.Signal=GPIO_Output
|
||||
PB13.GPIOParameters=GPIO_Label
|
||||
PB13.GPIO_Label=M0_AL
|
||||
PB13.Locked=true
|
||||
PB13.Mode=PWM Generation1 CH1 CH1N
|
||||
PB13.Signal=TIM1_CH1N
|
||||
PB14.GPIOParameters=GPIO_Label
|
||||
PB14.GPIO_Label=M0_BL
|
||||
PB14.Locked=true
|
||||
PB14.Mode=PWM Generation2 CH2 CH2N
|
||||
PB14.Signal=TIM1_CH2N
|
||||
PB15.GPIOParameters=GPIO_Label
|
||||
PB15.GPIO_Label=M0_CL
|
||||
PB15.Locked=true
|
||||
PB15.Mode=PWM Generation3 CH3 CH3N
|
||||
PB15.Signal=TIM1_CH3N
|
||||
PB2.GPIOParameters=GPIO_Label
|
||||
PB2.GPIO_Label=GPIO_6
|
||||
PB2.Locked=true
|
||||
PB2.Signal=GPIO_Input
|
||||
PB3.GPIOParameters=GPIO_Label
|
||||
PB3.GPIO_Label=GPIO_8
|
||||
PB3.Locked=true
|
||||
PB3.Signal=GPIO_Input
|
||||
PB4.GPIOParameters=GPIO_Label
|
||||
PB4.GPIO_Label=M0_ENC_A
|
||||
PB4.Signal=S_TIM3_CH1
|
||||
PB5.GPIOParameters=GPIO_Label
|
||||
PB5.GPIO_Label=M0_ENC_B
|
||||
PB5.Signal=S_TIM3_CH2
|
||||
PB6.GPIOParameters=GPIO_Label
|
||||
PB6.GPIO_Label=M1_ENC_A
|
||||
PB6.Signal=S_TIM4_CH1
|
||||
PB7.GPIOParameters=GPIO_Label
|
||||
PB7.GPIO_Label=M1_ENC_B
|
||||
PB7.Signal=S_TIM4_CH2
|
||||
PB8.Locked=true
|
||||
PB8.Signal=SharedStack_PB8
|
||||
PB8.Stacked=true
|
||||
PB9.Locked=true
|
||||
PB9.Signal=SharedStack_PB9
|
||||
PB9.Stacked=true
|
||||
PC0.GPIOParameters=GPIO_Label
|
||||
PC0.GPIO_Label=M0_IB
|
||||
PC0.Signal=ADCx_IN10
|
||||
PC1.GPIOParameters=GPIO_Label
|
||||
PC1.GPIO_Label=M0_IC
|
||||
PC1.Signal=ADCx_IN11
|
||||
PC10.Mode=Full_Duplex_Master
|
||||
PC10.Signal=SPI3_SCK
|
||||
PC11.Mode=Full_Duplex_Master
|
||||
PC11.Signal=SPI3_MISO
|
||||
PC12.Mode=Full_Duplex_Master
|
||||
PC12.Signal=SPI3_MOSI
|
||||
PC13-ANTI_TAMP.GPIOParameters=PinState,GPIO_Label
|
||||
PC13-ANTI_TAMP.GPIO_Label=M0_nCS
|
||||
PC13-ANTI_TAMP.Locked=true
|
||||
PC13-ANTI_TAMP.PinState=GPIO_PIN_SET
|
||||
PC13-ANTI_TAMP.Signal=GPIO_Output
|
||||
PC14-OSC32_IN.GPIOParameters=PinState,GPIO_Label
|
||||
PC14-OSC32_IN.GPIO_Label=M1_nCS
|
||||
PC14-OSC32_IN.Locked=true
|
||||
PC14-OSC32_IN.PinState=GPIO_PIN_SET
|
||||
PC14-OSC32_IN.Signal=GPIO_Output
|
||||
PC15-OSC32_OUT.GPIOParameters=GPIO_Label
|
||||
PC15-OSC32_OUT.GPIO_Label=M1_ENC_Z
|
||||
PC15-OSC32_OUT.Locked=true
|
||||
PC15-OSC32_OUT.Signal=GPIO_Input
|
||||
PC2.GPIOParameters=GPIO_Label
|
||||
PC2.GPIO_Label=M1_IC
|
||||
PC2.Signal=ADCx_IN12
|
||||
PC3.GPIOParameters=GPIO_Label
|
||||
PC3.GPIO_Label=M1_IB
|
||||
PC3.Signal=ADCx_IN13
|
||||
PC4.GPIOParameters=GPIO_Label
|
||||
PC4.GPIO_Label=GPIO_5
|
||||
PC4.Locked=true
|
||||
PC4.Signal=GPIO_Input
|
||||
PC5.GPIOParameters=GPIO_Label
|
||||
PC5.GPIO_Label=M0_TEMP
|
||||
PC5.Signal=ADCx_IN15
|
||||
PC6.GPIOParameters=GPIO_Label
|
||||
PC6.GPIO_Label=M1_AH
|
||||
PC6.Locked=true
|
||||
PC6.Signal=S_TIM8_CH1
|
||||
PC7.GPIOParameters=GPIO_Label
|
||||
PC7.GPIO_Label=M1_BH
|
||||
PC7.Locked=true
|
||||
PC7.Signal=S_TIM8_CH2
|
||||
PC8.GPIOParameters=GPIO_Label
|
||||
PC8.GPIO_Label=M1_CH
|
||||
PC8.Locked=true
|
||||
PC8.Signal=S_TIM8_CH3
|
||||
PC9.GPIOParameters=GPIO_Label
|
||||
PC9.GPIO_Label=M0_ENC_Z
|
||||
PC9.Locked=true
|
||||
PC9.Signal=GPIO_Input
|
||||
PCC.Checker=false
|
||||
PCC.Line=STM32F405/415
|
||||
PCC.MCU=STM32F405RGTx
|
||||
PCC.PartNumber=STM32F405RGTx
|
||||
PCC.Seq0=0
|
||||
PCC.Series=STM32F4
|
||||
PCC.Temperature=25
|
||||
PCC.Vdd=3.3
|
||||
PD2.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PD2.GPIO_Label=nFAULT
|
||||
PD2.GPIO_PuPd=GPIO_PULLUP
|
||||
PD2.Locked=true
|
||||
PD2.Signal=GPIO_Input
|
||||
PH0-OSC_IN.Mode=HSE-External-Oscillator
|
||||
PH0-OSC_IN.Signal=RCC_OSC_IN
|
||||
PH1-OSC_OUT.Mode=HSE-External-Oscillator
|
||||
PH1-OSC_OUT.Signal=RCC_OSC_OUT
|
||||
PinOutPanel.RotationAngle=0
|
||||
ProjectManager.AskForMigrate=true
|
||||
ProjectManager.BackupPrevious=false
|
||||
ProjectManager.CompilerOptimize=2
|
||||
ProjectManager.ComputerToolchain=false
|
||||
ProjectManager.CoupleFile=true
|
||||
ProjectManager.CustomerFirmwarePackage=
|
||||
ProjectManager.DefaultFWLocation=true
|
||||
ProjectManager.DeletePrevious=true
|
||||
ProjectManager.DeviceId=STM32F405RGTx
|
||||
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.21.0
|
||||
ProjectManager.FreePins=false
|
||||
ProjectManager.HalAssertFull=false
|
||||
ProjectManager.HeapSize=0x3C00
|
||||
ProjectManager.KeepUserCode=true
|
||||
ProjectManager.LastFirmware=true
|
||||
ProjectManager.LibraryCopy=1
|
||||
ProjectManager.MainLocation=Src
|
||||
ProjectManager.NoMain=false
|
||||
ProjectManager.PreviousToolchain=SW4STM32
|
||||
ProjectManager.ProjectBuild=false
|
||||
ProjectManager.ProjectFileName=Odrive.ioc
|
||||
ProjectManager.ProjectName=Odrive
|
||||
ProjectManager.StackSize=0x800
|
||||
ProjectManager.TargetToolchain=Makefile
|
||||
ProjectManager.ToolChainLocation=
|
||||
ProjectManager.UnderRoot=false
|
||||
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_ADC2_Init-ADC2-false-HAL-true,5-MX_CAN1_Init-CAN1-false-HAL-true,6-MX_TIM1_Init-TIM1-false-HAL-true,7-MX_TIM8_Init-TIM8-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,9-MX_TIM4_Init-TIM4-false-HAL-true,10-MX_SPI3_Init-SPI3-false-HAL-true,11-MX_ADC3_Init-ADC3-false-HAL-true,12-SystemClock_Config-RCC-false-HAL-true,13-MX_TIM2_Init-TIM2-false-HAL-true,14-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-true,15-MX_UART4_Init-UART4-false-HAL-true,16-MX_TIM5_Init-TIM5-false-HAL-true,17-MX_TIM13_Init-TIM13-false-HAL-true
|
||||
RCC.48MHZClocksFreq_Value=48000000
|
||||
RCC.AHBFreq_Value=168000000
|
||||
RCC.APB1CLKDivider=RCC_HCLK_DIV4
|
||||
RCC.APB1Freq_Value=42000000
|
||||
RCC.APB1TimFreq_Value=84000000
|
||||
RCC.APB2CLKDivider=RCC_HCLK_DIV2
|
||||
RCC.APB2Freq_Value=84000000
|
||||
RCC.APB2TimCLKDivider=1
|
||||
RCC.APB2TimFreq_Value=84000000
|
||||
RCC.CortexFreq_Value=168000000
|
||||
RCC.EthernetFreq_Value=168000000
|
||||
RCC.FCLKCortexFreq_Value=168000000
|
||||
RCC.FamilyName=M
|
||||
RCC.HCLKFreq_Value=168000000
|
||||
RCC.HSE_VALUE=8000000
|
||||
RCC.HSI_VALUE=16000000
|
||||
RCC.I2SClocksFreq_Value=192000000
|
||||
RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimCLKDivider,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLM,PLLN,PLLQ,PLLQCLKFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S
|
||||
RCC.LSE_VALUE=32768
|
||||
RCC.LSI_VALUE=32000
|
||||
RCC.MCO2PinFreq_Value=168000000
|
||||
RCC.PLLCLKFreq_Value=168000000
|
||||
RCC.PLLM=4
|
||||
RCC.PLLN=168
|
||||
RCC.PLLQ=7
|
||||
RCC.PLLQCLKFreq_Value=48000000
|
||||
RCC.RTCFreq_Value=32000
|
||||
RCC.RTCHSEDivFreq_Value=4000000
|
||||
RCC.SYSCLKFreq_VALUE=168000000
|
||||
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
|
||||
RCC.VCOI2SOutputFreq_Value=384000000
|
||||
RCC.VCOInputFreq_Value=2000000
|
||||
RCC.VCOOutputFreq_Value=336000000
|
||||
RCC.VcooutputI2S=192000000
|
||||
SH.ADCx_IN10.0=ADC1_IN10,IN10
|
||||
SH.ADCx_IN10.1=ADC2_IN10,IN10
|
||||
SH.ADCx_IN10.2=ADC3_IN10,IN10
|
||||
SH.ADCx_IN10.ConfNb=3
|
||||
SH.ADCx_IN11.0=ADC1_IN11,IN11
|
||||
SH.ADCx_IN11.1=ADC2_IN11,IN11
|
||||
SH.ADCx_IN11.2=ADC3_IN11,IN11
|
||||
SH.ADCx_IN11.ConfNb=3
|
||||
SH.ADCx_IN12.0=ADC1_IN12,IN12
|
||||
SH.ADCx_IN12.1=ADC2_IN12,IN12
|
||||
SH.ADCx_IN12.2=ADC3_IN12,IN12
|
||||
SH.ADCx_IN12.ConfNb=3
|
||||
SH.ADCx_IN13.0=ADC1_IN13,IN13
|
||||
SH.ADCx_IN13.1=ADC2_IN13,IN13
|
||||
SH.ADCx_IN13.2=ADC3_IN13,IN13
|
||||
SH.ADCx_IN13.ConfNb=3
|
||||
SH.ADCx_IN15.0=ADC1_IN15,IN15
|
||||
SH.ADCx_IN15.1=ADC2_IN15,IN15
|
||||
SH.ADCx_IN15.ConfNb=2
|
||||
SH.ADCx_IN4.0=ADC1_IN4,IN4
|
||||
SH.ADCx_IN4.1=ADC2_IN4,IN4
|
||||
SH.ADCx_IN4.ConfNb=2
|
||||
SH.ADCx_IN5.0=ADC1_IN5,IN5
|
||||
SH.ADCx_IN5.1=ADC2_IN5,IN5
|
||||
SH.ADCx_IN5.ConfNb=2
|
||||
SH.ADCx_IN6.0=ADC1_IN6,IN6
|
||||
SH.ADCx_IN6.1=ADC2_IN6,IN6
|
||||
SH.ADCx_IN6.ConfNb=2
|
||||
SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 CH1N
|
||||
SH.S_TIM1_CH1.ConfNb=1
|
||||
SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2 CH2N
|
||||
SH.S_TIM1_CH2.ConfNb=1
|
||||
SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3 CH3N
|
||||
SH.S_TIM1_CH3.ConfNb=1
|
||||
SH.S_TIM2_CH3.0=TIM2_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM2_CH3.ConfNb=1
|
||||
SH.S_TIM2_CH4.0=TIM2_CH4,PWM Generation4 CH4
|
||||
SH.S_TIM2_CH4.ConfNb=1
|
||||
SH.S_TIM3_CH1.0=TIM3_CH1,Encoder_Interface
|
||||
SH.S_TIM3_CH1.ConfNb=1
|
||||
SH.S_TIM3_CH2.0=TIM3_CH2,Encoder_Interface
|
||||
SH.S_TIM3_CH2.ConfNb=1
|
||||
SH.S_TIM4_CH1.0=TIM4_CH1,Encoder_Interface
|
||||
SH.S_TIM4_CH1.ConfNb=1
|
||||
SH.S_TIM4_CH2.0=TIM4_CH2,Encoder_Interface
|
||||
SH.S_TIM4_CH2.ConfNb=1
|
||||
SH.S_TIM5_CH3.0=TIM5_CH3,Input_Capture3_from_TI3
|
||||
SH.S_TIM5_CH3.ConfNb=1
|
||||
SH.S_TIM5_CH4.0=TIM5_CH4,Input_Capture4_from_TI4
|
||||
SH.S_TIM5_CH4.ConfNb=1
|
||||
SH.S_TIM8_CH1.0=TIM8_CH1,PWM Generation1 CH1 CH1N
|
||||
SH.S_TIM8_CH1.ConfNb=1
|
||||
SH.S_TIM8_CH2.0=TIM8_CH2,PWM Generation2 CH2 CH2N
|
||||
SH.S_TIM8_CH2.ConfNb=1
|
||||
SH.S_TIM8_CH3.0=TIM8_CH3,PWM Generation3 CH3 CH3N
|
||||
SH.S_TIM8_CH3.ConfNb=1
|
||||
SH.SharedStack_PA0.0=GPIO_EXTI0+0
|
||||
SH.SharedStack_PA0.1=UART4_TX,Asynchronous
|
||||
SH.SharedStack_PA0.ConfNb=2
|
||||
SH.SharedStack_PA1.0=GPIO_Input+0
|
||||
SH.SharedStack_PA1.1=UART4_RX,Asynchronous
|
||||
SH.SharedStack_PA1.ConfNb=2
|
||||
SH.SharedStack_PB8.0=CAN1_RX,Master
|
||||
SH.SharedStack_PB8.1=I2C1_SCL
|
||||
SH.SharedStack_PB8.ConfNb=2
|
||||
SH.SharedStack_PB9.0=CAN1_TX,Master
|
||||
SH.SharedStack_PB9.1=I2C1_SDA
|
||||
SH.SharedStack_PB9.ConfNb=2
|
||||
SPI3.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
|
||||
SPI3.CLKPhase=SPI_PHASE_2EDGE
|
||||
SPI3.CalculateBaudRate=2.625 MBits/s
|
||||
SPI3.DataSize=SPI_DATASIZE_16BIT
|
||||
SPI3.Direction=SPI_DIRECTION_2LINES
|
||||
SPI3.FirstBit=SPI_FIRSTBIT_MSB
|
||||
SPI3.IPParameters=Mode,CalculateBaudRate,BaudRatePrescaler,DataSize,FirstBit,CLKPhase,VirtualType,Direction
|
||||
SPI3.Mode=SPI_MODE_MASTER
|
||||
SPI3.VirtualType=VM_MASTER
|
||||
TIM1.Channel-Output\ Compare4\ No\ Output=TIM_CHANNEL_4
|
||||
TIM1.Channel-PWM\ Generation1\ CH1\ CH1N=TIM_CHANNEL_1
|
||||
TIM1.Channel-PWM\ Generation2\ CH2\ CH2N=TIM_CHANNEL_2
|
||||
TIM1.Channel-PWM\ Generation3\ CH3\ CH3N=TIM_CHANNEL_3
|
||||
TIM1.CounterMode=TIM_COUNTERMODE_CENTERALIGNED3
|
||||
TIM1.DeadTime=TIM_1_8_DEADTIME_CLOCKS
|
||||
TIM1.IPParameters=Channel-PWM Generation2 CH2 CH2N,Channel-PWM Generation3 CH3 CH3N,OCNPolarity_1,OCNPolarity_2,OCNPolarity_3,CounterMode,OCMode_PWM-PWM Generation1 CH1 CH1N,OCMode_PWM-PWM Generation2 CH2 CH2N,OCMode_PWM-PWM Generation3 CH3 CH3N,Period,DeadTime,OffStateRunMode,OffStateIDLEMode,Channel-Output Compare4 No Output,TIM_MasterOutputTrigger,Channel-PWM Generation1 CH1 CH1N,RepetitionCounter
|
||||
TIM1.OCMode_PWM-PWM\ Generation1\ CH1\ CH1N=TIM_OCMODE_PWM2
|
||||
TIM1.OCMode_PWM-PWM\ Generation2\ CH2\ CH2N=TIM_OCMODE_PWM2
|
||||
TIM1.OCMode_PWM-PWM\ Generation3\ CH3\ CH3N=TIM_OCMODE_PWM2
|
||||
TIM1.OCNPolarity_1=TIM_OCNPOLARITY_HIGH
|
||||
TIM1.OCNPolarity_2=TIM_OCNPOLARITY_HIGH
|
||||
TIM1.OCNPolarity_3=TIM_OCNPOLARITY_HIGH
|
||||
TIM1.OffStateIDLEMode=TIM_OSSI_ENABLE
|
||||
TIM1.OffStateRunMode=TIM_OSSR_ENABLE
|
||||
TIM1.Period=TIM_1_8_PERIOD_CLOCKS
|
||||
TIM1.RepetitionCounter=TIM_1_8_RCR
|
||||
TIM1.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
||||
TIM13.IPParameters=Period
|
||||
TIM13.Period=(2 * TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR+1)) * (TIM_APB1_CLOCK_HZ / TIM_1_8_CLOCK_HZ)
|
||||
TIM2.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM2.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
|
||||
TIM2.CounterMode=TIM_COUNTERMODE_CENTERALIGNED3
|
||||
TIM2.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,CounterMode,Period,OCMode_PWM-PWM Generation3 CH3,OCMode_PWM-PWM Generation4 CH4,OCPolarity_3,Pulse-PWM Generation4 CH4
|
||||
TIM2.OCMode_PWM-PWM\ Generation3\ CH3=TIM_OCMODE_PWM2
|
||||
TIM2.OCMode_PWM-PWM\ Generation4\ CH4=TIM_OCMODE_PWM2
|
||||
TIM2.OCPolarity_3=TIM_OCPOLARITY_LOW
|
||||
TIM2.Period=TIM_APB1_PERIOD_CLOCKS
|
||||
TIM2.Pulse-PWM\ Generation4\ CH4=TIM_APB1_PERIOD_CLOCKS+1
|
||||
TIM3.EncoderMode=TIM_ENCODERMODE_TI12
|
||||
TIM3.IC1Filter=4
|
||||
TIM3.IC1Polarity=TIM_ICPOLARITY_RISING
|
||||
TIM3.IC2Filter=4
|
||||
TIM3.IC2Polarity=TIM_ICPOLARITY_RISING
|
||||
TIM3.IPParameters=EncoderMode,IC1Polarity,IC2Polarity,IC1Filter,IC2Filter,Period
|
||||
TIM3.Period=0xffff
|
||||
TIM4.EncoderMode=TIM_ENCODERMODE_TI12
|
||||
TIM4.IC1Filter=4
|
||||
TIM4.IC1Polarity=TIM_ICPOLARITY_RISING
|
||||
TIM4.IC2Filter=4
|
||||
TIM4.IC2Polarity=TIM_ICPOLARITY_RISING
|
||||
TIM4.IPParameters=EncoderMode,IC1Polarity,IC2Polarity,IC1Filter,IC2Filter,Period
|
||||
TIM4.Period=0xffff
|
||||
TIM5.Channel-Input_Capture3_from_TI3=TIM_CHANNEL_3
|
||||
TIM5.Channel-Input_Capture4_from_TI4=TIM_CHANNEL_4
|
||||
TIM5.ICFilter_CH3=15
|
||||
TIM5.ICFilter_CH4=15
|
||||
TIM5.ICPolarity_CH3=TIM_INPUTCHANNELPOLARITY_BOTHEDGE
|
||||
TIM5.ICPolarity_CH4=TIM_INPUTCHANNELPOLARITY_BOTHEDGE
|
||||
TIM5.IPParameters=Channel-Input_Capture3_from_TI3,Channel-Input_Capture4_from_TI4,ICFilter_CH3,ICFilter_CH4,ICPolarity_CH3,ICPolarity_CH4,Period
|
||||
TIM5.Period=0xFFFFFFFF
|
||||
TIM8.Channel-Output\ Compare4\ No\ Output=TIM_CHANNEL_4
|
||||
TIM8.Channel-PWM\ Generation1\ CH1\ CH1N=TIM_CHANNEL_1
|
||||
TIM8.Channel-PWM\ Generation2\ CH2\ CH2N=TIM_CHANNEL_2
|
||||
TIM8.Channel-PWM\ Generation3\ CH3\ CH3N=TIM_CHANNEL_3
|
||||
TIM8.CounterMode=TIM_COUNTERMODE_CENTERALIGNED3
|
||||
TIM8.DeadTime=TIM_1_8_DEADTIME_CLOCKS
|
||||
TIM8.IPParameters=Channel-PWM Generation3 CH3 CH3N,Channel-PWM Generation2 CH2 CH2N,CounterMode,Period,OffStateRunMode,OffStateIDLEMode,DeadTime,OCMode_PWM-PWM Generation1 CH1 CH1N,OCMode_PWM-PWM Generation2 CH2 CH2N,OCMode_PWM-PWM Generation3 CH3 CH3N,Channel-Output Compare4 No Output,TIM_MasterOutputTrigger,Channel-PWM Generation1 CH1 CH1N,RepetitionCounter
|
||||
TIM8.OCMode_PWM-PWM\ Generation1\ CH1\ CH1N=TIM_OCMODE_PWM2
|
||||
TIM8.OCMode_PWM-PWM\ Generation2\ CH2\ CH2N=TIM_OCMODE_PWM2
|
||||
TIM8.OCMode_PWM-PWM\ Generation3\ CH3\ CH3N=TIM_OCMODE_PWM2
|
||||
TIM8.OffStateIDLEMode=TIM_OSSI_ENABLE
|
||||
TIM8.OffStateRunMode=TIM_OSSR_ENABLE
|
||||
TIM8.Period=TIM_1_8_PERIOD_CLOCKS
|
||||
TIM8.RepetitionCounter=TIM_1_8_RCR
|
||||
TIM8.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
||||
UART4.IPParameters=VirtualMode
|
||||
UART4.VirtualMode=Asynchronous
|
||||
USB_DEVICE.APP_RX_DATA_SIZE-CDC_FS=64
|
||||
USB_DEVICE.APP_TX_DATA_SIZE-CDC_FS=64
|
||||
USB_DEVICE.CLASS_NAME_FS=CDC
|
||||
USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING-CDC_FS,PRODUCT_STRING_CDC_FS,VID-CDC_FS,PID_CDC_FS,SERIALNUMBER_STRING_CDC_FS,APP_RX_DATA_SIZE-CDC_FS,APP_TX_DATA_SIZE-CDC_FS
|
||||
USB_DEVICE.MANUFACTURER_STRING-CDC_FS=ODrive Robotics
|
||||
USB_DEVICE.PID_CDC_FS=0x0D32
|
||||
USB_DEVICE.PRODUCT_STRING_CDC_FS=ODrive v3.3
|
||||
USB_DEVICE.SERIALNUMBER_STRING_CDC_FS=000000000001
|
||||
USB_DEVICE.VID-CDC_FS=0x1209
|
||||
USB_DEVICE.VirtualMode-CDC_FS=Cdc
|
||||
USB_DEVICE.VirtualModeFS=Cdc_FS
|
||||
USB_OTG_FS.IPParameters=VirtualMode,vbus_sensing_enable
|
||||
USB_OTG_FS.VirtualMode=Device_Only
|
||||
USB_OTG_FS.vbus_sensing_enable=DISABLE
|
||||
VP_FREERTOS_VS_ENABLE.Mode=Enabled
|
||||
VP_FREERTOS_VS_ENABLE.Signal=FREERTOS_VS_ENABLE
|
||||
VP_SYS_VS_tim14.Mode=TIM14
|
||||
VP_SYS_VS_tim14.Signal=SYS_VS_tim14
|
||||
VP_TIM13_VS_ClockSourceINT.Mode=Enable_Timer
|
||||
VP_TIM13_VS_ClockSourceINT.Signal=TIM13_VS_ClockSourceINT
|
||||
VP_TIM1_VS_ClockSourceINT.Mode=Internal
|
||||
VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
|
||||
VP_TIM1_VS_no_output4.Mode=Output Compare4 No Output
|
||||
VP_TIM1_VS_no_output4.Signal=TIM1_VS_no_output4
|
||||
VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS
|
||||
VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Signal=USB_DEVICE_VS_USB_DEVICE_CDC_FS
|
||||
board=Odrive
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
*****************************************************************************
|
||||
**
|
||||
|
||||
** File : LinkerScript.ld
|
||||
**
|
||||
** Abstract : Linker script for STM32F405RGTx Device with
|
||||
** 1024KByte FLASH, 128KByte RAM
|
||||
**
|
||||
** Set heap size, stack size and stack location according
|
||||
** to application requirements.
|
||||
**
|
||||
** Set memory bank area and size if external memory is used.
|
||||
**
|
||||
** Target : STMicroelectronics STM32
|
||||
**
|
||||
**
|
||||
** Distribution: The file is distributed as is, without any warranty
|
||||
** of any kind.
|
||||
**
|
||||
** (c)Copyright Ac6.
|
||||
** You may use this file as-is or modify it according to the needs of your
|
||||
** project. Distribution of this file (unmodified or modified) is not
|
||||
** permitted. Ac6 permit registered System Workbench for MCU users the
|
||||
** rights to distribute the assembled, compiled & linked contents of this
|
||||
** file as part of an application binary file, provided that it is built
|
||||
** using the System Workbench for MCU toolchain.
|
||||
**
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/* Entry Point */
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
/* Highest address of the user mode stack */
|
||||
_estack = 0x20020000; /* end of RAM */
|
||||
/* Generate a link error if heap and stack don't fit into RAM */
|
||||
_Min_Heap_Size = 0x3C00; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x800; /* required amount of stack */
|
||||
_heap_end_max = _estack - _Min_Stack_Size;
|
||||
|
||||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
|
||||
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
|
||||
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 768K
|
||||
NVM (r) : ORIGIN = 0x80C0000, LENGTH = 256K
|
||||
}
|
||||
|
||||
/* Define output sections */
|
||||
SECTIONS
|
||||
{
|
||||
/* The startup code goes first into FLASH */
|
||||
.isr_vector :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector)) /* Startup code */
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
/* The program code and other data goes into FLASH */
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.glue_7) /* glue arm to thumb code */
|
||||
*(.glue_7t) /* glue thumb to arm code */
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .; /* define a global symbols at end of code */
|
||||
} >FLASH
|
||||
|
||||
/* Constant data goes into FLASH */
|
||||
.rodata :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
|
||||
.ARM : {
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
} >FLASH
|
||||
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array*))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
} >FLASH
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array*))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
} >FLASH
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
KEEP (*(.fini_array*))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} >FLASH
|
||||
|
||||
/* used by the startup to initialize data */
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
/* Initialized data sections goes into RAM, load LMA copy after code */
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .; /* create a global symbol at data start */
|
||||
*(.testdata)
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
|
||||
. = ALIGN(4);
|
||||
_edata = .; /* define a global symbol at data end */
|
||||
} >RAM AT> FLASH
|
||||
|
||||
_siccmram = LOADADDR(.ccmram);
|
||||
|
||||
/* CCM-RAM section
|
||||
*
|
||||
* IMPORTANT NOTE!
|
||||
* If initialized variables will be placed in this section,
|
||||
* the startup code needs to be modified to copy the init-values.
|
||||
* Oskar: Added NOLOAD to remove this section from .bin outputs
|
||||
*/
|
||||
.ccmram (NOLOAD):
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sccmram = .; /* create a global symbol at ccmram start */
|
||||
*(.ccmram)
|
||||
*(.ccmram*)
|
||||
|
||||
. = ALIGN(4);
|
||||
_eccmram = .; /* create a global symbol at ccmram end */
|
||||
} >CCMRAM /*AT> FLASH*/
|
||||
|
||||
|
||||
/* Uninitialized data section */
|
||||
. = ALIGN(4);
|
||||
.bss :
|
||||
{
|
||||
/* This is used by the startup in order to initialize the .bss secion */
|
||||
_sbss = .; /* define a global symbol at bss start */
|
||||
__bss_start__ = _sbss;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .; /* define a global symbol at bss end */
|
||||
__bss_end__ = _ebss;
|
||||
} >RAM
|
||||
|
||||
/* User_heap_stack section, used to check that there is enough RAM left */
|
||||
._user_heap_stack :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
PROVIDE ( end = . );
|
||||
PROVIDE ( _end = . );
|
||||
. = . + _Min_Heap_Size;
|
||||
. = . + _Min_Stack_Size;
|
||||
. = ALIGN(8);
|
||||
} >RAM
|
||||
|
||||
|
||||
|
||||
/* Remove information from the standard libraries */
|
||||
/DISCARD/ :
|
||||
{
|
||||
libc.a ( * )
|
||||
libm.a ( * )
|
||||
libgcc.a ( * )
|
||||
}
|
||||
|
||||
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,465 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : ADC.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of the ADC instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "adc.h"
|
||||
|
||||
#include "gpio.h"
|
||||
#include "dma.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \
|
||||
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2
|
||||
#include "prev_board_ver/adc_V3_2.c"
|
||||
#elif HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 3 \
|
||||
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 4
|
||||
#include "prev_board_ver/adc_V3_4.c"
|
||||
#else
|
||||
/* USER CODE END 0 */
|
||||
|
||||
ADC_HandleTypeDef hadc1;
|
||||
ADC_HandleTypeDef hadc2;
|
||||
ADC_HandleTypeDef hadc3;
|
||||
DMA_HandleTypeDef hdma_adc1;
|
||||
|
||||
/* ADC1 init function */
|
||||
void MX_ADC1_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc1.Instance = ADC1;
|
||||
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc1.Init.ScanConvMode = DISABLE;
|
||||
hadc1.Init.ContinuousConvMode = DISABLE;
|
||||
hadc1.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
|
||||
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
|
||||
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc1.Init.NbrOfConversion = 1;
|
||||
hadc1.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_6;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_6;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* ADC2 init function */
|
||||
void MX_ADC2_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc2.Instance = ADC2;
|
||||
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc2.Init.ScanConvMode = DISABLE;
|
||||
hadc2.Init.ContinuousConvMode = DISABLE;
|
||||
hadc2.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
|
||||
hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
|
||||
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc2.Init.NbrOfConversion = 1;
|
||||
hadc2.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc2) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_13;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_10;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* ADC3 init function */
|
||||
void MX_ADC3_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc3.Instance = ADC3;
|
||||
hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc3.Init.ScanConvMode = DISABLE;
|
||||
hadc3.Init.ContinuousConvMode = DISABLE;
|
||||
hadc3.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
|
||||
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
|
||||
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc3.Init.NbrOfConversion = 1;
|
||||
hadc3.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_12;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_11;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc3, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if(adcHandle->Instance==ADC1)
|
||||
{
|
||||
/* USER CODE BEGIN ADC1_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC1_MspInit 0 */
|
||||
/* ADC1 clock enable */
|
||||
__HAL_RCC_ADC1_CLK_ENABLE();
|
||||
|
||||
/**ADC1 GPIO Configuration
|
||||
PC0 ------> ADC1_IN10
|
||||
PC1 ------> ADC1_IN11
|
||||
PC2 ------> ADC1_IN12
|
||||
PC3 ------> ADC1_IN13
|
||||
PA4 ------> ADC1_IN4
|
||||
PA5 ------> ADC1_IN5
|
||||
PA6 ------> ADC1_IN6
|
||||
PC5 ------> ADC1_IN15
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|M0_TEMP_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* ADC1 DMA Init */
|
||||
/* ADC1 Init */
|
||||
hdma_adc1.Instance = DMA2_Stream0;
|
||||
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
|
||||
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||
hdma_adc1.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
|
||||
|
||||
/* USER CODE BEGIN ADC1_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC1_MspInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 0 */
|
||||
/* ADC2 clock enable */
|
||||
__HAL_RCC_ADC2_CLK_ENABLE();
|
||||
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
PC1 ------> ADC2_IN11
|
||||
PC2 ------> ADC2_IN12
|
||||
PC3 ------> ADC2_IN13
|
||||
PA4 ------> ADC2_IN4
|
||||
PA5 ------> ADC2_IN5
|
||||
PA6 ------> ADC2_IN6
|
||||
PC5 ------> ADC2_IN15
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|M0_TEMP_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC3)
|
||||
{
|
||||
/* USER CODE BEGIN ADC3_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC3_MspInit 0 */
|
||||
/* ADC3 clock enable */
|
||||
__HAL_RCC_ADC3_CLK_ENABLE();
|
||||
|
||||
/**ADC3 GPIO Configuration
|
||||
PC0 ------> ADC3_IN10
|
||||
PC1 ------> ADC3_IN11
|
||||
PC2 ------> ADC3_IN12
|
||||
PC3 ------> ADC3_IN13
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN ADC3_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC3_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
|
||||
{
|
||||
|
||||
if(adcHandle->Instance==ADC1)
|
||||
{
|
||||
/* USER CODE BEGIN ADC1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC1_CLK_DISABLE();
|
||||
|
||||
/**ADC1 GPIO Configuration
|
||||
PC0 ------> ADC1_IN10
|
||||
PC1 ------> ADC1_IN11
|
||||
PC2 ------> ADC1_IN12
|
||||
PC3 ------> ADC1_IN13
|
||||
PA4 ------> ADC1_IN4
|
||||
PA5 ------> ADC1_IN5
|
||||
PA6 ------> ADC1_IN6
|
||||
PC5 ------> ADC1_IN15
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|M0_TEMP_Pin);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin);
|
||||
|
||||
/* ADC1 DMA DeInit */
|
||||
HAL_DMA_DeInit(adcHandle->DMA_Handle);
|
||||
|
||||
/* ADC1 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC1:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC1:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC1_MspDeInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC2_CLK_DISABLE();
|
||||
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
PC1 ------> ADC2_IN11
|
||||
PC2 ------> ADC2_IN12
|
||||
PC3 ------> ADC2_IN13
|
||||
PA4 ------> ADC2_IN4
|
||||
PA5 ------> ADC2_IN5
|
||||
PA6 ------> ADC2_IN6
|
||||
PC5 ------> ADC2_IN15
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|M0_TEMP_Pin);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_TEMP_Pin|VBUS_S_Pin);
|
||||
|
||||
/* ADC2 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC2:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC2:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC3)
|
||||
{
|
||||
/* USER CODE BEGIN ADC3_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC3_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC3_CLK_DISABLE();
|
||||
|
||||
/**ADC3 GPIO Configuration
|
||||
PC0 ------> ADC3_IN10
|
||||
PC1 ------> ADC3_IN11
|
||||
PC2 ------> ADC3_IN12
|
||||
PC3 ------> ADC3_IN13
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin);
|
||||
|
||||
/* ADC3 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC3:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC3:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC3_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC3_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
#endif // END ADC Include
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : CAN.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of the CAN instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "can.h"
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
CAN_HandleTypeDef hcan1 = {
|
||||
.Instance = CAN1,
|
||||
.Init = {
|
||||
.Prescaler = 8,
|
||||
.Mode = CAN_MODE_NORMAL,
|
||||
.SyncJumpWidth = CAN_SJW_4TQ,
|
||||
.TimeSeg1 = CAN_BS1_16TQ,
|
||||
.TimeSeg2 = CAN_BS2_4TQ,
|
||||
.TimeTriggeredMode = DISABLE,
|
||||
.AutoBusOff = ENABLE,
|
||||
.AutoWakeUp = ENABLE,
|
||||
.AutoRetransmission = ENABLE,
|
||||
.ReceiveFifoLocked = DISABLE,
|
||||
.TransmitFifoPriority = DISABLE,
|
||||
}
|
||||
};
|
||||
|
||||
/* CAN1 init function */
|
||||
//void MX_CAN1_Init(void)
|
||||
//{
|
||||
//
|
||||
// hcan1.Instance = CAN1;
|
||||
// hcan1.Init.Prescaler = 8;
|
||||
// hcan1.Init.Mode = CAN_MODE_NORMAL;
|
||||
// hcan1.Init.SyncJumpWidth = CAN_SJW_4TQ;
|
||||
// hcan1.Init.TimeSeg1 = CAN_BS1_16TQ;
|
||||
// hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
|
||||
// hcan1.Init.TimeTriggeredMode = DISABLE;
|
||||
// hcan1.Init.AutoBusOff = ENABLE;
|
||||
// hcan1.Init.AutoWakeUp = ENABLE;
|
||||
// hcan1.Init.AutoRetransmission = ENABLE;
|
||||
// hcan1.Init.ReceiveFifoLocked = DISABLE;
|
||||
// hcan1.Init.TransmitFifoPriority = DISABLE;
|
||||
// if (HAL_CAN_Init(&hcan1) != HAL_OK)
|
||||
// {
|
||||
// _Error_Handler(__FILE__, __LINE__);
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if(canHandle->Instance==CAN1)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_MspInit 0 */
|
||||
|
||||
/* USER CODE END CAN1_MspInit 0 */
|
||||
/* CAN1 clock enable */
|
||||
__HAL_RCC_CAN1_CLK_ENABLE();
|
||||
|
||||
/**CAN1 GPIO Configuration
|
||||
PB8 ------> CAN1_RX
|
||||
PB9 ------> CAN1_TX
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* CAN1 interrupt Init */
|
||||
HAL_NVIC_SetPriority(CAN1_TX_IRQn, 9, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
|
||||
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 9, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
|
||||
HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 9, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
|
||||
HAL_NVIC_SetPriority(CAN1_SCE_IRQn, 9, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn);
|
||||
/* USER CODE BEGIN CAN1_MspInit 1 */
|
||||
|
||||
/* USER CODE END CAN1_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
|
||||
{
|
||||
|
||||
if(canHandle->Instance==CAN1)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END CAN1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_CAN1_CLK_DISABLE();
|
||||
|
||||
/**CAN1 GPIO Configuration
|
||||
PB8 ------> CAN1_RX
|
||||
PB9 ------> CAN1_TX
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9);
|
||||
|
||||
/* CAN1 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(CAN1_TX_IRQn);
|
||||
HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
|
||||
HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
|
||||
HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn);
|
||||
/* USER CODE BEGIN CAN1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END CAN1_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : dma.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of all the requested memory to memory DMA transfers.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "dma.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Configure DMA */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* Enable DMA controller clock
|
||||
*/
|
||||
void MX_DMA_Init(void)
|
||||
{
|
||||
/* DMA controller clock enable */
|
||||
__HAL_RCC_DMA1_CLK_ENABLE();
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
|
||||
/* DMA interrupt init */
|
||||
/* DMA1_Stream0_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 4, 0); // SPI RX - must have lower priority than SPI TX
|
||||
// and higher priority than the control loop handler
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
|
||||
/* DMA1_Stream2_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
|
||||
/* DMA1_Stream4_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
|
||||
/* DMA1_Stream5_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
|
||||
/* DMA1_Stream6_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
|
||||
/* DMA1_Stream7_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 3, 0); // SPI TX - must have higher priority than SPI RX
|
||||
// and higher priority than the control loop handler
|
||||
HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
|
||||
/* DMA2_Stream0_IRQn interrupt configuration */
|
||||
// Dear STM, no we _don't_ want to fire an interrupt for this DMA
|
||||
// (it's not possible to deselect this in CubeMX)
|
||||
//HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
|
||||
//HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,177 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : freertos.c
|
||||
* Description : Code for freertos applications
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "main.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Variables */
|
||||
/* USER CODE END Variables */
|
||||
osThreadId defaultTaskHandle;
|
||||
const uint32_t stack_size_default_task = 2048; // Bytes
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN FunctionPrototypes */
|
||||
|
||||
/* USER CODE END FunctionPrototypes */
|
||||
|
||||
void StartDefaultTask(void * argument);
|
||||
|
||||
extern void MX_USB_DEVICE_Init(void);
|
||||
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
|
||||
|
||||
/* Hook prototypes */
|
||||
void vApplicationIdleHook(void);
|
||||
void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName);
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
__weak void vApplicationIdleHook( void )
|
||||
{
|
||||
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
|
||||
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
|
||||
task. It is essential that code added to this hook function never attempts
|
||||
to block in any way (for example, call xQueueReceive() with a block time
|
||||
specified, or call vTaskDelay()). If the application makes use of the
|
||||
vTaskDelete() API function (as this demo application does) then it is also
|
||||
important that vApplicationIdleHook() is permitted to return to its calling
|
||||
function, because it is the responsibility of the idle task to clean up
|
||||
memory allocated by the kernel to any task that has since been deleted. */
|
||||
}
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
__weak void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName)
|
||||
{
|
||||
/* Run time stack overflow checking is performed if
|
||||
configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is
|
||||
called if a stack overflow is detected. */
|
||||
}
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
* @brief FreeRTOS initialization
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void MX_FREERTOS_Init(void) {
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* USER CODE BEGIN RTOS_MUTEX */
|
||||
/* add mutexes, ... */
|
||||
/* USER CODE END RTOS_MUTEX */
|
||||
|
||||
/* USER CODE BEGIN RTOS_SEMAPHORES */
|
||||
/* USER CODE END RTOS_SEMAPHORES */
|
||||
|
||||
/* USER CODE BEGIN RTOS_TIMERS */
|
||||
/* start timers, add new ones, ... */
|
||||
/* USER CODE END RTOS_TIMERS */
|
||||
|
||||
/* Create the thread(s) */
|
||||
/* definition and creation of defaultTask */
|
||||
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, stack_size_default_task / sizeof(StackType_t));
|
||||
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
|
||||
|
||||
/* USER CODE BEGIN RTOS_THREADS */
|
||||
|
||||
/* USER CODE END RTOS_THREADS */
|
||||
|
||||
/* USER CODE BEGIN RTOS_QUEUES */
|
||||
/* add queues, ... */
|
||||
/* USER CODE END RTOS_QUEUES */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Header_StartDefaultTask */
|
||||
/**
|
||||
* @brief Function implementing the defaultTask thread.
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
/* USER CODE END Header_StartDefaultTask */
|
||||
void StartDefaultTask(void * argument)
|
||||
{
|
||||
/* init code for USB_DEVICE */
|
||||
MX_USB_DEVICE_Init();
|
||||
|
||||
/* USER CODE BEGIN StartDefaultTask */
|
||||
|
||||
/* USER CODE END StartDefaultTask */
|
||||
}
|
||||
|
||||
/* Private application code --------------------------------------------------*/
|
||||
/* USER CODE BEGIN Application */
|
||||
|
||||
/* USER CODE END Application */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : gpio.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of all used GPIO pins.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "gpio.h"
|
||||
/* USER CODE BEGIN 0 */
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 1 \
|
||||
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 2
|
||||
#include "prev_board_ver/gpio_V3_2.c"
|
||||
#elif HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 3 \
|
||||
|| HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR == 4
|
||||
#include "prev_board_ver/gpio_V3_4.c"
|
||||
#else
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Configure GPIO */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/** Configure pins as
|
||||
* Analog
|
||||
* Input
|
||||
* Output
|
||||
* EVENT_OUT
|
||||
* EXTI
|
||||
*/
|
||||
void MX_GPIO_Init(void)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
|
||||
/* GPIO Ports Clock Enable */
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOC, M0_nCS_Pin|M1_nCS_Pin, GPIO_PIN_SET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pins : PCPin PCPin */
|
||||
GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : PCPin PCPin PCPin */
|
||||
GPIO_InitStruct.Pin = M1_ENC_Z_Pin|GPIO_5_Pin|M0_ENC_Z_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = EN_GATE_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(EN_GATE_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = nFAULT_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
#endif // End GPIO Include
|
||||
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : I2C.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of the I2C instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "i2c.h"
|
||||
|
||||
#include "gpio.h"
|
||||
#include "dma.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
I2C_HandleTypeDef hi2c1;
|
||||
DMA_HandleTypeDef hdma_i2c1_rx;
|
||||
DMA_HandleTypeDef hdma_i2c1_tx;
|
||||
|
||||
/* I2C1 init function */
|
||||
void MX_I2C1_Init(uint8_t addr)
|
||||
{
|
||||
|
||||
hi2c1.Instance = I2C1;
|
||||
hi2c1.Init.ClockSpeed = 100000;
|
||||
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
|
||||
hi2c1.Init.OwnAddress1 = addr << 1;
|
||||
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
|
||||
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
|
||||
hi2c1.Init.OwnAddress2 = 0;
|
||||
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
|
||||
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
|
||||
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
|
||||
{
|
||||
|
||||
if(i2cHandle->Instance==I2C1)
|
||||
{
|
||||
/* USER CODE BEGIN I2C1_MspInit 0 */
|
||||
|
||||
/* USER CODE END I2C1_MspInit 0 */
|
||||
|
||||
/* I2C1 clock enable */
|
||||
__HAL_RCC_I2C1_CLK_ENABLE();
|
||||
|
||||
/* I2C1 DMA Init */
|
||||
/* I2C1_RX Init */
|
||||
hdma_i2c1_rx.Instance = DMA1_Stream0;
|
||||
hdma_i2c1_rx.Init.Channel = DMA_CHANNEL_1;
|
||||
hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_i2c1_rx.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_i2c1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c1_rx);
|
||||
|
||||
/* I2C1_TX Init */
|
||||
hdma_i2c1_tx.Instance = DMA1_Stream6;
|
||||
hdma_i2c1_tx.Init.Channel = DMA_CHANNEL_1;
|
||||
hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_i2c1_tx.Init.Mode = DMA_NORMAL;
|
||||
hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_i2c1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c1_tx);
|
||||
|
||||
/* I2C1 interrupt Init */
|
||||
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 9, 0);
|
||||
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 9, 0);
|
||||
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
|
||||
/* USER CODE BEGIN I2C1_MspInit 1 */
|
||||
|
||||
/* USER CODE END I2C1_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
|
||||
{
|
||||
|
||||
if(i2cHandle->Instance==I2C1)
|
||||
{
|
||||
/* USER CODE BEGIN I2C1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END I2C1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_I2C1_CLK_DISABLE();
|
||||
|
||||
/**I2C1 GPIO Configuration
|
||||
PB8 ------> I2C1_SCL
|
||||
PB9 ------> I2C1_SDA
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9);
|
||||
|
||||
/* I2C1 DMA DeInit */
|
||||
HAL_DMA_DeInit(i2cHandle->hdmarx);
|
||||
HAL_DMA_DeInit(i2cHandle->hdmatx);
|
||||
|
||||
/* I2C1 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
|
||||
HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
|
||||
/* USER CODE BEGIN I2C1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END I2C1_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,280 @@
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.c
|
||||
* @brief : Main program body
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "adc.h"
|
||||
#include "can.h"
|
||||
#include "dma.h"
|
||||
#include "spi.h"
|
||||
#include "tim.h"
|
||||
#include "usart.h"
|
||||
#include "usb_device.h"
|
||||
#include "gpio.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void SystemClock_Config(void);
|
||||
void MX_FREERTOS_Init(void);
|
||||
|
||||
/* USER CODE BEGIN PFP */
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/**
|
||||
* @brief The application entry point.
|
||||
* => Nope. We provide our own.
|
||||
*
|
||||
* @retval None
|
||||
*/
|
||||
//int main(void)
|
||||
//{
|
||||
#if 0
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* MCU Configuration----------------------------------------------------------*/
|
||||
|
||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||||
HAL_Init();
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* Configure the system clock */
|
||||
SystemClock_Config();
|
||||
|
||||
/* USER CODE BEGIN SysInit */
|
||||
|
||||
/* USER CODE END SysInit */
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
MX_DMA_Init();
|
||||
MX_ADC1_Init();
|
||||
MX_ADC2_Init();
|
||||
// MX_CAN1_Init(); // CAN or I2C called in main.cpp instead
|
||||
MX_TIM1_Init();
|
||||
MX_TIM8_Init();
|
||||
MX_TIM3_Init();
|
||||
MX_TIM4_Init();
|
||||
MX_SPI3_Init();
|
||||
MX_ADC3_Init();
|
||||
MX_TIM2_Init();
|
||||
MX_UART4_Init();
|
||||
MX_TIM5_Init();
|
||||
MX_TIM13_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Call init function for freertos objects (in freertos.c) */
|
||||
MX_FREERTOS_Init();
|
||||
|
||||
/* Start scheduler */
|
||||
osKernelStart();
|
||||
|
||||
/* We should never get here as control is now taken by the scheduler */
|
||||
|
||||
/* Infinite loop */
|
||||
/* USER CODE BEGIN WHILE */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct;
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct;
|
||||
|
||||
/**Configure the main internal regulator output voltage
|
||||
*/
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
|
||||
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||||
|
||||
/**Initializes the CPU, AHB and APB busses clocks
|
||||
*/
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
|
||||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||||
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||||
RCC_OscInitStruct.PLL.PLLM = 4;
|
||||
RCC_OscInitStruct.PLL.PLLN = 168;
|
||||
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
||||
RCC_OscInitStruct.PLL.PLLQ = 7;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Initializes the CPU, AHB and APB busses clocks
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
|
||||
|
||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure the Systick interrupt time
|
||||
*/
|
||||
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
|
||||
|
||||
/**Configure the Systick
|
||||
*/
|
||||
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
* @brief Period elapsed callback in non blocking mode
|
||||
* @note This function is called when TIM14 interrupt took place, inside
|
||||
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
|
||||
* a global variable "uwTick" used as application time base.
|
||||
* @param htim : TIM handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
|
||||
{
|
||||
/* USER CODE BEGIN Callback 0 */
|
||||
|
||||
/* USER CODE END Callback 0 */
|
||||
if (htim->Instance == TIM14) {
|
||||
HAL_IncTick();
|
||||
}
|
||||
/* USER CODE BEGIN Callback 1 */
|
||||
|
||||
/* USER CODE END Callback 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function is executed in case of error occurrence.
|
||||
* @param file: The file name as string.
|
||||
* @param line: The line in file as a number.
|
||||
* @retval None
|
||||
*/
|
||||
void _Error_Handler(char *file, int line)
|
||||
{
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
while(1) // TODO: do something more useful
|
||||
{
|
||||
}
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
}
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief Reports the name of the source file and the source line number
|
||||
* where the assert_param error has occurred.
|
||||
* @param file: pointer to the source file name
|
||||
* @param line: assert_param error line source number
|
||||
* @retval None
|
||||
*/
|
||||
void assert_failed(uint8_t* file, uint32_t line)
|
||||
{
|
||||
/* USER CODE BEGIN 6 */
|
||||
/* User can add his own implementation to report the file name and line number,
|
||||
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
|
||||
/* USER CODE END 6 */
|
||||
}
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,390 @@
|
||||
|
||||
ADC_HandleTypeDef hadc1;
|
||||
ADC_HandleTypeDef hadc2;
|
||||
ADC_HandleTypeDef hadc3;
|
||||
DMA_HandleTypeDef hdma_adc1;
|
||||
|
||||
/* ADC1 init function */
|
||||
void MX_ADC1_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc1.Instance = ADC1;
|
||||
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc1.Init.ScanConvMode = DISABLE;
|
||||
hadc1.Init.ContinuousConvMode = DISABLE;
|
||||
hadc1.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
|
||||
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
|
||||
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc1.Init.NbrOfConversion = 1;
|
||||
hadc1.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_0;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_0;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* ADC2 init function */
|
||||
void MX_ADC2_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc2.Instance = ADC2;
|
||||
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc2.Init.ScanConvMode = DISABLE;
|
||||
hadc2.Init.ContinuousConvMode = DISABLE;
|
||||
hadc2.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
|
||||
hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
|
||||
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc2.Init.NbrOfConversion = 1;
|
||||
hadc2.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc2) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_13;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_10;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* ADC3 init function */
|
||||
void MX_ADC3_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc3.Instance = ADC3;
|
||||
hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc3.Init.ScanConvMode = DISABLE;
|
||||
hadc3.Init.ContinuousConvMode = DISABLE;
|
||||
hadc3.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
|
||||
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
|
||||
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc3.Init.NbrOfConversion = 1;
|
||||
hadc3.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_12;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_11;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc3, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if(adcHandle->Instance==ADC1)
|
||||
{
|
||||
/* USER CODE BEGIN ADC1_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC1_MspInit 0 */
|
||||
/* ADC1 clock enable */
|
||||
__HAL_RCC_ADC1_CLK_ENABLE();
|
||||
|
||||
/**ADC1 GPIO Configuration
|
||||
PC0 ------> ADC1_IN10
|
||||
PC1 ------> ADC1_IN11
|
||||
PC2 ------> ADC1_IN12
|
||||
PC3 ------> ADC1_IN13
|
||||
PA0-WKUP ------> ADC1_IN0
|
||||
PA1 ------> ADC1_IN1
|
||||
PA2 ------> ADC1_IN2
|
||||
PA6 ------> ADC1_IN6
|
||||
PC4 ------> ADC1_IN14
|
||||
PC5 ------> ADC1_IN15
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* ADC1 DMA Init */
|
||||
/* ADC1 Init */
|
||||
hdma_adc1.Instance = DMA2_Stream0;
|
||||
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
|
||||
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||
hdma_adc1.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
|
||||
|
||||
/* USER CODE BEGIN ADC1_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC1_MspInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 0 */
|
||||
/* ADC2 clock enable */
|
||||
__HAL_RCC_ADC2_CLK_ENABLE();
|
||||
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
PC1 ------> ADC2_IN11
|
||||
PC2 ------> ADC2_IN12
|
||||
PC3 ------> ADC2_IN13
|
||||
PA0-WKUP ------> ADC2_IN0
|
||||
PA1 ------> ADC2_IN1
|
||||
PA2 ------> ADC2_IN2
|
||||
PA6 ------> ADC2_IN6
|
||||
PC4 ------> ADC2_IN14
|
||||
PC5 ------> ADC2_IN15
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC3)
|
||||
{
|
||||
/* USER CODE BEGIN ADC3_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC3_MspInit 0 */
|
||||
/* ADC3 clock enable */
|
||||
__HAL_RCC_ADC3_CLK_ENABLE();
|
||||
|
||||
/**ADC3 GPIO Configuration
|
||||
PC0 ------> ADC3_IN10
|
||||
PC1 ------> ADC3_IN11
|
||||
PC2 ------> ADC3_IN12
|
||||
PC3 ------> ADC3_IN13
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN ADC3_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC3_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
|
||||
{
|
||||
|
||||
if(adcHandle->Instance==ADC1)
|
||||
{
|
||||
/* USER CODE BEGIN ADC1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC1_CLK_DISABLE();
|
||||
|
||||
/**ADC1 GPIO Configuration
|
||||
PC0 ------> ADC1_IN10
|
||||
PC1 ------> ADC1_IN11
|
||||
PC2 ------> ADC1_IN12
|
||||
PC3 ------> ADC1_IN13
|
||||
PA0-WKUP ------> ADC1_IN0
|
||||
PA1 ------> ADC1_IN1
|
||||
PA2 ------> ADC1_IN2
|
||||
PA6 ------> ADC1_IN6
|
||||
PC4 ------> ADC1_IN14
|
||||
PC5 ------> ADC1_IN15
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin);
|
||||
|
||||
/* ADC1 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC1:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC1:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC1_MspDeInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC2_CLK_DISABLE();
|
||||
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
PC1 ------> ADC2_IN11
|
||||
PC2 ------> ADC2_IN12
|
||||
PC3 ------> ADC2_IN13
|
||||
PA0-WKUP ------> ADC2_IN0
|
||||
PA1 ------> ADC2_IN1
|
||||
PA2 ------> ADC2_IN2
|
||||
PA6 ------> ADC2_IN6
|
||||
PC4 ------> ADC2_IN14
|
||||
PC5 ------> ADC2_IN15
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, VBUS_S_Pin|M1_TEMP_Pin|AUX_I_Pin|AUX_V_Pin);
|
||||
|
||||
/* ADC2 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC2:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC2:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC3)
|
||||
{
|
||||
/* USER CODE BEGIN ADC3_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC3_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC3_CLK_DISABLE();
|
||||
|
||||
/**ADC3 GPIO Configuration
|
||||
PC0 ------> ADC3_IN10
|
||||
PC1 ------> ADC3_IN11
|
||||
PC2 ------> ADC3_IN12
|
||||
PC3 ------> ADC3_IN13
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin);
|
||||
|
||||
/* ADC3 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC3:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC3:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC3_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC3_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
|
||||
ADC_HandleTypeDef hadc1;
|
||||
ADC_HandleTypeDef hadc2;
|
||||
ADC_HandleTypeDef hadc3;
|
||||
DMA_HandleTypeDef hdma_adc1;
|
||||
|
||||
/* ADC1 init function */
|
||||
void MX_ADC1_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc1.Instance = ADC1;
|
||||
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc1.Init.ScanConvMode = DISABLE;
|
||||
hadc1.Init.ContinuousConvMode = DISABLE;
|
||||
hadc1.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
|
||||
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
|
||||
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc1.Init.NbrOfConversion = 1;
|
||||
hadc1.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_6;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_6;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* ADC2 init function */
|
||||
void MX_ADC2_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc2.Instance = ADC2;
|
||||
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc2.Init.ScanConvMode = DISABLE;
|
||||
hadc2.Init.ContinuousConvMode = DISABLE;
|
||||
hadc2.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
|
||||
hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
|
||||
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc2.Init.NbrOfConversion = 1;
|
||||
hadc2.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc2) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_13;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_10;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc2, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* ADC3 init function */
|
||||
void MX_ADC3_Init(void)
|
||||
{
|
||||
ADC_ChannelConfTypeDef sConfig;
|
||||
ADC_InjectionConfTypeDef sConfigInjected;
|
||||
|
||||
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
|
||||
*/
|
||||
hadc3.Instance = ADC3;
|
||||
hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
|
||||
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
|
||||
hadc3.Init.ScanConvMode = DISABLE;
|
||||
hadc3.Init.ContinuousConvMode = DISABLE;
|
||||
hadc3.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
|
||||
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
|
||||
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc3.Init.NbrOfConversion = 1;
|
||||
hadc3.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
if (HAL_ADC_Init(&hadc3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
|
||||
*/
|
||||
sConfig.Channel = ADC_CHANNEL_12;
|
||||
sConfig.Rank = 1;
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
/**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
|
||||
*/
|
||||
sConfigInjected.InjectedChannel = ADC_CHANNEL_11;
|
||||
sConfigInjected.InjectedRank = 1;
|
||||
sConfigInjected.InjectedNbrOfConversion = 1;
|
||||
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_3CYCLES;
|
||||
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
|
||||
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_TRGO;
|
||||
sConfigInjected.AutoInjectedConv = DISABLE;
|
||||
sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
|
||||
sConfigInjected.InjectedOffset = 0;
|
||||
if (HAL_ADCEx_InjectedConfigChannel(&hadc3, &sConfigInjected) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if(adcHandle->Instance==ADC1)
|
||||
{
|
||||
/* USER CODE BEGIN ADC1_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC1_MspInit 0 */
|
||||
/* ADC1 clock enable */
|
||||
__HAL_RCC_ADC1_CLK_ENABLE();
|
||||
|
||||
/**ADC1 GPIO Configuration
|
||||
PC0 ------> ADC1_IN10
|
||||
PC1 ------> ADC1_IN11
|
||||
PC2 ------> ADC1_IN12
|
||||
PC3 ------> ADC1_IN13
|
||||
PA4 ------> ADC1_IN4
|
||||
PA5 ------> ADC1_IN5
|
||||
PA6 ------> ADC1_IN6
|
||||
PC4 ------> ADC1_IN14
|
||||
PC5 ------> ADC1_IN15
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* ADC1 DMA Init */
|
||||
/* ADC1 Init */
|
||||
hdma_adc1.Instance = DMA2_Stream0;
|
||||
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
|
||||
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||
hdma_adc1.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
|
||||
|
||||
/* USER CODE BEGIN ADC1_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC1_MspInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 0 */
|
||||
/* ADC2 clock enable */
|
||||
__HAL_RCC_ADC2_CLK_ENABLE();
|
||||
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
PC1 ------> ADC2_IN11
|
||||
PC2 ------> ADC2_IN12
|
||||
PC3 ------> ADC2_IN13
|
||||
PA4 ------> ADC2_IN4
|
||||
PA5 ------> ADC2_IN5
|
||||
PA6 ------> ADC2_IN6
|
||||
PC4 ------> ADC2_IN14
|
||||
PC5 ------> ADC2_IN15
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC3)
|
||||
{
|
||||
/* USER CODE BEGIN ADC3_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC3_MspInit 0 */
|
||||
/* ADC3 clock enable */
|
||||
__HAL_RCC_ADC3_CLK_ENABLE();
|
||||
|
||||
/**ADC3 GPIO Configuration
|
||||
PC0 ------> ADC3_IN10
|
||||
PC1 ------> ADC3_IN11
|
||||
PC2 ------> ADC3_IN12
|
||||
PC3 ------> ADC3_IN13
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN ADC3_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC3_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
|
||||
{
|
||||
|
||||
if(adcHandle->Instance==ADC1)
|
||||
{
|
||||
/* USER CODE BEGIN ADC1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC1_CLK_DISABLE();
|
||||
|
||||
/**ADC1 GPIO Configuration
|
||||
PC0 ------> ADC1_IN10
|
||||
PC1 ------> ADC1_IN11
|
||||
PC2 ------> ADC1_IN12
|
||||
PC3 ------> ADC1_IN13
|
||||
PA4 ------> ADC1_IN4
|
||||
PA5 ------> ADC1_IN5
|
||||
PA6 ------> ADC1_IN6
|
||||
PC4 ------> ADC1_IN14
|
||||
PC5 ------> ADC1_IN15
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin);
|
||||
|
||||
/* ADC1 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC1:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC1:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC1_MspDeInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC2_CLK_DISABLE();
|
||||
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
PC1 ------> ADC2_IN11
|
||||
PC2 ------> ADC2_IN12
|
||||
PC3 ------> ADC2_IN13
|
||||
PA4 ------> ADC2_IN4
|
||||
PA5 ------> ADC2_IN5
|
||||
PA6 ------> ADC2_IN6
|
||||
PC4 ------> ADC2_IN14
|
||||
PC5 ------> ADC2_IN15
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin
|
||||
|AUX_TEMP_Pin|M0_TEMP_Pin);
|
||||
|
||||
HAL_GPIO_DeInit(GPIOA, M1_TEMP_Pin|AUX_I_Pin|VBUS_S_Pin);
|
||||
|
||||
/* ADC2 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC2:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC2:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 1 */
|
||||
}
|
||||
else if(adcHandle->Instance==ADC3)
|
||||
{
|
||||
/* USER CODE BEGIN ADC3_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC3_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC3_CLK_DISABLE();
|
||||
|
||||
/**ADC3 GPIO Configuration
|
||||
PC0 ------> ADC3_IN10
|
||||
PC1 ------> ADC3_IN11
|
||||
PC2 ------> ADC3_IN12
|
||||
PC3 ------> ADC3_IN13
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, M0_IB_Pin|M0_IC_Pin|M1_IC_Pin|M1_IB_Pin);
|
||||
|
||||
/* ADC3 interrupt Deinit */
|
||||
/* USER CODE BEGIN ADC3:ADC_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "ADC_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(ADC_IRQn); */
|
||||
/* USER CODE END ADC3:ADC_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN ADC3_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC3_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/** Configure pins as
|
||||
* Analog
|
||||
* Input
|
||||
* Output
|
||||
* EVENT_OUT
|
||||
* EXTI
|
||||
*/
|
||||
void MX_GPIO_Init(void)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
|
||||
/* GPIO Ports Clock Enable */
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOC, M0_nCS_Pin|M1_nCS_Pin, GPIO_PIN_SET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOC, M1_DC_CAL_Pin|M0_DC_CAL_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pins : PCPin PCPin PCPin PCPin */
|
||||
GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin|M1_DC_CAL_Pin|M0_DC_CAL_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : PAPin PAPin */
|
||||
GPIO_InitStruct.Pin = GPIO_4_Pin|GPIO_2_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = GPIO_3_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = GPIO_1_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
HAL_GPIO_Init(GPIO_1_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = EN_GATE_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(EN_GATE_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = M0_ENC_Z_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(M0_ENC_Z_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = nFAULT_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = M1_ENC_Z_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(M1_ENC_Z_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/* EXTI interrupt init*/
|
||||
HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
|
||||
|
||||
HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/** Configure pins as
|
||||
* Analog
|
||||
* Input
|
||||
* Output
|
||||
* EVENT_OUT
|
||||
* EXTI
|
||||
*/
|
||||
void MX_GPIO_Init(void)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
|
||||
/* GPIO Ports Clock Enable */
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOC, M0_nCS_Pin|M1_nCS_Pin, GPIO_PIN_SET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOC, M1_DC_CAL_Pin|M0_DC_CAL_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pins : PCPin PCPin PCPin PCPin */
|
||||
GPIO_InitStruct.Pin = M0_nCS_Pin|M1_nCS_Pin|M1_DC_CAL_Pin|M0_DC_CAL_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = GPIO_3_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
|
||||
HAL_GPIO_Init(GPIO_3_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : PAPin PAPin */
|
||||
GPIO_InitStruct.Pin = GPIO_4_Pin|M0_ENC_Z_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : PBPin PBPin */
|
||||
GPIO_InitStruct.Pin = GPIO_5_Pin|M1_ENC_Z_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = EN_GATE_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(EN_GATE_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = nFAULT_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(nFAULT_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/* EXTI interrupt init*/
|
||||
HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : SPI.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of the SPI instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "spi.h"
|
||||
|
||||
#include "gpio.h"
|
||||
#include "dma.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
SPI_HandleTypeDef hspi3;
|
||||
DMA_HandleTypeDef hdma_spi3_tx;
|
||||
DMA_HandleTypeDef hdma_spi3_rx;
|
||||
|
||||
/* SPI3 init function */
|
||||
void MX_SPI3_Init(void)
|
||||
{
|
||||
|
||||
hspi3.Instance = SPI3;
|
||||
hspi3.Init.Mode = SPI_MODE_MASTER;
|
||||
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
hspi3.Init.DataSize = SPI_DATASIZE_16BIT;
|
||||
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
|
||||
hspi3.Init.NSS = SPI_NSS_SOFT;
|
||||
hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
|
||||
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
hspi3.Init.CRCPolynomial = 10;
|
||||
if (HAL_SPI_Init(&hspi3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if(spiHandle->Instance==SPI3)
|
||||
{
|
||||
/* USER CODE BEGIN SPI3_MspInit 0 */
|
||||
|
||||
/* USER CODE END SPI3_MspInit 0 */
|
||||
/* SPI3 clock enable */
|
||||
__HAL_RCC_SPI3_CLK_ENABLE();
|
||||
|
||||
/**SPI3 GPIO Configuration
|
||||
PC10 ------> SPI3_SCK
|
||||
PC11 ------> SPI3_MISO
|
||||
PC12 ------> SPI3_MOSI
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLDOWN; // Idle clock and MOSI low.
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
// MISO pull-up required for disconnect detection on SPI encoders with even parity
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_11;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/* SPI3 DMA Init */
|
||||
/* SPI3_TX Init */
|
||||
hdma_spi3_tx.Instance = DMA1_Stream7;
|
||||
hdma_spi3_tx.Init.Channel = DMA_CHANNEL_0;
|
||||
hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_spi3_tx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
|
||||
if(spiHandle->Init.DataSize == SPI_DATASIZE_8BIT){
|
||||
hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
} else {
|
||||
hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||
hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||
}
|
||||
|
||||
hdma_spi3_tx.Init.Mode = DMA_NORMAL;
|
||||
hdma_spi3_tx.Init.Priority = DMA_PRIORITY_HIGH; // SPI TX must have higher priority than SPI RX
|
||||
hdma_spi3_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_spi3_tx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(spiHandle,hdmatx,hdma_spi3_tx);
|
||||
|
||||
/* SPI3_RX Init */
|
||||
hdma_spi3_rx.Instance = DMA1_Stream0;
|
||||
hdma_spi3_rx.Init.Channel = DMA_CHANNEL_0;
|
||||
hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
if (spiHandle->Init.DataSize == SPI_DATASIZE_8BIT) {
|
||||
hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
} else {
|
||||
hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||
hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||
}
|
||||
hdma_spi3_rx.Init.Mode = DMA_NORMAL;
|
||||
hdma_spi3_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
|
||||
hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_spi3_rx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(spiHandle,hdmarx,hdma_spi3_rx);
|
||||
|
||||
/* SPI3 interrupt Init */
|
||||
//HAL_NVIC_SetPriority(SPI3_IRQn, 3, 0);
|
||||
//HAL_NVIC_EnableIRQ(SPI3_IRQn);
|
||||
/* USER CODE BEGIN SPI3_MspInit 1 */
|
||||
|
||||
/* USER CODE END SPI3_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
|
||||
{
|
||||
|
||||
if(spiHandle->Instance==SPI3)
|
||||
{
|
||||
/* USER CODE BEGIN SPI3_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END SPI3_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_SPI3_CLK_DISABLE();
|
||||
|
||||
/**SPI3 GPIO Configuration
|
||||
PC10 ------> SPI3_SCK
|
||||
PC11 ------> SPI3_MISO
|
||||
PC12 ------> SPI3_MOSI
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12);
|
||||
|
||||
/* SPI3 DMA DeInit */
|
||||
HAL_DMA_DeInit(spiHandle->hdmatx);
|
||||
HAL_DMA_DeInit(spiHandle->hdmarx);
|
||||
|
||||
/* SPI3 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(SPI3_IRQn);
|
||||
/* USER CODE BEGIN SPI3_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END SPI3_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : stm32f4xx_hal_msp.c
|
||||
* Description : This file provides code for the MSP Initialization
|
||||
* and de-Initialization codes.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
extern void _Error_Handler(char *, int);
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
/**
|
||||
* Initializes the Global MSP.
|
||||
*/
|
||||
void HAL_MspInit(void)
|
||||
{
|
||||
/* USER CODE BEGIN MspInit 0 */
|
||||
|
||||
/* USER CODE END MspInit 0 */
|
||||
|
||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
|
||||
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
|
||||
|
||||
/* System interrupt init*/
|
||||
/* MemoryManagement_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
|
||||
/* BusFault_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
|
||||
/* UsageFault_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
|
||||
/* SVCall_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(SVCall_IRQn, 3, 0);
|
||||
/* DebugMonitor_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
|
||||
/* PendSV_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0);
|
||||
/* SysTick_IRQn interrupt configuration */
|
||||
HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
|
||||
|
||||
/* USER CODE BEGIN MspInit 1 */
|
||||
|
||||
/* USER CODE END MspInit 1 */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_hal_timebase_TIM.c
|
||||
* @brief HAL time base based on the hardware TIM.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "stm32f4xx_hal_tim.h"
|
||||
/** @addtogroup STM32F7xx_HAL_Examples
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup HAL_TimeBase
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
TIM_HandleTypeDef htim14;
|
||||
uint32_t uwIncrementState = 0;
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief This function configures the TIM14 as a time base source.
|
||||
* The time source is configured to have 1ms time base with a dedicated
|
||||
* Tick interrupt priority.
|
||||
* @note This function is called automatically at the beginning of program after
|
||||
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
|
||||
* @param TickPriority: Tick interrupt priorty.
|
||||
* @retval HAL status
|
||||
*/
|
||||
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
||||
{
|
||||
RCC_ClkInitTypeDef clkconfig;
|
||||
uint32_t uwTimclock = 0;
|
||||
uint32_t uwPrescalerValue = 0;
|
||||
uint32_t pFLatency;
|
||||
|
||||
/*Configure the TIM14 IRQ priority */
|
||||
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, TickPriority ,0);
|
||||
|
||||
/* Enable the TIM14 global Interrupt */
|
||||
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||
|
||||
/* Enable TIM14 clock */
|
||||
__HAL_RCC_TIM14_CLK_ENABLE();
|
||||
|
||||
/* Get clock configuration */
|
||||
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
|
||||
|
||||
/* Compute TIM14 clock */
|
||||
uwTimclock = 2*HAL_RCC_GetPCLK1Freq();
|
||||
|
||||
/* Compute the prescaler value to have TIM14 counter clock equal to 1MHz */
|
||||
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000) - 1);
|
||||
|
||||
/* Initialize TIM14 */
|
||||
htim14.Instance = TIM14;
|
||||
|
||||
/* Initialize TIMx peripheral as follow:
|
||||
+ Period = [(TIM14CLK/1000) - 1]. to have a (1/1000) s time base.
|
||||
+ Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
|
||||
+ ClockDivision = 0
|
||||
+ Counter direction = Up
|
||||
*/
|
||||
htim14.Init.Period = (1000000 / 1000) - 1;
|
||||
htim14.Init.Prescaler = uwPrescalerValue;
|
||||
htim14.Init.ClockDivision = 0;
|
||||
htim14.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
if(HAL_TIM_Base_Init(&htim14) == HAL_OK)
|
||||
{
|
||||
/* Start the TIM time Base generation in interrupt mode */
|
||||
return HAL_TIM_Base_Start_IT(&htim14);
|
||||
}
|
||||
|
||||
/* Return function status */
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspend Tick increment.
|
||||
* @note Disable the tick increment by disabling TIM14 update interrupt.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_SuspendTick(void)
|
||||
{
|
||||
/* Disable TIM14 update Interrupt */
|
||||
__HAL_TIM_DISABLE_IT(&htim14, TIM_IT_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume Tick increment.
|
||||
* @note Enable the tick increment by Enabling TIM14 update interrupt.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_ResumeTick(void)
|
||||
{
|
||||
/* Enable TIM14 Update interrupt */
|
||||
__HAL_TIM_ENABLE_IT(&htim14, TIM_IT_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,416 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f4xx_it.c
|
||||
* @brief Interrupt Service Routines.
|
||||
******************************************************************************
|
||||
*
|
||||
* COPYRIGHT(c) 2018 STMicroelectronics
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "stm32f4xx.h"
|
||||
#include "stm32f4xx_it.h"
|
||||
#include "cmsis_os.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
#include <Drivers/STM32/stm32_system.h>
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/* External variables --------------------------------------------------------*/
|
||||
extern PCD_HandleTypeDef hpcd_USB_OTG_FS;
|
||||
extern ADC_HandleTypeDef hadc1;
|
||||
extern ADC_HandleTypeDef hadc2;
|
||||
extern ADC_HandleTypeDef hadc3;
|
||||
extern CAN_HandleTypeDef hcan1;
|
||||
extern DMA_HandleTypeDef hdma_spi3_tx;
|
||||
extern DMA_HandleTypeDef hdma_spi3_rx;
|
||||
extern SPI_HandleTypeDef hspi3;
|
||||
extern TIM_HandleTypeDef htim5;
|
||||
extern TIM_HandleTypeDef htim8;
|
||||
extern DMA_HandleTypeDef hdma_uart4_rx;
|
||||
extern DMA_HandleTypeDef hdma_uart4_tx;
|
||||
extern DMA_HandleTypeDef hdma_usart2_rx;
|
||||
extern DMA_HandleTypeDef hdma_usart2_tx;
|
||||
extern UART_HandleTypeDef huart4;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
extern TIM_HandleTypeDef htim14;
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex-M4 Processor Interruption and Exception Handlers */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief This function handles Non maskable interrupt.
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
|
||||
COUNT_IRQ(NonMaskableInt_IRQn);
|
||||
/* USER CODE END NonMaskableInt_IRQn 0 */
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
||||
|
||||
/* USER CODE END NonMaskableInt_IRQn 1 */
|
||||
}
|
||||
|
||||
__attribute__((used))
|
||||
void get_regs(void** stack_ptr) {
|
||||
TIM1->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M0 PWM
|
||||
TIM8->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M1 PWM
|
||||
|
||||
void* volatile r0 __attribute__((unused)) = stack_ptr[0];
|
||||
void* volatile r1 __attribute__((unused)) = stack_ptr[1];
|
||||
void* volatile r2 __attribute__((unused)) = stack_ptr[2];
|
||||
void* volatile r3 __attribute__((unused)) = stack_ptr[3];
|
||||
|
||||
void* volatile r12 __attribute__((unused)) = stack_ptr[4];
|
||||
void* volatile lr __attribute__((unused)) = stack_ptr[5]; // Link register
|
||||
void* volatile pc __attribute__((unused)) = stack_ptr[6]; // Program counter
|
||||
void* volatile psr __attribute__((unused)) = stack_ptr[7]; // Program status register
|
||||
|
||||
void* volatile cfsr __attribute__((unused)) = (void*)SCB->CFSR; // Configurable fault status register
|
||||
void* volatile cpacr __attribute__((unused)) = (void*)SCB->CPACR;
|
||||
void* volatile fpccr __attribute__((unused)) = (void*)FPU->FPCCR;
|
||||
|
||||
volatile bool preciserr __attribute__((unused)) = (uint32_t)cfsr & 0x200;
|
||||
volatile bool ibuserr __attribute__((unused)) = (uint32_t)cfsr & 0x100;
|
||||
|
||||
volatile int stay_looping = 1;
|
||||
while(stay_looping);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Hard fault interrupt.
|
||||
*/
|
||||
__attribute__((naked))
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
__asm(
|
||||
" tst lr, #4 \n\t"
|
||||
" ite eq \n\t"
|
||||
" mrseq r0, msp \n\t"
|
||||
" mrsne r0, psp \n\t"
|
||||
" b get_regs \n\t"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Memory management fault.
|
||||
*/
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
|
||||
COUNT_IRQ(MemoryManagement_IRQn);
|
||||
/* USER CODE END MemoryManagement_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
|
||||
TIM1->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M0 PWM
|
||||
TIM8->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M1 PWM
|
||||
/* USER CODE END W1_MemoryManagement_IRQn 0 */
|
||||
}
|
||||
/* USER CODE BEGIN MemoryManagement_IRQn 1 */
|
||||
|
||||
/* USER CODE END MemoryManagement_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Pre-fetch fault, memory access fault.
|
||||
*/
|
||||
void BusFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN BusFault_IRQn 0 */
|
||||
COUNT_IRQ(BusFault_IRQn);
|
||||
/* USER CODE END BusFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
|
||||
TIM1->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M0 PWM
|
||||
TIM8->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M1 PWM
|
||||
/* USER CODE END W1_BusFault_IRQn 0 */
|
||||
}
|
||||
/* USER CODE BEGIN BusFault_IRQn 1 */
|
||||
|
||||
/* USER CODE END BusFault_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Undefined instruction or illegal state.
|
||||
*/
|
||||
void UsageFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN UsageFault_IRQn 0 */
|
||||
COUNT_IRQ(UsageFault_IRQn);
|
||||
/* USER CODE END UsageFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
|
||||
TIM1->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M0 PWM
|
||||
TIM8->BDTR &= ~(TIM_BDTR_AOE_Msk | TIM_BDTR_MOE_Msk); // disable M1 PWM
|
||||
/* USER CODE END W1_UsageFault_IRQn 0 */
|
||||
}
|
||||
/* USER CODE BEGIN UsageFault_IRQn 1 */
|
||||
|
||||
/* USER CODE END UsageFault_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Debug monitor.
|
||||
*/
|
||||
void DebugMon_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
|
||||
COUNT_IRQ(DebugMonitor_IRQn);
|
||||
/* USER CODE END DebugMonitor_IRQn 0 */
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
|
||||
|
||||
/* USER CODE END DebugMonitor_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System tick timer.
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||
COUNT_IRQ(SysTick_IRQn);
|
||||
/* USER CODE END SysTick_IRQn 0 */
|
||||
osSystickHandler();
|
||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 1 */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* STM32F4xx Peripheral Interrupt Handlers */
|
||||
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||
/* For the available peripheral interrupt handler names, */
|
||||
/* please refer to the startup file (startup_stm32f4xx.s). */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream0 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream0_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream0_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream0_IRQn);
|
||||
/* USER CODE END DMA1_Stream0_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_spi3_rx);
|
||||
/* USER CODE BEGIN DMA1_Stream0_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream0_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream2 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream2_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream2_IRQn);
|
||||
/* USER CODE END DMA1_Stream2_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_uart4_rx);
|
||||
/* USER CODE BEGIN DMA1_Stream2_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream2_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream4 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream4_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream4_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream4_IRQn);
|
||||
/* USER CODE END DMA1_Stream4_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_uart4_tx);
|
||||
/* USER CODE BEGIN DMA1_Stream4_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream4_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream5 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream5_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream5_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream5_IRQn);
|
||||
/* USER CODE END DMA1_Stream5_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_usart2_rx);
|
||||
/* USER CODE BEGIN DMA1_Stream5_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream5_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream6 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream6_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream6_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream6_IRQn);
|
||||
/* USER CODE END DMA1_Stream6_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_usart2_tx);
|
||||
/* USER CODE BEGIN DMA1_Stream6_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream6_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles DMA1 stream7 global interrupt.
|
||||
*/
|
||||
void DMA1_Stream7_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream7_IRQn 0 */
|
||||
COUNT_IRQ(DMA1_Stream7_IRQn);
|
||||
/* USER CODE END DMA1_Stream7_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_spi3_tx);
|
||||
/* USER CODE BEGIN DMA1_Stream7_IRQn 1 */
|
||||
|
||||
/* USER CODE END DMA1_Stream7_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles CAN1 TX interrupts.
|
||||
*/
|
||||
void CAN1_TX_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_TX_IRQn 0 */
|
||||
COUNT_IRQ(CAN1_TX_IRQn);
|
||||
/* USER CODE END CAN1_TX_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_TX_IRQn 1 */
|
||||
|
||||
/* USER CODE END CAN1_TX_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles CAN1 RX0 interrupts.
|
||||
*/
|
||||
void CAN1_RX0_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_RX0_IRQn 0 */
|
||||
COUNT_IRQ(CAN1_RX0_IRQn);
|
||||
/* USER CODE END CAN1_RX0_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_RX0_IRQn 1 */
|
||||
|
||||
/* USER CODE END CAN1_RX0_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles CAN1 RX1 interrupt.
|
||||
*/
|
||||
void CAN1_RX1_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_RX1_IRQn 0 */
|
||||
COUNT_IRQ(CAN1_RX1_IRQn);
|
||||
/* USER CODE END CAN1_RX1_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_RX1_IRQn 1 */
|
||||
|
||||
/* USER CODE END CAN1_RX1_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles CAN1 SCE interrupt.
|
||||
*/
|
||||
void CAN1_SCE_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_SCE_IRQn 0 */
|
||||
COUNT_IRQ(CAN1_SCE_IRQn);
|
||||
/* USER CODE END CAN1_SCE_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_SCE_IRQn 1 */
|
||||
|
||||
/* USER CODE END CAN1_SCE_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles USART2 global interrupt.
|
||||
*/
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_IRQn 0 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 0 */
|
||||
HAL_UART_IRQHandler(&huart2);
|
||||
/* USER CODE BEGIN USART2_IRQn 1 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles TIM8 trigger and commutation interrupts and TIM14 global interrupt.
|
||||
*/
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||
COUNT_IRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||
/* USER CODE END TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||
HAL_TIM_IRQHandler(&htim8);
|
||||
HAL_TIM_IRQHandler(&htim14);
|
||||
/* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 1 */
|
||||
|
||||
/* USER CODE END TIM8_TRG_COM_TIM14_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles SPI3 global interrupt.
|
||||
*/
|
||||
void SPI3_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SPI3_IRQn 0 */
|
||||
COUNT_IRQ(SPI3_IRQn);
|
||||
/* USER CODE END SPI3_IRQn 0 */
|
||||
HAL_SPI_IRQHandler(&hspi3);
|
||||
/* USER CODE BEGIN SPI3_IRQn 1 */
|
||||
|
||||
/* USER CODE END SPI3_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles UART4 global interrupt.
|
||||
*/
|
||||
void UART4_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN UART4_IRQn 0 */
|
||||
COUNT_IRQ(UART4_IRQn);
|
||||
/* USER CODE END UART4_IRQn 0 */
|
||||
HAL_UART_IRQHandler(&huart4);
|
||||
/* USER CODE BEGIN UART4_IRQn 1 */
|
||||
|
||||
/* USER CODE END UART4_IRQn 1 */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,763 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f4xx.c
|
||||
* @author MCD Application Team
|
||||
* @version V2.6.0
|
||||
* @date 04-November-2016
|
||||
* @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
|
||||
*
|
||||
* This file provides two functions and one global variable to be called from
|
||||
* user application:
|
||||
* - SystemInit(): This function is called at startup just after reset and
|
||||
* before branch to main program. This call is made inside
|
||||
* the "startup_stm32f4xx.s" file.
|
||||
*
|
||||
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
|
||||
* by the user application to setup the SysTick
|
||||
* timer or configure other parameters.
|
||||
*
|
||||
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
|
||||
* be called whenever the core clock is changed
|
||||
* during program execution.
|
||||
*
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f4xx_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
#include "stm32f4xx.h"
|
||||
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
|
||||
/************************* Miscellaneous Configuration ************************/
|
||||
/*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory */
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
|
||||
|| defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
/* #define DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\
|
||||
STM32F412Zx || STM32F412Vx */
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* #define DATA_IN_ExtSDRAM */
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx ||\
|
||||
STM32F479xx */
|
||||
|
||||
/*!< Uncomment the following line if you need to relocate your vector Table in
|
||||
Internal SRAM. */
|
||||
/* #define VECT_TAB_SRAM */
|
||||
#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
|
||||
This value must be a multiple of 0x200. */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
/* This variable is updated in three ways:
|
||||
1) by calling CMSIS function SystemCoreClockUpdate()
|
||||
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
|
||||
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
|
||||
Note: If you use this function to configure the system clock; then there
|
||||
is no need to call the 2 first functions listed above, since SystemCoreClock
|
||||
variable is updated automatically.
|
||||
*/
|
||||
uint32_t SystemCoreClock = 16000000;
|
||||
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
static void SystemInit_ExtMemCtl(void);
|
||||
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F4xx_System_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Setup the microcontroller system
|
||||
* Initialize the FPU setting, vector table location and External memory
|
||||
* configuration.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* FPU settings ------------------------------------------------------------*/
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
|
||||
#endif
|
||||
/* Reset the RCC clock configuration to the default reset state ------------*/
|
||||
/* Set HSION bit */
|
||||
RCC->CR |= (uint32_t)0x00000001;
|
||||
|
||||
/* Reset CFGR register */
|
||||
RCC->CFGR = 0x00000000;
|
||||
|
||||
/* Reset HSEON, CSSON and PLLON bits */
|
||||
RCC->CR &= (uint32_t)0xFEF6FFFF;
|
||||
|
||||
/* Reset PLLCFGR register */
|
||||
RCC->PLLCFGR = 0x24003010;
|
||||
|
||||
/* Reset HSEBYP bit */
|
||||
RCC->CR &= (uint32_t)0xFFFBFFFF;
|
||||
|
||||
/* Disable all interrupts */
|
||||
RCC->CIR = 0x00000000;
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
SystemInit_ExtMemCtl();
|
||||
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
|
||||
|
||||
/* Configure the Vector Table location add offset address ------------------*/
|
||||
#ifdef VECT_TAB_SRAM
|
||||
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
|
||||
#else
|
||||
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update SystemCoreClock variable according to Clock Register Values.
|
||||
* The SystemCoreClock variable contains the core clock (HCLK), it can
|
||||
* be used by the user application to setup the SysTick timer or configure
|
||||
* other parameters.
|
||||
*
|
||||
* @note Each time the core clock (HCLK) changes, this function must be called
|
||||
* to update SystemCoreClock variable value. Otherwise, any configuration
|
||||
* based on this variable will be incorrect.
|
||||
*
|
||||
* @note - The system frequency computed by this function is not the real
|
||||
* frequency in the chip. It is calculated based on the predefined
|
||||
* constant and the selected clock source:
|
||||
*
|
||||
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
|
||||
*
|
||||
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
*
|
||||
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
|
||||
*
|
||||
* (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
|
||||
* 16 MHz) but the real value may vary depending on the variations
|
||||
* in voltage and temperature.
|
||||
*
|
||||
* (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value
|
||||
* depends on the application requirements), user has to ensure that HSE_VALUE
|
||||
* is same as the real frequency of the crystal used. Otherwise, this function
|
||||
* may have wrong result.
|
||||
*
|
||||
* - The result of this function could be not correct when using fractional
|
||||
* value for HSE crystal.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
|
||||
|
||||
/* Get SYSCLK source -------------------------------------------------------*/
|
||||
tmp = RCC->CFGR & RCC_CFGR_SWS;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case 0x00: /* HSI used as system clock source */
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
case 0x04: /* HSE used as system clock source */
|
||||
SystemCoreClock = HSE_VALUE;
|
||||
break;
|
||||
case 0x08: /* PLL used as system clock source */
|
||||
|
||||
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
|
||||
SYSCLK = PLL_VCO / PLL_P
|
||||
*/
|
||||
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
|
||||
pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
|
||||
|
||||
if (pllsource != 0)
|
||||
{
|
||||
/* HSE used as PLL clock source */
|
||||
pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* HSI used as PLL clock source */
|
||||
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
|
||||
}
|
||||
|
||||
pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
|
||||
SystemCoreClock = pllvco/pllp;
|
||||
break;
|
||||
default:
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
}
|
||||
/* Compute HCLK frequency --------------------------------------------------*/
|
||||
/* Get HCLK prescaler */
|
||||
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
|
||||
/* HCLK frequency */
|
||||
SystemCoreClock >>= tmp;
|
||||
}
|
||||
|
||||
#if defined (DATA_IN_ExtSRAM) && defined (DATA_IN_ExtSDRAM)
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/**
|
||||
* @brief Setup the external memory controller.
|
||||
* Called in startup_stm32f4xx.s before jump to main.
|
||||
* This function configures the external memories (SRAM/SDRAM)
|
||||
* This SRAM/SDRAM will be used as program data memory (including heap and stack).
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
__IO uint32_t tmp = 0x00;
|
||||
|
||||
register uint32_t tmpreg = 0, timeout = 0xFFFF;
|
||||
register __IO uint32_t index;
|
||||
|
||||
/* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface clock */
|
||||
RCC->AHB1ENR |= 0x000001F8;
|
||||
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x00CCC0CC;
|
||||
GPIOD->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xAAAA0A8A;
|
||||
/* Configure PDx pins speed to 100 MHz */
|
||||
GPIOD->OSPEEDR = 0xFFFF0FCF;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00CC0CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA828A;
|
||||
/* Configure PEx pins speed to 100 MHz */
|
||||
GPIOE->OSPEEDR = 0xFFFFC3CF;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA800AAA;
|
||||
/* Configure PFx pins speed to 50 MHz */
|
||||
GPIOF->OSPEEDR = 0xAA800AAA;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOG->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0xAAAAAAAA;
|
||||
/* Configure PGx pins speed to 50 MHz */
|
||||
GPIOG->OSPEEDR = 0xAAAAAAAA;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PHx pins to FMC Alternate function */
|
||||
GPIOH->AFR[0] = 0x00C0CC00;
|
||||
GPIOH->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PHx pins in Alternate function mode */
|
||||
GPIOH->MODER = 0xAAAA08A0;
|
||||
/* Configure PHx pins speed to 50 MHz */
|
||||
GPIOH->OSPEEDR = 0xAAAA08A0;
|
||||
/* Configure PHx pins Output type to push-pull */
|
||||
GPIOH->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PHx pins */
|
||||
GPIOH->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PIx pins to FMC Alternate function */
|
||||
GPIOI->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOI->AFR[1] = 0x00000CC0;
|
||||
/* Configure PIx pins in Alternate function mode */
|
||||
GPIOI->MODER = 0x0028AAAA;
|
||||
/* Configure PIx pins speed to 50 MHz */
|
||||
GPIOI->OSPEEDR = 0x0028AAAA;
|
||||
/* Configure PIx pins Output type to push-pull */
|
||||
GPIOI->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PIx pins */
|
||||
GPIOI->PUPDR = 0x00000000;
|
||||
|
||||
/*-- FMC Configuration -------------------------------------------------------*/
|
||||
/* Enable the FMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
|
||||
FMC_Bank5_6->SDCR[0] = 0x000019E4;
|
||||
FMC_Bank5_6->SDTR[0] = 0x01115351;
|
||||
|
||||
/* SDRAM initialization sequence */
|
||||
/* Clock enable command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000011;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Delay */
|
||||
for (index = 0; index<1000; index++);
|
||||
|
||||
/* PALL command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000012;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Auto refresh command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000073;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* MRD register program */
|
||||
FMC_Bank5_6->SDCMR = 0x00046014;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Set refresh count */
|
||||
tmpreg = FMC_Bank5_6->SDRTR;
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
|
||||
|
||||
/* Disable write protection */
|
||||
tmpreg = FMC_Bank5_6->SDCR[0];
|
||||
FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
|
||||
#if defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001091;
|
||||
FMC_Bank1->BTCR[3] = 0x00110212;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F469xx || STM32F479xx */
|
||||
|
||||
(void)(tmp);
|
||||
}
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
|
||||
#elif defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
|
||||
/**
|
||||
* @brief Setup the external memory controller.
|
||||
* Called in startup_stm32f4xx.s before jump to main.
|
||||
* This function configures the external memories (SRAM/SDRAM)
|
||||
* This SRAM/SDRAM will be used as program data memory (including heap and stack).
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
__IO uint32_t tmp = 0x00;
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
|
||||
#if defined (DATA_IN_ExtSDRAM)
|
||||
register uint32_t tmpreg = 0, timeout = 0xFFFF;
|
||||
register __IO uint32_t index;
|
||||
|
||||
#if defined(STM32F446xx)
|
||||
/* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface
|
||||
clock */
|
||||
RCC->AHB1ENR |= 0x0000007D;
|
||||
#else
|
||||
/* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface
|
||||
clock */
|
||||
RCC->AHB1ENR |= 0x000001F8;
|
||||
#endif /* STM32F446xx */
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
|
||||
|
||||
#if defined(STM32F446xx)
|
||||
/* Connect PAx pins to FMC Alternate function */
|
||||
GPIOA->AFR[0] |= 0xC0000000;
|
||||
GPIOA->AFR[1] |= 0x00000000;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOA->MODER |= 0x00008000;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOA->OSPEEDR |= 0x00008000;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOA->OTYPER |= 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOA->PUPDR |= 0x00000000;
|
||||
|
||||
/* Connect PCx pins to FMC Alternate function */
|
||||
GPIOC->AFR[0] |= 0x00CC0000;
|
||||
GPIOC->AFR[1] |= 0x00000000;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOC->MODER |= 0x00000A00;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOC->OSPEEDR |= 0x00000A00;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOC->OTYPER |= 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOC->PUPDR |= 0x00000000;
|
||||
#endif /* STM32F446xx */
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x000000CC;
|
||||
GPIOD->AFR[1] = 0xCC000CCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xA02A000A;
|
||||
/* Configure PDx pins speed to 50 MHz */
|
||||
GPIOD->OSPEEDR = 0xA02A000A;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00000CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA800A;
|
||||
/* Configure PEx pins speed to 50 MHz */
|
||||
GPIOE->OSPEEDR = 0xAAAA800A;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA800AAA;
|
||||
/* Configure PFx pins speed to 50 MHz */
|
||||
GPIOF->OSPEEDR = 0xAA800AAA;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOG->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0xAAAAAAAA;
|
||||
/* Configure PGx pins speed to 50 MHz */
|
||||
GPIOG->OSPEEDR = 0xAAAAAAAA;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Connect PHx pins to FMC Alternate function */
|
||||
GPIOH->AFR[0] = 0x00C0CC00;
|
||||
GPIOH->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PHx pins in Alternate function mode */
|
||||
GPIOH->MODER = 0xAAAA08A0;
|
||||
/* Configure PHx pins speed to 50 MHz */
|
||||
GPIOH->OSPEEDR = 0xAAAA08A0;
|
||||
/* Configure PHx pins Output type to push-pull */
|
||||
GPIOH->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PHx pins */
|
||||
GPIOH->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PIx pins to FMC Alternate function */
|
||||
GPIOI->AFR[0] = 0xCCCCCCCC;
|
||||
GPIOI->AFR[1] = 0x00000CC0;
|
||||
/* Configure PIx pins in Alternate function mode */
|
||||
GPIOI->MODER = 0x0028AAAA;
|
||||
/* Configure PIx pins speed to 50 MHz */
|
||||
GPIOI->OSPEEDR = 0x0028AAAA;
|
||||
/* Configure PIx pins Output type to push-pull */
|
||||
GPIOI->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PIx pins */
|
||||
GPIOI->PUPDR = 0x00000000;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
|
||||
|
||||
/*-- FMC Configuration -------------------------------------------------------*/
|
||||
/* Enable the FMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
|
||||
/* Configure and enable SDRAM bank1 */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCR[0] = 0x00001954;
|
||||
#else
|
||||
FMC_Bank5_6->SDCR[0] = 0x000019E4;
|
||||
#endif /* STM32F446xx */
|
||||
FMC_Bank5_6->SDTR[0] = 0x01115351;
|
||||
|
||||
/* SDRAM initialization sequence */
|
||||
/* Clock enable command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000011;
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Delay */
|
||||
for (index = 0; index<1000; index++);
|
||||
|
||||
/* PALL command */
|
||||
FMC_Bank5_6->SDCMR = 0x00000012;
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Auto refresh command */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCMR = 0x000000F3;
|
||||
#else
|
||||
FMC_Bank5_6->SDCMR = 0x00000073;
|
||||
#endif /* STM32F446xx */
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* MRD register program */
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDCMR = 0x00044014;
|
||||
#else
|
||||
FMC_Bank5_6->SDCMR = 0x00046014;
|
||||
#endif /* STM32F446xx */
|
||||
timeout = 0xFFFF;
|
||||
while((tmpreg != 0) && (timeout-- > 0))
|
||||
{
|
||||
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
|
||||
}
|
||||
|
||||
/* Set refresh count */
|
||||
tmpreg = FMC_Bank5_6->SDRTR;
|
||||
#if defined(STM32F446xx)
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1));
|
||||
#else
|
||||
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
|
||||
#endif /* STM32F446xx */
|
||||
|
||||
/* Disable write protection */
|
||||
tmpreg = FMC_Bank5_6->SDCR[0];
|
||||
FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
|
||||
#endif /* DATA_IN_ExtSDRAM */
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx */
|
||||
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
|
||||
|| defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
|
||||
|| defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
|
||||
#if defined(DATA_IN_ExtSRAM)
|
||||
/*-- GPIOs Configuration -----------------------------------------------------*/
|
||||
/* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
|
||||
RCC->AHB1ENR |= 0x00000078;
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN);
|
||||
|
||||
/* Connect PDx pins to FMC Alternate function */
|
||||
GPIOD->AFR[0] = 0x00CCC0CC;
|
||||
GPIOD->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PDx pins in Alternate function mode */
|
||||
GPIOD->MODER = 0xAAAA0A8A;
|
||||
/* Configure PDx pins speed to 100 MHz */
|
||||
GPIOD->OSPEEDR = 0xFFFF0FCF;
|
||||
/* Configure PDx pins Output type to push-pull */
|
||||
GPIOD->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PDx pins */
|
||||
GPIOD->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PEx pins to FMC Alternate function */
|
||||
GPIOE->AFR[0] = 0xC00CC0CC;
|
||||
GPIOE->AFR[1] = 0xCCCCCCCC;
|
||||
/* Configure PEx pins in Alternate function mode */
|
||||
GPIOE->MODER = 0xAAAA828A;
|
||||
/* Configure PEx pins speed to 100 MHz */
|
||||
GPIOE->OSPEEDR = 0xFFFFC3CF;
|
||||
/* Configure PEx pins Output type to push-pull */
|
||||
GPIOE->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PEx pins */
|
||||
GPIOE->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PFx pins to FMC Alternate function */
|
||||
GPIOF->AFR[0] = 0x00CCCCCC;
|
||||
GPIOF->AFR[1] = 0xCCCC0000;
|
||||
/* Configure PFx pins in Alternate function mode */
|
||||
GPIOF->MODER = 0xAA000AAA;
|
||||
/* Configure PFx pins speed to 100 MHz */
|
||||
GPIOF->OSPEEDR = 0xFF000FFF;
|
||||
/* Configure PFx pins Output type to push-pull */
|
||||
GPIOF->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PFx pins */
|
||||
GPIOF->PUPDR = 0x00000000;
|
||||
|
||||
/* Connect PGx pins to FMC Alternate function */
|
||||
GPIOG->AFR[0] = 0x00CCCCCC;
|
||||
GPIOG->AFR[1] = 0x000000C0;
|
||||
/* Configure PGx pins in Alternate function mode */
|
||||
GPIOG->MODER = 0x00085AAA;
|
||||
/* Configure PGx pins speed to 100 MHz */
|
||||
GPIOG->OSPEEDR = 0x000CAFFF;
|
||||
/* Configure PGx pins Output type to push-pull */
|
||||
GPIOG->OTYPER = 0x00000000;
|
||||
/* No pull-up, pull-down for PGx pins */
|
||||
GPIOG->PUPDR = 0x00000000;
|
||||
|
||||
/*-- FMC/FSMC Configuration --------------------------------------------------*/
|
||||
/* Enable the FMC/FSMC interface clock */
|
||||
RCC->AHB3ENR |= 0x00000001;
|
||||
|
||||
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
|
||||
#if defined(STM32F469xx) || defined(STM32F479xx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FMC_Bank1->BTCR[2] = 0x00001091;
|
||||
FMC_Bank1->BTCR[3] = 0x00110212;
|
||||
FMC_Bank1E->BWTR[2] = 0x0fffffff;
|
||||
#endif /* STM32F469xx || STM32F479xx */
|
||||
#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\
|
||||
|| defined(STM32F412Zx) || defined(STM32F412Vx)
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN);
|
||||
/* Configure and enable Bank1_SRAM2 */
|
||||
FSMC_Bank1->BTCR[2] = 0x00001011;
|
||||
FSMC_Bank1->BTCR[3] = 0x00000201;
|
||||
FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF;
|
||||
#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx */
|
||||
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx ||\
|
||||
STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx */
|
||||
(void)(tmp);
|
||||
}
|
||||
#endif /* DATA_IN_ExtSRAM && DATA_IN_ExtSDRAM */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,729 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : TIM.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of the TIM instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "tim.h"
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
TIM_HandleTypeDef htim1;
|
||||
TIM_HandleTypeDef htim2;
|
||||
TIM_HandleTypeDef htim3;
|
||||
TIM_HandleTypeDef htim4;
|
||||
TIM_HandleTypeDef htim5;
|
||||
TIM_HandleTypeDef htim8;
|
||||
TIM_HandleTypeDef htim13;
|
||||
|
||||
/* TIM1 init function */
|
||||
void MX_TIM1_Init(void)
|
||||
{
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig;
|
||||
TIM_MasterConfigTypeDef sMasterConfig;
|
||||
TIM_OC_InitTypeDef sConfigOC;
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
|
||||
|
||||
htim1.Instance = TIM1;
|
||||
htim1.Init.Prescaler = 0;
|
||||
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
|
||||
htim1.Init.Period = TIM_1_8_PERIOD_CLOCKS;
|
||||
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim1.Init.RepetitionCounter = TIM_1_8_RCR;
|
||||
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (HAL_TIM_OC_Init(&htim1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM2;
|
||||
sConfigOC.Pulse = 0;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
|
||||
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sConfigOC.OCMode = TIM_OCMODE_TIMING;
|
||||
if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
|
||||
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
|
||||
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
|
||||
sBreakDeadTimeConfig.DeadTime = TIM_1_8_DEADTIME_CLOCKS;
|
||||
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
|
||||
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
|
||||
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
HAL_TIM_MspPostInit(&htim1);
|
||||
|
||||
}
|
||||
/* TIM2 init function */
|
||||
void MX_TIM2_Init(void)
|
||||
{
|
||||
TIM_MasterConfigTypeDef sMasterConfig;
|
||||
TIM_OC_InitTypeDef sConfigOC;
|
||||
|
||||
htim2.Instance = TIM2;
|
||||
htim2.Init.Prescaler = 0;
|
||||
htim2.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
|
||||
htim2.Init.Period = TIM_APB1_PERIOD_CLOCKS;
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM2;
|
||||
sConfigOC.Pulse = 0;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sConfigOC.Pulse = TIM_APB1_PERIOD_CLOCKS+1;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
HAL_TIM_MspPostInit(&htim2);
|
||||
|
||||
}
|
||||
/* TIM3 init function */
|
||||
void MX_TIM3_Init(void)
|
||||
{
|
||||
TIM_Encoder_InitTypeDef sConfig;
|
||||
TIM_MasterConfigTypeDef sMasterConfig;
|
||||
|
||||
htim3.Instance = TIM3;
|
||||
htim3.Init.Prescaler = 0;
|
||||
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim3.Init.Period = 0xffff;
|
||||
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
|
||||
sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
|
||||
sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
|
||||
sConfig.IC1Filter = 4;
|
||||
sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
|
||||
sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
|
||||
sConfig.IC2Filter = 4;
|
||||
if (HAL_TIM_Encoder_Init(&htim3, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* TIM4 init function */
|
||||
void MX_TIM4_Init(void)
|
||||
{
|
||||
TIM_Encoder_InitTypeDef sConfig;
|
||||
TIM_MasterConfigTypeDef sMasterConfig;
|
||||
|
||||
htim4.Instance = TIM4;
|
||||
htim4.Init.Prescaler = 0;
|
||||
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim4.Init.Period = 0xffff;
|
||||
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
|
||||
sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
|
||||
sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
|
||||
sConfig.IC1Filter = 4;
|
||||
sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
|
||||
sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
|
||||
sConfig.IC2Filter = 4;
|
||||
if (HAL_TIM_Encoder_Init(&htim4, &sConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* TIM5 init function */
|
||||
void MX_TIM5_Init(void)
|
||||
{
|
||||
TIM_MasterConfigTypeDef sMasterConfig;
|
||||
TIM_IC_InitTypeDef sConfigIC;
|
||||
|
||||
htim5.Instance = TIM5;
|
||||
htim5.Init.Prescaler = 0;
|
||||
htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim5.Init.Period = 0xFFFFFFFF;
|
||||
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
if (HAL_TIM_IC_Init(&htim5) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
|
||||
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
|
||||
sConfigIC.ICFilter = 15;
|
||||
if (HAL_TIM_IC_ConfigChannel(&htim5, &sConfigIC, TIM_CHANNEL_3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (HAL_TIM_IC_ConfigChannel(&htim5, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* TIM8 init function */
|
||||
void MX_TIM8_Init(void)
|
||||
{
|
||||
TIM_MasterConfigTypeDef sMasterConfig;
|
||||
TIM_OC_InitTypeDef sConfigOC;
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
|
||||
|
||||
htim8.Instance = TIM8;
|
||||
htim8.Init.Prescaler = 0;
|
||||
htim8.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED3;
|
||||
htim8.Init.Period = TIM_1_8_PERIOD_CLOCKS;
|
||||
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim8.Init.RepetitionCounter = TIM_1_8_RCR;
|
||||
if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM2;
|
||||
sConfigOC.Pulse = 0;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
|
||||
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
|
||||
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
|
||||
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
|
||||
sBreakDeadTimeConfig.DeadTime = TIM_1_8_DEADTIME_CLOCKS;
|
||||
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
|
||||
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
|
||||
if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
HAL_TIM_MspPostInit(&htim8);
|
||||
|
||||
}
|
||||
/* TIM13 init function */
|
||||
void MX_TIM13_Init(void)
|
||||
{
|
||||
|
||||
htim13.Instance = TIM13;
|
||||
htim13.Init.Prescaler = 0;
|
||||
htim13.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim13.Init.Period = (2 * TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR+1)) * ((float)TIM_APB1_CLOCK_HZ / (float)TIM_1_8_CLOCK_HZ) - 1;
|
||||
htim13.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
if (HAL_TIM_Base_Init(&htim13) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
{
|
||||
|
||||
if(tim_baseHandle->Instance==TIM1)
|
||||
{
|
||||
/* USER CODE BEGIN TIM1_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM1_MspInit 0 */
|
||||
/* TIM1 clock enable */
|
||||
__HAL_RCC_TIM1_CLK_ENABLE();
|
||||
/* USER CODE BEGIN TIM1_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM1_MspInit 1 */
|
||||
}
|
||||
else if(tim_baseHandle->Instance==TIM13)
|
||||
{
|
||||
/* USER CODE BEGIN TIM13_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM13_MspInit 0 */
|
||||
/* TIM13 clock enable */
|
||||
__HAL_RCC_TIM13_CLK_ENABLE();
|
||||
/* USER CODE BEGIN TIM13_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM13_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
|
||||
{
|
||||
|
||||
if(tim_pwmHandle->Instance==TIM2)
|
||||
{
|
||||
/* USER CODE BEGIN TIM2_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM2_MspInit 0 */
|
||||
/* TIM2 clock enable */
|
||||
__HAL_RCC_TIM2_CLK_ENABLE();
|
||||
/* USER CODE BEGIN TIM2_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM2_MspInit 1 */
|
||||
}
|
||||
else if(tim_pwmHandle->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM8_MspInit 0 */
|
||||
/* TIM8 clock enable */
|
||||
__HAL_RCC_TIM8_CLK_ENABLE();
|
||||
/* USER CODE BEGIN TIM8_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM8_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* tim_encoderHandle)
|
||||
{
|
||||
|
||||
if(tim_encoderHandle->Instance==TIM3)
|
||||
{
|
||||
/* USER CODE BEGIN TIM3_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM3_MspInit 0 */
|
||||
/* TIM3 clock enable */
|
||||
__HAL_RCC_TIM3_CLK_ENABLE();
|
||||
|
||||
/* USER CODE BEGIN TIM3_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM3_MspInit 1 */
|
||||
}
|
||||
else if(tim_encoderHandle->Instance==TIM4)
|
||||
{
|
||||
/* USER CODE BEGIN TIM4_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM4_MspInit 0 */
|
||||
/* TIM4 clock enable */
|
||||
__HAL_RCC_TIM4_CLK_ENABLE();
|
||||
|
||||
/* USER CODE BEGIN TIM4_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM4_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef* tim_icHandle)
|
||||
{
|
||||
|
||||
if(tim_icHandle->Instance==TIM5)
|
||||
{
|
||||
/* USER CODE BEGIN TIM5_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM5_MspInit 0 */
|
||||
/* TIM5 clock enable */
|
||||
__HAL_RCC_TIM5_CLK_ENABLE();
|
||||
|
||||
/* TIM5 interrupt Init */
|
||||
HAL_NVIC_SetPriority(TIM5_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM5_IRQn);
|
||||
/* USER CODE BEGIN TIM5_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM5_MspInit 1 */
|
||||
}
|
||||
}
|
||||
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if(timHandle->Instance==TIM1)
|
||||
{
|
||||
/* USER CODE BEGIN TIM1_MspPostInit 0 */
|
||||
|
||||
/* USER CODE END TIM1_MspPostInit 0 */
|
||||
/**TIM1 GPIO Configuration
|
||||
PB13 ------> TIM1_CH1N
|
||||
PB14 ------> TIM1_CH2N
|
||||
PB15 ------> TIM1_CH3N
|
||||
PA8 ------> TIM1_CH1
|
||||
PA9 ------> TIM1_CH2
|
||||
PA10 ------> TIM1_CH3
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M0_AL_Pin|M0_BL_Pin|M0_CL_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = M0_AH_Pin|M0_BH_Pin|M0_CH_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN TIM1_MspPostInit 1 */
|
||||
|
||||
/* USER CODE END TIM1_MspPostInit 1 */
|
||||
}
|
||||
else if(timHandle->Instance==TIM2)
|
||||
{
|
||||
/* USER CODE BEGIN TIM2_MspPostInit 0 */
|
||||
|
||||
/* USER CODE END TIM2_MspPostInit 0 */
|
||||
|
||||
/**TIM2 GPIO Configuration
|
||||
PB10 ------> TIM2_CH3
|
||||
PB11 ------> TIM2_CH4
|
||||
*/
|
||||
GPIO_InitStruct.Pin = AUX_L_Pin|AUX_H_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN TIM2_MspPostInit 1 */
|
||||
|
||||
/* USER CODE END TIM2_MspPostInit 1 */
|
||||
}
|
||||
else if(timHandle->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_MspPostInit 0 */
|
||||
|
||||
/* USER CODE END TIM8_MspPostInit 0 */
|
||||
|
||||
/**TIM8 GPIO Configuration
|
||||
PA7 ------> TIM8_CH1N
|
||||
PB0 ------> TIM8_CH2N
|
||||
PB1 ------> TIM8_CH3N
|
||||
PC6 ------> TIM8_CH1
|
||||
PC7 ------> TIM8_CH2
|
||||
PC8 ------> TIM8_CH3
|
||||
*/
|
||||
GPIO_InitStruct.Pin = M1_AL_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8;
|
||||
HAL_GPIO_Init(M1_AL_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = M1_BL_Pin|M1_CL_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = M1_AH_Pin|M1_BH_Pin|M1_CH_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN TIM8_MspPostInit 1 */
|
||||
|
||||
/* USER CODE END TIM8_MspPostInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
{
|
||||
|
||||
if(tim_baseHandle->Instance==TIM1)
|
||||
{
|
||||
/* USER CODE BEGIN TIM1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM1_CLK_DISABLE();
|
||||
|
||||
/* TIM1 interrupt Deinit */
|
||||
/* USER CODE BEGIN TIM1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM1_MspDeInit 1 */
|
||||
}
|
||||
else if(tim_baseHandle->Instance==TIM13)
|
||||
{
|
||||
/* USER CODE BEGIN TIM13_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM13_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM13_CLK_DISABLE();
|
||||
|
||||
/* TIM13 interrupt Deinit */
|
||||
/* USER CODE BEGIN TIM13:TIM8_UP_TIM13_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "TIM8_UP_TIM13_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(TIM8_UP_TIM13_IRQn); */
|
||||
/* USER CODE END TIM13:TIM8_UP_TIM13_IRQn disable */
|
||||
|
||||
/* USER CODE BEGIN TIM13_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM13_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
|
||||
{
|
||||
|
||||
if(tim_pwmHandle->Instance==TIM2)
|
||||
{
|
||||
/* USER CODE BEGIN TIM2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM2_CLK_DISABLE();
|
||||
/* USER CODE BEGIN TIM2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM2_MspDeInit 1 */
|
||||
}
|
||||
else if(tim_pwmHandle->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM8_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM8_CLK_DISABLE();
|
||||
|
||||
/* TIM8 interrupt Deinit */
|
||||
/* USER CODE BEGIN TIM8:TIM8_UP_TIM13_IRQn disable */
|
||||
/**
|
||||
* Uncomment the line below to disable the "TIM8_UP_TIM13_IRQn" interrupt
|
||||
* Be aware, disabling shared interrupt may affect other IPs
|
||||
*/
|
||||
/* HAL_NVIC_DisableIRQ(TIM8_UP_TIM13_IRQn); */
|
||||
/* USER CODE END TIM8:TIM8_UP_TIM13_IRQn disable */
|
||||
/* USER CODE BEGIN TIM8_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM8_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_Encoder_MspDeInit(TIM_HandleTypeDef* tim_encoderHandle)
|
||||
{
|
||||
|
||||
if(tim_encoderHandle->Instance==TIM3)
|
||||
{
|
||||
/* USER CODE BEGIN TIM3_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM3_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM3_CLK_DISABLE();
|
||||
|
||||
/**TIM3 GPIO Configuration
|
||||
PB4 ------> TIM3_CH1
|
||||
PB5 ------> TIM3_CH2
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, M0_ENC_A_Pin|M0_ENC_B_Pin);
|
||||
|
||||
/* USER CODE BEGIN TIM3_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM3_MspDeInit 1 */
|
||||
}
|
||||
else if(tim_encoderHandle->Instance==TIM4)
|
||||
{
|
||||
/* USER CODE BEGIN TIM4_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM4_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM4_CLK_DISABLE();
|
||||
|
||||
/**TIM4 GPIO Configuration
|
||||
PB6 ------> TIM4_CH1
|
||||
PB7 ------> TIM4_CH2
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, M1_ENC_A_Pin|M1_ENC_B_Pin);
|
||||
|
||||
/* USER CODE BEGIN TIM4_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM4_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef* tim_icHandle)
|
||||
{
|
||||
|
||||
if(tim_icHandle->Instance==TIM5)
|
||||
{
|
||||
/* USER CODE BEGIN TIM5_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM5_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM5_CLK_DISABLE();
|
||||
|
||||
/**TIM5 GPIO Configuration
|
||||
PA2 ------> TIM5_CH3
|
||||
PA3 ------> TIM5_CH4
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_3_Pin|GPIO_4_Pin);
|
||||
|
||||
/* TIM5 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(TIM5_IRQn);
|
||||
/* USER CODE BEGIN TIM5_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM5_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : USART.c
|
||||
* Description : This file provides code for the configuration
|
||||
* of the USART instances.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usart.h"
|
||||
|
||||
#include "gpio.h"
|
||||
#include "dma.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
UART_HandleTypeDef huart4;
|
||||
UART_HandleTypeDef huart2;
|
||||
DMA_HandleTypeDef hdma_uart4_rx;
|
||||
DMA_HandleTypeDef hdma_uart4_tx;
|
||||
DMA_HandleTypeDef hdma_usart2_rx;
|
||||
DMA_HandleTypeDef hdma_usart2_tx;
|
||||
|
||||
/* UART4 init function */
|
||||
void MX_UART4_Init(void)
|
||||
{
|
||||
|
||||
huart4.Instance = UART4;
|
||||
//huart4.Init.BaudRate = 115200; // Provisionally this can be changed to 921600 for faster transfers, the low power Arduinos will not keep up.
|
||||
huart4.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart4.Init.StopBits = UART_STOPBITS_1;
|
||||
huart4.Init.Parity = UART_PARITY_NONE;
|
||||
huart4.Init.Mode = UART_MODE_TX_RX;
|
||||
huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart4.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
if (HAL_UART_Init(&huart4) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
/* USART2 init function */
|
||||
|
||||
void MX_USART2_UART_Init(void)
|
||||
{
|
||||
|
||||
huart2.Instance = USART2;
|
||||
//huart2.Init.BaudRate = 115200;
|
||||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart2.Init.StopBits = UART_STOPBITS_1;
|
||||
huart2.Init.Parity = UART_PARITY_NONE;
|
||||
huart2.Init.Mode = UART_MODE_TX_RX;
|
||||
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
if (HAL_UART_Init(&huart2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
|
||||
{
|
||||
|
||||
if(uartHandle->Instance==UART4)
|
||||
{
|
||||
/* USER CODE BEGIN UART4_MspInit 0 */
|
||||
|
||||
/* USER CODE END UART4_MspInit 0 */
|
||||
/* UART4 clock enable */
|
||||
__HAL_RCC_UART4_CLK_ENABLE();
|
||||
|
||||
/* UART4 DMA Init */
|
||||
/* UART4_RX Init */
|
||||
hdma_uart4_rx.Instance = DMA1_Stream2;
|
||||
hdma_uart4_rx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_uart4_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_uart4_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_uart4_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_uart4_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_uart4_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_uart4_rx.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_uart4_rx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_uart4_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_uart4_rx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(uartHandle,hdmarx,hdma_uart4_rx);
|
||||
|
||||
/* UART4_TX Init */
|
||||
hdma_uart4_tx.Instance = DMA1_Stream4;
|
||||
hdma_uart4_tx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_uart4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
hdma_uart4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_uart4_tx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_uart4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_uart4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_uart4_tx.Init.Mode = DMA_NORMAL;
|
||||
hdma_uart4_tx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_uart4_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_uart4_tx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(uartHandle,hdmatx,hdma_uart4_tx);
|
||||
|
||||
/* UART4 interrupt Init */
|
||||
HAL_NVIC_SetPriority(UART4_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(UART4_IRQn);
|
||||
/* USER CODE BEGIN UART4_MspInit 1 */
|
||||
|
||||
/* USER CODE END UART4_MspInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspInit 0 */
|
||||
/* USART2 clock enable */
|
||||
__HAL_RCC_USART2_CLK_ENABLE();
|
||||
|
||||
/* USART2 DMA Init */
|
||||
/* USART2_RX Init */
|
||||
hdma_usart2_rx.Instance = DMA1_Stream5;
|
||||
hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_usart2_rx.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx);
|
||||
|
||||
/* USART2_TX Init */
|
||||
hdma_usart2_tx.Instance = DMA1_Stream6;
|
||||
hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
|
||||
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||||
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
|
||||
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart2_tx);
|
||||
|
||||
/* USART2 interrupt Init */
|
||||
HAL_NVIC_SetPriority(USART2_IRQn, 10, 0);
|
||||
HAL_NVIC_EnableIRQ(USART2_IRQn);
|
||||
/* USER CODE BEGIN USART2_MspInit 1 */
|
||||
|
||||
/* USER CODE END USART2_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
|
||||
{
|
||||
|
||||
if(uartHandle->Instance==UART4)
|
||||
{
|
||||
/* USER CODE BEGIN UART4_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END UART4_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_UART4_CLK_DISABLE();
|
||||
|
||||
/* UART4 DMA DeInit */
|
||||
HAL_DMA_DeInit(uartHandle->hdmarx);
|
||||
HAL_DMA_DeInit(uartHandle->hdmatx);
|
||||
|
||||
/* UART4 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(UART4_IRQn);
|
||||
/* USER CODE BEGIN UART4_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END UART4_MspDeInit 1 */
|
||||
}
|
||||
else if(uartHandle->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_USART2_CLK_DISABLE();
|
||||
|
||||
/* USART2 DMA DeInit */
|
||||
HAL_DMA_DeInit(uartHandle->hdmarx);
|
||||
HAL_DMA_DeInit(uartHandle->hdmatx);
|
||||
|
||||
/* USART2 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(USART2_IRQn);
|
||||
/* USER CODE BEGIN USART2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usb_device.c
|
||||
* @version : v1.0_Cube
|
||||
* @brief : This file implements the USB Device
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "usb_device.h"
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_desc.h"
|
||||
#include "usbd_cdc.h"
|
||||
#include "usbd_cdc_if.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* USER CODE BEGIN PFP */
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* USB Device Core handle declaration. */
|
||||
USBD_HandleTypeDef hUsbDeviceFS;
|
||||
|
||||
/*
|
||||
* -- Insert your variables declaration here --
|
||||
*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/*
|
||||
* -- Insert your external function declaration here --
|
||||
*/
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/**
|
||||
* Init USB device Library, add supported class and start the library
|
||||
* @retval None
|
||||
*/
|
||||
void MX_USB_DEVICE_Init(void)
|
||||
{
|
||||
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
|
||||
|
||||
/* USER CODE END USB_DEVICE_Init_PreTreatment */
|
||||
|
||||
/* Init Device Library, add supported class and start the library. */
|
||||
USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);
|
||||
|
||||
USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);
|
||||
|
||||
USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);
|
||||
|
||||
USBD_Start(&hUsbDeviceFS);
|
||||
|
||||
/* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */
|
||||
|
||||
/* USER CODE END USB_DEVICE_Init_PostTreatment */
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usbd_cdc_if.c
|
||||
* @version : v1.0_Cube
|
||||
* @brief : Usb device for Virtual Com Port.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usbd_cdc_if.h"
|
||||
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
#include "cmsis_os.h"
|
||||
#include <communication/interface_usb.h>
|
||||
#include <freertos_vars.h>
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
|
||||
* @brief Usb device library.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup USBD_CDC_IF
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions
|
||||
* @brief Private types.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_TYPES */
|
||||
/* USER CODE END PRIVATE_TYPES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines
|
||||
* @brief Private defines.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_DEFINES */
|
||||
/* USER CODE END PRIVATE_DEFINES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros
|
||||
* @brief Private macros.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_MACRO */
|
||||
/* USER CODE END PRIVATE_MACRO */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables
|
||||
* @brief Private variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_VARIABLES */
|
||||
/* USER CODE END PRIVATE_VARIABLES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
|
||||
* @brief Public variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern USBD_HandleTypeDef hUsbDeviceFS;
|
||||
|
||||
/* USER CODE BEGIN EXPORTED_VARIABLES */
|
||||
/* USER CODE END EXPORTED_VARIABLES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes
|
||||
* @brief Private functions declaration.
|
||||
* @{
|
||||
*/
|
||||
|
||||
static int8_t CDC_Init_FS(void);
|
||||
static int8_t CDC_DeInit_FS(void);
|
||||
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
|
||||
static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len, uint8_t endpoint_pair);
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
|
||||
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
|
||||
{
|
||||
CDC_Init_FS,
|
||||
CDC_DeInit_FS,
|
||||
CDC_Control_FS,
|
||||
CDC_Receive_FS
|
||||
};
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Initializes the CDC media low layer over the FS USB IP
|
||||
* @retval USBD_OK if all operations are OK else USBD_FAIL
|
||||
*/
|
||||
static int8_t CDC_Init_FS(void)
|
||||
{
|
||||
/* USER CODE BEGIN 3 */
|
||||
/* Set Application Buffers */
|
||||
osMessagePut(usb_event_queue, 1, 0);
|
||||
return (USBD_OK);
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DeInitializes the CDC media low layer
|
||||
* @retval USBD_OK if all operations are OK else USBD_FAIL
|
||||
*/
|
||||
static int8_t CDC_DeInit_FS(void)
|
||||
{
|
||||
/* USER CODE BEGIN 4 */
|
||||
osMessagePut(usb_event_queue, 2, 0);
|
||||
return (USBD_OK);
|
||||
/* USER CODE END 4 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Manage the CDC class requests
|
||||
* @param cmd: Command code
|
||||
* @param pbuf: Buffer containing command data (request parameters)
|
||||
* @param length: Number of data to be sent (in bytes)
|
||||
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
|
||||
*/
|
||||
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
|
||||
{
|
||||
/* USER CODE BEGIN 5 */
|
||||
switch (cmd)
|
||||
{
|
||||
case CDC_SEND_ENCAPSULATED_COMMAND:
|
||||
|
||||
break;
|
||||
|
||||
case CDC_GET_ENCAPSULATED_RESPONSE:
|
||||
|
||||
break;
|
||||
|
||||
case CDC_SET_COMM_FEATURE:
|
||||
|
||||
break;
|
||||
|
||||
case CDC_GET_COMM_FEATURE:
|
||||
|
||||
break;
|
||||
|
||||
case CDC_CLEAR_COMM_FEATURE:
|
||||
|
||||
break;
|
||||
|
||||
/*******************************************************************************/
|
||||
/* Line Coding Structure */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Offset | Field | Size | Value | Description */
|
||||
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
|
||||
/* 4 | bCharFormat | 1 | Number | Stop bits */
|
||||
/* 0 - 1 Stop bit */
|
||||
/* 1 - 1.5 Stop bits */
|
||||
/* 2 - 2 Stop bits */
|
||||
/* 5 | bParityType | 1 | Number | Parity */
|
||||
/* 0 - None */
|
||||
/* 1 - Odd */
|
||||
/* 2 - Even */
|
||||
/* 3 - Mark */
|
||||
/* 4 - Space */
|
||||
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
|
||||
/*******************************************************************************/
|
||||
case CDC_SET_LINE_CODING:
|
||||
|
||||
break;
|
||||
|
||||
case CDC_GET_LINE_CODING:
|
||||
pbuf[0] = (uint8_t)(115200);
|
||||
pbuf[1] = (uint8_t)(115200 >> 8);
|
||||
pbuf[2] = (uint8_t)(115200 >> 16);
|
||||
pbuf[3] = (uint8_t)(115200 >> 24);
|
||||
pbuf[4] = 0; // stop bits (1)
|
||||
pbuf[5] = 0; // parity (none)
|
||||
pbuf[6] = 8; // number of bits (8)
|
||||
break;
|
||||
|
||||
case CDC_SET_CONTROL_LINE_STATE:
|
||||
|
||||
break;
|
||||
|
||||
case CDC_SEND_BREAK:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (USBD_OK);
|
||||
/* USER CODE END 5 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Data received over USB OUT endpoint are sent over CDC interface
|
||||
* through this function.
|
||||
*
|
||||
* @note
|
||||
* This function will block any OUT packet reception on USB endpoint
|
||||
* untill exiting this function. If you exit this function before transfer
|
||||
* is complete on CDC interface (ie. using DMA controller) it will result
|
||||
* in receiving more data while previous ones are still not sent.
|
||||
*
|
||||
* @param Buf: Buffer of data to be received
|
||||
* @param Len: Number of data received (in bytes)
|
||||
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
|
||||
*/
|
||||
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len, uint8_t endpoint_pair)
|
||||
{
|
||||
/* USER CODE BEGIN 6 */
|
||||
usb_rx_process_packet(Buf, *Len, endpoint_pair);
|
||||
|
||||
return (USBD_OK);
|
||||
/* USER CODE END 6 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CDC_Transmit_FS
|
||||
* Data to send over USB IN endpoint are sent over CDC interface
|
||||
* through this function.
|
||||
* @note
|
||||
*
|
||||
*
|
||||
* @param Buf: Buffer of data to be sent
|
||||
* @param Len: Number of data to be sent (in bytes)
|
||||
* @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
|
||||
*/
|
||||
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len, uint8_t endpoint_pair)
|
||||
{
|
||||
uint8_t result = USBD_OK;
|
||||
/* USER CODE BEGIN 7 */
|
||||
//Check length
|
||||
if (Len > USB_TX_DATA_SIZE)
|
||||
return USBD_FAIL;
|
||||
|
||||
USBD_CDC_HandleTypeDef* hcdc = (USBD_CDC_HandleTypeDef*) hUsbDeviceFS.pClassData;
|
||||
|
||||
// Select EP
|
||||
USBD_CDC_EP_HandleTypeDef* hEP_Tx;
|
||||
if (endpoint_pair == CDC_IN_EP) {
|
||||
hEP_Tx = &hcdc->CDC_Tx;
|
||||
} else if (endpoint_pair == ODRIVE_IN_EP) {
|
||||
hEP_Tx = &hcdc->ODRIVE_Tx;
|
||||
} else {
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
// Check for ongoing transmission
|
||||
if (hEP_Tx->State != 0)
|
||||
return USBD_BUSY;
|
||||
|
||||
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS, Buf, Len, endpoint_pair);
|
||||
/* USER CODE END 7 */
|
||||
return result;
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
||||
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,801 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usbd_conf.c
|
||||
* @version : v1.0_Cube
|
||||
* @brief : This file implements the board support package for the USB device library
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f4xx.h"
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "usbd_def.h"
|
||||
#include "usbd_core.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
PCD_HandleTypeDef hpcd_USB_OTG_FS;
|
||||
void _Error_Handler(char * file, int line);
|
||||
|
||||
/* External functions --------------------------------------------------------*/
|
||||
void SystemClock_Config(void);
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/* USER CODE BEGIN PFP */
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/*******************************************************************************
|
||||
LL Driver Callbacks (PCD -> USB Device Library)
|
||||
*******************************************************************************/
|
||||
/* MSP Init */
|
||||
|
||||
void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
if(pcdHandle->Instance==USB_OTG_FS)
|
||||
{
|
||||
/* USER CODE BEGIN USB_OTG_FS_MspInit 0 */
|
||||
|
||||
/* USER CODE END USB_OTG_FS_MspInit 0 */
|
||||
|
||||
/**USB_OTG_FS GPIO Configuration
|
||||
PA11 ------> USB_OTG_FS_DM
|
||||
PA12 ------> USB_OTG_FS_DP
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();
|
||||
|
||||
/* Peripheral interrupt init */
|
||||
HAL_NVIC_SetPriority(OTG_FS_IRQn, 6, 0);
|
||||
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
|
||||
/* USER CODE BEGIN USB_OTG_FS_MspInit 1 */
|
||||
|
||||
/* USER CODE END USB_OTG_FS_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
|
||||
{
|
||||
if(pcdHandle->Instance==USB_OTG_FS)
|
||||
{
|
||||
/* USER CODE BEGIN USB_OTG_FS_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END USB_OTG_FS_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_USB_OTG_FS_CLK_DISABLE();
|
||||
|
||||
/**USB_OTG_FS GPIO Configuration
|
||||
PA11 ------> USB_OTG_FS_DM
|
||||
PA12 ------> USB_OTG_FS_DP
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
|
||||
|
||||
/* Peripheral interrupt Deinit*/
|
||||
HAL_NVIC_DisableIRQ(OTG_FS_IRQn);
|
||||
|
||||
/* USER CODE BEGIN USB_OTG_FS_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END USB_OTG_FS_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup stage callback
|
||||
* @param hpcd: PCD handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
|
||||
{
|
||||
USBD_StatusTypeDef ret = USBD_OK;
|
||||
USBD_HandleTypeDef *pdev = hpcd->pData;
|
||||
USBD_SetupReqTypedef *req = &pdev->request;
|
||||
USBD_ParseSetupRequest(req, (uint8_t *)hpcd->Setup);
|
||||
if ( ( USB_REQ_TYPE_VENDOR == (req->bmRequest & USB_REQ_TYPE_MASK) ) && ( MS_VendorCode == req->bRequest ) )
|
||||
{
|
||||
pdev->ep0_state = USBD_EP0_SETUP;
|
||||
pdev->ep0_data_len = pdev->request.wLength;
|
||||
|
||||
ret = pdev->pClass->Setup(pdev, req);
|
||||
|
||||
if( (req->wLength == 0) && (ret == USBD_OK) )
|
||||
{
|
||||
USBD_CtlSendStatus(pdev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Data Out stage callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @param epnum: Endpoint number
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
|
||||
{
|
||||
USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Data In stage callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @param epnum: Endpoint number
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
|
||||
{
|
||||
USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SOF callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
|
||||
{
|
||||
USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
|
||||
{
|
||||
USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
|
||||
|
||||
/* Set USB current speed. */
|
||||
switch (hpcd->Init.speed)
|
||||
{
|
||||
case PCD_SPEED_HIGH:
|
||||
speed = USBD_SPEED_HIGH;
|
||||
break;
|
||||
case PCD_SPEED_FULL:
|
||||
speed = USBD_SPEED_FULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
speed = USBD_SPEED_FULL;
|
||||
break;
|
||||
}
|
||||
USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed);
|
||||
|
||||
/* Reset Device. */
|
||||
USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspend callback.
|
||||
* When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
|
||||
* @param hpcd: PCD handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
|
||||
{
|
||||
/* Inform USB library that core enters in suspend Mode. */
|
||||
USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData);
|
||||
__HAL_PCD_GATE_PHYCLOCK(hpcd);
|
||||
/* Enter in STOP mode. */
|
||||
/* USER CODE BEGIN 2 */
|
||||
// TODO: do we really want this?
|
||||
if (hpcd->Init.low_power_enable)
|
||||
{
|
||||
/* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register */
|
||||
SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
|
||||
}
|
||||
/* USER CODE END 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume callback.
|
||||
* When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
|
||||
* @param hpcd: PCD handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
|
||||
{
|
||||
/* USER CODE BEGIN 3 */
|
||||
/* USER CODE END 3 */
|
||||
USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ISOOUTIncomplete callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @param epnum: Endpoint number
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
|
||||
{
|
||||
USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ISOINIncomplete callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @param epnum: Endpoint number
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
|
||||
{
|
||||
USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connect callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
|
||||
{
|
||||
USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnect callback.
|
||||
* @param hpcd: PCD handle
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
|
||||
{
|
||||
USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
LL Driver Interface (USB Device Library --> PCD)
|
||||
*******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Initializes the low level portion of the device driver.
|
||||
* @param pdev: Device handle
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
/* Init USB Ip. */
|
||||
if (pdev->id == DEVICE_FS) {
|
||||
/* Link the driver to the stack. */
|
||||
hpcd_USB_OTG_FS.pData = pdev;
|
||||
pdev->pData = &hpcd_USB_OTG_FS;
|
||||
|
||||
hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
|
||||
hpcd_USB_OTG_FS.Init.dev_endpoints = 6;
|
||||
hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
|
||||
hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
|
||||
hpcd_USB_OTG_FS.Init.ep0_mps = DEP0CTL_MPS_64;
|
||||
hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
|
||||
hpcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
|
||||
hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
|
||||
hpcd_USB_OTG_FS.Init.lpm_enable = DISABLE;
|
||||
hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
|
||||
hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;
|
||||
if (HAL_PCD_Init(&hpcd_USB_OTG_FS) != HAL_OK)
|
||||
{
|
||||
_Error_Handler(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80);
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40);
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x40); // CDC IN endpoint
|
||||
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 3, 0x40); // ODrive IN endpoint
|
||||
}
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief De-Initializes the low level portion of the device driver.
|
||||
* @param pdev: Device handle
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_DeInit(pdev->pData);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the low level portion of the device driver.
|
||||
* @param pdev: Device handle
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_Start(pdev->pData);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the low level portion of the device driver.
|
||||
* @param pdev: Device handle
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_Stop(pdev->pData);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Opens an endpoint of the low level driver.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @param ep_type: Endpoint type
|
||||
* @param ep_mps: Endpoint max packet size
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes an endpoint of the low level driver.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flushes an endpoint of the Low Level Driver.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a Stall condition on an endpoint of the Low Level Driver.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears a Stall condition on an endpoint of the Low Level Driver.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns Stall condition.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @retval Stall (1: Yes, 0: No)
|
||||
*/
|
||||
uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
|
||||
{
|
||||
PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData;
|
||||
|
||||
if((ep_addr & 0x80) == 0x80)
|
||||
{
|
||||
return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
|
||||
}
|
||||
else
|
||||
{
|
||||
return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a USB address to the device.
|
||||
* @param pdev: Device handle
|
||||
* @param dev_addr: Device address
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmits data over an endpoint.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @param pbuf: Pointer to data to be sent
|
||||
* @param size: Data size
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepares an endpoint for reception.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @param pbuf: Pointer to data to be received
|
||||
* @param size: Data size
|
||||
* @retval USBD status
|
||||
*/
|
||||
USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
|
||||
{
|
||||
HAL_StatusTypeDef hal_status = HAL_OK;
|
||||
USBD_StatusTypeDef usb_status = USBD_OK;
|
||||
|
||||
hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
|
||||
|
||||
switch (hal_status) {
|
||||
case HAL_OK :
|
||||
usb_status = USBD_OK;
|
||||
break;
|
||||
case HAL_ERROR :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
case HAL_BUSY :
|
||||
usb_status = USBD_BUSY;
|
||||
break;
|
||||
case HAL_TIMEOUT :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
default :
|
||||
usb_status = USBD_FAIL;
|
||||
break;
|
||||
}
|
||||
return usb_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last transfered packet size.
|
||||
* @param pdev: Device handle
|
||||
* @param ep_addr: Endpoint number
|
||||
* @retval Recived Data Size
|
||||
*/
|
||||
uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
|
||||
{
|
||||
return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr);
|
||||
}
|
||||
|
||||
#if (USBD_LPM_ENABLED == 1)
|
||||
/**
|
||||
* @brief Send LPM message to user layer
|
||||
* @param hpcd: PCD handle
|
||||
* @param msg: LPM message
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case PCD_LPM_L0_ACTIVE:
|
||||
if (hpcd->Init.low_power_enable)
|
||||
{
|
||||
SystemClock_Config();
|
||||
|
||||
/* Reset SLEEPDEEP bit of Cortex System Control Register. */
|
||||
SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
|
||||
}
|
||||
__HAL_PCD_UNGATE_PHYCLOCK(hpcd);
|
||||
USBD_LL_Resume(hpcd->pData);
|
||||
break;
|
||||
|
||||
case PCD_LPM_L1_ACTIVE:
|
||||
__HAL_PCD_GATE_PHYCLOCK(hpcd);
|
||||
USBD_LL_Suspend(hpcd->pData);
|
||||
|
||||
/* Enter in STOP mode. */
|
||||
if (hpcd->Init.low_power_enable)
|
||||
{
|
||||
/* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
|
||||
SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* (USBD_LPM_ENABLED == 1) */
|
||||
|
||||
/**
|
||||
* @brief Delays routine for the USB Device Library.
|
||||
* @param Delay: Delay in ms
|
||||
* @retval None
|
||||
*/
|
||||
void USBD_LL_Delay(uint32_t Delay)
|
||||
{
|
||||
HAL_Delay(Delay);
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : usbd_desc.c
|
||||
* @version : v1.0_Cube
|
||||
* @brief : This file implements the USB device descriptors.
|
||||
******************************************************************************
|
||||
* This notice applies to any and all portions of this file
|
||||
* that are not between comment pairs USER CODE BEGIN and
|
||||
* USER CODE END. Other portions of this file, whether
|
||||
* inserted by the user or by software development tools
|
||||
* are owned by their respective copyright owners.
|
||||
*
|
||||
* Copyright (c) 2018 STMicroelectronics International N.V.
|
||||
* 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. Redistribution of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of other
|
||||
* contributors to this software may be used to endorse or promote products
|
||||
* derived from this software without specific written permission.
|
||||
* 4. This software, including modifications and/or derivative works of this
|
||||
* software, must execute solely and exclusively on microcontroller or
|
||||
* microprocessor devices manufactured by or for STMicroelectronics.
|
||||
* 5. Redistribution and use of this software other than as permitted under
|
||||
* this license is void and will automatically terminate your rights under
|
||||
* this license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
|
||||
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
|
||||
* SHALL STMICROELECTRONICS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_desc.h"
|
||||
#include "usbd_conf.h"
|
||||
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
#include <MotorControl/odrive_main.h>
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup USBD_DESC
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Private_TypesDefinitions USBD_DESC_Private_TypesDefinitions
|
||||
* @brief Private types.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_TYPES */
|
||||
|
||||
/* USER CODE END PRIVATE_TYPES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Private_Defines USBD_DESC_Private_Defines
|
||||
* @brief Private defines.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define USBD_VID 0x1209
|
||||
#define USBD_LANGID_STRING 1033
|
||||
#define USBD_MANUFACTURER_STRING "ODrive Robotics"
|
||||
#define USBD_PID_FS 0x0D32
|
||||
#define USBD_PRODUCT_XSTR(s) USBD_PRODUCT_STR(s)
|
||||
#define USBD_PRODUCT_STR(s) #s
|
||||
#define USBD_PRODUCT_STRING_FS ODrive HW_VERSION_MAJOR.HW_VERSION_MINOR CDC Interface
|
||||
#define NATIVE_STRING ODrive HW_VERSION_MAJOR.HW_VERSION_MINOR Native Interface
|
||||
#define USBD_CONFIGURATION_STRING_FS "CDC Config"
|
||||
#define USBD_INTERFACE_STRING_FS "CDC Interface"
|
||||
|
||||
#define USB_SIZ_BOS_DESC 0x0C
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_DEFINES */
|
||||
|
||||
/* USER CODE END PRIVATE_DEFINES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
// MS OS String descriptor to tell Windows that it may query for other descriptors
|
||||
// It's a standard string descriptor.
|
||||
// Windows will only query for OS descriptors once!
|
||||
// Delete the information about already queried devices in registry by deleting:
|
||||
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\VVVVPPPPRRRR
|
||||
__ALIGN_BEGIN uint8_t USBD_MS_OS_StringDescriptor[] __ALIGN_END =
|
||||
{
|
||||
0x12, // bLength 1 0x12 Length of the descriptor
|
||||
0x03, // bDescriptorType 1 0x03 Descriptor type
|
||||
// qwSignature 14 ‘MSFT100’ Signature field
|
||||
0x4D, 0x00, // 'M'
|
||||
0x53, 0x00, // 'S'
|
||||
0x46, 0x00, // 'F'
|
||||
0x54, 0x00, // 'T'
|
||||
0x31, 0x00, // '1'
|
||||
0x30, 0x00, // '0'
|
||||
0x30, 0x00, // '0'
|
||||
MS_VendorCode, // bMS_VendorCode 1 Vendor-specific Vendor code
|
||||
0x00 // bPad 1 0x00 Pad field
|
||||
};
|
||||
|
||||
// redefined further down
|
||||
__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
|
||||
/**
|
||||
* @brief UsrStrDescriptor
|
||||
* return non standard string descriptor
|
||||
* @param pdev: device instance
|
||||
* @param index : descriptor index (0xEE for MS OS String Descriptor)
|
||||
* @param length : pointer data length
|
||||
* @retval pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_UsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length)
|
||||
{
|
||||
*length = 0;
|
||||
if (USBD_IDX_MICROSOFT_DESC_STR == index) {
|
||||
*length = sizeof (USBD_MS_OS_StringDescriptor);
|
||||
return USBD_MS_OS_StringDescriptor;
|
||||
} else if (USBD_IDX_ODRIVE_INTF_STR == index) {
|
||||
USBD_GetString((uint8_t *)USBD_PRODUCT_XSTR(NATIVE_STRING), USBD_StrDesc, length);
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros
|
||||
* @brief Private macros.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* USER CODE BEGIN PRIVATE_MACRO */
|
||||
|
||||
/* USER CODE END PRIVATE_MACRO */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes
|
||||
* @brief Private functions declaration.
|
||||
* @{
|
||||
*/
|
||||
|
||||
uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
|
||||
#ifdef USB_SUPPORT_USER_STRING_DESC
|
||||
uint8_t * USBD_FS_USRStringDesc(USBD_SpeedTypeDef speed, uint8_t idx, uint16_t *length);
|
||||
#endif /* USB_SUPPORT_USER_STRING_DESC */
|
||||
|
||||
#if (USBD_LPM_ENABLED == 1)
|
||||
uint8_t * USBD_FS_USR_BOSDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
|
||||
#endif /* (USBD_LPM_ENABLED == 1) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
|
||||
* @brief Private variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
USBD_DescriptorsTypeDef FS_Desc =
|
||||
{
|
||||
USBD_FS_DeviceDescriptor
|
||||
, USBD_FS_LangIDStrDescriptor
|
||||
, USBD_FS_ManufacturerStrDescriptor
|
||||
, USBD_FS_ProductStrDescriptor
|
||||
, USBD_FS_SerialStrDescriptor
|
||||
, USBD_FS_ConfigStrDescriptor
|
||||
, USBD_FS_InterfaceStrDescriptor
|
||||
#if (USBD_LPM_ENABLED == 1)
|
||||
, USBD_FS_USR_BOSDescriptor
|
||||
#endif /* (USBD_LPM_ENABLED == 1) */
|
||||
};
|
||||
|
||||
#if defined ( __ICCARM__ ) /* IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif /* defined ( __ICCARM__ ) */
|
||||
/** USB standard device descriptor. */
|
||||
__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
|
||||
{
|
||||
0x12, /*bLength */
|
||||
USB_DESC_TYPE_DEVICE, /*bDescriptorType*/
|
||||
#if (USBD_LPM_ENABLED == 1)
|
||||
0x01, /*bcdUSB */ /* changed to USB version 2.01
|
||||
in order to support LPM L1 suspend
|
||||
resume test of USBCV3.0*/
|
||||
#else
|
||||
0x00, /*bcdUSB */
|
||||
#endif /* (USBD_LPM_ENABLED == 1) */
|
||||
0x02,
|
||||
// Notify OS that this is a composite device
|
||||
0xEF, /*bDeviceClass*/
|
||||
0x02, /*bDeviceSubClass*/
|
||||
0x01, /*bDeviceProtocol*/
|
||||
USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
|
||||
LOBYTE(USBD_VID), /*idVendor*/
|
||||
HIBYTE(USBD_VID), /*idVendor*/
|
||||
LOBYTE(USBD_PID_FS), /*idProduct*/
|
||||
HIBYTE(USBD_PID_FS), /*idProduct*/
|
||||
0x00, /*bcdDevice rel. 2.00*/
|
||||
0x03, /* bNumInterfaces */
|
||||
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
|
||||
USBD_IDX_PRODUCT_STR, /*Index of product string*/
|
||||
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
|
||||
USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/
|
||||
};
|
||||
|
||||
/* USB_DeviceDescriptor */
|
||||
/** BOS descriptor. */
|
||||
#if (USBD_LPM_ENABLED == 1)
|
||||
#if defined ( __ICCARM__ ) /* IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif /* defined ( __ICCARM__ ) */
|
||||
__ALIGN_BEGIN uint8_t USBD_FS_BOSDesc[USB_SIZ_BOS_DESC] __ALIGN_END =
|
||||
{
|
||||
0x5,
|
||||
USB_DESC_TYPE_BOS,
|
||||
0xC,
|
||||
0x0,
|
||||
0x1, /* 1 device capability*/
|
||||
/* device capability*/
|
||||
0x7,
|
||||
USB_DEVICE_CAPABITY_TYPE,
|
||||
0x2,
|
||||
0x2, /* LPM capability bit set*/
|
||||
0x0,
|
||||
0x0,
|
||||
0x0
|
||||
};
|
||||
#endif /* (USBD_LPM_ENABLED == 1) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
|
||||
* @brief Private variables.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined ( __ICCARM__ ) /* IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif /* defined ( __ICCARM__ ) */
|
||||
|
||||
/** USB lang indentifier descriptor. */
|
||||
__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
|
||||
{
|
||||
USB_LEN_LANGID_STR_DESC,
|
||||
USB_DESC_TYPE_STRING,
|
||||
LOBYTE(USBD_LANGID_STRING),
|
||||
HIBYTE(USBD_LANGID_STRING)
|
||||
};
|
||||
|
||||
#if defined ( __ICCARM__ ) /* IAR Compiler */
|
||||
#pragma data_alignment=4
|
||||
#endif /* defined ( __ICCARM__ ) */
|
||||
/* Internal string descriptor. */
|
||||
__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup USBD_DESC_Private_Functions USBD_DESC_Private_Functions
|
||||
* @brief Private functions.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Return the device descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
*length = sizeof(USBD_FS_DeviceDesc);
|
||||
return USBD_FS_DeviceDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the LangID string descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
*length = sizeof(USBD_LangIDDesc);
|
||||
return USBD_LangIDDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the product string descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
if(speed == 0)
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_PRODUCT_XSTR(USBD_PRODUCT_STRING_FS), USBD_StrDesc, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_PRODUCT_XSTR(USBD_PRODUCT_STRING_FS), USBD_StrDesc, length);
|
||||
}
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the manufacturer string descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the serial number string descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
USBD_GetString ((uint8_t *)serial_number_str, USBD_StrDesc, length);
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the configuration string descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
if(speed == USBD_SPEED_HIGH)
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING_FS, USBD_StrDesc, length);
|
||||
}
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the interface string descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
if(speed == 0)
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
USBD_GetString((uint8_t *)USBD_INTERFACE_STRING_FS, USBD_StrDesc, length);
|
||||
}
|
||||
return USBD_StrDesc;
|
||||
}
|
||||
|
||||
#if (USBD_LPM_ENABLED == 1)
|
||||
/**
|
||||
* @brief Return the BOS descriptor
|
||||
* @param speed : Current device speed
|
||||
* @param length : Pointer to data length variable
|
||||
* @retval Pointer to descriptor buffer
|
||||
*/
|
||||
uint8_t * USBD_FS_USR_BOSDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
|
||||
{
|
||||
*length = sizeof(USBD_FS_BOSDesc);
|
||||
return (uint8_t*)USBD_FS_BOSDesc;
|
||||
}
|
||||
#endif /* (USBD_LPM_ENABLED == 1) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,593 @@
|
||||
/*
|
||||
* @brief Contains board specific variables and initialization functions
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#include <odrive_main.h>
|
||||
#include <low_level.h>
|
||||
|
||||
#include <Drivers/STM32/stm32_timer.hpp>
|
||||
|
||||
#include <adc.h>
|
||||
#include <dma.h>
|
||||
#include <tim.h>
|
||||
#include <usart.h>
|
||||
#include <freertos_vars.h>
|
||||
|
||||
// this should technically be in task_timer.cpp but let's not make a one-line file
|
||||
bool TaskTimer::enabled = false;
|
||||
|
||||
extern "C" void SystemClock_Config(void); // defined in main.c generated by CubeMX
|
||||
|
||||
#define ControlLoop_IRQHandler OTG_HS_IRQHandler
|
||||
#define ControlLoop_IRQn OTG_HS_IRQn
|
||||
|
||||
// This array is placed at the very start of the ram (0x20000000) and will be
|
||||
// used during manufacturing to test the struct that will go to the OTP before
|
||||
// _actually_ putting anything into OTP. This avoids bulk-destroying STM32's if
|
||||
// we introduce unintended breakage in our manufacturing scripts.
|
||||
uint8_t __attribute__((section(".testdata"))) fake_otp[FLASH_OTP_END + 1 - FLASH_OTP_BASE] = {0, 0, 0, HW_VERSION_MAJOR, HW_VERSION_MINOR, HW_VERSION_VOLTAGE};
|
||||
|
||||
Stm32SpiArbiter spi3_arbiter{&hspi3};
|
||||
Stm32SpiArbiter& ext_spi_arbiter = spi3_arbiter;
|
||||
|
||||
UART_HandleTypeDef* uart_a = &huart4;
|
||||
UART_HandleTypeDef* uart_b = &huart2; // TODO: this could be supported in ODrive v3.6 (or similar) using STM32's USART2
|
||||
UART_HandleTypeDef* uart_c = nullptr;
|
||||
|
||||
Drv8301 m0_gate_driver{
|
||||
&spi3_arbiter,
|
||||
{M0_nCS_GPIO_Port, M0_nCS_Pin}, // nCS
|
||||
{}, // EN pin (shared between both motors, therefore we actuate it outside of the drv8301 driver)
|
||||
{nFAULT_GPIO_Port, nFAULT_Pin} // nFAULT pin (shared between both motors)
|
||||
};
|
||||
|
||||
Drv8301 m1_gate_driver{
|
||||
&spi3_arbiter,
|
||||
{M1_nCS_GPIO_Port, M1_nCS_Pin}, // nCS
|
||||
{}, // EN pin (shared between both motors, therefore we actuate it outside of the drv8301 driver)
|
||||
{nFAULT_GPIO_Port, nFAULT_Pin} // nFAULT pin (shared between both motors)
|
||||
};
|
||||
|
||||
const float fet_thermistor_poly_coeffs[] =
|
||||
{363.93910201f, -462.15369634f, 307.55129571f, -27.72569531f};
|
||||
const size_t fet_thermistor_num_coeffs = sizeof(fet_thermistor_poly_coeffs)/sizeof(fet_thermistor_poly_coeffs[1]);
|
||||
|
||||
OnboardThermistorCurrentLimiter fet_thermistors[AXIS_COUNT] = {
|
||||
{
|
||||
15, // adc_channel
|
||||
&fet_thermistor_poly_coeffs[0], // coefficients
|
||||
fet_thermistor_num_coeffs // num_coeffs
|
||||
}, {
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 3
|
||||
4, // adc_channel
|
||||
#else
|
||||
1, // adc_channel
|
||||
#endif
|
||||
&fet_thermistor_poly_coeffs[0], // coefficients
|
||||
fet_thermistor_num_coeffs // num_coeffs
|
||||
}
|
||||
};
|
||||
|
||||
OffboardThermistorCurrentLimiter motor_thermistors[AXIS_COUNT];
|
||||
|
||||
Motor motors[AXIS_COUNT] = {
|
||||
{
|
||||
&htim1, // timer
|
||||
0b110, // current_sensor_mask
|
||||
1.0f / SHUNT_RESISTANCE, // shunt_conductance [S]
|
||||
m0_gate_driver, // gate_driver
|
||||
m0_gate_driver, // opamp
|
||||
fet_thermistors[0],
|
||||
motor_thermistors[0]
|
||||
},
|
||||
{
|
||||
&htim8, // timer
|
||||
0b110, // current_sensor_mask
|
||||
1.0f / SHUNT_RESISTANCE, // shunt_conductance [S]
|
||||
m1_gate_driver, // gate_driver
|
||||
m1_gate_driver, // opamp
|
||||
fet_thermistors[1],
|
||||
motor_thermistors[1]
|
||||
}
|
||||
};
|
||||
|
||||
Encoder encoders[AXIS_COUNT] = {
|
||||
{
|
||||
&htim3, // timer
|
||||
{M0_ENC_Z_GPIO_Port, M0_ENC_Z_Pin}, // index_gpio
|
||||
{M0_ENC_A_GPIO_Port, M0_ENC_A_Pin}, // hallA_gpio
|
||||
{M0_ENC_B_GPIO_Port, M0_ENC_B_Pin}, // hallB_gpio
|
||||
{M0_ENC_Z_GPIO_Port, M0_ENC_Z_Pin}, // hallC_gpio
|
||||
&spi3_arbiter // spi_arbiter
|
||||
},
|
||||
{
|
||||
&htim4, // timer
|
||||
{M1_ENC_Z_GPIO_Port, M1_ENC_Z_Pin}, // index_gpio
|
||||
{M1_ENC_A_GPIO_Port, M1_ENC_A_Pin}, // hallA_gpio
|
||||
{M1_ENC_B_GPIO_Port, M1_ENC_B_Pin}, // hallB_gpio
|
||||
{M1_ENC_Z_GPIO_Port, M1_ENC_Z_Pin}, // hallC_gpio
|
||||
&spi3_arbiter // spi_arbiter
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: this has no hardware dependency and should be allocated depending on config
|
||||
Endstop endstops[2 * AXIS_COUNT];
|
||||
MechanicalBrake mechanical_brakes[AXIS_COUNT];
|
||||
|
||||
SensorlessEstimator sensorless_estimators[AXIS_COUNT];
|
||||
Controller controllers[AXIS_COUNT];
|
||||
TrapezoidalTrajectory trap[AXIS_COUNT];
|
||||
|
||||
std::array<Axis, AXIS_COUNT> axes{{
|
||||
{
|
||||
0, // axis_num
|
||||
1, // step_gpio_pin
|
||||
2, // dir_gpio_pin
|
||||
(osPriority)(osPriorityHigh + (osPriority)1), // thread_priority
|
||||
encoders[0], // encoder
|
||||
sensorless_estimators[0], // sensorless_estimator
|
||||
controllers[0], // controller
|
||||
motors[0], // motor
|
||||
trap[0], // trap
|
||||
endstops[0], endstops[1], // min_endstop, max_endstop
|
||||
mechanical_brakes[0], // mechanical brake
|
||||
},
|
||||
{
|
||||
1, // axis_num
|
||||
#if HW_VERSION_MAJOR == 3 && HW_VERSION_MINOR >= 5
|
||||
7, // step_gpio_pin
|
||||
8, // dir_gpio_pin
|
||||
#else
|
||||
3, // step_gpio_pin
|
||||
4, // dir_gpio_pin
|
||||
#endif
|
||||
osPriorityHigh, // thread_priority
|
||||
encoders[1], // encoder
|
||||
sensorless_estimators[1], // sensorless_estimator
|
||||
controllers[1], // controller
|
||||
motors[1], // motor
|
||||
trap[1], // trap
|
||||
endstops[2], endstops[3], // min_endstop, max_endstop
|
||||
mechanical_brakes[1], // mechanical brake
|
||||
},
|
||||
}};
|
||||
|
||||
|
||||
|
||||
#if (HW_VERSION_MINOR == 1) || (HW_VERSION_MINOR == 2)
|
||||
Stm32Gpio gpios[] = {
|
||||
{nullptr, 0}, // dummy GPIO0 so that PCB labels and software numbers match
|
||||
|
||||
{GPIOB, GPIO_PIN_2}, // GPIO1
|
||||
{GPIOA, GPIO_PIN_5}, // GPIO2
|
||||
{GPIOA, GPIO_PIN_4}, // GPIO3
|
||||
{GPIOA, GPIO_PIN_3}, // GPIO4
|
||||
{nullptr, 0}, // GPIO5 (doesn't exist on this board)
|
||||
{nullptr, 0}, // GPIO6 (doesn't exist on this board)
|
||||
{nullptr, 0}, // GPIO7 (doesn't exist on this board)
|
||||
{nullptr, 0}, // GPIO8 (doesn't exist on this board)
|
||||
|
||||
{GPIOB, GPIO_PIN_4}, // ENC0_A
|
||||
{GPIOB, GPIO_PIN_5}, // ENC0_B
|
||||
{GPIOA, GPIO_PIN_15}, // ENC0_Z
|
||||
{GPIOB, GPIO_PIN_6}, // ENC1_A
|
||||
{GPIOB, GPIO_PIN_7}, // ENC1_B
|
||||
{GPIOB, GPIO_PIN_3}, // ENC1_Z
|
||||
{GPIOB, GPIO_PIN_8}, // CAN_R
|
||||
{GPIOB, GPIO_PIN_9}, // CAN_D
|
||||
};
|
||||
#elif (HW_VERSION_MINOR == 3) || (HW_VERSION_MINOR == 4)
|
||||
Stm32Gpio gpios[] = {
|
||||
{nullptr, 0}, // dummy GPIO0 so that PCB labels and software numbers match
|
||||
|
||||
{GPIOA, GPIO_PIN_0}, // GPIO1
|
||||
{GPIOA, GPIO_PIN_1}, // GPIO2
|
||||
{GPIOA, GPIO_PIN_2}, // GPIO3
|
||||
{GPIOA, GPIO_PIN_3}, // GPIO4
|
||||
{GPIOB, GPIO_PIN_2}, // GPIO5
|
||||
{nullptr, 0}, // GPIO6 (doesn't exist on this board)
|
||||
{nullptr, 0}, // GPIO7 (doesn't exist on this board)
|
||||
{nullptr, 0}, // GPIO8 (doesn't exist on this board)
|
||||
|
||||
{GPIOB, GPIO_PIN_4}, // ENC0_A
|
||||
{GPIOB, GPIO_PIN_5}, // ENC0_B
|
||||
{GPIOA, GPIO_PIN_15}, // ENC0_Z
|
||||
{GPIOB, GPIO_PIN_6}, // ENC1_A
|
||||
{GPIOB, GPIO_PIN_7}, // ENC1_B
|
||||
{GPIOB, GPIO_PIN_3}, // ENC1_Z
|
||||
{GPIOB, GPIO_PIN_8}, // CAN_R
|
||||
{GPIOB, GPIO_PIN_9}, // CAN_D
|
||||
};
|
||||
#elif (HW_VERSION_MINOR == 5) || (HW_VERSION_MINOR == 6)
|
||||
Stm32Gpio gpios[GPIO_COUNT] = {
|
||||
{nullptr, 0}, // dummy GPIO0 so that PCB labels and software numbers match
|
||||
|
||||
{GPIOA, GPIO_PIN_0}, // GPIO1
|
||||
{GPIOA, GPIO_PIN_1}, // GPIO2
|
||||
{GPIOA, GPIO_PIN_2}, // GPIO3
|
||||
{GPIOA, GPIO_PIN_3}, // GPIO4
|
||||
{GPIOC, GPIO_PIN_4}, // GPIO5
|
||||
{GPIOB, GPIO_PIN_2}, // GPIO6
|
||||
{GPIOA, GPIO_PIN_15}, // GPIO7
|
||||
{GPIOB, GPIO_PIN_3}, // GPIO8
|
||||
|
||||
{GPIOB, GPIO_PIN_4}, // ENC0_A
|
||||
{GPIOB, GPIO_PIN_5}, // ENC0_B
|
||||
{GPIOC, GPIO_PIN_9}, // ENC0_Z
|
||||
{GPIOB, GPIO_PIN_6}, // ENC1_A
|
||||
{GPIOB, GPIO_PIN_7}, // ENC1_B
|
||||
{GPIOC, GPIO_PIN_15}, // ENC1_Z
|
||||
{GPIOB, GPIO_PIN_8}, // CAN_R
|
||||
{GPIOB, GPIO_PIN_9}, // CAN_D
|
||||
};
|
||||
#else
|
||||
#error "unknown GPIOs"
|
||||
#endif
|
||||
|
||||
std::array<GpioFunction, 3> alternate_functions[GPIO_COUNT] = {
|
||||
/* GPIO0 (inexistent): */ {{}},
|
||||
|
||||
#if HW_VERSION_MINOR >= 3
|
||||
/* GPIO1: */ {{{ODrive::GPIO_MODE_UART_A, GPIO_AF8_UART4}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
/* GPIO2: */ {{{ODrive::GPIO_MODE_UART_A, GPIO_AF8_UART4}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
/* GPIO3: */ {{{ODrive::GPIO_MODE_UART_B, GPIO_AF7_USART2}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
#else
|
||||
/* GPIO1: */ {{}},
|
||||
/* GPIO2: */ {{}},
|
||||
/* GPIO3: */ {{}},
|
||||
#endif
|
||||
|
||||
/* GPIO4: */ {{{ODrive::GPIO_MODE_UART_B, GPIO_AF7_USART2}, {ODrive::GPIO_MODE_PWM, GPIO_AF2_TIM5}}},
|
||||
/* GPIO5: */ {{}},
|
||||
/* GPIO6: */ {{}},
|
||||
/* GPIO7: */ {{}},
|
||||
/* GPIO8: */ {{}},
|
||||
/* ENC0_A: */ {{{ODrive::GPIO_MODE_ENC0, GPIO_AF2_TIM3}}},
|
||||
/* ENC0_B: */ {{{ODrive::GPIO_MODE_ENC0, GPIO_AF2_TIM3}}},
|
||||
/* ENC0_Z: */ {{}},
|
||||
/* ENC1_A: */ {{{ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}, {ODrive::GPIO_MODE_ENC1, GPIO_AF2_TIM4}}},
|
||||
/* ENC1_B: */ {{{ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}, {ODrive::GPIO_MODE_ENC1, GPIO_AF2_TIM4}}},
|
||||
/* ENC1_Z: */ {{}},
|
||||
/* CAN_R: */ {{{ODrive::GPIO_MODE_CAN_A, GPIO_AF9_CAN1}, {ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}}},
|
||||
/* CAN_D: */ {{{ODrive::GPIO_MODE_CAN_A, GPIO_AF9_CAN1}, {ODrive::GPIO_MODE_I2C_A, GPIO_AF4_I2C1}}},
|
||||
};
|
||||
|
||||
#if HW_VERSION_MINOR <= 2
|
||||
PwmInput pwm0_input{&htim5, {0, 0, 0, 4}}; // 0 means not in use
|
||||
#else
|
||||
PwmInput pwm0_input{&htim5, {1, 2, 3, 4}};
|
||||
#endif
|
||||
|
||||
extern USBD_HandleTypeDef hUsbDeviceFS;
|
||||
USBD_HandleTypeDef& usb_dev_handle = hUsbDeviceFS;
|
||||
|
||||
bool check_board_version(const uint8_t* otp_ptr) {
|
||||
return (otp_ptr[3] == HW_VERSION_MAJOR) &&
|
||||
(otp_ptr[4] == HW_VERSION_MINOR) &&
|
||||
(otp_ptr[5] == HW_VERSION_VOLTAGE);
|
||||
}
|
||||
|
||||
void system_init() {
|
||||
// Reset of all peripherals, Initializes the Flash interface and the Systick.
|
||||
HAL_Init();
|
||||
|
||||
// Configure the system clock
|
||||
SystemClock_Config();
|
||||
|
||||
// If the OTP is pristine, use the fake-otp in RAM instead
|
||||
const uint8_t* otp_ptr = (const uint8_t*)FLASH_OTP_BASE;
|
||||
if (*otp_ptr == 0xff) {
|
||||
otp_ptr = fake_otp;
|
||||
}
|
||||
|
||||
// Ensure that the board version for which this firmware is compiled matches
|
||||
// the board we're running on.
|
||||
if (!check_board_version(otp_ptr)) {
|
||||
for (;;);
|
||||
}
|
||||
}
|
||||
|
||||
bool board_init() {
|
||||
// Initialize all configured peripherals
|
||||
MX_GPIO_Init();
|
||||
MX_DMA_Init();
|
||||
MX_ADC1_Init();
|
||||
MX_ADC2_Init();
|
||||
MX_TIM1_Init();
|
||||
MX_TIM8_Init();
|
||||
MX_TIM3_Init();
|
||||
MX_TIM4_Init();
|
||||
MX_SPI3_Init();
|
||||
MX_ADC3_Init();
|
||||
MX_TIM2_Init();
|
||||
MX_TIM5_Init();
|
||||
MX_TIM13_Init();
|
||||
|
||||
// External interrupt lines are individually enabled in stm32_gpio.cpp
|
||||
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
|
||||
HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
|
||||
HAL_NVIC_SetPriority(EXTI2_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
|
||||
HAL_NVIC_SetPriority(EXTI3_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
|
||||
HAL_NVIC_SetPriority(EXTI4_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
|
||||
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
|
||||
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
|
||||
|
||||
HAL_NVIC_SetPriority(ControlLoop_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(ControlLoop_IRQn);
|
||||
|
||||
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
|
||||
|
||||
if (odrv.config_.enable_uart_a) {
|
||||
uart_a->Init.BaudRate = odrv.config_.uart_a_baudrate;
|
||||
MX_UART4_Init();
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_uart_b) {
|
||||
uart_b->Init.BaudRate = odrv.config_.uart_b_baudrate;
|
||||
MX_USART2_UART_Init();
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_i2c_a) {
|
||||
// Set up the direction GPIO as input
|
||||
get_gpio(3).config(GPIO_MODE_INPUT, GPIO_PULLUP);
|
||||
get_gpio(4).config(GPIO_MODE_INPUT, GPIO_PULLUP);
|
||||
get_gpio(5).config(GPIO_MODE_INPUT, GPIO_PULLUP);
|
||||
|
||||
osDelay(1); // This has no effect but was here before.
|
||||
i2c_stats_.addr = (0xD << 3);
|
||||
i2c_stats_.addr |= get_gpio(3).read() ? 0x1 : 0;
|
||||
i2c_stats_.addr |= get_gpio(4).read() ? 0x2 : 0;
|
||||
i2c_stats_.addr |= get_gpio(5).read() ? 0x4 : 0;
|
||||
MX_I2C1_Init(i2c_stats_.addr);
|
||||
}
|
||||
|
||||
if (odrv.config_.enable_can_a) {
|
||||
// The CAN initialization will (and must) init its own GPIOs before the
|
||||
// GPIO modes are initialized. Therefore we ensure that the later GPIO
|
||||
// mode initialization won't override the CAN mode.
|
||||
if (odrv.config_.gpio_modes[15] != ODriveIntf::GPIO_MODE_CAN_A || odrv.config_.gpio_modes[16] != ODriveIntf::GPIO_MODE_CAN_A) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that debug halting of the core doesn't leave the motor PWM running
|
||||
__HAL_DBGMCU_FREEZE_TIM1();
|
||||
__HAL_DBGMCU_FREEZE_TIM8();
|
||||
__HAL_DBGMCU_FREEZE_TIM13();
|
||||
|
||||
Stm32Gpio drv_enable_gpio = {EN_GATE_GPIO_Port, EN_GATE_Pin};
|
||||
|
||||
// Reset both DRV chips. The enable pin also controls the SPI interface, not
|
||||
// only the driver stages.
|
||||
drv_enable_gpio.write(false);
|
||||
delay_us(40); // mimumum pull-down time for full reset: 20us
|
||||
drv_enable_gpio.write(true);
|
||||
delay_us(20000); // mimumum pull-down time for full reset: 20us
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void start_timers() {
|
||||
CRITICAL_SECTION() {
|
||||
// Temporarily disable ADC triggers so they don't trigger as a side
|
||||
// effect of starting the timers.
|
||||
hadc1.Instance->CR2 &= ~(ADC_CR2_JEXTEN);
|
||||
hadc2.Instance->CR2 &= ~(ADC_CR2_EXTEN | ADC_CR2_JEXTEN);
|
||||
hadc3.Instance->CR2 &= ~(ADC_CR2_EXTEN | ADC_CR2_JEXTEN);
|
||||
|
||||
/*
|
||||
* Synchronize TIM1, TIM8 and TIM13 such that:
|
||||
* 1. The triangle waveform of TIM1 leads the triangle waveform of TIM8 by a
|
||||
* 90° phase shift.
|
||||
* 2. Each TIM13 reload coincides with a TIM1 lower update event.
|
||||
*/
|
||||
Stm32Timer::start_synchronously<3>(
|
||||
{&htim1, &htim8, &htim13},
|
||||
{TIM1_INIT_COUNT, 0, TIM1_INIT_COUNT / 2 /* TIM13 is on a clock that's only have as fast as TIM1 */}
|
||||
);
|
||||
|
||||
hadc1.Instance->CR2 |= (ADC_EXTERNALTRIGINJECCONVEDGE_RISING);
|
||||
hadc2.Instance->CR2 |= (ADC_EXTERNALTRIGCONVEDGE_RISING | ADC_EXTERNALTRIGINJECCONVEDGE_RISING);
|
||||
hadc3.Instance->CR2 |= (ADC_EXTERNALTRIGCONVEDGE_RISING | ADC_EXTERNALTRIGINJECCONVEDGE_RISING);
|
||||
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_JEOC);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc2, ADC_FLAG_JEOC);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_JEOC);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_EOC);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc2, ADC_FLAG_EOC);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_EOC);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_OVR);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc2, ADC_FLAG_OVR);
|
||||
__HAL_ADC_CLEAR_FLAG(&hadc3, ADC_FLAG_OVR);
|
||||
|
||||
__HAL_TIM_CLEAR_IT(&htim8, TIM_IT_UPDATE);
|
||||
__HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE);
|
||||
}
|
||||
}
|
||||
|
||||
static bool fetch_and_reset_adcs(
|
||||
std::optional<Iph_ABC_t>* current0,
|
||||
std::optional<Iph_ABC_t>* current1) {
|
||||
bool all_adcs_done = (ADC1->SR & ADC_SR_JEOC) == ADC_SR_JEOC
|
||||
&& (ADC2->SR & (ADC_SR_EOC | ADC_SR_JEOC)) == (ADC_SR_EOC | ADC_SR_JEOC)
|
||||
&& (ADC3->SR & (ADC_SR_EOC | ADC_SR_JEOC)) == (ADC_SR_EOC | ADC_SR_JEOC);
|
||||
if (!all_adcs_done) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vbus_sense_adc_cb(ADC1->JDR1);
|
||||
|
||||
if (m0_gate_driver.is_ready()) {
|
||||
std::optional<float> phB = motors[0].phase_current_from_adcval(ADC2->JDR1);
|
||||
std::optional<float> phC = motors[0].phase_current_from_adcval(ADC3->JDR1);
|
||||
if (phB.has_value() && phC.has_value()) {
|
||||
*current0 = {-*phB - *phC, *phB, *phC};
|
||||
}
|
||||
}
|
||||
|
||||
if (m1_gate_driver.is_ready()) {
|
||||
std::optional<float> phB = motors[1].phase_current_from_adcval(ADC2->DR);
|
||||
std::optional<float> phC = motors[1].phase_current_from_adcval(ADC3->DR);
|
||||
if (phB.has_value() && phC.has_value()) {
|
||||
*current1 = {-*phB - *phC, *phB, *phC};
|
||||
}
|
||||
}
|
||||
|
||||
ADC1->SR = ~(ADC_SR_JEOC);
|
||||
ADC2->SR = ~(ADC_SR_EOC | ADC_SR_JEOC | ADC_SR_OVR);
|
||||
ADC3->SR = ~(ADC_SR_EOC | ADC_SR_JEOC | ADC_SR_OVR);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
HAL_SPI_TxRxCpltCallback(hspi);
|
||||
}
|
||||
|
||||
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
HAL_SPI_TxRxCpltCallback(hspi);
|
||||
}
|
||||
|
||||
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
if (hspi == &hspi3) {
|
||||
spi3_arbiter.on_complete();
|
||||
}
|
||||
}
|
||||
|
||||
void TIM5_IRQHandler(void) {
|
||||
COUNT_IRQ(TIM5_IRQn);
|
||||
pwm0_input.on_capture();
|
||||
}
|
||||
|
||||
volatile uint32_t timestamp_ = 0;
|
||||
volatile bool counting_down_ = false;
|
||||
|
||||
void TIM8_UP_TIM13_IRQHandler(void) {
|
||||
COUNT_IRQ(TIM8_UP_TIM13_IRQn);
|
||||
|
||||
// Entry into this function happens at 21-23 clock cycles after the timer
|
||||
// update event.
|
||||
__HAL_TIM_CLEAR_IT(&htim8, TIM_IT_UPDATE);
|
||||
|
||||
// If the corresponding timer is counting up, we just sampled in SVM vector 0, i.e. real current
|
||||
// If we are counting down, we just sampled in SVM vector 7, with zero current
|
||||
bool counting_down = TIM8->CR1 & TIM_CR1_DIR;
|
||||
|
||||
bool timer_update_missed = (counting_down_ == counting_down);
|
||||
if (timer_update_missed) {
|
||||
motors[0].disarm_with_error(Motor::ERROR_TIMER_UPDATE_MISSED);
|
||||
motors[1].disarm_with_error(Motor::ERROR_TIMER_UPDATE_MISSED);
|
||||
return;
|
||||
}
|
||||
counting_down_ = counting_down;
|
||||
|
||||
timestamp_ += TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR + 1);
|
||||
|
||||
if (!counting_down) {
|
||||
TaskTimer::enabled = odrv.task_timers_armed_;
|
||||
// Run sampling handlers and kick off control tasks when TIM8 is
|
||||
// counting up.
|
||||
odrv.sampling_cb();
|
||||
NVIC->STIR = ControlLoop_IRQn;
|
||||
} else {
|
||||
// Tentatively reset all PWM outputs to 50% duty cycles. If the control
|
||||
// loop handler finishes in time then these values will be overridden
|
||||
// before they go into effect.
|
||||
TIM1->CCR1 =
|
||||
TIM1->CCR2 =
|
||||
TIM1->CCR3 =
|
||||
TIM8->CCR1 =
|
||||
TIM8->CCR2 =
|
||||
TIM8->CCR3 =
|
||||
TIM_1_8_PERIOD_CLOCKS / 2;
|
||||
}
|
||||
}
|
||||
|
||||
void ControlLoop_IRQHandler(void) {
|
||||
COUNT_IRQ(ControlLoop_IRQn);
|
||||
uint32_t timestamp = timestamp_;
|
||||
|
||||
// Ensure that all the ADCs are done
|
||||
std::optional<Iph_ABC_t> current0;
|
||||
std::optional<Iph_ABC_t> current1;
|
||||
|
||||
if (!fetch_and_reset_adcs(¤t0, ¤t1)) {
|
||||
motors[0].disarm_with_error(Motor::ERROR_BAD_TIMING);
|
||||
motors[1].disarm_with_error(Motor::ERROR_BAD_TIMING);
|
||||
}
|
||||
|
||||
// If the motor FETs are not switching then we can't measure the current
|
||||
// because for this we need the low side FET to conduct.
|
||||
// So for now we guess the current to be 0 (this is not correct shortly after
|
||||
// disarming and when the motor spins fast in idle). Passing an invalid
|
||||
// current reading would create problems with starting FOC.
|
||||
if (!(TIM1->BDTR & TIM_BDTR_MOE_Msk)) {
|
||||
current0 = {0.0f, 0.0f};
|
||||
}
|
||||
if (!(TIM8->BDTR & TIM_BDTR_MOE_Msk)) {
|
||||
current1 = {0.0f, 0.0f};
|
||||
}
|
||||
|
||||
motors[0].current_meas_cb(timestamp - TIM1_INIT_COUNT, current0);
|
||||
motors[1].current_meas_cb(timestamp, current1);
|
||||
|
||||
odrv.control_loop_cb(timestamp);
|
||||
|
||||
// By this time the ADCs for both M0 and M1 should have fired again. But
|
||||
// let's wait for them just to be sure.
|
||||
MEASURE_TIME(odrv.task_times_.dc_calib_wait) {
|
||||
while (!(ADC2->SR & ADC_SR_EOC));
|
||||
}
|
||||
|
||||
if (!fetch_and_reset_adcs(¤t0, ¤t1)) {
|
||||
motors[0].disarm_with_error(Motor::ERROR_BAD_TIMING);
|
||||
motors[1].disarm_with_error(Motor::ERROR_BAD_TIMING);
|
||||
}
|
||||
|
||||
motors[0].dc_calib_cb(timestamp + TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR + 1) - TIM1_INIT_COUNT, current0);
|
||||
motors[1].dc_calib_cb(timestamp + TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR + 1), current1);
|
||||
|
||||
motors[0].pwm_update_cb(timestamp + 3 * TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR + 1) - TIM1_INIT_COUNT);
|
||||
motors[1].pwm_update_cb(timestamp + 3 * TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR + 1));
|
||||
|
||||
// If we did everything right, the TIM8 update handler should have been
|
||||
// called exactly once between the start of this function and now.
|
||||
|
||||
if (timestamp_ != timestamp + TIM_1_8_PERIOD_CLOCKS * (TIM_1_8_RCR + 1)) {
|
||||
motors[0].disarm_with_error(Motor::ERROR_CONTROL_DEADLINE_MISSED);
|
||||
motors[1].disarm_with_error(Motor::ERROR_CONTROL_DEADLINE_MISSED);
|
||||
}
|
||||
|
||||
odrv.task_timers_armed_ = odrv.task_timers_armed_ && !TaskTimer::enabled;
|
||||
TaskTimer::enabled = false;
|
||||
}
|
||||
|
||||
void I2C1_EV_IRQHandler(void) {
|
||||
COUNT_IRQ(I2C1_EV_IRQn);
|
||||
HAL_I2C_EV_IRQHandler(&hi2c1);
|
||||
}
|
||||
|
||||
void I2C1_ER_IRQHandler(void) {
|
||||
COUNT_IRQ(I2C1_ER_IRQn);
|
||||
HAL_I2C_ER_IRQHandler(&hi2c1);
|
||||
}
|
||||
|
||||
extern PCD_HandleTypeDef hpcd_USB_OTG_FS; // defined in usbd_conf.c
|
||||
void OTG_FS_IRQHandler(void) {
|
||||
COUNT_IRQ(OTG_FS_IRQn);
|
||||
HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file startup_stm32f405xx.s
|
||||
* @author MCD Application Team
|
||||
* @brief STM32F405xx Devices vector table for GCC based toolchains.
|
||||
* This module performs:
|
||||
* - Set the initial SP
|
||||
* - Set the initial PC == Reset_Handler,
|
||||
* - Set the vector table entries with the exceptions ISR address
|
||||
* - Branches to main in the C library (which eventually
|
||||
* calls main()).
|
||||
* After Reset the Cortex-M4 processor is in Thread mode,
|
||||
* priority is Privileged, and the Stack is set to Main.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2017 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m4
|
||||
.fpu softvfp
|
||||
.thumb
|
||||
|
||||
.global g_pfnVectors
|
||||
.global Default_Handler
|
||||
|
||||
/* start address for the initialization values of the .data section.
|
||||
defined in linker script */
|
||||
.word _sidata
|
||||
/* start address for the .data section. defined in linker script */
|
||||
.word _sdata
|
||||
/* end address for the .data section. defined in linker script */
|
||||
.word _edata
|
||||
/* start address for the .bss section. defined in linker script */
|
||||
.word _sbss
|
||||
/* end address for the .bss section. defined in linker script */
|
||||
.word _ebss
|
||||
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
|
||||
|
||||
/**
|
||||
* @brief 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 main() routine is called.
|
||||
* @param None
|
||||
* @retval : None
|
||||
*/
|
||||
|
||||
.section .text.Reset_Handler
|
||||
.weak Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
ldr sp, =_estack /* set stack pointer */
|
||||
|
||||
/* Copy the data segment initializers from flash to SRAM */
|
||||
movs r1, #0
|
||||
b LoopCopyDataInit
|
||||
|
||||
CopyDataInit:
|
||||
ldr r3, =_sidata
|
||||
ldr r3, [r3, r1]
|
||||
str r3, [r0, r1]
|
||||
adds r1, r1, #4
|
||||
|
||||
LoopCopyDataInit:
|
||||
ldr r0, =_sdata
|
||||
ldr r3, =_edata
|
||||
adds r2, r0, r1
|
||||
cmp r2, r3
|
||||
bcc CopyDataInit
|
||||
ldr r2, =_sbss
|
||||
b LoopFillZerobss
|
||||
/* Zero fill the bss segment. */
|
||||
FillZerobss:
|
||||
movs r3, #0
|
||||
str r3, [r2], #4
|
||||
|
||||
LoopFillZerobss:
|
||||
ldr r3, = _ebss
|
||||
cmp r2, r3
|
||||
bcc FillZerobss
|
||||
|
||||
/* Call the clock system intitialization function.*/
|
||||
bl SystemInit
|
||||
bl early_start_checks
|
||||
|
||||
/* Call static constructors */
|
||||
bl __libc_init_array
|
||||
/* Call the application's entry point.*/
|
||||
bl main
|
||||
bx lr
|
||||
.size Reset_Handler, .-Reset_Handler
|
||||
|
||||
/**
|
||||
* @brief This is the code that gets called when the processor receives an
|
||||
* unexpected interrupt. This simply enters an infinite loop, preserving
|
||||
* the system state for examination by a debugger.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.section .text.Default_Handler,"ax",%progbits
|
||||
Default_Handler:
|
||||
Infinite_Loop:
|
||||
b Infinite_Loop
|
||||
.size Default_Handler, .-Default_Handler
|
||||
/******************************************************************************
|
||||
*
|
||||
* The minimal vector table for a Cortex M3. Note that the proper constructs
|
||||
* must be placed on this to ensure that it ends up at physical address
|
||||
* 0x0000.0000.
|
||||
*
|
||||
*******************************************************************************/
|
||||
.section .isr_vector,"a",%progbits
|
||||
.type g_pfnVectors, %object
|
||||
.size g_pfnVectors, .-g_pfnVectors
|
||||
|
||||
|
||||
|
||||
g_pfnVectors:
|
||||
.word _estack
|
||||
.word Reset_Handler
|
||||
|
||||
.word NMI_Handler
|
||||
.word HardFault_Handler
|
||||
.word MemManage_Handler
|
||||
.word BusFault_Handler
|
||||
.word UsageFault_Handler
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word SVC_Handler
|
||||
.word DebugMon_Handler
|
||||
.word 0
|
||||
.word PendSV_Handler
|
||||
.word SysTick_Handler
|
||||
|
||||
/* External Interrupts */
|
||||
.word WWDG_IRQHandler /* Window WatchDog */
|
||||
.word PVD_IRQHandler /* PVD through EXTI Line detection */
|
||||
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
|
||||
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
|
||||
.word FLASH_IRQHandler /* FLASH */
|
||||
.word RCC_IRQHandler /* RCC */
|
||||
.word EXTI0_IRQHandler /* EXTI Line0 */
|
||||
.word EXTI1_IRQHandler /* EXTI Line1 */
|
||||
.word EXTI2_IRQHandler /* EXTI Line2 */
|
||||
.word EXTI3_IRQHandler /* EXTI Line3 */
|
||||
.word EXTI4_IRQHandler /* EXTI Line4 */
|
||||
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
|
||||
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
|
||||
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
|
||||
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
|
||||
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
|
||||
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
|
||||
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
|
||||
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
|
||||
.word CAN1_TX_IRQHandler /* CAN1 TX */
|
||||
.word CAN1_RX0_IRQHandler /* CAN1 RX0 */
|
||||
.word CAN1_RX1_IRQHandler /* CAN1 RX1 */
|
||||
.word CAN1_SCE_IRQHandler /* CAN1 SCE */
|
||||
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
|
||||
.word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
|
||||
.word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
|
||||
.word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
|
||||
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
|
||||
.word TIM2_IRQHandler /* TIM2 */
|
||||
.word TIM3_IRQHandler /* TIM3 */
|
||||
.word TIM4_IRQHandler /* TIM4 */
|
||||
.word I2C1_EV_IRQHandler /* I2C1 Event */
|
||||
.word I2C1_ER_IRQHandler /* I2C1 Error */
|
||||
.word I2C2_EV_IRQHandler /* I2C2 Event */
|
||||
.word I2C2_ER_IRQHandler /* I2C2 Error */
|
||||
.word SPI1_IRQHandler /* SPI1 */
|
||||
.word SPI2_IRQHandler /* SPI2 */
|
||||
.word USART1_IRQHandler /* USART1 */
|
||||
.word USART2_IRQHandler /* USART2 */
|
||||
.word USART3_IRQHandler /* USART3 */
|
||||
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
|
||||
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
|
||||
.word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
|
||||
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
|
||||
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
|
||||
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
|
||||
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
|
||||
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
|
||||
.word FSMC_IRQHandler /* FSMC */
|
||||
.word SDIO_IRQHandler /* SDIO */
|
||||
.word TIM5_IRQHandler /* TIM5 */
|
||||
.word SPI3_IRQHandler /* SPI3 */
|
||||
.word UART4_IRQHandler /* UART4 */
|
||||
.word UART5_IRQHandler /* UART5 */
|
||||
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
|
||||
.word TIM7_IRQHandler /* TIM7 */
|
||||
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
|
||||
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
|
||||
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
|
||||
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
|
||||
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word CAN2_TX_IRQHandler /* CAN2 TX */
|
||||
.word CAN2_RX0_IRQHandler /* CAN2 RX0 */
|
||||
.word CAN2_RX1_IRQHandler /* CAN2 RX1 */
|
||||
.word CAN2_SCE_IRQHandler /* CAN2 SCE */
|
||||
.word OTG_FS_IRQHandler /* USB OTG FS */
|
||||
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
|
||||
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
|
||||
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
|
||||
.word USART6_IRQHandler /* USART6 */
|
||||
.word I2C3_EV_IRQHandler /* I2C3 event */
|
||||
.word I2C3_ER_IRQHandler /* I2C3 error */
|
||||
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
|
||||
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
|
||||
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
|
||||
.word OTG_HS_IRQHandler /* USB OTG HS */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word HASH_RNG_IRQHandler /* Hash and Rng */
|
||||
.word FPU_IRQHandler /* FPU */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Provide weak aliases for each Exception handler to the Default_Handler.
|
||||
* As they are weak aliases, any function with the same name will override
|
||||
* this definition.
|
||||
*
|
||||
*******************************************************************************/
|
||||
.weak NMI_Handler
|
||||
.thumb_set NMI_Handler,Default_Handler
|
||||
|
||||
.weak HardFault_Handler
|
||||
.thumb_set HardFault_Handler,Default_Handler
|
||||
|
||||
.weak MemManage_Handler
|
||||
.thumb_set MemManage_Handler,Default_Handler
|
||||
|
||||
.weak BusFault_Handler
|
||||
.thumb_set BusFault_Handler,Default_Handler
|
||||
|
||||
.weak UsageFault_Handler
|
||||
.thumb_set UsageFault_Handler,Default_Handler
|
||||
|
||||
.weak SVC_Handler
|
||||
.thumb_set SVC_Handler,Default_Handler
|
||||
|
||||
.weak DebugMon_Handler
|
||||
.thumb_set DebugMon_Handler,Default_Handler
|
||||
|
||||
.weak PendSV_Handler
|
||||
.thumb_set PendSV_Handler,Default_Handler
|
||||
|
||||
.weak SysTick_Handler
|
||||
.thumb_set SysTick_Handler,Default_Handler
|
||||
|
||||
.weak WWDG_IRQHandler
|
||||
.thumb_set WWDG_IRQHandler,Default_Handler
|
||||
|
||||
.weak PVD_IRQHandler
|
||||
.thumb_set PVD_IRQHandler,Default_Handler
|
||||
|
||||
.weak TAMP_STAMP_IRQHandler
|
||||
.thumb_set TAMP_STAMP_IRQHandler,Default_Handler
|
||||
|
||||
.weak RTC_WKUP_IRQHandler
|
||||
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak FLASH_IRQHandler
|
||||
.thumb_set FLASH_IRQHandler,Default_Handler
|
||||
|
||||
.weak RCC_IRQHandler
|
||||
.thumb_set RCC_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI0_IRQHandler
|
||||
.thumb_set EXTI0_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI1_IRQHandler
|
||||
.thumb_set EXTI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI2_IRQHandler
|
||||
.thumb_set EXTI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI3_IRQHandler
|
||||
.thumb_set EXTI3_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI4_IRQHandler
|
||||
.thumb_set EXTI4_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream0_IRQHandler
|
||||
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream1_IRQHandler
|
||||
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream2_IRQHandler
|
||||
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream3_IRQHandler
|
||||
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream4_IRQHandler
|
||||
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream5_IRQHandler
|
||||
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream6_IRQHandler
|
||||
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
|
||||
|
||||
.weak ADC_IRQHandler
|
||||
.thumb_set ADC_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_TX_IRQHandler
|
||||
.thumb_set CAN1_TX_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_RX0_IRQHandler
|
||||
.thumb_set CAN1_RX0_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_RX1_IRQHandler
|
||||
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN1_SCE_IRQHandler
|
||||
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI9_5_IRQHandler
|
||||
.thumb_set EXTI9_5_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_BRK_TIM9_IRQHandler
|
||||
.thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_UP_TIM10_IRQHandler
|
||||
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_TRG_COM_TIM11_IRQHandler
|
||||
.thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_CC_IRQHandler
|
||||
.thumb_set TIM1_CC_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM2_IRQHandler
|
||||
.thumb_set TIM2_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM3_IRQHandler
|
||||
.thumb_set TIM3_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM4_IRQHandler
|
||||
.thumb_set TIM4_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C1_EV_IRQHandler
|
||||
.thumb_set I2C1_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C1_ER_IRQHandler
|
||||
.thumb_set I2C1_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C2_EV_IRQHandler
|
||||
.thumb_set I2C2_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C2_ER_IRQHandler
|
||||
.thumb_set I2C2_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI1_IRQHandler
|
||||
.thumb_set SPI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI2_IRQHandler
|
||||
.thumb_set SPI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART1_IRQHandler
|
||||
.thumb_set USART1_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART2_IRQHandler
|
||||
.thumb_set USART2_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART3_IRQHandler
|
||||
.thumb_set USART3_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI15_10_IRQHandler
|
||||
.thumb_set EXTI15_10_IRQHandler,Default_Handler
|
||||
|
||||
.weak RTC_Alarm_IRQHandler
|
||||
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_FS_WKUP_IRQHandler
|
||||
.thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_BRK_TIM12_IRQHandler
|
||||
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_UP_TIM13_IRQHandler
|
||||
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_TRG_COM_TIM14_IRQHandler
|
||||
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_CC_IRQHandler
|
||||
.thumb_set TIM8_CC_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream7_IRQHandler
|
||||
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
|
||||
|
||||
.weak FSMC_IRQHandler
|
||||
.thumb_set FSMC_IRQHandler,Default_Handler
|
||||
|
||||
.weak SDIO_IRQHandler
|
||||
.thumb_set SDIO_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM5_IRQHandler
|
||||
.thumb_set TIM5_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI3_IRQHandler
|
||||
.thumb_set SPI3_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART4_IRQHandler
|
||||
.thumb_set UART4_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART5_IRQHandler
|
||||
.thumb_set UART5_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM6_DAC_IRQHandler
|
||||
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM7_IRQHandler
|
||||
.thumb_set TIM7_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream0_IRQHandler
|
||||
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream1_IRQHandler
|
||||
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream2_IRQHandler
|
||||
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream3_IRQHandler
|
||||
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream4_IRQHandler
|
||||
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_TX_IRQHandler
|
||||
.thumb_set CAN2_TX_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_RX0_IRQHandler
|
||||
.thumb_set CAN2_RX0_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_RX1_IRQHandler
|
||||
.thumb_set CAN2_RX1_IRQHandler,Default_Handler
|
||||
|
||||
.weak CAN2_SCE_IRQHandler
|
||||
.thumb_set CAN2_SCE_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_FS_IRQHandler
|
||||
.thumb_set OTG_FS_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream5_IRQHandler
|
||||
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream6_IRQHandler
|
||||
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream7_IRQHandler
|
||||
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART6_IRQHandler
|
||||
.thumb_set USART6_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_EV_IRQHandler
|
||||
.thumb_set I2C3_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_ER_IRQHandler
|
||||
.thumb_set I2C3_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_EP1_OUT_IRQHandler
|
||||
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_EP1_IN_IRQHandler
|
||||
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_WKUP_IRQHandler
|
||||
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_IRQHandler
|
||||
.thumb_set OTG_HS_IRQHandler,Default_Handler
|
||||
|
||||
.weak HASH_RNG_IRQHandler
|
||||
.thumb_set HASH_RNG_IRQHandler,Default_Handler
|
||||
|
||||
.weak FPU_IRQHandler
|
||||
.thumb_set FPU_IRQHandler,Default_Handler
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
|
||||
#include "drv8301.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "cmsis_os.h"
|
||||
#include "board.h"
|
||||
|
||||
const SPI_InitTypeDef Drv8301::spi_config_ = {
|
||||
.Mode = SPI_MODE_MASTER,
|
||||
.Direction = SPI_DIRECTION_2LINES,
|
||||
.DataSize = SPI_DATASIZE_16BIT,
|
||||
.CLKPolarity = SPI_POLARITY_LOW,
|
||||
.CLKPhase = SPI_PHASE_2EDGE,
|
||||
.NSS = SPI_NSS_SOFT,
|
||||
.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16,
|
||||
.FirstBit = SPI_FIRSTBIT_MSB,
|
||||
.TIMode = SPI_TIMODE_DISABLE,
|
||||
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
|
||||
.CRCPolynomial = 10,
|
||||
};
|
||||
|
||||
bool Drv8301::config(float requested_gain, float* actual_gain) {
|
||||
// Calculate gain setting: Snap down to have equal or larger range as
|
||||
// requested or largest possible range otherwise
|
||||
|
||||
// for reference:
|
||||
// 20V/V on 500uOhm gives a range of +/- 150A
|
||||
// 40V/V on 500uOhm gives a range of +/- 75A
|
||||
// 20V/V on 666uOhm gives a range of +/- 110A
|
||||
// 40V/V on 666uOhm gives a range of +/- 55A
|
||||
|
||||
uint16_t gain_setting = 3;
|
||||
float gain_choices[] = {10.0f, 20.0f, 40.0f, 80.0f};
|
||||
while (gain_setting && (gain_choices[gain_setting] > requested_gain)) {
|
||||
gain_setting--;
|
||||
}
|
||||
|
||||
if (actual_gain) {
|
||||
*actual_gain = gain_choices[gain_setting];
|
||||
}
|
||||
|
||||
RegisterFile new_config;
|
||||
|
||||
new_config.control_register_1 =
|
||||
(21 << 6) // Overcurrent set to approximately 150A at 100degC. This may need tweaking.
|
||||
| (0b01 << 4) // OCP_MODE: latch shut down
|
||||
| (0b0 << 3) // 6x PWM mode
|
||||
| (0b0 << 2) // don't reset latched faults
|
||||
| (0b00 << 0); // gate-drive peak current: 1.7A
|
||||
|
||||
new_config.control_register_2 =
|
||||
(0b0 << 6) // OC_TOFF: cycle by cycle
|
||||
| (0b00 << 4) // calibration off (normal operation)
|
||||
| (gain_setting << 2) // select gain
|
||||
| (0b00 << 0); // report both over temperature and over current on nOCTW pin
|
||||
|
||||
bool regs_equal = (regs_.control_register_1 == new_config.control_register_1)
|
||||
&& (regs_.control_register_2 == new_config.control_register_2);
|
||||
|
||||
if (!regs_equal) {
|
||||
regs_ = new_config;
|
||||
state_ = kStateUninitialized;
|
||||
enable_gpio_.write(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Drv8301::init() {
|
||||
uint16_t val;
|
||||
|
||||
if (state_ == kStateReady) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reset DRV chip. The enable pin also controls the SPI interface, not only
|
||||
// the driver stages.
|
||||
enable_gpio_.write(false);
|
||||
delay_us(40); // mimumum pull-down time for full reset: 20us
|
||||
state_ = kStateUninitialized; // make is_ready() ignore transient errors before registers are set up
|
||||
enable_gpio_.write(true);
|
||||
osDelay(20); // t_spi_ready, max = 10ms
|
||||
|
||||
// Write current configuration
|
||||
bool wrote_regs = write_reg(kRegNameControl1, regs_.control_register_1)
|
||||
&& write_reg(kRegNameControl1, regs_.control_register_1)
|
||||
&& write_reg(kRegNameControl1, regs_.control_register_1)
|
||||
&& write_reg(kRegNameControl1, regs_.control_register_1)
|
||||
&& write_reg(kRegNameControl1, regs_.control_register_1) // the write operation tends to be ignored if only done once (not sure why)
|
||||
&& write_reg(kRegNameControl2, regs_.control_register_2);
|
||||
if (!wrote_regs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for configuration to be applied
|
||||
delay_us(100);
|
||||
state_ = kStateStartupChecks;
|
||||
|
||||
bool is_read_regs = read_reg(kRegNameControl1, &val) && (val == regs_.control_register_1)
|
||||
&& read_reg(kRegNameControl2, &val) && (val == regs_.control_register_2);
|
||||
if (!is_read_regs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_error() != FaultType_NoFault) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There could have been an nFAULT edge meanwhile. In this case we shouldn't
|
||||
// consider the driver ready.
|
||||
CRITICAL_SECTION() {
|
||||
if (state_ == kStateStartupChecks) {
|
||||
state_ = kStateReady;
|
||||
}
|
||||
}
|
||||
|
||||
return state_ == kStateReady;
|
||||
}
|
||||
|
||||
void Drv8301::do_checks() {
|
||||
if (state_ != kStateUninitialized && !nfault_gpio_.read()) {
|
||||
state_ = kStateUninitialized;
|
||||
}
|
||||
}
|
||||
|
||||
bool Drv8301::is_ready() {
|
||||
return state_ == kStateReady;
|
||||
}
|
||||
|
||||
Drv8301::FaultType_e Drv8301::get_error() {
|
||||
uint16_t fault1, fault2;
|
||||
|
||||
if (!read_reg(kRegNameStatus1, &fault1) ||
|
||||
!read_reg(kRegNameStatus2, &fault2)) {
|
||||
return (FaultType_e)0xffffffff;
|
||||
}
|
||||
|
||||
return (FaultType_e)((uint32_t)fault1 | ((uint32_t)(fault2 & 0x0080) << 16));
|
||||
}
|
||||
|
||||
bool Drv8301::read_reg(const RegName_e regName, uint16_t* data) {
|
||||
tx_buf_ = build_ctrl_word(DRV8301_CtrlMode_Read, regName, 0);
|
||||
if (!spi_arbiter_->transfer(spi_config_, ncs_gpio_, (uint8_t *)(&tx_buf_), nullptr, 1, 1000)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delay_us(1);
|
||||
|
||||
tx_buf_ = build_ctrl_word(DRV8301_CtrlMode_Read, regName, 0);
|
||||
rx_buf_ = 0xffff;
|
||||
if (!spi_arbiter_->transfer(spi_config_, ncs_gpio_, (uint8_t *)(&tx_buf_), (uint8_t *)(&rx_buf_), 1, 1000)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delay_us(1);
|
||||
|
||||
if (rx_buf_ == 0xbeef) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
*data = rx_buf_ & 0x07FF;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Drv8301::write_reg(const RegName_e regName, const uint16_t data) {
|
||||
// Do blocking write
|
||||
tx_buf_ = build_ctrl_word(DRV8301_CtrlMode_Write, regName, data);
|
||||
if (!spi_arbiter_->transfer(spi_config_, ncs_gpio_, (uint8_t *)(&tx_buf_), nullptr, 1, 1000)) {
|
||||
return false;
|
||||
}
|
||||
delay_us(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#ifndef __DRV8301_HPP
|
||||
#define __DRV8301_HPP
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "stdint.h"
|
||||
|
||||
#include <Drivers/gate_driver.hpp>
|
||||
#include <Drivers/STM32/stm32_spi_arbiter.hpp>
|
||||
#include <Drivers/STM32/stm32_gpio.hpp>
|
||||
|
||||
|
||||
class Drv8301 : public GateDriverBase, public OpAmpBase {
|
||||
public:
|
||||
typedef enum : uint32_t {
|
||||
FaultType_NoFault = (0 << 0), //!< No fault
|
||||
|
||||
// Status Register 1
|
||||
FaultType_FETLC_OC = (1 << 0), //!< FET Low side, Phase C Over Current fault
|
||||
FaultType_FETHC_OC = (1 << 1), //!< FET High side, Phase C Over Current fault
|
||||
FaultType_FETLB_OC = (1 << 2), //!< FET Low side, Phase B Over Current fault
|
||||
FaultType_FETHB_OC = (1 << 3), //!< FET High side, Phase B Over Current fault
|
||||
FaultType_FETLA_OC = (1 << 4), //!< FET Low side, Phase A Over Current fault
|
||||
FaultType_FETHA_OC = (1 << 5), //!< FET High side, Phase A Over Current fault
|
||||
FaultType_OTW = (1 << 6), //!< Over Temperature Warning fault
|
||||
FaultType_OTSD = (1 << 7), //!< Over Temperature Shut Down fault
|
||||
FaultType_PVDD_UV = (1 << 8), //!< Power supply Vdd Under Voltage fault
|
||||
FaultType_GVDD_UV = (1 << 9), //!< DRV8301 Vdd Under Voltage fault
|
||||
FaultType_FAULT = (1 << 10),
|
||||
|
||||
// Status Register 2
|
||||
FaultType_GVDD_OV = (1 << 23) //!< DRV8301 Vdd Over Voltage fault
|
||||
} FaultType_e;
|
||||
|
||||
Drv8301(Stm32SpiArbiter* spi_arbiter, Stm32Gpio ncs_gpio,
|
||||
Stm32Gpio enable_gpio, Stm32Gpio nfault_gpio)
|
||||
: spi_arbiter_(spi_arbiter), ncs_gpio_(ncs_gpio),
|
||||
enable_gpio_(enable_gpio), nfault_gpio_(nfault_gpio) {}
|
||||
|
||||
/**
|
||||
* @brief Prepares the gate driver's configuration.
|
||||
*
|
||||
* If the gate driver was in ready state and the new configuration is
|
||||
* different from the old one then the gate driver will exit ready state.
|
||||
*
|
||||
* In any case changes to the configuration only take effect with a call to
|
||||
* init().
|
||||
*/
|
||||
bool config(float requested_gain, float* actual_gain);
|
||||
|
||||
/**
|
||||
* @brief Initializes the gate driver to the configuration prepared with
|
||||
* config().
|
||||
*
|
||||
* Returns true on success or false otherwise (e.g. if the gate driver is
|
||||
* not connected or not powered or if config() was not yet called).
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief Monitors the nFAULT pin.
|
||||
*
|
||||
* This must be run at an interval of <8ms from the moment the init()
|
||||
* functions starts to run, otherwise it's possible that a temporary power
|
||||
* loss is missed, leading to unwanted register values.
|
||||
* In case of power loss the nFAULT pin can be low for as little as 8ms.
|
||||
*/
|
||||
void do_checks();
|
||||
|
||||
/**
|
||||
* @brief Returns true if and only if the DRV8301 chip is in an initialized
|
||||
* state and ready to do switching and current sensor opamp operation.
|
||||
*/
|
||||
bool is_ready() final;
|
||||
|
||||
/**
|
||||
* @brief This has no effect on this driver chip because the drive stages are
|
||||
* always enabled while the chip is initialized
|
||||
*/
|
||||
bool set_enabled(bool enabled) final { return true; }
|
||||
|
||||
FaultType_e get_error();
|
||||
|
||||
float get_midpoint() final {
|
||||
return 0.5f; // [V]
|
||||
}
|
||||
|
||||
float get_max_output_swing() final {
|
||||
return 1.35f / 1.65f; // +-1.35V, normalized from a scale of +-1.65V to +-0.5
|
||||
}
|
||||
|
||||
private:
|
||||
enum CtrlMode_e {
|
||||
DRV8301_CtrlMode_Read = 1 << 15, //!< Read Mode
|
||||
DRV8301_CtrlMode_Write = 0 << 15 //!< Write Mode
|
||||
};
|
||||
|
||||
enum RegName_e {
|
||||
kRegNameStatus1 = 0 << 11, //!< Status Register 1
|
||||
kRegNameStatus2 = 1 << 11, //!< Status Register 2
|
||||
kRegNameControl1 = 2 << 11, //!< Control Register 1
|
||||
kRegNameControl2 = 3 << 11 //!< Control Register 2
|
||||
};
|
||||
|
||||
struct RegisterFile {
|
||||
uint16_t control_register_1;
|
||||
uint16_t control_register_2;
|
||||
};
|
||||
|
||||
static inline uint16_t build_ctrl_word(const CtrlMode_e ctrlMode,
|
||||
const RegName_e regName,
|
||||
const uint16_t data) {
|
||||
return ctrlMode | regName | (data & 0x07FF);
|
||||
}
|
||||
|
||||
/** @brief Reads data from a DRV8301 register */
|
||||
bool read_reg(const RegName_e regName, uint16_t* data);
|
||||
|
||||
/** @brief Writes data to a DRV8301 register. There is no check if the write succeeded. */
|
||||
bool write_reg(const RegName_e regName, const uint16_t data);
|
||||
|
||||
static const SPI_InitTypeDef spi_config_;
|
||||
|
||||
// Configuration
|
||||
Stm32SpiArbiter* spi_arbiter_;
|
||||
Stm32Gpio ncs_gpio_;
|
||||
Stm32Gpio enable_gpio_;
|
||||
Stm32Gpio nfault_gpio_;
|
||||
|
||||
RegisterFile regs_; //!< Current configuration. If is_ready_ is
|
||||
//!< true then this can be considered consistent
|
||||
//!< with the actual file on the DRV8301 chip.
|
||||
|
||||
// We don't put these buffers on the stack because we place the stack in
|
||||
// a RAM section which cannot be used by DMA.
|
||||
uint16_t tx_buf_, rx_buf_;
|
||||
|
||||
enum {
|
||||
kStateUninitialized,
|
||||
kStateStartupChecks,
|
||||
kStateReady,
|
||||
} state_ = kStateUninitialized;
|
||||
};
|
||||
|
||||
|
||||
#endif // __DRV8301_HPP
|
||||
@@ -0,0 +1,234 @@
|
||||
|
||||
#include "stm32_gpio.hpp"
|
||||
|
||||
#define N_EXTI 16
|
||||
|
||||
struct subscription_t {
|
||||
GPIO_TypeDef* port = nullptr;
|
||||
void (*callback)(void*) = nullptr;
|
||||
void* ctx = nullptr;
|
||||
} subscriptions[N_EXTI];
|
||||
|
||||
const Stm32Gpio Stm32Gpio::none{nullptr, 0};
|
||||
|
||||
/**
|
||||
* @brief Returns the IRQ number associated with a certain pin.
|
||||
* Note that all GPIOs with the same pin number map to the same IRQn,
|
||||
* no matter which port they belong to.
|
||||
*/
|
||||
static inline IRQn_Type get_irq_number(uint16_t pin_number) {
|
||||
switch (pin_number) {
|
||||
case 0: return EXTI0_IRQn;
|
||||
case 1: return EXTI1_IRQn;
|
||||
case 2: return EXTI2_IRQn;
|
||||
case 3: return EXTI3_IRQn;
|
||||
case 4: return EXTI4_IRQn;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9: return EXTI9_5_IRQn;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15: return EXTI15_10_IRQn;
|
||||
default: return (IRQn_Type)0; // impossible
|
||||
}
|
||||
}
|
||||
|
||||
#define GPIO_MODE 0x00000003U
|
||||
#define GPIO_OUTPUT_TYPE 0x00000010U
|
||||
|
||||
|
||||
bool Stm32Gpio::config(uint32_t mode, uint32_t pull, uint32_t speed) {
|
||||
if (port_ == GPIOA) {
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
} else if (port_ == GPIOB) {
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
} else if (port_ == GPIOC) {
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
} else if (port_ == GPIOD) {
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
} else if (port_ == GPIOE) {
|
||||
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||||
} else if (port_ == GPIOF) {
|
||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||
} else if (port_ == GPIOG) {
|
||||
__HAL_RCC_GPIOG_CLK_ENABLE();
|
||||
} else if (port_ == GPIOH) {
|
||||
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t position = get_pin_number();
|
||||
|
||||
// The following code is mostly taken from HAL_GPIO_Init
|
||||
|
||||
/* Configure IO Direction mode (Input, Output, Alternate or Analog) */
|
||||
uint32_t temp = port_->MODER;
|
||||
temp &= ~(GPIO_MODER_MODER0 << (position * 2U));
|
||||
temp |= ((mode & GPIO_MODE) << (position * 2U));
|
||||
port_->MODER = temp;
|
||||
|
||||
/* In case of Output or Alternate function mode selection */
|
||||
if((mode == GPIO_MODE_OUTPUT_PP) || (mode == GPIO_MODE_AF_PP) ||
|
||||
(mode == GPIO_MODE_OUTPUT_OD) || (mode == GPIO_MODE_AF_OD))
|
||||
{
|
||||
/* Check the Speed parameter */
|
||||
assert_param(IS_GPIO_SPEED(speed));
|
||||
/* Configure the IO Speed */
|
||||
temp = port_->OSPEEDR;
|
||||
temp &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2U));
|
||||
temp |= (speed << (position * 2U));
|
||||
port_->OSPEEDR = temp;
|
||||
|
||||
/* Configure the IO Output Type */
|
||||
temp = port_->OTYPER;
|
||||
temp &= ~(GPIO_OTYPER_OT_0 << position) ;
|
||||
temp |= (((mode & GPIO_OUTPUT_TYPE) >> 4U) << position);
|
||||
port_->OTYPER = temp;
|
||||
}
|
||||
|
||||
/* Activate the Pull-up or Pull down resistor for the current IO */
|
||||
temp = port_->PUPDR;
|
||||
temp &= ~(GPIO_PUPDR_PUPDR0 << (position * 2U));
|
||||
temp |= ((pull) << (position * 2U));
|
||||
port_->PUPDR = temp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Stm32Gpio::subscribe(bool rising_edge, bool falling_edge, void (*callback)(void*), void* ctx) {
|
||||
uint32_t pin_number = get_pin_number();
|
||||
if (pin_number >= N_EXTI) {
|
||||
return false; // invalid pin number
|
||||
}
|
||||
|
||||
struct subscription_t& subscription = subscriptions[pin_number];
|
||||
|
||||
GPIO_TypeDef* no_port = nullptr;
|
||||
if (!__atomic_compare_exchange_n(&subscription.port, &no_port, port_, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
|
||||
return false; // already in use
|
||||
}
|
||||
|
||||
// The following code is mostly taken from HAL_GPIO_Init
|
||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||
|
||||
uint32_t temp = SYSCFG->EXTICR[pin_number >> 2U];
|
||||
temp &= ~(0x0FU << (4U * (pin_number & 0x03U)));
|
||||
temp |= ((uint32_t)(GPIO_GET_INDEX(port_)) << (4U * (pin_number & 0x03U)));
|
||||
SYSCFG->EXTICR[pin_number >> 2U] = temp;
|
||||
|
||||
|
||||
if (rising_edge) {
|
||||
EXTI->RTSR |= (uint32_t)pin_mask_;
|
||||
} else {
|
||||
EXTI->RTSR &= ~((uint32_t)pin_mask_);
|
||||
}
|
||||
|
||||
if (falling_edge) {
|
||||
EXTI->FTSR |= (uint32_t)pin_mask_;
|
||||
} else {
|
||||
EXTI->FTSR &= ~((uint32_t)pin_mask_);
|
||||
}
|
||||
|
||||
EXTI->EMR &= ~((uint32_t)pin_mask_);
|
||||
EXTI->IMR |= (uint32_t)pin_mask_;
|
||||
|
||||
// Clear any previous triggers
|
||||
__HAL_GPIO_EXTI_CLEAR_IT(pin_mask_);
|
||||
|
||||
subscription.ctx = ctx;
|
||||
subscription.callback = callback;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Stm32Gpio::unsubscribe() {
|
||||
uint32_t pin_number = get_pin_number();
|
||||
if (pin_number >= N_EXTI) {
|
||||
return; // invalid pin number
|
||||
}
|
||||
|
||||
struct subscription_t& subscription = subscriptions[pin_number];
|
||||
|
||||
if (subscription.port != port_) {
|
||||
return; // the subscription was not for this GPIO
|
||||
}
|
||||
|
||||
EXTI->IMR |= (uint32_t)pin_mask_;
|
||||
__HAL_GPIO_EXTI_CLEAR_IT(pin_mask_);
|
||||
|
||||
// At this point no more interrupts will be triggered for this GPIO
|
||||
|
||||
subscription.callback = nullptr;
|
||||
subscription.ctx = nullptr;
|
||||
subscription.port = nullptr; // after this line, the subscription can be reused (possibly by another thread)
|
||||
}
|
||||
|
||||
void maybe_handle(uint16_t exti_number) {
|
||||
if(__HAL_GPIO_EXTI_GET_IT(1 << exti_number) == RESET) {
|
||||
return; // This interrupt source did not trigger the interrupt line
|
||||
}
|
||||
|
||||
__HAL_GPIO_EXTI_CLEAR_IT(1 << exti_number);
|
||||
|
||||
if (exti_number >= N_EXTI) {
|
||||
return;
|
||||
}
|
||||
|
||||
subscription_t& subscription = subscriptions[exti_number];
|
||||
if (subscription.callback) {
|
||||
(*subscription.callback)(subscription.ctx);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
/** @brief Entrypoint for the EXTI line 0 interrupt. */
|
||||
void EXTI0_IRQHandler(void) {
|
||||
maybe_handle(0);
|
||||
}
|
||||
|
||||
/** @brief Entrypoint for the EXTI line 1 interrupt. */
|
||||
void EXTI1_IRQHandler(void) {
|
||||
maybe_handle(1);
|
||||
}
|
||||
|
||||
/** @brief Entrypoint for the EXTI line 2 interrupt. */
|
||||
void EXTI2_IRQHandler(void) {
|
||||
maybe_handle(2);
|
||||
}
|
||||
|
||||
/** @brief Entrypoint for the EXTI line 3 interrupt. */
|
||||
void EXTI3_IRQHandler(void) {
|
||||
maybe_handle(3);
|
||||
}
|
||||
|
||||
/** @brief Entrypoint for the EXTI line 4 interrupt. */
|
||||
void EXTI4_IRQHandler(void) {
|
||||
maybe_handle(4);
|
||||
}
|
||||
|
||||
/** @brief Entrypoint for the EXTI lines 5-9 interrupt. */
|
||||
void EXTI9_5_IRQHandler(void) {
|
||||
maybe_handle(5);
|
||||
maybe_handle(6);
|
||||
maybe_handle(7);
|
||||
maybe_handle(8);
|
||||
maybe_handle(9);
|
||||
}
|
||||
|
||||
/** @brief This function handles EXTI lines 10-15 interrupt. */
|
||||
void EXTI15_10_IRQHandler(void) {
|
||||
maybe_handle(10);
|
||||
maybe_handle(11);
|
||||
maybe_handle(12);
|
||||
maybe_handle(13);
|
||||
maybe_handle(14);
|
||||
maybe_handle(15);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#ifndef __STM32_GPIO_HPP
|
||||
#define __STM32_GPIO_HPP
|
||||
|
||||
#include <gpio.h>
|
||||
|
||||
class Stm32Gpio {
|
||||
public:
|
||||
static const Stm32Gpio none;
|
||||
|
||||
Stm32Gpio() : port_(nullptr), pin_mask_(0) {}
|
||||
Stm32Gpio(GPIO_TypeDef* port, uint16_t pin) : port_(port), pin_mask_(pin) {}
|
||||
|
||||
operator bool() const { return port_ && pin_mask_; }
|
||||
|
||||
/**
|
||||
* @brief Configures the GPIO with the specified parameters.
|
||||
*
|
||||
* This can be done regardless of the current state of the GPIO.
|
||||
*
|
||||
* If any subscription is in place, it is not disabled by this function.
|
||||
*/
|
||||
bool config(uint32_t mode, uint32_t pull, uint32_t speed = GPIO_SPEED_FREQ_LOW);
|
||||
|
||||
void write(bool state) {
|
||||
if (port_) {
|
||||
HAL_GPIO_WritePin(port_, pin_mask_, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
bool read() {
|
||||
return port_ && (port_->IDR & pin_mask_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Subscribes to external interrupts on the specified GPIO.
|
||||
*
|
||||
* Before calling this function the gpio should most likely be configured as
|
||||
* input (however this is not mandatory, the interrupt works in output mode
|
||||
* too).
|
||||
* Also you need to enable the EXTIx_IRQn interrupt vectors in the NVIC,
|
||||
* otherwise the subscription won't have any effect.
|
||||
*
|
||||
* Only one subscription is allowed per pin number. I.e. it is not possible
|
||||
* to set up a subscription for both PA0 and PB0 at the same time.
|
||||
*
|
||||
* This function is thread-safe with respect to all other public functions
|
||||
* of this class.
|
||||
*
|
||||
* Returns true if the subscription was set up successfully or false otherwise.
|
||||
*/
|
||||
bool subscribe(bool rising_edge, bool falling_edge, void (*callback)(void*), void* ctx);
|
||||
|
||||
/**
|
||||
* @brief Unsubscribes from external interrupt on the specified GPIO.
|
||||
*
|
||||
* If no subscription was active for this GPIO, calling this function has no
|
||||
* effect.
|
||||
*
|
||||
* This function is thread-safe with respect to all other public functions
|
||||
* of this class, however it must not be called from an interrupt routine
|
||||
* running at a higher priority than the interrupt that is being unsubscribed.
|
||||
*
|
||||
* After this function returns the callback given to subscribe() will no
|
||||
* longer be invoked.
|
||||
*/
|
||||
void unsubscribe();
|
||||
|
||||
uint16_t get_pin_number() {
|
||||
uint16_t pin_number = 0;
|
||||
uint16_t pin_mask = pin_mask_ >> 1;
|
||||
while (pin_mask) {
|
||||
pin_mask >>= 1;
|
||||
pin_number++;
|
||||
}
|
||||
return pin_number;
|
||||
}
|
||||
|
||||
GPIO_TypeDef* port_;
|
||||
uint16_t pin_mask_; // TODO: store pin_number_ instead of pin_mask_
|
||||
};
|
||||
|
||||
#endif // __STM32_GPIO_HPP
|
||||
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Flash-based Non-Volatile Memory (NVM)
|
||||
*
|
||||
* This file supports storing and loading persistent configuration based on
|
||||
* the STM32 builtin flash memory.
|
||||
*
|
||||
* The STM32F405xx has 12 flash sectors of heterogeneous size. We use the last
|
||||
* two sectors for configuration data. These pages have a size of 128kB each.
|
||||
* Setting any bit in these sectors to 0 is always possible, but setting them
|
||||
* to 1 requires erasing the whole sector.
|
||||
*
|
||||
* We consider each sector as an array of 64-bit fields except the first N bytes, which we
|
||||
* instead use as an allocation block. The allocation block is a compact bit-field (2 bit per entry)
|
||||
* that keeps track of the state of each field (erased, invalid, valid).
|
||||
*
|
||||
* One sector is always considered the valid (read) sector and the other one is the
|
||||
* target for the next write access: they can be considered to be ping-pong or double buffred.
|
||||
*
|
||||
* When writing a block of data, instead of always erasing the whole writable sector the
|
||||
* new data is appended in the erased area. This presumably increases flash life span.
|
||||
* The writable sector is only erased if there is not enough space for the new data.
|
||||
*
|
||||
* On startup, if there is exactly one sector
|
||||
* whose last non-erased value has the state "valid" that sector is considered
|
||||
* the valid sector. In any other case the selection is undefined.
|
||||
*
|
||||
*
|
||||
* To write a new block of data atomically we first mark all associated fields
|
||||
* as "invalid" (in the allocation table) then write the data and then mark the
|
||||
* fields as "valid" (in the direction of increasing address).
|
||||
*/
|
||||
|
||||
#include "stm32_nvm.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(STM32F405xx)
|
||||
|
||||
#include <stm32f405xx.h>
|
||||
#include <stm32f4xx_hal.h>
|
||||
|
||||
// refer to page 75 of datasheet:
|
||||
// http://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf
|
||||
#define FLASH_SECTOR_A FLASH_SECTOR_10
|
||||
#define FLASH_SECTOR_A_BASE (const volatile uint8_t*)0x80C0000UL
|
||||
#define FLASH_SECTOR_A_SIZE 0x20000UL
|
||||
#define FLASH_SECTOR_B FLASH_SECTOR_11
|
||||
#define FLASH_SECTOR_B_BASE (const volatile uint8_t*)0x80E0000UL
|
||||
#define FLASH_SECTOR_B_SIZE 0x20000UL
|
||||
|
||||
#elif defined(STM32F722xx)
|
||||
|
||||
#include <stm32f722xx.h>
|
||||
#include <stm32f7xx_hal.h>
|
||||
|
||||
// refer to page 68 of datasheet:
|
||||
// https://www.st.com/resource/en/reference_manual/dm00305990-stm32f72xxx-and-stm32f73xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
|
||||
#define FLASH_SECTOR_A FLASH_SECTOR_1
|
||||
#define FLASH_SECTOR_A_BASE (const volatile uint8_t*)0x8004000UL
|
||||
#define FLASH_SECTOR_A_SIZE 0x4000UL
|
||||
#define FLASH_SECTOR_B FLASH_SECTOR_2
|
||||
#define FLASH_SECTOR_B_BASE (const volatile uint8_t*)0x8008000UL
|
||||
#define FLASH_SECTOR_B_SIZE 0x4000UL
|
||||
|
||||
#else
|
||||
#error "unknown flash sector size"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
VALID = 0,
|
||||
INVALID = 1,
|
||||
ERASED = 3
|
||||
} field_state_t;
|
||||
|
||||
typedef struct {
|
||||
size_t index; //!< next field to be written to (can be equal to n_data)
|
||||
const uint32_t sector_id; //!< HAL ID of this sector
|
||||
const size_t n_data; //!< number of 64-bit fields in this sector
|
||||
const size_t n_reserved; //!< number of 64-bit fields in this sector that are reserved for the allocation table
|
||||
const volatile uint8_t* const alloc_table;
|
||||
const volatile uint64_t* const data;
|
||||
} sector_t;
|
||||
|
||||
sector_t sectors[] = { {
|
||||
.sector_id = FLASH_SECTOR_A,
|
||||
.n_data = FLASH_SECTOR_A_SIZE >> 3,
|
||||
.n_reserved = (FLASH_SECTOR_A_SIZE >> 3) >> 5,
|
||||
.alloc_table = FLASH_SECTOR_A_BASE,
|
||||
.data = (uint64_t *)FLASH_SECTOR_A_BASE
|
||||
}, {
|
||||
.sector_id = FLASH_SECTOR_B,
|
||||
.n_data = FLASH_SECTOR_B_SIZE >> 3,
|
||||
.n_reserved = (FLASH_SECTOR_B_SIZE >> 3) >> 5,
|
||||
.alloc_table = FLASH_SECTOR_B_BASE,
|
||||
.data = (uint64_t *)FLASH_SECTOR_B_BASE
|
||||
}};
|
||||
|
||||
uint8_t read_sector_; // 0 or 1 to indicate which sector to read from and which to write to
|
||||
size_t n_staging_area_; // number of 64-bit values that were reserved using NVM_start_write
|
||||
size_t n_valid_; // number of 64-bit fields that can be read
|
||||
|
||||
static const uint32_t FLASH_ERR_FLAGS =
|
||||
#if defined(FLASH_FLAG_EOP)
|
||||
FLASH_FLAG_EOP |
|
||||
#endif
|
||||
#if defined(FLASH_FLAG_OPERR)
|
||||
FLASH_FLAG_OPERR |
|
||||
#endif
|
||||
#if defined(FLASH_FLAG_WRPERR)
|
||||
FLASH_FLAG_WRPERR |
|
||||
#endif
|
||||
#if defined(FLASH_FLAG_PGAERR)
|
||||
FLASH_FLAG_PGAERR |
|
||||
#endif
|
||||
#if defined(FLASH_FLAG_PGSERR)
|
||||
FLASH_FLAG_PGSERR |
|
||||
#endif
|
||||
#if defined(FLASH_FLAG_PGPERR)
|
||||
FLASH_FLAG_PGPERR |
|
||||
#endif
|
||||
0;
|
||||
|
||||
static void HAL_FLASH_ClearError() {
|
||||
__HAL_FLASH_CLEAR_FLAG(FLASH_ERR_FLAGS);
|
||||
}
|
||||
|
||||
|
||||
// @brief Erases a flash sector. This sets all bits in the sector to 1.
|
||||
// The sector's current index is reset to the minimum value (n_reserved).
|
||||
// @returns 0 on success or a non-zero error code otherwise
|
||||
int erase(sector_t *sector) {
|
||||
FLASH_EraseInitTypeDef erase_struct = {
|
||||
.TypeErase = FLASH_TYPEERASE_SECTORS,
|
||||
#if defined(FLASH_OPTCR_nDBANK)
|
||||
.Banks = 0, // only used for mass erase
|
||||
#endif
|
||||
.Sector = sector->sector_id,
|
||||
.NbSectors = 1,
|
||||
.VoltageRange = FLASH_VOLTAGE_RANGE_3
|
||||
};
|
||||
HAL_FLASH_Unlock();
|
||||
HAL_FLASH_ClearError();
|
||||
uint32_t sector_error;
|
||||
if (HAL_FLASHEx_Erase(&erase_struct, §or_error) != HAL_OK)
|
||||
goto fail;
|
||||
sector->index = sector->n_reserved;
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return 0;
|
||||
fail:
|
||||
HAL_FLASH_Lock();
|
||||
//printf("erase failed: %u \r\n", HAL_FLASH_GetError());
|
||||
return HAL_FLASH_GetError(); // non-zero
|
||||
}
|
||||
|
||||
|
||||
// @brief Writes states into the allocation table.
|
||||
// The write operation goes in the direction of increasing indices.
|
||||
// @param state: 11: erased, 10: writing, 00: valid data
|
||||
// @returns 0 on success or a non-zero error code otherwise
|
||||
int set_allocation_state(sector_t *sector, size_t index, size_t count, field_state_t state) {
|
||||
if (index < sector->n_reserved)
|
||||
return -1;
|
||||
if (index + count >= sector->n_data)
|
||||
return -1;
|
||||
|
||||
// expand state to state for 4 values
|
||||
const uint8_t states = (state << 0) | (state << 2) | (state << 4) | (state << 6);
|
||||
|
||||
// handle unaligned start
|
||||
uint8_t mask = ~(0xff << ((index & 0x3) << 1));
|
||||
count += index & 0x3;
|
||||
index -= index & 0x3;
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
HAL_FLASH_ClearError();
|
||||
|
||||
// write states
|
||||
for (; count >= 4; count -= 4, index += 4) {
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, (uintptr_t)§or->alloc_table[index >> 2], states | mask) != HAL_OK)
|
||||
goto fail;
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
// handle unaligned end
|
||||
if (count) {
|
||||
mask |= ~(0xff >> ((4 - count) << 1));
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, (uintptr_t)§or->alloc_table[index >> 2], states | mask) != HAL_OK)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return 0;
|
||||
fail:
|
||||
HAL_FLASH_Lock();
|
||||
return HAL_FLASH_GetError(); // non-zero
|
||||
}
|
||||
|
||||
// @brief Reads the allocation table from behind to determine how many fields match the
|
||||
// reference state.
|
||||
// @param sector: The sector on which to perform the search
|
||||
// @param max_index: The maximum index that should be considered
|
||||
// @param ref_state: The reference state
|
||||
// @param state: Set to the first encountered state that is unequal to ref_state.
|
||||
// Set to ref_state if all encountered states are equal to ref_state.
|
||||
// @returns The smallest index that points to a field with ref_state.
|
||||
// This value is at least sector->n_reserved and at most max_index.
|
||||
size_t scan_allocation_table(sector_t *sector, size_t max_index, field_state_t ref_state, field_state_t *state) {
|
||||
const uint8_t ref_states = (ref_state << 0) | (ref_state << 2) | (ref_state << 4) | (ref_state << 6);
|
||||
size_t index = (((max_index + 3) >> 2) << 2); // start at the max index but round up to a multiple of 4
|
||||
size_t ignore = index - max_index;
|
||||
uint8_t states = ref_states;
|
||||
|
||||
//printf("scan from %08x to %08x for %02x\r\n", index, sector->n_reserved, ref_states); osDelay(5);
|
||||
|
||||
// read 4 states at a time
|
||||
for (; index >= (sector->n_reserved + 4); index -= 4) {
|
||||
states = sector->alloc_table[(index - 1) >> 2];
|
||||
if (ignore) { // ignore the upper 1, 2 or 3 states if max_index was unaligned
|
||||
uint8_t ignore_mask = ~(0xff >> (ignore << 1));
|
||||
states = (states & ~ignore_mask) | (ref_states & ignore_mask);
|
||||
ignore = 0;
|
||||
}
|
||||
if (states != ref_states)
|
||||
break;
|
||||
}
|
||||
|
||||
// once we encounterd a byte with any state mismatch determine which of the 4 states it is
|
||||
for (; ((states >> 6) == (ref_states & 0x3)) && (index > sector->n_reserved); index--) {
|
||||
states <<= 2;
|
||||
}
|
||||
|
||||
*state = states >> 6;
|
||||
//printf("(it's %02x)\r\n", index); osDelay(5);
|
||||
return index;
|
||||
}
|
||||
|
||||
// Loads the head of the NVM data.
|
||||
// If this function fails subsequent calls to NVM functions (other than NVM_init or NVM_erase)
|
||||
// cause undefined behavior.
|
||||
// @returns 0 on success or a non-zero error code otherwise
|
||||
int NVM_init(void) {
|
||||
field_state_t sector0_state, sector1_state;
|
||||
sectors[0].index = scan_allocation_table(§ors[0], sectors[0].n_data,
|
||||
ERASED, §or0_state);
|
||||
sectors[1].index = scan_allocation_table(§ors[1], sectors[1].n_data,
|
||||
ERASED, §or1_state);
|
||||
//printf("sector states: %02x, %02x\r\n", sector0_state, sector1_state); osDelay(5);
|
||||
|
||||
// Select valid sector on a best effort basis
|
||||
// (in unfortunate cases valid_sector might actually point
|
||||
// to an invalid or erased sector)
|
||||
read_sector_ = 0;
|
||||
if (sector1_state == VALID)
|
||||
read_sector_ = 1;
|
||||
|
||||
// count the number of valid fields
|
||||
sector_t *read_sector = §ors[read_sector_];
|
||||
uint8_t first_nonvalid_state;
|
||||
size_t min_valid_index = scan_allocation_table(read_sector, read_sector->index,
|
||||
VALID, &first_nonvalid_state);
|
||||
n_valid_ = read_sector->index - min_valid_index;
|
||||
|
||||
n_staging_area_ = 0;
|
||||
|
||||
int status = 0;
|
||||
/*// bring non-valid sectors into a known state
|
||||
this is not absolutely required
|
||||
if (sector0_state != VALID)
|
||||
status |= erase(§ors[0]);
|
||||
if (sector1_state != VALID)
|
||||
status |= erase(§ors[1]);
|
||||
*/
|
||||
return status;
|
||||
}
|
||||
|
||||
// @brief Erases all data in the NVM.
|
||||
//
|
||||
// If this function fails subsequent calls to NVM functions (other than NVM_init or NVM_erase)
|
||||
// cause undefined behavior.
|
||||
// Caution: this function may take a long time (like 1 second)
|
||||
//
|
||||
// @returns 0 on success or a non-zero error code otherwise
|
||||
int NVM_erase(void) {
|
||||
read_sector_ = 0;
|
||||
sectors[0].index = sectors[0].n_reserved;
|
||||
sectors[1].index = sectors[1].n_reserved;
|
||||
|
||||
int state = 0;
|
||||
state |= erase(§ors[0]);
|
||||
state |= erase(§ors[1]);
|
||||
return state;
|
||||
}
|
||||
|
||||
// @brief Returns the maximum number of bytes that can be read using NVM_read.
|
||||
// This holds until NVM_commit is called.
|
||||
size_t NVM_get_max_read_length(void) {
|
||||
return n_valid_ << 3;
|
||||
}
|
||||
|
||||
// @brief Returns the maximum length (in bytes) that can passed to NVM_start_write.
|
||||
// This holds until NVM_commit is called.
|
||||
size_t NVM_get_max_write_length(void) {
|
||||
sector_t *target = §ors[1 - read_sector_];
|
||||
return (target->n_data - target->n_reserved) << 3;
|
||||
}
|
||||
|
||||
// @brief Reads from the latest committed block in the non-volatile memory.
|
||||
// The function either succeeds or leaves the provided buffer unmodified.
|
||||
// @param offset: offset in bytes (0 meaning the beginning of the valid area)
|
||||
// @param data: buffer to write to
|
||||
// @param length: length in bytes (if (offset + length) is out of range, the function fails)
|
||||
// @returns 0 on success or a non-zero error code otherwise
|
||||
int NVM_read(size_t offset, uint8_t *data, size_t length) {
|
||||
if (offset + length > (n_valid_ << 3))
|
||||
return -1;
|
||||
sector_t *read_sector = §ors[read_sector_];
|
||||
const uint8_t *src_ptr = ((const uint8_t *)&read_sector->data[read_sector->index - n_valid_]) + offset;
|
||||
memcpy(data, src_ptr, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// @brief Starts an atomic write operation.
|
||||
//
|
||||
// The most recent valid NVM data is not modified or invalidated until NVM_commit is called.
|
||||
// The length must be at most equal to the size indicated by NVM_get_max_write_length().
|
||||
//
|
||||
// @param length: Length of the staging block that should be created
|
||||
int NVM_start_write(size_t length) {
|
||||
int status = 0;
|
||||
sector_t *target = §ors[1 - read_sector_];
|
||||
|
||||
length = (length + 7) >> 3; // round to multiple of 64 bit
|
||||
if (length > target->n_data - target->n_reserved)
|
||||
return -1;
|
||||
|
||||
// make room for the new data
|
||||
if (length > target->n_data - target->index)
|
||||
if ((status = erase(target)))
|
||||
return status;
|
||||
|
||||
// invalidate the fields we're about to write
|
||||
status = set_allocation_state(target, target->index, length, INVALID);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
n_staging_area_ = length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// @brief Writes to the current data block that was opened with NVM_start_write.
|
||||
//
|
||||
// The operation fails if (offset + length) is larger than the length passed to NVM_start_write.
|
||||
// The most recent valid NVM data is not modified or invalidated until NVM_commit is called.
|
||||
// Warning: Writing different data to the same area multiple times during a single transaction
|
||||
// will cause data corruption.
|
||||
//
|
||||
// @param offset: The offset in bytes, 0 being the beginning of the staging block.
|
||||
// @param data: Pointer to the data that should be written
|
||||
// @param length: Data length in bytes
|
||||
int NVM_write(size_t offset, uint8_t *data, size_t length) {
|
||||
if (offset + length > (n_staging_area_ << 3))
|
||||
return -1;
|
||||
sector_t *target = §ors[1 - read_sector_];
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
HAL_FLASH_ClearError();
|
||||
|
||||
// handle unaligned start
|
||||
for (; (offset & 0x3) && length; ++data, ++offset, --length)
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
|
||||
((uintptr_t)&target->data[target->index]) + offset, *data) != HAL_OK)
|
||||
goto fail;
|
||||
|
||||
// write 32-bit values (64-bit doesn't work)
|
||||
for (; length >= 4; data += 4, offset += 4, length -=4)
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
|
||||
((uintptr_t)&target->data[target->index]) + offset, *(uint32_t*)data) != HAL_OK)
|
||||
goto fail;
|
||||
|
||||
// handle unaligned end
|
||||
for (; length; ++data, ++offset, --length)
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
|
||||
((uintptr_t)&target->data[target->index]) + offset, *data) != HAL_OK)
|
||||
goto fail;
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
return 0;
|
||||
fail:
|
||||
HAL_FLASH_Lock();
|
||||
return HAL_FLASH_GetError(); // non-zero
|
||||
}
|
||||
|
||||
// @brief Commits the new data to NVM atomically.
|
||||
int NVM_commit(void) {
|
||||
sector_t *read_sector = §ors[read_sector_];
|
||||
sector_t *write_sector = §ors[1 - read_sector_];
|
||||
|
||||
// mark the newly-written fields as valid
|
||||
int status = set_allocation_state(write_sector, write_sector->index, n_staging_area_, VALID);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
write_sector->index += n_staging_area_;
|
||||
n_valid_ = n_staging_area_;
|
||||
n_staging_area_ = 0;
|
||||
read_sector_ = 1 - read_sector_;
|
||||
|
||||
// invalidate the other sector
|
||||
if (read_sector->index < read_sector->n_data) {
|
||||
status = set_allocation_state(read_sector, read_sector->index, 1, INVALID);
|
||||
read_sector->index += 1;
|
||||
} else {
|
||||
status = erase(read_sector);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#include <cmsis_os.h>
|
||||
#include <stdio.h>
|
||||
/** @brief Call this at startup to test/demo the NVM driver
|
||||
|
||||
Expected output when starting with a fully erased NVM
|
||||
|
||||
[1st boot]
|
||||
=== NVM TEST ===
|
||||
NVM is empty
|
||||
write 0x00, ..., 0x25 to NVM
|
||||
new data committed to NVM
|
||||
|
||||
[2nd boot]
|
||||
=== NVM TEST ===
|
||||
NVM contains 40 valid bytes:
|
||||
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
|
||||
10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
|
||||
20 21 22 23 24 25 ff ff
|
||||
write 0xbd, ..., 0xe2 to NVM
|
||||
new data committed to NVM
|
||||
|
||||
[3rd boot]
|
||||
=== NVM TEST ===
|
||||
NVM contains 40 valid bytes:
|
||||
bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc
|
||||
cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc
|
||||
dd de df e0 e1 e2 ff ff
|
||||
write 0xcb, ..., 0xf0 to NVM
|
||||
new data committed to NVM
|
||||
*/
|
||||
void NVM_demo(void) {
|
||||
const size_t len = 38;
|
||||
uint8_t data[len];
|
||||
int progress = 0;
|
||||
uint8_t seed = 0;
|
||||
|
||||
osDelay(100);
|
||||
printf("=== NVM TEST ===\r\n"); osDelay(5);
|
||||
//NVM_erase();
|
||||
if (progress++, NVM_init() != 0)
|
||||
goto fail;
|
||||
|
||||
// load bytes from NVM and print them
|
||||
size_t available = NVM_get_max_read_length();
|
||||
if (available) {
|
||||
printf("NVM contains %d valid bytes:\r\n", available); osDelay(5);
|
||||
uint8_t buf[available];
|
||||
if (progress++, NVM_read(0, buf, available) != 0)
|
||||
goto fail;
|
||||
for (size_t pos = 0; pos < available; ++pos) {
|
||||
seed += buf[pos];
|
||||
printf(" %02x", buf[pos]);
|
||||
if ((((pos + 1) % 16) == 0) || ((pos + 1) == available))
|
||||
printf("\r\n");
|
||||
osDelay(2);
|
||||
}
|
||||
} else {
|
||||
printf("NVM is empty\r\n"); osDelay(5);
|
||||
}
|
||||
|
||||
// store new bytes in NVM (data based on seed)
|
||||
printf("write 0x%02x, ..., 0x%02x to NVM\r\n", seed, seed + len - 1); osDelay(5);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
data[i] = seed++;
|
||||
if (progress++, NVM_start_write(len) != 0)
|
||||
goto fail;
|
||||
if (progress++, NVM_write(0, data, len / 2))
|
||||
goto fail;
|
||||
if (progress++, NVM_write(len / 2, &data[len / 2], len - (len / 2)))
|
||||
goto fail;
|
||||
if (progress++, NVM_commit())
|
||||
goto fail;
|
||||
printf("new data committed to NVM\r\n"); osDelay(5);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
printf("NVM test failed at %d!\r\n", progress);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __NVM_H
|
||||
#define __NVM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported variables --------------------------------------------------------*/
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported functions --------------------------------------------------------*/
|
||||
|
||||
int NVM_init(void);
|
||||
int NVM_erase(void);
|
||||
size_t NVM_get_max_read_length(void);
|
||||
size_t NVM_get_max_write_length(void);
|
||||
int NVM_read(size_t offset, uint8_t *data, size_t length);
|
||||
int NVM_start_write(size_t length);
|
||||
int NVM_write(size_t offset, uint8_t *data, size_t length);
|
||||
int NVM_commit(void);
|
||||
void NVM_demo(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__NVM_H
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
#include "stm32_spi_arbiter.hpp"
|
||||
#include "stm32_system.h"
|
||||
#include "utils.hpp"
|
||||
#include <cmsis_os.h>
|
||||
|
||||
bool equals(const SPI_InitTypeDef& lhs, const SPI_InitTypeDef& rhs) {
|
||||
return (lhs.Mode == rhs.Mode)
|
||||
&& (lhs.Direction == rhs.Direction)
|
||||
&& (lhs.DataSize == rhs.DataSize)
|
||||
&& (lhs.CLKPolarity == rhs.CLKPolarity)
|
||||
&& (lhs.CLKPhase == rhs.CLKPhase)
|
||||
&& (lhs.NSS == rhs.NSS)
|
||||
&& (lhs.BaudRatePrescaler == rhs.BaudRatePrescaler)
|
||||
&& (lhs.FirstBit == rhs.FirstBit)
|
||||
&& (lhs.TIMode == rhs.TIMode)
|
||||
&& (lhs.CRCCalculation == rhs.CRCCalculation)
|
||||
&& (lhs.CRCPolynomial == rhs.CRCPolynomial);
|
||||
}
|
||||
|
||||
bool Stm32SpiArbiter::acquire_task(SpiTask* task) {
|
||||
return !__atomic_exchange_n(&task->is_in_use, true, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
void Stm32SpiArbiter::release_task(SpiTask* task) {
|
||||
task->is_in_use = false;
|
||||
}
|
||||
|
||||
bool Stm32SpiArbiter::start() {
|
||||
if (!task_list_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpiTask& task = *task_list_;
|
||||
if (!equals(task.config, hspi_->Init)) {
|
||||
HAL_SPI_DeInit(hspi_);
|
||||
hspi_->Init = task.config;
|
||||
HAL_SPI_Init(hspi_);
|
||||
__HAL_SPI_ENABLE(hspi_);
|
||||
}
|
||||
task.ncs_gpio.write(false);
|
||||
|
||||
HAL_StatusTypeDef status = HAL_ERROR;
|
||||
|
||||
if (hspi_->hdmatx->State != HAL_DMA_STATE_READY || hspi_->hdmarx->State != HAL_DMA_STATE_READY) {
|
||||
// This can happen if the DMA or interrupt priorities are not configured properly.
|
||||
status = HAL_BUSY;
|
||||
} else if (task.tx_buf && task.rx_buf) {
|
||||
status = HAL_SPI_TransmitReceive_DMA(hspi_, (uint8_t*)task.tx_buf, task.rx_buf, task.length);
|
||||
} else if (task.tx_buf) {
|
||||
status = HAL_SPI_Transmit_DMA(hspi_, (uint8_t*)task.tx_buf, task.length);
|
||||
} else if (task.rx_buf) {
|
||||
status = HAL_SPI_Receive_DMA(hspi_, task.rx_buf, task.length);
|
||||
}
|
||||
|
||||
if (status != HAL_OK) {
|
||||
task.ncs_gpio.write(true);
|
||||
}
|
||||
|
||||
return status == HAL_OK;
|
||||
}
|
||||
|
||||
void Stm32SpiArbiter::transfer_async(SpiTask* task) {
|
||||
task->next = nullptr;
|
||||
|
||||
// Append new task to task list.
|
||||
// We could try to do this lock free but we could also use our time for useful things.
|
||||
SpiTask** ptr = &task_list_;
|
||||
CRITICAL_SECTION() {
|
||||
while (*ptr)
|
||||
ptr = &(*ptr)->next;
|
||||
*ptr = task;
|
||||
}
|
||||
|
||||
// If the list was empty before, kick off the SPI arbiter now
|
||||
if (ptr == &task_list_) {
|
||||
if (!start()) {
|
||||
if (task->on_complete) {
|
||||
(*task->on_complete)(task->on_complete_ctx, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this currently only works when called in a CMSIS thread.
|
||||
bool Stm32SpiArbiter::transfer(SPI_InitTypeDef config, Stm32Gpio ncs_gpio, const uint8_t* tx_buf, uint8_t* rx_buf, size_t length, uint32_t timeout_ms) {
|
||||
volatile uint8_t result = 0xff;
|
||||
|
||||
SpiTask task = {
|
||||
.config = config,
|
||||
.ncs_gpio = ncs_gpio,
|
||||
.tx_buf = tx_buf,
|
||||
.rx_buf = rx_buf,
|
||||
.length = length,
|
||||
.on_complete = [](void* ctx, bool success) { *(volatile uint8_t*)ctx = success ? 1 : 0; },
|
||||
.on_complete_ctx = (void*)&result,
|
||||
.is_in_use = false,
|
||||
.next = nullptr
|
||||
};
|
||||
|
||||
transfer_async(&task);
|
||||
|
||||
while (result == 0xff) {
|
||||
osDelay(1); // TODO: honor timeout
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Stm32SpiArbiter::on_complete() {
|
||||
if (!task_list_) {
|
||||
return; // this should not happen
|
||||
}
|
||||
|
||||
// Wrap up transfer
|
||||
task_list_->ncs_gpio.write(true);
|
||||
if (task_list_->on_complete) {
|
||||
(*task_list_->on_complete)(task_list_->on_complete_ctx, true);
|
||||
}
|
||||
|
||||
// Start next task if any
|
||||
SpiTask* next = nullptr;
|
||||
CRITICAL_SECTION() {
|
||||
next = task_list_ = task_list_->next;
|
||||
}
|
||||
if (next) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef __STM32_SPI_ARBITER_HPP
|
||||
#define __STM32_SPI_ARBITER_HPP
|
||||
|
||||
#include "stm32_gpio.hpp"
|
||||
|
||||
#include <spi.h>
|
||||
|
||||
class Stm32SpiArbiter {
|
||||
public:
|
||||
struct SpiTask {
|
||||
SPI_InitTypeDef config;
|
||||
Stm32Gpio ncs_gpio;
|
||||
const uint8_t* tx_buf;
|
||||
uint8_t* rx_buf;
|
||||
size_t length;
|
||||
void (*on_complete)(void*, bool);
|
||||
void* on_complete_ctx;
|
||||
bool is_in_use = false;
|
||||
struct SpiTask* next;
|
||||
};
|
||||
|
||||
Stm32SpiArbiter(SPI_HandleTypeDef* hspi): hspi_(hspi) {}
|
||||
|
||||
/**
|
||||
* Reserves the task for the caller if it's not in use currently.
|
||||
*
|
||||
* This can be used by the caller to ensure that the task structure is not
|
||||
* overwritten while it's in use in a preceding transfer.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* if (acquire_task(&task)) {
|
||||
* transfer_async(&task)
|
||||
* }
|
||||
*
|
||||
* A call to release_task() makes the task available for use again.
|
||||
*/
|
||||
static bool acquire_task(SpiTask* task);
|
||||
|
||||
/**
|
||||
* Releases the task so that the next call to `acquire_task()` returns true.
|
||||
* This should usually be called inside the on_complete() callback after
|
||||
* the rx buffer has been processed.
|
||||
*/
|
||||
static void release_task(SpiTask* task);
|
||||
|
||||
/**
|
||||
* @brief Enqueues a non-blocking transfer.
|
||||
*
|
||||
* Once the transfer completes, fails or is aborted, the callback is invoked.
|
||||
*
|
||||
* This function is thread-safe with respect to all other public functions
|
||||
* of this class.
|
||||
*
|
||||
* @param task: Contains all configuration data for this transfer.
|
||||
* The struct pointed to by this argument must remain valid and
|
||||
* unmodified until the completion callback is invoked.
|
||||
*/
|
||||
void transfer_async(SpiTask* task);
|
||||
|
||||
/**
|
||||
* @brief Executes a blocking transfer.
|
||||
*
|
||||
* If the SPI is busy this function waits until it becomes available or
|
||||
* the specified timeout passes, whichever comes first.
|
||||
*
|
||||
* Returns true on successful transfer or false otherwise.
|
||||
*
|
||||
* This function is thread-safe with respect to all other public functions
|
||||
* of this class.
|
||||
*
|
||||
* @param config: The SPI configuration to apply for this transfer.
|
||||
* @param ncs_gpio: The active low GPIO to actuate during this transfer.
|
||||
* @param tx_buf: Buffer for the outgoing data to be sent. Can be null unless
|
||||
* rx_buf is null too.
|
||||
* @param rx_buf: Buffer for the incoming data to be sent. Can be null unless
|
||||
* tx_buf is null too.
|
||||
*/
|
||||
bool transfer(SPI_InitTypeDef config, Stm32Gpio ncs_gpio, const uint8_t* tx_buf, uint8_t* rx_buf, size_t length, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Completion method to be called from HAL_SPI_TxCpltCallback,
|
||||
* HAL_SPI_RxCpltCallback and HAL_SPI_TxRxCpltCallback.
|
||||
*/
|
||||
void on_complete();
|
||||
|
||||
private:
|
||||
bool start();
|
||||
|
||||
SPI_HandleTypeDef* hspi_;
|
||||
SpiTask* task_list_ = nullptr;
|
||||
};
|
||||
|
||||
#endif // __STM32_SPI_ARBITER_HPP
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
#include "stm32_system.h"
|
||||
|
||||
uint32_t irq_counters[254]; // 14 core interrupts, 240 NVIC interrupts
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifndef __STM32_SYSTEM_H
|
||||
#define __STM32_SYSTEM_H
|
||||
|
||||
#if defined(STM32F405xx)
|
||||
#include <stm32f405xx.h>
|
||||
#elif defined(STM32F722xx)
|
||||
#include <stm32f722xx.h>
|
||||
#else
|
||||
#error "unknown STM32 microcontroller"
|
||||
#endif
|
||||
|
||||
// C/C++ definitions
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Uncomment the following line to sacrifice 1kB of RAM for the ability to
|
||||
// monitor the number of times each interrupt fires.
|
||||
//#define ENABLE_IRQ_COUNTER
|
||||
|
||||
#ifdef ENABLE_IRQ_COUNTER
|
||||
extern uint32_t irq_counters[];
|
||||
#define COUNT_IRQ(irqn) (++irq_counters[irqn + 14])
|
||||
#define GET_IRQ_COUNTER(irqn) irq_counters[irqn + 14]
|
||||
#else
|
||||
#define COUNT_IRQ(irqn) ((void)0)
|
||||
#define GET_IRQ_COUNTER(irqn) 0
|
||||
#endif
|
||||
|
||||
static inline uint32_t cpu_enter_critical() {
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
return primask;
|
||||
}
|
||||
|
||||
static inline void cpu_exit_critical(uint32_t priority_mask) {
|
||||
__set_PRIMASK(priority_mask);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// C++ only definitions
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct CriticalSectionContext {
|
||||
CriticalSectionContext(const CriticalSectionContext&) = delete;
|
||||
CriticalSectionContext(const CriticalSectionContext&&) = delete;
|
||||
void operator=(const CriticalSectionContext&) = delete;
|
||||
void operator=(const CriticalSectionContext&&) = delete;
|
||||
operator bool() { return true; };
|
||||
CriticalSectionContext() : mask_(cpu_enter_critical()) {}
|
||||
~CriticalSectionContext() { cpu_exit_critical(mask_); }
|
||||
uint32_t mask_;
|
||||
bool exit_ = false;
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#define CRITICAL_SECTION() for (CriticalSectionContext __critical_section_context; !__critical_section_context.exit_; __critical_section_context.exit_ = true)
|
||||
#else
|
||||
#define CRITICAL_SECTION() if (CriticalSectionContext __critical_section_context{})
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __STM32_SYSTEM_H
|
||||
@@ -0,0 +1,83 @@
|
||||
#ifndef __STM32_TIMER_HPP
|
||||
#define __STM32_TIMER_HPP
|
||||
|
||||
#include "stm32_system.h"
|
||||
#include <tim.h>
|
||||
#include <array>
|
||||
|
||||
class Stm32Timer {
|
||||
public:
|
||||
/**
|
||||
* @brief Starts multiple timers deterministically and synchronously from the
|
||||
* specified offset.
|
||||
*
|
||||
* All timers are atomically (*) put into the following state (regardless of
|
||||
* their previous state/configuration):
|
||||
* - TIMx_CNT will be initialized according to the corresponding counter[i] parameter.
|
||||
* - If the timer is in center-aligned mode, it will be set to up-counting direction.
|
||||
* - The update repetition counter is reset to TIMx_RCR (if applicable).
|
||||
* - The prescaler counter is reset.
|
||||
* - Update interrupts are disabled.
|
||||
* - The counter put into running state.
|
||||
*
|
||||
* This function is implemented by generating an update event on all selected timers.
|
||||
* That means as a side effect all things that are connected to the update event
|
||||
* except the interrupt routine itself (i.e. ADCs, DMAs, slave timers, etc) will
|
||||
* be triggered.
|
||||
*
|
||||
* Also you probably want to disable any connected PWM outputs to prevent glitches.
|
||||
*
|
||||
* (*) Best-effort atomically. There will be skew of a handful of clock cycles
|
||||
* but it's always the same given the compiler version and configuration.
|
||||
*/
|
||||
template<size_t I>
|
||||
static void start_synchronously(std::array<TIM_HandleTypeDef*, I> timers, std::array<size_t, I> counters) {
|
||||
start_synchronously_impl(timers, counters, std::make_index_sequence<I>());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize (3)
|
||||
|
||||
template<size_t I, size_t ... Is>
|
||||
static void start_synchronously_impl(std::array<TIM_HandleTypeDef*, I> timers, std::array<size_t, I> counters, std::index_sequence<Is...>) {
|
||||
for (size_t i = 0; i < I; ++i) {
|
||||
TIM_HandleTypeDef* htim = timers[i];
|
||||
|
||||
// Stop the timer so we can start all of them later more atomically.
|
||||
htim->Instance->CR1 &= ~TIM_CR1_CEN;
|
||||
|
||||
// Generate update event to force all of the timer's registers into
|
||||
// a known state.
|
||||
__HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE);
|
||||
htim->Instance->EGR |= TIM_EGR_UG;
|
||||
__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
|
||||
|
||||
// Load counter with the desired value.
|
||||
htim->Instance->CNT = counters[i];
|
||||
}
|
||||
|
||||
register volatile uint32_t* cr_addr[I];
|
||||
register uint32_t cr_val[I];
|
||||
for (size_t i = 0; i < I; ++i) {
|
||||
cr_addr[i] = &timers[i]->Instance->CR1;
|
||||
cr_val[i] = timers[i]->Instance->CR1 | TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
// Restart all timers as atomically as possible.
|
||||
// By inspection we find that this is compiled to the following code:
|
||||
// f7ff faa0 bl 800bdd0 <cpu_enter_critical()>
|
||||
// f8c9 6000 str.w r6, [r9]
|
||||
// f8c8 5000 str.w r5, [r8]
|
||||
// 603c str r4, [r7, #0]
|
||||
// f7ff fa9d bl 800bdd8 <cpu_exit_critical(unsigned long)>
|
||||
uint32_t mask = cpu_enter_critical();
|
||||
int dummy[I] = {(*cr_addr[Is] = cr_val[Is], 0)...};
|
||||
(void)dummy;
|
||||
cpu_exit_critical(mask);
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
};
|
||||
|
||||
#endif // __STM32_TIMER_HPP
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef __GATE_DRIVER_HPP
|
||||
#define __GATE_DRIVER_HPP
|
||||
|
||||
struct GateDriverBase {
|
||||
/**
|
||||
* @brief Unlocks or locks the gate signals of the gate driver.
|
||||
*
|
||||
* While locked the PWM inputs are ignored and the switches are always in
|
||||
* OFF state.
|
||||
* Not all gate drivers implement this function and may return true even if
|
||||
* the gate driver was not locked.
|
||||
*/
|
||||
virtual bool set_enabled(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns false if the gate driver is in a state where the output
|
||||
* drive stages are disarmed or not properly configured (e.g. because they
|
||||
* are not initialized or there was a fault condition).
|
||||
*/
|
||||
virtual bool is_ready() = 0;
|
||||
};
|
||||
|
||||
struct OpAmpBase {
|
||||
/**
|
||||
* @brief Returns false if the opamp is in a state where it's not operating
|
||||
* with the latest configured gain (e.g. because it was not initialized or
|
||||
* there was a fault condition).
|
||||
*/
|
||||
virtual bool is_ready() = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the neutral voltage of the OpAmp in Volts
|
||||
*/
|
||||
virtual float get_midpoint() = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum voltage swing away from the midpoint voltage (in Volts)
|
||||
*/
|
||||
virtual float get_max_output_swing() = 0;
|
||||
};
|
||||
|
||||
#endif // __GATE_DRIVER_HPP
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer
|
||||
* present in the kernel, so it has to be supplied by other means for
|
||||
* OpenOCD's threads awareness.
|
||||
*
|
||||
* Add this file to your project, and, if you're using --gc-sections,
|
||||
* ``--undefined=uxTopUsedPriority'' (or
|
||||
* ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final
|
||||
* linking) to your LDFLAGS; same with all the other symbols you need.
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define USED __attribute__((used))
|
||||
#else
|
||||
#define USED
|
||||
#endif
|
||||
|
||||
const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2018 Oskar Weigl
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
# This is only a stub for various commands.
|
||||
# Tup is used for the actual compilation.
|
||||
|
||||
BUILD_DIR = build
|
||||
FIRMWARE = $(BUILD_DIR)/ODriveFirmware.elf
|
||||
FIRMWARE_HEX = $(BUILD_DIR)/ODriveFirmware.hex
|
||||
PROGRAMMER_CMD=$(if $(value PROGRAMMER),-c 'hla_serial $(PROGRAMMER)',)
|
||||
|
||||
include tup.config # source build configuration to get CONFIG_BOARD_VERSION
|
||||
|
||||
ifeq ($(shell python -c "import sys; print(sys.version_info.major)"), 3)
|
||||
PY_CMD := python -B
|
||||
else
|
||||
PY_CMD := python3 -B
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring v3.,$(CONFIG_BOARD_VERSION)))
|
||||
OPENOCD := openocd -f interface/stlink-v2.cfg $(PROGRAMMER_CMD) -f target/stm32f4x.cfg -c init
|
||||
GDB := arm-none-eabi-gdb --ex 'target extended-remote | openocd -f "interface/stlink-v2.cfg" -f "target/stm32f4x.cfg" -c "gdb_port pipe; log_output openocd.log"' --ex 'monitor reset halt'
|
||||
else ifneq (,$(findstring v4.,$(CONFIG_BOARD_VERSION)))
|
||||
OPENOCD := openocd -f interface/stlink.cfg $(PROGRAMMER_CMD) -f target/stm32f7x.cfg -c 'reset_config none separate' -c init
|
||||
GDB := arm-none-eabi-gdb --ex 'target extended-remote | openocd -f "interface/stlink-v2.cfg" -f "target/stm32f7x.cfg" -c "reset_config none separate" -c "gdb_port pipe; log_output openocd.log"' --ex 'monitor reset halt'
|
||||
else
|
||||
$(error unknown board version)
|
||||
endif
|
||||
|
||||
$(info board version: $(CONFIG_BOARD_VERSION))
|
||||
|
||||
all:
|
||||
@mkdir -p autogen
|
||||
@$(PY_CMD) ../tools/odrive/version.py --output autogen/version.c
|
||||
@tup --quiet -no-environ-check
|
||||
@$(PY_CMD) interface_generator_stub.py --definitions odrive-interface.yaml --template ../tools/enums_template.j2 --output ../tools/odrive/enums.py
|
||||
@$(PY_CMD) interface_generator_stub.py --definitions odrive-interface.yaml --template ../tools/arduino_enums_template.j2 --output ../Arduino/ODriveArduino/ODriveEnums.h
|
||||
@cd ../tools/ && $(PY_CMD) create_can_dbc.py
|
||||
|
||||
# Copy libfibre files to odrivetool if they were built
|
||||
@ ! test -f "fibre-cpp/build/libfibre-linux-amd64.so" || cp fibre-cpp/build/libfibre-linux-amd64.so ../tools/odrive/pyfibre/fibre/
|
||||
@ ! test -f "fibre-cpp/build/libfibre-linux-armhf.so" || cp fibre-cpp/build/libfibre-linux-armhf.so ../tools/odrive/pyfibre/fibre/
|
||||
@ ! test -f "fibre-cpp/build/libfibre-linux-aarch64.so" || cp fibre-cpp/build/libfibre-linux-aarch64.so ../tools/odrive/pyfibre/fibre/
|
||||
@ ! test -f "fibre-cpp/build/libfibre-macos-x86.dylib" || cp fibre-cpp/build/libfibre-macos-x86.dylib ../tools/odrive/pyfibre/fibre/
|
||||
@ ! test -f "fibre-cpp/build/libfibre-windows-amd64.dll" || cp fibre-cpp/build/libfibre-windows-amd64.dll ../tools/odrive/pyfibre/fibre/
|
||||
|
||||
libfibre-linux-armhf:
|
||||
docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/fibre-linux-armhf-build:/build/build -w /build fibre-compiler configs/linux-armhf.config
|
||||
cp /tmp/fibre-linux-armhf-build/libfibre-*.so ../tools/odrive/pyfibre/fibre/
|
||||
|
||||
libfibre-all:
|
||||
docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/linux-amd64.config
|
||||
cp /tmp/libfibre-build/libfibre-linux-amd64.so ../tools/odrive/pyfibre/fibre/
|
||||
docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/linux-armhf.config
|
||||
cp /tmp/libfibre-build/libfibre-linux-armhf.so ../tools/odrive/pyfibre/fibre/
|
||||
docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/linux-aarch64.config
|
||||
cp /tmp/libfibre-build/libfibre-linux-aarch64.so ../tools/odrive/pyfibre/fibre/
|
||||
docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/macos-x86.config
|
||||
cp /tmp/libfibre-build/libfibre-macos-x86.dylib ../tools/odrive/pyfibre/fibre/
|
||||
docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/windows-amd64.config
|
||||
cp /tmp/libfibre-build/libfibre-windows-amd64.dll ../tools/odrive/pyfibre/fibre/
|
||||
docker run -it -v "`pwd`/fibre-cpp":/build -v /tmp/libfibre-build:/build/build -w /build fibre-compiler configs/wasm.config
|
||||
cp /tmp/libfibre-build/libfibre-wasm.* ../GUI/fibre-js/
|
||||
|
||||
clean:
|
||||
-rm -fR .dep $(BUILD_DIR)
|
||||
|
||||
flash-stlink2: all
|
||||
$(OPENOCD) \
|
||||
-c 'reset halt' \
|
||||
-c 'flash write_image erase $(FIRMWARE)' \
|
||||
-c 'reset run' \
|
||||
-c exit
|
||||
|
||||
gdb-stlink2:
|
||||
$(GDB) $(FIRMWARE)
|
||||
|
||||
# Erase entire STM32
|
||||
erase-stlink2:
|
||||
$(OPENOCD) -c 'reset halt' -c 'flash erase_sector 0 0 last' -c exit
|
||||
|
||||
# Sometimes the STM32 will get it's protection bits set for unknown reasons. Unlock it with this command
|
||||
unlock-stlink2:
|
||||
$(OPENOCD) -c 'reset halt' -c 'stm32f2x unlock 0'
|
||||
|
||||
flash-bmp: all
|
||||
arm-none-eabi-gdb --ex 'target extended-remote $(BMP_PORT)' \
|
||||
--ex 'monitor swdp_scan' \
|
||||
--ex 'attach 1' \
|
||||
--ex 'load' \
|
||||
--ex 'detach' \
|
||||
--ex 'quit' \
|
||||
$(FIRMWARE)
|
||||
|
||||
gdb-bmp: all
|
||||
arm-none-eabi-gdb --ex 'target extended-remote /dev/stlink' \
|
||||
--ex 'monitor swdp_scan' \
|
||||
--ex 'attach 1' \
|
||||
--ex 'load' $(FIRMWARE)
|
||||
|
||||
dfu: all
|
||||
python ../tools/odrivetool $(if $(value SERIAL_NUMBER),--serial-number $(SERIAL_NUMBER),) dfu $(FIRMWARE_HEX)
|
||||
|
||||
flash: flash-stlink2
|
||||
gdb: gdb-stlink2
|
||||
erase: erase-stlink2
|
||||
unlock: unlock-stlink2
|
||||
|
||||
.PHONY: stlink2-config flash-stlink2 gdb-stlink2 erase-stlink2 unlock-stlink2
|
||||
.PHONY: flash-bmp gdb-bmp
|
||||
.PHONY: all clean flash gdb erase unlock dfu fibre
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#include "acim_estimator.hpp"
|
||||
#include <board.h>
|
||||
|
||||
void AcimEstimator::update(uint32_t timestamp) {
|
||||
std::optional<float> rotor_phase = rotor_phase_src_.present();
|
||||
std::optional<float> rotor_phase_vel = rotor_phase_vel_src_.present();
|
||||
std::optional<float2D> idq = idq_src_.present();
|
||||
|
||||
if (!rotor_phase.has_value() || !rotor_phase_vel.has_value() || !idq.has_value()) {
|
||||
active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
auto [id, iq] = *idq;
|
||||
|
||||
float dt = (float)(timestamp - last_timestamp_) / (float)TIM_1_8_CLOCK_HZ;
|
||||
last_timestamp_ = timestamp;
|
||||
|
||||
if (!active_) {
|
||||
// Skip first iteration and use it to reset state
|
||||
rotor_flux_ = 0.0f;
|
||||
phase_offset_ = 0.0f;
|
||||
active_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that the effect of the current commands on the real currents is actually 1.5 PWM cycles later
|
||||
// However the rotor time constant is (usually) so slow that it doesn't matter
|
||||
// So we elect to write it as if the effect is immediate, to have cleaner code
|
||||
|
||||
// acim_rotor_flux is normalized to units of [A] tracking Id; rotor inductance is unspecified
|
||||
float dflux_by_dt = config_.slip_velocity * (id - rotor_flux_);
|
||||
rotor_flux_ += dflux_by_dt * dt;
|
||||
float slip_velocity = config_.slip_velocity * (iq / rotor_flux_);
|
||||
// Check for issues with small denominator.
|
||||
if (is_nan(slip_velocity) || (std::abs(slip_velocity) > 0.1f / dt)) {
|
||||
slip_velocity = 0.0f;
|
||||
}
|
||||
slip_vel_ = slip_velocity; // reporting only
|
||||
|
||||
stator_phase_vel_ = *rotor_phase_vel + slip_velocity;
|
||||
phase_offset_ = wrap_pm_pi(phase_offset_ + slip_velocity * dt);
|
||||
stator_phase_ = wrap_pm_pi(*rotor_phase + phase_offset_);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef __ACIM_ESTIMATOR_HPP
|
||||
#define __ACIM_ESTIMATOR_HPP
|
||||
|
||||
#include <component.hpp>
|
||||
#include <cmath>
|
||||
#include <autogen/interfaces.hpp>
|
||||
|
||||
class AcimEstimator : public ComponentBase {
|
||||
public:
|
||||
struct Config_t {
|
||||
float slip_velocity = 14.706f; // [rad/s electrical] = 1/rotor_tau
|
||||
};
|
||||
|
||||
void update(uint32_t timestamp) final;
|
||||
|
||||
// Config
|
||||
Config_t config_;
|
||||
|
||||
// Inputs
|
||||
InputPort<float> rotor_phase_src_;
|
||||
InputPort<float> rotor_phase_vel_src_;
|
||||
InputPort<float2D> idq_src_;
|
||||
|
||||
// State variables
|
||||
bool active_ = false;
|
||||
uint32_t last_timestamp_ = 0;
|
||||
float rotor_flux_ = 0.0f; // [A]
|
||||
float phase_offset_ = 0.0f; // [A]
|
||||
|
||||
// Outputs
|
||||
OutputPort<float> slip_vel_ = 0.0f; // [rad/s electrical]
|
||||
OutputPort<float> stator_phase_vel_ = 0.0f; // [rad/s] rotor flux angular velocity estimate
|
||||
OutputPort<float> stator_phase_ = 0.0f; // [rad] rotor flux phase angle estimate
|
||||
};
|
||||
|
||||
#endif // __ACIM_ESTIMATOR_HPP
|
||||
@@ -0,0 +1,123 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: arm_cos_f32.c
|
||||
* Description: Fast cosine calculation for floating-point values
|
||||
*
|
||||
* $Date: 27. January 2017
|
||||
* $Revision: V.1.5.1
|
||||
*
|
||||
* Target Processor: Cortex-M cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2017 ARM Limited or its affiliates. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include "arm_math.h"
|
||||
#include "arm_common_tables.h"
|
||||
|
||||
/**
|
||||
* @ingroup groupFastMath
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup cos Cosine
|
||||
*
|
||||
* Computes the trigonometric cosine function using a combination of table lookup
|
||||
* and linear interpolation. There are separate functions for
|
||||
* Q15, Q31, and floating-point data types.
|
||||
* The input to the floating-point version is in radians and in the range [0 2*pi) while the
|
||||
* fixed-point Q15 and Q31 have a scaled input with the range
|
||||
* [0 +0.9999] mapping to [0 2*pi). The fixed-point range is chosen so that a
|
||||
* value of 2*pi wraps around to 0.
|
||||
*
|
||||
* The implementation is based on table lookup using 256 values together with linear interpolation.
|
||||
* The steps used are:
|
||||
* -# Calculation of the nearest integer table index
|
||||
* -# Compute the fractional portion (fract) of the table index.
|
||||
* -# The final result equals <code>(1.0f-fract)*a + fract*b;</code>
|
||||
*
|
||||
* where
|
||||
* <pre>
|
||||
* b=Table[index+0];
|
||||
* c=Table[index+1];
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup cos
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Fast approximation to the trigonometric cosine function for floating-point data.
|
||||
* @param[in] x input value in radians.
|
||||
* @return cos(x).
|
||||
*/
|
||||
|
||||
float32_t our_arm_cos_f32(
|
||||
float32_t x)
|
||||
{
|
||||
float32_t cosVal, fract, in; /* Temporary variables for input, output */
|
||||
uint16_t index; /* Index variable */
|
||||
float32_t a, b; /* Two nearest output values */
|
||||
int32_t n;
|
||||
float32_t findex;
|
||||
|
||||
/* input x is in radians */
|
||||
/* Scale the input to [0 1] range from [0 2*PI] , divide input by 2*pi, add 0.25 (pi/2) to read sine table */
|
||||
in = x * 0.159154943092f + 0.25f;
|
||||
|
||||
/* Calculation of floor value of input */
|
||||
n = (int32_t) in;
|
||||
|
||||
/* Make negative values towards -infinity */
|
||||
if (in < 0.0f)
|
||||
{
|
||||
n--;
|
||||
}
|
||||
|
||||
/* Map input value to [0 1] */
|
||||
in = in - (float32_t) n;
|
||||
|
||||
/* Calculation of index of the table */
|
||||
findex = (float32_t)FAST_MATH_TABLE_SIZE * in;
|
||||
index = (uint16_t)findex;
|
||||
|
||||
/* when "in" is exactly 1, we need to rotate the index down to 0 */
|
||||
if (index >= FAST_MATH_TABLE_SIZE) {
|
||||
index = 0;
|
||||
findex -= (float32_t)FAST_MATH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
/* fractional value calculation */
|
||||
fract = findex - (float32_t) index;
|
||||
|
||||
/* Read two nearest values of input value from the cos table */
|
||||
a = sinTable_f32[index];
|
||||
b = sinTable_f32[index+1];
|
||||
|
||||
/* Linear interpolation process */
|
||||
cosVal = (1.0f-fract)*a + fract*b;
|
||||
|
||||
/* Return the output value */
|
||||
return (cosVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* @} end of cos group
|
||||
*/
|
||||
@@ -0,0 +1,123 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: arm_sin_f32.c
|
||||
* Description: Fast sine calculation for floating-point values
|
||||
*
|
||||
* $Date: 27. January 2017
|
||||
* $Revision: V.1.5.1
|
||||
*
|
||||
* Target Processor: Cortex-M cores
|
||||
* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* Copyright (C) 2010-2017 ARM Limited or its affiliates. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include "arm_math.h"
|
||||
#include "arm_common_tables.h"
|
||||
|
||||
/**
|
||||
* @ingroup groupFastMath
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup sin Sine
|
||||
*
|
||||
* Computes the trigonometric sine function using a combination of table lookup
|
||||
* and linear interpolation. There are separate functions for
|
||||
* Q15, Q31, and floating-point data types.
|
||||
* The input to the floating-point version is in radians and in the range [0 2*pi) while the
|
||||
* fixed-point Q15 and Q31 have a scaled input with the range
|
||||
* [0 +0.9999] mapping to [0 2*pi). The fixed-point range is chosen so that a
|
||||
* value of 2*pi wraps around to 0.
|
||||
*
|
||||
* The implementation is based on table lookup using 256 values together with linear interpolation.
|
||||
* The steps used are:
|
||||
* -# Calculation of the nearest integer table index
|
||||
* -# Compute the fractional portion (fract) of the table index.
|
||||
* -# The final result equals <code>(1.0f-fract)*a + fract*b;</code>
|
||||
*
|
||||
* where
|
||||
* <pre>
|
||||
* b=Table[index+0];
|
||||
* c=Table[index+1];
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup sin
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Fast approximation to the trigonometric sine function for floating-point data.
|
||||
* @param[in] x input value in radians.
|
||||
* @return sin(x).
|
||||
*/
|
||||
|
||||
float32_t our_arm_sin_f32(
|
||||
float32_t x)
|
||||
{
|
||||
float32_t sinVal, fract, in; /* Temporary variables for input, output */
|
||||
uint16_t index; /* Index variable */
|
||||
float32_t a, b; /* Two nearest output values */
|
||||
int32_t n;
|
||||
float32_t findex;
|
||||
|
||||
/* input x is in radians */
|
||||
/* Scale the input to [0 1] range from [0 2*PI] , divide input by 2*pi */
|
||||
in = x * 0.159154943092f;
|
||||
|
||||
/* Calculation of floor value of input */
|
||||
n = (int32_t) in;
|
||||
|
||||
/* Make negative values towards -infinity */
|
||||
if (x < 0.0f)
|
||||
{
|
||||
n--;
|
||||
}
|
||||
|
||||
/* Map input value to [0 1] */
|
||||
in = in - (float32_t) n;
|
||||
|
||||
/* Calculation of index of the table */
|
||||
findex = (float32_t)FAST_MATH_TABLE_SIZE * in;
|
||||
index = (uint16_t)findex;
|
||||
|
||||
/* when "in" is exactly 1, we need to rotate the index down to 0 */
|
||||
if (index >= FAST_MATH_TABLE_SIZE) {
|
||||
index = 0;
|
||||
findex -= (float32_t)FAST_MATH_TABLE_SIZE;
|
||||
}
|
||||
|
||||
/* fractional value calculation */
|
||||
fract = findex - (float32_t) index;
|
||||
|
||||
/* Read two nearest values of input value from the sin table */
|
||||
a = sinTable_f32[index];
|
||||
b = sinTable_f32[index+1];
|
||||
|
||||
/* Linear interpolation process */
|
||||
sinVal = (1.0f-fract)*a + fract*b;
|
||||
|
||||
/* Return the output value */
|
||||
return (sinVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* @} end of sin group
|
||||
*/
|
||||
@@ -0,0 +1,602 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
#include "gpio.h"
|
||||
|
||||
#include "odrive_main.h"
|
||||
#include "utils.hpp"
|
||||
#include "communication/interface_can.hpp"
|
||||
|
||||
Axis::Axis(int axis_num,
|
||||
uint16_t default_step_gpio_pin,
|
||||
uint16_t default_dir_gpio_pin,
|
||||
osPriority thread_priority,
|
||||
Encoder& encoder,
|
||||
SensorlessEstimator& sensorless_estimator,
|
||||
Controller& controller,
|
||||
Motor& motor,
|
||||
TrapezoidalTrajectory& trap,
|
||||
Endstop& min_endstop,
|
||||
Endstop& max_endstop,
|
||||
MechanicalBrake& mechanical_brake)
|
||||
: axis_num_(axis_num),
|
||||
default_step_gpio_pin_(default_step_gpio_pin),
|
||||
default_dir_gpio_pin_(default_dir_gpio_pin),
|
||||
thread_priority_(thread_priority),
|
||||
encoder_(encoder),
|
||||
sensorless_estimator_(sensorless_estimator),
|
||||
controller_(controller),
|
||||
motor_(motor),
|
||||
trap_traj_(trap),
|
||||
min_endstop_(min_endstop),
|
||||
max_endstop_(max_endstop),
|
||||
mechanical_brake_(mechanical_brake)
|
||||
{
|
||||
encoder_.axis_ = this;
|
||||
sensorless_estimator_.axis_ = this;
|
||||
controller_.axis_ = this;
|
||||
motor_.axis_ = this;
|
||||
trap_traj_.axis_ = this;
|
||||
min_endstop_.axis_ = this;
|
||||
max_endstop_.axis_ = this;
|
||||
mechanical_brake_.axis_ = this;
|
||||
}
|
||||
|
||||
Axis::LockinConfig_t Axis::default_calibration() {
|
||||
Axis::LockinConfig_t config;
|
||||
config.current = 10.0f; // [A]
|
||||
config.ramp_time = 0.4f; // [s]
|
||||
config.ramp_distance = 1 * M_PI; // [rad]
|
||||
config.accel = 20.0f; // [rad/s^2]
|
||||
config.vel = 40.0f; // [rad/s]
|
||||
config.finish_distance = 100.0f * 2.0f * M_PI; // [rad]
|
||||
config.finish_on_vel = false;
|
||||
config.finish_on_distance = true;
|
||||
config.finish_on_enc_idx = true;
|
||||
return config;
|
||||
}
|
||||
|
||||
Axis::LockinConfig_t Axis::default_sensorless() {
|
||||
Axis::LockinConfig_t config;
|
||||
config.current = 10.0f; // [A]
|
||||
config.ramp_time = 0.4f; // [s]
|
||||
config.ramp_distance = 1 * M_PI; // [rad]
|
||||
config.accel = 200.0f; // [rad/s^2]
|
||||
config.vel = 400.0f; // [rad/s]
|
||||
config.finish_distance = 100.0f; // [rad]
|
||||
config.finish_on_vel = true;
|
||||
config.finish_on_distance = false;
|
||||
config.finish_on_enc_idx = false;
|
||||
return config;
|
||||
}
|
||||
|
||||
static void step_cb_wrapper(void* ctx) {
|
||||
reinterpret_cast<Axis*>(ctx)->step_cb();
|
||||
}
|
||||
|
||||
bool Axis::apply_config() {
|
||||
config_.parent = this;
|
||||
decode_step_dir_pins();
|
||||
watchdog_feed();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Axis::clear_config() {
|
||||
config_ = {};
|
||||
config_.step_gpio_pin = default_step_gpio_pin_;
|
||||
config_.dir_gpio_pin = default_dir_gpio_pin_;
|
||||
config_.can.node_id = axis_num_;
|
||||
}
|
||||
|
||||
static void run_state_machine_loop_wrapper(void* ctx) {
|
||||
reinterpret_cast<Axis*>(ctx)->run_state_machine_loop();
|
||||
reinterpret_cast<Axis*>(ctx)->thread_id_valid_ = false;
|
||||
}
|
||||
|
||||
// @brief Starts run_state_machine_loop in a new thread
|
||||
void Axis::start_thread() {
|
||||
osThreadDef(thread_def, run_state_machine_loop_wrapper, thread_priority_, 0, stack_size_ / sizeof(StackType_t));
|
||||
thread_id_ = osThreadCreate(osThread(thread_def), this);
|
||||
thread_id_valid_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Blocks until at least one complete control loop has been executed.
|
||||
*/
|
||||
bool Axis::wait_for_control_iteration() {
|
||||
osSignalWait(0x0001, osWaitForever); // this might return instantly
|
||||
osSignalWait(0x0001, osWaitForever); // this might be triggered at the
|
||||
// end of a control loop iteration
|
||||
// which was started before we entered
|
||||
// this function
|
||||
osSignalWait(0x0001, osWaitForever);
|
||||
return true;
|
||||
}
|
||||
|
||||
// step/direction interface
|
||||
void Axis::step_cb() {
|
||||
if (step_dir_active_) {
|
||||
dir_gpio_.read() ? ++steps_ : --steps_;
|
||||
controller_.input_pos_updated();
|
||||
}
|
||||
}
|
||||
|
||||
void Axis::decode_step_dir_pins() {
|
||||
step_gpio_ = get_gpio(config_.step_gpio_pin);
|
||||
dir_gpio_ = get_gpio(config_.dir_gpio_pin);
|
||||
}
|
||||
|
||||
// @brief (de)activates step/dir input
|
||||
void Axis::set_step_dir_active(bool active) {
|
||||
if (active) {
|
||||
// Subscribe to rising edges of the step GPIO
|
||||
if (!step_gpio_.subscribe(true, false, step_cb_wrapper, this)) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
|
||||
step_dir_active_ = true;
|
||||
} else {
|
||||
step_dir_active_ = false;
|
||||
|
||||
// Unsubscribe from step GPIO
|
||||
// TODO: if we change the GPIO while the subscription is active and then
|
||||
// unsubscribe then the unsubscribe is for the wrong pin.
|
||||
step_gpio_.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
// @brief Do axis level checks and call subcomponent do_checks
|
||||
// Returns true if everything is ok.
|
||||
bool Axis::do_checks(uint32_t timestamp) {
|
||||
// Sub-components should use set_error which will propegate to this error_
|
||||
motor_.effective_current_lim();
|
||||
motor_.do_checks(timestamp);
|
||||
|
||||
// Check for endstop presses
|
||||
if (min_endstop_.config_.enabled && min_endstop_.rose() && !(current_state_ == AXIS_STATE_HOMING)) {
|
||||
error_ |= ERROR_MIN_ENDSTOP_PRESSED;
|
||||
} else if (max_endstop_.config_.enabled && max_endstop_.rose() && !(current_state_ == AXIS_STATE_HOMING)) {
|
||||
error_ |= ERROR_MAX_ENDSTOP_PRESSED;
|
||||
}
|
||||
|
||||
return check_for_errors();
|
||||
}
|
||||
|
||||
// @brief Feed the watchdog to prevent watchdog timeouts.
|
||||
void Axis::watchdog_feed() {
|
||||
watchdog_current_value_ = get_watchdog_reset();
|
||||
}
|
||||
|
||||
// @brief Check the watchdog timer for expiration. Also sets the watchdog error bit if expired.
|
||||
bool Axis::watchdog_check() {
|
||||
if (!config_.enable_watchdog) return true;
|
||||
|
||||
// explicit check here to ensure that we don't underflow back to UINT32_MAX
|
||||
if (watchdog_current_value_ > 0) {
|
||||
watchdog_current_value_--;
|
||||
return true;
|
||||
} else {
|
||||
error_ |= ERROR_WATCHDOG_TIMER_EXPIRED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Axis::run_lockin_spin(const LockinConfig_t &lockin_config, bool remain_armed,
|
||||
std::function<bool(bool)> loop_cb) {
|
||||
CRITICAL_SECTION() {
|
||||
// Reset state variables
|
||||
open_loop_controller_.Idq_setpoint_ = {0.0f, 0.0f};
|
||||
open_loop_controller_.Vdq_setpoint_ = {0.0f, 0.0f};
|
||||
open_loop_controller_.phase_ = 0.0f;
|
||||
open_loop_controller_.phase_vel_ = 0.0f;
|
||||
|
||||
open_loop_controller_.max_current_ramp_ = lockin_config.current / lockin_config.ramp_time;
|
||||
open_loop_controller_.max_voltage_ramp_ = lockin_config.current / lockin_config.ramp_time;
|
||||
open_loop_controller_.max_phase_vel_ramp_ = lockin_config.accel;
|
||||
open_loop_controller_.target_current_ = motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL ? lockin_config.current : 0.0f;
|
||||
open_loop_controller_.target_voltage_ = motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL ? 0.0f : lockin_config.current;
|
||||
open_loop_controller_.target_vel_ = lockin_config.vel;
|
||||
open_loop_controller_.total_distance_ = 0.0f;
|
||||
|
||||
motor_.current_control_.enable_current_control_src_ = motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL;
|
||||
motor_.current_control_.Idq_setpoint_src_.connect_to(&open_loop_controller_.Idq_setpoint_);
|
||||
motor_.current_control_.Vdq_setpoint_src_.connect_to(&open_loop_controller_.Vdq_setpoint_);
|
||||
|
||||
motor_.current_control_.phase_src_.connect_to(&open_loop_controller_.phase_);
|
||||
acim_estimator_.rotor_phase_src_.connect_to(&open_loop_controller_.phase_);
|
||||
|
||||
motor_.phase_vel_src_.connect_to(&open_loop_controller_.phase_vel_);
|
||||
motor_.current_control_.phase_vel_src_.connect_to(&open_loop_controller_.phase_vel_);
|
||||
acim_estimator_.rotor_phase_vel_src_.connect_to(&open_loop_controller_.phase_vel_);
|
||||
}
|
||||
wait_for_control_iteration();
|
||||
|
||||
motor_.arm(&motor_.current_control_);
|
||||
|
||||
bool subscribed_to_idx_once = false;
|
||||
bool success = false;
|
||||
float dir = lockin_config.vel >= 0.0f ? 1.0f : -1.0f;
|
||||
|
||||
while ((requested_state_ == AXIS_STATE_UNDEFINED) && motor_.is_armed_) {
|
||||
bool reached_target_vel = std::abs(open_loop_controller_.phase_vel_.any().value_or(0.0f) - lockin_config.vel) <= std::numeric_limits<float>::epsilon();
|
||||
bool reached_target_dist = open_loop_controller_.total_distance_.any().value_or(0.0f) * dir >= lockin_config.finish_distance * dir;
|
||||
|
||||
// Check if terminal condition is reached
|
||||
bool terminal_condition = (reached_target_vel && lockin_config.finish_on_vel)
|
||||
|| (reached_target_dist && lockin_config.finish_on_distance)
|
||||
|| (encoder_.index_found_ && lockin_config.finish_on_enc_idx);
|
||||
if (terminal_condition) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Activate index pin as soon as target velocity was reached. This is
|
||||
// to avoid hitting the index from the wrong direction.
|
||||
if (reached_target_vel && !encoder_.index_found_ && !subscribed_to_idx_once) {
|
||||
encoder_.set_idx_subscribe(true);
|
||||
subscribed_to_idx_once = true;
|
||||
}
|
||||
|
||||
if (loop_cb)
|
||||
if (!loop_cb(reached_target_vel))
|
||||
break;
|
||||
|
||||
// TODO: use new sync function instead
|
||||
asm volatile ("" ::: "memory");
|
||||
osDelay(1);
|
||||
}
|
||||
|
||||
if (!success || !remain_armed) {
|
||||
motor_.disarm();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool Axis::start_closed_loop_control() {
|
||||
bool sensorless_mode = config_.enable_sensorless_mode;
|
||||
|
||||
if (sensorless_mode) {
|
||||
// TODO: restart if desired
|
||||
if (!run_lockin_spin(config_.sensorless_ramp, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Hook up the data paths between the components
|
||||
CRITICAL_SECTION() {
|
||||
if (sensorless_mode) {
|
||||
controller_.pos_estimate_linear_src_.disconnect();
|
||||
controller_.pos_estimate_circular_src_.disconnect();
|
||||
controller_.pos_wrap_src_.disconnect();
|
||||
controller_.vel_estimate_src_.connect_to(&sensorless_estimator_.vel_estimate_);
|
||||
} else if (controller_.config_.load_encoder_axis < AXIS_COUNT) {
|
||||
Axis* ax = &axes[controller_.config_.load_encoder_axis];
|
||||
controller_.pos_estimate_circular_src_.connect_to(&ax->encoder_.pos_circular_);
|
||||
controller_.pos_wrap_src_.connect_to(&controller_.config_.circular_setpoint_range);
|
||||
controller_.pos_estimate_linear_src_.connect_to(&ax->encoder_.pos_estimate_);
|
||||
controller_.vel_estimate_src_.connect_to(&ax->encoder_.vel_estimate_);
|
||||
} else {
|
||||
controller_.pos_estimate_circular_src_.disconnect();
|
||||
controller_.pos_estimate_linear_src_.disconnect();
|
||||
controller_.pos_wrap_src_.disconnect();
|
||||
controller_.vel_estimate_src_.disconnect();
|
||||
controller_.set_error(Controller::ERROR_INVALID_LOAD_ENCODER);
|
||||
return false;
|
||||
}
|
||||
|
||||
// To avoid any transient on startup, we intialize the setpoint to be the current position
|
||||
controller_.control_mode_updated();
|
||||
controller_.input_pos_updated();
|
||||
|
||||
// Avoid integrator windup issues
|
||||
controller_.vel_integrator_torque_ = 0.0f;
|
||||
|
||||
motor_.torque_setpoint_src_.connect_to(&controller_.torque_output_);
|
||||
motor_.direction_ = sensorless_mode ? 1.0f : encoder_.config_.direction;
|
||||
|
||||
motor_.current_control_.enable_current_control_src_ = motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL;
|
||||
motor_.current_control_.Idq_setpoint_src_.connect_to(&motor_.Idq_setpoint_);
|
||||
motor_.current_control_.Vdq_setpoint_src_.connect_to(&motor_.Vdq_setpoint_);
|
||||
|
||||
bool is_acim = motor_.config_.motor_type == Motor::MOTOR_TYPE_ACIM;
|
||||
// phase
|
||||
OutputPort<float>* phase_src = sensorless_mode ? &sensorless_estimator_.phase_ : &encoder_.phase_;
|
||||
acim_estimator_.rotor_phase_src_.connect_to(phase_src);
|
||||
OutputPort<float>* stator_phase_src = is_acim ? &acim_estimator_.stator_phase_ : phase_src;
|
||||
motor_.current_control_.phase_src_.connect_to(stator_phase_src);
|
||||
// phase vel
|
||||
OutputPort<float>* phase_vel_src = sensorless_mode ? &sensorless_estimator_.phase_vel_ : &encoder_.phase_vel_;
|
||||
acim_estimator_.rotor_phase_vel_src_.connect_to(phase_vel_src);
|
||||
OutputPort<float>* stator_phase_vel_src = is_acim ? &acim_estimator_.stator_phase_vel_ : phase_vel_src;
|
||||
motor_.phase_vel_src_.connect_to(stator_phase_vel_src);
|
||||
motor_.current_control_.phase_vel_src_.connect_to(stator_phase_vel_src);
|
||||
|
||||
if (sensorless_mode) {
|
||||
// Make the final velocity of the loĉk-in spin the setpoint of the
|
||||
// closed loop controller to allow for smooth transition.
|
||||
float vel = config_.sensorless_ramp.vel / (2.0f * M_PI * motor_.config_.pole_pairs);
|
||||
controller_.input_vel_ = vel;
|
||||
controller_.vel_setpoint_ = vel;
|
||||
}
|
||||
}
|
||||
|
||||
// In sensorless mode the motor is already armed.
|
||||
if (!motor_.is_armed_) {
|
||||
wait_for_control_iteration();
|
||||
motor_.arm(&motor_.current_control_);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Axis::stop_closed_loop_control() {
|
||||
motor_.disarm();
|
||||
return check_for_errors();
|
||||
}
|
||||
|
||||
bool Axis::run_closed_loop_control_loop() {
|
||||
start_closed_loop_control();
|
||||
set_step_dir_active(config_.enable_step_dir);
|
||||
|
||||
while ((requested_state_ == AXIS_STATE_UNDEFINED) && motor_.is_armed_) {
|
||||
osDelay(1);
|
||||
}
|
||||
|
||||
set_step_dir_active(config_.enable_step_dir && config_.step_dir_always_on);
|
||||
stop_closed_loop_control();
|
||||
|
||||
return check_for_errors();
|
||||
}
|
||||
|
||||
|
||||
// Slowly drive in the negative direction at homing_speed until the min endstop is pressed
|
||||
// When pressed, set the linear count to the offset (default 0), and then go to position 0
|
||||
bool Axis::run_homing() {
|
||||
// TODO: theoretically this check should be inside the update loop,
|
||||
// otherwise someone could disable the endstop while homing is in progress.
|
||||
if (!min_endstop_.config_.enabled) {
|
||||
return error_ |= ERROR_HOMING_WITHOUT_ENDSTOP, false;
|
||||
}
|
||||
|
||||
controller_.config_.control_mode = Controller::CONTROL_MODE_VELOCITY_CONTROL;
|
||||
controller_.config_.input_mode = Controller::INPUT_MODE_VEL_RAMP;
|
||||
|
||||
controller_.input_pos_ = 0.0f;
|
||||
controller_.input_pos_updated();
|
||||
controller_.input_vel_ = -controller_.config_.homing_speed;
|
||||
controller_.input_torque_ = 0.0f;
|
||||
|
||||
homing_.is_homed = false;
|
||||
|
||||
error_ &= ~ERROR_MIN_ENDSTOP_PRESSED;
|
||||
|
||||
bool done = false;
|
||||
|
||||
start_closed_loop_control();
|
||||
|
||||
// Driving toward the endstop
|
||||
while ((requested_state_ == AXIS_STATE_UNDEFINED) && motor_.is_armed_ && !(done = min_endstop_.get_state())) {
|
||||
osDelay(1);
|
||||
}
|
||||
|
||||
stop_closed_loop_control();
|
||||
|
||||
controller_.input_vel_ = 0.0f;
|
||||
|
||||
if (!done) {
|
||||
return false;
|
||||
}
|
||||
|
||||
error_ &= ~ERROR_MIN_ENDSTOP_PRESSED; // clear this error since we deliberately drove into the endstop
|
||||
|
||||
std::optional<float> pos_estimate_local = encoder_.pos_estimate_.any();
|
||||
if (pos_estimate_local == std::nullopt || !pos_estimate_local.has_value()){
|
||||
return error_ |= ERROR_UNKNOWN_POSITION, false;
|
||||
}
|
||||
|
||||
controller_.config_.control_mode = Controller::CONTROL_MODE_POSITION_CONTROL;
|
||||
controller_.config_.input_mode = Controller::INPUT_MODE_TRAP_TRAJ;
|
||||
|
||||
// Initialize closed loop control, and then set the desired location.
|
||||
start_closed_loop_control();
|
||||
|
||||
controller_.input_pos_ = pos_estimate_local.value() + min_endstop_.config_.offset;
|
||||
controller_.pos_setpoint_ = pos_estimate_local.value();
|
||||
controller_.vel_setpoint_ = 0.0f;
|
||||
controller_.input_pos_updated();
|
||||
|
||||
// Synchronization issue. Ensure trajectory_done is false prior to the while loop, so that
|
||||
// the controller has time to run move_to_pos() on the next update()
|
||||
controller_.trajectory_done_ = false;
|
||||
|
||||
while ((requested_state_ == AXIS_STATE_UNDEFINED) && motor_.is_armed_ && !(done = controller_.trajectory_done_)) {
|
||||
osDelay(1);
|
||||
}
|
||||
|
||||
stop_closed_loop_control();
|
||||
|
||||
if (!done) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the current position to 0, the target to zero, and make sure we're path planning from 0 to 0
|
||||
encoder_.set_linear_count(0);
|
||||
const auto load_encoder_axis = controller_.config_.load_encoder_axis;
|
||||
if(load_encoder_axis != axis_num_ && load_encoder_axis < AXIS_COUNT) {
|
||||
axes[load_encoder_axis].encoder_.set_linear_count(0);
|
||||
}
|
||||
controller_.input_pos_ = 0.0f;
|
||||
controller_.pos_setpoint_ = 0.0f;
|
||||
controller_.vel_setpoint_ = 0.0f;
|
||||
controller_.input_pos_updated();
|
||||
|
||||
// Force encoder estimate to update
|
||||
osDelay(1);
|
||||
|
||||
homing_.is_homed = true;
|
||||
|
||||
return check_for_errors();
|
||||
}
|
||||
|
||||
bool Axis::run_idle_loop() {
|
||||
last_drv_fault_ = motor_.gate_driver_.get_error();
|
||||
mechanical_brake_.engage();
|
||||
set_step_dir_active(config_.enable_step_dir && config_.step_dir_always_on);
|
||||
while (requested_state_ == AXIS_STATE_UNDEFINED) {
|
||||
motor_.setup();
|
||||
osDelay(1);
|
||||
}
|
||||
return check_for_errors();
|
||||
}
|
||||
|
||||
// Infinite loop that does calibration and enters main control loop as appropriate
|
||||
void Axis::run_state_machine_loop() {
|
||||
for (;;) {
|
||||
// Load the task chain if a specific request is pending
|
||||
if (requested_state_ != AXIS_STATE_UNDEFINED) {
|
||||
size_t pos = 0;
|
||||
if (requested_state_ == AXIS_STATE_STARTUP_SEQUENCE) {
|
||||
if (config_.startup_motor_calibration)
|
||||
task_chain_[pos++] = AXIS_STATE_MOTOR_CALIBRATION;
|
||||
if (config_.startup_encoder_index_search && encoder_.config_.use_index)
|
||||
task_chain_[pos++] = AXIS_STATE_ENCODER_INDEX_SEARCH;
|
||||
if (config_.startup_encoder_offset_calibration)
|
||||
task_chain_[pos++] = AXIS_STATE_ENCODER_OFFSET_CALIBRATION;
|
||||
if (config_.startup_homing)
|
||||
task_chain_[pos++] = AXIS_STATE_HOMING;
|
||||
if (config_.startup_closed_loop_control)
|
||||
task_chain_[pos++] = AXIS_STATE_CLOSED_LOOP_CONTROL;
|
||||
task_chain_[pos++] = AXIS_STATE_IDLE;
|
||||
} else if (requested_state_ == AXIS_STATE_FULL_CALIBRATION_SEQUENCE) {
|
||||
task_chain_[pos++] = AXIS_STATE_MOTOR_CALIBRATION;
|
||||
if (encoder_.config_.mode == ODriveIntf::EncoderIntf::MODE_HALL)
|
||||
task_chain_[pos++] = AXIS_STATE_ENCODER_HALL_POLARITY_CALIBRATION;
|
||||
if (encoder_.config_.use_index)
|
||||
task_chain_[pos++] = AXIS_STATE_ENCODER_INDEX_SEARCH;
|
||||
task_chain_[pos++] = AXIS_STATE_ENCODER_OFFSET_CALIBRATION;
|
||||
task_chain_[pos++] = AXIS_STATE_IDLE;
|
||||
} else if (requested_state_ != AXIS_STATE_UNDEFINED) {
|
||||
task_chain_[pos++] = requested_state_;
|
||||
task_chain_[pos++] = AXIS_STATE_IDLE;
|
||||
}
|
||||
task_chain_[pos++] = AXIS_STATE_UNDEFINED; // TODO: bounds checking
|
||||
requested_state_ = AXIS_STATE_UNDEFINED;
|
||||
// Auto-clear any invalid state error
|
||||
error_ &= ~ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// Note that current_state is a reference to task_chain_[0]
|
||||
|
||||
// Run the specified state
|
||||
// Handlers should exit if requested_state != AXIS_STATE_UNDEFINED
|
||||
bool status;
|
||||
switch (current_state_) {
|
||||
case AXIS_STATE_MOTOR_CALIBRATION: {
|
||||
// These error checks are a hacky way to force legacy behavior
|
||||
// when an error is raised. TODO: remove this when we overhaul
|
||||
// the error architecture
|
||||
// (https://github.com/madcowswe/ODrive/issues/526).
|
||||
//if (odrv.any_error())
|
||||
// goto invalid_state_label;
|
||||
status = motor_.run_calibration();
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_ENCODER_INDEX_SEARCH: {
|
||||
//if (odrv.any_error())
|
||||
// goto invalid_state_label;
|
||||
if (!motor_.is_calibrated_)
|
||||
goto invalid_state_label;
|
||||
|
||||
status = encoder_.run_index_search();
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_ENCODER_DIR_FIND: {
|
||||
//if (odrv.any_error())
|
||||
// goto invalid_state_label;
|
||||
if (!motor_.is_calibrated_)
|
||||
goto invalid_state_label;
|
||||
|
||||
status = encoder_.run_direction_find();
|
||||
// Help facilitate encoder.is_ready without reboot
|
||||
if (status)
|
||||
encoder_.apply_config(motor_.config_.motor_type);
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_ENCODER_HALL_POLARITY_CALIBRATION: {
|
||||
if (!motor_.is_calibrated_)
|
||||
goto invalid_state_label;
|
||||
|
||||
status = encoder_.run_hall_polarity_calibration();
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_ENCODER_HALL_PHASE_CALIBRATION: {
|
||||
if (!motor_.is_calibrated_)
|
||||
goto invalid_state_label;
|
||||
|
||||
if (!encoder_.config_.hall_polarity_calibrated) {
|
||||
encoder_.set_error(ODriveIntf::EncoderIntf::ERROR_HALL_NOT_CALIBRATED_YET);
|
||||
goto invalid_state_label;
|
||||
}
|
||||
|
||||
status = encoder_.run_hall_phase_calibration();
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_HOMING: {
|
||||
Controller::ControlMode stored_control_mode = controller_.config_.control_mode;
|
||||
Controller::InputMode stored_input_mode = controller_.config_.input_mode;
|
||||
|
||||
status = run_homing();
|
||||
|
||||
controller_.config_.control_mode = stored_control_mode;
|
||||
controller_.config_.input_mode = stored_input_mode;
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_ENCODER_OFFSET_CALIBRATION: {
|
||||
//if (odrv.any_error())
|
||||
// goto invalid_state_label;
|
||||
if (!motor_.is_calibrated_)
|
||||
goto invalid_state_label;
|
||||
status = encoder_.run_offset_calibration();
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_LOCKIN_SPIN: {
|
||||
//if (odrv.any_error())
|
||||
// goto invalid_state_label;
|
||||
if (!motor_.is_calibrated_ || encoder_.config_.direction==0)
|
||||
goto invalid_state_label;
|
||||
status = run_lockin_spin(config_.general_lockin, false);
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_CLOSED_LOOP_CONTROL: {
|
||||
//if (odrv.any_error())
|
||||
// goto invalid_state_label;
|
||||
if (!motor_.is_calibrated_ || (encoder_.config_.direction==0 && !config_.enable_sensorless_mode))
|
||||
goto invalid_state_label;
|
||||
watchdog_feed();
|
||||
status = run_closed_loop_control_loop();
|
||||
} break;
|
||||
|
||||
case AXIS_STATE_IDLE: {
|
||||
run_idle_loop();
|
||||
status = true;
|
||||
} break;
|
||||
|
||||
default:
|
||||
invalid_state_label:
|
||||
error_ |= ERROR_INVALID_STATE;
|
||||
status = false; // this will set the state to idle
|
||||
break;
|
||||
}
|
||||
|
||||
// If the state failed, go to idle, else advance task chain
|
||||
if (!status) {
|
||||
std::fill(task_chain_.begin(), task_chain_.end(), AXIS_STATE_UNDEFINED);
|
||||
current_state_ = AXIS_STATE_IDLE;
|
||||
} else {
|
||||
std::rotate(task_chain_.begin(), task_chain_.begin() + 1, task_chain_.end());
|
||||
task_chain_.back() = AXIS_STATE_UNDEFINED;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
#ifndef __AXIS_HPP
|
||||
#define __AXIS_HPP
|
||||
|
||||
class Axis;
|
||||
|
||||
#include "encoder.hpp"
|
||||
#include "acim_estimator.hpp"
|
||||
#include "sensorless_estimator.hpp"
|
||||
#include "controller.hpp"
|
||||
#include "open_loop_controller.hpp"
|
||||
#include "trapTraj.hpp"
|
||||
#include "endstop.hpp"
|
||||
#include "mechanical_brake.hpp"
|
||||
#include "low_level.h"
|
||||
#include "utils.hpp"
|
||||
#include "task_timer.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
class Axis : public ODriveIntf::AxisIntf {
|
||||
public:
|
||||
struct LockinConfig_t {
|
||||
float current = 10.0f; // [A]
|
||||
float ramp_time = 0.4f; // [s]
|
||||
float ramp_distance = 1 * M_PI; // [rad]
|
||||
float accel = 20.0f; // [rad/s^2]
|
||||
float vel = 40.0f; // [rad/s]
|
||||
float finish_distance = 100.0f; // [rad]
|
||||
bool finish_on_vel = false;
|
||||
bool finish_on_distance = false;
|
||||
bool finish_on_enc_idx = false;
|
||||
};
|
||||
|
||||
struct TaskTimes {
|
||||
TaskTimer thermistor_update;
|
||||
TaskTimer encoder_update;
|
||||
TaskTimer sensorless_estimator_update;
|
||||
TaskTimer endstop_update;
|
||||
TaskTimer can_heartbeat;
|
||||
TaskTimer controller_update;
|
||||
TaskTimer open_loop_controller_update;
|
||||
TaskTimer acim_estimator_update;
|
||||
TaskTimer motor_update;
|
||||
TaskTimer current_controller_update;
|
||||
TaskTimer dc_calib;
|
||||
TaskTimer current_sense;
|
||||
TaskTimer pwm_update;
|
||||
};
|
||||
|
||||
static LockinConfig_t default_calibration();
|
||||
static LockinConfig_t default_sensorless();
|
||||
static LockinConfig_t default_lockin();
|
||||
|
||||
struct CANConfig_t {
|
||||
uint32_t node_id = 0;
|
||||
bool is_extended = false;
|
||||
uint32_t heartbeat_rate_ms = 100;
|
||||
uint32_t encoder_rate_ms = 10;
|
||||
uint32_t motor_error_rate_ms = 0;
|
||||
uint32_t encoder_error_rate_ms = 0;
|
||||
uint32_t controller_error_rate_ms = 0;
|
||||
uint32_t sensorless_error_rate_ms = 0;
|
||||
uint32_t encoder_count_rate_ms = 0;
|
||||
uint32_t iq_rate_ms = 0;
|
||||
uint32_t sensorless_rate_ms = 0;
|
||||
uint32_t bus_vi_rate_ms = 0;
|
||||
};
|
||||
|
||||
struct Config_t {
|
||||
bool startup_motor_calibration = false; //<! run motor calibration at startup, skip otherwise
|
||||
bool startup_encoder_index_search = false; //<! run encoder index search after startup, skip otherwise
|
||||
// this only has an effect if encoder.config.use_index is also true
|
||||
bool startup_encoder_offset_calibration = false; //<! run encoder offset calibration after startup, skip otherwise
|
||||
bool startup_closed_loop_control = false; //<! enable closed loop control after calibration/startup
|
||||
bool startup_homing = false; //<! enable homing after calibration/startup
|
||||
|
||||
bool enable_step_dir = false; //<! enable step/dir input after calibration
|
||||
// For M0 this has no effect if enable_uart is true
|
||||
bool step_dir_always_on = false; //<! Keep step/dir enabled while the motor is disabled.
|
||||
//<! This is ignored if enable_step_dir is false.
|
||||
//<! This setting only takes effect on a state transition
|
||||
//<! into idle or out of closed loop control.
|
||||
|
||||
bool enable_sensorless_mode = false;
|
||||
|
||||
float watchdog_timeout = 0.0f; // [s]
|
||||
bool enable_watchdog = false;
|
||||
|
||||
// Defaults loaded from hw_config in load_configuration in main.cpp
|
||||
uint16_t step_gpio_pin = 0;
|
||||
uint16_t dir_gpio_pin = 0;
|
||||
|
||||
LockinConfig_t calibration_lockin = default_calibration();
|
||||
LockinConfig_t sensorless_ramp = default_sensorless();
|
||||
LockinConfig_t general_lockin;
|
||||
|
||||
CANConfig_t can;
|
||||
|
||||
// custom setters
|
||||
Axis* parent = nullptr;
|
||||
void set_step_gpio_pin(uint16_t value) { step_gpio_pin = value; parent->decode_step_dir_pins(); }
|
||||
void set_dir_gpio_pin(uint16_t value) { dir_gpio_pin = value; parent->decode_step_dir_pins(); }
|
||||
};
|
||||
|
||||
struct Homing_t {
|
||||
bool is_homed = false;
|
||||
};
|
||||
|
||||
struct CAN_t {
|
||||
uint32_t last_heartbeat = 0;
|
||||
uint32_t last_encoder = 0;
|
||||
uint32_t last_motor_error = 0;
|
||||
uint32_t last_encoder_error = 0;
|
||||
uint32_t last_controller_error = 0;
|
||||
uint32_t last_sensorless_error = 0;
|
||||
uint32_t last_encoder_count = 0;
|
||||
uint32_t last_iq = 0;
|
||||
uint32_t last_sensorless = 0;
|
||||
uint32_t last_bus_vi = 0;
|
||||
};
|
||||
|
||||
Axis(int axis_num,
|
||||
uint16_t default_step_gpio_pin,
|
||||
uint16_t default_dir_gpio_pin,
|
||||
osPriority thread_priority,
|
||||
Encoder& encoder,
|
||||
SensorlessEstimator& sensorless_estimator,
|
||||
Controller& controller,
|
||||
Motor& motor,
|
||||
TrapezoidalTrajectory& trap,
|
||||
Endstop& min_endstop,
|
||||
Endstop& max_endstop,
|
||||
MechanicalBrake& mechanical_brake);
|
||||
|
||||
bool apply_config();
|
||||
void clear_config();
|
||||
|
||||
void start_thread();
|
||||
bool wait_for_control_iteration();
|
||||
|
||||
void step_cb();
|
||||
void set_step_dir_active(bool enable);
|
||||
void decode_step_dir_pins();
|
||||
|
||||
bool do_checks(uint32_t timestamp);
|
||||
|
||||
void watchdog_feed();
|
||||
bool watchdog_check();
|
||||
|
||||
// True if there are no errors
|
||||
bool inline check_for_errors() {
|
||||
return error_ == ERROR_NONE;
|
||||
}
|
||||
|
||||
bool start_closed_loop_control();
|
||||
bool stop_closed_loop_control();
|
||||
bool run_lockin_spin(const LockinConfig_t &lockin_config, bool remain_armed,
|
||||
std::function<bool(bool)> loop_cb = {} );
|
||||
bool run_closed_loop_control_loop();
|
||||
bool run_homing();
|
||||
bool run_idle_loop();
|
||||
|
||||
constexpr uint32_t get_watchdog_reset() {
|
||||
return static_cast<uint32_t>(std::clamp<float>(config_.watchdog_timeout, 0, UINT32_MAX / (current_meas_hz + 1)) * current_meas_hz);
|
||||
}
|
||||
|
||||
void run_state_machine_loop();
|
||||
|
||||
// hardware config
|
||||
int axis_num_;
|
||||
uint16_t default_step_gpio_pin_;
|
||||
uint16_t default_dir_gpio_pin_;
|
||||
osPriority thread_priority_;
|
||||
Config_t config_;
|
||||
|
||||
Encoder& encoder_;
|
||||
AcimEstimator acim_estimator_;
|
||||
SensorlessEstimator& sensorless_estimator_;
|
||||
Controller& controller_;
|
||||
OpenLoopController open_loop_controller_;
|
||||
Motor& motor_;
|
||||
TrapezoidalTrajectory& trap_traj_;
|
||||
Endstop& min_endstop_;
|
||||
Endstop& max_endstop_;
|
||||
MechanicalBrake& mechanical_brake_;
|
||||
TaskTimes task_times_;
|
||||
|
||||
osThreadId thread_id_ = 0;
|
||||
const uint32_t stack_size_ = 2048; // Bytes
|
||||
volatile bool thread_id_valid_ = false;
|
||||
|
||||
// variables exposed on protocol
|
||||
Error error_ = ERROR_NONE;
|
||||
bool step_dir_active_ = false; // auto enabled after calibration, based on config.enable_step_dir
|
||||
int64_t steps_ = 0; // Steps counted at interface
|
||||
uint32_t last_drv_fault_ = 0;
|
||||
|
||||
// updated from config in constructor, and on protocol hook
|
||||
Stm32Gpio step_gpio_;
|
||||
Stm32Gpio dir_gpio_;
|
||||
|
||||
AxisState requested_state_ = AXIS_STATE_STARTUP_SEQUENCE;
|
||||
std::array<AxisState, 10> task_chain_ = { AXIS_STATE_UNDEFINED };
|
||||
AxisState& current_state_ = task_chain_.front();
|
||||
Homing_t homing_;
|
||||
CAN_t can_;
|
||||
|
||||
|
||||
// watchdog
|
||||
uint32_t watchdog_current_value_= 0;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __AXIS_HPP */
|
||||
@@ -0,0 +1,182 @@
|
||||
#ifndef __COMPONENT_HPP
|
||||
#define __COMPONENT_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
class ComponentBase {
|
||||
public:
|
||||
/**
|
||||
* @brief Shall run the update action of this component.
|
||||
*
|
||||
* This function gets called in a low priority interrupt context and is
|
||||
* allowed to call CMSIS functions.
|
||||
*
|
||||
* @param timestamp: The timestamp (in HCLK ticks) for which this update
|
||||
* is run.
|
||||
*/
|
||||
virtual void update(uint32_t timestamp) = 0;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class InputPort;
|
||||
|
||||
/**
|
||||
* @brief An output port stores a value for consumption by a connecting input
|
||||
* port.
|
||||
*
|
||||
* Output ports are supposed to be reset at the beginning of a control loop
|
||||
* iteration. This ensures that connecting input ports don't use an outdated
|
||||
* value and, more importantly, ensures proper handling if the producer of the
|
||||
* value is incapable of producing the value for any reason.
|
||||
*
|
||||
* Member functions of this class are not thread-safe unless noted otherwise.
|
||||
*/
|
||||
template<typename T>
|
||||
class OutputPort {
|
||||
public:
|
||||
/**
|
||||
* @brief Initializes the output port with the specified value.
|
||||
*
|
||||
* An initialization value is required for any() to work properly.
|
||||
* present() and previous() cannot be used to fetch the
|
||||
* initialization value.
|
||||
*/
|
||||
OutputPort(T val) : content_(val) {}
|
||||
|
||||
/**
|
||||
* @brief Updates the underlying value of this output port.
|
||||
*/
|
||||
void operator=(T value) {
|
||||
content_ = value;
|
||||
age_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks the contained value as outdated. The value is not actually
|
||||
* deleted and can still be accessed through some of the member functions
|
||||
* of this class.
|
||||
*/
|
||||
void reset() {
|
||||
// This will eventually overflow to 0 so present() could
|
||||
// theoretically return a very old value however it is very likely that
|
||||
// the motor will be long disarmed by then.
|
||||
age_++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the value from this control loop iteration or std::nullopt
|
||||
* if the value was not yet set during this control loop iteration.
|
||||
*/
|
||||
std::optional<T> present() {
|
||||
if (age_ == 0) {
|
||||
return content_;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the value from exactly the previous control loop iteration.
|
||||
*
|
||||
* If during the last iteration no value was set or the value was already
|
||||
* overwritten during this control loop iteration then this function returns
|
||||
* std::nullopt.
|
||||
*/
|
||||
std::optional<T> previous() {
|
||||
if (age_ == 1) {
|
||||
return content_;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the value contained in this output port with disregard of
|
||||
* when the value was set.
|
||||
*
|
||||
* This function is thread-safe if load/store operations of T are atomic.
|
||||
*/
|
||||
std::optional<T> any() {
|
||||
return content_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t age_ = 2; // Age in number of control loop iterations
|
||||
T content_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An input port provides a value from the source to which it's configured.
|
||||
*
|
||||
* The source can be one of:
|
||||
* - an internally stored value
|
||||
* - an externally stored value (referenced by a pointer)
|
||||
* - an external OutputPort (referenced by a pointer)
|
||||
* - none (all queries will return std::nullopt)
|
||||
*
|
||||
* Member functions of this class are not thread-safe unless otherwise noted.
|
||||
*/
|
||||
template<typename T>
|
||||
class InputPort {
|
||||
public:
|
||||
void connect_to(OutputPort<T>* input_port) {
|
||||
content_ = input_port;
|
||||
}
|
||||
|
||||
void connect_to(T* input_ptr) {
|
||||
content_ = input_ptr;
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
content_ = (OutputPort<T>*)nullptr;
|
||||
}
|
||||
|
||||
std::optional<T> present() {
|
||||
if (content_.index() == 2) {
|
||||
OutputPort<T>* ptr = std::get<2>(content_);
|
||||
return ptr ? ptr->present() : std::nullopt;
|
||||
} else if (content_.index() == 1) {
|
||||
T* ptr = std::get<1>(content_);
|
||||
return ptr ? std::make_optional(*ptr) : std::nullopt;
|
||||
} else {
|
||||
return std::get<0>(content_);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: probably it makes sense to let the application define that it's
|
||||
// ok for this input port to fetch the value from the last iteration.
|
||||
// This would provide a general way to resolve same-iteration data path cycles.
|
||||
|
||||
//std::optional<T> previous() {
|
||||
// if (content_.index() == 2) {
|
||||
// OutputPort<T>* ptr = std::get<2>(content_);
|
||||
// return ptr ? ptr->previous() : std::nullopt;
|
||||
// } else if (content_.index() == 1) {
|
||||
// T* ptr = std::get<1>(content_);
|
||||
// return ptr ? std::make_optional(*ptr) : std::nullopt;
|
||||
// } else {
|
||||
// return std::get<0>(content_);
|
||||
// }
|
||||
//}
|
||||
|
||||
std::optional<T> any() {
|
||||
if (content_.index() == 2) {
|
||||
OutputPort<T>* ptr = std::get<2>(content_);
|
||||
return ptr ? ptr->any() : std::nullopt;
|
||||
} else if (content_.index() == 1) {
|
||||
T* ptr = std::get<1>(content_);
|
||||
return ptr ? std::make_optional(*ptr) : std::nullopt;
|
||||
} else {
|
||||
return std::get<0>(content_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::variant<T, T*, OutputPort<T>*> content_;
|
||||
};
|
||||
|
||||
|
||||
#endif // __COMPONENT_HPP
|
||||
@@ -0,0 +1,451 @@
|
||||
|
||||
#include "odrive_main.h"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
bool Controller::apply_config() {
|
||||
config_.parent = this;
|
||||
update_filter_gains();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Controller::reset() {
|
||||
// pos_setpoint is initialized in start_closed_loop_control
|
||||
vel_setpoint_ = 0.0f;
|
||||
vel_integrator_torque_ = 0.0f;
|
||||
torque_setpoint_ = 0.0f;
|
||||
mechanical_power_ = 0.0f;
|
||||
electrical_power_ = 0.0f;
|
||||
}
|
||||
|
||||
void Controller::set_error(Error error) {
|
||||
error_ |= error;
|
||||
last_error_time_ = odrv.n_evt_control_loop_ * current_meas_period;
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// Command Handling
|
||||
//--------------------------------
|
||||
|
||||
|
||||
void Controller::move_to_pos(float goal_point) {
|
||||
axis_->trap_traj_.planTrapezoidal(goal_point, pos_setpoint_, vel_setpoint_,
|
||||
axis_->trap_traj_.config_.vel_limit,
|
||||
axis_->trap_traj_.config_.accel_limit,
|
||||
axis_->trap_traj_.config_.decel_limit);
|
||||
axis_->trap_traj_.t_ = 0.0f;
|
||||
trajectory_done_ = false;
|
||||
}
|
||||
|
||||
void Controller::move_incremental(float displacement, bool from_input_pos = true){
|
||||
if(from_input_pos){
|
||||
input_pos_ += displacement;
|
||||
} else{
|
||||
input_pos_ = pos_setpoint_ + displacement;
|
||||
}
|
||||
|
||||
input_pos_updated();
|
||||
}
|
||||
|
||||
void Controller::start_anticogging_calibration() {
|
||||
// Ensure the cogging map was correctly allocated earlier and that the motor is capable of calibrating
|
||||
if (axis_->error_ == Axis::ERROR_NONE) {
|
||||
config_.anticogging.calib_anticogging = true;
|
||||
}
|
||||
}
|
||||
|
||||
float Controller::remove_anticogging_bias()
|
||||
{
|
||||
auto& cogmap = config_.anticogging.cogging_map;
|
||||
|
||||
auto sum = std::accumulate(std::begin(cogmap), std::end(cogmap), 0.0f);
|
||||
auto average = sum / std::size(cogmap);
|
||||
|
||||
for(auto& val : cogmap) {
|
||||
val -= average;
|
||||
}
|
||||
|
||||
return average;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This anti-cogging implementation iterates through each encoder position,
|
||||
* waits for zero velocity & position error,
|
||||
* then samples the current required to maintain that position.
|
||||
*
|
||||
* This holding current is added as a feedforward term in the control loop.
|
||||
*/
|
||||
bool Controller::anticogging_calibration(float pos_estimate, float vel_estimate) {
|
||||
float pos_err = input_pos_ - pos_estimate;
|
||||
if (std::abs(pos_err) <= config_.anticogging.calib_pos_threshold / (float)axis_->encoder_.config_.cpr &&
|
||||
std::abs(vel_estimate) < config_.anticogging.calib_vel_threshold / (float)axis_->encoder_.config_.cpr) {
|
||||
config_.anticogging.cogging_map[std::clamp<uint32_t>(config_.anticogging.index++, 0, 3600)] = vel_integrator_torque_;
|
||||
}
|
||||
if (config_.anticogging.index < 3600) {
|
||||
config_.control_mode = CONTROL_MODE_POSITION_CONTROL;
|
||||
input_pos_ = config_.anticogging.index * axis_->encoder_.getCoggingRatio();
|
||||
input_vel_ = 0.0f;
|
||||
input_torque_ = 0.0f;
|
||||
input_pos_updated();
|
||||
return false;
|
||||
} else {
|
||||
config_.anticogging.index = 0;
|
||||
config_.control_mode = CONTROL_MODE_POSITION_CONTROL;
|
||||
input_pos_ = 0.0f; // Send the motor home
|
||||
input_vel_ = 0.0f;
|
||||
input_torque_ = 0.0f;
|
||||
input_pos_updated();
|
||||
anticogging_valid_ = true;
|
||||
config_.anticogging.calib_anticogging = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::set_input_pos_and_steps(float const pos) {
|
||||
input_pos_ = pos;
|
||||
if (config_.circular_setpoints) {
|
||||
float const range = config_.circular_setpoint_range;
|
||||
axis_->steps_ = (int64_t)(fmodf_pos(pos, range) / range * config_.steps_per_circular_range);
|
||||
} else {
|
||||
axis_->steps_ = (int64_t)(pos * config_.steps_per_circular_range);
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller::control_mode_updated() {
|
||||
if (config_.control_mode >= CONTROL_MODE_POSITION_CONTROL) {
|
||||
std::optional<float> estimate = (config_.circular_setpoints ?
|
||||
pos_estimate_circular_src_ :
|
||||
pos_estimate_linear_src_).any();
|
||||
if (!estimate.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pos_setpoint_ = *estimate;
|
||||
set_input_pos_and_steps(*estimate);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Controller::update_filter_gains() {
|
||||
float bandwidth = std::min(config_.input_filter_bandwidth, 0.25f * current_meas_hz);
|
||||
input_filter_ki_ = 2.0f * bandwidth; // basic conversion to discrete time
|
||||
input_filter_kp_ = 0.25f * (input_filter_ki_ * input_filter_ki_); // Critically damped
|
||||
}
|
||||
|
||||
static float limitVel(const float vel_limit, const float vel_estimate, const float vel_gain, const float torque) {
|
||||
float Tmax = (vel_limit - vel_estimate) * vel_gain;
|
||||
float Tmin = (-vel_limit - vel_estimate) * vel_gain;
|
||||
return std::clamp(torque, Tmin, Tmax);
|
||||
}
|
||||
|
||||
bool Controller::update() {
|
||||
std::optional<float> pos_estimate_linear = pos_estimate_linear_src_.present();
|
||||
std::optional<float> pos_estimate_circular = pos_estimate_circular_src_.present();
|
||||
std::optional<float> pos_wrap = pos_wrap_src_.present();
|
||||
std::optional<float> vel_estimate = vel_estimate_src_.present();
|
||||
|
||||
std::optional<float> anticogging_pos_estimate = axis_->encoder_.pos_estimate_.present();
|
||||
std::optional<float> anticogging_vel_estimate = axis_->encoder_.vel_estimate_.present();
|
||||
|
||||
if (axis_->step_dir_active_) {
|
||||
if (config_.circular_setpoints) {
|
||||
if (!pos_wrap.has_value()) {
|
||||
set_error(ERROR_INVALID_CIRCULAR_RANGE);
|
||||
return false;
|
||||
}
|
||||
input_pos_ = (float)(axis_->steps_ % config_.steps_per_circular_range) * (*pos_wrap / (float)(config_.steps_per_circular_range));
|
||||
} else {
|
||||
input_pos_ = (float)(axis_->steps_) / (float)(config_.steps_per_circular_range);
|
||||
}
|
||||
}
|
||||
|
||||
if (config_.anticogging.calib_anticogging) {
|
||||
if (!anticogging_pos_estimate.has_value() || !anticogging_vel_estimate.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
// non-blocking
|
||||
anticogging_calibration(*anticogging_pos_estimate, *anticogging_vel_estimate);
|
||||
}
|
||||
|
||||
// TODO also enable circular deltas for 2nd order filter, etc.
|
||||
if (config_.circular_setpoints) {
|
||||
if (!pos_wrap.has_value()) {
|
||||
set_error(ERROR_INVALID_CIRCULAR_RANGE);
|
||||
return false;
|
||||
}
|
||||
input_pos_ = fmodf_pos(input_pos_, *pos_wrap);
|
||||
}
|
||||
|
||||
// Update inputs
|
||||
switch (config_.input_mode) {
|
||||
case INPUT_MODE_INACTIVE: {
|
||||
// do nothing
|
||||
} break;
|
||||
case INPUT_MODE_PASSTHROUGH: {
|
||||
pos_setpoint_ = input_pos_;
|
||||
vel_setpoint_ = input_vel_;
|
||||
torque_setpoint_ = input_torque_;
|
||||
} break;
|
||||
case INPUT_MODE_VEL_RAMP: {
|
||||
float max_step_size = std::abs(current_meas_period * config_.vel_ramp_rate);
|
||||
float full_step = input_vel_ - vel_setpoint_;
|
||||
float step = std::clamp(full_step, -max_step_size, max_step_size);
|
||||
|
||||
vel_setpoint_ += step;
|
||||
torque_setpoint_ = (step / current_meas_period) * config_.inertia;
|
||||
} break;
|
||||
case INPUT_MODE_TORQUE_RAMP: {
|
||||
float max_step_size = std::abs(current_meas_period * config_.torque_ramp_rate);
|
||||
float full_step = input_torque_ - torque_setpoint_;
|
||||
float step = std::clamp(full_step, -max_step_size, max_step_size);
|
||||
|
||||
torque_setpoint_ += step;
|
||||
} break;
|
||||
case INPUT_MODE_POS_FILTER: {
|
||||
// 2nd order pos tracking filter
|
||||
float delta_pos = input_pos_ - pos_setpoint_; // Pos error
|
||||
if (config_.circular_setpoints) {
|
||||
if (!pos_wrap.has_value()) {
|
||||
set_error(ERROR_INVALID_CIRCULAR_RANGE);
|
||||
return false;
|
||||
}
|
||||
delta_pos = wrap_pm(delta_pos, *pos_wrap);
|
||||
}
|
||||
float delta_vel = input_vel_ - vel_setpoint_; // Vel error
|
||||
float accel = input_filter_kp_*delta_pos + input_filter_ki_*delta_vel; // Feedback
|
||||
torque_setpoint_ = accel * config_.inertia; // Accel
|
||||
vel_setpoint_ += current_meas_period * accel; // delta vel
|
||||
pos_setpoint_ += current_meas_period * vel_setpoint_; // Delta pos
|
||||
} break;
|
||||
case INPUT_MODE_MIRROR: {
|
||||
if (config_.axis_to_mirror < AXIS_COUNT) {
|
||||
std::optional<float> other_pos = axes[config_.axis_to_mirror].encoder_.pos_estimate_.present();
|
||||
std::optional<float> other_vel = axes[config_.axis_to_mirror].encoder_.vel_estimate_.present();
|
||||
std::optional<float> other_torque = axes[config_.axis_to_mirror].controller_.torque_output_.present();
|
||||
|
||||
if (!other_pos.has_value() || !other_vel.has_value() || !other_torque.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
|
||||
pos_setpoint_ = *other_pos * config_.mirror_ratio;
|
||||
vel_setpoint_ = *other_vel * config_.mirror_ratio;
|
||||
torque_setpoint_ = *other_torque * config_.torque_mirror_ratio;
|
||||
} else {
|
||||
set_error(ERROR_INVALID_MIRROR_AXIS);
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
// case INPUT_MODE_MIX_CHANNELS: {
|
||||
// // NOT YET IMPLEMENTED
|
||||
// } break;
|
||||
case INPUT_MODE_TRAP_TRAJ: {
|
||||
if(input_pos_updated_){
|
||||
move_to_pos(input_pos_);
|
||||
input_pos_updated_ = false;
|
||||
}
|
||||
// Avoid updating uninitialized trajectory
|
||||
if (trajectory_done_)
|
||||
break;
|
||||
|
||||
if (axis_->trap_traj_.t_ > axis_->trap_traj_.Tf_) {
|
||||
// Drop into position control mode when done to avoid problems on loop counter delta overflow
|
||||
config_.control_mode = CONTROL_MODE_POSITION_CONTROL;
|
||||
pos_setpoint_ = axis_->trap_traj_.Xf_;
|
||||
vel_setpoint_ = 0.0f;
|
||||
torque_setpoint_ = 0.0f;
|
||||
trajectory_done_ = true;
|
||||
} else {
|
||||
TrapezoidalTrajectory::Step_t traj_step = axis_->trap_traj_.eval(axis_->trap_traj_.t_);
|
||||
pos_setpoint_ = traj_step.Y;
|
||||
vel_setpoint_ = traj_step.Yd;
|
||||
torque_setpoint_ = traj_step.Ydd * config_.inertia;
|
||||
axis_->trap_traj_.t_ += current_meas_period;
|
||||
}
|
||||
anticogging_pos_estimate = pos_setpoint_; // FF the position setpoint instead of the pos_estimate
|
||||
} break;
|
||||
case INPUT_MODE_TUNING: {
|
||||
autotuning_phase_ = wrap_pm_pi(autotuning_phase_ + (2.0f * M_PI * autotuning_.frequency * current_meas_period));
|
||||
float c = our_arm_cos_f32(autotuning_phase_);
|
||||
float s = our_arm_sin_f32(autotuning_phase_);
|
||||
pos_setpoint_ = input_pos_ + autotuning_.pos_amplitude * s; // + pos_amp_c * c
|
||||
vel_setpoint_ = input_vel_ + autotuning_.vel_amplitude * c;
|
||||
torque_setpoint_ = input_torque_ + autotuning_.torque_amplitude * -s;
|
||||
} break;
|
||||
default: {
|
||||
set_error(ERROR_INVALID_INPUT_MODE);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Never command a setpoint beyond its limit
|
||||
if(config_.enable_vel_limit) {
|
||||
vel_setpoint_ = std::clamp(vel_setpoint_, -config_.vel_limit, config_.vel_limit);
|
||||
}
|
||||
const float Tlim = axis_->motor_.max_available_torque();
|
||||
torque_setpoint_ = std::clamp(torque_setpoint_, -Tlim, Tlim);
|
||||
|
||||
// Position control
|
||||
// TODO Decide if we want to use encoder or pll position here
|
||||
float gain_scheduling_multiplier = 1.0f;
|
||||
float vel_des = vel_setpoint_;
|
||||
if (config_.control_mode >= CONTROL_MODE_POSITION_CONTROL) {
|
||||
float pos_err;
|
||||
|
||||
if (config_.circular_setpoints) {
|
||||
if (!pos_estimate_circular.has_value() || !pos_wrap.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
// Keep pos setpoint from drifting
|
||||
pos_setpoint_ = fmodf_pos(pos_setpoint_, *pos_wrap);
|
||||
// Circular delta
|
||||
pos_err = pos_setpoint_ - *pos_estimate_circular;
|
||||
pos_err = wrap_pm(pos_err, *pos_wrap);
|
||||
} else {
|
||||
if (!pos_estimate_linear.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
pos_err = pos_setpoint_ - *pos_estimate_linear;
|
||||
}
|
||||
|
||||
vel_des += config_.pos_gain * pos_err;
|
||||
// V-shaped gain shedule based on position error
|
||||
float abs_pos_err = std::abs(pos_err);
|
||||
if (config_.enable_gain_scheduling && abs_pos_err <= config_.gain_scheduling_width) {
|
||||
gain_scheduling_multiplier = abs_pos_err / config_.gain_scheduling_width;
|
||||
}
|
||||
}
|
||||
|
||||
// Velocity limiting
|
||||
float vel_lim = config_.vel_limit;
|
||||
if (config_.enable_vel_limit) {
|
||||
vel_des = std::clamp(vel_des, -vel_lim, vel_lim);
|
||||
}
|
||||
|
||||
// Check for overspeed fault (done in this module (controller) for cohesion with vel_lim)
|
||||
if (config_.enable_overspeed_error) { // 0.0f to disable
|
||||
if (!vel_estimate.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
if (std::abs(*vel_estimate) > config_.vel_limit_tolerance * vel_lim) {
|
||||
set_error(ERROR_OVERSPEED);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Change to controller working in torque units
|
||||
// Torque per amp gain scheduling (ACIM)
|
||||
float vel_gain = config_.vel_gain;
|
||||
float vel_integrator_gain = config_.vel_integrator_gain;
|
||||
if (axis_->motor_.config_.motor_type == Motor::MOTOR_TYPE_ACIM) {
|
||||
float effective_flux = axis_->acim_estimator_.rotor_flux_;
|
||||
float minflux = axis_->motor_.config_.acim_gain_min_flux;
|
||||
if (std::abs(effective_flux) < minflux)
|
||||
effective_flux = std::copysignf(minflux, effective_flux);
|
||||
vel_gain /= effective_flux;
|
||||
vel_integrator_gain /= effective_flux;
|
||||
// TODO: also scale the integral value which is also changing units.
|
||||
// (or again just do control in torque units)
|
||||
}
|
||||
|
||||
// Velocity control
|
||||
float torque = torque_setpoint_;
|
||||
|
||||
// Anti-cogging is enabled after calibration
|
||||
// We get the current position and apply a current feed-forward
|
||||
// ensuring that we handle negative encoder positions properly (-1 == motor->encoder.encoder_cpr - 1)
|
||||
if (anticogging_valid_ && config_.anticogging.anticogging_enabled) {
|
||||
if (!anticogging_pos_estimate.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
float anticogging_pos = *anticogging_pos_estimate / axis_->encoder_.getCoggingRatio();
|
||||
torque += config_.anticogging.cogging_map[std::clamp(mod((int)anticogging_pos, 3600), 0, 3600)];
|
||||
}
|
||||
|
||||
float v_err = 0.0f;
|
||||
if (config_.control_mode >= CONTROL_MODE_VELOCITY_CONTROL) {
|
||||
if (!vel_estimate.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
|
||||
v_err = vel_des - *vel_estimate;
|
||||
torque += (vel_gain * gain_scheduling_multiplier) * v_err;
|
||||
|
||||
// Velocity integral action before limiting
|
||||
torque += vel_integrator_torque_;
|
||||
}
|
||||
|
||||
// Velocity limiting in current mode
|
||||
if (config_.control_mode < CONTROL_MODE_VELOCITY_CONTROL && config_.enable_torque_mode_vel_limit) {
|
||||
if (!vel_estimate.has_value()) {
|
||||
set_error(ERROR_INVALID_ESTIMATE);
|
||||
return false;
|
||||
}
|
||||
torque = limitVel(config_.vel_limit, *vel_estimate, vel_gain, torque);
|
||||
}
|
||||
|
||||
// Torque limiting
|
||||
bool limited = false;
|
||||
if (torque > Tlim) {
|
||||
limited = true;
|
||||
torque = Tlim;
|
||||
}
|
||||
if (torque < -Tlim) {
|
||||
limited = true;
|
||||
torque = -Tlim;
|
||||
}
|
||||
|
||||
// Velocity integrator (behaviour dependent on limiting)
|
||||
if (config_.control_mode < CONTROL_MODE_VELOCITY_CONTROL) {
|
||||
// reset integral if not in use
|
||||
vel_integrator_torque_ = 0.0f;
|
||||
} else {
|
||||
if (limited) {
|
||||
// TODO make decayfactor configurable
|
||||
vel_integrator_torque_ *= 0.99f;
|
||||
} else {
|
||||
vel_integrator_torque_ += ((vel_integrator_gain * gain_scheduling_multiplier) * current_meas_period) * v_err;
|
||||
}
|
||||
// integrator limiting to prevent windup
|
||||
vel_integrator_torque_ = std::clamp(vel_integrator_torque_, -config_.vel_integrator_limit, config_.vel_integrator_limit);
|
||||
}
|
||||
|
||||
float ideal_electrical_power = 0.0f;
|
||||
if (axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL) {
|
||||
ideal_electrical_power = axis_->motor_.current_control_.power_ - \
|
||||
SQ(axis_->motor_.current_control_.Iq_measured_) * 1.5f * axis_->motor_.config_.phase_resistance - \
|
||||
SQ(axis_->motor_.current_control_.Id_measured_) * 1.5f * axis_->motor_.config_.phase_resistance;
|
||||
}
|
||||
else {
|
||||
ideal_electrical_power = axis_->motor_.current_control_.power_;
|
||||
}
|
||||
mechanical_power_ += config_.mechanical_power_bandwidth * current_meas_period * (torque * *vel_estimate * M_PI * 2.0f - mechanical_power_);
|
||||
electrical_power_ += config_.electrical_power_bandwidth * current_meas_period * (ideal_electrical_power - electrical_power_);
|
||||
|
||||
// Spinout check
|
||||
// If mechanical power is negative (braking) and measured power is positive, something is wrong
|
||||
// This indicates that the controller is trying to stop, but torque is being produced.
|
||||
// Usually caused by an incorrect encoder offset
|
||||
if (mechanical_power_ < config_.spinout_mechanical_power_threshold && electrical_power_ > config_.spinout_electrical_power_threshold) {
|
||||
set_error(ERROR_SPINOUT_DETECTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
torque_output_ = torque;
|
||||
|
||||
// TODO: this is inconsistent with the other errors which are sticky.
|
||||
// However if we make ERROR_INVALID_ESTIMATE sticky then it will be
|
||||
// confusing that a normal sequence of motor calibration + encoder
|
||||
// calibration would leave the controller in an error state.
|
||||
error_ &= ~ERROR_INVALID_ESTIMATE;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
#ifndef __CONTROLLER_HPP
|
||||
#define __CONTROLLER_HPP
|
||||
|
||||
class Controller : public ODriveIntf::ControllerIntf {
|
||||
public:
|
||||
struct Anticogging_t {
|
||||
uint32_t index = 0;
|
||||
float cogging_map[3600];
|
||||
bool pre_calibrated = false;
|
||||
bool calib_anticogging = false;
|
||||
float calib_pos_threshold = 1.0f;
|
||||
float calib_vel_threshold = 1.0f;
|
||||
float cogging_ratio = 1.0f;
|
||||
bool anticogging_enabled = true;
|
||||
};
|
||||
|
||||
struct Autotuning_t {
|
||||
float frequency = 0.0f;
|
||||
float pos_amplitude = 0.0f;
|
||||
float vel_amplitude = 0.0f;
|
||||
float torque_amplitude = 0.0f;
|
||||
};
|
||||
|
||||
struct Config_t {
|
||||
ControlMode control_mode = CONTROL_MODE_POSITION_CONTROL; //see: ControlMode_t
|
||||
InputMode input_mode = INPUT_MODE_PASSTHROUGH; //see: InputMode_t
|
||||
float pos_gain = 20.0f; // [(turn/s) / turn]
|
||||
float vel_gain = 1.0f / 6.0f; // [Nm/(turn/s)]
|
||||
// float vel_gain = 0.2f / 200.0f, // [Nm/(rad/s)] <sensorless example>
|
||||
float vel_integrator_gain = 2.0f / 6.0f; // [Nm/(turn/s * s)]
|
||||
float vel_limit = 2.0f; // [turn/s] Infinity to disable.
|
||||
float vel_limit_tolerance = 1.2f; // ratio to vel_lim. Infinity to disable.
|
||||
float vel_integrator_limit = INFINITY; // Vel. integrator clamping value. Infinity to disable.
|
||||
float vel_ramp_rate = 1.0f; // [(turn/s) / s]
|
||||
float torque_ramp_rate = 0.01f; // Nm / sec
|
||||
bool circular_setpoints = false;
|
||||
float circular_setpoint_range = 1.0f; // Circular range when circular_setpoints is true. [turn]
|
||||
uint32_t steps_per_circular_range = 1024;
|
||||
float inertia = 0.0f; // [Nm/(turn/s^2)]
|
||||
float input_filter_bandwidth = 2.0f; // [1/s]
|
||||
float homing_speed = 0.25f; // [turn/s]
|
||||
Anticogging_t anticogging;
|
||||
float gain_scheduling_width = 10.0f;
|
||||
bool enable_gain_scheduling = false;
|
||||
bool enable_vel_limit = true;
|
||||
bool enable_overspeed_error = true;
|
||||
bool enable_torque_mode_vel_limit = true; // enable velocity limit in current control mode (requires a valid velocity estimator)
|
||||
uint8_t axis_to_mirror = -1;
|
||||
float mirror_ratio = 1.0f;
|
||||
float torque_mirror_ratio = 0.0f;
|
||||
uint8_t load_encoder_axis = -1; // default depends on Axis number and is set in load_configuration(). Set to -1 to select sensorless estimator.
|
||||
float mechanical_power_bandwidth = 20.0f; // [rad/s] filter cutoff for mechanical power for spinout detction
|
||||
float electrical_power_bandwidth = 20.0f; // [rad/s] filter cutoff for electrical power for spinout detection
|
||||
float spinout_electrical_power_threshold = 10.0f; // [W] electrical power threshold for spinout detection
|
||||
float spinout_mechanical_power_threshold = -10.0f; // [W] mechanical power threshold for spinout detection
|
||||
|
||||
// custom setters
|
||||
Controller* parent;
|
||||
void set_input_filter_bandwidth(float value) { input_filter_bandwidth = value; parent->update_filter_gains(); }
|
||||
void set_steps_per_circular_range(uint32_t value) { steps_per_circular_range = value > 0 ? value : steps_per_circular_range; }
|
||||
void set_control_mode(ControlMode value) { control_mode = value; parent->control_mode_updated(); }
|
||||
};
|
||||
|
||||
|
||||
bool apply_config();
|
||||
|
||||
void reset();
|
||||
void set_error(Error error);
|
||||
|
||||
constexpr void input_pos_updated() {
|
||||
input_pos_updated_ = true;
|
||||
}
|
||||
bool control_mode_updated();
|
||||
void set_input_pos_and_steps(float pos);
|
||||
|
||||
bool select_encoder(size_t encoder_num);
|
||||
|
||||
// Trajectory-Planned control
|
||||
void move_to_pos(float goal_point);
|
||||
void move_incremental(float displacement, bool from_goal_point);
|
||||
|
||||
// TODO: make this more similar to other calibration loops
|
||||
void start_anticogging_calibration();
|
||||
float remove_anticogging_bias();
|
||||
bool anticogging_calibration(float pos_estimate, float vel_estimate);
|
||||
|
||||
float get_anticogging_value(uint32_t index) {
|
||||
return (index < 3600) ? config_.anticogging.cogging_map[index] : 0.0f;
|
||||
}
|
||||
|
||||
void update_filter_gains();
|
||||
bool update();
|
||||
|
||||
Config_t config_;
|
||||
Axis* axis_ = nullptr; // set by Axis constructor
|
||||
|
||||
Error error_ = ERROR_NONE;
|
||||
float last_error_time_ = 0.0f;
|
||||
|
||||
// Inputs
|
||||
InputPort<float> pos_estimate_linear_src_;
|
||||
InputPort<float> pos_estimate_circular_src_;
|
||||
InputPort<float> vel_estimate_src_;
|
||||
InputPort<float> pos_wrap_src_;
|
||||
|
||||
float pos_setpoint_ = 0.0f; // [turns]
|
||||
float vel_setpoint_ = 0.0f; // [turn/s]
|
||||
// float vel_setpoint = 800.0f; <sensorless example>
|
||||
float vel_integrator_torque_ = 0.0f; // [Nm]
|
||||
float torque_setpoint_ = 0.0f; // [Nm]
|
||||
|
||||
float input_pos_ = 0.0f; // [turns]
|
||||
float input_vel_ = 0.0f; // [turn/s]
|
||||
float input_torque_ = 0.0f; // [Nm]
|
||||
float input_filter_kp_ = 0.0f;
|
||||
float input_filter_ki_ = 0.0f;
|
||||
|
||||
Autotuning_t autotuning_;
|
||||
float autotuning_phase_ = 0.0f;
|
||||
|
||||
bool input_pos_updated_ = false;
|
||||
|
||||
bool trajectory_done_ = true;
|
||||
|
||||
bool anticogging_valid_ = false;
|
||||
float mechanical_power_ = 0.0f; // [W]
|
||||
float electrical_power_ = 0.0f; // [W]
|
||||
|
||||
// Outputs
|
||||
OutputPort<float> torque_output_ = 0.0f;
|
||||
|
||||
// custom setters
|
||||
void set_input_pos(float value) { set_input_pos_and_steps(value); input_pos_updated(); }
|
||||
};
|
||||
|
||||
#endif // __CONTROLLER_HPP
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef __CURRENT_LIMITER_HPP
|
||||
#define __CURRENT_LIMITER_HPP
|
||||
|
||||
class CurrentLimiter {
|
||||
public:
|
||||
virtual ~CurrentLimiter() = default;
|
||||
virtual float get_current_limit(float base_current_lim) const = 0;
|
||||
};
|
||||
|
||||
#endif // __CURRENT_LIMITER_HPP
|
||||
@@ -0,0 +1,842 @@
|
||||
|
||||
#include "odrive_main.h"
|
||||
#include <Drivers/STM32/stm32_system.h>
|
||||
#include <bitset>
|
||||
|
||||
Encoder::Encoder(TIM_HandleTypeDef* timer, Stm32Gpio index_gpio,
|
||||
Stm32Gpio hallA_gpio, Stm32Gpio hallB_gpio, Stm32Gpio hallC_gpio,
|
||||
Stm32SpiArbiter* spi_arbiter) :
|
||||
timer_(timer), index_gpio_(index_gpio),
|
||||
hallA_gpio_(hallA_gpio), hallB_gpio_(hallB_gpio), hallC_gpio_(hallC_gpio),
|
||||
spi_arbiter_(spi_arbiter)
|
||||
{
|
||||
}
|
||||
|
||||
static void enc_index_cb_wrapper(void* ctx) {
|
||||
reinterpret_cast<Encoder*>(ctx)->enc_index_cb();
|
||||
}
|
||||
|
||||
bool Encoder::apply_config(ODriveIntf::MotorIntf::MotorType motor_type) {
|
||||
config_.parent = this;
|
||||
|
||||
update_pll_gains();
|
||||
|
||||
if (config_.pre_calibrated) {
|
||||
if (config_.mode == Encoder::MODE_HALL && config_.hall_polarity_calibrated)
|
||||
is_ready_ = true;
|
||||
if (config_.mode == Encoder::MODE_SINCOS)
|
||||
is_ready_ = true;
|
||||
if (motor_type == Motor::MOTOR_TYPE_ACIM)
|
||||
is_ready_ = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Encoder::setup() {
|
||||
HAL_TIM_Encoder_Start(timer_, TIM_CHANNEL_ALL);
|
||||
set_idx_subscribe();
|
||||
|
||||
mode_ = config_.mode;
|
||||
|
||||
spi_task_.config = {
|
||||
.Mode = SPI_MODE_MASTER,
|
||||
.Direction = SPI_DIRECTION_2LINES,
|
||||
.DataSize = SPI_DATASIZE_16BIT,
|
||||
.CLKPolarity = (mode_ == MODE_SPI_ABS_AEAT || mode_ == MODE_SPI_ABS_MA732) ? SPI_POLARITY_HIGH : SPI_POLARITY_LOW,
|
||||
.CLKPhase = SPI_PHASE_2EDGE,
|
||||
.NSS = SPI_NSS_SOFT,
|
||||
.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16,
|
||||
.FirstBit = SPI_FIRSTBIT_MSB,
|
||||
.TIMode = SPI_TIMODE_DISABLE,
|
||||
.CRCCalculation = SPI_CRCCALCULATION_DISABLE,
|
||||
.CRCPolynomial = 10,
|
||||
};
|
||||
|
||||
if (mode_ == MODE_SPI_ABS_MA732) {
|
||||
abs_spi_dma_tx_[0] = 0x0000;
|
||||
}
|
||||
|
||||
if(mode_ & MODE_FLAG_ABS){
|
||||
abs_spi_cs_pin_init();
|
||||
|
||||
if (axis_->controller_.config_.anticogging.pre_calibrated) {
|
||||
axis_->controller_.anticogging_valid_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::set_error(Error error) {
|
||||
vel_estimate_valid_ = false;
|
||||
pos_estimate_valid_ = false;
|
||||
error_ |= error;
|
||||
axis_->error_ |= Axis::ERROR_ENCODER_FAILED;
|
||||
}
|
||||
|
||||
bool Encoder::do_checks(){
|
||||
return error_ == ERROR_NONE;
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Hardware Dependent
|
||||
//--------------------
|
||||
|
||||
// Triggered when an encoder passes over the "Index" pin
|
||||
// TODO: only arm index edge interrupt when we know encoder has powered up
|
||||
// (maybe by attaching the interrupt on start search, synergistic with following)
|
||||
void Encoder::enc_index_cb() {
|
||||
if (config_.use_index) {
|
||||
set_circular_count(0, false);
|
||||
if (config_.use_index_offset)
|
||||
set_linear_count((int32_t)(config_.index_offset * config_.cpr));
|
||||
if (config_.pre_calibrated) {
|
||||
is_ready_ = true;
|
||||
if(axis_->controller_.config_.anticogging.pre_calibrated){
|
||||
axis_->controller_.anticogging_valid_ = true;
|
||||
}
|
||||
} else {
|
||||
// We can't use the update_offset facility in set_circular_count because
|
||||
// we also set the linear count before there is a chance to update. Therefore:
|
||||
// Invalidate offset calibration that may have happened before idx search
|
||||
is_ready_ = false;
|
||||
}
|
||||
index_found_ = true;
|
||||
}
|
||||
|
||||
// Disable interrupt
|
||||
index_gpio_.unsubscribe();
|
||||
}
|
||||
|
||||
void Encoder::set_idx_subscribe(bool override_enable) {
|
||||
if (config_.use_index && (override_enable || !config_.find_idx_on_lockin_only)) {
|
||||
if (!index_gpio_.subscribe(true, false, enc_index_cb_wrapper, this)) {
|
||||
odrv.misconfigured_ = true;
|
||||
}
|
||||
} else if (!config_.use_index || config_.find_idx_on_lockin_only) {
|
||||
index_gpio_.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::update_pll_gains() {
|
||||
pll_kp_ = 2.0f * config_.bandwidth; // basic conversion to discrete time
|
||||
pll_ki_ = 0.25f * (pll_kp_ * pll_kp_); // Critically damped
|
||||
|
||||
// Check that we don't get problems with discrete time approximation
|
||||
if (!(current_meas_period * pll_kp_ < 1.0f)) {
|
||||
set_error(ERROR_UNSTABLE_GAIN);
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::check_pre_calibrated() {
|
||||
// TODO: restoring config from python backup is fragile here (ACIM motor type must be set first)
|
||||
if (axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_ACIM) {
|
||||
if (!is_ready_)
|
||||
config_.pre_calibrated = false;
|
||||
if (mode_ == MODE_INCREMENTAL && !index_found_)
|
||||
config_.pre_calibrated = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Function that sets the current encoder count to a desired 32-bit value.
|
||||
void Encoder::set_linear_count(int32_t count) {
|
||||
// Disable interrupts to make a critical section to avoid race condition
|
||||
uint32_t prim = cpu_enter_critical();
|
||||
|
||||
// Update states
|
||||
shadow_count_ = count;
|
||||
pos_estimate_counts_ = (float)count;
|
||||
tim_cnt_sample_ = count;
|
||||
|
||||
//Write hardware last
|
||||
timer_->Instance->CNT = count;
|
||||
|
||||
cpu_exit_critical(prim);
|
||||
}
|
||||
|
||||
// Function that sets the CPR circular tracking encoder count to a desired 32-bit value.
|
||||
// Note that this will get mod'ed down to [0, cpr)
|
||||
void Encoder::set_circular_count(int32_t count, bool update_offset) {
|
||||
// Disable interrupts to make a critical section to avoid race condition
|
||||
uint32_t prim = cpu_enter_critical();
|
||||
|
||||
if (update_offset) {
|
||||
config_.phase_offset += count - count_in_cpr_;
|
||||
config_.phase_offset = mod(config_.phase_offset, config_.cpr);
|
||||
}
|
||||
|
||||
// Update states
|
||||
count_in_cpr_ = mod(count, config_.cpr);
|
||||
pos_cpr_counts_ = (float)count_in_cpr_;
|
||||
|
||||
cpu_exit_critical(prim);
|
||||
}
|
||||
|
||||
bool Encoder::run_index_search() {
|
||||
config_.use_index = true;
|
||||
index_found_ = false;
|
||||
set_idx_subscribe();
|
||||
|
||||
bool success = axis_->run_lockin_spin(axis_->config_.calibration_lockin, false);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Encoder::run_direction_find() {
|
||||
int32_t init_enc_val = shadow_count_;
|
||||
|
||||
Axis::LockinConfig_t lockin_config = axis_->config_.calibration_lockin;
|
||||
lockin_config.finish_distance = lockin_config.vel * 3.0f; // run for 3 seconds
|
||||
lockin_config.finish_on_distance = true;
|
||||
lockin_config.finish_on_enc_idx = false;
|
||||
lockin_config.finish_on_vel = false;
|
||||
bool success = axis_->run_lockin_spin(lockin_config, false);
|
||||
|
||||
if (success) {
|
||||
// Check response and direction
|
||||
if (shadow_count_ > init_enc_val + 8) {
|
||||
// motor same dir as encoder
|
||||
config_.direction = 1;
|
||||
} else if (shadow_count_ < init_enc_val - 8) {
|
||||
// motor opposite dir as encoder
|
||||
config_.direction = -1;
|
||||
} else {
|
||||
config_.direction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool Encoder::run_hall_polarity_calibration() {
|
||||
Axis::LockinConfig_t lockin_config = axis_->config_.calibration_lockin;
|
||||
lockin_config.finish_distance = lockin_config.vel * 3.0f; // run for 3 seconds
|
||||
lockin_config.finish_on_distance = true;
|
||||
lockin_config.finish_on_enc_idx = false;
|
||||
lockin_config.finish_on_vel = false;
|
||||
|
||||
auto loop_cb = [this](bool const_vel) {
|
||||
if (const_vel)
|
||||
sample_hall_states_ = true;
|
||||
// No need to cancel early
|
||||
return true;
|
||||
};
|
||||
|
||||
config_.hall_polarity_calibrated = false;
|
||||
states_seen_count_.fill(0);
|
||||
bool success = axis_->run_lockin_spin(lockin_config, false, loop_cb);
|
||||
sample_hall_states_ = false;
|
||||
|
||||
if (success) {
|
||||
std::bitset<8> state_seen;
|
||||
std::bitset<8> state_confirmed;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (states_seen_count_[i] > 0)
|
||||
state_seen[i] = true;
|
||||
if (states_seen_count_[i] > 50)
|
||||
state_confirmed[i] = true;
|
||||
}
|
||||
if (!(state_seen == state_confirmed)) {
|
||||
set_error(ERROR_ILLEGAL_HALL_STATE);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hall effect sensors can be arranged at 60 or 120 electrical degrees.
|
||||
// Out of 8 possible states, 120 and 60 deg arrangements each miss 2 states.
|
||||
// ODrive assumes 120 deg separation - if a 60 deg setup is used, it can
|
||||
// be converted to 120 deg states by flipping the polarity of one sensor.
|
||||
uint8_t states = state_seen.to_ulong();
|
||||
uint8_t hall_polarity = 0;
|
||||
auto flip_detect = [](uint8_t states, unsigned int idx)->bool {
|
||||
return (~states & 0xFF) == (1<<(0+idx) | 1<<(7-idx));
|
||||
};
|
||||
if (flip_detect(states, 0)) {
|
||||
hall_polarity = 0b000;
|
||||
} else if (flip_detect(states, 1)) {
|
||||
hall_polarity = 0b001;
|
||||
} else if (flip_detect(states, 2)) {
|
||||
hall_polarity = 0b010;
|
||||
} else if (flip_detect(states, 3)) {
|
||||
hall_polarity = 0b100;
|
||||
} else {
|
||||
set_error(ERROR_ILLEGAL_HALL_STATE);
|
||||
return false;
|
||||
}
|
||||
config_.hall_polarity = hall_polarity;
|
||||
config_.hall_polarity_calibrated = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Encoder::run_hall_phase_calibration() {
|
||||
Axis::LockinConfig_t lockin_config = axis_->config_.calibration_lockin;
|
||||
lockin_config.finish_distance = lockin_config.vel * 30.0f; // run for 30 seconds
|
||||
lockin_config.finish_on_distance = true;
|
||||
lockin_config.finish_on_enc_idx = false;
|
||||
lockin_config.finish_on_vel = false;
|
||||
|
||||
auto loop_cb = [this](bool const_vel) {
|
||||
if (const_vel)
|
||||
sample_hall_phase_ = true;
|
||||
// No need to cancel early
|
||||
return true;
|
||||
};
|
||||
|
||||
// TODO: There is a race condition here with the execution in Encoder::update.
|
||||
// We should evaluate making thread execution synchronous with the control loops
|
||||
// at least optionally.
|
||||
// Perhaps the new loop_sync feature will give a loose timing guarantee that may be sufficient
|
||||
calibrate_hall_phase_ = true;
|
||||
config_.hall_edge_phcnt.fill(0.0f);
|
||||
hall_phase_calib_seen_count_.fill(0);
|
||||
bool success = axis_->run_lockin_spin(lockin_config, false, loop_cb);
|
||||
if (error_ & ERROR_ILLEGAL_HALL_STATE)
|
||||
success = false;
|
||||
|
||||
if (success) {
|
||||
// Check deltas to dicern rotation direction
|
||||
float delta_phase = 0.0f;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int next_i = (i == 5) ? 0 : i+1;
|
||||
delta_phase += wrap_pm_pi(config_.hall_edge_phcnt[next_i] - config_.hall_edge_phcnt[i]);
|
||||
}
|
||||
// Correct reverse rotation
|
||||
if (delta_phase < 0.0f) {
|
||||
config_.direction = -1;
|
||||
for (int i = 0; i < 6; i++)
|
||||
config_.hall_edge_phcnt[i] = wrap_pm_pi(-config_.hall_edge_phcnt[i]);
|
||||
} else {
|
||||
config_.direction = 1;
|
||||
}
|
||||
// Normalize edge timing to 1st edge in sequence, and change units to counts
|
||||
float offset = config_.hall_edge_phcnt[0];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
float& phcnt = config_.hall_edge_phcnt[i];
|
||||
phcnt = fmodf_pos((6.0f / (2.0f * M_PI)) * (phcnt - offset), 6.0f);
|
||||
}
|
||||
} else {
|
||||
config_.hall_edge_phcnt = hall_edge_defaults;
|
||||
}
|
||||
|
||||
calibrate_hall_phase_ = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
// @brief Turns the motor in one direction for a bit and then in the other
|
||||
// direction in order to find the offset between the electrical phase 0
|
||||
// and the encoder state 0.
|
||||
bool Encoder::run_offset_calibration() {
|
||||
const float start_lock_duration = 1.0f;
|
||||
|
||||
// Require index found if enabled
|
||||
if (config_.use_index && !index_found_) {
|
||||
set_error(ERROR_INDEX_NOT_FOUND_YET);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config_.mode == MODE_HALL && !config_.hall_polarity_calibrated) {
|
||||
set_error(ERROR_HALL_NOT_CALIBRATED_YET);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We use shadow_count_ to do the calibration, but the offset is used by count_in_cpr_
|
||||
// Therefore we have to sync them for calibration
|
||||
shadow_count_ = count_in_cpr_;
|
||||
|
||||
CRITICAL_SECTION() {
|
||||
// Reset state variables
|
||||
axis_->open_loop_controller_.Idq_setpoint_ = {0.0f, 0.0f};
|
||||
axis_->open_loop_controller_.Vdq_setpoint_ = {0.0f, 0.0f};
|
||||
axis_->open_loop_controller_.phase_ = 0.0f;
|
||||
axis_->open_loop_controller_.phase_vel_ = 0.0f;
|
||||
|
||||
float max_current_ramp = axis_->motor_.config_.calibration_current / start_lock_duration * 2.0f;
|
||||
axis_->open_loop_controller_.max_current_ramp_ = max_current_ramp;
|
||||
axis_->open_loop_controller_.max_voltage_ramp_ = max_current_ramp;
|
||||
axis_->open_loop_controller_.max_phase_vel_ramp_ = INFINITY;
|
||||
axis_->open_loop_controller_.target_current_ = axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL ? axis_->motor_.config_.calibration_current : 0.0f;
|
||||
axis_->open_loop_controller_.target_voltage_ = axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL ? 0.0f : axis_->motor_.config_.calibration_current;
|
||||
axis_->open_loop_controller_.target_vel_ = 0.0f;
|
||||
axis_->open_loop_controller_.total_distance_ = 0.0f;
|
||||
axis_->open_loop_controller_.phase_ = axis_->open_loop_controller_.initial_phase_ = wrap_pm_pi(0 - config_.calib_scan_distance / 2.0f);
|
||||
|
||||
axis_->motor_.current_control_.enable_current_control_src_ = (axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL);
|
||||
axis_->motor_.current_control_.Idq_setpoint_src_.connect_to(&axis_->open_loop_controller_.Idq_setpoint_);
|
||||
axis_->motor_.current_control_.Vdq_setpoint_src_.connect_to(&axis_->open_loop_controller_.Vdq_setpoint_);
|
||||
|
||||
axis_->motor_.current_control_.phase_src_.connect_to(&axis_->open_loop_controller_.phase_);
|
||||
axis_->acim_estimator_.rotor_phase_src_.connect_to(&axis_->open_loop_controller_.phase_);
|
||||
|
||||
axis_->motor_.phase_vel_src_.connect_to(&axis_->open_loop_controller_.phase_vel_);
|
||||
axis_->motor_.current_control_.phase_vel_src_.connect_to(&axis_->open_loop_controller_.phase_vel_);
|
||||
axis_->acim_estimator_.rotor_phase_vel_src_.connect_to(&axis_->open_loop_controller_.phase_vel_);
|
||||
}
|
||||
axis_->wait_for_control_iteration();
|
||||
|
||||
axis_->motor_.arm(&axis_->motor_.current_control_);
|
||||
|
||||
// go to start position of forward scan for start_lock_duration to get ready to scan
|
||||
for (size_t i = 0; i < (size_t)(start_lock_duration * 1000.0f); ++i) {
|
||||
if (!axis_->motor_.is_armed_) {
|
||||
return false; // TODO: return "disarmed" error code
|
||||
}
|
||||
if (axis_->requested_state_ != Axis::AXIS_STATE_UNDEFINED) {
|
||||
axis_->motor_.disarm();
|
||||
return false; // TODO: return "aborted" error code
|
||||
}
|
||||
osDelay(1);
|
||||
}
|
||||
|
||||
|
||||
int32_t init_enc_val = shadow_count_;
|
||||
uint32_t num_steps = 0;
|
||||
int64_t encvaluesum = 0;
|
||||
|
||||
CRITICAL_SECTION() {
|
||||
axis_->open_loop_controller_.target_vel_ = config_.calib_scan_omega;
|
||||
axis_->open_loop_controller_.total_distance_ = 0.0f;
|
||||
}
|
||||
|
||||
// scan forward
|
||||
while ((axis_->requested_state_ == Axis::AXIS_STATE_UNDEFINED) && axis_->motor_.is_armed_) {
|
||||
bool reached_target_dist = axis_->open_loop_controller_.total_distance_.any().value_or(-INFINITY) >= config_.calib_scan_distance;
|
||||
if (reached_target_dist) {
|
||||
break;
|
||||
}
|
||||
encvaluesum += shadow_count_;
|
||||
num_steps++;
|
||||
osDelay(1);
|
||||
}
|
||||
|
||||
// Check response and direction
|
||||
if (shadow_count_ > init_enc_val + 8) {
|
||||
// motor same dir as encoder
|
||||
config_.direction = 1;
|
||||
} else if (shadow_count_ < init_enc_val - 8) {
|
||||
// motor opposite dir as encoder
|
||||
config_.direction = -1;
|
||||
} else {
|
||||
// Encoder response error
|
||||
set_error(ERROR_NO_RESPONSE);
|
||||
axis_->motor_.disarm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check CPR
|
||||
float elec_rad_per_enc = axis_->motor_.config_.pole_pairs * 2 * M_PI * (1.0f / (float)(config_.cpr));
|
||||
float expected_encoder_delta = config_.calib_scan_distance / elec_rad_per_enc;
|
||||
calib_scan_response_ = std::abs(shadow_count_ - init_enc_val);
|
||||
if (std::abs(calib_scan_response_ - expected_encoder_delta) / expected_encoder_delta > config_.calib_range) {
|
||||
set_error(ERROR_CPR_POLEPAIRS_MISMATCH);
|
||||
axis_->motor_.disarm();
|
||||
return false;
|
||||
}
|
||||
|
||||
CRITICAL_SECTION() {
|
||||
axis_->open_loop_controller_.target_vel_ = -config_.calib_scan_omega;
|
||||
}
|
||||
|
||||
// scan backwards
|
||||
while ((axis_->requested_state_ == Axis::AXIS_STATE_UNDEFINED) && axis_->motor_.is_armed_) {
|
||||
bool reached_target_dist = axis_->open_loop_controller_.total_distance_.any().value_or(INFINITY) <= 0.0f;
|
||||
if (reached_target_dist) {
|
||||
break;
|
||||
}
|
||||
encvaluesum += shadow_count_;
|
||||
num_steps++;
|
||||
osDelay(1);
|
||||
}
|
||||
|
||||
// Motor disarmed because of an error
|
||||
if (!axis_->motor_.is_armed_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
axis_->motor_.disarm();
|
||||
|
||||
config_.phase_offset = encvaluesum / num_steps;
|
||||
int32_t residual = encvaluesum - ((int64_t)config_.phase_offset * (int64_t)num_steps);
|
||||
config_.phase_offset_float = (float)residual / (float)num_steps + 0.5f; // add 0.5 to center-align state to phase
|
||||
|
||||
is_ready_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool decode_hall(uint8_t hall_state, int32_t* hall_cnt) {
|
||||
switch (hall_state) {
|
||||
case 0b001: *hall_cnt = 0; return true;
|
||||
case 0b011: *hall_cnt = 1; return true;
|
||||
case 0b010: *hall_cnt = 2; return true;
|
||||
case 0b110: *hall_cnt = 3; return true;
|
||||
case 0b100: *hall_cnt = 4; return true;
|
||||
case 0b101: *hall_cnt = 5; return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::sample_now() {
|
||||
switch (mode_) {
|
||||
case MODE_INCREMENTAL: {
|
||||
tim_cnt_sample_ = (int16_t)timer_->Instance->CNT;
|
||||
} break;
|
||||
|
||||
case MODE_HALL: {
|
||||
// do nothing: samples already captured in general GPIO capture
|
||||
} break;
|
||||
|
||||
case MODE_SINCOS: {
|
||||
sincos_sample_s_ = get_adc_relative_voltage(get_gpio(config_.sincos_gpio_pin_sin)) - 0.5f;
|
||||
sincos_sample_c_ = get_adc_relative_voltage(get_gpio(config_.sincos_gpio_pin_cos)) - 0.5f;
|
||||
} break;
|
||||
|
||||
case MODE_SPI_ABS_AMS:
|
||||
case MODE_SPI_ABS_CUI:
|
||||
case MODE_SPI_ABS_AEAT:
|
||||
case MODE_SPI_ABS_RLS:
|
||||
case MODE_SPI_ABS_MA732:
|
||||
{
|
||||
abs_spi_start_transaction();
|
||||
// Do nothing
|
||||
} break;
|
||||
|
||||
default: {
|
||||
set_error(ERROR_UNSUPPORTED_ENCODER_MODE);
|
||||
} break;
|
||||
}
|
||||
|
||||
// Sample all GPIO digital input data registers, used for HALL sensors for example.
|
||||
for (size_t i = 0; i < sizeof(ports_to_sample) / sizeof(ports_to_sample[0]); ++i) {
|
||||
port_samples_[i] = ports_to_sample[i]->IDR;
|
||||
}
|
||||
}
|
||||
|
||||
bool Encoder::read_sampled_gpio(Stm32Gpio gpio) {
|
||||
for (size_t i = 0; i < sizeof(ports_to_sample) / sizeof(ports_to_sample[0]); ++i) {
|
||||
if (ports_to_sample[i] == gpio.port_) {
|
||||
return port_samples_[i] & gpio.pin_mask_;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Encoder::decode_hall_samples() {
|
||||
hall_state_ = (read_sampled_gpio(hallA_gpio_) ? 1 : 0)
|
||||
| (read_sampled_gpio(hallB_gpio_) ? 2 : 0)
|
||||
| (read_sampled_gpio(hallC_gpio_) ? 4 : 0);
|
||||
}
|
||||
|
||||
bool Encoder::abs_spi_start_transaction() {
|
||||
if (mode_ & MODE_FLAG_ABS){
|
||||
if (Stm32SpiArbiter::acquire_task(&spi_task_)) {
|
||||
spi_task_.ncs_gpio = abs_spi_cs_gpio_;
|
||||
spi_task_.tx_buf = (uint8_t*)abs_spi_dma_tx_;
|
||||
spi_task_.rx_buf = (uint8_t*)abs_spi_dma_rx_;
|
||||
spi_task_.length = 1;
|
||||
spi_task_.on_complete = [](void* ctx, bool success) { ((Encoder*)ctx)->abs_spi_cb(success); };
|
||||
spi_task_.on_complete_ctx = this;
|
||||
spi_task_.next = nullptr;
|
||||
|
||||
spi_arbiter_->transfer_async(&spi_task_);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ams_parity(uint16_t v) {
|
||||
v ^= v >> 8;
|
||||
v ^= v >> 4;
|
||||
v ^= v >> 2;
|
||||
v ^= v >> 1;
|
||||
return v & 1;
|
||||
}
|
||||
|
||||
uint8_t cui_parity(uint16_t v) {
|
||||
v ^= v >> 8;
|
||||
v ^= v >> 4;
|
||||
v ^= v >> 2;
|
||||
return ~v & 3;
|
||||
}
|
||||
|
||||
void Encoder::abs_spi_cb(bool success) {
|
||||
uint16_t pos;
|
||||
|
||||
if (!success) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (mode_) {
|
||||
case MODE_SPI_ABS_AMS: {
|
||||
uint16_t rawVal = abs_spi_dma_rx_[0];
|
||||
// check if parity is correct (even) and error flag clear
|
||||
if (ams_parity(rawVal) || ((rawVal >> 14) & 1)) {
|
||||
goto done;
|
||||
}
|
||||
pos = rawVal & 0x3fff;
|
||||
} break;
|
||||
|
||||
case MODE_SPI_ABS_CUI: {
|
||||
uint16_t rawVal = abs_spi_dma_rx_[0];
|
||||
// check if parity is correct
|
||||
if (cui_parity(rawVal)) {
|
||||
goto done;
|
||||
}
|
||||
pos = rawVal & 0x3fff;
|
||||
} break;
|
||||
|
||||
case MODE_SPI_ABS_RLS: {
|
||||
uint16_t rawVal = abs_spi_dma_rx_[0];
|
||||
pos = (rawVal >> 2) & 0x3fff;
|
||||
} break;
|
||||
|
||||
case MODE_SPI_ABS_MA732: {
|
||||
uint16_t rawVal = abs_spi_dma_rx_[0];
|
||||
pos = (rawVal >> 2) & 0x3fff;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
set_error(ERROR_UNSUPPORTED_ENCODER_MODE);
|
||||
goto done;
|
||||
} break;
|
||||
}
|
||||
|
||||
pos_abs_ = pos;
|
||||
abs_spi_pos_updated_ = true;
|
||||
if (config_.pre_calibrated) {
|
||||
is_ready_ = true;
|
||||
}
|
||||
|
||||
done:
|
||||
Stm32SpiArbiter::release_task(&spi_task_);
|
||||
}
|
||||
|
||||
void Encoder::abs_spi_cs_pin_init(){
|
||||
// Decode and init cs pin
|
||||
#if HW_VERSION_MAJOR == 4
|
||||
if (mode_ == MODE_SPI_ABS_MA732)
|
||||
abs_spi_cs_gpio_ = {GPIOA, GPIO_PIN_15};
|
||||
else
|
||||
#else
|
||||
abs_spi_cs_gpio_ = get_gpio(config_.abs_spi_cs_gpio_pin);
|
||||
#endif
|
||||
abs_spi_cs_gpio_.config(GPIO_MODE_OUTPUT_PP, GPIO_PULLUP);
|
||||
|
||||
// Write pin high
|
||||
abs_spi_cs_gpio_.write(true);
|
||||
}
|
||||
|
||||
// Note that this may return counts +1 or -1 without any wrapping
|
||||
int32_t Encoder::hall_model(float internal_pos) {
|
||||
int32_t base_cnt = (int32_t)std::floor(internal_pos);
|
||||
|
||||
float pos_in_range = fmodf_pos(internal_pos, 6.0f);
|
||||
int pos_idx = (int)pos_in_range;
|
||||
if (pos_idx == 6) pos_idx = 5; // in case of rounding error
|
||||
int next_i = (pos_idx == 5) ? 0 : pos_idx+1;
|
||||
|
||||
float below_edge = config_.hall_edge_phcnt[pos_idx];
|
||||
float above_edge = config_.hall_edge_phcnt[next_i];
|
||||
|
||||
// if we are blow the "below" edge, we are the count under
|
||||
if (wrap_pm(pos_in_range - below_edge, 6.0f) < 0.0f)
|
||||
return base_cnt - 1;
|
||||
// if we are above the "above" edge, we are the count over
|
||||
else if (wrap_pm(pos_in_range - above_edge, 6.0f) > 0.0f)
|
||||
return base_cnt + 1;
|
||||
// otherwise we are in the nominal count (or completely lost)
|
||||
return base_cnt;
|
||||
}
|
||||
|
||||
bool Encoder::update() {
|
||||
// update internal encoder state.
|
||||
int32_t delta_enc = 0;
|
||||
int32_t pos_abs_latched = pos_abs_; //LATCH
|
||||
|
||||
switch (mode_) {
|
||||
case MODE_INCREMENTAL: {
|
||||
//TODO: use count_in_cpr_ instead as shadow_count_ can overflow
|
||||
//or use 64 bit
|
||||
int16_t delta_enc_16 = (int16_t)tim_cnt_sample_ - (int16_t)shadow_count_;
|
||||
delta_enc = (int32_t)delta_enc_16; //sign extend
|
||||
} break;
|
||||
|
||||
case MODE_HALL: {
|
||||
decode_hall_samples();
|
||||
if (sample_hall_states_) {
|
||||
states_seen_count_[hall_state_]++;
|
||||
}
|
||||
if (config_.hall_polarity_calibrated) {
|
||||
int32_t hall_cnt;
|
||||
if (decode_hall((hall_state_ ^ config_.hall_polarity), &hall_cnt)) {
|
||||
if (calibrate_hall_phase_) {
|
||||
if (sample_hall_phase_ && last_hall_cnt_.has_value()) {
|
||||
int mod_hall_cnt = mod(hall_cnt - last_hall_cnt_.value(), 6);
|
||||
size_t edge_idx;
|
||||
if (mod_hall_cnt == 0) { goto skip; } // no count - do nothing
|
||||
else if (mod_hall_cnt == 1) { // counted up
|
||||
edge_idx = hall_cnt;
|
||||
} else if (mod_hall_cnt == 5) { // counted down
|
||||
edge_idx = last_hall_cnt_.value();
|
||||
} else {
|
||||
set_error(ERROR_ILLEGAL_HALL_STATE);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto maybe_phase = axis_->open_loop_controller_.phase_.any();
|
||||
if (maybe_phase) {
|
||||
float phase = maybe_phase.value();
|
||||
// Early increment to get the right divisor in recursive average
|
||||
hall_phase_calib_seen_count_[edge_idx]++;
|
||||
float& edge_phase = config_.hall_edge_phcnt[edge_idx];
|
||||
if (hall_phase_calib_seen_count_[edge_idx] == 1)
|
||||
edge_phase = phase;
|
||||
else {
|
||||
// circularly wrapped recursive average
|
||||
edge_phase += (phase - edge_phase) / hall_phase_calib_seen_count_[edge_idx];
|
||||
edge_phase = wrap_pm_pi(edge_phase);
|
||||
}
|
||||
}
|
||||
}
|
||||
skip:
|
||||
last_hall_cnt_ = hall_cnt;
|
||||
|
||||
return true; // Skip all velocity and phase estimation
|
||||
}
|
||||
|
||||
delta_enc = hall_cnt - count_in_cpr_;
|
||||
delta_enc = mod(delta_enc, 6);
|
||||
if (delta_enc > 3)
|
||||
delta_enc -= 6;
|
||||
} else {
|
||||
if (!config_.ignore_illegal_hall_state) {
|
||||
set_error(ERROR_ILLEGAL_HALL_STATE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case MODE_SINCOS: {
|
||||
float phase = fast_atan2(sincos_sample_s_, sincos_sample_c_);
|
||||
int fake_count = (int)(1000.0f * phase);
|
||||
//CPR = 6283 = 2pi * 1k
|
||||
|
||||
delta_enc = fake_count - count_in_cpr_;
|
||||
delta_enc = mod(delta_enc, 6283);
|
||||
if (delta_enc > 6283/2)
|
||||
delta_enc -= 6283;
|
||||
} break;
|
||||
|
||||
case MODE_SPI_ABS_RLS:
|
||||
case MODE_SPI_ABS_AMS:
|
||||
case MODE_SPI_ABS_CUI:
|
||||
case MODE_SPI_ABS_AEAT:
|
||||
case MODE_SPI_ABS_MA732: {
|
||||
if (abs_spi_pos_updated_ == false) {
|
||||
// Low pass filter the error
|
||||
spi_error_rate_ += current_meas_period * (1.0f - spi_error_rate_);
|
||||
if (spi_error_rate_ > 0.05f) {
|
||||
set_error(ERROR_ABS_SPI_COM_FAIL);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Low pass filter the error
|
||||
spi_error_rate_ += current_meas_period * (0.0f - spi_error_rate_);
|
||||
}
|
||||
|
||||
abs_spi_pos_updated_ = false;
|
||||
delta_enc = pos_abs_latched - count_in_cpr_; //LATCH
|
||||
delta_enc = mod(delta_enc, config_.cpr);
|
||||
if (delta_enc > config_.cpr/2) {
|
||||
delta_enc -= config_.cpr;
|
||||
}
|
||||
|
||||
}break;
|
||||
default: {
|
||||
set_error(ERROR_UNSUPPORTED_ENCODER_MODE);
|
||||
return false;
|
||||
} break;
|
||||
}
|
||||
|
||||
shadow_count_ += delta_enc;
|
||||
count_in_cpr_ += delta_enc;
|
||||
count_in_cpr_ = mod(count_in_cpr_, config_.cpr);
|
||||
|
||||
if(mode_ & MODE_FLAG_ABS)
|
||||
count_in_cpr_ = pos_abs_latched;
|
||||
|
||||
// Memory for pos_circular
|
||||
float pos_cpr_counts_last = pos_cpr_counts_;
|
||||
|
||||
//// run pll (for now pll is in units of encoder counts)
|
||||
// Predict current pos
|
||||
pos_estimate_counts_ += current_meas_period * vel_estimate_counts_;
|
||||
pos_cpr_counts_ += current_meas_period * vel_estimate_counts_;
|
||||
// Encoder model
|
||||
auto encoder_model = [this](float internal_pos)->int32_t {
|
||||
if (config_.mode == MODE_HALL)
|
||||
return hall_model(internal_pos);
|
||||
else
|
||||
return (int32_t)std::floor(internal_pos);
|
||||
};
|
||||
// discrete phase detector
|
||||
float delta_pos_counts = (float)(shadow_count_ - encoder_model(pos_estimate_counts_));
|
||||
float delta_pos_cpr_counts = (float)(count_in_cpr_ - encoder_model(pos_cpr_counts_));
|
||||
delta_pos_cpr_counts = wrap_pm(delta_pos_cpr_counts, (float)(config_.cpr));
|
||||
delta_pos_cpr_counts_ += 0.1f * (delta_pos_cpr_counts - delta_pos_cpr_counts_); // for debug
|
||||
// pll feedback
|
||||
pos_estimate_counts_ += current_meas_period * pll_kp_ * delta_pos_counts;
|
||||
pos_cpr_counts_ += current_meas_period * pll_kp_ * delta_pos_cpr_counts;
|
||||
pos_cpr_counts_ = fmodf_pos(pos_cpr_counts_, (float)(config_.cpr));
|
||||
vel_estimate_counts_ += current_meas_period * pll_ki_ * delta_pos_cpr_counts;
|
||||
bool snap_to_zero_vel = false;
|
||||
if (std::abs(vel_estimate_counts_) < 0.5f * current_meas_period * pll_ki_) {
|
||||
vel_estimate_counts_ = 0.0f; //align delta-sigma on zero to prevent jitter
|
||||
snap_to_zero_vel = true;
|
||||
}
|
||||
|
||||
// Outputs from Encoder for Controller
|
||||
pos_estimate_ = pos_estimate_counts_ / (float)config_.cpr;
|
||||
vel_estimate_ = vel_estimate_counts_ / (float)config_.cpr;
|
||||
|
||||
// TODO: we should strictly require that this value is from the previous iteration
|
||||
// to avoid spinout scenarios. However that requires a proper way to reset
|
||||
// the encoder from error states.
|
||||
float pos_circular = pos_circular_.any().value_or(0.0f);
|
||||
pos_circular += wrap_pm((pos_cpr_counts_ - pos_cpr_counts_last) / (float)config_.cpr, 1.0f);
|
||||
pos_circular = fmodf_pos(pos_circular, axis_->controller_.config_.circular_setpoint_range);
|
||||
pos_circular_ = pos_circular;
|
||||
|
||||
//// run encoder count interpolation
|
||||
int32_t corrected_enc = count_in_cpr_ - config_.phase_offset;
|
||||
// if we are stopped, make sure we don't randomly drift
|
||||
if (snap_to_zero_vel || !config_.enable_phase_interpolation) {
|
||||
interpolation_ = 0.5f;
|
||||
// reset interpolation if encoder edge comes
|
||||
// TODO: This isn't correct. At high velocities the first phase in this count may very well not be at the edge.
|
||||
} else if (delta_enc > 0) {
|
||||
interpolation_ = 0.0f;
|
||||
} else if (delta_enc < 0) {
|
||||
interpolation_ = 1.0f;
|
||||
} else {
|
||||
// Interpolate (predict) between encoder counts using vel_estimate,
|
||||
interpolation_ += current_meas_period * vel_estimate_counts_;
|
||||
// don't allow interpolation indicated position outside of [enc, enc+1)
|
||||
if (interpolation_ > 1.0f) interpolation_ = 1.0f;
|
||||
if (interpolation_ < 0.0f) interpolation_ = 0.0f;
|
||||
}
|
||||
float interpolated_enc = corrected_enc + interpolation_;
|
||||
|
||||
//// compute electrical phase
|
||||
//TODO avoid recomputing elec_rad_per_enc every time
|
||||
float elec_rad_per_enc = axis_->motor_.config_.pole_pairs * 2 * M_PI * (1.0f / (float)(config_.cpr));
|
||||
float ph = elec_rad_per_enc * (interpolated_enc - config_.phase_offset_float);
|
||||
|
||||
if (is_ready_) {
|
||||
phase_ = wrap_pm_pi(ph) * config_.direction;
|
||||
phase_vel_ = (2*M_PI) * *vel_estimate_.present() * axis_->motor_.config_.pole_pairs * config_.direction;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user