National CP3BT26 Computer Hardware User Manual


 
www.national.com 190
CP3BT26
24.4.1 Avoiding Bus Error During Write Transaction
A Bus Error (BER) may occur during a write transaction if
the data register is written at a very specific time. The mod-
ule generates one system-clock cycle setup time of SDA to
SCL vs. the minimum time of the clock divider ratio.
The problem can be masked within the driver by dynamical-
ly dividing-by-half the SCL width immediately after the slave
address is successfully sent and before writing to the ACB-
SDA register. This has the effect of forcing SCL into the
stretch state.
The following code example is the relevant segment of the
ACCESS.bus driver addressing this issue.
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
; NAME: ACBRead Reads "Count" byte(s) from selected I2C Slave. If read address differs from previous
; Read or Write operation (as recorded in NextAddress), a "dummy" write transaction is
; initiated to reset the address to the desired location. This is followed by a repeated
; Start sequence and the Read transaction. All transactions begin with a call to ACBStartX
; which sends the Start condition and Slave address. Checks for errors throughout process.
;
; PARAMETERS: UBYTE Slave - Slave Device Address. Must be of format 0xXXXX0000
; UWORD Addrs - Byte/Array address (extended addressing mode uses two byte address)
; UWORD Count - Number of bytes to read
; UBYTE *buf - Pointer to receive buffer
;
; CALLS: ACBStartX
;
; RETURNED: error status
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
UWORD ACBRead (UBYTE Slave, UWORD Addrs, UWORD Count, UBYTE *buf)
{
ACB_T *acb;
UBYTE err, *rcv;
UWORD Timeout;
acb = (ACB_T*)ACB_ADDRESS; /* Set pointer to ACB module */
/* If the indicated address differs from the last */
if (Addrs != NextAddress) {
/* recorded access (i.e. Random Read), we must first */
/* send a "dummy" write to the desired new address.. */
NextAddress = Addrs; /* Update last address placeholder */
KeyInit();
KBD_OUT &= ~BIT0;
/* Send start bit and Slave address... */
if ((err = ACBStartX (Slave | (Addrs >> 7 & 0x0E), ACB_WRITE, 0)))
return (err); /* If unsuccessful, return error code */
// KBD_OUT &= ~BIT0;
acb->ACBsda = (UBYTE)Addrs; /* Send new address byte */
KBD_OUT &= ~BIT0;
Timeout = 1000; /* Set timeout */
/* Wait for xmitter to be ready...zzzzzzzzz */
while (!(acb->ACBst & ACBSDAST) && !(acb->ACBst & ACBBER) && Timeout--);
if (acb->ACBst & ACBBER) {
/* If a bus error occurs while sending address, clear */
acb->ACBst |= ACBBER; /* the error flag and return error status */
return (ACBERR_COLLISION);
}
KBD_OUT &= ~BIT0;
if (!Timeout) /* If we timeout, return error */
return (ACBERR_TIMEOUT);
}
/* (Re)Send start bit and Slave address... */
if ((err = ACBStartX (Slave | (Addrs >> 7 & 0x0E), ACB_READ, Count)))
/* If error, return */
return (err);
rcv = buf; /* Get address of read buffer */
/* Read Count bytes into user’s buffer */
while (Count) {
if (Count-- == 1) /* If this the final byte, or only one requested, send */
acb->ACBctl1 |= ACBACK; /* the NACK bit after reception */
Timeout = 1000; /* Set timeout */
while (!(acb->ACBst & ACBSDAST) && Timeout--);
if (!Timeout) /* Timed out?? */
/* YES - return error */
return (ACBERR_TIMEOUT);
*rcv++ = acb->ACBsda; /* NO - Read byte from Recv register */
/* Adjust current address placeholder */
NextAddress++;
}