diff --git a/Makefile b/Makefile index bacd9b5d..b027d9c0 100644 --- a/Makefile +++ b/Makefile @@ -182,7 +182,7 @@ tinygo-test: .PHONY: smoketest smoketest: $(TINYGO) version - # test all examples + # test all examples (except pwm) $(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1 @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc @@ -203,8 +203,6 @@ smoketest: @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink @$(MD5SUM) test.hex - $(TINYGO) build -size short -o test.hex -target=pca10040 examples/pwm - @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=pca10040 examples/systick @@ -296,6 +294,8 @@ ifneq ($(AVR), 0) @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1 @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=arduino examples/pwm + @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1 @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1 diff --git a/src/examples/button/button.go b/src/examples/button/button.go index 8c245cda..ad028ea0 100644 --- a/src/examples/button/button.go +++ b/src/examples/button/button.go @@ -5,11 +5,9 @@ import ( "time" ) -// This example assumes that the button is connected to pin 8. Change the value -// below to use a different pin. const ( led = machine.LED - button = machine.Pin(8) + button = machine.BUTTON ) func main() { diff --git a/src/examples/pwm/pwm.go b/src/examples/pwm/pwm.go index 104934e5..96220ee5 100644 --- a/src/examples/pwm/pwm.go +++ b/src/examples/pwm/pwm.go @@ -8,9 +8,9 @@ import ( // 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 + redPin = machine.D3 + greenPin = machine.D5 + bluePin = machine.D6 ) // cycleColor is just a placeholder until math/rand or some equivalent is working. diff --git a/src/machine/board_arduino.go b/src/machine/board_arduino.go index 92f17dac..001ba9c7 100644 --- a/src/machine/board_arduino.go +++ b/src/machine/board_arduino.go @@ -7,21 +7,39 @@ func CPUFrequency() uint32 { return 16000000 } +// Digital pins, marked as plain numbers on the board. +const ( + D0 = PD0 // RX + D1 = PD1 // TX + D2 = PD2 + D3 = PD3 + D4 = PD4 + D5 = PD5 + D6 = PD6 + D7 = PD7 + D8 = PB0 + D9 = PB1 + D10 = PB2 + D11 = PB3 + D12 = PB4 + D13 = PB5 +) + // LED on the Arduino -const LED Pin = 13 +const LED Pin = D13 // ADC on the Arduino const ( - ADC0 Pin = 0 - ADC1 Pin = 1 - ADC2 Pin = 2 - ADC3 Pin = 3 - ADC4 Pin = 4 // Used by TWI for SDA - ADC5 Pin = 5 // Used by TWI for SCL + ADC0 Pin = PC0 + ADC1 Pin = PC1 + ADC2 Pin = PC2 + ADC3 Pin = PC3 + ADC4 Pin = PC4 // Used by TWI for SDA + ADC5 Pin = PC5 // Used by TWI for SCL ) // UART pins const ( - UART_TX_PIN Pin = 1 - UART_RX_PIN Pin = 0 + UART_TX_PIN Pin = PD1 + UART_RX_PIN Pin = PD0 ) diff --git a/src/machine/board_arduino_nano.go b/src/machine/board_arduino_nano.go index 1e96c95f..d84b23f3 100644 --- a/src/machine/board_arduino_nano.go +++ b/src/machine/board_arduino_nano.go @@ -7,21 +7,39 @@ func CPUFrequency() uint32 { return 16000000 } +// Digital pins. +const ( + D0 = PD0 // RX0 + D1 = PD1 // TX1 + D2 = PD2 + D3 = PD3 + D4 = PD4 + D5 = PD5 + D6 = PD6 + D7 = PD7 + D8 = PB0 + D9 = PB1 + D10 = PB2 + D11 = PB3 + D12 = PB4 + D13 = PB5 +) + // LED on the Arduino -const LED Pin = 13 +const LED Pin = D13 // ADC on the Arduino const ( - ADC0 Pin = 0 - ADC1 Pin = 1 - ADC2 Pin = 2 - ADC3 Pin = 3 - ADC4 Pin = 4 // Used by TWI for SDA - ADC5 Pin = 5 // Used by TWI for SCL + ADC0 Pin = PC0 + ADC1 Pin = PC1 + ADC2 Pin = PC2 + ADC3 Pin = PC3 + ADC4 Pin = PC4 // Used by TWI for SDA + ADC5 Pin = PC5 // Used by TWI for SCL ) // UART pins const ( - UART_TX_PIN Pin = 1 - UART_RX_PIN Pin = 0 + UART_TX_PIN Pin = PD1 + UART_RX_PIN Pin = PD0 ) diff --git a/src/machine/board_atmega328p.go b/src/machine/board_atmega328p.go new file mode 100644 index 00000000..030c78fe --- /dev/null +++ b/src/machine/board_atmega328p.go @@ -0,0 +1,37 @@ +// +build avr,atmega328p arduino arduino_nano + +package machine + +const ( + // Note: start at port B because there is no port A. + portB Pin = iota * 8 + portC + portD +) + +const ( + PB0 = portB + 0 + PB1 = portB + 1 + PB2 = portB + 2 + PB3 = portB + 3 + PB4 = portB + 4 + PB5 = portB + 5 + PB6 = portB + 6 + PB7 = portB + 7 + PC0 = portC + 0 + PC1 = portC + 1 + PC2 = portC + 2 + PC3 = portC + 3 + PC4 = portC + 4 + PC5 = portC + 5 + PC6 = portC + 6 + PC7 = portC + 7 + PD0 = portD + 0 + PD1 = portD + 1 + PD2 = portD + 2 + PD3 = portD + 3 + PD4 = portD + 4 + PD5 = portD + 5 + PD6 = portD + 6 + PD7 = portD + 7 +) diff --git a/src/machine/machine_atmega.go b/src/machine/machine_atmega.go index cac2ce6e..147d80ff 100644 --- a/src/machine/machine_atmega.go +++ b/src/machine/machine_atmega.go @@ -7,72 +7,6 @@ import ( "runtime/interrupt" ) -// InitPWM initializes the registers needed for PWM. -func InitPWM() { - // use waveform generation - avr.TCCR0A.SetBits(avr.TCCR0A_WGM00) - - // set timer 0 prescale factor to 64 - avr.TCCR0B.SetBits(avr.TCCR0B_CS01 | avr.TCCR0B_CS00) - - // set timer 1 prescale factor to 64 - avr.TCCR1B.SetBits(avr.TCCR1B_CS11) - - // put timer 1 in 8-bit phase correct pwm mode - avr.TCCR1A.SetBits(avr.TCCR1A_WGM10) - - // set timer 2 prescale factor to 64 - avr.TCCR2B.SetBits(avr.TCCR2B_CS22) - - // configure timer 2 for phase correct pwm (8-bit) - avr.TCCR2A.SetBits(avr.TCCR2A_WGM20) -} - -// Configure configures a PWM pin for output. -func (pwm PWM) Configure() { - if pwm.Pin < 8 { - avr.DDRD.SetBits(1 << uint8(pwm.Pin)) - } else { - avr.DDRB.SetBits(1 << uint8(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 := uint8(value >> 8) - switch pwm.Pin { - case 3: - // connect pwm to pin on timer 2, channel B - avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1) - avr.OCR2B.Set(value8) // set pwm duty - case 5: - // connect pwm to pin on timer 0, channel B - avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1) - avr.OCR0B.Set(value8) // set pwm duty - case 6: - // connect pwm to pin on timer 0, channel A - avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1) - avr.OCR0A.Set(value8) // set pwm duty - case 9: - // connect pwm to pin on timer 1, channel A - avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1) - // this is a 16-bit value, but we only currently allow the low order bits to be set - avr.OCR1AL.Set(value8) // set pwm duty - case 10: - // connect pwm to pin on timer 1, channel B - avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1) - // this is a 16-bit value, but we only currently allow the low order bits to be set - avr.OCR1BL.Set(value8) // set pwm duty - case 11: - // connect pwm to pin on timer 2, channel A - avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1) - avr.OCR2A.Set(value8) // set pwm duty - default: - panic("Invalid PWM pin") - } -} - // I2CConfig is used to store config info for I2C. type I2CConfig struct { Frequency uint32 diff --git a/src/machine/machine_atmega328p.go b/src/machine/machine_atmega328p.go index 60c36a37..2e7926a9 100644 --- a/src/machine/machine_atmega328p.go +++ b/src/machine/machine_atmega328p.go @@ -12,44 +12,114 @@ const irq_USART0_RX = avr.IRQ_USART_RX // Configure sets the pin to input or output. func (p Pin) Configure(config PinConfig) { if config.Mode == PinOutput { // set output bit - if p < 8 { - avr.DDRD.SetBits(1 << uint8(p)) - } else if p < 14 { - avr.DDRB.SetBits(1 << uint8(p-8)) - } else { - avr.DDRC.SetBits(1 << uint8(p-14)) + switch p / 8 { + case 0: // port B + avr.DDRB.SetBits(1 << uint8(p)) + case 1: // port C + avr.DDRC.SetBits(1 << uint8(p-8)) + case 2: // port D + avr.DDRD.SetBits(1 << uint8(p-16)) } } else { // configure input: clear output bit - if p < 8 { - avr.DDRD.ClearBits(1 << uint8(p)) - } else if p < 14 { - avr.DDRB.ClearBits(1 << uint8(p-8)) - } else { - avr.DDRC.ClearBits(1 << uint8(p-14)) + switch p / 8 { + case 0: // port B + avr.DDRB.ClearBits(1 << uint8(p)) + case 1: // port C + avr.DDRC.ClearBits(1 << uint8(p-8)) + case 2: // port D + avr.DDRD.ClearBits(1 << uint8(p-16)) } } } // Get returns the current value of a GPIO pin. func (p Pin) Get() bool { - if p < 8 { - val := avr.PIND.Get() & (1 << uint8(p)) - return (val > 0) - } else if p < 14 { - val := avr.PINB.Get() & (1 << uint8(p-8)) - return (val > 0) - } else { - val := avr.PINC.Get() & (1 << uint8(p-14)) - return (val > 0) + var val uint8 + switch p / 8 { + case 0: // port B + val = avr.PINB.Get() & (1 << uint8(p)) + case 1: // port C + val = avr.PINC.Get() & (1 << uint8(p-8)) + case 2: // port D + val = avr.PIND.Get() & (1 << uint8(p-16)) } + return val != 0 } func (p Pin) getPortMask() (*volatile.Register8, uint8) { - if p < 8 { - return avr.PORTD, 1 << uint8(p) - } else if p < 14 { - return avr.PORTB, 1 << uint8(p-8) - } else { - return avr.PORTC, 1 << uint8(p-14) + switch p / 8 { + case 0: // port B + return avr.PORTB, 1 << uint8(p) + case 1: + return avr.PORTC, 1 << uint8(p-8) + default: + return avr.PORTD, 1 << uint8(p-16) + } +} + +// InitPWM initializes the registers needed for PWM. +func InitPWM() { + // use waveform generation + avr.TCCR0A.SetBits(avr.TCCR0A_WGM00) + + // set timer 0 prescale factor to 64 + avr.TCCR0B.SetBits(avr.TCCR0B_CS01 | avr.TCCR0B_CS00) + + // set timer 1 prescale factor to 64 + avr.TCCR1B.SetBits(avr.TCCR1B_CS11) + + // put timer 1 in 8-bit phase correct pwm mode + avr.TCCR1A.SetBits(avr.TCCR1A_WGM10) + + // set timer 2 prescale factor to 64 + avr.TCCR2B.SetBits(avr.TCCR2B_CS22) + + // configure timer 2 for phase correct pwm (8-bit) + avr.TCCR2A.SetBits(avr.TCCR2A_WGM20) +} + +// Configure configures a PWM pin for output. +func (pwm PWM) Configure() { + switch pwm.Pin / 8 { + case 0: // port B + avr.DDRB.SetBits(1 << uint8(pwm.Pin)) + case 2: // port D + avr.DDRD.SetBits(1 << uint8(pwm.Pin-16)) + } +} + +// 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 := uint8(value >> 8) + switch pwm.Pin { + case PD3: + // connect pwm to pin on timer 2, channel B + avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1) + avr.OCR2B.Set(value8) // set pwm duty + case PD5: + // connect pwm to pin on timer 0, channel B + avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1) + avr.OCR0B.Set(value8) // set pwm duty + case PD6: + // connect pwm to pin on timer 0, channel A + avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1) + avr.OCR0A.Set(value8) // set pwm duty + case PB1: + // connect pwm to pin on timer 1, channel A + avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1) + // this is a 16-bit value, but we only currently allow the low order bits to be set + avr.OCR1AL.Set(value8) // set pwm duty + case PB2: + // connect pwm to pin on timer 1, channel B + avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1) + // this is a 16-bit value, but we only currently allow the low order bits to be set + avr.OCR1BL.Set(value8) // set pwm duty + case PB3: + // connect pwm to pin on timer 2, channel A + avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1) + avr.OCR2A.Set(value8) // set pwm duty + default: + panic("Invalid PWM pin") } }