diff --git a/src/examples/blinkm/blinkm.go b/src/examples/blinkm/blinkm.go new file mode 100644 index 00000000..1cab2592 --- /dev/null +++ b/src/examples/blinkm/blinkm.go @@ -0,0 +1,42 @@ +// Connects to an BlinkM I2C RGB LED. +// http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf +package main + +import ( + "machine" + "time" +) + +func main() { + machine.I2C0.Configure(machine.I2CConfig{}) + + // Init BlinkM + machine.I2C0.WriteTo(0x09, []byte("o")) + + version := []byte{0, 0} + machine.I2C0.WriteTo(0x09, []byte("Z")) + machine.I2C0.ReadFrom(0x09, version) + println("Firmware version:", string(version[0]), string(version[1])) + + count := 0 + for { + machine.I2C0.WriteTo(0x09, []byte("n")) + + switch count { + case 0: + // Crimson + machine.I2C0.WriteTo(0x09, []byte{0xdc, 0x14, 0x3c}) + count = 1 + case 1: + // MediumPurple + machine.I2C0.WriteTo(0x09, []byte{0x93, 0x70, 0xdb}) + count = 2 + case 2: + // MediumSeaGreen + machine.I2C0.WriteTo(0x09, []byte{0x3c, 0xb3, 0x71}) + count = 0 + } + + time.Sleep(100 * time.Millisecond) + } +} diff --git a/src/machine/board_arduino.go b/src/machine/board_arduino.go index f6a4659a..77c8bf4e 100644 --- a/src/machine/board_arduino.go +++ b/src/machine/board_arduino.go @@ -2,6 +2,8 @@ package machine +const CPU_FREQUENCY = 16000000 + // LED on the Arduino const LED = 13 diff --git a/src/machine/machine_avr.go b/src/machine/machine_avr.go index 8fd1a4e8..e2fa7da4 100644 --- a/src/machine/machine_avr.go +++ b/src/machine/machine_avr.go @@ -122,6 +122,16 @@ func (pwm PWM) Set(value uint16) { } } +// ADC on the Arduino +const ( + ADC0 = 0 + ADC1 = 1 + ADC2 = 2 + ADC3 = 3 + ADC4 = 4 // Used by TWI for SDA + ADC5 = 5 // Used by TWI for SCL +) + // InitADC initializes the registers needed for ADC. func InitADC() { // set a2d prescaler so we are inside the desired 50-200 KHz range at 16MHz. @@ -157,3 +167,117 @@ func (a ADC) Get() uint16 { high := uint16(*avr.ADCH) return uint16(low) | uint16(high<<8) } + +// I2C on the Arduino +type I2C struct { +} + +// I2C0 is the only I2C interface on the Arduino. +var I2C0 = I2C{} + +// TWI_FREQ is the bus speed. Normally either 100 kHz, or 400 kHz for high-speed bus. +const ( + TWI_FREQ_100KHZ = 100000 + TWI_FREQ_400KHZ = 400000 +) + +// I2CConfig does not do much of anything on Arduino. +type I2CConfig struct { + Frequency uint32 +} + +// Configure is intended to setup the I2C interface. +func (i2c I2C) Configure(config I2CConfig) { + // Default I2C bus speed is 100 kHz. + if config.Frequency == 0 { + config.Frequency = TWI_FREQ_100KHZ + } + + // Activate internal pullups for twi. + *avr.PORTC |= (avr.DIDR0_ADC4D | avr.DIDR0_ADC5D) + + // Initialize twi prescaler and bit rate. + *avr.TWSR |= (avr.TWSR_TWPS0 | avr.TWSR_TWPS1) + + // twi bit rate formula from atmega128 manual pg. 204: + // SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) + // NOTE: TWBR should be 10 or higher for master mode. + // It is 72 for a 16mhz board with 100kHz TWI + *avr.TWBR = avr.RegValue(((CPU_FREQUENCY / config.Frequency) - 16) / 2) + + // Enable twi module. + *avr.TWCR = avr.TWCR_TWEN +} + +// Start starts an I2C communication session. +func (i2c I2C) Start() { + // 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 { + } +} + +// Stop ends an I2C communication session. +func (i2c I2C) Stop() { + // Send stop condition. + *avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO) + + // Wait for stop condition to be executed on bus. + for (*avr.TWCR & avr.TWCR_TWSTO) == 0 { + } +} + +// 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) { + // Write data to register. + *avr.TWDR = avr.RegValue(data) + + // Clear TWI interrupt flag and enable TWI. + *avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT) + + // Wait till data is transmitted. + for (*avr.TWCR & avr.TWCR_TWINT) == 0 { + } +} + +// 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) + + // Wait till read request is transmitted. + for (*avr.TWCR & avr.TWCR_TWINT) == 0 { + } + + return byte(*avr.TWDR) +}