Compare commits
230 commits
jenkins-fu
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7593b15dbd | ||
|
|
912c0fd20a | ||
|
|
6259086c96 | ||
|
|
2b7ba8d7ab | ||
|
|
5da69aa411 | ||
|
|
8bfbd716da | ||
|
|
dda161cb1f | ||
|
|
74c3b730fa | ||
|
|
8dbb3475da | ||
|
|
d6548b1f46 | ||
|
|
95a30a9840 | ||
|
|
57fc841ddb | ||
|
|
be669ce370 | ||
|
|
1dfa0742d6 | ||
|
|
eb8bc546a8 | ||
|
|
3e274a881d | ||
|
|
73562ded31 | ||
|
|
aa76109b6a | ||
|
|
d6913807a6 | ||
|
|
3afd5d2acd | ||
|
|
092d034d80 | ||
|
|
42b7f7703d | ||
|
|
bb1f835403 | ||
|
|
9153f3d55e | ||
|
|
bd2440277d | ||
|
|
404429de2a | ||
|
|
fd470d078d | ||
|
|
977a9d24a6 | ||
|
|
0585339269 | ||
|
|
d534e1d019 | ||
|
|
e3ffbf68f0 | ||
|
|
b533e1c5dc | ||
|
|
9c0a211f13 | ||
|
|
a7925bd74e | ||
|
|
9d6e43a1cb | ||
|
|
c77c962b71 | ||
|
|
a716b642ec | ||
|
|
ff052af352 | ||
|
|
7a0e31f4aa | ||
|
|
595ea6c072 | ||
|
|
6761b6a429 | ||
|
|
c2db36265c | ||
|
|
e32695e24f | ||
|
|
5d9b6bf411 | ||
|
|
4f9f6a4c74 | ||
|
|
b86b139305 | ||
|
|
eb2e6a1c05 | ||
|
|
74d0437e6b | ||
|
|
cc69102202 | ||
|
|
7cce66a7fa | ||
|
|
62229fdf73 | ||
|
|
c2262ccda1 | ||
|
|
621fc1dc3a | ||
|
|
6c01a078d5 | ||
|
|
62cdff3448 | ||
|
|
835e7b618a | ||
|
|
9423133c4b | ||
|
|
4c69adb9da | ||
|
|
50ce90908f | ||
|
|
49bce311e2 | ||
|
|
06453e2924 | ||
|
|
dc255468b1 | ||
|
|
76dd5916a7 | ||
|
|
2d1f53d730 | ||
|
|
8ddf7f7649 | ||
|
|
c77e7e7358 | ||
|
|
478a520d65 | ||
|
|
016910567b | ||
|
|
a1cdbaddbf | ||
|
|
098b9dd9f2 | ||
|
|
d00dae3835 | ||
|
|
b460014811 | ||
|
|
fe060fd04b | ||
|
|
db44436fda | ||
|
|
6ff7f8ed63 | ||
|
|
e9b2ff852c | ||
|
|
23104c7bd9 | ||
|
|
01ffff68ee | ||
|
|
9c81954b1b | ||
|
|
3bbd0702b1 | ||
|
|
475db9c53a | ||
|
|
181946c78a | ||
|
|
8bdefc2d89 | ||
|
|
8569c1dfd2 | ||
|
|
d0f61abcd7 | ||
|
|
90ab84ba28 | ||
|
|
9688caaf1c | ||
|
|
f73c2b8e6a | ||
|
|
ec1ff486b4 | ||
|
|
f970722195 | ||
|
|
a20da328ba | ||
|
|
83fd6a00a8 | ||
|
|
5b4392f609 | ||
|
|
58334a565b | ||
|
|
e8cfb86e10 | ||
|
|
a426b7518d | ||
|
|
47f91d29cf | ||
|
|
b97d1978b0 | ||
|
|
9a3abb6413 | ||
|
|
c8a0b02d85 | ||
|
|
3efc8bdbb6 | ||
|
|
76252016b6 | ||
|
|
01a3b34542 | ||
|
|
5d7b6c33cf | ||
|
|
f655bec11f | ||
|
|
ac93a68a02 | ||
|
|
e5c8dc2350 | ||
|
|
4f44917f68 | ||
|
|
858ffd268a | ||
|
|
1af5055720 | ||
|
|
f1ece3769c | ||
|
|
a23503812f | ||
|
|
03119000a4 | ||
|
|
5afdd6dfef | ||
|
|
90625818ad | ||
|
|
9584416b49 | ||
|
|
3517d0adfc | ||
|
|
ebe5a5acdf | ||
|
|
cebf0c7ce1 | ||
|
|
0fb7b1c8c0 | ||
|
|
40a8dc53dc | ||
|
|
d222e0188e | ||
|
|
ba5fe7f7da | ||
|
|
7efffeac52 | ||
|
|
fd0c7cc5f1 | ||
|
|
3e1542261a | ||
|
|
db376ad194 | ||
|
|
eaa858bf5d | ||
|
|
679179eb63 | ||
|
|
10ab440b2f | ||
|
|
60f7ccf4eb | ||
|
|
adf83cbac2 | ||
|
|
f1c28bce5c | ||
|
|
49e7b18a18 | ||
|
|
5672be9d00 | ||
|
|
e2741090ad | ||
|
|
634bd605b9 | ||
|
|
799af35b5f | ||
|
|
92476260ed | ||
|
|
b8cd1d51a7 | ||
|
|
902ae831bf | ||
|
|
230bfbc36f | ||
|
|
4bd414194a | ||
|
|
f2962ce9b1 | ||
|
|
91439ec79e | ||
|
|
f7a3d43407 | ||
|
|
7a6b099624 | ||
|
|
439f6fd355 | ||
|
|
d4b2091b12 | ||
|
|
9b5f342be0 | ||
|
|
421af49744 | ||
|
|
6387a0b100 | ||
|
|
3faa91ef85 | ||
|
|
85dfacf6ef | ||
|
|
938c020f3b | ||
|
|
6c4023e179 | ||
|
|
54dfdd9174 | ||
|
|
ed1a4d0e9e | ||
|
|
9285573f0b | ||
|
|
233951c9c9 | ||
|
|
275b75fc85 | ||
|
|
3aaa7185bd | ||
|
|
cdc17d5e67 | ||
|
|
cfd729597c | ||
|
|
c913e81ed6 | ||
|
|
8d4570d2cb | ||
|
|
d0ac3183f5 | ||
|
|
6176dbcdd5 | ||
|
|
5120383da3 | ||
|
|
afb8474668 | ||
|
|
a36f5ca08a | ||
|
|
da017d7c77 | ||
|
|
533c3f15c2 | ||
|
|
94d1517153 | ||
|
|
1b37541237 | ||
|
|
43454dd512 | ||
|
|
57285507d1 | ||
|
|
59e8670c51 | ||
|
|
62e381ef90 | ||
|
|
1e69ee09b7 | ||
|
|
3d616df762 | ||
|
|
5a82627a2b | ||
|
|
4366b49206 | ||
|
|
207ed04f6b | ||
|
|
d032dedf9f | ||
|
|
e84e867a6c | ||
|
|
14d196d3dd | ||
|
|
4063cddd7b | ||
|
|
1b06ccf0f7 | ||
|
|
911483b79c | ||
|
|
b76c8759bd | ||
|
|
5af101e45c | ||
|
|
59c61c9ace | ||
|
|
53f316291b | ||
|
|
0205dd441d | ||
|
|
3e256d1415 | ||
|
|
3f51f407fa | ||
|
|
caa47500c5 | ||
|
|
c386327696 | ||
|
|
a3e620ee25 | ||
|
|
693b7e79f7 | ||
|
|
0cf5cc2298 | ||
|
|
bca9b185a0 | ||
|
|
c4bc078364 | ||
|
|
5aff56dec9 | ||
|
|
8018feb1d0 | ||
|
|
96172175a3 | ||
|
|
159050ba8f | ||
|
|
d49b5b1f13 | ||
|
|
b11f6b2f7e | ||
|
|
a06232270e | ||
|
|
98bdd30197 | ||
|
|
1e9991e42c | ||
|
|
d1b37390e2 | ||
|
|
1c29079faf | ||
|
|
8e9b06ba1b | ||
|
|
6fccdb5f1d | ||
|
|
e9986d4601 | ||
|
|
5f8601b8c8 | ||
|
|
020e57b2f5 | ||
|
|
dc8b0c84b1 | ||
|
|
73987e607f | ||
|
|
37ad28a03a | ||
|
|
627c43b279 | ||
|
|
b2669ef2fd | ||
|
|
68f9ee8b79 | ||
|
|
e5f79913eb | ||
|
|
f2a221d0b8 | ||
|
|
3f1549c51c | ||
|
|
e9b69b144c |
172
.github/workflows/build.yml
vendored
|
|
@ -17,70 +17,127 @@ jobs:
|
|||
host:
|
||||
strategy:
|
||||
matrix:
|
||||
sys:
|
||||
- {os: 'macos', shell: 'bash'}
|
||||
- {os: 'ubuntu', shell: 'bash'}
|
||||
- {os: 'windows', shell: 'pwsh'}
|
||||
- {os: 'windows', shell: 'msys2'}
|
||||
cmake: ['3.10.0', '3.16.0', '3.21.0', '4.0.0', 'latest']
|
||||
os: ['macos', 'ubuntu', 'windows']
|
||||
cmake: ['3.10.0', '3.21.7', '4.2.6', 'latest']
|
||||
compiler: ['gcc', 'msvc']
|
||||
exclude:
|
||||
# GitHub runners use Visual Studio 2022. Support added in CMake 3.21.
|
||||
- sys: {os: 'windows', shell: 'pwsh'}
|
||||
# MSVC only runs on Windows.
|
||||
- os: 'macos'
|
||||
compiler: 'msvc'
|
||||
- os: 'ubuntu'
|
||||
compiler: 'msvc'
|
||||
# We can't use the oldest CMake versions on Windows.
|
||||
- os: 'windows'
|
||||
cmake: '3.10.0'
|
||||
- sys: {os: 'windows', shell: 'pwsh'}
|
||||
cmake: '3.16.0'
|
||||
# MSYS2 always supplies the latest cmake.
|
||||
- sys: {os: 'windows', shell: 'msys2'}
|
||||
cmake: '3.10.0'
|
||||
- sys: {os: 'windows', shell: 'msys2'}
|
||||
cmake: '3.16.0'
|
||||
- sys: {os: 'windows', shell: 'msys2'}
|
||||
cmake: '3.21.0'
|
||||
- sys: {os: 'windows', shell: 'msys2'}
|
||||
cmake: '4.0.0'
|
||||
# The in-between CMake versions aren't so intersting with GCC.
|
||||
- compiler: 'gcc'
|
||||
cmake: '3.21.7'
|
||||
- compiler: 'gcc'
|
||||
cmake: '4.2.6'
|
||||
include:
|
||||
- sys: {os: 'windows', shell: 'pwsh'}
|
||||
# Shell selection
|
||||
- os: 'macos'
|
||||
shell: 'bash'
|
||||
- os: 'ubuntu'
|
||||
shell: 'bash'
|
||||
- os: 'windows'
|
||||
compiler: 'msvc'
|
||||
shell: 'pwsh'
|
||||
- os: 'windows'
|
||||
compiler: 'gcc'
|
||||
shell: 'msys2'
|
||||
# MSVC version selection
|
||||
- cmake: '3.21.7'
|
||||
msvc: '17.14'
|
||||
- cmake: '4.2.6'
|
||||
msvc: 'latest'
|
||||
- cmake: 'latest'
|
||||
msvc: 'latest'
|
||||
# CMake generator selection
|
||||
- os: 'macos'
|
||||
generator: 'Unix Makefiles'
|
||||
- os: 'ubuntu'
|
||||
generator: 'Unix Makefiles'
|
||||
- compiler: 'msvc'
|
||||
cmake: '3.21.7'
|
||||
generator: 'Visual Studio 17 2022'
|
||||
- compiler: 'msvc'
|
||||
cmake: '4.2.6'
|
||||
generator: 'Visual Studio 18 2026'
|
||||
- compiler: 'msvc'
|
||||
cmake: 'latest'
|
||||
generator: 'Visual Studio 18 2026'
|
||||
- os: 'windows'
|
||||
compiler: 'gcc'
|
||||
generator: 'MSYS Makefiles'
|
||||
# Additional CMake arguments
|
||||
- os: 'windows'
|
||||
compiler: 'msvc'
|
||||
cmake_args: >-
|
||||
-DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe
|
||||
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||
--install-prefix=$env:GITHUB_WORKSPACE/install
|
||||
- sys: {os: 'windows', shell: 'msys2'}
|
||||
- os: 'windows'
|
||||
compiler: 'gcc'
|
||||
cmake_args: >-
|
||||
--install-prefix=/usr/local
|
||||
# CMake 3.10 uses --build with --target install
|
||||
- cmake: '3.10.0'
|
||||
install_cmd: --build
|
||||
install_args: --target install
|
||||
# Later versions just use --install
|
||||
- cmake: '3.21.7'
|
||||
install_cmd: --install
|
||||
- cmake: '4.2.6'
|
||||
install_cmd: --install
|
||||
- cmake: 'latest'
|
||||
install_cmd: --install
|
||||
# We need sudo on MacOS and Ubuntu only
|
||||
- os: macos
|
||||
sudo: sudo
|
||||
- os: ubuntu
|
||||
sudo: sudo
|
||||
|
||||
|
||||
# Don't cancel all builds when one fails
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.sys.os }}-latest
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: '${{ matrix.sys.shell }} {0}'
|
||||
shell: '${{ matrix.shell }} {0}'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmake-version: ${{ matrix.cmake }}
|
||||
if: matrix.sys.shell != 'msys2'
|
||||
cmakeVersion: ${{ matrix.cmake }}
|
||||
if: matrix.shell != 'msys2'
|
||||
|
||||
- name: Install MSVC (Windows)
|
||||
uses: k3DW/setup-msvc@v1
|
||||
with:
|
||||
vs-version: ${{ matrix.msvc }}
|
||||
if: matrix.compiler == 'msvc' && matrix.msvc != 'latest'
|
||||
|
||||
- name: Install dependencies (macOS)
|
||||
run: brew install fftw
|
||||
if: matrix.sys.os == 'macos'
|
||||
if: matrix.os == 'macos'
|
||||
|
||||
- name: Install dependencies (Ubuntu)
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libfftw3-dev libusb-1.0-0-dev
|
||||
if: matrix.sys.os == 'ubuntu'
|
||||
if: matrix.os == 'ubuntu'
|
||||
|
||||
- name: Install dependencies (Windows)
|
||||
run: vcpkg install --triplet=x64-windows libusb fftw3 pthreads pkgconf
|
||||
if: matrix.sys.os == 'windows' && matrix.sys.shell != 'msys2'
|
||||
if: matrix.os == 'windows' && matrix.shell != 'msys2'
|
||||
|
||||
- name: Setup MSYS (Windows)
|
||||
if: matrix.sys.os == 'windows' && matrix.sys.shell == 'msys2'
|
||||
if: matrix.os == 'windows' && matrix.shell == 'msys2'
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: UCRT64
|
||||
|
|
@ -98,7 +155,7 @@ jobs:
|
|||
run: |
|
||||
cmake -E make_directory host/build
|
||||
cd host/build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release ${{matrix.cmake_args}}
|
||||
cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{matrix.cmake_args}}
|
||||
cmake --build . --config Release
|
||||
|
||||
# Build libhackrf ONLY
|
||||
|
|
@ -107,22 +164,12 @@ jobs:
|
|||
run: |
|
||||
cmake -E make_directory host/libhackrf/build
|
||||
cd host/libhackrf/build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
|
||||
cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Install (libhackrf)
|
||||
run: |
|
||||
sudo cmake --install host/libhackrf/build --config Release
|
||||
if: matrix.sys.os != 'windows' && matrix.cmake != '3.10.0'
|
||||
|
||||
- name: Install (libhackrf, CMake 3.10)
|
||||
run: |
|
||||
sudo cmake --build host/libhackrf/build --target install --config Release
|
||||
if: matrix.sys.os != 'windows' && matrix.cmake == '3.10.0'
|
||||
|
||||
- name: Install (libhackrf, Windows)
|
||||
run: cmake --install host/libhackrf/build --config Release
|
||||
if: matrix.sys.os == 'windows'
|
||||
${{ matrix.sudo }} cmake ${{ matrix.install_cmd }} host/libhackrf/build ${{ matrix.install_args }} --config Release
|
||||
|
||||
# Build hackrf-tools ONLY
|
||||
|
||||
|
|
@ -130,22 +177,12 @@ jobs:
|
|||
run: |
|
||||
cmake -E make_directory host/hackrf-tools/build
|
||||
cd host/hackrf-tools/build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
|
||||
cmake .. -G "${{ matrix.generator }}" -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Install (hackrf-tools)
|
||||
run: |
|
||||
sudo cmake --install host/hackrf-tools/build --config Release
|
||||
if: matrix.sys.os != 'windows' && matrix.cmake != '3.10.0'
|
||||
|
||||
- name: Install (hackrf-tools, CMake 3.10)
|
||||
run: |
|
||||
sudo cmake --build host/hackrf-tools/build --target install --config Release
|
||||
if: matrix.sys.os != 'windows' && matrix.cmake == '3.10.0'
|
||||
|
||||
- name: Install (hackrf-tools, Windows)
|
||||
run: cmake --install host/hackrf-tools/build --config Release
|
||||
if: matrix.sys.os == 'windows'
|
||||
${{ matrix.sudo }} cmake ${{ matrix.install_cmd }} host/hackrf-tools/build ${{ matrix.install_args }}
|
||||
|
||||
# Publish the contents of install/bin (which should be the combination libhackrf and host-tools) for Windows
|
||||
- name: Publish Artifacts (Windows)
|
||||
|
|
@ -153,31 +190,40 @@ jobs:
|
|||
with:
|
||||
name: hackrf-tools-windows
|
||||
path: ${{github.workspace}}/install/bin
|
||||
if: matrix.sys.os == 'windows' && matrix.cmake == 'latest' && matrix.sys.shell == 'pwsh'
|
||||
if: matrix.os == 'windows' && matrix.cmake == 'latest' && matrix.shell == 'pwsh'
|
||||
|
||||
firmware:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ['macos', 'ubuntu', 'windows']
|
||||
board: ['HACKRF_ONE', 'JAWBREAKER', 'RAD1O', 'PRALINE']
|
||||
cmake: ['3.10.0', 'latest']
|
||||
board: ['HACKRF_ONE', 'JAWBREAKER', 'RAD1O', 'PRALINE', 'UNIVERSAL']
|
||||
cmake: ['3.12.0', 'latest']
|
||||
exclude:
|
||||
- os: 'windows'
|
||||
cmake: '3.10.0'
|
||||
cmake: '3.12.0'
|
||||
# GitHub doesn't give us many macOS runners, so don't build for every board.
|
||||
# We just need to know that building firmware works on macOS. Use PRALINE
|
||||
# since that's the most complicated one due to FPGA bitstreams.
|
||||
- os: 'macos'
|
||||
board: 'HACKRF_ONE'
|
||||
- os: 'macos'
|
||||
board: 'JAWBREAKER'
|
||||
- os: 'macos'
|
||||
board: 'RAD1O'
|
||||
|
||||
# Don't cancel all builds when one fails
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmake-version: ${{ matrix.cmake }}
|
||||
cmakeVersion: ${{ matrix.cmake }}
|
||||
if: matrix.os != 'windows'
|
||||
|
||||
- name: Install Arm GNU Toolchain
|
||||
|
|
|
|||
2
.github/workflows/clang-format-check.yml
vendored
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
- check: 'firmware/hackrf_usb'
|
||||
exclude: ''
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Run clang-format-action
|
||||
uses: jidicula/clang-format-action@v4.6.2
|
||||
with:
|
||||
|
|
|
|||
96
.github/workflows/includes-check.yml
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
name: Check includes
|
||||
on: [push, pull_request]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
includes-check:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: "debian:13"
|
||||
options: --user 0
|
||||
strategy:
|
||||
matrix:
|
||||
board: ['HACKRF_ONE', 'JAWBREAKER', 'RAD1O', 'PRALINE', 'UNIVERSAL']
|
||||
cmake: ['3.12.0', 'latest']
|
||||
|
||||
# Don't cancel all builds when one fails
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
|
||||
- name: Make it work on debian
|
||||
run: |
|
||||
apt update
|
||||
apt install -y git python3 python3-pip python3-venv nodejs unzip
|
||||
# actions/checkout insists on putting the checkout in the
|
||||
# working directory rather than ${{ github.workspace }}.
|
||||
#
|
||||
# This may just be because the 'runner' user does not exist
|
||||
# in the docker image at startup.
|
||||
#
|
||||
# also see: https://github.com/actions/runner/issues/878
|
||||
useradd -ms /bin/bash runner
|
||||
ln -s /__w /home/runner/work
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup cmake
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: ${{ matrix.cmake }}
|
||||
|
||||
- name: Install Arm GNU Toolchain
|
||||
uses: carlosperate/arm-none-eabi-gcc-action@v1
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python3 -m venv environment && source environment/bin/activate
|
||||
python3 -m pip install PyYAML
|
||||
apt install -y iwyu
|
||||
iwyu --version
|
||||
|
||||
- name: Build libopencm3
|
||||
working-directory: ${{github.workspace}}/firmware/libopencm3/
|
||||
run: |
|
||||
source ../../environment/bin/activate
|
||||
make
|
||||
|
||||
- name: Create Build Environment
|
||||
run: cmake -E make_directory ${{github.workspace}}/firmware/build
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{github.workspace}}/firmware/build
|
||||
run: cmake ${{github.workspace}}/firmware/ -DCMAKE_BUILD_TYPE=Release -DBOARD=${{ matrix.board }} -DCHECK_INCLUDES=1
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}/firmware/build
|
||||
run: |
|
||||
source ../../environment/bin/activate
|
||||
output="$(cmake --build . --config Release 2>&1)"
|
||||
while IFS= read -r line
|
||||
do
|
||||
if [[ "${line}" == "Warning: include-what-you-use"* ]]; then
|
||||
exit_code=1
|
||||
dump=1
|
||||
echo
|
||||
elif [[ "${line}" == "---" ]]; then
|
||||
dump=0
|
||||
echo
|
||||
fi
|
||||
if [[ ${dump} == "1" ]]; then
|
||||
echo "${line}"
|
||||
fi
|
||||
done <<< ${output}
|
||||
if [[ ${exit_code} == "1" ]]; then
|
||||
echo "Includes check failed for board target: ${{ matrix.board }}"
|
||||
else
|
||||
echo "Includes check succeeded for board target: ${{ matrix.board }}"
|
||||
fi
|
||||
echo $(include-what-you-use --version)
|
||||
exit ${exit_code}
|
||||
198
Jenkinsfile
vendored
|
|
@ -1,99 +1,123 @@
|
|||
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
|
||||
|
||||
def docker_args = '''--group-add=20 --group-add=46 --device-cgroup-rule="c 189:* rmw" \
|
||||
--device-cgroup-rule="c 166:* rmw" -v /dev/bus/usb:/dev/bus/usb \
|
||||
-v /tmp/req_pipe:/tmp/req_pipe -v /tmp/res_pipe:/tmp/res_pipe'''
|
||||
|
||||
def h1_test = '''python3 ci-scripts/hackrf_test.py --ci --log log \
|
||||
--hostdir host/build/hackrf-tools/src/ \
|
||||
--fwupdate firmware/hackrf_usb/build/ \
|
||||
--tester 0000000000000000325866e629a25623 \
|
||||
--eut RunningFromRAM --unattended --rev r4'''
|
||||
|
||||
def hpro_test = '''python3 ci-scripts/hackrf_pro_test.py --ci --log log \
|
||||
--hostdir host/build/hackrf-tools/src \
|
||||
--fwupdate firmware/hackrf_usb/build \
|
||||
--tester 0000000000000000a06063c82338145f \
|
||||
--eut RunningFromRAM -p --rev r1.2'''
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Build Docker Image') {
|
||||
options {
|
||||
timeout(time: 20, unit: 'MINUTES')
|
||||
}
|
||||
steps {
|
||||
sh 'docker build -t hackrf https://github.com/greatscottgadgets/hackrf.git'
|
||||
}
|
||||
}
|
||||
stage('Test HackRF One') {
|
||||
stage('Test HackRF One with BOARD=HACKRF_ONE') {
|
||||
agent {
|
||||
docker {
|
||||
image 'hackrf'
|
||||
reuseNode true
|
||||
args '''--group-add=20 --group-add=46 --device-cgroup-rule="c 189:* rmw" \
|
||||
--device-cgroup-rule="c 166:* rmw" -v /dev/bus/usb:/dev/bus/usb \
|
||||
-v /tmp/req_pipe:/tmp/req_pipe -v /tmp/res_pipe:/tmp/res_pipe'''
|
||||
args docker_args
|
||||
}
|
||||
}
|
||||
options {
|
||||
timeout(time: 20, unit: 'MINUTES')
|
||||
}
|
||||
steps {
|
||||
sh './ci-scripts/install_host.sh'
|
||||
sh './ci-scripts/build_h1_firmware.sh'
|
||||
script {
|
||||
allOff();
|
||||
}
|
||||
retry(3) {
|
||||
runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES')
|
||||
runCommand("Build HackRF One Firmware", './ci-scripts/build_firmware.sh HACKRF_ONE', 3, 1, 'MINUTES')
|
||||
lock('HIL_hubs') {
|
||||
script {
|
||||
reset('h1_eut')
|
||||
}
|
||||
sh 'sleep 1s'
|
||||
sh './ci-scripts/test_host.sh'
|
||||
}
|
||||
retry(3) {
|
||||
script {
|
||||
reset('h1_tester h1_eut')
|
||||
}
|
||||
sh 'sleep 1s'
|
||||
script {
|
||||
// Allow 5 minutes for the test to run
|
||||
runCommand(5, 'MINUTES', "HackRF One Test",
|
||||
'''python3 ci-scripts/hackrf_test.py --ci --log log \
|
||||
--hostdir host/build/hackrf-tools/src/ \
|
||||
--fwupdate firmware/hackrf_usb/build/ \
|
||||
--tester 0000000000000000325866e629a25623 \
|
||||
--eut RunningFromRAM --unattended --rev r4'''
|
||||
)
|
||||
allOff()
|
||||
runTest("Check Host", 'h1_eut', './ci-scripts/test_host.sh')
|
||||
runTest("HackRF One HIL Test", 'h1_tester h1_eut', h1_test)
|
||||
runTest("SGPIO Debug Test", 'h1_eut', 'python3 ci-scripts/test_sgpio_debug.py')
|
||||
}
|
||||
}
|
||||
retry(3) {
|
||||
script {
|
||||
reset('h1_eut')
|
||||
}
|
||||
sh 'sleep 1s'
|
||||
sh 'python3 ci-scripts/test_sgpio_debug.py'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Test HackRF Pro') {
|
||||
stage('Test HackRF One with BOARD=UNIVERSAL') {
|
||||
agent {
|
||||
docker {
|
||||
image 'hackrf'
|
||||
reuseNode true
|
||||
args '''--group-add=20 --group-add=46 --device-cgroup-rule="c 189:* rmw" \
|
||||
--device-cgroup-rule="c 166:* rmw" -v /dev/bus/usb:/dev/bus/usb \
|
||||
-v /tmp/req_pipe:/tmp/req_pipe -v /tmp/res_pipe:/tmp/res_pipe'''
|
||||
args docker_args
|
||||
}
|
||||
}
|
||||
options {
|
||||
timeout(time: 20, unit: 'MINUTES')
|
||||
}
|
||||
steps {
|
||||
sh './ci-scripts/install_host.sh'
|
||||
sh './ci-scripts/build_hpro_firmware.sh'
|
||||
script {
|
||||
allOff();
|
||||
}
|
||||
retry(3) {
|
||||
runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES')
|
||||
runCommand("Build Universal Firmware", './ci-scripts/build_firmware.sh UNIVERSAL', 3, 1, 'MINUTES')
|
||||
lock('HIL_hubs') {
|
||||
script {
|
||||
reset('hpro_eut')
|
||||
allOff()
|
||||
runTest("Check Host", 'h1_eut', './ci-scripts/test_host.sh')
|
||||
runTest("HackRF One HIL Test", 'h1_tester h1_eut', h1_test)
|
||||
runTest("SGPIO Debug Test", 'h1_eut', 'python3 ci-scripts/test_sgpio_debug.py')
|
||||
}
|
||||
sh 'sleep 1s'
|
||||
sh './ci-scripts/test_host.sh'
|
||||
}
|
||||
retry(3) {
|
||||
|
||||
}
|
||||
}
|
||||
stage('Test HackRF Pro with BOARD=PRALINE') {
|
||||
agent {
|
||||
docker {
|
||||
image 'hackrf'
|
||||
reuseNode true
|
||||
args "$docker_args"
|
||||
}
|
||||
}
|
||||
options {
|
||||
timeout(time: 20, unit: 'MINUTES')
|
||||
}
|
||||
steps {
|
||||
runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES')
|
||||
runCommand("Build Praline Firmware", './ci-scripts/build_firmware.sh PRALINE', 3, 1, 'MINUTES')
|
||||
lock('HIL_hubs') {
|
||||
script {
|
||||
reset('hpro_tester hpro_eut')
|
||||
allOff()
|
||||
runTest("Check Host", 'hpro_eut', './ci-scripts/test_host.sh')
|
||||
runTest("HackRF Pro HIL Test", 'hpro_tester hpro_eut', hpro_test)
|
||||
}
|
||||
sh 'sleep 1s'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Test HackRF Pro with BOARD=UNIVERSAL') {
|
||||
agent {
|
||||
docker {
|
||||
image 'hackrf'
|
||||
reuseNode true
|
||||
args "$docker_args"
|
||||
}
|
||||
}
|
||||
options {
|
||||
timeout(time: 20, unit: 'MINUTES')
|
||||
}
|
||||
steps {
|
||||
runCommand("Install Host Tools", './ci-scripts/install_host.sh', 3, 1, 'MINUTES')
|
||||
runCommand("Build Universal Firmware", './ci-scripts/build_firmware.sh UNIVERSAL', 3, 1, 'MINUTES')
|
||||
lock('HIL_hubs') {
|
||||
script {
|
||||
// Allow 5 minutes for the test to run
|
||||
runCommand(5, 'MINUTES', "HackRF Pro Test",
|
||||
'''python3 ci-scripts/hackrf_pro_test.py --ci --log log \
|
||||
--hostdir host/build/hackrf-tools/src \
|
||||
--fwupdate firmware/hackrf_usb/build \
|
||||
--tester 0000000000000000a06063c82338145f \
|
||||
--eut RunningFromRAM -p --rev r1.2'''
|
||||
)
|
||||
allOff()
|
||||
runTest("Check Host", 'hpro_eut', './ci-scripts/test_host.sh')
|
||||
runTest("HackRF Pro HIL Test", 'hpro_tester hpro_eut', hpro_test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -110,32 +134,44 @@ pipeline {
|
|||
}
|
||||
|
||||
def allOff() {
|
||||
// Allow 20 seconds for the USB hub port power server to respond
|
||||
runCommand(20, 'SECONDS', 'USB hub port power server command', "hubs all off")
|
||||
// Allow up to 3 retries, 20 seconds each, for the USB hub port power server to respond appropriately
|
||||
runCommand('USB hub port power server command', "hubs all off", 3, 20, 'SECONDS')
|
||||
}
|
||||
|
||||
def reset(devices) {
|
||||
// Allow 20 seconds for the USB hub port power server to respond
|
||||
runCommand(20, 'SECONDS', 'USB hub port power server command', "hubs ${devices} reset")
|
||||
// Allow up to 3 retries, 20 seconds each, for the USB hub port power server to respond appropriately
|
||||
runCommand('USB hub port power server command', "hubs ${devices} reset", 3, 20, 'SECONDS')
|
||||
}
|
||||
|
||||
def runCommand(time, unit, title, cmd) {
|
||||
try {
|
||||
timeout(time: time, unit: unit) {
|
||||
sh "${cmd}"
|
||||
def runCommand(title, cmd, retries, time, unit) {
|
||||
retry(retries) {
|
||||
try {
|
||||
timeout(time: time, unit: unit) {
|
||||
sh "${cmd}"
|
||||
}
|
||||
} catch (FlowInterruptedException err) {
|
||||
// Check if the cause was specifically an exceeded timeout
|
||||
def cause = err.getCauses().get(0)
|
||||
if (cause instanceof org.jenkinsci.plugins.workflow.steps.TimeoutStepExecution.ExceededTimeout) {
|
||||
echo "${title} timeout reached."
|
||||
throw err // Re-throw the exception to fail the build
|
||||
} else {
|
||||
echo "Build interrupted for another reason."
|
||||
throw err // Re-throw the exception to fail the build
|
||||
}
|
||||
} catch (Exception err) {
|
||||
echo "An unrelated error occurred: ${err.getMessage()}"
|
||||
throw err
|
||||
}
|
||||
} catch (FlowInterruptedException err) {
|
||||
// Check if the cause was specifically an exceeded timeout
|
||||
def cause = err.getCauses().get(0)
|
||||
if (cause instanceof org.jenkinsci.plugins.workflow.steps.TimeoutStepExecution.ExceededTimeout) {
|
||||
echo "${title} timeout reached."
|
||||
throw err // Re-throw the exception to fail the build
|
||||
} else {
|
||||
echo "Build interrupted for another reason."
|
||||
throw err // Re-throw the exception to fail the build
|
||||
}
|
||||
} catch (Exception err) {
|
||||
echo "An unrelated error occurred: ${err.getMessage()}"
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
def runTest(title, devices, cmd) {
|
||||
retry(3) {
|
||||
// reset() retains it's own internal retries
|
||||
reset(devices)
|
||||
sh 'sleep 1s'
|
||||
// run the test with 0 internal retries and 3 external retries to ensure resets between runs
|
||||
runCommand(title, cmd, 0, 5, 'MINUTES')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ git submodule init
|
|||
git submodule update
|
||||
cd firmware/hackrf_usb
|
||||
rm -rf build
|
||||
cmake -DBOARD=PRALINE -B build
|
||||
cmake -DBOARD=$1 -B build
|
||||
cmake --build build
|
||||
cd ../..
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
git submodule init
|
||||
git submodule update
|
||||
cd firmware/hackrf_usb
|
||||
rm -rf build
|
||||
cmake -DBOARD=HACKRF_ONE -B build
|
||||
cmake --build build
|
||||
cd ../..
|
||||
|
|
@ -663,9 +663,6 @@ class HackRF:
|
|||
self.rf_test_cases = praline_r110_rf_test_cases
|
||||
|
||||
def clkin(self):
|
||||
if self.name == "EUT" and self.id == "5":
|
||||
debug = subprocess.run([self.bin_dir + "/hackrf_debug", "-d", self.serial,
|
||||
"-C", "0"])
|
||||
command = subprocess.run([self.bin_dir + "/hackrf_clock", "-i", "-d",
|
||||
self.serial], capture_output=True, encoding="utf-8",
|
||||
timeout=TIMEOUT)
|
||||
|
|
@ -1413,11 +1410,11 @@ def program(bin_dir, fw_dir, serial, unattended=False):
|
|||
if spiflash.returncode != 0:
|
||||
log(spiflash.stdout + spiflash.stderr)
|
||||
fail(70)
|
||||
time.sleep(3)
|
||||
|
||||
then = time.time()
|
||||
device_found = False
|
||||
while time.time() < (then + 5):
|
||||
time.sleep(1)
|
||||
flash_info = subprocess.run([bin_dir + "/hackrf_info"], capture_output=True,
|
||||
timeout=TIMEOUT)
|
||||
if serial == "RunningFromRAM" and not unattended:
|
||||
|
|
@ -1433,7 +1430,7 @@ def program(bin_dir, fw_dir, serial, unattended=False):
|
|||
if serial in flash_info.stdout.decode('utf-8', errors='ignore'):
|
||||
device_found = True
|
||||
break
|
||||
time.sleep(0.1)
|
||||
time.sleep(1)
|
||||
if not device_found:
|
||||
fail(75)
|
||||
|
||||
|
|
|
|||
BIN
docs/images/gateware-basic-block-diagram.png
Normal file
|
After Width: | Height: | Size: 191 KiB |
4
docs/images/gateware-basic-block-diagram.svg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/images/gateware-ext-prec-rx-dsp-chain.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
4
docs/images/gateware-ext-prec-rx-dsp-chain.svg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/images/gateware-ext-prec-tx-dsp-chain.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
4
docs/images/gateware-ext-prec-tx-dsp-chain.svg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/images/gateware-halfprec-dsp-chain.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
4
docs/images/gateware-halfprec-dsp-chain.svg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/images/gateware-rx-only-basic-block-diagram.png
Normal file
|
After Width: | Height: | Size: 135 KiB |
4
docs/images/gateware-rx-only-basic-block-diagram.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/images/gateware-standard-dsp-chain.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
4
docs/images/gateware-standard-dsp-chain.svg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/images/gateware-tx-only-basic-block-diagram.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
4
docs/images/gateware-tx-only-basic-block-diagram.svg
Normal file
|
After Width: | Height: | Size: 34 KiB |
|
|
@ -9,12 +9,18 @@ HackRF Pro
|
|||
|
||||
HackRF Pro has two configurable SMA ports, P1 and P2. By default, P1 is configured as CLKIN and P2 as CLKOUT. The default behaviour of these signals is as described for HackRF One below.
|
||||
|
||||
A second CLKIN signal is available on header P22 pin 2. Unlike HackRF One, HackRF Pro's P22_CLKIN is a separate signal from P1_CLKIN. To enable P22_CLKIN instead of P1_CLKIN use ``hackrf_clock -c p22``.
|
||||
|
||||
Various internal signals can be connected to P1 or P2 instead of the default CLKIN and CLKOUT signals. Use ``hackrf_clock -1`` or ``hackrf_clock -2`` to select a different signal.
|
||||
|
||||
HackRF One
|
||||
~~~~~~~~~~
|
||||
|
||||
HackRF One produces a 10 MHz clock signal on CLKOUT. The signal is a 3.3 V, 10 MHz square wave intended for a high impedance load.
|
||||
HackRF One produces a 10 MHz clock signal on the CLKOUT SMA port. The signal is a 3.3 V, 10 MHz square wave intended for a high impedance load.
|
||||
|
||||
The CLKIN port on HackRF One is a high impedance input that expects 3.3 V square wave at 10 MHz. Do not exceed 3.3 V or drop below 0 V on this input. Do not connect a clock signal at a frequency other than 10 MHz (unless you modify the firmware to support this). You may directly connect the CLKOUT port of one HackRF One to the CLKIN port of another HackRF One.
|
||||
The CLKIN SMA port on HackRF One is a high impedance input that expects 3.3 V square wave at 10 MHz. Do not exceed 3.3 V or drop below 0 V on this input. Do not connect a clock signal at a frequency other than 10 MHz (unless you modify the firmware to support this). You may directly connect the CLKOUT port of one HackRF One to the CLKIN port of another HackRF.
|
||||
|
||||
The CLKIN signal is also connected to header P22 pin 2. Unlike HackRF Pro, HackRF One has only one CLKIN signal shared between P22 pin 2 and the CLKIN port. Do not connect input signals to both CLKIN and P22 pin 2 simultaneously.
|
||||
|
||||
HackRF One uses CLKIN instead of the internal crystal when a clock signal is detected on CLKIN. The switch to or from CLKIN only happens when a transmit or receive operation begins.
|
||||
|
||||
|
|
|
|||
118
docs/source/gateware.rst
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
================================================
|
||||
Gateware
|
||||
================================================
|
||||
|
||||
One of the significant hardware changes in :ref:`HackRF Pro <hackrf_pro>` is the replacement of the CPLD with a FPGA. While the older CPLD primarily provided glue logic between the MCU and RF front end, the FPGA in HackRF Pro introduces more logic and DSP capability. This enables offloading digital signal processing tasks from the MCU.
|
||||
|
||||
FPGAs are highly flexible devices whose behavior is defined by *gateware*: hardware descriptions that configure the internal logic fabric. HackRF Pro gateware is written in `Amaranth HDL <https://amaranth-lang.org/>`__, a Python-based hardware description language.
|
||||
|
||||
The specific FPGA device used in HackRF Pro is the Lattice iCE40UP5K, which features
|
||||
5280 LUT4s and 8 dedicated DSP (multiply-accumulate) blocks. We rely on the `open-source iCE40 FPGA toolchain <https://github.com/YosysHQ/icestorm>`__ to build the required bitstreams that are bundled in the firmware.
|
||||
|
||||
All gateware source code lives under `firmware/fpga/` in the HackRF repository. Top-level designs reside in `firmware/fpga/top/` and are the primary entry points for different operational modes.
|
||||
|
||||
By default, a standard gateware configuration is loaded at boot. However, the firmware can dynamically reconfigure the FPGA at runtime to switch between different gateware variants.
|
||||
|
||||
|
||||
Standard gateware
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The standard gateware is used by default when the firmware has not requested an alternative bitstream.
|
||||
|
||||
The standard gateware provides a balanced configuration optimized for general-purpose operation. It implements configurable digital signal processing paths for the reception and transmission paths, capable of (limited) frequency translation and supporting a wide range of sample rates.
|
||||
|
||||
Block diagram
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. image:: ../images/gateware-basic-block-diagram.png
|
||||
:align: center
|
||||
|
||||
.. image:: ../images/gateware-standard-dsp-chain.png
|
||||
:align: center
|
||||
:width: 75%
|
||||
|
||||
Features
|
||||
^^^^^^^^
|
||||
* 8-bit I, 8-bit Q data format
|
||||
* Receiver signal chain:
|
||||
* Optional DC offset removal (DC blocker)
|
||||
* Configurable fs/4 shifter (quarter sample rate): bypass, shift up or shift down
|
||||
* Configurable decimation rates: 1x, 2x, 4x, 8x, 16x, 32x
|
||||
* Transmitter signal chain:
|
||||
* Configurable interpolation rates: 1x, 2x, 4x, 8x, 16x, 32x
|
||||
* SPI control interface for register configuration
|
||||
* Double data rate (DDR) interface to RF transceiver
|
||||
* Interface to MCU (SGPIO)
|
||||
|
||||
|
||||
Half-precision gateware
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The half-precision gateware reduces sample width to 4 bits per I/Q component, enabling higher throughput within the constraints of the USB interface (up to 40 Msps).
|
||||
|
||||
This configuration is intended for applications where bandwidth is more critical than dynamic range, such as wideband spectrum monitoring.
|
||||
|
||||
Block diagram
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. image:: ../images/gateware-basic-block-diagram.png
|
||||
:align: center
|
||||
|
||||
.. image:: ../images/gateware-halfprec-dsp-chain.png
|
||||
:align: center
|
||||
:width: 75%
|
||||
|
||||
Features
|
||||
^^^^^^^^
|
||||
* 4-bit I, 4-bit Q data format
|
||||
* Receiver signal chain:
|
||||
* Optional DC offset removal (DC blocker)
|
||||
* Round to 4-bit I/Q
|
||||
* Transmitter signal chain:
|
||||
* Extend width to 8-bit I/Q
|
||||
* SPI control interface for register configuration
|
||||
* Double data rate (DDR) interface to RF transceiver
|
||||
* Interface to MCU (SGPIO)
|
||||
|
||||
Extended-precision gateware (RX and TX)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The extended-precision gateware increases internal signal processing precision and output sample width to improve signal quality. The main drawback is that the minimum decimation or interpolation factor is 16x. Due to increased logic requirements, this gateware is split in two top-level designs (RX and TX).
|
||||
|
||||
Samples are 16-bit I/Q, while the effective number of bits (ENOB) depends on the selected configuration and typically ranges between 9 and 11 bits.
|
||||
|
||||
The increased dynamic range of the output makes it particularly useful for weak and/or narrowband signals.
|
||||
|
||||
Block diagram (RX)
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. image:: ../images/gateware-rx-only-basic-block-diagram.png
|
||||
:align: center
|
||||
|
||||
.. image:: ../images/gateware-ext-prec-rx-dsp-chain.png
|
||||
:align: center
|
||||
:width: 75%
|
||||
|
||||
Block diagram (TX)
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. image:: ../images/gateware-tx-only-basic-block-diagram.png
|
||||
:align: center
|
||||
|
||||
.. image:: ../images/gateware-ext-prec-tx-dsp-chain.png
|
||||
:align: center
|
||||
:width: 75%
|
||||
|
||||
Features
|
||||
^^^^^^^^
|
||||
* 16-bit I, 16-bit Q data format
|
||||
* Receiver signal chain (RX extended-precision gateware):
|
||||
* Optional DC offset removal (DC blocker)
|
||||
* Configurable mixer (in fs/128 steps)
|
||||
* Configurable decimation rates: 16x, 32x, 64x, 128x
|
||||
* Transmitter signal chain (TX extended-precision gateware):
|
||||
* Configurable interpolation rates: 16x, 32x, 64x, 128x
|
||||
* SPI control interface for register configuration
|
||||
* Double data rate (DDR) interface to RF transceiver
|
||||
* Interface to MCU (SGPIO)
|
||||
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
HackRF Pro
|
||||
================================================
|
||||
|
||||
.. _hackrf_pro:
|
||||
|
||||
.. image:: ../images/hackrf-pro-preliminary-photo.jpg
|
||||
:alt: HackRF Pro
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,13 @@ Welcome to HackRF's documentation!
|
|||
setting_gain
|
||||
virtual_machines
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Gateware
|
||||
|
||||
gateware
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Opera Cake Documentation
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ Software That Has Direct Support For HackRF
|
|||
|
||||
* `https://xakcop.com/aprs-sdr <https://xakcop.com/aprs-sdr/>`__
|
||||
|
||||
* SigDigger (Windows/Linux/macOS)
|
||||
|
||||
* `https://github.com/BatchDrake/SigDigger <https://github.com/BatchDrake/SigDigger>`__
|
||||
* Supports HackRF through SoapySDR / SoapyHackRF
|
||||
|
||||
|
||||
|
||||
Software That Can Use Data From HackRF
|
||||
|
|
@ -74,4 +79,4 @@ Troubleshooting Recommendations
|
|||
|
||||
Many of these tools require libhackrf and at times HackRF Tools. It may help you to have updated libhackrf and HackRF Tools when troubleshooting these applications.
|
||||
|
||||
It is also strongly suggested, and usually required, that your HackRF Tools and HackRF firmware match.
|
||||
It is also strongly suggested, and usually required, that your HackRF Tools and HackRF firmware match.
|
||||
|
|
|
|||
|
|
@ -20,10 +20,17 @@
|
|||
|
||||
# Top directory CMake project for HackRF firmware
|
||||
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
option(CHECK_INCLUDES
|
||||
"Check firmware sources for unused includes and transitive dependencies. (Requires iwyu)" OFF)
|
||||
|
||||
cmake_minimum_required(VERSION 3.12.0)
|
||||
set(CMAKE_TOOLCHAIN_FILE toolchain-arm-cortex-m.cmake)
|
||||
|
||||
project (hackrf_firmware_all C)
|
||||
|
||||
if(CHECK_INCLUDES)
|
||||
include(include-what-you-use.cmake)
|
||||
endif()
|
||||
|
||||
add_subdirectory(blinky)
|
||||
add_subdirectory(hackrf_usb)
|
||||
|
|
|
|||
|
|
@ -19,14 +19,16 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "hackrf_core.h"
|
||||
#include "platform_detect.h"
|
||||
#include "delay.h"
|
||||
#include "leds.h"
|
||||
#include "pins.h"
|
||||
#include "platform_detect.h"
|
||||
#include "power.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
detect_hardware_platform();
|
||||
pin_setup();
|
||||
pins_setup();
|
||||
|
||||
#ifndef PRALINE
|
||||
/* enable 1V8 power supply so that the 1V8 LED lights up */
|
||||
|
|
@ -37,19 +39,19 @@ int main(void)
|
|||
#endif
|
||||
|
||||
/* Blink LED1/2/3 on the board. */
|
||||
while (1)
|
||||
while (1)
|
||||
{
|
||||
led_on(LED1);
|
||||
led_on(LED2);
|
||||
led_on(LED3);
|
||||
|
||||
delay(2000000);
|
||||
|
||||
delay_ms(150);
|
||||
|
||||
led_off(LED1);
|
||||
led_off(LED2);
|
||||
led_off(LED3);
|
||||
|
||||
delay(2000000);
|
||||
|
||||
delay_ms(150);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ MEMORY
|
|||
{
|
||||
/* rom is really the shadow region that points to SPI flash or elsewhere */
|
||||
rom (rx) : ORIGIN = 0x00000000, LENGTH = 1M
|
||||
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 96K
|
||||
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 64K
|
||||
ram_usb (rw) : ORIGIN = 0x10010000, LENGTH = 32K
|
||||
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 32K
|
||||
ram_sleep (rwx) : ORIGIN = 0x10088000, LENGTH = 8K
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ MEMORY
|
|||
{
|
||||
/* rom is really the shadow region that points to SPI flash or elsewhere */
|
||||
rom (rx) : ORIGIN = 0x00000000, LENGTH = 128K
|
||||
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 128K
|
||||
ram_local1 (rwx) : ORIGIN = 0x10000000, LENGTH = 96K
|
||||
ram_usb(rw) : ORIGIN = 0x10018000, LENGTH = 32K
|
||||
ram_local2 (rwx) : ORIGIN = 0x10080000, LENGTH = 64K
|
||||
ram_sleep (rwx) : ORIGIN = 0x10090000, LENGTH = 8K
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,12 @@ MEMORY
|
|||
* to get performance benefit of having two USB buffers addressable
|
||||
* simultaneously (on two different buses of the AHB multilayer matrix)
|
||||
*/
|
||||
ram_usb (rwx) : ORIGIN = 0x20008000, LENGTH = 32K
|
||||
ram_samp (rwx) : ORIGIN = 0x20008000, LENGTH = 32K
|
||||
}
|
||||
|
||||
usb_bulk_buffer = ORIGIN(ram_usb);
|
||||
lz4_in_buf = ORIGIN(ram_lz4_in);
|
||||
lz4_out_buf = ORIGIN(ram_lz4_out);
|
||||
usb_samp_buffer = ORIGIN(ram_samp);
|
||||
usb_bulk_buffer = ORIGIN(ram_usb);
|
||||
m0_state = ORIGIN(ram_shared);
|
||||
PROVIDE(__ram_m0_start__ = ORIGIN(ram_m0));
|
||||
|
|
|
|||
|
|
@ -19,12 +19,9 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ADC_H__
|
||||
#define __ADC_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t adc_read(uint8_t pin);
|
||||
void adc_off(void);
|
||||
|
||||
#endif // __ADC_H__
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __BITBAND_H__
|
||||
#define __BITBAND_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -37,5 +36,3 @@ void peripheral_bitband_clear(
|
|||
uint32_t peripheral_bitband_get(
|
||||
volatile void* const peripheral_address,
|
||||
const uint_fast8_t bit_number);
|
||||
|
||||
#endif //__BITBAND_H__
|
||||
|
|
|
|||
420
firmware/common/clock_gen.c
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "clock_gen.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hackrf_ui.h"
|
||||
#include "platform_detect.h"
|
||||
#include "sgpio.h"
|
||||
#include "si5351c.h"
|
||||
#if defined(IS_HACKRF_ONE) || defined(IS_PRALINE)
|
||||
#include "delay.h"
|
||||
#include "portapack.h"
|
||||
#endif
|
||||
|
||||
void clock_gen_init(void)
|
||||
{
|
||||
si5351c_init(&si5351c);
|
||||
si5351c_disable_all_outputs(&si5351c);
|
||||
si5351c_disable_oeb_pin_control(&si5351c);
|
||||
si5351c_power_down_all_clocks(&si5351c);
|
||||
si5351c_set_crystal_configuration(&si5351c);
|
||||
si5351c_enable_xo_and_ms_fanout(&si5351c);
|
||||
|
||||
/*
|
||||
* Clocks on HackRF One r9:
|
||||
* CLK0 -> MAX5864/CPLD/SGPIO (sample clocks)
|
||||
* CLK1 -> RFFC5072/MAX2839
|
||||
* CLK2 -> External Clock Output/LPC43xx (power down at boot)
|
||||
*
|
||||
* Clocks on other platforms:
|
||||
* CLK0 -> MAX5864/CPLD
|
||||
* CLK1 -> CPLD
|
||||
* CLK2 -> SGPIO
|
||||
* CLK3 -> External Clock Output (power down at boot)
|
||||
* CLK4 -> RFFC5072 (MAX2837 on rad1o)
|
||||
* CLK5 -> MAX2837 (MAX2871 on rad1o)
|
||||
* CLK6 -> none
|
||||
* CLK7 -> LPC43xx (uses a 12MHz crystal by default)
|
||||
*
|
||||
* Clocks on Praline:
|
||||
* CLK0 -> AFE_CLK (MAX5864/FPGA)
|
||||
* CLK1 -> SCT_CLK
|
||||
* CLK2 -> MCU_CLK (uses a 12MHz crystal by default)
|
||||
* CLK3 -> External Clock Output (power down at boot)
|
||||
* CLK4 -> XCVR_CLK (MAX2837)
|
||||
* CLK5 -> MIX_CLK (RFFC5072)
|
||||
* CLK6 -> AUX_CLK1
|
||||
* CLK7 -> AUX_CLK2
|
||||
*/
|
||||
|
||||
#ifdef IS_H1_R9
|
||||
if (IS_H1_R9) {
|
||||
/* MS0/CLK0 is the reference for both RFFC5071 and MAX2839. */
|
||||
si5351c_configure_multisynth(
|
||||
&si5351c,
|
||||
0,
|
||||
20 * 128 - 512,
|
||||
0,
|
||||
1,
|
||||
0); /* 800/20 = 40MHz */
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_H1_R9
|
||||
if (IS_NOT_H1_R9) {
|
||||
/* MS4/CLK4 is the source for the RFFC5071 mixer (MAX2837 on rad1o). */
|
||||
si5351c_configure_multisynth(
|
||||
&si5351c,
|
||||
4,
|
||||
20 * 128 - 512,
|
||||
0,
|
||||
1,
|
||||
0); /* 800/20 = 40MHz */
|
||||
/* MS5/CLK5 is the source for the MAX2837 clock input (MAX2871 on rad1o). */
|
||||
si5351c_configure_multisynth(
|
||||
&si5351c,
|
||||
5,
|
||||
20 * 128 - 512,
|
||||
0,
|
||||
1,
|
||||
0); /* 800/20 = 40MHz */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MS6/CLK6 is unused. */
|
||||
/* MS7/CLK7 is unused. */
|
||||
|
||||
/* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */
|
||||
sample_rate_set(SR_FP_MHZ(10), true);
|
||||
|
||||
si5351c_configure_clock_control(&si5351c);
|
||||
si5351c_change_input(&si5351c, SI5351C_INPUT_XTAL);
|
||||
// soft reset
|
||||
si5351c_reset_plls(&si5351c, SI5351C_PLL_MASK_BOTH);
|
||||
si5351c_enable_clock_outputs(&si5351c);
|
||||
}
|
||||
|
||||
void clock_gen_shutdown(void)
|
||||
{
|
||||
si5351c_disable_all_outputs(&si5351c);
|
||||
si5351c_disable_oeb_pin_control(&si5351c);
|
||||
si5351c_power_down_all_clocks(&si5351c);
|
||||
}
|
||||
|
||||
clock_source_t activate_best_clock_source(void)
|
||||
{
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
/* Ensure PortaPack reference oscillator is off while checking for external clock input. */
|
||||
if (portapack_present()) {
|
||||
portapack_reference_oscillator(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
clock_source_t source = CLOCK_SOURCE_HACKRF;
|
||||
|
||||
/* Check for external clock input. */
|
||||
if (si5351c_clkin_signal_valid(&si5351c)) {
|
||||
source = CLOCK_SOURCE_EXTERNAL;
|
||||
} else {
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
/* Enable PortaPack reference oscillator (if present), and check for valid clock. */
|
||||
if (portapack_present()) {
|
||||
portapack_reference_oscillator(true);
|
||||
delay_ms(18); // for oscillator to enable.
|
||||
if (si5351c_clkin_signal_valid(&si5351c)) {
|
||||
source = CLOCK_SOURCE_PORTAPACK;
|
||||
} else {
|
||||
portapack_reference_oscillator(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* No external or PortaPack clock was found. Use HackRF Si5351C crystal. */
|
||||
}
|
||||
|
||||
si5351c_input_t input = (source == CLOCK_SOURCE_HACKRF) ? SI5351C_INPUT_XTAL :
|
||||
SI5351C_INPUT_CLKIN;
|
||||
si5351c_change_input(&si5351c, input);
|
||||
|
||||
hackrf_ui()->set_clock_source(source);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closest fraction to m/d with denominator <= max_den.
|
||||
* Returns result in *r / *s with gcd(*r, *s) == 1 and 0 < *s <= max_den.
|
||||
* Straight port from CPython's fractions, and better documented there.
|
||||
*/
|
||||
void limit_denominator(
|
||||
uint64_t m,
|
||||
uint64_t d,
|
||||
const uint64_t max_den,
|
||||
uint64_t* r,
|
||||
uint64_t* s)
|
||||
{
|
||||
if (d <= max_den) {
|
||||
*r = m;
|
||||
*s = d;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t p0 = 0, q0 = 1, p1 = 1, q1 = 0;
|
||||
uint64_t n = m, orig_d = d;
|
||||
uint64_t tmp;
|
||||
|
||||
while (1) {
|
||||
uint64_t a = n / d;
|
||||
uint64_t q2 = q0 + a * q1;
|
||||
|
||||
if (q2 > max_den)
|
||||
break;
|
||||
|
||||
tmp = p0 + a * p1;
|
||||
p0 = p1;
|
||||
q0 = q1;
|
||||
p1 = tmp;
|
||||
q1 = q2;
|
||||
|
||||
tmp = n - a * d;
|
||||
n = d;
|
||||
d = tmp;
|
||||
if (d == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t k = (max_den - q0) / q1;
|
||||
|
||||
/* Return closer candidate. */
|
||||
if (2 * d * (q0 + k * q1) <= orig_d) {
|
||||
*r = p1;
|
||||
*s = q1;
|
||||
} else {
|
||||
*r = p0 + k * p1;
|
||||
*s = q0 + k * q1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure clock generator to produce sample clock in units of 1/(2**36) Hz.
|
||||
* Can be called with program=false for a dry run that returns the resultant
|
||||
* frequency without actually configuring the clock generator.
|
||||
*
|
||||
* The clock generator output frequency is:
|
||||
*
|
||||
* fs = 128 * vco / (512 + p1 + p2/p3))
|
||||
*
|
||||
* where p1, p2, and p3 are register values.
|
||||
*
|
||||
* For more information see:
|
||||
* https://www.pa3fwm.nl/technotes/tn42a-si5351-programming.html
|
||||
*/
|
||||
fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program)
|
||||
{
|
||||
const uint64_t vco_hz = 800 * 1000ULL * 1000ULL;
|
||||
uint64_t p1, p2, p3;
|
||||
uint64_t n, d, q1, q2, q3, r1, r2;
|
||||
fp_28_36_t resultant_rate;
|
||||
|
||||
/*
|
||||
* First double the sample rate so that we can produce a clock at twice
|
||||
* the intended sample rate. The 2x clock is sometimes used directly,
|
||||
* and it is divided by two in an output divider to produce the actual
|
||||
* AFE clock.
|
||||
*/
|
||||
fp_28_36_t rate = sample_rate * 2;
|
||||
|
||||
/*
|
||||
* Computes p1 = (N << 36) / rate - 512, where N = 128 * vco_hz.
|
||||
*
|
||||
* Full numerator (N << 36) is 73 bits, so we split the division:
|
||||
*
|
||||
* (N << 36) / rate = ((N << 27) / rate) << 9
|
||||
* + (((N << 27) % rate) << 9) / rate
|
||||
*
|
||||
* IMPORTANT: Assumes sample rate is in [200e3 << 36, 43.6e6 << 36].
|
||||
*/
|
||||
const uint64_t A = (128 * vco_hz) << 27;
|
||||
|
||||
q1 = A / rate;
|
||||
r1 = A % rate;
|
||||
|
||||
// Remaining 9 bits with long division.
|
||||
q2 = 0;
|
||||
r2 = r1;
|
||||
for (int j = 0; j < 9; j++) {
|
||||
uint64_t msb = r2 >> 63;
|
||||
r2 <<= 1;
|
||||
q2 <<= 1;
|
||||
if (msb || r2 >= rate) {
|
||||
r2 -= rate;
|
||||
q2 |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
p1 = (q1 << 9) + q2 - 512;
|
||||
|
||||
if (r2) {
|
||||
/* Use the remainder for the fractional part. */
|
||||
n = r2;
|
||||
d = rate;
|
||||
|
||||
/* Reduce fraction. */
|
||||
const uint64_t p3_max = 0xfffff;
|
||||
limit_denominator(n, d, p3_max, &p2, &p3);
|
||||
|
||||
/* Roll over to next p1 to enable integer mode. */
|
||||
if (p2 >= p3) {
|
||||
p1++;
|
||||
p2 = 0;
|
||||
}
|
||||
} else {
|
||||
p2 = 0;
|
||||
}
|
||||
|
||||
/* Maximum: (128 * 2048) - 512 */
|
||||
if (p1 > 0x3fe00) {
|
||||
p1 = 0x3fe00;
|
||||
p2 = 0;
|
||||
}
|
||||
|
||||
if (p2 == 0) {
|
||||
/* Use unity denominator for integer mode. */
|
||||
p3 = 1;
|
||||
n = (128 * vco_hz) << 18;
|
||||
d = (p1 + 512);
|
||||
q1 = n / d;
|
||||
r1 = n % d;
|
||||
q2 = ((r1 << 18) + (d / 2)) / d;
|
||||
resultant_rate = (q1 << 18) + q2;
|
||||
} else {
|
||||
n = p3 * vco_hz * 128;
|
||||
d = p3 * (p1 + 512) + p2;
|
||||
q1 = n / d;
|
||||
r1 = n % d;
|
||||
q2 = (r1 << 18) / d;
|
||||
r2 = (r1 << 18) % d;
|
||||
q3 = ((r2 << 18) + (d / 2)) / d;
|
||||
resultant_rate = (q1 << 36) + (q2 << 18) + q3;
|
||||
}
|
||||
|
||||
/* Return MCU sample rate, not AFE clock rate. */
|
||||
resultant_rate = (resultant_rate + 1) / 2;
|
||||
|
||||
if (!program) {
|
||||
return resultant_rate;
|
||||
}
|
||||
|
||||
bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config);
|
||||
|
||||
if (streaming) {
|
||||
sgpio_cpld_stream_disable(&sgpio_config);
|
||||
}
|
||||
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
/* Integer mode can be enabled if p1 is even and p2 is zero. */
|
||||
if (p1 & 0x1 || p2) {
|
||||
si5351c_set_int_mode(&si5351c, 0, 0);
|
||||
} else {
|
||||
si5351c_set_int_mode(&si5351c, 0, 1);
|
||||
}
|
||||
|
||||
#ifdef IS_H1_R9
|
||||
if (IS_H1_R9) {
|
||||
/*
|
||||
* On HackRF One r9 all sample clocks are externally derived
|
||||
* from MS1/CLK1 operating at twice the sample rate.
|
||||
*/
|
||||
si5351c_configure_multisynth(&si5351c, 1, p1, p2, p3, 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_H1_R9
|
||||
if (IS_NOT_H1_R9) {
|
||||
/*
|
||||
* On other platforms the clock generator produces three
|
||||
* different sample clocks, all derived from multisynth 0.
|
||||
*/
|
||||
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
|
||||
si5351c_configure_multisynth(&si5351c, 0, p1, p2, p3, 1);
|
||||
|
||||
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
|
||||
si5351c_configure_multisynth(
|
||||
&si5351c,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0); //p1 doesn't matter
|
||||
|
||||
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
|
||||
si5351c_configure_multisynth(
|
||||
&si5351c,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0); //p1 doesn't matter
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
/* MS0/CLK0 is the source for the MAX5864 (AFE_CLK). */
|
||||
si5351c_configure_multisynth(&si5351c, 0, p1, p2, p3, 1);
|
||||
|
||||
/* MS1/CLK1 is the source for the FPGA (FPGA_CLK and SCT_CLK). */
|
||||
si5351c_configure_multisynth(&si5351c, 1, p1, p2, p3, 1);
|
||||
|
||||
/* Delay FPGA_CLK relative to AFE_CLK. */
|
||||
uint8_t phase_offset = 0;
|
||||
if (p1 < 2100) {
|
||||
phase_offset = (p1 >> 4) - 6;
|
||||
}
|
||||
si5351c_set_phase(&si5351c, 1, phase_offset);
|
||||
|
||||
if ((detected_revision() & ~BOARD_REV_GSG) < BOARD_REV_PRALINE_R1_1) {
|
||||
/*
|
||||
* On older boards FPGA_CLK is on CLK2 while SCT_CLK is on
|
||||
* CLK1. We configure both so that behavior is consistent with
|
||||
* newer boards that use CLK1 for both FPGA_CLK and SCT_CLK.
|
||||
*/
|
||||
si5351c_configure_multisynth(&si5351c, 2, p1, p2, p3, 1);
|
||||
si5351c_set_phase(&si5351c, 2, phase_offset);
|
||||
}
|
||||
|
||||
/* Reset PLL to synchronize output clock phase. */
|
||||
si5351c_reset_plls(&si5351c, SI5351C_PLL_MASK_A);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (streaming) {
|
||||
sgpio_cpld_stream_enable(&sgpio_config);
|
||||
}
|
||||
|
||||
return resultant_rate;
|
||||
}
|
||||
47
firmware/common/clock_gen.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
|
||||
typedef enum {
|
||||
CLOCK_SOURCE_HACKRF = 0,
|
||||
CLOCK_SOURCE_EXTERNAL = 1,
|
||||
CLOCK_SOURCE_PORTAPACK = 2,
|
||||
} clock_source_t;
|
||||
|
||||
void clock_gen_init(void);
|
||||
void clock_gen_shutdown(void);
|
||||
|
||||
clock_source_t activate_best_clock_source(void);
|
||||
|
||||
fp_28_36_t sample_rate_set(const fp_28_36_t sample_rate, const bool program);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2022 Great Scott Gadgets
|
||||
* Copyright 2022-2026 Great Scott Gadgets
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -19,8 +19,9 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "clkin.h"
|
||||
#include "clock_io.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/timer.h>
|
||||
|
|
@ -30,6 +31,15 @@
|
|||
#include <libopencm3/lpc43xx/creg.h>
|
||||
|
||||
#include "gpdma.h"
|
||||
#include "gpio.h"
|
||||
#include "platform_detect.h"
|
||||
#ifdef IS_NOT_PRALINE
|
||||
#include "sgpio.h"
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
#include "fpga.h"
|
||||
#include "platform_gpio.h"
|
||||
#endif
|
||||
|
||||
#define CLOCK_CYCLES_1_MS (204000)
|
||||
#define MEASUREMENT_WINDOW_MS (50)
|
||||
|
|
@ -114,4 +124,47 @@ void clkin_detect_init(void)
|
|||
uint32_t clkin_frequency(void)
|
||||
{
|
||||
return TIMER2_CR3 * (1000 / MEASUREMENT_WINDOW_MS);
|
||||
};
|
||||
}
|
||||
|
||||
void trigger_enable(const bool enable)
|
||||
{
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
gpio_write(sgpio_config.gpio_trigger_enable, enable);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
fpga_set_trigger_enable(&fpga, enable);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IS_PRALINE
|
||||
void clkin_ctrl_set(const clkin_signal_t signal)
|
||||
{
|
||||
gpio_write(platform_gpio()->clkin_ctrl, signal & 1);
|
||||
}
|
||||
|
||||
void p1_ctrl_set(const p1_ctrl_signal_t signal)
|
||||
{
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
|
||||
gpio_write(gpio->p1_ctrl0, signal & 1);
|
||||
gpio_write(gpio->p1_ctrl1, (signal >> 1) & 1);
|
||||
gpio_write(gpio->p1_ctrl2, (signal >> 2) & 1);
|
||||
}
|
||||
|
||||
void p2_ctrl_set(const p2_ctrl_signal_t signal)
|
||||
{
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
|
||||
gpio_write(gpio->p2_ctrl0, signal & 1);
|
||||
gpio_write(gpio->p2_ctrl1, (signal >> 1) & 1);
|
||||
}
|
||||
|
||||
void pps_out_set(const uint8_t value)
|
||||
{
|
||||
gpio_write(platform_gpio()->pps_out, value & 1);
|
||||
}
|
||||
#endif
|
||||
60
firmware/common/clock_io.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2022-2026 Great Scott Gadgets
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void clkin_detect_init(void);
|
||||
uint32_t clkin_frequency(void);
|
||||
|
||||
void trigger_enable(const bool enable);
|
||||
|
||||
#ifdef IS_PRALINE
|
||||
typedef enum {
|
||||
CLKIN_SIGNAL_P1 = 0,
|
||||
CLKIN_SIGNAL_P22 = 1,
|
||||
} clkin_signal_t;
|
||||
|
||||
typedef enum {
|
||||
P1_SIGNAL_TRIGGER_IN = 0,
|
||||
P1_SIGNAL_AUX_CLK1 = 1,
|
||||
P1_SIGNAL_CLKIN = 2,
|
||||
P1_SIGNAL_TRIGGER_OUT = 3,
|
||||
P1_SIGNAL_P22_CLKIN = 4,
|
||||
P1_SIGNAL_P2_5 = 5,
|
||||
P1_SIGNAL_NC = 6,
|
||||
P1_SIGNAL_AUX_CLK2 = 7,
|
||||
} p1_ctrl_signal_t;
|
||||
|
||||
typedef enum {
|
||||
P2_SIGNAL_CLK3 = 0,
|
||||
P2_SIGNAL_TRIGGER_IN = 2,
|
||||
P2_SIGNAL_TRIGGER_OUT = 3,
|
||||
} p2_ctrl_signal_t;
|
||||
|
||||
void clkin_ctrl_set(const clkin_signal_t value);
|
||||
void p1_ctrl_set(const p1_ctrl_signal_t signal);
|
||||
void p2_ctrl_set(const p2_ctrl_signal_t signal);
|
||||
|
||||
void pps_out_set(const uint8_t value);
|
||||
#endif
|
||||
|
|
@ -19,21 +19,52 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#if !defined(PRALINE)
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "cpld_jtag.h"
|
||||
#if !defined(PRALINE)
|
||||
|
||||
#include "platform_detect.h"
|
||||
#include "platform_gpio.h"
|
||||
#ifdef IS_NOT_PRALINE
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "xapp058/micro.h"
|
||||
#include "cpld_xc2c.h"
|
||||
#endif
|
||||
|
||||
#ifndef PRALINE
|
||||
#ifdef IS_NOT_PRALINE
|
||||
static refill_buffer_cb refill_buffer;
|
||||
static uint32_t xsvf_buffer_len, xsvf_pos;
|
||||
static unsigned char* xsvf_buffer;
|
||||
#endif
|
||||
|
||||
/* Driver instance. */
|
||||
jtag_gpio_t jtag_gpio_cpld = {};
|
||||
|
||||
jtag_t jtag_cpld = {
|
||||
.gpio = &jtag_gpio_cpld,
|
||||
};
|
||||
|
||||
void cpld_jtag_pin_setup(void)
|
||||
{
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
|
||||
jtag_gpio_cpld.gpio_tck = gpio->cpld_tck;
|
||||
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
jtag_gpio_cpld.gpio_tms = gpio->cpld_tms;
|
||||
jtag_gpio_cpld.gpio_tdi = gpio->cpld_tdi;
|
||||
jtag_gpio_cpld.gpio_tdo = gpio->cpld_tdo;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
jtag_gpio_cpld.gpio_pp_tms = gpio->cpld_pp_tms;
|
||||
jtag_gpio_cpld.gpio_pp_tdo = gpio->cpld_pp_tdo;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpld_jtag_take(jtag_t* const jtag)
|
||||
{
|
||||
const jtag_gpio_t* const gpio = jtag->gpio;
|
||||
|
|
@ -41,25 +72,37 @@ void cpld_jtag_take(jtag_t* const jtag)
|
|||
/* Set initial GPIO state to the voltages of the internal or external pull-ups/downs,
|
||||
* to avoid any glitches.
|
||||
*/
|
||||
#if (defined HACKRF_ONE || defined PRALINE)
|
||||
gpio_set(gpio->gpio_pp_tms);
|
||||
#endif
|
||||
gpio_clear(gpio->gpio_tck);
|
||||
#ifndef PRALINE
|
||||
gpio_set(gpio->gpio_tms);
|
||||
gpio_set(gpio->gpio_tdi);
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
gpio_set(gpio->gpio_pp_tms);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined HACKRF_ONE || defined PRALINE)
|
||||
/* Do not drive PortaPack-specific TMS pin initially, just to be cautious. */
|
||||
gpio_input(gpio->gpio_pp_tms);
|
||||
gpio_input(gpio->gpio_pp_tdo);
|
||||
gpio_clear(gpio->gpio_tck);
|
||||
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
gpio_set(gpio->gpio_tms);
|
||||
gpio_set(gpio->gpio_tdi);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
/* Do not drive PortaPack-specific TMS pin initially, just to be cautious. */
|
||||
gpio_input(gpio->gpio_pp_tms);
|
||||
gpio_input(gpio->gpio_pp_tdo);
|
||||
}
|
||||
#endif
|
||||
|
||||
gpio_output(gpio->gpio_tck);
|
||||
#ifndef PRALINE
|
||||
gpio_output(gpio->gpio_tms);
|
||||
gpio_output(gpio->gpio_tdi);
|
||||
gpio_input(gpio->gpio_tdo);
|
||||
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
gpio_output(gpio->gpio_tms);
|
||||
gpio_output(gpio->gpio_tdi);
|
||||
gpio_input(gpio->gpio_tdo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -70,20 +113,26 @@ void cpld_jtag_release(jtag_t* const jtag)
|
|||
/* Make all pins inputs when JTAG interface not active.
|
||||
* Let the pull-ups/downs do the work.
|
||||
*/
|
||||
#if (defined HACKRF_ONE || defined PRALINE)
|
||||
/* Do not drive PortaPack-specific pins, initially, just to be cautious. */
|
||||
gpio_input(gpio->gpio_pp_tms);
|
||||
gpio_input(gpio->gpio_pp_tdo);
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
/* Do not drive PortaPack-specific pins, initially, just to be cautious. */
|
||||
gpio_input(gpio->gpio_pp_tms);
|
||||
gpio_input(gpio->gpio_pp_tdo);
|
||||
}
|
||||
#endif
|
||||
|
||||
gpio_input(gpio->gpio_tck);
|
||||
#ifndef PRALINE
|
||||
gpio_input(gpio->gpio_tms);
|
||||
gpio_input(gpio->gpio_tdi);
|
||||
gpio_input(gpio->gpio_tdo);
|
||||
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
gpio_input(gpio->gpio_tms);
|
||||
gpio_input(gpio->gpio_tdi);
|
||||
gpio_input(gpio->gpio_tdo);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef PRALINE
|
||||
#ifdef IS_NOT_PRALINE
|
||||
/* return 0 if success else return error code see xsvfExecute() */
|
||||
int cpld_jtag_program(
|
||||
jtag_t* const jtag,
|
||||
|
|
@ -114,4 +163,16 @@ unsigned char cpld_jtag_get_next_byte(void)
|
|||
xsvf_pos++;
|
||||
return byte;
|
||||
}
|
||||
|
||||
bool cpld_jtag_sram_load(jtag_t* const jtag)
|
||||
{
|
||||
cpld_jtag_take(jtag);
|
||||
cpld_xc2c64a_jtag_sram_write(jtag, &cpld_hackrf_program_sram);
|
||||
const bool success = cpld_xc2c64a_jtag_sram_verify(
|
||||
jtag,
|
||||
&cpld_hackrf_program_sram,
|
||||
&cpld_hackrf_verify);
|
||||
cpld_jtag_release(jtag);
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,32 +19,33 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CPLD_JTAG_H__
|
||||
#define __CPLD_JTAG_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
typedef struct jtag_gpio_t {
|
||||
typedef struct {
|
||||
gpio_t gpio_tck;
|
||||
#ifndef PRALINE
|
||||
#ifdef IS_NOT_PRALINE
|
||||
gpio_t gpio_tms;
|
||||
gpio_t gpio_tdi;
|
||||
gpio_t gpio_tdo;
|
||||
#endif
|
||||
#if (defined HACKRF_ONE || defined PRALINE)
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
gpio_t gpio_pp_tms;
|
||||
gpio_t gpio_pp_tdo;
|
||||
#endif
|
||||
} jtag_gpio_t;
|
||||
|
||||
typedef struct jtag_t {
|
||||
typedef struct {
|
||||
jtag_gpio_t* const gpio;
|
||||
} jtag_t;
|
||||
|
||||
typedef void (*refill_buffer_cb)(void);
|
||||
|
||||
void cpld_jtag_pin_setup(void);
|
||||
void cpld_jtag_take(jtag_t* const jtag);
|
||||
void cpld_jtag_release(jtag_t* const jtag);
|
||||
|
||||
|
|
@ -59,5 +60,8 @@ int cpld_jtag_program(
|
|||
unsigned char* const buffer,
|
||||
refill_buffer_cb refill);
|
||||
unsigned char cpld_jtag_get_next_byte(void);
|
||||
bool cpld_jtag_sram_load(jtag_t* const jtag);
|
||||
|
||||
#endif //__CPLD_JTAG_H__
|
||||
/* Driver instance. */
|
||||
extern jtag_gpio_t jtag_gpio_cpld;
|
||||
extern jtag_t jtag_cpld;
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CPLD_XC2C_H__
|
||||
#define __CPLD_XC2C_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -69,5 +68,3 @@ bool cpld_xc2c64a_jtag_sram_verify(
|
|||
extern const cpld_xc2c64a_program_t cpld_hackrf_program_sram;
|
||||
extern const cpld_xc2c64a_verify_t cpld_hackrf_verify;
|
||||
extern const cpld_xc2c64a_row_addresses_t cpld_hackrf_row_addresses;
|
||||
|
||||
#endif /*__CPLD_XC2C_H__*/
|
||||
|
|
|
|||
262
firmware/common/cpu_clock.c
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "cpu_clock.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/cgu.h>
|
||||
#if defined(IS_JAWBREAKER) || defined(IS_HACKRF_ONE) || defined(IS_PRALINE)
|
||||
#include <libopencm3/lpc43xx/ccu.h>
|
||||
#endif
|
||||
|
||||
#include "delay.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "i2c_lpc.h"
|
||||
#include "si5351c.h"
|
||||
|
||||
/* We start with the CPU clock at 96MHz */
|
||||
unsigned int cpu_clock_mhz = 96;
|
||||
|
||||
/*
|
||||
Configure PLL1 (Main MCU Clock) to max speed (204MHz).
|
||||
Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1.
|
||||
This function shall be called after cpu_clock_init().
|
||||
*/
|
||||
static void cpu_clock_pll1_max_speed(void)
|
||||
{
|
||||
uint32_t reg_val;
|
||||
|
||||
/* This function implements the sequence recommended in:
|
||||
* UM10503 Rev 2.4 (Aug 2018), section 13.2.1.1, page 167. */
|
||||
|
||||
/* 1. Select the IRC as BASE_M4_CLK source. */
|
||||
reg_val = CGU_BASE_M4_CLK;
|
||||
reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK;
|
||||
reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_IRC) | CGU_BASE_M4_CLK_AUTOBLOCK(1);
|
||||
CGU_BASE_M4_CLK = reg_val;
|
||||
|
||||
/* CPU is now at 12MHz */
|
||||
cpu_clock_mhz = 12;
|
||||
|
||||
/* 2. Enable the crystal oscillator. */
|
||||
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE_MASK;
|
||||
|
||||
/* 3. Wait 250us. */
|
||||
delay_us(250);
|
||||
|
||||
/* 4. Set the AUTOBLOCK bit. */
|
||||
CGU_PLL1_CTRL |= CGU_PLL1_CTRL_AUTOBLOCK(1);
|
||||
|
||||
/* 5. Reconfigure PLL1 to produce the final output frequency, with the
|
||||
* crystal oscillator as clock source. */
|
||||
reg_val = CGU_PLL1_CTRL;
|
||||
// clang-format off
|
||||
reg_val &= ~( CGU_PLL1_CTRL_CLK_SEL_MASK |
|
||||
CGU_PLL1_CTRL_PD_MASK |
|
||||
CGU_PLL1_CTRL_FBSEL_MASK |
|
||||
CGU_PLL1_CTRL_BYPASS_MASK |
|
||||
CGU_PLL1_CTRL_DIRECT_MASK |
|
||||
CGU_PLL1_CTRL_PSEL_MASK |
|
||||
CGU_PLL1_CTRL_MSEL_MASK |
|
||||
CGU_PLL1_CTRL_NSEL_MASK );
|
||||
/* Set PLL1 up to 12MHz * 17 = 204MHz.
|
||||
* Direct mode: FCLKOUT = FCCO = M*(FCLKIN/N) */
|
||||
reg_val |= CGU_PLL1_CTRL_CLK_SEL(CGU_SRC_XTAL) |
|
||||
CGU_PLL1_CTRL_PSEL(0) |
|
||||
CGU_PLL1_CTRL_NSEL(0) |
|
||||
CGU_PLL1_CTRL_MSEL(16) |
|
||||
CGU_PLL1_CTRL_FBSEL(0) |
|
||||
CGU_PLL1_CTRL_DIRECT(1);
|
||||
// clang-format on
|
||||
CGU_PLL1_CTRL = reg_val;
|
||||
|
||||
/* 6. Wait for PLL1 to lock. */
|
||||
while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK_MASK)) {}
|
||||
|
||||
/* 7. Set the PLL1 P-divider to divide by 2 (DIRECT=0, PSEL=0). */
|
||||
CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_DIRECT_MASK;
|
||||
|
||||
/* 8. Select PLL1 as BASE_M4_CLK source. */
|
||||
reg_val = CGU_BASE_M4_CLK;
|
||||
reg_val &= ~CGU_BASE_M4_CLK_CLK_SEL_MASK;
|
||||
reg_val |= CGU_BASE_M4_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
CGU_BASE_M4_CLK = reg_val;
|
||||
|
||||
/* CPU is now at 102MHz */
|
||||
cpu_clock_mhz = 102;
|
||||
|
||||
/* 9. Wait 50us. */
|
||||
delay_us(50);
|
||||
|
||||
/* 10. Set the PLL1 P-divider to direct output mode (DIRECT=1). */
|
||||
CGU_PLL1_CTRL |= CGU_PLL1_CTRL_DIRECT_MASK;
|
||||
|
||||
/* CPU is now at 204MHz */
|
||||
cpu_clock_mhz = 204;
|
||||
}
|
||||
|
||||
/* clock startup for LPC4320 configure PLL1 to max speed (204MHz).
|
||||
Note: PLL1 clock is used by M4/M0 core, Peripheral, APB1. */
|
||||
void cpu_clock_init(void)
|
||||
{
|
||||
/* use IRC as clock source for APB1 (including I2C0) */
|
||||
CGU_BASE_APB1_CLK = CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_IRC);
|
||||
|
||||
/* use IRC as clock source for APB3 */
|
||||
CGU_BASE_APB3_CLK = CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_IRC);
|
||||
|
||||
//FIXME disable I2C
|
||||
/* Kick I2C0 down to 400kHz when we switch over to APB1 clock = 204MHz */
|
||||
i2c_bus_start(si5351c.bus, &i2c_config_fast_clock);
|
||||
|
||||
/*
|
||||
* 12MHz clock is entering LPC XTAL1/OSC input now.
|
||||
* On HackRF One and Jawbreaker, there is a 12 MHz crystal at the LPC.
|
||||
* Set up PLL1 to run from XTAL1 input.
|
||||
*/
|
||||
|
||||
//FIXME a lot of the details here should be in a CGU driver
|
||||
|
||||
/* set xtal oscillator to low frequency mode */
|
||||
CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF_MASK;
|
||||
|
||||
cpu_clock_pll1_max_speed();
|
||||
|
||||
/* use XTAL_OSC as clock source for APB1 */
|
||||
CGU_BASE_APB1_CLK =
|
||||
CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_XTAL);
|
||||
|
||||
/* use XTAL_OSC as clock source for APB3 */
|
||||
CGU_BASE_APB3_CLK =
|
||||
CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_XTAL);
|
||||
|
||||
/* use XTAL_OSC as clock source for PLL0USB */
|
||||
CGU_PLL0USB_CTRL = CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_AUTOBLOCK(1) |
|
||||
CGU_PLL0USB_CTRL_CLK_SEL(CGU_SRC_XTAL);
|
||||
while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK) {}
|
||||
|
||||
/* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */
|
||||
/* Values from User Manual v1.4 Table 94, for 12MHz oscillator. */
|
||||
CGU_PLL0USB_MDIV = 0x06167FFA;
|
||||
CGU_PLL0USB_NP_DIV = 0x00302062;
|
||||
CGU_PLL0USB_CTRL |=
|
||||
(CGU_PLL0USB_CTRL_PD(1) | CGU_PLL0USB_CTRL_DIRECTI(1) |
|
||||
CGU_PLL0USB_CTRL_DIRECTO(1) | CGU_PLL0USB_CTRL_CLKEN(1));
|
||||
|
||||
/* power on PLL0USB and wait until stable */
|
||||
CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD_MASK;
|
||||
while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK_MASK)) {}
|
||||
|
||||
/* use PLL0USB as clock source for USB0 */
|
||||
CGU_BASE_USB0_CLK = CGU_BASE_USB0_CLK_AUTOBLOCK(1) |
|
||||
CGU_BASE_USB0_CLK_CLK_SEL(CGU_SRC_PLL0USB);
|
||||
|
||||
/* Switch peripheral clock over to use PLL1 (204MHz) */
|
||||
CGU_BASE_PERIPH_CLK = CGU_BASE_PERIPH_CLK_AUTOBLOCK(1) |
|
||||
CGU_BASE_PERIPH_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
/* Switch APB1 clock over to use PLL1 (204MHz) */
|
||||
CGU_BASE_APB1_CLK =
|
||||
CGU_BASE_APB1_CLK_AUTOBLOCK(1) | CGU_BASE_APB1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
/* Switch APB3 clock over to use PLL1 (204MHz) */
|
||||
CGU_BASE_APB3_CLK =
|
||||
CGU_BASE_APB3_CLK_AUTOBLOCK(1) | CGU_BASE_APB3_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
CGU_BASE_SSP0_CLK =
|
||||
CGU_BASE_SSP0_CLK_AUTOBLOCK(1) | CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
CGU_BASE_SSP1_CLK =
|
||||
CGU_BASE_SSP1_CLK_AUTOBLOCK(1) | CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1);
|
||||
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
/* Disable unused clocks */
|
||||
/* Start with PLLs */
|
||||
CGU_PLL0AUDIO_CTRL = CGU_PLL0AUDIO_CTRL_PD(1);
|
||||
|
||||
/* Dividers */
|
||||
CGU_IDIVA_CTRL = CGU_IDIVA_CTRL_PD(1);
|
||||
CGU_IDIVB_CTRL = CGU_IDIVB_CTRL_PD(1);
|
||||
CGU_IDIVC_CTRL = CGU_IDIVC_CTRL_PD(1);
|
||||
CGU_IDIVD_CTRL = CGU_IDIVD_CTRL_PD(1);
|
||||
CGU_IDIVE_CTRL = CGU_IDIVE_CTRL_PD(1);
|
||||
|
||||
/* Base clocks */
|
||||
CGU_BASE_SPIFI_CLK =
|
||||
CGU_BASE_SPIFI_CLK_PD(1); /* SPIFI is only used at boot */
|
||||
CGU_BASE_USB1_CLK =
|
||||
CGU_BASE_USB1_CLK_PD(1); /* USB1 is not exposed on HackRF */
|
||||
CGU_BASE_PHY_RX_CLK = CGU_BASE_PHY_RX_CLK_PD(1);
|
||||
CGU_BASE_PHY_TX_CLK = CGU_BASE_PHY_TX_CLK_PD(1);
|
||||
CGU_BASE_LCD_CLK = CGU_BASE_LCD_CLK_PD(1);
|
||||
CGU_BASE_VADC_CLK = CGU_BASE_VADC_CLK_PD(1);
|
||||
CGU_BASE_SDIO_CLK = CGU_BASE_SDIO_CLK_PD(1);
|
||||
CGU_BASE_UART0_CLK = CGU_BASE_UART0_CLK_PD(1);
|
||||
CGU_BASE_UART1_CLK = CGU_BASE_UART1_CLK_PD(1);
|
||||
CGU_BASE_UART2_CLK = CGU_BASE_UART2_CLK_PD(1);
|
||||
CGU_BASE_UART3_CLK = CGU_BASE_UART3_CLK_PD(1);
|
||||
CGU_BASE_OUT_CLK = CGU_BASE_OUT_CLK_PD(1);
|
||||
CGU_BASE_AUDIO_CLK = CGU_BASE_AUDIO_CLK_PD(1);
|
||||
CGU_BASE_CGU_OUT0_CLK = CGU_BASE_CGU_OUT0_CLK_PD(1);
|
||||
CGU_BASE_CGU_OUT1_CLK = CGU_BASE_CGU_OUT1_CLK_PD(1);
|
||||
|
||||
/* Disable unused peripheral clocks */
|
||||
CCU1_CLK_APB1_CAN1_CFG = 0;
|
||||
CCU1_CLK_APB1_I2S_CFG = 0;
|
||||
CCU1_CLK_APB1_MOTOCONPWM_CFG = 0;
|
||||
//CCU1_CLK_APB3_ADC0_CFG = 0;
|
||||
CCU1_CLK_APB3_ADC1_CFG = 0;
|
||||
CCU1_CLK_APB3_CAN0_CFG = 0;
|
||||
CCU1_CLK_APB3_DAC_CFG = 0;
|
||||
//CCU1_CLK_M4_DMA_CFG = 0;
|
||||
CCU1_CLK_M4_EMC_CFG = 0;
|
||||
CCU1_CLK_M4_EMCDIV_CFG = 0;
|
||||
CCU1_CLK_M4_ETHERNET_CFG = 0;
|
||||
CCU1_CLK_M4_LCD_CFG = 0;
|
||||
CCU1_CLK_M4_QEI_CFG = 0;
|
||||
CCU1_CLK_M4_RITIMER_CFG = 0;
|
||||
// CCU1_CLK_M4_SCT_CFG = 0;
|
||||
CCU1_CLK_M4_SDIO_CFG = 0;
|
||||
CCU1_CLK_M4_SPIFI_CFG = 0;
|
||||
CCU1_CLK_M4_TIMER0_CFG = 0;
|
||||
//CCU1_CLK_M4_TIMER1_CFG = 0;
|
||||
//CCU1_CLK_M4_TIMER2_CFG = 0;
|
||||
CCU1_CLK_M4_TIMER3_CFG = 0;
|
||||
CCU1_CLK_M4_UART1_CFG = 0;
|
||||
CCU1_CLK_M4_USART0_CFG = 0;
|
||||
CCU1_CLK_M4_USART2_CFG = 0;
|
||||
CCU1_CLK_M4_USART3_CFG = 0;
|
||||
CCU1_CLK_M4_USB1_CFG = 0;
|
||||
CCU1_CLK_M4_VADC_CFG = 0;
|
||||
// CCU1_CLK_SPIFI_CFG = 0;
|
||||
// CCU1_CLK_USB1_CFG = 0;
|
||||
// CCU1_CLK_VADC_CFG = 0;
|
||||
// CCU2_CLK_APB0_UART1_CFG = 0;
|
||||
// CCU2_CLK_APB0_USART0_CFG = 0;
|
||||
// CCU2_CLK_APB2_USART2_CFG = 0;
|
||||
// CCU2_CLK_APB2_USART3_CFG = 0;
|
||||
// CCU2_CLK_APLL_CFG = 0;
|
||||
// CCU2_CLK_SDIO_CFG = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
35
firmware/common/cpu_clock.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cpu_clock_init(void);
|
||||
|
||||
// Current clock speed in MHz, updated on clock changes.
|
||||
extern unsigned int cpu_clock_mhz;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CRC_H__
|
||||
#define __CRC_H__
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -35,5 +34,3 @@ typedef struct {
|
|||
void crc32_init(crc32_t* const crc);
|
||||
void crc32_update(crc32_t* const crc, const uint8_t* const data, const size_t byte_count);
|
||||
uint32_t crc32_digest(const crc32_t* const crc);
|
||||
|
||||
#endif //__CRC_H__
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "da7219.h"
|
||||
#include "hackrf_core.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "i2c_lpc.h"
|
||||
|
||||
#define DA7219_REG_CHIP_ID1 0x81
|
||||
#define DA7219_REG_CHIP_ID2 0x82
|
||||
|
|
|
|||
|
|
@ -19,13 +19,10 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __DA7219_H
|
||||
#define __DA7219_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define DA7219_ADDRESS 0x1A
|
||||
|
||||
bool da7219_detect(void);
|
||||
|
||||
#endif /* __DA7219_H */
|
||||
|
|
|
|||
|
|
@ -21,16 +21,9 @@
|
|||
|
||||
#include "delay.h"
|
||||
|
||||
void delay(uint32_t duration)
|
||||
{
|
||||
uint32_t i;
|
||||
#include "cpu_clock.h"
|
||||
|
||||
for (i = 0; i < duration; i++) {
|
||||
__asm__("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void delay_us_at_mhz(uint32_t us, uint32_t mhz)
|
||||
static void delay_us_at_mhz(uint32_t us, uint32_t mhz)
|
||||
{
|
||||
#if defined(LPC43XX_M4)
|
||||
// The loop below takes 3 cycles per iteration.
|
||||
|
|
@ -52,3 +45,13 @@ void delay_us_at_mhz(uint32_t us, uint32_t mhz)
|
|||
#error "No delay loop implementation"
|
||||
#endif
|
||||
}
|
||||
|
||||
void delay_us(uint32_t us)
|
||||
{
|
||||
delay_us_at_mhz(us, cpu_clock_mhz);
|
||||
}
|
||||
|
||||
void delay_ms(uint32_t ms)
|
||||
{
|
||||
delay_us_at_mhz(ms * 1000, cpu_clock_mhz);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __DELAY_H
|
||||
#define __DELAY_H
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -28,7 +27,9 @@ extern "C" {
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
void delay(uint32_t duration);
|
||||
void delay_us_at_mhz(uint32_t us, uint32_t mhz);
|
||||
void delay_us(uint32_t us);
|
||||
void delay_ms(uint32_t ms);
|
||||
|
||||
#endif /* __DELAY_H */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FAULT_HANDLER__
|
||||
#define __FAULT_HANDLER__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -30,9 +29,7 @@
|
|||
// TODO: Move all this to a Cortex-M(?) include file, since these
|
||||
// structures are supposedly the same between processors (to an
|
||||
// undetermined extent).
|
||||
typedef struct armv7m_scb_t armv7m_scb_t;
|
||||
|
||||
struct armv7m_scb_t {
|
||||
typedef struct {
|
||||
volatile const uint32_t CPUID;
|
||||
volatile uint32_t ICSR;
|
||||
volatile uint32_t VTOR;
|
||||
|
|
@ -64,12 +61,10 @@ struct armv7m_scb_t {
|
|||
volatile const uint32_t ID_ISAR4;
|
||||
volatile const uint32_t __reserved_0x74_0x87[5];
|
||||
volatile uint32_t CPACR;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed)) armv7m_scb_t;
|
||||
|
||||
static armv7m_scb_t* const SCB = (armv7m_scb_t*) SCB_BASE;
|
||||
|
||||
#define SCB_HFSR_DEBUGEVT (1 << 31)
|
||||
#define SCB_HFSR_FORCED (1 << 30)
|
||||
#define SCB_HFSR_VECTTBL (1 << 1)
|
||||
|
||||
#endif //__FAULT_HANDLER__
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#define SUPPORTED_PLATFORM PLATFORM_RAD1O
|
||||
#elif PRALINE
|
||||
#define SUPPORTED_PLATFORM PLATFORM_PRALINE
|
||||
#elif UNIVERSAL
|
||||
#define SUPPORTED_PLATFORM \
|
||||
(PLATFORM_PRALINE | PLATFORM_HACKRF1_OG | PLATFORM_HACKRF1_R9)
|
||||
#else
|
||||
#define SUPPORTED_PLATFORM 0
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef FIRMWARE_INFO_H
|
||||
#define FIRMWARE_INFO_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -33,5 +32,3 @@ struct firmware_info_t {
|
|||
} __attribute__((packed, aligned(1)));
|
||||
|
||||
extern const struct firmware_info_t firmware_info;
|
||||
|
||||
#endif
|
||||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FIXED_POINT_H__
|
||||
#define __FIXED_POINT_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -30,7 +29,45 @@ typedef uint64_t fp_40_24_t;
|
|||
/* one million in 40.24 fixed-point */
|
||||
#define FP_ONE_MHZ ((1000ULL * 1000ULL) << 24)
|
||||
|
||||
/* one thousand in 40.24 fixed-point */
|
||||
#define FP_ONE_KHZ ((1000ULL) << 24)
|
||||
|
||||
/* one in 40.24 fixed-point */
|
||||
#define FP_ONE_HZ (1 << 24)
|
||||
|
||||
#endif /*__FIXED_POINT_H__*/
|
||||
#define FP_MHZ(mhz) (mhz##ULL * FP_ONE_MHZ)
|
||||
#define FP_KHZ(khz) (khz##ULL * FP_ONE_KHZ)
|
||||
#define FP_HZ(hz) (hz##ULL * FP_ONE_HZ)
|
||||
|
||||
/* 28.36 fixed-point */
|
||||
typedef uint64_t fp_28_36_t;
|
||||
|
||||
/* one million in 28.36 fixed-point */
|
||||
#define SR_FP_ONE_MHZ ((1000ULL * 1000ULL) << 36)
|
||||
|
||||
/* one thousand in 28.36 fixed-point */
|
||||
#define SR_FP_ONE_KHZ (1000ULL << 36)
|
||||
|
||||
/* one in 28.36 fixed-point */
|
||||
#define SR_FP_ONE_HZ (1ULL << 36)
|
||||
|
||||
#define SR_FP_MHZ(mhz) (mhz##ULL * SR_FP_ONE_MHZ)
|
||||
#define SR_FP_KHZ(khz) (khz##ULL * SR_FP_ONE_KHZ)
|
||||
#define SR_FP_HZ(hz) (hz##ULL * SR_FP_ONE_HZ)
|
||||
|
||||
/* 1.63 fixed point */
|
||||
typedef uint64_t fp_1_63_t;
|
||||
|
||||
#define FRAC_ONE (1ULL << 63)
|
||||
|
||||
/* one hundredth in 1.63 fixed point */
|
||||
#define FRAC_ONE_PERCENT (FRAC_ONE / (100ULL))
|
||||
|
||||
/* one thousandth in 1.63 fixed point */
|
||||
#define FRAC_ONE_PERMILLE (FRAC_ONE / (1000ULL))
|
||||
|
||||
/* one millionth in 1.63 fixed point */
|
||||
#define FRAC_ONE_PPM (FRAC_ONE / (1000000ULL))
|
||||
|
||||
/* one billionth in 1.63 fixed point */
|
||||
#define FRAC_ONE_PPB (FRAC_ONE / (1000000000ULL))
|
||||
|
|
|
|||
|
|
@ -20,13 +20,17 @@
|
|||
*/
|
||||
|
||||
#include "fpga.h"
|
||||
#include "fpga_regs.def"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "fpga_regs.def"
|
||||
#include "hackrf_core.h"
|
||||
#include "ice40_spi.h"
|
||||
|
||||
/* Driver instance. */
|
||||
fpga_driver_t fpga = {
|
||||
.bus = &ice40,
|
||||
};
|
||||
|
||||
/* Set up all registers according to the loaded bitstream's defaults. */
|
||||
void fpga_init(fpga_driver_t* const drv)
|
||||
{
|
||||
|
|
@ -52,9 +56,7 @@ void fpga_setup(fpga_driver_t* const drv)
|
|||
uint8_t fpga_reg_read(fpga_driver_t* const drv, uint8_t r)
|
||||
{
|
||||
uint8_t v;
|
||||
ssp1_set_mode_ice40();
|
||||
v = ice40_spi_read(drv->bus, r);
|
||||
ssp1_set_mode_max283x();
|
||||
drv->regs[r] = v;
|
||||
return v;
|
||||
}
|
||||
|
|
@ -62,9 +64,7 @@ uint8_t fpga_reg_read(fpga_driver_t* const drv, uint8_t r)
|
|||
void fpga_reg_write(fpga_driver_t* const drv, uint8_t r, uint8_t v)
|
||||
{
|
||||
drv->regs[r] = v;
|
||||
ssp1_set_mode_ice40();
|
||||
ice40_spi_write(drv->bus, r, v);
|
||||
ssp1_set_mode_max283x();
|
||||
FPGA_REG_SET_CLEAN(drv, r);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FPGA_H
|
||||
#define __FPGA_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -37,14 +36,11 @@ typedef enum {
|
|||
FPGA_QUARTER_SHIFT_MODE_DOWN = 0b01,
|
||||
} fpga_quarter_shift_mode_t;
|
||||
|
||||
struct fpga_driver_t; // IWYU pragma: keep - fixed in #1704
|
||||
typedef struct fpga_driver_t fpga_driver_t;
|
||||
|
||||
struct fpga_driver_t {
|
||||
typedef struct {
|
||||
ice40_spi_driver_t* bus;
|
||||
uint8_t regs[FPGA_NUM_REGS];
|
||||
uint8_t regs_dirty;
|
||||
};
|
||||
} fpga_driver_t;
|
||||
|
||||
struct fpga_loader_t {
|
||||
/* Start address added as an offset to all read() calls. */
|
||||
|
|
@ -95,4 +91,5 @@ bool fpga_spi_selftest(void);
|
|||
bool fpga_sgpio_selftest(void);
|
||||
bool fpga_if_xcvr_selftest(void);
|
||||
|
||||
#endif // __FPGA_H
|
||||
/* Driver instance. */
|
||||
extern fpga_driver_t fpga;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "fpga.h"
|
||||
#include "hackrf_core.h"
|
||||
#include "ice40_spi.h"
|
||||
#include "lz4_blk.h"
|
||||
#include "selftest.h"
|
||||
|
|
@ -86,7 +85,6 @@ bool fpga_image_load(struct fpga_loader_t* loader, unsigned int index)
|
|||
// A callback function is used by the FPGA programmer
|
||||
// to obtain consecutive gateware chunks.
|
||||
ice40_spi_target_init(&ice40);
|
||||
ssp1_set_mode_ice40();
|
||||
struct fpga_image_read_ctx fpga_image_ctx = {
|
||||
.loader = loader,
|
||||
.addr = loader->start_addr + bitstream_offset,
|
||||
|
|
@ -96,7 +94,6 @@ bool fpga_image_load(struct fpga_loader_t* loader, unsigned int index)
|
|||
loader->out_buffer,
|
||||
fpga_image_read_block_cb,
|
||||
&fpga_image_ctx);
|
||||
ssp1_set_mode_max283x();
|
||||
|
||||
// Update selftest result.
|
||||
selftest.fpga_image_load = success ? PASSED : FAILED;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* -*- mode: c -*-
|
||||
*
|
||||
* Copyright 2012 Michael Ossmann
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2025-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -21,8 +21,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FPGA_REGS_DEF
|
||||
#define __FPGA_REGS_DEF
|
||||
#pragma once
|
||||
|
||||
#define FPGA_REG_SET_CLEAN(_d, _r) (_d->regs_dirty &= ~(1UL<<_r))
|
||||
#define FPGA_REG_SET_DIRTY(_d, _r) (_d->regs_dirty |= (1UL<<_r))
|
||||
|
|
@ -71,5 +70,3 @@ __MREG__(FPGA_STANDARD_TX_INTRP, 5, 0, 3)
|
|||
|
||||
/* REG 06 (6): TX_PSTEP */
|
||||
__MREG__(FPGA_STANDARD_TX_PSTEP, 6, 0, 8)
|
||||
|
||||
#endif // __FPGA_REGS_DEF
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2025-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -23,10 +23,10 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "clock_gen.h"
|
||||
#include "delay.h"
|
||||
#include "fixed_point.h"
|
||||
#include "fpga.h"
|
||||
#include "hackrf_core.h"
|
||||
#include "ice40_spi.h"
|
||||
#include "m0_state.h"
|
||||
#include "max283x.h"
|
||||
|
|
@ -36,8 +36,8 @@
|
|||
#include "streaming.h"
|
||||
|
||||
// USB buffer used during selftests.
|
||||
#define USB_BULK_BUFFER_SIZE 0x8000
|
||||
extern uint8_t usb_bulk_buffer[USB_BULK_BUFFER_SIZE];
|
||||
#define USB_SAMP_BUFFER_SIZE 0x8000
|
||||
extern uint8_t usb_samp_buffer[USB_SAMP_BUFFER_SIZE];
|
||||
|
||||
static int rx_samples(const unsigned int num_samples, uint32_t max_cycles)
|
||||
{
|
||||
|
|
@ -71,10 +71,8 @@ bool fpga_spi_selftest(void)
|
|||
// Test writing a register and reading it back.
|
||||
uint8_t reg = 6;
|
||||
uint8_t write_value = 0xA5;
|
||||
ssp1_set_mode_ice40();
|
||||
ice40_spi_write(&ice40, reg, write_value);
|
||||
uint8_t read_value = ice40_spi_read(&ice40, reg);
|
||||
ssp1_set_mode_max283x();
|
||||
|
||||
// Update selftest result.
|
||||
selftest.fpga_spi = (read_value == write_value) ? PASSED : FAILED;
|
||||
|
|
@ -114,10 +112,10 @@ bool fpga_sgpio_selftest(void)
|
|||
fpga_set_prbs_enable(&fpga, false);
|
||||
|
||||
// Generate sequence from first value and compare.
|
||||
bool seq_in_sync = (usb_bulk_buffer[0] != 0);
|
||||
uint8_t seq = lfsr_advance(usb_bulk_buffer[0]);
|
||||
bool seq_in_sync = (usb_samp_buffer[0] != 0);
|
||||
uint8_t seq = lfsr_advance(usb_samp_buffer[0]);
|
||||
for (int i = 1; i < 512; ++i) {
|
||||
if (usb_bulk_buffer[i] != seq) {
|
||||
if (usb_samp_buffer[i] != seq) {
|
||||
seq_in_sync = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -188,7 +186,7 @@ bool fpga_if_xcvr_selftest(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
const size_t num_samples = USB_BULK_BUFFER_SIZE / 2;
|
||||
const size_t num_samples = USB_SAMP_BUFFER_SIZE / 2;
|
||||
|
||||
// Set common RX path and gateware settings for the measurements.
|
||||
fpga_set_tx_nco_pstep(&fpga, 64); // NCO phase increment
|
||||
|
|
@ -196,56 +194,56 @@ bool fpga_if_xcvr_selftest(void)
|
|||
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_RX_CALIBRATION);
|
||||
max283x_set_lna_gain(&max283x, 16);
|
||||
max283x_set_vga_gain(&max283x, 36);
|
||||
max283x_set_frequency(&max283x, 2500000000);
|
||||
max283x_set_frequency(&max283x, FP_MHZ(2500), true);
|
||||
|
||||
// Capture 1: 4 Msps, tone at 0.5 MHz, narrowband filter OFF
|
||||
sample_rate_set(4ULL * FP_ONE_MHZ, true);
|
||||
delay_us_at_mhz(1000, 204);
|
||||
sample_rate_set(SR_FP_MHZ(4), true);
|
||||
delay_ms(1);
|
||||
if (rx_samples(num_samples, 2000000) == -1) {
|
||||
timeout = true;
|
||||
}
|
||||
measure_tone(
|
||||
(int8_t*) usb_bulk_buffer,
|
||||
(int8_t*) usb_samp_buffer,
|
||||
num_samples,
|
||||
&selftest.xcvr_measurements[0]);
|
||||
|
||||
// Capture 2: 4 Msps, tone at 0.5 MHz, narrowband filter ON
|
||||
narrowband_filter_set(1);
|
||||
delay_us_at_mhz(1000, 204);
|
||||
delay_ms(1);
|
||||
if (rx_samples(num_samples, 2000000) == -1) {
|
||||
timeout = true;
|
||||
}
|
||||
measure_tone(
|
||||
(int8_t*) usb_bulk_buffer,
|
||||
(int8_t*) usb_samp_buffer,
|
||||
num_samples,
|
||||
&selftest.xcvr_measurements[1]);
|
||||
|
||||
// Capture 3: 20 Msps, tone at 5 MHz, narrowband filter OFF
|
||||
fpga_set_tx_nco_pstep(&fpga, 255);
|
||||
sample_rate_set(20ULL * FP_ONE_MHZ, true);
|
||||
sample_rate_set(SR_FP_MHZ(20), true);
|
||||
narrowband_filter_set(0);
|
||||
delay_us_at_mhz(1000, 204);
|
||||
delay_ms(1);
|
||||
if (rx_samples(num_samples, 2000000) == -1) {
|
||||
timeout = true;
|
||||
}
|
||||
measure_tone(
|
||||
(int8_t*) usb_bulk_buffer,
|
||||
(int8_t*) usb_samp_buffer,
|
||||
num_samples,
|
||||
&selftest.xcvr_measurements[2]);
|
||||
|
||||
// Capture 4: 20 Msps, tone at 5 MHz, narrowband filter ON
|
||||
narrowband_filter_set(1);
|
||||
delay_us_at_mhz(1000, 204);
|
||||
delay_ms(1);
|
||||
if (rx_samples(num_samples, 2000000) == -1) {
|
||||
timeout = true;
|
||||
}
|
||||
measure_tone(
|
||||
(int8_t*) usb_bulk_buffer,
|
||||
(int8_t*) usb_samp_buffer,
|
||||
num_samples,
|
||||
&selftest.xcvr_measurements[3]);
|
||||
|
||||
// Restore default settings.
|
||||
sample_rate_set(10ULL * FP_ONE_MHZ, true);
|
||||
sample_rate_set(SR_FP_MHZ(10), true);
|
||||
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF);
|
||||
narrowband_filter_set(0);
|
||||
fpga_init(&fpga);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GPDMA_H__
|
||||
#define __GPDMA_H__
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -40,5 +39,3 @@ void gpdma_lli_enable_interrupt(gpdma_lli_t* const lli);
|
|||
|
||||
void gpdma_lli_create_loop(gpdma_lli_t* const lli, const size_t lli_count);
|
||||
void gpdma_lli_create_oneshot(gpdma_lli_t* const lli, const size_t lli_count);
|
||||
|
||||
#endif /*__GPDMA_H__*/
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GPIO_H__
|
||||
#define __GPIO_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
|
@ -35,5 +34,3 @@ void gpio_output(gpio_t gpio);
|
|||
void gpio_input(gpio_t gpio);
|
||||
void gpio_write(gpio_t gpio, const bool value);
|
||||
bool gpio_read(gpio_t gpio);
|
||||
|
||||
#endif /*__GPIO_H__*/
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GPIO_LPC_H__
|
||||
#define __GPIO_LPC_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -30,7 +29,7 @@
|
|||
* register #defines and API declarations into separate header files.
|
||||
*/
|
||||
|
||||
typedef struct gpio_port {
|
||||
typedef struct {
|
||||
volatile uint32_t dir; /* +0x000 */
|
||||
uint32_t _reserved0[31];
|
||||
volatile uint32_t mask; /* +0x080 */
|
||||
|
|
@ -69,5 +68,3 @@ struct gpio {
|
|||
.gpio_w = GPIO_LPC_W(_port_num, _pin_num), \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
#endif /*__GPIO_LPC_H__*/
|
||||
|
|
|
|||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Benjamin Vernoux <titanmkd@gmail.com>
|
||||
* Copyright 2012 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __HACKRF_CORE_H
|
||||
#define __HACKRF_CORE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpld_jtag.h"
|
||||
#include "fixed_point.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "max283x.h"
|
||||
#include "max5864.h"
|
||||
#include "mixer.h"
|
||||
#include "radio.h"
|
||||
#include "rf_path.h"
|
||||
#include "sgpio.h"
|
||||
#include "si5351c.h"
|
||||
#include "spi_ssp.h"
|
||||
#include "w25q80bv.h"
|
||||
#if defined(PRALINE)
|
||||
#include "fpga.h"
|
||||
#include "ice40_spi.h"
|
||||
#endif
|
||||
|
||||
/* TODO: Hide these configurations */
|
||||
extern si5351c_driver_t clock_gen;
|
||||
extern ssp_config_t ssp_config_w25q80bv;
|
||||
|
||||
#ifdef PRALINE
|
||||
extern ice40_spi_driver_t ice40;
|
||||
extern fpga_driver_t fpga;
|
||||
#endif
|
||||
extern max283x_driver_t max283x;
|
||||
extern max5864_driver_t max5864;
|
||||
extern mixer_driver_t mixer;
|
||||
extern w25q80bv_driver_t spi_flash;
|
||||
extern sgpio_config_t sgpio_config;
|
||||
extern radio_t radio;
|
||||
extern rf_path_t rf_path;
|
||||
extern jtag_t jtag_cpld;
|
||||
extern i2c_bus_t i2c0;
|
||||
|
||||
void cpu_clock_init(void);
|
||||
void clock_gen_init(void);
|
||||
void clock_gen_shutdown(void);
|
||||
void ssp1_set_mode_max283x(void);
|
||||
void ssp1_set_mode_max5864(void);
|
||||
#ifdef PRALINE
|
||||
void ssp1_set_mode_ice40(void);
|
||||
#endif
|
||||
|
||||
void pin_shutdown(void);
|
||||
void pin_setup(void);
|
||||
|
||||
#ifdef PRALINE
|
||||
void enable_1v2_power(void);
|
||||
void disable_1v2_power(void);
|
||||
void enable_3v3aux_power(void);
|
||||
void disable_3v3aux_power(void);
|
||||
#else
|
||||
void enable_1v8_power(void);
|
||||
void disable_1v8_power(void);
|
||||
#endif
|
||||
|
||||
fp_40_24_t sample_rate_set(const fp_40_24_t sample_rate, const bool program);
|
||||
|
||||
clock_source_t activate_best_clock_source(void);
|
||||
|
||||
#if (defined HACKRF_ONE || defined RAD1O || defined PRALINE)
|
||||
void enable_rf_power(void);
|
||||
void disable_rf_power(void);
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
LED1 = 0,
|
||||
LED2 = 1,
|
||||
LED3 = 2,
|
||||
LED4 = 3,
|
||||
} led_t;
|
||||
|
||||
void led_on(const led_t led);
|
||||
void led_off(const led_t led);
|
||||
void led_toggle(const led_t led);
|
||||
void set_leds(const uint8_t state);
|
||||
|
||||
void trigger_enable(const bool enable);
|
||||
|
||||
void halt_and_flash(const uint32_t duration);
|
||||
|
||||
#ifdef PRALINE
|
||||
typedef enum {
|
||||
P1_SIGNAL_TRIGGER_IN = 0,
|
||||
P1_SIGNAL_AUX_CLK1 = 1,
|
||||
P1_SIGNAL_CLKIN = 2,
|
||||
P1_SIGNAL_TRIGGER_OUT = 3,
|
||||
P1_SIGNAL_P22_CLKIN = 4,
|
||||
P1_SIGNAL_P2_5 = 5,
|
||||
P1_SIGNAL_NC = 6,
|
||||
P1_SIGNAL_AUX_CLK2 = 7,
|
||||
} p1_ctrl_signal_t;
|
||||
|
||||
typedef enum {
|
||||
P2_SIGNAL_CLK3 = 0,
|
||||
P2_SIGNAL_TRIGGER_IN = 2,
|
||||
P2_SIGNAL_TRIGGER_OUT = 3,
|
||||
} p2_ctrl_signal_t;
|
||||
|
||||
typedef enum {
|
||||
CLKIN_SIGNAL_P1 = 0,
|
||||
CLKIN_SIGNAL_P22 = 1,
|
||||
} clkin_signal_t;
|
||||
|
||||
void p1_ctrl_set(const p1_ctrl_signal_t signal);
|
||||
void p2_ctrl_set(const p2_ctrl_signal_t signal);
|
||||
void narrowband_filter_set(const uint8_t value);
|
||||
void clkin_ctrl_set(const clkin_signal_t value);
|
||||
void pps_out_set(const uint8_t value);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HACKRF_CORE_H */
|
||||
|
|
@ -23,10 +23,11 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "hackrf_ui.h"
|
||||
#if defined(PRALINE) || defined(HACKRF_ONE)
|
||||
#include "transceiver_mode.h"
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
#include "ui_portapack.h"
|
||||
#endif
|
||||
#if defined(RAD1O)
|
||||
#ifdef IS_RAD1O
|
||||
#include "ui_rad1o.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -81,14 +82,18 @@ const hackrf_ui_t* hackrf_ui(void)
|
|||
{
|
||||
/* Detect on first use. If no UI hardware is detected, use a stub function table. */
|
||||
if (ui == NULL && ui_enabled) {
|
||||
#if (defined HACKRF_ONE || defined PRALINE)
|
||||
if (portapack_hackrf_ui_init) {
|
||||
ui = portapack_hackrf_ui_init();
|
||||
#ifdef IS_EXPANSION_COMPATIBLE
|
||||
if (IS_EXPANSION_COMPATIBLE) {
|
||||
if (portapack_hackrf_ui_init) {
|
||||
ui = portapack_hackrf_ui_init();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef RAD1O
|
||||
if (rad1o_ui_setup) {
|
||||
ui = rad1o_ui_setup();
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
if (rad1o_ui_setup) {
|
||||
ui = rad1o_ui_setup();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef HACKRF_UI_H
|
||||
#define HACKRF_UI_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "radio.h"
|
||||
#include "clock_gen.h"
|
||||
#include "rf_path.h"
|
||||
#include "transceiver_mode.h"
|
||||
|
||||
typedef void (*hackrf_ui_init_fn)(void);
|
||||
typedef void (*hackrf_ui_deinit_fn)(void);
|
||||
|
|
@ -71,5 +71,3 @@ typedef struct {
|
|||
*/
|
||||
const hackrf_ui_t* hackrf_ui(void);
|
||||
void hackrf_ui_set_enable(bool);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,27 +20,23 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __I2C_BUS_H__
|
||||
#define __I2C_BUS_H__
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct i2c_bus_t; // IWYU pragma: keep - fixed in #1704
|
||||
typedef struct i2c_bus_t i2c_bus_t;
|
||||
|
||||
struct i2c_bus_t {
|
||||
typedef struct _i2c_bus_t {
|
||||
void* const obj;
|
||||
void (*start)(i2c_bus_t* const bus, const void* const config);
|
||||
void (*stop)(i2c_bus_t* const bus);
|
||||
void (*start)(struct _i2c_bus_t* const bus, const void* const config);
|
||||
void (*stop)(struct _i2c_bus_t* const bus);
|
||||
void (*transfer)(
|
||||
i2c_bus_t* const bus,
|
||||
struct _i2c_bus_t* const bus,
|
||||
const uint_fast8_t peripheral_address,
|
||||
const uint8_t* const tx,
|
||||
const size_t tx_count,
|
||||
uint8_t* const rx,
|
||||
const size_t rx_count);
|
||||
};
|
||||
} i2c_bus_t;
|
||||
|
||||
void i2c_bus_start(i2c_bus_t* const bus, const void* const config);
|
||||
void i2c_bus_stop(i2c_bus_t* const bus);
|
||||
|
|
@ -51,5 +47,3 @@ void i2c_bus_transfer(
|
|||
const size_t tx_count,
|
||||
uint8_t* const rx,
|
||||
const size_t rx_count);
|
||||
|
||||
#endif /*__I2C_BUS_H__*/
|
||||
|
|
|
|||
|
|
@ -23,6 +23,28 @@
|
|||
#include "i2c_lpc.h"
|
||||
|
||||
#include <libopencm3/lpc43xx/i2c.h>
|
||||
#include <libopencm3/lpc43xx/memorymap.h>
|
||||
|
||||
#include "cpu_clock.h"
|
||||
|
||||
/* Driver instances. */
|
||||
i2c_bus_t i2c0 = {
|
||||
.obj = (void*) I2C0_BASE,
|
||||
.start = i2c_lpc_start,
|
||||
.stop = i2c_lpc_stop,
|
||||
.transfer = i2c_lpc_transfer,
|
||||
};
|
||||
|
||||
i2c_bus_t i2c1 = {
|
||||
.obj = (void*) I2C1_BASE,
|
||||
.start = i2c_lpc_start,
|
||||
.stop = i2c_lpc_stop,
|
||||
.transfer = i2c_lpc_transfer,
|
||||
};
|
||||
|
||||
const i2c_lpc_config_t i2c_config_fast_clock = {
|
||||
.clock_khz = 400,
|
||||
};
|
||||
|
||||
/* FIXME return i2c0 status from each function */
|
||||
|
||||
|
|
@ -31,7 +53,9 @@ void i2c_lpc_start(i2c_bus_t* const bus, const void* const _config)
|
|||
const i2c_lpc_config_t* const config = _config;
|
||||
|
||||
const uint32_t port = (uint32_t) bus->obj;
|
||||
i2c_init(port, config->duty_cycle_count);
|
||||
const uint16_t duty_cycle_count =
|
||||
(cpu_clock_mhz * (2000 / config->clock_khz)) / 4;
|
||||
i2c_init(port, duty_cycle_count);
|
||||
}
|
||||
|
||||
void i2c_lpc_stop(i2c_bus_t* const bus)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __I2C_LPC_H__
|
||||
#define __I2C_LPC_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
|
@ -29,8 +28,8 @@
|
|||
|
||||
#include "i2c_bus.h"
|
||||
|
||||
typedef struct i2c_lpc_config_t {
|
||||
const uint16_t duty_cycle_count;
|
||||
typedef struct {
|
||||
const uint16_t clock_khz;
|
||||
} i2c_lpc_config_t;
|
||||
|
||||
void i2c_lpc_start(i2c_bus_t* const bus, const void* const config);
|
||||
|
|
@ -44,4 +43,7 @@ void i2c_lpc_transfer(
|
|||
const size_t count_rx);
|
||||
bool i2c_probe(i2c_bus_t* const bus, const uint_fast8_t device_address);
|
||||
|
||||
#endif /*__I2C_LPC_H__*/
|
||||
/* Driver instances. */
|
||||
extern const i2c_lpc_config_t i2c_config_fast_clock;
|
||||
extern i2c_bus_t i2c0;
|
||||
extern i2c_bus_t i2c1;
|
||||
|
|
|
|||
|
|
@ -26,12 +26,32 @@
|
|||
#include <libopencm3/lpc43xx/ssp.h>
|
||||
|
||||
#include "delay.h"
|
||||
#include "platform_gpio.h"
|
||||
#include "platform_scu.h"
|
||||
|
||||
/* Driver instance. */
|
||||
ssp_config_t ssp_config_ice40_fpga = {
|
||||
.data_bits = SSP_DATA_8BITS,
|
||||
.spi_mode = SSP_CPOL_1_CPHA_1,
|
||||
.serial_clock_rate = 21,
|
||||
.clock_prescale_rate = 2,
|
||||
};
|
||||
|
||||
ice40_spi_driver_t ice40 = {
|
||||
.bus = &spi_bus_ssp1,
|
||||
};
|
||||
|
||||
void ice40_spi_target_init(ice40_spi_driver_t* const drv)
|
||||
{
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
const platform_scu_t* scu = platform_scu();
|
||||
|
||||
/* Configure drivers and driver pins */
|
||||
ssp_config_ice40_fpga.gpio_select = gpio->fpga_cfg_spi_cs;
|
||||
ice40.gpio_select = gpio->fpga_cfg_spi_cs;
|
||||
ice40.gpio_creset = gpio->fpga_cfg_creset;
|
||||
ice40.gpio_cdone = gpio->fpga_cfg_cdone;
|
||||
|
||||
/* Configure SSP1 Peripheral and relevant FPGA pins. */
|
||||
scu_pinmux(scu->SSP1_CIPO, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
||||
scu_pinmux(scu->SSP1_COPI, (SCU_SSP_IO | SCU_CONF_FUNCTION5));
|
||||
|
|
@ -50,14 +70,14 @@ void ice40_spi_target_init(ice40_spi_driver_t* const drv)
|
|||
uint8_t ice40_spi_read(ice40_spi_driver_t* const drv, uint8_t r)
|
||||
{
|
||||
uint8_t value[3] = {r & 0x7F, 0, 0};
|
||||
spi_bus_transfer(drv->bus, value, 3);
|
||||
spi_bus_transfer(drv->bus, &ssp_config_ice40_fpga, value, 3);
|
||||
return value[2];
|
||||
}
|
||||
|
||||
void ice40_spi_write(ice40_spi_driver_t* const drv, uint8_t r, uint16_t v)
|
||||
{
|
||||
uint8_t value[3] = {(r & 0x7F) | 0x80, v, 0};
|
||||
spi_bus_transfer(drv->bus, value, 3);
|
||||
spi_bus_transfer(drv->bus, &ssp_config_ice40_fpga, value, 3);
|
||||
}
|
||||
|
||||
static void spi_ssp1_wait_for_tx_fifo_not_full(void)
|
||||
|
|
@ -90,19 +110,21 @@ bool ice40_spi_syscfg_program(
|
|||
size_t (*read_block_cb)(void* ctx),
|
||||
void* read_ctx)
|
||||
{
|
||||
spi_bus_start(drv->bus, &ssp_config_ice40_fpga);
|
||||
|
||||
// Drive CRESET_B = 0, SPI_SS = 0, SPI_SCK = 1.
|
||||
gpio_clear(drv->gpio_creset);
|
||||
gpio_clear(drv->gpio_select);
|
||||
|
||||
// Wait a minimum of 200 ns.
|
||||
delay_us_at_mhz(1, 204 / 4); // 250 ns.
|
||||
delay_us(1);
|
||||
|
||||
// Release CRESET_B or drive CRESET_B = 1.
|
||||
gpio_set(drv->gpio_creset);
|
||||
|
||||
// Wait a minimum of 1200 μs to clear internal configuration memory.
|
||||
// Testing showed us that we need to wait longer. Let's wait 1800 μs.
|
||||
delay_us_at_mhz(1800, 204);
|
||||
delay_us(1800);
|
||||
|
||||
// Set SPI_SS = 1, Send 8 dummy clocks.
|
||||
gpio_set(drv->gpio_select);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ICE40_SPI_H
|
||||
#define __ICE40_SPI_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -28,16 +27,14 @@
|
|||
|
||||
#include "gpio.h"
|
||||
#include "spi_bus.h"
|
||||
#include "spi_ssp.h"
|
||||
|
||||
struct ice40_spi_driver_t; // IWYU pragma: keep - fixed in #1704
|
||||
typedef struct ice40_spi_driver_t ice40_spi_driver_t;
|
||||
|
||||
struct ice40_spi_driver_t {
|
||||
typedef struct {
|
||||
spi_bus_t* const bus;
|
||||
gpio_t gpio_select;
|
||||
gpio_t gpio_creset;
|
||||
gpio_t gpio_cdone;
|
||||
};
|
||||
} ice40_spi_driver_t;
|
||||
|
||||
void ice40_spi_target_init(ice40_spi_driver_t* const drv);
|
||||
uint8_t ice40_spi_read(ice40_spi_driver_t* const drv, uint8_t r);
|
||||
|
|
@ -48,4 +45,6 @@ bool ice40_spi_syscfg_program(
|
|||
size_t (*read_block_cb)(void* ctx),
|
||||
void* read_ctx);
|
||||
|
||||
#endif // __ICE40_SPI_H
|
||||
/* Driver instance. */
|
||||
extern ssp_config_t ssp_config_ice40_fpga;
|
||||
extern ice40_spi_driver_t ice40;
|
||||
|
|
|
|||
100
firmware/common/leds.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "leds.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "delay.h"
|
||||
#include "gpio.h"
|
||||
#include "platform_detect.h"
|
||||
#include "platform_gpio.h"
|
||||
|
||||
void led_on(const led_t led)
|
||||
{
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
gpio_clear(platform_gpio()->led[led]);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
gpio_set(platform_gpio()->led[led]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_off(const led_t led)
|
||||
{
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
gpio_set(platform_gpio()->led[led]);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
gpio_clear(platform_gpio()->led[led]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_toggle(const led_t led)
|
||||
{
|
||||
gpio_toggle(platform_gpio()->led[led]);
|
||||
}
|
||||
|
||||
void set_leds(const uint8_t state)
|
||||
{
|
||||
int num_leds = 3;
|
||||
#ifdef IS_FOUR_LEDS
|
||||
if (IS_FOUR_LEDS) {
|
||||
num_leds = 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < num_leds; i++) {
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
gpio_write(platform_gpio()->led[i], ((state >> i) & 1) == 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void halt_and_flash(const uint32_t period_ms)
|
||||
{
|
||||
/* blink LED1, LED2, and LED3 */
|
||||
while (1) {
|
||||
led_on(LED1);
|
||||
led_on(LED2);
|
||||
led_on(LED3);
|
||||
delay_ms(period_ms / 2);
|
||||
led_off(LED1);
|
||||
led_off(LED2);
|
||||
led_off(LED3);
|
||||
delay_ms(period_ms / 2);
|
||||
}
|
||||
}
|
||||
46
firmware/common/leds.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
LED1 = 0,
|
||||
LED2 = 1,
|
||||
LED3 = 2,
|
||||
LED4 = 3,
|
||||
} led_t;
|
||||
|
||||
void led_on(const led_t led);
|
||||
void led_off(const led_t led);
|
||||
void led_toggle(const led_t led);
|
||||
void set_leds(const uint8_t state);
|
||||
|
||||
void halt_and_flash(const uint32_t duration);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LOCKING_H__
|
||||
#define __LOCKING_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -51,5 +50,3 @@ static inline uint32_t store_exclusive(uint32_t val, volatile uint32_t* addr)
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LOCKING_H__ */
|
||||
|
|
|
|||
|
|
@ -19,12 +19,9 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LZ4_BLK_H
|
||||
#define __LZ4_BLK_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int lz4_blk_decompress(const uint8_t* src, uint8_t* dst, size_t length);
|
||||
|
||||
#endif
|
||||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LZ4_BUF_H
|
||||
#define __LZ4_BUF_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -31,5 +30,3 @@
|
|||
|
||||
extern uint8_t lz4_in_buf[LZ4_BUFFER_SIZE];
|
||||
extern uint8_t lz4_out_buf[LZ4_BUFFER_SIZE];
|
||||
|
||||
#endif /*__LZ4_BUF_H */
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __M0_STATE_H__
|
||||
#define __M0_STATE_H__
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
@ -60,5 +59,3 @@ enum m0_error {
|
|||
extern volatile struct m0_state m0_state;
|
||||
|
||||
void m0_set_mode(enum m0_mode mode);
|
||||
|
||||
#endif /*__M0_STATE_H__*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2025-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -27,14 +27,18 @@
|
|||
* pirate commands to do the same thing.
|
||||
*/
|
||||
|
||||
#include "max2831.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "max2831.h"
|
||||
#include "fixed_point.h"
|
||||
#include "max2831_regs.def" // private register def macros
|
||||
#include "selftest.h"
|
||||
#include "adc.h"
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
/* Default register values. */
|
||||
static const uint16_t max2831_regs_default[MAX2831_NUM_REGS] = {
|
||||
|
|
@ -105,7 +109,7 @@ static void max2831_write(max2831_driver_t* const drv, uint8_t r, uint16_t v)
|
|||
{
|
||||
uint32_t word = (((uint32_t) v & 0x3fff) << 4) | (r & 0xf);
|
||||
uint16_t values[2] = {word >> 9, word & 0x1ff};
|
||||
spi_bus_transfer(drv->bus, values, 2);
|
||||
spi_bus_transfer(drv->bus, drv->config, values, 2);
|
||||
}
|
||||
|
||||
uint16_t max2831_reg_read(max2831_driver_t* const drv, uint8_t r)
|
||||
|
|
@ -222,36 +226,40 @@ void max2831_stop(max2831_driver_t* const drv)
|
|||
max2831_set_mode(drv, MAX2831_MODE_SHUTDOWN);
|
||||
}
|
||||
|
||||
void max2831_set_frequency(max2831_driver_t* const drv, uint32_t freq)
|
||||
{
|
||||
uint32_t div_frac;
|
||||
uint32_t div_int;
|
||||
uint32_t div_rem;
|
||||
uint32_t div_cmp;
|
||||
int i;
|
||||
/* Assume 40 MHz reference clock with R divider of 2. */
|
||||
#define PFD_FREQ_HZ (20ULL * (1000ULL * 1000ULL))
|
||||
|
||||
/* ASSUME 40MHz PLL. Ratio = F*R/40,000,000. */
|
||||
/* TODO: fixed to R=2. Check if it's worth exploring R=1. */
|
||||
freq += (20000000 >> 21); /* round to nearest frequency */
|
||||
div_int = freq / 20000000;
|
||||
div_rem = freq % 20000000;
|
||||
div_frac = 0;
|
||||
div_cmp = 20000000;
|
||||
for (i = 0; i < 20; i++) {
|
||||
div_frac <<= 1;
|
||||
div_rem <<= 1;
|
||||
if (div_rem >= div_cmp) {
|
||||
div_frac |= 0x1;
|
||||
div_rem -= div_cmp;
|
||||
}
|
||||
#define MIN_FREQ FP_MHZ(2000)
|
||||
#define MAX_FREQ FP_MHZ(3000)
|
||||
|
||||
fp_40_24_t max2831_set_frequency(
|
||||
max2831_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program)
|
||||
{
|
||||
uint64_t div;
|
||||
|
||||
freq = MIN(freq, MAX_FREQ);
|
||||
freq = MAX(freq, MIN_FREQ);
|
||||
|
||||
freq += ((PFD_FREQ_HZ * FP_ONE_HZ) >> 21); /* round to nearest frequency */
|
||||
div = freq / PFD_FREQ_HZ;
|
||||
|
||||
/*
|
||||
* Shift from 40.24 fixed-point to 44.20 to match 20-bit fractional
|
||||
* divider.
|
||||
*/
|
||||
div = div >> 4;
|
||||
|
||||
if (program) {
|
||||
//set_MAX2831_SYN_REF_DIV(drv, MAX2831_SYN_REF_DIV_2);
|
||||
set_MAX2831_SYN_INT(drv, (div >> 20) & 0xff);
|
||||
set_MAX2831_SYN_FRAC_HI(drv, (div >> 6) & 0x3fff);
|
||||
set_MAX2831_SYN_FRAC_LO(drv, div & 0x3f);
|
||||
max2831_regs_commit(drv);
|
||||
}
|
||||
|
||||
/* Write order matters? */
|
||||
//set_MAX2831_SYN_REF_DIV(drv, MAX2831_SYN_REF_DIV_2);
|
||||
set_MAX2831_SYN_INT(drv, div_int);
|
||||
set_MAX2831_SYN_FRAC_HI(drv, (div_frac >> 6) & 0x3fff);
|
||||
set_MAX2831_SYN_FRAC_LO(drv, div_frac & 0x3f);
|
||||
max2831_regs_commit(drv);
|
||||
return PFD_FREQ_HZ * (div << 4);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2025 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2025-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -19,12 +19,12 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2831_H
|
||||
#define __MAX2831_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#include "gpio.h"
|
||||
#include "spi_bus.h"
|
||||
|
||||
|
|
@ -48,22 +48,22 @@ typedef enum {
|
|||
MAX2831_RX_HPF_600_KHZ = 3,
|
||||
} max2831_rx_hpf_freq_t;
|
||||
|
||||
struct max2831_driver_t; // IWYU pragma: keep - fixed in #1704
|
||||
typedef struct max2831_driver_t max2831_driver_t;
|
||||
|
||||
struct max2831_driver_t {
|
||||
typedef struct _max2831_driver_t {
|
||||
spi_bus_t* bus;
|
||||
void* config;
|
||||
gpio_t gpio_enable;
|
||||
gpio_t gpio_rxtx;
|
||||
gpio_t gpio_rxhp;
|
||||
gpio_t gpio_ld;
|
||||
void (*target_init)(max2831_driver_t* const drv);
|
||||
void (*set_mode)(max2831_driver_t* const drv, const max2831_mode_t new_mode);
|
||||
void (*target_init)(struct _max2831_driver_t* const drv);
|
||||
void (*set_mode)(
|
||||
struct _max2831_driver_t* const drv,
|
||||
const max2831_mode_t new_mode);
|
||||
max2831_mode_t mode;
|
||||
uint16_t regs[MAX2831_NUM_REGS];
|
||||
uint16_t regs_dirty;
|
||||
uint32_t desired_lpf_bw;
|
||||
};
|
||||
} max2831_driver_t;
|
||||
|
||||
/* Initialize chip. */
|
||||
extern void max2831_setup(max2831_driver_t* const drv);
|
||||
|
|
@ -88,9 +88,11 @@ void max2831_set_mode(max2831_driver_t* const drv, const max2831_mode_t new_mode
|
|||
extern void max2831_start(max2831_driver_t* const drv);
|
||||
extern void max2831_stop(max2831_driver_t* const drv);
|
||||
|
||||
/* Set frequency in Hz. Frequency setting is a multi-step function
|
||||
* where order of register writes matters. */
|
||||
extern void max2831_set_frequency(max2831_driver_t* const drv, uint32_t freq);
|
||||
/* Set frequency in 1/(2**24) Hz */
|
||||
extern fp_40_24_t max2831_set_frequency(
|
||||
max2831_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program);
|
||||
uint32_t max2831_set_lpf_bandwidth(
|
||||
max2831_driver_t* const drv,
|
||||
const max2831_mode_t mode,
|
||||
|
|
@ -108,5 +110,3 @@ extern void max2831_tx(max2831_driver_t* const drv);
|
|||
extern void max2831_rx(max2831_driver_t* const drv);
|
||||
extern void max2831_tx_calibration(max2831_driver_t* const drv);
|
||||
extern void max2831_rx_calibration(max2831_driver_t* const drv);
|
||||
|
||||
#endif // __MAX2831_H
|
||||
|
|
|
|||
|
|
@ -1,7 +1,27 @@
|
|||
/* -*- mode: c -*- */
|
||||
/* -*- mode: c -*-
|
||||
*
|
||||
* Copyright 2012 Michael Ossmann
|
||||
* Copyright 2025-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2831_REGS_DEF
|
||||
#define __MAX2831_REGS_DEF
|
||||
#pragma once
|
||||
|
||||
/* Generate static inline accessors that operate on the global
|
||||
* regs. Done this way to (1) allow defs to be scraped out and used
|
||||
|
|
@ -128,5 +148,3 @@ __MREG__(MAX2831_RXIQ_VCM,15,10,2) // RX I/Q output common mode
|
|||
#define MAX2831_RXIQ_VCM_1_2 1 // 1.2V
|
||||
#define MAX2831_RXIQ_VCM_1_3 2 // 1.3V
|
||||
#define MAX2831_RXIQ_VCM_1_45 3 // 1.45V
|
||||
|
||||
#endif // __MAX2831_REGS_DEF
|
||||
|
|
@ -19,12 +19,9 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2831_TARGET_H
|
||||
#define __MAX2831_TARGET_H
|
||||
#pragma once
|
||||
|
||||
#include "max2831.h"
|
||||
|
||||
void max2831_target_init(max2831_driver_t* const drv);
|
||||
void max2831_target_set_mode(max2831_driver_t* const drv, const max2831_mode_t new_mode);
|
||||
|
||||
#endif // __MAX2831_TARGET_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Will Code <willcode4@gmail.com>
|
||||
* Copyright 2014 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
|
|
@ -29,12 +29,18 @@
|
|||
* pirate commands to do the same thing.
|
||||
*/
|
||||
|
||||
#include "max2837.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "max2837.h"
|
||||
#include "fixed_point.h"
|
||||
#include "max2837_regs.def" // private register def macros
|
||||
#include "selftest.h"
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
/* Default register values. */
|
||||
static const uint16_t max2837_regs_default[MAX2837_NUM_REGS] = {
|
||||
0x150, /* 0 */
|
||||
|
|
@ -150,14 +156,14 @@ void max2837_setup(max2837_driver_t* const drv)
|
|||
static uint16_t max2837_read(max2837_driver_t* const drv, uint8_t r)
|
||||
{
|
||||
uint16_t value = (1 << 15) | (r << 10);
|
||||
spi_bus_transfer(drv->bus, &value, 1);
|
||||
spi_bus_transfer(drv->bus, drv->config, &value, 1);
|
||||
return value & 0x3ff;
|
||||
}
|
||||
|
||||
static void max2837_write(max2837_driver_t* const drv, uint8_t r, uint16_t v)
|
||||
{
|
||||
uint16_t value = (r << 10) | (v & 0x3ff);
|
||||
spi_bus_transfer(drv->bus, &value, 1);
|
||||
spi_bus_transfer(drv->bus, drv->config, &value, 1);
|
||||
}
|
||||
|
||||
uint16_t max2837_reg_read(max2837_driver_t* const drv, uint8_t r)
|
||||
|
|
@ -228,24 +234,32 @@ void max2837_stop(max2837_driver_t* const drv)
|
|||
max2837_set_mode(drv, MAX2837_MODE_SHUTDOWN);
|
||||
}
|
||||
|
||||
void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq)
|
||||
/* Assume 40 MHz reference clock with R divider of 1. */
|
||||
#define PFD_FREQ_HZ (40ULL * (1000ULL * 1000ULL))
|
||||
|
||||
#define MIN_FREQ FP_MHZ(2000)
|
||||
#define MAX_FREQ FP_MHZ(3000)
|
||||
|
||||
fp_40_24_t max2837_set_frequency(
|
||||
max2837_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program)
|
||||
{
|
||||
uint8_t band;
|
||||
uint8_t lna_band;
|
||||
uint32_t div_frac;
|
||||
uint32_t div_int;
|
||||
uint32_t div_rem;
|
||||
uint32_t div_cmp;
|
||||
int i;
|
||||
uint64_t div;
|
||||
|
||||
freq = MIN(freq, MAX_FREQ);
|
||||
freq = MAX(freq, MIN_FREQ);
|
||||
|
||||
/* Select band. Allow tuning outside specified bands. */
|
||||
if (freq < 2400000000U) {
|
||||
if (freq < FP_MHZ(2400)) {
|
||||
band = MAX2837_LOGEN_BSW_2_3;
|
||||
lna_band = MAX2837_LNAband_2_4;
|
||||
} else if (freq < 2500000000U) {
|
||||
} else if (freq < FP_MHZ(2500)) {
|
||||
band = MAX2837_LOGEN_BSW_2_4;
|
||||
lna_band = MAX2837_LNAband_2_4;
|
||||
} else if (freq < 2600000000U) {
|
||||
} else if (freq < FP_MHZ(2600)) {
|
||||
band = MAX2837_LOGEN_BSW_2_5;
|
||||
lna_band = MAX2837_LNAband_2_6;
|
||||
} else {
|
||||
|
|
@ -253,35 +267,34 @@ void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq)
|
|||
lna_band = MAX2837_LNAband_2_6;
|
||||
}
|
||||
|
||||
/* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */
|
||||
freq += (30000000 >> 21); /* round to nearest frequency */
|
||||
div_int = freq / 30000000;
|
||||
div_rem = freq % 30000000;
|
||||
div_frac = 0;
|
||||
div_cmp = 30000000;
|
||||
for (i = 0; i < 20; i++) {
|
||||
div_frac <<= 1;
|
||||
div_rem <<= 1;
|
||||
if (div_rem >= div_cmp) {
|
||||
div_frac |= 0x1;
|
||||
div_rem -= div_cmp;
|
||||
}
|
||||
fp_40_24_t vco = (freq * 4) / 3;
|
||||
|
||||
vco += ((PFD_FREQ_HZ * FP_ONE_HZ) >> 21); /* round to nearest frequency */
|
||||
div = vco / PFD_FREQ_HZ;
|
||||
|
||||
/*
|
||||
* Shift from 40.24 fixed-point to 44.20 to match 20-bit fractional
|
||||
* divider.
|
||||
*/
|
||||
div = div >> 4;
|
||||
|
||||
if (program) {
|
||||
/* Band settings */
|
||||
set_MAX2837_LOGEN_BSW(drv, band);
|
||||
set_MAX2837_LNAband(drv, lna_band);
|
||||
|
||||
/*
|
||||
* Write order matters here, so commit INT and FRAC_HI before
|
||||
* committing FRAC_LO, which is the trigger for VCO auto-select.
|
||||
*/
|
||||
set_MAX2837_SYN_INT(drv, (div >> 20) & 0xff);
|
||||
set_MAX2837_SYN_FRAC_HI(drv, (div >> 10) & 0x3ff);
|
||||
max2837_regs_commit(drv);
|
||||
set_MAX2837_SYN_FRAC_LO(drv, div & 0x3ff);
|
||||
max2837_regs_commit(drv);
|
||||
}
|
||||
|
||||
/* Band settings */
|
||||
set_MAX2837_LOGEN_BSW(drv, band);
|
||||
set_MAX2837_LNAband(drv, lna_band);
|
||||
|
||||
/* Write order matters here, so commit INT and FRAC_HI before
|
||||
* committing FRAC_LO, which is the trigger for VCO
|
||||
* auto-select. TODO - it's cleaner this way, but it would be
|
||||
* faster to explicitly commit the registers explicitly so the
|
||||
* dirty bits aren't scanned twice. */
|
||||
set_MAX2837_SYN_INT(drv, div_int);
|
||||
set_MAX2837_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff);
|
||||
max2837_regs_commit(drv);
|
||||
set_MAX2837_SYN_FRAC_LO(drv, div_frac & 0x3ff);
|
||||
max2837_regs_commit(drv);
|
||||
return ((PFD_FREQ_HZ * 3) / 4) * (div << 4);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Will Code <willcode4@gmail.com>
|
||||
* Copyright 2014 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
|
|
@ -21,12 +21,12 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2837_H
|
||||
#define __MAX2837_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#include "gpio.h"
|
||||
#include "spi_bus.h"
|
||||
|
||||
|
|
@ -41,20 +41,20 @@ typedef enum {
|
|||
MAX2837_MODE_RX
|
||||
} max2837_mode_t;
|
||||
|
||||
struct max2837_driver_t; // IWYU pragma: keep - fixed in #1704
|
||||
typedef struct max2837_driver_t max2837_driver_t;
|
||||
|
||||
struct max2837_driver_t {
|
||||
typedef struct _max2837_driver_t {
|
||||
spi_bus_t* bus;
|
||||
void* config;
|
||||
gpio_t gpio_enable;
|
||||
gpio_t gpio_rx_enable;
|
||||
gpio_t gpio_tx_enable;
|
||||
void (*target_init)(max2837_driver_t* const drv);
|
||||
void (*set_mode)(max2837_driver_t* const drv, const max2837_mode_t new_mode);
|
||||
void (*target_init)(struct _max2837_driver_t* const drv);
|
||||
void (*set_mode)(
|
||||
struct _max2837_driver_t* const drv,
|
||||
const max2837_mode_t new_mode);
|
||||
max2837_mode_t mode;
|
||||
uint16_t regs[MAX2837_NUM_REGS];
|
||||
uint32_t regs_dirty;
|
||||
};
|
||||
} max2837_driver_t;
|
||||
|
||||
/* Initialize chip. */
|
||||
extern void max2837_setup(max2837_driver_t* const drv);
|
||||
|
|
@ -79,9 +79,11 @@ void max2837_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode
|
|||
extern void max2837_start(max2837_driver_t* const drv);
|
||||
extern void max2837_stop(max2837_driver_t* const drv);
|
||||
|
||||
/* Set frequency in Hz. Frequency setting is a multi-step function
|
||||
* where order of register writes matters. */
|
||||
extern void max2837_set_frequency(max2837_driver_t* const drv, uint32_t freq);
|
||||
/* Set frequency in 1/(2**24) Hz. */
|
||||
extern fp_40_24_t max2837_set_frequency(
|
||||
max2837_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program);
|
||||
uint32_t max2837_set_lpf_bandwidth(
|
||||
max2837_driver_t* const drv,
|
||||
const uint32_t bandwidth_hz);
|
||||
|
|
@ -91,5 +93,3 @@ bool max2837_set_txvga_gain(max2837_driver_t* const drv, const uint32_t gain_db)
|
|||
|
||||
extern void max2837_tx(max2837_driver_t* const drv);
|
||||
extern void max2837_rx(max2837_driver_t* const drv);
|
||||
|
||||
#endif // __MAX2837_H
|
||||
|
|
|
|||
|
|
@ -1,7 +1,26 @@
|
|||
/* -*- mode: c -*- */
|
||||
/* -*- mode: c -*- *
|
||||
* Copyright 2012 Michael Ossmann
|
||||
* Copyright 2025-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2837_REGS_DEF
|
||||
#define __MAX2837_REGS_DEF
|
||||
#pragma once
|
||||
|
||||
/* Generate static inline accessors that operate on the global
|
||||
* regs. Done this way to (1) allow defs to be scraped out and used
|
||||
|
|
@ -404,5 +423,3 @@ __MREG__(MAX2837_FUSE_RTH,30,9,1)
|
|||
// 0 -> 992/0uA correction, 15 -> 0/992uA correction ... if TX_DCCORR_SPI_EN
|
||||
__MREG__(MAX2837_TX_DCCORR_I,31,4,5)
|
||||
__MREG__(MAX2837_TX_DCCORR_Q,31,9,5)
|
||||
|
||||
#endif // __MAX2837_REGS_DEF
|
||||
|
|
|
|||
|
|
@ -21,12 +21,9 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2837_TARGET_H
|
||||
#define __MAX2837_TARGET_H
|
||||
#pragma once
|
||||
|
||||
#include "max2837.h"
|
||||
|
||||
void max2837_target_init(max2837_driver_t* const drv);
|
||||
void max2837_target_set_mode(max2837_driver_t* const drv, const max2837_mode_t new_mode);
|
||||
|
||||
#endif // __MAX2837_TARGET_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Will Code <willcode4@gmail.com>
|
||||
* Copyright 2014 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
|
|
@ -29,12 +29,18 @@
|
|||
* pirate commands to do the same thing.
|
||||
*/
|
||||
|
||||
#include "max2839.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "max2839.h"
|
||||
#include "fixed_point.h"
|
||||
#include "max2839_regs.def" // private register def macros
|
||||
#include "selftest.h"
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
static uint8_t requested_lna_gain = 0;
|
||||
static uint8_t requested_vga_gain = 0;
|
||||
|
||||
|
|
@ -158,14 +164,14 @@ void max2839_setup(max2839_driver_t* const drv)
|
|||
static uint16_t max2839_read(max2839_driver_t* const drv, uint8_t r)
|
||||
{
|
||||
uint16_t value = (1 << 15) | (r << 10);
|
||||
spi_bus_transfer(drv->bus, &value, 1);
|
||||
spi_bus_transfer(drv->bus, drv->config, &value, 1);
|
||||
return value & 0x3ff;
|
||||
}
|
||||
|
||||
static void max2839_write(max2839_driver_t* const drv, uint8_t r, uint16_t v)
|
||||
{
|
||||
uint16_t value = (r << 10) | (v & 0x3ff);
|
||||
spi_bus_transfer(drv->bus, &value, 1);
|
||||
spi_bus_transfer(drv->bus, drv->config, &value, 1);
|
||||
}
|
||||
|
||||
uint16_t max2839_reg_read(max2839_driver_t* const drv, uint8_t r)
|
||||
|
|
@ -239,54 +245,61 @@ void max2839_stop(max2839_driver_t* const drv)
|
|||
max2839_set_mode(drv, MAX2839_MODE_SHUTDOWN);
|
||||
}
|
||||
|
||||
void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq)
|
||||
/* Assume 40 MHz reference clock with R divider of 1. */
|
||||
#define PFD_FREQ_HZ (40ULL * (1000ULL * 1000ULL))
|
||||
|
||||
#define MIN_FREQ FP_MHZ(2000)
|
||||
#define MAX_FREQ FP_MHZ(3000)
|
||||
|
||||
fp_40_24_t max2839_set_frequency(
|
||||
max2839_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program)
|
||||
{
|
||||
uint8_t band;
|
||||
uint32_t div_frac;
|
||||
uint32_t div_int;
|
||||
uint32_t div_rem;
|
||||
uint32_t div_cmp;
|
||||
int i;
|
||||
uint64_t div;
|
||||
|
||||
freq = MIN(freq, MAX_FREQ);
|
||||
freq = MAX(freq, MIN_FREQ);
|
||||
|
||||
/* Select band. Allow tuning outside specified bands. */
|
||||
if (freq < 2400000000U) {
|
||||
if (freq < FP_MHZ(2400)) {
|
||||
band = MAX2839_LOGEN_BSW_2_3;
|
||||
} else if (freq < 2500000000U) {
|
||||
} else if (freq < FP_MHZ(2500)) {
|
||||
band = MAX2839_LOGEN_BSW_2_4;
|
||||
} else if (freq < 2600000000U) {
|
||||
} else if (freq < FP_MHZ(2600)) {
|
||||
band = MAX2839_LOGEN_BSW_2_5;
|
||||
} else {
|
||||
band = MAX2839_LOGEN_BSW_2_6;
|
||||
}
|
||||
|
||||
/* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */
|
||||
freq += (30000000 >> 21); /* round to nearest frequency */
|
||||
div_int = freq / 30000000;
|
||||
div_rem = freq % 30000000;
|
||||
div_frac = 0;
|
||||
div_cmp = 30000000;
|
||||
for (i = 0; i < 20; i++) {
|
||||
div_frac <<= 1;
|
||||
div_rem <<= 1;
|
||||
if (div_rem >= div_cmp) {
|
||||
div_frac |= 0x1;
|
||||
div_rem -= div_cmp;
|
||||
}
|
||||
fp_40_24_t vco = (freq * 4) / 3;
|
||||
|
||||
vco += ((PFD_FREQ_HZ * FP_ONE_HZ) >> 21); /* round to nearest frequency */
|
||||
div = vco / PFD_FREQ_HZ;
|
||||
|
||||
/*
|
||||
* Shift from 40.24 fixed-point to 44.20 to match 20-bit fractional
|
||||
* divider.
|
||||
*/
|
||||
div = div >> 4;
|
||||
|
||||
if (program) {
|
||||
/* Band settings */
|
||||
set_MAX2839_LOGEN_BSW(drv, band);
|
||||
|
||||
/*
|
||||
* Write order matters here, so commit INT and FRAC_HI before
|
||||
* committing FRAC_LO, which is the trigger for VCO auto-select.
|
||||
*/
|
||||
set_MAX2839_SYN_INT(drv, (div >> 20) & 0xff);
|
||||
set_MAX2839_SYN_FRAC_HI(drv, (div >> 10) & 0x3ff);
|
||||
max2839_regs_commit(drv);
|
||||
set_MAX2839_SYN_FRAC_LO(drv, div & 0x3ff);
|
||||
max2839_regs_commit(drv);
|
||||
}
|
||||
|
||||
/* Band settings */
|
||||
set_MAX2839_LOGEN_BSW(drv, band);
|
||||
|
||||
/* Write order matters here, so commit INT and FRAC_HI before
|
||||
* committing FRAC_LO, which is the trigger for VCO
|
||||
* auto-select. TODO - it's cleaner this way, but it would be
|
||||
* faster to explicitly commit the registers explicitly so the
|
||||
* dirty bits aren't scanned twice. */
|
||||
set_MAX2839_SYN_INT(drv, div_int);
|
||||
set_MAX2839_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff);
|
||||
max2839_regs_commit(drv);
|
||||
set_MAX2839_SYN_FRAC_LO(drv, div_frac & 0x3ff);
|
||||
max2839_regs_commit(drv);
|
||||
return ((PFD_FREQ_HZ * 3) / 4) * (div << 4);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Will Code <willcode4@gmail.com>
|
||||
* Copyright 2014 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
|
|
@ -21,12 +21,12 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2839_H
|
||||
#define __MAX2839_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#include "gpio.h"
|
||||
#include "spi_bus.h"
|
||||
|
||||
|
|
@ -44,19 +44,19 @@ typedef enum {
|
|||
MAX2839_MODE_CLKOUT,
|
||||
} max2839_mode_t;
|
||||
|
||||
struct max2839_driver_t; // IWYU pragma: keep - fixed in #1704
|
||||
typedef struct max2839_driver_t max2839_driver_t;
|
||||
|
||||
struct max2839_driver_t {
|
||||
typedef struct _max2839_driver_t {
|
||||
spi_bus_t* bus;
|
||||
void* config;
|
||||
gpio_t gpio_enable;
|
||||
gpio_t gpio_rxtx;
|
||||
void (*target_init)(max2839_driver_t* const drv);
|
||||
void (*set_mode)(max2839_driver_t* const drv, const max2839_mode_t new_mode);
|
||||
void (*target_init)(struct _max2839_driver_t* const drv);
|
||||
void (*set_mode)(
|
||||
struct _max2839_driver_t* const drv,
|
||||
const max2839_mode_t new_mode);
|
||||
max2839_mode_t mode;
|
||||
uint16_t regs[MAX2839_NUM_REGS];
|
||||
uint32_t regs_dirty;
|
||||
};
|
||||
} max2839_driver_t;
|
||||
|
||||
/* Initialize chip. */
|
||||
extern void max2839_setup(max2839_driver_t* const drv);
|
||||
|
|
@ -81,9 +81,11 @@ void max2839_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode
|
|||
extern void max2839_start(max2839_driver_t* const drv);
|
||||
extern void max2839_stop(max2839_driver_t* const drv);
|
||||
|
||||
/* Set frequency in Hz. Frequency setting is a multi-step function
|
||||
* where order of register writes matters. */
|
||||
extern void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq);
|
||||
/* Set frequency in 1/(2**24) Hz. */
|
||||
extern fp_40_24_t max2839_set_frequency(
|
||||
max2839_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program);
|
||||
uint32_t max2839_set_lpf_bandwidth(
|
||||
max2839_driver_t* const drv,
|
||||
const uint32_t bandwidth_hz);
|
||||
|
|
@ -93,5 +95,3 @@ bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db)
|
|||
|
||||
extern void max2839_tx(max2839_driver_t* const drv);
|
||||
extern void max2839_rx(max2839_driver_t* const drv);
|
||||
|
||||
#endif // __MAX2839_H
|
||||
|
|
|
|||
|
|
@ -1,7 +1,26 @@
|
|||
/* -*- mode: c -*- */
|
||||
/* -*- mode: c -*- *
|
||||
* Copyright 2012 Michael Ossmann
|
||||
* Copyright 2025-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2839_REGS_DEF
|
||||
#define __MAX2839_REGS_DEF
|
||||
#pragma once
|
||||
|
||||
/* Generate static inline accessors that operate on the global
|
||||
* regs. Done this way to (1) allow defs to be scraped out and used
|
||||
|
|
@ -255,5 +274,3 @@ __MREG__(MAX2839_PA_DAC_Voltage_Mode_Output_Select,30,9,1)
|
|||
__MREG__(MAX2839_TX_DC_Offset_Correction_QChannel,31,5,6)
|
||||
__MREG__(MAX2839_RESERVED_31_8,31,8,3)
|
||||
__MREG__(MAX2839_PA_DAC_Clk_Divide_Ratio,31,9,1)
|
||||
|
||||
#endif // __MAX2839_REGS_DEF
|
||||
|
|
|
|||
|
|
@ -21,12 +21,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2839_TARGET_H
|
||||
#define __MAX2839_TARGET_H
|
||||
|
||||
#include "max2839.h"
|
||||
|
||||
void max2839_target_init(max2839_driver_t* const drv);
|
||||
void max2839_target_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode);
|
||||
|
||||
#endif // __MAX2839_TARGET_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Will Code <willcode4@gmail.com>
|
||||
* Copyright 2014 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
|
|
@ -21,171 +21,203 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "max283x.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/ssp.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#include "platform_detect.h"
|
||||
#include "platform_gpio.h"
|
||||
#include "spi_bus.h"
|
||||
#if defined(PRALINE)
|
||||
#include "max2831.h"
|
||||
|
||||
#ifdef IS_PRALINE
|
||||
#include "max2831_target.h"
|
||||
#else
|
||||
#include "max2837.h"
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
#include "max2837_target.h"
|
||||
#include "max2839.h"
|
||||
#endif
|
||||
#ifdef IS_H1_R9
|
||||
#include "max2839_target.h"
|
||||
#endif
|
||||
|
||||
extern spi_bus_t spi_bus_ssp1;
|
||||
/* Driver instance. */
|
||||
ssp_config_t ssp_config_max283x = {
|
||||
/* FIXME speed up once everything is working reliably */
|
||||
/*
|
||||
// Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
|
||||
const uint8_t serial_clock_rate = 32;
|
||||
const uint8_t clock_prescale_rate = 128;
|
||||
*/
|
||||
// Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
|
||||
.serial_clock_rate = 21,
|
||||
.clock_prescale_rate = 2,
|
||||
};
|
||||
|
||||
#ifdef PRALINE
|
||||
max283x_driver_t max283x = {};
|
||||
|
||||
#ifdef IS_PRALINE
|
||||
max2831_driver_t max2831 = {
|
||||
.bus = &spi_bus_ssp1,
|
||||
.config = &ssp_config_max283x,
|
||||
.target_init = max2831_target_init,
|
||||
.set_mode = max2831_target_set_mode,
|
||||
};
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef IS_NOT_PRALINE
|
||||
max2837_driver_t max2837 = {
|
||||
.bus = &spi_bus_ssp1,
|
||||
.config = &ssp_config_max283x,
|
||||
.target_init = max2837_target_init,
|
||||
.set_mode = max2837_target_set_mode,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef IS_HACKRF_ONE
|
||||
max2839_driver_t max2839 = {
|
||||
.bus = &spi_bus_ssp1,
|
||||
.config = &ssp_config_max283x,
|
||||
.target_init = max2839_target_init,
|
||||
.set_mode = max2839_target_set_mode,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Initialize chip. */
|
||||
void max283x_setup(max283x_driver_t* const drv, max283x_variant_t type)
|
||||
void max283x_setup(max283x_driver_t* const drv)
|
||||
{
|
||||
drv->type = type;
|
||||
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
|
||||
/* MAX283x GPIO PinMux */
|
||||
#if defined(PRALINE)
|
||||
max2831.gpio_enable = gpio->max283x_enable;
|
||||
max2831.gpio_rxtx = gpio->max283x_rx_enable;
|
||||
max2831.gpio_rxhp = gpio->max2831_rxhp;
|
||||
max2831.gpio_ld = gpio->max2831_ld;
|
||||
#else
|
||||
max2837.gpio_enable = gpio->max283x_enable;
|
||||
max2837.gpio_rx_enable = gpio->max283x_rx_enable;
|
||||
max2837.gpio_tx_enable = gpio->max283x_tx_enable;
|
||||
max2839.gpio_enable = gpio->max283x_enable;
|
||||
max2839.gpio_rxtx = gpio->max283x_rx_enable;
|
||||
#endif
|
||||
|
||||
switch (type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
ssp_config_max283x.gpio_select = gpio->max283x_select;
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
ssp_config_max283x.data_bits = SSP_DATA_9BITS;
|
||||
drv->type = MAX2831_VARIANT;
|
||||
max2831.gpio_enable = gpio->max283x_enable;
|
||||
max2831.gpio_rxtx = gpio->max283x_rx_enable;
|
||||
max2831.gpio_rxhp = gpio->max2831_rxhp;
|
||||
max2831.gpio_ld = gpio->max2831_ld;
|
||||
memcpy(&drv->drv.max2831, &max2831, sizeof(max2831));
|
||||
max2831_setup(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
memcpy(&drv->drv.max2837, &max2837, sizeof(max2837));
|
||||
max2837_setup(&drv->drv.max2837);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
memcpy(&drv->drv.max2839, &max2839, sizeof(max2839));
|
||||
max2839_setup(&drv->drv.max2839);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
ssp_config_max283x.data_bits = SSP_DATA_16BITS;
|
||||
#ifdef IS_H1_R9
|
||||
if (IS_H1_R9) {
|
||||
drv->type = MAX2839_VARIANT;
|
||||
max2839.gpio_enable = gpio->max283x_enable;
|
||||
max2839.gpio_rxtx = gpio->max283x_rx_enable;
|
||||
memcpy(&drv->drv.max2839, &max2839, sizeof(max2839));
|
||||
max2839_setup(&drv->drv.max2839);
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_NOT_H1_R9
|
||||
if (IS_NOT_H1_R9) {
|
||||
drv->type = MAX2837_VARIANT;
|
||||
max2837.gpio_enable = gpio->max283x_enable;
|
||||
max2837.gpio_rx_enable = gpio->max283x_rx_enable;
|
||||
max2837.gpio_tx_enable = gpio->max283x_tx_enable;
|
||||
memcpy(&drv->drv.max2837, &max2837, sizeof(max2837));
|
||||
max2837_setup(&drv->drv.max2837);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Macros to simplify dispatch of variant-specific operations. */
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#if UNIVERSAL
|
||||
// UNIVERSAL: all variants
|
||||
#define DISPATCH(_drv, _max2831, _max2837, _max2839) \
|
||||
if (_drv->type == MAX2831_VARIANT) { \
|
||||
_max2831; \
|
||||
} else if (_drv->type == MAX2837_VARIANT) { \
|
||||
_max2837; \
|
||||
} else { \
|
||||
_max2839; \
|
||||
}
|
||||
#elif HACKRF_ONE
|
||||
// HACKRF_ONE: MAX2837 and MAX2839 only
|
||||
#define DISPATCH(_drv, _max2831, _max2837, _max2839) \
|
||||
if (_drv->type == MAX2837_VARIANT) { \
|
||||
_max2837; \
|
||||
} else { \
|
||||
_max2839; \
|
||||
}
|
||||
#elif PRALINE
|
||||
// PRALINE: MAX2831 only
|
||||
#define DISPATCH(_drv, _max2831, _max2837, _max2839) \
|
||||
(void) drv; \
|
||||
_max2831
|
||||
#else
|
||||
// JAWBREAKER, RAD1O: MAX2837 only
|
||||
#define DISPATCH(_drv, _max2831, _max2837, _max2839) \
|
||||
(void) drv; \
|
||||
_max2837
|
||||
#endif
|
||||
|
||||
#define CALL(_drv, _func, ...) \
|
||||
DISPATCH(drv, \
|
||||
max2831_ ## _func(&_drv->drv.max2831, ##__VA_ARGS__), \
|
||||
max2837_ ## _func(&_drv->drv.max2837, ##__VA_ARGS__), \
|
||||
max2839_ ## _func(&_drv->drv.max2839, ##__VA_ARGS__) \
|
||||
); \
|
||||
|
||||
#define RESULT(_drv, _type, _func, ...) ({ \
|
||||
_type _result; \
|
||||
DISPATCH(drv, \
|
||||
_result = max2831_ ## _func(&_drv->drv.max2831, ##__VA_ARGS__), \
|
||||
_result = max2837_ ## _func(&_drv->drv.max2837, ##__VA_ARGS__), \
|
||||
_result = max2839_ ## _func(&_drv->drv.max2839, ##__VA_ARGS__) \
|
||||
); \
|
||||
_result; \
|
||||
})
|
||||
|
||||
#define CONSTANT(_drv, _type, _name) ({\
|
||||
_type value; \
|
||||
DISPATCH(drv, \
|
||||
value = MAX2831_ ## _name, \
|
||||
value = MAX2837_ ## _name, \
|
||||
value = MAX2839_ ## _name \
|
||||
); \
|
||||
value; \
|
||||
})
|
||||
|
||||
#define PRALINE_ONLY(_drv, _max2831) DISPATCH(_drv, _max2831, , )
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/* Returns the number of registers supported by the driver. */
|
||||
uint16_t max283x_num_regs(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
return MAX2831_NUM_REGS;
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return MAX2837_NUM_REGS;
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return MAX2839_NUM_REGS;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
return CONSTANT(drv, uint16_t, NUM_REGS);
|
||||
}
|
||||
|
||||
/* Returns the maximum data register value supported by the driver. */
|
||||
uint16_t max283x_data_regs_max_value(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
return MAX2831_DATA_REGS_MAX_VALUE;
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return MAX2837_DATA_REGS_MAX_VALUE;
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return MAX2839_DATA_REGS_MAX_VALUE;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
return CONSTANT(drv, uint16_t, DATA_REGS_MAX_VALUE);
|
||||
}
|
||||
|
||||
/* Read a register via SPI. Save a copy to memory and return
|
||||
* value. Mark clean. */
|
||||
uint16_t max283x_reg_read(max283x_driver_t* const drv, uint8_t r)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
return max2831_reg_read(&drv->drv.max2831, r);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return max2837_reg_read(&drv->drv.max2837, r);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return max2839_reg_read(&drv->drv.max2839, r);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
return RESULT(drv, uint16_t, reg_read, r);
|
||||
}
|
||||
|
||||
/* Write value to register via SPI and save a copy to memory. Mark
|
||||
* clean. */
|
||||
void max283x_reg_write(max283x_driver_t* const drv, uint8_t r, uint16_t v)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_reg_write(&drv->drv.max2831, r, v);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_reg_write(&drv->drv.max2837, r, v);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_reg_write(&drv->drv.max2839, r, v);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
CALL(drv, reg_write, r, v);
|
||||
}
|
||||
|
||||
/* Write all dirty registers via SPI from memory. Mark all clean. Some
|
||||
|
|
@ -193,120 +225,45 @@ void max283x_reg_write(max283x_driver_t* const drv, uint8_t r, uint16_t v)
|
|||
* provided routines for those operations. */
|
||||
void max283x_regs_commit(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_regs_commit(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_regs_commit(&drv->drv.max2837);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_regs_commit(&drv->drv.max2839);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
CALL(drv, regs_commit);
|
||||
}
|
||||
|
||||
void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_set_mode(&drv->drv.max2831, (max2831_mode_t) new_mode);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_set_mode(&drv->drv.max2837, (max2837_mode_t) new_mode);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_set_mode(&drv->drv.max2839, (max2839_mode_t) new_mode);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
DISPATCH(
|
||||
drv,
|
||||
max2831_set_mode(&drv->drv.max2831, (max2831_mode_t) new_mode),
|
||||
max2837_set_mode(&drv->drv.max2837, (max2837_mode_t) new_mode),
|
||||
max2839_set_mode(&drv->drv.max2839, (max2839_mode_t) new_mode));
|
||||
}
|
||||
|
||||
max283x_mode_t max283x_mode(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
return (max283x_mode_t) max2831_mode(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return (max283x_mode_t) max2837_mode(&drv->drv.max2837);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return (max283x_mode_t) max2839_mode(&drv->drv.max2839);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
DISPATCH(
|
||||
drv,
|
||||
return (max283x_mode_t) max2831_mode(&drv->drv.max2831),
|
||||
return (max283x_mode_t) max2837_mode(&drv->drv.max2837),
|
||||
return (max283x_mode_t) max2839_mode(&drv->drv.max2839));
|
||||
}
|
||||
|
||||
/* Turn on/off all chip functions. Does not control oscillator and CLKOUT */
|
||||
void max283x_start(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_start(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_start(&drv->drv.max2837);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_start(&drv->drv.max2839);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
CALL(drv, start);
|
||||
}
|
||||
|
||||
void max283x_stop(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_stop(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_stop(&drv->drv.max2837);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_stop(&drv->drv.max2839);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
CALL(drv, stop);
|
||||
}
|
||||
|
||||
/* Set frequency in Hz. Frequency setting is a multi-step function
|
||||
* where order of register writes matters. */
|
||||
void max283x_set_frequency(max283x_driver_t* const drv, uint32_t freq)
|
||||
/* Set frequency in 1/(2**24) Hz. */
|
||||
fp_40_24_t max283x_set_frequency(
|
||||
max283x_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_set_frequency(&drv->drv.max2831, freq);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_set_frequency(&drv->drv.max2837, freq);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_set_frequency(&drv->drv.max2839, freq);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return RESULT(drv, fp_40_24_t, set_frequency, freq, program);
|
||||
}
|
||||
|
||||
uint32_t max283x_set_lpf_bandwidth(
|
||||
|
|
@ -314,194 +271,61 @@ uint32_t max283x_set_lpf_bandwidth(
|
|||
const max283x_mode_t mode,
|
||||
const uint32_t bandwidth_hz)
|
||||
{
|
||||
#ifndef PRALINE
|
||||
(void) mode;
|
||||
#endif
|
||||
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
DISPATCH(
|
||||
drv,
|
||||
return max2831_set_lpf_bandwidth(
|
||||
&drv->drv.max2831,
|
||||
(max2831_mode_t) mode,
|
||||
bandwidth_hz);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return max2837_set_lpf_bandwidth(&drv->drv.max2837, bandwidth_hz);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return max2839_set_lpf_bandwidth(&drv->drv.max2839, bandwidth_hz);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
bandwidth_hz),
|
||||
return max2837_set_lpf_bandwidth(&drv->drv.max2837, bandwidth_hz),
|
||||
return max2839_set_lpf_bandwidth(&drv->drv.max2839, bandwidth_hz));
|
||||
}
|
||||
|
||||
bool max283x_set_lna_gain(max283x_driver_t* const drv, const uint32_t gain_db)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
return max2831_set_lna_gain(&drv->drv.max2831, gain_db);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return max2837_set_lna_gain(&drv->drv.max2837, gain_db);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return max2839_set_lna_gain(&drv->drv.max2839, gain_db);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
return RESULT(drv, bool, set_lna_gain, gain_db);
|
||||
}
|
||||
|
||||
bool max283x_set_vga_gain(max283x_driver_t* const drv, const uint32_t gain_db)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
return max2831_set_vga_gain(&drv->drv.max2831, gain_db);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return max2837_set_vga_gain(&drv->drv.max2837, gain_db);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return max2839_set_vga_gain(&drv->drv.max2839, gain_db);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
return RESULT(drv, bool, set_vga_gain, gain_db);
|
||||
}
|
||||
|
||||
bool max283x_set_txvga_gain(max283x_driver_t* const drv, const uint32_t gain_db)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
return max2831_set_txvga_gain(&drv->drv.max2831, gain_db);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
return max2837_set_txvga_gain(&drv->drv.max2837, gain_db);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
return max2839_set_txvga_gain(&drv->drv.max2839, gain_db);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
return RESULT(drv, bool, set_txvga_gain, gain_db);
|
||||
}
|
||||
|
||||
void max283x_tx(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_tx(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_tx(&drv->drv.max2837);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_tx(&drv->drv.max2839);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
CALL(drv, tx);
|
||||
}
|
||||
|
||||
void max283x_rx(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_rx(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
max2837_rx(&drv->drv.max2837);
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
max2839_rx(&drv->drv.max2839);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
CALL(drv, rx);
|
||||
}
|
||||
|
||||
/* Set MAX2831 receiver high-pass filter corner frequency in Hz */
|
||||
void max283x_set_rx_hpf_frequency(
|
||||
max283x_driver_t* const drv,
|
||||
const max283x_rx_hpf_freq_t freq)
|
||||
{
|
||||
#ifndef PRALINE
|
||||
(void) freq;
|
||||
#endif
|
||||
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
PRALINE_ONLY(
|
||||
drv,
|
||||
max2831_set_rx_hpf_frequency(
|
||||
&drv->drv.max2831,
|
||||
(max2831_rx_hpf_freq_t) freq);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
// unsupported
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
// unsupported
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
(max2831_rx_hpf_freq_t) freq));
|
||||
}
|
||||
|
||||
void max283x_tx_calibration(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_tx_calibration(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
// unsupported - use max283x_set_mode instead
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
// unsupported - use max283x_set_mode instead
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
PRALINE_ONLY(drv, max2831_tx_calibration(&drv->drv.max2831));
|
||||
}
|
||||
|
||||
void max283x_rx_calibration(max283x_driver_t* const drv)
|
||||
{
|
||||
switch (drv->type) {
|
||||
#ifdef PRALINE
|
||||
case MAX2831_VARIANT:
|
||||
max2831_rx_calibration(&drv->drv.max2831);
|
||||
break;
|
||||
#else
|
||||
case MAX2837_VARIANT:
|
||||
// unsupported - use max283x_set_mode instead
|
||||
break;
|
||||
|
||||
case MAX2839_VARIANT:
|
||||
// unsupported - use max283x_set_mode instead
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
PRALINE_ONLY(drv, max2831_rx_calibration(&drv->drv.max2831));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012 Will Code <willcode4@gmail.com>
|
||||
* Copyright 2014 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
|
|
@ -21,16 +21,21 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX283x_H
|
||||
#define __MAX283x_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(PRALINE)
|
||||
#include "fixed_point.h"
|
||||
#include "spi_ssp.h"
|
||||
|
||||
#ifdef IS_PRALINE
|
||||
#include "max2831.h"
|
||||
#else
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
#include "max2837.h"
|
||||
#endif
|
||||
#ifdef IS_H1_R9
|
||||
#include "max2839.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -52,10 +57,13 @@ typedef enum {
|
|||
} max283x_rx_hpf_freq_t;
|
||||
|
||||
typedef enum {
|
||||
#ifdef PRALINE
|
||||
#ifdef IS_PRALINE
|
||||
MAX2831_VARIANT,
|
||||
#else
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
MAX2837_VARIANT,
|
||||
#endif
|
||||
#ifdef IS_H1_R9
|
||||
MAX2839_VARIANT,
|
||||
#endif
|
||||
} max283x_variant_t;
|
||||
|
|
@ -64,17 +72,20 @@ typedef struct {
|
|||
max283x_variant_t type;
|
||||
|
||||
union {
|
||||
#ifdef PRALINE
|
||||
#ifdef IS_PRALINE
|
||||
max2831_driver_t max2831;
|
||||
#else
|
||||
#endif
|
||||
#ifdef IS_NOT_PRALINE
|
||||
max2837_driver_t max2837;
|
||||
#endif
|
||||
#ifdef IS_H1_R9
|
||||
max2839_driver_t max2839;
|
||||
#endif
|
||||
} drv;
|
||||
} max283x_driver_t;
|
||||
|
||||
/* Initialize chip. */
|
||||
void max283x_setup(max283x_driver_t* const drv, max283x_variant_t type);
|
||||
void max283x_setup(max283x_driver_t* const drv);
|
||||
|
||||
/* Returns the number of registers supported by the driver. */
|
||||
uint16_t max283x_num_regs(max283x_driver_t* const drv);
|
||||
|
|
@ -102,9 +113,11 @@ void max283x_set_mode(max283x_driver_t* const drv, const max283x_mode_t new_mode
|
|||
void max283x_start(max283x_driver_t* const drv);
|
||||
void max283x_stop(max283x_driver_t* const drv);
|
||||
|
||||
/* Set frequency in Hz. Frequency setting is a multi-step function
|
||||
* where order of register writes matters. */
|
||||
void max283x_set_frequency(max283x_driver_t* const drv, uint32_t freq);
|
||||
/* Set frequency in 1/(2**24) Hz. */
|
||||
fp_40_24_t max283x_set_frequency(
|
||||
max283x_driver_t* const drv,
|
||||
fp_40_24_t freq,
|
||||
bool program);
|
||||
uint32_t max283x_set_lpf_bandwidth(
|
||||
max283x_driver_t* const drv,
|
||||
const max283x_mode_t mode,
|
||||
|
|
@ -127,4 +140,6 @@ void max283x_set_rx_hpf_frequency(
|
|||
void max283x_tx_calibration(max283x_driver_t* const drv);
|
||||
void max283x_rx_calibration(max283x_driver_t* const drv);
|
||||
|
||||
#endif // __MAX283x_H
|
||||
/* Driver instance. */
|
||||
extern ssp_config_t ssp_config_max283x;
|
||||
extern max283x_driver_t max283x;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2015-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2015-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -24,18 +24,23 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#include "max2871_regs.h"
|
||||
#include "selftest.h"
|
||||
#include "platform_scu.h"
|
||||
#include "selftest.h"
|
||||
|
||||
#if (defined DEBUG)
|
||||
#include <stdio.h>
|
||||
#define LOG printf
|
||||
#else
|
||||
#define LOG(x, ...)
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
#endif
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
static uint32_t max2871_spi_read(max2871_driver_t* const drv);
|
||||
static void max2871_spi_write(max2871_driver_t* const drv, uint8_t r, uint32_t v);
|
||||
static void max2871_write_registers(max2871_driver_t* const drv);
|
||||
|
|
@ -132,7 +137,7 @@ void max2871_setup(max2871_driver_t* const drv)
|
|||
|
||||
max2871_write_registers(drv);
|
||||
|
||||
max2871_set_frequency(drv, 3500);
|
||||
max2871_set_frequency(drv, FP_MHZ(3500), true);
|
||||
}
|
||||
|
||||
static void delay_ms(int ms)
|
||||
|
|
@ -228,9 +233,16 @@ static void max2871_write_registers(max2871_driver_t* const drv)
|
|||
}
|
||||
}
|
||||
|
||||
/* Set frequency (MHz). */
|
||||
uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz)
|
||||
#define MIN_LO FP_MHZ(40)
|
||||
#define MAX_LO FP_MHZ(6000)
|
||||
|
||||
/* Set frequency in 1/(2**24) Hz, rounded to nearest 40 MHz. */
|
||||
fp_40_24_t max2871_set_frequency(max2871_driver_t* const drv, fp_40_24_t lo, bool program)
|
||||
{
|
||||
lo = MIN(lo, MAX_LO);
|
||||
lo = MAX(lo, MIN_LO);
|
||||
|
||||
uint16_t mhz = lo / FP_ONE_MHZ;
|
||||
int n = mhz / 40;
|
||||
int diva = 0;
|
||||
|
||||
|
|
@ -239,19 +251,21 @@ uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz)
|
|||
diva += 1;
|
||||
}
|
||||
|
||||
max2871_set_RFA_EN(0);
|
||||
max2871_write_registers(drv);
|
||||
if (program) {
|
||||
max2871_set_RFA_EN(0);
|
||||
max2871_write_registers(drv);
|
||||
|
||||
max2871_set_N(n);
|
||||
max2871_set_DIVA(diva);
|
||||
max2871_write_registers(drv);
|
||||
max2871_set_N(n);
|
||||
max2871_set_DIVA(diva);
|
||||
max2871_write_registers(drv);
|
||||
|
||||
while (max2871_spi_read(drv) & MAX2871_VASA) {}
|
||||
while (max2871_spi_read(drv) & MAX2871_VASA) {}
|
||||
|
||||
max2871_set_RFA_EN(1);
|
||||
max2871_write_registers(drv);
|
||||
max2871_set_RFA_EN(1);
|
||||
max2871_write_registers(drv);
|
||||
}
|
||||
|
||||
return (mhz / 40) * 40 * 1000000;
|
||||
return (mhz / 40) * FP_MHZ(40);
|
||||
}
|
||||
|
||||
void max2871_enable(max2871_driver_t* const drv)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2017-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -19,11 +19,11 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef MAX2871_H
|
||||
#define MAX2871_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#include "gpio.h"
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -36,7 +36,9 @@ typedef struct {
|
|||
} max2871_driver_t;
|
||||
|
||||
extern void max2871_setup(max2871_driver_t* const drv);
|
||||
extern uint64_t max2871_set_frequency(max2871_driver_t* const drv, uint16_t mhz);
|
||||
extern fp_40_24_t max2871_set_frequency(
|
||||
max2871_driver_t* const drv,
|
||||
fp_40_24_t lo,
|
||||
bool program);
|
||||
extern void max2871_enable(max2871_driver_t* const drv);
|
||||
extern void max2871_disable(max2871_driver_t* const drv);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef MAX2871_REGS_H
|
||||
#define MAX2871_REGS_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX2871_VASA (1 << 9)
|
||||
|
|
@ -75,4 +75,3 @@ void max2871_set_F01(uint32_t v);
|
|||
void max2871_set_LD(uint32_t v);
|
||||
void max2871_set_ADCS(uint32_t v);
|
||||
void max2871_set_ADCM(uint32_t v);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,9 +24,34 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libopencm3/lpc43xx/ssp.h>
|
||||
|
||||
#include "max5864_target.h"
|
||||
#include "platform_gpio.h"
|
||||
#include "spi_bus.h"
|
||||
|
||||
/* Driver instance. */
|
||||
ssp_config_t ssp_config_max5864 = {
|
||||
/* FIXME speed up once everything is working reliably */
|
||||
/*
|
||||
// Freq About 0.0498MHz / 49.8KHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
|
||||
const uint8_t serial_clock_rate = 32;
|
||||
const uint8_t clock_prescale_rate = 128;
|
||||
*/
|
||||
// Freq About 4.857MHz => Freq = PCLK / (CPSDVSR * [SCR+1]) with PCLK=PLL1=204MHz
|
||||
.data_bits = SSP_DATA_8BITS,
|
||||
.serial_clock_rate = 21,
|
||||
.clock_prescale_rate = 2,
|
||||
};
|
||||
|
||||
max5864_driver_t max5864 = {
|
||||
.bus = &spi_bus_ssp1,
|
||||
.target_init = max5864_target_init,
|
||||
};
|
||||
|
||||
static void max5864_write(max5864_driver_t* const drv, uint8_t value)
|
||||
{
|
||||
spi_bus_transfer(drv->bus, &value, 1);
|
||||
spi_bus_transfer(drv->bus, &ssp_config_max5864, &value, 1);
|
||||
}
|
||||
|
||||
static void max5864_init(max5864_driver_t* const drv)
|
||||
|
|
@ -36,6 +61,8 @@ static void max5864_init(max5864_driver_t* const drv)
|
|||
|
||||
void max5864_setup(max5864_driver_t* const drv)
|
||||
{
|
||||
ssp_config_max5864.gpio_select = platform_gpio()->max5864_select;
|
||||
|
||||
max5864_init(drv);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,18 +20,15 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX5864_H
|
||||
#define __MAX5864_H
|
||||
#pragma once
|
||||
|
||||
#include "spi_bus.h"
|
||||
#include "spi_ssp.h"
|
||||
|
||||
struct max5864_driver_t; // IWYU pragma: keep - fixed in #1704
|
||||
typedef struct max5864_driver_t max5864_driver_t;
|
||||
|
||||
struct max5864_driver_t {
|
||||
typedef struct _max5864_driver_t {
|
||||
spi_bus_t* const bus;
|
||||
void (*target_init)(max5864_driver_t* const drv);
|
||||
};
|
||||
void (*target_init)(struct _max5864_driver_t* const drv);
|
||||
} max5864_driver_t;
|
||||
|
||||
void max5864_setup(max5864_driver_t* const drv);
|
||||
|
||||
|
|
@ -42,4 +39,6 @@ void max5864_rx(max5864_driver_t* const drv);
|
|||
void max5864_tx(max5864_driver_t* const drv);
|
||||
void max5864_xcvr(max5864_driver_t* const drv);
|
||||
|
||||
#endif // __MAX5864_H
|
||||
/* Driver instance. */
|
||||
extern ssp_config_t ssp_config_max5864;
|
||||
extern max5864_driver_t max5864;
|
||||
|
|
|
|||
|
|
@ -20,11 +20,8 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MAX5864_TARGET_H__
|
||||
#define __MAX5864_TARGET_H__
|
||||
#pragma once
|
||||
|
||||
#include "max5864.h"
|
||||
|
||||
void max5864_target_init(max5864_driver_t* const drv);
|
||||
|
||||
#endif /*__MAX5864_TARGET_H__*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2017-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2017-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
|
|
@ -21,102 +21,146 @@
|
|||
|
||||
#include "mixer.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#include "platform_detect.h"
|
||||
#include "platform_gpio.h"
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
#ifdef IS_RAD1O
|
||||
#include "max2871.h"
|
||||
#endif
|
||||
#ifdef IS_NOT_RAD1O
|
||||
#include "rffc5071.h"
|
||||
#include "rffc5071_spi.h"
|
||||
#include "spi_bus.h"
|
||||
#elif defined(RAD1O)
|
||||
#include "max2871.h"
|
||||
#endif
|
||||
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
#ifdef IS_NOT_RAD1O
|
||||
static rffc5071_spi_config_t rffc5071_spi_config;
|
||||
|
||||
spi_bus_t spi_bus_rffc5071 = {
|
||||
static spi_bus_t spi_bus_rffc5071 = {
|
||||
.config = &rffc5071_spi_config,
|
||||
.start = rffc5071_spi_start,
|
||||
.stop = rffc5071_spi_stop,
|
||||
.transfer = rffc5071_spi_transfer,
|
||||
.transfer_gather = rffc5071_spi_transfer_gather,
|
||||
};
|
||||
#endif
|
||||
|
||||
mixer_driver_t mixer = {
|
||||
.bus = &spi_bus_rffc5071,
|
||||
};
|
||||
#elif defined(RAD1O)
|
||||
mixer_driver_t mixer = {};
|
||||
#ifdef IS_NOT_RAD1O
|
||||
.rffc5071.bus = &spi_bus_rffc5071,
|
||||
#endif
|
||||
};
|
||||
|
||||
void mixer_bus_setup(mixer_driver_t* const mixer)
|
||||
{
|
||||
(void) mixer;
|
||||
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
rffc5071_spi_config = (rffc5071_spi_config_t){
|
||||
.gpio_select = gpio->rffc5072_select,
|
||||
.gpio_clock = gpio->rffc5072_clock,
|
||||
.gpio_data = gpio->rffc5072_data,
|
||||
};
|
||||
spi_bus_start(&spi_bus_rffc5071, &rffc5071_spi_config);
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
|
||||
rffc5071_spi_config = (rffc5071_spi_config_t){
|
||||
.gpio_select = gpio->rffc5072_select,
|
||||
.gpio_clock = gpio->rffc5072_clock,
|
||||
.gpio_data = gpio->rffc5072_data,
|
||||
};
|
||||
spi_bus_start(&spi_bus_rffc5071, &rffc5071_spi_config);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mixer_setup(mixer_driver_t* const mixer)
|
||||
void mixer_setup(mixer_driver_t* const mixer, mixer_variant_t type)
|
||||
{
|
||||
mixer->type = type;
|
||||
|
||||
const platform_gpio_t* gpio = platform_gpio();
|
||||
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
mixer->gpio_reset = gpio->rffc5072_reset;
|
||||
#if defined(PRALINE)
|
||||
mixer->gpio_ld = gpio->rffc5072_ld;
|
||||
#endif
|
||||
rffc5071_setup(mixer);
|
||||
#elif defined(RAD1O)
|
||||
mixer->gpio_vco_ce = gpio->vco_ce;
|
||||
mixer->gpio_vco_sclk = gpio->vco_sclk;
|
||||
mixer->gpio_vco_sdata = gpio->vco_sdata;
|
||||
mixer->gpio_vco_le = gpio->vco_le;
|
||||
mixer->gpio_synt_rfout_en = gpio->synt_rfout_en;
|
||||
mixer->gpio_vco_mux = gpio->vco_mux;
|
||||
max2871_setup(mixer);
|
||||
/* Mixer GPIO serial interface PinMux */
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
mixer->rffc5071.gpio_ld = gpio->rffc5072_ld;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
mixer->rffc5071.gpio_reset = gpio->rffc5072_reset;
|
||||
rffc5071_setup(&mixer->rffc5071);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
mixer->max2871.gpio_vco_ce = gpio->vco_ce;
|
||||
mixer->max2871.gpio_vco_sclk = gpio->vco_sclk;
|
||||
mixer->max2871.gpio_vco_sdata = gpio->vco_sdata;
|
||||
mixer->max2871.gpio_vco_le = gpio->vco_le;
|
||||
mixer->max2871.gpio_synt_rfout_en = gpio->synt_rfout_en;
|
||||
mixer->max2871.gpio_vco_mux = gpio->vco_mux;
|
||||
max2871_setup(&mixer->max2871);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint64_t hz)
|
||||
fp_40_24_t mixer_set_frequency(mixer_driver_t* const mixer, fp_40_24_t lo, bool program)
|
||||
{
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
return rffc5071_set_frequency(mixer, hz);
|
||||
#elif defined(RAD1O)
|
||||
return max2871_set_frequency(mixer, hz / 1000000);
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
return rffc5071_set_frequency(&mixer->rffc5071, lo, program);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
return max2871_set_frequency(&mixer->max2871, lo, program);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mixer_enable(mixer_driver_t* const mixer)
|
||||
{
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
rffc5071_enable(mixer);
|
||||
#elif defined(RAD1O)
|
||||
max2871_enable(mixer);
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
rffc5071_enable(&mixer->rffc5071);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
max2871_enable(&mixer->max2871);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mixer_disable(mixer_driver_t* const mixer)
|
||||
{
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
rffc5071_disable(mixer);
|
||||
#elif defined(RAD1O)
|
||||
max2871_disable(mixer);
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
rffc5071_disable(&mixer->rffc5071);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
max2871_disable(&mixer->max2871);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mixer_set_gpo(mixer_driver_t* const mixer, uint8_t gpo)
|
||||
{
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
rffc5071_set_gpo(mixer, gpo);
|
||||
#elif defined(RAD1O)
|
||||
(void) mixer;
|
||||
(void) gpo;
|
||||
#ifdef IS_NOT_RAD1O
|
||||
if (IS_NOT_RAD1O) {
|
||||
rffc5071_set_gpo(&mixer->rffc5071, gpo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_RAD1O
|
||||
if (IS_RAD1O) {
|
||||
(void) mixer;
|
||||
(void) gpo;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2012-2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
* Copyright 2014 Jared Boone <jared@sharebrained.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
|
|
@ -20,26 +20,49 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MIXER_H
|
||||
#define __MIXER_H
|
||||
#pragma once
|
||||
|
||||
#if defined(JAWBREAKER) || defined(HACKRF_ONE) || defined(PRALINE)
|
||||
#include "rffc5071.h"
|
||||
typedef rffc5071_driver_t mixer_driver_t;
|
||||
#elif defined(RAD1O)
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
#ifdef IS_RAD1O
|
||||
#include "max2871.h"
|
||||
typedef max2871_driver_t mixer_driver_t;
|
||||
#endif
|
||||
#ifdef IS_NOT_RAD1O
|
||||
#include "rffc5071.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
typedef enum {
|
||||
RFFC5071_VARIANT,
|
||||
MAX2871_VARIANT,
|
||||
} mixer_variant_t;
|
||||
|
||||
typedef struct {
|
||||
mixer_variant_t type;
|
||||
|
||||
union {
|
||||
#ifdef IS_RAD1O
|
||||
max2871_driver_t max2871;
|
||||
#endif
|
||||
#ifdef IS_NOT_RAD1O
|
||||
rffc5071_driver_t rffc5071;
|
||||
#endif
|
||||
};
|
||||
} mixer_driver_t;
|
||||
|
||||
extern void mixer_bus_setup(mixer_driver_t* const mixer);
|
||||
extern void mixer_setup(mixer_driver_t* const mixer);
|
||||
extern void mixer_setup(mixer_driver_t* const mixer, mixer_variant_t type);
|
||||
|
||||
/* Set frequency (Hz). */
|
||||
extern uint64_t mixer_set_frequency(mixer_driver_t* const mixer, uint64_t hz);
|
||||
extern fp_40_24_t mixer_set_frequency(
|
||||
mixer_driver_t* const mixer,
|
||||
fp_40_24_t lo,
|
||||
bool program);
|
||||
|
||||
extern void mixer_enable(mixer_driver_t* const mixer);
|
||||
extern void mixer_disable(mixer_driver_t* const mixer);
|
||||
extern void mixer_set_gpo(mixer_driver_t* const drv, uint8_t gpo);
|
||||
|
||||
#endif // __MIXER_H
|
||||
/* Mixer instance. */
|
||||
extern mixer_driver_t mixer;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
#include "gpio.h"
|
||||
#include "gpio_lpc.h"
|
||||
#include "hackrf_core.h"
|
||||
#include "i2c_bus.h"
|
||||
#include "i2c_lpc.h"
|
||||
#include "operacake_sctimer.h"
|
||||
#include "platform_scu.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __OPERACAKE_H
|
||||
#define __OPERACAKE_H
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -57,5 +56,3 @@ uint16_t gpio_test(uint8_t address);
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OPERACAKE_H */
|
||||
|
|
|
|||
|
|
@ -25,14 +25,16 @@
|
|||
#include <libopencm3/lpc43xx/gima.h>
|
||||
#include <libopencm3/lpc43xx/rgu.h>
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
#if !defined(PRALINE)
|
||||
|
||||
#include "delay.h"
|
||||
#include "platform_detect.h"
|
||||
#include "platform_scu.h"
|
||||
#include "sct.h"
|
||||
#ifdef IS_NOT_PRALINE
|
||||
#include <libopencm3/cm3/common.h>
|
||||
#include <libopencm3/lpc43xx/sgpio.h>
|
||||
#endif
|
||||
|
||||
#include "delay.h"
|
||||
#include "sct.h"
|
||||
|
||||
#define U1CTRL_SET SCT_OUT14_SET
|
||||
#define U1CTRL_CLR SCT_OUT14_CLR
|
||||
#define U2CTRL0_SET SCT_OUT13_SET
|
||||
|
|
@ -60,6 +62,8 @@ static uint32_t default_output = 0;
|
|||
*/
|
||||
void operacake_sctimer_init(void)
|
||||
{
|
||||
const platform_scu_t* scu = platform_scu();
|
||||
|
||||
// We start by resetting the SCTimer
|
||||
RESET_CTRL1 = RESET_CTRL1_SCT_RST;
|
||||
|
||||
|
|
@ -71,48 +75,45 @@ void operacake_sctimer_init(void)
|
|||
// there are additional instructions that fill the time. If the duration of
|
||||
// the actions from here to the first access to the SCTimer is changed, then
|
||||
// this delay may need to be increased.
|
||||
delay(8);
|
||||
delay_us(1);
|
||||
|
||||
// Pin definitions for the HackRF
|
||||
// U2CTRL0
|
||||
scu_pinmux(
|
||||
P7_4,
|
||||
SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
scu_pinmux(scu->CTOUT_13, scu->CTOUT_PINCFG);
|
||||
// U2CTRL1
|
||||
scu_pinmux(
|
||||
P7_5,
|
||||
SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
scu_pinmux(scu->CTOUT_12, scu->CTOUT_PINCFG);
|
||||
// U3CTRL0
|
||||
scu_pinmux(
|
||||
P7_6,
|
||||
SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
scu_pinmux(scu->CTOUT_11, scu->CTOUT_PINCFG);
|
||||
// U3CTRL1
|
||||
scu_pinmux(
|
||||
P7_7,
|
||||
SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
scu_pinmux(scu->CTOUT_8, scu->CTOUT_PINCFG);
|
||||
// U1CTRL
|
||||
scu_pinmux(
|
||||
P7_0,
|
||||
SCU_CONF_EPUN_DIS_PULLUP | SCU_CONF_EHS_FAST | SCU_CONF_FUNCTION1);
|
||||
scu_pinmux(scu->CTOUT_14, scu->CTOUT_PINCFG);
|
||||
|
||||
#ifndef PRALINE
|
||||
// Configure the SGPIO to output the clock (f=2 * sample clock) on pin 12
|
||||
SGPIO_OUT_MUX_CFG12 = SGPIO_OUT_MUX_CFG_P_OUT_CFG(0x08) | // clkout output mode
|
||||
SGPIO_OUT_MUX_CFG_P_OE_CFG(0); // gpio_oe
|
||||
SGPIO_GPIO_OENREG |= BIT12;
|
||||
uint8_t sct_clock_input;
|
||||
#ifdef IS_NOT_PRALINE
|
||||
if (IS_NOT_PRALINE) {
|
||||
// Configure the SGPIO to output the clock (f=2 * sample clock) on pin 12
|
||||
SGPIO_OUT_MUX_CFG12 =
|
||||
SGPIO_OUT_MUX_CFG_P_OUT_CFG(0x08) | // clkout output mode
|
||||
SGPIO_OUT_MUX_CFG_P_OE_CFG(0); // gpio_oe
|
||||
SGPIO_GPIO_OENREG |= BIT12;
|
||||
|
||||
// Use the GIMA to connect the SGPIO clock to the SCTimer
|
||||
GIMA_CTIN_1_IN = 0x2 << 4; // Route SGPIO12 to SCTIN1
|
||||
// Use the GIMA to connect the SGPIO clock to the SCTimer
|
||||
GIMA_CTIN_1_IN = 0x2 << 4; // Route SGPIO12 to SCTIN1
|
||||
|
||||
uint8_t sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_1;
|
||||
#else
|
||||
// Configure pin P6_4 as SCT_IN_6
|
||||
scu_pinmux(P6_4, SCU_CLK_IN | SCU_CONF_FUNCTION1);
|
||||
sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_1;
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_PRALINE
|
||||
if (IS_PRALINE) {
|
||||
// Configure pin P6_4 as CTIN_6
|
||||
scu_pinmux(scu->SCT_CLK, scu->SCT_CLK_PINCFG);
|
||||
|
||||
// Use the GIMA to connect MS0/CLK1 (SCT_CLK) on pin P6_4 to the SCTimer
|
||||
GIMA_CTIN_6_IN = 0x0 << 4;
|
||||
// Use the GIMA to connect MS0/CLK1 (SCT_CLK) on pin P6_4 to the SCTimer
|
||||
GIMA_CTIN_6_IN = 0x0 << 4;
|
||||
|
||||
uint8_t sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_6;
|
||||
sct_clock_input = SCT_CONFIG_CKSEL_RISING_EDGES_ON_INPUT_6;
|
||||
}
|
||||
#endif
|
||||
|
||||
// We configure this register first, because the user manual says to
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __OPERACAKE_SCTIMER_H
|
||||
#define __OPERACAKE_SCTIMER_H
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
|
@ -37,5 +36,3 @@ void operacake_sctimer_enable(bool enable);
|
|||
void operacake_sctimer_set_dwell_times(struct operacake_dwell_times* times, int n);
|
||||
void operacake_sctimer_stop(void);
|
||||
void operacake_sctimer_reset_state(void);
|
||||
|
||||
#endif /* __OPERACAKE_SCTIMER_H */
|
||||
|
|
|
|||