gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/pca9501_driver.go (about) 1 package i2c 2 3 // PCA9501 supports addresses from 0x00 to 0x7F 4 // 0x00 - 0x3F: GPIO, 0x40 - 0x7F: EEPROM 5 // 6 // 0 EE A5 A4 A3 A2 A1 A0|rd 7 // Lowest bit (rd) is mapped to switch between write(0)/read(1), it is not part of the "real" address. 8 // Highest bit (EE) is mapped to switch between GPIO(0)/EEPROM(1). 9 // 10 // The EEPROM address will be generated from GPIO address in this driver. 11 const pca9501DefaultAddress = 0x3F // this applies, if all 6 address pins left open (have pull up resistors) 12 13 // PCA9501Driver is a Gobot Driver for the PCA9501 8-bit GPIO & 2-kbit EEPROM with 6 address program pins. 14 // 2-kbit EEPROM has 256 byte, means addresses between 0x00-0xFF 15 // 16 // please refer to data sheet: https://www.nxp.com/docs/en/data-sheet/PCA9501.pdf 17 // 18 // PCA9501 is the replacement for PCF8574, so this driver should also work for PCF8574 except EEPROM calls 19 // 20 type PCA9501Driver struct { 21 connectionMem Connection 22 *Driver 23 } 24 25 // NewPCA9501Driver creates a new driver with specified i2c interface 26 // Params: 27 // a Connector - the Adaptor to use with this Driver 28 // 29 // Optional params: 30 // i2c.WithBus(int): bus to use with this driver 31 // i2c.WithAddress(int): address to use with this driver 32 // 33 func NewPCA9501Driver(a Connector, options ...func(Config)) *PCA9501Driver { 34 p := &PCA9501Driver{ 35 Driver: NewDriver(a, "PCA9501", pca9501DefaultAddress, options...), 36 } 37 p.afterStart = p.initialize 38 39 // API commands 40 p.AddCommand("WriteGPIO", func(params map[string]interface{}) interface{} { 41 pin := params["pin"].(uint8) 42 val := params["val"].(uint8) 43 err := p.WriteGPIO(pin, val) 44 return map[string]interface{}{"err": err} 45 }) 46 47 p.AddCommand("ReadGPIO", func(params map[string]interface{}) interface{} { 48 pin := params["pin"].(uint8) 49 val, err := p.ReadGPIO(pin) 50 return map[string]interface{}{"val": val, "err": err} 51 }) 52 53 p.AddCommand("WriteEEPROM", func(params map[string]interface{}) interface{} { 54 address := params["address"].(uint8) 55 val := params["val"].(uint8) 56 err := p.WriteEEPROM(address, val) 57 return map[string]interface{}{"err": err} 58 }) 59 60 p.AddCommand("ReadEEPROM", func(params map[string]interface{}) interface{} { 61 address := params["address"].(uint8) 62 val, err := p.ReadEEPROM(address) 63 return map[string]interface{}{"val": val, "err": err} 64 }) 65 return p 66 } 67 68 // WriteGPIO writes a value to a gpio pin (0-7) 69 func (p *PCA9501Driver) WriteGPIO(pin uint8, val uint8) error { 70 p.mutex.Lock() 71 defer p.mutex.Unlock() 72 73 // read current value of CTRL register, 0 is output, 1 is no output 74 iodir, err := p.connection.ReadByte() 75 if err != nil { 76 return err 77 } 78 // set pin as output by clearing bit 79 iodirVal := clearBit(iodir, uint8(pin)) 80 // write CTRL register 81 err = p.connection.WriteByte(uint8(iodirVal)) 82 if err != nil { 83 return err 84 } 85 // read current value of port 86 cVal, err := p.connection.ReadByte() 87 if err != nil { 88 return err 89 } 90 // set or reset the bit in value 91 var nVal uint8 92 if val == 0 { 93 nVal = clearBit(cVal, uint8(pin)) 94 } else { 95 nVal = setBit(cVal, uint8(pin)) 96 } 97 // write new value to port 98 err = p.connection.WriteByte(uint8(nVal)) 99 if err != nil { 100 return err 101 } 102 return nil 103 } 104 105 // ReadGPIO reads a value from a given gpio pin (0-7) 106 func (p *PCA9501Driver) ReadGPIO(pin uint8) (uint8, error) { 107 p.mutex.Lock() 108 defer p.mutex.Unlock() 109 110 // read current value of CTRL register, 0 is no input, 1 is an input 111 iodir, err := p.connection.ReadByte() 112 if err != nil { 113 return 0, err 114 } 115 // set pin as input by setting bit 116 iodirVal := setBit(iodir, uint8(pin)) 117 // write CTRL register 118 err = p.connection.WriteByte(uint8(iodirVal)) 119 if err != nil { 120 return 0, err 121 } 122 // read port and create return bit 123 val, err := p.connection.ReadByte() 124 if err != nil { 125 return val, err 126 } 127 val = 1 << uint8(pin) & val 128 if val > 1 { 129 val = 1 130 } 131 return val, nil 132 } 133 134 // ReadEEPROM reads a value from a given address (0x00-0xFF) 135 // Note: only this sequence for memory read is supported: "STARTW-DATA1-STARTR-DATA2-STOP" 136 // DATA1: EEPROM address, DATA2: read value 137 func (p *PCA9501Driver) ReadEEPROM(address uint8) (uint8, error) { 138 p.mutex.Lock() 139 defer p.mutex.Unlock() 140 141 return p.connectionMem.ReadByteData(address) 142 } 143 144 // WriteEEPROM writes a value to a given address in memory (0x00-0xFF) 145 func (p *PCA9501Driver) WriteEEPROM(address uint8, val uint8) error { 146 p.mutex.Lock() 147 defer p.mutex.Unlock() 148 149 return p.connectionMem.WriteByteData(address, val) 150 } 151 152 func (p *PCA9501Driver) initialize() (err error) { 153 // initialize the EEPROM connection 154 bus := p.GetBusOrDefault(p.connector.DefaultI2cBus()) 155 addressMem := p.GetAddressOrDefault(pca9501DefaultAddress) | 0x40 156 p.connectionMem, err = p.connector.GetI2cConnection(addressMem, bus) 157 return 158 }