gobot.io/x/gobot/v2@v2.1.0/examples/tinkerboard_generic.go (about) 1 //go:build example 2 // +build example 3 4 // 5 // Do not build by default. 6 7 package main 8 9 import ( 10 "fmt" 11 "reflect" 12 "time" 13 14 "gobot.io/x/gobot/v2" 15 "gobot.io/x/gobot/v2/drivers/i2c" 16 "gobot.io/x/gobot/v2/platforms/tinkerboard" 17 ) 18 19 // Attention! Possibly this will not work, because the current kernel of Tinker-OS 4.4.194 (2021-10-06) needs the 20 // workaround for bad timing to emulate a PCA9501 EEPROM random read (switch on the flag below in this case). 21 // The armbian image with kernel 5.15.74-rockchip (2022-10-18) is known to work. 22 // 23 // Wiring 24 // PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND) 25 // I2C1 Tinkerboard: 3 (SDA), 5 (SCL) 26 // PCA9501: 20 (VDD, +2.5..3.6V), 10 (VSS, GND), 19 (SDA), 18 (SCL) 27 // HW address pins: 1 (A0), 2 (A1), 3 (A2), 12 (A3), 11 (A4), 9 (A5) 28 func main() { 29 const ( 30 defaultAddress = 0x7F // with open address pins (internal pull-up) 31 myAddress = 0x44 // needs to be adjusted for your configuration 32 workaroundBadTiming = false 33 eepromAddr = uint8(0x02) 34 dataLen = 7 35 write = true 36 read = true 37 ) 38 39 board := tinkerboard.NewAdaptor() 40 drv := i2c.NewGenericDriver(board, "PCA9501-EEPROM", defaultAddress, i2c.WithAddress(myAddress)) 41 42 var valWr uint8 = 0x09 43 var err error 44 45 wData := make([]byte, dataLen) 46 rData := make([]byte, dataLen) 47 48 work := func() { 49 gobot.Every(500*time.Millisecond, func() { 50 // write "dataLen" values, starting by EEPROM address 51 valWr++ 52 53 if write { 54 for i := range wData { 55 wData[i] = byte(i) + valWr 56 } 57 err = drv.WriteBlockData(eepromAddr, wData) 58 if err != nil { 59 fmt.Println("err write:", err) 60 } else if read != write { 61 fmt.Printf("EEPROM addr: %d, wr: %v\n", eepromAddr, wData) 62 } 63 } 64 65 // write process needs some time, so wait at least 5ms before read a value 66 // when decreasing to much, the check below will fail 67 time.Sleep(10 * time.Millisecond) 68 69 if read { 70 if workaroundBadTiming { 71 err = readBlockDataBadTiming(drv, eepromAddr, rData) 72 } else { 73 err = drv.ReadBlockData(eepromAddr, rData) 74 } 75 76 if err != nil { 77 fmt.Println("err read:", err) 78 } else if read != write { 79 fmt.Printf("EEPROM addr: %d, rd: %v\n", eepromAddr, rData) 80 } 81 } 82 83 // compare read and write 84 if read && write { 85 if reflect.DeepEqual(wData, rData) { 86 fmt.Printf("EEPROM addr: %d equal: %v\n", eepromAddr, rData) 87 88 } else { 89 fmt.Printf("EEPROM addr: %d wr: %v differ rd: %v\n", eepromAddr, wData, rData) 90 } 91 } 92 }) 93 } 94 95 robot := gobot.NewRobot("genericDriverI2c", 96 []gobot.Connection{board}, 97 []gobot.Device{drv}, 98 work, 99 ) 100 101 err = robot.Start() 102 if err != nil { 103 fmt.Println(err) 104 } 105 } 106 107 // workaround for some boards (e.g. tinkerboard), because Read*Data not working together with PCA9501 caused by bad timing 108 func readBlockDataBadTiming(drv *i2c.GenericDriver, reg uint8, data []byte) error { 109 // set a value to the dummy address 110 if err := drv.WriteByteData(reg-1, 0x00); err != nil { 111 return err 112 } 113 114 // write process needs some time, so wait at least 5ms before read a value 115 // when decreasing to much, the check below will fail 116 time.Sleep(20 * time.Millisecond) 117 118 return drv.Read(data) 119 }