Skip to content
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

Next set of split_common changes #4974

Merged
merged 7 commits into from
Mar 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -316,16 +316,16 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
OPT_DEFS += -DSPLIT_KEYBOARD

# Include files used by all split keyboards
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \
$(QUANTUM_DIR)/split_common/split_util.c
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_util.c

# Determine which (if any) transport files are required
ifneq ($(strip $(SPLIT_TRANSPORT)), custom)
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c
# Functions added via QUANTUM_LIB_SRC are only included in the final binary if they're called.
# Unused functions are pruned away, which is why we can add both drivers here without bloat.
QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/i2c.c \
$(QUANTUM_DIR)/split_common/serial.c
# Unused functions are pruned away, which is why we can add multiple drivers here without bloat.
QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/serial.c \
i2c_master.c \
i2c_slave.c
endif
COMMON_VPATH += $(QUANTUM_PATH)/split_common
endif
2 changes: 1 addition & 1 deletion docs/i2c_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The I2C Master drivers used in QMK have a set of common functions to allow porta
|`uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);` |Receive data over I2C. Address is the 7-bit slave address without the direction. Saves number of bytes specified by `length` in `data` array. Returns status of transaction. |
|`uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);` |Same as the `i2c_transmit` function but `regaddr` sets where in the slave the data will be written. |
|`uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);` |Same as the `i2c_receive` function but `regaddr` sets from where in the slave the data will be read. |
|`uint8_t i2c_stop(uint16_t timeout);` |Stops the I2C driver. |
|`uint8_t i2c_stop(void);` |Ends an I2C transaction. |

### Function Return

Expand Down
3 changes: 1 addition & 2 deletions drivers/arm/i2c_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t l
return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), regaddr, 1, data, length, MS2ST(timeout));
}

// This is usually not needed. It releases the driver to allow pins to become GPIO again.
uint8_t i2c_stop(uint16_t timeout)
uint8_t i2c_stop(void)
{
i2cStop(&I2C_DRIVER);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion drivers/arm/i2c_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t ti
uint8_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length);
uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
uint8_t i2c_stop(uint16_t timeout);
uint8_t i2c_stop(void);
160 changes: 67 additions & 93 deletions drivers/avr/i2c_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,82 +7,84 @@

#include "i2c_master.h"
#include "timer.h"
#include "wait.h"

#ifndef F_SCL
#define F_SCL 400000UL // SCL frequency
# define F_SCL 400000UL // SCL frequency
#endif
#define Prescaler 1
#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2)
#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16) / 2)

void i2c_init(void)
{
TWSR = 0; /* no prescaler */
void i2c_init(void) {
TWSR = 0; /* no prescaler */
TWBR = (uint8_t)TWBR_val;
}

i2c_status_t i2c_start(uint8_t address, uint16_t timeout)
{
i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
// reset TWI control register
TWCR = 0;
// transmit START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);

uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
}

// check if the start condition was successfully transmitted
if(((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)){ return I2C_STATUS_ERROR; }
if (((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)) {
return I2C_STATUS_ERROR;
}

// load slave address into data register
TWDR = address;
// start transmission of address
TWCR = (1<<TWINT) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWEN);

timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
}

// check if the device has acknowledged the READ / WRITE mode
uint8_t twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return I2C_STATUS_ERROR;
if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
return I2C_STATUS_ERROR;
}

return I2C_STATUS_SUCCESS;
}

i2c_status_t i2c_write(uint8_t data, uint16_t timeout)
{
i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
// load data into data register
TWDR = data;
// start transmission of data
TWCR = (1<<TWINT) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWEN);

uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
}

if( (TW_STATUS & 0xF8) != TW_MT_DATA_ACK ){ return I2C_STATUS_ERROR; }
if ((TW_STATUS & 0xF8) != TW_MT_DATA_ACK) {
return I2C_STATUS_ERROR;
}

return I2C_STATUS_SUCCESS;
}

int16_t i2c_read_ack(uint16_t timeout)
{

int16_t i2c_read_ack(uint16_t timeout) {
// start TWI module and acknowledge data after reception
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);

uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
Expand All @@ -92,14 +94,12 @@ int16_t i2c_read_ack(uint16_t timeout)
return TWDR;
}

int16_t i2c_read_nack(uint16_t timeout)
{

int16_t i2c_read_nack(uint16_t timeout) {
// start receiving without acknowledging reception
TWCR = (1<<TWINT) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWEN);

uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
Expand All @@ -109,115 +109,89 @@ int16_t i2c_read_nack(uint16_t timeout)
return TWDR;
}

i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
if (status) return status;

for (uint16_t i = 0; i < length; i++) {
for (uint16_t i = 0; i < length && status >= 0; i++) {
status = i2c_write(data[i], timeout);
if (status) return status;
}

status = i2c_stop(timeout);
if (status) return status;
i2c_stop();

return I2C_STATUS_SUCCESS;
return status;
}

