Increase T4.1 wire buffer to 512 bytes

Status
Not open for further replies.

rrace001

Member
I have a setup where I had to increase the Adafruit SAMD Wire Rx buffer from 256 to 512 in order to receive data from a ST VL53L5CX on an Adafruit M0 board (QT Py) and it works well. I am new to Teensy and had tried to do this for the T4.1 but is not working. I tried increasing BUFFER_LENGTH on line 35 from 32 bytes to 512 bytes in the WireIMXRT.h file but no go.

Before increasing the buffer on the T4.1, the sensor would initialize (load firmware to the sensor) and then report but just with no data. After I increase the buffer then the sensor does not initialize and the T4.1 just locks up. I kept reducing the buffer down to see what it would do and when I got to 128 it would initialize and report but the same with no data. 512 is what got it going on the M0 so this is my target.

Any suggestions?
 
Still locks up. I looked in the twi.cpp and all the code is for the AVR.

I believe I found it. The qty / length in requestFrom is 8bit. This function is heavily overloaded so it will take a little time to change to 16bit. I will post the results after I make the change.
 
So got it to compile after changing to 16bit but same behavior. Took a dive in the data sheet and I think the Wire library is using a hardware buffer that is only 256 bytes. It looks like the MCU can flag when the buffer is full so maybe this could be incorporated in the wire library for the user to handle receives larger than 256 bytes.

Can anyone confirm?
 
I found a way to get the sensor data without increasing the Wire buffer. I could have done this all along but it took some more learning on my part. It would be good to have a hardware version but I am up an running on the T4.1.

This thing is FAST. Ran some matrix math on the M0 and it took about 8600 microseconds - ran the same on the T4.1 and it took 18 microseconds. WOW!!! It's a whole new world...
 
The sensor comes with an API that you just add in your platform i2c commands for reading/writing. In the read multiple bytes function (RdMulti) I created a buffer limit variable (buffer_byte_limit) and if the API requests more than this then it breaks it up into multiple Wire.requestFrom. It did not dawn on me to do this until I finally read the code for Wire.requestFrom. For some reason I assumed that Wire.read() talks directly to the bus but the learned that it just reads from the buffer created by Wire.requestFrom - hence the whole buffer limit. I still need to clean up the code for the status/error checking but it works as is.

Code:
uint8_t RdMulti(
		VL53L5CX_Platform *p_platform,
		uint16_t RegisterAddress,
		uint8_t *p_values,
		uint32_t size)
{
	uint8_t status = 255;
	const uint16_t buffer_byte_limit = 32;

	Wire.beginTransmission(p_platform->address);
	Wire.write((RegisterAddress >> 8) & 0xFF);
	Wire.write(RegisterAddress & 0xFF); 
	status = Wire.endTransmission();	


	if (int((size - 1.0) / buffer_byte_limit) == 0){

		Wire.requestFrom(p_platform->address, size);

		while(size--){
			*p_values = Wire.read();
			p_values++;
		}

	} else {

		Wire.requestFrom(p_platform->address, buffer_byte_limit);
		uint16_t bytes_read = buffer_byte_limit;
		uint16_t bytes_left = size;		

		while(bytes_left){	

			bytes_left -= bytes_read;		
			
			while(bytes_read--){
				*p_values = Wire.read();
				p_values++;
				RegisterAddress++;
			}

			if(bytes_left){
				Wire.beginTransmission(p_platform->address);
				Wire.write((RegisterAddress >> 8) & 0xFF);
				Wire.write(RegisterAddress & 0xFF); 
				status = Wire.endTransmission();
				bytes_read = (bytes_left > buffer_byte_limit)?buffer_byte_limit:bytes_left;
				Wire.requestFrom(p_platform->address, bytes_read );
			}		
		} 
	}
	
	return status;
}
 
I've been playing around with the repeated start feature of I2C. Although you can't read a large amount of data (e.g. 512 bytes) in one call to requestFrom, you can use the repeated start (if the sensor will handle it) to read the data in chunks. I tested it on a DS3231 RTC which has 19 registers. I first read them all with one call to requestFrom and then read them in two chunks of 10 and then 9 using repeated start. The two methods return the same data.
This is a function which reads/prints the 19 registers all in one go.
Code:
// Use standard method to request all 19 bytes in one
// call to requestFrom
unsigned char RTC_read_registers(void)
{
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 0x13);
  for(int i = 0; i < 0x13; i++) {
    Serial.printf("%02X ",Wire.read());
  }
  Serial.println();
}

and this does the same thing but in two chunks using repeated start.
Code:
// Use a repeated START
// First read 10 bytes with repeated START
// Then read the remaining 9 bytes with
// a standard call which will end with a STOP
// This works with the DS3231
unsigned char RTC_read_registers_rstart(void)
{
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  // Read 10 bytes and do not send a STOP
  Wire.requestFrom(CLOCK_ADDRESS, 10,0);
  for(int i = 0; i < 10; i++) {
    Serial.printf("%02X ",Wire.read());
  }
  // Read the remaining 9 bytes and send the STOP
  // which is the default action with requestFrom
  // when it has two arguments.
  Wire.requestFrom(CLOCK_ADDRESS, 9);
  for(int i = 0; i < 9; i++) {
    Serial.printf("%02X ",Wire.read());
  }
  Serial.println();
}

One advantage to the repeated start is that it only has to reissue the device address but not the register address. It relies on the fact that the sensor automatically increments the current address after each read, so the processor doesn't also have to reissue a register address. This will speed up the transmission, especially when you have to read 512 bytes in chunks of 32 bytes.
Of course, if you need to speed it up more, you can edit the library buffer size (to 128 say) and reduce the number of requestFrom calls that are required.

You might be able to do the same kind of thing with the VL53L5CX.
Pete
 
Yes. I did not think of that. The VL53L5CX does auto increment the address so I put in a false for releasing the bus then removed the manual incrementing and manual setting of the address. Thanks!
 
Status
Not open for further replies.
Back
Top