mrjohnk / ADNS-9800

Avago ADNS-9800 Test
94 stars 41 forks source link

Can't upload firmware and I don't get the frame burst. #6

Open Majanao opened 7 years ago

Majanao commented 7 years ago

Hi, I 've got the issue that I do get x, y, squal-value and so on, but I don't upload the firmware, cause it doesn't work. The target is to read the frame data. At the moment the 900 pixels do have the value 255 or 0.

I'm working with a Atmega328P and C. My code for uploading the firmware looks like that:

` void adns9800_srom_up(void) { int SROM_ID; char buffer[10];

USART_Transmit_string("Uploud.SROM\r\n");

adns9800_write(0x39,0x02);                              // select 3K bytes Srom size
adns9800_write(0x13,0x1d);                              // srom_enable register fot initializing
_delay_us(10);                                          // wait for one frame 
adns9800_write(0x13,0x18);                              // srom enable register to start srom downloading
PORT_CS &= ~(1<<CS_Pin);                                // enable serial port
SPI_MasterTransmit(0x62 | 0x80);                        // start with srom burst 
_delay_us(15);

int i;
unsigned char c;
for(i=0;i<firmware_length;i++)
{
    c=pgm_read_byte(firmware_data + i);                 // load byte from firmware file
    SPI_MasterTransmit(c);                              // transmit firmware byte
    _delay_us(15);
}
//_delay_us(10);

_delay_us(161); 

SROM_ID = adns9800_read(0x2a);
itoa(SROM_ID,buffer,10);
USART_Transmit_string("SROM_ID=");
USART_Transmit_string(buffer);
USART_Transmit_string("\r\n");

PORT_CS |= (1<<CS_Pin);                             // disable serial port

if (SROM_ID == 0x00)
{
    USART_Transmit_string("Upload failed\r\n");
}
else
{
    USART_Transmit_string("Upload succeed\r\n");
}

} `

I always get 0 as SROM_ID. Might this be the reason why I don't get the real pixel data? It would be great if you could help me with this issue!

Thanks,

  Marian
mrjohnk commented 7 years ago

Do you have another subroutine that is executed to perform the startup procedures? That is needed to get the chip in shape to start receiving commands. It essentially resets the SPI functions, reads any residual data and cleans everything up before attempting to the code upload. I didn't crawl through your code in-depth, but didn't see this in there either.

void performStartup(void){

adns_com_end(); // ensure that the serial port is reset

adns_com_begin(); // ensure that the serial port is reset

adns_com_end(); // ensure that the serial port is reset

adns_write_reg(REG_Power_Up_Reset, 0x5a); // force reset

delay(50); // wait for it to reboot

// read registers 0x02 to 0x06 (and discard the data)

adns_read_reg(REG_Motion);

adns_read_reg(REG_Delta_X_L);

adns_read_reg(REG_Delta_X_H);

adns_read_reg(REG_Delta_Y_L);

adns_read_reg(REG_Delta_Y_H);

// upload the firmware

adns_upload_firmware();

delay(10);

//enable laser(bit 0 = 0b), in normal mode (bits 3,2,1 = 000b)

// reading the actual value of the register is important because the real

// default value is different from what is said in the datasheet, and if you

// change the reserved bytes (like by writing 0x00...) it would not work.

byte laser_ctrl0 = adns_read_reg(REG_LASER_CTRL0);

adns_write_reg(REG_LASER_CTRL0, laser_ctrl0 & 0xf0 );

delay(1);

Serial.println("Optical Chip Initialized");

}

On Mon, May 8, 2017 at 9:18 AM, Majanao notifications@github.com wrote:

Hi, I 've got the issue that I do get x, y, squal-value and so on, but I don't upload the firmware, cause it doesn't work. The target is to read the frame data. At the moment the 900 pixels do have the value 255 or 0.

I'm working with a Atmega328P and C. My code for uploading the firmware looks like that:

