2020-06-15 15:40:39 +08:00
|
|
|
#![no_std]
|
|
|
|
|
2020-06-16 17:34:16 +08:00
|
|
|
use core::fmt;
|
|
|
|
|
2020-06-15 15:40:39 +08:00
|
|
|
/// STM32F4xx-HAL specific implementations
|
|
|
|
pub mod spi;
|
2020-06-16 17:34:16 +08:00
|
|
|
use stm32f4xx_hal::{
|
|
|
|
hal::{
|
|
|
|
blocking::spi::Transfer,
|
|
|
|
digital::v2::OutputPin,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pub mod rx;
|
|
|
|
|
|
|
|
#[cfg(feature="smoltcp")]
|
|
|
|
pub mod smoltcp_phy;
|
|
|
|
|
|
|
|
pub trait EthController {
|
|
|
|
fn init_dev(&mut self) -> Result<(), EthControllerError>;
|
|
|
|
fn init_rxbuf(&mut self) -> Result<(), EthControllerError>;
|
|
|
|
fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError>;
|
|
|
|
fn set_promiscuous(&mut self) -> Result<(), EthControllerError>;
|
|
|
|
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// TODO: Improve these error types
|
|
|
|
pub enum EthControllerError {
|
|
|
|
SpiPortError,
|
|
|
|
GeneralError
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<spi::SpiPortError> for EthControllerError {
|
|
|
|
fn from(e: spi::SpiPortError) -> EthControllerError {
|
|
|
|
EthControllerError::SpiPortError
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Ethernet controller using SPI interface
|
|
|
|
pub struct SpiEth<SPI: Transfer<u8>,
|
|
|
|
NSS: OutputPin> {
|
|
|
|
spi_port: spi::SpiPort<SPI, NSS>,
|
|
|
|
rx_buf: rx::RxBuffer
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <SPI: Transfer<u8>,
|
|
|
|
NSS: OutputPin> SpiEth<SPI, NSS> {
|
|
|
|
pub fn new(spi: SPI, mut nss: NSS) -> Self {
|
|
|
|
SpiEth {
|
|
|
|
spi_port: spi::SpiPort::new(spi, nss),
|
|
|
|
rx_buf: rx::RxBuffer::new(),
|
|
|
|
// TODO: tx_buf
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <SPI: Transfer<u8>,
|
|
|
|
NSS: OutputPin> EthController for SpiEth<SPI, NSS> {
|
|
|
|
fn init_dev(&mut self) -> Result<(), EthControllerError> {
|
|
|
|
// Write 0x1234 to EUDAST
|
|
|
|
self.spi_port.write_reg_16b(spi::EUDAST, 0x1234)?;
|
|
|
|
// Verify that EUDAST is 0x1234
|
|
|
|
let mut eudast = self.spi_port.read_reg_16b(spi::EUDAST)?;
|
|
|
|
if eudast != 0x1234 {
|
|
|
|
return Err(EthControllerError::GeneralError)
|
|
|
|
}
|
|
|
|
// Poll CLKRDY (ESTAT<12>) to check if it is set
|
|
|
|
loop {
|
|
|
|
let estat = self.spi_port.read_reg_16b(spi::ESTAT)?;
|
|
|
|
if estat & 0x1000 == 0x1000 { break }
|
|
|
|
}
|
|
|
|
// Set ETHRST (ECON2<4>) to 1
|
|
|
|
let econ2 = self.spi_port.read_reg_8b(spi::ECON2)?;
|
|
|
|
self.spi_port.write_reg_8b(spi::ECON2, 0x10 | (econ2 & 0b11101111))?;
|
|
|
|
// Verify that EUDAST is 0x0000
|
|
|
|
eudast = self.spi_port.read_reg_16b(spi::EUDAST)?;
|
|
|
|
if eudast != 0x0000 {
|
|
|
|
return Err(EthControllerError::GeneralError)
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init_rxbuf(&mut self) -> Result<(), EthControllerError> {
|
|
|
|
// Set ERXST pointer
|
|
|
|
self.spi_port.write_reg_16b(spi::ERXST, self.rx_buf.get_wrap_addr());
|
|
|
|
// Set ERXTAIL pointer
|
|
|
|
self.spi_port.write_reg_16b(spi::ERXTAIL, self.rx_buf.get_tail_addr());
|
|
|
|
// Set MAMXFL to maximum number of bytes in each accepted packet
|
|
|
|
self.spi_port.write_reg_16b(spi::MAMXFL, rx::RAW_FRAME_LENGTH_MAX as u16);
|
|
|
|
// Enable RXEN (ECON1<0>)
|
|
|
|
let econ1 = self.spi_port.read_reg_16b(spi::ECON1)?;
|
|
|
|
self.spi_port.write_reg_16b(spi::ECON1, 0x1 | (econ1 & 0xfffe));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Receive the next packet
|
|
|
|
fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError> {
|
|
|
|
// Poll PKTIF (EIR<4>) to check if it is set
|
|
|
|
loop {
|
|
|
|
let eir = self.spi_port.read_reg_16b(spi::EIR)?;
|
|
|
|
if eir & 0x40 == 0x40 { break }
|
|
|
|
}
|
|
|
|
// Set ERXRDPT pointer to next_addr
|
|
|
|
self.spi_port.write_reg_16b(spi::ERXRDPT, self.rx_buf.get_next_addr())?;
|
|
|
|
// Read 2 bytes to update next_addr
|
|
|
|
let mut next_addr_buf = [0; 3];
|
|
|
|
self.spi_port.read_rxdat(&mut next_addr_buf, 2)?;
|
|
|
|
self.rx_buf.set_next_addr((next_addr_buf[1] as u16) | ((next_addr_buf[2] as u16) << 8));
|
|
|
|
// Read 6 bytes to update rsv
|
|
|
|
let mut rsv_buf = [0; 7];
|
|
|
|
self.spi_port.read_rxdat(&mut rsv_buf, 6)?;
|
|
|
|
// Construct an RxPacket
|
|
|
|
// TODO: can we directly assign to fields instead of using functions?
|
|
|
|
let mut rx_packet = rx::RxPacket::new();
|
|
|
|
// Get and update frame length
|
|
|
|
rx_packet.write_to_rsv(&rsv_buf[1..]);
|
|
|
|
rx_packet.update_frame_length();
|
|
|
|
// Read frame bytes
|
|
|
|
let mut frame_buf = [0; rx::RAW_FRAME_LENGTH_MAX];
|
|
|
|
self.spi_port.read_rxdat(&mut frame_buf, rx_packet.get_frame_length() as u32)?;
|
|
|
|
rx_packet.write_to_frame(&frame_buf[1..]);
|
|
|
|
// Set ERXTAIL pointer to (next_addr - 2)
|
|
|
|
if self.rx_buf.get_next_addr() > rx::ERXST_DEFAULT {
|
|
|
|
self.spi_port.write_reg_16b(spi::ERXTAIL, self.rx_buf.get_next_addr() - 2)?;
|
|
|
|
} else {
|
|
|
|
self.spi_port.write_reg_16b(spi::ERXTAIL, rx::RX_MAX_ADDRESS - 1)?;
|
|
|
|
}
|
|
|
|
// Set PKTDEC to decrement PKTCNT
|
|
|
|
let econ1_hi = self.spi_port.read_reg_8b(spi::ECON1 + 1)?;
|
|
|
|
self.spi_port.write_reg_8b(spi::ECON1 + 1, 0x01 | (econ1_hi & 0xfe))?;
|
|
|
|
// Return the RxPacket
|
|
|
|
Ok(rx_packet)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set controller to Promiscuous Mode
|
|
|
|
fn set_promiscuous(&mut self) -> Result<(), EthControllerError> {
|
|
|
|
// From ENC424J600 Data Sheet Section 10.12:
|
|
|
|
// "To accept all incoming frames regardless of content (Promiscuous mode),
|
|
|
|
// set the CRCEN, RUNTEN, UCEN, NOTMEEN and MCEN bits."
|
|
|
|
let mut erxfcon_lo = self.spi_port.read_reg_8b(spi::ERXFCON)?;
|
|
|
|
self.spi_port.write_reg_8b(spi::ERXFCON, 0b0101_1110 | (erxfcon_lo & 0b1010_0001));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Read MAC to [u8; 6]
|
|
|
|
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError> {
|
|
|
|
mac[0] = self.spi_port.read_reg_8b(spi::MAADR1)?;
|
|
|
|
mac[1] = self.spi_port.read_reg_8b(spi::MAADR1 + 1)?;
|
|
|
|
mac[2] = self.spi_port.read_reg_8b(spi::MAADR2)?;
|
|
|
|
mac[3] = self.spi_port.read_reg_8b(spi::MAADR2 + 1)?;
|
|
|
|
mac[4] = self.spi_port.read_reg_8b(spi::MAADR3)?;
|
|
|
|
mac[5] = self.spi_port.read_reg_8b(spi::MAADR3 + 1)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|