i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(address | I2C_READ, timeout);
if (status) return status;

for (uint16_t i = 0; i < (length-1); i++) {
for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
status = i2c_read_ack(timeout);
if (status >= 0) {
data[i] = status;
} else {
return status;
}
}

status = i2c_read_nack(timeout);
if (status >= 0 ) {
data[(length-1)] = status;
} else {
return status;
if (status >= 0) {
status = i2c_read_nack(timeout);
if (status >= 0) {
data[(length - 1)] = status;
}
}

status = i2c_stop(timeout);
if (status) return status;
i2c_stop();

return I2C_STATUS_SUCCESS;
return status;
}

i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
if (status) return status;

status = i2c_write(regaddr, timeout);
if (status) return status;
if (status >= 0) {
status = i2c_write(regaddr, timeout);

for (uint16_t i = 0; i < length; i++) {
status = i2c_write(data[i], timeout);
if (status) return status;
for (uint16_t i = 0; i < length && status >= 0; i++) {
status = i2c_write(data[i], timeout);
}
}

status = i2c_stop(timeout);
if (status) return status;
i2c_stop();

return I2C_STATUS_SUCCESS;
return status;
}

i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(devaddr, timeout);
if (status) return status;
if (status < 0) {
goto error;
}

status = i2c_write(regaddr, timeout);
if (status) return status;

status = i2c_stop(timeout);
if (status) return status;
if (status < 0) {
goto error;
}

status = i2c_start(devaddr | 0x01, timeout);
if (status) return status;

for (uint16_t i = 0; i < (length-1); i++) {
for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
status = i2c_read_ack(timeout);
if (status >= 0) {
data[i] = status;
} else {
return status;
}
}

status = i2c_read_nack(timeout);
if (status >= 0 ) {
data[(length-1)] = status;
} else {
return status;
if (status >= 0) {
status = i2c_read_nack(timeout);
if (status >= 0) {
data[(length - 1)] = status;
}
}

status = i2c_stop(timeout);
if (status) return status;
error:
i2c_stop();

return I2C_STATUS_SUCCESS;
return status;
}

i2c_status_t i2c_stop(uint16_t timeout)
{
void i2c_stop(void) {
// transmit STOP condition
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

uint16_t timeout_timer = timer_read();
while(TWCR & (1<<TWSTO)) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
}

return I2C_STATUS_SUCCESS;
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
}
2 changes: 1 addition & 1 deletion drivers/avr/i2c_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint1
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_stop(uint16_t timeout);
void i2c_stop(void);

#endif // I2C_MASTER_H
2 changes: 1 addition & 1 deletion drivers/avr/i2c_slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ static volatile bool slave_has_register_set = false;

void i2c_slave_init(uint8_t address){
// load address into TWI address register
TWAR = (address << 1);
TWAR = address;
// set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
TWCR = (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
}
Expand Down
2 changes: 1 addition & 1 deletion keyboards/cannonkeys/satisfaction75/i2c_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t l
}

// This is usually not needed. It releases the driver to allow pins to become GPIO again.
uint8_t i2c_stop(uint16_t timeout)
uint8_t i2c_stop(void)
{
i2cStop(&I2C_DRIVER);
return 0;
Expand Down
4 changes: 2 additions & 2 deletions keyboards/dc01/left/matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,10 @@ i2c_status_t i2c_transaction(uint8_t address, uint32_t mask, uint8_t col_offset)
matrix[MATRIX_ROWS - 1] |= ((uint32_t)err << (MATRIX_COLS_SCANNED + col_offset)); //add new bits at the end

} else {
i2c_stop(10);
i2c_stop();
return 1;
}

i2c_stop(10);
i2c_stop();
return 0;
}
6 changes: 3 additions & 3 deletions keyboards/ergodox_ez/ergodox_ez.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ uint8_t init_mcp23018(void) {
mcp23018_status = i2c_write(IODIRA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b00000000, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
mcp23018_status = i2c_write(0b00111111, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
i2c_stop(ERGODOX_EZ_I2C_TIMEOUT);
i2c_stop();

// set pull-up
// - unused : on : 1
Expand All @@ -140,7 +140,7 @@ uint8_t init_mcp23018(void) {
mcp23018_status = i2c_write(0b00111111, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;

out:
i2c_stop(ERGODOX_EZ_I2C_TIMEOUT);
i2c_stop();

#ifdef LEFT_LEDS
if (!mcp23018_status) mcp23018_status = ergodox_left_leds_update();
Expand Down Expand Up @@ -179,7 +179,7 @@ uint8_t ergodox_left_leds_update(void) {
if (mcp23018_status) goto out;

out:
i2c_stop(ERGODOX_EZ_I2C_TIMEOUT);
i2c_stop();
return mcp23018_status;
}
#endif
Expand Down
Loading