National CP3BT26 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 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
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.
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.
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
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
; 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_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 */
/* 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;
KBD_OUT &= ~BIT0;
/* Send start bit and Slave address... */
if ((err = ACBStartX (Slave | (Addrs >> 7 & 0x0E), ACB_WRITE, 0)))
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--);
/* 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 */
/* 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);
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) {
/* 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 */
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++;
}
/* YES - return error */
return (ACBERR_TIMEOUT);
*rcv++ = acb->ACBsda; /* NO - Read byte from Recv register */
/* Adjust current address placeholder */
NextAddress++;
}