Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions source/accessories/amds/daisy-chain-protocol/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Daisy Chain Protocol

This document outlines the architecture, setup, and features of the Daisy Chain protocol implementation, allowing robust data routing, selective sampling, and high-speed multi-board communication.

## Multi-Target Firmware Project (Custom Build Configurations)

The firmware is designed to operate on multiple target hardware platforms using a single, unified codebase.

- **Target Definitions**: The firmware uses `TARGET_AMDS` and `TARGET_2S` preprocessor macros to conditionally compile board-specific configurations.
- **Dynamic Peripheral Assignment**: Depending on the selected target, the system correctly configures the corresponding hardware peripherals. For example, `TARGET_AMDS` utilizes `UART4` and `UART5` for the Daisy Chain RX lines, while `TARGET_2S` relies on `USART6` and `USART1`.
- **Custom Run Configurations**: You can program either an AMDS or other devices without creating separate project branches, simply by toggling the target macro in your build/run configurations.

## Direct Memory Access (DMA) Setup for Receiving Data

To ensure zero-CPU overhead when receiving incoming UART data, the protocol utilizes DMA streams.

- **Circular Buffers**: Incoming daisy-chain data is placed into `DAISY_RX1_Pool` and `DAISY_RX2_Pool`, both of which are 256-byte circular buffers (`AMDS_RX_BUF_SIZE`). Utilizing a 256-byte size allows for 8-bit integer math to handle wrap-around without complex modulo logic.
- **Error Recovery**: In high-noise environments, UART hardware errors (Parity, Overrun, Noise, or Frame errors) can cause the hardware to drop the `DMAR` (DMA Receiver) bit, halting the stream. The UART Interrupt Service Routines (ISRs) actively monitor for these flags, clear them, and immediately re-enable the DMA requests to ensure continuous stream operation without resetting the device.

## Selective Channel Transmitting

To optimize processing and transmission bandwidth, the system supports disabling unused sensor channels.

- **Active Sensor Mask**: A global variable `active_sensor_mask` acts as a bitmask where `1 = Active` and `0 = Inactive`.
- **Target Defaults**: By default, `TARGET_AMDS` activates all 8 channels (`0xFF`), while `TARGET_2S` activates a subset of channels (`0x11`).

## Modified Sample-and-Transmit Fast Path

The firmware bypasses standard abstraction overhead to achieve low latency during critical sampling and transmission windows via the `adc_sample_and_transmit_fast_path` function.

- **Hardware Cycle Counting**: Rather than using `NOP` loops for the mandatory 1300ns ADC wait time, the fast path uses the Cortex-M7 DWT Cycle Counter (`DWT->CYCCNT`) for deterministic waiting.
- **Instruction Interleaving**: The code optimizes wait states by starting SPI reads, and transmitting UART header bytes (`0x90`) while the CPU is waiting for the SPI RX buffers to fill.

## Process Routing Architecture

Handling high-speed daisy-chained data relies on the `try_process_routing()` and `process_routing()` implementations.

- **Thread-safe Invocation**: The main `while(1)` loop constantly checks `drv_uart_has_dma_data()` and invokes `try_process_routing()`. This wrapper uses an atomic lock (`is_routing_active`) to safely avert reentrancy without stalling the CPU or permanently blinding interrupts.
- **Dual-Stream Optimization**: Inside `process_routing()`, if both UART streams have at least a full 3-byte packet ready, the logic processes them completely interleaved. This keeps both hardware TX lines saturated simultaneously.
- **Single-Stream and Slow Path**: If one UART runs slightly faster, it employs a Single-Stream Fast Path. If a packet gets fragmented across a DMA boundary or becomes misaligned, the system reverts to a 1-byte-at-a-time State Machine (the "Slow Path") to recover the stream automatically.
10 changes: 8 additions & 2 deletions source/accessories/amds/firmware/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ The message structure is equal between both `DATA0` and `DATA1`. However, each m

_NOTE: there is no full CRC included in the transmission. The simple protocol relies on the parity check in the UART packet. This is not a terribly robust approach, but has worked well is moderate EMI environments._

### Daisy Chain Protocol Implementation

The physical routing, interleaving, and transmission of the sensor data across the dual UART TX lines are managed by a specialized firmware implementation known as the Daisy Chain Protocol. This protocol leverages DMA (Direct Memory Access) streams, selective channel masking, and a thread-safe routing architecture to ensure zero-CPU-overhead data receiving.

For a comprehensive breakdown of the DMA setup and the modified sample-and-transmit fast path, please refer to the detailed [Daisy Chain Protocol Documentation](../daisy-chain-protocol/index.md).

For instructions on programming the AMDS, please refer to [Building and Flashing Documentation](../flashing/index.md)

### Interrupt-Driven Design

