Skip to content
Closed
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
23 changes: 18 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ dmod_add_library(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}
src/dmspi.c
)

dmod_link_modules(${DMOD_MODULE_NAME}
dmdrvi
dmini
dmhaman
dm_sw_ring
dmgpio
dmosi
)

target_include_directories(${DMOD_MODULE_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
Expand All @@ -75,12 +84,16 @@ target_include_directories(${DMOD_MODULE_NAME}_if INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include
)

# To depend on another module's headers, use:
# dmod_link_modules(${DMOD_MODULE_NAME}
# other_module@1.0
# )

add_subdirectory(src/port)
target_link_libraries(${DMOD_MODULE_NAME} ${DMOD_MODULE_NAME}_port_if)
enable_testing()
add_subdirectory(tests)

# ======================================================================
# spitest Tool
# ======================================================================
# Manual device test tool - flashed onto a real board to exercise a real
# master<->slave SPI link against an already-dmdevfs-configured device (see
# tools/spitest/README.md). Not part of the ctest suite: it needs real
# hardware, a dmdevfs config, and a human to wire it up.
add_subdirectory(tools/spitest)
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ DMOD_CXXSOURCES=
DMOD_INC_DIRS=include

# The list of libraries to link
DMOD_LIBS=
DMOD_LIBS=dmdrvi dmini dmhaman dm_sw_ring dmspi_port

# The list of definitions
DMOD_DEFINITIONS=
Expand Down
112 changes: 85 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,32 @@
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![CI](https://github.com/choco-technologies/dmspi/actions/workflows/ci.yml/badge.svg)](https://github.com/choco-technologies/dmspi/actions/workflows/ci.yml)

dmspi DMOD library module.
SPI driver module for the DMOD ecosystem, supporting both master and slave
roles.

## Description

TODO: describe what this module does.
dmspi is a hardware driver (like `dmuart`/`dmgpio`): it registers with
`dmdrvi` and is used through the generic device API (create/open/read/
write/ioctl/close), configured from an INI file via `dmini`. It supports:

- Master and slave roles
- Configurable clock polarity/phase (CPOL/CPHA, or a `mode=0..3` shorthand)
- MSB-first or LSB-first bit order
- Software or hardware NSS (chip-select) management
- Polling or interrupt-driven operation, with an optional RX ring buffer
(useful for slave mode, where reception isn't driven by the local CPU)
- True full-duplex transfers via `dmspi_ioctl_cmd_transfer`

Like `dmuart`/`dmgpio`, dmspi only configures the SPI peripheral itself -
pin muxing (SCK/MOSI/MISO/NSS alternate functions) is done externally via
`dmgpio`, and in `nss_mode=soft` chip-select is a plain GPIO the caller
toggles around each transaction.

See [docs/configuration.md](docs/configuration.md) for the full
configuration reference and a usage example, and
[configs/](configs/README.md) for ready-made per-board/per-MCU INI files
(the same `dmdevfs`-loadable format `dmuart`/`dmgpio`/`dmclk` use).

## Building

Expand Down Expand Up @@ -48,54 +69,76 @@ dmf-get install -d ${DMOD_DMF_DIR}/test_dmspi-local.dmd -y
dmod_loader build/dmf/test_dmspi.dmf
```

## Usage

<TBD>

This library module provides functions that can be used by other modules:

```c
#include "dmspi.h"
```

## API
This exercises hardware-independent logic only (safe to run on the host).
For a real master<->slave SPI link on actual hardware, see
[tools/spitest/](tools/spitest/) - a small CLI tool, flashed onto a board
and run from the `dmell` shell, that opens an already-`dmdevfs`-configured
device by path (see [configs/](configs/README.md)) and exercises it. It
supports both a single-board loopback (two devices wired together) and a
two-board test (one board master, one board slave).

| Function | Description |
|----------|-------------|
| `dmspi_create()` | Create a new `dmspi_t` instance. |
| `dmspi_destroy()` | Destroy an instance created by `_create()`. |
| `dmspi_is_valid()` | Check whether a handle is a valid instance. |
## Usage

See [include/dmspi.h](include/dmspi.h) for the full
declarations and [docs/api-reference.md](docs/api-reference.md) for the
complete reference.
The normal way to use a dmspi device is through `dmdevfs`, like any other
file: open the path `dmdevfs` created for it
(`Dmod_FileOpen("/dev/dmspi1", "r+")`), then `Dmod_Ioctl`/`Dmod_FileClose`
(portable SAL wrappers declared in `dmod.h`, no extra module to link) - see
[tools/spitest/main.c](tools/spitest/main.c) for a complete, build-tested
example.

Writing your own driver-adjacent code that talks to dmspi *without* going
through a mounted path is also possible, but lower-level: dmspi is a
separate loadable module, so its `dmdrvi` entry points
(`dmdrvi_dmspi_create`, `_open`, `_ioctl`, ...) must be resolved dynamically
via `Dmod_GetDifFunction()` rather than called by name - see
[docs/configuration.md](docs/configuration.md) for why and how. See
[docs/api-reference.md](docs/api-reference.md) for the complete API
reference.

## Documentation

See the `docs/` directory:

- **[api-reference.md](docs/api-reference.md)** - Complete API documentation
- **[configuration.md](docs/configuration.md)** - INI configuration reference and usage example
- **[port-implementation.md](docs/port-implementation.md)** - How the port is structured and how to add another architecture

View documentation using `dmf-man dmspi`.

## Configuration Files

[configs/](configs/README.md) has ready-made, `dmdevfs`-loadable INI files
per board (SPI pins muxed via `dmgpio` + the `dmspi` section itself) and per
MCU (pin-agnostic defaults) - the same layout and mechanism `dmuart`,
`dmgpio`, and `dmclk` use.

## Hardware Port

This module ships two DMOD modules: the architecture-independent
`dmspi` and `dmspi_port`, which contains the
architecture-specific implementation. The active architecture is selected via
architecture-specific implementation. `stm32f4` and `stm32f7` are supported
today, sharing a common SPI register implementation (both families use the
same SPI IP block). The active architecture is selected via
`DMOD_CPU_FAMILY` (default: `stm32f7`):

```bash
cmake .. -DDMOD_CPU_FAMILY=stm32f7
cmake .. -DDMOD_CPU_FAMILY=stm32f7 # or stm32f4
```

See [docs/port-implementation.md](docs/port-implementation.md) for how to add
another architecture. Port-specific files:
See [docs/port-implementation.md](docs/port-implementation.md) for how the
common/per-family split works and how to add another architecture.
Port-specific files:

```
├── include/dmspi_port.h
├── src/port/
│ ├── CMakeLists.txt
│ ├── stm32_common/ # shared STM32 SPI register implementation
│ │ ├── stm32_common.h
│ │ └── stm32_common.c
│ ├── stm32f4/
│ │ ├── config.cmake
│ │ └── port.c
│ └── stm32f7/
│ ├── config.cmake
│ └── port.c
Expand All @@ -105,17 +148,32 @@ another architecture. Port-specific files:

```
dmspi/
├── configs/ # per-board/per-MCU INI files - see "Configuration Files" above
│ ├── board/
│ └── mcu/
├── docs/ # Documentation (markdown format)
├── examples/
│ └── config.ini # minimal, board-agnostic sample
├── include/ # Public headers
│ └── dmspi.h
│ ├── dmspi.h
│ ├── dmspi_port.h
│ └── dmspi_types.h
├── src/
│ └── dmspi.c
│ ├── dmspi.c
│ └── port/ # see "Hardware Port" above
├── tests/
│ ├── CMakeLists.txt
│ └── dmspi_test.c
├── tools/
│ └── spitest/ # hardware self-test - see "Testing" above
│ ├── CMakeLists.txt
│ ├── main.c
│ ├── README.md
│ └── spitest.dmr
├── CMakeLists.txt
├── Makefile
├── dmspi.dmr
├── dmspi_port.dmr
└── manifest.dmm
```

Expand Down
Loading
Loading