The maximum bytes that I2C can write or read on teensy 4.1

zhichao

Member
Do you know the maximum bytes that I2C can write or read on teensy 4.1 by Wire.write(data, length) or Wire.requestFrom(address, quantity) ?

I want to write 1024 bytes or read 256 bytes in a I2C transmission. Do you know how to do?
 
At the very least I would have thought that we would need to know what you are reading from/writing to.
 
Write camera registers, and read camera registers to debug. Writing about three thousand registers is required to let the camera work. There are approximately 1000 registers with consecutive addresses
 
Camera has chip. To make the camera work, it is necessary to configure the chip on the camera.
About three thousand registers are required to be configured. These registers are from open-source code of the camera driver.
 
What have you tried?
If you are using the wire library, it looks like it is configured for:
#define BUFFER_LENGTH 136

You might get away with increasing it...

Do you need to read/write all of them at once, or can tell it this is the register I wish to start with, and then
do reads and writes from there?

Have you tried request from with optional parameter, sendStop:
 
There are approximately 1000 registers with consecutive addresses

But is editing the library buffer size really valuable for this use case? Writing all 1000 in a single large transfer would be only slightly faster than performing 8 writes of 120 bytes. Sending the I2C address, register address (or whatever other command bytes this device needs) and the start & stop condition 7 more times is only minimal overhead.

Still, if you really want to do all 1000 in a single transfer, you probably can make it work. Just edit WireIMXRT.h to make the buffer huge and the index variables 16 bits rather than only 8 bits. Make a backup copy in a safe place, in case a future update or install overwrites that file.
 
Thanks.
Performing 8 writes of 120 bytes is a good idea for me. But I need to implement the requirement proposed by the customer.
Is it possible to perform a write of 120 bytes then call Wire.endTransmission(false), loop 8 times, at last call Wire.endTransmission(true)?

The purpose of calling Wire.endTransmission(false) is to send 120 bytes to i2c bus, but don't send stop.
 
The purpose of calling Wire.endTransmission(false) is to send 120 bytes to i2c bus, but don't send stop.

Yes, you can use Wire.endTransmission(false) for the first 7 if you don't want to send a stop condition. Of course you should use regular Wire.endTransmission() for the last transfer to send a stop.

Or you could edit the library code for a large buffer if you really want to do it all as 1 large transfer.
 
I did indeed do this exact thing in a project of mine that uses a teensy micromod. I copied the I2C code to my project and just edited it to accept 258 bytes in the buffer so I could send all at once. I did this because my EEPROM I'm using has 256 byte pages (plus the bytes to set up where you want to write to) and its just easiest to blast it all out at once and not have to bother with doing two transfers. So, I know the idea can work. You might say one should just do a series of smaller transfers instead. That's valid too, I just wanted to be able to fire once and forget it so that's what I did.
 
Sorry for late reply.
I changed code according to "When you edit BUFFER_LENGTH also edit rxBufferIndex, rxBufferLength, txBufferIndex, txBufferLength. They're in WireIMXRT.h starting at line 171. These are currently uint8_t. If you make the buffer larger than 255, they will need to become uint16_t."
And I wrote 1024 bytes at once. Although wire->write(i2c_data, 1024) returned 0, the teensy4.1 wrote about 559 bytes to i2c bus not 1024 bytes. I catched the i2c signal on i2c bus by DSLogic tool, found it.
I don't find the cod limitation. Do you know how to resolve it?
 
my changes:
//#define BUFFER_LENGTH 136
#define BUFFER_LENGTH 1056


#if 0
uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop);
uint8_t requestFrom(uint8_t address, uint8_t quantity, bool sendStop) {
return requestFrom(address, quantity, (uint8_t)(sendStop ? 1 : 0));
}
uint8_t requestFrom(uint8_t address, uint8_t quantity) {
return requestFrom(address, quantity, (uint8_t)1);
}
uint8_t requestFrom(int address, int quantity, int sendStop) {
return requestFrom((uint8_t)address, (uint8_t)quantity,
(uint8_t)(sendStop ? 1 : 0));
}
uint8_t requestFrom(int address, int quantity) {
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)1);
}
uint8_t requestFrom(uint8_t addr, uint8_t qty, uint32_t iaddr, uint8_t n, uint8_t stop);
#endif
uint8_t requestFrom(uint8_t address, uint16_t quantity, uint8_t sendStop);
uint8_t requestFrom(uint8_t address, uint16_t quantity, bool sendStop) {
return requestFrom(address, quantity, (uint8_t)(sendStop ? 1 : 0));
}
uint8_t requestFrom(uint8_t address, uint16_t quantity) {
return requestFrom(address, quantity, (uint8_t)1);
}
uint8_t requestFrom(int address, int quantity, int sendStop) {
return requestFrom((uint8_t)address, (uint16_t)quantity,
(uint8_t)(sendStop ? 1 : 0));
}
uint8_t requestFrom(int address, int quantity) {
return requestFrom((uint8_t)address, (uint16_t)quantity, (uint8_t)1);
}
uint8_t requestFrom(uint8_t addr, uint16_t qty, uint32_t iaddr, uint8_t n, uint8_t stop);



//uint8_t rxBufferIndex = 0;
//uint8_t rxBufferLength = 0;
uint16_t rxBufferIndex = 0;
uint16_t rxBufferLength = 0;


//uint8_t txBufferIndex = 0;
//uint8_t txBufferLength = 0;
uint16_t txBufferIndex = 0;
uint16_t txBufferLength = 0;



//uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
uint8_t TwoWire::requestFrom(uint8_t address, uint16_t length, uint8_t sendStop)
{
IMXRT_LPI2C_t* port = (IMXRT_LPI2C_t*)portAddr;
if (!wait_idle()) return 4;
address = (address & 0x7F) << 1;
if (length < 1) length = 1;
//ares mod
//if (length > 255) length = 255;
rxBufferIndex = 0;
rxBufferLength = 0;
 
I find the limitation. The timeout value needs to be changed in function endTransmission "if ((status & LPI2C_MSR_PLTF) || timeout > 50) "
 
Back
Top