diff options
Diffstat (limited to 'src/devices/machine/ds2401.c')
-rw-r--r-- | src/devices/machine/ds2401.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/src/devices/machine/ds2401.c b/src/devices/machine/ds2401.c new file mode 100644 index 00000000000..48182b2d2c3 --- /dev/null +++ b/src/devices/machine/ds2401.c @@ -0,0 +1,270 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * DS2401 + * + * Dallas Semiconductor + * Silicon Serial Number + * + */ + +#include "emu.h" +#include "machine/ds2401.h" + +#define VERBOSE_LEVEL 0 + +inline void ds2401_device::verboselog(int n_level, const char *s_fmt, ...) +{ + if(VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start(v, s_fmt); + vsprintf(buf, s_fmt, v); + va_end(v); + logerror("ds2401 %s %s: %s", tag(), machine().describe_context(), buf); + } +} + +// device type definition +const device_type DS2401 = &device_creator<ds2401_device>; + +ds2401_device::ds2401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DS2401, "DS2401", tag, owner, clock, "ds2401", __FILE__) +{ +} + +void ds2401_device::device_start() +{ + t_samp = attotime::from_usec( 30); + t_rdv = attotime::from_usec( 30); + t_rstl = attotime::from_usec(480); + t_pdh = attotime::from_usec( 30); + t_pdl = attotime::from_usec(120); + + m_rx = true; + m_tx = true; + + save_item(NAME(m_state)); + save_item(NAME(m_bit)); + save_item(NAME(m_byte)); + save_item(NAME(m_shift)); + save_item(NAME(m_rx)); + save_item(NAME(m_tx)); + + m_timer_main = timer_alloc(TIMER_MAIN); + m_timer_reset = timer_alloc(TIMER_RESET); +} + +void ds2401_device::device_reset() +{ + m_state = STATE_IDLE; + m_bit = 0; + m_byte = 0; + m_shift = 0; + m_rx = true; + m_tx = true; + + if(m_region) + { + if(m_region->bytes() == SIZE_DATA) + { + memcpy(m_data, m_region->base(), SIZE_DATA); + return; + } + + logerror("ds2401 %s: Wrong region length for id data, expected 0x%x, got 0x%x\n", tag(), SIZE_DATA, m_region->bytes()); + } + else + { + logerror("ds2401 %s: Warning, no id provided, answer will be all zeroes.\n", tag()); + } + + memset(m_data, 0, SIZE_DATA); +} + +void ds2401_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_RESET: + verboselog(1, "timer_reset\n"); + m_state = STATE_RESET; + m_timer_reset->adjust(attotime::never); + break; + + case TIMER_MAIN: + switch(m_state) + { + case STATE_RESET1: + verboselog(2, "timer_main state_reset1 %d\n", m_rx); + m_tx = false; + m_state = STATE_RESET2; + m_timer_main->adjust(t_pdl); + break; + + case STATE_RESET2: + verboselog(2, "timer_main state_reset2 %d\n", m_rx); + m_tx = true; + m_bit = 0; + m_shift = 0; + m_state = STATE_COMMAND; + break; + + case STATE_COMMAND: + verboselog(2, "timer_main state_command %d\n", m_rx); + + m_shift >>= 1; + if(m_rx) + { + m_shift |= 0x80; + } + + m_bit++; + if(m_bit == 8) + { + switch(m_shift) + { + case COMMAND_READROM: + verboselog(1, "timer_main readrom\n"); + m_bit = 0; + m_byte = 0; + m_state = STATE_READROM; + break; + + default: + verboselog(0, "timer_main command not handled %02x\n", m_shift); + m_state = STATE_IDLE; + break; + } + } + break; + + case STATE_READROM: + m_tx = true; + + if( m_byte == SIZE_DATA ) + { + verboselog(1, "timer_main readrom finished\n"); + m_state = STATE_IDLE; + } + else + { + verboselog(2, "timer_main readrom window closed\n"); + } + break; + default: + verboselog(0, "timer_main state not handled: %d\n", m_state); + break; + } + } +} + +WRITE_LINE_MEMBER( ds2401_device::write ) +{ + verboselog(1, "write(%d)\n", state); + + if(!state && m_rx) + { + switch(m_state) + { + case STATE_IDLE: + break; + + case STATE_COMMAND: + verboselog(2, "state_command\n"); + m_timer_main->adjust(t_samp); + break; + + case STATE_READROM: + if(!m_bit) + { + m_shift = m_data[7 - m_byte]; + verboselog(1, "<- data %02x\n", m_shift); + } + + m_tx = m_shift & 1; + m_shift >>= 1; + + m_bit++; + if(m_bit == 8) + { + m_bit = 0; + m_byte++; + } + + verboselog(2, "state_readrom %d\n", m_tx); + m_timer_main->adjust(t_rdv); + break; + + default: + verboselog(0, "state not handled: %d\n", m_state ); + break; + } + + m_timer_reset->adjust(t_rstl); + } + else if(state && !m_rx) + { + switch(m_state) + { + case STATE_RESET: + m_state = STATE_RESET1; + m_timer_main->adjust(t_pdh); + break; + } + + m_timer_reset->adjust(attotime::never); + } + + m_rx = state; +} + +READ_LINE_MEMBER( ds2401_device::read ) +{ + verboselog(2, "read %d\n", m_tx && m_rx); + return m_tx && m_rx; +} + +UINT8 ds2401_device::direct_read(int index) +{ + return m_data[index]; +} + +/* + +app74.pdf + +Under normal circumstances an ibutton will sample the line 30us after the falling edge of the start condition. +The internal time base of ibutton may deviate from its nominal value. The allowed tollerance band ranges from 15us to 60us. +This means that the actual slave sampling may occur anywhere from 15 and 60us after the start condition, which is a ratio of 1 to 4. +During this time frame the voltage on the data line must stay below Vilmax or above Vihmin. + +In the 1-Wire system, the logical values 1 and 0 are represented by certain voltages in special waveforms. +The waveforms needed to write commands or data to ibuttons are called write-1 and write-0 time slots. +The duration of a low pulse to write a 1 must be shorter than 15us. +To write a 0, the duration of the low pulse must be at least 60us to cope with worst-case conditions. + +The duration of the active part of a time slot can be extended beyond 60us. +The maximum extension is limited by the fact that a low pulse of a duration of at least eight active time slots ( 480us ) is defined as a Reset Pulse. +Allowing the same worst-case tolerance ratio, a low pulse of 120us might be sufficient for a reset. +This limits the extension of the active part of a time slot to a maximum of 120us to prevent misinterpretation with reset. + +Commands and data are sent to ibuttons by combining write-0 and write-1 time slots. +To read data, the master has to generate read-data time slots to define the start condition of each bit. +The read-data time slots looks essentially the same as a write-1 time slot from the masters point of view. +Starting at the high-to-low transition, the ibuttons sends 1 bit of its addressed contents. +If the data bit is a 1, the ibutton leaves the pulse unchanged. +If the data bit is a 0, the ibutton will pull the data line low for 15us. +In this time frame data is valid for reading by the master. +The duration of the low pulse sent by the master should be a minimum of 1us with a maximum value as short as possible to maximize the master sampling window. + +The Reset Pulse provides a clear starting condition that supersedes any time slot synchronisation. +It is defined as single low pulse of minimum duration of eight time slots or 480us followed by a Reset-high time tRSTH of another 480us. +After a Reset Pulse has been sent, the ibutton will wait for the time tPDH and then generate a Pulse-Presence Pulse of duration tPDL. +No other communication on the 1-Wire bus is allowed during tRSTH. + +There are 1,000 microseconds in a millisecond, and 1,000 milliseconds in a second. +Thus, there are 1,000,000 microseconds in a second. Why is it "usec"? +The "u" is supposed to look like the Greek letter Mu that we use for "micro". . +*/ |