diff --git a/src/lib.rs b/src/lib.rs index 2c56381..7ffe179 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,9 +81,8 @@ impl , let estat = self.spi_port.read_reg_16b(spi::addrs::ESTAT)?; if estat & 0x1000 == 0x1000 { break } } - // Set ETHRST (ECON2<4>) to 1 - let econ2 = self.spi_port.read_reg_8b(spi::addrs::ECON2)?; - self.spi_port.write_reg_8b(spi::addrs::ECON2, 0x10 | (econ2 & 0b11101111))?; + // Issue system reset - set ETHRST (ECON2<4>) to 1 + self.spi_port.send_opcode(spi::opcodes::SETETHRST)?; self.spi_port.delay_us(25); // Verify that EUDAST is 0x0000 eudast = self.spi_port.read_reg_16b(spi::addrs::EUDAST)?; @@ -101,9 +100,8 @@ impl , self.spi_port.write_reg_16b(spi::addrs::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::addrs::MAMXFL, RAW_FRAME_LENGTH_MAX as u16)?; - // Enable RXEN (ECON1<0>) - let econ1 = self.spi_port.read_reg_16b(spi::addrs::ECON1)?; - self.spi_port.write_reg_16b(spi::addrs::ECON1, 0x1 | (econ1 & 0xfffe))?; + // Enable RX - set RXEN (ECON1<0>) to 1 + self.spi_port.send_opcode(spi::opcodes::ENABLERX)?; Ok(()) } @@ -188,9 +186,8 @@ impl , } else { self.spi_port.write_reg_16b(spi::addrs::ERXTAIL, rx::RX_MAX_ADDRESS - 1)?; } - // Set PKTDEC (ECON1<88>) to decrement PKTCNT - let econ1_hi = self.spi_port.read_reg_8b(spi::addrs::ECON1 + 1)?; - self.spi_port.write_reg_8b(spi::addrs::ECON1 + 1, 0x01 | (econ1_hi & 0xfe))?; + // Decrement PKTCNT - set PKTDEC (ECON1<8>) + self.spi_port.send_opcode(spi::opcodes::SETPKTDEC)?; // Return the RxPacket Ok(rx_packet) } @@ -208,12 +205,11 @@ impl , self.spi_port.write_reg_16b(spi::addrs::ETXST, self.tx_buf.get_next_addr())?; // Set ETXLEN to packet length self.spi_port.write_reg_16b(spi::addrs::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::addrs::ECON1)?; - self.spi_port.write_reg_8b(spi::addrs::ECON1, 0x02 | (econ1_lo & 0xfd))?; + // Send packet - set TXRTS (ECON1<1>) to start transmission + self.spi_port.send_opcode(spi::opcodes::SETTXRTS)?; // Poll TXRTS (ECON1<1>) to check if it is reset loop { - econ1_lo = self.spi_port.read_reg_8b(spi::addrs::ECON1)?; + let econ1_lo = self.spi_port.read_reg_8b(spi::addrs::ECON1)?; if econ1_lo & 0x02 == 0 { break } } // TODO: Read ETXSTAT to understand Ethernet transmission status diff --git a/src/spi.rs b/src/spi.rs index 724dac9..169a525 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -15,7 +15,17 @@ pub mod interfaces { } pub mod opcodes { - /// SPI Opcodes + /// 1-byte Instructions + pub const SETETHRST: u8 = 0b1100_1010; + pub const SETPKTDEC: u8 = 0b1100_1100; + pub const SETTXRTS: u8 = 0b1101_0100; + pub const ENABLERX: u8 = 0b1110_1000; + /// 3-byte Instructions + pub const WRXRDPT: u8 = 0b0110_0100; // 8-bit opcode followed by data + pub const RRXRDPT: u8 = 0b0110_0110; // 8-bit opcode followed by data + pub const WGPWRPT: u8 = 0b0110_1100; // 8-bit opcode followed by data + pub const RGPWRPT: u8 = 0b0110_1110; // 8-bit opcode followed by data + /// N-byte Instructions pub const RCRU: u8 = 0b0010_0000; pub const WCRU: u8 = 0b0010_0010; pub const RRXDATA: u8 = 0b0010_1100; // 8-bit opcode followed by data @@ -60,6 +70,7 @@ pub struct SpiPort, } pub enum Error { + OpcodeError, TransferError } @@ -85,23 +96,38 @@ impl , } pub fn read_reg_16b(&mut self, lo_addr: u8) -> Result { - let r_data_lo = self.read_reg_8b(lo_addr)?; - let r_data_hi = self.read_reg_8b(lo_addr + 1)?; - // Combine top and bottom 8-bit to return 16-bit - Ok(((r_data_hi as u16) << 8) | r_data_lo as u16) + match lo_addr { + addrs::ERXRDPT | addrs::EGPWRPT => { + let mut buf: [u8; 3] = [0; 3]; + self.rw_n( + &mut buf, match lo_addr { + addrs::ERXRDPT => opcodes::RRXRDPT, + addrs::EGPWRPT => opcodes::RGPWRPT, + _ => unreachable!() + }, 2 + )?; + Ok((buf[2] as u16) << 8 | buf[1] as u16) + } + _ => { + let r_data_lo = self.read_reg_8b(lo_addr)?; + let r_data_hi = self.read_reg_8b(lo_addr + 1)?; + // Combine top and bottom 8-bit to return 16-bit + Ok(((r_data_hi as u16) << 8) | r_data_lo as u16) + } + } } // Currently requires manual slicing (buf[1..]) for the data read back pub fn read_rxdat<'a>(&mut self, buf: &'a mut [u8], data_length: usize) -> Result<(), Error> { - self.r_n(buf, opcodes::RRXDATA, data_length) + self.rw_n(buf, opcodes::RRXDATA, data_length) } // Currently 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: usize) -> Result<(), Error> { - self.w_n(buf, opcodes::WGPDATA, data_length) + self.rw_n(buf, opcodes::WGPDATA, data_length) } pub fn write_reg_8b(&mut self, addr: u8, data: u8) -> Result<(), Error> { @@ -112,9 +138,36 @@ impl , } pub fn write_reg_16b(&mut self, lo_addr: u8, data: u16) -> Result<(), Error> { - self.write_reg_8b(lo_addr, (data & 0xff) as u8)?; - self.write_reg_8b(lo_addr + 1, ((data & 0xff00) >> 8) as u8)?; - Ok(()) + match lo_addr { + addrs::ERXRDPT | addrs::EGPWRPT => { + let mut buf: [u8; 3] = [0; 3]; + buf[1] = data as u8 & 8; + buf[2] = (data >> 8) as u8 & 8; + self.rw_n( + &mut buf, match lo_addr { + addrs::ERXRDPT => opcodes::WRXRDPT, + addrs::EGPWRPT => opcodes::WGPWRPT, + _ => unreachable!() + }, 2 + ) + } + _ => { + self.write_reg_8b(lo_addr, (data & 0xff) as u8)?; + self.write_reg_8b(lo_addr + 1, ((data & 0xff00) >> 8) as u8)?; + Ok(()) + } + } + } + + pub fn send_opcode(&mut self, opcode: u8) -> Result<(), Error> { + match opcode { + opcodes::SETETHRST | opcodes::SETPKTDEC | + opcodes::SETTXRTS | opcodes::ENABLERX => { + let mut buf: [u8; 1] = [0]; + self.rw_n(&mut buf, opcode, 0) + } + _ => Err(Error::OpcodeError) + } } pub fn delay_us(&mut self, duration: u32) { @@ -122,8 +175,9 @@ impl , } // TODO: Generalise transfer functions - // TODO: (Make data read/write as reference to array) - // Currently requires 1-byte addr, read/write data is only 1-byte + // Completes an SPI transfer for reading or writing 8-bit data, + // and returns the data read/written. + // It starts with an 8-bit instruction, followed by an 8-bit address. fn rw_addr_u8(&mut self, opcode: u8, addr: u8, data: u8) -> Result { // Enable chip select @@ -154,40 +208,20 @@ impl , } // TODO: Generalise transfer functions - // Currently does NOT accept addr, read data is N-byte long - // Returns a reference to the data returned - // Note: buf must be at least (data_length + 1)-byte long - // 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: usize) - -> Result<(), Error> { - // Enable chip select - self.nss.set_low(); - // Start writing to SLAVE - buf[0] = opcode; - match self.spi.transfer(&mut buf[..data_length+1]) { - Ok(_) => { - // Disable chip select - self.nss.set_high(); - Ok(()) - }, - // TODO: Maybe too naive? - Err(_) => { - // Disable chip select - self.nss.set_high(); - Err(Error::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: usize) + // Completes an SPI transfer for reading data to the given buffer, + // or writing data from the buffer. + // It sends an 8-bit instruction, followed by either + // receiving or sending n*8-bit data. + // The slice of buffer provided must begin with the 8-bit instruction. + // If n = 0, the transfer will only involve sending the instruction. + fn rw_n<'a>(&mut self, buf: &'a mut [u8], opcode: u8, data_length: usize) -> Result<(), Error> { + assert!(buf.len() > data_length); // 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(&mut buf[..data_length+1]) { Ok(_) => { // Disable chip select