Generates 2-Wire start condition. Can also be called to generate a re-start condition.
1
int Stop()
Generates 2-Wire stop condition
1
int WriteData(unsigned char ucData);
Writes the argument to the slave
1 if slave acknowledges,
0 if slave does not acknowledge
int ReadDataAck(unsigned char *ucData);
Reads the data byte from slave to ucData and acknowledges
1
int ReadDataNack(unsigned char *ucData);
Reads the data byte from slave to ucData and does not acknowledge
1
int ResetBus()
Clocks SCL 9-times then generates a stop condition
1
表2. Multiple-Byte 2-Wire Functions
FUNCTION PROTOTYPE
FUNCTION DESCRIPTION
RETURN VALUE
int SetSlaveAddress(unsigned char ucADDR)
Sets the slave address for multiple-byte read and write accesses
1
int WriteBytes(int iCount, unsigned char ucMemAddr, unsigned char ucData[256])
Writes iCount bytes to the slave at the device address set by SetSlaveAddress(), beginning at memory address set by ucMemAddr.
1 if slave acknowledges,
0 if slave does not acknowledge any byte.
Int ReadBytes(int iCount, unsigned char ucMemAddr, unsigned char ucData[256])
Reads iCount bytes to the slave at the device address set by SetSlaveAddress(), beginning at memory address set by ucMemAddr.
1 if slave acknowledges during command writes,
0 if slave does not acknowledge during command writes.
表3. 追加のポートセットアップ及びデバッグ関数
FUNCTION PROTOTYPE
FUNCTION DESCRIPTION
RETURN VALUE
int ParPortSelect(int iLPT)
Sets parallel port access variables to specified port number. iLPT = 1 for LPT1.
1 for successful change
0 for failure
int ChangeDelayCount(int iCount)
This determines the "i" value used with the DelayASMx10() command during SDA and SCL communications. Call this function with higher i values to make communication slower. The default value is 1000, which should provide moderate to slow communication speed. This is a safe value for i. Most PCs will be able to use a lower value of i to speed up communications.
1
void DelayASMx10(int i)
Delays 10 clock cycles per i. This is called as the delay that determines SDA and SCL timing. It does not need to be called by the software developer, it is already embedded into the start/stop/read/write commands.
NULL
int EnableLED()
enables LED in AN3230 circuit
1
int DisableLED()
disables LED in AN3230 circuit
1
int SetStrobe()
Sets the LED pin in the AN3230 circuit high for oscilloscope triggering
1
int ClearStrobe()
Sets the LED pin in the AN3230 circuit low for oscilloscope triggering
unsigned char fail = 0;
Start(); // Generates Start Condition
fail |= !WriteData(0xB0); // Writes the slave address
fail |= !WriteData(0x08); // Writes the memory address of the DAC register
fail |= !WriteData(0x01); // Writes the MSB of the DAC register
fail |= !WriteData(0x80); // Writes the LSB of the DAC register
Stop(); // Generates Stop Condition
if(fail == 1)
Error("Device failed to acknowledge during write attempt");
DACレジスタに書き込まれた2バイトを読み出すためには、次のコードが使えます。
unsigned char ucDataMSB=0; // define variable for MSB data to be stored after the read
unsigned char ucDataLSB=0; // define variable for LSB data to be stored after the read
unsigned char fail = 0;
Start(); // Generate Start Condition
fail |= !WriteData(0xB0); // Write the slave address, LSbit=0 to signify write byte
fail |= !WriteData(0x08); // Write the memory address of the DAC register
Start(); // Generates a re-start condition
WriteData(0xB1); // Writes the slave address, LSbit=1 to signify read byte
ReadDataAck(&ucDataMSB); // Reads the MSB of DAC and sends acknowledgement to the slave
ReadDataNack(&ucDataLSB); // Reads the LSB of DAC and does not acknowledge the slave
Stop(); // Generates Stop Condition
if(fail ==1)
Error("Device failed to acknowledge during read attempt");
このアプリケーションノートでは、An3230の中で示された[parallel port 2-Wire circuit]を使って、「2wire.c」ファイルで提供されるソースコードで、2線式デバイスのプログラミングが簡単であることを検証しました。「2wire.c」の中のルーチンは信号伝達機能を遂行しますが、これによりプログラマがインタフェースタイミングの調整及び2線式デバイスのデータシートで概説されている通りに2線式ルーチンを適切な順序でコールすることに専念することを可能にします。
このアプリケーションノートに関する質問は、Dallas Semiconductor Mixed Signal Applications group、宛に英語でお問い合わせください。
付録A - ソースコード
///////////////////////////////////////////////////////////////////////////////
// 2-Wire Parallel Port Functions for Win95/Win98
//
// Dallas Semiconductor (C) 2004
//
// This software is free and available "as is" for use by Dallas
// Semiconductor's customers. Dallas Semiconductor accepts no liability for any
// damages the software may cause. Use at your own risk.
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Include Files
#include <conio.h>
///////////////////////////////////////////////////////////////////////////////
// Definitions
#define LPT1 0x378
#define LPT2 0x3BC
#define LPT3 0x278
#define LPT4 0x378 // not implemented - set to LPT1 for now,
// returns error code if assigned
///////////////////////////////////////////////////////////////////////////////
// Global Variables
unsigned short LPTData; // parallel port base address
unsigned short LPTStatus; // LPT Base Address + 1
unsigned short LPTControl; // LPT Base Address + 2
unsigned char ucDeviceAddress; // 2-Wire device address for
// multibyte communication
int DCNT = 1000; // Delay Count...Sets the delay time used for SDA/SCL
// during 2-Wire communication. DCNT=25 works well for MY P3 600MHz
// Laptop. 1000 is the default value providing some guardband for
// faster machines so they do not attempt to talk faster than the
// 400kHz rating of the 2-Wire interface. This value can be changed
// high or lower to find the best value using ChangeDelayCount();
///////////////////////////////////////////////////////////////////////////////
// Function Prototypes
// Parallel Port Utility Functions
void DelayASMx10(int i); // delays 10 clock cycles per i
int ChangeDelayCount(int iCount); // changes i for DelayASMx10
int ParPortSelect(int iLPT); // sets access variables to specified
// port. Must be called before any other parallel port functions
// Basic 2-Wire Functions
int Start(); // 2-Wire Start Command
int Stop(); // 2-Wire Stop Command
int WriteData(unsigned char ucDATA); // 2-Wire Write Byte
int ReadDataNack(unsigned char *ucDATA); // 2-Wire Read Byte with NACK
int ReadDataAck(unsigned char *ucDATA); // 2-Wire Read Byte with ACK
// MultiByte Write/Read 2-Wire Functions
int SetSlaveAddress(unsigned char ucADDR); // sets slave address for
// WriteBytes and ReadBytes Commands
int WriteBytes(int iCount, unsigned char ucMemAddr, unsigned char ucData[256]);
// Write upto 256 bytes to device address set by SetSlaveAddress.
int ReadBytes(int iCount, unsigned char ucMemAddr, unsigned char ucData[256]);
// Reads upto 256 bytes from device address set by SetSlaveAddress.
// Utility 2-Wire Functions
int ResetBus(); // clocks SCL 9 times and performs stop to "free"
// SDA and SCL for the software master.
int SetStrobe(); // sets strobe pin for debugging (AN3230)
int ClearStrobe(); // clears strobe pin for debugging (AN3230)
// Enable / Disable LED on AN3230 circuit
int EnableLED(); // enables LED in AN3230 circuit
int DisableLED(); // disables LED in AN3230 circuit
///////////////////////////////////////////////////////////////////////////////
// Function Definitions
void DelayASMx10(int iDelayCount) // delays 10 NOPs iDelayCount times.
{ // See DCNT description in variable declarations for more information
int iLoopCount = 1;
for (; iLoopCount<=iDelayCount; iLoopCount++)
{
__asm
{
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
}
}
}
int ParPortSelect(int iLPT)
{ // Selects the parallel port used for operation.
if(iLPT == 1)
{
LPTData = LPT1;
LPTStatus = LPTData + 1; // LPT Data + 1
LPTControl = LPTData + 2; // LPT Data + 2
return 1; // legal port value
}
else if(iLPT == 2)
{
LPTData = LPT2;
LPTStatus = LPTData + 1; // LPT Data + 1
LPTControl = LPTData + 2; // LPT Data + 2
return 1; // legal port value
}
else if(iLPT == 3)
{
LPTData = LPT3; // legal port value
LPTStatus = LPTData + 1; // LPT Data + 1
LPTControl = LPTData + 2; // LPT Data + 2
return 1; // legal port value
}
else if(iLPT == 4)
{
LPTData = LPT4; // not implemented,but defined as LPT1
LPTStatus = LPTData + 1; // LPT Data + 1
LPTControl = LPTData + 2; // LPT Data + 2
return 0; // return 0 for unimplemented value
}
else
return 0; // illegal value, return 0 for error
}
int ChangeDelayCount(int iCount) // changes i for DelayASMx10
{ // Changes the DCNT to increase/decreas delays between 2-Wire edges
DCNT = iCount; // See DCNT declaration in variable declarations.
return 1;
}
int EnableLED()
{ // Enables the LED shown on the AN3230 circuit
unsigned char Data;
// Read original value of control byte
Data = _inp(LPTControl);
// Turn LED on
_outp(LPTControl, (Data & 0xF7)); // Clear P17 to turn LED on
return 1;
}
int DisableLED()
{ // Disables the LED shown on the AN3230 circuit
unsigned char Data;
// Read original value of control byte
Data = _inp(LPTControl);
// Turn LED on
_outp(LPTControl, (Data | 0x08)); // Clear P17 to turn LED on
return 1;
}
int Start()
{ // Performs 2-Wire start condition
unsigned char Data;
// Read original value of data byte
Data = _inp(LPTData);
// Ensure SDA and SCL are high
// Set SDA high (write D1 to a 0)
Data = Data & 0xFD;
_outp(LPTData, Data);
DelayASMx10(DCNT);
// Set SCL high (write D0 to a 0)
Data = Data & 0xFE;
_outp(LPTData, Data);
DelayASMx10(DCNT);
// Bring SDA low, then bring SCL low
// Bring SDA low (write D1 to a 1)
Data = Data | 0x02;
_outp(LPTData, Data);
DelayASMx10(DCNT);
// Bring SCL low (write D0 to a 1)
Data = Data | 0x01;
_outp(LPTData, Data);
DelayASMx10(DCNT);
return 1;
}
int Stop()
{ // Performs 2-Wire stop condition
unsigned char Data;
// Read original value of data byte
Data = _inp(LPTData);
// Ensure SDA and SCL are low
// Make SCL low (write D0 to a 1)
Data = Data | 0x01;
_outp(LPTData, Data);
DelayASMx10(DCNT);
// Make SDA low (write D1 to a 1)
Data = Data | 0x02;
_outp(LPTData, Data);
DelayASMx10(DCNT);
// Bring SCL high, then bring SDA high
// Bring SCL high (write D0 to a 0)
Data = Data & 0xFE;
_outp(LPTData, Data);
DelayASMx10(DCNT);
// Bring SDA high (write D1 to a 0)
Data = Data & 0xFD;
_outp(LPTData, Data);
DelayASMx10(DCNT);
return 1;
}
int WriteData(unsigned char ucDATA)
{
// This routine writes 1 data byte and checks for slave acknoledgement
// Assumes Start already issued and SDA and SCL are both low
unsigned char shiftbyte, statusbyte;
int i;
unsigned char ucTempData;
shiftbyte = ucDATA;
ucTempData = _inp(LPTData);
// loop for 8 bits
for (i=0; i<8; i++)
{
if (shiftbyte & 0x80)
{
// Set SDA high (D1=0)
ucTempData = ucTempData & 0xFD;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Clock SCL (D0=0, D0=1)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Bring SDA low (D1=1)
ucTempData = ucTempData | 0x02;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
}
else
{
// Bring SDA low (D1=1)
ucTempData = ucTempData | 0x02;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Clock SCL (D0=0, D0=1)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
}
shiftbyte = shiftbyte << 1;
}
// Release SDA (D1=0)
ucTempData = ucTempData & 0xFD;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Check if slave ACKs
// Bring SCL high (D0=0)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Read SDA
statusbyte = _inp(LPTStatus);
// Bring SCL low (D0=1)
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Display ACK
if (statusbyte & 0x20)
{ // Slave ACK'd
return 1;
}
else
{ // Slave did not ACK
return 0;
}
}
int ReadDataNack(unsigned char *ucDATA)
{ // This routine reads one byte and NACKs. It assumes SDA and SCL
// are low becuase a start condition/communication has already occured
unsigned char shiftbyte;
int i;
int ucTempData, Status;
shiftbyte = 0x00;
// Ensure SDA is released (D1=0) and SCL is low (D0=1)
ucTempData = _inp(LPTData);
ucTempData = ((ucTempData & 0xFD) | 0x01);
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// loop for 8 bits
for (i=0; i<8; i++)
{ // Clock in one bit
// Bring SCL high (D0=0)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Read in SDA
Status = _inp(LPTStatus);
// Bring SCL low (D0=1)
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
if (Status & 0x20)
{ // Bit is high (although inverted through the 7405)
shiftbyte = shiftbyte << 1;
shiftbyte = shiftbyte & 0xFE; // Just in case compiler does not shift in 0
}
else
{ // Bit is low (although inverted through the 7405)
shiftbyte = shiftbyte << 1;
shiftbyte = shiftbyte | 0x01;
}
}
// NACK - Release SDA and clock SCL
// Release SDA high (D1=0)
ucTempData = ucTempData & 0xFD;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Bring SCL high (D0=0)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Bring SCL low (D0=1)
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
*ucDATA = shiftbyte;
return 1;
}
int ReadDataAck(unsigned char *ucDATA)
{
// Read 8 bits of data and ACK
unsigned char shiftbyte;
int i;
int ucTempData, Status;
shiftbyte = 0x00;
// Ensure SDA is released (D1=0) and SCL is low (D0=1)
ucTempData = _inp(LPTData);
ucTempData = ((ucTempData & 0xFD) | 0x01);
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// loop for 8 bits
for (i=0; i<8; i++)
{ // Clock in one bit
// Bring SCL high (D0=0)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Read in SDA
Status = _inp(LPTStatus);
// Bring SCL low (D0=1)
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
if (Status & 0x20)
{ // Bit is high (although inverted through the 7405)
shiftbyte = shiftbyte << 1;
shiftbyte = shiftbyte & 0xFE; // Just in case compiler does not shift in 0
}
else
{ // Bit is low (although inverted through the 7405)
shiftbyte = shiftbyte << 1;
shiftbyte = shiftbyte | 0x01;
}
}
// ACK - Pull SDA low and clock SCL, then release SDA
// Pull SDA low (D1=1)
ucTempData = ucTempData | 0x02;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Bring SCL high (D0=0)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Bring SCL low (D0=1)
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Release SDA (D1=0)
ucTempData = ucTempData & 0xFD;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
*ucDATA = shiftbyte;
return 1;
}
int SetSlaveAddress(unsigned char ucADDR) // sets slave address for
{ // WriteBytes and ReadBytes Commands
ucDeviceAddress = ucADDR & 0xFE;
return 1;
}
int WriteBytes(int iCount, unsigned char ucMemAddr, unsigned char ucData[256])
{ // Write upto 256 bytes to device address set by SetSlaveAddress.
int fail = 0;
int i;
fail |= !Start();
fail |= !WriteData((unsigned char)((long)ucDeviceAddress & 0xFE));
fail |= !WriteData(ucMemAddr);
for(i = 0; i <iCount; i++)
{
fail |= !WriteData(ucData[i]);
}
fail |= !Stop();
if(fail)
return 0;
else
return 1;
}
int ReadBytes(int iCount, unsigned char ucMemAddr, unsigned char ucData[256])
{ // Reads upto 256 bytes from device address set by SetSlaveAddress.
int fail = 0;
int i;
fail |= !Start();
fail |= !WriteData((unsigned char)((long)ucDeviceAddress & 0xFE));
fail |= !WriteData(ucMemAddr);
fail |= !Start();
fail |= !WriteData((unsigned char)((long)ucDeviceAddress | 0x01));
for(i = 0; i <(iCount-1); i++)
{
fail |= !ReadDataAck(&ucData[i]);
}
fail |= !ReadDataNack(&ucData[i]);
fail |= !Stop();
if(fail)
return 0;
else
return 1;
}
int ResetBus()
{
unsigned char ucTempData;
int i;
ucTempData = _inp(LPTData);
for (i = 0; i < 9; i++)
{
// Bring SCL low (D0=1)
ucTempData = ucTempData | 0x01;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
// Bring SCL high (D0=0)
ucTempData = ucTempData & 0xFE;
_outp(LPTData, ucTempData);
DelayASMx10(DCNT/2);
}
Stop();
return 1;
}
int SetStrobe() // sets strobe pin (LED) for debuging (AN3230)
{
EnableLED();
//DisableLED();
return 1;
}
int ClearStrobe() // clears strobe pin (LED) for debugging (AN3230)
{
DisableLED();
//EnableLED();
return 1;
}