github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/examples/i2c-target/main.go (about)

     1  // Example demonstrating I2C controller / target comms.
     2  //
     3  // To use this example, physically connect I2C0 and I2C1.
     4  // I2C0 will be used as the controller and I2C1 used as
     5  // the target.
     6  //
     7  // In this example, the target implements a simple memory
     8  // map, with the controller able to read and write the
     9  // memory.
    10  
    11  package main
    12  
    13  import (
    14  	"machine"
    15  	"time"
    16  )
    17  
    18  const (
    19  	targetAddress = 0x11
    20  	maxTxSize     = 16
    21  )
    22  
    23  func main() {
    24  	// Delay to enable USB monitor time to attach
    25  	time.Sleep(3 * time.Second)
    26  
    27  	// Controller uses default I2C pins and controller
    28  	// mode is default
    29  	err := controller.Configure(machine.I2CConfig{})
    30  	if err != nil {
    31  		panic("failed to config I2C0 as controller")
    32  	}
    33  
    34  	// Target uses alternate pins and target mode is
    35  	// explicit
    36  	err = target.Configure(machine.I2CConfig{
    37  		Mode: machine.I2CModeTarget,
    38  		SCL:  TARGET_SCL,
    39  		SDA:  TARGET_SDA,
    40  	})
    41  	if err != nil {
    42  		panic("failed to config I2C1 as target")
    43  	}
    44  
    45  	// Put welcome message directly into target memory
    46  	copy(mem[0:], []byte("Hello World!"))
    47  	err = target.Listen(targetAddress)
    48  	if err != nil {
    49  		panic("failed to listen as I2C target")
    50  	}
    51  
    52  	// Start the target
    53  	go targetMain()
    54  
    55  	// Read welcome message from target over I2C
    56  	buf := make([]byte, 12)
    57  	err = controller.Tx(targetAddress, []byte{0}, buf)
    58  	if err != nil {
    59  		println("failed to read welcome message over I2C")
    60  		panic(err)
    61  	}
    62  	println("message from target:", string(buf))
    63  
    64  	// Write (1,2,3) to the target starting at memory address 3
    65  	println("writing (1,2,3) @ 0x3")
    66  	err = controller.Tx(targetAddress, []byte{3, 1, 2, 3}, nil)
    67  	if err != nil {
    68  		println("failed to write to I2C target")
    69  		panic(err)
    70  	}
    71  
    72  	time.Sleep(100 * time.Millisecond) // Wait for target to process write
    73  	println("mem:", mem[0], mem[1], mem[2], mem[3], mem[4], mem[5])
    74  
    75  	// Read memory address 4 from target, which should be the value 2
    76  	buf = make([]byte, 1)
    77  	err = controller.Tx(targetAddress, []byte{4}, buf[:1])
    78  	if err != nil {
    79  		println("failed to read from I2C target")
    80  		panic(err)
    81  	}
    82  
    83  	if buf[0] != 2 {
    84  		panic("read incorrect value from I2C target")
    85  	}
    86  
    87  	println("all done!")
    88  	for {
    89  		time.Sleep(1 * time.Second)
    90  	}
    91  }
    92  
    93  // -- target ---
    94  
    95  var (
    96  	mem [256]byte
    97  )
    98  
    99  // targetMain implements the 'main loop' for an I2C target
   100  func targetMain() {
   101  	buf := make([]byte, maxTxSize)
   102  	var ptr uint8
   103  
   104  	for {
   105  		evt, n, err := target.WaitForEvent(buf)
   106  		if err != nil {
   107  			panic(err)
   108  		}
   109  
   110  		switch evt {
   111  		case machine.I2CReceive:
   112  			if n > 0 {
   113  				ptr = buf[0]
   114  			}
   115  
   116  			for o := 1; o < n; o++ {
   117  				mem[ptr] = buf[o]
   118  				ptr++
   119  			}
   120  
   121  		case machine.I2CRequest:
   122  			target.Reply(mem[ptr:256])
   123  
   124  		case machine.I2CFinish:
   125  			// nothing to do
   126  
   127  		default:
   128  		}
   129  	}
   130  }