diff --git a/src/examples/pwm/pwm.go b/src/examples/pwm/pwm.go new file mode 100644 index 00000000..104934e5 --- /dev/null +++ b/src/examples/pwm/pwm.go @@ -0,0 +1,54 @@ +package main + +import ( + "machine" + "time" +) + +// This example assumes that an RGB LED is connected to pins 3, 5 and 6 on an Arduino. +// Change the values below to use different pins. +const ( + redPin = 3 + greenPin = 5 + bluePin = 6 +) + +// cycleColor is just a placeholder until math/rand or some equivalent is working. +func cycleColor(color uint8) uint8 { + if color < 10 { + return color + 1 + } else if color < 200 { + return color + 10 + } else { + return 0 + } +} + +func main() { + machine.InitPWM() + + red := machine.PWM{redPin} + red.Configure() + + green := machine.PWM{greenPin} + green.Configure() + + blue := machine.PWM{bluePin} + blue.Configure() + + var rc uint8 + var gc uint8 = 20 + var bc uint8 = 30 + + for { + rc = cycleColor(rc) + gc = cycleColor(gc) + bc = cycleColor(bc) + + red.Set(uint16(rc) << 8) + green.Set(uint16(gc) << 8) + blue.Set(uint16(bc) << 8) + + time.Sleep(time.Millisecond * 500) + } +} diff --git a/src/machine/machine.go b/src/machine/machine.go index abe43688..bc8e14cd 100644 --- a/src/machine/machine.go +++ b/src/machine/machine.go @@ -15,3 +15,7 @@ func (p GPIO) High() { func (p GPIO) Low() { p.Set(false) } + +type PWM struct { + Pin uint8 +} diff --git a/src/machine/machine_avr.go b/src/machine/machine_avr.go index a7e79a07..dd46f15a 100644 --- a/src/machine/machine_avr.go +++ b/src/machine/machine_avr.go @@ -58,3 +58,69 @@ func (p GPIO) Get() bool { return (val > 0) } } + +// InitPWM initializes the registers needed for PWM. +func InitPWM() { + // use waveform generation + *avr.TCCR0A |= avr.TCCR0A_WGM00 + + // set timer 0 prescale factor to 64 + *avr.TCCR0B |= avr.TCCR0B_CS01 | avr.TCCR0B_CS00 + + // set timer 1 prescale factor to 64 + *avr.TCCR1B |= avr.TCCR1B_CS11 + + // put timer 1 in 8-bit phase correct pwm mode + *avr.TCCR1A |= avr.TCCR1A_WGM10 + + // set timer 2 prescale factor to 64 + *avr.TCCR2B |= avr.TCCR2B_CS22 + + // configure timer 2 for phase correct pwm (8-bit) + *avr.TCCR2A |= avr.TCCR2A_WGM20 +} + +// Configure configures a PWM pin for output. +func (pwm PWM) Configure() { + if pwm.Pin < 8 { + *avr.DDRD |= 1 << pwm.Pin + } else { + *avr.DDRB |= 1 << (pwm.Pin - 8) + } +} + +// Set turns on the duty cycle for a PWM pin using the provided value. On the AVR this is normally a +// 8-bit value ranging from 0 to 255. +func (pwm PWM) Set(value uint16) { + value8 := value >> 8 + switch pwm.Pin { + case 3: + // connect pwm to pin on timer 2, channel B + *avr.TCCR2A |= avr.TCCR2A_COM2B1 + *avr.OCR2B = avr.RegValue(value8) // set pwm duty + case 5: + // connect pwm to pin on timer 0, channel B + *avr.TCCR0A |= avr.TCCR0A_COM0B1 + *avr.OCR0B = avr.RegValue(value8) // set pwm duty + case 6: + // connect pwm to pin on timer 0, channel A + *avr.TCCR0A |= avr.TCCR0A_COM0A1 + *avr.OCR0A = avr.RegValue(value8) // set pwm duty + case 9: + // connect pwm to pin on timer 1, channel A + *avr.TCCR1A |= avr.TCCR1A_COM1A1 + // this is a 16-bit value, but we only currently allow the low order bits to be set + *avr.OCR1AL = avr.RegValue(value8) // set pwm duty + case 10: + // connect pwm to pin on timer 1, channel B + *avr.TCCR1A |= avr.TCCR1A_COM1B1 + // this is a 16-bit value, but we only currently allow the low order bits to be set + *avr.OCR1BL = avr.RegValue(value8) // set pwm duty + case 11: + // connect pwm to pin on timer 2, channel A + *avr.TCCR2A |= avr.TCCR2A_COM2A1 + *avr.OCR2A = avr.RegValue(value8) // set pwm duty + default: + panic("Invalid PWM pin") + } +} diff --git a/src/runtime/runtime_avr.go b/src/runtime/runtime_avr.go index 958cd7cd..8436e1b2 100644 --- a/src/runtime/runtime_avr.go +++ b/src/runtime/runtime_avr.go @@ -56,8 +56,8 @@ func initUART() { // Initialize UART at 115200 baud when running at 16MHz. *avr.UBRR0H = 0 *avr.UBRR0L = 8 - *avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 // enable RX and TX - *avr.UCSR0C = avr.UCSR0C_UCSZ0 // 8-bits data + *avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 // enable RX and TX + *avr.UCSR0C = avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00 // 8-bits data } func putchar(c byte) { diff --git a/tools/gen-device-avr.py b/tools/gen-device-avr.py index 0e10df41..1f5aa2b0 100755 --- a/tools/gen-device-avr.py +++ b/tools/gen-device-avr.py @@ -183,10 +183,22 @@ const ( out.write(': {description}'.format(**register)) out.write('\n') for bitfield in register['bitfields']: - out.write('\t{name} = 0x{value:x}'.format(**bitfield)) - if bitfield['description']: - out.write(' // {description}'.format(**bitfield)) - out.write('\n') + name = bitfield['name'] + value = bitfield['value'] + if '{:08b}'.format(value).count('1') == 1: + out.write('\t{name} = 0x{value:x}'.format(**bitfield)) + if bitfield['description']: + out.write(' // {description}'.format(**bitfield)) + out.write('\n') + else: + n = 0 + for i in range(8): + if (value >> i) & 1 == 0: continue + out.write('\t{}{} = 0x{:x}'.format(name, n, 1 << i)) + if bitfield['description']: + out.write(' // {description}'.format(**bitfield)) + n += 1 + out.write('\n') out.write(')\n') def writeLD(outdir, device):