2

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. enter image description here

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).enter image description here enter image description here enter image description here

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:

  1. 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)
    
  2. 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:

  1. 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
    
  2. 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?

  3. How do I set the microcontroller into High-Z state after the last address data bit?

3

Question 1

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

If you start from Cycle one.. Yes. Looking at the read cycle waveform, SCLK should be high before initiating a read or write request and after completing the communication.

Question 2

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?

Here is the code for digital write function
void digitalWrite(uint8_t pin, uint8_t val)
{
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;

    if (port == NOT_A_PIN)
        return;

    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    if (timer != NOT_ON_TIMER)
        turnOffPWM(timer);

    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;
    cli();

    if (val == LOW) {
        *out &= ~bit;
    }
    else {
        *out |= bit;
    }

    SREG = oldSREG;
}

Please do not give any delay. the above DigtalWrite function will take 1000's of ns of delay already. it is sufficient.

Question 3:

How do I set the micro controller into High-Z state after the last address data bit?

I would do the following. Configure the pin which you want to set to high impedance as input pin. You can always change it to output mode before you want to use it again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.