machine: redesign I2C interface
Этот коммит содержится в:
родитель
100901574b
коммит
1ba463c7ee
4 изменённых файлов: 120 добавлений и 66 удалений
|
@ -11,11 +11,10 @@ func main() {
|
|||
machine.I2C0.Configure(machine.I2CConfig{})
|
||||
|
||||
// Init BlinkM
|
||||
machine.I2C0.WriteTo(0x09, []byte("o"))
|
||||
machine.I2C0.WriteRegister(0x09, 'o', nil)
|
||||
|
||||
version := []byte{0, 0}
|
||||
machine.I2C0.WriteTo(0x09, []byte("Z"))
|
||||
machine.I2C0.ReadFrom(0x09, version)
|
||||
machine.I2C0.ReadRegister(0x09, 'Z', version)
|
||||
println("Firmware version:", string(version[0]), string(version[1]))
|
||||
|
||||
count := 0
|
||||
|
@ -23,15 +22,15 @@ func main() {
|
|||
switch count {
|
||||
case 0:
|
||||
// Crimson
|
||||
machine.I2C0.WriteTo(0x09, []byte{'n', 0xdc, 0x14, 0x3c})
|
||||
machine.I2C0.WriteRegister(0x09, 'n', []byte{0xdc, 0x14, 0x3c})
|
||||
count = 1
|
||||
case 1:
|
||||
// MediumPurple
|
||||
machine.I2C0.WriteTo(0x09, []byte{'n', 0x93, 0x70, 0xdb})
|
||||
machine.I2C0.WriteRegister(0x09, 'n', []byte{0x93, 0x70, 0xdb})
|
||||
count = 2
|
||||
case 2:
|
||||
// MediumSeaGreen
|
||||
machine.I2C0.WriteTo(0x09, []byte{'n', 0x3c, 0xb3, 0x71})
|
||||
machine.I2C0.WriteRegister(0x09, 'n', []byte{0x3c, 0xb3, 0x71})
|
||||
count = 0
|
||||
}
|
||||
|
||||
|
|
|
@ -7,3 +7,26 @@ const (
|
|||
TWI_FREQ_100KHZ = 100000
|
||||
TWI_FREQ_400KHZ = 400000
|
||||
)
|
||||
|
||||
// WriteRegister transmits first the register and then the data to the
|
||||
// peripheral device.
|
||||
//
|
||||
// Many I2C-compatible devices are organized in terms of registers. This method
|
||||
// is a shortcut to easily write to such registers. Also, it only works for
|
||||
// devices with 7-bit addresses, which is the vast majority.
|
||||
func (i2c I2C) WriteRegister(address uint8, register uint8, data []byte) error {
|
||||
buf := make([]uint8, len(data)+1)
|
||||
buf[0] = register
|
||||
copy(buf[1:], data)
|
||||
return i2c.Tx(uint16(address), buf, nil)
|
||||
}
|
||||
|
||||
// ReadRegister transmits the register, restarts the connection as a read
|
||||
// operation, and reads the response.
|
||||
//
|
||||
// Many I2C-compatible devices are organized in terms of registers. This method
|
||||
// is a shortcut to easily read such registers. Also, it only works for devices
|
||||
// with 7-bit addresses, which is the vast majority.
|
||||
func (i2c I2C) ReadRegister(address uint8, register uint8, data []byte) error {
|
||||
return i2c.Tx(uint16(address), []byte{register}, data)
|
||||
}
|
||||
|
|
|
@ -193,18 +193,48 @@ func (i2c I2C) Configure(config I2CConfig) {
|
|||
*avr.TWCR = avr.TWCR_TWEN
|
||||
}
|
||||
|
||||
// Start starts an I2C communication session.
|
||||
func (i2c I2C) Start() {
|
||||
// Tx does a single I2C transaction at the specified address.
|
||||
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
||||
// bytes and stores them in r, and generates a stop condition on the bus.
|
||||
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
||||
if len(w) != 0 {
|
||||
i2c.start(uint8(addr), true) // start transmission for writing
|
||||
for _, b := range w {
|
||||
i2c.writeByte(b)
|
||||
}
|
||||
}
|
||||
if len(r) != 0 {
|
||||
i2c.start(uint8(addr), false) // re-start transmission for reading
|
||||
for i := range r { // read each char
|
||||
r[i] = i2c.readByte()
|
||||
}
|
||||
}
|
||||
if len(w) != 0 || len(r) != 0 {
|
||||
// Stop the transmission after it has been started.
|
||||
i2c.stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// start starts an I2C communication session.
|
||||
func (i2c I2C) start(address uint8, write bool) {
|
||||
// Clear TWI interrupt flag, put start condition on SDA, and enable TWI.
|
||||
*avr.TWCR = (avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN)
|
||||
|
||||
// Wait till start condition is transmitted.
|
||||
for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
|
||||
}
|
||||
|
||||
// Write 7-bit shifted peripheral address.
|
||||
address <<= 1
|
||||
if !write {
|
||||
address |= 1 // set read flag
|
||||
}
|
||||
i2c.writeByte(address)
|
||||
}
|
||||
|
||||
// Stop ends an I2C communication session.
|
||||
func (i2c I2C) Stop() {
|
||||
// stop ends an I2C communication session.
|
||||
func (i2c I2C) stop() {
|
||||
// Send stop condition.
|
||||
*avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
|
||||
|
||||
|
@ -213,36 +243,8 @@ func (i2c I2C) Stop() {
|
|||
}
|
||||
}
|
||||
|
||||
// WriteTo writes a slice of data bytes to a peripheral with a specific address.
|
||||
func (i2c I2C) WriteTo(address uint8, data []byte) {
|
||||
i2c.Start()
|
||||
|
||||
// Write 7-bit shifted peripheral address plus write flag(0)
|
||||
i2c.WriteByte(address << 1)
|
||||
|
||||
for _, v := range data {
|
||||
i2c.WriteByte(v)
|
||||
}
|
||||
|
||||
i2c.Stop()
|
||||
}
|
||||
|
||||
// ReadFrom reads a slice of data bytes from an I2C peripheral with a specific address.
|
||||
func (i2c I2C) ReadFrom(address uint8, data []byte) {
|
||||
i2c.Start()
|
||||
|
||||
// Write 7-bit shifted peripheral address + read flag(1)
|
||||
i2c.WriteByte(address<<1 + 1)
|
||||
|
||||
for i, _ := range data {
|
||||
data[i] = i2c.ReadByte()
|
||||
}
|
||||
|
||||
i2c.Stop()
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte to the I2C bus.
|
||||
func (i2c I2C) WriteByte(data byte) {
|
||||
// writeByte writes a single byte to the I2C bus.
|
||||
func (i2c I2C) writeByte(data byte) {
|
||||
// Write data to register.
|
||||
*avr.TWDR = avr.RegValue(data)
|
||||
|
||||
|
@ -254,8 +256,8 @@ func (i2c I2C) WriteByte(data byte) {
|
|||
}
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the I2C bus.
|
||||
func (i2c I2C) ReadByte() byte {
|
||||
// readByte reads a single byte from the I2C bus.
|
||||
func (i2c I2C) readByte() byte {
|
||||
// Clear TWI interrupt flag and enable TWI.
|
||||
*avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
|
||||
|
||||
|
|
|
@ -167,38 +167,68 @@ func (i2c I2C) Configure(config I2CConfig) {
|
|||
i2c.setPins(config.SCL, config.SDA)
|
||||
}
|
||||
|
||||
// WriteTo writes a slice of data bytes to a peripheral with a specific address.
|
||||
func (i2c I2C) WriteTo(address uint8, data []byte) {
|
||||
i2c.Bus.ADDRESS = nrf.RegValue(address)
|
||||
i2c.Bus.TASKS_STARTTX = 1
|
||||
for _, v := range data {
|
||||
i2c.Bus.TXD = nrf.RegValue(v)
|
||||
for i2c.Bus.EVENTS_TXDSENT == 0 {
|
||||
// Tx does a single I2C transaction at the specified address.
|
||||
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
||||
// bytes and stores them in r, and generates a stop condition on the bus.
|
||||
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
||||
i2c.Bus.ADDRESS = nrf.RegValue(addr)
|
||||
if len(w) != 0 {
|
||||
i2c.Bus.TASKS_STARTTX = 1 // start transmission for writing
|
||||
for _, b := range w {
|
||||
i2c.writeByte(b)
|
||||
}
|
||||
i2c.Bus.EVENTS_TXDSENT = 0
|
||||
}
|
||||
if len(r) != 0 {
|
||||
i2c.Bus.TASKS_STARTRX = 1 // re-start transmission for reading
|
||||
for i := range r { // read each char
|
||||
if i+1 == len(r) {
|
||||
// The 'stop' signal must be sent before reading back the last
|
||||
// byte, so that it will be sent by the I2C peripheral right
|
||||
// after the last byte has been read.
|
||||
r[i] = i2c.readLastByte()
|
||||
} else {
|
||||
r[i] = i2c.readByte()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Nothing to read back. Stop the transmission.
|
||||
i2c.signalStop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assume stop after write.
|
||||
// signalStop sends a stop signal when writing or tells the I2C peripheral that
|
||||
// it must generate a stop condition after the next character is retrieved when
|
||||
// reading.
|
||||
func (i2c I2C) signalStop() {
|
||||
i2c.Bus.TASKS_STOP = 1
|
||||
for i2c.Bus.EVENTS_STOPPED == 0 {
|
||||
}
|
||||
i2c.Bus.EVENTS_STOPPED = 0
|
||||
}
|
||||
|
||||
// ReadFrom reads a slice of data bytes from an I2C peripheral with a specific address.
|
||||
func (i2c I2C) ReadFrom(address uint8, data []byte) {
|
||||
i2c.Bus.ADDRESS = nrf.RegValue(address)
|
||||
i2c.Bus.TASKS_STARTRX = 1
|
||||
for i, _ := range data {
|
||||
for i2c.Bus.EVENTS_RXDREADY == 0 {
|
||||
}
|
||||
i2c.Bus.EVENTS_RXDREADY = 0
|
||||
data[i] = byte(i2c.Bus.RXD)
|
||||
// writeByte writes a single byte to the I2C bus.
|
||||
func (i2c I2C) writeByte(data byte) {
|
||||
i2c.Bus.TXD = nrf.RegValue(data)
|
||||
for i2c.Bus.EVENTS_TXDSENT == 0 {
|
||||
}
|
||||
|
||||
// Assume stop after read.
|
||||
i2c.Bus.TASKS_STOP = 1
|
||||
for i2c.Bus.EVENTS_STOPPED == 0 {
|
||||
}
|
||||
i2c.Bus.EVENTS_STOPPED = 0
|
||||
i2c.Bus.EVENTS_TXDSENT = 0
|
||||
}
|
||||
|
||||
// readByte reads a single byte from the I2C bus.
|
||||
func (i2c I2C) readByte() byte {
|
||||
for i2c.Bus.EVENTS_RXDREADY == 0 {
|
||||
}
|
||||
i2c.Bus.EVENTS_RXDREADY = 0
|
||||
return byte(i2c.Bus.RXD)
|
||||
}
|
||||
|
||||
// readLastByte reads a single byte from the I2C bus, sending a stop signal
|
||||
// after it has been read.
|
||||
func (i2c I2C) readLastByte() byte {
|
||||
for i2c.Bus.EVENTS_RXDREADY == 0 {
|
||||
}
|
||||
i2c.Bus.EVENTS_RXDREADY = 0
|
||||
i2c.signalStop() // signal 'stop' now, so it is sent when reading RXD
|
||||
return byte(i2c.Bus.RXD)
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче