1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
//! Rust drivers and hardware abstraction layer for Infineon PSOC microcontrollers.
//!
//! The following families are currently supported:
//!
//! - PSOC 6
//! - PSOC Control C3
//!
//! The following drivers are currently supported:
//!
//! - System clock
//! - GPIO
//! - Watchdog
//!
//! # Important note about documentation
//!
//! The documentation available on docs.rs only covers a single chip
//! ([PSC3M5FDS2AFQ1](https://www.infineon.com/part/PSC3M5FDS2AFQ1), a PSOC Control C3 device).
//! Available drivers and APIs vary across devices. It is recommended to build documentation locally
//! for your specific chip by running `cargo doc --open` in your project.
//!
//! # Getting started
//!
//! To build an application from scratch, add `psoc` as a dependency in your `Cargo.toml` and
//! specify your device with a feature flag. You'll also need
//! [`cortex-m-rt`](https://crates.io/crates/cortex-m-rt), and a panic handler such as
//! [`panic-halt`](https://crates.io/crates/panic-halt) or
//! [`panic-probe`](https://crates.io/crates/panic-probe).
//!
//! ```toml
//! [dependencies]
//! psoc = { version = "0.1", features = ["device-psc3m5fds2afq1"] }
//!
//! cortex-m-rt = "0.7.5"
//! panic-halt = "1.0.0"
//! ```
//!
//!
//! Specify flashing, linker, and target options in `.cargo/config.toml`:
//!
//! ```toml
//! [target.'cfg(all(target_arch = "arm", target_os = "none"))']
//! runner = ["probe-rs", "run", "--log-format=oneline", "--speed=16000"]
//!
//! [build]
//! rustflags = [
//! "-Clink-arg=-Tpsoc.x",
//! "-Clink-arg=-Tdefmt.x",
//! "-C", "link-arg=--nmagic"
//! ]
//!
//! # Pick ONE of these for your target
//! # target = "thumbv6m-none-eabi" # Cortex-M0/M0+
//! # target = "thumbv7m-none-eabi" # Cortex-M3
//! # target = "thumbv7em-none-eabi" # Cortex-M4/M7 (no FPU)
//! # target = "thumbv7em-none-eabihf" # Cortex-M4/M7 (with FPU)
//! # target = "thumbv8m.main-none-eabi" # Cortex-M33/M55/M85 (no FPU)
//! target = "thumbv8m.main-none-eabihf" # Cortex-M33/M55/M85 (with FPU)
//! ```
//!
//! Write a main function and initialize the device:
//!
//! ```rust
//! #![no_main]
//! #![no_std]
//!
//! use panic_halt as _;
//!
//! #[cortex_m_rt::entry]
//! fn main() -> ! {
//! let mut device = psoc::device::Device::take();
//! // Initialize clocks
//! device.clock.configure(&Default::default(), None);
//!
//! // Initialize an LED pin
//! let led_port = device
//! .gpio
//! .8
//! .p5(psoc::gpio::mode::Strong::<false>, Default::default())
//! .initialize();
//! let mut led_pin = led_port.5;
//! loop {
//! led_pin.toggle();
//! psoc::sys::delay_microseconds(500_000);
//! }
//! }
//! ```
//!
//! Install probe-rs, and flash with `cargo flash --release`.
//!
//! See the [example applications](https://github.com/Infineon/psoc-rs/tree/main/examples) for
//! examples on how to structure applications and BSPS, and recommended configuration for
//! improved compiler optimizations and IDE integration.
//!
//! # Cargo features
//!
//! The following feature flags are provided:
//!
//! - `device-*`: Selects a specific chip to build for. Exactly one chip must be selected.
//! - `core-*`: For multi-core devices, selects a specific core to build for. Exactly one core must
//! be selected (see below for more information about multi-core support).
//! - `boot-image`: If targetting a multi-core device and selecting a core other than one used to
//! boot the system, this flag adds a small bootloader to your application which starts up the
//! selected core and launches your application. Required for running on a non-boot core (such as
//! the Cortex-M4 on PSOC 6), unless you already have another binary running on the boot core.
//! - `defmt`: Enables support for the [`defmt`](https://crates.io/crates/defmt) formatting library.
//! - `embassy-time`: Implements an [`embassy-time`](https://crates.io/crates/embassy-time) driver
//! using a multi-counter watchdog timer, enabling the use of the [Embassy](https://embassy.dev)
//! framework. You must call `psoc::sys::embassy_time::init()` in your application startup to
//! select a MCWDT instance to use and initialize the driver.
//! - `fault-handler`: Enables a default HardFault handler which prints a register dump using
//! `defmt`.
//!
//! # Driver Model and Lifecycle
//!
//! ## Typestates
//!
//! All drivers in this crate make use of the [typestate pattern][typestate], in which drivers'
//! instance and configuration option are represented statically using the type system (in
//! accordance with the standard design patterns for embedded Rust). For instance, a C driver would
//! typically use struct fields to represent the pin and port number of a GPIO pin:
//!
//! [typestate]: https://cliffle.com/blog/rust-typestate/
//!
//! ```c
//! typedef enum {
//! PIN_MODE_OUTPUT,
//! // ...
//! } pin_mode_t;
//!
//! typedef struct {
//! uint8_t port;
//! uint8_t pin;
//! } gpio_pin_t;
//!
//! void gpio_pin_init(gpio_pin_t *pin, uint8_t port, uint8_t pin, pin_mode_t mode);
//!
//! gpio_pin_t led_pin;
//! gpio_pin_init(&led_pin, 4, 2, PIN_MODE_OUTPUT);
//! ```
//!
//! The psoc-rs GPIO driver instead uses generic parameters, with a third parameter to represent
//! the pin mode (e.g. whether it's consfigured as an input or output):
//!
//! ```
//! trait PinMode { /* ... */ }
//! struct Output;
//! impl PinMode for Output {}
//!
//! struct Pin<const PORT: u8, const PIN: u8, Mode: PinMode> {
//! pub mode: PinMode
//! }
//!
//! let led_pin: Pin<4, 2, Output> = ...;
//! ```
//!
//! In effect, configuration constants are tracked as compile-time variables through the type
//! system rather than runtime variables stored in memory. This has several advantages:
//!
//! - Correctness: the compiler will statically catch many mistakes such as forgetting to
//! initialize a pin, trying to write to an input pin, or passing an incorrectly-configured pin to
//! a function or driver
//! - Performance: the Pin struct is a zero-sized type that takes up no memory and incurs no
//! overhead to pass around the program. And since the pin to be used is known at compile time, the
//! compiler can directly emit appropriate register accesses to interact with a pin rather than
//! going through a layer of indirection at runtime.
//!
//! This does have the effect of making type signatures long and unwieldy. It is recommended your
//! board support package define type aliases for drivers as they are used in your design:
//!
//! ```
//! type LedPin = Pin<4, 2, Output>;
//!
//! fn blink_led(pin: &mut LedPin) { /* ... */ }
//! ```
//!
//! ## Type Erasure
//!
//! All drivers in this crate can be also used in the "traditional C" model in which instance and
//! configuration properties are carried around as runtime fields. This is useful when you want to
//! parameterize over driver instances at runtime.
//!
//! To obtain a type-erased instance of a driver, call the `into_erased` or `as_erased` function on
//! a driver instance. Note that some drivers have separate type-erased variants for sync vs. async
//! usage, because async usage of a driver requires instantiating the appropriate interrupt
//! handlers (see below).
//!
//! ## Obtaining and Configuring Drivers
//!
//! To obtain an instance of a driver, use the `device` module. This module provides a struct
//! containing unconfigured driver instances for all hardware available on your chip. An
//! unconfigured driver instance is a zero-sized type representing an uninitialized hardware block
//! and provididing configuration functions allowing you to create and initialize a driver.
//!
//! ## Multi-core devices
//!
//! Multi-core support is still somewhat TBD. Multi-core applications will be consist of a separate
//! binary per core rather than one binary with multiple "threads" (because different cores may have
//! different ISA versions, and may not have cache coherency across the entire memory space).
//!
//! Right now, we don't provide any out-of-the-box way to build applications targetting multiple
//! cores (you can wrangle the linker scripts yourself if you want to do that), but we do have boot
//! images allowing you to easily run an application on a non-boot core (such as the CM4 on PSOC 6).
//! The boot image is a small binary that runs on the boot core, starts the application on the other
//! core, and goes to sleep. The boot images are selected by selecting a non-boot core by enabling
//! the `boot-image` Cargo feature.
//!
//! ## Interrupts
//!
//! You may define interrupt handlers using the `#[interrupt]` macro from the Cortex-M crate:
//!
//! ```
//! use cortex_m::interrupt;
//!
//! #[interrupt]
//! fn IOSS_INTERRUPT_GPIO_0() {
//! // ...
//! }
//! ```
//!
//! However, note that some optional driver features require specific interrupt handlers. In
//! particular, `async` driver functions typically require a driver-provided interrupt handler to
//! notify the runtime when an event occurs. If your application makes use of a driver feature that
//! requires an interrupt handler, a driver-provided interrupt handler will be automatically
//! generated. Note that such an interrupt handler will conflict with a user-provided handler for
//! the same interrupt, causing a linker error.
//!
//! Driver-provided interrupts are instantiated through generic monomorphization. The presence
//! of a call in your application to a driver function requiring an interrupt causes that function
//! to be monomorphized, resulting in the interrupt handler being emitted.
//!
// Copyright (c) 2026, Infineon Technologies AG or an affiliate of Infineon Technologies AG.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing permissions and
// limitations under the License.
pub use *;
/// The device structure, which contains all the peripherals available on the device.
pub use Device;