After start-up, the AMDS firmware is completely interrupt driven. This means that all processing occurs within an interrupt context, not the main loop. The interrupt which used to drive the firmware occurs on the rising and falling edges of the `SYNC_ADC` signal.
Expand Down Expand Up @@ -117,5 +125,3 @@ The AMDS firmware works, albeit with limitations as described above. Some ideas
2. The total sampling and data transmission latency as seen by the master (AMDC) could be improved. In the current firmware, the time from when the `SYNC_ADC` line is toggled to when the newly sampled data has fully been received by the master is about 11 µs. This places limitations on the control rate of the master (AMDC). The improvements can come in several parts: 1) the actual ADC sampling time can be shorten by using the `BUSY` signal from each ADC in an ISR to end the ADC sampling window. These are not used in the current firmware. Instead, the simpler approach of busy waiting until the max timeout occurs is used (i.e. wait for 1300 ns). However, the nominal wait time is only about 50% of this. 2) The data transmission time could be shorten by removing/reducing the overhead in the packet format, i.e., removing the header bytes.

3. There is no robust CRC error detection on the data transmission from the AMDS to the master device, although the UART parity is used. Future improvements could add a footer CRC to ensure the received message at the master is valid. Error correction codes could also be used to further increase the communication robustness in high EMI environments (e.g. SECDED). There is no free lunch: all of these methods would increase the data transmission latency from the AMDS.

4. There is no need to transmit the data from all eight sensor cards if they are not all populated. Theoretically, a user could run the AMDS interface MUCH faster with fewer sensor cards installed, if changes are made such that only real data acquired from populated sensor cards are transmitted back to the master.
64 changes: 64 additions & 0 deletions source/accessories/amds/flashing/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Building and Flashing

This guide provides step-by-step instructions on how to configure, build, and flash the AMDS firmware onto different hardware targets (e.g., AMDS and 2S).

## Prerequisites

- **IDE:** STM32CubeIDE (or your preferred C/C++ IDE configured for ARM Cortex-M development).
- **Hardware:** ST-Link V2/V3 or equivalent hardware debugger/programmer.
- **Target Board:** Either an AMDS board or AMDS-compatible board.

## Step 1: Open the Project

1. Launch STM32CubeIDE.
2. Go to **File > Open Projects from File System...**
3. Select the directory containing the firmware source code and click **Finish**.

## Step 2: Set the Build Configuration (Target Macro)

The firmware uses preprocessor macros to conditionally compile the correct peripheral assignments and active sensor masks for your specific board.

1. Right-click on `motherboard_v1` and go to **Build Configuration > Set Active > AMDS or 2S**

*Note: Alternatively, simply select the appropriate active configuration the Build "hammer" dropdown menu.*

## Step 3: Build the Project

1. **Clean** the project to ensure no artifact mix-ups from previous board builds: Go to **Project > Clean...** and select your project.
2. **Build** the project: Click the **Build** (hammer) icon or go to **Project > Build Project**.
3. Check the console output to ensure there are no compilation errors and that the build finishes successfully.

```{important}
If you did not set the build configuration in the previous steps you will see many compilation errors that look like this:

#error "Please define a target board (TARGET_AMDS or TARGET_2S)!"
```

## Step 4: Configure the Run/Debug Settings

1. Connect your ST-Link to your PC and the target board's SWD (Serial Wire Debug) header.
2. Power on the target board.
3. In STM32CubeIDE, go to **Run > Debug Configurations...**
4. Double-click **STM32 Cortex-M C/C++ Application** to create a new configuration.
5. In the **Main** tab, ensure the correct `.elf` file is selected from your recent build.
6. In the **Debugger** tab, ensure the Debug probe is set to **ST-LINK** and the interface is set to **SWD**.
7. Click **Apply**.

## Step 5: Flash and Verify

1. Click **Debug** (or **Run**) from the configuration window to flash the firmware.
2. The IDE will connect to the board, erase the necessary flash sectors, and write the new firmware.
3. Once flashing is complete, if you are in Debug mode, click the **Resume** (play) button to start execution.
4. **Verification:** Observe the board's behavior. Depending on your configuration, verify that the active sensor mask operates correctly (AMDS enables all 8 channels `0xFF`, 2S enables a subset `0x11`) and that UART/DMA streams begin processing as expected.

```{tip}
For the AMDS board, a good indicator that things are running smoothly is the 4 LEDS near the MCU blinking in order.
```

## Switching Between Boards

Because the project shares a single codebase, programming a different board type is simple:

1. Disconnect the current board and connect the new one.
2. Return to **Step 2** and swap the target macro.
3. Rebuild (Step 3) and Flash (Step 5).
2 changes: 2 additions & 0 deletions source/accessories/amds/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ However, it is a complete system which could be interfaced to any other host dev

amds-in-action/index
firmware/index
daisy-chain-protocol/index
flashing/index
mainboard/index
sensor-cards/index
```
4 changes: 4 additions & 0 deletions source/getting-started/tutorials/profiling-tasks/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ int task_controller_init(void)
// ...
```

```{warning}
Ensure that you
```

Next, add task functions which wrap the `print()` and `reset()` functions for the timing stats:

`task_controller.c`:
Expand Down