avr: use register wrappers that use runtime/volatile.*Uint8 calls
This avoids the //go:volatile pragma on types in Go source code, at least for AVR targets.
Этот коммит содержится в:
родитель
6f6afb0515
коммит
e0cf74e638
5 изменённых файлов: 116 добавлений и 76 удалений
|
@ -10,15 +10,15 @@ import (
|
|||
func (p GPIO) Configure(config GPIOConfig) {
|
||||
if config.Mode == GPIO_OUTPUT { // set output bit
|
||||
if p.Pin < 8 {
|
||||
*avr.DDRD |= 1 << p.Pin
|
||||
avr.DDRD.SetBits(1 << p.Pin)
|
||||
} else {
|
||||
*avr.DDRB |= 1 << (p.Pin - 8)
|
||||
avr.DDRB.SetBits(1 << (p.Pin - 8))
|
||||
}
|
||||
} else { // configure input: clear output bit
|
||||
if p.Pin < 8 {
|
||||
*avr.DDRD &^= 1 << p.Pin
|
||||
avr.DDRD.ClearBits(1 << p.Pin)
|
||||
} else {
|
||||
*avr.DDRB &^= 1 << (p.Pin - 8)
|
||||
avr.DDRB.ClearBits(1 << (p.Pin - 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,15 +26,15 @@ func (p GPIO) Configure(config GPIOConfig) {
|
|||
// Get returns the current value of a GPIO pin.
|
||||
func (p GPIO) Get() bool {
|
||||
if p.Pin < 8 {
|
||||
val := *avr.PIND & (1 << p.Pin)
|
||||
val := avr.PIND.Get() & (1 << p.Pin)
|
||||
return (val > 0)
|
||||
} else {
|
||||
val := *avr.PINB & (1 << (p.Pin - 8))
|
||||
val := avr.PINB.Get() & (1 << (p.Pin - 8))
|
||||
return (val > 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (p GPIO) getPortMask() (*avr.RegValue, uint8) {
|
||||
func (p GPIO) getPortMask() (*avr.Register8, uint8) {
|
||||
if p.Pin < 8 {
|
||||
return avr.PORTD, 1 << p.Pin
|
||||
} else {
|
||||
|
@ -45,64 +45,64 @@ func (p GPIO) getPortMask() (*avr.RegValue, uint8) {
|
|||
// InitPWM initializes the registers needed for PWM.
|
||||
func InitPWM() {
|
||||
// use waveform generation
|
||||
*avr.TCCR0A |= avr.TCCR0A_WGM00
|
||||
avr.TCCR0A.SetBits(avr.TCCR0A_WGM00)
|
||||
|
||||
// set timer 0 prescale factor to 64
|
||||
*avr.TCCR0B |= avr.TCCR0B_CS01 | avr.TCCR0B_CS00
|
||||
avr.TCCR0B.SetBits(avr.TCCR0B_CS01 | avr.TCCR0B_CS00)
|
||||
|
||||
// set timer 1 prescale factor to 64
|
||||
*avr.TCCR1B |= avr.TCCR1B_CS11
|
||||
avr.TCCR1B.SetBits(avr.TCCR1B_CS11)
|
||||
|
||||
// put timer 1 in 8-bit phase correct pwm mode
|
||||
*avr.TCCR1A |= avr.TCCR1A_WGM10
|
||||
avr.TCCR1A.SetBits(avr.TCCR1A_WGM10)
|
||||
|
||||
// set timer 2 prescale factor to 64
|
||||
*avr.TCCR2B |= avr.TCCR2B_CS22
|
||||
avr.TCCR2B.SetBits(avr.TCCR2B_CS22)
|
||||
|
||||
// configure timer 2 for phase correct pwm (8-bit)
|
||||
*avr.TCCR2A |= avr.TCCR2A_WGM20
|
||||
avr.TCCR2A.SetBits(avr.TCCR2A_WGM20)
|
||||
}
|
||||
|
||||
// Configure configures a PWM pin for output.
|
||||
func (pwm PWM) Configure() {
|
||||
if pwm.Pin < 8 {
|
||||
*avr.DDRD |= 1 << pwm.Pin
|
||||
avr.DDRD.SetBits(1 << pwm.Pin)
|
||||
} else {
|
||||
*avr.DDRB |= 1 << (pwm.Pin - 8)
|
||||
avr.DDRB.SetBits(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
|
||||
value8 := uint8(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
|
||||
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 |= avr.TCCR0A_COM0B1
|
||||
*avr.OCR0B = avr.RegValue(value8) // set pwm duty
|
||||
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 |= avr.TCCR0A_COM0A1
|
||||
*avr.OCR0A = avr.RegValue(value8) // set pwm duty
|
||||
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 |= avr.TCCR1A_COM1A1
|
||||
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 = avr.RegValue(value8) // set pwm duty
|
||||
avr.OCR1AL.Set(value8) // set pwm duty
|
||||
case 10:
|
||||
// connect pwm to pin on timer 1, channel B
|
||||
*avr.TCCR1A |= avr.TCCR1A_COM1B1
|
||||
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 = avr.RegValue(value8) // set pwm duty
|
||||
avr.OCR1BL.Set(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
|
||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
||||
avr.OCR2A.Set(value8) // set pwm duty
|
||||
default:
|
||||
panic("Invalid PWM pin")
|
||||
}
|
||||
|
@ -121,19 +121,19 @@ func (i2c I2C) Configure(config I2CConfig) {
|
|||
}
|
||||
|
||||
// Activate internal pullups for twi.
|
||||
*avr.PORTC |= (avr.DIDR0_ADC4D | avr.DIDR0_ADC5D)
|
||||
avr.PORTC.SetBits((avr.DIDR0_ADC4D | avr.DIDR0_ADC5D))
|
||||
|
||||
// Initialize twi prescaler and bit rate.
|
||||
*avr.TWSR |= (avr.TWSR_TWPS0 | avr.TWSR_TWPS1)
|
||||
avr.TWSR.SetBits((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)
|
||||
avr.TWBR.Set(uint8(((CPU_FREQUENCY / config.Frequency) - 16) / 2))
|
||||
|
||||
// Enable twi module.
|
||||
*avr.TWCR = avr.TWCR_TWEN
|
||||
avr.TWCR.Set(avr.TWCR_TWEN)
|
||||
}
|
||||
|
||||
// Tx does a single I2C transaction at the specified address.
|
||||
|
@ -162,10 +162,10 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|||
// 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)
|
||||
avr.TWCR.Set((avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN))
|
||||
|
||||
// Wait till start condition is transmitted.
|
||||
for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
|
||||
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
|
||||
}
|
||||
|
||||
// Write 7-bit shifted peripheral address.
|
||||
|
@ -179,36 +179,36 @@ func (i2c I2C) start(address uint8, write bool) {
|
|||
// stop ends an I2C communication session.
|
||||
func (i2c I2C) stop() {
|
||||
// Send stop condition.
|
||||
*avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
|
||||
avr.TWCR.Set(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 {
|
||||
for (avr.TWCR.Get() & avr.TWCR_TWSTO) == 0 {
|
||||
}
|
||||
}
|
||||
|
||||
// writeByte writes a single byte to the I2C bus.
|
||||
func (i2c I2C) writeByte(data byte) {
|
||||
// Write data to register.
|
||||
*avr.TWDR = avr.RegValue(data)
|
||||
avr.TWDR.Set(data)
|
||||
|
||||
// Clear TWI interrupt flag and enable TWI.
|
||||
*avr.TWCR = (avr.TWCR_TWEN | avr.TWCR_TWINT)
|
||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT)
|
||||
|
||||
// Wait till data is transmitted.
|
||||
for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
|
||||
for (avr.TWCR.Get() & 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)
|
||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
|
||||
|
||||
// Wait till read request is transmitted.
|
||||
for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
|
||||
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
|
||||
}
|
||||
|
||||
return byte(*avr.TWDR)
|
||||
return byte(avr.TWDR.Get())
|
||||
}
|
||||
|
||||
// UART on the AVR.
|
||||
|
@ -226,32 +226,32 @@ func (uart UART) Configure(config UARTConfig) {
|
|||
// https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_wrong_baud_rate.html
|
||||
// ((F_CPU + UART_BAUD_RATE * 8L) / (UART_BAUD_RATE * 16L) - 1)
|
||||
ps := ((CPU_FREQUENCY+config.BaudRate*8)/(config.BaudRate*16) - 1)
|
||||
*avr.UBRR0H = avr.RegValue(ps >> 8)
|
||||
*avr.UBRR0L = avr.RegValue(ps & 0xff)
|
||||
avr.UBRR0H.Set(uint8(ps >> 8))
|
||||
avr.UBRR0L.Set(uint8(ps & 0xff))
|
||||
|
||||
// enable RX, TX and RX interrupt
|
||||
*avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0
|
||||
avr.UCSR0B.Set(avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0)
|
||||
|
||||
// 8-bits data
|
||||
*avr.UCSR0C = avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00
|
||||
avr.UCSR0C.Set(avr.UCSR0C_UCSZ01 | avr.UCSR0C_UCSZ00)
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the UART.
|
||||
func (uart UART) WriteByte(c byte) error {
|
||||
// Wait until UART buffer is not busy.
|
||||
for (*avr.UCSR0A & avr.UCSR0A_UDRE0) == 0 {
|
||||
for (avr.UCSR0A.Get() & avr.UCSR0A_UDRE0) == 0 {
|
||||
}
|
||||
*avr.UDR0 = avr.RegValue(c) // send char
|
||||
avr.UDR0.Set(c) // send char
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:interrupt USART_RX_vect
|
||||
func handleUSART_RX() {
|
||||
// Read register to clear it.
|
||||
data := *avr.UDR0
|
||||
data := avr.UDR0.Get()
|
||||
|
||||
// Ensure no error.
|
||||
if (*avr.UCSR0A & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
|
||||
if (avr.UCSR0A.Get() & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
|
||||
// Put data from UDR register into buffer.
|
||||
UART0.Receive(byte(data))
|
||||
}
|
||||
|
|
|
@ -9,19 +9,19 @@ import (
|
|||
// Configure sets the pin to input or output.
|
||||
func (p GPIO) Configure(config GPIOConfig) {
|
||||
if config.Mode == GPIO_OUTPUT { // set output bit
|
||||
*avr.DDRB |= 1 << p.Pin
|
||||
avr.DDRB.SetBits(1 << p.Pin)
|
||||
} else { // configure input: clear output bit
|
||||
*avr.DDRB &^= 1 << p.Pin
|
||||
avr.DDRB.ClearBits(1 << p.Pin)
|
||||
}
|
||||
}
|
||||
|
||||
func (p GPIO) getPortMask() (*avr.RegValue, uint8) {
|
||||
func (p GPIO) getPortMask() (*avr.Register8, uint8) {
|
||||
return avr.PORTB, 1 << p.Pin
|
||||
}
|
||||
|
||||
// Get returns the current value of a GPIO pin.
|
||||
func (p GPIO) Get() bool {
|
||||
val := *avr.PINB & (1 << p.Pin)
|
||||
val := avr.PINB.Get() & (1 << p.Pin)
|
||||
return (val > 0)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ const (
|
|||
func (p GPIO) Set(value bool) {
|
||||
if value { // set bits
|
||||
port, mask := p.PortMaskSet()
|
||||
*port = mask
|
||||
port.Set(mask)
|
||||
} else { // clear bits
|
||||
port, mask := p.PortMaskClear()
|
||||
*port = mask
|
||||
port.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,9 @@ func (p GPIO) Set(value bool) {
|
|||
// Warning: there are no separate pin set/clear registers on the AVR. The
|
||||
// returned mask is only valid as long as no other pin in the same port has been
|
||||
// changed.
|
||||
func (p GPIO) PortMaskSet() (*avr.RegValue, avr.RegValue) {
|
||||
func (p GPIO) PortMaskSet() (*avr.Register8, uint8) {
|
||||
port, mask := p.getPortMask()
|
||||
return port, *port | avr.RegValue(mask)
|
||||
return port, port.Get() | mask
|
||||
}
|
||||
|
||||
// Return the register and mask to disable a given port. This can be used to
|
||||
|
@ -41,18 +41,18 @@ func (p GPIO) PortMaskSet() (*avr.RegValue, avr.RegValue) {
|
|||
// Warning: there are no separate pin set/clear registers on the AVR. The
|
||||
// returned mask is only valid as long as no other pin in the same port has been
|
||||
// changed.
|
||||
func (p GPIO) PortMaskClear() (*avr.RegValue, avr.RegValue) {
|
||||
func (p GPIO) PortMaskClear() (*avr.Register8, uint8) {
|
||||
port, mask := p.getPortMask()
|
||||
return port, *port &^ avr.RegValue(mask)
|
||||
return port, port.Get() &^ mask
|
||||
}
|
||||
|
||||
// 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)
|
||||
avr.ADCSRA.SetBits(avr.ADCSRA_ADPS2 | avr.ADCSRA_ADPS1 | avr.ADCSRA_ADPS0)
|
||||
|
||||
// enable a2d conversions
|
||||
*avr.ADCSRA |= avr.ADCSRA_ADEN
|
||||
avr.ADCSRA.SetBits(avr.ADCSRA_ADEN)
|
||||
}
|
||||
|
||||
// Configure configures a ADCPin to be able to be used to read data.
|
||||
|
@ -68,18 +68,16 @@ func (a ADC) Get() uint16 {
|
|||
// set the ADLAR bit (left-adjusted result) to get a value scaled to 16
|
||||
// bits. This has the same effect as shifting the return value left by 6
|
||||
// bits.
|
||||
*avr.ADMUX = avr.RegValue(avr.ADMUX_REFS0 | avr.ADMUX_ADLAR | (a.Pin & 0x07))
|
||||
avr.ADMUX.Set(avr.ADMUX_REFS0 | avr.ADMUX_ADLAR | (a.Pin & 0x07))
|
||||
|
||||
// start the conversion
|
||||
*avr.ADCSRA |= avr.ADCSRA_ADSC
|
||||
avr.ADCSRA.SetBits(avr.ADCSRA_ADSC)
|
||||
|
||||
// ADSC is cleared when the conversion finishes
|
||||
for ok := true; ok; ok = (*avr.ADCSRA & avr.ADCSRA_ADSC) > 0 {
|
||||
for ok := true; ok; ok = (avr.ADCSRA.Get() & avr.ADCSRA_ADSC) > 0 {
|
||||
}
|
||||
|
||||
low := uint16(*avr.ADCL)
|
||||
high := uint16(*avr.ADCH)
|
||||
return uint16(low) | uint16(high<<8)
|
||||
return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8
|
||||
}
|
||||
|
||||
// I2C on AVR.
|
||||
|
|
|
@ -17,19 +17,19 @@ func sleepWDT(period uint8) {
|
|||
avr.Asm("cli")
|
||||
avr.Asm("wdr")
|
||||
// Start timed sequence.
|
||||
*avr.WDTCSR |= avr.WDTCSR_WDCE | avr.WDTCSR_WDE
|
||||
avr.WDTCSR.SetBits(avr.WDTCSR_WDCE | avr.WDTCSR_WDE)
|
||||
// Enable WDT and set new timeout
|
||||
*avr.WDTCSR = avr.WDTCSR_WDIE | avr.RegValue(period)
|
||||
avr.WDTCSR.SetBits(avr.WDTCSR_WDIE | period)
|
||||
avr.Asm("sei")
|
||||
|
||||
// Set sleep mode to idle and enable sleep mode.
|
||||
// Note: when using something other than idle, the UART won't work
|
||||
// correctly. This needs to be fixed, though, so we can truly sleep.
|
||||
*avr.SMCR = (0 << 1) | avr.SMCR_SE
|
||||
avr.SMCR.Set((0 << 1) | avr.SMCR_SE)
|
||||
|
||||
// go to sleep
|
||||
avr.Asm("sleep")
|
||||
|
||||
// disable sleep
|
||||
*avr.SMCR = 0
|
||||
avr.SMCR.Set(0)
|
||||
}
|
||||
|
|
|
@ -151,12 +151,54 @@ def writeGo(outdir, device):
|
|||
// {description}
|
||||
package {pkgName}
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Special type that causes loads/stores to be volatile (necessary for
|
||||
// memory-mapped registers).
|
||||
//go:volatile
|
||||
type RegValue uint8
|
||||
type Register8 struct {{
|
||||
Reg uint8
|
||||
}}
|
||||
|
||||
// Get returns the value in the register. It is the volatile equivalent of:
|
||||
//
|
||||
// *r.Reg
|
||||
//
|
||||
//go:inline
|
||||
func (r *Register8) Get() uint8 {{
|
||||
return volatile.LoadUint8(&r.Reg)
|
||||
}}
|
||||
|
||||
// Set updates the register value. It is the volatile equivalent of:
|
||||
//
|
||||
// *r.Reg = value
|
||||
//
|
||||
//go:inline
|
||||
func (r *Register8) Set(value uint8) {{
|
||||
volatile.StoreUint8(&r.Reg, value)
|
||||
}}
|
||||
|
||||
// SetBits reads the register, sets the given bits, and writes it back. It is
|
||||
// the volatile equivalent of:
|
||||
//
|
||||
// r.Reg |= value
|
||||
//
|
||||
//go:inline
|
||||
func (r *Register8) SetBits(value uint8) {{
|
||||
volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) | value)
|
||||
}}
|
||||
|
||||
// ClearBits reads the register, clears the given bits, and writes it back. It
|
||||
// is the volatile equivalent of:
|
||||
//
|
||||
// r.Reg &^= value
|
||||
//
|
||||
//go:inline
|
||||
func (r *Register8) ClearBits(value uint8) {{
|
||||
volatile.StoreUint8(&r.Reg, volatile.LoadUint8(&r.Reg) &^ value)
|
||||
}}
|
||||
|
||||
// Some information about this device.
|
||||
const (
|
||||
|
@ -179,7 +221,7 @@ const (
|
|||
out.write('\n\t// {description}\n'.format(**peripheral))
|
||||
for register in peripheral['registers']:
|
||||
for variant in register['variants']:
|
||||
out.write('\t{name} = (*RegValue)(unsafe.Pointer(uintptr(0x{address:x})))\n'.format(**variant))
|
||||
out.write('\t{name} = (*Register8)(unsafe.Pointer(uintptr(0x{address:x})))\n'.format(**variant))
|
||||
out.write(')\n')
|
||||
|
||||
for peripheral in device.peripherals:
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче