To receive data from our imaginary yet-to-be-created I2C bridge on a Raspberry Pi, we’ll need a way to talk to I2C which matches how the slave is set up.
Let’s invent a little protocol to talk to the LPC810, and keep it as simple as possible:
- the slave is listening for requests on I2C address 0x70
- it listens for three different requests, by checking the first byte of a write
- this first byte in each write is interpreted by the slave as a “register” address:
- write to reg #0: (nodeid, group, freq) = configure radio
- read from reg #1: 1 byte, number of data available in next packet
- read N bytes from reg #2: read the next packet, N obtained from reg #1
- so to read register N, we first write N as 1 byte, and then read the register contents
- note that we’re creating a polling mechanism, the master (RPi) is asking for data
- we’ll poll once every 100 ms, i.e. ten times per second
Here is the “decode” app, also available on GitHub, written in Go:
package main
import (
"fmt"
"os"
"syscall"
"time"
)
const (
dev = "/dev/i2c-1"
addr = 0x70
I2CSLAVE = 0x0703
)
const (
RF_CONFIG = iota
RF_STATUS
RF_PACKET
)
func main() {
file, err := os.OpenFile(dev, os.O_RDWR, os.ModeExclusive)
if err != nil {
panic(err)
}
syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), I2CSLAVE, addr)
file.Write([]byte{RF_CONFIG, 1, 42, 8})
for {
file.Write([]byte{RF_STATUS})
nbuf := make([]byte, 1)
n, _ := file.Read(nbuf)
if n > 0 && nbuf[0] > 0 {
file.Write([]byte{RF_PACKET})
buf := make([]byte, n)
m, _ := file.Read(buf)
if m == n {
fmt.Printf("%02X\n", buf)
} else {
fmt.Println("n?", n, m)
}
} else {
time.Sleep(100 * time.Millisecond)
}
}
}
That’s all there is to it. You should be able to recognise the logic outlined earlier in the above code. The only complication is the way the I2C bus 1 is being accessed: in a very Unix-like manner, there is a device called /dev/i2c-1
, which we open and send a special “IOCTL” request for specifying the I2C address. After that, it’s all quite simple: write some bytes, read some bytes – everything will pass through the I2C bus.
Note also how the “registers” are defined as constants 0, 1, and 2 with names RF_CONFIG
, RF_STATUS
, and RF_PACKET
, respectively. The “iota” is a Go idiom for auto-incrementing.
[Back to article index]