-
-
Notifications
You must be signed in to change notification settings - Fork 39.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
i2c_master: Add support for reading/writing to 16-bit registers #14289
Conversation
I definitely don't like this. But part of that is because I think it has already been implemented using i2c already, elsewhere. Eg, for the cirque trackpad that I've been working on: /* ERA (Extended Register Access) Functions */
// Reads <count> bytes from an extended register at <address> (16-bit address),
// stores values in <*data>
void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) {
uint8_t ERAControlValue = 0xFF;
Pinnacle_EnableFeed(false); // Disable feed
RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Send upper byte of ERA address
RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address
for (uint16_t i = 0; i < count; i++) {
RAP_Write(ERA_CONTROL, 0x05); // Signal ERA-read (auto-increment) to Pinnacle
// Wait for status register 0x1E to clear
do {
RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1);
} while (ERAControlValue != 0x00);
RAP_ReadBytes(ERA_VALUE, data + i, 1);
Pinnacle_ClearFlags();
}
}
// Writes a byte, <data>, to an extended register at <address> (16-bit address)
void ERA_WriteByte(uint16_t address, uint8_t data) {
uint8_t ERAControlValue = 0xFF;
Pinnacle_EnableFeed(false); // Disable feed
RAP_Write(ERA_VALUE, data); // Send data byte to be written
RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Upper byte of ERA address
RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address
RAP_Write(ERA_CONTROL, 0x02); // Signal an ERA-write to Pinnacle
// Wait for status register 0x1E to clear
do {
RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1);
} while (ERAControlValue != 0x00);
Pinnacle_ClearFlags();
}
/* RAP Functions */
// Reads <count> Pinnacle registers starting at <address>
void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
uint8_t cmdByte = READ_MASK | address; // Form the READ command byte
// uint8_t i = 0;
if (touchpad_init[0]) {
i2c_writeReg(SLAVE_ADDR << 1, cmdByte, NULL, 0, I2C_TIMEOUT);
if (i2c_readReg(SLAVE_ADDR << 1, cmdByte, data, count, I2C_TIMEOUT) != I2C_STATUS_SUCCESS) {
dprintf("error right touchpad\n");
touchpad_init[0] = false;
}
i2c_stop();
}
if (touchpad_init[1]) {
i2c2_writeReg(SLAVE_ADDR << 1, cmdByte, NULL, 0, I2C_TIMEOUT);
if (i2c2_readReg(SLAVE_ADDR << 1, cmdByte, data, count, I2C_TIMEOUT) != I2C_STATUS_SUCCESS) {
dprintf("error left touchpad\n");
touchpad_init[1] = false;
}
i2c2_stop();
}
}
// Writes single-byte <data> to <address>
void RAP_Write(uint8_t address, uint8_t data) {
uint8_t cmdByte = WRITE_MASK | address; // Form the WRITE command byte
if (touchpad_init[0]) {
if (i2c_writeReg(SLAVE_ADDR << 1, cmdByte, &data, sizeof(data), I2C_TIMEOUT) != I2C_STATUS_SUCCESS) {
dprintf("error right touchpad\n");
touchpad_init[0] = false;
}
i2c_stop();
}
if (address == FEEDCONFIG_1 && data == FEEDCONFIG_1_VALUE) {
data = 0xC3;
}
if (touchpad_init[1]) {
if (i2c2_writeReg(SLAVE_ADDR << 1, cmdByte, &data, sizeof(data), I2C_TIMEOUT) != I2C_STATUS_SUCCESS) {
dprintf("error left touchpad\n");
touchpad_init[1] = false;
}
i2c2_stop();
}
} |
I'm not sure what your point is here. Yes, you could build on the existing API to "emulate" 16-bit register access (which this PR is doing too), but then you need to do that for every such device driver. Why not just have it in core? It won't be compiled in if it's not used. |
More importantly, it seems that the cirque trackpad just has some features so that it could work even when the I2C master cannot do 16-bit addressing; however, the trackpad that inspired this PR apparently does not have any such features. Maybe it could even make sense to expose the underlying API in a more general form, allowing arbitrary sizes for both phases: i2c_status_t i2c_transaction(uint8_t devaddr, const uint8_t *txdata, uint16_t txsize, uint8_t *rxdata, uint16_t rxsize, uint16_t timeout); |
Looks good to me |
@purdeaandrei did you have anything else to add on this? |
Nope, looks good to me |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but I don't have any hardware to verify this.
* qmk/develop: (47 commits) Correct the Turkish F '?' keycode (TR_QUES) (qmk#14740) Enabled Bootmagic Lite (qmk#14573) Remove SERIAL_LINK feature (qmk#14727) Reuse of EEPROM debounce logic (qmk#14699) Fix i2c_readReg16 (qmk#14730) Purge uGFX. (qmk#14720) i2c_master: Add support for reading/writing to 16-bit registers (qmk#14289) Updated Keychron Q1 user keymap (qmk#14666) Mode M65S touch-up (qmk#14722) Remove sysex API (qmk#14723) MelGeek Mach80: correct Configurator layout (qmk#14716) Added semicolons to rules.mk to allow symlinks from /bin/sh to /bin/zsh to complete the filesize check without error. (qmk#14718) Move Audio drivers from quantum to platform drivers folder (qmk#14308) [Bug] Fix command feature if mousekey is enabled and using 3-speed setting (qmk#14697) [Keyboard] Add basic Keyhive Sofle support (qmk#14296) [Keymap] Some updates to mechmerlin userspace and keymaps (qmk#14711) 0xc7/61key touch-up (qmk#14712) Durgod DGK6X Galaxy: correct Configurator layout (qmk#14714) More PR checklist updates (qmk#14705) Add clarification for licensing. (qmk#14704) ...
Description
I2C itself has no concept of registers, but for devices that do specify the first two bytes of a given transaction as the "register address", this should provide an easier to use interface than splitting the address up manually into the
regaddr
parameter and the first actual data byte.Types of Changes
Issues Fixed or Closed by This PR
Checklist