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  }