// Dallas 2401 one-wire serial number driver // Larry Doolittle, LBNL, October 29, 2002 // // exit reset: Z0ZZZZZZZZZZRZZ // write a zero: Z0000000000000Z >60 uS low // write a one: Z0111111111111Z 5 uS low, >60 uS total // read a bit: Z0ZZRZZZZZZZZZZ 5 uS low, 15 uS from first 0 to R // count 0123456789abcd0 // one "slot" should be a little over 60 uS // // My simple-minded counting of registers and "difficult" logic // gives about 26 Cells in an FPGA. Xilinx ISE 4.2i says it // implements in 17 slices (34 cells). // // write register: { write_data2, write_data1, reset, run } // read register: { count, run, read_presence, read_data } // // November 20, 2002: I changed this to report (count!=0 | run) instead // of { count, run }. This makes the interface to the sofware cleaner, // and actually reduces the logic footprint, since more bits in the output // mean more multiplexers used to fan-in to the host. The change is // backwards compatible: the software can still check for completion // using a mask of 0x7c (zero count & zero run), since we force unused // read_bus bits to zero. // // Reset: // write 0010; wait at least 480 us; // write 1101; wait at least 480 us; // check read_presence bit // Write a bit: // write b001; poll until run==0 // Read a bit: // write 1001; poll until run==0, use read_data // Note that the output is the same for reading a bit and writing a 1. // This is correct. read_data should be 1 after writing a 1. `timescale 1ns / 1ns module ds2401( clock, dallas_pin, host_write, write_bus, read_bus); input clock; inout dallas_pin; input host_write; input [3:0] write_bus; output [15:0] read_bus; `ifdef SIMULATE reg [2:0] divider; initial divider=0; `else reg [6:0] divider; `endif reg tick; always @(posedge clock) begin divider <= divider + 1'b1; tick <= (divider == 0); end reg [3:0] count; wire zero_count = (count == 4'd0); wire indata_count = (count == 4'd4); wire end_of_count = (count == 4'd13); reg run, reset, write_data1, write_data2; always @(posedge clock) begin if (host_write | tick & end_of_count) begin run <= host_write & write_bus[0]; end if (host_write) begin reset <= write_bus[1]; write_data1 <= write_bus[2]; write_data2 <= write_bus[3]; end end reg drive, read_data, read_presence; always @(posedge clock) if (tick) begin count <= run ? (count + 1'b1) : 0; drive <= reset | run & ~end_of_count & ~(zero_count ? write_data1 : write_data2); if (indata_count) read_data <= dallas_pin; if (end_of_count) read_presence <= dallas_pin; end assign dallas_pin = drive ? 1'b0 : 1'bz; assign read_bus = { 13'b0000000000000, ~zero_count | run, read_presence, read_data }; endmodule