Add packet TX

pull/3/head
Harry Ho 2020-06-17 18:26:48 +08:00
parent 9b48a585cf
commit 82f4bef09f
4 changed files with 227 additions and 67 deletions

View File

@ -12,93 +12,107 @@ use stm32f4xx_hal::{
}; };
pub mod rx; pub mod rx;
pub mod tx;
#[cfg(feature="smoltcp")] #[cfg(feature="smoltcp")]
pub mod smoltcp_phy; pub mod smoltcp_phy;
pub trait EthController { pub trait EthController {
fn init_dev(&mut self) -> Result<(), EthControllerError>; fn init_dev(&mut self) -> Result<(), EthControllerError>;
fn init_rxbuf(&mut self) -> Result<(), EthControllerError>; fn init_rxbuf(&mut self) -> Result<(), EthControllerError>;
fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError>; // TODO:
fn set_promiscuous(&mut self) -> Result<(), EthControllerError>; fn init_txbuf(&mut self) -> Result<(), EthControllerError>;
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError>; fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError>;
// TODO: send_packet() is not using TxBuffer, but it should later on
fn send_raw_packet(&mut self, packet: tx::TxPacket) -> Result<(), EthControllerError>;
fn set_promiscuous(&mut self) -> Result<(), EthControllerError>;
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError>;
} }
/// TODO: Improve these error types /// TODO: Improve these error types
pub enum EthControllerError { pub enum EthControllerError {
SpiPortError, SpiPortError,
GeneralError GeneralError
} }
impl From<spi::SpiPortError> for EthControllerError { impl From<spi::SpiPortError> for EthControllerError {
fn from(e: spi::SpiPortError) -> EthControllerError { fn from(e: spi::SpiPortError) -> EthControllerError {
EthControllerError::SpiPortError EthControllerError::SpiPortError
} }
} }
/// Ethernet controller using SPI interface /// Ethernet controller using SPI interface
pub struct SpiEth<SPI: Transfer<u8>, pub struct SpiEth<SPI: Transfer<u8>,
NSS: OutputPin> { NSS: OutputPin> {
spi_port: spi::SpiPort<SPI, NSS>, spi_port: spi::SpiPort<SPI, NSS>,
rx_buf: rx::RxBuffer rx_buf: rx::RxBuffer,
tx_buf: tx::TxBuffer
} }
impl <SPI: Transfer<u8>, impl <SPI: Transfer<u8>,
NSS: OutputPin> SpiEth<SPI, NSS> { NSS: OutputPin> SpiEth<SPI, NSS> {
pub fn new(spi: SPI, mut nss: NSS) -> Self { pub fn new(spi: SPI, mut nss: NSS) -> Self {
SpiEth { SpiEth {
spi_port: spi::SpiPort::new(spi, nss), spi_port: spi::SpiPort::new(spi, nss),
rx_buf: rx::RxBuffer::new(), rx_buf: rx::RxBuffer::new(),
// TODO: tx_buf // TODO: tx_buf
} tx_buf: tx::TxBuffer::new()
}
} }
} }
impl <SPI: Transfer<u8>, impl <SPI: Transfer<u8>,
NSS: OutputPin> EthController for SpiEth<SPI, NSS> { NSS: OutputPin> EthController for SpiEth<SPI, NSS> {
fn init_dev(&mut self) -> Result<(), EthControllerError> { fn init_dev(&mut self) -> Result<(), EthControllerError> {
// Write 0x1234 to EUDAST // Write 0x1234 to EUDAST
self.spi_port.write_reg_16b(spi::EUDAST, 0x1234)?; self.spi_port.write_reg_16b(spi::EUDAST, 0x1234)?;
// Verify that EUDAST is 0x1234 // Verify that EUDAST is 0x1234
let mut eudast = self.spi_port.read_reg_16b(spi::EUDAST)?; let mut eudast = self.spi_port.read_reg_16b(spi::EUDAST)?;
if eudast != 0x1234 { if eudast != 0x1234 {
return Err(EthControllerError::GeneralError) return Err(EthControllerError::GeneralError)
} }
// Poll CLKRDY (ESTAT<12>) to check if it is set // Poll CLKRDY (ESTAT<12>) to check if it is set
loop { loop {
let estat = self.spi_port.read_reg_16b(spi::ESTAT)?; let estat = self.spi_port.read_reg_16b(spi::ESTAT)?;
if estat & 0x1000 == 0x1000 { break } if estat & 0x1000 == 0x1000 { break }
} }
// Set ETHRST (ECON2<4>) to 1 // Set ETHRST (ECON2<4>) to 1
let econ2 = self.spi_port.read_reg_8b(spi::ECON2)?; let econ2 = self.spi_port.read_reg_8b(spi::ECON2)?;
self.spi_port.write_reg_8b(spi::ECON2, 0x10 | (econ2 & 0b11101111))?; self.spi_port.write_reg_8b(spi::ECON2, 0x10 | (econ2 & 0b11101111))?;
// Verify that EUDAST is 0x0000 // Verify that EUDAST is 0x0000
eudast = self.spi_port.read_reg_16b(spi::EUDAST)?; eudast = self.spi_port.read_reg_16b(spi::EUDAST)?;
if eudast != 0x0000 { if eudast != 0x0000 {
return Err(EthControllerError::GeneralError) return Err(EthControllerError::GeneralError)
} }
Ok(()) Ok(())
} }
fn init_rxbuf(&mut self) -> Result<(), EthControllerError> { fn init_rxbuf(&mut self) -> Result<(), EthControllerError> {
// Set ERXST pointer // Set ERXST pointer
self.spi_port.write_reg_16b(spi::ERXST, self.rx_buf.get_wrap_addr()); self.spi_port.write_reg_16b(spi::ERXST, self.rx_buf.get_wrap_addr())?;
// Set ERXTAIL pointer // Set ERXTAIL pointer
self.spi_port.write_reg_16b(spi::ERXTAIL, self.rx_buf.get_tail_addr()); 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 // 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); self.spi_port.write_reg_16b(spi::MAMXFL, rx::RAW_FRAME_LENGTH_MAX as u16)?;
// Enable RXEN (ECON1<0>) // Enable RXEN (ECON1<0>)
let econ1 = self.spi_port.read_reg_16b(spi::ECON1)?; let econ1 = self.spi_port.read_reg_16b(spi::ECON1)?;
self.spi_port.write_reg_16b(spi::ECON1, 0x1 | (econ1 & 0xfffe)); self.spi_port.write_reg_16b(spi::ECON1, 0x1 | (econ1 & 0xfffe));
Ok(()) Ok(())
} }
/// TODO:
fn init_txbuf(&mut self) -> Result<(), EthControllerError> {
// Set EGPWRPT pointer
self.spi_port.write_reg_16b(spi::EGPWRPT, 0x0000)?;
Ok(())
}
/// Receive the next packet /// Receive the next packet
fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError> { fn receive_next(&mut self) -> Result<rx::RxPacket, EthControllerError> {
// Poll PKTIF (EIR<4>) to check if it is set // Poll PKTIF (EIR<4>) to check if it is set
loop { loop {
let eir = self.spi_port.read_reg_16b(spi::EIR)?; let eir = self.spi_port.read_reg_16b(spi::EIR)?;
if eir & 0x40 == 0x40 { break } if eir & 0x40 == 0x40 { break }
} }
// Set ERXRDPT pointer to next_addr // Set ERXRDPT pointer to next_addr
self.spi_port.write_reg_16b(spi::ERXRDPT, self.rx_buf.get_next_addr())?; self.spi_port.write_reg_16b(spi::ERXRDPT, self.rx_buf.get_next_addr())?;
@ -125,31 +139,60 @@ impl <SPI: Transfer<u8>,
} else { } else {
self.spi_port.write_reg_16b(spi::ERXTAIL, rx::RX_MAX_ADDRESS - 1)?; self.spi_port.write_reg_16b(spi::ERXTAIL, rx::RX_MAX_ADDRESS - 1)?;
} }
// Set PKTDEC to decrement PKTCNT // Set PKTDEC (ECON1<88>) to decrement PKTCNT
let econ1_hi = self.spi_port.read_reg_8b(spi::ECON1 + 1)?; 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))?; self.spi_port.write_reg_8b(spi::ECON1 + 1, 0x01 | (econ1_hi & 0xfe))?;
// Return the RxPacket // Return the RxPacket
Ok(rx_packet) Ok(rx_packet)
} }
/// Send an established packet
/// TODO: Should be eliminated when TxBuffer is used instead later on
fn send_raw_packet(&mut self, packet: tx::TxPacket) -> Result<(), EthControllerError> {
// Set EGPWRPT pointer to next_addr
self.spi_port.write_reg_16b(spi::EGPWRPT, self.tx_buf.get_next_addr())?;
// Copy packet data to SRAM Buffer
// 1-byte Opcode is included
let mut txdat_buf: [u8; tx::RAW_FRAME_LENGTH_MAX + 1] = [0; tx::RAW_FRAME_LENGTH_MAX + 1];
packet.copy_from_frame(&mut txdat_buf[1..]);
self.spi_port.write_txdat(&mut txdat_buf, packet.get_frame_length() as u32)?;
// Set ETXST to packet start address
self.spi_port.write_reg_16b(spi::ETXST, self.tx_buf.get_next_addr())?;
// Set ETXLEN to packet length
self.spi_port.write_reg_16b(spi::ETXLEN, packet.get_frame_length() as u16)?;
// Set TXRTS (ECON1<1>) to start transmission
let mut econ1_lo = self.spi_port.read_reg_8b(spi::ECON1)?;
self.spi_port.write_reg_8b(spi::ECON1, 0x02 | (econ1_lo & 0xfd))?;
// Poll TXRTS (ECON1<1>) to check if it is reset
loop {
econ1_lo = self.spi_port.read_reg_8b(spi::ECON1)?;
if econ1_lo & 0x02 == 0x02 { break }
}
// TODO: Read ETXSTAT
// Update TX buffer start address
self.tx_buf.set_next_addr((self.tx_buf.get_next_addr() + packet.get_frame_length() as u16) %
tx::GPBUFEN_DEFAULT);
Ok(())
}
/// Set controller to Promiscuous Mode /// Set controller to Promiscuous Mode
fn set_promiscuous(&mut self) -> Result<(), EthControllerError> { fn set_promiscuous(&mut self) -> Result<(), EthControllerError> {
// From ENC424J600 Data Sheet Section 10.12: // From ENC424J600 Data Sheet Section 10.12:
// "To accept all incoming frames regardless of content (Promiscuous mode), // "To accept all incoming frames regardless of content (Promiscuous mode),
// set the CRCEN, RUNTEN, UCEN, NOTMEEN and MCEN bits." // set the CRCEN, RUNTEN, UCEN, NOTMEEN and MCEN bits."
let mut erxfcon_lo = self.spi_port.read_reg_8b(spi::ERXFCON)?; 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)); self.spi_port.write_reg_8b(spi::ERXFCON, 0b0101_1110 | (erxfcon_lo & 0b1010_0001));
Ok(()) Ok(())
} }
/// Read MAC to [u8; 6] /// Read MAC to [u8; 6]
fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError> { fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError> {
mac[0] = self.spi_port.read_reg_8b(spi::MAADR1)?; mac[0] = self.spi_port.read_reg_8b(spi::MAADR1)?;
mac[1] = self.spi_port.read_reg_8b(spi::MAADR1 + 1)?; mac[1] = self.spi_port.read_reg_8b(spi::MAADR1 + 1)?;
mac[2] = self.spi_port.read_reg_8b(spi::MAADR2)?; mac[2] = self.spi_port.read_reg_8b(spi::MAADR2)?;
mac[3] = self.spi_port.read_reg_8b(spi::MAADR2 + 1)?; mac[3] = self.spi_port.read_reg_8b(spi::MAADR2 + 1)?;
mac[4] = self.spi_port.read_reg_8b(spi::MAADR3)?; mac[4] = self.spi_port.read_reg_8b(spi::MAADR3)?;
mac[5] = self.spi_port.read_reg_8b(spi::MAADR3 + 1)?; mac[5] = self.spi_port.read_reg_8b(spi::MAADR3 + 1)?;
Ok(()) Ok(())
} }
} }

