116
.github/workflows/ci-tests.yml
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
name: AERIS-10 CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
push:
|
||||
branches: [main, develop]
|
||||
|
||||
jobs:
|
||||
# ===========================================================================
|
||||
# Python: lint (ruff), syntax check (py_compile), unit tests (pytest)
|
||||
# CI structure proposed by hcm444 — uses uv for dependency management
|
||||
# ===========================================================================
|
||||
python-tests:
|
||||
name: Python Lint + Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --group dev
|
||||
|
||||
- name: Ruff lint (whole repo)
|
||||
run: uv run ruff check .
|
||||
|
||||
- name: Syntax check (py_compile)
|
||||
run: |
|
||||
uv run python - <<'PY'
|
||||
import py_compile
|
||||
from pathlib import Path
|
||||
|
||||
skip = {".git", "__pycache__", ".venv", "venv", "docs"}
|
||||
for p in Path(".").rglob("*.py"):
|
||||
if skip & set(p.parts):
|
||||
continue
|
||||
py_compile.compile(str(p), doraise=True)
|
||||
PY
|
||||
|
||||
- name: Unit tests
|
||||
run: >
|
||||
uv run pytest
|
||||
firmware/9_3_GUI/test_GUI_V65_Tk.py
|
||||
firmware/9_3_GUI/test_v7.py
|
||||
-v --tb=short
|
||||
|
||||
# ===========================================================================
|
||||
# MCU Firmware Unit Tests (20 tests)
|
||||
# Bug regression (15) + Gap-3 safety tests (5)
|
||||
# ===========================================================================
|
||||
mcu-tests:
|
||||
name: MCU Firmware Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install build tools
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential
|
||||
|
||||
- name: Build and run MCU tests
|
||||
run: make test
|
||||
working-directory: firmware/9_1_Microcontroller/tests
|
||||
|
||||
# ===========================================================================
|
||||
# FPGA RTL Regression (25 testbenches + lint)
|
||||
# ===========================================================================
|
||||
fpga-regression:
|
||||
name: FPGA Regression
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Icarus Verilog
|
||||
run: sudo apt-get update && sudo apt-get install -y iverilog
|
||||
|
||||
- name: Run full FPGA regression
|
||||
run: bash run_regression.sh
|
||||
working-directory: firmware/9_2_FPGA
|
||||
|
||||
# ===========================================================================
|
||||
# Cross-Layer Contract Tests (Python ↔ Verilog ↔ C)
|
||||
# Validates opcode maps, bit widths, packet layouts, and round-trip
|
||||
# correctness across FPGA RTL, Python GUI, and STM32 firmware.
|
||||
# ===========================================================================
|
||||
cross-layer-tests:
|
||||
name: Cross-Layer Contract Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync --group dev
|
||||
|
||||
- name: Install Icarus Verilog
|
||||
run: sudo apt-get update && sudo apt-get install -y iverilog
|
||||
|
||||
- name: Run cross-layer contract tests
|
||||
run: >
|
||||
uv run pytest
|
||||
firmware/tests/cross_layer/test_cross_layer_contract.py
|
||||
-v --tb=short
|
||||
59
.gitignore
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
# Verilog simulation artifacts
|
||||
*.vvp
|
||||
*.vcd
|
||||
|
||||
# Debug / scratch RTL (not part of the design)
|
||||
firmware/9_2_FPGA/debug_*.v
|
||||
firmware/9_2_FPGA/tb/tb_fft_debug*.v
|
||||
firmware/9_2_FPGA/tb/tb_fft_mini*.v
|
||||
firmware/9_2_FPGA/tb/tb_bram_debug.v
|
||||
|
||||
# Local simulation artifacts and CSV outputs
|
||||
firmware/9_2_FPGA/cic_*.csv
|
||||
firmware/9_2_FPGA/fir_*.csv
|
||||
firmware/9_2_FPGA/nco_*.csv
|
||||
firmware/9_2_FPGA/ddc_*.csv
|
||||
firmware/9_2_FPGA/mf_pipeline_output.csv
|
||||
firmware/9_2_FPGA/mf_chain_autocorr.csv
|
||||
firmware/9_2_FPGA/rbd_mode00_ramp.csv
|
||||
firmware/9_2_FPGA/rbd_mode01_peak.csv
|
||||
firmware/9_2_FPGA/rbd_mode10_avg.csv
|
||||
firmware/9_2_FPGA/rbd_mode10_ramp.csv
|
||||
firmware/9_2_FPGA/rmc_autoscan.csv
|
||||
firmware/9_2_FPGA/tb/mf_chain_autocorr.csv
|
||||
firmware/9_2_FPGA/tb/rbd_mode00_ramp.csv
|
||||
firmware/9_2_FPGA/tb/rbd_mode01_peak.csv
|
||||
firmware/9_2_FPGA/tb/rbd_mode10_avg.csv
|
||||
firmware/9_2_FPGA/tb/rbd_mode10_ramp.csv
|
||||
firmware/9_2_FPGA/tb/rmc_autoscan.csv
|
||||
firmware/9_2_FPGA/tb_usb_data_interface.csv
|
||||
|
||||
# Co-sim intermediate CSVs (regenerated by scripts)
|
||||
firmware/9_2_FPGA/tb/cosim/rtl_doppler_*.csv
|
||||
firmware/9_2_FPGA/tb/cosim/compare_doppler_*.csv
|
||||
firmware/9_2_FPGA/tb/cosim/rtl_multiseg_*.csv
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Local organization/archival folders (not part of repo source)
|
||||
10_docs/
|
||||
|
||||
# Local simulation workspaces and generated outputs
|
||||
hardware/rf-simulations/generated/
|
||||
hardware/rf-simulations/aeris10_antenna_sim.py
|
||||
hardware/rf-simulations/aeris10_radar_sim.py
|
||||
|
||||
# Local FPGA report dumps and scratch constraints
|
||||
firmware/9_2_FPGA/reports/
|
||||
firmware/9_2_FPGA/synth_only.xdc
|
||||
|
||||
# Local timing closure report snapshots
|
||||
build*_reports/
|
||||
|
||||
# UART capture logs (generated by tools/uart_capture.py)
|
||||
logs/
|
||||
115
CONTRIBUTING.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Contributing to PLFM_RADAR (AERIS-10)
|
||||
|
||||
Thanks for your interest in the project! This guide covers the basics
|
||||
for getting a change reviewed and merged.
|
||||
|
||||
## Getting started
|
||||
|
||||
1. Fork the repository and create a topic branch from `develop`. The `main` branch is for production releases only.
|
||||
2. Keep generated outputs (Vivado projects, bitstreams, build logs) out of version control.
|
||||
|
||||
### Security Mandate: Package Installation
|
||||
Due to supply chain attack risks, **ALL package installations MUST use the `sfw` (secure firewall) prefix**.
|
||||
- Python: `sfw uv pip install <package>` (Do not use raw pip)
|
||||
- Node/JS: `sfw npm install <package>`
|
||||
- Rust/Cargo: `sfw cargo <command>`
|
||||
|
||||
Never run bare package installation commands without the `sfw` prefix.
|
||||
|
||||
## Repository layout
|
||||
|
||||
| Path | Contents |
|
||||
|------|----------|
|
||||
| `simulation/` | Overwatch |
|
||||
| `schematics/` | Schematics, Gerbers, BOM/CPL |
|
||||
| `parts/` | Consolidated parts list and datasheets |
|
||||
| `firmware/9_1_Microcontroller/` | STM32 MCU C/C++ firmware and unit tests |
|
||||
| `firmware/9_2_FPGA/` | Verilog RTL, constraints, testbenches, build scripts |
|
||||
| `firmware/9_3_GUI/` | Python radar dashboard (Tkinter/PyQt6) and CLI tools |
|
||||
| `firmware/tests/cross_layer/` | Python-based system invariant/contract tests |
|
||||
| `docs/` | GitHub Pages documentation site |
|
||||
|
||||
## Code Standards & Tooling
|
||||
|
||||
- **Python (GUI, Scripts, Tests)**:
|
||||
- We use `uv` for dependency management.
|
||||
- We strictly enforce linting with `ruff`. Run `uv run ruff check .` before committing.
|
||||
- Test with `pytest`.
|
||||
- **Verilog (FPGA)**:
|
||||
- The RTL (`radar_system_top.v`) is the single source of truth for opcode values, bit widths, reset defaults, and valid ranges.
|
||||
- Testbenches must include **adversarial validation**: actively test boundary conditions, race conditions, unexpected input sequences, and reset mid-operation.
|
||||
- Use `iverilog` for simulation.
|
||||
- **C/C++ (MCU)**:
|
||||
- Use `make test` for host-side unit testing (cpputest).
|
||||
- **System-Level Invariants**:
|
||||
- Whenever adding code, verify that system-level invariants (across module, process, and chip boundaries) hold true.
|
||||
|
||||
## AI Usage Policy
|
||||
|
||||
The use of AI is permitted but we have to make sure that the quality and control of the codebase doesn't depend on the agents but the maintainer pushing the changes, meaning they are fully responsible for the code they commit.
|
||||
|
||||
1. **Human Accountability** — The committing engineer is fully responsible for AI-generated code as if they wrote it. Every PR must be understood and defensible by a human.
|
||||
2. **Mandatory Review** — No raw AI output may be committed unread. AI code must pass the same review bar as hand-written code.
|
||||
3. **Full CI Before Commit** — All AI-assisted changes must pass the complete CI suite locally (lint, unit, regression, cross-layer) before commit.
|
||||
|
||||
## Running the Test Suites
|
||||
|
||||
We use GitHub Actions for CI, which runs four main jobs on every PR. Run these locally before pushing.
|
||||
|
||||
### 1. Python & Linting
|
||||
```bash
|
||||
uv run ruff check .
|
||||
cd firmware/9_3_GUI
|
||||
uv run pytest test_GUI_V65_Tk.py test_v7.py -v
|
||||
```
|
||||
|
||||
### 2. FPGA Regression
|
||||
```bash
|
||||
cd firmware/9_2_FPGA
|
||||
bash run_regression.sh
|
||||
```
|
||||
This runs five phases (Lint, Changed Modules, Integration, Signal Processing, Infrastructure, and **P0 Adversarial Tests**). All must pass.
|
||||
|
||||
### 3. MCU Unit Tests
|
||||
```bash
|
||||
cd firmware/9_1_Microcontroller/tests
|
||||
make clean && make
|
||||
```
|
||||
|
||||
### 4. Cross-Layer Contract Tests
|
||||
```bash
|
||||
uv run pytest firmware/tests/cross_layer/test_cross_layer_contract.py -v
|
||||
```
|
||||
|
||||
## Before merging: CI checklist
|
||||
|
||||
All PRs must pass CI:
|
||||
|
||||
| Job | What it checks |
|
||||
|----|---------------|
|
||||
| `python-tests` | ruff clean + pytest green |
|
||||
| `mcu-tests` | make all exits 0 |
|
||||
| `fpga-regression` | run_regression.sh exits 0 |
|
||||
| `cross-layer-tests` | pytest exits 0 |
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **NO LEGACY COMPATIBILITY** unless explicitly requested by the maintainer.
|
||||
- **The FPGA RTL (`radar_system_top.v`) is the single source of truth** for opcode values, bit widths, reset defaults, and valid ranges. All other layers must align to it.
|
||||
- **Adversarial testing is mandatory**: Every test must actively try to break the code.
|
||||
- **Testbench timing**: Always add a `#1` delay after `@(posedge clk)` before driving DUT inputs with blocking assignments.
|
||||
- **Pre-fetch FIFO**: Remember `wr_full` is asserted after DEPTH+1 writes, not just DEPTH.
|
||||
|
||||
## Checklist Before Push
|
||||
|
||||
- [ ] `uv run ruff check .` — no lint errors
|
||||
- [ ] `uv run pytest test_GUI_V65_Tk.py test_v7.py -v` — all pass
|
||||
- [ ] `cd firmware/9_2_FPGA && bash run_regression.sh` — all 5 phases pass
|
||||
- [ ] `cd firmware/9_1_Microcontroller/tests && make clean && make` — pass
|
||||
- [ ] `uv run pytest firmware/tests/cross_layer/test_cross_layer_contract.py` — pass
|
||||
- [ ] `git diff --check` — no whitespace issues
|
||||
- [ ] PR targets `develop` branch
|
||||
|
||||
## Questions?
|
||||
|
||||
Open a GitHub issue — discussion is visible to everyone.
|
||||
60
README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# AERIS-10
|
||||
|
||||
10.5 GHz pulse linear-FM phased-array radar, with Overwatch beside the hardware design.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| [simulation/](simulation/) | Overwatch. Physics, radar model, and the operator view. |
|
||||
| [schematics/](schematics/) | Board schematics, stack-up, and production Gerbers. |
|
||||
| [parts/parts-list.csv](parts/parts-list.csv) | Parts list taken from the production bills of materials. |
|
||||
| [parts/cost.md](parts/cost.md) | Component prices from published catalogs, rolled up for both radars. |
|
||||
|
||||
## Radar
|
||||
|
||||
Two builds share the signal chain.
|
||||
|
||||
- **AERIS-10N**, about 3 km, 8×16 patch array.
|
||||
- **AERIS-10X**, about 20 km, 32×16 dielectric-filled slotted waveguide, plus a 10 W QPA2962 stage on each of 16 amplifier boards.
|
||||
|
||||
The array steers elevation electronically over ±45°. Azimuth on the prototype is a stepper. Carrier is 10.5 GHz. The FPGA does chirp generation, pulse compression, Doppler, MTI, and CFAR. An STM32 sequences power, clocks, phase shifters, and the GPS/IMU.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Where the rest of the design lives
|
||||
|
||||
| Path | Contents |
|
||||
|---|---|
|
||||
| `schematics/4_6_Schematics/` | Main board, power board, frequency synthesizer, power amplifier, antennas |
|
||||
| `schematics/4_7_Production Files/` | Gerbers, pick-and-place, and the original board bills of materials |
|
||||
| `parts/datasheets/` | Component datasheets |
|
||||
| `hardware/diagrams/` | Functional diagram |
|
||||
| `hardware/power/` | Power-rail and sequencing sheet |
|
||||
| `hardware/description/` | Project description |
|
||||
| `hardware/rf-simulations/` | Antenna, filter, and waveguide studies. These are circuit simulations, not Overwatch. |
|
||||
| `hardware/mechanical/` | Enclosure and waveguide drawings |
|
||||
| `hardware/application-notes/` | ADAR1000 user guide |
|
||||
| `firmware/` | STM32, FPGA, and the radar GUI |
|
||||
| `docs/` | Architecture notes, bring-up, and reports |
|
||||
|
||||
## Overwatch
|
||||
|
||||
From the repository root, install the environment once, then start the stack. The start script generates local auth secrets on the first run, builds the operator UI, starts Postgres, Auth, PostgREST, Kong, and Nginx, and restarts the simulation backend. The operator view is at <http://127.0.0.1:54321>. The demo password is written to `simulation/deploy/supabase/.env`, which stays uncommitted.
|
||||
|
||||
```bash
|
||||
./scripts/setup_environment.sh
|
||||
./scripts/start_stack.sh
|
||||
```
|
||||
|
||||
The field proposal for the drone command link is [docs/drone-command-link.md](docs/drone-command-link.md).
|
||||
|
||||
A headless physics check, after the environment exists:
|
||||
|
||||
```bash
|
||||
simulation/.venv/bin/python -m defense_sim.cli --steps 500 --seed 7
|
||||
```
|
||||
|
||||

|
||||
|
||||

|
||||
0
docs/.nojekyll
Normal file
472
docs/AERIS_Antenna_Report.pdf
Normal file
821
docs/AERIS_Simulation_Report.pdf
Normal file
199
docs/AERIS_Simulation_Report_v2.pdf
Normal file
95
docs/architecture.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AERIS-10 Docs | Architecture</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="index.html">AERIS-10 Docs</a>
|
||||
<nav>
|
||||
<a href="architecture.html">Architecture</a>
|
||||
<a href="implementation-log.html">Implementation Log</a>
|
||||
<a href="bring-up.html">Bring-Up</a>
|
||||
<a href="reports.html">Reports</a>
|
||||
<a href="release-notes.html">Release Notes</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container page">
|
||||
<section class="hero">
|
||||
<p class="eyebrow">System View</p>
|
||||
<h1>Architecture and Data Path</h1>
|
||||
<p>Hardware and firmware structure for the current XC7A200T implementation and bring-up targets.</p>
|
||||
</section>
|
||||
|
||||
<section class="grid-2">
|
||||
<article class="card">
|
||||
<h2>Top-level processing flow</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Stage</th>
|
||||
<th>Module Focus</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ADC capture</td>
|
||||
<td>AD9484 interface + CDC edge</td>
|
||||
<td>400 MHz sampling domain, synchronized into processing pipeline.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DDC</td>
|
||||
<td>NCO + CIC + FIR</td>
|
||||
<td>I/Q conversion and decimation for baseband-ready stream.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Matched filter</td>
|
||||
<td>FFT-based chain</td>
|
||||
<td>Synthesis branch is golden for hardware-equivalent co-sim.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Range/Doppler</td>
|
||||
<td>Range bin decimator + Doppler FFT</td>
|
||||
<td>32 chirps/frame, 64 range bins, deterministic frame outputs.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Host path</td>
|
||||
<td>FT601 interface</td>
|
||||
<td>USB streaming with framing and soak validation in bring-up.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<h2>Current target split strategy</h2>
|
||||
<ul>
|
||||
<li>Production target remains <code>xc7a200t-2fbg484i</code> with full board constraints.</li>
|
||||
<li>TE0712/TE0701 and TE0713/TE0701 use dedicated top wrappers and dedicated XDC files.</li>
|
||||
<li>Board-specific pinouts are isolated from core DSP modules to avoid accidental cross-target regression.</li>
|
||||
<li>Bring-up sequence starts from minimal heartbeat top, then steps into full signal chain validation.</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Reference block diagram</h2>
|
||||
<img class="diagram" src="assets/img/RADAR_V6.jpg" alt="AERIS-10 system architecture diagram">
|
||||
<p class="muted">Diagram snapshot from AERIS-10 project architecture.</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container"><p>Architecture is updated as bring-up and integration milestones complete.</p></div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
BIN
docs/artifacts/te0713-te0701-heartbeat-2026-03-21.bit
Normal file
33
docs/artifacts/te0713-te0701-heartbeat-2026-03-21.md
Normal file
@@ -0,0 +1,33 @@
|
||||
<!doctype markdown>
|
||||
|
||||
# TE0713/TE0701 heartbeat bring-up artifact
|
||||
|
||||
- Date: 2026-03-21
|
||||
- Target: Trenz `TE0713-03-82C46-A` on `TE0701-06`
|
||||
- Top module: `radar_system_top_te0713_dev`
|
||||
- Constraint file: `firmware/9_2_FPGA/constraints/te0713_te0701_minimal.xdc`
|
||||
- Bitstream: `docs/artifacts/te0713-te0701-heartbeat-2026-03-21.bit`
|
||||
|
||||
Build result:
|
||||
|
||||
- Vivado: `2025.2`
|
||||
- Implementation: `write_bitstream Complete!`
|
||||
- DRC: `0 Errors`
|
||||
- WNS: `+17.863 ns`
|
||||
- WHS: `+0.265 ns`
|
||||
|
||||
Purpose:
|
||||
|
||||
- Lowest-risk first-power image for `TE0713 + TE0701`
|
||||
- Verifies FPGA configuration, primary clock path, and heartbeat/status outputs before FT601 or radar-path bring-up
|
||||
|
||||
Board-day usage:
|
||||
|
||||
- Program this image first
|
||||
- Confirm JTAG enumeration and successful configuration
|
||||
- Verify heartbeat/status activity before moving to FT601 or higher-risk integrations
|
||||
|
||||
Build origin:
|
||||
|
||||
- Built remotely on `livepeerservice.ddns.net`
|
||||
- Vivado path: `/mnt/bcache/Xilinx/Vivado/2025.2/Vivado/bin/vivado`
|
||||
BIN
docs/artifacts/te0713-te0701-umft601x-dev-2026-03-21.bit
Normal file
78
docs/artifacts/te0713-te0701-umft601x-dev-2026-03-21.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# AERIS-10 FT601 Integration Dev Bitstream
|
||||
|
||||
**File:** `te0713-te0701-umft601x-dev-2026-03-21.bit`
|
||||
**Tag:** `v0.1.8-te0713-ft601-dev`
|
||||
**Date:** 2026-03-21
|
||||
**Target:** XC7A200T-2FBG484C (TE0713-03) on TE0701-06 carrier + UMFT601X-B FMC LPC
|
||||
|
||||
## Build Summary
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| WNS (setup) | +0.059 ns |
|
||||
| WHS (hold) | +0.121 ns |
|
||||
| WPWS (pulse width) | +4.500 ns |
|
||||
| Failing endpoints | 0 |
|
||||
| DRC errors | 0 |
|
||||
| Clock | ft601_clk_in 100 MHz (10 ns period) |
|
||||
| Strategy | Performance_ExplorePostRoutePhysOpt |
|
||||
| Vivado | 2025.2 |
|
||||
|
||||
## What This Bitstream Does
|
||||
|
||||
- Instantiates `usb_data_interface.v` (full FT601 USB data path) via a thin
|
||||
wrapper (`radar_system_top_te0713_umft601x_dev.v`)
|
||||
- Generates synthetic test data: range profile packets (counter XOR pattern),
|
||||
optional Doppler and CFAR packets, controlled by host commands
|
||||
- Responds to USB host commands (stream control 0x04, status request 0xFF)
|
||||
- Drives `ft601_gpio0` with a ~6 Hz heartbeat (counter bit 24)
|
||||
- Drives `ft601_chip_reset_n` after power-on reset (32k clock cycles)
|
||||
- `ft601_wakeup_n` held high (inactive)
|
||||
|
||||
## Hardware Setup
|
||||
|
||||
1. TE0713-03 mounted on TE0701-06 carrier
|
||||
2. UMFT601X-B plugged into TE0701 J10 (FMC LPC connector)
|
||||
3. TE0701 VIOTB = 3.3V (jumper configuration)
|
||||
4. UMFT601X-B jumpers: JP1=open, JP2=2-3, JP3=open, JP6=short (3.3V),
|
||||
JP4=2-3, JP5=2-3 (245 Sync FIFO mode)
|
||||
5. USB 3.0 Micro-B cable from UMFT601X-B to host PC
|
||||
6. Trenz programming USB for JTAG
|
||||
|
||||
## Programming
|
||||
|
||||
```
|
||||
# Open Vivado Hardware Manager
|
||||
open_hw_manager
|
||||
connect_hw_server
|
||||
open_hw_target
|
||||
set_property PROGRAM.FILE {te0713-te0701-umft601x-dev-2026-03-21.bit} [current_hw_device]
|
||||
program_hw_devices [current_hw_device]
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. After programming, check `ft601_gpio0` toggles (~6 Hz) — confirms FPGA running
|
||||
2. On host PC, FT601 should enumerate as USB 3.0 device (VID 0x0403, PID 0x601F)
|
||||
3. Use FTDI D3XX driver / `ftd3xx` Python library to read data:
|
||||
- Open device, set pipe to channel 0
|
||||
- Read should return 32-bit words with test pattern packets
|
||||
- Packet header: `0xAE10xxxx` where xxxx = packet type
|
||||
|
||||
## Timing Closure Notes
|
||||
|
||||
Previous builds failed setup timing due to source-synchronous clock skew:
|
||||
- The FT601 clock enters via IBUF+BUFG (~5 ns insertion delay)
|
||||
- `set_output_delay` referenced to `ft601_clk_in` created a false ~5 ns
|
||||
skew penalty (source has insertion, destination at port has 0)
|
||||
- Fixed by using `set_max_delay -datapath_only` for output constraints,
|
||||
which constrains the register-to-pad path directly (7.5 ns budget)
|
||||
- Input delays still use `set_input_delay` referenced to `ft601_clk_in`
|
||||
(correct direction: FT601 drives data, FPGA samples after IBUF+BUFG)
|
||||
|
||||
## Source Files
|
||||
|
||||
- `firmware/9_2_FPGA/radar_system_top_te0713_umft601x_dev.v` — wrapper top
|
||||
- `firmware/9_2_FPGA/usb_data_interface.v` — FT601 USB data interface
|
||||
- `firmware/9_2_FPGA/constraints/te0713_te0701_umft601x.xdc` — FMC LPC constraints
|
||||
- `firmware/9_2_FPGA/scripts/build_te0713_umft601x_dev.tcl` — build script
|
||||
24687
docs/artifacts/te0713-te0701-umft601x-dev-timing-2026-03-21.rpt
Normal file
BIN
docs/assets/img/0044.jpg
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
docs/assets/img/3fb1dabf-2c6d-4b5d-b471-48bc461ce914.jpg
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
docs/assets/img/Antenna_Array.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
docs/assets/img/RADAR_V6.jpg
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
docs/assets/img/RADAR_V6_V2.jpg
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
docs/assets/img/RADAR_V6_V2.png
Normal file
|
After Width: | Height: | Size: 443 KiB |
BIN
docs/assets/img/SplitRing_test.mp4
Normal file
BIN
docs/assets/img/overwatch-radar.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
docs/assets/img/overwatch-simulation.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
205
docs/assets/style.css
Normal file
@@ -0,0 +1,205 @@
|
||||
:root {
|
||||
--bg: #0b1220;
|
||||
--bg-soft: #10192b;
|
||||
--card: #162235;
|
||||
--text: #e6edf6;
|
||||
--muted: #9fb0c7;
|
||||
--accent: #06b6d4;
|
||||
--accent-2: #22c55e;
|
||||
--border: #2a3a52;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
background: radial-gradient(1200px 700px at 10% -10%, #1a2740 0, var(--bg) 52%);
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
a { color: #7dd3fc; }
|
||||
a:hover { color: #bae6fd; }
|
||||
|
||||
.container {
|
||||
width: min(1120px, calc(100% - 2rem));
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
background: rgba(8, 15, 28, 0.9);
|
||||
border-bottom: 1px solid var(--border);
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 62px;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.brand {
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.nav nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.nav nav a {
|
||||
color: var(--muted);
|
||||
text-decoration: none;
|
||||
padding: 0.35rem 0.55rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.nav nav a:hover {
|
||||
color: var(--text);
|
||||
background: #1b2a43;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 2.2rem 0 3.4rem;
|
||||
}
|
||||
|
||||
.hero {
|
||||
background: linear-gradient(140deg, #0f1a2e, #111e35 55%, #0f172a);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
padding: 1.4rem;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0;
|
||||
color: #67e8f9;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
font-size: 0.76rem;
|
||||
}
|
||||
|
||||
h1 { margin: 0.4rem 0 0.6rem; line-height: 1.2; }
|
||||
h2 { margin: 0 0 0.5rem; line-height: 1.25; }
|
||||
h3 { margin: 0.2rem 0 0.5rem; }
|
||||
|
||||
.cta-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.7rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
color: #00141a;
|
||||
background: linear-gradient(135deg, var(--accent), #38bdf8);
|
||||
border-radius: 9px;
|
||||
padding: 0.55rem 0.9rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.button.ghost {
|
||||
color: var(--text);
|
||||
background: #0e1728;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
margin-top: 1rem;
|
||||
display: grid;
|
||||
gap: 0.8rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
margin-top: 1rem;
|
||||
display: grid;
|
||||
gap: 0.8rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.stat .metric {
|
||||
margin: 0.1rem 0 0.25rem;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.muted { color: var(--muted); }
|
||||
|
||||
ul { margin: 0.4rem 0 0; padding-left: 1.1rem; }
|
||||
li { margin-bottom: 0.35rem; }
|
||||
|
||||
.table-wrap { overflow-x: auto; }
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.94rem;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid var(--border);
|
||||
padding: 0.55rem;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
th { background: #1b2b46; }
|
||||
|
||||
.chip {
|
||||
display: inline-block;
|
||||
padding: 0.2rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.76rem;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: grid;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
|
||||
.timeline article {
|
||||
background: #122037;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
width: 100%;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: #0d1527;
|
||||
}
|
||||
|
||||
.footer {
|
||||
border-top: 1px solid var(--border);
|
||||
color: var(--muted);
|
||||
padding: 1rem 0 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.nav { align-items: flex-start; padding: 0.5rem 0; }
|
||||
.nav nav { gap: 0.35rem; }
|
||||
}
|
||||
204
docs/board-day-worksheet.html
Normal file
@@ -0,0 +1,204 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AERIS-10 Docs | Board-Day Worksheet</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="index.html">AERIS-10 Docs</a>
|
||||
<nav>
|
||||
<a href="architecture.html">Architecture</a>
|
||||
<a href="implementation-log.html">Implementation Log</a>
|
||||
<a href="bring-up.html">Bring-Up</a>
|
||||
<a href="reports.html">Reports</a>
|
||||
<a href="release-notes.html">Release Notes</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container page">
|
||||
<section class="hero">
|
||||
<p class="eyebrow">Board-Day Execution</p>
|
||||
<h1>Board-Day Worksheet</h1>
|
||||
<p>Printable operator worksheet for the first FPGA module and carrier-board sessions. Use this alongside the bring-up plan and artifact inventory to capture evidence, pass/fail state, and blockers in real time.</p>
|
||||
<div class="cta-row">
|
||||
<a class="button" href="bring-up.html">Open Bring-Up Plan</a>
|
||||
<a class="button ghost" href="reports.html">Open Artifact Inventory</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Session metadata</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td>Date / Time</td><td></td><td>Operator</td><td></td></tr>
|
||||
<tr><td>Carrier board revision</td><td></td><td>FPGA module revision</td><td></td></tr>
|
||||
<tr><td>MCU firmware commit</td><td></td><td>FPGA bitstream / probes tag</td><td></td></tr>
|
||||
<tr><td>Power supply setup</td><td></td><td>Ambient temperature</td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Pre-power checks</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Check</th>
|
||||
<th>Expected evidence</th>
|
||||
<th>Status</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Carrier jumpers / default straps reviewed</td><td>Documented against board notes</td><td></td><td></td></tr>
|
||||
<tr><td>Module seating and connectors inspected</td><td>No bent pins, no obvious shorts, no cable strain</td><td></td><td></td></tr>
|
||||
<tr><td>RF transmit path kept disabled for initial power-up</td><td>Safe GPIO / supply state confirmed</td><td></td><td></td></tr>
|
||||
<tr><td>Chosen image set identified</td><td>Heartbeat, debug, or baseline image selected intentionally</td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Power and configuration checks</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Step</th>
|
||||
<th>Expected evidence</th>
|
||||
<th>Status</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Initial power applied</td><td>Idle current within planned envelope, no thermal surprise</td><td></td><td></td></tr>
|
||||
<tr><td>JTAG enumeration</td><td>Target device visible in hardware manager</td><td></td><td></td></tr>
|
||||
<tr><td>Bitstream programming</td><td>DONE = HIGH, INIT_COMPLETE = asserted</td><td></td><td></td></tr>
|
||||
<tr><td>Optional probes load</td><td>Expected ILA cores enumerate</td><td></td><td></td></tr>
|
||||
<tr><td>Reset / heartbeat sanity</td><td>Deterministic reset release and status activity</td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Firmware and control-path checks</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Check</th>
|
||||
<th>Expected evidence</th>
|
||||
<th>Status</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>USART3 bring-up log</td><td>Boot messages present with timestamps</td><td></td><td></td></tr>
|
||||
<tr><td>AD9523 status</td><td>Status pins/logs indicate healthy clocking</td><td></td><td></td></tr>
|
||||
<tr><td>ADF4382A TX/RX init</td><td>Initialization returns OK, lock states sensible</td><td></td><td></td></tr>
|
||||
<tr><td>ADAR1000 communication</td><td>Scratchpad/readback passes on all devices</td><td></td><td></td></tr>
|
||||
<tr><td>Temperature / health checks</td><td>No early overtemp, fault, or emergency shutdown</td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>FPGA data-path and USB checks</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Stage</th>
|
||||
<th>Expected evidence</th>
|
||||
<th>Status</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Raw ADC visibility</td><td>ILA or status evidence shows activity on expected clock</td><td></td><td></td></tr>
|
||||
<tr><td>DDC / matched-filter activity</td><td>Valid strobes and non-flat outputs observed</td><td></td><td></td></tr>
|
||||
<tr><td>USB framing sanity</td><td>Headers, payload length, and footer remain consistent</td><td></td><td></td></tr>
|
||||
<tr><td>FT601 behavior</td><td>No obvious backpressure or bus-direction anomalies</td><td></td><td></td></tr>
|
||||
<tr><td>Sustained streaming trial</td><td>No immediate lockup, framing drift, or reset event</td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid-2" style="margin-top:0.8rem;">
|
||||
<article class="card">
|
||||
<h2>Measurements to record</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Measurement</th>
|
||||
<th>Observed value</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Carrier/module idle current</td><td></td><td></td></tr>
|
||||
<tr><td>5V / 3V3 rails</td><td></td><td></td></tr>
|
||||
<tr><td>LO lock indicators</td><td></td><td></td></tr>
|
||||
<tr><td>ADAR temperatures</td><td></td><td></td></tr>
|
||||
<tr><td>PA IDQ spot checks</td><td></td><td></td></tr>
|
||||
<tr><td>USB enumeration / throughput notes</td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2>Stop conditions encountered?</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Condition</th>
|
||||
<th>Triggered</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Unexpected current or thermal rise</td><td></td><td></td></tr>
|
||||
<tr><td>LO lock/readback disagreement</td><td></td><td></td></tr>
|
||||
<tr><td>ADAR comm failure</td><td></td><td></td></tr>
|
||||
<tr><td>USB framing or bus-direction anomaly</td><td></td><td></td></tr>
|
||||
<tr><td>Reset / clock ambiguity</td><td></td><td></td></tr>
|
||||
<tr><td>Other blocker</td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Outcome</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td>Session result</td><td></td><td>Next image to use</td><td></td></tr>
|
||||
<tr><td>Main blocker</td><td colspan="3"></td></tr>
|
||||
<tr><td>Next action owner</td><td></td><td>Target completion</td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container"><p>Use this worksheet together with the bring-up plan and artifact inventory so observations are captured consistently.</p></div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
162
docs/bring-up.html
Normal file
@@ -0,0 +1,162 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AERIS-10 Docs | Bring-Up</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="index.html">AERIS-10 Docs</a>
|
||||
<nav>
|
||||
<a href="architecture.html">Architecture</a>
|
||||
<a href="implementation-log.html">Implementation Log</a>
|
||||
<a href="bring-up.html">Bring-Up</a>
|
||||
<a href="reports.html">Reports</a>
|
||||
<a href="release-notes.html">Release Notes</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container page">
|
||||
<section class="hero">
|
||||
<p class="eyebrow">Execution Checklist</p>
|
||||
<h1>Hardware Bring-Up Plan</h1>
|
||||
<p>Pre-arrival completeness gates, board-day smoke tests, and fault-localization rules for the first FPGA module and carrier-board sessions.</p>
|
||||
<div class="cta-row">
|
||||
<a class="button" href="board-day-worksheet.html">Open Board-Day Worksheet</a>
|
||||
<a class="button ghost" href="reports.html">Open Artifact Inventory</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Pre-arrival completeness gates</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Gate</th>
|
||||
<th>Objective</th>
|
||||
<th>Pass Criteria</th>
|
||||
<th>Evidence</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>1</td><td>Freeze known-good firmware and bitstream baselines</td><td>Tracked commit, named artifact set, and repeatable programming flow are available</td><td>Git commit, bitstream path, reports, programming TCL; heartbeat image at <code>docs/artifacts/te0713-te0701-heartbeat-2026-03-21.bit</code>; FT601 integration dev image at <code>docs/artifacts/te0713-te0701-umft601x-dev-2026-03-21.bit</code> (WNS +0.059 ns, timing clean)</td></tr>
|
||||
<tr><td>2</td><td>Preserve clean implementation constraints</td><td>Positive WNS/WHS/WPWS, XDCB-5 cleared, only documented methodology residue remains</td><td>Timing summary and methodology report</td></tr>
|
||||
<tr><td>3</td><td>Keep regressions green before board arrival</td><td>MCU host tests and FPGA regression/integration suites pass on the tracked tree</td><td>15/15 MCU and 18/18 FPGA logs</td></tr>
|
||||
<tr><td>4</td><td>Make first-power-on behavior observable</td><td>Clock, LO, beamformer, PA, and USB status can be identified from logs or status outputs</td><td>DIAG coverage, status fields, ILA/debug plan</td></tr>
|
||||
<tr><td>5</td><td>Prepare board-arrival execution checklist</td><td>Power order, abort criteria, and host-side capture steps are written and reviewed</td><td>This page plus reports and scripts references</td></tr>
|
||||
<tr><td>6</td><td>Document unresolved pre-hardware risks</td><td>Open issues are explicitly listed so Day-0 findings are interpreted correctly</td><td>Known-open-risks section below</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid-2" style="margin-top:0.8rem;">
|
||||
<article class="card">
|
||||
<h2>Board-arrival smoke test</h2>
|
||||
<ol>
|
||||
<li>Inspect carrier defaults, regulator enables, jumpers, and any board-level clock source selections before power is applied.</li>
|
||||
<li>Power the carrier and module in the safest configuration with RF transmit paths disabled and document current draw immediately.</li>
|
||||
<li>Run the FPGA programming flow, verify JTAG enumeration, and confirm DONE and INIT_COMPLETE from the hardware manager script.</li>
|
||||
<li>Check deterministic reset release and heartbeat/status outputs before enabling any analog or RF-dependent function.</li>
|
||||
<li>Bring up MCU firmware logging, confirm AD9523 status pins, LO initialization results, and beamformer communication readback.</li>
|
||||
<li>Use the debug-capable FPGA image and probes to confirm raw ADC, DDC, matched-filter, and USB-path activity in that order.</li>
|
||||
<li>Exercise the FT601 path with known framing expectations before any long-duration streaming test.</li>
|
||||
<li>Only after all previous steps pass, begin PA bias, calibration, and higher-risk RF activation.</li>
|
||||
</ol>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2>Abort criteria</h2>
|
||||
<ul>
|
||||
<li>Stop immediately on unexpected rail current, regulator instability, or thermal rise beyond the planned idle envelope.</li>
|
||||
<li>Do not continue past LO bring-up if the lock GPIOs or lock-status reads disagree repeatedly.</li>
|
||||
<li>Stop RF activation if beamformer scratchpad/readback checks fail on any device.</li>
|
||||
<li>Do not continue USB stress testing if framing, backpressure, or bus-direction behavior is inconsistent.</li>
|
||||
<li>Revert to the heartbeat or debug image if reset sequencing or clock presence is ambiguous.</li>
|
||||
<li>Keep the production-target constraints and pinout source untouched while bring-up-specific targets are being adjusted.</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>First-power-on observability targets</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Subsystem</th>
|
||||
<th>What must be visible</th>
|
||||
<th>Expected evidence</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>FPGA configuration</td><td>JTAG enumeration, DONE, INIT_COMPLETE, optional ILA probe presence</td><td>program_fpga.tcl summary and hardware-manager status</td></tr>
|
||||
<tr><td>Clocking</td><td>AD9523 status pins and deterministic downstream reset release</td><td>DIAG clock messages and status GPIO snapshots</td></tr>
|
||||
<tr><td>LO chain</td><td>ADF4382A init status, timed-sync path status, TX/RX lock state</td><td>USART3 DIAG log plus lock GPIO behavior</td></tr>
|
||||
<tr><td>Beamformer control</td><td>Per-device communication sanity and basic temperature readback</td><td>ADAR1000 scratchpad/readback and temperature prints</td></tr>
|
||||
<tr><td>PA biasing</td><td>DAC/ADC bring-up progression and IDQ calibration convergence bounds</td><td>Per-channel PA DIAG output with stop conditions</td></tr>
|
||||
<tr><td>FPGA data path</td><td>ADC, DDC, matched-filter, and USB-path activity in sequence</td><td>ILA captures and system status outputs</td></tr>
|
||||
<tr><td>USB/FT601 link</td><td>Stable framing, no obvious underrun/backpressure surprises, host decode sanity</td><td>Host capture script output and stable packet boundaries</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid-2" style="margin-top:0.8rem;">
|
||||
<article class="card">
|
||||
<h2>Required artifacts before hardware arrives</h2>
|
||||
<ul>
|
||||
<li>Named firmware baseline commit and build instructions for the MCU image.</li>
|
||||
<li>Named FPGA baseline bitstream and matching `.ltx` probes file for debug sessions; current low-risk heartbeat artifact is <code>docs/artifacts/te0713-te0701-heartbeat-2026-03-21.bit</code>.</li>
|
||||
<li>Current production-target XDC, timing summary, and methodology report.</li>
|
||||
<li>Programming and debug TCL scripts for baseline and debug images.</li>
|
||||
<li>Regression evidence for the tracked branch: MCU host suite and FPGA regression/integration suite.</li>
|
||||
<li>Day-0 measurement sheet covering supply currents, temperatures, and observed status outputs.</li>
|
||||
</ul>
|
||||
<p><a class="button ghost" href="reports.html">View concrete artifact inventory</a></p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2>Host-side tools and workflows</h2>
|
||||
<ul>
|
||||
<li>JTAG programming workflow using the checked-in Vivado TCL scripts and the TE0713 heartbeat baseline built on 2026-03-21.</li>
|
||||
<li>Serial capture on USART3 with timestamps preserved for bring-up logs.</li>
|
||||
<li>FT601 or host-side USB capture/decoder workflow to validate framing and payload stability.</li>
|
||||
<li>ILA capture workflow for raw ADC, DDC, matched-filter, and USB-domain checkpoints.</li>
|
||||
<li>Repeatable checklist for baseline image, debug image, and rollback image selection.</li>
|
||||
</ul>
|
||||
<p><a class="button ghost" href="board-day-worksheet.html">Open printable worksheet</a></p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Known open risks before board arrival</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Risk</th>
|
||||
<th>Current state</th>
|
||||
<th>Day-0 handling</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Residual FT601 methodology warning</td><td>Production-target XDC cleanup is validated, but one `ft601_txe` methodology residue remains documented.</td><td>Treat as a known observation item and verify real FT601 status behavior before attempting deeper constraint churn.</td></tr>
|
||||
<tr><td>RF control-path realism</td><td>Firmware sequencing and diagnostics improved, but LO sync, phase behavior, and beamformer control still require physical validation.</td><td>Use readback-first bring-up and do not assume analog behavior from simulation or logs alone.</td></tr>
|
||||
<tr><td>Prototype-grade top-level functional assumptions</td><td>The active FPGA baseline is regression-clean, but some radar-function behavior still needs real-board confirmation under actual I/O conditions.</td><td>Validate each data-path stage incrementally with ILA and host captures before full streaming claims.</td></tr>
|
||||
<tr><td>PA calibration boundaries</td><td>IDQ calibration logic is much safer than before, but real-device convergence and margin limits are not yet board-proven.</td><td>Use conservative limits, observe every channel, and stop on abnormal current or non-convergent channels.</td></tr>
|
||||
<tr><td>Board-specific integration unknowns</td><td>Carrier/module interaction, rails, clocks, and connector assumptions remain partially unproven until first assembly.</td><td>Begin with the tracked TE0713/TE0701 heartbeat image and configuration checks before enabling higher-energy subsystems.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container"><p>This page is the operational source of truth for pre-arrival readiness and first-power-on execution.</p></div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
50
docs/drone-command-link.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Drone command link
|
||||
|
||||
Proposal, 21 October 2026. This is the radio for Overwatch to command a tasked defense drone. The simulator still uses a generic half-duplex pipe (20 Hz, 250 kbit/s, 50 ms one way) and has not been switched to this waveform.
|
||||
|
||||
## What the link has to carry
|
||||
|
||||
One drone is given a line and front-runs it at full speed. The ground side has to send two things: that line, and the latest attacker track so altitude and the line can be rewritten as the radar picture settles. The drone reports its own state on the way back.
|
||||
|
||||
The bodies are the ones already modeled: a 48-byte command and 64 bytes of telemetry. The approach from line commit to the pass is on the order of two minutes, over a few kilometres of line of sight from a radar site on the 12 km ring to a drone that started on the 9 km loiter ring. The last part of the intercept is the drone's own IR track and does not use this radio.
|
||||
|
||||
A missed update leaves the drone on the last line it accepted. A forged update must not move that line. The early climb locks a drone onto a heading, so a false track is the failure to design against.
|
||||
|
||||
## Decision
|
||||
|
||||
Slotted UHF frequency hopping, half duplex, carrying signed MAVLink 2.
|
||||
|
||||
The radar site on the inbound side points a directional antenna at the tasked drone. Ten times a second the ground station sends the line and the attacker track. The drone answers with telemetry in its half of the slot. The hop sequence comes from the link key.
|
||||
|
||||
Two custom MAVLink 2 messages are enough:
|
||||
|
||||
| Message | Contents |
|
||||
|---|---|
|
||||
| Line | Position on the line, direction, altitude, time |
|
||||
| Track | Attacker position, velocity, time |
|
||||
|
||||
MAVLink 2 signs the frame. The drone accepts a frame only when the signature checks and the sequence number is newer than the last one it took. Any other frame is dropped. Between accepted frames, and whenever the slots go empty, the drone keeps flying the last line.
|
||||
|
||||
At an air rate of about 100 kbit/s a command with the existing 24 bytes of framing is 72 bytes, about 6 ms on the air. Telemetry is 88 bytes, about 7 ms. A 10 Hz exchange therefore uses well under a tenth of a second of airtime per second for both directions, and the wait for the next slot is in the same range as the 50 ms delay the simulator already assumes. The drone does not need a stick position at 20 Hz. It needs a newer line.
|
||||
|
||||
## Interference
|
||||
|
||||
Each packet occupies one hop and then leaves it. Energy left on a single frequency takes that slot. The next slot is already on another frequency. The directional antenna puts the station's power down the inbound sector rather than across the horizon. Short airtime, a hop set that is not a published channel list, and one aimed path are the resistance this link has.
|
||||
|
||||
The signature is what stops a rewritten track. Hopping does not. A packet that fails the signature, or that repeats an older sequence, does not become the line.
|
||||
|
||||
## Channel
|
||||
|
||||
Fly this inside a coordinated UHF assignment. The hop set is then private, and a 10 Hz exchange is lawful. Ten hertz is several percent of the channel on each side (about 6% for commands and about 7% for telemetry at 100 kbit/s), which a public ISM duty-cycle cap of 1% does not allow.
|
||||
|
||||
Until that assignment exists, the same two signed messages can run at 1 Hz on an ordinary UHF hopper. Each side then stays under 1% (about 0.6% and 0.7%). The drone still coasts on the last line, and one fix per second is enough to rewrite altitude across a two-minute approach.
|
||||
|
||||
## Left out of the first build
|
||||
|
||||
A second band is not part of this proposal. If a trial shows the hop set denied for long enough that the coasted line goes stale before IR locks, copy the same signed frames onto a second radio. The drone takes whichever copy arrives with the newer sequence. The two radios do not have to agree. Requiring both before a command is accepted would let the loss of one band freeze the line.
|
||||
|
||||
LoRaWAN was set aside for this job. At the spreading factor that reaches a drone out at the loiter ring, one command takes on the order of a second of airtime, and the public channel plan plus the gateway duty cycle forbid a steady stream of them. The processing gain of the chirp helps against weak co-channel noise. It is not a substitute for a moving channel and a signed sequence.
|
||||
|
||||
## What this does not change
|
||||
|
||||
The simulator's link settings stay the field-tuning baseline in `simulation/PROJECT_SPEC.md`: 20 Hz slots, 250 kbit/s, 48-byte commands, 64-byte telemetry, 24-byte overhead, 50 ms one-way delay. Those figures describe timing, not this radio. Radar tracks still come from the AERIS sites over the wired path. This proposal is only the path from the command point to the tasked drone.
|
||||
135
docs/implementation-log.html
Normal file
@@ -0,0 +1,135 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AERIS-10 Docs | Implementation Log</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="index.html">AERIS-10 Docs</a>
|
||||
<nav>
|
||||
<a href="architecture.html">Architecture</a>
|
||||
<a href="implementation-log.html">Implementation Log</a>
|
||||
<a href="bring-up.html">Bring-Up</a>
|
||||
<a href="reports.html">Reports</a>
|
||||
<a href="release-notes.html">Release Notes</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container page">
|
||||
<section class="hero">
|
||||
<p class="eyebrow">Engineering Journal</p>
|
||||
<h1>Implementation Timeline and Improvements</h1>
|
||||
<p>Consolidated record of key firmware, timing, debug and infrastructure changes.</p>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Recent milestone timeline</h2>
|
||||
<div class="timeline">
|
||||
<article>
|
||||
<h3>Build 25 — MTI canceller + DC notch filter (ed629e7)</h3>
|
||||
<p class="muted">MTI 2-pulse canceller (H(z) = 1 - z^{-1}) integrated between range bin decimator and Doppler processor for ground clutter removal. DC notch filter (post-Doppler, pre-CFAR) zeroes bins within ±host_dc_notch_width of bin 0. Two new host registers: host_mti_enable (0x26), host_dc_notch_width (0x27). Both default to off/pass-through for backward compatibility. Build 25: WNS +0.132 ns, WHS +0.058 ns. 9,252 LUTs, 12,488 FFs, 17 BRAM, 142 DSP, 0.753 W. 23/23 FPGA regression, 29/29 MTI standalone checks, 3/3 real-data co-sim exact match.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Build 24 tagged v0.1.5-cfar — CA-CFAR production baseline (075ae1e)</h3>
|
||||
<p class="muted">CA-CFAR detector with CA/GO/SO modes integrated, replacing old threshold detector. Pipelined noise computation (Build 23 fix). WNS +0.179 ns, WHS +0.056 ns. 8,558 LUTs, 10,384 FFs, 17 BRAM, 142 DSP, 0.754 W. CFAR cost: +2,229 LUTs, +1,281 FFs, +1 BRAM, +3 DSP. Includes magnitude BRAM buffer, sliding-window algorithm, host-configurable guard/train/alpha/mode registers (opcodes 0x21-0x25).</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Build 23 failed timing, root-caused and fixed (0745cc4)</h3>
|
||||
<p class="muted">Build 23 had WNS -0.309 ns due to combinational path through CFAR noise_sum_comb → cross-multiply → alpha*noise DSP. Fixed by pipelining noise computation into ST_CFAR_THR + ST_CFAR_MUL stages, splitting the path across two clock cycles.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>7 production fixes tagged v0.1.4-prod-fixes (e93bc33)</h3>
|
||||
<p class="muted">Detection bug fixes (sticky flag + one-cycle-lag magnitude), rename cfar→threshold_detect, digital gain control (host-configurable power-of-2 shift), Doppler/chirps mismatch protection (clamp + error flag), decimator watchdog (timeout counter), bypass_mode dead code removal, range-mode register (0x20). Real-data co-simulation framework added. 22/22 FPGA regression.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Real-data co-simulation framework (0b06436)</h3>
|
||||
<p class="muted">Three real-data testbenches added: range FFT, Doppler, and full-chain. Compare RTL outputs against Python golden reference using recorded ADC captures. 5,137 total data checks, all exact bit-for-bit match. Tagged v0.1.4-pre-fixes as safety net before production fixes.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Build 21 tagged v0.1.4-build21 — pre-CFAR production baseline (2efab23)</h3>
|
||||
<p class="muted">WNS +0.156 ns, WHS +0.064 ns, WPWS +0.361 ns. 6,192 LUTs (4.6%), 9,064 FFs (3.4%), 16 BRAM (4.4%), 139 DSP48E1 (18.8%), 0.732 W. Includes FFT 4-cycle butterfly (20% throughput), barrel-shift twiddle (-1 DSP), Gap 2 GUI Settings, E2E RTL fixes (mixer sequencing, USB data-pending, receiver toggle wiring), Vivado DRC multiple-driver fix for data_pending flags, and MMCM LOCKED XDC false_path correction (-from → -through). Build script crash at report_exceptions/check_timing (Vivado 2025.2 bug) fixed by wrapping in catch blocks; all 12 critical reports and bitstream generated successfully.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>E2E integration test + RTL fixes: mixer sequencing, USB data-pending, receiver wiring (0773001)</h3>
|
||||
<p class="muted">New end-to-end testbench (tb_system_e2e.v) with 46 checks across 12 groups covering reset, TX, safety, RX, USB R/W, CDC, beam scanning, reset recovery, stream control, latency budgets, and watchdog. RTL fixes discovered via E2E: chirp controller TX/RX mixer enables now mutually exclusive by FSM state; USB write FSM gains doppler/cfar data_pending sticky flags with stream-control reset default changed to range-only (3'b001); receiver gets STM32 toggle signal inputs and dynamic frame detection. USB unit tests 21/22/56 updated for data_pending architecture. Regression script PASS/FAIL parsing hardened. 19/19 FPGA, 20/20 MCU.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>FFT engine optimizations: 4-cycle butterfly + barrel-shift twiddle (a3e1996)</h3>
|
||||
<p class="muted">Merged SHIFT state into WRITE stage for a 5→4 cycle butterfly pipeline (20% throughput improvement). Replaced multiplier-based twiddle factor index computation with variable left-shift (barrel shift), freeing one DSP48 multiplier. Both changes verified via FFT testbench.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Gap 2: GUI Settings — runtime chirp timing, stream control, status readback (7cdfa48)</h3>
|
||||
<p class="muted">Radar chirp timing parameters (long/short chirp, listen, guard cycles, chirps-per-elevation) are now runtime-configurable via 6 new USB opcodes (0x10-0x15). Stream control (opcode 0x04) gates the USB write FSM per-stream. CFAR threshold (opcode 0x03) is wired to actual comparison logic (was hardcoded). Status readback (opcode 0xFF) returns a 7-word packet with all current settings. CDC handled via per-bit 2-stage synchronizers (stream control) and toggle CDC (status request). 4 new testbench groups added. 18/18 FPGA, 20/20 MCU.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Gap 4: USB Read Path wired with toggle CDC (e5d1b3c)</h3>
|
||||
<p class="muted">FT601 read FSM cmd_* outputs connected through toggle CDC to clk_100m command decode registers in radar_system_top.v. Host can now set radar mode, trigger chirps, set CFAR threshold, and control data streaming via USB. 3 new testbench groups (55 total checks). 18/18 FPGA regression.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Build 20 tagged v0.1.3-build20 — new production baseline (c6103b3)</h3>
|
||||
<p class="muted">WNS improved 7x to +0.426 ns (from +0.062 ns in Build 18). Includes 400 MHz MMCM jitter cleaner, CIC comb DSP48E1 CREG pipeline, and XDC clock-name fix. All timing constraints met. 6,092 LUTs (4.5%), 9,024 FFs (3.4%), 16 BRAM (4.4%), 140 DSP48E1 (18.9%), 0.730 W.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Build 19 timing failure root-caused and fixed</h3>
|
||||
<p class="muted">Build 19 had WNS -0.011 ns due to conflicting XDC create_generated_clock preventing false-path application on CDC paths. Fixed by removing the conflicting constraint and using Vivado auto-generated clk_mmcm_out0.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Gap 3: Safety Architecture closed (f3bbf77)</h3>
|
||||
<p class="muted">Added IWDG watchdog configuration, Emergency_Stop PA rail cutoff, temperature max guard, periodic IDQ re-read, and emergency state ordering. 5 new MCU tests, 20/20 MCU regression pass.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Gap 5: BRAM async reset fixed (c87dce0)</h3>
|
||||
<p class="muted">Chirp memory loader BRAM async reset converted to synchronous reset pattern per Xilinx UG901 guidelines. Prevents BRAM inference failures on production target.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Build 18 tagged v0.1.2-build18 — prior production baseline</h3>
|
||||
<p class="muted">WNS +0.062 ns, WHS +0.059 ns. 6,088 LUTs, 8,946 FFs, 16 BRAM, 140 DSP48E1, 0.631 W. All timing met.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Firmware bug sweep closed with regression coverage</h3>
|
||||
<p class="muted">All 17 audited MCU firmware bugs were fixed, regression-tested, and pushed, including LO init ordering, SPI chip-select handling, PA calibration logic, TIM3 PWM bring-up, and stale diagnostic mismatches. 20/20 MCU tests pass.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>FPGA timing/resource cleanup phase completed</h3>
|
||||
<p class="muted">Chirp BRAM migration, Doppler DSP48 pipelining, CIC pipeline staging, matched-filter regression repair, and full FPGA regression brought the active baseline to 18/18 passing tests.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid-2" style="margin-top:0.8rem;">
|
||||
<article class="card">
|
||||
<h2>Codebase quality and verification upgrades</h2>
|
||||
<ul>
|
||||
<li>FPGA regression: 23/23 passing suites covering matched filter, Doppler, CIC, CDC, USB (with read path), FFT, NCO, FIR, range decimator, mode controller, system-top integration, system E2E, CFAR standalone, and MTI standalone.</li>
|
||||
<li>MCU regression: 20/20 passing tests (15 bug-fix + 5 Gap-3 safety tests).</li>
|
||||
<li>Architectural gaps 1–7 all closed. Gap 1 (CFAR) integrated as CA-CFAR detector (Build 24). MTI canceller + DC notch filter added (Build 25). Gaps 2–7 closed prior to Build 21.</li>
|
||||
<li>USB host-to-FPGA command path fully wired: read FSM, toggle CDC, command decode for mode/trigger/CFAR/stream control. GUI settings (chirp timing, stream gating, status readback) fully operational.</li>
|
||||
<li>Safety architecture: IWDG watchdog, emergency stop PA cutoff, temperature guard, IDQ re-read, state ordering.</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2>Build history and timing improvements</h2>
|
||||
<ul>
|
||||
<li><strong>Build 25 (v0.1.6-mti)</strong>: Current production baseline. WNS +0.132 ns, WHS +0.058 ns. MTI canceller + DC notch filter. 9,252 LUTs, 12,488 FFs, 142 DSP48E1. 0.753 W.</li>
|
||||
<li><strong>Build 24 (v0.1.5-cfar)</strong>: Prior production baseline. WNS +0.179 ns, WHS +0.056 ns. CA-CFAR detector (CA/GO/SO). 8,558 LUTs, 142 DSP48E1. 0.754 W.</li>
|
||||
<li><strong>Build 21 (v0.1.4-build21)</strong>: Pre-CFAR baseline. WNS +0.156 ns, WHS +0.064 ns. FFT 4-cycle butterfly + barrel-shift twiddle. 139 DSP48E1 (-1). 0.732 W.</li>
|
||||
<li><strong>Build 20 (v0.1.3-build20)</strong>: Prior production baseline. WNS +0.426 ns, WHS +0.058 ns. 400 MHz MMCM + CIC CREG pipeline. 0.730 W.</li>
|
||||
<li><strong>Build 19</strong>: Failed (WNS -0.011 ns). Root cause: conflicting XDC generated clock prevented false-path application.</li>
|
||||
<li><strong>Build 18 (v0.1.2-build18)</strong>: Prior baseline. WNS +0.062 ns, WHS +0.059 ns. 0.631 W.</li>
|
||||
<li><strong>Build 17 (v0.1.1-build17)</strong>: FIR DSP48 pipelining + matched filter BRAM migration.</li>
|
||||
<li>Remote Vivado build infrastructure on Ubuntu 24.04 with Vivado 2025.2, targeting XC7A200T-2FBG484I.</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container"><p>Update this page at each major commit or bring-up gate.</p></div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
92
docs/index.html
Normal file
@@ -0,0 +1,92 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AERIS-10 Engineering Docs</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="index.html">AERIS-10 Docs</a>
|
||||
<nav>
|
||||
<a href="architecture.html">Architecture</a>
|
||||
<a href="implementation-log.html">Implementation Log</a>
|
||||
<a href="bring-up.html">Bring-Up</a>
|
||||
<a href="reports.html">Reports</a>
|
||||
<a href="release-notes.html">Release Notes</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container page">
|
||||
<section class="hero">
|
||||
<p class="eyebrow">Open-Source Phased Array Radar</p>
|
||||
<h1>Engineering Documentation Site</h1>
|
||||
<p>This site tracks architecture, validated implementation baselines, constraint cleanup progress, and pre-hardware bring-up readiness for AERIS-10.</p>
|
||||
<div class="cta-row">
|
||||
<a class="button" href="implementation-log.html">View Change Timeline</a>
|
||||
<a class="button ghost" href="bring-up.html">Open Readiness Package</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="stats-grid">
|
||||
<article class="card stat notice">
|
||||
<h2>Production Board USB</h2>
|
||||
<p class="metric">FT2232H (USB 2.0)</p>
|
||||
<p class="muted">50T production board uses FT2232H. FT601 USB 3.0 is available on 200T premium dev board only.</p>
|
||||
</article>
|
||||
<article class="card stat">
|
||||
<h2>Tracked Timing Baseline</h2>
|
||||
<p class="metric">WNS +0.058 ns</p>
|
||||
<p class="muted">WHS +0.068, WPWS +0.684 after validated Build 16 XDC port</p>
|
||||
</article>
|
||||
<article class="card stat">
|
||||
<h2>Regression Status</h2>
|
||||
<p class="metric">MCU 15 / 15, FPGA 18 / 18</p>
|
||||
<p class="muted">Host firmware regression plus FPGA unit and integration suites passing</p>
|
||||
</article>
|
||||
<article class="card stat">
|
||||
<h2>Methodology State</h2>
|
||||
<p class="metric">XDCB-5 = 0</p>
|
||||
<p class="muted">Single documented TIMING-18 residue on `ft601_txe` async observation</p>
|
||||
</article>
|
||||
<article class="card stat">
|
||||
<h2>Current Phase</h2>
|
||||
<p class="metric">Pre-Hardware Readiness</p>
|
||||
<p class="muted">Board-arrival smoke test, artifact inventory, and open-risk tracking prepared</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="grid-2">
|
||||
<article class="card">
|
||||
<h2>What changed recently</h2>
|
||||
<ul>
|
||||
<li>Ported the validated Build 16 production-target XDC cleanup into the tracked repository.</li>
|
||||
<li>Preserved positive post-route timing while clearing XDCB-5 and reducing methodology residue to a single documented item.</li>
|
||||
<li>Validated the tracked branch with MCU host regression and FPGA regression/integration suites.</li>
|
||||
<li>Refreshed the bring-up documentation into a pre-arrival readiness package for the FPGA module and carrier board.</li>
|
||||
<li>Kept upstream ADAR1000 bulk imports out of the baseline pending selective, justified reuse only.</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2>Documentation Map</h2>
|
||||
<ul>
|
||||
<li><a href="architecture.html">System and FPGA Architecture</a></li>
|
||||
<li><a href="implementation-log.html">Detailed Engineering Change Log</a></li>
|
||||
<li><a href="bring-up.html">Pre-Arrival Bring-Up Plan, Artifact Checklist, and Open Risks</a></li>
|
||||
<li><a href="reports.html">Published reports, simulations, and artifact context</a></li>
|
||||
<li><a href="release-notes.html">Release Notes by Key Commit</a></li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p>AERIS-10 documentation published via GitHub Pages from <code>/docs</code>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
204
docs/release-notes.html
Normal file
@@ -0,0 +1,204 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AERIS-10 Docs | Release Notes</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="index.html">AERIS-10 Docs</a>
|
||||
<nav>
|
||||
<a href="architecture.html">Architecture</a>
|
||||
<a href="implementation-log.html">Implementation Log</a>
|
||||
<a href="bring-up.html">Bring-Up</a>
|
||||
<a href="reports.html">Reports</a>
|
||||
<a href="release-notes.html">Release Notes</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container page">
|
||||
<section class="hero">
|
||||
<p class="eyebrow">Traceability</p>
|
||||
<h1>Release Notes by Key Commit</h1>
|
||||
<p>Milestone notes keyed to major bring-up, debug, and documentation commits.</p>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Commit timeline</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Commit</th>
|
||||
<th>Title</th>
|
||||
<th>Impact</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>TBD</code> <strong>v0.1.8-te0713-ft601-dev</strong></td>
|
||||
<td>TE0713/TE0701 + UMFT601X-B FT601 integration dev bitstream</td>
|
||||
<td>First timing-clean FT601 USB integration build for the Trenz + UMFT601X-B FMC LPC stack. Wrapper module (<code>radar_system_top_te0713_umft601x_dev</code>) instantiates the full <code>usb_data_interface</code> with synthetic test data (range/Doppler/CFAR packets). Timing closure achieved after fixing source-synchronous clock skew: replaced <code>set_output_delay</code> with <code>set_max_delay -datapath_only</code> for outputs, removed erroneous <code>set_input_delay</code> on output-only <code>ft601_be[*]</code>. WNS +0.059 ns, WHS +0.121 ns, DRC 0 errors. Strategy: <code>Performance_ExplorePostRoutePhysOpt</code>. Vivado 2025.2. Bitstream: <code>docs/artifacts/te0713-te0701-umft601x-dev-2026-03-21.bit</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>TBD</code> <strong>v0.1.7-te0713-heartbeat</strong></td>
|
||||
<td>TE0713/TE0701 minimal heartbeat bring-up bitstream</td>
|
||||
<td>Created a low-risk bring-up artifact for the Trenz TE0713 + TE0701 stack using <code>radar_system_top_te0713_dev</code> and <code>te0713_te0701_minimal.xdc</code>. Remote Vivado 2025.2 build completed with DRC 0 errors, WNS +17.863 ns, WHS +0.265 ns. Intended as the first board-day image before FT601 arrival and before any radar-path integration.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ed629e7</code> <strong>v0.1.6-mti</strong></td>
|
||||
<td>Build 25: MTI canceller + DC notch filter integration</td>
|
||||
<td>New production baseline. WNS +0.132 ns, WHS +0.058 ns. 9,252 LUTs (6.87%), 12,488 FFs (4.64%), 17 BRAM (4.66%), 142 DSP48E1 (19.19%), 0.753 W. New modules: mti_canceller.v (2-pulse canceller, H(z)=1-z^-1), DC notch filter (inline in system_top). Two new host registers: host_mti_enable (0x26), host_dc_notch_width (0x27). 23/23 FPGA, 20/20 MCU, 3/3 real-data co-sim exact match.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>075ae1e</code> <strong>v0.1.5-cfar</strong></td>
|
||||
<td>Build 24: CA-CFAR detector integration with pipelined noise computation</td>
|
||||
<td>Prior production baseline. WNS +0.179 ns, WHS +0.056 ns. 8,558 LUTs, 10,384 FFs, 17 BRAM, 142 DSP48E1, 0.754 W. CA/GO/SO CFAR modes with BRAM magnitude buffer, sliding-window algorithm. Host-configurable guard/train/alpha/mode registers (0x21-0x25). Build 23 timing failure fixed by pipelining noise computation. 22/22 FPGA, 20/20 MCU.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>e93bc33</code> <strong>v0.1.4-prod-fixes</strong></td>
|
||||
<td>7 production-quality fixes: detection bugs, digital gain, watchdog, dead code removal</td>
|
||||
<td>Detection sticky flag + magnitude lag fix, rename cfar→threshold_detect, host-configurable digital gain control (power-of-2 shift), Doppler/chirps mismatch protection (clamp + error flag), decimator watchdog timeout, bypass_mode dead code removal, range-mode register (0x20). Real-data co-sim framework added. 22/22 FPGA.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>2efab23</code> <strong>v0.1.4-build21</strong></td>
|
||||
<td>Build 21: FFT opts + E2E RTL fixes + Vivado DRC fix + MMCM LOCKED false_path fix</td>
|
||||
<td>New production baseline. WNS +0.156 ns, WHS +0.064 ns, WPWS +0.361 ns. 6,192 LUTs (4.6%), 9,064 FFs (3.4%), 16 BRAM (4.4%), 139 DSP48E1 (18.8%), 0.732 W. Includes 4-cycle FFT butterfly (20% throughput), barrel-shift twiddle (-1 DSP), Vivado DRC multiple-driver fix for data_pending flags, MMCM LOCKED XDC false_path fix (-from → -through). 19/19 FPGA, 20/20 MCU.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>0773001</code></td>
|
||||
<td>E2E integration test + RTL fixes: mixer sequencing, USB data-pending flags, receiver toggle wiring</td>
|
||||
<td>New 46-check E2E testbench (tb_system_e2e.v) across 12 groups. RTL fixes: TX/RX mixer enables mutually exclusive by FSM state, USB write FSM data_pending sticky flags with stream-control reset default 3'b001, STM32 toggle signal wiring for mode-00, dynamic frame detection. USB tests 21/22/56 and regression script PASS/FAIL parsing fixed. 19/19 FPGA, 20/20 MCU.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>a3e1996</code></td>
|
||||
<td>FFT engine: merge SHIFT into WRITE (4-cycle butterfly) + barrel-shift twiddle index</td>
|
||||
<td>SHIFT state merged into WRITE for 5→4 cycle butterfly (20% throughput gain). Multiplier-based twiddle index replaced with barrel-shift (frees 1 DSP48). Verified via FFT testbench; no timing regression expected.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>7cdfa48</code></td>
|
||||
<td>Gap 2 GUI Settings: runtime chirp timing, stream control gating, status readback</td>
|
||||
<td>Runtime-configurable chirp timing (6 new opcodes 0x10-0x15), stream control gating (opcode 0x04 now gates USB write FSM), CFAR threshold wiring (opcode 0x03 replaces hardcoded value), status readback (opcode 0xFF returns 7-word packet). 4 new TB test groups. 18/18 FPGA, 20/20 MCU regression.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>e5d1b3c</code></td>
|
||||
<td>Gap 4 USB Read Path: host-to-FPGA command path with toggle CDC</td>
|
||||
<td>Wired FT601 read FSM cmd_* outputs through toggle CDC to clk_100m command decode registers. Host can now set radar mode, trigger chirps, set CFAR threshold, and control data streaming. 3 new TB test groups (55 checks). 18/18 FPGA regression.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>c6103b3</code> <strong>v0.1.3-build20</strong></td>
|
||||
<td>Gap 7 MMCM jitter cleaner + CIC CREG pipeline + XDC clock-name fix</td>
|
||||
<td>Added 400 MHz MMCM for ADC clock jitter cleaning, CIC comb DSP48E1 CREG pipeline, and fixed XDC conflicting generated clock. Build 20: WNS +0.426 ns (7x improvement over Build 18). All timing met.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>f3bbf77</code></td>
|
||||
<td>Gap 3 Safety Architecture</td>
|
||||
<td>IWDG watchdog, Emergency_Stop PA rail cutoff, temperature max guard, periodic IDQ re-read, emergency state ordering. 5 new MCU tests, 20/20 pass.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>c87dce0</code></td>
|
||||
<td>Gap 5 BRAM async reset fix</td>
|
||||
<td>Fixed chirp memory loader BRAM async reset to use synchronous reset pattern per Xilinx UG901 guidelines.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>3b7afba</code> <strong>v0.1.2-build18</strong></td>
|
||||
<td>Build 18 production build</td>
|
||||
<td>Production baseline: WNS +0.062 ns, WHS +0.059 ns. 6,088 LUTs, 8,946 FFs, 16 BRAM, 140 DSP48E1, 0.631 W.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ed6f79c</code> <strong>v0.1.1-build17</strong></td>
|
||||
<td>FIR DSP48 pipelining + matched filter BRAM migration</td>
|
||||
<td>Build 17 production build with DSP48 pipelining improvements.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>c466021</code></td>
|
||||
<td>Firmware bug sweep closure (B12-B17)</td>
|
||||
<td>Closed the PA calibration, ADC buffer, DIAG macro, TIM3 PWM, and stale-diagnostic issues with additional MCU regression coverage.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>49c9aa2</code></td>
|
||||
<td>SPI platform fix plus FPGA B2/B3 timing work</td>
|
||||
<td>Fixed the legacy platform SPI transmit-only path and landed chirp BRAM migration plus Doppler DSP48 pipelining work.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>3b32f67</code></td>
|
||||
<td>ADF4382A SPI and chip-select correctness</td>
|
||||
<td>Fixed platform SPI ops wiring, added software-managed CS behavior, and widened SPI chip-select storage to handle STM32 pin values correctly.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>3979693</code></td>
|
||||
<td>Initial 8-firmware-bug closure with tests</td>
|
||||
<td>Closed the LO init ordering, AD9523 sequencing, sync trigger, temperature timer, GPIO mapping, and related MCU issues with regression coverage.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Tagged releases</h2>
|
||||
<ul>
|
||||
<li><strong>v0.1.7-te0713-heartbeat</strong> — TE0713/TE0701 first-power baseline. Minimal heartbeat top, DRC clean, WNS +17.863 ns, WHS +0.265 ns. Artifact tracked at <code>docs/artifacts/te0713-te0701-heartbeat-2026-03-21.bit</code>.</li>
|
||||
<li><strong>v0.1.6-mti</strong> (ed629e7) — Current production baseline. WNS +0.132 ns, WHS +0.058 ns. MTI canceller + DC notch filter. 9,252 LUTs, 12,488 FFs, 142 DSP48E1, 17 BRAM. 0.753 W.</li>
|
||||
<li><strong>v0.1.5-cfar</strong> (075ae1e) — Prior production baseline. WNS +0.179 ns. CA-CFAR detector (CA/GO/SO modes) with pipelined noise computation.</li>
|
||||
<li><strong>v0.1.4-prod-fixes</strong> (e93bc33) — 7 production fixes + real-data co-sim framework. WNS same as Build 21 (simulation-only changes).</li>
|
||||
<li><strong>v0.1.4-build21</strong> (2efab23) — Pre-CFAR production baseline. WNS +0.156 ns, WHS +0.064 ns. Includes FFT opts, E2E RTL fixes, Vivado DRC fix, MMCM LOCKED XDC fix. 139 DSP48E1 (-1 vs Build 20).</li>
|
||||
<li><strong>v0.1.3-build20</strong> (c6103b3) — Prior production baseline. WNS +0.426 ns, all timing met. Includes Gaps 3, 5, 7.</li>
|
||||
<li><strong>v0.1.2-build18</strong> (3b7afba) — Prior production baseline. WNS +0.062 ns.</li>
|
||||
<li><strong>v0.1.1-build17</strong> (ed6f79c) — FIR DSP48 + BRAM migration build.</li>
|
||||
<li><strong>v0.1.0-bringup</strong> — Initial bring-up tag.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Architectural gap status</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>#</th><th>Gap</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>3</td><td>Safety Architecture</td><td>Done (f3bbf77)</td></tr>
|
||||
<tr><td>5</td><td>BRAM Async Reset</td><td>Done (c87dce0)</td></tr>
|
||||
<tr><td>7</td><td>400 MHz MMCM</td><td>Done (c6103b3, Build 20)</td></tr>
|
||||
<tr><td>4</td><td>USB Read Path</td><td>Done (e5d1b3c)</td></tr>
|
||||
<tr><td>2</td><td>GUI Settings</td><td>Done (7cdfa48)</td></tr>
|
||||
<tr><td>6</td><td>CDC-15 USB Buses</td><td>Post-bring-up</td></tr>
|
||||
<tr><td>1</td><td>CFAR Real Implementation</td><td>Done (075ae1e, Build 24 + MTI in ed629e7)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Open in GitHub</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/ed629e7" target="_blank" rel="noopener">ed629e7</a> MTI canceller + DC notch filter (v0.1.6-mti)</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/075ae1e" target="_blank" rel="noopener">075ae1e</a> Build 24 report (v0.1.5-cfar)</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/0745cc4" target="_blank" rel="noopener">0745cc4</a> Pipeline CFAR noise computation (timing fix)</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/f71923b" target="_blank" rel="noopener">f71923b</a> Integrate CA-CFAR detector</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/e93bc33" target="_blank" rel="noopener">e93bc33</a> Production fixes 1-7 (v0.1.4-prod-fixes)</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/0b06436" target="_blank" rel="noopener">0b06436</a> Real-data co-simulation (v0.1.4-pre-fixes)</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/2efab23" target="_blank" rel="noopener">2efab23</a> Build 21: FFT opts + DRC fix + XDC fix (v0.1.4-build21)</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/0773001" target="_blank" rel="noopener">0773001</a> E2E test + RTL fixes</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/a3e1996" target="_blank" rel="noopener">a3e1996</a> FFT engine optimizations</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/7cdfa48" target="_blank" rel="noopener">7cdfa48</a> Gap 2 GUI Settings</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/e5d1b3c" target="_blank" rel="noopener">e5d1b3c</a> Gap 4 USB Read Path</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/c6103b3" target="_blank" rel="noopener">c6103b3</a> Gap 7 MMCM + CREG (v0.1.3-build20)</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/f3bbf77" target="_blank" rel="noopener">f3bbf77</a> Gap 3 Safety Architecture</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/c87dce0" target="_blank" rel="noopener">c87dce0</a> Gap 5 BRAM Reset</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/c466021" target="_blank" rel="noopener">c466021</a> Firmware bugs B12-B17</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/49c9aa2" target="_blank" rel="noopener">49c9aa2</a> SPI + FPGA timing</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/3b32f67" target="_blank" rel="noopener">3b32f67</a> ADF4382A SPI</li>
|
||||
<li><a href="https://github.com/JJassonn69/PLFM_RADAR/commit/3979693" target="_blank" rel="noopener">3979693</a> Initial 8-bug closure</li>
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container"><p>Keep this page updated whenever major hardware validation milestones are merged.</p></div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
573
docs/reports.html
Normal file
@@ -0,0 +1,573 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>AERIS-10 Docs | Reports</title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="container nav">
|
||||
<a class="brand" href="index.html">AERIS-10 Docs</a>
|
||||
<nav>
|
||||
<a href="architecture.html">Architecture</a>
|
||||
<a href="implementation-log.html">Implementation Log</a>
|
||||
<a href="bring-up.html">Bring-Up</a>
|
||||
<a href="reports.html">Reports</a>
|
||||
<a href="release-notes.html">Release Notes</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container page">
|
||||
<section class="hero">
|
||||
<p class="eyebrow">Artifacts</p>
|
||||
<h1>Published Reports and Visuals</h1>
|
||||
<p>Central access point for antenna simulations, implementation summaries, timing baselines, and board-day artifact references.</p>
|
||||
<div class="cta-row">
|
||||
<a class="button" href="board-day-worksheet.html">Open Board-Day Worksheet</a>
|
||||
<a class="button ghost" href="bring-up.html">Open Bring-Up Plan</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Current FPGA implementation status</h2>
|
||||
<ul>
|
||||
<li><strong>Build 25</strong> is the current production baseline for the XC7A200T target. All timing constraints met. Includes MTI canceller + DC notch filter integration on top of CA-CFAR.</li>
|
||||
<li>Build 25 reports are available on the remote Vivado host at <code>~/PLFM_RADAR_work/vivado_project/reports_build25/</code>.</li>
|
||||
<li>Build 24 (v0.1.5-cfar) retained as pre-MTI reference at <code>reports_build24/</code>.</li>
|
||||
<li>Build 21 (v0.1.4-build21) retained as pre-CFAR reference at <code>reports_build21/</code>.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<!-- ===== Build 25 — 15-Point Report ===== -->
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Build 25 — 15-Point Engineering Report</h2>
|
||||
<p><span class="chip">Status: PASS — Production-safe bitstream generated</span></p>
|
||||
<p class="muted">Date: 2026-03-20 | Commit: <code>ed629e7</code> | Device: XC7A200T-2FBG484I | Vivado 2025.2</p>
|
||||
|
||||
<!-- 1. Timing -->
|
||||
<h3>1. Timing Summary</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Clock Domain</th><th>Period (ns)</th><th>WNS (ns)</th><th>WHS (ns)</th><th>WPWS (ns)</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>clk_100m</td><td>10.000</td><td>+0.634</td><td>+0.058</td><td>+3.870</td><td>PASS</td></tr>
|
||||
<tr><td>clk_mmcm_out0 (400 MHz)</td><td>2.500</td><td>+0.304</td><td>+0.115</td><td>+0.684</td><td>PASS</td></tr>
|
||||
<tr><td>adc_dco_p</td><td>—</td><td>+0.904</td><td>—</td><td>+0.361</td><td>PASS</td></tr>
|
||||
<tr><td>ft601_clk_in</td><td>10.000</td><td>+0.132</td><td>+0.121</td><td>+4.500</td><td>PASS</td></tr>
|
||||
<tr><td>clk_120m_dac</td><td>—</td><td>+0.773</td><td>+0.151</td><td>+3.666</td><td>PASS</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">TNS = 0.000 ns, THS = 0.000 ns across all domains. Zero failing endpoints. Overall WNS +0.132 ns (ft601_clk_in domain, USB FSM path). Overall WHS +0.058 ns.</p>
|
||||
|
||||
<!-- 2. Utilization -->
|
||||
<h3>2. Utilization (Post-Route)</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Resource</th><th>Build 24 (CFAR)</th><th>Build 25 (MTI)</th><th>Available</th><th>Util%</th><th>Delta</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Slice LUTs</td><td>8,558</td><td>9,252</td><td>134,600</td><td>6.87%</td><td>+694 (+8.1%)</td></tr>
|
||||
<tr><td>Slice Registers (FFs)</td><td>10,384</td><td>12,488</td><td>269,200</td><td>4.64%</td><td>+2,104 (+20%)</td></tr>
|
||||
<tr><td>Block RAM Tiles</td><td>17</td><td>17</td><td>365</td><td>4.66%</td><td>0</td></tr>
|
||||
<tr><td> RAMB36E1</td><td>12</td><td>12</td><td>365</td><td>3.29%</td><td>0</td></tr>
|
||||
<tr><td> RAMB18E1</td><td>10</td><td>10</td><td>730</td><td>1.37%</td><td>0</td></tr>
|
||||
<tr><td>LUT as Distributed RAM</td><td>—</td><td>48</td><td>46,200</td><td>0.10%</td><td>—</td></tr>
|
||||
<tr><td>DSP48E1</td><td>142</td><td>142</td><td>740</td><td>19.19%</td><td>0</td></tr>
|
||||
<tr><td>Bonded IOBs</td><td>178</td><td>178</td><td>285</td><td>62.46%</td><td>0</td></tr>
|
||||
<tr><td>BUFGCTRL</td><td>5</td><td>5</td><td>32</td><td>15.63%</td><td>0</td></tr>
|
||||
<tr><td>MMCME2_ADV</td><td>1</td><td>1</td><td>10</td><td>10.00%</td><td>0</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">MTI canceller added +694 LUTs (distributed RAM for chirp delay line + subtraction logic + DC notch comparators) and +2,104 FFs (I/Q pipeline registers, saturation logic, notch width comparators). Zero BRAM and DSP impact — MTI uses distributed RAM and fabric arithmetic only.</p>
|
||||
|
||||
<!-- 3. DSP48E1 Breakdown -->
|
||||
<h3>3. DSP48E1 Breakdown by Module</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Module</th><th>DSP48E1</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>DDC (FIR I + FIR Q + CIC + NCO)</td><td>117</td><td>Dominant consumer: 47+47 FIR taps + 10+10 CIC + 2 DDC + 1 NCO</td></tr>
|
||||
<tr><td>Matched Filter Processing Chain</td><td>12</td><td>8 FFT butterflies + 4 freq-domain multiply</td></tr>
|
||||
<tr><td>Doppler Processor + FFT</td><td>10</td><td>8 FFT butterflies + 2 magnitude</td></tr>
|
||||
<tr><td>CFAR Detector</td><td>3</td><td>alpha*noise multiply + GO/SO cross-multiply (pipelined)</td></tr>
|
||||
<tr><td>MTI Canceller</td><td>0</td><td>Pure fabric arithmetic (subtraction + saturation)</td></tr>
|
||||
<tr><td><strong>Total</strong></td><td><strong>142</strong></td><td>19.19% of 740 available</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 4. BRAM Breakdown -->
|
||||
<h3>4. BRAM Breakdown by Module</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Module</th><th>RAMB36</th><th>RAMB18</th><th>Tiles</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Doppler Processor</td><td>4</td><td>0</td><td>4</td><td>Range-Doppler accumulation buffers</td></tr>
|
||||
<tr><td>Matched Filter (mf_dual)</td><td>2</td><td>10</td><td>7</td><td>Coefficient + I/Q data BRAMs</td></tr>
|
||||
<tr><td>CFAR Detector</td><td>1</td><td>0</td><td>1</td><td>Magnitude buffer (2048×17 bits)</td></tr>
|
||||
<tr><td>Transmitter (chirp mem)</td><td>1</td><td>0</td><td>1</td><td>Chirp waveform storage</td></tr>
|
||||
<tr><td>FFT Engines (2×)</td><td>4</td><td>0</td><td>4</td><td>Twiddle factor + butterfly BRAMs</td></tr>
|
||||
<tr><td>MTI Canceller</td><td>0</td><td>0</td><td>0</td><td>Uses distributed RAM (LUTs), not BRAM</td></tr>
|
||||
<tr><td><strong>Total</strong></td><td><strong>12</strong></td><td><strong>10</strong></td><td><strong>17</strong></td><td>4.66% of 365 tiles</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 5. Power -->
|
||||
<h3>5. Power Estimate</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Category</th><th>Build 24</th><th>Build 25</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Dynamic Power</td><td>0.591 W</td><td>0.590 W</td></tr>
|
||||
<tr><td>Device Static</td><td>0.163 W</td><td>0.163 W</td></tr>
|
||||
<tr><td><strong>Total On-Chip</strong></td><td><strong>0.754 W</strong></td><td><strong>0.753 W</strong></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">Power is essentially unchanged (-1 mW). MTI logic is lightweight fabric arithmetic; DC notch is combinational zeroing with negligible dynamic power.</p>
|
||||
|
||||
<!-- 6. Critical Path -->
|
||||
<h3>6. Critical Path Analysis</h3>
|
||||
<p>The tightest path (WNS = +0.132 ns) is in the <code>ft601_clk_in</code> (100 MHz) domain: <code>ft601_rxf</code> input pad → 8 logic levels (IBUF + LUT1 + LUT3 + 4×LUT6 + LUT5) → <code>usb_inst/FSM_sequential_current_state_reg[2]/D</code>. This is the USB read FSM path and is unrelated to MTI or CFAR.</p>
|
||||
<p>The <code>clk_100m</code> domain (where MTI, CFAR, and Doppler operate) has +0.634 ns slack — improved from Build 24's +0.287 ns. The MTI canceller adds no new critical paths.</p>
|
||||
|
||||
<!-- 7. Post-synth vs Post-route -->
|
||||
<h3>7. Post-Synthesis vs Post-Route Comparison</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Metric</th><th>Post-Synth</th><th>Post-Route (final)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>WNS (setup)</td><td>+0.123 ns</td><td>+0.132 ns</td></tr>
|
||||
<tr><td>WHS (hold)</td><td>-0.076 ns (29 violations)</td><td>+0.058 ns (0 violations)</td></tr>
|
||||
<tr><td>LUTs</td><td>9,363</td><td>9,252</td></tr>
|
||||
<tr><td>FFs</td><td>12,537</td><td>12,488</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">Post-route phys_opt resolved all 29 hold violations and improved setup slack by 9 ps. LUT/FF count reduced slightly by optimization passes.</p>
|
||||
|
||||
<!-- 8. DRC -->
|
||||
<h3>8. DRC (Design Rule Checks)</h3>
|
||||
<p>184 checks performed. <strong>0 errors, 0 critical warnings.</strong> Same advisory/warning profile as Build 24 (DPIP-1, DPOP-1/2, REQP-1839/1840, RPBF-3 etc.). No new DRC issues from MTI integration.</p>
|
||||
|
||||
<!-- 9. Methodology -->
|
||||
<h3>9. Methodology Report</h3>
|
||||
<p>Same methodology advisory profile as Build 24. No new methodology warnings from MTI or DC notch logic.</p>
|
||||
|
||||
<!-- 10. Congestion -->
|
||||
<h3>10. Congestion</h3>
|
||||
<p><strong>No congestion windows found above level 5.</strong> The design remains well-placed at 6.87% LUT utilization.</p>
|
||||
|
||||
<!-- 11. Route Status -->
|
||||
<h3>11. Route Status</h3>
|
||||
<ul>
|
||||
<li>Total logical nets: 34,325</li>
|
||||
<li>Routable nets: 24,510 — <strong>24,510 fully routed (100%)</strong></li>
|
||||
<li>Nets with routing errors: <strong>0</strong></li>
|
||||
</ul>
|
||||
|
||||
<!-- 12. Hierarchical Utilization (MTI focus) -->
|
||||
<h3>12. Hierarchical Utilization — MTI Module</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Instance</th><th>LUTs</th><th>FFs</th><th>BRAM</th><th>DSP</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>radar_system_top (total)</td><td>9,252</td><td>12,488</td><td>17</td><td>142</td><td>Full design</td></tr>
|
||||
<tr><td> cfar_inst</td><td>2,210</td><td>1,282</td><td>1</td><td>3</td><td>CA-CFAR detector</td></tr>
|
||||
<tr><td> rx_inst (receiver)</td><td>6,731</td><td>10,703</td><td>10</td><td>139</td><td>Full receiver chain</td></tr>
|
||||
<tr><td> mti_inst</td><td>544</td><td>2,082</td><td>0</td><td>0</td><td>MTI canceller (new)</td></tr>
|
||||
<tr><td> doppler_proc</td><td>681</td><td>540</td><td>4</td><td>10</td><td>Doppler processor</td></tr>
|
||||
<tr><td> ddc</td><td>676</td><td>2,959</td><td>0</td><td>117</td><td>DDC subsystem</td></tr>
|
||||
<tr><td> mf_dual</td><td>2,439</td><td>4,796</td><td>7</td><td>12</td><td>Matched filter</td></tr>
|
||||
<tr><td> range_decim</td><td>219</td><td>129</td><td>0</td><td>0</td><td>Range bin decimator</td></tr>
|
||||
<tr><td> usb_inst</td><td>159</td><td>217</td><td>0</td><td>0</td><td>USB data interface</td></tr>
|
||||
<tr><td> tx_inst</td><td>111</td><td>91</td><td>1</td><td>0</td><td>Transmitter</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">MTI canceller: 544 LUTs (0.40% device), 2,082 FFs (0.77% device), 0 BRAM, 0 DSP. The high FF count is from the chirp delay line (64 range bins × 16-bit I + 16-bit Q = 2,048 FFs for storage) implemented as distributed register file rather than BRAM.</p>
|
||||
|
||||
<!-- 13. Build Comparison -->
|
||||
<h3>13. Build-Over-Build Comparison</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Metric</th><th>Build 21 (baseline)</th><th>Build 23 (failed)</th><th>Build 24 (CFAR)</th><th>Build 25 (MTI)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>WNS (ns)</td><td>+0.156</td><td style="color:#c33;">-0.309</td><td>+0.179</td><td style="color:#080;"><strong>+0.132</strong></td></tr>
|
||||
<tr><td>WHS (ns)</td><td>+0.064</td><td>—</td><td>+0.056</td><td>+0.058</td></tr>
|
||||
<tr><td>LUTs</td><td>6,192</td><td>8,668 (synth)</td><td>8,558</td><td>9,252</td></tr>
|
||||
<tr><td>FFs</td><td>9,064</td><td>10,411 (synth)</td><td>10,384</td><td>12,488</td></tr>
|
||||
<tr><td>BRAM Tiles</td><td>16</td><td>17 (synth)</td><td>17</td><td>17</td></tr>
|
||||
<tr><td>DSP48E1</td><td>139</td><td>—</td><td>142</td><td>142</td></tr>
|
||||
<tr><td>Power (W)</td><td>0.732</td><td>—</td><td>0.754</td><td>0.753</td></tr>
|
||||
<tr><td>Bitstream</td><td>Safe</td><td style="color:#c33;">Unsafe</td><td>Safe</td><td style="color:#080;"><strong>Safe</strong></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 14. MTI + DC Notch Resource Cost -->
|
||||
<h3>14. MTI + DC Notch Integration Resource Cost</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Resource</th><th>MTI + DC Notch</th><th>% of Device</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>LUTs</td><td>~694</td><td>0.52%</td><td>MTI: 544 LUTs (subtraction, saturation, mux). DC notch: ~150 LUTs (bin compare, data zeroing) in system_top.</td></tr>
|
||||
<tr><td>FFs</td><td>~2,104</td><td>0.78%</td><td>MTI: 2,082 FFs (chirp delay line 64×32-bit + control). DC notch: ~22 FFs (registered width, active flags).</td></tr>
|
||||
<tr><td>BRAM</td><td>0</td><td>0%</td><td>Chirp delay line fits in distributed registers (64 bins × 32 bits = 2,048 bits)</td></tr>
|
||||
<tr><td>DSP48E1</td><td>0</td><td>0%</td><td>Subtraction uses fabric adders, no multiply needed</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">Total MTI + DC notch cost: 0.52% of device LUTs, 0.78% of FFs. Very lightweight addition. Backward-compatible: <code>host_mti_enable</code> defaults to 0 (pass-through), <code>host_dc_notch_width</code> defaults to 0 (off).</p>
|
||||
|
||||
<!-- 15. Verification Summary -->
|
||||
<h3>15. Verification Summary</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Test Suite</th><th>Tests</th><th>Checks</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>FPGA regression (run_regression.sh)</td><td>23</td><td>—</td><td>23/23 PASS</td></tr>
|
||||
<tr><td>MTI standalone (tb_mti_canceller.v)</td><td>11</td><td>29</td><td>29/29 PASS</td></tr>
|
||||
<tr><td>CFAR standalone (tb_cfar_ca.v)</td><td>14</td><td>23</td><td>23/23 PASS</td></tr>
|
||||
<tr><td>Digital gain (tb_rx_gain_control.v)</td><td>—</td><td>32</td><td>32/32 PASS</td></tr>
|
||||
<tr><td>Threshold fallback (tb_threshold_detector.v)</td><td>—</td><td>22</td><td>22/22 PASS</td></tr>
|
||||
<tr><td>System E2E (tb_system_e2e.v, Group 14)</td><td>13</td><td>67</td><td>67/67 PASS</td></tr>
|
||||
<tr><td>Real-data co-sim: Range FFT</td><td>1</td><td>1,024</td><td>1024/1024 exact</td></tr>
|
||||
<tr><td>Real-data co-sim: Doppler</td><td>1</td><td>2,056</td><td>2056/2056 exact</td></tr>
|
||||
<tr><td>Real-data co-sim: Full-chain</td><td>1</td><td>2,057</td><td>2057/2057 exact</td></tr>
|
||||
<tr><td>MCU regression</td><td>20</td><td>—</td><td>20/20 PASS</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">5,310 individual data checks across all RTL test suites. Zero failures. MTI standalone test covers: pass-through, first-chirp mute, subtraction correctness, stationary target cancellation, moving target preservation, saturation (positive/negative), enable toggle, reset behavior, bin tracking, back-to-back chirps, and negative value handling.</p>
|
||||
|
||||
<h3>Build 25 Artifacts</h3>
|
||||
<ul>
|
||||
<li>Bitstream: <code>~/PLFM_RADAR_work/vivado_project/bitstream/radar_system_top_build25.bit</code> (9.7 MB)</li>
|
||||
<li>Reports: <code>~/PLFM_RADAR_work/vivado_project/reports_build25/</code> (21 report files)</li>
|
||||
<li>Build log: <code>~/PLFM_RADAR_work/build25.log</code></li>
|
||||
<li>TCL script: <code>~/PLFM_RADAR_work/vivado_project/build25_mti.tcl</code></li>
|
||||
</ul>
|
||||
<p class="muted">Note: TCL crashed at step 13/15 (<code>extract_files</code> missing parameter) after all reports were generated. Same non-critical scripting bug as Build 24.</p>
|
||||
</section>
|
||||
|
||||
<!-- ===== Build 24 — 15-Point Report ===== -->
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Build 24 — 15-Point Engineering Report</h2>
|
||||
<p><span class="chip">Status: PASS — Production-safe bitstream generated</span></p>
|
||||
<p class="muted">Date: 2026-03-20 | Commit: <code>0745cc4</code> | Device: XC7A200T-2FBG484I | Vivado 2025.2</p>
|
||||
|
||||
<!-- 1. Timing -->
|
||||
<h3>1. Timing Summary</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Clock Domain</th><th>Period (ns)</th><th>WNS (ns)</th><th>WHS (ns)</th><th>WPWS (ns)</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>clk_100m</td><td>10.000</td><td>+0.287</td><td>+0.056</td><td>+3.870</td><td>PASS</td></tr>
|
||||
<tr><td>clk_mmcm_out0 (400 MHz)</td><td>2.500</td><td>+0.179</td><td>+0.092</td><td>+0.684</td><td>PASS</td></tr>
|
||||
<tr><td>adc_dco_p</td><td>—</td><td>+0.904</td><td>—</td><td>+0.361</td><td>PASS</td></tr>
|
||||
<tr><td>ft601_clk_in</td><td>10.000</td><td>+0.347</td><td>+0.094</td><td>+4.500</td><td>PASS</td></tr>
|
||||
<tr><td>clk_120m_dac</td><td>—</td><td>+1.755</td><td>+0.056</td><td>+3.666</td><td>PASS</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">TNS = 0.000 ns, THS = 0.000 ns across all domains. Zero failing endpoints.</p>
|
||||
|
||||
<!-- 2. Utilization -->
|
||||
<h3>2. Utilization (Post-Route)</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Resource</th><th>Build 21 (baseline)</th><th>Build 24</th><th>Available</th><th>Util%</th><th>Delta</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Slice LUTs</td><td>6,192</td><td>8,558</td><td>134,600</td><td>6.36%</td><td>+2,366 (+38%)</td></tr>
|
||||
<tr><td>Slice Registers (FFs)</td><td>9,064</td><td>10,384</td><td>269,200</td><td>3.86%</td><td>+1,320 (+15%)</td></tr>
|
||||
<tr><td>Block RAM Tiles</td><td>16</td><td>17</td><td>365</td><td>4.66%</td><td>+1</td></tr>
|
||||
<tr><td> RAMB36E1</td><td>—</td><td>12</td><td>365</td><td>3.29%</td><td>—</td></tr>
|
||||
<tr><td> RAMB18E1</td><td>—</td><td>10</td><td>730</td><td>1.37%</td><td>—</td></tr>
|
||||
<tr><td>DSP48E1</td><td>139</td><td>142</td><td>740</td><td>19.19%</td><td>+3</td></tr>
|
||||
<tr><td>Bonded IOBs</td><td>—</td><td>178</td><td>285</td><td>62.46%</td><td>—</td></tr>
|
||||
<tr><td>BUFGCTRL</td><td>—</td><td>5</td><td>32</td><td>15.63%</td><td>—</td></tr>
|
||||
<tr><td>MMCME2_ADV</td><td>—</td><td>1</td><td>10</td><td>10.00%</td><td>—</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">CFAR added +1 BRAM18 (magnitude buffer, 2048×17), +3 DSP48E1 (alpha multiply + cross-multiply for GO/SO), +2,366 LUTs (sliding window logic, state machine, mode mux), +1,320 FFs (pipeline registers, counters, window sums).</p>
|
||||
|
||||
<!-- 3. DSP48E1 Breakdown -->
|
||||
<h3>3. DSP48E1 Breakdown by Module</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Module</th><th>DSP48E1</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>DDC (FIR I + FIR Q + CIC + NCO)</td><td>117</td><td>Dominant consumer: 47+47 FIR taps + 10+10 CIC + 2 DDC + 1 NCO</td></tr>
|
||||
<tr><td>Matched Filter Processing Chain</td><td>12</td><td>8 FFT butterflies + 4 freq-domain multiply</td></tr>
|
||||
<tr><td>Doppler Processor + FFT</td><td>10</td><td>8 FFT butterflies + 2 magnitude</td></tr>
|
||||
<tr><td>CFAR Detector</td><td>3</td><td>alpha*noise multiply + GO/SO cross-multiply (pipelined)</td></tr>
|
||||
<tr><td>System Top + Other</td><td>0</td><td>—</td></tr>
|
||||
<tr><td><strong>Total</strong></td><td><strong>142</strong></td><td>19.19% of 740 available</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 4. BRAM Breakdown -->
|
||||
<h3>4. BRAM Breakdown by Module</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Module</th><th>RAMB36</th><th>RAMB18</th><th>Tiles</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Doppler Processor</td><td>4</td><td>0</td><td>4</td><td>Range-Doppler accumulation buffers</td></tr>
|
||||
<tr><td>Matched Filter (mf_dual)</td><td>2</td><td>10</td><td>7</td><td>Coefficient + I/Q data BRAMs</td></tr>
|
||||
<tr><td>CFAR Detector</td><td>1</td><td>0</td><td>1</td><td>Magnitude buffer (2048×17 bits)</td></tr>
|
||||
<tr><td>Transmitter (chirp mem)</td><td>1</td><td>0</td><td>1</td><td>Chirp waveform storage</td></tr>
|
||||
<tr><td>FFT Engines (2×)</td><td>4</td><td>0</td><td>4</td><td>Twiddle factor + butterfly BRAMs</td></tr>
|
||||
<tr><td><strong>Total</strong></td><td><strong>12</strong></td><td><strong>10</strong></td><td><strong>17</strong></td><td>4.66% of 365 tiles</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 5. Power -->
|
||||
<h3>5. Power Estimate</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Category</th><th>Build 21</th><th>Build 24</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Dynamic Power</td><td>—</td><td>0.591 W</td></tr>
|
||||
<tr><td>Device Static</td><td>—</td><td>0.163 W</td></tr>
|
||||
<tr><td><strong>Total On-Chip</strong></td><td><strong>0.732 W</strong></td><td><strong>0.754 W</strong></td></tr>
|
||||
<tr><td>Junction Temperature</td><td>—</td><td>26.9°C</td></tr>
|
||||
<tr><td>Max Ambient (TJA)</td><td>—</td><td>83.1°C</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">+22 mW (+3%) from CFAR logic. Well within thermal budget.</p>
|
||||
|
||||
<!-- 6. Critical Path -->
|
||||
<h3>6. Critical Path Analysis</h3>
|
||||
<p>The tightest path (WNS = +0.179 ns) is in the <code>clk_mmcm_out0</code> (400 MHz) domain: NCO sine LUT index register → LUT6 → <code>sin_abs_reg</code>. This is the same path that was critical in Build 21 and is unrelated to CFAR.</p>
|
||||
<p>The <code>clk_100m</code> domain (where CFAR operates) has +0.287 ns slack. The Build 23 critical path (<code>cfar_inst/leading_sum → cross-multiply → alpha*noise DSP</code>, WNS = -0.309 ns) has been completely eliminated by the pipeline fix.</p>
|
||||
|
||||
<!-- 7. Post-synth vs Post-route -->
|
||||
<h3>7. Post-Synthesis vs Post-Route Comparison</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Metric</th><th>Post-Synth</th><th>Post-Route (final)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>WNS (setup)</td><td>+0.123 ns</td><td>+0.179 ns</td></tr>
|
||||
<tr><td>WHS (hold)</td><td>-0.076 ns (29 violations)</td><td>+0.056 ns (0 violations)</td></tr>
|
||||
<tr><td>LUTs</td><td>8,671</td><td>8,558</td></tr>
|
||||
<tr><td>FFs</td><td>10,433</td><td>10,384</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">Post-route phys_opt resolved all 29 hold violations and improved setup slack by 56 ps. LUT/FF count reduced slightly by optimization passes.</p>
|
||||
|
||||
<!-- 8. DRC -->
|
||||
<h3>8. DRC (Design Rule Checks)</h3>
|
||||
<p>184 checks performed. <strong>0 errors, 0 critical warnings.</strong> Advisory/warning breakdown:</p>
|
||||
<ul>
|
||||
<li>DPIP-1 (input pipelining advisory): 68 — DSP input pipeline suggestions, acceptable for our architecture</li>
|
||||
<li>DPOP-1/2 (output pipelining): 18 + 19 — DSP PREG/MREG advisory, non-critical</li>
|
||||
<li>REQP-1839/1840 (BRAM async control): 20 + 20 — expected with async-reset BRAMs</li>
|
||||
<li>RPBF-3 (IO buffering): 8 — intentional for differential pairs</li>
|
||||
<li>CHECK-3 (report rule limit): 2 — tool display limit, not design issue</li>
|
||||
<li>IOSR-1 (IOB set/reset sharing): 1 — non-critical</li>
|
||||
</ul>
|
||||
|
||||
<!-- 9. Methodology -->
|
||||
<h3>9. Methodology Report</h3>
|
||||
<ul>
|
||||
<li>DPIR-1 (async driver): 91 — known from async-reset architecture, mitigated by CDC modules</li>
|
||||
<li>HPDR-1 (port direction inconsistency): 8 — bidir USB data bus, expected</li>
|
||||
<li>LUTAR-1 (LUT drives async reset): 1 — watchdog reset path, intentional</li>
|
||||
<li>PDRC-190 (suboptimal sync register placement): 3 — minor, does not affect timing</li>
|
||||
<li>SYNTH-6 (RAM timing sub-optimal): 18 — inferred RAMs, all meeting timing</li>
|
||||
<li>TIMING-9 (unknown CDC logic): 1 — covered by explicit CDC synchronizers</li>
|
||||
<li>TIMING-28 (auto-derived clock in constraint): 8 — expected with MMCM-derived clocks</li>
|
||||
<li>TIMING-47 (false path between sync clocks): 4 — intentional XDC false_path constraints</li>
|
||||
</ul>
|
||||
|
||||
<!-- 10. Congestion -->
|
||||
<h3>10. Congestion</h3>
|
||||
<p><strong>No congestion windows found above level 5.</strong> The design is well-placed with no routing pressure. XC7A200T provides ample routing resources at 6.36% LUT utilization.</p>
|
||||
|
||||
<!-- 11. Route Status -->
|
||||
<h3>11. Route Status</h3>
|
||||
<ul>
|
||||
<li>Total logical nets: 31,136</li>
|
||||
<li>Routable nets: 22,026 — <strong>22,026 fully routed (100%)</strong></li>
|
||||
<li>Nets with routing errors: <strong>0</strong></li>
|
||||
</ul>
|
||||
|
||||
<!-- 12. Logic Level Distribution -->
|
||||
<h3>12. Logic Level Distribution (Top 1000 Worst Paths)</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Clock</th><th>Period</th><th>Lvl 0</th><th>Lvl 1</th><th>Lvl 2</th><th>Lvl 3</th><th>Lvl 4</th><th>Lvl 5</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>clk_100m</td><td>10.000 ns</td><td>25</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr>
|
||||
<tr><td>clk_mmcm_out0</td><td>2.500 ns</td><td>808</td><td>108</td><td>3</td><td>19</td><td>8</td><td>3</td></tr>
|
||||
<tr><td>ft601_clk_in</td><td>10.000 ns</td><td>0</td><td>0</td><td>0</td><td>2</td><td>1</td><td>23</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">The <code>clk_100m</code> domain has only level-0 paths in the top-1000 worst — CFAR pipeline fix reduced logic depth to register-to-register transfers. The 400 MHz DDC domain remains the most timing-critical area.</p>
|
||||
|
||||
<!-- 13. Build Comparison -->
|
||||
<h3>13. Build-Over-Build Comparison</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Metric</th><th>Build 21 (baseline)</th><th>Build 23 (CFAR, failed)</th><th>Build 24 (CFAR + pipeline)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>WNS (ns)</td><td>+0.156</td><td style="color:#c33;">-0.309</td><td style="color:#080;"><strong>+0.179</strong></td></tr>
|
||||
<tr><td>WHS (ns)</td><td>+0.064</td><td>—</td><td>+0.056</td></tr>
|
||||
<tr><td>LUTs</td><td>6,192</td><td>8,668 (post-synth)</td><td>8,558</td></tr>
|
||||
<tr><td>FFs</td><td>9,064</td><td>10,411 (post-synth)</td><td>10,384</td></tr>
|
||||
<tr><td>BRAM Tiles</td><td>16</td><td>17 (post-synth)</td><td>17</td></tr>
|
||||
<tr><td>DSP48E1</td><td>139</td><td>—</td><td>142</td></tr>
|
||||
<tr><td>Power (W)</td><td>0.732</td><td>—</td><td>0.754</td></tr>
|
||||
<tr><td>Bitstream</td><td>Safe</td><td style="color:#c33;">Unsafe (timing fail)</td><td style="color:#080;"><strong>Safe</strong></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 14. CFAR Resource Cost -->
|
||||
<h3>14. CFAR Integration Resource Cost</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Resource</th><th>CFAR Module Only</th><th>% of Device</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>LUTs</td><td>2,229</td><td>1.66%</td><td>Sliding window sums, GO/SO cross-multiply, state machine, mode mux</td></tr>
|
||||
<tr><td>FFs</td><td>1,281</td><td>0.48%</td><td>Pipeline registers, window counters, sum accumulators, noise_sum_reg</td></tr>
|
||||
<tr><td>RAMB36E1</td><td>1</td><td>0.27%</td><td>Magnitude buffer: 2048 entries × 17 bits</td></tr>
|
||||
<tr><td>DSP48E1</td><td>3</td><td>0.41%</td><td>alpha×noise, leading cross-multiply, lagging cross-multiply</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">Total CFAR cost: 2.82% of device LUTs, 0.48% of FFs, 0.27% of BRAM, 0.41% of DSPs. Minimal impact on headroom.</p>
|
||||
|
||||
<!-- 15. Verification Summary -->
|
||||
<h3>15. Verification Summary</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Test Suite</th><th>Tests</th><th>Checks</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>FPGA regression (run_regression.sh)</td><td>22</td><td>—</td><td>22/22 PASS</td></tr>
|
||||
<tr><td>CFAR standalone (tb_cfar_ca.v)</td><td>14</td><td>23</td><td>23/23 PASS</td></tr>
|
||||
<tr><td>Digital gain (tb_rx_gain_control.v)</td><td>—</td><td>32</td><td>32/32 PASS</td></tr>
|
||||
<tr><td>Threshold fallback (tb_threshold_detector.v)</td><td>—</td><td>22</td><td>22/22 PASS</td></tr>
|
||||
<tr><td>System E2E (tb_system_e2e.v, Group 14)</td><td>13</td><td>67</td><td>67/67 PASS</td></tr>
|
||||
<tr><td>Real-data co-sim: Range FFT</td><td>1</td><td>1,024</td><td>1024/1024 exact</td></tr>
|
||||
<tr><td>Real-data co-sim: Doppler</td><td>1</td><td>2,056</td><td>2056/2056 exact</td></tr>
|
||||
<tr><td>Real-data co-sim: Full-chain</td><td>1</td><td>2,057</td><td>2057/2057 exact</td></tr>
|
||||
<tr><td>MCU regression</td><td>20</td><td>—</td><td>20/20 PASS</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="muted">5,281 individual data checks across all RTL test suites. Zero failures. Real-data co-simulation confirms bit-exact match with Python golden reference across the entire signal processing chain.</p>
|
||||
|
||||
<h3>Build 24 Artifacts</h3>
|
||||
<ul>
|
||||
<li>Bitstream: <code>~/PLFM_RADAR_work/vivado_project/bitstream/radar_system_top_build24.bit</code> (9.7 MB)</li>
|
||||
<li>Reports: <code>~/PLFM_RADAR_work/vivado_project/reports_build24/</code> (21 report files)</li>
|
||||
<li>Build log: <code>~/PLFM_RADAR_work/build24.log</code></li>
|
||||
<li>TCL script: <code>~/PLFM_RADAR_work/vivado_project/build24_cfar.tcl</code></li>
|
||||
</ul>
|
||||
<p class="muted">Note: TCL crashed at step 13/15 (<code>extract_files</code> missing parameter) after all reports were generated. Non-critical scripting bug; all implementation, optimization, and bitstream generation completed successfully.</p>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Board-day artifact inventory</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Artifact</th>
|
||||
<th>Source path</th>
|
||||
<th>Day-0 use</th>
|
||||
<th>Status / note</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>Production-target XDC</td><td><code>firmware/9_2_FPGA/constraints/xc7a200t_fbg484.xdc</code></td><td>Constraint source of truth for the production FPGA target</td><td>Tracked and validated after Build 16 cleanup port</td></tr>
|
||||
<tr><td>FPGA programming flow</td><td><code>firmware/9_2_FPGA/scripts/program_fpga.tcl</code></td><td>Programs the device and reports DONE / INIT_COMPLETE / probes presence</td><td>Primary operator-facing programming script</td></tr>
|
||||
<tr><td>Debug probe insertion flow</td><td><code>firmware/9_2_FPGA/scripts/insert_ila_probes.tcl</code></td><td>Used when generating or refreshing debug-capable images</td><td>Keep matched with the selected debug bitstream</td></tr>
|
||||
<tr><td>FPGA regression runner</td><td><code>firmware/9_2_FPGA/run_regression.sh</code></td><td>Pre-arrival regression evidence for the tracked FPGA baseline</td><td>23 / 23 passing on the current tracked branch (includes CFAR + MTI + E2E tests)</td></tr>
|
||||
<tr><td>MCU regression harness</td><td><code>firmware/9_1_Microcontroller/tests/Makefile</code></td><td>Pre-arrival firmware regression evidence before flashing hardware</td><td>20 / 20 passing on the current tracked branch</td></tr>
|
||||
<tr><td>Bring-up logging macros</td><td><code>firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/diag_log.h</code></td><td>Defines the main first-power-on log vocabulary used over USART3</td><td>Observation-only instrumentation layer</td></tr>
|
||||
<tr><td>Board-day worksheet</td><td><code>docs/board-day-worksheet.html</code></td><td>Record pass/fail, measurements, and blockers during first sessions</td><td>Use with this page and the bring-up plan</td></tr>
|
||||
<tr><td>Bring-up execution plan</td><td><code>docs/bring-up.html</code></td><td>Operator checklist, abort criteria, observability targets, and open risks</td><td>Primary readiness document</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid-2" style="margin-top:0.8rem;">
|
||||
<article class="card">
|
||||
<h2>Antenna Simulation Report</h2>
|
||||
<p><span class="chip">Status: Mostly current (historical Phase-0 context)</span></p>
|
||||
<p class="muted">File: <code>AERIS_Antenna_Report.pdf</code></p>
|
||||
<p class="muted">Notes: Valid for 10.5 GHz patch-element simulation and array projection context. Treat as element-level evidence, not full current hardware bring-up sign-off.</p>
|
||||
<p>
|
||||
<a class="button" href="AERIS_Antenna_Report.pdf" target="_blank" rel="noopener">Open PDF</a>
|
||||
<a class="button ghost" href="AERIS_Antenna_Report.pdf" download>Download</a>
|
||||
</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h2>Python Simulation Report</h2>
|
||||
<p><span class="chip">Status: Legacy (needs refresh)</span></p>
|
||||
<p class="muted">File: <code>AERIS_Simulation_Report.pdf</code></p>
|
||||
<p class="muted">Notes: Contains older architecture assumptions (e.g., XC7A100T-centric narrative). Use as historical reference only until Simulation Report v2 is published.</p>
|
||||
<p>
|
||||
<a class="button" href="AERIS_Simulation_Report.pdf" target="_blank" rel="noopener">Open PDF</a>
|
||||
<a class="button ghost" href="AERIS_Simulation_Report.pdf" download>Download</a>
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>FPGA implementation analysis</h2>
|
||||
<p><span class="chip">Status: Current engineering baseline — Build 25 (MTI + DC notch)</span></p>
|
||||
<p class="muted">Build 25 is the current production baseline. Includes MTI canceller (2-pulse clutter cancellation) and DC notch filter on top of CA-CFAR detector. Full 15-point report above. WNS +0.132 ns, WHS +0.058 ns. DSP count 142 (unchanged). BRAM 17 (unchanged). LUTs 9,252 (+694 from Build 24). FFs 12,488 (+2,104). Power 0.753 W (unchanged).</p>
|
||||
<p class="muted">Build 24 (v0.1.5-cfar) integrated CA-CFAR with pipelined noise computation. Build 23 failed timing (WNS -0.309 ns) due to combinational critical path — fixed by pipelining.</p>
|
||||
<p class="muted">Build 21 (v0.1.4-build21) retained as pre-CFAR reference. Build 20 (v0.1.3-build20) and earlier retained for historical reference.</p>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Latest Simulation Report (Recommended)</h2>
|
||||
<p><span class="chip">Status: Current baseline (v2)</span></p>
|
||||
<p class="muted">File: <code>AERIS_Simulation_Report_v2.pdf</code></p>
|
||||
<p class="muted">Aligned to the active project baseline: XC7A200T target, firmware regression closure, FPGA regression/timing gates, USB range-profile integration, and TE0712/TE0713 split-target flow.</p>
|
||||
<p>
|
||||
<a class="button" href="AERIS_Simulation_Report_v2.pdf" target="_blank" rel="noopener">Open PDF</a>
|
||||
<a class="button ghost" href="AERIS_Simulation_Report_v2.pdf" download>Download</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Report Currency Notice</h2>
|
||||
<ul>
|
||||
<li>The current routed production-target baseline is <strong>Build 25</strong> with all timing constraints met. WNS +0.132 ns, WHS +0.058 ns, 142 DSP48E1, 17 BRAM, 0.753 W.</li>
|
||||
<li>All architectural gaps are closed: Gap 1 (CFAR) integrated as CA-CFAR detector with CA/GO/SO modes (Build 24). MTI canceller + DC notch filter added in Build 25. Gaps 2–7 were closed prior to Build 21.</li>
|
||||
<li>FPGA regression: 23/23 pass (includes CFAR + MTI + E2E tests). MCU regression: 20/20 pass. Real-data co-sim: 3/3 exact match (5,137 data checks).</li>
|
||||
<li>MTI integration cost: +694 LUTs, +2,104 FFs, 0 BRAM, 0 DSPs. Backward-compatible: <code>host_mti_enable</code> and <code>host_dc_notch_width</code> default to disabled/off.</li>
|
||||
<li>Detailed Build 25 engineering reports are on the remote Vivado host at <code>~/PLFM_RADAR_work/vivado_project/reports_build25/</code>.</li>
|
||||
<li>The artifact inventory above is intended to stabilize day-0 execution even when detailed internal engineering reports stay outside the public docs site.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="card" style="margin-top:0.8rem;">
|
||||
<h2>Antenna concept snapshot</h2>
|
||||
<img class="diagram" src="assets/img/Antenna_Array.jpg" alt="Antenna array concept">
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container"><p>Add future report artifacts here to keep public references stable.</p></div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,116 @@
|
||||
// ADAR1000_AGC.cpp -- STM32 outer-loop AGC implementation
|
||||
//
|
||||
// See ADAR1000_AGC.h for architecture overview.
|
||||
|
||||
#include "ADAR1000_AGC.h"
|
||||
#include "ADAR1000_Manager.h"
|
||||
#include "diag_log.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constructor -- set all config fields to safe defaults
|
||||
// ---------------------------------------------------------------------------
|
||||
ADAR1000_AGC::ADAR1000_AGC()
|
||||
: agc_base_gain(ADAR1000Manager::kDefaultRxVgaGain) // 30
|
||||
, gain_step_down(4)
|
||||
, gain_step_up(1)
|
||||
, min_gain(0)
|
||||
, max_gain(127)
|
||||
, holdoff_frames(4)
|
||||
, enabled(false)
|
||||
, holdoff_counter(0)
|
||||
, last_saturated(false)
|
||||
, saturation_event_count(0)
|
||||
{
|
||||
memset(cal_offset, 0, sizeof(cal_offset));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// update -- called once per frame with the FPGA DIG_5 saturation flag
|
||||
//
|
||||
// Returns true if agc_base_gain changed (caller should then applyGain).
|
||||
// ---------------------------------------------------------------------------
|
||||
void ADAR1000_AGC::update(bool fpga_saturation)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
last_saturated = fpga_saturation;
|
||||
|
||||
if (fpga_saturation) {
|
||||
// Attack: reduce gain immediately
|
||||
saturation_event_count++;
|
||||
holdoff_counter = 0;
|
||||
|
||||
if (agc_base_gain >= gain_step_down + min_gain) {
|
||||
agc_base_gain -= gain_step_down;
|
||||
} else {
|
||||
agc_base_gain = min_gain;
|
||||
}
|
||||
|
||||
DIAG("AGC", "SAT detected -- gain_base -> %u (events=%lu)",
|
||||
(unsigned)agc_base_gain, (unsigned long)saturation_event_count);
|
||||
|
||||
} else {
|
||||
// Recovery: wait for holdoff, then increase gain
|
||||
holdoff_counter++;
|
||||
|
||||
if (holdoff_counter >= holdoff_frames) {
|
||||
holdoff_counter = 0;
|
||||
|
||||
if (agc_base_gain + gain_step_up <= max_gain) {
|
||||
agc_base_gain += gain_step_up;
|
||||
} else {
|
||||
agc_base_gain = max_gain;
|
||||
}
|
||||
|
||||
DIAG("AGC", "Recovery step -- gain_base -> %u", (unsigned)agc_base_gain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// applyGain -- write effective gain to all 16 RX VGA channels
|
||||
//
|
||||
// Uses the Manager's adarSetRxVgaGain which takes 1-based channel indices
|
||||
// (matching the convention in setBeamAngle).
|
||||
// ---------------------------------------------------------------------------
|
||||
void ADAR1000_AGC::applyGain(ADAR1000Manager &mgr)
|
||||
{
|
||||
for (uint8_t dev = 0; dev < AGC_NUM_DEVICES; ++dev) {
|
||||
for (uint8_t ch = 0; ch < AGC_NUM_CHANNELS; ++ch) {
|
||||
uint8_t gain = effectiveGain(dev * AGC_NUM_CHANNELS + ch);
|
||||
// Channel parameter is 1-based per Manager convention
|
||||
mgr.adarSetRxVgaGain(dev, ch + 1, gain, BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// resetState -- clear runtime counters, preserve configuration
|
||||
// ---------------------------------------------------------------------------
|
||||
void ADAR1000_AGC::resetState()
|
||||
{
|
||||
holdoff_counter = 0;
|
||||
last_saturated = false;
|
||||
saturation_event_count = 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// effectiveGain -- compute clamped per-channel gain
|
||||
// ---------------------------------------------------------------------------
|
||||
uint8_t ADAR1000_AGC::effectiveGain(uint8_t channel_index) const
|
||||
{
|
||||
if (channel_index >= AGC_TOTAL_CHANNELS)
|
||||
return min_gain; // safety fallback — OOB channels get minimum gain
|
||||
|
||||
int16_t raw = static_cast<int16_t>(agc_base_gain) + cal_offset[channel_index];
|
||||
|
||||
if (raw < static_cast<int16_t>(min_gain))
|
||||
return min_gain;
|
||||
if (raw > static_cast<int16_t>(max_gain))
|
||||
return max_gain;
|
||||
|
||||
return static_cast<uint8_t>(raw);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// ADAR1000_AGC.h -- STM32 outer-loop AGC for ADAR1000 RX VGA gain
|
||||
//
|
||||
// Adjusts the analog VGA common-mode gain on each ADAR1000 RX channel based on
|
||||
// the FPGA's saturation flag (DIG_5 / PD13). Runs once per radar frame
|
||||
// (~258 ms) in the main loop, after runRadarPulseSequence().
|
||||
//
|
||||
// Architecture:
|
||||
// - Inner loop (FPGA, per-sample): rx_gain_control auto-adjusts digital
|
||||
// gain_shift based on peak magnitude / saturation. Range ±42 dB.
|
||||
// - Outer loop (THIS MODULE, per-frame): reads FPGA DIG_5 GPIO. If
|
||||
// saturation detected, reduces agc_base_gain immediately (attack). If no
|
||||
// saturation for holdoff_frames, increases agc_base_gain (decay/recovery).
|
||||
//
|
||||
// Per-channel gain formula:
|
||||
// VGA[dev][ch] = clamp(agc_base_gain + cal_offset[dev*4+ch], min_gain, max_gain)
|
||||
//
|
||||
// The cal_offset array allows per-element calibration to correct inter-channel
|
||||
// gain imbalance. Default is all zeros (uniform gain).
|
||||
|
||||
#ifndef ADAR1000_AGC_H
|
||||
#define ADAR1000_AGC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Forward-declare to avoid pulling in the full ADAR1000_Manager header here.
|
||||
// The .cpp includes the real header.
|
||||
class ADAR1000Manager;
|
||||
|
||||
// Number of ADAR1000 devices
|
||||
#define AGC_NUM_DEVICES 4
|
||||
// Number of channels per ADAR1000
|
||||
#define AGC_NUM_CHANNELS 4
|
||||
// Total RX channels
|
||||
#define AGC_TOTAL_CHANNELS (AGC_NUM_DEVICES * AGC_NUM_CHANNELS)
|
||||
|
||||
class ADAR1000_AGC {
|
||||
public:
|
||||
// --- Configuration (public for easy field-testing / GUI override) ---
|
||||
|
||||
// Common-mode base gain (raw ADAR1000 register value, 0-255).
|
||||
// Default matches ADAR1000Manager::kDefaultRxVgaGain = 30.
|
||||
uint8_t agc_base_gain;
|
||||
|
||||
// Per-channel calibration offset (signed, added to agc_base_gain).
|
||||
// Index = device*4 + channel. Default: all 0.
|
||||
int8_t cal_offset[AGC_TOTAL_CHANNELS];
|
||||
|
||||
// How much to decrease agc_base_gain per frame when saturated (attack).
|
||||
uint8_t gain_step_down;
|
||||
|
||||
// How much to increase agc_base_gain per frame when recovering (decay).
|
||||
uint8_t gain_step_up;
|
||||
|
||||
// Minimum allowed agc_base_gain (floor).
|
||||
uint8_t min_gain;
|
||||
|
||||
// Maximum allowed agc_base_gain (ceiling).
|
||||
uint8_t max_gain;
|
||||
|
||||
// Number of consecutive non-saturated frames required before gain-up.
|
||||
uint8_t holdoff_frames;
|
||||
|
||||
// Master enable. When false, update() is a no-op.
|
||||
bool enabled;
|
||||
|
||||
// --- Runtime state (read-only for diagnostics) ---
|
||||
|
||||
// Consecutive non-saturated frame counter (resets on saturation).
|
||||
uint8_t holdoff_counter;
|
||||
|
||||
// True if the last update() saw saturation.
|
||||
bool last_saturated;
|
||||
|
||||
// Total saturation events since reset/construction.
|
||||
uint32_t saturation_event_count;
|
||||
|
||||
// --- Methods ---
|
||||
|
||||
ADAR1000_AGC();
|
||||
|
||||
// Call once per frame after runRadarPulseSequence().
|
||||
// fpga_saturation: result of HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_13) == GPIO_PIN_SET
|
||||
void update(bool fpga_saturation);
|
||||
|
||||
// Apply the current gain to all 16 RX VGA channels via the Manager.
|
||||
void applyGain(ADAR1000Manager &mgr);
|
||||
|
||||
// Reset runtime state (holdoff counter, saturation count) without
|
||||
// changing configuration.
|
||||
void resetState();
|
||||
|
||||
// Compute the effective gain for a specific channel index (0-15),
|
||||
// clamped to [min_gain, max_gain]. Useful for diagnostics.
|
||||
uint8_t effectiveGain(uint8_t channel_index) const;
|
||||
};
|
||||
|
||||
#endif // ADAR1000_AGC_H
|
||||
@@ -0,0 +1,930 @@
|
||||
// ADAR1000_Manager.cpp
|
||||
#include "main.h"
|
||||
#include "stm32f7xx_hal.h"
|
||||
#include "ADAR1000_Manager.h"
|
||||
#include "diag_log.h"
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
extern SPI_HandleTypeDef hspi1;
|
||||
extern UART_HandleTypeDef huart3;
|
||||
|
||||
// Chip Select GPIO definitions
|
||||
static const struct {
|
||||
GPIO_TypeDef* port;
|
||||
uint16_t pin;
|
||||
} CHIP_SELECTS[4] = {
|
||||
{ADAR_1_CS_3V3_GPIO_Port, ADAR_1_CS_3V3_Pin}, // ADAR1000 #1
|
||||
{ADAR_2_CS_3V3_GPIO_Port, ADAR_2_CS_3V3_Pin}, // ADAR1000 #2
|
||||
{ADAR_3_CS_3V3_GPIO_Port, ADAR_3_CS_3V3_Pin}, // ADAR1000 #3
|
||||
{ADAR_4_CS_3V3_GPIO_Port, ADAR_4_CS_3V3_Pin} // ADAR1000 #4
|
||||
};
|
||||
|
||||
// ADAR1000 Vector Modulator lookup tables (128-state phase grid, 2.8125 deg step).
|
||||
//
|
||||
// Source: Analog Devices ADAR1000 datasheet Rev. B, Tables 13-16, page 34
|
||||
// (7_Components Datasheets and Application notes/ADAR1000.pdf)
|
||||
// Cross-checked against the ADI Linux mainline driver (GPL-2.0, NOT vendored):
|
||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/
|
||||
// drivers/iio/beamformer/adar1000.c (adar1000_phase_values[])
|
||||
// The 128 byte values themselves are factual data from the datasheet and are
|
||||
// not subject to copyright; only the ADI driver code is GPL.
|
||||
//
|
||||
// Byte format (per datasheet):
|
||||
// bit [7:6] reserved (0)
|
||||
// bit [5] polarity: 1 = positive lobe (sign(I) or sign(Q) >= 0)
|
||||
// 0 = negative lobe
|
||||
// bits [4:0] 5-bit unsigned magnitude (0..31)
|
||||
// At magnitude=0 the polarity bit is physically meaningless; the datasheet
|
||||
// uses POL=1 (e.g. VM_Q at 0 deg = 0x20, VM_I at 90 deg = 0x21).
|
||||
//
|
||||
// Index mapping is uniform: VM_I[k] / VM_Q[k] correspond to phase angle
|
||||
// k * 360/128 = k * 2.8125 degrees. Callers index as VM_*[phase % 128].
|
||||
const uint8_t ADAR1000Manager::VM_I[128] = {
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, // [ 0] 0.0000 deg
|
||||
0x3D, 0x3C, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, // [ 8] 22.5000 deg
|
||||
0x36, 0x35, 0x34, 0x33, 0x32, 0x30, 0x2F, 0x2E, // [ 16] 45.0000 deg
|
||||
0x2C, 0x2B, 0x2A, 0x28, 0x27, 0x25, 0x24, 0x22, // [ 24] 67.5000 deg
|
||||
0x21, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, // [ 32] 90.0000 deg
|
||||
0x0B, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, 0x14, // [ 40] 112.5000 deg
|
||||
0x16, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1C, // [ 48] 135.0000 deg
|
||||
0x1C, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, // [ 56] 157.5000 deg
|
||||
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, // [ 64] 180.0000 deg
|
||||
0x1D, 0x1C, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, // [ 72] 202.5000 deg
|
||||
0x16, 0x15, 0x14, 0x13, 0x12, 0x10, 0x0F, 0x0E, // [ 80] 225.0000 deg
|
||||
0x0C, 0x0B, 0x0A, 0x08, 0x07, 0x05, 0x04, 0x02, // [ 88] 247.5000 deg
|
||||
0x01, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, // [ 96] 270.0000 deg
|
||||
0x2B, 0x2D, 0x2E, 0x2F, 0x31, 0x32, 0x33, 0x34, // [104] 292.5000 deg
|
||||
0x36, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3C, // [112] 315.0000 deg
|
||||
0x3C, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, // [120] 337.5000 deg
|
||||
};
|
||||
|
||||
const uint8_t ADAR1000Manager::VM_Q[128] = {
|
||||
0x20, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, // [ 0] 0.0000 deg
|
||||
0x2B, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x33, 0x34, // [ 8] 22.5000 deg
|
||||
0x35, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, // [ 16] 45.0000 deg
|
||||
0x3B, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D, // [ 24] 67.5000 deg
|
||||
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, // [ 32] 90.0000 deg
|
||||
0x3B, 0x3A, 0x3A, 0x39, 0x38, 0x38, 0x37, 0x36, // [ 40] 112.5000 deg
|
||||
0x35, 0x34, 0x33, 0x31, 0x30, 0x2F, 0x2E, 0x2D, // [ 48] 135.0000 deg
|
||||
0x2B, 0x2A, 0x28, 0x27, 0x26, 0x24, 0x23, 0x21, // [ 56] 157.5000 deg
|
||||
0x20, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, // [ 64] 180.0000 deg
|
||||
0x0B, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x14, // [ 72] 202.5000 deg
|
||||
0x15, 0x16, 0x17, 0x18, 0x18, 0x19, 0x1A, 0x1A, // [ 80] 225.0000 deg
|
||||
0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, // [ 88] 247.5000 deg
|
||||
0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, // [ 96] 270.0000 deg
|
||||
0x1B, 0x1A, 0x1A, 0x19, 0x18, 0x18, 0x17, 0x16, // [104] 292.5000 deg
|
||||
0x15, 0x14, 0x13, 0x11, 0x10, 0x0F, 0x0E, 0x0D, // [112] 315.0000 deg
|
||||
0x0B, 0x0A, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, // [120] 337.5000 deg
|
||||
};
|
||||
|
||||
// NOTE: a VM_GAIN[128] table previously existed here as a placeholder but was
|
||||
// never populated and never read. The ADAR1000 vector modulator has no
|
||||
// separate gain register: phase-state magnitude is encoded directly in
|
||||
// bits [4:0] of the VM_I/VM_Q bytes above. Per-channel VGA gain is a
|
||||
// distinct register (CHx_RX_GAIN at 0x10-0x13, CHx_TX_GAIN at 0x1C-0x1F)
|
||||
// written with the user-supplied byte directly by adarSetRxVgaGain() /
|
||||
// adarSetTxVgaGain(). Do not reintroduce a VM_GAIN[] array.
|
||||
|
||||
ADAR1000Manager::ADAR1000Manager() {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
devices_.push_back(std::make_unique<ADAR1000Device>(i));
|
||||
}
|
||||
}
|
||||
|
||||
ADAR1000Manager::~ADAR1000Manager() {
|
||||
// Automatic cleanup by unique_ptr
|
||||
}
|
||||
|
||||
// System Management
|
||||
bool ADAR1000Manager::powerUpSystem() {
|
||||
DIAG_SECTION("BF POWER-UP SEQUENCE");
|
||||
uint32_t t0 = HAL_GetTick();
|
||||
const uint8_t msg[] = "Starting System Power-Up Sequence...\r\n";
|
||||
HAL_UART_Transmit(&huart3, msg, sizeof(msg) - 1, 1000);
|
||||
|
||||
// Power-up sequence steps...
|
||||
DIAG("BF", "Enabling VDD_SW (3.3V)");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(2);
|
||||
|
||||
DIAG("BF", "Enabling VSS_SW (3.3V)");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(2);
|
||||
|
||||
// Initialize devices
|
||||
DIAG("BF", "Calling initializeAllDevices()");
|
||||
if (!initializeAllDevices()) {
|
||||
DIAG_ERR("BF", "initializeAllDevices() FAILED");
|
||||
const uint8_t err[] = "ERROR: ADAR1000 initialization failed!\r\n";
|
||||
HAL_UART_Transmit(&huart3, err, sizeof(err) - 1, 1000);
|
||||
return false;
|
||||
}
|
||||
DIAG("BF", "initializeAllDevices() OK");
|
||||
|
||||
// Start in RX mode
|
||||
DIAG("BF", "Setting initial mode to RX");
|
||||
switchToRXMode();
|
||||
|
||||
DIAG_ELAPSED("BF", "powerUpSystem() total", t0);
|
||||
const uint8_t success[] = "System Power-Up Sequence Completed Successfully.\r\n";
|
||||
HAL_UART_Transmit(&huart3, success, sizeof(success) - 1, 1000);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::powerDownSystem() {
|
||||
DIAG_SECTION("BF POWER-DOWN SEQUENCE");
|
||||
DIAG("BF", "Switching to RX mode before power-down");
|
||||
switchToRXMode();
|
||||
HAL_Delay(10);
|
||||
|
||||
DIAG("BF", "Disabling PA supplies");
|
||||
disablePASupplies();
|
||||
DIAG("BF", "Disabling LNA supplies");
|
||||
disableLNASupplies();
|
||||
DIAG("BF", "Disabling VSS_SW rail");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_RESET);
|
||||
DIAG("BF", "Disabling VDD_SW rail");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_RESET);
|
||||
|
||||
DIAG("BF", "powerDownSystem() complete");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mode Switching
|
||||
void ADAR1000Manager::switchToTXMode() {
|
||||
DIAG_SECTION("BF SWITCH TO TX MODE");
|
||||
DIAG("BF", "Step 1: LNA bias OFF");
|
||||
setLNABias(false);
|
||||
delayUs(10);
|
||||
DIAG("BF", "Step 2: Enable PA supplies");
|
||||
enablePASupplies();
|
||||
delayUs(100);
|
||||
DIAG("BF", "Step 3: PA bias ON");
|
||||
setPABias(true);
|
||||
delayUs(50);
|
||||
DIAG("BF", "Step 4: ADTR1107 -> TX");
|
||||
setADTR1107Control(true);
|
||||
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x0F, BROADCAST_OFF);
|
||||
adarSetTxBias(dev, BROADCAST_OFF);
|
||||
devices_[dev]->current_mode = BeamDirection::TX;
|
||||
DIAG("BF", " dev[%u] TX enables=0x0F, TX bias set", dev);
|
||||
}
|
||||
current_mode_ = BeamDirection::TX;
|
||||
DIAG("BF", "switchToTXMode() complete");
|
||||
}
|
||||
|
||||
void ADAR1000Manager::switchToRXMode() {
|
||||
DIAG_SECTION("BF SWITCH TO RX MODE");
|
||||
DIAG("BF", "Step 1: PA bias OFF");
|
||||
setPABias(false);
|
||||
delayUs(50);
|
||||
DIAG("BF", "Step 2: Disable PA supplies");
|
||||
disablePASupplies();
|
||||
delayUs(10);
|
||||
DIAG("BF", "Step 3: ADTR1107 -> RX");
|
||||
setADTR1107Control(false);
|
||||
DIAG("BF", "Step 4: Enable LNA supplies");
|
||||
enableLNASupplies();
|
||||
delayUs(50);
|
||||
DIAG("BF", "Step 5: LNA bias ON");
|
||||
setLNABias(true);
|
||||
delayUs(50);
|
||||
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x0F, BROADCAST_OFF);
|
||||
devices_[dev]->current_mode = BeamDirection::RX;
|
||||
DIAG("BF", " dev[%u] RX enables=0x0F", dev);
|
||||
}
|
||||
current_mode_ = BeamDirection::RX;
|
||||
DIAG("BF", "switchToRXMode() complete");
|
||||
}
|
||||
|
||||
void ADAR1000Manager::fastTXMode() {
|
||||
DIAG("BF", "fastTXMode(): ADTR1107 -> TX (no bias sequencing)");
|
||||
setADTR1107Control(true);
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x0F, BROADCAST_OFF);
|
||||
devices_[dev]->current_mode = BeamDirection::TX;
|
||||
}
|
||||
current_mode_ = BeamDirection::TX;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::fastRXMode() {
|
||||
DIAG("BF", "fastRXMode(): ADTR1107 -> RX (no bias sequencing)");
|
||||
setADTR1107Control(false);
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x0F, BROADCAST_OFF);
|
||||
devices_[dev]->current_mode = BeamDirection::RX;
|
||||
}
|
||||
current_mode_ = BeamDirection::RX;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::pulseTXMode() {
|
||||
DIAG("BF", "pulseTXMode(): TR switch only");
|
||||
setADTR1107Control(true);
|
||||
last_switch_time_us_ = HAL_GetTick() * 1000;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::pulseRXMode() {
|
||||
DIAG("BF", "pulseRXMode(): TR switch only");
|
||||
setADTR1107Control(false);
|
||||
last_switch_time_us_ = HAL_GetTick() * 1000;
|
||||
}
|
||||
|
||||
// Beam Steering
|
||||
bool ADAR1000Manager::setBeamAngle(float angle_degrees, BeamDirection direction) {
|
||||
DIAG("BF", "setBeamAngle(%.1f deg, %s)", (double)angle_degrees,
|
||||
direction == BeamDirection::TX ? "TX" : "RX");
|
||||
uint8_t phase_settings[4];
|
||||
calculatePhaseSettings(angle_degrees, phase_settings);
|
||||
DIAG("BF", " phase[0..3] = %u, %u, %u, %u",
|
||||
phase_settings[0], phase_settings[1], phase_settings[2], phase_settings[3]);
|
||||
|
||||
if (direction == BeamDirection::TX) {
|
||||
setAllDevicesTXMode();
|
||||
} else {
|
||||
setAllDevicesRXMode();
|
||||
}
|
||||
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
for (uint8_t ch = 0; ch < 4; ++ch) {
|
||||
if (direction == BeamDirection::TX) {
|
||||
adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
|
||||
adarSetTxVgaGain(dev, ch + 1, kDefaultTxVgaGain, BROADCAST_OFF);
|
||||
} else {
|
||||
adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
|
||||
adarSetRxVgaGain(dev, ch + 1, kDefaultRxVgaGain, BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::setCustomBeamPattern(const uint8_t phase_settings[4], const uint8_t gain_settings[4], BeamDirection direction) {
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
for (uint8_t ch = 0; ch < 4; ++ch) {
|
||||
if (direction == BeamDirection::TX) {
|
||||
adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
|
||||
adarSetTxVgaGain(dev, ch + 1, gain_settings[ch], BROADCAST_OFF);
|
||||
} else {
|
||||
adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
|
||||
adarSetRxVgaGain(dev, ch + 1, gain_settings[ch], BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Beam Sweeping
|
||||
void ADAR1000Manager::startBeamSweeping() {
|
||||
beam_sweeping_active_ = true;
|
||||
current_beam_index_ = 0;
|
||||
last_beam_update_time_ = HAL_GetTick();
|
||||
}
|
||||
|
||||
void ADAR1000Manager::stopBeamSweeping() {
|
||||
beam_sweeping_active_ = false;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::updateBeamPosition() {
|
||||
if (!beam_sweeping_active_) return;
|
||||
|
||||
uint32_t current_time = HAL_GetTick();
|
||||
const std::vector<BeamConfig>& sequence =
|
||||
(current_mode_ == BeamDirection::TX) ? tx_beam_sequence_ : rx_beam_sequence_;
|
||||
|
||||
if (sequence.empty()) return;
|
||||
|
||||
if (current_time - last_beam_update_time_ >= beam_dwell_time_ms_) {
|
||||
const BeamConfig& beam = sequence[current_beam_index_];
|
||||
setCustomBeamPattern(beam.phase_settings, beam.gain_settings, current_mode_);
|
||||
|
||||
current_beam_index_ = (current_beam_index_ + 1) % sequence.size();
|
||||
last_beam_update_time_ = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setBeamSequence(const std::vector<BeamConfig>& sequence, BeamDirection direction) {
|
||||
if (direction == BeamDirection::TX) {
|
||||
tx_beam_sequence_ = sequence;
|
||||
} else {
|
||||
rx_beam_sequence_ = sequence;
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::clearBeamSequence(BeamDirection direction) {
|
||||
if (direction == BeamDirection::TX) {
|
||||
tx_beam_sequence_.clear();
|
||||
} else {
|
||||
rx_beam_sequence_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Monitoring and Diagnostics
|
||||
float ADAR1000Manager::readTemperature(uint8_t deviceIndex) {
|
||||
if (deviceIndex >= devices_.size() || !devices_[deviceIndex]->initialized) {
|
||||
DIAG_WARN("BF", "readTemperature(dev[%u]) skipped: not initialized", deviceIndex);
|
||||
return -273.15f;
|
||||
}
|
||||
|
||||
uint8_t temp_raw = adarAdcRead(deviceIndex, BROADCAST_OFF);
|
||||
float temp_c = (temp_raw * 0.5f) - 50.0f;
|
||||
DIAG("BF", "readTemperature(dev[%u]): raw=0x%02X => %.1f C", deviceIndex, temp_raw, (double)temp_c);
|
||||
return temp_c;
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::verifyDeviceCommunication(uint8_t deviceIndex) {
|
||||
if (deviceIndex >= devices_.size()) {
|
||||
DIAG_ERR("BF", "verifyDeviceComm(dev[%u]): index out of range", deviceIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t test_value = 0xA5;
|
||||
adarWrite(deviceIndex, REG_SCRATCHPAD, test_value, BROADCAST_OFF);
|
||||
HAL_Delay(1);
|
||||
uint8_t readback = adarRead(deviceIndex, REG_SCRATCHPAD);
|
||||
bool pass = (readback == test_value);
|
||||
if (pass) {
|
||||
DIAG("BF", "verifyDeviceComm(dev[%u]): scratchpad 0xA5 -> 0x%02X OK", deviceIndex, readback);
|
||||
} else {
|
||||
DIAG_ERR("BF", "verifyDeviceComm(dev[%u]): scratchpad 0xA5 -> 0x%02X MISMATCH", deviceIndex, readback);
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
|
||||
uint8_t ADAR1000Manager::readRegister(uint8_t deviceIndex, uint32_t address) {
|
||||
return adarRead(deviceIndex, address);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::writeRegister(uint8_t deviceIndex, uint32_t address, uint8_t value) {
|
||||
adarWrite(deviceIndex, address, value, BROADCAST_OFF);
|
||||
}
|
||||
|
||||
// Configuration
|
||||
void ADAR1000Manager::setSwitchSettlingTime(uint32_t us) {
|
||||
switch_settling_time_us_ = us;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setFastSwitchMode(bool enable) {
|
||||
DIAG("BF", "setFastSwitchMode(%s)", enable ? "ON" : "OFF");
|
||||
fast_switch_mode_ = enable;
|
||||
if (enable) {
|
||||
switch_settling_time_us_ = 10;
|
||||
DIAG("BF", " settling time = 10 us, enabling PA+LNA supplies and bias simultaneously");
|
||||
enablePASupplies();
|
||||
enableLNASupplies();
|
||||
setPABias(true);
|
||||
setLNABias(true);
|
||||
} else {
|
||||
switch_settling_time_us_ = 50;
|
||||
DIAG("BF", " settling time = 50 us");
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setBeamDwellTime(uint32_t ms) {
|
||||
beam_dwell_time_ms_ = ms;
|
||||
}
|
||||
|
||||
// Private helper methods (implementation continues...)
|
||||
// ... include all the private method implementations from your original file
|
||||
// ============================================================================
|
||||
// PRIVATE HELPER METHODS - Add these to the end of ADAR1000_Manager.cpp
|
||||
// ============================================================================
|
||||
|
||||
bool ADAR1000Manager::initializeAllDevices() {
|
||||
DIAG_SECTION("BF INIT ALL DEVICES");
|
||||
|
||||
// Initialize each ADAR1000
|
||||
for (uint8_t i = 0; i < devices_.size(); ++i) {
|
||||
DIAG("BF", "Initializing ADAR1000 dev[%u]...", i);
|
||||
if (!initializeSingleDevice(i)) {
|
||||
DIAG_ERR("BF", "initializeSingleDevice(%u) FAILED -- aborting init", i);
|
||||
return false;
|
||||
}
|
||||
DIAG("BF", " dev[%u] init OK", i);
|
||||
}
|
||||
|
||||
DIAG("BF", "All 4 ADAR1000 devices initialized, setting TX mode");
|
||||
setAllDevicesTXMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::initializeSingleDevice(uint8_t deviceIndex) {
|
||||
if (deviceIndex >= devices_.size()) return false;
|
||||
|
||||
DIAG("BF", " dev[%u] soft reset", deviceIndex);
|
||||
adarSoftReset(deviceIndex);
|
||||
HAL_Delay(10);
|
||||
|
||||
DIAG("BF", " dev[%u] write ConfigA (SDO_ACTIVE)", deviceIndex);
|
||||
adarWriteConfigA(deviceIndex, INTERFACE_CONFIG_A_SDO_ACTIVE, BROADCAST_OFF);
|
||||
DIAG("BF", " dev[%u] set RAM bypass (bias+beam)", deviceIndex);
|
||||
adarSetRamBypass(deviceIndex, BROADCAST_OFF);
|
||||
|
||||
// Initialize ADC
|
||||
DIAG("BF", " dev[%u] enable ADC (2MHz clk)", deviceIndex);
|
||||
adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_2MHZ_CLK | ADAR1000_ADC_EN, BROADCAST_OFF);
|
||||
|
||||
// Verify communication with scratchpad test
|
||||
DIAG("BF", " dev[%u] verifying SPI communication...", deviceIndex);
|
||||
bool comms_ok = verifyDeviceCommunication(deviceIndex);
|
||||
if (!comms_ok) {
|
||||
DIAG_WARN("BF", " dev[%u] scratchpad verify FAILED but marking initialized anyway", deviceIndex);
|
||||
}
|
||||
|
||||
devices_[deviceIndex]->initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::initializeADTR1107Sequence() {
|
||||
DIAG_SECTION("ADTR1107 POWER SEQUENCE (9-step)");
|
||||
uint32_t t0 = HAL_GetTick();
|
||||
|
||||
//Powering up ADTR1107 TX mode
|
||||
const uint8_t msg[] = "Starting ADTR1107 Power Sequence...\r\n";
|
||||
HAL_UART_Transmit(&huart3, msg, sizeof(msg) - 1, 1000);
|
||||
|
||||
// Step 1: Connect all GND pins to ground (assumed in hardware)
|
||||
DIAG("BF", "Step 1: GND pins (hardware -- assumed connected)");
|
||||
|
||||
// Step 2: Set VDD_SW to 3.3V
|
||||
DIAG("BF", "Step 2: VDD_SW -> 3.3V");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(1);
|
||||
|
||||
// Step 3: Set VSS_SW to -3.3V
|
||||
DIAG("BF", "Step 3: VSS_SW -> -3.3V");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(1);
|
||||
|
||||
// Step 4: Set CTRL_SW to RX mode initially via GPIO
|
||||
DIAG("BF", "Step 4: CTRL_SW -> RX (initial safe mode)");
|
||||
setADTR1107Control(false); // RX mode
|
||||
HAL_Delay(1);
|
||||
|
||||
// Step 5: Set VGG_LNA to 0
|
||||
DIAG("BF", "Step 5: VGG_LNA bias -> OFF (0x%02X)", kLnaBiasOff);
|
||||
uint8_t lna_bias_voltage = kLnaBiasOff;
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_LNA_BIAS_ON, lna_bias_voltage, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_LNA_BIAS_OFF, kLnaBiasOff, BROADCAST_OFF);
|
||||
}
|
||||
|
||||
// Step 6: Set VDD_LNA to 0V for TX mode
|
||||
DIAG("BF", "Step 6: VDD_LNA -> 0V (disable ADTR LNA supply)");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_RESET);
|
||||
HAL_Delay(2);
|
||||
|
||||
// Step 7: Set VGG_PA to safe negative voltage (PA off for TX mode)
|
||||
/*A 0x00 value in the
|
||||
on or off bias registers, correspond to a 0 V output. A 0xFF in the
|
||||
on or off bias registers correspond to a −4.8 V output.*/
|
||||
DIAG("BF", "Step 7: VGG_PA -> safe bias 0x%02X (~ -1.75V, PA off)", kPaBiasTxSafe);
|
||||
uint8_t safe_pa_bias = kPaBiasTxSafe; // Safe negative voltage (-1.75V) to keep PA off
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
}
|
||||
HAL_Delay(10);
|
||||
|
||||
// Step 8: Set VDD_PA to 0V (PA powered up for TX mode)
|
||||
DIAG("BF", "Step 8: Enable PA supplies (VDD_PA)");
|
||||
enablePASupplies();
|
||||
HAL_Delay(50);
|
||||
|
||||
// Step 9: Adjust VGG_PA voltage between −1.75 V and −0.25 V to achieve the desired IDQ_PA=220mA
|
||||
//Set VGG_PA to safe negative voltage (PA off for TX mode)
|
||||
/*A 0x00 value in the
|
||||
on or off bias registers, correspond to a 0 V output. A 0xFF in the
|
||||
on or off bias registers correspond to a −4.8 V output.*/
|
||||
DIAG("BF", "Step 9: VGG_PA -> Idq cal bias 0x%02X (~ -0.24V, target 220mA)", kPaBiasIdqCalibration);
|
||||
uint8_t Idq_pa_bias = kPaBiasIdqCalibration; // Safe negative voltage (-0.2447V) to keep PA off
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_PA_CH1_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH2_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH3_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH4_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
|
||||
}
|
||||
HAL_Delay(10);
|
||||
|
||||
DIAG_ELAPSED("BF", "ADTR1107 power sequence", t0);
|
||||
|
||||
const uint8_t success[] = "ADTR1107 power sequence completed.\r\n";
|
||||
HAL_UART_Transmit(&huart3, success, sizeof(success) - 1, 1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::setAllDevicesTXMode() {
|
||||
DIAG("BF", "setAllDevicesTXMode(): ADTR1107 -> TX, then configure ADAR1000s");
|
||||
// Set ADTR1107 to TX mode first
|
||||
setADTR1107Mode(BeamDirection::TX);
|
||||
|
||||
// Then configure ADAR1000 for TX
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
// Disable RX first
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
|
||||
// Enable TX channels and set bias
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x0F, BROADCAST_OFF); // Enable all 4 channels
|
||||
adarSetTxBias(dev, BROADCAST_OFF);
|
||||
|
||||
devices_[dev]->current_mode = BeamDirection::TX;
|
||||
DIAG("BF", " dev[%u] TX mode set (enables=0x0F, bias applied)", dev);
|
||||
}
|
||||
current_mode_ = BeamDirection::TX;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::setAllDevicesRXMode() {
|
||||
DIAG("BF", "setAllDevicesRXMode(): ADTR1107 -> RX, then configure ADAR1000s");
|
||||
// Set ADTR1107 to RX mode first
|
||||
setADTR1107Mode(BeamDirection::RX);
|
||||
|
||||
// Then configure ADAR1000 for RX
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
// Disable TX first
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
|
||||
// Enable RX channels
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x0F, BROADCAST_OFF); // Enable all 4 channels
|
||||
|
||||
devices_[dev]->current_mode = BeamDirection::RX;
|
||||
DIAG("BF", " dev[%u] RX mode set (enables=0x0F)", dev);
|
||||
}
|
||||
current_mode_ = BeamDirection::RX;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
||||
if (direction == BeamDirection::TX) {
|
||||
DIAG_SECTION("ADTR1107 -> TX MODE");
|
||||
setADTR1107Control(true); // TX mode
|
||||
|
||||
// Step 1: Disable LNA power first
|
||||
DIAG("BF", " Disable LNA supplies");
|
||||
disableLNASupplies();
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 2: Set LNA bias to safe off value
|
||||
DIAG("BF", " LNA bias -> OFF (0x%02X)", kLnaBiasOff);
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_LNA_BIAS_ON, kLnaBiasOff, BROADCAST_OFF); // Turn off LNA bias
|
||||
}
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 3: Enable PA power
|
||||
DIAG("BF", " Enable PA supplies");
|
||||
enablePASupplies();
|
||||
HAL_Delay(10);
|
||||
|
||||
// Step 4: Set PA bias to operational value
|
||||
DIAG("BF", " PA bias -> operational (0x%02X)", kPaBiasOperational);
|
||||
uint8_t operational_pa_bias = kPaBiasOperational; // Maximum bias for full power
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_PA_CH1_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH2_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH3_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH4_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
|
||||
}
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 5: Set TR switch to TX mode
|
||||
DIAG("BF", " TR switch -> TX (TR_SOURCE=1, BIAS_EN)");
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarSetBit(dev, REG_SW_CONTROL, 2, BROADCAST_OFF); // TR_SOURCE = 1 (TX)
|
||||
adarSetBit(dev, REG_MISC_ENABLES, 5, BROADCAST_OFF); // BIAS_EN
|
||||
}
|
||||
DIAG("BF", " ADTR1107 TX mode complete");
|
||||
|
||||
} else {
|
||||
// RECEIVE MODE: Enable LNA, Disable PA
|
||||
DIAG_SECTION("ADTR1107 -> RX MODE");
|
||||
setADTR1107Control(false); // RX mode
|
||||
|
||||
// Step 1: Disable PA power first
|
||||
DIAG("BF", " Disable PA supplies");
|
||||
disablePASupplies();
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 2: Set PA bias to safe negative voltage
|
||||
DIAG("BF", " PA bias -> safe (0x%02X)", kPaBiasRxSafe);
|
||||
uint8_t safe_pa_bias = kPaBiasRxSafe;
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
|
||||
}
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 3: Enable LNA power
|
||||
DIAG("BF", " Enable LNA supplies");
|
||||
enableLNASupplies();
|
||||
HAL_Delay(10);
|
||||
|
||||
// Step 4: Set LNA bias to operational value
|
||||
DIAG("BF", " LNA bias -> operational (0x%02X)", kLnaBiasOperational);
|
||||
uint8_t operational_lna_bias = kLnaBiasOperational;
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_LNA_BIAS_ON, operational_lna_bias, BROADCAST_OFF);
|
||||
}
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 5: Set TR switch to RX mode
|
||||
DIAG("BF", " TR switch -> RX (TR_SOURCE=0, LNA_BIAS_OUT_EN)");
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarResetBit(dev, REG_SW_CONTROL, 2, BROADCAST_OFF); // TR_SOURCE = 0 (RX)
|
||||
adarSetBit(dev, REG_MISC_ENABLES, 4, BROADCAST_OFF); // LNA_BIAS_OUT_EN
|
||||
}
|
||||
DIAG("BF", " ADTR1107 RX mode complete");
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setADTR1107Control(bool tx_mode) {
|
||||
DIAG("BF", "setADTR1107Control(%s): setting TR switch on all %u devices, settling %lu us",
|
||||
tx_mode ? "TX" : "RX", (unsigned)devices_.size(), (unsigned long)switch_settling_time_us_);
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
setTRSwitchPosition(dev, tx_mode);
|
||||
}
|
||||
delayUs(switch_settling_time_us_);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setTRSwitchPosition(uint8_t deviceIndex, bool tx_mode) {
|
||||
if (tx_mode) {
|
||||
// TX mode: Set TR_SOURCE = 1
|
||||
adarSetBit(deviceIndex, REG_SW_CONTROL, 2, BROADCAST_OFF);
|
||||
} else {
|
||||
// RX mode: Set TR_SOURCE = 0
|
||||
adarResetBit(deviceIndex, REG_SW_CONTROL, 2, BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new public method
|
||||
bool ADAR1000Manager::setCustomBeamPattern16(const uint8_t phase_pattern[16], BeamDirection direction) {
|
||||
for (uint8_t dev = 0; dev < 4; ++dev) {
|
||||
for (uint8_t ch = 0; ch < 4; ++ch) {
|
||||
uint8_t phase = phase_pattern[dev * 4 + ch];
|
||||
if (direction == BeamDirection::TX) {
|
||||
adarSetTxPhase(dev, ch + 1, phase, BROADCAST_OFF);
|
||||
} else {
|
||||
adarSetRxPhase(dev, ch + 1, phase, BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::enablePASupplies() {
|
||||
DIAG("BF", "enablePASupplies(): PA1+PA2+PA3 -> ON");
|
||||
HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(EN_P_5V0_PA2_GPIO_Port, EN_P_5V0_PA2_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(EN_P_5V0_PA3_GPIO_Port, EN_P_5V0_PA3_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::disablePASupplies() {
|
||||
DIAG("BF", "disablePASupplies(): PA1+PA2+PA3 -> OFF");
|
||||
HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin, GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(EN_P_5V0_PA2_GPIO_Port, EN_P_5V0_PA2_Pin, GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(EN_P_5V0_PA3_GPIO_Port, EN_P_5V0_PA3_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::enableLNASupplies() {
|
||||
DIAG("BF", "enableLNASupplies(): ADTR 3.3V -> ON");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::disableLNASupplies() {
|
||||
DIAG("BF", "disableLNASupplies(): ADTR 3.3V -> OFF");
|
||||
HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setPABias(bool enable) {
|
||||
uint8_t pa_bias = enable ? kPaBiasOperational : kPaBiasRxSafe; // Operational vs safe bias
|
||||
DIAG("BF", "setPABias(%s): bias=0x%02X", enable ? "ON" : "OFF", pa_bias);
|
||||
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_PA_CH1_BIAS_ON, pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH2_BIAS_ON, pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH3_BIAS_ON, pa_bias, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_PA_CH4_BIAS_ON, pa_bias, BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setLNABias(bool enable) {
|
||||
uint8_t lna_bias = enable ? kLnaBiasOperational : kLnaBiasOff; // Operational vs off
|
||||
DIAG("BF", "setLNABias(%s): bias=0x%02X", enable ? "ON" : "OFF", lna_bias);
|
||||
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_LNA_BIAS_ON, lna_bias, BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::delayUs(uint32_t microseconds) {
|
||||
// Simple implementation - for F7 @ 216MHz, each loop ~7 cycles ≈ 0.032us
|
||||
volatile uint32_t cycles = microseconds * 10; // Adjust this multiplier for your clock
|
||||
while (cycles--) {
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]) {
|
||||
const float freq = 10.5e9;
|
||||
const float c = 3e8;
|
||||
const float wavelength = c / freq;
|
||||
const float element_spacing = wavelength / 2;
|
||||
|
||||
float angle_rad = angle_degrees * M_PI / 180.0;
|
||||
float phase_shift = (2 * M_PI * element_spacing * sin(angle_rad)) / wavelength;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float element_phase = i * phase_shift;
|
||||
while (element_phase < 0) element_phase += 2 * M_PI;
|
||||
while (element_phase >= 2 * M_PI) element_phase -= 2 * M_PI;
|
||||
phase_settings[i] = static_cast<uint8_t>((element_phase / (2 * M_PI)) * 128);
|
||||
}
|
||||
}
|
||||
|
||||
bool ADAR1000Manager::performSystemCalibration() {
|
||||
DIAG_SECTION("BF SYSTEM CALIBRATION");
|
||||
for (uint8_t i = 0; i < devices_.size(); ++i) {
|
||||
DIAG("BF", "Calibration: verifying dev[%u] communication...", i);
|
||||
if (!verifyDeviceCommunication(i)) {
|
||||
DIAG_ERR("BF", "Calibration FAILED at dev[%u]", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DIAG("BF", "performSystemCalibration() OK -- all devices verified");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LOW-LEVEL SPI COMMUNICATION METHODS
|
||||
// ============================================================================
|
||||
|
||||
uint32_t ADAR1000Manager::spiTransfer(uint8_t* txData, uint8_t* rxData, uint32_t size) {
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
if (rxData) {
|
||||
status = HAL_SPI_TransmitReceive(&hspi1, txData, rxData, size, 1000);
|
||||
} else {
|
||||
status = HAL_SPI_Transmit(&hspi1, txData, size, 1000);
|
||||
}
|
||||
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("BF", "SPI1 transfer FAILED: HAL status=%d, size=%lu", (int)status, (unsigned long)size);
|
||||
}
|
||||
|
||||
return (status == HAL_OK) ? size : 0;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setChipSelect(uint8_t deviceIndex, bool state) {
|
||||
if (deviceIndex >= devices_.size()) return;
|
||||
HAL_GPIO_WritePin(CHIP_SELECTS[deviceIndex].port,
|
||||
CHIP_SELECTS[deviceIndex].pin,
|
||||
state ? GPIO_PIN_RESET : GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarWrite(uint8_t deviceIndex, uint32_t mem_addr, uint8_t data, uint8_t broadcast) {
|
||||
uint8_t instruction[3];
|
||||
|
||||
if (broadcast) {
|
||||
instruction[0] = 0x08;
|
||||
} else {
|
||||
instruction[0] = ((devices_[deviceIndex]->dev_addr & 0x03) << 5);
|
||||
}
|
||||
|
||||
instruction[0] |= (0x1F00 & mem_addr) >> 8;
|
||||
instruction[1] = (0xFF & mem_addr);
|
||||
instruction[2] = data;
|
||||
|
||||
setChipSelect(deviceIndex, true);
|
||||
spiTransfer(instruction, nullptr, sizeof(instruction));
|
||||
setChipSelect(deviceIndex, false);
|
||||
}
|
||||
|
||||
uint8_t ADAR1000Manager::adarRead(uint8_t deviceIndex, uint32_t mem_addr) {
|
||||
uint8_t instruction[3] = {0};
|
||||
uint8_t rx_buffer[3] = {0};
|
||||
|
||||
// Set SDO active
|
||||
adarWrite(deviceIndex, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE, 0);
|
||||
|
||||
instruction[0] = 0x80 | ((devices_[deviceIndex]->dev_addr & 0x03) << 5);
|
||||
instruction[0] |= ((0xff00 & mem_addr) >> 8);
|
||||
instruction[1] = (0xff & mem_addr);
|
||||
instruction[2] = 0x00;
|
||||
|
||||
setChipSelect(deviceIndex, true);
|
||||
spiTransfer(instruction, rx_buffer, sizeof(instruction));
|
||||
setChipSelect(deviceIndex, false);
|
||||
|
||||
// Set SDO Inactive
|
||||
adarWrite(deviceIndex, REG_INTERFACE_CONFIG_A, 0, 0);
|
||||
|
||||
return rx_buffer[2];
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast) {
|
||||
uint8_t temp = adarRead(deviceIndex, mem_addr);
|
||||
uint8_t data = temp | (1 << bit);
|
||||
adarWrite(deviceIndex, mem_addr, data, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarResetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast) {
|
||||
uint8_t temp = adarRead(deviceIndex, mem_addr);
|
||||
uint8_t data = temp & ~(1 << bit);
|
||||
adarWrite(deviceIndex, mem_addr, data, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSoftReset(uint8_t deviceIndex) {
|
||||
DIAG("BF", "adarSoftReset(dev[%u]): addr=0x%02X", deviceIndex, devices_[deviceIndex]->dev_addr);
|
||||
uint8_t instruction[3];
|
||||
instruction[0] = ((devices_[deviceIndex]->dev_addr & 0x03) << 5);
|
||||
instruction[1] = 0x00;
|
||||
instruction[2] = 0x81;
|
||||
|
||||
setChipSelect(deviceIndex, true);
|
||||
spiTransfer(instruction, nullptr, sizeof(instruction));
|
||||
setChipSelect(deviceIndex, false);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarWriteConfigA(uint8_t deviceIndex, uint8_t flags, uint8_t broadcast) {
|
||||
adarWrite(deviceIndex, REG_INTERFACE_CONFIG_A, flags, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSetRamBypass(uint8_t deviceIndex, uint8_t broadcast) {
|
||||
uint8_t data = (MEM_CTRL_BIAS_RAM_BYPASS | MEM_CTRL_BEAM_RAM_BYPASS);
|
||||
adarWrite(deviceIndex, REG_MEM_CTL, data, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSetRxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast) {
|
||||
uint8_t i_val = VM_I[phase % 128];
|
||||
uint8_t q_val = VM_Q[phase % 128];
|
||||
|
||||
uint32_t mem_addr_i = REG_CH1_RX_PHS_I + (channel & 0x03) * 2;
|
||||
uint32_t mem_addr_q = REG_CH1_RX_PHS_Q + (channel & 0x03) * 2;
|
||||
|
||||
adarWrite(deviceIndex, mem_addr_i, i_val, broadcast);
|
||||
adarWrite(deviceIndex, mem_addr_q, q_val, broadcast);
|
||||
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x1, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSetTxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast) {
|
||||
uint8_t i_val = VM_I[phase % 128];
|
||||
uint8_t q_val = VM_Q[phase % 128];
|
||||
|
||||
uint32_t mem_addr_i = REG_CH1_TX_PHS_I + (channel & 0x03) * 2;
|
||||
uint32_t mem_addr_q = REG_CH1_TX_PHS_Q + (channel & 0x03) * 2;
|
||||
|
||||
adarWrite(deviceIndex, mem_addr_i, i_val, broadcast);
|
||||
adarWrite(deviceIndex, mem_addr_q, q_val, broadcast);
|
||||
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x1, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSetRxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast) {
|
||||
uint32_t mem_addr = REG_CH1_RX_GAIN + (channel & 0x03);
|
||||
adarWrite(deviceIndex, mem_addr, gain, broadcast);
|
||||
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x1, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast) {
|
||||
uint32_t mem_addr = REG_CH1_TX_GAIN + (channel & 0x03);
|
||||
adarWrite(deviceIndex, mem_addr, gain, broadcast);
|
||||
adarWrite(deviceIndex, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast) {
|
||||
adarWrite(deviceIndex, REG_BIAS_CURRENT_TX, kTxBiasCurrent, broadcast);
|
||||
adarWrite(deviceIndex, REG_BIAS_CURRENT_TX_DRV, kTxDriverBiasCurrent, broadcast);
|
||||
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x2, broadcast);
|
||||
}
|
||||
|
||||
uint8_t ADAR1000Manager::adarAdcRead(uint8_t deviceIndex, uint8_t broadcast) {
|
||||
adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast);
|
||||
|
||||
// Wait for conversion -- WARNING: no timeout, can hang if ADC never completes
|
||||
uint32_t t0 = HAL_GetTick();
|
||||
uint32_t polls = 0;
|
||||
while (!(adarRead(deviceIndex, REG_ADC_CONTROL) & 0x01)) {
|
||||
polls++;
|
||||
if (HAL_GetTick() - t0 > 100) {
|
||||
DIAG_ERR("BF", "adarAdcRead(dev[%u]): ADC conversion TIMEOUT after %lu ms, %lu polls",
|
||||
deviceIndex, (unsigned long)(HAL_GetTick() - t0), (unsigned long)polls);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
DIAG("BF", "adarAdcRead(dev[%u]): conversion done in %lu ms (%lu polls)",
|
||||
deviceIndex, (unsigned long)(HAL_GetTick() - t0), (unsigned long)polls);
|
||||
|
||||
return adarRead(deviceIndex, REG_ADC_OUT);
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
// ADAR1000_Manager.h
|
||||
#ifndef ADAR1000_MANAGER_H
|
||||
#define ADAR1000_MANAGER_H
|
||||
|
||||
#include "stm32f7xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
class ADAR1000Manager {
|
||||
public:
|
||||
enum class BeamDirection {
|
||||
TX = 0,
|
||||
RX = 1
|
||||
};
|
||||
|
||||
struct BeamConfig {
|
||||
float angle_degrees;
|
||||
uint8_t phase_settings[4];
|
||||
uint8_t gain_settings[4];
|
||||
uint32_t dwell_time_ms;
|
||||
|
||||
BeamConfig() : angle_degrees(0), dwell_time_ms(100) {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
phase_settings[i] = 0;
|
||||
gain_settings[i] = 0x7F;
|
||||
}
|
||||
}
|
||||
|
||||
BeamConfig(float angle, uint32_t dwell = 100) : angle_degrees(angle), dwell_time_ms(dwell) {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
phase_settings[i] = 0;
|
||||
gain_settings[i] = 0x7F;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ADAR1000Manager();
|
||||
~ADAR1000Manager();
|
||||
|
||||
// System Management
|
||||
bool powerUpSystem();
|
||||
bool powerDownSystem();
|
||||
bool initializeAllDevices();
|
||||
bool performSystemCalibration();
|
||||
|
||||
// Mode Switching
|
||||
void switchToTXMode();
|
||||
void switchToRXMode();
|
||||
void fastTXMode();
|
||||
void fastRXMode();
|
||||
void pulseTXMode();
|
||||
void pulseRXMode();
|
||||
|
||||
// Beam Steering
|
||||
bool setBeamAngle(float angle_degrees, BeamDirection direction);
|
||||
bool setCustomBeamPattern(const uint8_t phase_settings[16], const uint8_t gain_settings[4], BeamDirection direction);
|
||||
bool setCustomBeamPattern16(const uint8_t phase_pattern[16], BeamDirection direction);
|
||||
|
||||
// Beam Sweeping
|
||||
void startBeamSweeping();
|
||||
void stopBeamSweeping();
|
||||
void updateBeamPosition();
|
||||
void setBeamSequence(const std::vector<BeamConfig>& sequence, BeamDirection direction);
|
||||
void clearBeamSequence(BeamDirection direction);
|
||||
|
||||
// Device Control
|
||||
bool setAllDevicesTXMode();
|
||||
bool setAllDevicesRXMode();
|
||||
void setADTR1107Mode(BeamDirection direction);
|
||||
void setADTR1107Control(bool tx_mode);
|
||||
|
||||
// Monitoring and Diagnostics
|
||||
float readTemperature(uint8_t deviceIndex);
|
||||
bool verifyDeviceCommunication(uint8_t deviceIndex);
|
||||
uint8_t readRegister(uint8_t deviceIndex, uint32_t address);
|
||||
void writeRegister(uint8_t deviceIndex, uint32_t address, uint8_t value);
|
||||
|
||||
// Configuration
|
||||
void setSwitchSettlingTime(uint32_t us);
|
||||
void setFastSwitchMode(bool enable);
|
||||
void setBeamDwellTime(uint32_t ms);
|
||||
|
||||
// Getters
|
||||
bool isBeamSweepingActive() const { return beam_sweeping_active_; }
|
||||
uint8_t getCurrentBeamIndex() const { return current_beam_index_; }
|
||||
BeamDirection getCurrentMode() const { return current_mode_; }
|
||||
uint32_t getLastSwitchTime() const { return last_switch_time_us_; }
|
||||
|
||||
struct ADAR1000Device {
|
||||
uint8_t dev_addr;
|
||||
bool initialized;
|
||||
BeamDirection current_mode;
|
||||
float temperature;
|
||||
|
||||
ADAR1000Device(uint8_t addr)
|
||||
: dev_addr(addr), initialized(false), current_mode(BeamDirection::RX), temperature(25.0f) {
|
||||
}
|
||||
};
|
||||
|
||||
// Configuration
|
||||
bool fast_switch_mode_ = false;
|
||||
uint32_t switch_settling_time_us_ = 50;
|
||||
uint32_t beam_dwell_time_ms_ = 100;
|
||||
uint32_t last_switch_time_us_ = 0;
|
||||
|
||||
// Device Management
|
||||
std::vector<std::unique_ptr<ADAR1000Device>> devices_;
|
||||
BeamDirection current_mode_ = BeamDirection::RX;
|
||||
|
||||
// Beam Sweeping
|
||||
std::vector<BeamConfig> tx_beam_sequence_;
|
||||
std::vector<BeamConfig> rx_beam_sequence_;
|
||||
uint8_t current_beam_index_ = 0;
|
||||
bool beam_sweeping_active_ = false;
|
||||
uint32_t last_beam_update_time_ = 0;
|
||||
|
||||
// Vector Modulator lookup tables (see ADAR1000_Manager.cpp for provenance).
|
||||
// Indexed as VM_*[phase % 128] on a uniform 2.8125 deg grid.
|
||||
// No VM_GAIN[] table exists: VM magnitude is bits [4:0] of the I/Q bytes
|
||||
// themselves; per-channel VGA gain uses a separate register.
|
||||
static const uint8_t VM_I[128];
|
||||
static const uint8_t VM_Q[128];
|
||||
|
||||
// Named defaults for the ADTR1107 and ADAR1000 power sequence.
|
||||
static constexpr uint8_t kDefaultTxVgaGain = 0x7F;
|
||||
static constexpr uint8_t kDefaultRxVgaGain = 30;
|
||||
static constexpr uint8_t kLnaBiasOff = 0x00;
|
||||
static constexpr uint8_t kLnaBiasOperational = 0x30;
|
||||
static constexpr uint8_t kPaBiasTxSafe = 0x5D;
|
||||
static constexpr uint8_t kPaBiasIdqCalibration = 0x0D;
|
||||
static constexpr uint8_t kPaBiasOperational = 0x7F;
|
||||
static constexpr uint8_t kPaBiasRxSafe = 0x20;
|
||||
static constexpr uint8_t kTxBiasCurrent = 0x2D;
|
||||
static constexpr uint8_t kTxDriverBiasCurrent = 0x06;
|
||||
|
||||
// Private Methods
|
||||
bool initializeSingleDevice(uint8_t deviceIndex);
|
||||
bool initializeADTR1107Sequence();
|
||||
void calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]);
|
||||
void delayUs(uint32_t microseconds);
|
||||
|
||||
// Power Management
|
||||
void enablePASupplies();
|
||||
void disablePASupplies();
|
||||
void enableLNASupplies();
|
||||
void disableLNASupplies();
|
||||
void setPABias(bool enable);
|
||||
void setLNABias(bool enable);
|
||||
|
||||
// SPI Communication
|
||||
void setChipSelect(uint8_t deviceIndex, bool state);
|
||||
uint32_t spiTransfer(uint8_t* txData, uint8_t* rxData, uint32_t size);
|
||||
void adarWrite(uint8_t deviceIndex, uint32_t mem_addr, uint8_t data, uint8_t broadcast);
|
||||
uint8_t adarRead(uint8_t deviceIndex, uint32_t mem_addr);
|
||||
void adarSetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
|
||||
void adarResetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
|
||||
void adarSoftReset(uint8_t deviceIndex);
|
||||
void adarWriteConfigA(uint8_t deviceIndex, uint8_t flags, uint8_t broadcast);
|
||||
void adarSetRamBypass(uint8_t deviceIndex, uint8_t broadcast);
|
||||
|
||||
// Channel Configuration
|
||||
void adarSetRxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast);
|
||||
void adarSetTxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast);
|
||||
void adarSetRxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast);
|
||||
void adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast);
|
||||
void adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast);
|
||||
uint8_t adarAdcRead(uint8_t deviceIndex, uint8_t broadcast);
|
||||
void setTRSwitchPosition(uint8_t deviceIndex, bool tx_mode);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
// Register Definitions
|
||||
#define BROADCAST_OFF 0
|
||||
#define BROADCAST_ON 1
|
||||
|
||||
#define REG_INTERFACE_CONFIG_A 0x000
|
||||
#define REG_SCRATCHPAD 0x00A
|
||||
#define REG_CH1_RX_GAIN 0x010
|
||||
#define REG_CH2_RX_GAIN 0x011
|
||||
#define REG_CH3_RX_GAIN 0x012
|
||||
#define REG_CH4_RX_GAIN 0x013
|
||||
#define REG_CH1_RX_PHS_I 0x014
|
||||
#define REG_CH1_RX_PHS_Q 0x015
|
||||
#define REG_CH2_RX_PHS_I 0x016
|
||||
#define REG_CH2_RX_PHS_Q 0x017
|
||||
#define REG_CH3_RX_PHS_I 0x018
|
||||
#define REG_CH3_RX_PHS_Q 0x019
|
||||
#define REG_CH4_RX_PHS_I 0x01A
|
||||
#define REG_CH4_RX_PHS_Q 0x01B
|
||||
#define REG_CH1_TX_GAIN 0x01C
|
||||
#define REG_CH2_TX_GAIN 0x01D
|
||||
#define REG_CH3_TX_GAIN 0x01E
|
||||
#define REG_CH4_TX_GAIN 0x01F
|
||||
#define REG_CH1_TX_PHS_I 0x020
|
||||
#define REG_CH1_TX_PHS_Q 0x021
|
||||
#define REG_CH2_TX_PHS_I 0x022
|
||||
#define REG_CH2_TX_PHS_Q 0x023
|
||||
#define REG_CH3_TX_PHS_I 0x024
|
||||
#define REG_CH3_TX_PHS_Q 0x025
|
||||
#define REG_CH4_TX_PHS_I 0x026
|
||||
#define REG_CH4_TX_PHS_Q 0x027
|
||||
#define REG_LOAD_WORKING 0x028
|
||||
#define REG_PA_CH1_BIAS_ON 0x029
|
||||
#define REG_PA_CH2_BIAS_ON 0x02A
|
||||
#define REG_PA_CH3_BIAS_ON 0x02B
|
||||
#define REG_PA_CH4_BIAS_ON 0x02C
|
||||
#define REG_LNA_BIAS_ON 0x02D
|
||||
#define REG_RX_ENABLES 0x02E
|
||||
#define REG_TX_ENABLES 0x02F
|
||||
#define REG_MISC_ENABLES 0x030
|
||||
#define REG_SW_CONTROL 0x031
|
||||
#define REG_ADC_CONTROL 0x032
|
||||
#define REG_ADC_OUT 0x033
|
||||
#define REG_BIAS_CURRENT_TX 0x036
|
||||
#define REG_BIAS_CURRENT_TX_DRV 0x037
|
||||
#define REG_MEM_CTL 0x038
|
||||
#define REG_PA_CH1_BIAS_OFF 0x046
|
||||
#define REG_PA_CH2_BIAS_OFF 0x047
|
||||
#define REG_PA_CH3_BIAS_OFF 0x048
|
||||
#define REG_PA_CH4_BIAS_OFF 0x049
|
||||
#define REG_LNA_BIAS_OFF 0x04A
|
||||
|
||||
// Register Constants
|
||||
#define INTERFACE_CONFIG_A_SDO_ACTIVE ((1 << 4) | (1 << 3))
|
||||
#define ADAR1000_ADC_2MHZ_CLK 0x00
|
||||
#define ADAR1000_ADC_EN 0x60
|
||||
#define ADAR1000_ADC_ST_CONV 0x70
|
||||
#define MEM_CTRL_BIAS_RAM_BYPASS (1 << 5)
|
||||
#define MEM_CTRL_BEAM_RAM_BYPASS (1 << 6)
|
||||
#define LD_WRK_REGS_LDTX_OVERRIDE (1 << 1)
|
||||
|
||||
#endif // ADAR1000_MANAGER_H
|
||||
86
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADS7830.H
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef __ADS7830_H
|
||||
#define __ADS7830_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stm32f7xx_hal.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* I2C Address Definitions */
|
||||
#define ADS7830_DEFAULT_ADDRESS (0x48) // 1001 000 (ADDR = GND)
|
||||
#define ADS7830_VDD_ADDRESS (0x49) // 1001 001 (ADDR = VDD)
|
||||
#define ADS7830_SDA_ADDRESS (0x4A) // 1001 010 (ADDR = SDA)
|
||||
#define ADS7830_SCL_ADDRESS (0x4B) // 1001 011 (ADDR = SCL)
|
||||
|
||||
/* Conversion Delay (in ms) */
|
||||
#define ADS7830_CONVERSIONDELAY (1)
|
||||
|
||||
/* Command Byte Register Masks */
|
||||
#define ADS7830_REG_COMMAND_SD_MASK (0x80) // Single-Ended/Differential Inputs
|
||||
#define ADS7830_REG_COMMAND_SD_DIFF (0x00) // Bit = 0, Differential Inputs
|
||||
#define ADS7830_REG_COMMAND_SD_SINGLE (0x80) // Bit = 1, Single-Ended Inputs
|
||||
|
||||
#define ADS7830_REG_COMMAND_CH_MASK (0x70) // Input multiplexer Configuration
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_0_1 (0x00) // Differential P = CH0, N = CH1
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_2_3 (0x10) // Differential P = CH2, N = CH3
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_4_5 (0x20) // Differential P = CH4, N = CH5
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_6_7 (0x30) // Differential P = CH6, N = CH7
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_1_0 (0x40) // Differential P = CH1, N = CH0
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_3_2 (0x50) // Differential P = CH3, N = CH2
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_5_4 (0x60) // Differential P = CH5, N = CH4
|
||||
#define ADS7830_REG_COMMAND_CH_DIFF_7_6 (0x70) // Differential P = CH7, N = CH6
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_0 (0x00) // Single-ended P = CH0, N = COM
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_1 (0x10) // Single-ended P = CH1, N = COM
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_2 (0x20) // Single-ended P = CH2, N = COM
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_3 (0x30) // Single-ended P = CH3, N = COM
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_4 (0x40) // Single-ended P = CH4, N = COM
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_5 (0x50) // Single-ended P = CH5, N = COM
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_6 (0x60) // Single-ended P = CH6, N = COM
|
||||
#define ADS7830_REG_COMMAND_CH_SINGLE_7 (0x70) // Single-ended P = CH7, N = COM
|
||||
|
||||
#define ADS7830_REG_COMMAND_PD_MASK (0x0C) // Power-Down Selection
|
||||
#define ADS7830_REG_COMMAND_PD_PDADCONV (0x00) // Power Down Between A/D Converter Conversions
|
||||
#define ADS7830_REG_COMMAND_PD_IROFF_ADON (0x04) // Internal Reference OFF and A/D Converter ON
|
||||
#define ADS7830_REG_COMMAND_PD_IRON_ADOFF (0x08) // Internal Reference ON and A/D Converter OFF
|
||||
#define ADS7830_REG_COMMAND_PD_IRON_ADON (0x0C) // Internal Reference ON and A/D Converter ON
|
||||
|
||||
/* Mode Enumerations */
|
||||
typedef enum {
|
||||
ADS7830_SDMODE_DIFF = ADS7830_REG_COMMAND_SD_DIFF,
|
||||
ADS7830_SDMODE_SINGLE = ADS7830_REG_COMMAND_SD_SINGLE
|
||||
} ADS7830_SDMode_t;
|
||||
|
||||
typedef enum {
|
||||
ADS7830_PDADCONV = ADS7830_REG_COMMAND_PD_PDADCONV,
|
||||
ADS7830_PDIROFF_ADON = ADS7830_REG_COMMAND_PD_IROFF_ADON,
|
||||
ADS7830_PDIRON_ADOFF = ADS7830_REG_COMMAND_PD_IRON_ADOFF,
|
||||
ADS7830_PDIRON_ADON = ADS7830_REG_COMMAND_PD_IRON_ADON
|
||||
} ADS7830_PDMode_t;
|
||||
|
||||
/* ADC Handle Structure */
|
||||
typedef struct {
|
||||
I2C_HandleTypeDef *hi2c;
|
||||
uint8_t i2c_addr;
|
||||
ADS7830_SDMode_t sdmode;
|
||||
ADS7830_PDMode_t pdmode;
|
||||
uint8_t conversion_delay;
|
||||
uint8_t last_conversion_result;
|
||||
} ADS7830_HandleTypeDef;
|
||||
|
||||
/* Function Prototypes */
|
||||
bool ADS7830_Init(ADS7830_HandleTypeDef *hadc, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
|
||||
ADS7830_SDMode_t sdmode, ADS7830_PDMode_t pdmode);
|
||||
bool ADS7830_SetSDMode(ADS7830_HandleTypeDef *hadc, ADS7830_SDMode_t sdmode);
|
||||
bool ADS7830_SetPDMode(ADS7830_HandleTypeDef *hadc, ADS7830_PDMode_t pdmode);
|
||||
uint8_t ADS7830_Measure_SingleEnded(ADS7830_HandleTypeDef *hadc, uint8_t channel);
|
||||
int8_t ADS7830_Measure_Differential(ADS7830_HandleTypeDef *hadc, uint8_t channel);
|
||||
uint8_t ADS7830_GetLastConversionResult(ADS7830_HandleTypeDef *hadc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ADS7830_H */
|
||||
223
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ADS7830.c
Normal file
@@ -0,0 +1,223 @@
|
||||
#include "ADS7830.h"
|
||||
#include "diag_log.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize the ADS7830 ADC
|
||||
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
|
||||
* @param hi2c: pointer to an I2C_HandleTypeDef structure
|
||||
* @param i2c_addr: I2C address of the ADC
|
||||
* @param sdmode: Single-ended or differential mode
|
||||
* @param pdmode: Power-down mode
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool ADS7830_Init(ADS7830_HandleTypeDef *hadc, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
|
||||
ADS7830_SDMode_t sdmode, ADS7830_PDMode_t pdmode) {
|
||||
|
||||
DIAG("PA", "ADS7830_Init: addr=0x%02X (shifted=0x%02X), sdmode=%u, pdmode=%u",
|
||||
i2c_addr, i2c_addr << 1, (unsigned)sdmode, (unsigned)pdmode);
|
||||
|
||||
if (hadc == NULL || hi2c == NULL) {
|
||||
DIAG_ERR("PA", "ADS7830_Init: NULL handle(s)");
|
||||
return false;
|
||||
}
|
||||
|
||||
hadc->hi2c = hi2c;
|
||||
hadc->i2c_addr = i2c_addr << 1; // HAL requires 7-bit address shifted left
|
||||
hadc->sdmode = sdmode;
|
||||
hadc->pdmode = pdmode;
|
||||
hadc->conversion_delay = ADS7830_CONVERSIONDELAY;
|
||||
hadc->last_conversion_result = 0;
|
||||
|
||||
/* Test communication by reading from a channel */
|
||||
uint8_t test_read = ADS7830_Measure_SingleEnded(hadc, 0);
|
||||
bool ok = (test_read != 0xFF);
|
||||
DIAG("PA", "ADS7830_Init: test read ch0 = 0x%02X => %s", test_read, ok ? "OK" : "FAILED (0xFF)");
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Single-Ended/Differential mode
|
||||
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
|
||||
* @param sdmode: Single-ended or differential mode
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool ADS7830_SetSDMode(ADS7830_HandleTypeDef *hadc, ADS7830_SDMode_t sdmode) {
|
||||
if (hadc == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hadc->sdmode = sdmode;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Power-Down mode
|
||||
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
|
||||
* @param pdmode: Power-down mode
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool ADS7830_SetPDMode(ADS7830_HandleTypeDef *hadc, ADS7830_PDMode_t pdmode) {
|
||||
if (hadc == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hadc->pdmode = pdmode;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Measure single-ended voltage on specified channel
|
||||
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
|
||||
* @param channel: ADC channel (0-7)
|
||||
* @retval uint8_t: 8-bit conversion result (0-255), 0xFF on error
|
||||
*/
|
||||
uint8_t ADS7830_Measure_SingleEnded(ADS7830_HandleTypeDef *hadc, uint8_t channel) {
|
||||
if (hadc == NULL || channel > 7) {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
uint8_t config = 0;
|
||||
|
||||
// Set Single-Ended/Differential Inputs
|
||||
config |= hadc->sdmode;
|
||||
|
||||
// Set Power-Down Selection
|
||||
config |= hadc->pdmode;
|
||||
|
||||
// Set single-ended input channel
|
||||
switch (channel) {
|
||||
case (0):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_0;
|
||||
break;
|
||||
case (1):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_1;
|
||||
break;
|
||||
case (2):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_2;
|
||||
break;
|
||||
case (3):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_3;
|
||||
break;
|
||||
case (4):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_4;
|
||||
break;
|
||||
case (5):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_5;
|
||||
break;
|
||||
case (6):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_6;
|
||||
break;
|
||||
case (7):
|
||||
config |= ADS7830_REG_COMMAND_CH_SINGLE_7;
|
||||
break;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
// Write config register to the ADC
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hadc->hi2c, hadc->i2c_addr, &config, 1, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "ADS7830 I2C transmit FAILED: addr=0x%02X ch=%u HAL=%d", hadc->i2c_addr, channel, (int)status);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
// Wait for the conversion to complete
|
||||
HAL_Delay(hadc->conversion_delay);
|
||||
|
||||
// Read the conversion results
|
||||
uint8_t result = 0;
|
||||
status = HAL_I2C_Master_Receive(hadc->hi2c, hadc->i2c_addr, &result, 1, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "ADS7830 I2C receive FAILED: addr=0x%02X ch=%u HAL=%d", hadc->i2c_addr, channel, (int)status);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
hadc->last_conversion_result = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Measure differential voltage between specified channel pairs
|
||||
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
|
||||
* @param channel: Channel pair (01, 10, 23, 32, 45, 54, 67, 76)
|
||||
* @retval int8_t: 8-bit signed conversion result (-128 to 127), 0x80 on error
|
||||
*/
|
||||
int8_t ADS7830_Measure_Differential(ADS7830_HandleTypeDef *hadc, uint8_t channel) {
|
||||
if (hadc == NULL) {
|
||||
return (int8_t)0x80;
|
||||
}
|
||||
|
||||
uint8_t config = 0;
|
||||
|
||||
// Set Single-Ended/Differential Inputs
|
||||
config |= hadc->sdmode;
|
||||
|
||||
// Set Power-Down Selection
|
||||
config |= hadc->pdmode;
|
||||
|
||||
// Set Differential input channel
|
||||
switch (channel) {
|
||||
case (01):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_0_1; // CH0 = P, CH1 = N
|
||||
break;
|
||||
case (10):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_1_0; // CH1 = P, CH0 = N
|
||||
break;
|
||||
case (23):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_2_3; // CH2 = P, CH3 = N
|
||||
break;
|
||||
case (32):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_3_2; // CH3 = P, CH2 = N
|
||||
break;
|
||||
case (45):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_4_5; // CH4 = P, CH5 = N
|
||||
break;
|
||||
case (54):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_5_4; // CH5 = P, CH4 = N
|
||||
break;
|
||||
case (67):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_6_7; // CH6 = P, CH7 = N
|
||||
break;
|
||||
case (76):
|
||||
config |= ADS7830_REG_COMMAND_CH_DIFF_7_6; // CH7 = P, CH6 = N
|
||||
break;
|
||||
default:
|
||||
return (int8_t)0x80;
|
||||
}
|
||||
|
||||
// Write config register to the ADC
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hadc->hi2c, hadc->i2c_addr, &config, 1, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "ADS7830 diff I2C transmit FAILED: addr=0x%02X ch=%u HAL=%d", hadc->i2c_addr, channel, (int)status);
|
||||
return (int8_t)0x80;
|
||||
}
|
||||
|
||||
// Wait for the conversion to complete
|
||||
HAL_Delay(hadc->conversion_delay);
|
||||
|
||||
// Read the conversion results
|
||||
uint8_t raw_adc = 0;
|
||||
status = HAL_I2C_Master_Receive(hadc->hi2c, hadc->i2c_addr, &raw_adc, 1, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "ADS7830 diff I2C receive FAILED: addr=0x%02X ch=%u HAL=%d", hadc->i2c_addr, channel, (int)status);
|
||||
return (int8_t)0x80;
|
||||
}
|
||||
|
||||
// Convert to signed 8-bit value
|
||||
int8_t result = (int8_t)raw_adc;
|
||||
hadc->last_conversion_result = raw_adc;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the last conversion result
|
||||
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
|
||||
* @retval uint8_t: Last conversion result
|
||||
*/
|
||||
uint8_t ADS7830_GetLastConversionResult(ADS7830_HandleTypeDef *hadc) {
|
||||
if (hadc == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return hadc->last_conversion_result;
|
||||
}
|
||||
462
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/BMP180.cpp
Normal file
@@ -0,0 +1,462 @@
|
||||
/***************************************************************************************************/
|
||||
/*
|
||||
This is an Arduino basic library for Bosch BMP180 & BMP085 barometric pressure &
|
||||
temperature sensor
|
||||
|
||||
Power supply voltage: 1.8v - 3.6v
|
||||
Range: 30,000Pa..110,000Pa at -40°C..+85°C
|
||||
Typ. resolution: 1Pa / 0.1°C
|
||||
Typ. accuracy: ±100Pa* / ±1.0°C* at 0°C..+65°C
|
||||
Typ. relative accuracy: ±12Pa / xx°C
|
||||
Duty cycle: 10% active & 90% inactive, to prevent self heating
|
||||
|
||||
*sensor is sensitive to direct light, which can affect
|
||||
the accuracy of the measurement
|
||||
|
||||
written by : enjoyneering79
|
||||
sourse code: https://github.com/enjoyneering/
|
||||
|
||||
|
||||
This chip uses I2C bus to communicate, specials pins are required to interface
|
||||
Board: SDA SCL Level
|
||||
Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v
|
||||
Mega2560................................. 20 21 5v
|
||||
Due, SAM3X8E............................. 20 21 3.3v
|
||||
Leonardo, Micro, ATmega32U4.............. 2 3 5v
|
||||
Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v
|
||||
Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v
|
||||
ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v
|
||||
NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v
|
||||
ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v
|
||||
|
||||
NOTE:
|
||||
- EOC pin is not used, shows the end of conversion
|
||||
- XCLR pin is not used, reset pin
|
||||
|
||||
Frameworks & Libraries:
|
||||
ATtiny Core - https://github.com/SpenceKonde/ATTinyCore
|
||||
ESP32 Core - https://github.com/espressif/arduino-esp32
|
||||
ESP8266 Core - https://github.com/esp8266/Arduino
|
||||
STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32
|
||||
|
||||
GNU GPL license, all text above must be included in any redistribution,
|
||||
see link for details - https://www.gnu.org/licenses/licenses.html
|
||||
*/
|
||||
/***************************************************************************************************/
|
||||
|
||||
#include "BMP180.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Constructor
|
||||
|
||||
NOTE:
|
||||
- BMP180_ULTRALOWPOWER, pressure oversampled 1 time & consumption 3μA
|
||||
- BMP180_STANDARD, pressure oversampled 2 times & consumption 5μA
|
||||
- BMP180_HIGHRES, pressure oversampled 4 times & consumption 7μA
|
||||
- BMP180_ULTRAHIGHRES, pressure oversampled 8 times & consumption 12μA
|
||||
*/
|
||||
/**************************************************************************/
|
||||
BMP180::BMP180(BMP180_RESOLUTION res_mode)
|
||||
{
|
||||
_resolution = res_mode;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
getPressure()
|
||||
|
||||
Calculates compensated pressure, in Pa
|
||||
|
||||
NOTE:
|
||||
- resolutin 1Pa with accuracy ±150Pa at range 30,000Pa..110,000Pa
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int32_t BMP180::getPressure(void)
|
||||
{
|
||||
int32_t UT = 0;
|
||||
int32_t UP = 0;
|
||||
int32_t B3 = 0;
|
||||
int32_t B5 = 0;
|
||||
int32_t B6 = 0;
|
||||
int32_t X1 = 0;
|
||||
int32_t X2 = 0;
|
||||
int32_t X3 = 0;
|
||||
int32_t pressure = 0;
|
||||
uint32_t B4 = 0;
|
||||
uint32_t B7 = 0;
|
||||
|
||||
UT = readRawTemperature(); //read uncompensated temperature, 16-bit
|
||||
if (UT == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
|
||||
|
||||
UP = readRawPressure(); //read uncompensated pressure, 19-bit
|
||||
if (UP == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
|
||||
|
||||
B5 = computeB5(UT);
|
||||
|
||||
/* pressure calculation */
|
||||
B6 = B5 - 4000;
|
||||
X1 = ((int32_t)_calCoeff.bmpB2 * ((B6 * B6) >> 12)) >> 11;
|
||||
X2 = ((int32_t)_calCoeff.bmpAC2 * B6) >> 11;
|
||||
X3 = X1 + X2;
|
||||
B3 = ((((int32_t)_calCoeff.bmpAC1 * 4 + X3) << _resolution) + 2) / 4;
|
||||
|
||||
X1 = ((int32_t)_calCoeff.bmpAC3 * B6) >> 13;
|
||||
X2 = ((int32_t)_calCoeff.bmpB1 * ((B6 * B6) >> 12)) >> 16;
|
||||
X3 = ((X1 + X2) + 2) >> 2;
|
||||
B4 = ((uint32_t)_calCoeff.bmpAC4 * (X3 + 32768L)) >> 15;
|
||||
B7 = (UP - B3) * (50000UL >> _resolution);
|
||||
|
||||
if (B4 == 0) return BMP180_ERROR; //safety check, avoiding division by zero
|
||||
|
||||
if (B7 < 0x80000000) pressure = (B7 * 2) / B4;
|
||||
else pressure = (B7 / B4) * 2;
|
||||
|
||||
X1 = pow((pressure >> 8), 2);
|
||||
X1 = (X1 * 3038L) >> 16;
|
||||
X2 = (-7357L * pressure) >> 16;
|
||||
|
||||
return pressure = pressure + ((X1 + X2 + 3791L) >> 4);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
getTemperature()
|
||||
|
||||
Calculates compensated temperature, in °C
|
||||
|
||||
NOTE:
|
||||
- resolution 0.1°C with accuracy ±1.0°C at range 0°C..+65°C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
float BMP180::getTemperature(void)
|
||||
{
|
||||
int16_t rawTemperature = readRawTemperature();
|
||||
|
||||
if (rawTemperature == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
|
||||
return (float)((computeB5(rawTemperature) + 8) >> 4) / 10;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
getSeaLevelPressure()
|
||||
|
||||
Converts current pressure to sea level pressure at specific true
|
||||
altitude, in Pa
|
||||
|
||||
NOTE:
|
||||
- true altitude is the actual elevation above sea level, to find out
|
||||
your current true altitude do search with google earth or gps
|
||||
- see level pressure is commonly used in weather reports & forecasts
|
||||
to compensate current true altitude
|
||||
- for example, we know that a sunny day happens if the current sea
|
||||
level pressure is 250Pa above the average sea level pressure of
|
||||
101325 Pa, so by converting the current pressure to sea level &
|
||||
comparing it with an average sea level pressure we can instantly
|
||||
predict the weather conditions
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int32_t BMP180::getSeaLevelPressure(int16_t trueAltitude)
|
||||
{
|
||||
int32_t pressure = getPressure();
|
||||
|
||||
if (pressure == BMP180_ERROR) return BMP180_ERROR;
|
||||
return (pressure / pow(1.0 - (float)trueAltitude / 44330, 5.255));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
softReset()
|
||||
|
||||
Soft reset
|
||||
|
||||
NOTE:
|
||||
- performs the same sequence as power on reset
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void BMP180::softReset(void)
|
||||
{
|
||||
write8(BMP180_SOFT_RESET_REG, BMP180_SOFT_RESET_CTRL);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
readFirmwareVersion()
|
||||
|
||||
Reads ML & AL Version
|
||||
|
||||
NOTE:
|
||||
- ML version is LSB, 4-bit..0-bit
|
||||
- AL version is MSB, 7-bit..5-bit
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t BMP180::readFirmwareVersion(void)
|
||||
{
|
||||
return read8(BMP180_GET_VERSION_REG);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
readDeviceID()
|
||||
|
||||
Reads chip ID
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t BMP180::readDeviceID(void)
|
||||
{
|
||||
if (read8(BMP180_GET_ID_REG) == BMP180_CHIP_ID) return 180;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
readCalibrationCoefficients()
|
||||
|
||||
Reads factory calibration coefficients from E2PROM
|
||||
|
||||
NOTE:
|
||||
- every sensor module has individual calibration coefficients
|
||||
- before first temperature & pressure calculation master have to read
|
||||
calibration coefficients from 176-bit E2PROM
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool BMP180::readCalibrationCoefficients()
|
||||
{
|
||||
int32_t value = 0;
|
||||
|
||||
for (uint8_t reg = BMP180_CAL_AC1_REG; reg <= BMP180_CAL_MD_REG; reg++)
|
||||
{
|
||||
value = read16(reg);
|
||||
|
||||
if (value == BMP180_ERROR) return false; //error handler, collision on i2c bus
|
||||
|
||||
switch (reg)
|
||||
{
|
||||
case BMP180_CAL_AC1_REG: //used for pressure computation
|
||||
_calCoeff.bmpAC1 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_AC2_REG: //used for pressure computation
|
||||
_calCoeff.bmpAC2 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_AC3_REG: //used for pressure computation
|
||||
_calCoeff.bmpAC3 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_AC4_REG: //used for pressure computation
|
||||
_calCoeff.bmpAC4 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_AC5_REG: //used for temperature computation
|
||||
_calCoeff.bmpAC5 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_AC6_REG: //used for temperature computation
|
||||
_calCoeff.bmpAC6 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_B1_REG: //used for pressure computation
|
||||
_calCoeff.bmpB1 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_B2_REG: //used for pressure computation
|
||||
_calCoeff.bmpB2 = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_MB_REG: //???
|
||||
_calCoeff.bmpMB = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_MC_REG: //used for temperature computation
|
||||
_calCoeff.bmpMC = value;
|
||||
break;
|
||||
|
||||
case BMP180_CAL_MD_REG: //used for temperature computation
|
||||
_calCoeff.bmpMD = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
readRawTemperature()
|
||||
|
||||
Reads raw/uncompensated temperature value, 16-bit
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint16_t BMP180::readRawTemperature(void)
|
||||
{
|
||||
/* send temperature measurement command */
|
||||
if (write8(BMP180_START_MEASURMENT_REG, BMP180_GET_TEMPERATURE_CTRL) != true) return BMP180_ERROR; //error handler, collision on i2c bus
|
||||
|
||||
/* set measurement delay */
|
||||
HAL_Delay(5);
|
||||
|
||||
/* read result */
|
||||
return read16(BMP180_READ_ADC_MSB_REG); //reads msb + lsb
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
readRawPressure()
|
||||
|
||||
Reads raw/uncompensated pressure value, 19-bits
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t BMP180::readRawPressure(void)
|
||||
{
|
||||
uint8_t regControl = 0;
|
||||
uint32_t rawPressure = 0;
|
||||
|
||||
/* convert resolution to register control */
|
||||
switch (_resolution)
|
||||
{
|
||||
case BMP180_ULTRALOWPOWER: //oss0
|
||||
regControl = BMP180_GET_PRESSURE_OSS0_CTRL;
|
||||
break;
|
||||
|
||||
case BMP180_STANDARD: //oss1
|
||||
regControl = BMP180_GET_PRESSURE_OSS1_CTRL;
|
||||
break;
|
||||
|
||||
case BMP180_HIGHRES: //oss2
|
||||
regControl = BMP180_GET_PRESSURE_OSS2_CTRL;
|
||||
break;
|
||||
|
||||
case BMP180_ULTRAHIGHRES: //oss3
|
||||
regControl = BMP180_GET_PRESSURE_OSS3_CTRL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* send pressure measurement command */
|
||||
if (write8(BMP180_START_MEASURMENT_REG, regControl) != true) return BMP180_ERROR; //error handler, collision on i2c bus
|
||||
|
||||
/* set measurement delay */
|
||||
switch (_resolution)
|
||||
{
|
||||
case BMP180_ULTRALOWPOWER:
|
||||
HAL_Delay(5);
|
||||
break;
|
||||
|
||||
case BMP180_STANDARD:
|
||||
HAL_Delay(8);
|
||||
break;
|
||||
|
||||
case BMP180_HIGHRES:
|
||||
HAL_Delay(14);
|
||||
break;
|
||||
|
||||
case BMP180_ULTRAHIGHRES:
|
||||
HAL_Delay(26);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read result msb + lsb */
|
||||
rawPressure = read16(BMP180_READ_ADC_MSB_REG); //16-bits
|
||||
if (rawPressure == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
|
||||
|
||||
/* read result xlsb */
|
||||
rawPressure <<= 8;
|
||||
rawPressure |= read8(BMP180_READ_ADC_XLSB_REG); //19-bits
|
||||
|
||||
rawPressure >>= (8 - _resolution);
|
||||
|
||||
return rawPressure;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
computeB5()
|
||||
|
||||
Computes B5 value
|
||||
|
||||
NOTE:
|
||||
- to compensate raw/uncompensated temperature
|
||||
- also used for compensated pressure calculation
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int32_t BMP180::computeB5(int32_t UT)
|
||||
{
|
||||
int32_t X1 = ((UT - (int32_t)_calCoeff.bmpAC6) * (int32_t)_calCoeff.bmpAC5) >> 15;
|
||||
int32_t X2 = ((int32_t)_calCoeff.bmpMC << 11) / (X1 + (int32_t)_calCoeff.bmpMD);
|
||||
|
||||
return X1 + X2;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
read8()
|
||||
|
||||
Reads 8-bit value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t BMP180::read8(uint8_t reg)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
// Write register address
|
||||
status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, ®, 1, I2C_TIMEOUT);
|
||||
if (status != HAL_OK) return BMP180_ERROR;
|
||||
|
||||
// Read data from register
|
||||
status = HAL_I2C_Master_Receive(&hi2c3, BMP180_ADDRESS, &data, 1, I2C_TIMEOUT);
|
||||
if (status != HAL_OK) return BMP180_ERROR;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
read16()
|
||||
|
||||
Reads 16-bits value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
uint16_t BMP180::read16(uint8_t reg)
|
||||
{
|
||||
uint8_t data[2] = {0, 0};
|
||||
uint16_t value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
// Write register address
|
||||
status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, ®, 1, I2C_TIMEOUT);
|
||||
if (status != HAL_OK) return BMP180_ERROR;
|
||||
|
||||
// Read 2 bytes from register
|
||||
status = HAL_I2C_Master_Receive(&hi2c3, BMP180_ADDRESS, data, 2, I2C_TIMEOUT);
|
||||
if (status != HAL_OK) return BMP180_ERROR;
|
||||
|
||||
// Combine bytes (MSB first)
|
||||
value = (data[0] << 8) | data[1];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
write8()
|
||||
|
||||
Writes 8-bits value over I2C
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
bool BMP180::write8(uint8_t reg, uint8_t control)
|
||||
{
|
||||
uint8_t data[2] = {reg, control};
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
// Write register address and data
|
||||
status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, data, 2, I2C_TIMEOUT);
|
||||
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
156
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/BMP180.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/***************************************************************************************************/
|
||||
/*
|
||||
This is an Arduino basic library for Bosch BMP180 & BMP085 barometric pressure &
|
||||
temperature sensor
|
||||
|
||||
Power supply voltage: 1.8v - 3.6v
|
||||
Range: 30,000Pa..110,000Pa at -40°C..+85°C
|
||||
Typ. resolution: 1Pa / 0.1°C
|
||||
Typ. accuracy: ±100Pa* / ±1.0°C* at 0°C..+65°C
|
||||
Typ. relative accuracy: ±12Pa / xx°C
|
||||
Duty cycle: 10% active & 90% inactive, to prevent self heating
|
||||
|
||||
*sensor is sensitive to direct light, which can affect
|
||||
the accuracy of the measurement
|
||||
|
||||
written by : enjoyneering79
|
||||
sourse code: https://github.com/enjoyneering/
|
||||
|
||||
|
||||
This chip uses I2C bus to communicate, specials pins are required to interface
|
||||
Board: SDA SCL Level
|
||||
Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v
|
||||
Mega2560................................. 20 21 5v
|
||||
Due, SAM3X8E............................. 20 21 3.3v
|
||||
Leonardo, Micro, ATmega32U4.............. 2 3 5v
|
||||
Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v
|
||||
Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v
|
||||
ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v
|
||||
NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v
|
||||
ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v
|
||||
|
||||
NOTE:
|
||||
- EOC pin is not used, shows the end of conversion
|
||||
- XCLR pin is not used, reset pin
|
||||
|
||||
Frameworks & Libraries:
|
||||
ATtiny Core - https://github.com/SpenceKonde/ATTinyCore
|
||||
ESP32 Core - https://github.com/espressif/arduino-esp32
|
||||
ESP8266 Core - https://github.com/esp8266/Arduino
|
||||
STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32
|
||||
|
||||
GNU GPL license, all text above must be included in any redistribution,
|
||||
see link for details - https://www.gnu.org/licenses/licenses.html
|
||||
*/
|
||||
/***************************************************************************************************/
|
||||
|
||||
#ifndef BMP180_h
|
||||
#define BMP180_h
|
||||
|
||||
#include "stm32f7xx_hal.h"
|
||||
#include <cmath>
|
||||
|
||||
extern I2C_HandleTypeDef hi2c3;
|
||||
|
||||
/* resolutions */
|
||||
typedef enum : uint8_t
|
||||
{
|
||||
BMP180_ULTRALOWPOWER = 0x00, //low power mode, oss0
|
||||
BMP180_STANDARD = 0x01, //standard mode, oss1
|
||||
BMP180_HIGHRES = 0x02, //high resolution mode, oss2
|
||||
BMP180_ULTRAHIGHRES = 0x03 //ultra high resolution mode, oss3
|
||||
}
|
||||
BMP180_RESOLUTION;
|
||||
|
||||
|
||||
/* calibration registers */
|
||||
typedef enum : uint8_t
|
||||
{
|
||||
BMP180_CAL_AC1_REG = 0xAA, //ac1 pressure computation
|
||||
BMP180_CAL_AC2_REG = 0xAC, //ac2 pressure computation
|
||||
BMP180_CAL_AC3_REG = 0xAE, //ac3 pressure computation
|
||||
BMP180_CAL_AC4_REG = 0xB0, //ac4 pressure computation
|
||||
BMP180_CAL_AC5_REG = 0xB2, //ac5 temperature computation
|
||||
BMP180_CAL_AC6_REG = 0xB4, //ac6 temperature computation
|
||||
BMP180_CAL_B1_REG = 0xB6, //b1 pressure computation
|
||||
BMP180_CAL_B2_REG = 0xB8, //b2 pressure computation
|
||||
BMP180_CAL_MB_REG = 0xBA, //mb
|
||||
BMP180_CAL_MC_REG = 0xBC, //mc temperature computation
|
||||
BMP180_CAL_MD_REG = 0xBE //md temperature computation
|
||||
}
|
||||
BMP180_CAL_REG;
|
||||
|
||||
#define BMP180_GET_ID_REG 0xD0 //device id register
|
||||
#define BMP180_GET_VERSION_REG 0xD1 //device version register
|
||||
|
||||
#define BMP180_SOFT_RESET_REG 0xE0 //soft reset register
|
||||
#define BMP180_SOFT_RESET_CTRL 0xB6 //soft reset control
|
||||
|
||||
#define BMP180_START_MEASURMENT_REG 0xF4 //start measurment register
|
||||
#define BMP180_READ_ADC_MSB_REG 0xF6 //read adc msb register
|
||||
#define BMP180_READ_ADC_LSB_REG 0xF7 //read adc lsb register
|
||||
#define BMP180_READ_ADC_XLSB_REG 0xF8 //read adc xlsb register
|
||||
|
||||
/* BMP180_START_MEASURMENT_REG controls */
|
||||
#define BMP180_GET_TEMPERATURE_CTRL 0x2E //get temperature control
|
||||
#define BMP180_GET_PRESSURE_OSS0_CTRL 0x34 //get pressure oversampling 1 time/oss0 control
|
||||
#define BMP180_GET_PRESSURE_OSS1_CTRL 0x74 //get pressure oversampling 2 time/oss1 control
|
||||
#define BMP180_GET_PRESSURE_OSS2_CTRL 0xB4 //get pressure oversampling 4 time/oss2 control
|
||||
#define BMP180_GET_PRESSURE_OSS3_CTRL 0xF4 //get pressure oversampling 8 time/oss3 control
|
||||
|
||||
/* misc */
|
||||
#define BMP180_CHIP_ID 0x55 //id number
|
||||
|
||||
#define BMP180_ERROR 255 //returns 255, if communication error is occurred
|
||||
|
||||
#define BMP180_ADDRESS (0x77 << 1) // HAL requires 7-bit address shifted left by 1 bit
|
||||
|
||||
#define I2C_TIMEOUT 100
|
||||
|
||||
/* to store calibration coefficients */
|
||||
typedef struct
|
||||
{
|
||||
int16_t bmpAC1 = 0;
|
||||
int16_t bmpAC2 = 0;
|
||||
int16_t bmpAC3 = 0;
|
||||
uint16_t bmpAC4 = 0;
|
||||
uint16_t bmpAC5 = 0;
|
||||
uint16_t bmpAC6 = 0;
|
||||
|
||||
int16_t bmpB1 = 0;
|
||||
int16_t bmpB2 = 0;
|
||||
|
||||
int16_t bmpMB = 0;
|
||||
int16_t bmpMC = 0;
|
||||
int16_t bmpMD = 0;
|
||||
}
|
||||
BMP180_CAL_COEFF;
|
||||
|
||||
|
||||
class BMP180
|
||||
{
|
||||
public:
|
||||
BMP180(BMP180_RESOLUTION = BMP180_ULTRAHIGHRES); //BMP180_ULTRAHIGHRES, by default
|
||||
int32_t getPressure(void); //in Pa
|
||||
float getTemperature(void); //in °C
|
||||
int32_t getSeaLevelPressure(int16_t trueAltitude = 115); //in Pa, by default true altitude id 115 meters
|
||||
void softReset(void);
|
||||
uint8_t readFirmwareVersion(void);
|
||||
uint8_t readDeviceID(void);
|
||||
|
||||
|
||||
private:
|
||||
BMP180_CAL_COEFF _calCoeff;
|
||||
|
||||
uint8_t _resolution;
|
||||
|
||||
bool readCalibrationCoefficients(void);
|
||||
uint16_t readRawTemperature(void);
|
||||
uint32_t readRawPressure(void);
|
||||
int32_t computeB5(int32_t UT);
|
||||
uint8_t read8(uint8_t reg);
|
||||
uint16_t read16(uint8_t reg);
|
||||
bool write8(uint8_t reg, uint8_t control);
|
||||
};
|
||||
|
||||
#endif
|
||||
427
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/DA5578.c
Normal file
@@ -0,0 +1,427 @@
|
||||
#include "DAC5578.h"
|
||||
#include "diag_log.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize the DAC5578
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param hi2c: pointer to an I2C_HandleTypeDef structure
|
||||
* @param i2c_addr: I2C address of the DAC
|
||||
* @param resolution: DAC resolution (only 8 is valid for DAC5578)
|
||||
* @param ldac_port: GPIO port for LDAC pin
|
||||
* @param ldac_pin: GPIO pin for LDAC pin
|
||||
* @param clr_port: GPIO port for CLR pin
|
||||
* @param clr_pin: GPIO pin for CLR pin
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_Init(DAC5578_HandleTypeDef *hdac, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
|
||||
uint8_t resolution, GPIO_TypeDef *ldac_port, uint16_t ldac_pin,
|
||||
GPIO_TypeDef *clr_port, uint16_t clr_pin) {
|
||||
|
||||
DIAG("PA", "DAC5578_Init: addr=0x%02X (shifted=0x%02X), res=%u", i2c_addr, i2c_addr << 1, resolution);
|
||||
|
||||
if (hdac == NULL || hi2c == NULL) {
|
||||
DIAG_ERR("PA", "DAC5578_Init: NULL handle(s)");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* DAC5578 is 8-bit only */
|
||||
hdac->resolution_bits = 8;
|
||||
hdac->clear_code = DAC5578_CLR_CODE_ZERO; // Default clear to zero
|
||||
|
||||
hdac->hi2c = hi2c;
|
||||
hdac->i2c_addr = i2c_addr << 1; // HAL requires 7-bit address shifted left
|
||||
hdac->ldac_port = ldac_port;
|
||||
hdac->ldac_pin = ldac_pin;
|
||||
hdac->clr_port = clr_port;
|
||||
hdac->clr_pin = clr_pin;
|
||||
|
||||
/* Set LDAC high (inactive) and CLR high (normal operation) */
|
||||
if (ldac_port != NULL) {
|
||||
DIAG("PA", " LDAC pin -> HIGH (inactive)");
|
||||
HAL_GPIO_WritePin(ldac_port, ldac_pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
if (clr_port != NULL) {
|
||||
DIAG("PA", " CLR pin -> HIGH (normal operation)");
|
||||
HAL_GPIO_WritePin(clr_port, clr_pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
/* Reset the DAC and enable internal reference by default */
|
||||
DIAG("PA", " Resetting DAC5578...");
|
||||
bool success = DAC5578_Reset(hdac);
|
||||
if (success) {
|
||||
DIAG("PA", " Enabling internal reference...");
|
||||
success = DAC5578_SetInternalReference(hdac, true);
|
||||
} else {
|
||||
DIAG_ERR("PA", " DAC5578_Reset FAILED");
|
||||
}
|
||||
|
||||
/* Set the clear code in the device */
|
||||
if (success) {
|
||||
DIAG("PA", " Setting clear code to ZERO...");
|
||||
success = DAC5578_SetClearCode(hdac, hdac->clear_code);
|
||||
}
|
||||
|
||||
DIAG("PA", "DAC5578_Init: %s", success ? "OK" : "FAILED");
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the DAC5578
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_Reset(DAC5578_HandleTypeDef *hdac) {
|
||||
DIAG("PA", "DAC5578_Reset: addr=0x%02X", hdac->i2c_addr);
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = DAC5578_CMD_RESET;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = 0x00;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "DAC5578_Reset: I2C transmit FAILED, HAL status=%d", (int)status);
|
||||
}
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a value to a specific channel's input register
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param channel: DAC channel (0-7)
|
||||
* @param value: 8-bit value to write
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_WriteChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value) {
|
||||
if (channel > 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* DAC5578 is 8-bit, so mask value */
|
||||
value &= 0xFF;
|
||||
|
||||
return DAC5578_CommandWrite(hdac, DAC5578_CMD_WRITE | (channel & 0x7), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update a specific channel's DAC register from input register
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param channel: DAC channel (0-7) or DAC5578_CHANNEL_BROADCAST
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_UpdateChannel(DAC5578_HandleTypeDef *hdac, uint8_t channel) {
|
||||
if (channel > 7 && channel != DAC5578_CHANNEL_BROADCAST) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update command with channel selection */
|
||||
uint8_t command = DAC5578_CMD_UPDATE | (channel & 0x7);
|
||||
if (channel == DAC5578_CHANNEL_BROADCAST) {
|
||||
command = DAC5578_CMD_UPDATE | 0x8; // Broadcast flag
|
||||
}
|
||||
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = command;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = 0x00;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write and update a specific channel in one operation
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param channel: DAC channel (0-7)
|
||||
* @param value: 8-bit value to write and update
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_WriteAndUpdateChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value) {
|
||||
if (channel > 7) {
|
||||
DIAG_ERR("PA", "DAC5578_WriteAndUpdate: channel %u out of range", channel);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* DAC5578 is 8-bit, so mask value */
|
||||
value &= 0xFF;
|
||||
|
||||
DIAG("PA", "DAC5578_WriteAndUpdate: addr=0x%02X ch=%u val=0x%02X (%u)", hdac->i2c_addr, channel, value, value);
|
||||
return DAC5578_CommandWrite(hdac, DAC5578_CMD_WRITE_UPDATE | (channel & 0x7), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the same value to all channels' input registers
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param value: 8-bit value to write to all channels
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_WriteAllChannels(DAC5578_HandleTypeDef *hdac, uint16_t value) {
|
||||
/* DAC5578 is 8-bit, so mask value */
|
||||
value &= 0xFF;
|
||||
|
||||
return DAC5578_CommandWrite(hdac, DAC5578_CMD_WRITE_ALL, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the input register value of a specific channel
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param channel: DAC channel (0-7)
|
||||
* @param value: pointer to store the read value
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_ReadInputChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value) {
|
||||
if (channel > 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Note: DAC5578 has limited read capability - this reads back the input register */
|
||||
return DAC5578_CommandRead(hdac, DAC5578_CMD_WRITE | (channel & 0x7), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the DAC register value (current output) of a specific channel
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param channel: DAC channel (0-7)
|
||||
* @param value: pointer to store the read value
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_ReadDACChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value) {
|
||||
if (channel > 7) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Note: DAC5578 has limited read capability - this reads back the DAC register */
|
||||
return DAC5578_CommandRead(hdac, DAC5578_CMD_UPDATE | (channel & 0x7), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set power down mode for a specific channel
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param channel: DAC channel (0-7)
|
||||
* @param mode: power down mode
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_SetPowerDownMode(DAC5578_HandleTypeDef *hdac, uint8_t channel, DAC5578_PowerDownMode_t mode) {
|
||||
if (channel > 7 || mode > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = DAC5578_CMD_POWERDOWN | (channel & 0x7);
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = mode & 0x03;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set power down mode for all channels
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param mode: power down mode
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_SetPowerDownAll(DAC5578_HandleTypeDef *hdac, DAC5578_PowerDownMode_t mode) {
|
||||
if (mode > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = DAC5578_CMD_POWERDOWN_ALL;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = mode & 0x03;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the internal reference
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param enable: true to enable, false to disable
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_SetInternalReference(DAC5578_HandleTypeDef *hdac, bool enable) {
|
||||
uint8_t command = enable ? DAC5578_CMD_INT_REF_ENABLE : DAC5578_CMD_INT_REF_DISABLE;
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = command;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = 0x00;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup LDAC mask for hardware LDAC control
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param ldac_mask: 8-bit mask where each bit corresponds to a channel
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_SetupLDAC(DAC5578_HandleTypeDef *hdac, uint8_t ldac_mask) {
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = DAC5578_CMD_LDAC_SETUP;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = ldac_mask & 0xFF; // Each bit corresponds to a channel (0-7)
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Trigger software LDAC update
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_SoftwareLDAC(DAC5578_HandleTypeDef *hdac) {
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = DAC5578_CMD_SOFTWARE_LDAC;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = 0x00;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/* CLR Pin Functions */
|
||||
|
||||
/**
|
||||
* @brief Set the clear code that determines what happens when CLR pin is activated
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param clear_code: desired clear code behavior
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_SetClearCode(DAC5578_HandleTypeDef *hdac, DAC5578_ClearCode_t clear_code) {
|
||||
if (clear_code > DAC5578_CLR_CODE_NOP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The clear code is set using the RESET command with specific data bits */
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = DAC5578_CMD_RESET;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = (clear_code & 0x03); // Clear code in bits 1:0
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
|
||||
if (status == HAL_OK) {
|
||||
hdac->clear_code = clear_code;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current clear code setting
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @retval DAC5578_ClearCode_t: current clear code setting
|
||||
*/
|
||||
DAC5578_ClearCode_t DAC5578_GetClearCode(DAC5578_HandleTypeDef *hdac) {
|
||||
return hdac->clear_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Activate the CLR pin (set low) to clear DAC outputs
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @retval None
|
||||
*/
|
||||
void DAC5578_ActivateClearPin(DAC5578_HandleTypeDef *hdac) {
|
||||
DIAG_WARN("PA", "DAC5578_ActivateClearPin: CLR -> LOW (emergency clear), addr=0x%02X", hdac->i2c_addr);
|
||||
if (hdac->clr_port != NULL) {
|
||||
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_RESET);
|
||||
} else {
|
||||
DIAG_ERR("PA", " CLR port is NULL -- cannot activate hardware clear!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivate the CLR pin (set high) for normal operation
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @retval None
|
||||
*/
|
||||
void DAC5578_DeactivateClearPin(DAC5578_HandleTypeDef *hdac) {
|
||||
if (hdac->clr_port != NULL) {
|
||||
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_SET);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pulse the CLR pin to clear all DAC outputs according to clear code
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @retval None
|
||||
*/
|
||||
void DAC5578_ClearOutputs(DAC5578_HandleTypeDef *hdac) {
|
||||
DIAG_WARN("PA", "DAC5578_ClearOutputs: pulsing CLR pin, addr=0x%02X", hdac->i2c_addr);
|
||||
if (hdac->clr_port != NULL) {
|
||||
/* Generate a pulse on CLR pin (active low) */
|
||||
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_RESET);
|
||||
HAL_Delay(1); // Hold for at least 50ns (1ms is plenty)
|
||||
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_SET);
|
||||
} else {
|
||||
DIAG_ERR("PA", " CLR port is NULL -- cannot pulse clear!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Software clear - uses I2C command to clear outputs without CLR pin
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_SoftwareClear(DAC5578_HandleTypeDef *hdac) {
|
||||
/* Use the reset command with the current clear code to perform software clear */
|
||||
return DAC5578_SetClearCode(hdac, hdac->clear_code);
|
||||
}
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/**
|
||||
* @brief Write a command and value to the DAC
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param command: command byte
|
||||
* @param value: 8-bit value to write
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_CommandWrite(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t value) {
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = command;
|
||||
buffer[1] = (value >> 8) & 0xFF; // MSB (should be 0 for 8-bit DAC)
|
||||
buffer[2] = value & 0xFF; // LSB (actual 8-bit data)
|
||||
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "DAC5578 I2C write FAILED: addr=0x%02X cmd=0x%02X HAL=%d", hdac->i2c_addr, command, (int)status);
|
||||
}
|
||||
return (status == HAL_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a value from the DAC after sending a command
|
||||
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
|
||||
* @param command: command byte
|
||||
* @param value: pointer to store the read value
|
||||
* @retval bool: true if successful, false otherwise
|
||||
*/
|
||||
bool DAC5578_CommandRead(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t *value) {
|
||||
uint8_t buffer[3];
|
||||
|
||||
/* First write the command to set up readback */
|
||||
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, &command, 1, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "DAC5578 I2C read setup FAILED: addr=0x%02X cmd=0x%02X HAL=%d", hdac->i2c_addr, command, (int)status);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Then read 3 bytes back */
|
||||
status = HAL_I2C_Master_Receive(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
|
||||
if (status != HAL_OK) {
|
||||
DIAG_ERR("PA", "DAC5578 I2C read data FAILED: addr=0x%02X cmd=0x%02X HAL=%d", hdac->i2c_addr, command, (int)status);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Extract the 8-bit value from the response */
|
||||
*value = buffer[2] & 0xFF;
|
||||
DIAG("PA", "DAC5578_Read: addr=0x%02X cmd=0x%02X => 0x%02X", hdac->i2c_addr, command, *value);
|
||||
return true;
|
||||
}
|
||||
91
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/DAC5578.H
Normal file
@@ -0,0 +1,91 @@
|
||||
#ifndef __DAC5578_H
|
||||
#define __DAC5578_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stm32f7xx_hal.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
|
||||
extern I2C_HandleTypeDef hi2c1;
|
||||
|
||||
/* Command definitions - DAC5578 specific */
|
||||
#define DAC5578_CMD_WRITE (0x0 << 4) // Write to input register
|
||||
#define DAC5578_CMD_UPDATE (0x1 << 4) // Update DAC register
|
||||
#define DAC5578_CMD_WRITE_UPDATE (0x2 << 4) // Write and update
|
||||
#define DAC5578_CMD_WRITE_ALL (0x3 << 4) // Write to all channels
|
||||
#define DAC5578_CMD_POWERDOWN (0x4 << 4) // Power down
|
||||
#define DAC5578_CMD_POWERDOWN_ALL (0x5 << 4) // Power down all channels
|
||||
#define DAC5578_CMD_INT_REF_ENABLE (0x6 << 4) // Enable internal reference
|
||||
#define DAC5578_CMD_INT_REF_DISABLE (0x7 << 4) // Disable internal reference
|
||||
#define DAC5578_CMD_RESET (0x8 << 4) // Software reset
|
||||
#define DAC5578_CMD_LDAC_SETUP (0x9 << 4) // LDAC setup register
|
||||
#define DAC5578_CMD_SOFTWARE_LDAC (0xA << 4) // Software LDAC trigger
|
||||
|
||||
/* Broadcast channel for simultaneous updates */
|
||||
#define DAC5578_CHANNEL_BROADCAST 0x8
|
||||
|
||||
/* Power down modes */
|
||||
typedef enum {
|
||||
DAC5578_PWD_NORMAL = 0, // Normal operation
|
||||
DAC5578_PWD_1K = 1, // 1kΩ to GND
|
||||
DAC5578_PWD_100K = 2, // 100kΩ to GND
|
||||
DAC5578_PWD_HIZ = 3 // High impedance
|
||||
} DAC5578_PowerDownMode_t;
|
||||
|
||||
/* Clear code options - determines what happens when CLR pin is activated */
|
||||
typedef enum {
|
||||
DAC5578_CLR_CODE_ZERO = 0, // Clear to zero scale (0x00)
|
||||
DAC5578_CLR_CODE_MID = 1, // Clear to midscale (0x80)
|
||||
DAC5578_CLR_CODE_FULL = 2, // Clear to full scale (0xFF)
|
||||
DAC5578_CLR_CODE_NOP = 3 // No operation (retain current value)
|
||||
} DAC5578_ClearCode_t;
|
||||
|
||||
/* DAC handle structure */
|
||||
typedef struct {
|
||||
I2C_HandleTypeDef *hi2c;
|
||||
uint8_t i2c_addr;
|
||||
uint8_t resolution_bits;
|
||||
GPIO_TypeDef *ldac_port;
|
||||
uint16_t ldac_pin;
|
||||
GPIO_TypeDef *clr_port;
|
||||
uint16_t clr_pin;
|
||||
DAC5578_ClearCode_t clear_code; // Current clear code setting
|
||||
} DAC5578_HandleTypeDef;
|
||||
|
||||
/* Function prototypes */
|
||||
bool DAC5578_Init(DAC5578_HandleTypeDef *hdac, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
|
||||
uint8_t resolution, GPIO_TypeDef *ldac_port, uint16_t ldac_pin,
|
||||
GPIO_TypeDef *clr_port, uint16_t clr_pin);
|
||||
bool DAC5578_Reset(DAC5578_HandleTypeDef *hdac);
|
||||
bool DAC5578_WriteChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value);
|
||||
bool DAC5578_UpdateChannel(DAC5578_HandleTypeDef *hdac, uint8_t channel);
|
||||
bool DAC5578_WriteAndUpdateChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value);
|
||||
bool DAC5578_WriteAllChannels(DAC5578_HandleTypeDef *hdac, uint16_t value);
|
||||
bool DAC5578_ReadInputChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value);
|
||||
bool DAC5578_ReadDACChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value);
|
||||
bool DAC5578_SetPowerDownMode(DAC5578_HandleTypeDef *hdac, uint8_t channel, DAC5578_PowerDownMode_t mode);
|
||||
bool DAC5578_SetPowerDownAll(DAC5578_HandleTypeDef *hdac, DAC5578_PowerDownMode_t mode);
|
||||
bool DAC5578_SetInternalReference(DAC5578_HandleTypeDef *hdac, bool enable);
|
||||
bool DAC5578_SetupLDAC(DAC5578_HandleTypeDef *hdac, uint8_t ldac_mask);
|
||||
bool DAC5578_SoftwareLDAC(DAC5578_HandleTypeDef *hdac);
|
||||
|
||||
/* CLR Pin Functions */
|
||||
bool DAC5578_SetClearCode(DAC5578_HandleTypeDef *hdac, DAC5578_ClearCode_t clear_code);
|
||||
DAC5578_ClearCode_t DAC5578_GetClearCode(DAC5578_HandleTypeDef *hdac);
|
||||
void DAC5578_ActivateClearPin(DAC5578_HandleTypeDef *hdac);
|
||||
void DAC5578_DeactivateClearPin(DAC5578_HandleTypeDef *hdac);
|
||||
void DAC5578_ClearOutputs(DAC5578_HandleTypeDef *hdac); // Pulse CLR pin to clear outputs
|
||||
|
||||
/* Private functions */
|
||||
bool DAC5578_CommandWrite(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t value);
|
||||
bool DAC5578_CommandRead(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t *value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DAC5578_H */
|
||||
173
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/GY_85_HAL.c
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "GY_85_HAL.h"
|
||||
|
||||
static int16_t g_offx = 0, g_offy = 0, g_offz = 0;
|
||||
|
||||
// ---------------- Internal Functions ---------------- //
|
||||
static bool GY85_SetAccelerometer(void);
|
||||
static bool GY85_ReadAccelerometer(GY85_t *imu);
|
||||
static bool GY85_SetCompass(void);
|
||||
static bool GY85_ReadCompass(GY85_t *imu);
|
||||
static bool GY85_SetGyro(void);
|
||||
static bool GY85_GyroCalibrate(void);
|
||||
static bool GY85_ReadGyro(GY85_t *imu);
|
||||
static bool GY85_WriteRegister(uint16_t address, uint8_t reg, uint8_t value);
|
||||
static bool GY85_ReadRegisters(uint16_t address, uint8_t reg, uint8_t *buffer, uint16_t length);
|
||||
|
||||
// ---------------- Initialization ---------------- //
|
||||
bool GY85_Init(void)
|
||||
{
|
||||
if (!GY85_SetAccelerometer()) {
|
||||
return false;
|
||||
}
|
||||
if (!GY85_SetCompass()) {
|
||||
return false;
|
||||
}
|
||||
return GY85_SetGyro();
|
||||
}
|
||||
|
||||
// ---------------- Update All Sensors ---------------- //
|
||||
bool GY85_Update(GY85_t *imu)
|
||||
{
|
||||
GY85_t next_sample;
|
||||
|
||||
if (imu == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
next_sample = *imu;
|
||||
|
||||
if (!GY85_ReadAccelerometer(&next_sample)) {
|
||||
return false;
|
||||
}
|
||||
if (!GY85_ReadCompass(&next_sample)) {
|
||||
return false;
|
||||
}
|
||||
if (!GY85_ReadGyro(&next_sample)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*imu = next_sample;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------- Accelerometer ---------------- //
|
||||
static bool GY85_SetAccelerometer(void)
|
||||
{
|
||||
if (!GY85_WriteRegister(ADXL345_ADDR, 0x31, 0x01)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GY85_WriteRegister(ADXL345_ADDR, 0x2D, 0x08);
|
||||
}
|
||||
|
||||
static bool GY85_ReadAccelerometer(GY85_t *imu)
|
||||
{
|
||||
uint8_t buf[6];
|
||||
|
||||
if (imu == NULL || !GY85_ReadRegisters(ADXL345_ADDR, 0x32, buf, sizeof(buf))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
imu->ax = (int16_t)((buf[1] << 8) | buf[0]);
|
||||
imu->ay = (int16_t)((buf[3] << 8) | buf[2]);
|
||||
imu->az = (int16_t)((buf[5] << 8) | buf[4]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------- Compass ---------------- //
|
||||
static bool GY85_SetCompass(void)
|
||||
{
|
||||
return GY85_WriteRegister(HMC5883_ADDR, 0x02, 0x00);
|
||||
}
|
||||
|
||||
static bool GY85_ReadCompass(GY85_t *imu)
|
||||
{
|
||||
uint8_t buf[6];
|
||||
|
||||
if (imu == NULL || !GY85_ReadRegisters(HMC5883_ADDR, 0x03, buf, sizeof(buf))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
imu->mx = (int16_t)((buf[0] << 8) | buf[1]);
|
||||
imu->mz = (int16_t)((buf[2] << 8) | buf[3]);
|
||||
imu->my = (int16_t)((buf[4] << 8) | buf[5]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------- Gyroscope ---------------- //
|
||||
static bool GY85_SetGyro(void)
|
||||
{
|
||||
if (!GY85_WriteRegister(ITG3200_ADDR, 0x3E, 0x00)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GY85_WriteRegister(ITG3200_ADDR, 0x15, 0x07)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GY85_WriteRegister(ITG3200_ADDR, 0x16, 0x1E)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GY85_WriteRegister(ITG3200_ADDR, 0x17, 0x00)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HAL_Delay(10);
|
||||
return GY85_GyroCalibrate();
|
||||
}
|
||||
|
||||
static bool GY85_GyroCalibrate(void)
|
||||
{
|
||||
int32_t tmpx = 0, tmpy = 0, tmpz = 0;
|
||||
GY85_t imu;
|
||||
|
||||
for(uint8_t i = 0; i < 10; i++)
|
||||
{
|
||||
HAL_Delay(10);
|
||||
if (!GY85_ReadGyro(&imu)) {
|
||||
return false;
|
||||
}
|
||||
tmpx += imu.gx;
|
||||
tmpy += imu.gy;
|
||||
tmpz += imu.gz;
|
||||
}
|
||||
|
||||
g_offx = tmpx / 10;
|
||||
g_offy = tmpy / 10;
|
||||
g_offz = tmpz / 10;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GY85_ReadGyro(GY85_t *imu)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
|
||||
if (imu == NULL || !GY85_ReadRegisters(ITG3200_ADDR, 0x1B, buf, sizeof(buf))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
imu->gx = ((int16_t)((buf[2] << 8) | buf[3])) - g_offx;
|
||||
imu->gy = ((int16_t)((buf[4] << 8) | buf[5])) - g_offy;
|
||||
imu->gz = ((int16_t)((buf[6] << 8) | buf[7])) - g_offz;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GY85_WriteRegister(uint16_t address, uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t data[2] = {reg, value};
|
||||
return HAL_I2C_Master_Transmit(&hi2c3, address, data, sizeof(data), HAL_MAX_DELAY) == HAL_OK;
|
||||
}
|
||||
|
||||
static bool GY85_ReadRegisters(uint16_t address, uint8_t reg, uint8_t *buffer, uint16_t length)
|
||||
{
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HAL_I2C_Master_Transmit(&hi2c3, address, ®, 1, HAL_MAX_DELAY) != HAL_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return HAL_I2C_Master_Receive(&hi2c3, address, buffer, length, HAL_MAX_DELAY) == HAL_OK;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef __GY_85_HAL_H__
|
||||
#define __GY_85_HAL_H__
|
||||
|
||||
#include "stm32f7xx_hal.h" // change depending on MCU family
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define ADXL345_ADDR (0x53 << 1)
|
||||
#define HMC5883_ADDR (0x1E << 1)
|
||||
#define ITG3200_ADDR (0x68 << 1)
|
||||
|
||||
extern I2C_HandleTypeDef hi2c3;
|
||||
|
||||
// Struct to hold all sensor data
|
||||
typedef struct {
|
||||
int16_t ax, ay, az; // accelerometer
|
||||
float gx, gy, gz; // gyroscope
|
||||
int16_t mx, my, mz; // magnetometer
|
||||
} GY85_t;
|
||||
|
||||
// Public API
|
||||
bool GY85_Init(void);
|
||||
bool GY85_Update(GY85_t *imu); // reads all sensors and stores in struct
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "RadarSettings.h"
|
||||
#include <cstring>
|
||||
|
||||
RadarSettings::RadarSettings() {
|
||||
resetToDefaults();
|
||||
}
|
||||
|
||||
void RadarSettings::resetToDefaults() {
|
||||
system_frequency = 10.0e9; // 10 GHz
|
||||
chirp_duration_1 = 30.0e-6; // 30 <20>s
|
||||
chirp_duration_2 = 0.5e-6; // 0.5 <20>s
|
||||
chirps_per_position = 32;
|
||||
freq_min = 10.0e6; // 10 MHz
|
||||
freq_max = 30.0e6; // 30 MHz
|
||||
prf1 = 1000.0; // 1 kHz
|
||||
prf2 = 2000.0; // 2 kHz
|
||||
max_distance = 50000.0; // 50 km
|
||||
map_size = 50000.0; // 50 km
|
||||
|
||||
settings_valid = true;
|
||||
}
|
||||
|
||||
bool RadarSettings::parseFromUSB(const uint8_t* data, uint32_t length) {
|
||||
// Minimum packet size: "SET" + 9 doubles + 1 uint32_t + "END" = 3 + 9*8 + 4 + 3 = 82 bytes
|
||||
if (data == nullptr || length < 82) {
|
||||
settings_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for start marker "SET"
|
||||
if (memcmp(data, "SET", 3) != 0) {
|
||||
settings_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for end marker "END"
|
||||
if (memcmp(data + length - 3, "END", 3) != 0) {
|
||||
settings_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t offset = 3; // Skip "SET"
|
||||
|
||||
// Extract all parameters in order
|
||||
system_frequency = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
chirp_duration_1 = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
chirp_duration_2 = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
chirps_per_position = extractUint32(data + offset);
|
||||
offset += 4;
|
||||
|
||||
freq_min = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
freq_max = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
prf1 = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
prf2 = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
max_distance = extractDouble(data + offset);
|
||||
offset += 8;
|
||||
|
||||
map_size = extractDouble(data + offset);
|
||||
|
||||
// Validate the received settings
|
||||
settings_valid = validateSettings();
|
||||
|
||||
return settings_valid;
|
||||
}
|
||||
|
||||
bool RadarSettings::validateSettings() {
|
||||
// Check for reasonable value ranges
|
||||
if (system_frequency < 1e9 || system_frequency > 100e9) return false;
|
||||
if (chirp_duration_1 < 1e-6 || chirp_duration_1 > 1000e-6) return false;
|
||||
if (chirp_duration_2 < 0.1e-6 || chirp_duration_2 > 10e-6) return false;
|
||||
if (chirps_per_position < 1 || chirps_per_position > 256) return false;
|
||||
if (freq_min < 1e6 || freq_min > 100e6) return false;
|
||||
if (freq_max <= freq_min || freq_max > 100e6) return false;
|
||||
if (prf1 < 100 || prf1 > 10000) return false;
|
||||
if (prf2 < 100 || prf2 > 10000) return false;
|
||||
if (max_distance < 100 || max_distance > 100000) return false;
|
||||
if (map_size < 1000 || map_size > 200000) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double RadarSettings::extractDouble(const uint8_t* data) {
|
||||
uint64_t bits = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bits = (bits << 8) | data[i];
|
||||
}
|
||||
|
||||
double value;
|
||||
memcpy(&value, &bits, sizeof(double));
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t RadarSettings::extractUint32(const uint8_t* data) {
|
||||
uint32_t value = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
value = (value << 8) | data[i];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef RADARSETTINGS_H
|
||||
#define RADARSETTINGS_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class RadarSettings {
|
||||
public:
|
||||
// Default constructor with initial values
|
||||
RadarSettings();
|
||||
|
||||
// Parse settings from USB CDC data
|
||||
bool parseFromUSB(const uint8_t* data, uint32_t length);
|
||||
|
||||
// Getters for all settings
|
||||
double getSystemFrequency() const { return system_frequency; }
|
||||
double getChirpDuration1() const { return chirp_duration_1; }
|
||||
double getChirpDuration2() const { return chirp_duration_2; }
|
||||
uint32_t getChirpsPerPosition() const { return chirps_per_position; }
|
||||
double getFreqMin() const { return freq_min; }
|
||||
double getFreqMax() const { return freq_max; }
|
||||
double getPRF1() const { return prf1; }
|
||||
double getPRF2() const { return prf2; }
|
||||
double getMaxDistance() const { return max_distance; }
|
||||
double getMapSize() const { return map_size; }
|
||||
|
||||
// Check if settings are valid
|
||||
bool isValid() const { return settings_valid; }
|
||||
|
||||
// Reset to default values
|
||||
void resetToDefaults();
|
||||
|
||||
private:
|
||||
// Radar system parameters
|
||||
double system_frequency; // Hz
|
||||
double chirp_duration_1; // seconds (long chirp)
|
||||
double chirp_duration_2; // seconds (short chirp)
|
||||
uint32_t chirps_per_position;
|
||||
double freq_min; // Hz
|
||||
double freq_max; // Hz
|
||||
double prf1; // Hz
|
||||
double prf2; // Hz
|
||||
double max_distance; // meters
|
||||
double map_size; // meters
|
||||
|
||||
bool settings_valid;
|
||||
|
||||
// Helper methods
|
||||
bool validateSettings();
|
||||
double extractDouble(const uint8_t* data);
|
||||
uint32_t extractUint32(const uint8_t* data);
|
||||
};
|
||||
|
||||
#endif // RADARSETTINGS_H
|
||||
509
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/TinyGPS++.cpp
Normal file
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
|
||||
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
|
||||
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
|
||||
Location precision improvements suggested by Wayne Holder.
|
||||
Copyright (C) 2008-2024 Mikal Hart
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "TinyGPS++.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define _RMCterm "RMC"
|
||||
#define _GGAterm "GGA"
|
||||
|
||||
|
||||
TinyGPSPlus::TinyGPSPlus()
|
||||
: parity(0)
|
||||
, isChecksumTerm(false)
|
||||
, curSentenceType(GPS_SENTENCE_OTHER)
|
||||
, curTermNumber(0)
|
||||
, curTermOffset(0)
|
||||
, sentenceHasFix(false)
|
||||
, customElts(0)
|
||||
, customCandidates(0)
|
||||
, encodedCharCount(0)
|
||||
, sentencesWithFixCount(0)
|
||||
, failedChecksumCount(0)
|
||||
, passedChecksumCount(0)
|
||||
{
|
||||
term[0] = '\0';
|
||||
}
|
||||
|
||||
//
|
||||
// public methods
|
||||
//
|
||||
|
||||
bool TinyGPSPlus::encode(char c)
|
||||
{
|
||||
++encodedCharCount;
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case ',': // term terminators
|
||||
parity ^= (uint8_t)c;
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '*':
|
||||
{
|
||||
bool isValidSentence = false;
|
||||
if (curTermOffset < sizeof(term))
|
||||
{
|
||||
term[curTermOffset] = 0;
|
||||
isValidSentence = endOfTermHandler();
|
||||
}
|
||||
++curTermNumber;
|
||||
curTermOffset = 0;
|
||||
isChecksumTerm = c == '*';
|
||||
return isValidSentence;
|
||||
}
|
||||
break;
|
||||
|
||||
case '$': // sentence begin
|
||||
curTermNumber = curTermOffset = 0;
|
||||
parity = 0;
|
||||
curSentenceType = GPS_SENTENCE_OTHER;
|
||||
isChecksumTerm = false;
|
||||
sentenceHasFix = false;
|
||||
return false;
|
||||
|
||||
default: // ordinary characters
|
||||
if (curTermOffset < sizeof(term) - 1)
|
||||
term[curTermOffset++] = c;
|
||||
if (!isChecksumTerm)
|
||||
parity ^= c;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// internal utilities
|
||||
//
|
||||
int TinyGPSPlus::fromHex(char a)
|
||||
{
|
||||
if (a >= 'A' && a <= 'F')
|
||||
return a - 'A' + 10;
|
||||
else if (a >= 'a' && a <= 'f')
|
||||
return a - 'a' + 10;
|
||||
else
|
||||
return a - '0';
|
||||
}
|
||||
|
||||
// static
|
||||
// Parse a (potentially negative) number with up to 2 decimal digits -xxxx.yy
|
||||
int32_t TinyGPSPlus::parseDecimal(const char *term)
|
||||
{
|
||||
bool negative = *term == '-';
|
||||
if (negative) ++term;
|
||||
int32_t ret = 100 * (int32_t)atol(term);
|
||||
while (isdigit(*term)) ++term;
|
||||
if (*term == '.' && isdigit(term[1]))
|
||||
{
|
||||
ret += 10 * (term[1] - '0');
|
||||
if (isdigit(term[2]))
|
||||
ret += term[2] - '0';
|
||||
}
|
||||
return negative ? -ret : ret;
|
||||
}
|
||||
|
||||
// static
|
||||
// Parse degrees in that funny NMEA format DDMM.MMMM
|
||||
void TinyGPSPlus::parseDegrees(const char *term, RawDegrees °)
|
||||
{
|
||||
uint32_t leftOfDecimal = (uint32_t)atol(term);
|
||||
uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
|
||||
uint32_t multiplier = 10000000UL;
|
||||
uint32_t tenMillionthsOfMinutes = minutes * multiplier;
|
||||
|
||||
deg.deg = (int16_t)(leftOfDecimal / 100);
|
||||
|
||||
while (isdigit(*term))
|
||||
++term;
|
||||
|
||||
if (*term == '.')
|
||||
while (isdigit(*++term))
|
||||
{
|
||||
multiplier /= 10;
|
||||
tenMillionthsOfMinutes += (*term - '0') * multiplier;
|
||||
}
|
||||
|
||||
deg.billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
|
||||
deg.negative = false;
|
||||
}
|
||||
|
||||
#define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
|
||||
|
||||
// Processes a just-completed term
|
||||
// Returns true if new sentence has just passed checksum test and is validated
|
||||
bool TinyGPSPlus::endOfTermHandler()
|
||||
{
|
||||
// If it's the checksum term, and the checksum checks out, commit
|
||||
if (isChecksumTerm)
|
||||
{
|
||||
uint8_t checksum = 16 * fromHex(term[0]) + fromHex(term[1]);
|
||||
if (checksum == parity)
|
||||
{
|
||||
passedChecksumCount++;
|
||||
if (sentenceHasFix)
|
||||
++sentencesWithFixCount;
|
||||
|
||||
switch(curSentenceType)
|
||||
{
|
||||
case GPS_SENTENCE_RMC:
|
||||
date.commit();
|
||||
time.commit();
|
||||
if (sentenceHasFix)
|
||||
{
|
||||
location.commit();
|
||||
speed.commit();
|
||||
course.commit();
|
||||
}
|
||||
break;
|
||||
case GPS_SENTENCE_GGA:
|
||||
time.commit();
|
||||
if (sentenceHasFix)
|
||||
{
|
||||
location.commit();
|
||||
altitude.commit();
|
||||
}
|
||||
satellites.commit();
|
||||
hdop.commit();
|
||||
break;
|
||||
}
|
||||
|
||||
// Commit all custom listeners of this sentence type
|
||||
for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0; p = p->next)
|
||||
p->commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
++failedChecksumCount;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// the first term determines the sentence type
|
||||
if (curTermNumber == 0)
|
||||
{
|
||||
if (term[0] == 'G' && strchr("PNABL", term[1]) != NULL && !strcmp(term + 2, _RMCterm))
|
||||
curSentenceType = GPS_SENTENCE_RMC;
|
||||
else if (term[0] == 'G' && strchr("PNABL", term[1]) != NULL && !strcmp(term + 2, _GGAterm))
|
||||
curSentenceType = GPS_SENTENCE_GGA;
|
||||
else
|
||||
curSentenceType = GPS_SENTENCE_OTHER;
|
||||
|
||||
// Any custom candidates of this sentence type?
|
||||
for (customCandidates = customElts; customCandidates != NULL && strcmp(customCandidates->sentenceName, term) < 0; customCandidates = customCandidates->next);
|
||||
if (customCandidates != NULL && strcmp(customCandidates->sentenceName, term) > 0)
|
||||
customCandidates = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (curSentenceType != GPS_SENTENCE_OTHER && term[0])
|
||||
switch(COMBINE(curSentenceType, curTermNumber))
|
||||
{
|
||||
case COMBINE(GPS_SENTENCE_RMC, 1): // Time in both sentences
|
||||
case COMBINE(GPS_SENTENCE_GGA, 1):
|
||||
time.setTime(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 2): // RMC validity
|
||||
sentenceHasFix = term[0] == 'A';
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 3): // Latitude
|
||||
case COMBINE(GPS_SENTENCE_GGA, 2):
|
||||
location.setLatitude(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 4): // N/S
|
||||
case COMBINE(GPS_SENTENCE_GGA, 3):
|
||||
location.rawNewLatData.negative = term[0] == 'S';
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 5): // Longitude
|
||||
case COMBINE(GPS_SENTENCE_GGA, 4):
|
||||
location.setLongitude(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 6): // E/W
|
||||
case COMBINE(GPS_SENTENCE_GGA, 5):
|
||||
location.rawNewLngData.negative = term[0] == 'W';
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 7): // Speed (RMC)
|
||||
speed.set(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 8): // Course (RMC)
|
||||
course.set(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 9): // Date (RMC)
|
||||
date.setDate(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_GGA, 6): // Fix data (GGA)
|
||||
sentenceHasFix = term[0] > '0';
|
||||
location.newFixQuality = (TinyGPSLocation::Quality)term[0];
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_GGA, 7): // Satellites used (GGA)
|
||||
satellites.set(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_GGA, 8): // HDOP
|
||||
hdop.set(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_GGA, 9): // Altitude (GGA)
|
||||
altitude.set(term);
|
||||
break;
|
||||
case COMBINE(GPS_SENTENCE_RMC, 12):
|
||||
location.newFixMode = (TinyGPSLocation::Mode)term[0];
|
||||
break;
|
||||
}
|
||||
|
||||
// Set custom values as needed
|
||||
for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber; p = p->next)
|
||||
if (p->termNumber == curTermNumber)
|
||||
p->set(term);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
double TinyGPSPlus::distanceBetween(double lat1, double long1, double lat2, double long2)
|
||||
{
|
||||
// returns distance in meters between two positions, both specified
|
||||
// as signed decimal-degrees latitude and longitude. Uses great-circle
|
||||
// distance computation for hypothetical sphere of radius 6371009 meters.
|
||||
// Because Earth is no exact sphere, rounding errors may be up to 0.5%.
|
||||
// Courtesy of Maarten Lamers
|
||||
double delta = (long1-long2)* (PI / 180);
|
||||
double sdlong = sin(delta);
|
||||
double cdlong = cos(delta);
|
||||
lat1 = (lat1)* (PI / 180);
|
||||
lat2 = (lat2)* (PI / 180);
|
||||
double slat1 = sin(lat1);
|
||||
double clat1 = cos(lat1);
|
||||
double slat2 = sin(lat2);
|
||||
double clat2 = cos(lat2);
|
||||
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
|
||||
delta = delta*delta;
|
||||
delta += (clat2 * sdlong)*(clat2 * sdlong);
|
||||
delta = sqrt(delta);
|
||||
double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
|
||||
delta = atan2(delta, denom);
|
||||
return delta * _GPS_EARTH_MEAN_RADIUS;
|
||||
}
|
||||
|
||||
double TinyGPSPlus::courseTo(double lat1, double long1, double lat2, double long2)
|
||||
{
|
||||
// returns course in degrees (North=0, West=270) from position 1 to position 2,
|
||||
// both specified as signed decimal-degrees latitude and longitude.
|
||||
// Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
|
||||
// Courtesy of Maarten Lamers
|
||||
double dlon = (PI/180)*(long2-long1);
|
||||
lat1 = (PI/180)*(lat1);
|
||||
lat2 = (PI/180)*(lat2);
|
||||
double a1 = sin(dlon) * cos(lat2);
|
||||
double a2 = sin(lat1) * cos(lat2) * cos(dlon);
|
||||
a2 = cos(lat1) * sin(lat2) - a2;
|
||||
a2 = atan2(a1, a2);
|
||||
if (a2 < 0.0)
|
||||
{
|
||||
a2 += TWO_PI;
|
||||
}
|
||||
return 180/PI*(a2);
|
||||
}
|
||||
|
||||
const char *TinyGPSPlus::cardinal(double course)
|
||||
{
|
||||
static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
|
||||
int direction = (int)((course + 11.25f) / 22.5f);
|
||||
return directions[direction % 16];
|
||||
}
|
||||
|
||||
void TinyGPSLocation::commit()
|
||||
{
|
||||
rawLatData = rawNewLatData;
|
||||
rawLngData = rawNewLngData;
|
||||
fixQuality = newFixQuality;
|
||||
fixMode = newFixMode;
|
||||
lastCommitTime = HAL_GetTick();
|
||||
valid = updated = true;
|
||||
}
|
||||
|
||||
void TinyGPSLocation::setLatitude(const char *term)
|
||||
{
|
||||
TinyGPSPlus::parseDegrees(term, rawNewLatData);
|
||||
}
|
||||
|
||||
void TinyGPSLocation::setLongitude(const char *term)
|
||||
{
|
||||
TinyGPSPlus::parseDegrees(term, rawNewLngData);
|
||||
}
|
||||
|
||||
double TinyGPSLocation::lat()
|
||||
{
|
||||
updated = false;
|
||||
double ret = rawLatData.deg + rawLatData.billionths / 1000000000.0;
|
||||
return rawLatData.negative ? -ret : ret;
|
||||
}
|
||||
|
||||
double TinyGPSLocation::lng()
|
||||
{
|
||||
updated = false;
|
||||
double ret = rawLngData.deg + rawLngData.billionths / 1000000000.0;
|
||||
return rawLngData.negative ? -ret : ret;
|
||||
}
|
||||
|
||||
void TinyGPSDate::commit()
|
||||
{
|
||||
date = newDate;
|
||||
lastCommitTime = HAL_GetTick();
|
||||
valid = updated = true;
|
||||
}
|
||||
|
||||
void TinyGPSTime::commit()
|
||||
{
|
||||
time = newTime;
|
||||
lastCommitTime = HAL_GetTick();
|
||||
valid = updated = true;
|
||||
}
|
||||
|
||||
void TinyGPSTime::setTime(const char *term)
|
||||
{
|
||||
newTime = (uint32_t)TinyGPSPlus::parseDecimal(term);
|
||||
}
|
||||
|
||||
void TinyGPSDate::setDate(const char *term)
|
||||
{
|
||||
newDate = atol(term);
|
||||
}
|
||||
|
||||
uint16_t TinyGPSDate::year()
|
||||
{
|
||||
updated = false;
|
||||
uint16_t year = date % 100;
|
||||
return year + 2000;
|
||||
}
|
||||
|
||||
uint8_t TinyGPSDate::month()
|
||||
{
|
||||
updated = false;
|
||||
return (date / 100) % 100;
|
||||
}
|
||||
|
||||
uint8_t TinyGPSDate::day()
|
||||
{
|
||||
updated = false;
|
||||
return date / 10000;
|
||||
}
|
||||
|
||||
uint8_t TinyGPSTime::hour()
|
||||
{
|
||||
updated = false;
|
||||
return time / 1000000;
|
||||
}
|
||||
|
||||
uint8_t TinyGPSTime::minute()
|
||||
{
|
||||
updated = false;
|
||||
return (time / 10000) % 100;
|
||||
}
|
||||
|
||||
uint8_t TinyGPSTime::second()
|
||||
{
|
||||
updated = false;
|
||||
return (time / 100) % 100;
|
||||
}
|
||||
|
||||
uint8_t TinyGPSTime::centisecond()
|
||||
{
|
||||
updated = false;
|
||||
return time % 100;
|
||||
}
|
||||
|
||||
void TinyGPSDecimal::commit()
|
||||
{
|
||||
val = newval;
|
||||
lastCommitTime = HAL_GetTick();
|
||||
valid = updated = true;
|
||||
}
|
||||
|
||||
void TinyGPSDecimal::set(const char *term)
|
||||
{
|
||||
newval = TinyGPSPlus::parseDecimal(term);
|
||||
}
|
||||
|
||||
void TinyGPSInteger::commit()
|
||||
{
|
||||
val = newval;
|
||||
lastCommitTime = HAL_GetTick();
|
||||
valid = updated = true;
|
||||
}
|
||||
|
||||
void TinyGPSInteger::set(const char *term)
|
||||
{
|
||||
newval = atol(term);
|
||||
}
|
||||
|
||||
TinyGPSCustom::TinyGPSCustom(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
|
||||
{
|
||||
begin(gps, _sentenceName, _termNumber);
|
||||
}
|
||||
|
||||
void TinyGPSCustom::begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
|
||||
{
|
||||
lastCommitTime = 0;
|
||||
updated = valid = false;
|
||||
sentenceName = _sentenceName;
|
||||
termNumber = _termNumber;
|
||||
memset(stagingBuffer, '\0', sizeof(stagingBuffer));
|
||||
memset(buffer, '\0', sizeof(buffer));
|
||||
|
||||
// Insert this item into the GPS tree
|
||||
gps.insertCustom(this, _sentenceName, _termNumber);
|
||||
}
|
||||
|
||||
void TinyGPSCustom::commit()
|
||||
{
|
||||
strcpy(this->buffer, this->stagingBuffer);
|
||||
lastCommitTime = HAL_GetTick();
|
||||
valid = updated = true;
|
||||
}
|
||||
|
||||
void TinyGPSCustom::set(const char *term)
|
||||
{
|
||||
strncpy(this->stagingBuffer, term, sizeof(this->stagingBuffer) - 1);
|
||||
}
|
||||
|
||||
void TinyGPSPlus::insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int termNumber)
|
||||
{
|
||||
TinyGPSCustom **ppelt;
|
||||
|
||||
for (ppelt = &this->customElts; *ppelt != NULL; ppelt = &(*ppelt)->next)
|
||||
{
|
||||
int cmp = strcmp(sentenceName, (*ppelt)->sentenceName);
|
||||
if (cmp < 0 || (cmp == 0 && termNumber < (*ppelt)->termNumber))
|
||||
break;
|
||||
}
|
||||
|
||||
pElt->next = *ppelt;
|
||||
*ppelt = pElt;
|
||||
}
|
||||
289
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/TinyGPS++.h
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
|
||||
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
|
||||
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
|
||||
Location precision improvements suggested by Wayne Holder.
|
||||
Copyright (C) 2008-2024 Mikal Hart
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __TinyGPSPlus_h
|
||||
#define __TinyGPSPlus_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include "stm32f7xx_hal.h"
|
||||
|
||||
|
||||
#define _GPS_VERSION "1.1.0" // software version of this library
|
||||
#define _GPS_MPH_PER_KNOT 1.15077945
|
||||
#define _GPS_MPS_PER_KNOT 0.51444444
|
||||
#define _GPS_KMPH_PER_KNOT 1.852
|
||||
#define _GPS_MILES_PER_METER 0.00062137112
|
||||
#define _GPS_KM_PER_METER 0.001
|
||||
#define _GPS_FEET_PER_METER 3.2808399
|
||||
#define _GPS_MAX_FIELD_SIZE 15
|
||||
#define _GPS_EARTH_MEAN_RADIUS 6371009 // old: 6372795
|
||||
|
||||
#define PI 3.14159265359
|
||||
#define TWO_PI 6.28318530718
|
||||
|
||||
struct RawDegrees
|
||||
{
|
||||
uint16_t deg;
|
||||
uint32_t billionths;
|
||||
bool negative;
|
||||
public:
|
||||
RawDegrees() : deg(0), billionths(0), negative(false)
|
||||
{}
|
||||
};
|
||||
|
||||
struct TinyGPSLocation
|
||||
{
|
||||
friend class TinyGPSPlus;
|
||||
public:
|
||||
enum Quality { Invalid = '0', GPS = '1', DGPS = '2', PPS = '3', RTK = '4', FloatRTK = '5', Estimated = '6', Manual = '7', Simulated = '8' };
|
||||
enum Mode { N = 'N', A = 'A', D = 'D', E = 'E'};
|
||||
|
||||
bool isValid() const { return valid; }
|
||||
bool isUpdated() const { return updated; }
|
||||
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
|
||||
const RawDegrees &rawLat() { updated = false; return rawLatData; }
|
||||
const RawDegrees &rawLng() { updated = false; return rawLngData; }
|
||||
double lat();
|
||||
double lng();
|
||||
Quality FixQuality() { updated = false; return fixQuality; }
|
||||
Mode FixMode() { updated = false; return fixMode; }
|
||||
|
||||
TinyGPSLocation() : valid(false), updated(false), fixQuality(Invalid), fixMode(N)
|
||||
{}
|
||||
|
||||
private:
|
||||
bool valid, updated;
|
||||
RawDegrees rawLatData, rawLngData, rawNewLatData, rawNewLngData;
|
||||
Quality fixQuality, newFixQuality;
|
||||
Mode fixMode, newFixMode;
|
||||
uint32_t lastCommitTime;
|
||||
void commit();
|
||||
void setLatitude(const char *term);
|
||||
void setLongitude(const char *term);
|
||||
};
|
||||
|
||||
struct TinyGPSDate
|
||||
{
|
||||
friend class TinyGPSPlus;
|
||||
public:
|
||||
bool isValid() const { return valid; }
|
||||
bool isUpdated() const { return updated; }
|
||||
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
|
||||
|
||||
uint32_t value() { updated = false; return date; }
|
||||
uint16_t year();
|
||||
uint8_t month();
|
||||
uint8_t day();
|
||||
|
||||
TinyGPSDate() : valid(false), updated(false), date(0)
|
||||
{}
|
||||
|
||||
private:
|
||||
bool valid, updated;
|
||||
uint32_t date, newDate;
|
||||
uint32_t lastCommitTime;
|
||||
void commit();
|
||||
void setDate(const char *term);
|
||||
};
|
||||
|
||||
struct TinyGPSTime
|
||||
{
|
||||
friend class TinyGPSPlus;
|
||||
public:
|
||||
bool isValid() const { return valid; }
|
||||
bool isUpdated() const { return updated; }
|
||||
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
|
||||
|
||||
uint32_t value() { updated = false; return time; }
|
||||
uint8_t hour();
|
||||
uint8_t minute();
|
||||
uint8_t second();
|
||||
uint8_t centisecond();
|
||||
|
||||
TinyGPSTime() : valid(false), updated(false), time(0)
|
||||
{}
|
||||
|
||||
private:
|
||||
bool valid, updated;
|
||||
uint32_t time, newTime;
|
||||
uint32_t lastCommitTime;
|
||||
void commit();
|
||||
void setTime(const char *term);
|
||||
};
|
||||
|
||||
struct TinyGPSDecimal
|
||||
{
|
||||
friend class TinyGPSPlus;
|
||||
public:
|
||||
bool isValid() const { return valid; }
|
||||
bool isUpdated() const { return updated; }
|
||||
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
|
||||
int32_t value() { updated = false; return val; }
|
||||
|
||||
TinyGPSDecimal() : valid(false), updated(false), val(0)
|
||||
{}
|
||||
|
||||
private:
|
||||
bool valid, updated;
|
||||
uint32_t lastCommitTime;
|
||||
int32_t val, newval;
|
||||
void commit();
|
||||
void set(const char *term);
|
||||
};
|
||||
|
||||
struct TinyGPSInteger
|
||||
{
|
||||
friend class TinyGPSPlus;
|
||||
public:
|
||||
bool isValid() const { return valid; }
|
||||
bool isUpdated() const { return updated; }
|
||||
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
|
||||
uint32_t value() { updated = false; return val; }
|
||||
|
||||
TinyGPSInteger() : valid(false), updated(false), val(0)
|
||||
{}
|
||||
|
||||
private:
|
||||
bool valid, updated;
|
||||
uint32_t lastCommitTime;
|
||||
uint32_t val, newval;
|
||||
void commit();
|
||||
void set(const char *term);
|
||||
};
|
||||
|
||||
struct TinyGPSSpeed : TinyGPSDecimal
|
||||
{
|
||||
double knots() { return value() / 100.0; }
|
||||
double mph() { return _GPS_MPH_PER_KNOT * value() / 100.0; }
|
||||
double mps() { return _GPS_MPS_PER_KNOT * value() / 100.0; }
|
||||
double kmph() { return _GPS_KMPH_PER_KNOT * value() / 100.0; }
|
||||
};
|
||||
|
||||
struct TinyGPSCourse : public TinyGPSDecimal
|
||||
{
|
||||
double deg() { return value() / 100.0; }
|
||||
};
|
||||
|
||||
struct TinyGPSAltitude : TinyGPSDecimal
|
||||
{
|
||||
double meters() { return value() / 100.0; }
|
||||
double miles() { return _GPS_MILES_PER_METER * value() / 100.0; }
|
||||
double kilometers() { return _GPS_KM_PER_METER * value() / 100.0; }
|
||||
double feet() { return _GPS_FEET_PER_METER * value() / 100.0; }
|
||||
};
|
||||
|
||||
struct TinyGPSHDOP : TinyGPSDecimal
|
||||
{
|
||||
double hdop() { return value() / 100.0; }
|
||||
};
|
||||
|
||||
class TinyGPSPlus;
|
||||
class TinyGPSCustom
|
||||
{
|
||||
public:
|
||||
TinyGPSCustom() {};
|
||||
TinyGPSCustom(TinyGPSPlus &gps, const char *sentenceName, int termNumber);
|
||||
void begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber);
|
||||
|
||||
bool isUpdated() const { return updated; }
|
||||
bool isValid() const { return valid; }
|
||||
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
|
||||
const char *value() { updated = false; return buffer; }
|
||||
|
||||
private:
|
||||
void commit();
|
||||
void set(const char *term);
|
||||
|
||||
char stagingBuffer[_GPS_MAX_FIELD_SIZE + 1];
|
||||
char buffer[_GPS_MAX_FIELD_SIZE + 1];
|
||||
unsigned long lastCommitTime;
|
||||
bool valid, updated;
|
||||
const char *sentenceName;
|
||||
int termNumber;
|
||||
friend class TinyGPSPlus;
|
||||
TinyGPSCustom *next;
|
||||
};
|
||||
|
||||
class TinyGPSPlus
|
||||
{
|
||||
public:
|
||||
TinyGPSPlus();
|
||||
bool encode(char c); // process one character received from GPS
|
||||
TinyGPSPlus &operator << (char c) {encode(c); return *this;}
|
||||
|
||||
TinyGPSLocation location;
|
||||
TinyGPSDate date;
|
||||
TinyGPSTime time;
|
||||
TinyGPSSpeed speed;
|
||||
TinyGPSCourse course;
|
||||
TinyGPSAltitude altitude;
|
||||
TinyGPSInteger satellites;
|
||||
TinyGPSHDOP hdop;
|
||||
|
||||
static const char *libraryVersion() { return _GPS_VERSION; }
|
||||
|
||||
static double distanceBetween(double lat1, double long1, double lat2, double long2);
|
||||
static double courseTo(double lat1, double long1, double lat2, double long2);
|
||||
static const char *cardinal(double course);
|
||||
|
||||
static int32_t parseDecimal(const char *term);
|
||||
static void parseDegrees(const char *term, RawDegrees °);
|
||||
|
||||
uint32_t charsProcessed() const { return encodedCharCount; }
|
||||
uint32_t sentencesWithFix() const { return sentencesWithFixCount; }
|
||||
uint32_t failedChecksum() const { return failedChecksumCount; }
|
||||
uint32_t passedChecksum() const { return passedChecksumCount; }
|
||||
|
||||
private:
|
||||
enum {GPS_SENTENCE_GGA, GPS_SENTENCE_RMC, GPS_SENTENCE_OTHER};
|
||||
|
||||
// parsing state variables
|
||||
uint8_t parity;
|
||||
bool isChecksumTerm;
|
||||
char term[_GPS_MAX_FIELD_SIZE];
|
||||
uint8_t curSentenceType;
|
||||
uint8_t curTermNumber;
|
||||
uint8_t curTermOffset;
|
||||
bool sentenceHasFix;
|
||||
|
||||
// custom element support
|
||||
friend class TinyGPSCustom;
|
||||
TinyGPSCustom *customElts;
|
||||
TinyGPSCustom *customCandidates;
|
||||
void insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int index);
|
||||
|
||||
// statistics
|
||||
uint32_t encodedCharCount;
|
||||
uint32_t sentencesWithFixCount;
|
||||
uint32_t failedChecksumCount;
|
||||
uint32_t passedChecksumCount;
|
||||
|
||||
// internal utilities
|
||||
int fromHex(char a);
|
||||
bool endOfTermHandler();
|
||||
};
|
||||
|
||||
#endif // def(__TinyGPSPlus_h)
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
TinyGPSPlus - a small GPS library for Arduino providing universal NMEA parsing
|
||||
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
|
||||
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
|
||||
Location precision improvements suggested by Wayne Holder.
|
||||
Copyright (C) 2008-2024 Mikal Hart
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __TinyGPSPlus_h
|
||||
#include "TinyGPS++.h"
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "USBHandler.h"
|
||||
#include "diag_log.h"
|
||||
#include <cstring>
|
||||
|
||||
USBHandler::USBHandler() {
|
||||
DIAG("USB", "USBHandler constructed, calling reset()");
|
||||
reset();
|
||||
}
|
||||
|
||||
void USBHandler::reset() {
|
||||
DIAG("USB", "USBHandler::reset(): state -> WAITING_FOR_START");
|
||||
current_state = USBState::WAITING_FOR_START;
|
||||
start_flag_received = false;
|
||||
buffer_index = 0;
|
||||
current_settings.resetToDefaults();
|
||||
}
|
||||
|
||||
void USBHandler::processUSBData(const uint8_t* data, uint32_t length) {
|
||||
if (data == nullptr || length == 0) {
|
||||
DIAG_WARN("USB", "processUSBData: null/empty data");
|
||||
return;
|
||||
}
|
||||
|
||||
DIAG("USB", "processUSBData: %lu bytes, state=%d", (unsigned long)length, (int)current_state);
|
||||
|
||||
switch (current_state) {
|
||||
case USBState::WAITING_FOR_START:
|
||||
processStartFlag(data, length);
|
||||
break;
|
||||
|
||||
case USBState::RECEIVING_SETTINGS:
|
||||
processSettingsData(data, length);
|
||||
break;
|
||||
|
||||
case USBState::READY_FOR_DATA:
|
||||
// Ready to receive radar data commands
|
||||
DIAG("USB", " READY_FOR_DATA: ignoring %lu bytes", (unsigned long)length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void USBHandler::processStartFlag(const uint8_t* data, uint32_t length) {
|
||||
// Start flag: bytes [23, 46, 158, 237]
|
||||
const uint8_t START_FLAG[] = {23, 46, 158, 237};
|
||||
|
||||
// Guard: need at least 4 bytes to contain a start flag.
|
||||
// Without this, length - 4 wraps to ~4 billion (uint32_t unsigned underflow)
|
||||
// and the loop reads far past the buffer boundary.
|
||||
if (length < 4) return;
|
||||
|
||||
// Check if start flag is in the received data
|
||||
for (uint32_t i = 0; i <= length - 4; i++) {
|
||||
if (memcmp(data + i, START_FLAG, 4) == 0) {
|
||||
start_flag_received = true;
|
||||
current_state = USBState::RECEIVING_SETTINGS;
|
||||
buffer_index = 0; // Reset buffer for settings data
|
||||
DIAG("USB", "START FLAG found at offset %lu, state -> RECEIVING_SETTINGS", (unsigned long)i);
|
||||
|
||||
// If there's more data after the start flag, process it
|
||||
if (length > i + 4) {
|
||||
DIAG("USB", " %lu trailing bytes after start flag, forwarding to settings parser", (unsigned long)(length - i - 4));
|
||||
processSettingsData(data + i + 4, length - i - 4);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
DIAG("USB", " no start flag in %lu bytes", (unsigned long)length);
|
||||
}
|
||||
|
||||
void USBHandler::processSettingsData(const uint8_t* data, uint32_t length) {
|
||||
// Add data to buffer
|
||||
uint32_t bytes_to_copy = (length < (MAX_BUFFER_SIZE - buffer_index)) ?
|
||||
length : (MAX_BUFFER_SIZE - buffer_index);
|
||||
|
||||
memcpy(usb_buffer + buffer_index, data, bytes_to_copy);
|
||||
buffer_index += bytes_to_copy;
|
||||
DIAG("USB", " settings buffer: +%lu bytes, total=%lu/%u", (unsigned long)bytes_to_copy, (unsigned long)buffer_index, MAX_BUFFER_SIZE);
|
||||
|
||||
// Check if we have a complete settings packet (contains "SET" and "END")
|
||||
if (buffer_index >= 74) { // Minimum size for valid settings packet
|
||||
// Look for "SET" at beginning and "END" somewhere in the packet
|
||||
bool has_set = (memcmp(usb_buffer, "SET", 3) == 0);
|
||||
bool has_end = false;
|
||||
|
||||
DIAG_BOOL("USB", " packet starts with SET", has_set);
|
||||
|
||||
for (uint32_t i = 3; i <= buffer_index - 3; i++) {
|
||||
if (memcmp(usb_buffer + i, "END", 3) == 0) {
|
||||
has_end = true;
|
||||
DIAG("USB", " END marker found at offset %lu, packet_len=%lu", (unsigned long)i, (unsigned long)(i + 3));
|
||||
|
||||
// Parse the complete packet up to "END"
|
||||
if (has_set && current_settings.parseFromUSB(usb_buffer, i + 3)) {
|
||||
current_state = USBState::READY_FOR_DATA;
|
||||
DIAG("USB", " Settings parsed OK, state -> READY_FOR_DATA");
|
||||
} else {
|
||||
DIAG_ERR("USB", " Settings parse FAILED (has_set=%d)", has_set);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find a valid packet but buffer is full, reset
|
||||
if (buffer_index >= MAX_BUFFER_SIZE && !has_end) {
|
||||
DIAG_WARN("USB", " Buffer full (%u) without END marker -- resetting", MAX_BUFFER_SIZE);
|
||||
buffer_index = 0; // Reset buffer to avoid overflow
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef USBHANDLER_H
|
||||
#define USBHANDLER_H
|
||||
|
||||
#include "RadarSettings.h"
|
||||
#include <cstdint>
|
||||
|
||||
class USBHandler {
|
||||
public:
|
||||
enum class USBState {
|
||||
WAITING_FOR_START,
|
||||
RECEIVING_SETTINGS,
|
||||
READY_FOR_DATA
|
||||
};
|
||||
|
||||
USBHandler();
|
||||
|
||||
// Process incoming USB data
|
||||
void processUSBData(const uint8_t* data, uint32_t length);
|
||||
|
||||
// Check if start flag was received
|
||||
bool isStartFlagReceived() const { return start_flag_received; }
|
||||
|
||||
// Get current settings
|
||||
const RadarSettings& getSettings() const { return current_settings; }
|
||||
|
||||
// Get current state
|
||||
USBState getState() const { return current_state; }
|
||||
|
||||
// Reset USB handler
|
||||
void reset();
|
||||
|
||||
private:
|
||||
RadarSettings current_settings;
|
||||
USBState current_state;
|
||||
bool start_flag_received;
|
||||
|
||||
// Buffer for accumulating USB data
|
||||
static constexpr uint32_t MAX_BUFFER_SIZE = 256;
|
||||
uint8_t usb_buffer[MAX_BUFFER_SIZE];
|
||||
uint32_t buffer_index;
|
||||
|
||||
void processStartFlag(const uint8_t* data, uint32_t length);
|
||||
void processSettingsData(const uint8_t* data, uint32_t length);
|
||||
};
|
||||
|
||||
#endif // USBHANDLER_H
|
||||
731
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ad9523.c
Normal file
@@ -0,0 +1,731 @@
|
||||
/***************************************************************************//**
|
||||
* @file AD9523.c
|
||||
* @brief Implementation of AD9523 Driver.
|
||||
* @author ACozma(andrei.cozma@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2012-2016(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "ad9523.h"
|
||||
#include "no_os_alloc.h"
|
||||
|
||||
/* Helpers to avoid excess line breaks */
|
||||
#define AD_IFE(_pde, _a, _b) ((dev->pdata->_pde) ? _a : _b)
|
||||
#define AD_IF(_pde, _a) AD_IFE(_pde, _a, 0)
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Reads the value of the selected register.
|
||||
*
|
||||
* @param dev - The device structure.
|
||||
* @param reg_addr - The address of the register to read.
|
||||
* @param reg_data - Pointer to the read value.
|
||||
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_spi_read(struct ad9523_dev *dev,
|
||||
uint32_t reg_addr,
|
||||
uint32_t *reg_data)
|
||||
{
|
||||
uint8_t buf[3];
|
||||
|
||||
int32_t ret = 0;
|
||||
uint8_t index;
|
||||
|
||||
*reg_data = 0;
|
||||
for (index = 0; index < AD9523_TRANSF_LEN(reg_addr); index++) {
|
||||
buf[0] = 0x80 | (reg_addr >> 8);
|
||||
buf[1] = reg_addr & 0xFF;
|
||||
buf[2] = 0x00;
|
||||
ret |= no_os_spi_write_and_read(dev->spi_desc,
|
||||
buf,
|
||||
3);
|
||||
reg_addr--;
|
||||
*reg_data <<= 8;
|
||||
*reg_data |= buf[2];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Writes a value to the selected register.
|
||||
*
|
||||
* @param dev - The device structure.
|
||||
* @param reg_addr - The address of the register to write to.
|
||||
* @param reg_data - The value to write to the register.
|
||||
*
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_spi_write(struct ad9523_dev *dev,
|
||||
uint32_t reg_addr,
|
||||
uint32_t reg_data)
|
||||
{
|
||||
uint8_t buf[3];
|
||||
|
||||
int32_t ret = 0;
|
||||
uint8_t index;
|
||||
|
||||
for (index = 0; index < AD9523_TRANSF_LEN(reg_addr); index++) {
|
||||
buf[0] = reg_addr >> 8;
|
||||
buf[1] = reg_addr & 0xFF;
|
||||
buf[2] = (reg_data >> ((AD9523_TRANSF_LEN(reg_addr) - index - 1) * 8)) & 0xFF;
|
||||
ret |= no_os_spi_write_and_read(dev->spi_desc,
|
||||
buf,
|
||||
3);
|
||||
reg_addr--;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Updates the AD9523 configuration
|
||||
*
|
||||
* @param dev - The device structure.
|
||||
*
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_io_update(struct ad9523_dev *dev)
|
||||
{
|
||||
return ad9523_spi_write(dev,
|
||||
AD9523_IO_UPDATE,
|
||||
AD9523_IO_UPDATE_EN);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Sets the clock provider for selected channel.
|
||||
*
|
||||
* @param dev - The device structure.
|
||||
* @param ch - Selected channel.
|
||||
* @param out - Selected clock provider.
|
||||
*
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_vco_out_map(struct ad9523_dev *dev,
|
||||
uint32_t ch,
|
||||
uint32_t out)
|
||||
{
|
||||
int32_t ret;
|
||||
uint32_t mask;
|
||||
uint32_t reg_data;
|
||||
|
||||
switch (ch) {
|
||||
case 0 ... 3:
|
||||
ret = ad9523_spi_read(dev,
|
||||
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
|
||||
®_data);
|
||||
if (ret < 0)
|
||||
break;
|
||||
mask = AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH0 << ch;
|
||||
if (out) {
|
||||
reg_data |= mask;
|
||||
out = AD9523_VCXO;
|
||||
} else {
|
||||
reg_data &= ~mask;
|
||||
}
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
|
||||
reg_data);
|
||||
break;
|
||||
case 4 ... 6:
|
||||
ret = ad9523_spi_read(dev,
|
||||
AD9523_PLL1_OUTPUT_CTRL,
|
||||
®_data);
|
||||
if (ret < 0)
|
||||
break;
|
||||
mask = AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH4_M2 << (ch - 4);
|
||||
if (out)
|
||||
reg_data |= mask;
|
||||
else
|
||||
reg_data &= ~mask;
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_OUTPUT_CTRL,
|
||||
reg_data);
|
||||
break;
|
||||
case 7 ... 9:
|
||||
ret = ad9523_spi_read(dev,
|
||||
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
|
||||
®_data);
|
||||
if (ret < 0)
|
||||
break;
|
||||
mask = AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH7_M2 << (ch - 7);
|
||||
if (out)
|
||||
reg_data |= mask;
|
||||
else
|
||||
reg_data &= ~mask;
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
|
||||
reg_data);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->ad9523_st.vco_out_map[ch] = out;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Updates the AD9523 configuration.
|
||||
*
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
|
||||
// vco calibration on default setup may not work (as it is a buffered write)
|
||||
// calibration requires all registers to be written (not in hold registers) first.
|
||||
|
||||
int32_t ad9523_calibrate(struct ad9523_dev *dev)
|
||||
{
|
||||
uint32_t reg_data;
|
||||
uint32_t timeout;
|
||||
|
||||
ad9523_spi_write(dev,
|
||||
AD9523_PLL2_VCO_CTRL,
|
||||
AD9523_PLL2_VCO_CALIBRATE);
|
||||
ad9523_io_update(dev);
|
||||
|
||||
timeout = 0;
|
||||
while (timeout < 100) {
|
||||
no_os_mdelay(1);
|
||||
timeout = timeout + 1;
|
||||
ad9523_spi_read(dev,
|
||||
AD9523_READBACK_1,
|
||||
®_data);
|
||||
if ((reg_data & 0x1) == 0x0)
|
||||
break;
|
||||
}
|
||||
ad9523_spi_read(dev,
|
||||
AD9523_READBACK_1,
|
||||
®_data);
|
||||
if ((reg_data & 0x1) != 0x0) {
|
||||
printf("AD9523: VCO calibration failed (%#06lx)!\n", reg_data);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Updates the AD9523 configuration.
|
||||
*
|
||||
* @param dev - The device structure.
|
||||
*
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
|
||||
// status
|
||||
// calibration requires all registers to be written (not in hold registers) first.
|
||||
|
||||
int32_t ad9523_status(struct ad9523_dev *dev)
|
||||
{
|
||||
int32_t ret;
|
||||
uint32_t reg_data;
|
||||
uint32_t status;
|
||||
uint32_t timeout;
|
||||
|
||||
status = 0;
|
||||
|
||||
// vcxo + pll2 must always be okay- (is it not?)
|
||||
|
||||
status = status | AD9523_READBACK_0_STAT_VCXO;
|
||||
status = status | AD9523_READBACK_0_STAT_PLL2_LD;
|
||||
|
||||
if (dev->pdata->pll1_bypass_en == 0) {
|
||||
status = status | AD9523_READBACK_0_STAT_PLL2_REF_CLK;
|
||||
status = status | AD9523_READBACK_0_STAT_PLL2_FB_CLK;
|
||||
status = status | AD9523_READBACK_0_STAT_REF_TEST;
|
||||
status = status | AD9523_READBACK_0_STAT_REFB;
|
||||
status = status | AD9523_READBACK_0_STAT_REFA;
|
||||
status = status | AD9523_READBACK_0_STAT_PLL1_LD;
|
||||
}
|
||||
|
||||
timeout = 0;
|
||||
while (timeout < 100) {
|
||||
no_os_mdelay(1);
|
||||
timeout = timeout + 1;
|
||||
ad9523_spi_read(dev,
|
||||
AD9523_READBACK_0,
|
||||
®_data);
|
||||
if ((reg_data & status) == status)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if ((reg_data & AD9523_READBACK_0_STAT_VCXO) != AD9523_READBACK_0_STAT_VCXO) {
|
||||
printf("AD9523: VCXO status errors (%#06lx)!\n", reg_data);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if ((reg_data & AD9523_READBACK_0_STAT_PLL2_LD) !=
|
||||
AD9523_READBACK_0_STAT_PLL2_LD) {
|
||||
printf("AD9523: PLL2 NOT locked (%#06lx)!\n", reg_data);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Updates the AD9523 configuration.
|
||||
*
|
||||
* @param dev - The device structure.
|
||||
*
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_sync(struct ad9523_dev *dev)
|
||||
{
|
||||
int32_t ret, tmp;
|
||||
uint32_t reg_data;
|
||||
|
||||
ret = ad9523_spi_read(dev,
|
||||
AD9523_STATUS_SIGNALS,
|
||||
®_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tmp = reg_data;
|
||||
tmp |= AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_STATUS_SIGNALS,
|
||||
tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ad9523_io_update(dev);
|
||||
tmp &= ~AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_STATUS_SIGNALS,
|
||||
tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ad9523_io_update(dev);
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Initialize the AD9523 data structure with the default register values.
|
||||
*
|
||||
* @param init_param - The device initial parameters.
|
||||
*
|
||||
* @return Always return 0.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_init(struct ad9523_init_param *init_param)
|
||||
{
|
||||
|
||||
int32_t i = 0;
|
||||
|
||||
init_param->pdata->vcxo_freq = 0;
|
||||
init_param->pdata->spi3wire = 0;
|
||||
|
||||
/* Differential/ Single-Ended Input Configuration */
|
||||
init_param->pdata->refa_diff_rcv_en = 0;
|
||||
init_param->pdata->refb_diff_rcv_en = 0;
|
||||
init_param->pdata->zd_in_diff_en = 0;
|
||||
init_param->pdata->osc_in_diff_en = 0;
|
||||
|
||||
/*
|
||||
* Valid if differential input disabled
|
||||
* if not true defaults to pos input
|
||||
*/
|
||||
init_param->pdata->refa_cmos_neg_inp_en = 0;
|
||||
init_param->pdata->refb_cmos_neg_inp_en = 0;
|
||||
init_param->pdata->zd_in_cmos_neg_inp_en = 0;
|
||||
init_param->pdata->osc_in_cmos_neg_inp_en = 0;
|
||||
|
||||
/* PLL1 Setting */
|
||||
init_param->pdata->refa_r_div = 1;
|
||||
init_param->pdata->refb_r_div = 1;
|
||||
init_param->pdata->pll1_feedback_div = 1;
|
||||
init_param->pdata->pll1_charge_pump_current_nA = 0;
|
||||
init_param->pdata->zero_delay_mode_internal_en = 0;
|
||||
init_param->pdata->osc_in_feedback_en = 0;
|
||||
init_param->pdata->pll1_bypass_en = 1;
|
||||
init_param->pdata->pll1_loop_filter_rzero = 1;
|
||||
|
||||
/* Reference */
|
||||
init_param->pdata->ref_mode = 0;
|
||||
|
||||
/* PLL2 Setting */
|
||||
init_param->pdata->pll2_charge_pump_current_nA = 0;
|
||||
init_param->pdata->pll2_ndiv_a_cnt = 0;
|
||||
init_param->pdata->pll2_ndiv_b_cnt = 4;
|
||||
init_param->pdata->pll2_freq_doubler_en = 0;
|
||||
init_param->pdata->pll2_r2_div = 0;
|
||||
init_param->pdata->pll2_vco_diff_m1 = 0; /* 3..5 */
|
||||
init_param->pdata->pll2_vco_diff_m2 = 0; /* 3..5 */
|
||||
|
||||
/* Loop Filter PLL2 */
|
||||
init_param->pdata->rpole2 = 0;
|
||||
init_param->pdata->rzero = 0;
|
||||
init_param->pdata->cpole1 = 0;
|
||||
init_param->pdata->rzero_bypass_en = 0;
|
||||
|
||||
/* Output Channel Configuration */
|
||||
for (i = 0; i < init_param->pdata->num_channels; i++) {
|
||||
(&init_param->pdata->channels[i])->channel_num = 0;
|
||||
(&init_param->pdata->channels[i])->divider_output_invert_en = 0;
|
||||
(&init_param->pdata->channels[i])->sync_ignore_en = 0;
|
||||
(&init_param->pdata->channels[i])->low_power_mode_en = 0;
|
||||
(&init_param->pdata->channels[i])->use_alt_clock_src = 0;
|
||||
(&init_param->pdata->channels[i])->output_dis = 0;
|
||||
(&init_param->pdata->channels[i])->driver_mode = LVPECL_8mA;
|
||||
(&init_param->pdata->channels[i])->divider_phase = 0;
|
||||
(&init_param->pdata->channels[i])->channel_divider = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Setup the AD9523 device.
|
||||
*
|
||||
* @param device - The device structure.
|
||||
* @param init_param - The structure holding the device initial parameters.
|
||||
*
|
||||
* @return Returns 0 in case of success or negative error code.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_setup(struct ad9523_dev **device,
|
||||
const struct ad9523_init_param *init_param)
|
||||
|
||||
{
|
||||
struct ad9523_channel_spec *chan;
|
||||
uint32_t active_mask = 0;
|
||||
int32_t ret, i;
|
||||
uint32_t reg_data;
|
||||
uint32_t version_id;
|
||||
struct ad9523_dev *dev;
|
||||
|
||||
dev = (struct ad9523_dev *)no_os_malloc(sizeof(*dev));
|
||||
if (!dev)
|
||||
return -1;
|
||||
|
||||
/* SPI */
|
||||
ret = no_os_spi_init(&dev->spi_desc, &init_param->spi_init);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev->pdata = init_param->pdata;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_SERIAL_PORT_CONFIG,
|
||||
AD9523_SER_CONF_SOFT_RESET |
|
||||
(dev->pdata->spi3wire ? 0 :
|
||||
AD9523_SER_CONF_SDO_ACTIVE));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
no_os_mdelay(1);
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_READBACK_CTRL,
|
||||
AD9523_READBACK_CTRL_READ_BUFFERED);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_io_update(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_read(dev,
|
||||
AD9523_EEPROM_CUSTOMER_VERSION_ID,
|
||||
&version_id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_EEPROM_CUSTOMER_VERSION_ID,
|
||||
0xAD95);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_read(dev,
|
||||
AD9523_EEPROM_CUSTOMER_VERSION_ID,
|
||||
®_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (reg_data != 0xAD95) {
|
||||
printf("AD9523: SPI write-verify failed (%#06lX)!\n\r",
|
||||
reg_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_EEPROM_CUSTOMER_VERSION_ID,
|
||||
version_id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* PLL1 Setup
|
||||
*/
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_REF_A_DIVIDER,
|
||||
dev->pdata->refa_r_div);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_REF_B_DIVIDER,
|
||||
dev->pdata->refb_r_div);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_FEEDBACK_DIVIDER,
|
||||
dev->pdata->pll1_feedback_div);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_CHARGE_PUMP_CTRL,
|
||||
AD_IFE(pll1_bypass_en, AD9523_PLL1_CHARGE_PUMP_TRISTATE,
|
||||
AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(dev->pdata->
|
||||
pll1_charge_pump_current_nA) |
|
||||
AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL |
|
||||
AD9523_PLL1_BACKLASH_PW_MIN));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_INPUT_RECEIVERS_CTRL,
|
||||
AD_IFE(pll1_bypass_en, AD9523_PLL1_REFA_REFB_PWR_CTRL_EN |
|
||||
AD_IF(osc_in_diff_en, AD9523_PLL1_OSC_IN_DIFF_EN) |
|
||||
AD_IF(osc_in_cmos_neg_inp_en, AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN),
|
||||
AD_IF(refa_diff_rcv_en, AD9523_PLL1_REFA_RCV_EN) |
|
||||
AD_IF(refb_diff_rcv_en, AD9523_PLL1_REFB_RCV_EN) |
|
||||
AD_IF(osc_in_diff_en, AD9523_PLL1_OSC_IN_DIFF_EN) |
|
||||
AD_IF(osc_in_cmos_neg_inp_en,
|
||||
AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN) |
|
||||
AD_IF(refa_diff_rcv_en, AD9523_PLL1_REFA_DIFF_RCV_EN) |
|
||||
AD_IF(refb_diff_rcv_en, AD9523_PLL1_REFB_DIFF_RCV_EN)));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_REF_CTRL,
|
||||
AD_IFE(pll1_bypass_en, AD9523_PLL1_BYPASS_FEEDBACK_DIV_EN |
|
||||
AD9523_PLL1_ZERO_DELAY_MODE_INT,
|
||||
AD_IF(zd_in_diff_en, AD9523_PLL1_ZD_IN_DIFF_EN) |
|
||||
AD_IF(zd_in_cmos_neg_inp_en,
|
||||
AD9523_PLL1_ZD_IN_CMOS_NEG_INP_EN) |
|
||||
AD_IF(zero_delay_mode_internal_en,
|
||||
AD9523_PLL1_ZERO_DELAY_MODE_INT) |
|
||||
AD_IF(osc_in_feedback_en, AD9523_PLL1_OSC_IN_PLL_FEEDBACK_EN) |
|
||||
AD_IF(refa_cmos_neg_inp_en, AD9523_PLL1_REFA_CMOS_NEG_INP_EN) |
|
||||
AD_IF(refb_cmos_neg_inp_en, AD9523_PLL1_REFB_CMOS_NEG_INP_EN)));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_MISC_CTRL,
|
||||
AD9523_PLL1_REFB_INDEP_DIV_CTRL_EN |
|
||||
AD9523_PLL1_REF_MODE(dev->pdata->ref_mode));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL1_LOOP_FILTER_CTRL,
|
||||
AD9523_PLL1_LOOP_FILTER_RZERO(dev->pdata->
|
||||
pll1_loop_filter_rzero));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* PLL2 Setup
|
||||
*/
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL2_CHARGE_PUMP,
|
||||
AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(dev->pdata->
|
||||
pll2_charge_pump_current_nA));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL2_FEEDBACK_DIVIDER_AB,
|
||||
AD9523_PLL2_FB_NDIV_A_CNT(dev->pdata->pll2_ndiv_a_cnt) |
|
||||
AD9523_PLL2_FB_NDIV_B_CNT(dev->pdata->pll2_ndiv_b_cnt));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL2_CTRL,
|
||||
AD9523_PLL2_CHARGE_PUMP_MODE_NORMAL |
|
||||
AD9523_PLL2_BACKLASH_CTRL_EN |
|
||||
AD_IF(pll2_freq_doubler_en,
|
||||
AD9523_PLL2_FREQ_DOUBLER_EN));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev->ad9523_st.vco_freq = (dev->pdata->vcxo_freq *
|
||||
(dev->pdata->pll2_freq_doubler_en ? 2 : 1)
|
||||
/ dev->pdata->pll2_r2_div) * AD9523_PLL2_FB_NDIV(dev->pdata->
|
||||
pll2_ndiv_a_cnt,
|
||||
dev->pdata->
|
||||
pll2_ndiv_b_cnt);
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL2_VCO_CTRL,
|
||||
AD9523_PLL2_VCO_CALIBRATE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL2_VCO_DIVIDER,
|
||||
AD9523_PLL2_VCO_DIV_M1(dev->pdata->
|
||||
pll2_vco_diff_m1) |
|
||||
AD9523_PLL2_VCO_DIV_M2(dev->pdata->
|
||||
pll2_vco_diff_m2) |
|
||||
AD_IFE(pll2_vco_diff_m1,
|
||||
0,
|
||||
AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) |
|
||||
AD_IFE(pll2_vco_diff_m2,
|
||||
0,
|
||||
AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (dev->pdata->pll2_vco_diff_m1)
|
||||
dev->ad9523_st.vco_out_freq[AD9523_VCO1] =
|
||||
dev->ad9523_st.vco_freq / dev->pdata->pll2_vco_diff_m1;
|
||||
|
||||
if (dev->pdata->pll2_vco_diff_m2)
|
||||
dev->ad9523_st.vco_out_freq[AD9523_VCO2] =
|
||||
dev->ad9523_st.vco_freq / dev->pdata->pll2_vco_diff_m2;
|
||||
|
||||
dev->ad9523_st.vco_out_freq[AD9523_VCXO] = dev->pdata->vcxo_freq;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL2_R2_DIVIDER,
|
||||
AD9523_PLL2_R2_DIVIDER_VAL(dev->pdata->pll2_r2_div));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_PLL2_LOOP_FILTER_CTRL,
|
||||
AD9523_PLL2_LOOP_FILTER_CPOLE1(dev->pdata->cpole1) |
|
||||
AD9523_PLL2_LOOP_FILTER_RZERO(dev->pdata->rzero) |
|
||||
AD9523_PLL2_LOOP_FILTER_RPOLE2(dev->pdata->rpole2) |
|
||||
AD_IF(rzero_bypass_en,
|
||||
AD9523_PLL2_LOOP_FILTER_RZERO_BYPASS_EN));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < dev->pdata->num_channels; i++) {
|
||||
chan = &dev->pdata->channels[i];
|
||||
if (chan->channel_num < AD9523_NUM_CHAN) {
|
||||
active_mask |= (1 << chan->channel_num);
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_CHANNEL_CLOCK_DIST(chan->channel_num),
|
||||
AD9523_CLK_DIST_DRIVER_MODE(chan->driver_mode) |
|
||||
AD9523_CLK_DIST_DIV(chan->channel_divider) |
|
||||
AD9523_CLK_DIST_DIV_PHASE(chan->divider_phase) |
|
||||
(chan->sync_ignore_en ?
|
||||
AD9523_CLK_DIST_IGNORE_SYNC_EN : 0) |
|
||||
(chan->divider_output_invert_en ?
|
||||
AD9523_CLK_DIST_INV_DIV_OUTPUT_EN : 0) |
|
||||
(chan->low_power_mode_en ?
|
||||
AD9523_CLK_DIST_LOW_PWR_MODE_EN : 0) |
|
||||
(chan->output_dis ?
|
||||
AD9523_CLK_DIST_PWR_DOWN_EN : 0));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_vco_out_map(dev,
|
||||
chan->channel_num,
|
||||
chan->use_alt_clock_src);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < AD9523_NUM_CHAN; i++) {
|
||||
if (!(active_mask & (1 << i))) {
|
||||
ad9523_spi_write(dev,
|
||||
AD9523_CHANNEL_CLOCK_DIST(i),
|
||||
AD9523_CLK_DIST_DRIVER_MODE(TRISTATE) |
|
||||
AD9523_CLK_DIST_PWR_DOWN_EN);
|
||||
}
|
||||
}
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_POWER_DOWN_CTRL,
|
||||
0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_spi_write(dev,
|
||||
AD9523_STATUS_SIGNALS,
|
||||
AD9523_STATUS_MONITOR_01_PLL12_LOCKED);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_io_update(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad9523_sync(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ad9523_spi_write(dev,
|
||||
AD9523_READBACK_CTRL,
|
||||
0x0);
|
||||
ad9523_io_update(dev);
|
||||
ad9523_calibrate(dev);
|
||||
ad9523_sync(dev);
|
||||
|
||||
*device = dev;
|
||||
|
||||
return (ad9523_status(dev));
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Free the resources allocated by ad9523_setup().
|
||||
*
|
||||
* @param dev - The device structure.
|
||||
*
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*******************************************************************************/
|
||||
int32_t ad9523_remove(struct ad9523_dev *dev)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
ret = no_os_spi_remove(dev->spi_desc);
|
||||
|
||||
no_os_free(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
509
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/ad9523.h
Normal file
@@ -0,0 +1,509 @@
|
||||
/***************************************************************************//**
|
||||
* @file AD9523.h
|
||||
* @brief Header file of AD9523 Driver.
|
||||
* @author DBogdan (dragos.bogdan@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2012-2016(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
#ifndef _AD9523_H_
|
||||
#define _AD9523_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "no_os_delay.h"
|
||||
#include "no_os_spi.h"
|
||||
|
||||
/* Registers */
|
||||
|
||||
#define AD9523_READ (1 << 15)
|
||||
#define AD9523_WRITE (0 << 15)
|
||||
#define AD9523_CNT(x) (((x) - 1) << 13)
|
||||
#define AD9523_ADDR(x) ((x) & 0xFFF)
|
||||
|
||||
#define AD9523_R1B (1 << 16)
|
||||
#define AD9523_R2B (2 << 16)
|
||||
#define AD9523_R3B (3 << 16)
|
||||
#define AD9523_TRANSF_LEN(x) ((x) >> 16)
|
||||
|
||||
#define AD9523_SERIAL_PORT_CONFIG (AD9523_R1B | 0x0)
|
||||
#define AD9523_VERSION_REGISTER (AD9523_R1B | 0x2)
|
||||
#define AD9523_PART_REGISTER (AD9523_R1B | 0x3)
|
||||
#define AD9523_READBACK_CTRL (AD9523_R1B | 0x4)
|
||||
|
||||
#define AD9523_EEPROM_CUSTOMER_VERSION_ID (AD9523_R2B | 0x6)
|
||||
|
||||
#define AD9523_PLL1_REF_A_DIVIDER (AD9523_R2B | 0x11)
|
||||
#define AD9523_PLL1_REF_B_DIVIDER (AD9523_R2B | 0x13)
|
||||
#define AD9523_PLL1_REF_TEST_DIVIDER (AD9523_R1B | 0x14)
|
||||
#define AD9523_PLL1_FEEDBACK_DIVIDER (AD9523_R2B | 0x17)
|
||||
#define AD9523_PLL1_CHARGE_PUMP_CTRL (AD9523_R2B | 0x19)
|
||||
#define AD9523_PLL1_INPUT_RECEIVERS_CTRL (AD9523_R1B | 0x1A)
|
||||
#define AD9523_PLL1_REF_CTRL (AD9523_R1B | 0x1B)
|
||||
#define AD9523_PLL1_MISC_CTRL (AD9523_R1B | 0x1C)
|
||||
#define AD9523_PLL1_LOOP_FILTER_CTRL (AD9523_R1B | 0x1D)
|
||||
|
||||
#define AD9523_PLL2_CHARGE_PUMP (AD9523_R1B | 0xF0)
|
||||
#define AD9523_PLL2_FEEDBACK_DIVIDER_AB (AD9523_R1B | 0xF1)
|
||||
#define AD9523_PLL2_CTRL (AD9523_R1B | 0xF2)
|
||||
#define AD9523_PLL2_VCO_CTRL (AD9523_R1B | 0xF3)
|
||||
#define AD9523_PLL2_VCO_DIVIDER (AD9523_R1B | 0xF4)
|
||||
#define AD9523_PLL2_LOOP_FILTER_CTRL (AD9523_R2B | 0xF6)
|
||||
#define AD9523_PLL2_R2_DIVIDER (AD9523_R1B | 0xF7)
|
||||
|
||||
#define AD9523_CHANNEL_CLOCK_DIST(ch) (AD9523_R3B | (0x192 + 3 * ch))
|
||||
|
||||
#define AD9523_PLL1_OUTPUT_CTRL (AD9523_R1B | 0x1BA)
|
||||
#define AD9523_PLL1_OUTPUT_CHANNEL_CTRL (AD9523_R1B | 0x1BB)
|
||||
|
||||
#define AD9523_READBACK_0 (AD9523_R1B | 0x22C)
|
||||
#define AD9523_READBACK_1 (AD9523_R1B | 0x22D)
|
||||
|
||||
#define AD9523_STATUS_SIGNALS (AD9523_R3B | 0x232)
|
||||
#define AD9523_POWER_DOWN_CTRL (AD9523_R1B | 0x233)
|
||||
#define AD9523_IO_UPDATE (AD9523_R1B | 0x234)
|
||||
|
||||
#define AD9523_EEPROM_DATA_XFER_STATUS (AD9523_R1B | 0xB00)
|
||||
#define AD9523_EEPROM_ERROR_READBACK (AD9523_R1B | 0xB01)
|
||||
#define AD9523_EEPROM_CTRL1 (AD9523_R1B | 0xB02)
|
||||
#define AD9523_EEPROM_CTRL2 (AD9523_R1B | 0xB03)
|
||||
|
||||
/* AD9523_SERIAL_PORT_CONFIG */
|
||||
|
||||
#define AD9523_SER_CONF_SDO_ACTIVE ((1 << 7) | (1 << 0))
|
||||
#define AD9523_SER_CONF_SOFT_RESET ((1 << 5) | (1 << 2))
|
||||
|
||||
/* AD9523_READBACK_CTRL */
|
||||
#define AD9523_READBACK_CTRL_READ_BUFFERED (1 << 0)
|
||||
|
||||
/* AD9523_PLL1_CHARGE_PUMP_CTRL */
|
||||
#define AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(x) (((x) / 500) & 0x7F)
|
||||
#define AD9523_PLL1_CHARGE_PUMP_TRISTATE (1 << 7)
|
||||
#define AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL (3 << 8)
|
||||
#define AD9523_PLL1_CHARGE_PUMP_MODE_PUMP_DOWN (2 << 8)
|
||||
#define AD9523_PLL1_CHARGE_PUMP_MODE_PUMP_UP (1 << 8)
|
||||
#define AD9523_PLL1_CHARGE_PUMP_MODE_TRISTATE (0 << 8)
|
||||
#define AD9523_PLL1_BACKLASH_PW_MIN (0 << 10)
|
||||
#define AD9523_PLL1_BACKLASH_PW_LOW (1 << 10)
|
||||
#define AD9523_PLL1_BACKLASH_PW_HIGH (2 << 10)
|
||||
#define AD9523_PLL1_BACKLASH_PW_MAX (3 << 10)
|
||||
|
||||
/* AD9523_PLL1_INPUT_RECEIVERS_CTRL */
|
||||
#define AD9523_PLL1_REF_TEST_RCV_EN (1 << 7)
|
||||
#define AD9523_PLL1_REFB_DIFF_RCV_EN (1 << 6)
|
||||
#define AD9523_PLL1_REFA_DIFF_RCV_EN (1 << 5)
|
||||
#define AD9523_PLL1_REFB_RCV_EN (1 << 4)
|
||||
#define AD9523_PLL1_REFA_RCV_EN (1 << 3)
|
||||
#define AD9523_PLL1_REFA_REFB_PWR_CTRL_EN (1 << 2)
|
||||
#define AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN (1 << 1)
|
||||
#define AD9523_PLL1_OSC_IN_DIFF_EN (1 << 0)
|
||||
|
||||
/* AD9523_PLL1_REF_CTRL */
|
||||
#define AD9523_PLL1_BYPASS_REF_TEST_DIV_EN (1 << 7)
|
||||
#define AD9523_PLL1_BYPASS_FEEDBACK_DIV_EN (1 << 6)
|
||||
#define AD9523_PLL1_ZERO_DELAY_MODE_INT (1 << 5)
|
||||
#define AD9523_PLL1_ZERO_DELAY_MODE_EXT (0 << 5)
|
||||
#define AD9523_PLL1_OSC_IN_PLL_FEEDBACK_EN (1 << 4)
|
||||
#define AD9523_PLL1_ZD_IN_CMOS_NEG_INP_EN (1 << 3)
|
||||
#define AD9523_PLL1_ZD_IN_DIFF_EN (1 << 2)
|
||||
#define AD9523_PLL1_REFB_CMOS_NEG_INP_EN (1 << 1)
|
||||
#define AD9523_PLL1_REFA_CMOS_NEG_INP_EN (1 << 0)
|
||||
|
||||
/* AD9523_PLL1_MISC_CTRL */
|
||||
#define AD9523_PLL1_REFB_INDEP_DIV_CTRL_EN (1 << 7)
|
||||
#define AD9523_PLL1_OSC_CTRL_FAIL_VCC_BY2_EN (1 << 6)
|
||||
#define AD9523_PLL1_REF_MODE(x) ((x) << 2)
|
||||
#define AD9523_PLL1_BYPASS_REFB_DIV (1 << 1)
|
||||
#define AD9523_PLL1_BYPASS_REFA_DIV (1 << 0)
|
||||
|
||||
/* AD9523_PLL1_LOOP_FILTER_CTRL */
|
||||
#define AD9523_PLL1_LOOP_FILTER_RZERO(x) ((x) & 0xF)
|
||||
|
||||
/* AD9523_PLL2_CHARGE_PUMP */
|
||||
#define AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(x) ((x) / 3500)
|
||||
|
||||
/* AD9523_PLL2_FEEDBACK_DIVIDER_AB */
|
||||
#define AD9523_PLL2_FB_NDIV_A_CNT(x) (((x) & 0x3) << 6)
|
||||
#define AD9523_PLL2_FB_NDIV_B_CNT(x) (((x) & 0x3F) << 0)
|
||||
#define AD9523_PLL2_FB_NDIV(a, b) (4 * (b) + (a))
|
||||
|
||||
/* AD9523_PLL2_CTRL */
|
||||
#define AD9523_PLL2_CHARGE_PUMP_MODE_NORMAL (3 << 0)
|
||||
#define AD9523_PLL2_CHARGE_PUMP_MODE_PUMP_DOWN (2 << 0)
|
||||
#define AD9523_PLL2_CHARGE_PUMP_MODE_PUMP_UP (1 << 0)
|
||||
#define AD9523_PLL2_CHARGE_PUMP_MODE_TRISTATE (0 << 0)
|
||||
#define AD9523_PLL2_BACKLASH_PW_MIN (0 << 2)
|
||||
#define AD9523_PLL2_BACKLASH_PW_LOW (1 << 2)
|
||||
#define AD9523_PLL2_BACKLASH_PW_HIGH (2 << 2)
|
||||
#define AD9523_PLL2_BACKLASH_PW_MAX (3 << 1)
|
||||
#define AD9523_PLL2_BACKLASH_CTRL_EN (1 << 4)
|
||||
#define AD9523_PLL2_FREQ_DOUBLER_EN (1 << 5)
|
||||
#define AD9523_PLL2_LOCK_DETECT_PWR_DOWN_EN (1 << 7)
|
||||
|
||||
/* AD9523_PLL2_VCO_CTRL */
|
||||
#define AD9523_PLL2_VCO_CALIBRATE (1 << 1)
|
||||
#define AD9523_PLL2_FORCE_VCO_MIDSCALE (1 << 2)
|
||||
#define AD9523_PLL2_FORCE_REFERENCE_VALID (1 << 3)
|
||||
#define AD9523_PLL2_FORCE_RELEASE_SYNC (1 << 4)
|
||||
|
||||
/* AD9523_PLL2_VCO_DIVIDER */
|
||||
#define AD9523_PLL2_VCO_DIV_M1(x) ((((x) - 3) & 0x3) << 0)
|
||||
#define AD9523_PLL2_VCO_DIV_M2(x) ((((x) - 3) & 0x3) << 4)
|
||||
#define AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN (1 << 2)
|
||||
#define AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN (1 << 6)
|
||||
|
||||
/* AD9523_PLL2_LOOP_FILTER_CTRL */
|
||||
#define AD9523_PLL2_LOOP_FILTER_CPOLE1(x) (((x) & 0x7) << 0)
|
||||
#define AD9523_PLL2_LOOP_FILTER_RZERO(x) (((x) & 0x7) << 3)
|
||||
#define AD9523_PLL2_LOOP_FILTER_RPOLE2(x) (((x) & 0x7) << 6)
|
||||
#define AD9523_PLL2_LOOP_FILTER_RZERO_BYPASS_EN (1 << 8)
|
||||
|
||||
/* AD9523_PLL2_R2_DIVIDER */
|
||||
#define AD9523_PLL2_R2_DIVIDER_VAL(x) (((x) & 0x1F) << 0)
|
||||
|
||||
/* AD9523_CHANNEL_CLOCK_DIST */
|
||||
#define AD9523_CLK_DIST_DIV_PHASE(x) (((x) & 0x3F) << 18)
|
||||
#define AD9523_CLK_DIST_DIV_PHASE_REV(x) ((ret >> 18) & 0x3F)
|
||||
#define AD9523_CLK_DIST_DIV(x) ((((x) - 1) & 0x3FF) << 8)
|
||||
#define AD9523_CLK_DIST_DIV_REV(x) (((ret >> 8) & 0x3FF) + 1)
|
||||
#define AD9523_CLK_DIST_INV_DIV_OUTPUT_EN (1 << 7)
|
||||
#define AD9523_CLK_DIST_IGNORE_SYNC_EN (1 << 6)
|
||||
#define AD9523_CLK_DIST_PWR_DOWN_EN (1 << 5)
|
||||
#define AD9523_CLK_DIST_LOW_PWR_MODE_EN (1 << 4)
|
||||
#define AD9523_CLK_DIST_DRIVER_MODE(x) (((x) & 0xF) << 0)
|
||||
|
||||
/* AD9523_PLL1_OUTPUT_CTRL */
|
||||
#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH6_M2 (1 << 7)
|
||||
#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH5_M2 (1 << 6)
|
||||
#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH4_M2 (1 << 5)
|
||||
#define AD9523_PLL1_OUTP_CTRL_CMOS_DRV_WEAK (1 << 4)
|
||||
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_1 (0 << 0)
|
||||
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_2 (1 << 0)
|
||||
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_4 (2 << 0)
|
||||
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_8 (4 << 0)
|
||||
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_16 (8 << 0)
|
||||
|
||||
/* AD9523_PLL1_OUTPUT_CHANNEL_CTRL */
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_OUTPUT_PWR_DOWN_EN (1 << 7)
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH9_M2 (1 << 6)
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH8_M2 (1 << 5)
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH7_M2 (1 << 4)
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH3 (1 << 3)
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH2 (1 << 2)
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH1 (1 << 1)
|
||||
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH0 (1 << 0)
|
||||
|
||||
/* AD9523_READBACK_0 */
|
||||
#define AD9523_READBACK_0_STAT_PLL2_REF_CLK (1 << 7)
|
||||
#define AD9523_READBACK_0_STAT_PLL2_FB_CLK (1 << 6)
|
||||
#define AD9523_READBACK_0_STAT_VCXO (1 << 5)
|
||||
#define AD9523_READBACK_0_STAT_REF_TEST (1 << 4)
|
||||
#define AD9523_READBACK_0_STAT_REFB (1 << 3)
|
||||
#define AD9523_READBACK_0_STAT_REFA (1 << 2)
|
||||
#define AD9523_READBACK_0_STAT_PLL2_LD (1 << 1)
|
||||
#define AD9523_READBACK_0_STAT_PLL1_LD (1 << 0)
|
||||
|
||||
/* AD9523_READBACK_1 */
|
||||
#define AD9523_READBACK_1_HOLDOVER_ACTIVE (1 << 3)
|
||||
#define AD9523_READBACK_1_AUTOMODE_SEL_REFB (1 << 2)
|
||||
#define AD9523_READBACK_1_VCO_CALIB_IN_PROGRESS (1 << 0)
|
||||
|
||||
/* AD9523_STATUS_SIGNALS */
|
||||
#define AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL (1 << 16)
|
||||
#define AD9523_STATUS_MONITOR_01_PLL12_LOCKED (0x302)
|
||||
/* AD9523_POWER_DOWN_CTRL */
|
||||
#define AD9523_POWER_DOWN_CTRL_PLL1_PWR_DOWN (1 << 2)
|
||||
#define AD9523_POWER_DOWN_CTRL_PLL2_PWR_DOWN (1 << 1)
|
||||
#define AD9523_POWER_DOWN_CTRL_DIST_PWR_DOWN (1 << 0)
|
||||
|
||||
/* AD9523_IO_UPDATE */
|
||||
#define AD9523_IO_UPDATE_EN (1 << 0)
|
||||
|
||||
/* AD9523_EEPROM_DATA_XFER_STATUS */
|
||||
#define AD9523_EEPROM_DATA_XFER_IN_PROGRESS (1 << 0)
|
||||
|
||||
/* AD9523_EEPROM_ERROR_READBACK */
|
||||
#define AD9523_EEPROM_ERROR_READBACK_FAIL (1 << 0)
|
||||
|
||||
/* AD9523_EEPROM_CTRL1 */
|
||||
#define AD9523_EEPROM_CTRL1_SOFT_EEPROM (1 << 1)
|
||||
#define AD9523_EEPROM_CTRL1_EEPROM_WRITE_PROT_DIS (1 << 0)
|
||||
|
||||
/* AD9523_EEPROM_CTRL2 */
|
||||
#define AD9523_EEPROM_CTRL2_REG2EEPROM (1 << 0)
|
||||
|
||||
#define AD9523_NUM_CHAN 14
|
||||
#define AD9523_NUM_CHAN_ALT_CLK_SRC 10
|
||||
|
||||
enum outp_drv_mode {
|
||||
TRISTATE,
|
||||
LVPECL_8mA,
|
||||
LVDS_4mA,
|
||||
LVDS_7mA,
|
||||
HSTL0_16mA,
|
||||
HSTL1_8mA,
|
||||
CMOS_CONF1,
|
||||
CMOS_CONF2,
|
||||
CMOS_CONF3,
|
||||
CMOS_CONF4,
|
||||
CMOS_CONF5,
|
||||
CMOS_CONF6,
|
||||
CMOS_CONF7,
|
||||
CMOS_CONF8,
|
||||
CMOS_CONF9
|
||||
};
|
||||
|
||||
enum ref_sel_mode {
|
||||
NONEREVERTIVE_STAY_ON_REFB,
|
||||
REVERT_TO_REFA,
|
||||
SELECT_REFA,
|
||||
SELECT_REFB,
|
||||
EXT_REF_SEL
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct ad9523_channel_spec
|
||||
* @brief Output channel configuration
|
||||
*/
|
||||
struct ad9523_channel_spec {
|
||||
/** Output channel number. */
|
||||
uint8_t channel_num;
|
||||
/** Invert the polarity of the output clock. */
|
||||
uint8_t divider_output_invert_en;
|
||||
/** Ignore chip-level SYNC signal. */
|
||||
uint8_t sync_ignore_en;
|
||||
/** Reduce power used in the differential output modes. */
|
||||
uint8_t low_power_mode_en;
|
||||
/** Channel divider uses alternative clk source: CH0..CH3 VCXO, CH4..CH9 VCO2 */
|
||||
uint8_t use_alt_clock_src;
|
||||
/** Disables, powers down the entire channel. */
|
||||
uint8_t output_dis;
|
||||
/** Output driver mode (logic level family). */
|
||||
uint8_t driver_mode;
|
||||
/** Divider initial phase after a SYNC. Range 0..63
|
||||
* LSB = 1/2 of a period of the divider input clock.
|
||||
*/
|
||||
uint8_t divider_phase;
|
||||
/** 10-bit channel divider. */
|
||||
uint16_t channel_divider;
|
||||
/** Optional descriptive channel name. */
|
||||
int8_t extended_name[16];
|
||||
};
|
||||
|
||||
enum pll1_rzero_resistor {
|
||||
RZERO_883_OHM,
|
||||
RZERO_677_OHM,
|
||||
RZERO_341_OHM,
|
||||
RZERO_135_OHM,
|
||||
RZERO_10_OHM,
|
||||
RZERO_USE_EXT_RES = 8,
|
||||
};
|
||||
|
||||
enum rpole2_resistor {
|
||||
RPOLE2_900_OHM,
|
||||
RPOLE2_450_OHM,
|
||||
RPOLE2_300_OHM,
|
||||
RPOLE2_225_OHM,
|
||||
};
|
||||
|
||||
enum rzero_resistor {
|
||||
RZERO_3250_OHM,
|
||||
RZERO_2750_OHM,
|
||||
RZERO_2250_OHM,
|
||||
RZERO_2100_OHM,
|
||||
RZERO_3000_OHM,
|
||||
RZERO_2500_OHM,
|
||||
RZERO_2000_OHM,
|
||||
RZERO_1850_OHM,
|
||||
};
|
||||
|
||||
enum cpole1_capacitor {
|
||||
CPOLE1_0_PF,
|
||||
CPOLE1_8_PF,
|
||||
CPOLE1_16_PF,
|
||||
CPOLE1_24_PF,
|
||||
_CPOLE1_24_PF, /* place holder */
|
||||
CPOLE1_32_PF,
|
||||
CPOLE1_40_PF,
|
||||
CPOLE1_48_PF,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct ad9523_platform_data
|
||||
* @brief platform specific information
|
||||
*/
|
||||
struct ad9523_platform_data {
|
||||
/** External VCXO frequency in Hz */
|
||||
uint32_t vcxo_freq;
|
||||
/** Enable SPI-3wire mode */
|
||||
uint8_t spi3wire;
|
||||
|
||||
/** REFA differential/single-ended input selection. */
|
||||
uint8_t refa_diff_rcv_en;
|
||||
/** REFB differential/single-ended input selection. */
|
||||
uint8_t refb_diff_rcv_en;
|
||||
/** Zero Delay differential/single-ended input selection. */
|
||||
uint8_t zd_in_diff_en;
|
||||
/** OSC differential/ single-ended input selection. */
|
||||
uint8_t osc_in_diff_en;
|
||||
|
||||
/*
|
||||
* Valid if differential input disabled
|
||||
* if not true defaults to pos input
|
||||
*/
|
||||
/** REFA single-ended neg./pos. input enable. */
|
||||
uint8_t refa_cmos_neg_inp_en;
|
||||
/* REFB single-ended neg./pos. input enable. */
|
||||
uint8_t refb_cmos_neg_inp_en;
|
||||
/** Zero Delay single-ended neg./pos. input enable. */
|
||||
uint8_t zd_in_cmos_neg_inp_en;
|
||||
/** OSC single-ended neg./pos. input enable. */
|
||||
uint8_t osc_in_cmos_neg_inp_en;
|
||||
|
||||
/* PLL1 Setting */
|
||||
/** PLL1 10-bit: REFA R divider. */
|
||||
uint16_t refa_r_div;
|
||||
/** PLL1 10-bit: REFB R divider. */
|
||||
uint16_t refb_r_div;
|
||||
/** PLL1 10-bit Feedback N divider. */
|
||||
uint16_t pll1_feedback_div;
|
||||
/** Magnitude of PLL1 charge pump current (nA). */
|
||||
uint16_t pll1_charge_pump_current_nA;
|
||||
/** Internal, external Zero Delay mode selection. */
|
||||
uint8_t zero_delay_mode_internal_en;
|
||||
/** PLL1 feedback path, local feedback from the
|
||||
* OSC_IN receiver or zero delay mode
|
||||
*/
|
||||
uint8_t osc_in_feedback_en;
|
||||
|
||||
/** Bypass PLL1 - Single loop mode */
|
||||
uint8_t pll1_bypass_en;
|
||||
/** PLL1 Loop Filter Zero Resistor selection. */
|
||||
uint8_t pll1_loop_filter_rzero;
|
||||
|
||||
/** Reference mode selection. */
|
||||
uint8_t ref_mode;
|
||||
|
||||
/* PLL2 Setting */
|
||||
/** Magnitude of PLL2 charge pump current (nA). */
|
||||
uint32_t pll2_charge_pump_current_nA;
|
||||
/** PLL2 Feedback N-divider, A Counter, range 0..4. */
|
||||
uint8_t pll2_ndiv_a_cnt;
|
||||
/** PLL2 Feedback N-divider, B Counter, range 0..63. */
|
||||
uint8_t pll2_ndiv_b_cnt;
|
||||
/** PLL2 frequency doubler enable. */
|
||||
uint8_t pll2_freq_doubler_en;
|
||||
/** PLL2 R2 divider, range 0..31. */
|
||||
uint8_t pll2_r2_div;
|
||||
/** VCO1 divider, range 3..5. */
|
||||
uint8_t pll2_vco_diff_m1;
|
||||
/** VCO2 divider, range 3..5. */
|
||||
uint8_t pll2_vco_diff_m2;
|
||||
|
||||
/* Loop Filter PLL2 */
|
||||
/** PLL2 loop filter Rpole resistor value. */
|
||||
uint8_t rpole2;
|
||||
/** PLL2 loop filter Rzero resistor value. */
|
||||
uint8_t rzero;
|
||||
/** PLL2 loop filter Cpole capacitor value. */
|
||||
uint8_t cpole1;
|
||||
/** PLL2 loop filter Rzero bypass enable. */
|
||||
uint8_t rzero_bypass_en;
|
||||
|
||||
/* Output Channel Configuration */
|
||||
/** Array size of struct ad9523_channel_spec. */
|
||||
int32_t num_channels;
|
||||
/** Pointer to channel array. */
|
||||
struct ad9523_channel_spec *channels;
|
||||
|
||||
/** Optional alternative iio device name. */
|
||||
int8_t name[16];
|
||||
};
|
||||
|
||||
struct ad9523_state {
|
||||
struct ad9523_platform_data *pdata;
|
||||
uint32_t vcxo_freq;
|
||||
uint32_t vco_freq;
|
||||
uint32_t vco_out_freq[3];
|
||||
uint8_t vco_out_map[14];
|
||||
};
|
||||
|
||||
enum ad9523_out_frequencies {
|
||||
AD9523_VCO1,
|
||||
AD9523_VCO2,
|
||||
AD9523_VCXO,
|
||||
AD9523_NUM_CLK_SRC,
|
||||
};
|
||||
|
||||
struct ad9523_dev {
|
||||
/* SPI */
|
||||
struct no_os_spi_desc *spi_desc;
|
||||
/* Device Settings */
|
||||
struct ad9523_state ad9523_st;
|
||||
struct ad9523_platform_data *pdata;
|
||||
};
|
||||
|
||||
struct ad9523_init_param {
|
||||
/* SPI */
|
||||
struct no_os_spi_init_param spi_init;
|
||||
/* Device Settings */
|
||||
struct ad9523_platform_data *pdata;
|
||||
};
|
||||
|
||||
/* Reads the value of the selected register. */
|
||||
int32_t ad9523_spi_read(struct ad9523_dev *dev,
|
||||
uint32_t reg_addr,
|
||||
uint32_t *reg_data);
|
||||
|
||||
/* Writes a value to the selected register. */
|
||||
int32_t ad9523_spi_write(struct ad9523_dev *dev,
|
||||
uint32_t reg_addr,
|
||||
uint32_t reg_data);
|
||||
|
||||
/* Updates the AD9523 configuration */
|
||||
int32_t ad9523_io_update(struct ad9523_dev *dev);
|
||||
|
||||
/* Sets the clock provider for selected channel. */
|
||||
int32_t ad9523_vco_out_map(struct ad9523_dev *dev,
|
||||
uint32_t ch,
|
||||
uint32_t out);
|
||||
|
||||
/* Updates the AD9523 configuration. */
|
||||
int32_t ad9523_sync(struct ad9523_dev *dev);
|
||||
|
||||
/* Initialize the AD9523 data structure*/
|
||||
int32_t ad9523_init(struct ad9523_init_param *init_param);
|
||||
|
||||
/* Configure the AD9523. */
|
||||
int32_t ad9523_setup(struct ad9523_dev **device,
|
||||
const struct ad9523_init_param *init_param);
|
||||
|
||||
/* Free the resources allocated by ad9523_setup(). */
|
||||
int32_t ad9523_remove(struct ad9523_dev *dev);
|
||||
|
||||
int32_t ad9523_status(struct ad9523_dev *dev);
|
||||
#endif // __AD9523_H__
|
||||
2120
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/adf4382.c
Normal file
809
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/adf4382.h
Normal file
@@ -0,0 +1,809 @@
|
||||
/***************************************************************************//**
|
||||
* @file adf4382.h
|
||||
* @brief Implementation of adf4382 Driver.
|
||||
* @author Ciprian Hegbeli (ciprian.hegbeli@analog.com)
|
||||
* @author Jude Osemene (jude.osemene@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2024(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _ADF4382_H_
|
||||
#define _ADF4382_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "no_os_units.h"
|
||||
#include "no_os_util.h"
|
||||
#include "no_os_spi.h"
|
||||
|
||||
/* ADF4382 REG0000 Map */
|
||||
#define ADF4382_SOFT_RESET_R_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_LSB_FIRST_R_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_ADDRESS_ASC_R_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_SDO_ACTIVE_R_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_SDO_ACTIVE_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_ADDRESS_ASC_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_LSB_FIRST_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_SOFT_RESET_MSK NO_OS_BIT(0)
|
||||
#define ADF4382_RESET_CMD 0x81
|
||||
|
||||
/* ADF4382 REG0000 NO_OS_BIT Definition */
|
||||
#define ADF4382_SDO_ACTIVE_SPI_3W 0x0
|
||||
#define ADF4382_SDO_ACTIVE_SPI_4W 0x1
|
||||
|
||||
#define ADF4382_ADDR_ASC_AUTO_DECR 0x0
|
||||
#define ADF4382_ADDR_ASC_AUTO_INCR 0x1
|
||||
|
||||
#define ADF4382_LSB_FIRST_MSB 0x0
|
||||
#define ADF4382_LSB_FIRST_LSB 0x1
|
||||
|
||||
#define ADF4382_SOFT_RESET_N_OP 0x0
|
||||
#define ADF4382_SOFT_RESET_EN 0x1
|
||||
|
||||
/* ADF4382 REG0001 Map */
|
||||
#define ADF4382_SINGLE_INSTR_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_MASTER_RB_CTRL_MSK NO_OS_BIT(5)
|
||||
|
||||
/* ADF4382 REG0001 NO_OS_BIT Definition */
|
||||
#define ADF4382_SPI_STREAM_EN 0x0
|
||||
#define ADF4382_SPI_STREAM_DIS 0x1
|
||||
|
||||
#define ADF4382_RB_SLAVE_REG 0x0
|
||||
#define ADF4382_RB_MASTER_REG 0x1
|
||||
|
||||
/* ADF4382 REG0003 NO_OS_BIT Definition */
|
||||
#define ADF4382_CHIP_TYPE 0x06
|
||||
|
||||
/* ADF4382 REG0004 NO_OS_BIT Definition */
|
||||
#define ADF4382_PRODUCT_ID_LSB 0x0005
|
||||
|
||||
/* ADF4382 REG0005 NO_OS_BIT Definition */
|
||||
#define ADF4382_PRODUCT_ID_MSB 0x0005
|
||||
|
||||
/* ADF4382 REG000A Map */
|
||||
#define ADF4382_SCRATCHPAD_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG000C NO_OS_BIT Definition */
|
||||
#define ADF4382_VENDOR_ID_LSB 0x56
|
||||
|
||||
/* ADF4382 REG000D NO_OS_BIT Definition */
|
||||
#define ADF4382_VENDOR_ID_MSB 0x04
|
||||
|
||||
/* ADF4382 REG000F NO_OS_BIT Definition */
|
||||
#define ADF4382_M_S_TRANSF_NO_OS_BIT_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0010 Map*/
|
||||
#define ADF4382_N_INT_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0011 Map*/
|
||||
#define ADF4382_CLKOUT_DIV_MSK NO_OS_GENMASK(7, 5)
|
||||
#define ADF4382_INV_CLK_OUT_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_N_INT_MSB_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG0012 Map */
|
||||
#define ADF4382_FRAC1WORD_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0013 Map */
|
||||
#define ADF4382_FRAC1WORD_MID_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0014 Map */
|
||||
#define ADF4382_FRAC1WORD_MSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0015 Map */
|
||||
#define ADF4382_M_VCO_BAND_LSB_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_M_VCO_CORE_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_BIAS_DEC_MODE_MSK NO_OS_GENMASK(5, 3)
|
||||
#define ADF4382_INT_MODE_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_PFD_POL_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_FRAC1WORD_MSB NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0016 Map */
|
||||
#define ADF4382_M_VCO_BAND_MSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0017 Map */
|
||||
#define ADF4382_FRAC2WORD_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0018 Map */
|
||||
#define ADF4382_FRAC2WORD_MID_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0019 Map */
|
||||
#define ADF4382_FRAC2WORD_MSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG001A Map */
|
||||
#define ADF4382_MOD2WORD_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG001B Map */
|
||||
#define ADF4382_MOD2WORD_MID_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG001C Map */
|
||||
#define ADF4382_MOD2WORD_MSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG001D Map */
|
||||
#define ADF4382_FINE_BLEED_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG001E Map */
|
||||
#define ADF4382_EN_PHASE_RESYNC_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_EN_REF_RST_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_TIMED_SYNC_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_COARSE_BLEED_MSK NO_OS_GENMASK(4, 1)
|
||||
#define ADF4382_FINE_BLEED_MSB_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG001F Map */
|
||||
#define ADF4382_SW_SYNC_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_SPARE_1F_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_BLEED_POL_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_EN_BLEED_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_CP_I_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG0020 Map */
|
||||
#define ADF4382_EN_AUTOCAL_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_EN_RDBLR_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_R_DIV_MSK NO_OS_GENMASK(5, 0)
|
||||
|
||||
/* ADF4382 REG0021 Map */
|
||||
#define ADF4382_PHASE_WORD_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0022 Map */
|
||||
#define ADF4382_PHASE_WORD_MID_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0023 Map */
|
||||
#define ADF4382_PHASE_WORD_MSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0024 Map */
|
||||
#define ADF4382_SPARE_24_MSK NO_OS_GENMASK(7, 5)
|
||||
#define ADF4382_DCLK_DIV_SEL_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_DNCLK_DIV1_MSK NO_OS_GENMASK(3, 2)
|
||||
#define ADF4382_DCLK_DIV1_MSK NO_OS_GENMASK(1, 0)
|
||||
|
||||
/* ADF4382 REG0025 Map */
|
||||
#define ADF4382_RESYNC_WAIT_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0026 Map */
|
||||
#define ADF4382_RESYNC_WAIT_MSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0027 Map */
|
||||
#define ADF4382_CAL_BLEED_FINE_MIN_MSK NO_OS_GENMASK(7, 4)
|
||||
#define ADF4382_BLEED_ADJ_SCALE_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG0028 Map */
|
||||
#define ADF4382_PH_RESYNC_RB_SEL_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_LSB_P1_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_VAR_MOD_EN_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_DITHER1_SCALE_MSK NO_OS_GENMASK(4, 2)
|
||||
#define ADF4382_EN_DITHER2_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_EN_DITHER1_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0029 Map */
|
||||
#define ADF4382_CLK2_OPWR_MSK NO_OS_GENMASK(7, 4)
|
||||
#define ADF4382_CLK1_OPWR_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG002A Map */
|
||||
#define ADF4382_FN_DBL_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_PD_NDIV_TL_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_CLKOUT_BST_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_PD_SYNC_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_PD_CLK_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_PD_RDET_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_PD_ADC_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_PD_CALGEN_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG002B Map */
|
||||
#define ADF4382_PD_ALL_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_PD_RDIV_TL_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_PD_NDIV_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_PD_VCO_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_PD_LD_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_PD_PFDCP_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_PD_CLKOUT1_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_PD_CLKOUT2_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG002C Map */
|
||||
#define ADF4382_LDWIN_PW_MSK NO_OS_GENMASK(7, 5)
|
||||
#define ADF4382_LD_COUNT_OPWR_MSK NO_OS_GENMASK(4, 0)
|
||||
|
||||
/* ADF4382 REG002D Map */
|
||||
#define ADF4382_EN_DNCLK_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_EN_DRCLK_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_EN_LOL_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_EN_LDWIN_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_PDET_POL_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_RST_LD_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_LD_O_CTRL_MSK NO_OS_GENMASK(1, 0)
|
||||
|
||||
/* ADF4382 REG002E Map */
|
||||
#define ADF4382_MUXOUT_MSK NO_OS_GENMASK(7, 4)
|
||||
#define ADF4382_ABPW_WD_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_EN_CPTEST_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_CP_DOWN_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_CP_UP_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG002F Map*/
|
||||
#define ADF4382_BST_REF_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_FILT_REF_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_RDBLR_DC_MSK NO_OS_GENMASK(5, 0)
|
||||
|
||||
/* ADF4382 REG0030 Map */
|
||||
#define ADF4382_MUTE_NCLK_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_MUTE_RCLK_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_REF_SEL_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_INV_RDBLR_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_RDBLR_DEL_SEL_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG0031 Map */
|
||||
#define ADF4382_SYNC_DEL_MSK NO_OS_GENMASK(7, 5)
|
||||
#define ADF4382_RST_SYS_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_EN_ADC_CLK_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_EN_VCAL_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_CAL_CT_SEL_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_DCLK_MODE_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0032 Map */
|
||||
#define ADF4382_SPARE_32_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_BLEED_ADJ_CAL_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_DEL_MODE_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_EN_AUTO_ALIGN_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_PHASE_ADJ_POL_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_EFM3_MODE_MSK NO_OS_GENMASK(2, 0)
|
||||
|
||||
/* ADF4382 REG0033 Map */
|
||||
#define ADF4382_PHASE_ADJUST_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0034 Map */
|
||||
#define ADF4382_PHASE_ADJ_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_DRCLK_DEL_MSK NO_OS_GENMASK(6, 4)
|
||||
#define ADF4382_DNCLK_DEL_MSK NO_OS_GENMASK(3, 1)
|
||||
#define ADF4382_RST_CNTR_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0035 Map */
|
||||
#define ADF4382_SPARE_35_MSK NO_OS_GENMASK(7, 6)
|
||||
#define ADF4382_M_VCO_BIAS_MSK NO_OS_GENMASK(5, 0)
|
||||
|
||||
/* ADF4382 REG0036 Map */
|
||||
#define ADF4382_CLKODIV_DB_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_DCLK_DIV_DB_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_SPARE_36_MSK NO_OS_GENMASK(5, 2)
|
||||
#define ADF4382_EN_LUT_GEN_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_EN_LUT_CAL_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0037 Map */
|
||||
#define ADF4382_CAL_COUNT_TO_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0038 Map */
|
||||
#define ADF4382_CAL_VTUNE_TO_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0039 Map */
|
||||
#define ADF4382_O_VCO_DB_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_CAL_VTUNE_TO_MSB_MSK NO_OS_GENMASK(6, 0)
|
||||
|
||||
/* ADF4382 REG003A Map */
|
||||
#define ADF4382_CAL_VCO_TO_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG003B Map */
|
||||
#define ADF4382_DEL_CTRL_DB_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_CAL_VCO_TO_MSB_MSK NO_OS_GENMASK(6, 0)
|
||||
|
||||
/* ADF4382 REG003C Map */
|
||||
#define ADF4382_CNTR_DIV_WORD_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG003D Map */
|
||||
#define ADF4382_SPARE_3D_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_SYNC_SP_DB_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_CMOS_OV_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_READ_MODE_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_CNTR_DIV_WORD_MSB_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG003E Map */
|
||||
#define ADF4382_ADC_CLK_DIV_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG003F Map */
|
||||
#define ADF4382_EN_ADC_CNV_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_EN_ADC_VTEST_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_ADC_VTEST_SEL_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_ADC_MUX_SEL_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_ADC_F_CONV_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_ADC_C_CONV_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_EN_ADC_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_SPARE_3F_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0040 Map */
|
||||
#define ADF4382_EXT_DIV_DEC_SEL_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_ADC_CLK_TEST_SEL_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_MUTE_CLKOUT2_MSK NO_OS_GENMASK(5, 3)
|
||||
#define ADF4382_MUTE_CLKOUT1_MSK NO_OS_GENMASK(2, 0)
|
||||
|
||||
/* ADF4382 REG0041 Map */
|
||||
#define ADF4382_EXT_DIV_MSK NO_OS_GENMASK(7, 5)
|
||||
#define ADF4382_EN_VCO_CAP_TEST_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_EN_CALGEN_CAP_TEST_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_EN_CP_CAP_TEST_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_CAP_TEST_STATE_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_TRANS_LOOP_SEL_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0042 Map */
|
||||
#define ADF4382_NDIV_PWRUP_TIMEOUT_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0043 Map */
|
||||
#define ADF4382_CAL_BLEED_FINE_MAX_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0044 Map */
|
||||
#define ADF4382_VCAL_ZERO_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_VPTAT_CALGEN_MSK NO_OS_GENMASK(6, 0)
|
||||
|
||||
/* ADF4382 REG0045 Map */
|
||||
#define ADF4382_SPARE_45_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_VCTAT_CALGEN_MSK NO_OS_GENMASK(6, 0)
|
||||
|
||||
/* ADF4382 REG0046 Map */
|
||||
#define ADF4382_NVMDIN_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0047 Map */
|
||||
#define ADF4382_SPARE_47_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_NVMADDR_MSK NO_OS_GENMASK(6, 3)
|
||||
#define ADF4382_NVMNO_OS_BIT_SEL NO_OS_GENMASK(2, 0)
|
||||
|
||||
/* ADF4382 REG0048 Map */
|
||||
#define ADF4382_TRIM_LATCH_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_NVMTEST_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_NVMPROG_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_NVMRD_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_NVMSTART_MSK NO_OS_BIT(3)
|
||||
#define ADF4382_NVMON_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_MARGIN_MSK NO_OS_GENMASK(1, 0)
|
||||
|
||||
/* ADF4382 REG0049 Map */
|
||||
#define ADF4382_NVMDOUT_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG004A Map */
|
||||
#define ADF4382_SCAN_MODE_CODE_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG004B Map */
|
||||
#define ADF4382_TEMP_OFFSET_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG004C Map */
|
||||
#define ADF4382_SPARE_4C_MSK NO_OS_GENMASK(7, 6)
|
||||
#define ADF4382_TEMP_SLOPE_MSK NO_OS_GENMASK(5, 0)
|
||||
|
||||
/* ADF4382 REG004D Map */
|
||||
#define ADF4382_VCO_FSM_TEST_MUX_MSK NO_OS_GENMASK(7, 5)
|
||||
#define ADF4382_SPARE_4D_MSK NO_OS_GENMASK(4, 3)
|
||||
#define ADF4382_O_VCO_BIAS_MSK NO_OS_BIT(2)
|
||||
#define ADF4382_O_VCO_BAND_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_O_VCO_CORE_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG004E Map */
|
||||
#define ADF4382_SPARE_4E_MSK NO_OS_GENMASK(7, 5)
|
||||
#define ADF4382_EN_TWO_PASS_CAL_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_TWO_PASS_BAND_START_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG004F Map */
|
||||
#define ADF4382_LUT_SCALE_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0050 Map */
|
||||
#define ADF4382_SPARE0_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0051 Map */
|
||||
#define ADF4382_SPARE1_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0052 Map */
|
||||
#define ADF4382_SYNC_REF_SPARE_MSK NO_OS_GENMASK(7, 4)
|
||||
#define ADF4382_SYNC_MON_DEL_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG0053 Map */
|
||||
#define ADF4382_SPARE_53_MSK NO_OS_BIT(7)
|
||||
#define ADF4382_PD_SYNC_MON_MSK NO_OS_BIT(6)
|
||||
#define ADF4382_SYNC_SEL_MSK NO_OS_BIT(5)
|
||||
#define ADF4382_RST_SYNC_MON_MSK NO_OS_BIT(4)
|
||||
#define ADF4382_SYNC_SH_DEL_MSK NO_OS_GENMASK(3, 0)
|
||||
|
||||
/* ADF4382 REG0054 Map */
|
||||
#define ADF4382_ADC_ST_CNV_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0058 Map */
|
||||
#define ADF4382_FSM_BUSY_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_LOCKED_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG005E Map */
|
||||
#define ADF4382_VCO_BAND_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG005F Map */
|
||||
#define ADF4382_VCO_CORE_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_VCO_BAND_MSB_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0200 Map */
|
||||
#define ADF4382_LUT_WR_ADDR_MSK NO_OS_GENMASK(5, 1)
|
||||
#define ADF4382_O_VCO_LUT_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0201 Map */
|
||||
#define ADF4382_M_LUT_BAND_LSB_MSK NO_OS_GENMASK(7, 0)
|
||||
|
||||
/* ADF4382 REG0202 Map */
|
||||
#define ADF4382_M_LUT_N_LSB_MSK NO_OS_GENMASK(7, 2)
|
||||
#define ADF4382_M_LUT_CORE_MSK NO_OS_BIT(1)
|
||||
#define ADF4382_M_LUT_BAND_MSB_MSK NO_OS_BIT(0)
|
||||
|
||||
/* ADF4382 REG0203 Map */
|
||||
#define ADF4382_M_LUT_N_MSB_MSK NO_OS_GENMASK(5, 0)
|
||||
|
||||
#define ADF4382_SPI_3W_CFG(x) (no_os_field_prep(ADF4382_SDO_ACTIVE_MSK, x) | \
|
||||
no_os_field_prep(ADF4382_SDO_ACTIVE_R_MSK, x))
|
||||
|
||||
#define ADF4382_BLEED_MSB_MSK (ADF4382_COARSE_BLEED_MSK | \
|
||||
ADF4382_FINE_BLEED_MSB_MSK)
|
||||
|
||||
#define ADF4382_SPI_SCRATCHPAD_TEST 0x5A
|
||||
|
||||
/* Specifications */
|
||||
#define ADF4382_SPI_WRITE_CMD 0x0
|
||||
#define ADF4382_SPI_READ_CMD 0x8000
|
||||
#define ADF4382_SPI_DUMMY_DATA 0x00
|
||||
#define ADF4382_BUFF_SIZE_BYTES 3
|
||||
#define ADF4382_VCO_FREQ_MIN 11000000000U // 11GHz
|
||||
#define ADF4382_VCO_FREQ_MAX 22000000000U // 22GHz
|
||||
#define ADF4383_VCO_FREQ_MIN 10000000000U // 10GHz
|
||||
#define ADF4383_VCO_FREQ_MAX 20000000000U // 20GHz
|
||||
#define ADF4382A_VCO_FREQ_MIN 11500000000U // 11.5GHz
|
||||
#define ADF4382A_VCO_FREQ_MAX 21000000000U // 21GHz
|
||||
#define ADF4382_MOD1WORD 0x2000000U // 2^25
|
||||
#define ADF4382_MOD2WORD_MAX 0xFFFFFFU // 2^24 - 1
|
||||
#define ADF4382_PHASE_RESYNC_MOD2WORD_MAX 0x1FFFFU // 2^17 - 1
|
||||
#define ADF4382_CHANNEL_SPACING_MAX 78125U
|
||||
#define ADF4382_PFD_FREQ_MAX 625000000U // 625MHz
|
||||
#define ADF4382_PFD_FREQ_FRAC_MAX 250000000U // 250MHz
|
||||
#define ADF4382_PFD_FREQ_MIN 5400000U // 5.4MHz
|
||||
#define ADF4382_DCLK_DIV1_0_MAX 160000000U // 160MHz
|
||||
#define ADF4382_DCLK_DIV1_1_MAX 320000000U // 320MHz
|
||||
#define ADF4382_CLKOUT_DIV_REG_VAL_MAX 4
|
||||
#define ADF4382A_CLKOUT_DIV_REG_VAL_MAX 2
|
||||
|
||||
#define ADF4383_RFOUT_MAX 20000000000U
|
||||
#define ADF4383_RFOUT_MIN 625000000U
|
||||
#define ADF4382_RFOUT_MAX 22000000000U
|
||||
#define ADF4382_RFOUT_MIN 687500000U
|
||||
#define ADF4382A_RFOUT_MAX 21000000000U
|
||||
#define ADF4382A_RFOUT_MIN 2875000000U
|
||||
#define ADF4382_REF_CLK_MAX 5000000000U
|
||||
#define ADF4382_REF_CLK_MIN 10000000
|
||||
#define ADF4382_REF_DIV_MAX 63
|
||||
#define ADF4382_OUT_PWR_MAX 15
|
||||
#define ADF4382_CPI_VAL_MAX 15
|
||||
#define ADF4382_BLEED_WORD_MAX 8191
|
||||
|
||||
#define ADF4382_VPTAT_CALGEN 46
|
||||
#define ADF4382_VCTAT_CALGEN 82
|
||||
#define ADF4382_FASTCAL_VPTAT_CALGEN 7
|
||||
#define ADF4382_FASTCAL_VCTAT_CALGEN 21
|
||||
#define ADF4382_PHASE_BLEED_CNST 2044000
|
||||
#define ADF4382_VCO_CAL_CNT 183
|
||||
#define ADF4382_VCO_CAL_VTUNE 640
|
||||
#define ADF4382_VCO_CAL_ALC 123
|
||||
#define ADF4382_POR_DELAY_US 200
|
||||
#define ADF4382_LKD_DELAY_US 1000
|
||||
#define ADF4382_COARSE_BLEED_CONST 180U // 180 microseconds
|
||||
#define ADF4382_FINE_BLEED_CONST_1 512U // 512 microseconds
|
||||
#define ADF4382_FINE_BLEED_CONST_2 250U // 250 microseconds
|
||||
#define ADF4382_CAL_VTUNE_TO 124U
|
||||
#define ADF4382_FSM_BUSY_LOOP_CNT 100U
|
||||
|
||||
#define MHZ MEGA
|
||||
#define S_TO_NS NANO
|
||||
#define PS_TO_S PICO
|
||||
#define NS_TO_PS KHZ_PER_MHZ
|
||||
|
||||
/**
|
||||
* @brief Supported device ids.
|
||||
*/
|
||||
enum adf4382_dev_id {
|
||||
ID_ADF4382,
|
||||
ID_ADF4382A,
|
||||
ID_ADF4383,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct adf4382_init_param
|
||||
* @brief ADF4382 Initialization Parameters structure.
|
||||
*/
|
||||
struct adf4382_init_param {
|
||||
/** SPI Initialization parameters */
|
||||
struct no_os_spi_init_param *spi_init;
|
||||
bool spi_3wire_en;
|
||||
bool cmos_3v3;
|
||||
uint64_t ref_freq_hz;
|
||||
uint64_t freq;
|
||||
bool ref_doubler_en;
|
||||
uint8_t ref_div;
|
||||
uint8_t cp_i;
|
||||
uint16_t bleed_word;
|
||||
uint8_t ld_count;
|
||||
uint8_t en_lut_gen;
|
||||
uint8_t en_lut_cal;
|
||||
uint8_t max_lpf_cap_value_uf;
|
||||
enum adf4382_dev_id id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct adf4382_dev
|
||||
* @brief ADF4382 Device Descriptor.
|
||||
*/
|
||||
struct adf4382_dev {
|
||||
/** SPI Descriptor */
|
||||
struct no_os_spi_desc *spi_desc;
|
||||
bool spi_3wire_en;
|
||||
bool cmos_3v3;
|
||||
uint64_t ref_freq_hz;
|
||||
uint64_t freq;
|
||||
bool ref_doubler_en;
|
||||
uint8_t ref_div;
|
||||
uint8_t cp_i;
|
||||
uint16_t bleed_word;
|
||||
uint8_t ld_count;
|
||||
uint32_t phase_adj;
|
||||
uint8_t en_lut_gen;
|
||||
uint8_t en_lut_cal;
|
||||
uint64_t vco_max;
|
||||
uint64_t vco_min;
|
||||
uint64_t freq_max;
|
||||
uint64_t freq_min;
|
||||
uint8_t clkout_div_reg_val_max;
|
||||
uint8_t max_lpf_cap_value_uf;
|
||||
uint32_t cal_vtune_to;
|
||||
// N_INT variable to trigger auto calibration
|
||||
uint16_t n_int;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct reg_sequence
|
||||
* @brief ADF4382 register format structure for default values
|
||||
*/
|
||||
struct reg_sequence {
|
||||
uint16_t reg;
|
||||
uint8_t val;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct adf4382_reg_defaults
|
||||
* @brief ADF4382 register initialization
|
||||
*/
|
||||
static const struct reg_sequence adf4382_reg_defaults[] = {
|
||||
{ 0x000, 0x18 },
|
||||
{ 0x00a, 0xA5 },
|
||||
{ 0x200, 0x00 },
|
||||
{ 0x201, 0x00 },
|
||||
{ 0x202, 0x00 },
|
||||
{ 0x203, 0x00 },
|
||||
{ 0x203, 0x00 },
|
||||
{ 0x203, 0x00 },
|
||||
{ 0x100, 0x25 },
|
||||
{ 0x101, 0x3F },
|
||||
{ 0x102, 0x3F },
|
||||
{ 0x103, 0x3F },
|
||||
{ 0x104, 0x3F },
|
||||
{ 0x105, 0x3F },
|
||||
{ 0x106, 0x3F },
|
||||
{ 0x107, 0x3F },
|
||||
{ 0x108, 0x3F },
|
||||
{ 0x109, 0x25 },
|
||||
{ 0x10A, 0x25 },
|
||||
{ 0x10B, 0x3F },
|
||||
{ 0x10C, 0x3F },
|
||||
{ 0x10D, 0x3F },
|
||||
{ 0x10E, 0x3F },
|
||||
{ 0x10F, 0x3F },
|
||||
{ 0x110, 0x3F },
|
||||
{ 0x111, 0x3F },
|
||||
{ 0x054, 0x00 },
|
||||
{ 0x053, 0x45 },
|
||||
{ 0x052, 0x00 },
|
||||
{ 0x051, 0x00 },
|
||||
{ 0x050, 0x00 },
|
||||
{ 0x04f, 0x08 },
|
||||
{ 0x04e, 0x06 },
|
||||
{ 0x04d, 0x00 },
|
||||
{ 0x04c, 0x2B },
|
||||
{ 0x04b, 0x5D },
|
||||
{ 0x04a, 0x00 },
|
||||
{ 0x048, 0x00 },
|
||||
{ 0x047, 0x00 },
|
||||
{ 0x046, 0x00 },
|
||||
{ 0x045, 0x52 },
|
||||
{ 0x044, 0x2E },
|
||||
{ 0x043, 0xB8 },
|
||||
{ 0x042, 0x01 },
|
||||
{ 0x041, 0x00 },
|
||||
{ 0x040, 0x00 },
|
||||
{ 0x03f, 0x82 },
|
||||
{ 0x03e, 0x4E },
|
||||
{ 0x03d, 0x00 },
|
||||
{ 0x03c, 0x00 },
|
||||
{ 0x03b, 0x00 },
|
||||
{ 0x03a, 0xFA },
|
||||
{ 0x039, 0x00 },
|
||||
{ 0x038, 0x7C },
|
||||
{ 0x037, 0xCA },
|
||||
{ 0x036, 0xC0 },
|
||||
{ 0x035, 0x00 },
|
||||
{ 0x034, 0x36 },
|
||||
{ 0x033, 0x00 },
|
||||
{ 0x032, 0x40 },
|
||||
{ 0x031, 0x63 },
|
||||
{ 0x030, 0x0F },
|
||||
{ 0x02f, 0x3F },
|
||||
{ 0x02e, 0x00 },
|
||||
{ 0x02d, 0xF1 },
|
||||
{ 0x02c, 0x0E },
|
||||
{ 0x02b, 0x01 },
|
||||
{ 0x02a, 0x30 },
|
||||
{ 0x029, 0x09 },
|
||||
{ 0x028, 0x00 },
|
||||
{ 0x027, 0xF0 },
|
||||
{ 0x026, 0x00 },
|
||||
{ 0x025, 0x01 },
|
||||
{ 0x024, 0x01 },
|
||||
{ 0x023, 0x00 },
|
||||
{ 0x022, 0x00 },
|
||||
{ 0x021, 0x00 },
|
||||
{ 0x020, 0xC1 },
|
||||
{ 0x01f, 0x0F },
|
||||
{ 0x01e, 0x20 },
|
||||
{ 0x01d, 0x00 },
|
||||
{ 0x01c, 0x00 },
|
||||
{ 0x01b, 0x00 },
|
||||
{ 0x01a, 0x00 },
|
||||
{ 0x019, 0x00 },
|
||||
{ 0x018, 0x00 },
|
||||
{ 0x017, 0x00 },
|
||||
{ 0x016, 0x00 },
|
||||
{ 0x015, 0x06 },
|
||||
{ 0x014, 0x00 },
|
||||
{ 0x013, 0x00 },
|
||||
{ 0x012, 0x00 },
|
||||
{ 0x011, 0x00 },
|
||||
{ 0x010, 0x50 },
|
||||
};
|
||||
|
||||
/** ADF4382 SPI write */
|
||||
int adf4382_spi_write(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t data);
|
||||
|
||||
/** ADF4382 SPI Read */
|
||||
int adf4382_spi_read(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t *data);
|
||||
|
||||
/** ADF4382 updates a bit in the register space over SPI */
|
||||
int adf4382_spi_update_bits(struct adf4382_dev *dev, uint16_t reg_addr,
|
||||
uint8_t mask, uint8_t data);
|
||||
|
||||
/** ADF4382 Register dump */
|
||||
int adf4382_reg_dump(struct adf4382_dev *dev);
|
||||
|
||||
/** ADF4382 Set reference frequency attribute */
|
||||
int adf4382_set_ref_clk(struct adf4382_dev *dev, uint64_t val);
|
||||
|
||||
/** ADF4382 Get reference frequency attribute */
|
||||
int adf4382_get_ref_clk(struct adf4382_dev *dev, uint64_t *val);
|
||||
|
||||
/** ADF4382 Set reference doubler attribute */
|
||||
int adf4382_set_en_ref_doubler(struct adf4382_dev *dev, bool en);
|
||||
|
||||
/** ADF4382 Get reference doubler attribute */
|
||||
int adf4382_get_en_ref_doubler(struct adf4382_dev *dev, bool *en);
|
||||
|
||||
/** ADF4382 Set reference divider attribute */
|
||||
int adf4382_set_ref_div(struct adf4382_dev *dev, int32_t div);
|
||||
|
||||
/** ADF4382 Get reference divider attribute */
|
||||
int adf4382_get_ref_div(struct adf4382_dev *dev, int32_t *div);
|
||||
|
||||
/** ADF4382 Set charge pump current attribute */
|
||||
int adf4382_set_cp_i(struct adf4382_dev *dev, int32_t reg_val);
|
||||
|
||||
/** ADF4382 Get charge pump current attribute */
|
||||
int adf4382_get_cp_i(struct adf4382_dev *dev, int32_t *reg_val);
|
||||
|
||||
/** ADF4382 Set bleed current attribute */
|
||||
int adf4382_set_bleed_word(struct adf4382_dev *dev, int32_t word);
|
||||
|
||||
/** ADF4382 Get bleed current attribute */
|
||||
int adf4382_get_bleed_word(struct adf4382_dev *dev, int32_t *word);
|
||||
|
||||
/** ADF4382 Set output frequency attribute */
|
||||
int adf4382_set_rfout(struct adf4382_dev *dev, uint64_t val);
|
||||
|
||||
/** ADF4382 Get output frequency attribute */
|
||||
int adf4382_get_rfout(struct adf4382_dev *dev, uint64_t *val);
|
||||
|
||||
/** ADF4382 Set output power attributes */
|
||||
int adf4382_set_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t pwr);
|
||||
|
||||
/** ADF4382 Get output power attributes */
|
||||
int adf4382_get_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t *pwr);
|
||||
|
||||
/** ADF4382 Set channel enable attributes */
|
||||
int adf4382_set_en_chan(struct adf4382_dev *dev, uint8_t ch, bool en);
|
||||
|
||||
/** ADF4382 Get channel enable attributes */
|
||||
int adf4382_get_en_chan(struct adf4382_dev *dev, uint8_t ch, bool *en);
|
||||
|
||||
/** ADF4382 Sets frequency */
|
||||
int adf4382_set_freq(struct adf4382_dev *dev);
|
||||
|
||||
/** ADF4382 Set fast calibration attributes */
|
||||
int adf4382_set_en_fast_calibration(struct adf4382_dev *dev, bool en_fast_cal);
|
||||
|
||||
/** ADF4382 Set fast calibration LUT calibration attributes */
|
||||
int adf4382_set_en_lut_calibration(struct adf4382_dev *dev, bool en_lut_cal);
|
||||
|
||||
/** ADF4382 Get Fast Calibration LUT Calibration attributes */
|
||||
int adf4382_get_en_lut_calibration(struct adf4382_dev *dev, bool *en);
|
||||
|
||||
/** ADF4382 Set Output Frequency without writing the Ndiv Register */
|
||||
int adf4382_set_change_freq(struct adf4382_dev *dev);
|
||||
|
||||
/** ADF4382 Get Change Output Frequency attribute value */
|
||||
int adf4382_get_change_rfout(struct adf4382_dev *dev, uint64_t *val);
|
||||
|
||||
/** ADF4382 Set Change Output Frequency attribute value */
|
||||
int adf4382_set_change_rfout(struct adf4382_dev *dev, uint64_t val);
|
||||
|
||||
/** ADF4382 Set the NDIV register attribute value */
|
||||
int adf4382_set_start_calibration(struct adf4382_dev *dev);
|
||||
|
||||
/** ADF4382 Get the NDIV register attribute value as 0 */
|
||||
int adf4382_get_start_calibration(struct adf4382_dev *dev, bool *start_cal);
|
||||
|
||||
/** ADF4382 Sets Phase adjustment */
|
||||
int adf4382_set_phase_adjust(struct adf4382_dev *dev, uint32_t phase_ps);
|
||||
|
||||
/** ADF4382 Sets Phase adjustment polarity*/
|
||||
int adf4382_set_phase_pol(struct adf4382_dev *dev, bool polarity);
|
||||
|
||||
/** ADF4382 Gets Phase adjustment polarity*/
|
||||
int adf4382_get_phase_pol(struct adf4382_dev *dev, bool *polarity);
|
||||
|
||||
/** ADF4382 Set EZSYNC feature attributes */
|
||||
int adf4382_set_ezsync_setup(struct adf4382_dev *dev, bool sync);
|
||||
|
||||
/** ADF4382 Set Timed SYNC feature attributes */
|
||||
int adf4382_set_timed_sync_setup(struct adf4382_dev *dev, bool sync);
|
||||
|
||||
/** ADF4382 Get EZSYNC and Timed SYNC feature attributes */
|
||||
int adf4382_get_phase_sync_setup(struct adf4382_dev *dev, bool *en);
|
||||
|
||||
/** ADF4382 Set sw_sync attribute */
|
||||
int adf4382_set_sw_sync(struct adf4382_dev *dev, bool sw_sync);
|
||||
|
||||
/** ADF4382 Get sw_sync attribute */
|
||||
int adf4382_get_sw_sync(struct adf4382_dev *dev, bool *sw_sync);
|
||||
|
||||
/** ADF4382 Set VCO calibration settings attributes */
|
||||
int adf4382_set_vco_cal_timeout(struct adf4382_dev *dev);
|
||||
|
||||
/** ADF4382 Initialization */
|
||||
int adf4382_init(struct adf4382_dev **device,
|
||||
struct adf4382_init_param *init_param);
|
||||
|
||||
/** ADF4382 Remove */
|
||||
int adf4382_remove(struct adf4382_dev *dev);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,714 @@
|
||||
#include "adf4382a_manager.h"
|
||||
#include "stm32_spi.h"
|
||||
#include "diag_log.h"
|
||||
#include "no_os_delay.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// External SPI handle
|
||||
extern SPI_HandleTypeDef hspi4;
|
||||
|
||||
// External timer for DELADJ PWM (configured in CubeMX, period = DELADJ_MAX_DUTY_CYCLE)
|
||||
// TX DELADJ uses TIM3_CH2, RX DELADJ uses TIM3_CH3
|
||||
extern TIM_HandleTypeDef htim3;
|
||||
|
||||
// Static function prototypes
|
||||
static void set_chip_enable(uint16_t ce_pin, bool state);
|
||||
static void set_deladj_pin(uint8_t device, bool state);
|
||||
static void set_delstr_pin(uint8_t device, bool state);
|
||||
static void start_deladj_pwm(uint8_t device, uint16_t duty_cycle);
|
||||
static void stop_deladj_pwm(uint8_t device);
|
||||
static uint16_t phase_ps_to_duty_cycle(uint16_t phase_ps);
|
||||
|
||||
int ADF4382A_Manager_Init(ADF4382A_Manager *manager, SyncMethod method)
|
||||
{
|
||||
struct adf4382_init_param tx_param, rx_param;
|
||||
int ret;
|
||||
uint32_t t_start = HAL_GetTick();
|
||||
|
||||
/* Platform SPI extras carry HAL handle + software CS port/pin */
|
||||
static stm32_spi_extra spi_tx_extra;
|
||||
static stm32_spi_extra spi_rx_extra;
|
||||
|
||||
DIAG_SECTION("ADF4382A LO MANAGER INIT");
|
||||
DIAG("LO", "Init called with sync_method=%d (%s)",
|
||||
method, (method == SYNC_METHOD_TIMED) ? "TIMED" : "EZSYNC");
|
||||
|
||||
if (!manager) {
|
||||
DIAG_ERR("LO", "Init called with NULL manager pointer");
|
||||
return ADF4382A_MANAGER_ERROR_INVALID;
|
||||
}
|
||||
|
||||
// Initialize manager structure
|
||||
manager->tx_dev = NULL;
|
||||
manager->rx_dev = NULL;
|
||||
manager->initialized = false;
|
||||
manager->sync_method = method;
|
||||
manager->tx_phase_shift_ps = 0;
|
||||
manager->rx_phase_shift_ps = 0;
|
||||
|
||||
DIAG("LO", "Manager struct zeroed, initialized=%s", manager->initialized ? "true" : "false");
|
||||
|
||||
// Initialize SPI parameters in manager
|
||||
memset(&manager->spi_tx_param, 0, sizeof(manager->spi_tx_param));
|
||||
memset(&manager->spi_rx_param, 0, sizeof(manager->spi_rx_param));
|
||||
|
||||
// Setup platform SPI extras with software CS for each device
|
||||
spi_tx_extra.hspi = &hspi4;
|
||||
spi_tx_extra.cs_port = TX_CS_GPIO_Port;
|
||||
spi_tx_extra.cs_pin = TX_CS_Pin;
|
||||
|
||||
spi_rx_extra.hspi = &hspi4;
|
||||
spi_rx_extra.cs_port = RX_CS_GPIO_Port;
|
||||
spi_rx_extra.cs_pin = RX_CS_Pin;
|
||||
|
||||
// Setup TX SPI parameters for SPI4
|
||||
manager->spi_tx_param.device_id = ADF4382A_SPI_DEVICE_ID;
|
||||
manager->spi_tx_param.max_speed_hz = ADF4382A_SPI_SPEED_HZ;
|
||||
manager->spi_tx_param.mode = NO_OS_SPI_MODE_0;
|
||||
manager->spi_tx_param.chip_select = TX_CS_Pin;
|
||||
manager->spi_tx_param.bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST;
|
||||
manager->spi_tx_param.platform_ops = &stm32_spi_ops;
|
||||
manager->spi_tx_param.extra = &spi_tx_extra;
|
||||
|
||||
// Setup RX SPI parameters for SPI4
|
||||
manager->spi_rx_param.device_id = ADF4382A_SPI_DEVICE_ID;
|
||||
manager->spi_rx_param.max_speed_hz = ADF4382A_SPI_SPEED_HZ;
|
||||
manager->spi_rx_param.mode = NO_OS_SPI_MODE_0;
|
||||
manager->spi_rx_param.chip_select = RX_CS_Pin;
|
||||
manager->spi_rx_param.bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST;
|
||||
manager->spi_rx_param.platform_ops = &stm32_spi_ops;
|
||||
manager->spi_rx_param.extra = &spi_rx_extra;
|
||||
|
||||
DIAG("LO", "SPI4 params: TX_CS=0x%04X RX_CS=0x%04X speed=%lu Hz platform_ops=%p",
|
||||
TX_CS_Pin, RX_CS_Pin, (unsigned long)ADF4382A_SPI_SPEED_HZ,
|
||||
(const void*)manager->spi_tx_param.platform_ops);
|
||||
|
||||
// Configure TX parameters (10.5 GHz)
|
||||
memset(&tx_param, 0, sizeof(tx_param));
|
||||
tx_param.spi_3wire_en = 0;
|
||||
tx_param.cmos_3v3 = 1;
|
||||
tx_param.ref_freq_hz = REF_FREQ_HZ;
|
||||
tx_param.ref_div = 1;
|
||||
tx_param.ref_doubler_en = false;
|
||||
tx_param.freq = TX_FREQ_HZ;
|
||||
tx_param.id = ID_ADF4382A;
|
||||
tx_param.cp_i = 3;
|
||||
tx_param.bleed_word = 1000;
|
||||
tx_param.ld_count = 0x07;
|
||||
tx_param.spi_init = &manager->spi_tx_param;
|
||||
|
||||
// Configure RX parameters (10.38 GHz)
|
||||
memset(&rx_param, 0, sizeof(rx_param));
|
||||
rx_param.spi_3wire_en = 0;
|
||||
rx_param.cmos_3v3 = 1;
|
||||
rx_param.ref_freq_hz = REF_FREQ_HZ;
|
||||
rx_param.ref_div = 1;
|
||||
rx_param.ref_doubler_en = false;
|
||||
rx_param.freq = RX_FREQ_HZ;
|
||||
rx_param.id = ID_ADF4382A;
|
||||
rx_param.cp_i = 4;
|
||||
rx_param.bleed_word = 1200;
|
||||
rx_param.ld_count = 0x07;
|
||||
rx_param.spi_init = &manager->spi_rx_param;
|
||||
|
||||
DIAG("LO", "TX target: %llu Hz, ref=%llu Hz, cp_i=%d, bleed=%d",
|
||||
(unsigned long long)TX_FREQ_HZ, (unsigned long long)REF_FREQ_HZ,
|
||||
tx_param.cp_i, tx_param.bleed_word);
|
||||
DIAG("LO", "RX target: %llu Hz, ref=%llu Hz, cp_i=%d, bleed=%d",
|
||||
(unsigned long long)RX_FREQ_HZ, (unsigned long long)REF_FREQ_HZ,
|
||||
rx_param.cp_i, rx_param.bleed_word);
|
||||
|
||||
// Enable chips
|
||||
DIAG("LO", "Asserting CE pins (TX + RX)...");
|
||||
set_chip_enable(TX_CE_Pin, true);
|
||||
set_chip_enable(RX_CE_Pin, true);
|
||||
no_os_udelay(1000);
|
||||
DIAG("LO", "CE pins asserted, waited 1 ms");
|
||||
|
||||
// Initialize DELADJ and DELSTR pins
|
||||
set_deladj_pin(0, false); // TX device
|
||||
set_deladj_pin(1, false); // RX device
|
||||
set_delstr_pin(0, false); // TX device
|
||||
set_delstr_pin(1, false); // RX device
|
||||
DIAG("LO", "DELADJ/DELSTR pins initialized to LOW");
|
||||
|
||||
// Initialize TX device first
|
||||
DIAG("LO", "--- TX ADF4382A init (10.5 GHz) ---");
|
||||
uint32_t t_tx = HAL_GetTick();
|
||||
printf("Initializing TX ADF4382A (10.5 GHz) on SPI4...\n");
|
||||
ret = adf4382_init(&manager->tx_dev, &tx_param);
|
||||
DIAG("LO", "TX adf4382_init() returned %d (took %lu ms)",
|
||||
ret, (unsigned long)(HAL_GetTick() - t_tx));
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "TX init FAILED: %d -- disabling CE pins", ret);
|
||||
printf("TX ADF4382A initialization failed: %d\n", ret);
|
||||
set_chip_enable(TX_CE_Pin, false);
|
||||
set_chip_enable(RX_CE_Pin, false);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
DIAG("LO", "TX init OK, dev_ptr=%p", (void*)manager->tx_dev);
|
||||
|
||||
// Small delay between initializations
|
||||
no_os_udelay(5000);
|
||||
DIAG("LO", "5 ms inter-device delay complete");
|
||||
|
||||
// Initialize RX device
|
||||
DIAG("LO", "--- RX ADF4382A init (10.38 GHz) ---");
|
||||
uint32_t t_rx = HAL_GetTick();
|
||||
printf("Initializing RX ADF4382A (10.38 GHz) on SPI4...\n");
|
||||
ret = adf4382_init(&manager->rx_dev, &rx_param);
|
||||
DIAG("LO", "RX adf4382_init() returned %d (took %lu ms)",
|
||||
ret, (unsigned long)(HAL_GetTick() - t_rx));
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "RX init FAILED: %d -- cleaning up TX dev", ret);
|
||||
printf("RX ADF4382A initialization failed: %d\n", ret);
|
||||
adf4382_remove(manager->tx_dev);
|
||||
set_chip_enable(TX_CE_Pin, false);
|
||||
set_chip_enable(RX_CE_Pin, false);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
DIAG("LO", "RX init OK, dev_ptr=%p", (void*)manager->rx_dev);
|
||||
|
||||
// Set output power
|
||||
DIAG("LO", "Setting output power (both ch0=12, ch1=12)...");
|
||||
adf4382_set_out_power(manager->tx_dev, 0, 12);
|
||||
adf4382_set_out_power(manager->tx_dev, 1, 12);
|
||||
adf4382_set_out_power(manager->rx_dev, 0, 12);
|
||||
adf4382_set_out_power(manager->rx_dev, 1, 12);
|
||||
|
||||
// Enable outputs
|
||||
DIAG("LO", "Enabling outputs: TX_ch0=ON TX_ch1=OFF, RX_ch0=ON RX_ch1=OFF");
|
||||
adf4382_set_en_chan(manager->tx_dev, 0, true);
|
||||
adf4382_set_en_chan(manager->tx_dev, 1, false);
|
||||
adf4382_set_en_chan(manager->rx_dev, 0, true);
|
||||
adf4382_set_en_chan(manager->rx_dev, 1, false);
|
||||
|
||||
// Mark initialized BEFORE sync setup so SetupTimedSync/SetupEZSync
|
||||
// see initialized=true and actually configure the hardware.
|
||||
// (FIX for Bug #1: previously this was set AFTER the sync calls,
|
||||
// causing them to always return -2 NOT_INIT.)
|
||||
manager->initialized = true;
|
||||
DIAG("LO", "manager->initialized set to true (before sync setup)");
|
||||
|
||||
// Setup synchronization based on selected method
|
||||
DIAG("LO", "About to call sync setup -- manager->initialized=%s",
|
||||
manager->initialized ? "true" : "false");
|
||||
|
||||
if (method == SYNC_METHOD_TIMED) {
|
||||
ret = ADF4382A_SetupTimedSync(manager);
|
||||
DIAG("LO", "ADF4382A_SetupTimedSync() returned %d", ret);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "Timed sync setup FAILED: %d", ret);
|
||||
printf("Timed sync setup failed: %d\n", ret);
|
||||
manager->initialized = false;
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = ADF4382A_SetupEZSync(manager);
|
||||
DIAG("LO", "ADF4382A_SetupEZSync() returned %d", ret);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "EZSync setup FAILED: %d", ret);
|
||||
printf("EZSync setup failed: %d\n", ret);
|
||||
manager->initialized = false;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
printf("ADF4382A Manager initialized with %s synchronization on SPI4\n",
|
||||
(method == SYNC_METHOD_TIMED) ? "TIMED" : "EZSYNC");
|
||||
|
||||
DIAG_ELAPSED("LO", "Total Manager_Init", t_start);
|
||||
DIAG("LO", "Init returning OK (sync setup %s)",
|
||||
(ret == 0) ? "successful" : "had warnings");
|
||||
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_SetupTimedSync(ADF4382A_Manager *manager)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DIAG("LO", "SetupTimedSync called, manager=%p initialized=%s",
|
||||
(void*)manager, (manager ? (manager->initialized ? "true" : "false") : "N/A"));
|
||||
|
||||
if (!manager || !manager->initialized) {
|
||||
DIAG_ERR("LO", "SetupTimedSync REJECTED: %s",
|
||||
!manager ? "NULL manager" : "not initialized (initialized=false)");
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
printf("Setting up Timed Synchronization (60 MHz SYNCP/SYNCN)...\n");
|
||||
|
||||
// Setup TX for timed sync
|
||||
ret = adf4382_set_timed_sync_setup(manager->tx_dev, true);
|
||||
DIAG("LO", "TX adf4382_set_timed_sync_setup() returned %d", ret);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "TX timed sync register write FAILED: %d", ret);
|
||||
printf("TX timed sync setup failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Setup RX for timed sync
|
||||
ret = adf4382_set_timed_sync_setup(manager->rx_dev, true);
|
||||
DIAG("LO", "RX adf4382_set_timed_sync_setup() returned %d", ret);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "RX timed sync register write FAILED: %d", ret);
|
||||
printf("RX timed sync setup failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
manager->sync_method = SYNC_METHOD_TIMED;
|
||||
printf("Timed synchronization configured for 60 MHz SYNCP/SYNCN\n");
|
||||
DIAG("LO", "Timed sync setup complete for both TX and RX");
|
||||
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_SetupEZSync(ADF4382A_Manager *manager)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DIAG("LO", "SetupEZSync called, manager=%p initialized=%s",
|
||||
(void*)manager, (manager ? (manager->initialized ? "true" : "false") : "N/A"));
|
||||
|
||||
if (!manager || !manager->initialized) {
|
||||
DIAG_ERR("LO", "SetupEZSync REJECTED: %s",
|
||||
!manager ? "NULL manager" : "not initialized (initialized=false)");
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
printf("Setting up EZSync (SPI-based synchronization)...\n");
|
||||
|
||||
// Setup TX for EZSync
|
||||
ret = adf4382_set_ezsync_setup(manager->tx_dev, true);
|
||||
DIAG("LO", "TX adf4382_set_ezsync_setup() returned %d", ret);
|
||||
if (ret) {
|
||||
printf("TX EZSync setup failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Setup RX for EZSync
|
||||
ret = adf4382_set_ezsync_setup(manager->rx_dev, true);
|
||||
DIAG("LO", "RX adf4382_set_ezsync_setup() returned %d", ret);
|
||||
if (ret) {
|
||||
printf("RX EZSync setup failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
manager->sync_method = SYNC_METHOD_EZSYNC;
|
||||
printf("EZSync configured\n");
|
||||
DIAG("LO", "EZSync setup complete for both TX and RX");
|
||||
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_TriggerTimedSync(ADF4382A_Manager *manager)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!manager || !manager->initialized || manager->sync_method != SYNC_METHOD_TIMED) {
|
||||
DIAG_ERR("LO", "TriggerTimedSync REJECTED: init=%s method=%d",
|
||||
(manager && manager->initialized) ? "true" : "false",
|
||||
manager ? manager->sync_method : -1);
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
DIAG("LO", "Triggering timed sync via sw_sync pulse (SYNCP/SYNCN must be present)...");
|
||||
|
||||
// Arm the sync capture on both devices via sw_sync.
|
||||
// With timed_sync_setup already programmed, the device will synchronize
|
||||
// its output dividers to the next SYNCP/SYNCN rising edge after sw_sync
|
||||
// is asserted.
|
||||
ret = adf4382_set_sw_sync(manager->tx_dev, true);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "TX timed sw_sync SET failed: %d", ret);
|
||||
printf("TX timed sync trigger failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
ret = adf4382_set_sw_sync(manager->rx_dev, true);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "RX timed sw_sync SET failed: %d", ret);
|
||||
printf("RX timed sync trigger failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
// Wait for at least one sync clock cycle (60 MHz = 16.7 ns period).
|
||||
// 10 us is conservative — guarantees multiple sync edges are captured.
|
||||
no_os_udelay(10);
|
||||
|
||||
// De-assert sw_sync
|
||||
ret = adf4382_set_sw_sync(manager->tx_dev, false);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "TX timed sw_sync CLEAR failed: %d", ret);
|
||||
printf("TX timed sync clear failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
ret = adf4382_set_sw_sync(manager->rx_dev, false);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "RX timed sw_sync CLEAR failed: %d", ret);
|
||||
printf("RX timed sync clear failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
printf("Timed sync triggered via sw_sync pulse\n");
|
||||
DIAG("LO", "Timed sync trigger complete (sw_sync set + 10us + clear)");
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_TriggerEZSync(ADF4382A_Manager *manager)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!manager || !manager->initialized || manager->sync_method != SYNC_METHOD_EZSYNC) {
|
||||
DIAG_ERR("LO", "TriggerEZSync REJECTED");
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
DIAG("LO", "Triggering EZSync via SPI...");
|
||||
|
||||
// Trigger software sync on both devices
|
||||
ret = adf4382_set_sw_sync(manager->tx_dev, true);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "TX sw_sync SET failed: %d", ret);
|
||||
printf("TX software sync failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
ret = adf4382_set_sw_sync(manager->rx_dev, true);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "RX sw_sync SET failed: %d", ret);
|
||||
printf("RX software sync failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
// Small delay for sync to take effect
|
||||
no_os_udelay(10);
|
||||
|
||||
// Clear software sync
|
||||
ret = adf4382_set_sw_sync(manager->tx_dev, false);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "TX sw_sync CLEAR failed: %d", ret);
|
||||
printf("TX sync clear failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
ret = adf4382_set_sw_sync(manager->rx_dev, false);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "RX sw_sync CLEAR failed: %d", ret);
|
||||
printf("RX sync clear failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
printf("EZSync triggered via SPI\n");
|
||||
DIAG("LO", "EZSync trigger complete (set + 10us + clear)");
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_Manager_Deinit(ADF4382A_Manager *manager)
|
||||
{
|
||||
if (!manager || !manager->initialized) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
DIAG("LO", "Manager deinit starting...");
|
||||
|
||||
// Disable outputs first
|
||||
if (manager->tx_dev) {
|
||||
adf4382_set_en_chan(manager->tx_dev, 0, false);
|
||||
adf4382_set_en_chan(manager->tx_dev, 1, false);
|
||||
}
|
||||
|
||||
if (manager->rx_dev) {
|
||||
adf4382_set_en_chan(manager->rx_dev, 0, false);
|
||||
adf4382_set_en_chan(manager->rx_dev, 1, false);
|
||||
}
|
||||
|
||||
// Remove devices
|
||||
if (manager->tx_dev) {
|
||||
adf4382_remove(manager->tx_dev);
|
||||
manager->tx_dev = NULL;
|
||||
}
|
||||
|
||||
if (manager->rx_dev) {
|
||||
adf4382_remove(manager->rx_dev);
|
||||
manager->rx_dev = NULL;
|
||||
}
|
||||
|
||||
// Disable chips and phase control pins
|
||||
set_chip_enable(TX_CE_Pin, false);
|
||||
set_chip_enable(RX_CE_Pin, false);
|
||||
set_deladj_pin(0, false);
|
||||
set_deladj_pin(1, false);
|
||||
set_delstr_pin(0, false);
|
||||
set_delstr_pin(1, false);
|
||||
|
||||
manager->initialized = false;
|
||||
|
||||
printf("ADF4382A Manager deinitialized\n");
|
||||
DIAG("LO", "Manager deinit complete");
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_CheckLockStatus(ADF4382A_Manager *manager, bool *tx_locked, bool *rx_locked)
|
||||
{
|
||||
uint8_t tx_status, rx_status;
|
||||
int ret;
|
||||
|
||||
if (!manager || !manager->initialized || !tx_locked || !rx_locked) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
// Read lock status from registers
|
||||
ret = adf4382_spi_read(manager->tx_dev, 0x58, &tx_status);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "TX lock status SPI read FAILED: %d", ret);
|
||||
printf("TX lock status read failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
ret = adf4382_spi_read(manager->rx_dev, 0x58, &rx_status);
|
||||
if (ret) {
|
||||
DIAG_ERR("LO", "RX lock status SPI read FAILED: %d", ret);
|
||||
printf("RX lock status read failed: %d\n", ret);
|
||||
return ADF4382A_MANAGER_ERROR_SPI;
|
||||
}
|
||||
|
||||
bool tx_reg_locked = (tx_status & ADF4382_LOCKED_MSK) != 0;
|
||||
bool rx_reg_locked = (rx_status & ADF4382_LOCKED_MSK) != 0;
|
||||
|
||||
// Also check GPIO lock detect pins as backup
|
||||
bool tx_gpio_locked = HAL_GPIO_ReadPin(TX_LKDET_GPIO_Port, TX_LKDET_Pin) == GPIO_PIN_SET;
|
||||
bool rx_gpio_locked = HAL_GPIO_ReadPin(RX_LKDET_GPIO_Port, RX_LKDET_Pin) == GPIO_PIN_SET;
|
||||
|
||||
// Diagnostic: show both register and GPIO readings independently
|
||||
DIAG("LO", "Lock check: TX reg[0x58]=0x%02X(%s) GPIO=%s | RX reg[0x58]=0x%02X(%s) GPIO=%s",
|
||||
tx_status, tx_reg_locked ? "LK" : "UNL", tx_gpio_locked ? "HI" : "LO",
|
||||
rx_status, rx_reg_locked ? "LK" : "UNL", rx_gpio_locked ? "HI" : "LO");
|
||||
|
||||
// Flag disagreement between register and GPIO
|
||||
if (tx_reg_locked != tx_gpio_locked) {
|
||||
DIAG_WARN("LO", "TX LOCK DISAGREE: reg=%s GPIO=%s -- possible pin mapping issue",
|
||||
tx_reg_locked ? "LOCKED" : "UNLOCKED",
|
||||
tx_gpio_locked ? "HIGH" : "LOW");
|
||||
}
|
||||
if (rx_reg_locked != rx_gpio_locked) {
|
||||
DIAG_WARN("LO", "RX LOCK DISAGREE: reg=%s GPIO=%s -- possible pin mapping issue",
|
||||
rx_reg_locked ? "LOCKED" : "UNLOCKED",
|
||||
rx_gpio_locked ? "HIGH" : "LOW");
|
||||
}
|
||||
|
||||
// Use both register and GPIO status
|
||||
*tx_locked = tx_reg_locked && tx_gpio_locked;
|
||||
*rx_locked = rx_reg_locked && rx_gpio_locked;
|
||||
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_SetOutputPower(ADF4382A_Manager *manager, uint8_t tx_power, uint8_t rx_power)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!manager || !manager->initialized) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
// Clamp power values (0-15)
|
||||
tx_power = (tx_power > 15) ? 15 : tx_power;
|
||||
rx_power = (rx_power > 15) ? 15 : rx_power;
|
||||
|
||||
DIAG("LO", "SetOutputPower: TX=%d RX=%d", tx_power, rx_power);
|
||||
|
||||
// Set TX power for both channels
|
||||
ret = adf4382_set_out_power(manager->tx_dev, 0, tx_power);
|
||||
if (ret) return ret;
|
||||
ret = adf4382_set_out_power(manager->tx_dev, 1, tx_power);
|
||||
if (ret) return ret;
|
||||
|
||||
// Set RX power for both channels
|
||||
ret = adf4382_set_out_power(manager->rx_dev, 0, rx_power);
|
||||
if (ret) return ret;
|
||||
ret = adf4382_set_out_power(manager->rx_dev, 1, rx_power);
|
||||
|
||||
printf("Output power set: TX=%d, RX=%d\n", tx_power, rx_power);
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_EnableOutputs(ADF4382A_Manager *manager, bool tx_enable, bool rx_enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!manager || !manager->initialized) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
DIAG("LO", "EnableOutputs: TX=%s RX=%s",
|
||||
tx_enable ? "ON" : "OFF", rx_enable ? "ON" : "OFF");
|
||||
|
||||
// Enable/disable TX outputs
|
||||
ret = adf4382_set_en_chan(manager->tx_dev, 0, tx_enable);
|
||||
if (ret) return ret;
|
||||
ret = adf4382_set_en_chan(manager->tx_dev, 1, tx_enable);
|
||||
if (ret) return ret;
|
||||
|
||||
// Enable/disable RX outputs
|
||||
ret = adf4382_set_en_chan(manager->rx_dev, 0, rx_enable);
|
||||
if (ret) return ret;
|
||||
ret = adf4382_set_en_chan(manager->rx_dev, 1, rx_enable);
|
||||
|
||||
printf("Outputs: TX=%s, RX=%s\n",
|
||||
tx_enable ? "ENABLED" : "DISABLED",
|
||||
rx_enable ? "ENABLED" : "DISABLED");
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
// New phase delay functions
|
||||
|
||||
int ADF4382A_SetPhaseShift(ADF4382A_Manager *manager, uint16_t tx_phase_ps, uint16_t rx_phase_ps)
|
||||
{
|
||||
if (!manager || !manager->initialized) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
// Clamp phase shift values
|
||||
tx_phase_ps = (tx_phase_ps > PHASE_SHIFT_MAX_PS) ? PHASE_SHIFT_MAX_PS : tx_phase_ps;
|
||||
rx_phase_ps = (rx_phase_ps > PHASE_SHIFT_MAX_PS) ? PHASE_SHIFT_MAX_PS : rx_phase_ps;
|
||||
|
||||
DIAG("LO", "SetPhaseShift: TX=%d ps, RX=%d ps", tx_phase_ps, rx_phase_ps);
|
||||
|
||||
// Convert phase shift to duty cycle and apply
|
||||
if (tx_phase_ps != manager->tx_phase_shift_ps) {
|
||||
uint16_t duty_cycle = phase_ps_to_duty_cycle(tx_phase_ps);
|
||||
DIAG("LO", "TX phase: %d ps -> duty_cycle=%d/%d (TIM3 CH2 PWM)",
|
||||
tx_phase_ps, duty_cycle, DELADJ_MAX_DUTY_CYCLE);
|
||||
ADF4382A_SetFinePhaseShift(manager, 0, duty_cycle); // 0 = TX device
|
||||
manager->tx_phase_shift_ps = tx_phase_ps;
|
||||
}
|
||||
|
||||
if (rx_phase_ps != manager->rx_phase_shift_ps) {
|
||||
uint16_t duty_cycle = phase_ps_to_duty_cycle(rx_phase_ps);
|
||||
DIAG("LO", "RX phase: %d ps -> duty_cycle=%d/%d (TIM3 CH3 PWM)",
|
||||
rx_phase_ps, duty_cycle, DELADJ_MAX_DUTY_CYCLE);
|
||||
ADF4382A_SetFinePhaseShift(manager, 1, duty_cycle); // 1 = RX device
|
||||
manager->rx_phase_shift_ps = rx_phase_ps;
|
||||
}
|
||||
|
||||
printf("Phase shift set: TX=%d ps, RX=%d ps\n", tx_phase_ps, rx_phase_ps);
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_GetPhaseShift(ADF4382A_Manager *manager, uint16_t *tx_phase_ps, uint16_t *rx_phase_ps)
|
||||
{
|
||||
if (!manager || !manager->initialized || !tx_phase_ps || !rx_phase_ps) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
*tx_phase_ps = manager->tx_phase_shift_ps;
|
||||
*rx_phase_ps = manager->rx_phase_shift_ps;
|
||||
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_SetFinePhaseShift(ADF4382A_Manager *manager, uint8_t device, uint16_t duty_cycle)
|
||||
{
|
||||
if (!manager || !manager->initialized) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
// Clamp duty cycle
|
||||
duty_cycle = (duty_cycle > DELADJ_MAX_DUTY_CYCLE) ? DELADJ_MAX_DUTY_CYCLE : duty_cycle;
|
||||
|
||||
if (duty_cycle == 0) {
|
||||
// Fully OFF: stop PWM, drive pin LOW
|
||||
stop_deladj_pwm(device);
|
||||
set_deladj_pin(device, false);
|
||||
DIAG("LO", "Dev%d DELADJ=LOW (duty=0, PWM stopped)", device);
|
||||
} else if (duty_cycle >= DELADJ_MAX_DUTY_CYCLE) {
|
||||
// Fully ON: stop PWM, drive pin HIGH
|
||||
stop_deladj_pwm(device);
|
||||
set_deladj_pin(device, true);
|
||||
DIAG("LO", "Dev%d DELADJ=HIGH (duty=max, PWM stopped)", device);
|
||||
} else {
|
||||
// Intermediate: use TIM3 PWM output
|
||||
// The PWM output is low-pass filtered externally to produce a DC
|
||||
// voltage proportional to the duty cycle for the ADF4382 DELADJ input.
|
||||
start_deladj_pwm(device, duty_cycle);
|
||||
DIAG("LO", "Dev%d DELADJ PWM started: duty=%d/%d (%.1f%%)",
|
||||
device, duty_cycle, DELADJ_MAX_DUTY_CYCLE,
|
||||
(float)duty_cycle * 100.0f / DELADJ_MAX_DUTY_CYCLE);
|
||||
}
|
||||
|
||||
printf("Device %d DELADJ duty cycle set to %d/%d\n",
|
||||
device, duty_cycle, DELADJ_MAX_DUTY_CYCLE);
|
||||
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
int ADF4382A_StrobePhaseShift(ADF4382A_Manager *manager, uint8_t device)
|
||||
{
|
||||
if (!manager || !manager->initialized) {
|
||||
return ADF4382A_MANAGER_ERROR_NOT_INIT;
|
||||
}
|
||||
|
||||
DIAG("LO", "Dev%d DELSTR strobe (%d us pulse)", device, DELADJ_PULSE_WIDTH_US);
|
||||
|
||||
// Generate a pulse on DELSTR pin to latch the current DELADJ value
|
||||
set_delstr_pin(device, true);
|
||||
no_os_udelay(DELADJ_PULSE_WIDTH_US);
|
||||
set_delstr_pin(device, false);
|
||||
|
||||
printf("Device %d phase shift strobed\n", device);
|
||||
|
||||
return ADF4382A_MANAGER_OK;
|
||||
}
|
||||
|
||||
// Static helper functions
|
||||
|
||||
static void set_chip_enable(uint16_t ce_pin, bool state)
|
||||
{
|
||||
GPIO_TypeDef* port = (ce_pin == TX_CE_Pin) ? TX_CE_GPIO_Port : RX_CE_GPIO_Port;
|
||||
HAL_GPIO_WritePin(port, ce_pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
static void set_deladj_pin(uint8_t device, bool state)
|
||||
{
|
||||
if (device == 0) { // TX device
|
||||
HAL_GPIO_WritePin(TX_DELADJ_GPIO_Port, TX_DELADJ_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
} else { // RX device
|
||||
HAL_GPIO_WritePin(RX_DELADJ_GPIO_Port, RX_DELADJ_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_delstr_pin(uint8_t device, bool state)
|
||||
{
|
||||
if (device == 0) { // TX device
|
||||
HAL_GPIO_WritePin(TX_DELSTR_GPIO_Port, TX_DELSTR_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
} else { // RX device
|
||||
HAL_GPIO_WritePin(RX_DELSTR_GPIO_Port, RX_DELSTR_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_deladj_pwm(uint8_t device, uint16_t duty_cycle)
|
||||
{
|
||||
// TX DELADJ → TIM3_CH2, RX DELADJ → TIM3_CH3
|
||||
// Timer period (ARR) is configured to DELADJ_MAX_DUTY_CYCLE in CubeMX.
|
||||
uint32_t channel = (device == 0) ? TIM_CHANNEL_2 : TIM_CHANNEL_3;
|
||||
__HAL_TIM_SET_COMPARE(&htim3, channel, (uint32_t)duty_cycle);
|
||||
HAL_TIM_PWM_Start(&htim3, channel);
|
||||
}
|
||||
|
||||
static void stop_deladj_pwm(uint8_t device)
|
||||
{
|
||||
uint32_t channel = (device == 0) ? TIM_CHANNEL_2 : TIM_CHANNEL_3;
|
||||
HAL_TIM_PWM_Stop(&htim3, channel);
|
||||
}
|
||||
|
||||
static uint16_t phase_ps_to_duty_cycle(uint16_t phase_ps)
|
||||
{
|
||||
// Convert phase shift in picoseconds to DELADJ duty cycle
|
||||
// This is a linear mapping - adjust based on your specific requirements
|
||||
uint32_t duty = (uint32_t)phase_ps * DELADJ_MAX_DUTY_CYCLE / PHASE_SHIFT_MAX_PS;
|
||||
return (uint16_t)duty;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifndef ADF4382A_MANAGER_H
|
||||
#define ADF4382A_MANAGER_H
|
||||
|
||||
#include "main.h"
|
||||
#include "adf4382.h"
|
||||
#include "no_os_spi.h"
|
||||
|
||||
// GPIO Definitions — matched to CubeMX main.h (GPIOG pins 6-15)
|
||||
// RX pins: GPIOG pins 6-10
|
||||
#define RX_LKDET_Pin GPIO_PIN_6
|
||||
#define RX_LKDET_GPIO_Port GPIOG
|
||||
#define RX_DELADJ_Pin GPIO_PIN_7
|
||||
#define RX_DELADJ_GPIO_Port GPIOG
|
||||
#define RX_DELSTR_Pin GPIO_PIN_8
|
||||
#define RX_DELSTR_GPIO_Port GPIOG
|
||||
#define RX_CE_Pin GPIO_PIN_9
|
||||
#define RX_CE_GPIO_Port GPIOG
|
||||
#define RX_CS_Pin GPIO_PIN_10
|
||||
#define RX_CS_GPIO_Port GPIOG
|
||||
|
||||
// TX pins: GPIOG pins 11-15
|
||||
#define TX_LKDET_Pin GPIO_PIN_11
|
||||
#define TX_LKDET_GPIO_Port GPIOG
|
||||
#define TX_DELSTR_Pin GPIO_PIN_12
|
||||
#define TX_DELSTR_GPIO_Port GPIOG
|
||||
#define TX_DELADJ_Pin GPIO_PIN_13
|
||||
#define TX_DELADJ_GPIO_Port GPIOG
|
||||
#define TX_CS_Pin GPIO_PIN_14
|
||||
#define TX_CS_GPIO_Port GPIOG
|
||||
#define TX_CE_Pin GPIO_PIN_15
|
||||
#define TX_CE_GPIO_Port GPIOG
|
||||
|
||||
// Frequency definitions
|
||||
#define REF_FREQ_HZ 300000000ULL // 300 MHz
|
||||
#define TX_FREQ_HZ 10500000000ULL // 10.5 GHz
|
||||
#define RX_FREQ_HZ 10380000000ULL // 10.38 GHz
|
||||
#define SYNC_CLOCK_FREQ 60000000ULL // 60 MHz sync clock
|
||||
|
||||
// SPI Configuration
|
||||
#define ADF4382A_SPI_DEVICE_ID 4 // Using SPI4
|
||||
#define ADF4382A_SPI_SPEED_HZ 10000000 // 10 MHz
|
||||
|
||||
// Phase delay configuration
|
||||
#define DELADJ_MAX_DUTY_CYCLE 1000 // Maximum duty cycle for DELADJ PWM (1000 = 100%)
|
||||
#define DELADJ_PULSE_WIDTH_US 10 // Width of DELSTR pulse in microseconds
|
||||
#define PHASE_SHIFT_MAX_PS 10000 // Maximum phase shift in picoseconds
|
||||
|
||||
// Error code definitions
|
||||
#define ADF4382A_MANAGER_OK 0
|
||||
#define ADF4382A_MANAGER_ERROR_INVALID -1
|
||||
#define ADF4382A_MANAGER_ERROR_NOT_INIT -2
|
||||
#define ADF4382A_MANAGER_ERROR_SPI -3
|
||||
|
||||
typedef enum {
|
||||
SYNC_METHOD_EZSYNC = 0, // Software synchronization via SPI
|
||||
SYNC_METHOD_TIMED = 1 // Hardware synchronization via SYNCP/SYNCN
|
||||
} SyncMethod;
|
||||
|
||||
typedef struct {
|
||||
struct adf4382_dev *tx_dev;
|
||||
struct adf4382_dev *rx_dev;
|
||||
struct no_os_spi_init_param spi_tx_param;
|
||||
struct no_os_spi_init_param spi_rx_param;
|
||||
bool initialized;
|
||||
SyncMethod sync_method;
|
||||
uint16_t tx_phase_shift_ps; // Current TX phase shift in picoseconds
|
||||
uint16_t rx_phase_shift_ps; // Current RX phase shift in picoseconds
|
||||
} ADF4382A_Manager;
|
||||
|
||||
// Public functions
|
||||
int ADF4382A_Manager_Init(ADF4382A_Manager *manager, SyncMethod method);
|
||||
int ADF4382A_Manager_Deinit(ADF4382A_Manager *manager);
|
||||
int ADF4382A_SetupTimedSync(ADF4382A_Manager *manager);
|
||||
int ADF4382A_SetupEZSync(ADF4382A_Manager *manager);
|
||||
int ADF4382A_TriggerTimedSync(ADF4382A_Manager *manager);
|
||||
int ADF4382A_TriggerEZSync(ADF4382A_Manager *manager);
|
||||
int ADF4382A_CheckLockStatus(ADF4382A_Manager *manager, bool *tx_locked, bool *rx_locked);
|
||||
int ADF4382A_SetOutputPower(ADF4382A_Manager *manager, uint8_t tx_power, uint8_t rx_power);
|
||||
int ADF4382A_EnableOutputs(ADF4382A_Manager *manager, bool tx_enable, bool rx_enable);
|
||||
|
||||
// New phase delay functions
|
||||
int ADF4382A_SetPhaseShift(ADF4382A_Manager *manager, uint16_t tx_phase_ps, uint16_t rx_phase_ps);
|
||||
int ADF4382A_GetPhaseShift(ADF4382A_Manager *manager, uint16_t *tx_phase_ps, uint16_t *rx_phase_ps);
|
||||
int ADF4382A_SetFinePhaseShift(ADF4382A_Manager *manager, uint8_t device, uint16_t duty_cycle);
|
||||
int ADF4382A_StrobePhaseShift(ADF4382A_Manager *manager, uint8_t device);
|
||||
|
||||
#endif // ADF4382A_MANAGER_H
|
||||
126
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/diag_log.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/***************************************************************************//**
|
||||
* @file diag_log.h
|
||||
* @brief Bring-up diagnostic logging macros for AERIS-10 radar system.
|
||||
*
|
||||
* Provides timestamped, subsystem-tagged diagnostic output over USART3.
|
||||
* All output is observation-only instrumentation -- no behavioral changes.
|
||||
*
|
||||
* Usage:
|
||||
* #include "diag_log.h"
|
||||
* DIAG("LO", "TX init returned %d", ret);
|
||||
* DIAG_WARN("CLK", "PLL2 not locked after %lu ms", timeout);
|
||||
* DIAG_ERR("PA", "IDQ out of range: %d mA", idq_ma);
|
||||
* DIAG_REG("LO", "TX reg 0x58", reg_val);
|
||||
* DIAG_GPIO("LO", "TX_LKDET", port, pin);
|
||||
*
|
||||
* Compile-time control:
|
||||
* #define DIAG_DISABLE -- suppress all DIAG output
|
||||
* #define DIAG_VERBOSE -- include file:line in every message
|
||||
*
|
||||
* @author AERIS-10 Bring-up Instrumentation
|
||||
* @date 2026
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef DIAG_LOG_H
|
||||
#define DIAG_LOG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "stm32f7xx_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Core DIAG macro -- timestamped, subsystem-tagged printf.
|
||||
* Uses HAL_GetTick() for millisecond timestamps.
|
||||
* Output format: "[ 12345 ms] LO: TX init returned -2\n"
|
||||
*/
|
||||
#ifndef DIAG_DISABLE
|
||||
|
||||
#ifdef DIAG_VERBOSE
|
||||
#define DIAG(subsys, fmt, ...) \
|
||||
printf("[%7lu ms] %s: " fmt " (%s:%d)\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, ##__VA_ARGS__, __FILE__, __LINE__)
|
||||
#else
|
||||
#define DIAG(subsys, fmt, ...) \
|
||||
printf("[%7lu ms] %s: " fmt "\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Severity-tagged variants */
|
||||
#define DIAG_WARN(subsys, fmt, ...) \
|
||||
printf("[%7lu ms] %s WARN: " fmt "\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, ##__VA_ARGS__)
|
||||
|
||||
#define DIAG_ERR(subsys, fmt, ...) \
|
||||
printf("[%7lu ms] %s **ERR**: " fmt "\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, ##__VA_ARGS__)
|
||||
|
||||
/* Register read diagnostic -- prints hex value */
|
||||
#define DIAG_REG(subsys, name, val) \
|
||||
printf("[%7lu ms] %s: %s = 0x%02X\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, name, (unsigned int)(val))
|
||||
|
||||
/* Register read diagnostic -- 32-bit variant */
|
||||
#define DIAG_REG32(subsys, name, val) \
|
||||
printf("[%7lu ms] %s: %s = 0x%08lX\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, name, (unsigned long)(val))
|
||||
|
||||
/* GPIO pin state diagnostic */
|
||||
#define DIAG_GPIO(subsys, name, port, pin) \
|
||||
printf("[%7lu ms] %s: GPIO %s = %s\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, name, \
|
||||
(HAL_GPIO_ReadPin(port, pin) == GPIO_PIN_SET) ? "HIGH" : "LOW")
|
||||
|
||||
/* Boolean condition diagnostic */
|
||||
#define DIAG_BOOL(subsys, name, val) \
|
||||
printf("[%7lu ms] %s: %s = %s\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, name, (val) ? "YES" : "NO")
|
||||
|
||||
/* Section separator for init sequence readability */
|
||||
#define DIAG_SECTION(title) \
|
||||
printf("[%7lu ms] ======== %s ========\n", \
|
||||
(unsigned long)HAL_GetTick(), title)
|
||||
|
||||
/* Elapsed time helper -- use with a captured start tick */
|
||||
#define DIAG_ELAPSED(subsys, label, start_tick) \
|
||||
printf("[%7lu ms] %s: %s took %lu ms\n", \
|
||||
(unsigned long)HAL_GetTick(), subsys, label, \
|
||||
(unsigned long)(HAL_GetTick() - (start_tick)))
|
||||
|
||||
#else /* DIAG_DISABLE */
|
||||
|
||||
#define DIAG(subsys, fmt, ...) ((void)0)
|
||||
#define DIAG_WARN(subsys, fmt, ...) ((void)0)
|
||||
#define DIAG_ERR(subsys, fmt, ...) ((void)0)
|
||||
#define DIAG_REG(subsys, name, val) ((void)0)
|
||||
#define DIAG_REG32(subsys, name, val) ((void)0)
|
||||
#define DIAG_GPIO(subsys, name, port, pin) ((void)0)
|
||||
#define DIAG_BOOL(subsys, name, val) ((void)0)
|
||||
#define DIAG_SECTION(title) ((void)0)
|
||||
#define DIAG_ELAPSED(subsys, label, start) ((void)0)
|
||||
|
||||
#endif /* DIAG_DISABLE */
|
||||
|
||||
/*
|
||||
* Subsystem tag constants -- use these for consistency:
|
||||
* "CLK" -- AD9523 clock generator
|
||||
* "LO" -- ADF4382A LO synthesizers (manager level)
|
||||
* "LO_DRV" -- ADF4382 low-level driver
|
||||
* "BF" -- ADAR1000 beamformer
|
||||
* "PA" -- Power amplifier bias/monitoring
|
||||
* "FPGA" -- FPGA communication and handshake
|
||||
* "USB" -- USB data path (FT2232H production / FT601 premium)
|
||||
* "PWR" -- Power sequencing and rail monitoring
|
||||
* "IMU" -- IMU/GPS/barometer sensors
|
||||
* "MOT" -- Stepper motor/scan mechanics
|
||||
* "SYS" -- System-level init, health, safe-mode
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DIAG_LOG_H */
|
||||
100
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/errno.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/***************************************************************************//**
|
||||
* @file errno.h
|
||||
* @brief Error macro definition for ARM Compiler
|
||||
********************************************************************************
|
||||
* Copyright (c) 2021-2022 Analog Devices, Inc.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MBED_ERRNO_H_
|
||||
#define MBED_ERRNO_H_
|
||||
|
||||
// Platform drivers needs to be C-compatible to work with other drivers
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // _cplusplus
|
||||
|
||||
#if defined(__ARMCC_VERSION)
|
||||
#if !defined(__ELASTERROR)
|
||||
#define __ELASTERROR 2000
|
||||
#endif
|
||||
#if !defined(ENOTSUP)
|
||||
#define ENOTSUP 9926
|
||||
#endif
|
||||
#if !defined(EBADMSG)
|
||||
#define EBADMSG 9905
|
||||
#endif
|
||||
#if !defined(ETIME)
|
||||
#define ETIME 9935
|
||||
#endif
|
||||
#if !defined(EACCES)
|
||||
#define EACCES 9973
|
||||
#endif
|
||||
#if !defined(ETIMEDOUT)
|
||||
#define ETIMEDOUT 9938
|
||||
#endif
|
||||
#if !defined(ENODEV)
|
||||
#define ENODEV 9967
|
||||
#endif
|
||||
#if !defined(EFAULT)
|
||||
#define EFAULT 9948
|
||||
#endif
|
||||
#if !defined(EIO)
|
||||
#define EIO 9961
|
||||
#endif
|
||||
#if !defined(ENOENT)
|
||||
#define ENOENT 9968
|
||||
#endif
|
||||
#if !defined(EBUSY)
|
||||
#define EBUSY 9952
|
||||
#endif
|
||||
#if !defined(EAGAIN)
|
||||
#define EAGAIN 9976
|
||||
#endif
|
||||
#if !defined(EINVAL)
|
||||
#define EINVAL 9943
|
||||
#endif
|
||||
#if !defined(ENOMEM)
|
||||
#define ENOMEM 9971
|
||||
#endif
|
||||
#if !defined(ENOSYS)
|
||||
#define ENOSYS 88
|
||||
#endif
|
||||
#if !defined(ENOTCONN)
|
||||
#define ENOTCONN 128
|
||||
#endif
|
||||
|
||||
// End of defined(__ARMCC_VERSION)
|
||||
#endif
|
||||
|
||||
#include_next <errno.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // _cplusplus
|
||||
|
||||
#endif // MBED_ERRNO_H_
|
||||
@@ -0,0 +1,130 @@
|
||||
// gps_handler.cpp
|
||||
#include "gps_handler.h"
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
// UART handle for communication with GUI
|
||||
static UART_HandleTypeDef* gui_huart = NULL;
|
||||
|
||||
// GPS data buffer
|
||||
static GPS_Data_t current_gps = {0};
|
||||
|
||||
void GPS_Init(UART_HandleTypeDef* huart)
|
||||
{
|
||||
gui_huart = huart;
|
||||
memset(¤t_gps, 0, sizeof(GPS_Data_t));
|
||||
}
|
||||
|
||||
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data)
|
||||
{
|
||||
if (gps_data == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if GPS data is within valid ranges
|
||||
if (gps_data->latitude < -90.0 || gps_data->latitude > 90.0)
|
||||
return 0;
|
||||
if (gps_data->longitude < -180.0 || gps_data->longitude > 180.0)
|
||||
return 0;
|
||||
if (gps_data->altitude < -1000.0 || gps_data->altitude > 10000.0) // -1km to 10km
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GPS_ProcessData(GPS_Data_t* gps_data)
|
||||
{
|
||||
// Validate GPS data
|
||||
if (!GPS_IsDataValid(gps_data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update current GPS data
|
||||
memcpy(¤t_gps, gps_data, sizeof(GPS_Data_t));
|
||||
current_gps.timestamp = HAL_GetTick();
|
||||
|
||||
// Send to GUI
|
||||
return GPS_SendToGUI(¤t_gps);
|
||||
}
|
||||
|
||||
bool GPS_SendToGUI(GPS_Data_t* gps_data)
|
||||
{
|
||||
if (gui_huart == NULL || gps_data == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create packet: "GPS:lat,lon,alt\r\n"
|
||||
char buffer[64];
|
||||
|
||||
// Convert double and float to string with high precision
|
||||
int len = snprintf(buffer, sizeof(buffer), "GPS:%.8f,%.8f,%.2f\r\n",
|
||||
gps_data->latitude,
|
||||
gps_data->longitude,
|
||||
gps_data->altitude);
|
||||
|
||||
if (len <= 0 || len >= (int)sizeof(buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send via UART3 to GUI
|
||||
return HAL_UART_Transmit(gui_huart, (uint8_t*)buffer, len, 1000) == HAL_OK;
|
||||
}
|
||||
|
||||
// Alternative binary protocol version (more efficient)
|
||||
bool GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
|
||||
{
|
||||
if (gui_huart == NULL || gps_data == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Binary packet structure:
|
||||
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
|
||||
|
||||
uint8_t packet[30]; // 4 + 8 + 8 + 4 + 4 + 2 = 30 bytes
|
||||
uint16_t crc = 0;
|
||||
|
||||
// Header: "GPSB"
|
||||
packet[0] = 'G';
|
||||
packet[1] = 'P';
|
||||
packet[2] = 'S';
|
||||
packet[3] = 'B';
|
||||
|
||||
// Convert double latitude to bytes (big-endian)
|
||||
uint64_t lat_bits;
|
||||
memcpy(&lat_bits, &gps_data->latitude, sizeof(double));
|
||||
for(int i = 0; i < 8; i++) {
|
||||
packet[4 + i] = (lat_bits >> (56 - i*8)) & 0xFF;
|
||||
}
|
||||
|
||||
// Convert double longitude to bytes (big-endian)
|
||||
uint64_t lon_bits;
|
||||
memcpy(&lon_bits, &gps_data->longitude, sizeof(double));
|
||||
for(int i = 0; i < 8; i++) {
|
||||
packet[12 + i] = (lon_bits >> (56 - i*8)) & 0xFF;
|
||||
}
|
||||
|
||||
// Convert float altitude to bytes (big-endian)
|
||||
uint32_t alt_bits;
|
||||
memcpy(&alt_bits, &gps_data->altitude, sizeof(float));
|
||||
for(int i = 0; i < 4; i++) {
|
||||
packet[20 + i] = (alt_bits >> (24 - i*8)) & 0xFF;
|
||||
}
|
||||
|
||||
// Convert float pitch to bytes (big-endian)
|
||||
uint32_t pitch_bits;
|
||||
memcpy(&pitch_bits, &gps_data->pitch, sizeof(float));
|
||||
for(int i = 0; i < 4; i++) {
|
||||
packet[24 + i] = (pitch_bits >> (24 - i*8)) & 0xFF;
|
||||
}
|
||||
|
||||
// Calculate simple checksum (you can use CRC16 instead)
|
||||
for(int i = 0; i < 28; i++) {
|
||||
crc += packet[i];
|
||||
}
|
||||
|
||||
packet[28] = (crc >> 8) & 0xFF;
|
||||
packet[29] = crc & 0xFF;
|
||||
|
||||
// Send binary packet
|
||||
return CDC_Transmit_FS(packet, sizeof(packet)) == USBD_OK;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// gps_handler.h
|
||||
#ifndef GPS_HANDLER_H
|
||||
#define GPS_HANDLER_H
|
||||
|
||||
#include "main.h"
|
||||
#include "usb_device.h"
|
||||
#include "usbd_cdc_if.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
double latitude;
|
||||
double longitude;
|
||||
float altitude;
|
||||
float pitch;
|
||||
uint32_t timestamp;
|
||||
} GPS_Data_t;
|
||||
|
||||
void GPS_Init(UART_HandleTypeDef* huart);
|
||||
bool GPS_ProcessData(GPS_Data_t* gps_data);
|
||||
bool GPS_SendToGUI(GPS_Data_t* gps_data);
|
||||
bool GPS_SendBinaryToGUI(GPS_Data_t* gps_data);
|
||||
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GPS_HANDLER_H */
|
||||
2039
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.c
Normal file
143
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/***************************************************************************//**
|
||||
* @file iio.h
|
||||
* @brief Header file of iio
|
||||
* @author Cristian Pop (cristian.pop@analog.com)
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2013(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef IIO_H_
|
||||
#define IIO_H_
|
||||
|
||||
#include "iio_types.h"
|
||||
#include "no_os_uart.h"
|
||||
#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING)
|
||||
#include "tcp_socket.h"
|
||||
#endif
|
||||
|
||||
enum physical_link_type {
|
||||
USE_UART,
|
||||
USE_LOCAL_BACKEND,
|
||||
USE_NETWORK
|
||||
};
|
||||
|
||||
struct iio_desc;
|
||||
|
||||
struct iio_device_init {
|
||||
char *name;
|
||||
void *dev;
|
||||
struct iio_device *dev_descriptor;
|
||||
/*
|
||||
* IIO buffer implementation can use a user provided buffer in raw_buf.
|
||||
* If raw_buf is NULL and iio_device has buffer callback function set,
|
||||
* it will allocate memory for it when needed.
|
||||
*/
|
||||
int8_t *raw_buf;
|
||||
/* Length of raw_buf */
|
||||
uint32_t raw_buf_len;
|
||||
/* If set, trigger will be linked to this device */
|
||||
char *trigger_id;
|
||||
};
|
||||
|
||||
struct iio_trigger_init {
|
||||
char *name;
|
||||
void *trig;
|
||||
struct iio_trigger *descriptor;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_ctx_attr
|
||||
* @brief Structure holding the context attribute members
|
||||
*/
|
||||
struct iio_ctx_attr {
|
||||
/** Attribute name */
|
||||
const char *name;
|
||||
/** Attribute value */
|
||||
const char *value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_local_backend
|
||||
* @brief Structure holding the local backend init parameters
|
||||
*/
|
||||
struct iio_local_backend {
|
||||
int(*local_backend_event_read)(void *conn, uint8_t *buf, uint32_t len);
|
||||
int(*local_backend_event_write)(void *conn, uint8_t *buf, uint32_t len);
|
||||
char *local_backend_buff;
|
||||
uint32_t local_backend_buff_len;
|
||||
};
|
||||
|
||||
struct iio_init_param {
|
||||
enum physical_link_type phy_type;
|
||||
union {
|
||||
struct no_os_uart_desc *uart_desc;
|
||||
#if defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING)
|
||||
struct tcp_socket_init_param *tcp_socket_init_param;
|
||||
#endif
|
||||
};
|
||||
struct iio_local_backend *local_backend;
|
||||
struct iio_ctx_attr *ctx_attrs;
|
||||
uint32_t nb_ctx_attr;
|
||||
struct iio_device_init *devs;
|
||||
uint32_t nb_devs;
|
||||
struct iio_trigger_init *trigs;
|
||||
uint32_t nb_trigs;
|
||||
};
|
||||
|
||||
/* Set communication ops and read/write ops. */
|
||||
int iio_init(struct iio_desc **desc, struct iio_init_param *init_param);
|
||||
/* Free the resources allocated by iio_init(). */
|
||||
int iio_remove(struct iio_desc *desc);
|
||||
/* Execut an iio step. */
|
||||
int iio_step(struct iio_desc *desc);
|
||||
/* Signal iio that a trigger has been triggered.
|
||||
* This will be called in interrupt context. An application callback will be
|
||||
called in interrupt context if trigger is synchronous with the interrupt
|
||||
(is_synchronous = true) or will be called from iio_step if trigger is
|
||||
asynchronous (is_synchronous = false) */
|
||||
int iio_process_trigger_type(struct iio_desc *desc, char *trigger_name);
|
||||
|
||||
int32_t iio_parse_value(char *buf, enum iio_val fmt,
|
||||
int32_t *val, int32_t *val2);
|
||||
int iio_format_value(char *buf, uint32_t len, enum iio_val fmt,
|
||||
int32_t size, int32_t *vals);
|
||||
|
||||
/* DMA buffer functions. */
|
||||
/* Get buffer addr where to write iio_buffer.size bytes */
|
||||
int iio_buffer_get_block(struct iio_buffer *buffer, void **addr);
|
||||
/* To be called to mark last iio_buffer_read as done */
|
||||
int iio_buffer_block_done(struct iio_buffer *buffer);
|
||||
|
||||
/* Trigger buffer functions. */
|
||||
/* Write to buffer iio_buffer.bytes_per_scan bytes from data */
|
||||
int iio_buffer_push_scan(struct iio_buffer *buffer, void *data);
|
||||
/* Read from buffer iio_buffer.bytes_per_scan bytes into data */
|
||||
int iio_buffer_pop_scan(struct iio_buffer *buffer, void *data);
|
||||
|
||||
#endif /* IIO_H_ */
|
||||
475
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.c
Normal file
@@ -0,0 +1,475 @@
|
||||
/***************************************************************************//**
|
||||
* @file iio_app.c
|
||||
* @brief C file of iio_app
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifdef IIO_SUPPORT
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "iio_app.h"
|
||||
#include "parameters.h"
|
||||
#include "no_os_alloc.h"
|
||||
|
||||
#if defined(ADUCM_PLATFORM)
|
||||
#include "aducm3029_uart.h"
|
||||
#include "aducm3029_irq.h"
|
||||
#endif
|
||||
#if defined(XILINX_PLATFORM)
|
||||
#include "xilinx_uart.h"
|
||||
#include "xilinx_irq.h"
|
||||
#endif
|
||||
#if defined(STM32_PLATFORM)
|
||||
#include <errno.h>
|
||||
#include "stm32_uart.h"
|
||||
#include "stm32_irq.h"
|
||||
#endif
|
||||
#if defined(MAXIM_PLATFORM)
|
||||
#include "maxim_irq.h"
|
||||
#include "maxim_uart.h"
|
||||
#endif
|
||||
|
||||
#ifdef NO_OS_NETWORKING
|
||||
/* Fix: Use static buffers instead of calloc for new connections */
|
||||
#warning "iio may not work with WIFI on aducm3029."
|
||||
#ifdef ADUCM_PLATFORM
|
||||
#include "wifi.h"
|
||||
#endif
|
||||
#include "tcp_socket.h"
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_PLATFORM
|
||||
#include "linux_socket.h"
|
||||
#include "tcp_socket.h"
|
||||
#endif
|
||||
|
||||
#ifdef NO_OS_LWIP_NETWORKING
|
||||
#include "lwip_socket.h"
|
||||
#endif
|
||||
|
||||
// The default baudrate iio_app will use to print messages to console.
|
||||
#define UART_BAUDRATE_DEFAULT 115200
|
||||
#define UART_STOPBITS_DEFAULT NO_OS_UART_STOP_1_BIT
|
||||
|
||||
static inline uint32_t _calc_uart_xfer_time(uint32_t len, uint32_t baudrate)
|
||||
{
|
||||
uint32_t ms = 1000ul * len * 8 / UART_BAUDRATE_DEFAULT;
|
||||
ms += ms / 10; // overhead
|
||||
return ms;
|
||||
}
|
||||
|
||||
#if !defined(LINUX_PLATFORM) && !defined(NO_OS_NETWORKING) && !defined(NO_OS_USB_UART)
|
||||
static int32_t iio_print_uart_info_message(struct no_os_uart_desc **uart_desc,
|
||||
struct no_os_uart_init_param *user_uart_params,
|
||||
char *message, int32_t msglen)
|
||||
{
|
||||
int32_t status;
|
||||
uint32_t delay_ms;
|
||||
|
||||
status = no_os_uart_write(*uart_desc, (uint8_t *)message, msglen);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
delay_ms = _calc_uart_xfer_time(msglen, UART_BAUDRATE_DEFAULT);
|
||||
no_os_mdelay(delay_ms);
|
||||
|
||||
/** Reinitialize UART with parameters required by the IIO application */
|
||||
no_os_uart_remove(*uart_desc);
|
||||
return no_os_uart_init(uart_desc, user_uart_params);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int32_t print_uart_hello_message(struct no_os_uart_desc **uart_desc,
|
||||
struct no_os_uart_init_param *user_uart_params)
|
||||
{
|
||||
#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART)
|
||||
return 0;
|
||||
#else
|
||||
const char *uart_data_size[] = { "5", "6", "7", "8", "9" };
|
||||
const char *uart_parity[] = { "none", "mark", "space", "odd", "even" };
|
||||
const char *uart_stop[] = { "1", "2" };
|
||||
char message[512];
|
||||
uint32_t msglen = sprintf(message,
|
||||
"Running IIOD server...\n"
|
||||
"If successful, you may connect an IIO client application by:\n"
|
||||
"1. Disconnecting the serial terminal you use to view this message.\n"
|
||||
"2. Connecting the IIO client application using the serial backend configured as shown:\n"
|
||||
"\tBaudrate: %lu\n"
|
||||
"\tData size: %s bits\n"
|
||||
"\tParity: %s\n"
|
||||
"\tStop bits: %s\n"
|
||||
"\tFlow control: none\n",
|
||||
user_uart_params->baud_rate,
|
||||
uart_data_size[user_uart_params->size],
|
||||
uart_parity[user_uart_params->parity],
|
||||
uart_stop[user_uart_params->stop]);
|
||||
|
||||
return iio_print_uart_info_message(uart_desc, user_uart_params,
|
||||
message, msglen);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int32_t print_uart_error_message(struct no_os_uart_desc **uart_desc,
|
||||
struct no_os_uart_init_param *user_uart_params,
|
||||
int32_t status)
|
||||
{
|
||||
char message[512];
|
||||
uint32_t msglen = sprintf(message,
|
||||
"IIOD server failed with code %d.\n",
|
||||
(int)status);
|
||||
#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART)
|
||||
(void)msglen;
|
||||
printf("%s", message);
|
||||
return 0;
|
||||
#else
|
||||
return iio_print_uart_info_message(uart_desc, user_uart_params,
|
||||
message, msglen);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(NO_OS_LWIP_NETWORKING)
|
||||
static int32_t lwip_network_setup(struct iio_app_desc *app,
|
||||
struct iio_app_init_param param,
|
||||
struct iio_init_param *iio_init_param)
|
||||
{
|
||||
static struct tcp_socket_init_param socket_param;
|
||||
static struct lwip_network_desc lwip_desc;
|
||||
static bool is_initialized = false;
|
||||
int ret;
|
||||
|
||||
if (NO_OS_LWIP_INIT_ONETIME && is_initialized) {
|
||||
socket_param.net = &lwip_desc.no_os_net;
|
||||
} else {
|
||||
ret = no_os_lwip_init(&app->lwip_desc, ¶m.lwip_param);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
socket_param.net = &app->lwip_desc->no_os_net;
|
||||
memcpy(&lwip_desc, app->lwip_desc, sizeof(lwip_desc));
|
||||
}
|
||||
|
||||
is_initialized = true;
|
||||
socket_param.max_buff_size = 0;
|
||||
|
||||
iio_init_param->phy_type = USE_NETWORK;
|
||||
iio_init_param->tcp_socket_init_param = &socket_param;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM)
|
||||
static int32_t network_setup(struct iio_init_param *iio_init_param,
|
||||
struct no_os_uart_desc *uart_desc,
|
||||
void *irq_desc)
|
||||
{
|
||||
static struct tcp_socket_init_param socket_param;
|
||||
|
||||
#ifdef LINUX_PLATFORM
|
||||
socket_param.net = &linux_net;
|
||||
#endif
|
||||
#ifdef ADUCM_PLATFORM
|
||||
int32_t status;
|
||||
static struct wifi_desc *wifi;
|
||||
struct wifi_init_param wifi_param = {
|
||||
.irq_desc = irq_desc,
|
||||
.uart_desc = uart_desc,
|
||||
.uart_irq_conf = uart_desc,
|
||||
.uart_irq_id = UART_IRQ_ID,
|
||||
.sw_reset_en = true
|
||||
};
|
||||
status = wifi_init(&wifi, &wifi_param);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
status = wifi_connect(wifi, WIFI_SSID, WIFI_PWD);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
char buff[100];
|
||||
wifi_get_ip(wifi, buff, 100);
|
||||
printf("iiod ip is: %s\n", buff);
|
||||
|
||||
wifi_get_network_interface(wifi, &socket_param.net);
|
||||
#endif
|
||||
|
||||
socket_param.max_buff_size = 0;
|
||||
iio_init_param->phy_type = USE_NETWORK;
|
||||
iio_init_param->tcp_socket_init_param = &socket_param;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int32_t uart_setup(struct no_os_uart_desc **uart_desc,
|
||||
struct no_os_uart_init_param *uart_init_par)
|
||||
{
|
||||
#if defined(LINUX_PLATFORM) || defined(NO_OS_LWIP_NETWORKING)
|
||||
*uart_desc = NULL;
|
||||
return 0;
|
||||
#endif
|
||||
struct no_os_uart_init_param luart_par = {
|
||||
.device_id = uart_init_par->device_id,
|
||||
/* TODO: remove this ifdef when asynchrounous rx is implemented on every platform. */
|
||||
#if defined(STM32_PLATFORM) || defined(MAXIM_PLATFORM) || defined(ADUCM_PLATFORM) || defined(PICO_PLATFORM)
|
||||
.irq_id = uart_init_par->irq_id,
|
||||
.asynchronous_rx = true,
|
||||
#endif
|
||||
.baud_rate = UART_BAUDRATE_DEFAULT,
|
||||
.size = NO_OS_UART_CS_8,
|
||||
.parity = NO_OS_UART_PAR_NO,
|
||||
.stop = NO_OS_UART_STOP_1_BIT,
|
||||
.platform_ops = uart_init_par->platform_ops,
|
||||
#ifndef ADUCM_PLATFORM
|
||||
.extra = uart_init_par->extra
|
||||
#endif
|
||||
};
|
||||
|
||||
return no_os_uart_init(uart_desc, &luart_par);
|
||||
}
|
||||
|
||||
#if defined(ADUCM_PLATFORM) || (defined(STM32_PLATFORM)) || defined(MAXIM_PLATFORM)
|
||||
static int32_t irq_setup(struct no_os_irq_ctrl_desc **irq_desc)
|
||||
{
|
||||
int32_t status;
|
||||
#if defined(ADUCM_PLATFORM)
|
||||
void *platform_irq_init_par = NULL;
|
||||
const struct no_os_irq_platform_ops *platform_irq_ops = &aducm_irq_ops;
|
||||
#elif defined(STM32_PLATFORM)
|
||||
void *platform_irq_init_par = NULL;
|
||||
const struct no_os_irq_platform_ops *platform_irq_ops = &stm32_irq_ops;
|
||||
#elif defined(MAXIM_PLATFORM)
|
||||
void *platform_irq_init_par = NULL;
|
||||
const struct no_os_irq_platform_ops *platform_irq_ops = &max_irq_ops;
|
||||
#endif
|
||||
|
||||
struct no_os_irq_init_param irq_init_param = {
|
||||
.irq_ctrl_id = INTC_DEVICE_ID,
|
||||
.platform_ops = platform_irq_ops,
|
||||
.extra = platform_irq_init_par
|
||||
};
|
||||
|
||||
status = no_os_irq_ctrl_init(irq_desc, &irq_init_param);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
return no_os_irq_global_enable(*irq_desc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Register devices for an iio application
|
||||
*
|
||||
* Configuration for communication is done in parameters.h
|
||||
* @param app - the iio application descriptor
|
||||
* @param app_init_param - the iio application initialization parameters
|
||||
* @return 0 on success, negative value otherwise
|
||||
*/
|
||||
int iio_app_init(struct iio_app_desc **app,
|
||||
struct iio_app_init_param app_init_param)
|
||||
{
|
||||
struct iio_device_init *iio_init_devs = NULL;
|
||||
struct iio_init_param iio_init_param;
|
||||
struct no_os_uart_desc *uart_desc;
|
||||
struct iio_app_desc *application;
|
||||
struct iio_data_buffer *buff;
|
||||
unsigned int i;
|
||||
int status;
|
||||
void *irq_desc = app_init_param.irq_desc;
|
||||
|
||||
application = (struct iio_app_desc *)no_os_calloc(1, sizeof(*application));
|
||||
if (!application)
|
||||
return -ENOMEM;
|
||||
|
||||
application->post_step_callback = app_init_param.post_step_callback;
|
||||
application->arg = app_init_param.arg;
|
||||
|
||||
#if defined(ADUCM_PLATFORM) || defined(STM32_PLATFORM)
|
||||
/* Only one irq controller can exist and be initialized in
|
||||
* any of the iio_devices. */
|
||||
for (i = 0; i < app_init_param.nb_devices; i++) {
|
||||
if (app_init_param.devices[i].dev_descriptor->irq_desc) {
|
||||
irq_desc = (struct no_os_irq_ctrl_desc *)
|
||||
app_init_param.devices[i].dev_descriptor->irq_desc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!irq_desc) {
|
||||
status = irq_setup((struct no_os_irq_ctrl_desc **)&irq_desc);
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
status = uart_setup(&uart_desc, &app_init_param.uart_init_params);
|
||||
if (status < 0)
|
||||
goto error_uart;
|
||||
|
||||
status = print_uart_hello_message(&uart_desc,
|
||||
&app_init_param.uart_init_params);
|
||||
if (status < 0)
|
||||
goto error;
|
||||
|
||||
application->uart_desc = uart_desc;
|
||||
#if defined(NO_OS_LWIP_NETWORKING)
|
||||
status = lwip_network_setup(application, app_init_param, &iio_init_param);
|
||||
if (status)
|
||||
goto error;
|
||||
#elif defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM)
|
||||
status = network_setup(&iio_init_param, uart_desc, application->irq_desc);
|
||||
if (status < 0)
|
||||
goto error;
|
||||
#else
|
||||
iio_init_param.phy_type = USE_UART;
|
||||
iio_init_param.uart_desc = uart_desc;
|
||||
#endif
|
||||
|
||||
iio_init_devs = no_os_calloc(app_init_param.nb_devices, sizeof(*iio_init_devs));
|
||||
if (!iio_init_devs) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < app_init_param.nb_devices; ++i) {
|
||||
/*
|
||||
* iio_app_device is from iio_app.h and we don't want to include
|
||||
* this in iio.h.
|
||||
* At the moment iio_device_init has the same parameters but
|
||||
* it will change.
|
||||
* When changes are done in iio. iio_app_device may be removed
|
||||
*iio_init_param and use iio_device_init instead.
|
||||
* This way faster changes can be done without changing all
|
||||
* project for each change.
|
||||
*/
|
||||
iio_init_devs[i].name = app_init_param.devices[i].name;
|
||||
iio_init_devs[i].dev = app_init_param.devices[i].dev;
|
||||
iio_init_devs[i].dev_descriptor = app_init_param.devices[i].dev_descriptor;
|
||||
iio_init_devs[i].trigger_id = app_init_param.devices[i].default_trigger_id;
|
||||
buff = app_init_param.devices[i].read_buff ?
|
||||
app_init_param.devices[i].read_buff :
|
||||
app_init_param.devices[i].write_buff;
|
||||
if (buff) {
|
||||
iio_init_devs[i].raw_buf = buff->buff;
|
||||
iio_init_devs[i].raw_buf_len = buff->size;
|
||||
} else {
|
||||
iio_init_devs[i].raw_buf = NULL;
|
||||
iio_init_devs[i].raw_buf_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
iio_init_param.devs = iio_init_devs;
|
||||
iio_init_param.nb_devs = app_init_param.nb_devices;
|
||||
iio_init_param.trigs = app_init_param.trigs;
|
||||
iio_init_param.nb_trigs = app_init_param.nb_trigs;
|
||||
iio_init_param.ctx_attrs = app_init_param.ctx_attrs;
|
||||
iio_init_param.nb_ctx_attr = app_init_param.nb_ctx_attr;
|
||||
|
||||
status = iio_init(&application->iio_desc, &iio_init_param);
|
||||
if (status < 0)
|
||||
goto error;
|
||||
|
||||
no_os_free(iio_init_devs);
|
||||
|
||||
*app = application;
|
||||
|
||||
return 0;
|
||||
error_uart:
|
||||
/** We might have to reinit UART, settings might have changed for IIO */
|
||||
uart_setup(&uart_desc, &app_init_param.uart_init_params);
|
||||
error:
|
||||
no_os_free(iio_init_devs);
|
||||
|
||||
no_os_free(application);
|
||||
|
||||
print_uart_error_message(&uart_desc, &app_init_param.uart_init_params, status);
|
||||
no_os_uart_remove(uart_desc);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an IIO application
|
||||
*
|
||||
* Configuration for communication is done through iio_app_init_param
|
||||
* @param app - the iio application parameters
|
||||
* @return 0 on success, negative value otherwise
|
||||
*/
|
||||
int iio_app_run(struct iio_app_desc *app)
|
||||
{
|
||||
int status;
|
||||
|
||||
do {
|
||||
status = iio_step(app->iio_desc);
|
||||
if (status && status != -EAGAIN && status != -ENOTCONN
|
||||
&& status != -NO_OS_EOVERRUN)
|
||||
return status;
|
||||
if (app->post_step_callback) {
|
||||
status = app->post_step_callback(app->arg);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove resources allocated by the IIO application
|
||||
*
|
||||
* Configuration for communication is done through iio_app_init_param
|
||||
* @param app - the iio application parameters
|
||||
* @return 0 on success, negative value otherwise
|
||||
*/
|
||||
int iio_app_remove(struct iio_app_desc *app)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(ADUCM_PLATFORM) || (defined(XILINX_PLATFORM) && !defined(PLATFORM_MB)) || defined(STM32_PLATFORM)
|
||||
ret = no_os_irq_ctrl_remove(app->irq_desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
if (app->uart_desc) {
|
||||
ret = no_os_uart_remove(app->uart_desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_remove(app->iio_desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
no_os_free(app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
138
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_app.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/***************************************************************************//**
|
||||
* @file iio_app.h
|
||||
* @brief Header file of iio_app
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2013(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef IIO_APP
|
||||
#define IIO_APP
|
||||
|
||||
#include "iio.h"
|
||||
#include "no_os_irq.h"
|
||||
#include "no_os_uart.h"
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_delay.h"
|
||||
|
||||
#if defined(NO_OS_LWIP_NETWORKING)
|
||||
#include "lwip_socket.h"
|
||||
#endif
|
||||
|
||||
#define IIO_APP_DEVICE(_name, _dev, _dev_descriptor, _read_buff, _write_buff, _default_trigger_id) {\
|
||||
.name = _name,\
|
||||
.dev = _dev,\
|
||||
.dev_descriptor = _dev_descriptor,\
|
||||
.read_buff = _read_buff,\
|
||||
.write_buff = _write_buff,\
|
||||
.default_trigger_id = _default_trigger_id\
|
||||
}
|
||||
|
||||
#define IIO_APP_TRIGGER(_name, _trig, _trig_descriptor) {\
|
||||
.name = _name,\
|
||||
.trig = _trig,\
|
||||
.descriptor = _trig_descriptor,\
|
||||
}
|
||||
|
||||
struct iio_data_buffer {
|
||||
uint32_t size;
|
||||
void *buff;
|
||||
};
|
||||
|
||||
struct iio_app_device {
|
||||
char *name;
|
||||
void *dev;
|
||||
struct iio_device *dev_descriptor;
|
||||
struct iio_data_buffer *read_buff;
|
||||
struct iio_data_buffer *write_buff;
|
||||
char *default_trigger_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_app_desc
|
||||
* @brief IIO application descriptor.
|
||||
*/
|
||||
struct iio_app_desc {
|
||||
/** UART descriptor to be used */
|
||||
struct no_os_uart_desc *uart_desc;
|
||||
/** IRQ descriptor to be used */
|
||||
void *irq_desc;
|
||||
/** IIO descriptor to be returned */
|
||||
struct iio_desc *iio_desc;
|
||||
/** Function to be called each step */
|
||||
int (*post_step_callback)(void *arg);
|
||||
/** Function parameteres */
|
||||
void *arg;
|
||||
|
||||
#ifdef NO_OS_LWIP_NETWORKING
|
||||
struct lwip_network_desc *lwip_desc;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_app_init_param
|
||||
* @brief IIO application descriptor initialization parameters.
|
||||
*/
|
||||
struct iio_app_init_param {
|
||||
/** Array of context attribute name/value pairs */
|
||||
struct iio_ctx_attr *ctx_attrs;
|
||||
/** Number of context attributes in the array above */
|
||||
uint32_t nb_ctx_attr;
|
||||
/** Array of IIO devices */
|
||||
struct iio_app_device *devices;
|
||||
/** Number of devices */
|
||||
uint32_t nb_devices;
|
||||
/** IIO triggers to be used */
|
||||
struct iio_trigger_init *trigs;
|
||||
/** Number of triggers to be used */
|
||||
int32_t nb_trigs;
|
||||
/** UART init params */
|
||||
struct no_os_uart_init_param uart_init_params;
|
||||
/** IRQ descriptor to be used */
|
||||
void *irq_desc;
|
||||
/** Function to be called each step */
|
||||
int (*post_step_callback)(void *arg);
|
||||
/** Function parameteres */
|
||||
void *arg;
|
||||
|
||||
#ifdef NO_OS_LWIP_NETWORKING
|
||||
struct lwip_network_param lwip_param;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Register devices for an IIO application */
|
||||
int iio_app_init(struct iio_app_desc **app,
|
||||
struct iio_app_init_param app_init_param);
|
||||
|
||||
/** Start an IIO application */
|
||||
int iio_app_run(struct iio_app_desc *app);
|
||||
|
||||
/** Remove resources allocated by the IIO application */
|
||||
int iio_app_remove(struct iio_app_desc *app);
|
||||
|
||||
#endif
|
||||
227
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/***************************************************************************//**
|
||||
* @file iio_trigger.c
|
||||
* @brief Implementation of generic iio trigger.
|
||||
* @author RBolboac (ramona.bolboaca@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2022(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_alloc.h"
|
||||
#include "iio.h"
|
||||
#include "iio_trigger.h"
|
||||
|
||||
#ifndef LINUX_PLATFORM
|
||||
/**
|
||||
* @brief Initialize hardware trigger.
|
||||
*
|
||||
* @param iio_trig - The iio trigger structure.
|
||||
* @param init_param - The structure that contains the trigger initial params.
|
||||
*
|
||||
* @return ret - Result of the initialization procedure.
|
||||
*/
|
||||
int iio_hw_trig_init(struct iio_hw_trig **iio_trig,
|
||||
struct iio_hw_trig_init_param *init_param)
|
||||
{
|
||||
struct iio_hw_trig *trig_desc;
|
||||
int ret;
|
||||
|
||||
if (!init_param->name)
|
||||
return -EINVAL;
|
||||
|
||||
trig_desc = (struct iio_hw_trig*)no_os_calloc(1, sizeof(*trig_desc));
|
||||
if (!trig_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
trig_desc->iio_desc = init_param->iio_desc;
|
||||
strncpy(trig_desc->name, init_param->name, TRIG_MAX_NAME_SIZE);
|
||||
trig_desc->irq_ctrl = init_param->irq_ctrl;
|
||||
trig_desc->irq_id = init_param->irq_id;
|
||||
trig_desc->irq_trig_lvl = init_param->irq_trig_lvl;
|
||||
|
||||
struct no_os_callback_desc irq_cb = {
|
||||
.callback = iio_hw_trig_handler,
|
||||
.ctx = trig_desc,
|
||||
.event = init_param->cb_info.event,
|
||||
.handle = init_param->cb_info.handle,
|
||||
.peripheral = init_param->cb_info.peripheral
|
||||
};
|
||||
|
||||
ret = no_os_irq_register_callback(trig_desc->irq_ctrl,
|
||||
trig_desc->irq_id, &irq_cb);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
if (init_param->cb_info.event == NO_OS_EVT_GPIO) {
|
||||
ret = no_os_irq_trigger_level_set(trig_desc->irq_ctrl,
|
||||
trig_desc->irq_id, trig_desc->irq_trig_lvl);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
*iio_trig = trig_desc;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
no_os_free(trig_desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable system interrupt which is linked to the given trigger.
|
||||
*
|
||||
* @param trig - Trigger structure.
|
||||
*
|
||||
* @return ret - Result of the enable procedure.
|
||||
*/
|
||||
int iio_trig_enable(void *trig)
|
||||
{
|
||||
if (!trig)
|
||||
return -EINVAL;
|
||||
|
||||
struct iio_hw_trig *desc = trig;
|
||||
|
||||
return no_os_irq_enable(desc->irq_ctrl, desc->irq_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable system interrupt which is linked to the given trigger.
|
||||
*
|
||||
* @param trig - Trigger structure.
|
||||
*
|
||||
* @return ret - Result of the disable procedure.
|
||||
*/
|
||||
int iio_trig_disable(void *trig)
|
||||
{
|
||||
if (!trig)
|
||||
return -EINVAL;
|
||||
|
||||
struct iio_hw_trig *desc = trig;
|
||||
|
||||
return no_os_irq_disable(desc->irq_ctrl, desc->irq_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Trigger interrupt handler. This function will be called when a system
|
||||
* interrupt is asserted for the configured trigger.
|
||||
*
|
||||
* @param trig - Trigger structure which is linked to this handler.
|
||||
*/
|
||||
void iio_hw_trig_handler(void *trig)
|
||||
{
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
struct iio_hw_trig *desc = trig;
|
||||
|
||||
iio_process_trigger_type(desc->iio_desc, desc->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by iio_hw_trig_init().
|
||||
*
|
||||
* @param trig - The trigger structure.
|
||||
*
|
||||
* @return ret - Result of the remove procedure.
|
||||
*/
|
||||
int iio_hw_trig_remove(struct iio_hw_trig *trig)
|
||||
{
|
||||
if (trig)
|
||||
no_os_free(trig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize software trigger.
|
||||
*
|
||||
* @param iio_trig - The iio trigger structure.
|
||||
* @param init_param - The structure that contains the sw trigger initial params.
|
||||
*
|
||||
* @return ret - Result of the initialization procedure.
|
||||
*/
|
||||
int iio_sw_trig_init(struct iio_sw_trig **iio_trig,
|
||||
struct iio_sw_trig_init_param *init_param)
|
||||
{
|
||||
struct iio_sw_trig *trig_desc;
|
||||
|
||||
if (!init_param->iio_desc || !init_param->name)
|
||||
return -EINVAL;
|
||||
|
||||
trig_desc = (struct iio_sw_trig*)no_os_calloc(1, sizeof(*trig_desc));
|
||||
if (!trig_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
trig_desc->iio_desc = init_param->iio_desc;
|
||||
strncpy(trig_desc->name, init_param->name, TRIG_MAX_NAME_SIZE);
|
||||
|
||||
*iio_trig = trig_desc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles the write request for trigger_now attribute.
|
||||
*
|
||||
* @param trig - The iio trigger structure.
|
||||
* @param buf - Command buffer to be filled with the data to be written.
|
||||
* @param len - Length of the received command buffer in bytes.
|
||||
* @param channel - Command channel info (is NULL).
|
||||
* @param priv - Command attribute id.
|
||||
*
|
||||
* @return ret - Result of the sw trigger handler procedure.
|
||||
*/
|
||||
int iio_sw_trig_handler(void *trig, char *buf, uint32_t len,
|
||||
const struct iio_ch_info *channel,
|
||||
intptr_t priv)
|
||||
{
|
||||
if (!trig)
|
||||
return -EINVAL;
|
||||
|
||||
struct iio_sw_trig *desc = trig;
|
||||
|
||||
return iio_process_trigger_type(desc->iio_desc, desc->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by iio_sw_trig_init().
|
||||
*
|
||||
* @param trig - The trigger structure.
|
||||
*
|
||||
* @return ret - Result of the remove procedure.
|
||||
*/
|
||||
int iio_sw_trig_remove(struct iio_sw_trig *trig)
|
||||
{
|
||||
if (trig)
|
||||
no_os_free(trig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
138
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_trigger.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/***************************************************************************//**
|
||||
* @file iio_trigger.h
|
||||
* @brief Header file for iio_trigger.
|
||||
* @author RBolboac(ramona.bolboaca@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2022(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef IIO_TRIGGER_H_
|
||||
#define IIO_TRIGGER_H_
|
||||
|
||||
#include "iio.h"
|
||||
#include "iio_types.h"
|
||||
#include "no_os_irq.h"
|
||||
|
||||
#define TRIG_MAX_NAME_SIZE 20
|
||||
|
||||
/**
|
||||
* @struct iio_hw_trig
|
||||
* @brief IIO hardware trigger structure
|
||||
*/
|
||||
struct iio_hw_trig {
|
||||
/** IIO descriptor */
|
||||
struct iio_desc *iio_desc;
|
||||
/** Interrupt descriptor to be linked with the trigger */
|
||||
struct no_os_irq_ctrl_desc *irq_ctrl;
|
||||
/** Interrupt id to be linked with the trigger */
|
||||
uint32_t irq_id;
|
||||
/** Interrupt trigger level */
|
||||
enum no_os_irq_trig_level irq_trig_lvl;
|
||||
/** Device trigger name */
|
||||
char name[TRIG_MAX_NAME_SIZE + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_hw_trig_cb_info
|
||||
* @brief Hardware trigger callback extra information structure
|
||||
*/
|
||||
struct iio_hw_trig_cb_info {
|
||||
/** Platform specific event that triggers the calling of the callback. */
|
||||
enum no_os_irq_event event;
|
||||
/** Interrupt source peripheral specifier. */
|
||||
enum no_os_irq_peripheral peripheral;
|
||||
/** This will be used to store HAL specific descriptors */
|
||||
void *handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_hw_trig_init_param
|
||||
* @brief IIO hardware trigger initialization structure
|
||||
*/
|
||||
struct iio_hw_trig_init_param {
|
||||
/** IIO descriptor */
|
||||
struct iio_desc *iio_desc;
|
||||
/** Interrupt descriptor to be linked with the trigger */
|
||||
struct no_os_irq_ctrl_desc *irq_ctrl;
|
||||
/** Interrupt id to be linked with the trigger */
|
||||
uint32_t irq_id;
|
||||
/** Interrupt trigger level */
|
||||
enum no_os_irq_trig_level irq_trig_lvl;
|
||||
/** Additional interrupt callback information */
|
||||
struct iio_hw_trig_cb_info cb_info;
|
||||
/** Device trigger name */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_sw_trig
|
||||
* @brief IIO software trigger structure
|
||||
*/
|
||||
struct iio_sw_trig {
|
||||
/** IIO descriptor */
|
||||
struct iio_desc *iio_desc;
|
||||
/** Device trigger name */
|
||||
char name[TRIG_MAX_NAME_SIZE + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_sw_trig_init_param
|
||||
* @brief IIO software trigger initialization structure
|
||||
*/
|
||||
struct iio_sw_trig_init_param {
|
||||
/** IIO descriptor */
|
||||
struct iio_desc *iio_desc;
|
||||
/** Device trigger name */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#ifndef LINUX_PLATFORM
|
||||
/** API to initialize a hardware trigger */
|
||||
int iio_hw_trig_init(struct iio_hw_trig **iio_trig,
|
||||
struct iio_hw_trig_init_param *init_param);
|
||||
/** API to enable a hardware trigger */
|
||||
int iio_trig_enable(void *trig);
|
||||
/** API to disable a hardware trigger */
|
||||
int iio_trig_disable(void *trig);
|
||||
/** API for hardware trigger handler */
|
||||
void iio_hw_trig_handler(void *trig);
|
||||
/** API to remove a hardware trigger */
|
||||
int iio_hw_trig_remove(struct iio_hw_trig *trig);
|
||||
#endif
|
||||
|
||||
/** API to initialize a software trigger */
|
||||
int iio_sw_trig_init(struct iio_sw_trig **iio_trig,
|
||||
struct iio_sw_trig_init_param *init_param);
|
||||
/** API for software trigger handler */
|
||||
int iio_sw_trig_handler(void *trig, char *buf, uint32_t len,
|
||||
const struct iio_ch_info *channel,
|
||||
intptr_t priv);
|
||||
/** API to remove a software trigger */
|
||||
int iio_trig_remove(struct iio_sw_trig *trig);
|
||||
|
||||
#endif /* IIO_TRIGGER_H_ */
|
||||
280
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iio_types.h
Normal file
@@ -0,0 +1,280 @@
|
||||
/***************************************************************************//**
|
||||
* @file iio_types.h
|
||||
* @brief Header file for iio_types
|
||||
* @author Cristian Pop (cristian.pop@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2013(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef IIO_TYPES_H_
|
||||
#define IIO_TYPES_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "no_os_circular_buffer.h"
|
||||
|
||||
enum iio_val {
|
||||
IIO_VAL_INT = 1,
|
||||
IIO_VAL_INT_PLUS_MICRO,
|
||||
IIO_VAL_INT_PLUS_NANO,
|
||||
IIO_VAL_INT_PLUS_MICRO_DB,
|
||||
IIO_VAL_INT_MULTIPLE,
|
||||
IIO_VAL_FRACTIONAL = 10,
|
||||
IIO_VAL_FRACTIONAL_LOG2,
|
||||
IIO_VAL_CHAR
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_chan_type
|
||||
* @brief IIO channel types
|
||||
*/
|
||||
enum iio_chan_type {
|
||||
IIO_VOLTAGE,
|
||||
IIO_CURRENT,
|
||||
IIO_ALTVOLTAGE,
|
||||
IIO_ANGL_VEL,
|
||||
IIO_TEMP,
|
||||
IIO_CAPACITANCE,
|
||||
IIO_ACCEL,
|
||||
IIO_RESISTANCE,
|
||||
IIO_MAGN,
|
||||
IIO_INCLI,
|
||||
IIO_VELOCITY,
|
||||
IIO_ANGL,
|
||||
IIO_ROT,
|
||||
IIO_COUNT,
|
||||
IIO_DELTA_ANGL,
|
||||
IIO_DELTA_VELOCITY,
|
||||
IIO_WEIGHT,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_modifier
|
||||
* @brief IIO channel modifier
|
||||
*/
|
||||
enum iio_modifier {
|
||||
IIO_NO_MOD,
|
||||
IIO_MOD_X,
|
||||
IIO_MOD_Y,
|
||||
IIO_MOD_Z,
|
||||
IIO_MOD_TEMP_AMBIENT,
|
||||
IIO_MOD_PITCH,
|
||||
IIO_MOD_YAW,
|
||||
IIO_MOD_ROLL,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_ch_info
|
||||
* @brief Structure holding channel attributess.
|
||||
*/
|
||||
struct iio_ch_info {
|
||||
/** Channel number. TODO: refactor out the ch_ prefix. */
|
||||
int16_t ch_num;
|
||||
/** Channel direction: input/output. TODO: refactor out the ch_ prefix. */
|
||||
bool ch_out;
|
||||
/** Channel type */
|
||||
enum iio_chan_type type;
|
||||
/** Differential channel indicator */
|
||||
bool differential;
|
||||
/** Driver specific identifier. */
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
#define END_ATTRIBUTES_ARRAY {.name = NULL}
|
||||
|
||||
enum iio_attribute_shared {
|
||||
IIO_SEPARATE,
|
||||
IIO_SHARED_BY_TYPE,
|
||||
IIO_SHARED_BY_DIR,
|
||||
IIO_SHARED_BY_ALL,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_attribute
|
||||
* @brief Structure holding pointers to show and store functions.
|
||||
*/
|
||||
struct iio_attribute {
|
||||
/** Attribute name */
|
||||
const char *name;
|
||||
/** Attribute id */
|
||||
intptr_t priv;
|
||||
/** Whether this attribute is shared by all channels of the same type, or direction
|
||||
* or simply by all channels. If left uninitialized, the sharedness defaults to
|
||||
* separate.
|
||||
*/
|
||||
enum iio_attribute_shared shared;
|
||||
/** Show function pointer */
|
||||
int (*show)(void *device, char *buf, uint32_t len,
|
||||
const struct iio_ch_info *channel, intptr_t priv);
|
||||
/** Store function pointer */
|
||||
int (*store)(void *device, char *buf, uint32_t len,
|
||||
const struct iio_ch_info *channel, intptr_t priv);
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_channel
|
||||
* @brief Struct describing the scan type
|
||||
*/
|
||||
struct scan_type {
|
||||
/** 's' or 'u' to specify signed or unsigned */
|
||||
char sign;
|
||||
/** Number of valid bits of data */
|
||||
uint8_t realbits;
|
||||
/** Realbits + padding */
|
||||
uint8_t storagebits;
|
||||
/** Shift right by this before masking out realbits. */
|
||||
uint8_t shift;
|
||||
/** True if big endian, false if little endian */
|
||||
bool is_big_endian;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_channel
|
||||
* @brief Structure holding attributes of a channel.
|
||||
*/
|
||||
struct iio_channel {
|
||||
/** Channel name */
|
||||
const char *name;
|
||||
/** Chanel type */
|
||||
enum iio_chan_type ch_type;
|
||||
/** Channel number when the same channel type */
|
||||
int channel;
|
||||
/** If modified is set, this provides the modifier. E.g. IIO_MOD_X
|
||||
* for angular rate when applied to channel2 will make make the
|
||||
* IIO_ANGL_VEL have anglvel_x which corresponds to the x-axis. */
|
||||
int channel2;
|
||||
/** Driver specific identifier. */
|
||||
unsigned long address;
|
||||
/** Index to give ordering in scans when read from a buffer. */
|
||||
int scan_index;
|
||||
/** */
|
||||
struct scan_type *scan_type;
|
||||
/** Array of attributes. Last one should have its name set to NULL */
|
||||
struct iio_attribute *attributes;
|
||||
/** if true, the channel is an output channel */
|
||||
bool ch_out;
|
||||
/** Set if channel has a modifier. Use channel2 property to
|
||||
* select the modifier to use.*/
|
||||
bool modified;
|
||||
/** Specify if channel has a numerical index. If not set, channel
|
||||
* number will be suppressed. */
|
||||
bool indexed;
|
||||
/* Set if the channel is differential. */
|
||||
bool diferential;
|
||||
};
|
||||
|
||||
enum iio_buffer_direction {
|
||||
IIO_DIRECTION_INPUT,
|
||||
IIO_DIRECTION_OUTPUT
|
||||
};
|
||||
|
||||
struct iio_cyclic_buffer_info {
|
||||
bool is_cyclic;
|
||||
uint32_t buff_index;
|
||||
};
|
||||
|
||||
struct iio_buffer {
|
||||
/* Mask with active channels */
|
||||
uint32_t active_mask;
|
||||
/* Size in bytes */
|
||||
uint32_t size;
|
||||
/* Number of bytes per sample * number of active channels */
|
||||
uint32_t bytes_per_scan;
|
||||
/* Number of requested samples */
|
||||
uint32_t samples;
|
||||
/* Buffer direction */
|
||||
enum iio_buffer_direction dir;
|
||||
/* Buffer where data is stored */
|
||||
struct no_os_circular_buffer *buf;
|
||||
/* Stores cyclic buffer specific information */
|
||||
struct iio_cyclic_buffer_info cyclic_info;
|
||||
};
|
||||
|
||||
struct iio_device_data {
|
||||
void *dev;
|
||||
struct iio_buffer *buffer;
|
||||
};
|
||||
|
||||
struct iio_trigger {
|
||||
/** If true the trigger handler will be called in interrupt context
|
||||
* If false the handler will be called from iio_step */
|
||||
bool is_synchronous;
|
||||
/** Array of attributes. Last one should have its name set to NULL */
|
||||
struct iio_attribute *attributes;
|
||||
/** Called when needs to be enabled */
|
||||
int (*enable)(void *trig);
|
||||
/** Called when needs to be disabled */
|
||||
int (*disable)(void *trig);
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct iio_device
|
||||
* @brief Structure holding channels and attributes of a device.
|
||||
*/
|
||||
struct iio_device {
|
||||
/** Structure for existing initialized irq controllers. Has to be
|
||||
* set to NULL if there isn't any irq controller initialized. */
|
||||
struct no_os_irq_ctrl_desc *irq_desc;
|
||||
/** Device number of channels */
|
||||
uint16_t num_ch;
|
||||
/** List of channels */
|
||||
struct iio_channel *channels;
|
||||
/** Array of attributes. Last one should have its name set to NULL */
|
||||
struct iio_attribute *attributes;
|
||||
/** Array of attributes. Last one should have its name set to NULL */
|
||||
struct iio_attribute *debug_attributes;
|
||||
/** Array of attributes. Last one should have its name set to NULL */
|
||||
struct iio_attribute *buffer_attributes;
|
||||
/* Numbers of bytes will be:
|
||||
* samples * (storage_size_of_first_active_ch / 8) * nb_active_channels
|
||||
* DEPRECATED.
|
||||
*/
|
||||
int32_t (*read_dev)(void *dev, void *buff, uint32_t nb_samples);
|
||||
/* Numbers of bytes will be:
|
||||
* samples * (storage_size_of_first_active_ch / 8) * nb_active_channels
|
||||
* DEPRECATED.
|
||||
*/
|
||||
int32_t (*write_dev)(void *dev, void *buff, uint32_t nb_samples);
|
||||
|
||||
/* Bufer callbacks */
|
||||
/** Called before enabling buffer */
|
||||
int32_t (*pre_enable)(void *dev, uint32_t mask);
|
||||
/** Called after disabling buffer */
|
||||
int32_t (*post_disable)(void *dev);
|
||||
/** Called when buffer ready to transfer. Write/read to/from dev */
|
||||
int32_t (*submit)(struct iio_device_data *dev);
|
||||
/** Called after a trigger signal has been received by iio */
|
||||
int32_t (*trigger_handler)(struct iio_device_data *dev);
|
||||
|
||||
/* Read device register */
|
||||
int32_t (*debug_reg_read)(void *dev, uint32_t reg, uint32_t *readval);
|
||||
/* Write device register */
|
||||
int32_t (*debug_reg_write)(void *dev, uint32_t reg, uint32_t writeval);
|
||||
|
||||
};
|
||||
|
||||
#endif /* IIO_TYPES_H_ */
|
||||
927
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.c
Normal file
@@ -0,0 +1,927 @@
|
||||
/***************************************************************************//**
|
||||
* @file iiod.c
|
||||
* @brief Nonblocking implementation of iiod.
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2022(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "iiod.h"
|
||||
#include "iiod_private.h"
|
||||
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_util.h"
|
||||
|
||||
#define SET_DUMMY_IF_NULL(func, dummy) ((func) ? (func) : (dummy))
|
||||
|
||||
static char delim[] = " \r\n";
|
||||
|
||||
|
||||
static const char *attr_types_strs[] = {
|
||||
[IIO_ATTR_TYPE_DEBUG] = "DEBUG",
|
||||
[IIO_ATTR_TYPE_BUFFER] = "BUFFER",
|
||||
[IIO_ATTR_TYPE_CH_OUT] = "OUTPUT",
|
||||
[IIO_ATTR_TYPE_CH_IN] = "INPUT"
|
||||
};
|
||||
|
||||
static struct iiod_str cmds[] = {
|
||||
[IIOD_CMD_HELP] = IIOD_STR("HELP"),
|
||||
[IIOD_CMD_EXIT] = IIOD_STR("EXIT"),
|
||||
[IIOD_CMD_PRINT] = IIOD_STR("PRINT"),
|
||||
[IIOD_CMD_VERSION] = IIOD_STR("VERSION"),
|
||||
[IIOD_CMD_TIMEOUT] = IIOD_STR("TIMEOUT"),
|
||||
[IIOD_CMD_OPEN] = IIOD_STR("OPEN"),
|
||||
[IIOD_CMD_CLOSE] = IIOD_STR("CLOSE"),
|
||||
[IIOD_CMD_READ] = IIOD_STR("READ"),
|
||||
[IIOD_CMD_WRITE] = IIOD_STR("WRITE"),
|
||||
[IIOD_CMD_READBUF] = IIOD_STR("READBUF"),
|
||||
[IIOD_CMD_WRITEBUF] = IIOD_STR("WRITEBUF"),
|
||||
[IIOD_CMD_GETTRIG] = IIOD_STR("GETTRIG"),
|
||||
[IIOD_CMD_SETTRIG] = IIOD_STR("SETTRIG"),
|
||||
[IIOD_CMD_SET] = IIOD_STR("SET")
|
||||
};
|
||||
static const uint32_t priority_array[] = {
|
||||
/* Order not tested, just personal expectation. Function can
|
||||
* be improved, this improvement is chosen for simplicity */
|
||||
IIOD_CMD_READBUF,
|
||||
IIOD_CMD_WRITEBUF,
|
||||
IIOD_CMD_READ,
|
||||
IIOD_CMD_WRITE,
|
||||
IIOD_CMD_OPEN,
|
||||
IIOD_CMD_CLOSE,
|
||||
IIOD_CMD_PRINT,
|
||||
IIOD_CMD_EXIT,
|
||||
IIOD_CMD_TIMEOUT,
|
||||
IIOD_CMD_VERSION,
|
||||
IIOD_CMD_GETTRIG,
|
||||
IIOD_CMD_SETTRIG,
|
||||
IIOD_CMD_HELP,
|
||||
IIOD_CMD_SET
|
||||
};
|
||||
|
||||
static_assert(NO_OS_ARRAY_SIZE(cmds) == NO_OS_ARRAY_SIZE(priority_array),
|
||||
"Arrays must have the same size");
|
||||
|
||||
/* Set res->cmd to corresponding cmd and return the processed length of buf */
|
||||
static int32_t parse_cmd(const char *token, struct comand_desc *res)
|
||||
{
|
||||
uint32_t i;
|
||||
struct iiod_str *cmd;
|
||||
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < NO_OS_ARRAY_SIZE(cmds); ++i) {
|
||||
cmd = &cmds[priority_array[i]];
|
||||
if (strcmp(token, cmd->str) == 0) {
|
||||
res->cmd = priority_array[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int32_t parse_num(const char *token, uint32_t *res, uint32_t base)
|
||||
{
|
||||
char *end_ptr;
|
||||
|
||||
*res = strtoul(token, &end_ptr, base);
|
||||
if (*res == 0 && *end_ptr != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t iiod_parse_open(const char *token, struct comand_desc *res,
|
||||
char **ctx)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
|
||||
ret = parse_num(token, &res->sample_count, 10);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
|
||||
ret = parse_num(token, &res->mask, 16);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
res->cyclic = 0;
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
if (token) {
|
||||
if (strcmp(token, "CYCLIC") == 0)
|
||||
res->cyclic = 1;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t iiod_parse_set(const char *token, struct comand_desc *res,
|
||||
char **ctx)
|
||||
{
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
|
||||
if (strcmp(token, "BUFFERS_COUNT"))
|
||||
return -EINVAL;
|
||||
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
|
||||
return parse_num(token, &res->count, 10);
|
||||
}
|
||||
|
||||
static int32_t iiod_parse_rw_attr(const char *token, struct comand_desc *res,
|
||||
char **ctx)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
res->type = IIO_ATTR_TYPE_DEVICE;
|
||||
if (token) {
|
||||
for (i = 0; i < IIO_ATTR_TYPE_DEVICE; ++i) {
|
||||
if (strcmp(token, attr_types_strs[i]) == 0) {
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
res->type = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res->type == IIO_ATTR_TYPE_CH_IN ||
|
||||
res->type == IIO_ATTR_TYPE_CH_OUT) {
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
strncpy(res->channel, token, sizeof(res->channel));
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
}
|
||||
|
||||
if (res->cmd == IIOD_CMD_WRITE) {
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
|
||||
if (*token >= '0' && *token <= '9') {
|
||||
memset(res->attr, 0, sizeof(res->attr));
|
||||
|
||||
return parse_num(token, &res->bytes_count, 10);
|
||||
}
|
||||
|
||||
strncpy(res->attr, token, sizeof(res->attr));
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
if (!token)
|
||||
return -EINVAL;
|
||||
|
||||
return parse_num(token, &res->bytes_count, 10);
|
||||
}
|
||||
|
||||
if (token)
|
||||
strncpy(res->attr, token, sizeof(res->attr));
|
||||
else
|
||||
memset(res->attr, 0, sizeof(res->attr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t iiod_parse_line(char *buf, struct comand_desc *res, char **ctx)
|
||||
{
|
||||
int32_t ret;
|
||||
char *token;
|
||||
|
||||
token = strtok_r(buf, delim, ctx);
|
||||
ret = parse_cmd(token, res);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
/* Commands without device */
|
||||
switch (res->cmd) {
|
||||
case IIOD_CMD_HELP:
|
||||
case IIOD_CMD_EXIT:
|
||||
case IIOD_CMD_PRINT:
|
||||
case IIOD_CMD_VERSION:
|
||||
return 0;
|
||||
case IIOD_CMD_TIMEOUT:
|
||||
return parse_num(token, &res->timeout, 10);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(res->device, token, sizeof(res->device));
|
||||
token = strtok_r(NULL, delim, ctx);
|
||||
switch (res->cmd) {
|
||||
case IIOD_CMD_CLOSE:
|
||||
case IIOD_CMD_GETTRIG:
|
||||
return 0;
|
||||
case IIOD_CMD_OPEN:
|
||||
return iiod_parse_open(token, res, ctx);
|
||||
case IIOD_CMD_READ:
|
||||
case IIOD_CMD_WRITE:
|
||||
return iiod_parse_rw_attr(token, res, ctx);
|
||||
case IIOD_CMD_READBUF:
|
||||
case IIOD_CMD_WRITEBUF:
|
||||
return parse_num(token, &res->bytes_count, 10);
|
||||
case IIOD_CMD_SETTRIG:
|
||||
if (token)
|
||||
strncpy(res->trigger, token, sizeof(res->trigger));
|
||||
else
|
||||
memset(res->trigger, 0, sizeof(res->trigger));
|
||||
|
||||
return 0;
|
||||
case IIOD_CMD_SET:
|
||||
return iiod_parse_set(token, res, ctx);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dummy_open(struct iiod_ctx *ctx, const char *device,
|
||||
uint32_t samples, uint32_t mask, bool cyclic)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dummy_close(struct iiod_ctx *ctx, const char *device)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dummy_rw_attr(struct iiod_ctx *ctx, const char *device,
|
||||
struct iiod_attr *attr, char *buf, uint32_t len)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dummy_rd_data(struct iiod_ctx *ctx, const char *device, char *buf,
|
||||
uint32_t bytes)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dummy_wr_data(struct iiod_ctx *ctx, const char *device,
|
||||
const char *trig, uint32_t bytes)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dummy_set_timeout(struct iiod_ctx *ctx, uint32_t timeout)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dummy_set_buffers_count(struct iiod_ctx *ctx, const char *device,
|
||||
uint32_t buffers_count)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int32_t iiod_copy_ops(struct iiod_ops *ops, struct iiod_ops *new_ops)
|
||||
{
|
||||
if (!new_ops->recv || !new_ops->send)
|
||||
return -EINVAL;
|
||||
|
||||
ops->recv = new_ops->recv;
|
||||
ops->send = new_ops->send;
|
||||
|
||||
ops->open = SET_DUMMY_IF_NULL(new_ops->open, dummy_open);
|
||||
ops->close = SET_DUMMY_IF_NULL(new_ops->close, dummy_close);
|
||||
ops->read_buffer = SET_DUMMY_IF_NULL(new_ops->read_buffer, dummy_rd_data);
|
||||
ops->write_buffer = SET_DUMMY_IF_NULL(new_ops->write_buffer, dummy_wr_data);
|
||||
ops->read_attr = SET_DUMMY_IF_NULL(new_ops->read_attr, dummy_rw_attr);
|
||||
ops->write_attr = SET_DUMMY_IF_NULL(new_ops->write_attr, dummy_rw_attr);
|
||||
ops->get_trigger = SET_DUMMY_IF_NULL(new_ops->get_trigger, dummy_rd_data);
|
||||
ops->set_trigger = SET_DUMMY_IF_NULL(new_ops->set_trigger, dummy_wr_data);
|
||||
ops->set_timeout = SET_DUMMY_IF_NULL(new_ops->set_timeout, dummy_set_timeout);
|
||||
ops->set_buffers_count = SET_DUMMY_IF_NULL(new_ops->set_buffers_count,
|
||||
dummy_set_buffers_count);
|
||||
ops->refill_buffer = SET_DUMMY_IF_NULL(new_ops->refill_buffer,
|
||||
dummy_close);
|
||||
ops->push_buffer = SET_DUMMY_IF_NULL(new_ops->push_buffer,
|
||||
dummy_close);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t iiod_init(struct iiod_desc **desc, struct iiod_init_param *param)
|
||||
{
|
||||
struct iiod_desc *ldesc;
|
||||
int32_t ret;
|
||||
|
||||
if (!desc || !param || !param->ops)
|
||||
return -EINVAL;
|
||||
|
||||
ldesc = (struct iiod_desc *)calloc(1, sizeof(*ldesc));
|
||||
if (!ldesc)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = iiod_copy_ops(&ldesc->ops, param->ops);
|
||||
if (NO_OS_IS_ERR_VALUE(ret)) {
|
||||
free(ldesc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ldesc->xml = param->xml;
|
||||
ldesc->xml_len = param->xml_len;
|
||||
ldesc->app_instance = param->instance;
|
||||
ldesc->phy_type = param->phy_type;
|
||||
|
||||
*desc = ldesc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iiod_remove(struct iiod_desc *desc)
|
||||
{
|
||||
free(desc);
|
||||
}
|
||||
|
||||
static void conn_clean_state(struct iiod_conn_priv *conn)
|
||||
{
|
||||
memset(&conn->cmd_data, 0, sizeof(conn->cmd_data));
|
||||
memset(&conn->res, 0, sizeof(conn->res));
|
||||
memset(&conn->nb_buf, 0, sizeof(conn->nb_buf));
|
||||
|
||||
conn->res.buf.buf = NULL;
|
||||
conn->res.buf.idx = 0;
|
||||
conn->parser_idx = 0;
|
||||
conn->state = IIOD_READING_LINE;
|
||||
}
|
||||
|
||||
int32_t iiod_conn_add(struct iiod_desc *desc, struct iiod_conn_data *data,
|
||||
uint32_t *new_conn_id)
|
||||
{
|
||||
uint32_t i;
|
||||
struct iiod_conn_priv *conn;
|
||||
|
||||
if (!desc || !new_conn_id)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < IIOD_MAX_CONNECTIONS; ++i)
|
||||
if (!desc->conns[i].used) {
|
||||
conn = &desc->conns[i];
|
||||
memset(conn, 0, sizeof(*conn));
|
||||
conn->used = 1;
|
||||
conn->conn = data->conn;
|
||||
/*
|
||||
* TODO in future:
|
||||
* think of using other buffer (e.g. ciruclar_buffer)
|
||||
* to somehow implement zero copy
|
||||
*/
|
||||
conn->payload_buf = data->buf;
|
||||
conn->payload_buf_len = data->len;
|
||||
*new_conn_id = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
int32_t iiod_conn_remove(struct iiod_desc *desc, uint32_t conn_id,
|
||||
struct iiod_conn_data *data)
|
||||
{
|
||||
if (!desc || conn_id > IIOD_MAX_CONNECTIONS ||
|
||||
!desc->conns[conn_id].used)
|
||||
return -EINVAL;
|
||||
struct iiod_conn_priv *conn;
|
||||
conn = &desc->conns[conn_id];
|
||||
data->conn = conn->conn;
|
||||
data->len = conn->payload_buf_len;
|
||||
data->buf = conn->payload_buf;
|
||||
conn->used = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t call_op(struct iiod_ops *ops, struct comand_desc *data,
|
||||
struct iiod_ctx *ctx)
|
||||
{
|
||||
switch (data->cmd) {
|
||||
case IIOD_CMD_HELP:
|
||||
return -EINVAL;
|
||||
case IIOD_CMD_TIMEOUT:
|
||||
return ops->set_timeout(ctx, data->timeout);
|
||||
case IIOD_CMD_OPEN:
|
||||
return ops->open(ctx, data->device, data->sample_count,
|
||||
data->mask, data->cyclic);
|
||||
case IIOD_CMD_CLOSE:
|
||||
return ops->close(ctx, data->device);
|
||||
case IIOD_CMD_SETTRIG:
|
||||
return ops->set_trigger(ctx, data->device, data->trigger,
|
||||
strlen(data->trigger));
|
||||
case IIOD_CMD_SET:
|
||||
return ops->set_buffers_count(ctx, data->device, data->count);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unload data from buf without blocking.
|
||||
* When done will return 0, if there is still data to be sent it will return
|
||||
* -EAGIAN. On error, an negative error code is returned
|
||||
*/
|
||||
static int32_t rw_iiod_buff(struct iiod_desc *desc, struct iiod_conn_priv *conn,
|
||||
struct iiod_buff *buf, uint8_t flags)
|
||||
{
|
||||
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
|
||||
uint8_t *tmp_buf;
|
||||
int32_t ret;
|
||||
int32_t len;
|
||||
|
||||
len = buf->len - buf->idx;
|
||||
if (len) {
|
||||
tmp_buf = (uint8_t *)buf->buf + buf->idx;
|
||||
if (flags & IIOD_WR)
|
||||
ret = desc->ops.send(&ctx, tmp_buf, len);
|
||||
else
|
||||
ret = desc->ops.recv(&ctx, tmp_buf, len);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
buf->idx += ret;
|
||||
if (ret < len)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (flags & IIOD_ENDL) {
|
||||
ret = desc->ops.send(&ctx, (uint8_t *)"\n", 1);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
if (ret != 1)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t do_read_buff_delayed(struct iiod_desc *desc,
|
||||
struct iiod_conn_priv *conn)
|
||||
{
|
||||
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
|
||||
uint32_t max_to_read;
|
||||
int32_t ret, len;
|
||||
|
||||
conn->nb_buf.buf = conn->payload_buf;
|
||||
len = no_os_min(conn->payload_buf_len, conn->cmd_data.bytes_count);
|
||||
max_to_read = len - conn->nb_buf.len;
|
||||
ret = desc->ops.read_buffer(&ctx, conn->cmd_data.device,
|
||||
conn->nb_buf.buf + conn->nb_buf.len, max_to_read);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
conn->nb_buf.len += ret;
|
||||
|
||||
if (conn->nb_buf.len < conn->cmd_data.bytes_count)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_WR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
conn->nb_buf.len = 0;
|
||||
conn->nb_buf.idx = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t do_read_buff(struct iiod_desc *desc, struct iiod_conn_priv *conn)
|
||||
{
|
||||
struct iiod_ctx ctx;
|
||||
int32_t ret, len;
|
||||
|
||||
/*
|
||||
* When using the network backend wait for a whole buffer to be filled
|
||||
* before sending in order to reduce the ammount of network traffic.
|
||||
*/
|
||||
if (desc->phy_type == USE_NETWORK)
|
||||
return do_read_buff_delayed(desc, conn);
|
||||
|
||||
ctx = (struct iiod_ctx)IIOD_CTX(desc, conn);
|
||||
if (conn->nb_buf.len == 0) {
|
||||
conn->nb_buf.buf = conn->payload_buf;
|
||||
len = no_os_min(conn->payload_buf_len,
|
||||
conn->cmd_data.bytes_count);
|
||||
/* Read from dev */
|
||||
ret = desc->ops.read_buffer(&ctx, conn->cmd_data.device,
|
||||
conn->nb_buf.buf, len);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
len = ret;
|
||||
conn->nb_buf.len = len;
|
||||
conn->nb_buf.idx = 0;
|
||||
}
|
||||
if (conn->nb_buf.idx < conn->nb_buf.len) {
|
||||
/* Write on conn */
|
||||
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_WR);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
conn->cmd_data.bytes_count -= conn->nb_buf.len;
|
||||
conn->nb_buf.len = 0;
|
||||
if (conn->cmd_data.bytes_count)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t do_write_buff(struct iiod_desc *desc,
|
||||
struct iiod_conn_priv *conn)
|
||||
{
|
||||
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
|
||||
int32_t ret, len;
|
||||
|
||||
if (conn->nb_buf.len == 0) {
|
||||
conn->nb_buf.buf = conn->payload_buf;
|
||||
len = no_os_min(conn->payload_buf_len,
|
||||
conn->cmd_data.bytes_count);
|
||||
conn->nb_buf.len = len;
|
||||
conn->nb_buf.idx = 0;
|
||||
}
|
||||
if (conn->nb_buf.idx < conn->nb_buf.len) {
|
||||
/* Read from conn */
|
||||
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_RD);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
}
|
||||
/* Write to dev */
|
||||
ret = desc->ops.write_buffer(&ctx, conn->cmd_data.device,
|
||||
conn->nb_buf.buf, conn->nb_buf.len);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
conn->cmd_data.bytes_count -= conn->nb_buf.len;
|
||||
conn->nb_buf.len = 0;
|
||||
if (conn->cmd_data.bytes_count)
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t iiod_run_cmd(struct iiod_desc *desc,
|
||||
struct iiod_conn_priv *conn)
|
||||
{
|
||||
struct iiod_ctx ctx = IIOD_CTX(desc, conn);
|
||||
struct comand_desc *data = &conn->cmd_data;
|
||||
struct iiod_attr attr = {
|
||||
.type = data->type,
|
||||
.name = data->attr,
|
||||
.channel = data->channel
|
||||
};
|
||||
int32_t ret;
|
||||
|
||||
switch (data->cmd) {
|
||||
case IIOD_CMD_HELP:
|
||||
case IIOD_CMD_TIMEOUT:
|
||||
case IIOD_CMD_OPEN:
|
||||
case IIOD_CMD_CLOSE:
|
||||
case IIOD_CMD_SETTRIG:
|
||||
case IIOD_CMD_SET:
|
||||
if (data->cmd == IIOD_CMD_OPEN) {
|
||||
conn->mask = data->mask;
|
||||
if (data->cyclic)
|
||||
conn->is_cyclic_buffer = true;
|
||||
}
|
||||
if (data->cmd == IIOD_CMD_CLOSE)
|
||||
/* Set is_cyclic_buffer to false every time the device is closed */
|
||||
conn->is_cyclic_buffer = false;
|
||||
conn->res.val = call_op(&desc->ops, data, &ctx);
|
||||
conn->res.write_val = 1;
|
||||
break;
|
||||
case IIOD_CMD_EXIT:
|
||||
conn->res.val = 0;
|
||||
conn->res.write_val = 1;
|
||||
|
||||
return -ENOTCONN;
|
||||
case IIOD_CMD_PRINT:
|
||||
conn->res.val = desc->xml_len;
|
||||
conn->res.write_val = 1;
|
||||
conn->res.buf.buf = desc->xml;
|
||||
conn->res.buf.len = desc->xml_len;
|
||||
break;
|
||||
case IIOD_CMD_VERSION:
|
||||
conn->res.buf.buf = IIOD_VERSION;
|
||||
conn->res.buf.len = IIOD_VERSION_LEN;
|
||||
break;
|
||||
case IIOD_CMD_READ:
|
||||
case IIOD_CMD_GETTRIG:
|
||||
if (data->cmd == IIOD_CMD_READ)
|
||||
ret = desc->ops.read_attr(&ctx, data->device, &attr,
|
||||
conn->payload_buf,
|
||||
conn->payload_buf_len);
|
||||
else
|
||||
ret = desc->ops.get_trigger(&ctx, data->device,
|
||||
conn->payload_buf,
|
||||
conn->payload_buf_len);
|
||||
conn->res.val = ret;
|
||||
conn->res.write_val = 1;
|
||||
if (!NO_OS_IS_ERR_VALUE(ret)) {
|
||||
conn->res.buf.buf = conn->payload_buf;
|
||||
conn->res.buf.len = ret;
|
||||
}
|
||||
break;
|
||||
case IIOD_CMD_WRITE:
|
||||
conn->payload_buf[data->bytes_count] = '\0';
|
||||
ret = desc->ops.write_attr(&ctx, data->device, &attr,
|
||||
conn->payload_buf,
|
||||
data->bytes_count);
|
||||
conn->nb_buf.len = 0;
|
||||
conn->res.val = ret;
|
||||
conn->res.write_val = 1;
|
||||
break;
|
||||
case IIOD_CMD_READBUF:
|
||||
conn->res.write_val = 1;
|
||||
ret = desc->ops.refill_buffer(&ctx, data->device);
|
||||
if (NO_OS_IS_ERR_VALUE(ret)) {
|
||||
conn->res.val = ret;
|
||||
break;
|
||||
}
|
||||
conn->res.val = data->bytes_count;
|
||||
ret = snprintf(conn->buf_mask, 10, "%08"PRIx32, conn->mask);
|
||||
conn->res.buf.buf = conn->buf_mask;
|
||||
conn->res.buf.len = ret;
|
||||
break;
|
||||
case IIOD_CMD_WRITEBUF:
|
||||
conn->res.val = data->bytes_count;
|
||||
conn->res.write_val = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t iiod_read_line(struct iiod_desc *desc,
|
||||
struct iiod_conn_priv *conn)
|
||||
{
|
||||
struct iiod_ctx ctx = {
|
||||
.instance = desc->app_instance,
|
||||
.conn = conn->conn
|
||||
};
|
||||
int32_t ret;
|
||||
char *ch;
|
||||
|
||||
while (conn->parser_idx < IIOD_PARSER_MAX_BUF_SIZE - 1) {
|
||||
ch = conn->parser_buf + conn->parser_idx;
|
||||
ret = desc->ops.recv(&ctx, (uint8_t *)ch, 1);
|
||||
if (ret == -EAGAIN || ret == 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
goto end;
|
||||
|
||||
if (conn->parser_idx == 0 && (*ch == '\n' || *ch == '\r'))
|
||||
continue ;
|
||||
|
||||
++conn->parser_idx;
|
||||
if (*ch == '\n') {
|
||||
conn->parser_buf[conn->parser_idx] = '\0';
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = -EIO;
|
||||
end:
|
||||
conn->parser_idx = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function will return SUCCESS when a state was processed.
|
||||
* If a state is still in processing state, it will return -EAGAIN.
|
||||
* If other error occur. E.g. Connection errors, they are returned and
|
||||
* the connection must be cleaned up.
|
||||
*/
|
||||
static int32_t iiod_run_state(struct iiod_desc *desc,
|
||||
struct iiod_conn_priv *conn)
|
||||
{
|
||||
struct iiod_ctx ctx = {
|
||||
.instance = desc->app_instance,
|
||||
.conn = conn->conn
|
||||
};
|
||||
int32_t ret;
|
||||
|
||||
switch (conn->state) {
|
||||
case IIOD_READING_LINE:
|
||||
/* Read input data until \n. I/O Calls */
|
||||
ret = iiod_read_line(desc, conn);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
/* Fill struct comand_desc with data from line. No I/O */
|
||||
ret = iiod_parse_line(conn->parser_buf, &conn->cmd_data,
|
||||
&conn->strtok_ctx);
|
||||
if (NO_OS_IS_ERR_VALUE(ret)) {
|
||||
/* Parsing line failed */
|
||||
conn->res.write_val = 1;
|
||||
conn->res.val = ret;
|
||||
conn->state = IIOD_WRITING_CMD_RESULT;
|
||||
} else if (conn->cmd_data.cmd == IIOD_CMD_WRITE) {
|
||||
/* Special case. Attribute needs to be read */
|
||||
conn->nb_buf.buf = conn->payload_buf;
|
||||
conn->nb_buf.len = conn->cmd_data.bytes_count;
|
||||
conn->nb_buf.idx = 0;
|
||||
conn->state = IIOD_READING_WRITE_DATA;
|
||||
} else {
|
||||
conn->state = IIOD_RUNNING_CMD;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case IIOD_RUNNING_CMD:
|
||||
/* Execute or call necessary ops depending on cmd. No I/O */
|
||||
ret = iiod_run_cmd(desc, conn);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
conn->state = IIOD_WRITING_CMD_RESULT;
|
||||
|
||||
return 0;
|
||||
case IIOD_WRITING_CMD_RESULT:
|
||||
/* Write result or the length of data to be sent*/
|
||||
if (conn->res.write_val) {
|
||||
if (conn->nb_buf.len == 0) {
|
||||
conn->nb_buf.buf = conn->parser_buf;
|
||||
ret = sprintf(conn->nb_buf.buf, "%"PRIi32,
|
||||
conn->res.val);
|
||||
conn->nb_buf.len = ret;
|
||||
conn->nb_buf.idx = 0;
|
||||
}
|
||||
/* Non-blocking. Will enter here until val is sent */
|
||||
if (conn->nb_buf.idx < conn->nb_buf.len) {
|
||||
ret = rw_iiod_buff(desc, conn, &conn->nb_buf,
|
||||
IIOD_WR | IIOD_ENDL);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/* Send buf from result. Non blocking */
|
||||
if (conn->res.buf.buf &&
|
||||
conn->res.buf.idx < conn->res.buf.len) {
|
||||
ret = rw_iiod_buff(desc, conn, &conn->res.buf,
|
||||
IIOD_WR | IIOD_ENDL);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (conn->cmd_data.cmd != IIOD_CMD_READBUF &&
|
||||
conn->cmd_data.cmd != IIOD_CMD_WRITEBUF) {
|
||||
if (conn->is_cyclic_buffer && conn->cmd_data.cmd != IIOD_CMD_OPEN)
|
||||
conn->state = IIOD_PUSH_CYCLIC_BUFFER;
|
||||
else
|
||||
conn->state = IIOD_LINE_DONE;
|
||||
} else {
|
||||
/* Preapre for IIOD_RW_BUF state */
|
||||
memset(&conn->nb_buf, 0, sizeof(conn->nb_buf));
|
||||
conn->state = IIOD_RW_BUF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case IIOD_RW_BUF:
|
||||
/* IIOD_CMD_READBUF and IIOD_CMD_WRITEBUF special case */
|
||||
/* Non blocking read/write until all data is processed */
|
||||
if (conn->cmd_data.cmd == IIOD_CMD_READBUF)
|
||||
ret = do_read_buff(desc, conn);
|
||||
else {
|
||||
ret = do_write_buff(desc, conn);
|
||||
if (ret == 0) {
|
||||
conn->res.write_val = 1;
|
||||
ret = desc->ops.push_buffer(&ctx,
|
||||
conn->cmd_data.device);
|
||||
if (NO_OS_IS_ERR_VALUE(ret)) {
|
||||
conn->res.val = ret;
|
||||
conn->state = IIOD_LINE_DONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
memset(&conn->res.buf, 0, sizeof(conn->res.buf));
|
||||
conn->res.val = conn->cmd_data.bytes_count;
|
||||
conn->cmd_data.cmd = IIOD_CMD_PRINT;
|
||||
conn->state = IIOD_WRITING_CMD_RESULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
conn->state = IIOD_LINE_DONE;
|
||||
|
||||
return 0;
|
||||
case IIOD_READING_WRITE_DATA:
|
||||
/* Read attribute */
|
||||
ret = rw_iiod_buff(desc, conn, &conn->nb_buf, IIOD_RD);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return ret;
|
||||
|
||||
conn->state = IIOD_RUNNING_CMD;
|
||||
|
||||
return 0;
|
||||
case IIOD_PUSH_CYCLIC_BUFFER:
|
||||
/* Push puffer to IIO application */
|
||||
ret = desc->ops.push_buffer(&ctx,
|
||||
conn->cmd_data.device);
|
||||
/* If an error was encountered, close connection */
|
||||
if (NO_OS_IS_ERR_VALUE(ret)) {
|
||||
conn->res.val = ret;
|
||||
desc->ops.close(&ctx, conn->cmd_data.device);
|
||||
conn->state = IIOD_LINE_DONE;
|
||||
conn->is_cyclic_buffer = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read data from the client to verify whether a close command has been sent */
|
||||
ret = iiod_read_line(desc, conn);
|
||||
if (NO_OS_IS_ERR_VALUE(ret))
|
||||
return 0;
|
||||
|
||||
/* Fill struct comand_desc with data from line */
|
||||
ret = iiod_parse_line(conn->parser_buf, &conn->cmd_data,
|
||||
&conn->strtok_ctx);
|
||||
if (!NO_OS_IS_ERR_VALUE(ret) && conn->cmd_data.cmd == IIOD_CMD_CLOSE) {
|
||||
/* Exit this state only if a close command is received
|
||||
All other commands will be ignored.
|
||||
*/
|
||||
conn->nb_buf.len = 0;
|
||||
conn->state = IIOD_RUNNING_CMD;
|
||||
conn->is_cyclic_buffer = false;
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
/* Should never get here */
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t iiod_conn_step(struct iiod_desc *desc, uint32_t conn_id)
|
||||
{
|
||||
struct iiod_conn_priv *conn;
|
||||
int32_t ret;
|
||||
|
||||
if (!desc || conn_id > IIOD_MAX_CONNECTIONS ||
|
||||
!desc->conns[conn_id].used)
|
||||
return -EINVAL;
|
||||
|
||||
conn = &desc->conns[conn_id];
|
||||
do {
|
||||
ret = iiod_run_state(desc, conn);
|
||||
if (ret == -EAGAIN)
|
||||
return ret;
|
||||
if (NO_OS_IS_ERR_VALUE(ret) || conn->state == IIOD_LINE_DONE)
|
||||
break;
|
||||
//The loop will continue because the state was changed.
|
||||
} while (true);
|
||||
|
||||
conn_clean_state(conn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
192
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/iiod.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/***************************************************************************//**
|
||||
* @file iiod.h
|
||||
* @brief Header file of iiod
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2022(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef IIOD_H
|
||||
#define IIOD_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "iio.h"
|
||||
|
||||
/* Maximum nomber of iiod connections to allocate simultaneously */
|
||||
#define IIOD_MAX_CONNECTIONS 10
|
||||
#define IIOD_VERSION "1.1.0000000"
|
||||
#define IIOD_VERSION_LEN (sizeof(IIOD_VERSION) - 1)
|
||||
|
||||
#define MAX_DEV_ID 64
|
||||
#define MAX_TRIG_ID 64
|
||||
#define MAX_CHN_ID 64
|
||||
#define MAX_ATTR_NAME 256
|
||||
|
||||
enum iio_attr_type {
|
||||
IIO_ATTR_TYPE_DEBUG,
|
||||
IIO_ATTR_TYPE_BUFFER,
|
||||
IIO_ATTR_TYPE_CH_OUT,
|
||||
IIO_ATTR_TYPE_CH_IN,
|
||||
IIO_ATTR_TYPE_DEVICE,
|
||||
};
|
||||
|
||||
struct iiod_attr {
|
||||
enum iio_attr_type type;
|
||||
/*
|
||||
* Attribute name.
|
||||
* If empty (""), all attributes of the specified iio_attr_type must
|
||||
* be read/wrote
|
||||
*/
|
||||
const char *name;
|
||||
const char *channel;
|
||||
};
|
||||
|
||||
struct iiod_ctx {
|
||||
/* Value specified in iiod_init_param.instance in iiod_init */
|
||||
void *instance;
|
||||
/* Value specified in iiod_conn_data.conn in iiod_conn_add */
|
||||
void *conn;
|
||||
};
|
||||
|
||||
struct iiod_conn_data {
|
||||
/* Value to be used in iiod_ctx */
|
||||
void *conn;
|
||||
/* Buffer to store attributes or buffer data for a connection. */
|
||||
char *buf;
|
||||
/* Size of the provided buffer. It must fit the max attribute size */
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/* Functions should return a negative error code on failure */
|
||||
struct iiod_ops {
|
||||
/*
|
||||
* I/O operations
|
||||
* Send and recv are used to send or receive data to/from a connection.
|
||||
* They should send/receive the at maximum len bytes.
|
||||
* They must return the number of bytes sent/received.
|
||||
* They can return 0 or -EAGAIN when no data was processed.
|
||||
* They can do not block. They will be called again if there is still
|
||||
* data to be sent/recevied
|
||||
*/
|
||||
int (*send)(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len);
|
||||
int (*recv)(struct iiod_ctx *ctx, uint8_t *buf, uint32_t len);
|
||||
|
||||
/*
|
||||
* This is the equivalent of libiio iio_device_create_buffer.
|
||||
* Called in order to create a buffer to read or write data.
|
||||
* read_buffer or write_buffer will follow with a maximum of samples
|
||||
* (depending on the internal buffer).
|
||||
* All calls with the same ctx will refer to this buffer until close is
|
||||
* called.
|
||||
*/
|
||||
int (*open)(struct iiod_ctx *ctx, const char *device, uint32_t samples,
|
||||
uint32_t mask, bool cyclic);
|
||||
/* Equivalent of iio_buffer_destroy */
|
||||
int (*close)(struct iiod_ctx *ctx, const char *device);
|
||||
|
||||
/* Read data from opened buffer */
|
||||
int (*read_buffer)(struct iiod_ctx *ctx, const char *device, char *buf,
|
||||
uint32_t bytes);
|
||||
/* Called to notify that buffer must be refiiled */
|
||||
int (*refill_buffer)(struct iiod_ctx *ctx, const char *device);
|
||||
|
||||
/* Write data to opened buffer */
|
||||
int (*write_buffer)(struct iiod_ctx *ctx, const char *device,
|
||||
const char *buf, uint32_t bytes);
|
||||
/* Called to notify that buffer must be pushed to hardware */
|
||||
int (*push_buffer)(struct iiod_ctx *ctx, const char *device);
|
||||
|
||||
/*
|
||||
* Attribute has to be read in buf and return the number of bytes
|
||||
* written.
|
||||
*/
|
||||
int (*read_attr)(struct iiod_ctx *ctx, const char *device,
|
||||
struct iiod_attr *attr, char *buf, uint32_t len);
|
||||
/* Attribute buf is filled with the attribute value. */
|
||||
int (*write_attr)(struct iiod_ctx *ctx, const char *device,
|
||||
struct iiod_attr *attr, char *buf, uint32_t len);
|
||||
/* Simular with read_attr but trigger must be filled */
|
||||
int (*get_trigger)(struct iiod_ctx *ctx, const char *device,
|
||||
char *trigger, uint32_t len);
|
||||
/*
|
||||
* Simular with write_attr but trigger name is in trigger.
|
||||
* If trigger is equals to "". Trigger must be removed.
|
||||
*/
|
||||
int (*set_trigger)(struct iiod_ctx *ctx, const char *device,
|
||||
const char *trigger, uint32_t len);
|
||||
|
||||
/* I don't know what this should be used for :) */
|
||||
int (*set_timeout)(struct iiod_ctx *ctx, uint32_t timeout);
|
||||
|
||||
/* I don't know what this should be used for :) */
|
||||
int (*set_buffers_count)(struct iiod_ctx *ctx, const char *device,
|
||||
uint32_t buffers_count);
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal structure.
|
||||
* It is created in iiod_init and must be passed to all fucntions
|
||||
*/
|
||||
struct iiod_desc;
|
||||
|
||||
/* Parameter to initialize iiod_desc */
|
||||
struct iiod_init_param {
|
||||
struct iiod_ops *ops;
|
||||
/* Value to be send in each iiod_ctx from iiod_ops functions */
|
||||
void *instance;
|
||||
/*
|
||||
* Xml description of the context and devices. It should exist until
|
||||
* iiod_remove is called
|
||||
*/
|
||||
char *xml;
|
||||
/* Size of xml in bytes */
|
||||
uint32_t xml_len;
|
||||
/* Backend used by IIOD */
|
||||
enum physical_link_type phy_type;
|
||||
};
|
||||
|
||||
/* Initialize desc. */
|
||||
int32_t iiod_init(struct iiod_desc **desc, struct iiod_init_param *param);
|
||||
/* Remove desc resources */
|
||||
void iiod_remove(struct iiod_desc *desc);
|
||||
|
||||
/*
|
||||
* Notify iiod about a new connection in order to store context for it.
|
||||
* new_conn_id is set in order to reference the connection in iiod_conn_step
|
||||
*/
|
||||
int32_t iiod_conn_add(struct iiod_desc *desc, struct iiod_conn_data *data,
|
||||
uint32_t *new_conn_id);
|
||||
/* Remove conn_id from iiod. Provided data is returned in data */
|
||||
int32_t iiod_conn_remove(struct iiod_desc *desc, uint32_t conn_id,
|
||||
struct iiod_conn_data *data);
|
||||
/* Advance in the state machine of a connection. Will not block */
|
||||
int32_t iiod_conn_step(struct iiod_desc *desc, uint32_t conn_id);
|
||||
|
||||
#endif //IIOD_H
|
||||
@@ -0,0 +1,178 @@
|
||||
/***************************************************************************//**
|
||||
* @file iiod_private.h
|
||||
* @brief Private header file of iiod
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2022(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef IIOD_PRIVATE_H
|
||||
#define IIOD_PRIVATE_H
|
||||
|
||||
#include "iio.h"
|
||||
|
||||
#define IIOD_WR 0x1
|
||||
#define IIOD_ENDL 0x2
|
||||
#define IIOD_RD 0x4
|
||||
#define IIOD_PARSER_MAX_BUF_SIZE 128
|
||||
|
||||
#define IIOD_STR(cmd) {(cmd), sizeof(cmd) - 1}
|
||||
|
||||
#define IIOD_CTX(desc, conn) {.instance = (desc)->app_instance,\
|
||||
.conn = (conn)->conn}
|
||||
|
||||
|
||||
/* Used to store a string and its size */
|
||||
struct iiod_str {
|
||||
char *str;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Commads are the ones documented int the link:
|
||||
* https://wiki.analog.com/resources/tools-software/linux-software/libiio_internals#the_network_backend_and_iio_daemon
|
||||
*/
|
||||
enum iiod_cmd {
|
||||
IIOD_CMD_HELP,
|
||||
IIOD_CMD_EXIT,
|
||||
IIOD_CMD_PRINT,
|
||||
IIOD_CMD_VERSION,
|
||||
IIOD_CMD_TIMEOUT,
|
||||
IIOD_CMD_OPEN,
|
||||
IIOD_CMD_CLOSE,
|
||||
IIOD_CMD_READ,
|
||||
IIOD_CMD_WRITE,
|
||||
IIOD_CMD_READBUF,
|
||||
IIOD_CMD_WRITEBUF,
|
||||
IIOD_CMD_GETTRIG,
|
||||
IIOD_CMD_SETTRIG,
|
||||
IIOD_CMD_SET
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure to be filled after a command is parsed.
|
||||
* Depending of cmd some fields are set or not
|
||||
*/
|
||||
struct comand_desc {
|
||||
enum iiod_cmd cmd;
|
||||
uint32_t mask;
|
||||
uint32_t timeout;
|
||||
uint32_t sample_count;
|
||||
uint32_t bytes_count;
|
||||
uint32_t count;
|
||||
bool cyclic;
|
||||
char device[MAX_DEV_ID];
|
||||
char channel[MAX_CHN_ID];
|
||||
char attr[MAX_ATTR_NAME];
|
||||
char trigger[MAX_TRIG_ID];
|
||||
enum iio_attr_type type;
|
||||
};
|
||||
|
||||
/* Used to store buffer indexes for non blocking transfers */
|
||||
struct iiod_buff {
|
||||
char *buf;
|
||||
uint32_t idx;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/* Result after executing a command. */
|
||||
struct iiod_run_cmd_result {
|
||||
uint32_t val;
|
||||
/* If set. Val needs to be sent */
|
||||
bool write_val;
|
||||
/* If buf.len != 0 buf has to be sent */
|
||||
struct iiod_buff buf;
|
||||
};
|
||||
|
||||
/* Internal structure to handle a connection state */
|
||||
struct iiod_conn_priv {
|
||||
/* User instance of the connection to be sent in iiod_ctx */
|
||||
void *conn;
|
||||
/* Unset when can be used from the connection pool */
|
||||
bool used;
|
||||
|
||||
/* Command data after parsed */
|
||||
struct comand_desc cmd_data;
|
||||
/* Result of an executed cmd */
|
||||
struct iiod_run_cmd_result res;
|
||||
/* IIOD States */
|
||||
enum {
|
||||
/* Reading line until \n */
|
||||
IIOD_READING_LINE,
|
||||
/* Execut cmd without I/O operations */
|
||||
IIOD_RUNNING_CMD,
|
||||
/* Write result of executed cmd */
|
||||
IIOD_WRITING_CMD_RESULT,
|
||||
/* I/O operations for READBUF and WRITEBUF cmds */
|
||||
IIOD_RW_BUF,
|
||||
/* I/O operations for WRITE cmd */
|
||||
IIOD_READING_WRITE_DATA,
|
||||
/* Set when a operation is finalized */
|
||||
IIOD_LINE_DONE,
|
||||
/* Pushing cyclic buffer until IIO device is closed */
|
||||
IIOD_PUSH_CYCLIC_BUFFER,
|
||||
} state;
|
||||
|
||||
/* Buffer to store received line */
|
||||
char parser_buf[IIOD_PARSER_MAX_BUF_SIZE];
|
||||
/* Index in parser_buf. For nonblocking operation */
|
||||
uint32_t parser_idx;
|
||||
/* Buffer to store raw data (attributes or buffer data).*/
|
||||
char *payload_buf;
|
||||
/* Length of payload_buf_len */
|
||||
uint32_t payload_buf_len;
|
||||
/* Used in nonbloking transfers to save indexes */
|
||||
struct iiod_buff nb_buf;
|
||||
|
||||
/* Mask of current opened buffer */
|
||||
uint32_t mask;
|
||||
/* Buffer to store mask as a string */
|
||||
char buf_mask[10];
|
||||
/* Context for strtok_r function */
|
||||
char *strtok_ctx;
|
||||
/* True if the device was open with cyclic buffer flag */
|
||||
bool is_cyclic_buffer;
|
||||
};
|
||||
|
||||
/* Private iiod information */
|
||||
struct iiod_desc {
|
||||
/* Pool of iiod connections */
|
||||
struct iiod_conn_priv conns[IIOD_MAX_CONNECTIONS];
|
||||
/* Application operations */
|
||||
struct iiod_ops ops;
|
||||
/* Application instance */
|
||||
void *app_instance;
|
||||
/* Address of xml */
|
||||
char *xml;
|
||||
/* XML length in bytes */
|
||||
uint32_t xml_len;
|
||||
/* Backend used by IIOD */
|
||||
enum physical_link_type phy_type;
|
||||
};
|
||||
|
||||
#endif //IIOD_PRIVATE_H
|
||||
295
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/jesd204.h
Normal file
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* The JESD204 framework
|
||||
*
|
||||
* Copyright (c) 2022 Analog Devices Inc.
|
||||
*/
|
||||
#ifndef _JESD204_H_
|
||||
#define _JESD204_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct jesd204_dev;
|
||||
|
||||
enum jesd204_subclass {
|
||||
JESD204_SUBCLASS_0,
|
||||
JESD204_SUBCLASS_1,
|
||||
JESD204_SUBCLASS_2,
|
||||
};
|
||||
|
||||
enum jesd204_version {
|
||||
JESD204_VERSION_A,
|
||||
JESD204_VERSION_B,
|
||||
JESD204_VERSION_C,
|
||||
};
|
||||
|
||||
/* JESD204C Supported encoding scheme */
|
||||
enum jesd204_encoder {
|
||||
JESD204_ENCODER_UNKNOWN,
|
||||
JESD204_ENCODER_8B10B,
|
||||
JESD204_ENCODER_64B66B,
|
||||
JESD204_ENCODER_64B80B,
|
||||
|
||||
JESD204_ENCODER_MAX
|
||||
};
|
||||
|
||||
enum jesd204_sysref_mode {
|
||||
JESD204_SYSREF_DISABLED,
|
||||
JESD204_SYSREF_CONTINUOUS,
|
||||
JESD204_SYSREF_ONESHOT,
|
||||
};
|
||||
|
||||
enum jesd204_state_change_result {
|
||||
JESD204_STATE_CHANGE_ERROR = -1,
|
||||
JESD204_STATE_CHANGE_DEFER = 0,
|
||||
JESD204_STATE_CHANGE_DONE,
|
||||
};
|
||||
|
||||
#define JESD204_LINKS_ALL ((unsigned int)(-1))
|
||||
|
||||
#define JESD204_LMFC_OFFSET_UNINITIALIZED ((uint16_t)-1)
|
||||
|
||||
/** @struct jesd204_sysref
|
||||
* @brief JESD204 parameters for SYSREF
|
||||
* @param mode: SYSREF mode (see jesd204_sysref_mode)
|
||||
* @param capture_falling_edge: true if it should capture falling edge
|
||||
* @param valid_falling_edge: true if falling edge should be valid
|
||||
* @param lmfc_offset: offset for LMFC
|
||||
*/
|
||||
struct jesd204_sysref {
|
||||
enum jesd204_sysref_mode mode;
|
||||
uint8_t capture_falling_edge;
|
||||
uint8_t valid_falling_edge;
|
||||
uint16_t lmfc_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct jesd204_link
|
||||
* @brief JESD204 link configuration settings
|
||||
* @param link_id: JESD204 link ID provided via DT configuration
|
||||
* @param error: error code for this JESD204 link
|
||||
* @param is_transmit: true if this link is transmit (digital to analog)
|
||||
* @param sample_rate: sample rate for the link
|
||||
* @param sample_rate_div: optional sample rate divider for the link
|
||||
* final rate = sample_rate / sample_rate_div
|
||||
* @param num_lanes: number of JESD204 lanes (L)
|
||||
* @param num_converters: number of converters per link (M)
|
||||
* @param octets_per_frame: number of octets per frame (F)
|
||||
* @param frames_per_multiframe: number of frames per frame (K)
|
||||
* @param num_of_multiblocks_in_emb: number of multiblocks in extended multiblock (E) (JESD204C)
|
||||
* @param bits_per_sample: number of bits per sample (N')
|
||||
* @param converter_resolution: converter resolution (N)
|
||||
* @param jesd_version: JESD204 version (A, B or C) (JESDV)
|
||||
* @param jesd_encoder: JESD204C encoder (8B10B, 64B66B, 64B80B)
|
||||
* @param subclass: JESD204 subclass (0,1 or 2) (SUBCLASSV)
|
||||
* @param device_id: device ID (DID)
|
||||
* @param bank_id: bank ID (BID)
|
||||
* @param scrambling: true if scrambling enabled (SCR)
|
||||
* @param high_density: true if high-density format is used (HD)
|
||||
* @param ctrl_words_per_frame_clk: number of control words per frame clock
|
||||
* period (CF)
|
||||
* @param ctrl_bits_per_sample: number of control bits per sample (CS)
|
||||
* @param samples_per_conv_frame: number of samples per converter per frame
|
||||
* cycle (S)
|
||||
* @param lane_ids: array of lane IDs (LID); note that this is an
|
||||
* array the size of num_lanes
|
||||
* @param sysref: JESD204 sysref config, see jesd204_sysref
|
||||
* @param dac_adj_resolution_steps: number of adjustment resolution steps to adjust
|
||||
* DAC LMFC (ADJCNT) - Subclass 2 only
|
||||
* @param dac_adj_direction: direction to adjust DAC LMFC (ADJDIR)
|
||||
* Subclass 2 only
|
||||
* @param dac_phase_adj: true to do phase adjustment request to DAC
|
||||
* Subclass 2 only
|
||||
*/
|
||||
struct jesd204_link {
|
||||
uint32_t link_id;
|
||||
int error;
|
||||
|
||||
uint64_t sample_rate;
|
||||
uint32_t sample_rate_div;
|
||||
|
||||
bool is_transmit;
|
||||
|
||||
uint8_t num_lanes;
|
||||
uint8_t num_converters;
|
||||
uint8_t octets_per_frame;
|
||||
uint16_t frames_per_multiframe;
|
||||
uint8_t num_of_multiblocks_in_emb; /* E */
|
||||
|
||||
uint8_t bits_per_sample;
|
||||
|
||||
uint8_t converter_resolution;
|
||||
uint8_t jesd_version;
|
||||
uint8_t jesd_encoder;
|
||||
uint8_t subclass;
|
||||
|
||||
uint8_t device_id;
|
||||
uint8_t bank_id;
|
||||
|
||||
uint8_t scrambling;
|
||||
uint8_t high_density;
|
||||
|
||||
uint8_t ctrl_words_per_frame_clk;
|
||||
uint8_t ctrl_bits_per_sample;
|
||||
uint8_t samples_per_conv_frame;
|
||||
|
||||
uint8_t *lane_ids;
|
||||
|
||||
struct jesd204_sysref sysref;
|
||||
|
||||
/* Subclass 2 only */
|
||||
uint8_t dac_adj_resolution_steps;
|
||||
uint8_t dac_adj_direction;
|
||||
uint8_t dac_phase_adj;
|
||||
};
|
||||
|
||||
enum jesd204_state_op_reason {
|
||||
JESD204_STATE_OP_REASON_INIT,
|
||||
JESD204_STATE_OP_REASON_UNINIT,
|
||||
};
|
||||
|
||||
static inline const char *jesd204_state_op_reason_str(enum
|
||||
jesd204_state_op_reason reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case JESD204_STATE_OP_REASON_INIT:
|
||||
return "initialization";
|
||||
case JESD204_STATE_OP_REASON_UNINIT:
|
||||
return "uninitialization";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
typedef int (*jesd204_sysref_cb)(struct jesd204_dev *jdev);
|
||||
|
||||
typedef int (*jesd204_dev_cb)(struct jesd204_dev *jdev,
|
||||
enum jesd204_state_op_reason reason);
|
||||
|
||||
typedef int (*jesd204_link_cb)(struct jesd204_dev *jdev,
|
||||
enum jesd204_state_op_reason,
|
||||
struct jesd204_link *lnk);
|
||||
|
||||
enum jesd204_state_op_mode {
|
||||
JESD204_STATE_OP_MODE_PER_LINK,
|
||||
JESD204_STATE_OP_MODE_PER_DEVICE,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct jesd204_state_op
|
||||
* @brief JESD204 device per-state op
|
||||
* @param mode: mode for this state op, depending on this per_device or per_link is called
|
||||
* @param per_device: op called for each JESD204 **device** during a transition
|
||||
* @param per_link op called for each JESD204 **link** individually during a transition
|
||||
* // FIXME: maybe pass 'struct jesd204_sysref' for post_state_sysref, to make this configurable? we'll see later
|
||||
* // FIXME: for now, the device should also be a top-level device, in case of multi-chip setups
|
||||
* @param post_state_sysref: true if a SYSREF should be issued after the state change
|
||||
*/
|
||||
struct jesd204_state_op {
|
||||
enum jesd204_state_op_mode mode;
|
||||
jesd204_dev_cb per_device;
|
||||
jesd204_link_cb per_link;
|
||||
bool post_state_sysref;
|
||||
};
|
||||
|
||||
enum jesd204_dev_op {
|
||||
JESD204_OP_DEVICE_INIT,
|
||||
JESD204_OP_LINK_INIT,
|
||||
JESD204_OP_LINK_SUPPORTED,
|
||||
JESD204_OP_LINK_PRE_SETUP,
|
||||
JESD204_OP_CLK_SYNC_STAGE1,
|
||||
JESD204_OP_CLK_SYNC_STAGE2,
|
||||
JESD204_OP_CLK_SYNC_STAGE3,
|
||||
JESD204_OP_LINK_SETUP,
|
||||
JESD204_OP_OPT_SETUP_STAGE1,
|
||||
JESD204_OP_OPT_SETUP_STAGE2,
|
||||
JESD204_OP_OPT_SETUP_STAGE3,
|
||||
JESD204_OP_OPT_SETUP_STAGE4,
|
||||
JESD204_OP_OPT_SETUP_STAGE5,
|
||||
JESD204_OP_CLOCKS_ENABLE,
|
||||
JESD204_OP_LINK_ENABLE,
|
||||
JESD204_OP_LINK_RUNNING,
|
||||
JESD204_OP_OPT_POST_RUNNING_STAGE,
|
||||
|
||||
__JESD204_MAX_OPS,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct jesd204_dev_data
|
||||
* @brief JESD204 device initialization data
|
||||
* @param sysref_cb: SYSREF callback, if this device/driver supports it
|
||||
* @param sizeof_priv: amount of data to allocate for private information
|
||||
* @param max_num_links: maximum number of JESD204 links this device can support
|
||||
* @param num_retries: number of retries in case of error (only for top-level device)
|
||||
* @param state_ops: ops for each state transition of type @struct jesd204_state_op
|
||||
*/
|
||||
struct jesd204_dev_data {
|
||||
jesd204_sysref_cb sysref_cb;
|
||||
size_t sizeof_priv;
|
||||
unsigned int max_num_links;
|
||||
unsigned int num_retries;
|
||||
struct jesd204_state_op state_ops[__JESD204_MAX_OPS];
|
||||
};
|
||||
|
||||
/* no-OS specific */
|
||||
#define JESD204_MAX_TOPOLOGY_LINKS 16
|
||||
|
||||
/* no-OS specific */
|
||||
struct jesd204_topology_dev {
|
||||
struct jesd204_dev *jdev;
|
||||
bool is_top_device;
|
||||
bool is_sysref_provider;
|
||||
unsigned int link_ids[JESD204_MAX_TOPOLOGY_LINKS];
|
||||
unsigned int links_number;
|
||||
};
|
||||
|
||||
/* no-OS specific */
|
||||
struct jesd204_topology {
|
||||
struct jesd204_dev_top *dev_top;
|
||||
struct jesd204_topology_dev *devs;
|
||||
unsigned int devs_number;
|
||||
};
|
||||
|
||||
/* no-OS specific */
|
||||
int jesd204_dev_register(struct jesd204_dev **jdev,
|
||||
const struct jesd204_dev_data *dev_data);
|
||||
|
||||
/* no-OS specific */
|
||||
int jesd204_dev_unregister(struct jesd204_dev *jdev);
|
||||
|
||||
/* no-OS specific */
|
||||
int jesd204_topology_init(struct jesd204_topology **topology,
|
||||
struct jesd204_topology_dev *devs,
|
||||
unsigned int devs_number);
|
||||
|
||||
/* no-OS specific */
|
||||
int jesd204_topology_remove(struct jesd204_topology *topology);
|
||||
|
||||
/* no-OS specific */
|
||||
int jesd204_fsm_start(struct jesd204_topology *topology, unsigned int link_idx);
|
||||
|
||||
/* no-OS specific */
|
||||
int jesd204_fsm_stop(struct jesd204_topology *topology, unsigned int link_idx);
|
||||
|
||||
void *jesd204_dev_priv(struct jesd204_dev *jdev);
|
||||
|
||||
int jesd204_link_get_lmfc_lemc_rate(struct jesd204_link *lnk,
|
||||
unsigned long *rate_hz);
|
||||
|
||||
int jesd204_link_get_rate_khz(struct jesd204_link *lnk,
|
||||
unsigned long *lane_rate_khz);
|
||||
|
||||
int jesd204_link_get_device_clock(struct jesd204_link *lnk,
|
||||
unsigned long *device_clock);
|
||||
|
||||
int jesd204_sysref_async(struct jesd204_dev *jdev);
|
||||
|
||||
int jesd204_sysref_async_force(struct jesd204_dev *jdev);
|
||||
|
||||
bool jesd204_dev_is_top(struct jesd204_dev *jdev);
|
||||
|
||||
void jesd204_copy_link_params(struct jesd204_link *dst,
|
||||
const struct jesd204_link *src);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_ain.h
|
||||
* @author PMallick (Pratyush.Mallick@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright (c) 2021-22 Analog Devices, Inc.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef NO_OS_AIN_H
|
||||
#define NO_OS_AIN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @struct ain_init_param
|
||||
* @brief Structure holding parameters for analog input initialization
|
||||
*/
|
||||
struct no_os_ain_init_param {
|
||||
/* Analog input reference voltage */
|
||||
float vref;
|
||||
/* Analog extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct ain_desc
|
||||
* @brief Structure holding analog input descriptor
|
||||
*/
|
||||
struct no_os_ain_desc {
|
||||
/* Analog input reference voltage */
|
||||
float vref;
|
||||
/* Analog extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/* Read analog input voltage */
|
||||
int32_t no_os_ain_get_voltage(struct no_os_ain_desc *desc, float *value);
|
||||
|
||||
/* Initialize the analog input peripheral*/
|
||||
int32_t no_os_ain_init(struct no_os_ain_desc **desc,
|
||||
const struct no_os_ain_init_param *param);
|
||||
|
||||
/* Free the resources allocated by no_os_ain_init() */
|
||||
int32_t no_os_ain_remove(struct no_os_ain_desc *desc);
|
||||
|
||||
#endif // end of NO_OS_AIN_H
|
||||
@@ -0,0 +1,67 @@
|
||||
/*******************************************************************************
|
||||
* @file util/no_os_alloc.c
|
||||
* @brief Implementation of no-OS memory allocation functions.
|
||||
* @author GMois (george.mois@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2023(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "no_os_alloc.h"
|
||||
|
||||
/**
|
||||
* @brief Allocate memory and return a pointer to it.
|
||||
* @param size - Size of the memory block, in bytes.
|
||||
* @return Pointer to the allocated memory, or NULL if the request fails.
|
||||
*/
|
||||
__attribute__((weak)) void *no_os_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate memory and return a pointer to it, set memory to 0.
|
||||
* @param nitems - Number of elements to be allocated.
|
||||
* @param size - Size of elements.
|
||||
* @return Pointer to the allocated memory, or NULL if the request fails.
|
||||
*/
|
||||
__attribute__((weak)) void *no_os_calloc(size_t nitems, size_t size)
|
||||
{
|
||||
return calloc(nitems, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deallocate memory previously allocated by a call to no_os_calloc
|
||||
* or no_os_malloc.
|
||||
* @param ptr - Pointer to a memory block previously allocated by a call
|
||||
* to no_os_calloc or no_os_malloc.
|
||||
* @return None.
|
||||
*/
|
||||
__attribute__((weak)) void no_os_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*******************************************************************************
|
||||
* @file no_os_alloc.h
|
||||
* @brief Header file of memory allocator.
|
||||
* @author GMois (george.mois@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2023(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_ALLOC_H_
|
||||
#define _NO_OS_ALLOC_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Allocate memory and return a pointer to it */
|
||||
void *no_os_malloc(size_t size);
|
||||
|
||||
/* Allocate memory and return a pointer to it, set memory to 0 */
|
||||
void *no_os_calloc(size_t nitems, size_t size);
|
||||
|
||||
/* Deallocate memory previously allocated by a call to no_os_calloc or
|
||||
* no_os_malloc */
|
||||
void no_os_free(void *ptr);
|
||||
|
||||
#endif // _NO_OS_ALLOC_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_aout.h
|
||||
* @author PMallick (Pratyush.Mallick@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright (c) 2021-22 Analog Devices, Inc.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef NO_OS_AOUT_H
|
||||
#define NO_OS_AOUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @struct aout_init_param
|
||||
* @brief Structure holding the parameters for analog output initialization
|
||||
*/
|
||||
struct no_os_aout_init_param {
|
||||
/* Min output range of DAC in volts */
|
||||
float aout_min_v;
|
||||
/* Max output range of DAC in volts */
|
||||
float aout_max_v;
|
||||
/* Analog output reference voltage */
|
||||
float vref;
|
||||
/* Analog extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct aout_desc
|
||||
* @brief Structure holding analog output descriptor
|
||||
*/
|
||||
struct no_os_aout_desc {
|
||||
/* Min output value of DAC in volts */
|
||||
float aout_min_v;
|
||||
/* Max output value of DAC in volts */
|
||||
float aout_max_v;
|
||||
/* Analog output reference voltage */
|
||||
float vref;
|
||||
/* Analog extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/* Write analog output voltage */
|
||||
int32_t no_os_aout_set_voltage(struct no_os_aout_desc *desc, float value);
|
||||
|
||||
/* Initialize the analog output peripheral */
|
||||
int32_t no_so_aout_init(struct no_os_aout_desc **desc,
|
||||
const struct no_os_aout_init_param *param);
|
||||
|
||||
/* Free the resources allocated by no_os_aout_init() */
|
||||
int32_t no_os_aout_remove(struct no_os_aout_desc *desc);
|
||||
|
||||
#endif // end of NO_OS_AOUT_H
|
||||
@@ -0,0 +1,45 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_axi_io.h
|
||||
* @brief Header file of AXI IO.
|
||||
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _NO_OS_AXI_IO_H_
|
||||
#define _NO_OS_AXI_IO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* AXI IO Read data */
|
||||
int32_t no_os_axi_io_read(uint32_t base, uint32_t offset, uint32_t *data);
|
||||
|
||||
/* AXI IO Write data */
|
||||
int32_t no_os_axi_io_write(uint32_t base, uint32_t offset, uint32_t data);
|
||||
|
||||
#endif // _NO_OS_AXI_IO_H_
|
||||
@@ -0,0 +1,390 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_circular_buffer.c
|
||||
* @brief Circular buffer implementation
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* @copyright
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "no_os_circular_buffer.h"
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_util.h"
|
||||
#include "no_os_alloc.h"
|
||||
|
||||
int32_t no_os_cb_cfg(struct no_os_circular_buffer *desc, int8_t *buff,
|
||||
uint32_t size)
|
||||
{
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
desc->size = size;
|
||||
desc->buff = buff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create circular buffer structure.
|
||||
*
|
||||
* @note Circular buffer implementation is thread safe for one write
|
||||
* and one reader.
|
||||
* If multiple writer or multiple readers access the circular buffer then
|
||||
* function that updates the structure should be called inside a critical
|
||||
* critical section.
|
||||
*
|
||||
* @param desc - Where to store the circular buffer reference
|
||||
* @param buff_size - Buffer size
|
||||
* @return
|
||||
* - 0 : On success
|
||||
* - -1 : Otherwise
|
||||
*/
|
||||
int32_t no_os_cb_init(struct no_os_circular_buffer **desc, uint32_t buff_size)
|
||||
{
|
||||
struct no_os_circular_buffer *ldesc;
|
||||
|
||||
if (!desc || !buff_size)
|
||||
return -EINVAL;
|
||||
|
||||
ldesc = (struct no_os_circular_buffer*)no_os_calloc(1, sizeof(*ldesc));
|
||||
if (!ldesc)
|
||||
return -ENOMEM;
|
||||
|
||||
*desc = ldesc;
|
||||
|
||||
ldesc->size = buff_size;
|
||||
ldesc->buff = no_os_calloc(1, buff_size);
|
||||
if (!ldesc->buff) {
|
||||
no_os_free(ldesc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated for the circular buffer structure.
|
||||
* @param desc - Circular buffer reference
|
||||
* @return
|
||||
* - 0 : On success
|
||||
* - -1 : Otherwise
|
||||
*/
|
||||
int32_t no_os_cb_remove(struct no_os_circular_buffer *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return -1;
|
||||
|
||||
if (desc->buff)
|
||||
no_os_free(desc->buff);
|
||||
no_os_free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the number of elements in the buffer.
|
||||
* @param desc - Circular buffer reference
|
||||
* @param size - Where to store size of data available to read
|
||||
* @return
|
||||
* - 0 - No errors
|
||||
* - -EINVAL - Wrong parameters used
|
||||
* - -NO_OS_EOVERRUN - A buffer overrun occurred
|
||||
*/
|
||||
int32_t no_os_cb_size(struct no_os_circular_buffer *desc, uint32_t *size)
|
||||
{
|
||||
uint32_t nb_spins;
|
||||
|
||||
if (!desc || !size)
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->write.spin_count > desc->read.spin_count)
|
||||
nb_spins = desc->write.spin_count - desc->read.spin_count;
|
||||
else
|
||||
/* Integer overflow on desc->write.spin_count */
|
||||
nb_spins = UINT32_MAX - desc->read.spin_count +
|
||||
desc->write.spin_count + 1;
|
||||
|
||||
if (nb_spins > 0)
|
||||
*size = desc->size + desc->write.idx - desc->read.idx;
|
||||
else
|
||||
*size = desc->write.idx - desc->read.idx;
|
||||
|
||||
if (*size > desc->size) {
|
||||
*size = desc->size;
|
||||
return -NO_OS_EOVERRUN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functionality described at no_os_cb_prepare_async_write/read having the is_read
|
||||
* parameter to specifiy if it is a read or write operation.
|
||||
*/
|
||||
static int32_t no_os_cb_prepare_async_operation(struct no_os_circular_buffer
|
||||
*desc,
|
||||
uint32_t requested_size,
|
||||
void **buff,
|
||||
uint32_t *raw_size_available,
|
||||
bool is_read)
|
||||
{
|
||||
struct no_os_cb_ptr *ptr;
|
||||
uint32_t available_size;
|
||||
int32_t ret;
|
||||
|
||||
if (!desc || !buff || !raw_size_available)
|
||||
return -EINVAL;
|
||||
|
||||
ret = 0;
|
||||
/* Select if read or write index will be updated */
|
||||
ptr = is_read ? &desc->read : &desc->write;
|
||||
|
||||
/* Only one transaction type possible at a single time */
|
||||
if (ptr->async_started)
|
||||
return -EBUSY;
|
||||
|
||||
if (is_read) {
|
||||
ret = no_os_cb_size(desc, &available_size);
|
||||
if (ret == -NO_OS_EOVERRUN) {
|
||||
/* Update read index */
|
||||
desc->read.spin_count = desc->write.spin_count - 1;
|
||||
#ifndef IIO_IGNORE_BUFF_OVERRUN_ERR
|
||||
desc->read.idx = desc->write.idx;
|
||||
#endif
|
||||
}
|
||||
if (!available_size)
|
||||
/* No data to read */
|
||||
return 0;
|
||||
|
||||
/* We can only read available data */
|
||||
requested_size = no_os_min(requested_size, available_size);
|
||||
if (!requested_size)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Size to end of buffer */
|
||||
ptr->async_size = no_os_min(requested_size, desc->size - ptr->idx);
|
||||
|
||||
*raw_size_available = ptr->async_size;
|
||||
|
||||
/* Convert index to address in the buffer */
|
||||
*buff = (void *)(desc->buff + ptr->idx);
|
||||
|
||||
ptr->async_started = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functionality described at no_os_cb_end_async_write/read having the is_read
|
||||
* parameter to specifiy if it is a read or write operation.
|
||||
*/
|
||||
static int32_t no_os_cb_end_async_operation(struct no_os_circular_buffer *desc,
|
||||
bool is_read)
|
||||
{
|
||||
struct no_os_cb_ptr *ptr;
|
||||
uint32_t new_val;
|
||||
|
||||
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
/* Select if read or write index will be updated */
|
||||
ptr = is_read ? &desc->read : &desc->write;
|
||||
|
||||
/* Transaction not started */
|
||||
if (!ptr->async_started)
|
||||
return -1;
|
||||
|
||||
/* Update pointer value */
|
||||
new_val = ptr->idx + ptr->async_size;
|
||||
if (new_val >= desc->size) {
|
||||
ptr->spin_count++;
|
||||
new_val %= desc->size;
|
||||
}
|
||||
ptr->idx = new_val;
|
||||
ptr->async_size = 0;
|
||||
ptr->async_started = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functionality described at cb_write/read having the is_read
|
||||
* parameter to specifiy if it is a read or write operation.
|
||||
*/
|
||||
static int32_t no_os_cb_operation(struct no_os_circular_buffer *desc,
|
||||
void *data, uint32_t size,
|
||||
bool is_read)
|
||||
{
|
||||
uint8_t *buff;
|
||||
uint32_t available_size = 0;
|
||||
int32_t ret;
|
||||
uint32_t i;
|
||||
bool sticky_overrun;
|
||||
|
||||
if (!desc || !data || !size)
|
||||
return -EINVAL;
|
||||
|
||||
sticky_overrun = 0;
|
||||
i = 0;
|
||||
while (i < size) {
|
||||
do {
|
||||
ret = no_os_cb_prepare_async_operation(desc, size - i,
|
||||
(void **)&buff,
|
||||
&available_size,
|
||||
is_read);
|
||||
} while (ret == -EBUSY || ret == -EAGAIN);
|
||||
if (ret == -NO_OS_EOVERRUN)
|
||||
sticky_overrun = true;
|
||||
|
||||
/* If no data is available return error */
|
||||
if (!available_size)
|
||||
return -1;
|
||||
|
||||
if (is_read)
|
||||
memcpy((uint8_t *)data + i, buff, available_size);
|
||||
else
|
||||
memcpy(buff, (uint8_t *)data + i, available_size);
|
||||
|
||||
no_os_cb_end_async_operation(desc, is_read);
|
||||
|
||||
i += available_size;
|
||||
}
|
||||
|
||||
if (sticky_overrun)
|
||||
return -NO_OS_EOVERRUN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepare asynchronous write.
|
||||
*
|
||||
* Get the inside raw buffer to be used in DMA transactions.
|
||||
*
|
||||
* @param desc - Circular buffer reference
|
||||
* @param size_to_write - Number of bytes needed to write to the buffer.
|
||||
* @param write_buff - Address where to store the buffer where to write to.
|
||||
* @param size_avilable - no_os_min(size_to_write, size until end of allocated buffer)
|
||||
* @return
|
||||
* - 0 - No errors
|
||||
* - -EINVAL - Wrong parameters used
|
||||
* - -EBUSY - Asynchronous transaction already started
|
||||
*/
|
||||
int32_t no_os_cb_prepare_async_write(struct no_os_circular_buffer *desc,
|
||||
uint32_t size_to_write,
|
||||
void **write_buff,
|
||||
uint32_t *size_avilable)
|
||||
{
|
||||
return no_os_cb_prepare_async_operation(desc, size_to_write, write_buff,
|
||||
size_avilable, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepare asynchronous read.
|
||||
*
|
||||
* Get the inside raw buffer to be used in DMA transactions.
|
||||
*
|
||||
* @param desc - Circular buffer reference
|
||||
* @param size_to_read - Number of bytes needed to write to the buffer.
|
||||
* @param read_buff - Address where to store the buffer where data will be read.
|
||||
* @param size_avilable - no_os_min(size_to_read, size until end of allocated buffer)
|
||||
* @return
|
||||
* - 0 - No errors
|
||||
* - -EAGAIN - No data available at this moment
|
||||
* - -EINVAL - Wrong parameters used
|
||||
* - -EBUSY - Asynchronous transaction already started
|
||||
* - -NO_OS_EOVERRUN - An overrun occurred and some data have been overwritten
|
||||
*/
|
||||
int32_t no_os_cb_prepare_async_read(struct no_os_circular_buffer *desc,
|
||||
uint32_t size_to_read,
|
||||
void **read_buff,
|
||||
uint32_t *size_avilable)
|
||||
{
|
||||
return no_os_cb_prepare_async_operation(desc, size_to_read, read_buff,
|
||||
size_avilable, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \defgroup end_async_group End Ashyncronous functions
|
||||
* @brief End asynchronous transaction.
|
||||
*
|
||||
* @param desc - Circular buffer reference
|
||||
* @return
|
||||
* - 0 - No errors
|
||||
* - -1 - Asynchronous transaction not started
|
||||
* - -EINVAL - Wrong parameters used
|
||||
* @{
|
||||
*/
|
||||
int32_t no_os_cb_end_async_write(struct no_os_circular_buffer *desc)
|
||||
{
|
||||
return no_os_cb_end_async_operation(desc, 0);
|
||||
}
|
||||
|
||||
int32_t no_os_cb_end_async_read(struct no_os_circular_buffer *desc)
|
||||
{
|
||||
|
||||
return no_os_cb_end_async_operation(desc, 1);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Write data to the buffer (Blocking).
|
||||
* @param desc - Circular buffer reference
|
||||
* @param data - Buffer from where data is copied to the circular buffer
|
||||
* @param size - Size to write
|
||||
* @return
|
||||
* - 0 - No errors
|
||||
* - -EINVAL - Wrong parameters used
|
||||
*/
|
||||
int32_t no_os_cb_write(struct no_os_circular_buffer *desc, const void *data,
|
||||
uint32_t size)
|
||||
{
|
||||
return no_os_cb_operation(desc, (void *)data, size, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read data from the buffer (Blocking).
|
||||
* @param desc - Circular buffer reference
|
||||
* @param data - Buffer where to data is copied from the circular buffer
|
||||
* @param size - Size to read
|
||||
* @return
|
||||
* - 0 - No errors
|
||||
* - -EINVAL - Wrong parameters used
|
||||
* - -NO_OS_EOVERRUN - An overrun occurred and some data have been overwritten
|
||||
*/
|
||||
int32_t no_os_cb_read(struct no_os_circular_buffer *desc, void *data,
|
||||
uint32_t size)
|
||||
{
|
||||
return no_os_cb_operation(desc, data, size, 1);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_circular_buffer.h
|
||||
* @brief Circular buffer library header
|
||||
* @author Mihail Chindris (mihail.chindris@analog.com)
|
||||
********************************************************************************
|
||||
* @copyright
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _NO_OS_CIRCULAR_BUFFER_H_
|
||||
#define _NO_OS_CIRCULAR_BUFFER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @struct no_os_cb_ptr
|
||||
* @brief Circular buffer pointer
|
||||
*/
|
||||
struct no_os_cb_ptr {
|
||||
/** Index of data in the buffer */
|
||||
uint32_t idx;
|
||||
/** Counts the number of times idx exceeds the liniar buffer */
|
||||
uint32_t spin_count;
|
||||
/** Set if async transaction is active */
|
||||
bool async_started;
|
||||
/** Number of bytes to update after an async transaction is finished */
|
||||
uint32_t async_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_circular_buffer
|
||||
* @brief Circular buffer descriptor
|
||||
*/
|
||||
struct no_os_circular_buffer {
|
||||
/** Size of the buffer in bytes */
|
||||
uint32_t size;
|
||||
/** Address of the buffer */
|
||||
int8_t *buff;
|
||||
/** Write pointer */
|
||||
struct no_os_cb_ptr write;
|
||||
/** Read pointer */
|
||||
struct no_os_cb_ptr read;
|
||||
};
|
||||
|
||||
int32_t no_os_cb_init(struct no_os_circular_buffer **desc, uint32_t size);
|
||||
/* Configure cb structure with given parameters without memory allocation */
|
||||
int32_t no_os_cb_cfg(struct no_os_circular_buffer *desc, int8_t *buf,
|
||||
uint32_t size);
|
||||
int32_t no_os_cb_remove(struct no_os_circular_buffer *desc);
|
||||
int32_t no_os_cb_size(struct no_os_circular_buffer *desc, uint32_t *size);
|
||||
|
||||
int32_t no_os_cb_write(struct no_os_circular_buffer *desc, const void *data,
|
||||
uint32_t nb_elements);
|
||||
int32_t no_os_cb_read(struct no_os_circular_buffer *desc, void *data,
|
||||
uint32_t nb_elements);
|
||||
|
||||
int32_t no_os_cb_prepare_async_write(struct no_os_circular_buffer *desc,
|
||||
uint32_t raw_size_to_write,
|
||||
void **write_buff,
|
||||
uint32_t *raw_size_avilable);
|
||||
int32_t no_os_cb_end_async_write(struct no_os_circular_buffer *desc);
|
||||
|
||||
int32_t no_os_cb_prepare_async_read(struct no_os_circular_buffer *desc,
|
||||
uint32_t raw_size_to_read,
|
||||
void **read_buff,
|
||||
uint32_t *raw_size_avilable);
|
||||
int32_t no_os_cb_end_async_read(struct no_os_circular_buffer *desc);
|
||||
|
||||
#endif //_NO_OS_CIRCULAR_BUFFER_H_
|
||||
193
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_clk.c
|
||||
* @brief Implementation of Clock Driver.
|
||||
* @author DBogdan (dragos.bogdan@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
#include "no_os_alloc.h"
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_clk.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/************************** Functions Implementation **************************/
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* Initialize clock.
|
||||
* @param desc - CLK descriptor.
|
||||
* @param param - The structure that contains CLK parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_clk_init(struct no_os_clk_desc **desc,
|
||||
const struct no_os_clk_init_param *param)
|
||||
{
|
||||
struct no_os_clk_desc *clk;
|
||||
int ret;
|
||||
|
||||
if (!desc || !param || !param->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
clk = (struct no_os_clk_desc *)no_os_calloc(1, sizeof(*clk));
|
||||
if (!clk)
|
||||
return -ENOMEM;
|
||||
|
||||
clk->name = param->name;
|
||||
clk->hw_ch_num = param->hw_ch_num;
|
||||
clk->dev_desc = param->dev_desc;
|
||||
clk->platform_ops = param->platform_ops;
|
||||
|
||||
if (param->platform_ops->init) {
|
||||
ret = param->platform_ops->init(desc, param);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
*desc = clk;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
no_os_free(clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by no_os_clk_init().
|
||||
* @param desc - The clock descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_clk_remove(struct no_os_clk_desc *desc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->platform_ops->remove) {
|
||||
ret = desc->platform_ops->remove(desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
no_os_free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the clock.
|
||||
* @param clk - The clock descriptor.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int32_t no_os_clk_enable(struct no_os_clk_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->clk_enable)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->clk_enable(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the clock.
|
||||
* @param clk - The clock descriptor.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int32_t no_os_clk_disable(struct no_os_clk_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->clk_disable)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->clk_disable(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current frequency of the clock.
|
||||
* @param clk - The clock descriptor.
|
||||
* @param rate - The current frequency.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int32_t no_os_clk_recalc_rate(struct no_os_clk_desc *desc,
|
||||
uint64_t *rate)
|
||||
{
|
||||
if (!desc || !desc->platform_ops || !rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->clk_recalc_rate)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->clk_recalc_rate(desc, rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the desired frequency to a rate that the clock can actually output.
|
||||
* @param clk - The clock descriptor.
|
||||
* @param rate - The desired frequency.
|
||||
* @param rounded_rate - The rounded frequency.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int32_t no_os_clk_round_rate(struct no_os_clk_desc *desc,
|
||||
uint64_t rate,
|
||||
uint64_t *rounded_rate)
|
||||
{
|
||||
if (!desc || !desc->platform_ops || !rounded_rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->clk_round_rate)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->clk_round_rate(desc, rate, rounded_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the frequency of the clock.
|
||||
* @param clk - The clock descriptor.
|
||||
* @param rate - The desired frequency.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int32_t no_os_clk_set_rate(struct no_os_clk_desc *desc,
|
||||
uint64_t rate)
|
||||
{
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->clk_set_rate)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->clk_set_rate(desc, rate);
|
||||
}
|
||||
128
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_clk.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_clk.h
|
||||
* @brief Header file of Clock Driver.
|
||||
* @author DBogdan (dragos.bogdan@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_CLK_H_
|
||||
#define _NO_OS_CLK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct no_os_clk_init_param {
|
||||
/** Device name */
|
||||
const char *name;
|
||||
/** Channel number */
|
||||
uint8_t hw_ch_num;
|
||||
/** CLK function pointers */
|
||||
const struct no_os_clk_platform_ops *platform_ops;
|
||||
/** CLK hardware device descriptor */
|
||||
void *dev_desc;
|
||||
};
|
||||
|
||||
struct no_os_clk_hw {
|
||||
void *dev;
|
||||
int32_t (*dev_clk_enable)();
|
||||
int32_t (*dev_clk_disable)();
|
||||
int32_t (*dev_clk_recalc_rate)();
|
||||
int32_t (*dev_clk_set_rate)();
|
||||
int32_t (*dev_clk_round_rate)();
|
||||
};
|
||||
|
||||
struct no_os_clk {
|
||||
struct no_os_clk_hw *hw;
|
||||
uint32_t hw_ch_num;
|
||||
const char *name;
|
||||
const struct no_os_clk_desc *clk_desc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_clk_desc
|
||||
* @brief Structure holding CLK descriptor.
|
||||
*/
|
||||
typedef struct no_os_clk_desc {
|
||||
/** Device name */
|
||||
const char *name;
|
||||
/** Channel number */
|
||||
uint8_t hw_ch_num;
|
||||
/** CLK function pointers */
|
||||
const struct no_os_clk_platform_ops *platform_ops;
|
||||
/** CLK hardware device descriptor */
|
||||
void *dev_desc;
|
||||
} no_os_clk_desc;
|
||||
|
||||
/**
|
||||
* @struct no_os_clk_platform_ops
|
||||
* @brief Structure holding CLK function pointers that point to the platform
|
||||
* specific function
|
||||
*/
|
||||
struct no_os_clk_platform_ops {
|
||||
/** Initialize CLK function pointer. */
|
||||
int (*init)(struct no_os_clk_desc **, const struct no_os_clk_init_param *);
|
||||
/** Start CLK function pointer. */
|
||||
int (*clk_enable)(struct no_os_clk_desc *);
|
||||
/** Stop CLK function pointer. */
|
||||
int (*clk_disable)(struct no_os_clk_desc *);
|
||||
/** Get the current frequency of CLK function pointer. */
|
||||
int (*clk_recalc_rate)(struct no_os_clk_desc *, uint64_t *);
|
||||
/* Round the desired frequency to a rate that CLK can actually output. */
|
||||
int (*clk_round_rate)(struct no_os_clk_desc *, uint64_t, uint64_t *);
|
||||
/* Change CLK frequency function pointer. */
|
||||
int (*clk_set_rate)(struct no_os_clk_desc *, uint64_t);
|
||||
/** CLK remove function pointer */
|
||||
int (*remove)(struct no_os_clk_desc *);
|
||||
};
|
||||
|
||||
/* Initialize CLK ops. */
|
||||
int32_t no_os_clk_init(struct no_os_clk_desc **desc,
|
||||
const struct no_os_clk_init_param *param);
|
||||
|
||||
/* Free the resources allocated by no_os_clk_init(). */
|
||||
int32_t no_os_clk_remove(struct no_os_clk_desc *desc);
|
||||
|
||||
/* Start the clock. */
|
||||
int32_t no_os_clk_enable(struct no_os_clk_desc *desc);
|
||||
|
||||
/* Stop the clock. */
|
||||
int32_t no_os_clk_disable(struct no_os_clk_desc *desc);
|
||||
|
||||
/* Get the current frequency of the clock. */
|
||||
int32_t no_os_clk_recalc_rate(struct no_os_clk_desc *desc,
|
||||
uint64_t *rate);
|
||||
|
||||
/* Round the desired frequency to a rate that the clock can actually output. */
|
||||
int32_t no_os_clk_round_rate(struct no_os_clk_desc *desc,
|
||||
uint64_t rate,
|
||||
uint64_t *rounded_rate);
|
||||
|
||||
/* Change the frequency of the clock. */
|
||||
int32_t no_os_clk_set_rate(struct no_os_clk_desc *desc,
|
||||
uint64_t rate);
|
||||
|
||||
#endif // _NO_OS_CLK_H_
|
||||
@@ -0,0 +1,40 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_crc.h
|
||||
* @brief Generic header file for all CRC computation algorithms.
|
||||
* @author Darius Berghe (darius.berghe@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_CRC_H_
|
||||
#define _NO_OS_CRC_H_
|
||||
|
||||
#include "no_os_crc8.h"
|
||||
#include "no_os_crc16.h"
|
||||
#include "no_os_crc24.h"
|
||||
|
||||
#endif // _NO_OS_CRC_H_
|
||||
@@ -0,0 +1,97 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_crc16.c
|
||||
* @brief Source file of CRC-16 computation.
|
||||
* @author Darius Berghe (darius.berghe@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#include "no_os_crc16.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Creates the CRC-16 lookup table for a given polynomial.
|
||||
*
|
||||
* @param table - Pointer to a CRC-16 lookup table to write to.
|
||||
* @param polynomial - Msb-first representation of desired polynomial.
|
||||
*
|
||||
* Polynomials in CRC algorithms are typically represented as shown below.
|
||||
*
|
||||
* poly = x^16 + x^14 + x^13 + x^12 + x^10 + x^8 + x^6 + x^4 + x^3 +
|
||||
* x^1 + 1
|
||||
*
|
||||
* Using msb-first direction, x^15 maps to the msb.
|
||||
*
|
||||
* msb first: poly = (1)0111010101011011 = 0x755B
|
||||
* ^
|
||||
*
|
||||
* @return None.
|
||||
*******************************************************************************/
|
||||
void no_os_crc16_populate_msb(uint16_t * table, const uint16_t polynomial)
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (int16_t n = 0; n < NO_OS_CRC16_TABLE_SIZE; n++) {
|
||||
uint16_t currByte = (uint16_t)(n << 8);
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
if ((currByte & 0x8000) != 0) {
|
||||
currByte <<= 1;
|
||||
currByte ^= polynomial;
|
||||
} else {
|
||||
currByte <<= 1;
|
||||
}
|
||||
}
|
||||
table[n] = currByte;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Computes the CRC-16 over a buffer of data.
|
||||
*
|
||||
* @param table - Pointer to a CRC-16 lookup table for the desired polynomial.
|
||||
* @param pdata - Pointer to data buffer.
|
||||
* @param nbytes - Number of bytes to compute the CRC-16 over.
|
||||
* @param crc - Initial value for the CRC-16 computation. Can be used to
|
||||
* cascade calls to this function by providing a previous
|
||||
* output of this function as the crc parameter.
|
||||
*
|
||||
* @return crc - Computed CRC-16 value.
|
||||
*******************************************************************************/
|
||||
uint16_t no_os_crc16(const uint16_t * table, const uint8_t *pdata,
|
||||
size_t nbytes,
|
||||
uint16_t crc)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
while (nbytes--) {
|
||||
idx = ((crc >> 8) ^ *pdata) & 0xff;
|
||||
crc = (table[idx] ^ (crc << 8)) & 0xffff;
|
||||
pdata++;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_crc16.h
|
||||
* @brief Header file of CRC-16 computation.
|
||||
* @author Darius Berghe (darius.berghe@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_CRC16_H_
|
||||
#define _NO_OS_CRC16_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define NO_OS_CRC16_TABLE_SIZE 256
|
||||
|
||||
#define NO_OS_DECLARE_CRC16_TABLE(_table) \
|
||||
static uint16_t _table[NO_OS_CRC16_TABLE_SIZE]
|
||||
|
||||
void no_os_crc16_populate_msb(uint16_t * table, const uint16_t polynomial);
|
||||
uint16_t no_os_crc16(const uint16_t * table, const uint8_t *pdata,
|
||||
size_t nbytes,
|
||||
uint16_t crc);
|
||||
|
||||
#endif // _NO_OS_CRC16_H_
|
||||
@@ -0,0 +1,98 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_crc24.c
|
||||
* @brief Source file of CRC-24 computation.
|
||||
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2021(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#include "no_os_crc24.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Creates the CRC-24 lookup table for a given polynomial.
|
||||
*
|
||||
* @param table - Pointer to a CRC-24 lookup table to write to.
|
||||
* @param polynomial - msb-first representation of desired polynomial.
|
||||
*
|
||||
* Polynomials in CRC algorithms are typically represented as shown below.
|
||||
*
|
||||
* poly = x^24 + x^22 + x^20 + x^19 + x^18 + x^16 + x^14 + x^13 + x^11 +
|
||||
* x^10 + x^8 + x^7 + x^6 + x^3 + x^1 + 1
|
||||
*
|
||||
* Using msb-first direction, x^24 maps to the msb.
|
||||
*
|
||||
* msb first: poly = (1)010111010110110111001011 = 5D6DCB
|
||||
* ^
|
||||
*
|
||||
* @return None.
|
||||
*******************************************************************************/
|
||||
void no_os_crc24_populate_msb(uint32_t * table, const uint32_t polynomial)
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (int16_t n = 0; n < NO_OS_CRC24_TABLE_SIZE; n++) {
|
||||
uint32_t currByte = (uint32_t)(n << 16);
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
if ((currByte & 0x800000) != 0) {
|
||||
currByte &= 0x7FFFFF;
|
||||
currByte <<= 1;
|
||||
currByte ^= polynomial;
|
||||
} else {
|
||||
currByte <<= 1;
|
||||
}
|
||||
}
|
||||
table[n] = currByte;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Computes the CRC-24 over a buffer of data.
|
||||
*
|
||||
* @param table - Pointer to a CRC-24 lookup table for the desired polynomial.
|
||||
* @param pdata - Pointer to data buffer.
|
||||
* @param nbytes - Number of bytes to compute the CRC-24 over.
|
||||
* @param crc - Initial value for the CRC-24 computation. Can be used to
|
||||
* cascade calls to this function by providing a previous
|
||||
* output of this function as the crc parameter.
|
||||
*
|
||||
* @return crc - Computed CRC-24 value.
|
||||
*******************************************************************************/
|
||||
uint32_t no_os_crc24(const uint32_t * table, const uint8_t *pdata,
|
||||
size_t nbytes,
|
||||
uint32_t crc)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
while (nbytes--) {
|
||||
idx = ((crc >> 16) ^ *pdata) & 0xff;
|
||||
crc = (table[idx] ^ (crc << 8)) & 0xffffff;
|
||||
pdata++;
|
||||
}
|
||||
|
||||
return (crc & 0xffffff);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_crc24.h
|
||||
* @brief Header file of CRC-24 computation.
|
||||
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2021(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_CRC24_H_
|
||||
#define _NO_OS_CRC24_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define NO_OS_CRC24_TABLE_SIZE 256
|
||||
|
||||
#define NO_OS_DECLARE_CRC24_TABLE(_table) \
|
||||
static uint32_t _table[NO_OS_CRC24_TABLE_SIZE]
|
||||
|
||||
void no_os_crc24_populate_msb(uint32_t * table, const uint32_t polynomial);
|
||||
uint32_t no_os_crc24(const uint32_t * table, const uint8_t *pdata,
|
||||
size_t nbytes,
|
||||
uint32_t crc);
|
||||
|
||||
#endif // _NO_OS_CRC24_H_
|
||||
@@ -0,0 +1,94 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_crc8.c
|
||||
* @brief Source file of CRC-8 computation.
|
||||
* @author Darius Berghe (darius.berghe@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#include "no_os_crc8.h"
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Creates the CRC-8 lookup table for a given polynomial.
|
||||
*
|
||||
* @param table - Pointer to a CRC-8 lookup table to write to.
|
||||
* @param polynomial - msb-first representation of desired polynomial.
|
||||
*
|
||||
* Polynomials in CRC algorithms are typically represented as shown below.
|
||||
*
|
||||
* poly = x^8 + x^2 + x^1 + 1
|
||||
*
|
||||
* Using msb-first direction, x^7 maps to the msb.
|
||||
*
|
||||
* msb first: poly = (1)00000111 = 0x07
|
||||
*
|
||||
* @return None.
|
||||
*******************************************************************************/
|
||||
void no_os_crc8_populate_msb(uint8_t * table, const uint8_t polynomial)
|
||||
{
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
for (int16_t n = 0; n < NO_OS_CRC8_TABLE_SIZE; n++) {
|
||||
uint8_t currByte = (uint8_t)n;
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
if ((currByte & 0x80) != 0) {
|
||||
currByte <<= 1;
|
||||
currByte ^= polynomial;
|
||||
} else {
|
||||
currByte <<= 1;
|
||||
}
|
||||
}
|
||||
table[n] = currByte;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* @brief Computes the CRC-8 over a buffer of data.
|
||||
*
|
||||
* @param table - Pointer to a CRC-8 lookup table for the desired polynomial.
|
||||
* @param pdata - Pointer to 8-bit data buffer.
|
||||
* @param nbytes - Number of bytes to compute the CRC-8 over.
|
||||
* @param crc - Initial value for the CRC-8 computation. Can be used to
|
||||
* cascade calls to this function by providing a previous
|
||||
* output of this function as the crc parameter.
|
||||
*
|
||||
* @return crc - Computed CRC-8 value.
|
||||
*******************************************************************************/
|
||||
uint8_t no_os_crc8(const uint8_t * table, const uint8_t *pdata, size_t nbytes,
|
||||
uint8_t crc)
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
while (nbytes--) {
|
||||
idx = (crc ^ *pdata);
|
||||
crc = (table[idx]) & 0xff;
|
||||
pdata++;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_crc8.h
|
||||
* @brief Header file of CRC-8 computation.
|
||||
* @author Darius Berghe (darius.berghe@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_CRC8_H_
|
||||
#define _NO_OS_CRC8_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define NO_OS_CRC8_TABLE_SIZE 256
|
||||
|
||||
#define NO_OS_DECLARE_CRC8_TABLE(_table) \
|
||||
static uint8_t _table[NO_OS_CRC8_TABLE_SIZE]
|
||||
|
||||
void no_os_crc8_populate_msb(uint8_t * table, const uint8_t polynomial);
|
||||
uint8_t no_os_crc8(const uint8_t * table, const uint8_t *pdata, size_t nbytes,
|
||||
uint8_t crc);
|
||||
|
||||
#endif // _NO_OS_CRC8_H_
|
||||
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_delay.h
|
||||
* @brief Header file of Delay functions
|
||||
* @author DBogdan (dragos.bogdan@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _NO_OS_DELAY_H_
|
||||
#define _NO_OS_DELAY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @struct no_os_time
|
||||
* @brief Structure holding time data (seconds, microseconds).
|
||||
*/
|
||||
struct no_os_time {
|
||||
unsigned int s, us;
|
||||
};
|
||||
|
||||
/* Generate microseconds delay. */
|
||||
void no_os_udelay(uint32_t usecs);
|
||||
|
||||
/* Generate miliseconds delay. */
|
||||
void no_os_mdelay(uint32_t msecs);
|
||||
|
||||
/* Get current time */
|
||||
struct no_os_time no_os_get_time(void);
|
||||
|
||||
#endif // _NO_OS_DELAY_H_
|
||||
449
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.c
Normal file
@@ -0,0 +1,449 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_dma.c
|
||||
* @brief Platform independent implementation for the DMA API.
|
||||
* @author Ciprian Regus (ciprian.regus@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2024(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#include <inttypes.h>
|
||||
#include "no_os_dma.h"
|
||||
#include <stdlib.h>
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_mutex.h"
|
||||
#include "no_os_irq.h"
|
||||
#include "no_os_alloc.h"
|
||||
#include "no_os_list.h"
|
||||
|
||||
/**
|
||||
* @brief Default handler for cycling though the channel's list of transfers
|
||||
* @param context - structure which stores the state of the current channel
|
||||
* and DMA controller state.
|
||||
*/
|
||||
static void default_sg_callback(void *context)
|
||||
{
|
||||
struct no_os_dma_default_handler_data *data = context;
|
||||
struct no_os_dma_xfer_desc *next_xfer;
|
||||
struct no_os_dma_xfer_desc *old_xfer;
|
||||
uint32_t list_size;
|
||||
int ret;
|
||||
|
||||
/* Handle the next transfer from the SG list */
|
||||
ret = no_os_list_get_first(data->channel->sg_list, (void **)&old_xfer);
|
||||
if (ret) {
|
||||
/*
|
||||
* This should only happen if the list descriptor is NULL.
|
||||
* The case in which there is no transfer left in the list should
|
||||
* have been handled in the previous interrupt.
|
||||
*/
|
||||
no_os_dma_xfer_abort(data->desc, data->channel);
|
||||
return;
|
||||
}
|
||||
|
||||
no_os_list_read_first(data->channel->sg_list, (void **)&next_xfer);
|
||||
no_os_list_get_size(data->channel->sg_list, &list_size);
|
||||
if (old_xfer->xfer_complete_cb)
|
||||
old_xfer->xfer_complete_cb(old_xfer, next_xfer,
|
||||
old_xfer->xfer_complete_ctx);
|
||||
|
||||
if (!list_size) {
|
||||
no_os_irq_disable(data->desc->irq_ctrl, data->channel->irq_num);
|
||||
data->channel->free = true;
|
||||
return;
|
||||
}
|
||||
|
||||
data->desc->platform_ops->dma_config_xfer(data->channel, next_xfer);
|
||||
|
||||
no_os_dma_xfer_start(data->desc, data->channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the DMA controller.
|
||||
* @param desc - Structure containing the state of the DMA controller
|
||||
* @param param - Initialization parameter for the DMA controller.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int no_os_dma_init(struct no_os_dma_desc **desc,
|
||||
struct no_os_dma_init_param *param)
|
||||
{
|
||||
int ret;
|
||||
uint32_t i, j;
|
||||
void *mutex;
|
||||
|
||||
if (!param || !param->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!param->platform_ops->dma_init)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_init(&mutex);
|
||||
|
||||
no_os_mutex_lock(mutex);
|
||||
ret = param->platform_ops->dma_init(desc, param);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
no_os_mutex_init(&(*desc)->mutex);
|
||||
|
||||
(*desc)->platform_ops = param->platform_ops;
|
||||
|
||||
for (i = 0; i < param->num_ch; i++) {
|
||||
ret = no_os_list_init(&(*desc)->channels[i].sg_list, NO_OS_LIST_QUEUE, NULL);
|
||||
if (ret)
|
||||
goto list_err;
|
||||
|
||||
no_os_mutex_init(&(*desc)->channels[i].mutex);
|
||||
}
|
||||
|
||||
(*desc)->ref++;
|
||||
no_os_mutex_unlock(mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
list_err:
|
||||
for (j = 0; j < i; j++)
|
||||
no_os_list_remove((*desc)->channels[i].sg_list);
|
||||
|
||||
no_os_dma_remove(*desc);
|
||||
unlock:
|
||||
no_os_mutex_unlock(mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove resources allocated for the DMA controller.
|
||||
* @param desc - Structure containing the state of the DMA controller
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int no_os_dma_remove(struct no_os_dma_desc *desc)
|
||||
{
|
||||
uint32_t i;
|
||||
int ret;
|
||||
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->ref)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < desc->num_ch; i++) {
|
||||
ret = no_os_list_remove(desc->channels->sg_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
no_os_mutex_remove(desc->channels[i].mutex);
|
||||
if (desc->irq_ctrl && desc->channels[i].cb_desc.handle) {
|
||||
no_os_irq_unregister_callback(desc->irq_ctrl,
|
||||
desc->channels[i].irq_num,
|
||||
&desc->channels[i].cb_desc);
|
||||
}
|
||||
|
||||
}
|
||||
no_os_mutex_remove(desc->mutex);
|
||||
|
||||
ret = desc->platform_ops->dma_remove(desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
desc->ref--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a free DMA channel.
|
||||
* @param desc - Structure containing the state of the DMA controller.
|
||||
* @param channel - Reference to the acquired channel.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int no_os_dma_acquire_channel(struct no_os_dma_desc *desc,
|
||||
struct no_os_dma_ch **channel)
|
||||
{
|
||||
uint32_t ch_num;
|
||||
int ret;
|
||||
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->dma_acquire_ch)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_lock(desc->mutex);
|
||||
|
||||
ret = desc->platform_ops->dma_acquire_ch(desc, &ch_num);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
*channel = &desc->channels[ch_num];
|
||||
|
||||
unlock:
|
||||
no_os_mutex_unlock(desc->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free DMA channel.
|
||||
* @param desc - Structure containing the state of the DMA controller.
|
||||
* @param channel - Reference to the currently acquired channel.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int no_os_dma_release_channel(struct no_os_dma_desc *desc,
|
||||
struct no_os_dma_ch *channel)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!desc || !desc->platform_ops || !channel)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->dma_release_ch)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_lock(channel->mutex);
|
||||
ret = desc->platform_ops->dma_release_ch(desc, channel->id);
|
||||
no_os_mutex_unlock(channel->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Acquire a channel and configure the list of transfers.
|
||||
* @param desc - Structure containing the state of the DMA controller
|
||||
* @param xfer - Array of DMA transfers.
|
||||
* @param len - The number of transfers in the xfer list.
|
||||
* @param ch - Previously acquired channel, for which the transfer will be configured.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int no_os_dma_config_xfer(struct no_os_dma_desc *desc,
|
||||
struct no_os_dma_xfer_desc *xfer,
|
||||
uint32_t len, struct no_os_dma_ch *ch)
|
||||
{
|
||||
uint32_t i;
|
||||
int ret;
|
||||
void *discard;
|
||||
struct no_os_callback_desc *sg_callback;
|
||||
|
||||
if (!desc || !xfer || !len || !ch)
|
||||
return -EINVAL;
|
||||
|
||||
no_os_mutex_lock(ch->mutex);
|
||||
|
||||
/*
|
||||
* Add the transfers to the channel's SG list. It's safe to do so, since
|
||||
* there are no ongoing transfers on this channel.
|
||||
*/
|
||||
for (i = 0; i < len; i++)
|
||||
no_os_list_add_last(ch->sg_list, &xfer[i]);
|
||||
|
||||
if (desc->irq_ctrl) {
|
||||
sg_callback = &ch->cb_desc;
|
||||
sg_callback->ctx = &ch->irq_ctx;
|
||||
sg_callback->handle = (void *)ch->id;
|
||||
sg_callback->peripheral = xfer[0].periph;
|
||||
ch->irq_ctx.desc = desc;
|
||||
ch->irq_ctx.channel = ch;
|
||||
|
||||
switch (xfer[0].xfer_type) {
|
||||
case MEM_TO_DEV:
|
||||
case MEM_TO_MEM:
|
||||
sg_callback->event = NO_OS_EVT_DMA_TX_COMPLETE;
|
||||
break;
|
||||
case DEV_TO_MEM:
|
||||
sg_callback->event = NO_OS_EVT_DMA_RX_COMPLETE;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = desc->platform_ops->dma_config_xfer(ch, xfer);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (desc->sg_handler)
|
||||
sg_callback->callback = desc->sg_handler;
|
||||
else
|
||||
sg_callback->callback = default_sg_callback;
|
||||
|
||||
ret = no_os_irq_register_callback(desc->irq_ctrl,
|
||||
ch->irq_num,
|
||||
sg_callback);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
no_os_irq_set_priority(desc->irq_ctrl, ch->irq_num, xfer[0].irq_priority);
|
||||
}
|
||||
|
||||
no_os_mutex_unlock(ch->mutex);
|
||||
return 0;
|
||||
err:
|
||||
for (i = 0; i < len; i++)
|
||||
no_os_list_get_first(ch->sg_list, &discard);
|
||||
no_os_mutex_unlock(ch->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lock a DMA channel, so it won't be acquired even if it's free.
|
||||
* @param ch - Reference to the DMA channel
|
||||
* @return 0 in case of success, -EINVAL if a NULL channel reference is provided.
|
||||
*/
|
||||
int no_os_dma_chan_lock(struct no_os_dma_ch *ch)
|
||||
{
|
||||
no_os_mutex_lock(ch->mutex);
|
||||
|
||||
if (!ch)
|
||||
return -EINVAL;
|
||||
|
||||
ch->sync_lock = true;
|
||||
|
||||
no_os_mutex_unlock(ch->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlock a DMA channel, marking it available for acquisition.
|
||||
* @param ch - Reference to the DMA channel
|
||||
* @return 0 in case of success, -EINVAL if a NULL channel reference is provided.
|
||||
*/
|
||||
int no_os_dma_chan_unlock(struct no_os_dma_ch *ch)
|
||||
{
|
||||
no_os_mutex_lock(ch->mutex);
|
||||
|
||||
if (!ch)
|
||||
return -EINVAL;
|
||||
|
||||
ch->sync_lock = false;
|
||||
|
||||
no_os_mutex_unlock(ch->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Acquire a channel and configure the list of transfers.
|
||||
* @param desc - Structure containing the state of the DMA controller
|
||||
* @param ch - Index for the channel we want to start the transfer on.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int no_os_dma_xfer_start(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!desc || !desc->platform_ops || !ch)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->dma_xfer_start)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_lock(ch->mutex);
|
||||
|
||||
if (desc->irq_ctrl)
|
||||
no_os_irq_enable(desc->irq_ctrl, ch->irq_num);
|
||||
|
||||
ret = desc->platform_ops->dma_xfer_start(desc, ch);
|
||||
|
||||
no_os_mutex_unlock(ch->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Abort the ongoing and any other future transfers scheduled for a channel.
|
||||
* @param desc - Structure containing the state of the DMA controller
|
||||
* @param ch - Index for the channel we want to abort the transfer.
|
||||
* @return 0 in case of success, negative error code otherwise.
|
||||
*/
|
||||
int no_os_dma_xfer_abort(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch)
|
||||
{
|
||||
void *discard;
|
||||
int ret;
|
||||
|
||||
if (!desc || !desc->platform_ops || !ch)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->dma_xfer_abort)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_lock(ch->mutex);
|
||||
|
||||
if (desc->irq_ctrl)
|
||||
no_os_irq_disable(desc->irq_ctrl, ch->irq_num);
|
||||
|
||||
do {
|
||||
ret = no_os_list_get_first(ch->sg_list, &discard);
|
||||
} while (!ret);
|
||||
|
||||
ret = desc->platform_ops->dma_xfer_abort(desc, ch);
|
||||
|
||||
no_os_mutex_unlock(ch->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the state of a DMA channel (free or not).
|
||||
* @param desc - Reference to the DMA controller.
|
||||
* @param ch - Reference to the DMA channel.
|
||||
* @return true if a channel is free, false otherwise.
|
||||
*/
|
||||
bool no_os_dma_is_completed(struct no_os_dma_desc *desc,
|
||||
struct no_os_dma_ch *ch)
|
||||
{
|
||||
(void)desc;
|
||||
|
||||
if (!ch)
|
||||
return -EINVAL;
|
||||
|
||||
return ch->free;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Whether or not there is a transfer in progress on a specific channel.
|
||||
* @param desc - Reference to the DMA controller.
|
||||
* @param ch - Reference to the DMA channel.
|
||||
* @return true if a channel is free, false otherwise.
|
||||
*/
|
||||
bool no_os_dma_in_progress(struct no_os_dma_desc *desc, struct no_os_dma_ch *ch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!desc || !desc->platform_ops || !ch)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->dma_ch_in_progress)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_lock(ch->mutex);
|
||||
ret = desc->platform_ops->dma_ch_in_progress(desc, ch);
|
||||
no_os_mutex_unlock(ch->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
265
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_dma.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_dma.h
|
||||
* @brief Platform independent function definitions and data types
|
||||
* for the DMA API.
|
||||
* @author Ciprian Regus (ciprian.regus@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2024(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_DMA_H_
|
||||
#define _NO_OS_DMA_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "no_os_list.h"
|
||||
#include "no_os_irq.h"
|
||||
#include "no_os_mutex.h"
|
||||
|
||||
/**
|
||||
* @enum no_os_dma_xfer_type
|
||||
* @brief Supported transfer directions
|
||||
*/
|
||||
enum no_os_dma_xfer_type {
|
||||
MEM_TO_MEM,
|
||||
MEM_TO_DEV,
|
||||
DEV_TO_MEM,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_dma_default_handler_data
|
||||
* @brief IRQ parameter for the default inter transfer handler
|
||||
*/
|
||||
struct no_os_dma_default_handler_data {
|
||||
struct no_os_dma_desc *desc;
|
||||
struct no_os_dma_ch *channel;
|
||||
void *extra;
|
||||
};
|
||||
|
||||
struct no_os_dma_platform_ops;
|
||||
|
||||
/**
|
||||
* @struct no_os_dma_xfer_desc
|
||||
* @brief It's used to setup a generic DMA transfer.
|
||||
*/
|
||||
struct no_os_dma_xfer_desc {
|
||||
/** Source address for the data */
|
||||
uint8_t *src;
|
||||
/** Destination address for the data */
|
||||
uint8_t *dst;
|
||||
/** Transfer length in bytes */
|
||||
uint32_t length;
|
||||
/** Transfer direction */
|
||||
enum no_os_dma_xfer_type xfer_type;
|
||||
|
||||
/** This function will be called once the transfer completes. */
|
||||
void (*xfer_complete_cb)(struct no_os_dma_xfer_desc *,
|
||||
struct no_os_dma_xfer_desc *,
|
||||
void *);
|
||||
/**
|
||||
* Parameter for the transfer complete callback. This data should
|
||||
* be valid at least until the callback is invoked.
|
||||
*/
|
||||
void *xfer_complete_ctx;
|
||||
/** Transfer complete interrupt priority level */
|
||||
uint32_t irq_priority;
|
||||
|
||||
/**
|
||||
* Peripheral which originated the transfer. Will be used to add
|
||||
* the callback to the proper event list.
|
||||
*/
|
||||
enum no_os_irq_peripheral periph;
|
||||
|
||||
/** User or platform defined data */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_dma_ch
|
||||
* @brief Describes the state of a DMA channel.
|
||||
*/
|
||||
struct no_os_dma_ch {
|
||||
/** Channel number */
|
||||
uint32_t id;
|
||||
/** Whether or not there is a transfer in progress on this channel */
|
||||
bool free;
|
||||
/** List of transfers for this channel */
|
||||
struct no_os_list_desc *sg_list;
|
||||
/** Channel specific interrupt line number */
|
||||
uint32_t irq_num;
|
||||
/** irq callback */
|
||||
struct no_os_callback_desc cb_desc;
|
||||
/** IRQ parameter for the default inter transfer handler */
|
||||
struct no_os_dma_default_handler_data irq_ctx;
|
||||
void *extra;
|
||||
|
||||
/** Used to synchronize channel specific operations */
|
||||
void *mutex;
|
||||
|
||||
/**
|
||||
* Mark the channel as locked, in order to prevent it from being acquired
|
||||
* even if it's free. Used as a synchronization mechanism between channels.
|
||||
*/
|
||||
bool sync_lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_dma_desc
|
||||
* @brief Describes the state of the DMA controller.
|
||||
*/
|
||||
struct no_os_dma_desc {
|
||||
/** Unique id of a DMA controller */
|
||||
uint32_t id;
|
||||
/** The number of channels associated with the controller */
|
||||
uint32_t num_ch;
|
||||
/** References to channels associated with the controller */
|
||||
struct no_os_dma_ch *channels;
|
||||
/** Platform specific DMA functions */
|
||||
struct no_os_dma_platform_ops *platform_ops;
|
||||
/**
|
||||
* Interrupt controller configured by the platform specific DMA functions.
|
||||
* May be left uninitialized,Start resulting in the interrupt handler not being
|
||||
* called once a transfer completes. As such, the user (or platform code) has
|
||||
* to provide the cycling mechanism.
|
||||
*/
|
||||
struct no_os_irq_ctrl_desc *irq_ctrl;
|
||||
/** Platform specific data */
|
||||
void *extra;
|
||||
/** Reference counter */
|
||||
uint32_t ref;
|
||||
/** Used to synchronize DMA controller specific operations */
|
||||
void *mutex;
|
||||
|
||||
/**
|
||||
* Interrupt handler function called when a transfer is completed.
|
||||
* It's used to configure the DMA controller for the next transfer in
|
||||
* a channel's list.
|
||||
*/
|
||||
void (*sg_handler)(void *);
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_dma_init_param
|
||||
* @brief Initialization parameter for the DMA controller
|
||||
*/
|
||||
struct no_os_dma_init_param {
|
||||
/** Unique id of a DMA controller */
|
||||
uint32_t id;
|
||||
/** The number of channels associated with the controller */
|
||||
uint32_t num_ch;
|
||||
/** Platform specific DMA functions */
|
||||
struct no_os_dma_platform_ops *platform_ops;
|
||||
/** Platform specific data */
|
||||
void *extra;
|
||||
|
||||
/**
|
||||
* Optional custom scatter gather callback. May be set to NULL in
|
||||
* order to use the default one.
|
||||
*/
|
||||
void (*sg_handler)(void *);
|
||||
/**
|
||||
* Optional custom parameter for the scatter gather callback. Only takes
|
||||
* effect if the handler is also provided.
|
||||
*/
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
/** Initialize a DMA controller. */
|
||||
int no_os_dma_init(struct no_os_dma_desc **,
|
||||
struct no_os_dma_init_param *);
|
||||
|
||||
/** Free the resources allocated by the DMA layer. Disables the DMA controller. */
|
||||
int no_os_dma_remove(struct no_os_dma_desc *);
|
||||
|
||||
/** Acquire a channel and add the transfers to it's SG list. */
|
||||
int no_os_dma_config_xfer(struct no_os_dma_desc *,
|
||||
struct no_os_dma_xfer_desc *,
|
||||
uint32_t,
|
||||
struct no_os_dma_ch *);
|
||||
|
||||
/** Prevent a channel from being acquired, even if it's free. */
|
||||
int no_os_dma_chan_lock(struct no_os_dma_ch *);
|
||||
|
||||
/** Allow a channel to be acquired, in case it's free. */
|
||||
int no_os_dma_chan_unlock(struct no_os_dma_ch *);
|
||||
|
||||
/** Start the DMA transactions for a specific channel. */
|
||||
int no_os_dma_xfer_start(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
|
||||
/**
|
||||
* Stop the DMA transactions for a specific channel and remove the transfers
|
||||
* from the SG list.
|
||||
*/
|
||||
int no_os_dma_xfer_abort(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
|
||||
/**
|
||||
* Check whether a transfer is complete. By default, it requires the interrupt
|
||||
* handler to set the free flag for the channel.
|
||||
*/
|
||||
bool no_os_dma_is_completed(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
|
||||
/** Whether or not a specific channel has an ongoing transfer. */
|
||||
bool no_os_dma_in_progress(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
|
||||
/** Get a free DMA channel. */
|
||||
int no_os_dma_acquire_channel(struct no_os_dma_desc *, struct no_os_dma_ch **);
|
||||
|
||||
/** Free a DMA channel. */
|
||||
int no_os_dma_release_channel(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
|
||||
/**
|
||||
* @struct no_os_irq_platform_ops
|
||||
* @brief Structure holding IRQ function pointers that point to the platform
|
||||
* specific function
|
||||
*/
|
||||
struct no_os_dma_platform_ops {
|
||||
/** Initialize platform specific resources for the DMA controller. */
|
||||
int (*dma_init)(struct no_os_dma_desc **, struct no_os_dma_init_param *);
|
||||
/** Remove resources allocated for the DMA controller. */
|
||||
int (*dma_remove)(struct no_os_dma_desc *desc);
|
||||
/** Get a free channel and set it as busy. */
|
||||
int (*dma_acquire_ch)(struct no_os_dma_desc *, uint32_t *);
|
||||
int (*dma_release_ch)(struct no_os_dma_desc *, uint32_t);
|
||||
/** Configure platform specific settings required for the current DMA transfer */
|
||||
int (*dma_config_xfer)(struct no_os_dma_ch *,
|
||||
struct no_os_dma_xfer_desc *);
|
||||
/** Signal the DMA controller to start the transfer. */
|
||||
int (*dma_xfer_start)(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
/** Signal the DMA controller to stop the transfer. */
|
||||
int (*dma_xfer_abort)(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
/** Whether or not a specific channel has an ongoing or future transfer configured */
|
||||
bool (*dma_ch_is_completed)(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
/**
|
||||
* Whether or not a specific channel has an ongoing transfer.
|
||||
* This returns true between transfers.
|
||||
*/
|
||||
bool (*dma_ch_in_progress)(struct no_os_dma_desc *, struct no_os_dma_ch *);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_eeprom.c
|
||||
* @brief Implementation of the EEPROM APIs
|
||||
* @author Mahesh Phalke (mahesh.phalke@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2022(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include "no_os_eeprom.h"
|
||||
#include "no_os_error.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize the EEPROM
|
||||
* @param desc - EEPROM descriptor
|
||||
* @param param - EEPROM init parameters
|
||||
* @return 0 in case of success, negative error code otherwise
|
||||
*/
|
||||
int32_t no_os_eeprom_init(struct no_os_eeprom_desc **desc,
|
||||
const struct no_os_eeprom_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (!param || !param->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!param->platform_ops->init)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = param->platform_ops->init(desc, param);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
(*desc)->platform_ops = param->platform_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by no_os_eeprom_init()
|
||||
* @param desc - EEPROM descriptor
|
||||
* @return 0 in case of success, negative error code otherwise
|
||||
*/
|
||||
int32_t no_os_eeprom_remove(struct no_os_eeprom_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->remove)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->remove(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the EEPROM data
|
||||
* @param desc - EEPROM descriptor
|
||||
* @param address - EEPROM address/location to write
|
||||
* @param data - EEPROM data (pointer)
|
||||
* @param bytes - Number of data bytes to write
|
||||
* @return 0 in case of success, negative error code otherwise
|
||||
*/
|
||||
int32_t no_os_eeprom_write(struct no_os_eeprom_desc *desc, uint32_t address,
|
||||
uint8_t *data, uint16_t bytes)
|
||||
{
|
||||
if (!desc || !desc->platform_ops || !data)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->write)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->write(desc, address, data, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the EEPROM data
|
||||
* @param desc - EEPROM descriptor
|
||||
* @param address - EEPROM address/location to read
|
||||
* @param data - EEPROM data (pointer)
|
||||
* @param bytes - Number of data bytes to read
|
||||
* @return 0 in case of success, negative error code otherwise
|
||||
*/
|
||||
int32_t no_os_eeprom_read(struct no_os_eeprom_desc *desc, uint32_t address,
|
||||
uint8_t *data, uint16_t bytes)
|
||||
{
|
||||
if (!desc || !desc->platform_ops || !data)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->read)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->read(desc, address, data, bytes);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_eeprom.h
|
||||
* @brief Header file for EEPROM APIs
|
||||
* @author Mahesh Phalke (mahesh.phalke@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2022(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _NO_OS_EEPROM_H_
|
||||
#define _NO_OS_EEPROM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* Forward declaration of structure */
|
||||
struct no_os_eeprom_platform_ops;
|
||||
|
||||
/**
|
||||
* @struct no_os_eeprom_init_param
|
||||
* @brief Structure holding the parameters for EEPROM initialization
|
||||
*/
|
||||
struct no_os_eeprom_init_param {
|
||||
/** Device ID */
|
||||
uint32_t device_id;
|
||||
const struct no_os_eeprom_platform_ops *platform_ops;
|
||||
/** EEPROM extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_eeprom_desc
|
||||
* @brief Structure holding the EEPROM descriptor
|
||||
*/
|
||||
struct no_os_eeprom_desc {
|
||||
/** Device ID */
|
||||
uint32_t device_id;
|
||||
const struct no_os_eeprom_platform_ops *platform_ops;
|
||||
/** EEPROM extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_eeprom_platform_ops
|
||||
* @brief Structure holding the EEPROM function pointers that point to the
|
||||
* platform specific function
|
||||
*/
|
||||
struct no_os_eeprom_platform_ops {
|
||||
/** EEPROM initialization function pointer */
|
||||
int32_t (*init)(struct no_os_eeprom_desc **,
|
||||
const struct no_os_eeprom_init_param *);
|
||||
/** EEPROM data write function pointer */
|
||||
int32_t (*write)(struct no_os_eeprom_desc *, uint32_t, uint8_t *, uint16_t);
|
||||
/** EEPROM data read function pointer */
|
||||
int32_t (*read)(struct no_os_eeprom_desc *, uint32_t, uint8_t *, uint16_t);
|
||||
/** EEPROM remove function pointer */
|
||||
int32_t (*remove)(struct no_os_eeprom_desc *);
|
||||
};
|
||||
|
||||
/* Initialize the EEPROM */
|
||||
int32_t no_os_eeprom_init(struct no_os_eeprom_desc **desc,
|
||||
const struct no_os_eeprom_init_param *param);
|
||||
|
||||
/* Write into EEPROM */
|
||||
int32_t no_os_eeprom_write(struct no_os_eeprom_desc *desc, uint32_t address,
|
||||
uint8_t *data, uint16_t bytes);
|
||||
|
||||
/* Read from EEPROM */
|
||||
int32_t no_os_eeprom_read(struct no_os_eeprom_desc *desc, uint32_t address,
|
||||
uint8_t *data, uint16_t bytes);
|
||||
|
||||
/* Free the resources allocated by no_os_eeprom_init() */
|
||||
int32_t no_os_eeprom_remove(struct no_os_eeprom_desc *desc);
|
||||
|
||||
#endif // _NO_OS_EEPROM_H_
|
||||
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_error.h
|
||||
* @brief Error codes definition
|
||||
* @author DBogdan (dragos.bogdan@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _NO_OS_ERROR_H_
|
||||
#define _NO_OS_ERROR_H_
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef __NO_OS_ELASTERROR
|
||||
#define __NO_OS_ELASTERROR 2000
|
||||
#endif
|
||||
|
||||
#define NO_OS_EOVERRUN (__NO_OS_ELASTERROR + 1) /* Circular buffer overrun */
|
||||
|
||||
|
||||
#define NO_OS_IS_ERR_VALUE(x) ((x) < 0)
|
||||
|
||||
#endif // _NO_OS_ERROR_H_
|
||||
126
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_fifo.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_fifo.c
|
||||
* @brief Implementation of fifo.
|
||||
* @author Cristian Pop (cristian.pop@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "no_os_fifo.h"
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_alloc.h"
|
||||
|
||||
/**
|
||||
* @brief Create new fifo element
|
||||
* @param buff - Data to be saved in fifo.
|
||||
* @param len - Length of the data.
|
||||
* @return fifo element in case of success, NULL otherwise
|
||||
*/
|
||||
static struct no_os_fifo_element * fifo_new_element(char *buff, uint32_t len)
|
||||
{
|
||||
struct no_os_fifo_element *q = no_os_calloc(1,
|
||||
sizeof(struct no_os_fifo_element));
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
q->len = len;
|
||||
q->data = no_os_calloc(1, len);
|
||||
if (!(q->data)) {
|
||||
no_os_free(q);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(q->data, buff, len);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get last element in fifo
|
||||
* @param p_fifo - pointer to fifo
|
||||
* @return fifo last element if exists, NULL otherwise
|
||||
*/
|
||||
static struct no_os_fifo_element *no_os_fifo_get_last(struct no_os_fifo_element
|
||||
*p_fifo)
|
||||
{
|
||||
if (p_fifo == NULL)
|
||||
return NULL;
|
||||
while (p_fifo->next) {
|
||||
p_fifo = p_fifo->next;
|
||||
}
|
||||
|
||||
return p_fifo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert element to fifo, in the last position.
|
||||
* @param p_fifo - Pointer to fifo.
|
||||
* @param buff - Data to be saved in fifo.
|
||||
* @param len - Length of the data.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t no_os_fifo_insert(struct no_os_fifo_element **p_fifo, char *buff,
|
||||
uint32_t len)
|
||||
{
|
||||
struct no_os_fifo_element *p, *q;
|
||||
|
||||
if (len <= 0)
|
||||
return -1;
|
||||
|
||||
q = fifo_new_element(buff, len);
|
||||
if (!q)
|
||||
return -1;
|
||||
|
||||
if (!(*p_fifo)) {
|
||||
*p_fifo = q;
|
||||
} else {
|
||||
p = no_os_fifo_get_last(*p_fifo);
|
||||
p->next = q;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove fifo head
|
||||
* @param p_fifo - Pointer to fifo.
|
||||
* @return next element in fifo if exists, NULL otherwise.
|
||||
*/
|
||||
struct no_os_fifo_element * no_os_fifo_remove(struct no_os_fifo_element *p_fifo)
|
||||
{
|
||||
struct no_os_fifo_element *p = p_fifo;
|
||||
|
||||
if (p_fifo != NULL) {
|
||||
p_fifo = p_fifo->next;
|
||||
no_os_free(p->data);
|
||||
no_os_free(p);
|
||||
}
|
||||
|
||||
return p_fifo;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_fifo.h
|
||||
* @brief Header file of fifo
|
||||
* @author Cristian Pop (cristian.pop@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
#ifndef _NO_OS_FIFO_H_
|
||||
#define _NO_OS_FIFO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @struct no_os_fifo_element
|
||||
* @brief Structure holding the fifo element parameters.
|
||||
*/
|
||||
struct no_os_fifo_element {
|
||||
/** next FIFO element */
|
||||
struct no_os_fifo_element *next;
|
||||
/** FIFO data pointer */
|
||||
char *data;
|
||||
/** FIFO length */
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/* Insert element to fifo tail. */
|
||||
int32_t no_os_fifo_insert(struct no_os_fifo_element **p_fifo, char *buff,
|
||||
uint32_t len);
|
||||
|
||||
/* Remove fifo head. */
|
||||
struct no_os_fifo_element *no_os_fifo_remove(struct no_os_fifo_element *p_fifo);
|
||||
|
||||
#endif // _NO_OS_FIFO_H_
|
||||
@@ -0,0 +1,96 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_flash.h
|
||||
* @brief Header file for flash controller driver.
|
||||
* @author Andrei Drimbarean (andrei.drimbarean@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2021(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _NO_OS_FLASH_H_
|
||||
#define _NO_OS_FLASH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @struct no_os_flash_dev
|
||||
* @brief Flash controller device structure
|
||||
*/
|
||||
struct no_os_flash_dev {
|
||||
/** Flash Device ID */
|
||||
uint8_t id;
|
||||
/** Size of flash memory in bytes */
|
||||
uint32_t flash_size;
|
||||
/** Size of flash page in bytes */
|
||||
uint32_t page_size;
|
||||
/** Flash extra parameters */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_flash_init_param
|
||||
* @brief Flash controller initialization structure
|
||||
*/
|
||||
struct no_os_flash_init_param {
|
||||
/** Flash Device ID */
|
||||
uint8_t id;
|
||||
/** Size of flash memory in bytes */
|
||||
uint32_t flash_size;
|
||||
/** Size of flash page in bytes */
|
||||
uint32_t flash_page_size;
|
||||
/** Flash extra parameters */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/** Initialize flash controller. */
|
||||
int32_t no_os_flash_init(struct no_os_flash_dev **device,
|
||||
struct no_os_flash_init_param *init_param);
|
||||
|
||||
/** Free memory allocated by no_os_flash_init(). */
|
||||
int32_t no_os_flash_remove(struct no_os_flash_dev *dev);
|
||||
|
||||
/** Erase a flash page. */
|
||||
int32_t no_os_flash_clear_page(struct no_os_flash_dev *dev, int32_t page_no);
|
||||
|
||||
/** Write a flash page. */
|
||||
int32_t no_os_flash_write_page(struct no_os_flash_dev *dev, int32_t page_no,
|
||||
uint32_t *data);
|
||||
|
||||
/** Read a flash page. */
|
||||
int32_t flash_read_page(struct no_os_flash_dev *dev, int32_t page_no,
|
||||
uint32_t *data);
|
||||
|
||||
/** Write data in flash memory. */
|
||||
int32_t no_os_flash_write(struct no_os_flash_dev *dev, uint32_t flash_addr,
|
||||
uint32_t *array, uint32_t array_size);
|
||||
|
||||
/** Read data from the flash memory. */
|
||||
int32_t no_os_flash_read(struct no_os_flash_dev *dev, uint32_t flash_addr,
|
||||
uint32_t *array,
|
||||
uint32_t size);
|
||||
|
||||
#endif // _NO_OS_FLASH_H_
|
||||
@@ -0,0 +1,166 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_font_8x8.c
|
||||
* @brief Font style for 8x8 characters.
|
||||
* @author Andrei Porumb (andrei.porumb@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2021(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* ASCII to bitmap */
|
||||
const uint8_t no_os_chr_8x8[128][8] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00},
|
||||
{0x64, 0x3c, 0x26, 0x64, 0x3c, 0x26, 0x24, 0x00},
|
||||
{0x26, 0x49, 0x49, 0x7f, 0x49, 0x49, 0x32, 0x00},
|
||||
{0x42, 0x25, 0x12, 0x08, 0x24, 0x52, 0x21, 0x00},
|
||||
{0x20, 0x50, 0x4e, 0x55, 0x22, 0x58, 0x28, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, 0x00},
|
||||
{0x00, 0x15, 0x15, 0x0e, 0x0e, 0x15, 0x15, 0x00},
|
||||
{0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x50, 0x30, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00},
|
||||
{0x00, 0x3e, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x41, 0x7f, 0x40, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x42, 0x61, 0x51, 0x49, 0x6e, 0x00, 0x00},
|
||||
{0x00, 0x22, 0x41, 0x49, 0x49, 0x36, 0x00, 0x00},
|
||||
{0x00, 0x18, 0x14, 0x12, 0x7f, 0x10, 0x00, 0x00},
|
||||
{0x00, 0x27, 0x49, 0x49, 0x49, 0x71, 0x00, 0x00},
|
||||
{0x00, 0x3c, 0x4a, 0x49, 0x48, 0x70, 0x00, 0x00},
|
||||
{0x00, 0x43, 0x21, 0x11, 0x0d, 0x03, 0x00, 0x00},
|
||||
{0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00},
|
||||
{0x00, 0x06, 0x09, 0x49, 0x29, 0x1e, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x52, 0x30, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x08, 0x14, 0x14, 0x22, 0x00, 0x00},
|
||||
{0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00},
|
||||
{0x00, 0x00, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00},
|
||||
{0x00, 0x02, 0x01, 0x59, 0x05, 0x02, 0x00, 0x00},
|
||||
{0x3e, 0x41, 0x5d, 0x55, 0x4d, 0x51, 0x2e, 0x00},
|
||||
{0x40, 0x7c, 0x4a, 0x09, 0x4a, 0x7c, 0x40, 0x00},
|
||||
{0x41, 0x7f, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00},
|
||||
{0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x22, 0x00},
|
||||
{0x41, 0x7f, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00},
|
||||
{0x41, 0x7f, 0x49, 0x49, 0x5d, 0x41, 0x63, 0x00},
|
||||
{0x41, 0x7f, 0x49, 0x09, 0x1d, 0x01, 0x03, 0x00},
|
||||
{0x1c, 0x22, 0x41, 0x49, 0x49, 0x3a, 0x08, 0x00},
|
||||
{0x41, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x41, 0x00},
|
||||
{0x00, 0x41, 0x41, 0x7F, 0x41, 0x41, 0x00, 0x00},
|
||||
{0x30, 0x40, 0x41, 0x41, 0x3F, 0x01, 0x01, 0x00},
|
||||
{0x41, 0x7f, 0x08, 0x0c, 0x12, 0x61, 0x41, 0x00},
|
||||
{0x41, 0x7f, 0x41, 0x40, 0x40, 0x40, 0x60, 0x00},
|
||||
{0x41, 0x7f, 0x42, 0x0c, 0x42, 0x7f, 0x41, 0x00},
|
||||
{0x41, 0x7f, 0x42, 0x0c, 0x11, 0x7f, 0x01, 0x00},
|
||||
{0x1c, 0x22, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00},
|
||||
{0x41, 0x7f, 0x49, 0x09, 0x09, 0x09, 0x06, 0x00},
|
||||
{0x0c, 0x12, 0x21, 0x21, 0x61, 0x52, 0x4c, 0x00},
|
||||
{0x41, 0x7f, 0x09, 0x09, 0x19, 0x69, 0x46, 0x00},
|
||||
{0x66, 0x49, 0x49, 0x49, 0x49, 0x49, 0x33, 0x00},
|
||||
{0x03, 0x01, 0x41, 0x7f, 0x41, 0x01, 0x03, 0x00},
|
||||
{0x01, 0x3f, 0x41, 0x40, 0x41, 0x3f, 0x01, 0x00},
|
||||
{0x01, 0x0f, 0x31, 0x40, 0x31, 0x0f, 0x01, 0x00},
|
||||
{0x01, 0x1f, 0x61, 0x14, 0x61, 0x1f, 0x01, 0x00},
|
||||
{0x41, 0x41, 0x36, 0x08, 0x36, 0x41, 0x41, 0x00},
|
||||
{0x01, 0x03, 0x44, 0x78, 0x44, 0x03, 0x01, 0x00},
|
||||
{0x43, 0x61, 0x51, 0x49, 0x45, 0x43, 0x61, 0x00},
|
||||
{0x00, 0x00, 0x7f, 0x41, 0x41, 0x00, 0x00, 0x00},
|
||||
{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00},
|
||||
{0x00, 0x00, 0x41, 0x41, 0x7f, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x04, 0x02, 0x01, 0x01, 0x02, 0x04, 0x00},
|
||||
{0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00},
|
||||
{0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x34, 0x4a, 0x4a, 0x4a, 0x3c, 0x40, 0x00},
|
||||
{0x00, 0x41, 0x3f, 0x48, 0x48, 0x48, 0x30, 0x00},
|
||||
{0x00, 0x3c, 0x42, 0x42, 0x42, 0x24, 0x00, 0x00},
|
||||
{0x00, 0x30, 0x48, 0x48, 0x49, 0x3f, 0x40, 0x00},
|
||||
{0x00, 0x3c, 0x4a, 0x4a, 0x4a, 0x2c, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x48, 0x7e, 0x49, 0x09, 0x00, 0x00},
|
||||
{0x00, 0x26, 0x49, 0x49, 0x49, 0x3f, 0x01, 0x00},
|
||||
{0x41, 0x7f, 0x48, 0x04, 0x44, 0x78, 0x40, 0x00},
|
||||
{0x00, 0x00, 0x44, 0x7d, 0x40, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x40, 0x44, 0x3d, 0x00, 0x00, 0x00},
|
||||
{0x41, 0x7f, 0x10, 0x18, 0x24, 0x42, 0x42, 0x00},
|
||||
{0x00, 0x40, 0x41, 0x7f, 0x40, 0x40, 0x00, 0x00},
|
||||
{0x42, 0x7e, 0x02, 0x7c, 0x02, 0x7e, 0x40, 0x00},
|
||||
{0x42, 0x7e, 0x44, 0x02, 0x42, 0x7c, 0x40, 0x00},
|
||||
{0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00},
|
||||
{0x00, 0x41, 0x7f, 0x49, 0x09, 0x09, 0x06, 0x00},
|
||||
{0x00, 0x06, 0x09, 0x09, 0x49, 0x7f, 0x41, 0x00},
|
||||
{0x00, 0x42, 0x7e, 0x44, 0x02, 0x02, 0x04, 0x00},
|
||||
{0x00, 0x64, 0x4a, 0x4a, 0x4a, 0x36, 0x00, 0x00},
|
||||
{0x00, 0x04, 0x3f, 0x44, 0x44, 0x20, 0x00, 0x00},
|
||||
{0x00, 0x02, 0x3e, 0x40, 0x40, 0x22, 0x7e, 0x40},
|
||||
{0x02, 0x0e, 0x32, 0x40, 0x32, 0x0e, 0x02, 0x00},
|
||||
{0x02, 0x1e, 0x62, 0x18, 0x62, 0x1e, 0x02, 0x00},
|
||||
{0x42, 0x62, 0x14, 0x08, 0x14, 0x62, 0x42, 0x00},
|
||||
{0x01, 0x43, 0x45, 0x38, 0x05, 0x03, 0x01, 0x00},
|
||||
{0x00, 0x46, 0x62, 0x52, 0x4a, 0x46, 0x62, 0x00},
|
||||
{0x00, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x00},
|
||||
{0x00, 0x18, 0x08, 0x08, 0x10, 0x10, 0x18, 0x00},
|
||||
{0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}
|
||||
};
|
||||
231
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_gpio.c
|
||||
* @brief Implementation of the GPIO Interface
|
||||
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "no_os_gpio.h"
|
||||
#include <stdlib.h>
|
||||
#include "no_os_error.h"
|
||||
|
||||
/**
|
||||
* @brief Obtain the GPIO decriptor.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param param - GPIO Initialization parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_get(struct no_os_gpio_desc **desc,
|
||||
const struct no_os_gpio_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (!param || !param->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!param->platform_ops->gpio_ops_get)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = param->platform_ops->gpio_ops_get(desc, param);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
(*desc)->platform_ops = param->platform_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value of an optional GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param param - GPIO Initialization parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_get_optional(struct no_os_gpio_desc **desc,
|
||||
const struct no_os_gpio_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (!param || (param->number == -1)) {
|
||||
*desc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!param->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!param->platform_ops->gpio_ops_get_optional)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = param->platform_ops->gpio_ops_get_optional(desc, param);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
(*desc)->platform_ops = param->platform_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief Free the resources allocated by no_os_gpio_get().
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_remove(struct no_os_gpio_desc *desc)
|
||||
{
|
||||
if (desc) {
|
||||
if (!desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->gpio_ops_remove)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->gpio_ops_remove(desc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the input direction of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_direction_input(struct no_os_gpio_desc *desc)
|
||||
{
|
||||
if (desc) {
|
||||
if (!desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->gpio_ops_direction_input)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->gpio_ops_direction_input(desc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the output direction of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param value - The value.
|
||||
* Example: NO_OS_GPIO_HIGH
|
||||
* NO_OS_GPIO_LOW
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_direction_output(struct no_os_gpio_desc *desc,
|
||||
uint8_t value)
|
||||
{
|
||||
if (desc) {
|
||||
if (!desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->gpio_ops_direction_output)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->
|
||||
gpio_ops_direction_output(desc, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the direction of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param direction - The direction.
|
||||
* Example: NO_OS_GPIO_OUT
|
||||
* NO_OS_GPIO_IN
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_get_direction(struct no_os_gpio_desc *desc,
|
||||
uint8_t *direction)
|
||||
{
|
||||
if (desc) {
|
||||
if (!desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->gpio_ops_get_direction)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->
|
||||
gpio_ops_get_direction(desc, direction);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the value of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param value - The value.
|
||||
* Example: NO_OS_GPIO_HIGH
|
||||
* NO_OS_GPIO_LOW
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_set_value(struct no_os_gpio_desc *desc,
|
||||
uint8_t value)
|
||||
{
|
||||
if (desc) {
|
||||
if (!desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->gpio_ops_set_value)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->gpio_ops_set_value(desc, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param value - The value.
|
||||
* Example: NO_OS_GPIO_HIGH
|
||||
* NO_OS_GPIO_LOW
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_gpio_get_value(struct no_os_gpio_desc *desc,
|
||||
uint8_t *value)
|
||||
{
|
||||
if (desc) {
|
||||
if (!desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->gpio_ops_set_value)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->gpio_ops_get_value(desc, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
166
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_gpio.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_gpio.h
|
||||
* @brief Header file of GPIO Interface
|
||||
* @author DBogdan (dragos.bogdan@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _NO_OS_GPIO_H_
|
||||
#define _NO_OS_GPIO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define NO_OS_GPIO_OUT 0x01
|
||||
#define NO_OS_GPIO_IN 0x00
|
||||
|
||||
/**
|
||||
* @struct no_os_gpio_platform_ops
|
||||
* @brief Structure holding gpio function pointers that point to the platform
|
||||
* specific function
|
||||
*/
|
||||
struct no_os_gpio_platform_ops ;
|
||||
|
||||
/**
|
||||
* @enum no_os_gpio_pull_up
|
||||
* @brief Enum that holds the possible pull up/ pull down resistor configuration.
|
||||
*/
|
||||
enum no_os_gpio_pull_up {
|
||||
NO_OS_PULL_NONE,
|
||||
/** Strong pull up */
|
||||
NO_OS_PULL_UP,
|
||||
/** Strong pull down */
|
||||
NO_OS_PULL_DOWN,
|
||||
NO_OS_PULL_UP_WEAK,
|
||||
NO_OS_PULL_DOWN_WEAK
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_gpio_init_param
|
||||
* @brief Structure holding the parameters for GPIO initialization.
|
||||
*/
|
||||
struct no_os_gpio_init_param {
|
||||
/** Port number */
|
||||
int32_t port;
|
||||
/** GPIO number */
|
||||
int32_t number;
|
||||
/** Pull up/down resistor configuration */
|
||||
enum no_os_gpio_pull_up pull;
|
||||
/** GPIO platform specific functions */
|
||||
const struct no_os_gpio_platform_ops *platform_ops;
|
||||
/** GPIO extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_gpio_desc
|
||||
* @brief Structure holding the GPIO descriptor.
|
||||
*/
|
||||
struct no_os_gpio_desc {
|
||||
/** Port number */
|
||||
int32_t port;
|
||||
/** GPIO number */
|
||||
int32_t number;
|
||||
/** Pull up/down resistor configuration */
|
||||
enum no_os_gpio_pull_up pull;
|
||||
/** GPIO platform specific functions */
|
||||
const struct no_os_gpio_platform_ops *platform_ops;
|
||||
/** GPIO extra parameters (device specific) */
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum no_os_gpio_values
|
||||
* @brief Enum that holds the possible output states of a GPIO.
|
||||
*/
|
||||
enum no_os_gpio_values {
|
||||
/** GPIO logic low */
|
||||
NO_OS_GPIO_LOW,
|
||||
/** GPIO logic high */
|
||||
NO_OS_GPIO_HIGH,
|
||||
/** GPIO high impedance */
|
||||
NO_OS_GPIO_HIGH_Z
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct no_os_gpio_platform_ops
|
||||
* @brief Structure holding gpio function pointers that point to the platform
|
||||
* specific function
|
||||
*/
|
||||
struct no_os_gpio_platform_ops {
|
||||
/** gpio initialization function pointer */
|
||||
int32_t (*gpio_ops_get)(struct no_os_gpio_desc **,
|
||||
const struct no_os_gpio_init_param *);
|
||||
/** gpio optional descriptor function pointer */
|
||||
int32_t (*gpio_ops_get_optional)(struct no_os_gpio_desc **,
|
||||
const struct no_os_gpio_init_param *);
|
||||
/** gpio remove function pointer */
|
||||
int32_t (*gpio_ops_remove)(struct no_os_gpio_desc *);
|
||||
/** gpio direction input function pointer */
|
||||
int32_t (*gpio_ops_direction_input)(struct no_os_gpio_desc *);
|
||||
/** gpio direction output function pointer */
|
||||
int32_t (*gpio_ops_direction_output)(struct no_os_gpio_desc *, uint8_t);
|
||||
/** gpio get direction function pointer */
|
||||
int32_t (*gpio_ops_get_direction)(struct no_os_gpio_desc *, uint8_t *);
|
||||
/** gpio set value function pointer */
|
||||
int32_t (*gpio_ops_set_value)(struct no_os_gpio_desc *, uint8_t);
|
||||
/** gpio get value function pointer */
|
||||
int32_t (*gpio_ops_get_value)(struct no_os_gpio_desc *, uint8_t *);
|
||||
};
|
||||
|
||||
/* Obtain the GPIO decriptor. */
|
||||
int32_t no_os_gpio_get(struct no_os_gpio_desc **desc,
|
||||
const struct no_os_gpio_init_param *param);
|
||||
|
||||
/* Obtain optional GPIO descriptor. */
|
||||
int32_t no_os_gpio_get_optional(struct no_os_gpio_desc **desc,
|
||||
const struct no_os_gpio_init_param *param);
|
||||
|
||||
/* Free the resources allocated by no_os_gpio_get(). */
|
||||
int32_t no_os_gpio_remove(struct no_os_gpio_desc *desc);
|
||||
|
||||
/* Enable the input direction of the specified GPIO. */
|
||||
int32_t no_os_gpio_direction_input(struct no_os_gpio_desc *desc);
|
||||
|
||||
/* Enable the output direction of the specified GPIO. */
|
||||
int32_t no_os_gpio_direction_output(struct no_os_gpio_desc *desc,
|
||||
uint8_t value);
|
||||
|
||||
/* Get the direction of the specified GPIO. */
|
||||
int32_t no_os_gpio_get_direction(struct no_os_gpio_desc *desc,
|
||||
uint8_t *direction);
|
||||
|
||||
/* Set the value of the specified GPIO. */
|
||||
int32_t no_os_gpio_set_value(struct no_os_gpio_desc *desc,
|
||||
uint8_t value);
|
||||
|
||||
/* Get the value of the specified GPIO. */
|
||||
int32_t no_os_gpio_get_value(struct no_os_gpio_desc *desc,
|
||||
uint8_t *value);
|
||||
|
||||
#endif // _NO_OS_GPIO_H_
|
||||
209
firmware/9_1_Microcontroller/9_1_1_C_Cpp_Libraries/no_os_i2c.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/***************************************************************************//**
|
||||
* @file no_os_i2c.c
|
||||
* @brief Implementation of the I2C Interface
|
||||
* @author Antoniu Miclaus (antoniu.miclaus@analog.com)
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "no_os_i2c.h"
|
||||
#include <stdlib.h>
|
||||
#include "no_os_error.h"
|
||||
#include "no_os_mutex.h"
|
||||
#include "no_os_alloc.h"
|
||||
|
||||
/**
|
||||
* @brief i2c_table contains the pointers towards the i2c buses
|
||||
*/
|
||||
static void *i2c_table[I2C_MAX_BUS_NUMBER + 1];
|
||||
|
||||
/**
|
||||
* @brief Initialize the I2C communication peripheral.
|
||||
* @param desc - The I2C descriptor.
|
||||
* @param param - The structure that contains the I2C parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_i2c_init(struct no_os_i2c_desc **desc,
|
||||
const struct no_os_i2c_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (!param || !param->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!param->platform_ops->i2c_ops_init)
|
||||
return -ENOSYS;
|
||||
if (param->device_id > I2C_MAX_BUS_NUMBER)
|
||||
return -EINVAL;
|
||||
// Initializing BUS descriptor
|
||||
if (i2c_table[param->device_id] == NULL) {
|
||||
ret = no_os_i2cbus_init(param);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
// Initilize I2C descriptor
|
||||
ret = param->platform_ops->i2c_ops_init(desc, param);
|
||||
if (ret)
|
||||
return ret;
|
||||
(*desc)->bus = i2c_table[param->device_id];
|
||||
(*desc)->bus->slave_number++;
|
||||
(*desc)->platform_ops = param->platform_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the i2c bus communication peripheral.
|
||||
* @param param - The structure that containes the i2c bus parameters
|
||||
* @return 0 in case of success, error code otherwise
|
||||
*/
|
||||
int32_t no_os_i2cbus_init(const struct no_os_i2c_init_param *param)
|
||||
{
|
||||
struct no_os_i2cbus_desc *bus = (struct no_os_i2cbus_desc *)no_os_calloc(1,
|
||||
sizeof(struct no_os_i2cbus_desc));
|
||||
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
|
||||
no_os_mutex_init(&(bus->mutex));
|
||||
|
||||
bus->slave_number = 0;
|
||||
bus->device_id = param->device_id;
|
||||
bus->max_speed_hz = param->max_speed_hz;
|
||||
bus->platform_ops = param->platform_ops;
|
||||
bus->extra = param->extra;
|
||||
|
||||
i2c_table[param->device_id] = bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by no_os_i2c_init().
|
||||
* @param desc - The I2C descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_i2c_remove(struct no_os_i2c_desc *desc)
|
||||
{
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->bus)
|
||||
no_os_i2cbus_remove(desc->bus->device_id);
|
||||
|
||||
if (!desc->platform_ops->i2c_ops_remove)
|
||||
return -ENOSYS;
|
||||
|
||||
return desc->platform_ops->i2c_ops_remove(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes i2c bus instance
|
||||
* @param bus_number - i2c bus number
|
||||
*/
|
||||
void no_os_i2cbus_remove(uint32_t bus_number)
|
||||
{
|
||||
struct no_os_i2cbus_desc *bus = (struct no_os_i2cbus_desc *)
|
||||
i2c_table[bus_number];
|
||||
|
||||
if (bus->slave_number > 0)
|
||||
bus->slave_number--;
|
||||
|
||||
if (bus->slave_number == 0) {
|
||||
no_os_mutex_remove(bus->mutex);
|
||||
|
||||
if (bus != NULL) {
|
||||
no_os_free(bus);
|
||||
i2c_table[bus_number] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2C Write data to slave device.
|
||||
* @param desc - The I2C descriptor.
|
||||
* @param data - The buffer with the transmitted/received data.
|
||||
* @param bytes_number - Number of bytes to write.
|
||||
* @param stop_bit - Stop conditional control.
|
||||
* Example: 0 - A stop condition will not be generated.
|
||||
* 1 - A stop condition will be generated.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_i2c_write(struct no_os_i2c_desc *desc,
|
||||
uint8_t *data,
|
||||
uint8_t bytes_number,
|
||||
uint8_t stop_bit)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->i2c_ops_write)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_lock(desc->bus->mutex);
|
||||
ret = desc->platform_ops->i2c_ops_write(desc, data, bytes_number,
|
||||
stop_bit);
|
||||
no_os_mutex_unlock(desc->bus->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2C Read data from slave device.
|
||||
* @param desc - The i2c descriptor.
|
||||
* @param data - The buffer with the transmitted/received data.
|
||||
* @param bytes_number - Number of bytes to read.
|
||||
* @param stop_bit - Stop conditional control.
|
||||
* Example: 0 - A stop condition will not be generated.
|
||||
* 1 - A stop condition will be generated.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t no_os_i2c_read(struct no_os_i2c_desc *desc,
|
||||
uint8_t *data,
|
||||
uint8_t bytes_number,
|
||||
uint8_t stop_bit)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (!desc || !desc->platform_ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!desc->platform_ops->i2c_ops_read)
|
||||
return -ENOSYS;
|
||||
|
||||
no_os_mutex_lock(desc->bus->mutex);
|
||||
ret = desc->platform_ops->i2c_ops_read(desc, data, bytes_number,
|
||||
stop_bit);
|
||||
no_os_mutex_unlock(desc->bus->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||