1.Preliminaries
I have optical sensor ADNS2610 (see datasheet here) which I plug in to Arduino Uno R3 board.
It is possible either to read from either to write to the sensor. Here is what datasheet says (p. 12):
Write Operation
Write operations, where data is going from the microcontroller to the ADNS-2610, is always initiated by the microcontroller and consists of two bytes. The first byte contains the address (seven bits) and has a “1” as its MSB to indicate data direction. The second byte contains the data. The transfer is synchronized by SCK. The microcontroller changes SDIO on falling edges of SCK. The ADNS-2610 reads SDIO on rising edges of SCK.
Read Operation
A read operation, meaning data that is going from the ADNS-2610 to the microcontroller, is always initiated by the microcontroller and consists of two bytes. The first byte that contains the address is written by the microcontroller and has a “0” as its MSB to indicate data direction. The second byte contains the data and is driven by the ADNS-2610. The transfer synchronized by SCK. SDIO is changed on falling edges of SCK and read on every rising edge of SCK. The microcontroller must go to a High-Z state after the last address data bit. The ADNS-2610 will go to the High-Z state after the last data bit. Another thing to note during a read operation; SCK needs to be delayed after the last address data bit to ensure that the ADNS-2610 has at least 100 μs to prepare the requested data. This is shown in the timing diagrams below (See Figures to 23).
![]()
![]()
2 Arduino program
WriteRegister
and ReadRegister
functions are borrowed (though slightly modified) from OptiMouse project by zapmaker.
2.1 SetAddress function
This function writes the first byte: data direction (MSB) and address of a register (seven bits) which user intents to read from or to write to.
void ADNS2610::SetAddress( uint8_t address, DataDirection direction ) const
{
pinMode( sdioPin, OUTPUT );
/*Specify data direction:
*MSB = 0 ===> read operation
*MSB = 1 ===> write operation*/
switch( direction )
{
case( toSensor ) :
address |= 0b10000000 ;
break;
case( fromSensor ) :
address &= ~0b10000000 ;
break;
}
for( uint8_t mask = 0b10000000; mask; mask >>= 1 )
{
digitalWrite( sckPin, LOW );
digitalWrite( sdioPin, address & mask );
digitalWrite( sckPin, HIGH );
}
/*Wait for 100 microseconds between address write operation
*and read data operation (see p.15 of the datasheet)*/
delayMicroseconds( 100 );
}
2.2 ReadRegister function
uint8_t ADNS2610::ReadRegister( uint8_t address ) const
{
SetAddress( address, fromSensor );
uint8_t data = 0;
/*Read data from a register*/
pinMode( sdioPin, INPUT );
for( int i = 7; i >= 0; i++ )
{
digitalWrite( sckPin, LOW );
digitalWrite( sckPin, HIGH );
data |= ( digitalRead( sdioPin ) << i );
}
/*Wait for 0.25 microseconds between read and either
*read or write operations (see p.15 of the datasheet)*/
delayMicroseconds( 1 );
return data;
}
2.3 WriteRegister function
void ADNS2610::WriteRegister( uint8_t address, uint8_t data ) const
{
SetAddress( address, toSensor );
/*Write data to a register*/
for( uint8_t mask = 0b10000000; mask; mask >>= 1 )
{
digitalWrite( sckPin, LOW );
digitalWrite( sdioPin, data & mask );
digitalWrite( sckPin, HIGH );
}
/*Wait for 100 microseconds between write and either
*read or write operations (see p.15 of the datasheet)*/
delayMicroseconds( 100 );
}
3.Discussion
3.1 Write operation
According to the datasheet
... The microcontroller changes SDIO on falling edges of SCK. The ADNS-2610 reads SDIO on rising edges of SCK.
And this is how I understand the code (see sec. 2.1):
digitalWrite( sckPin, LOW );//create a falling edge
digitalWrite( sdioPin, address & mask );//change SDIO on falling edge
digitalWrite( sckPin, HIGH );//create a rising edge (ADNS reads here)
Two questions here:
The first line in the above creates a falling edge only if the previous state of SCK was
HIGH
, doesn't it? So would it be better to have the following:digitalWrite( sckPin, HIGH); digitalWrite( sckPin, LOW );//create a falling edge digitalWrite( sdioPin, address & mask );//change SDIO on falling edge digitalWrite( sckPin, HIGH );//create a rising edge (ADNS reads here)
On figure 20 (see sec. 1, Write operation) you can see that it is required some minimal duration of the clock pulses (250 ns). Does the above code provide such a duration? I know that ATMega328p has frequency 16 MHz, so it seems that time between two operations could be less than 250 ns. Am I right?
3.2 Read operation
According to the datasheet
SDIO is changed on falling edges of SCK and read on every rising edge of SCK. The microcontroller must go to a High-Z state after the last address data bit. The ADNS-2610 will go to the High-Z state after the last data bit
And this is how I understand the code (see sec. 2.2):
digitalWrite( sckPin, LOW );//create a falling edge (SDIO changes here)
digitalWrite( sckPin, HIGH );//create a rising edge
data |= ( digitalRead( sdioPin ) << i );//read SDIO on rising edge
Three questions here:
The first line in the code above creates a falling edge only if the previous state of SCK was
HIGH
, doesn't it? Would it be better to have the following:digitalWrite( sckPin, HIGH); digitalWrite( sckPin, LOW );//create a falling edge (SDIO changes here) digitalWrite( sckPin, HIGH );//create a rising edge data |= ( digitalRead( sdioPin ) << i );//read SDIO on rising edge
On figure 23 (see sec. 1,Read operation) you can see that it is required some minimal duration of the clock pulses (250 ns). Does the above code provide such a duration?
How do I set the microcontroller into High-Z state after the last address data bit?