View File

@ -86,6 +86,7 @@ impl RxPacket {
} }
} }
/// TODO: Mostly for debugging only?
pub fn get_frame_byte(&self, i: usize) -> u8 { pub fn get_frame_byte(&self, i: usize) -> u8 {
self.frame[i] self.frame[i]
} }

View File

@ -23,7 +23,8 @@ pub const SPI_CLOCK: MegaHertz = MegaHertz(14);
/// SPI Opcodes /// SPI Opcodes
const RCRU: u8 = 0b0010_0000; const RCRU: u8 = 0b0010_0000;
const WCRU: u8 = 0b0010_0010; const WCRU: u8 = 0b0010_0010;
const ERXDATA: u8 = 0b0010_1100; // Treated as 8-bit opcode followed by data const RERXDATA: u8 = 0b0010_1100; // 8-bit opcode followed by data
const WEGPDATA: u8 = 0b0010_1010; // 8-bit opcode followed by data
/// SPI Register Mapping /// SPI Register Mapping
/// Note: PSP interface use different address mapping /// Note: PSP interface use different address mapping
@ -44,6 +45,11 @@ pub const ERXTAIL: u8 = 0x06; // 16-bit data
pub const EIR: u8 = 0x1c; // 16-bit data pub const EIR: u8 = 0x1c; // 16-bit data
pub const ECON1: u8 = 0x1e; // 16-bit data pub const ECON1: u8 = 0x1e; // 16-bit data
pub const MAMXFL: u8 = 0x4a; // 16-bit data pub const MAMXFL: u8 = 0x4a; // 16-bit data
// TX Registers
pub const EGPWRPT: u8 = 0x88; // 16-bit data
pub const ETXST: u8 = 0x00; // 16-bit data
pub const ETXSTAT: u8 = 0x12; // 16-bit data
pub const ETXLEN: u8 = 0x02; // 16-bit data
/// Struct for SPI I/O interface on ENC424J600 /// Struct for SPI I/O interface on ENC424J600
/// Note: stm32f4xx_hal::spi's pins include: SCK, MISO, MOSI /// Note: stm32f4xx_hal::spi's pins include: SCK, MISO, MOSI
@ -82,13 +88,21 @@ impl <SPI: Transfer<u8>,
Ok(((r_data_hi as u16) << 8) | r_data_lo as u16) Ok(((r_data_hi as u16) << 8) | r_data_lo as u16)
} }
// Currently requires manual slicing (buf[1:]) for the data read back // Currently requires manual slicing (buf[1..]) for the data read back
pub fn read_rxdat<'a>(&mut self, buf: &'a mut [u8], data_length: u32) pub fn read_rxdat<'a>(&mut self, buf: &'a mut [u8], data_length: u32)
-> Result<u8, SpiPortError> { -> Result<(), SpiPortError> {
let r_valid = self.r_n(buf, ERXDATA, data_length)?; let r_valid = self.r_n(buf, RERXDATA, data_length)?;
Ok(r_valid) Ok(r_valid)
} }
// Currenly requires actual data to be stored in buf[1..] instead of buf[0..]
// TODO: Maybe better naming?
pub fn write_txdat<'a>(&mut self, buf: &'a mut [u8], data_length: u32)
-> Result<(), SpiPortError> {
let w_valid = self.w_n(buf, WEGPDATA, data_length)?;
Ok(w_valid)
}
pub fn write_reg_8b(&mut self, addr: u8, data: u8) -> Result<(), SpiPortError> { pub fn write_reg_8b(&mut self, addr: u8, data: u8) -> Result<(), SpiPortError> {
// TODO: addr should be separated from w_data // TODO: addr should be separated from w_data
// Using WCRU instruction to write using unbanked (full) address // Using WCRU instruction to write using unbanked (full) address
@ -136,17 +150,40 @@ impl <SPI: Transfer<u8>,
// Note: buf must be at least (data_length + 1)-byte long // Note: buf must be at least (data_length + 1)-byte long
// TODO: Check and raise error for array size < (data_length + 1) // TODO: Check and raise error for array size < (data_length + 1)
fn r_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: u32) fn r_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: u32)
-> Result<u8, SpiPortError> { -> Result<(), SpiPortError> {
// Enable chip select // Enable chip select
self.nss.set_low(); self.nss.set_low();
// Start writing to SLAVE // Start writing to SLAVE
buf[0] = opcode; buf[0] = opcode;
match self.spi.transfer(buf) { match self.spi.transfer(buf) {
// TODO: Now returns a boolean, maybe use Option<u8> later on?
Ok(_) => { Ok(_) => {
// Disable chip select // Disable chip select
self.nss.set_high(); self.nss.set_high();
Ok(1) Ok(())
},
// TODO: Maybe too naive?
Err(e) => {
// Disable chip select
self.nss.set_high();
Err(SpiPortError::TransferError)
}
}
}
// Note: buf[0] is currently reserved for opcode to overwrite
// TODO: Actual data should start from buf[0], not buf[1]
fn w_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: u32)
-> Result<(), SpiPortError> {
// Enable chip select
self.nss.set_low();
// Start writing to SLAVE
buf[0] = opcode;
// TODO: Maybe need to copy data to buf later on
match self.spi.transfer(buf) {
Ok(_) => {
// Disable chip select
self.nss.set_high();
Ok(())
}, },
// TODO: Maybe too naive? // TODO: Maybe too naive?
Err(e) => { Err(e) => {

79
src/tx.rs Normal file
View File

@ -0,0 +1,79 @@
/// SRAM Addresses
pub const GPBUFST_DEFAULT: u16 = 0x0000; // Start of General-Purpose SRAM Buffer
pub const GPBUFEN_DEFAULT: u16 = 0x5340; // End of General-Purpose SRAM Buffer == ERXST default
/// Max raw frame array size
pub const RAW_FRAME_LENGTH_MAX: usize = 0x1000;
/// Struct for TX Buffer
/// TODO: Should be a singleton
pub struct TxBuffer {
wrap_addr: u16,
// The following two fields are controlled by firmware
next_addr: u16,
tail_addr: u16
}
impl TxBuffer {
pub fn new() -> Self {
TxBuffer {
wrap_addr: GPBUFST_DEFAULT,
next_addr: GPBUFST_DEFAULT + 1,
tail_addr: GPBUFST_DEFAULT
}
}
pub fn set_wrap_addr(&mut self, addr: u16) {
self.wrap_addr = addr;
}
pub fn get_wrap_addr(& self) -> u16{
self.wrap_addr
}
pub fn set_next_addr(&mut self, addr: u16) {
self.next_addr = addr;
}
pub fn get_next_addr(& self) -> u16{
self.next_addr
}
// TODO: Need more functions for smoltcp::phy compatibility (maybe?)
}
/// Struct for TX Packet
/// TODO: Generalise MAC addresses
pub struct TxPacket {
frame: [u8; RAW_FRAME_LENGTH_MAX],
frame_length: usize
}
impl TxPacket {
pub fn new() -> Self {
TxPacket {
frame: [0; RAW_FRAME_LENGTH_MAX],
frame_length: 0
}
}
/// Currently, frame data is copied from an external buffer
pub fn update_frame(&mut self, raw_frame: &[u8], raw_frame_length: usize) {
self.frame_length = raw_frame_length;
for i in 0..self.frame_length {
self.frame[i] = raw_frame[i];
}
}
pub fn copy_from_frame(&self, frame: &mut [u8]) {
for i in 0..self.frame_length {
frame[i] = self.frame[i];
}
}
pub fn get_frame_length(&self) -> usize {
self.frame_length
}
/// TODO: Mostly for debugging only?
pub fn get_frame_byte(&self, i: usize) -> u8 {
self.frame[i]
}
}