170 строки
4,1 КиБ
Go
170 строки
4,1 КиБ
Go
// +build avr
|
|
|
|
package machine
|
|
|
|
import (
|
|
"device/avr"
|
|
)
|
|
|
|
type GPIOMode uint8
|
|
|
|
const (
|
|
GPIO_INPUT = iota
|
|
GPIO_OUTPUT
|
|
)
|
|
|
|
// LED on the Arduino
|
|
const LED = 13
|
|
|
|
func (p GPIO) Configure(config GPIOConfig) {
|
|
if config.Mode == GPIO_OUTPUT { // set output bit
|
|
if p.Pin < 8 {
|
|
*avr.DDRD |= 1 << p.Pin
|
|
} else {
|
|
*avr.DDRB |= 1 << (p.Pin - 8)
|
|
}
|
|
} else { // configure input: clear output bit
|
|
if p.Pin < 8 {
|
|
*avr.DDRD &^= 1 << p.Pin
|
|
} else {
|
|
*avr.DDRB &^= 1 << (p.Pin - 8)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (p GPIO) Set(value bool) {
|
|
if value { // set bits
|
|
if p.Pin < 8 {
|
|
*avr.PORTD |= 1 << p.Pin
|
|
} else {
|
|
*avr.PORTB |= 1 << (p.Pin - 8)
|
|
}
|
|
} else { // clear bits
|
|
if p.Pin < 8 {
|
|
*avr.PORTD &^= 1 << p.Pin
|
|
} else {
|
|
*avr.PORTB &^= 1 << (p.Pin - 8)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get returns the current value of a GPIO pin.
|
|
func (p GPIO) Get() bool {
|
|
if p.Pin < 8 {
|
|
val := *avr.PIND & (1 << p.Pin)
|
|
return (val > 0)
|
|
} else {
|
|
val := *avr.PINB & (1 << (p.Pin - 8))
|
|
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")
|
|
}
|
|
}
|
|
|
|
// ADC on the Arduino
|
|
const (
|
|
ADC0 = 0
|
|
ADC1 = 1
|
|
ADC2 = 2
|
|
ADC3 = 3
|
|
ADC4 = 4
|
|
ADC5 = 5
|
|
)
|
|
|
|
// InitADC initializes the registers needed for ADC.
|
|
func InitADC() {
|
|
// set a2d prescaler so we are inside the desired 50-200 KHz range at 16MHz.
|
|
*avr.ADCSRA |= (avr.ADCSRA_ADPS2 | avr.ADCSRA_ADPS1 | avr.ADCSRA_ADPS0)
|
|
|
|
// enable a2d conversions
|
|
*avr.ADCSRA |= avr.ADCSRA_ADEN
|
|
}
|
|
|
|
// Configure configures a ADCPin to be able to be used to read data.
|
|
func (a ADC) Configure() {
|
|
return // no pin specific setup on AVR machine.
|
|
}
|
|
|
|
// Get returns the current value of a ADC pin. The AVR will return a 10bit value ranging
|
|
// from 0-1023.
|
|
func (a ADC) Get() uint16 {
|
|
// set the analog reference (high two bits of ADMUX) and select the
|
|
// channel (low 4 bits), masked to only turn on one ADC at a time.
|
|
// this also sets ADLAR (left-adjust result) to 0 (the default).
|
|
*avr.ADMUX = avr.RegValue(avr.ADMUX_REFS0 | (a.Pin & 0x07))
|
|
|
|
// start the conversion
|
|
*avr.ADCSRA |= avr.ADCSRA_ADSC
|
|
|
|
// ADSC is cleared when the conversion finishes
|
|
for ok := true; ok; ok = (*avr.ADCSRA & avr.ADCSRA_ADSC) > 0 {
|
|
}
|
|
|
|
low := uint16(*avr.ADCL)
|
|
high := uint16(*avr.ADCH)
|
|
return uint16(low) | uint16(high<<8)
|
|
}
|