Add embassy-net-adin1110
This add a library for Analog ADIN1110 SPE SPI chip. This library is inspired by `embassy-net-w5500`.
This commit is contained in:
parent
bed1f07c15
commit
e19f7d9a76
1
embassy-net-adin1110/.gitignore
vendored
Normal file
1
embassy-net-adin1110/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
8
embassy-net-adin1110/.vscode/settings.json
vendored
Normal file
8
embassy-net-adin1110/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"rust-analyzer.check.command": "clippy",
|
||||||
|
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||||
|
"[rust]": {
|
||||||
|
"editor.defaultFormatter": "rust-lang.rust-analyzer",
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
}
|
||||||
|
}
|
41
embassy-net-adin1110/Cargo.toml
Normal file
41
embassy-net-adin1110/Cargo.toml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
[package]
|
||||||
|
name = "embassy-net-adin1110"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "embassy-net driver for the ADIN1110 ethernet chip"
|
||||||
|
keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"]
|
||||||
|
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
heapless = "0.7.16"
|
||||||
|
defmt = { version = "0.3", optional = true }
|
||||||
|
log = { version = "0.4.4", default-features = false, optional = true }
|
||||||
|
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
|
||||||
|
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||||
|
embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
|
||||||
|
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||||
|
embassy-time = { version = "0.1.0" }
|
||||||
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
|
bitfield = "0.14.0"
|
||||||
|
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged.
|
||||||
|
#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] }
|
||||||
|
embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] }
|
||||||
|
crc = "3.0.1"
|
||||||
|
env_logger = "0.10"
|
||||||
|
critical-section = { version = "1.1.1", features = ["std"] }
|
||||||
|
futures-test = "0.3.17"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = [ ]
|
||||||
|
defmt = [ "dep:defmt" ]
|
||||||
|
|
||||||
|
[package.metadata.embassy_docs]
|
||||||
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/"
|
||||||
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/"
|
||||||
|
target = "thumbv7em-none-eabi"
|
55
embassy-net-adin1110/README.md
Normal file
55
embassy-net-adin1110/README.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# SPE ADIN1110 `embassy-net` integration
|
||||||
|
|
||||||
|
[`embassy-net`](https://crates.io/crates/embassy-net) integration for the `Analog ADIN1110` SPI SPE ethernet chips.
|
||||||
|
|
||||||
|
## What is SPE or Single Pair Ethernet / 10 BASE-T1L
|
||||||
|
|
||||||
|
SPE is Single Pair Ethernet, what the names implies, it uses a single twisted/differancial pair (only 2 wires) to transmit ethernet packet in full-duplex.
|
||||||
|
SPE is still ethernet, only the phissical layer is different.
|
||||||
|
|
||||||
|
SPE also supports [`PoDL(Power over Data Line)`](https://www.ti.com/lit/an/snla395/snla395.pdf), power delivery from 0.5 up to 50 Watts, similair to [`PoE`](https://en.wikipedia.org/wiki/Power_over_Ethernet), but additional hardware and handshake protocol is needed.
|
||||||
|
|
||||||
|
SPE has many link speeds but only `10 BASE-T1L` is able to reach cable length up to 1000 meters in `2.4 Vpp` transmit amplitude.
|
||||||
|
Currently in 2023, none of the standards are compatiable with eachother.
|
||||||
|
So `10 BASE-T1L` don't work with a `10 BASE-T1S` or `100 BASE-T1`.
|
||||||
|
|
||||||
|
In the industry SPE is also called [`APL(Advanced Physical Layer)`](https://www.ethernet-apl.org), it is based on the `10 BASE-T1L` standard.
|
||||||
|
|
||||||
|
APL can be use in [`intrinsic safety applications/explosion hazardous areas`](https://en.wikipedia.org/wiki/Electrical_equipment_in_hazardous_areas) which has it's own name and standard [`2-WISE(2-wire intrinsically safe ethernet) IEC TS 60079-47:2021`](https://webstore.iec.ch/publication/64292).
|
||||||
|
|
||||||
|
`10 BASE-T1L` and `ADIN1110` are designed to support intrinsic safety applications. The power supply energy is fixed and PDoL is not supported.
|
||||||
|
|
||||||
|
## Supported SPI modes
|
||||||
|
|
||||||
|
`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
|
||||||
|
|
||||||
|
Both modes support with and without additional CRC.
|
||||||
|
Currently only `Generic` SPI with or without CRC is supported.
|
||||||
|
|
||||||
|
*NOTE:* SPI Mode is selected by the hardware pins `SPI_CFG0` and `SPI_CFG1`. Software can't detect nor change the mode.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
- Testen on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with a `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) example.
|
||||||
|
- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit`](https://www.sparkfun.com/products/19628), the kit supports multiple microcontrollers, please check if get the right microcontroller that is supported by Embassy!
|
||||||
|
|
||||||
|
## Other SPE chips
|
||||||
|
|
||||||
|
* [`Analog ADIN2111`](https://www.analog.com/en/products/adin2111.html) 2 Port SPI version. Can work with this driver.
|
||||||
|
* [`Analog ADIN1100`](https://www.analog.com/en/products/adin1100.html) RGMII version.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
ADIN1110 library can tested on the host with a mock SPI driver
|
||||||
|
|
||||||
|
$ `cargo test --target x86_64-unknown-linux-gnu`
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This work is licensed under either of
|
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
3
embassy-net-adin1110/rust-toolchain.toml
Normal file
3
embassy-net-adin1110/rust-toolchain.toml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
|
components = [ "rustfmt", "rustc-dev" ]
|
101
embassy-net-adin1110/src/crc32.rs
Normal file
101
embassy-net-adin1110/src/crc32.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
|
||||||
|
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832,
|
||||||
|
0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
|
||||||
|
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A,
|
||||||
|
0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||||
|
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
|
||||||
|
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
|
||||||
|
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
|
||||||
|
0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||||
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,
|
||||||
|
0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
|
||||||
|
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
|
||||||
|
0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||||
|
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,
|
||||||
|
0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
|
||||||
|
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
|
||||||
|
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||||
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76,
|
||||||
|
0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
|
||||||
|
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,
|
||||||
|
0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||||
|
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
|
||||||
|
0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
|
||||||
|
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7,
|
||||||
|
0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||||
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
|
||||||
|
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
|
||||||
|
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
|
||||||
|
0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||||
|
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ETH_FSC(pub u32);
|
||||||
|
|
||||||
|
impl ETH_FSC {
|
||||||
|
pub const CRC32_OK: u32 = 0x2144df1c;
|
||||||
|
|
||||||
|
pub fn new(data: &[u8]) -> Self {
|
||||||
|
let fsc = data.iter().fold(u32::MAX, |crc, byte| {
|
||||||
|
let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
|
||||||
|
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
|
||||||
|
}) ^ u32::MAX;
|
||||||
|
Self(fsc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn crc_ok(&self) -> bool {
|
||||||
|
self.0 == Self::CRC32_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hton_bytes(&self) -> [u8; 4] {
|
||||||
|
self.0.to_le_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hton(&self) -> u32 {
|
||||||
|
self.0.to_le()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn crc32_ethernet_frame() {
|
||||||
|
let packet_a = &[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xff, 0x06, 0x00, 0x01, 0x08, 0x00,
|
||||||
|
0x06, 0x04, 0x00, 0x01, 0x00, 0xe0, 0x4c, 0x68, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xc0, 0xa8, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x65, 0x90, 0x3d,
|
||||||
|
];
|
||||||
|
|
||||||
|
let packet_b = &[
|
||||||
|
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0x00, 0xe0, 0x4c, 0x68, 0xee, 0xee, 0xdd, 0x06, 0x00, 0x01, 0x08, 0x00,
|
||||||
|
0x06, 0x04, 0x00, 0x02, 0x00, 0xe0, 0x4c, 0x68, 0x09, 0xde, 0xc0, 0xa8, 0x01, 0x02, 0x12, 0x34, 0x56, 0x78,
|
||||||
|
0x9a, 0xbc, 0xc0, 0xa8, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x3d, 0x67, 0x7c,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Packet A
|
||||||
|
let own_crc = ETH_FSC::new(&packet_a[0..60]);
|
||||||
|
let crc_bytes = own_crc.hton_bytes();
|
||||||
|
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
|
||||||
|
assert_eq!(&crc_bytes, &packet_a[60..64]);
|
||||||
|
|
||||||
|
let own_crc = ETH_FSC::new(packet_a);
|
||||||
|
println!("{:08x}", own_crc.0);
|
||||||
|
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
|
||||||
|
|
||||||
|
// Packet B
|
||||||
|
let own_crc = ETH_FSC::new(&packet_b[0..60]);
|
||||||
|
let crc_bytes = own_crc.hton_bytes();
|
||||||
|
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
|
||||||
|
assert_eq!(&crc_bytes, &packet_b[60..64]);
|
||||||
|
|
||||||
|
let own_crc = ETH_FSC::new(packet_b);
|
||||||
|
println!("{:08x}", own_crc.0);
|
||||||
|
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
|
||||||
|
}
|
||||||
|
}
|
53
embassy-net-adin1110/src/crc8.rs
Normal file
53
embassy-net-adin1110/src/crc8.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/// CRC-8/ITU
|
||||||
|
const CRC8X_TABLE: [u8; 256] = [
|
||||||
|
0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e,
|
||||||
|
0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb,
|
||||||
|
0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8,
|
||||||
|
0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6,
|
||||||
|
0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d,
|
||||||
|
0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50,
|
||||||
|
0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, 0x95,
|
||||||
|
0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
|
||||||
|
0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f,
|
||||||
|
0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a,
|
||||||
|
0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e,
|
||||||
|
0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
|
||||||
|
0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc,
|
||||||
|
0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Calculate the crc of a pease of data.
|
||||||
|
pub fn crc8(data: &[u8]) -> u8 {
|
||||||
|
data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use ::crc::{Crc, CRC_8_SMBUS};
|
||||||
|
|
||||||
|
use super::crc8;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spi_header_crc8() {
|
||||||
|
let data = &[0x80, 0x00];
|
||||||
|
|
||||||
|
let c = Crc::<u8>::new(&CRC_8_SMBUS);
|
||||||
|
let mut dig = c.digest();
|
||||||
|
dig.update(data);
|
||||||
|
let sw_crc = dig.finalize();
|
||||||
|
|
||||||
|
let own_crc = crc8(data);
|
||||||
|
|
||||||
|
assert_eq!(own_crc, sw_crc);
|
||||||
|
assert_eq!(own_crc, 182);
|
||||||
|
|
||||||
|
let data = &[0x80, 0x01];
|
||||||
|
let mut dig = c.digest();
|
||||||
|
dig.update(data);
|
||||||
|
let sw_crc = dig.finalize();
|
||||||
|
let own_crc = crc8(data);
|
||||||
|
|
||||||
|
assert_eq!(own_crc, sw_crc);
|
||||||
|
assert_eq!(own_crc, 177);
|
||||||
|
}
|
||||||
|
}
|
1246
embassy-net-adin1110/src/lib.rs
Normal file
1246
embassy-net-adin1110/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
174
embassy-net-adin1110/src/mdio.rs
Normal file
174
embassy-net-adin1110/src/mdio.rs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/// PHY Address: (0..=0x1F), 5-bits long.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
type PhyAddr = u8;
|
||||||
|
|
||||||
|
/// PHY Register: (0..=0x1F), 5-bits long.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
type RegC22 = u8;
|
||||||
|
|
||||||
|
/// PHY Register Clause 45.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
type RegC45 = u16;
|
||||||
|
|
||||||
|
/// PHY Register Value
|
||||||
|
#[allow(dead_code)]
|
||||||
|
type RegVal = u16;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const REG13: RegC22 = 13;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const REG14: RegC22 = 14;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const PHYADDR_MASK: u8 = 0x1f;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const DEV_MASK: u8 = 0x1f;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(u16)]
|
||||||
|
enum Reg13Op {
|
||||||
|
Addr = 0b00 << 14,
|
||||||
|
Write = 0b01 << 14,
|
||||||
|
PostReadIncAddr = 0b10 << 14,
|
||||||
|
Read = 0b11 << 14,
|
||||||
|
}
|
||||||
|
/// MdioBus trait
|
||||||
|
/// Driver needs to implemnt the Claus 22
|
||||||
|
/// Optional Clause 45 is the device supports this.
|
||||||
|
///
|
||||||
|
/// Claus 45 methodes are bases on https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf
|
||||||
|
pub trait MdioBus {
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
/// Read, Clause 22
|
||||||
|
async fn read_cl22(&mut self, phy_id: PhyAddr, reg: RegC22) -> Result<RegVal, Self::Error>;
|
||||||
|
|
||||||
|
/// Write, Clause 22
|
||||||
|
async fn write_cl22(&mut self, phy_id: PhyAddr, reg: RegC22, reg_val: RegVal) -> Result<(), Self::Error>;
|
||||||
|
|
||||||
|
/// Read, Clause 45
|
||||||
|
/// This is the default implementation.
|
||||||
|
/// Many hardware these days support direct Clause 45 operations.
|
||||||
|
/// Implement this function when your hardware supports it.
|
||||||
|
async fn read_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45)) -> Result<RegVal, Self::Error> {
|
||||||
|
// Write FN
|
||||||
|
let val = (Reg13Op::Addr as RegVal) | (regc45.0 & DEV_MASK) as RegVal;
|
||||||
|
self.write_cl22(phy_id, REG13, val).await?;
|
||||||
|
// Write Addr
|
||||||
|
self.write_cl22(phy_id, REG14, regc45.1).await?;
|
||||||
|
|
||||||
|
// Write FN
|
||||||
|
let val = (Reg13Op::Read as RegVal) | (regc45.0 & DEV_MASK) as RegVal;
|
||||||
|
self.write_cl22(phy_id, REG13, val).await?;
|
||||||
|
// Write Addr
|
||||||
|
self.read_cl22(phy_id, REG14).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write, Clause 45
|
||||||
|
/// This is the default implementation.
|
||||||
|
/// Many hardware these days support direct Clause 45 operations.
|
||||||
|
/// Implement this function when your hardware supports it.
|
||||||
|
async fn write_cl45(&mut self, phy_id: PhyAddr, regc45: (u8, RegC45), reg_val: RegVal) -> Result<(), Self::Error> {
|
||||||
|
let dev_addr = (regc45.0 & DEV_MASK) as RegVal;
|
||||||
|
let reg = regc45.1;
|
||||||
|
|
||||||
|
// Write FN
|
||||||
|
let val = (Reg13Op::Addr as RegVal) | dev_addr;
|
||||||
|
self.write_cl22(phy_id, REG13, val).await?;
|
||||||
|
// Write Addr
|
||||||
|
self.write_cl22(phy_id, REG14, reg).await?;
|
||||||
|
|
||||||
|
// Write FN
|
||||||
|
let val = (Reg13Op::Write as RegVal) | dev_addr;
|
||||||
|
self.write_cl22(phy_id, REG13, val).await?;
|
||||||
|
// Write Addr
|
||||||
|
self.write_cl22(phy_id, REG14, reg_val).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[cfg(test)]
|
||||||
|
// mod tests {
|
||||||
|
// use core::convert::Infallible;
|
||||||
|
|
||||||
|
// use super::{MdioBus, PhyAddr, RegC22, RegVal};
|
||||||
|
|
||||||
|
// #[derive(Debug, PartialEq, Eq)]
|
||||||
|
// enum A {
|
||||||
|
// Read(PhyAddr, RegC22),
|
||||||
|
// Write(PhyAddr, RegC22, RegVal),
|
||||||
|
// }
|
||||||
|
|
||||||
|
// struct MockMdioBus(Vec<A>);
|
||||||
|
|
||||||
|
// impl MockMdioBus {
|
||||||
|
// pub fn clear(&mut self) {
|
||||||
|
// self.0.clear();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl MdioBus for MockMdioBus {
|
||||||
|
// type Error = Infallible;
|
||||||
|
|
||||||
|
// fn write_cl22(
|
||||||
|
// &mut self,
|
||||||
|
// phy_id: super::PhyAddr,
|
||||||
|
// reg: super::RegC22,
|
||||||
|
// reg_val: super::RegVal,
|
||||||
|
// ) -> Result<(), Self::Error> {
|
||||||
|
// self.0.push(A::Write(phy_id, reg, reg_val));
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn read_cl22(
|
||||||
|
// &mut self,
|
||||||
|
// phy_id: super::PhyAddr,
|
||||||
|
// reg: super::RegC22,
|
||||||
|
// ) -> Result<super::RegVal, Self::Error> {
|
||||||
|
// self.0.push(A::Read(phy_id, reg));
|
||||||
|
// Ok(0)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn read_test() {
|
||||||
|
// let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
|
||||||
|
|
||||||
|
// mdiobus.clear();
|
||||||
|
// mdiobus.read_cl22(0x01, 0x00).unwrap();
|
||||||
|
// assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]);
|
||||||
|
|
||||||
|
// mdiobus.clear();
|
||||||
|
// mdiobus.read_cl45(0x01, (0xBB, 0x1234)).unwrap();
|
||||||
|
// assert_eq!(
|
||||||
|
// mdiobus.0,
|
||||||
|
// vec![
|
||||||
|
// #[allow(clippy::identity_op)]
|
||||||
|
// A::Write(0x01, 13, (0b00 << 14) | 27),
|
||||||
|
// A::Write(0x01, 14, 0x1234),
|
||||||
|
// A::Write(0x01, 13, (0b11 << 14) | 27),
|
||||||
|
// A::Read(0x01, 14)
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn write_test() {
|
||||||
|
// let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
|
||||||
|
|
||||||
|
// mdiobus.clear();
|
||||||
|
// mdiobus.write_cl22(0x01, 0x00, 0xABCD).unwrap();
|
||||||
|
// assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]);
|
||||||
|
|
||||||
|
// mdiobus.clear();
|
||||||
|
// mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).unwrap();
|
||||||
|
// assert_eq!(
|
||||||
|
// mdiobus.0,
|
||||||
|
// vec![
|
||||||
|
// A::Write(0x01, 13, 27),
|
||||||
|
// A::Write(0x01, 14, 0x1234),
|
||||||
|
// A::Write(0x01, 13, (0b01 << 14) | 27),
|
||||||
|
// A::Write(0x01, 14, 0xABCD)
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
137
embassy-net-adin1110/src/phy.rs
Normal file
137
embassy-net-adin1110/src/phy.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
use crate::mdio::MdioBus;
|
||||||
|
|
||||||
|
#[allow(dead_code, non_camel_case_types, clippy::upper_case_acronyms)]
|
||||||
|
#[repr(u8)]
|
||||||
|
/// Clause 22 Registers
|
||||||
|
pub enum RegsC22 {
|
||||||
|
/// MII Control Register
|
||||||
|
CONTROL = 0x00,
|
||||||
|
/// MII Status Register
|
||||||
|
STATUS = 0x01,
|
||||||
|
/// PHY Identifier 1 Register
|
||||||
|
PHY_ID1 = 0x02,
|
||||||
|
/// PHY Identifier 2 Register.
|
||||||
|
PHY_ID2 = 0x03,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clause 45 Registers
|
||||||
|
#[allow(non_snake_case, dead_code)]
|
||||||
|
pub mod RegsC45 {
|
||||||
|
/// Device Address: 0x01
|
||||||
|
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum DA1 {
|
||||||
|
/// PMA/PMD Control 1 Register
|
||||||
|
PMA_PMD_CNTRL1 = 0x0000,
|
||||||
|
/// PMA/PMD Status 1 Register
|
||||||
|
PMA_PMD_STAT1 = 0x0001,
|
||||||
|
/// MSE Value Register
|
||||||
|
MSE_VAL = 0x830B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DA1 {
|
||||||
|
pub fn into(self) -> (u8, u16) {
|
||||||
|
(0x01, self as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Device Address: 0x03
|
||||||
|
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum DA3 {
|
||||||
|
/// PCS Control 1 Register
|
||||||
|
PCS_CNTRL1 = 0x0000,
|
||||||
|
/// PCS Status 1 Register
|
||||||
|
PCS_STAT1 = 0x0001,
|
||||||
|
/// PCS Status 2 Register
|
||||||
|
PCS_STAT2 = 0x0008,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DA3 {
|
||||||
|
pub fn into(self) -> (u8, u16) {
|
||||||
|
(0x03, self as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Device Address: 0x07
|
||||||
|
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum DA7 {
|
||||||
|
/// Extra Autonegotiation Status Register
|
||||||
|
AN_STATUS_EXTRA = 0x8001,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DA7 {
|
||||||
|
pub fn into(self) -> (u8, u16) {
|
||||||
|
(0x07, self as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Device Address: 0x1E
|
||||||
|
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum DA1E {
|
||||||
|
/// System Interrupt Status Register
|
||||||
|
CRSM_IRQ_STATUS = 0x0010,
|
||||||
|
/// System Interrupt Mask Register
|
||||||
|
CRSM_IRQ_MASK = 0x0020,
|
||||||
|
/// Pin Mux Configuration 1 Register
|
||||||
|
DIGIO_PINMUX = 0x8c56,
|
||||||
|
/// LED Control Register.
|
||||||
|
LED_CNTRL = 0x8C82,
|
||||||
|
/// LED Polarity Register
|
||||||
|
LED_POLARITY = 0x8C83,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DA1E {
|
||||||
|
pub fn into(self) -> (u8, u16) {
|
||||||
|
(0x1e, self as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Device Address: 0x1F
|
||||||
|
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum DA1F {
|
||||||
|
/// PHY Subsystem Interrupt Status Register
|
||||||
|
PHY_SYBSYS_IRQ_STATUS = 0x0011,
|
||||||
|
/// PHY Subsystem Interrupt Mask Register
|
||||||
|
PHY_SYBSYS_IRQ_MASK = 0x0021,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DA1F {
|
||||||
|
pub fn into(self) -> (u8, u16) {
|
||||||
|
(0x1f, self as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Phy10BaseT1x(u8);
|
||||||
|
|
||||||
|
impl Default for Phy10BaseT1x {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(0x01)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Phy10BaseT1x {
|
||||||
|
/// Get the both parts of the PHYID.
|
||||||
|
pub async fn get_id<MDIOBUS, MDE>(&self, mdiobus: &mut MDIOBUS) -> Result<u32, MDE>
|
||||||
|
where
|
||||||
|
MDIOBUS: MdioBus<Error = MDE>,
|
||||||
|
MDE: core::fmt::Debug,
|
||||||
|
{
|
||||||
|
let mut phyid = (mdiobus.read_cl22(self.0, RegsC22::PHY_ID1 as u8).await? as u32) << 16;
|
||||||
|
phyid |= mdiobus.read_cl22(self.0, RegsC22::PHY_ID2 as u8).await? as u32;
|
||||||
|
Ok(phyid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the Mean Squared Error Value.
|
||||||
|
pub async fn get_sqi<MDIOBUS, MDE>(&self, mdiobus: &mut MDIOBUS) -> Result<u16, MDE>
|
||||||
|
where
|
||||||
|
MDIOBUS: MdioBus<Error = MDE>,
|
||||||
|
MDE: core::fmt::Debug,
|
||||||
|
{
|
||||||
|
mdiobus.read_cl45(self.0, RegsC45::DA1::MSE_VAL.into()).await
|
||||||
|
}
|
||||||
|
}
|
407
embassy-net-adin1110/src/regs.rs
Normal file
407
embassy-net-adin1110/src/regs.rs
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[repr(u16)]
|
||||||
|
/// SPI REGISTER DETAILS
|
||||||
|
/// Table 38.
|
||||||
|
pub enum SpiRegisters {
|
||||||
|
IDVER = 0x00,
|
||||||
|
PHYID = 0x01,
|
||||||
|
CAPABILITY = 0x02,
|
||||||
|
RESET = 0x03,
|
||||||
|
CONFIG0 = 0x04,
|
||||||
|
CONFIG2 = 0x06,
|
||||||
|
STATUS0 = 0x08,
|
||||||
|
STATUS1 = 0x09,
|
||||||
|
IMASK0 = 0x0C,
|
||||||
|
IMASK1 = 0x0D,
|
||||||
|
MDIO_ACC = 0x20,
|
||||||
|
TX_FSIZE = 0x30,
|
||||||
|
TX = 0x31,
|
||||||
|
TX_SPACE = 0x32,
|
||||||
|
FIFO_CLR = 0x36,
|
||||||
|
ADDR_FILT_UPR0 = 0x50,
|
||||||
|
ADDR_FILT_LWR0 = 0x51,
|
||||||
|
ADDR_FILT_UPR1 = 0x52,
|
||||||
|
ADDR_FILT_LWR1 = 0x53,
|
||||||
|
ADDR_MSK_LWR0 = 0x70,
|
||||||
|
ADDR_MSK_UPR0 = 0x71,
|
||||||
|
ADDR_MSK_LWR1 = 0x72,
|
||||||
|
ADDR_MSK_UPR1 = 0x73,
|
||||||
|
RX_FSIZE = 0x90,
|
||||||
|
RX = 0x91,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SpiRegisters> for u16 {
|
||||||
|
fn from(val: SpiRegisters) -> Self {
|
||||||
|
val as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u16> for SpiRegisters {
|
||||||
|
fn from(value: u16) -> Self {
|
||||||
|
match value {
|
||||||
|
0x00 => Self::IDVER,
|
||||||
|
0x01 => Self::PHYID,
|
||||||
|
0x02 => Self::CAPABILITY,
|
||||||
|
0x03 => Self::RESET,
|
||||||
|
0x04 => Self::CONFIG0,
|
||||||
|
0x06 => Self::CONFIG2,
|
||||||
|
0x08 => Self::STATUS0,
|
||||||
|
0x09 => Self::STATUS1,
|
||||||
|
0x0C => Self::IMASK0,
|
||||||
|
0x0D => Self::IMASK1,
|
||||||
|
0x20 => Self::MDIO_ACC,
|
||||||
|
0x30 => Self::TX_FSIZE,
|
||||||
|
0x31 => Self::TX,
|
||||||
|
0x32 => Self::TX_SPACE,
|
||||||
|
0x36 => Self::FIFO_CLR,
|
||||||
|
0x50 => Self::ADDR_FILT_UPR0,
|
||||||
|
0x51 => Self::ADDR_FILT_LWR0,
|
||||||
|
0x52 => Self::ADDR_FILT_UPR1,
|
||||||
|
0x53 => Self::ADDR_FILT_LWR1,
|
||||||
|
0x70 => Self::ADDR_MSK_LWR0,
|
||||||
|
0x71 => Self::ADDR_MSK_UPR0,
|
||||||
|
0x72 => Self::ADDR_MSK_LWR1,
|
||||||
|
0x73 => Self::ADDR_MSK_UPR1,
|
||||||
|
0x90 => Self::RX_FSIZE,
|
||||||
|
0x91 => Self::RX,
|
||||||
|
e => panic!("Unknown value {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register definitions
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
/// Status0 Register bits
|
||||||
|
pub struct Status0(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
/// Control Data Protection Error
|
||||||
|
pub cdpe, _ : 12;
|
||||||
|
/// Transmit Frame Check Squence Error
|
||||||
|
pub txfcse, _: 11;
|
||||||
|
/// Transmit Time Stamp Capture Available C
|
||||||
|
pub ttscac, _ : 10;
|
||||||
|
/// Transmit Time Stamp Capture Available B
|
||||||
|
pub ttscab, _ : 9;
|
||||||
|
/// Transmit Time Stamp Capture Available A
|
||||||
|
pub ttscaa, _ : 8;
|
||||||
|
/// PHY Interrupt for Port 1
|
||||||
|
pub phyint, _ : 7;
|
||||||
|
/// Reset Complete
|
||||||
|
pub resetc, _ : 6;
|
||||||
|
/// Header error
|
||||||
|
pub hdre, _ : 5;
|
||||||
|
/// Loss of Frame Error
|
||||||
|
pub lofe, _ : 4;
|
||||||
|
/// Receiver Buffer Overflow Error
|
||||||
|
pub rxboe, _ : 3;
|
||||||
|
/// Host Tx FIFO Under Run Error
|
||||||
|
pub txbue, _ : 2;
|
||||||
|
/// Host Tx FIFO Overflow
|
||||||
|
pub txboe, _ : 1;
|
||||||
|
/// Transmit Protocol Error
|
||||||
|
pub txpe, _ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
/// Status1 Register bits
|
||||||
|
pub struct Status1(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
/// ECC Error on Reading the Frame Size from a Tx FIFO
|
||||||
|
pub tx_ecc_err, set_tx_ecc_err: 12;
|
||||||
|
/// ECC Error on Reading the Frame Size from an Rx FIFO
|
||||||
|
pub rx_ecc_err, set_rx_ecc_err : 11;
|
||||||
|
/// Detected an Error on an SPI Transaction
|
||||||
|
pub spi_err, set_spi_err: 10;
|
||||||
|
/// Rx MAC Interframe Gap Error
|
||||||
|
pub p1_rx_ifg_err, set_p1_rx_ifg_err : 8;
|
||||||
|
/// Port1 Rx Ready High Priority
|
||||||
|
pub p1_rx_rdy_hi, set_p1_rx_rdy_hi : 5;
|
||||||
|
/// Port 1 Rx FIFO Contains Data
|
||||||
|
pub p1_rx_rdy, set_p1_rx_rdy : 4;
|
||||||
|
/// Tx Ready
|
||||||
|
pub tx_rdy, set_tx_rdy : 3;
|
||||||
|
/// Link Status Changed
|
||||||
|
pub link_change, set_link_change : 1;
|
||||||
|
/// Port 1 Link Status
|
||||||
|
pub p1_link_status, _ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
/// Config0 Register bits
|
||||||
|
pub struct Config0(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
/// Configuration Synchronization
|
||||||
|
pub sync, set_sync : 15;
|
||||||
|
/// Transmit Frame Check Sequence Validation Enable
|
||||||
|
pub txfcsve, set_txfcsve : 14;
|
||||||
|
/// !CS Align Receive Frame Enable
|
||||||
|
pub csarfe, set_csarfe : 13;
|
||||||
|
/// Zero Align Receive Frame Enable
|
||||||
|
pub zarfe, set_zarfe : 12;
|
||||||
|
/// Transmit Credit Threshold
|
||||||
|
pub tcxthresh, set_tcxthresh : 11, 10;
|
||||||
|
/// Transmit Cut Through Enable
|
||||||
|
pub txcte, set_txcte : 9;
|
||||||
|
/// Receive Cut Through Enable
|
||||||
|
pub rxcte, set_rxcte : 8;
|
||||||
|
/// Frame Time Stamp Enable
|
||||||
|
pub ftse, set_ftse : 7;
|
||||||
|
/// Receive Frame Time Stamp Select
|
||||||
|
pub ftss, set_ftss : 6;
|
||||||
|
/// Enable Control Data Read Write Protection
|
||||||
|
pub prote, set_prote : 5;
|
||||||
|
/// Enable TX Data Chunk Sequence and Retry
|
||||||
|
pub seqe, set_seqe : 4;
|
||||||
|
/// Chunk Payload Selector (N).
|
||||||
|
pub cps, set_cps : 2, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
/// Config2 Register bits
|
||||||
|
pub struct Config2(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
/// Assert TX_RDY When the Tx FIFO is Empty
|
||||||
|
pub tx_rdy_on_empty, set_tx_rdy_on_empty : 8;
|
||||||
|
/// Determines If the SFD is Detected in the PHY or MAC
|
||||||
|
pub sdf_detect_src, set_sdf_detect_src : 7;
|
||||||
|
/// Statistics Clear on Reading
|
||||||
|
pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
|
||||||
|
/// Enable CRC Append
|
||||||
|
pub crc_append, set_crc_append : 5;
|
||||||
|
/// Admit Frames with IFG Errors on Port 1 (P1)
|
||||||
|
pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;
|
||||||
|
/// Forward Frames Not Matching Any MAC Address to the Host
|
||||||
|
pub p1_fwd_unk2host, set_p1_fwd_unk2host : 2;
|
||||||
|
/// SPI to MDIO Bridge MDC Clock Speed
|
||||||
|
pub mspeed, set_mspeed : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
/// IMASK0 Register bits
|
||||||
|
pub struct IMask0(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
/// Control Data Protection Error Mask
|
||||||
|
pub cppem, set_cppem : 12;
|
||||||
|
/// Transmit Frame Check Sequence Error Mask
|
||||||
|
pub txfcsem, set_txfcsem : 11;
|
||||||
|
/// Transmit Time Stamp Capture Available C Mask
|
||||||
|
pub ttscacm, set_ttscacm : 10;
|
||||||
|
/// Transmit Time Stamp Capture Available B Mask
|
||||||
|
pub ttscabm, set_ttscabm : 9;
|
||||||
|
/// Transmit Time Stamp Capture Available A Mask
|
||||||
|
pub ttscaam, set_ttscaam : 8;
|
||||||
|
/// Physical Layer Interrupt Mask
|
||||||
|
pub phyintm, set_phyintm : 7;
|
||||||
|
/// RESET Complete Mask
|
||||||
|
pub resetcm, set_resetcm : 6;
|
||||||
|
/// Header Error Mask
|
||||||
|
pub hdrem, set_hdrem : 5;
|
||||||
|
/// Loss of Frame Error Mask
|
||||||
|
pub lofem, set_lofem : 4;
|
||||||
|
/// Receive Buffer Overflow Error Mask
|
||||||
|
pub rxboem, set_rxboem : 3;
|
||||||
|
/// Transmit Buffer Underflow Error Mask
|
||||||
|
pub txbuem, set_txbuem : 2;
|
||||||
|
/// Transmit Buffer Overflow Error Mask
|
||||||
|
pub txboem, set_txboem : 1;
|
||||||
|
/// Transmit Protocol Error Mask
|
||||||
|
pub txpem, set_txpem : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
/// IMASK1 Register bits
|
||||||
|
pub struct IMask1(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
/// Mask Bit for TXF_ECC_ERR
|
||||||
|
pub tx_ecc_err_mask, set_tx_ecc_err_mask : 12;
|
||||||
|
/// Mask Bit for RXF_ECC_ERR
|
||||||
|
pub rx_ecc_err_mask, set_rx_ecc_err_mask : 11;
|
||||||
|
/// Mask Bit for SPI_ERR
|
||||||
|
/// This field is only used with the generic SPI protocol
|
||||||
|
pub spi_err_mask, set_spi_err_mask : 10;
|
||||||
|
/// Mask Bit for RX_IFG_ERR
|
||||||
|
pub p1_rx_ifg_err_mask, set_p1_rx_ifg_err_mask : 8;
|
||||||
|
/// Mask Bit for P1_RX_RDY
|
||||||
|
/// This field is only used with the generic SPI protocol
|
||||||
|
pub p1_rx_rdy_mask, set_p1_rx_rdy_mask : 4;
|
||||||
|
/// Mask Bit for TX_FRM_DONE
|
||||||
|
/// This field is only used with the generic SPI protocol
|
||||||
|
pub tx_rdy_mask, set_tx_rdy_mask : 3;
|
||||||
|
/// Mask Bit for LINK_CHANGE
|
||||||
|
pub link_change_mask, set_link_change_mask : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum LedFunc {
|
||||||
|
LinkupTxRxActicity = 0,
|
||||||
|
LinkupTxActicity,
|
||||||
|
LinkupRxActicity,
|
||||||
|
LinkupOnly,
|
||||||
|
TxRxActivity,
|
||||||
|
TxActivity,
|
||||||
|
RxActivity,
|
||||||
|
LinkupRxEr,
|
||||||
|
LinkupRxTxEr,
|
||||||
|
RxEr,
|
||||||
|
RxTxEr,
|
||||||
|
TxSop,
|
||||||
|
RxSop,
|
||||||
|
On,
|
||||||
|
Off,
|
||||||
|
Blink,
|
||||||
|
TxLevel2P4,
|
||||||
|
TxLevel1P0,
|
||||||
|
Master,
|
||||||
|
Slave,
|
||||||
|
IncompatiableLinkCfg,
|
||||||
|
AnLinkGood,
|
||||||
|
AnComplete,
|
||||||
|
TsTimer,
|
||||||
|
LocRcvrStatus,
|
||||||
|
RemRcvrStatus,
|
||||||
|
Clk25Ref,
|
||||||
|
TxTCLK,
|
||||||
|
Clk120MHz,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LedFunc> for u8 {
|
||||||
|
fn from(val: LedFunc) -> Self {
|
||||||
|
val as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for LedFunc {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => LedFunc::LinkupTxRxActicity,
|
||||||
|
1 => LedFunc::LinkupTxActicity,
|
||||||
|
2 => LedFunc::LinkupRxActicity,
|
||||||
|
3 => LedFunc::LinkupOnly,
|
||||||
|
4 => LedFunc::TxRxActivity,
|
||||||
|
5 => LedFunc::TxActivity,
|
||||||
|
6 => LedFunc::RxActivity,
|
||||||
|
7 => LedFunc::LinkupRxEr,
|
||||||
|
8 => LedFunc::LinkupRxTxEr,
|
||||||
|
9 => LedFunc::RxEr,
|
||||||
|
10 => LedFunc::RxTxEr,
|
||||||
|
11 => LedFunc::TxSop,
|
||||||
|
12 => LedFunc::RxSop,
|
||||||
|
13 => LedFunc::On,
|
||||||
|
14 => LedFunc::Off,
|
||||||
|
15 => LedFunc::Blink,
|
||||||
|
16 => LedFunc::TxLevel2P4,
|
||||||
|
17 => LedFunc::TxLevel1P0,
|
||||||
|
18 => LedFunc::Master,
|
||||||
|
19 => LedFunc::Slave,
|
||||||
|
20 => LedFunc::IncompatiableLinkCfg,
|
||||||
|
21 => LedFunc::AnLinkGood,
|
||||||
|
22 => LedFunc::AnComplete,
|
||||||
|
23 => LedFunc::TsTimer,
|
||||||
|
24 => LedFunc::LocRcvrStatus,
|
||||||
|
25 => LedFunc::RemRcvrStatus,
|
||||||
|
26 => LedFunc::Clk25Ref,
|
||||||
|
27 => LedFunc::TxTCLK,
|
||||||
|
28 => LedFunc::Clk120MHz,
|
||||||
|
e => panic!("Invalid value {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// LED Control Register
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct LedCntrl(pub u16);
|
||||||
|
bitfield_bitrange! {struct LedCntrl(u16)}
|
||||||
|
|
||||||
|
impl LedCntrl {
|
||||||
|
bitfield_fields! {
|
||||||
|
u8;
|
||||||
|
/// LED_0 Pin Function
|
||||||
|
pub from into LedFunc, led0_function, set_led0_function: 4, 0;
|
||||||
|
/// LED 0 Mode Selection
|
||||||
|
pub led0_mode, set_led0_mode: 5;
|
||||||
|
/// Qualify Certain LED 0 Options with Link Status.
|
||||||
|
pub led0_link_st_qualify, set_led0_link_st_qualify: 6;
|
||||||
|
/// LED 0 Enable
|
||||||
|
pub led0_en, set_led0_en: 7;
|
||||||
|
/// LED_1 Pin Function
|
||||||
|
pub from into LedFunc, led1_function, set_led1_function: 12, 8;
|
||||||
|
/// /// LED 1 Mode Selection
|
||||||
|
pub led1_mode, set_led1_mode: 13;
|
||||||
|
/// Qualify Certain LED 1 Options with Link Status.
|
||||||
|
pub led1_link_st_qualify, set_led1_link_st_qualify: 14;
|
||||||
|
/// LED 1 Enable
|
||||||
|
pub led1_en, set_led1_en: 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
LedCntrl(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[allow(dead_code)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum LedPol {
|
||||||
|
AutoSense = 0,
|
||||||
|
ActiveHigh,
|
||||||
|
ActiveLow,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LedPol> for u8 {
|
||||||
|
fn from(val: LedPol) -> Self {
|
||||||
|
val as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for LedPol {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => LedPol::AutoSense,
|
||||||
|
1 => LedPol::ActiveHigh,
|
||||||
|
2 => LedPol::ActiveLow,
|
||||||
|
e => panic!("Invalid value {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// LED Control Register
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct LedPolarity(pub u16);
|
||||||
|
bitfield_bitrange! {struct LedPolarity(u16)}
|
||||||
|
|
||||||
|
impl LedPolarity {
|
||||||
|
bitfield_fields! {
|
||||||
|
u8;
|
||||||
|
/// LED 1 Polarity
|
||||||
|
pub from into LedPol, led1_polarity, set_led1_polarity: 3, 2;
|
||||||
|
/// LED_0 Polarity
|
||||||
|
pub from into LedPol, led0_polarity, set_led0_polarity: 1, 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// LED Control Register
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SpiHeader(pub u16);
|
||||||
|
bitfield_bitrange! {struct SpiHeader(u16)}
|
||||||
|
|
||||||
|
impl SpiHeader {
|
||||||
|
bitfield_fields! {
|
||||||
|
u16;
|
||||||
|
/// Mask Bit for TXF_ECC_ERR
|
||||||
|
pub control, set_control : 15;
|
||||||
|
pub full_duplex, set_full_duplex : 14;
|
||||||
|
pub write, set_write : 13;
|
||||||
|
/// LED_0 Polarity
|
||||||
|
pub from into SpiRegisters, addr, set_addr: 11, 0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user