`void adns9800_srom_up(void) { int SROM_ID; char buffer[10];

USART_Transmit_string("Uploud.SROM\r\n");

adns9800_write(0x39,0x02); // select 3K bytes Srom size adns9800_write(0x13,0x1d); // srom_enable register fot initializing _delay_us(10); // wait for one frame adns9800_write(0x13,0x18); // srom enable register to start srom downloading PORT_CS &= ~(1<<CS_Pin); // enable serial port SPI_MasterTransmit(0x62 | 0x80); // start with srom burst _delay_us(15);

int i; unsigned char c; for(i=0;i<firmware_length;i++) { c=pgm_read_byte(firmware_data + i); // load byte from firmware file SPI_MasterTransmit(c); // transmit firmware byte _delay_us(15); } //_delay_us(10);

_delay_us(161);

SROM_ID = adns9800_read(0x2a); itoa(SROM_ID,buffer,10); USART_Transmit_string("SROM_ID="); USART_Transmit_string(buffer); USART_Transmit_string("\r\n");

PORT_CS |= (1<<CS_Pin); // disable serial port

if (SROM_ID == 0x00) { USART_Transmit_string("Upload failed\r\n"); } else { USART_Transmit_string("Upload succeed\r\n"); }

}`

I always get 0 as SROM_ID. Might this be the reason why I don't get the real pixel data? It would be great if you could help me with this issue!

Thanks,

Marian

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mrjohnk/ADNS-9800/issues/6, or mute the thread https://github.com/notifications/unsubscribe-auth/ABG0-SJUwGS3OW5JDRWYxBWhlVCif4s6ks5r3yQ1gaJpZM4NUA1Y .

Majanao commented 7 years ago

Hi,

thanks for your answer. I checked my init and did adapt the setting of the laser reg. It looks like this now:

`void adns9800_init(void){

//USART_Transmit_string("Initialize ADNS9800\r\n");
Out_SCK |= SCK_Pin;                                     //SCK as output
Out_SDIO |= MOSI_Pin;                                   //MOSI as output
Out_SDIO &= ~MISO_Pin;                                  //MISO as input
Out_CS  |= CS_Pin;                                      //CS as output

//PORTC |= (1<<PORTC5);                                 //power to the sensor
//_delay_us(2);

PORT_CS |= (1<<CS_Pin);
_delay_us(2);
PORT_CS &= ~(1<<CS_Pin);                                //reset the SPI Port 
_delay_us(2);
PORT_CS |= (1<<CS_Pin);
_delay_us(2);

adns9800_write(0x3a,0x5a);                              //full chip reset

_delay_ms(50);

adns9800_read(0x02);                                    //dump readout of the motion registers
_delay_us(5);
adns9800_read(0x03);
_delay_us(5);
adns9800_read(0x04);
_delay_us(5);
adns9800_read(0x05);
_delay_us(5);
adns9800_read(0x06);
_delay_us(5);

adns9800_srom_up();                                         //upload firmware

_delay_ms(10);

char laser_ctrl = adns9800_read(0x20);
adns9800_write(0x20, laser_ctrl & 0xf0);                    //enable The Laser into normal operation mode

}`

But unfortunatly it still doesn't work. I still get the SROM_ID = 0. I also checked the data the µC is sending to the sensor. It's all like it should be.

Any more ideas?

doruserban commented 1 year ago

I am running into the same situation - I am experiencing the same problem with both of the Tindie ADNS9800 - trying to load firmware and thereafter reading SROM_ID returns 0. SPI connection seems fine as I get the proper PRODUCT_ID & INVERSE_PRODUCT_ID as well as the REVISION_ID. I am using the Arduino example modified for PIC18F46K22 and using Mikroelektronika C Compiler. Any help someone could offer will be highly appreciated - here is my modified code:

enum motion_burst { motion = 0, observation, delta_x_l, delta_x_h, delta_y_l, delta_y_h, squal, pixel_sum, maximum_pixel, minimum_pixel, shutter_upper, shutter_lower, frame_period_upper, frame_period_lower, end_data }; typedef struct { uint8_t param [end_data], srom_id; uint16_t ux, uy, ux_dist, uy_dist; } adns9800_t; adns9800_t adns9800; volatile uint8_t _moved = 0;

