Refactor use of legacy i2c implementation (#14341)
This commit is contained in:
		| @@ -1,178 +0,0 @@ | ||||
| #ifndef _I2CMASTER_H | ||||
| #define _I2CMASTER_H   1 | ||||
| /*************************************************************************  | ||||
| * Title:    C include file for the I2C master interface  | ||||
| *           (i2cmaster.S or twimaster.c) | ||||
| * Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury | ||||
| * File:     $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $ | ||||
| * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 | ||||
| * Target:   any AVR device | ||||
| * Usage:    see Doxygen manual | ||||
| **************************************************************************/ | ||||
|  | ||||
| #ifdef DOXYGEN | ||||
| /** | ||||
|  @defgroup pfleury_ic2master I2C Master library | ||||
|  @code #include <i2cmaster.h> @endcode | ||||
|    | ||||
|  @brief I2C (TWI) Master Software Library | ||||
|  | ||||
|  Basic routines for communicating with I2C slave devices. This single master  | ||||
|  implementation is limited to one bus master on the I2C bus.  | ||||
|  | ||||
|  This I2c library is implemented as a compact assembler software implementation of the I2C protocol  | ||||
|  which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c). | ||||
|  Since the API for these two implementations is exactly the same, an application can be linked either against the | ||||
|  software I2C implementation or the hardware I2C implementation. | ||||
|  | ||||
|  Use 4.7k pull-up resistor on the SDA and SCL pin. | ||||
|   | ||||
|  Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module  | ||||
|  i2cmaster.S to your target when using the software I2C implementation !  | ||||
|   | ||||
|  Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion. | ||||
|  | ||||
|  @note  | ||||
|     The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted  | ||||
|     to GNU assembler and AVR-GCC C call interface. | ||||
|     Replaced the incorrect quarter period delays found in AVR300 with  | ||||
|     half period delays.  | ||||
|      | ||||
|  @author Peter Fleury pfleury@gmx.ch  http://jump.to/fleury | ||||
|  | ||||
|  @par API Usage Example | ||||
|   The following code shows typical usage of this library, see example test_i2cmaster.c | ||||
|  | ||||
|  @code | ||||
|  | ||||
|  #include <i2cmaster.h> | ||||
|  | ||||
|  | ||||
|  #define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet | ||||
|  | ||||
|  int main(void) | ||||
|  { | ||||
|      unsigned char ret; | ||||
|  | ||||
|      i2c_init();                             // initialize I2C library | ||||
|  | ||||
|      // write 0x75 to EEPROM address 5 (Byte Write)  | ||||
|      i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode | ||||
|      i2c_write(0x05);                        // write address = 5 | ||||
|      i2c_write(0x75);                        // write value 0x75 to EEPROM | ||||
|      i2c_stop();                             // set stop conditon = release bus | ||||
|  | ||||
|  | ||||
|      // read previously written value back from EEPROM address 5  | ||||
|      i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode | ||||
|  | ||||
|      i2c_write(0x05);                        // write address = 5 | ||||
|      i2c_rep_start(Dev24C02+I2C_READ);       // set device address and read mode | ||||
|  | ||||
|      ret = i2c_readNak();                    // read one byte from EEPROM | ||||
|      i2c_stop(); | ||||
|  | ||||
|      for(;;); | ||||
|  } | ||||
|  @endcode | ||||
|  | ||||
| */ | ||||
| #endif /* DOXYGEN */ | ||||
|  | ||||
| /**@{*/ | ||||
|  | ||||
| #if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 | ||||
| #error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" | ||||
| #endif | ||||
|  | ||||
| #include <avr/io.h> | ||||
|  | ||||
| /** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */ | ||||
| #define I2C_READ    1 | ||||
|  | ||||
| /** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */ | ||||
| #define I2C_WRITE   0 | ||||
|  | ||||
|  | ||||
| /** | ||||
|  @brief initialize the I2C master interace. Need to be called only once  | ||||
|  @param  void | ||||
|  @return none | ||||
|  */ | ||||
| extern void i2c_init(void); | ||||
|  | ||||
|  | ||||
| /**  | ||||
|  @brief Terminates the data transfer and releases the I2C bus  | ||||
|  @param void | ||||
|  @return none | ||||
|  */ | ||||
| extern void i2c_stop(void); | ||||
|  | ||||
|  | ||||
| /**  | ||||
|  @brief Issues a start condition and sends address and transfer direction  | ||||
|    | ||||
|  @param    addr address and transfer direction of I2C device | ||||
|  @retval   0   device accessible  | ||||
|  @retval   1   failed to access device  | ||||
|  */ | ||||
| extern unsigned char i2c_start(unsigned char addr); | ||||
|  | ||||
|  | ||||
| /** | ||||
|  @brief Issues a repeated start condition and sends address and transfer direction  | ||||
|  | ||||
|  @param   addr address and transfer direction of I2C device | ||||
|  @retval  0 device accessible | ||||
|  @retval  1 failed to access device | ||||
|  */ | ||||
| extern unsigned char i2c_rep_start(unsigned char addr); | ||||
|  | ||||
|  | ||||
| /** | ||||
|  @brief Issues a start condition and sends address and transfer direction  | ||||
|     | ||||
|  If device is busy, use ack polling to wait until device ready  | ||||
|  @param    addr address and transfer direction of I2C device | ||||
|  @return   none | ||||
|  */ | ||||
| extern void i2c_start_wait(unsigned char addr); | ||||
|  | ||||
|   | ||||
| /** | ||||
|  @brief Send one byte to I2C device | ||||
|  @param    data  byte to be transfered | ||||
|  @retval   0 write successful | ||||
|  @retval   1 write failed | ||||
|  */ | ||||
| extern unsigned char i2c_write(unsigned char data); | ||||
|  | ||||
|  | ||||
| /** | ||||
|  @brief    read one byte from the I2C device, request more data from device  | ||||
|  @return   byte read from I2C device | ||||
|  */ | ||||
| extern unsigned char i2c_readAck(void); | ||||
|  | ||||
| /** | ||||
|  @brief    read one byte from the I2C device, read is followed by a stop condition  | ||||
|  @return   byte read from I2C device | ||||
|  */ | ||||
| extern unsigned char i2c_readNak(void); | ||||
|  | ||||
| /**  | ||||
|  @brief    read one byte from the I2C device | ||||
|   | ||||
|  Implemented as a macro, which calls either i2c_readAck or i2c_readNak | ||||
|   | ||||
|  @param    ack 1 send ack, request more data from device<br> | ||||
|                0 send nak, read is followed by a stop condition  | ||||
|  @return   byte read from I2C device | ||||
|  */ | ||||
| extern unsigned char i2c_read(unsigned char ack); | ||||
| #define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak();  | ||||
|  | ||||
|  | ||||
| /**@}*/ | ||||
| #endif | ||||
| @@ -243,15 +243,11 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) | ||||
|         /* if there was an error */ | ||||
|         return 0; | ||||
|     } else { | ||||
|         uint16_t data = 0; | ||||
|         mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out; | ||||
|         mcp23018_status = i2c_write(GPIOA);             if (mcp23018_status) goto out; | ||||
|         mcp23018_status = i2c_start(I2C_ADDR_READ);     if (mcp23018_status) goto out; | ||||
|         data = i2c_readNak(); | ||||
|         data = ~data; | ||||
|     out: | ||||
|         i2c_stop(); | ||||
|         current_matrix[current_row] |= (data << 8); | ||||
|         uint8_t data = 0; | ||||
|         mcp23018_status = i2c_readReg(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT); | ||||
|         if (!mcp23018_status) { | ||||
|             current_matrix[current_row] |= (~((uint16_t)data) << 8); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* For each col... */ | ||||
| @@ -278,11 +274,8 @@ static void select_row(uint8_t row) | ||||
|         /* set active row low  : 0 | ||||
|            set active row output : 1 | ||||
|            set other rows hi-Z : 1 */ | ||||
|         mcp23018_status = i2c_start(I2C_ADDR_WRITE);   if (mcp23018_status) goto out; | ||||
|         mcp23018_status = i2c_write(GPIOB);            if (mcp23018_status) goto out; | ||||
|         mcp23018_status = i2c_write(0xFF & ~(1<<abs(row-4))); if (mcp23018_status) goto out; | ||||
|     out: | ||||
|         i2c_stop(); | ||||
|         uint8_t port = 0xFF & ~(1<<abs(row-4)); | ||||
|         mcp23018_status = i2c_writeReg(I2C_ADDR, GPIOB, &port, 1, I2C_TIMEOUT); | ||||
|     } | ||||
|  | ||||
|     uint8_t pin = row_pins[row]; | ||||
|   | ||||
| @@ -27,5 +27,5 @@ RGBLIGHT_ENABLE = no | ||||
| CUSTOM_MATRIX = yes | ||||
|  | ||||
| # project specific files | ||||
| SRC =  twimaster.c \ | ||||
|   matrix.c | ||||
| QUANTUM_LIB_SRC += i2c_master.c | ||||
| SRC += matrix.c | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| #include "sx60.h" | ||||
| #include "i2cmaster.h" | ||||
| #include "i2c_master.h" | ||||
|  | ||||
|  | ||||
| bool i2c_initialized = 0; | ||||
| @@ -18,21 +18,18 @@ uint8_t init_mcp23018(void) { | ||||
|  | ||||
|     /* B Pins are Row, A pins are Columns  | ||||
|        Set them to output */ | ||||
|     mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out; | ||||
|     mcp23018_status = i2c_write(IODIRA);            if (mcp23018_status) goto out; | ||||
|     mcp23018_status = i2c_write(0b11111111);        if (mcp23018_status) goto out; | ||||
|     /* Now write to IODIRB */ | ||||
|     mcp23018_status = i2c_write(0b00000000);        if (mcp23018_status) goto out; | ||||
|     i2c_stop(); | ||||
|     static uint8_t direction[2] = { | ||||
|         0b11111111, | ||||
|         0b00000000, | ||||
|     }; | ||||
|     static uint8_t pullup[2] = { | ||||
|         0b11111111, | ||||
|         0b00000000, | ||||
|     }; | ||||
|  | ||||
|     mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out; | ||||
|     mcp23018_status = i2c_write(GPPUA);             if (mcp23018_status) goto out; | ||||
|     mcp23018_status = i2c_write(0b11111111);        if (mcp23018_status) goto out; | ||||
|     /* Now write to GPPUB */ | ||||
|     mcp23018_status = i2c_write(0b00000000);        if (mcp23018_status) goto out; | ||||
|  | ||||
| out: | ||||
|     i2c_stop(); | ||||
|     mcp23018_status = i2c_writeReg(I2C_ADDR, IODIRA, direction, 2, I2C_TIMEOUT); | ||||
|     if (mcp23018_status) return mcp23018_status; | ||||
|  | ||||
|     mcp23018_status = i2c_writeReg(I2C_ADDR, GPPUA, pullup, 2, I2C_TIMEOUT); | ||||
|     return mcp23018_status; | ||||
| } | ||||
|   | ||||
| @@ -4,13 +4,12 @@ | ||||
| #include "quantum.h" | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include "i2cmaster.h" | ||||
| #include "i2c_master.h" | ||||
| #include <util/delay.h> | ||||
|  | ||||
| /* I2C aliases and register addresses (see "mcp23018.md") */ | ||||
| #define I2C_ADDR        0b0100000 | ||||
| #define I2C_ADDR_WRITE  ( (I2C_ADDR<<1) | I2C_WRITE ) | ||||
| #define I2C_ADDR_READ   ( (I2C_ADDR<<1) | I2C_READ  ) | ||||
| #define I2C_TIMEOUT     100 | ||||
| #define IODIRA          0x00            /* i/o direction register */ | ||||
| #define IODIRB          0x01 | ||||
| #define GPPUA           0x0C            /* GPIO pull-up resistor register */ | ||||
|   | ||||
| @@ -1,207 +0,0 @@ | ||||
| /************************************************************************* | ||||
| * Title:    I2C master library using hardware TWI interface | ||||
| * Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury | ||||
| * File:     $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ | ||||
| * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 | ||||
| * Target:   any AVR device with hardware TWI | ||||
| * Usage:    API compatible with I2C Software Library i2cmaster.h | ||||
| **************************************************************************/ | ||||
| #include <inttypes.h> | ||||
| #include <compat/twi.h> | ||||
|  | ||||
| #include <i2cmaster.h> | ||||
|  | ||||
| /* define CPU frequency in Hz here if not defined in Makefile */ | ||||
| #ifndef F_CPU | ||||
| #define F_CPU 16000000UL | ||||
| #endif | ||||
|  | ||||
| /* I2C clock in Hz */ | ||||
| #define SCL_CLOCK  400000L | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|  Initialization of the I2C bus interface. Need to be called only once | ||||
| *************************************************************************/ | ||||
| void i2c_init(void) | ||||
| { | ||||
|   /* initialize TWI clock | ||||
|    * minimal values in Bit Rate Register (TWBR) and minimal Prescaler | ||||
|    * bits in the TWI Status Register should give us maximal possible | ||||
|    * I2C bus speed - about 444 kHz | ||||
|    * | ||||
|    * for more details, see 20.5.2 in ATmega16/32 secification | ||||
|    */ | ||||
|  | ||||
|   TWSR = 0;     /* no prescaler */ | ||||
|   TWBR = 10;    /* must be >= 10 for stable operation */ | ||||
|  | ||||
| }/* i2c_init */ | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|   Issues a start condition and sends address and transfer direction. | ||||
|   return 0 = device accessible, 1= failed to access device | ||||
| *************************************************************************/ | ||||
| unsigned char i2c_start(unsigned char address) | ||||
| { | ||||
|     uint8_t   twst; | ||||
|  | ||||
|   /* send START condition */ | ||||
|   TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); | ||||
|   | ||||
|   /* wait until transmission completed */ | ||||
|   while(!(TWCR & (1<<TWINT))); | ||||
|  | ||||
|   /* check value of TWI Status Register. Mask prescaler bits. */ | ||||
|   twst = TW_STATUS & 0xF8; | ||||
|   if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; | ||||
|  | ||||
|   /* send device address */ | ||||
|   TWDR = address; | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN); | ||||
|  | ||||
|   /* wail until transmission completed and ACK/NACK has been received */ | ||||
|   while(!(TWCR & (1<<TWINT))); | ||||
|  | ||||
|   /* check value of TWI Status Register. Mask prescaler bits. */ | ||||
|   twst = TW_STATUS & 0xF8; | ||||
|   if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1; | ||||
|  | ||||
|   return 0; | ||||
|  | ||||
| }/* i2c_start */ | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|  Issues a start condition and sends address and transfer direction. | ||||
|  If device is busy, use ack polling to wait until device is ready | ||||
|  | ||||
|  Input:   address and transfer direction of I2C device | ||||
| *************************************************************************/ | ||||
| void i2c_start_wait(unsigned char address) | ||||
| { | ||||
|     uint8_t   twst; | ||||
|  | ||||
|  | ||||
|     while ( 1 ) | ||||
|     { | ||||
|       /* send START condition */ | ||||
|       TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); | ||||
|  | ||||
|       /* wait until transmission completed */ | ||||
|       while(!(TWCR & (1<<TWINT))); | ||||
|  | ||||
|       /* check value of TWI Status Register. Mask prescaler bits. */ | ||||
|       twst = TW_STATUS & 0xF8; | ||||
|       if ( (twst != TW_START) && (twst != TW_REP_START)) continue; | ||||
|  | ||||
|       /* send device address */ | ||||
|       TWDR = address; | ||||
|       TWCR = (1<<TWINT) | (1<<TWEN); | ||||
|  | ||||
|       /* wail until transmission completed */ | ||||
|       while(!(TWCR & (1<<TWINT))); | ||||
|  | ||||
|       /* check value of TWI Status Register. Mask prescaler bits. */ | ||||
|       twst = TW_STATUS & 0xF8; | ||||
|       if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) | ||||
|       { | ||||
|           /* device busy, send stop condition to terminate write operation */ | ||||
|           TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); | ||||
|  | ||||
|           /* wait until stop condition is executed and bus released */ | ||||
|           while(TWCR & (1<<TWSTO)); | ||||
|  | ||||
|           continue; | ||||
|       } | ||||
|        | ||||
|       break; | ||||
|      } | ||||
|  | ||||
| }/* i2c_start_wait */ | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|  Issues a repeated start condition and sends address and transfer direction | ||||
|  | ||||
|  Input:   address and transfer direction of I2C device | ||||
|  | ||||
|  Return:  0 device accessible | ||||
|           1 failed to access device | ||||
| *************************************************************************/ | ||||
| unsigned char i2c_rep_start(unsigned char address) | ||||
| { | ||||
|     return i2c_start( address ); | ||||
|  | ||||
| }/* i2c_rep_start */ | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|  Terminates the data transfer and releases the I2C bus | ||||
| *************************************************************************/ | ||||
| void i2c_stop(void) | ||||
| { | ||||
|   /* send stop condition */ | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); | ||||
|  | ||||
|   /* wait until stop condition is executed and bus released */ | ||||
|   while(TWCR & (1<<TWSTO)); | ||||
|  | ||||
| }/* i2c_stop */ | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|   Send one byte to I2C device | ||||
|  | ||||
|   Input:    byte to be transfered | ||||
|   Return:   0 write successful | ||||
|             1 write failed | ||||
| *************************************************************************/ | ||||
| unsigned char i2c_write( unsigned char data ) | ||||
| { | ||||
|     uint8_t   twst; | ||||
|  | ||||
|   /* send data to the previously addressed device */ | ||||
|   TWDR = data; | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN); | ||||
|  | ||||
|   /* wait until transmission completed */ | ||||
|   while(!(TWCR & (1<<TWINT))); | ||||
|  | ||||
|   /* check value of TWI Status Register. Mask prescaler bits */ | ||||
|   twst = TW_STATUS & 0xF8; | ||||
|   if( twst != TW_MT_DATA_ACK) return 1; | ||||
|   return 0; | ||||
|  | ||||
| }/* i2c_write */ | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|  Read one byte from the I2C device, request more data from device | ||||
|  | ||||
|  Return:  byte read from I2C device | ||||
| *************************************************************************/ | ||||
| unsigned char i2c_readAck(void) | ||||
| { | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); | ||||
|   while(!(TWCR & (1<<TWINT))); | ||||
|  | ||||
|   return TWDR; | ||||
|  | ||||
| }/* i2c_readAck */ | ||||
|  | ||||
|  | ||||
| /************************************************************************* | ||||
|  Read one byte from the I2C device, read is followed by a stop condition | ||||
|  | ||||
|  Return:  byte read from I2C device | ||||
| *************************************************************************/ | ||||
| unsigned char i2c_readNak(void) | ||||
| { | ||||
|   TWCR = (1<<TWINT) | (1<<TWEN); | ||||
|   while(!(TWCR & (1<<TWINT))); | ||||
|  | ||||
|   return TWDR; | ||||
|  | ||||
| }/* i2c_readNak */ | ||||
		Reference in New Issue
	
	Block a user