void adns9800_com_begin() { cs_adns9800 = LOW; } void adns9800_com_end() { cs_adns9800 = HIGH; } uint8_t adns9800_read_register ( uint8_t reg_addr ) { uint8_t byte_data; adns9800_com_begin (); mcu_spi_txrx_8 ( reg_addr & 0x7F ); //send adress of the register, with MSBit = 0 to indicate it's a read Delay_us (100) ; //delayMicroseconds(100); // tSRAD byte_data = mcu_spi_txrx_8 (0); // read data Delay_us (1) ; //delayMicroseconds(1); // tSCLK-_ncs for read operation is 120ns adns9800_com_end(); Delay_us (19) ; //delayMicroseconds(19); //tSRW/tSRR (=20us) minus tSCLK-_ncs return byte_data; } void adns9800_write_register ( uint8_t reg_addr, uint8_t wk_data) { adns9800_com_begin (); mcu_spi_txrx_8 ( reg_addr | 0x80 ); //send adress of the register, with MSBit = 1 to indicate it's a write mcu_spi_txrx_8 ( wk_data ); //sent data Delay_us (20); //tSCLK-_ncs for write operation adns9800_com_end(); Delay_us (100) ; //tSWW/tSWR (=120us) minus tSCLK-_ncs. Could be shortened, but is looks like a safe lower bound } void adns9800_read_motion_burst_data () { uint8_t i; adns9800_com_begin(); mcu_spi_txrx_8 ( REG_MOTION_BURST | 0x7F ); //send adress of the register, with MSBit = 1 to indicate it's a write Delay_us (100); //delayMicroseconds(100); // tSRAD for ( i = 0; i < pixel_sum; ++i) { // read data adns9800.param [i] = mcu_spi_txrx_8 (0x00); } adns9800_com_end(); Delay_us (1); // tBEXIT } uint16_t adns9800_join_bytes ( uint8_t low, uint8_t high ) { uint16_t b = low; b |= (high << 8); return b; } int8_t adns9800_convert_twos_compliment_8 ( uint8_t b ) { int8_t val = b; //Convert from 2's complement if (b & 0x80) { val = -1 ( (b ^ 0xFF) + 1); } return val; } int16_t adns9800_convert_twos_compliment_16 (uint16_t b){ int16_t val = b; //Convert from 2's complement if ( b & 0x8000 ) { val = -1 ( (b ^ 0xFFFF) + 1); } return val; } int16_t adns9800_convert_twos_compliment_88 (uint8_t l, uint8_t h) { uint16_t b = adns9800_join_bytes(l, h); return adns9800_convert_twos_compliment_8(b); } void adns9800_copy_data() { //_squal = _data[SQUAL]; adns9800.ux = adns9800_join_bytes (adns9800.param[delta_x_l], adns9800.param[delta_x_h]); adns9800.uy = adns9800_join_bytes (adns9800.param[delta_y_l], adns9800.param[delta_y_h]); adns9800.ux_dist += adns9800.ux; adns9800.uy_dist += adns9800.uy; } void adns9800_update_motion_data() { uint8_t _mot,_fault; adns9800_com_begin(); adns9800.param[motion] = adns9800_read_register(REG_MOTION); adns9800.param[squal] = adns9800_read_register(REG_SQUAL); _mot = adns9800.param[motion] & 0x80; _fault = adns9800.param[motion] & 0x40; if ( !_fault && _mot ) { adns9800.param[delta_x_l] = adns9800_read_register(REG_DELTA_X_L); adns9800.param[delta_x_h] = adns9800_read_register(REG_DELTA_X_H); adns9800.param[delta_y_l] = adns9800_read_register(REG_DELTA_Y_L); adns9800.param[delta_y_h] = adns9800_read_register(REG_DELTA_Y_H); adns9800_copy_data(); _moved = 1; } adns9800_com_end(); } void adns9800_update_motion_burst_data() { uint8_t _mot,_fault; adns9800_com_begin(); adns9800_read_motion_burst_data(); _mot = adns9800.param[motion] & 0x80; _fault = adns9800.param[motion] & 0x40; if ( !_fault && _mot ) { adns9800_copy_data(); _moved = 1; } adns9800_com_end(); } void adns9800_upload_firmware() { uint16_t i; // send the firmware to the chip, cf p.18 of the datasheet // set the configuration_IV register in 3k firmware mode adns9800_write_register (REG_CONFIGURATION_IV, 0x02); // bit 1 = 1 for 3k mode, other bits are reserved adns9800_write_register (REG_SROM_ENABLE, 0x1d); // write 0x1d in SROM_enable reg for initializing // wait for more than one frame period Delay_ms (10); //delay(10); // assume that the frame rate is as low as 100fps... even if it should never be that low adns9800_write_register (REG_SROM_ENABLE, 0x18); // write 0x18 to SROM_enable to start SROM download //Delay_us (20); adns9800_com_begin(); mcu_spi_txrx_8 (REG_SROM_LOAD_BURST | 0x80); //SPI.transfer(REG_SROM_Load_Burst | 0x80); // write burst destination adress Delay_us (15); //for ( i = 0; i < sizeof (firmware_data)/sizeof(firmware_data[0]); i++ ) { for ( i = 0; i < firmware_length; i++ ) { mcu_spi_txrx_8 ( (uint8_t)firmware_data [i] ); //if (i <30) {out_buff_write_text(firmware_data [i] ); out_buff_write_text(" " ); } //mcu_spi_txrx_8 ( firmware_data [i] ); Delay_us (15); } adns9800_com_end(); //Delay_us (180); //adns9800.srom_id = adns9800_read_register (REG_SROM_ID); } uint16_t adns9800_check_firmware ( void ) { uint16_t crc; adns9800_write_register (REG_SROM_ENABLE, 0x15); Delay_ms (10); crc = (uint16_t) adns9800_read_register(REG_DATA_OUT_LOWER) | adns9800_read_register(REG_DATA_OUT_UPPER) << 8; return crc; } uint8_t modify_register8 ( const uint8_t *name, uint8_t address, uint8_t new_value) { uint8_t read_back; adns9800_write_register (address, new_value); read_back = adns9800_read_register ( address ); return read_back; } void modify_register16 ( uint8_t addr_upper, uint16_t new_value) { uint16_t old_value; old_value = (adns9800_read_register (addr_upper) << 8) + adns9800_read_register (addr_upper - 1); adns9800_write_register (addr_upper - 1, new_value & 0xFF); adns9800_write_register (addr_upper,new_value >> 8); //return old_value;

} void adns9800_setup() { uint8_t laser_ctrl0; uint16_t shutter_max_bound; cs_adns9800_direction = io_out; adns9800_com_end (); // ensure that the serial port is reset adns9800_com_begin (); // ensure that the serial port is reset adns9800_com_end (); // ensure that the serial port is reset adns9800_write_register (REG_POWER_UP_RESET, 0x5a); // force reset Delay_ms (50); // wait for it to reboot //read registers 0x02 to 0x06 (and discard the data) adns9800_read_register (REG_MOTION); adns9800_read_register (REG_DELTA_X_L); adns9800_read_register (REG_DELTA_X_H); adns9800_read_register (REG_DELTA_Y_L); adns9800_read_register (REG_DELTA_Y_H); //upload the firmware adns9800_upload_firmware(); Delay_ms (10); //adns9800_write_register(REG_CONFIGURATION_I, 0xA4); //adns9800_write_register(REG_CONFIGURATION_V, 0x44); //Disable rest mode, 0x08 = fixed frame rate, disable AGC //adns9800_write_register(REG_CONFIGURATION_II, 0x10 + 0x08); //modify_register16 ( REG_SHUTTER_MAX_BOUND_UPPER, 0x100); //modify_register16 ( REG_FRAME_PERIOD_MIN_BOUND_UPPER, 0x0fa0); //modify_register16 ( REG_FRAME_PERIOD_MAX_BOUND_UPPER, 0x0fa0);
// set the configuration_I register // 0x01 = 50, minimum // 0x44 = 3400, default // 0x8e = 7100 // 0xA4 = 8200, maximum modify_register8 ("REG_CONFIGURATION_I", REG_CONFIGURATION_I, 0x29); modify_register8 ("REG_CONFIGURATION_V", REG_CONFIGURATION_V, 0x09); //disable rest mode, 0x08 fixed frame rate, disable AGC modify_register8 ("REG_CONFIGURATION_II", REG_CONFIGURATION_II, 0x08 + 0x10); shutter_max_bound = 0x100; modify_register16 (REG_SHUTTER_MAX_BOUND_UPPER, shutter_max_bound); modify_register16 (REG_FRAME_PERIOD_MIN_BOUND_UPPER, 0x0fa0); modify_register16 (REG_FRAME_PERIOD_MAX_BOUND_UPPER, 0x0fa0 + shutter_max_bound); Delay_ms(2);

 //enable laser(bit 0 = 0b), in normal mode (bits 3,2,1 = 000b)
 // reading the actual value of the register is important because the real
 // default value is different from what is said in the datasheet, and if you
 // change the reserved bytes (like by writing 0x00...) it would not work.
 laser_ctrl0 = adns9800_read_register (REG_LASER_CTRL0);
 modify_register8 ( "REG_LASER_CTRL0", REG_LASER_CTRL0, (laser_ctrl0 & 0xf0) | 0x04); //CW mode, laser enabled
 //adns9800_write_register(REG_LASER_CTRL0, laser_ctrl0 & 0xF0 );
 Delay_ms (1);

}