avr: add support for the digispark
Blinking the on-board LED works. Nothing else has been tested yet.
Этот коммит содержится в:
родитель
a96e2879b2
коммит
9392ef900d
14 изменённых файлов: 421 добавлений и 291 удалений
|
@ -25,4 +25,5 @@ script:
|
|||
- tinygo build -o blinky1.nrf51.elf -target=microbit examples/echo
|
||||
- tinygo build -o test.nrf.elf -target=nrf52840-mdk examples/blinky1
|
||||
- tinygo build -o blinky1.stm32.elf -target=bluepill examples/blinky1
|
||||
- tinygo build -o blinky1.avr.o -target=arduino examples/blinky1 # TODO: avr-as/avr-gcc doesn't work
|
||||
- tinygo build -o blinky1.o -target=arduino examples/blinky1 # TODO: avr-as/avr-gcc doesn't work
|
||||
- tinygo build -o blinky1.o -target=digispark examples/blinky1
|
||||
|
|
1
Makefile
1
Makefile
|
@ -72,6 +72,7 @@ gen-device: gen-device-avr gen-device-nrf gen-device-stm32
|
|||
|
||||
gen-device-avr:
|
||||
./tools/gen-device-avr.py lib/avr/packs/atmega src/device/avr/
|
||||
./tools/gen-device-avr.py lib/avr/packs/tiny src/device/avr/
|
||||
go fmt ./src/device/avr
|
||||
|
||||
gen-device-nrf:
|
||||
|
|
|
@ -47,6 +47,9 @@ Note: the AVR backend of LLVM is still experimental so you may encounter bugs.
|
|||
|
||||
* `Arduino Uno <https://store.arduino.cc/arduino-uno-rev3>`_ (`ATmega328p
|
||||
<https://www.microchip.com/wwwproducts/en/ATmega328p>`_)
|
||||
* `Digispark <http://digistump.com/products/1>`_ (`ATtiny85
|
||||
<https://www.microchip.com/wwwproducts/en/ATtiny85>`_) |br|
|
||||
Very limited support at the moment.
|
||||
|
||||
|
||||
WebAssembly
|
||||
|
|
7
src/machine/board_digispark.go
Обычный файл
7
src/machine/board_digispark.go
Обычный файл
|
@ -0,0 +1,7 @@
|
|||
// +build attiny85,digispark
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
LED = 1
|
||||
)
|
262
src/machine/machine_atmega.go
Обычный файл
262
src/machine/machine_atmega.go
Обычный файл
|
@ -0,0 +1,262 @@
|
|||
// +build avr,atmega
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/avr"
|
||||
)
|
||||
|
||||
// Configure sets the pin to input or output.
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
// I2CConfig is used to store config info for I2C.
|
||||
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
|
||||
}
|
||||
|
||||
// Tx does a single I2C transaction at the specified address.
|
||||
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
||||
// bytes and stores them in r, and generates a stop condition on the bus.
|
||||
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
||||
if len(w) != 0 {
|
||||
i2c.start(uint8(addr), true) // start transmission for writing
|
||||
for _, b := range w {
|
||||
i2c.writeByte(b)
|
||||
}
|
||||
}
|
||||
if len(r) != 0 {
|
||||
i2c.start(uint8(addr), false) // re-start transmission for reading
|
||||
for i := range r { // read each char
|
||||
r[i] = i2c.readByte()
|
||||
}
|
||||
}
|
||||
if len(w) != 0 || len(r) != 0 {
|
||||
// Stop the transmission after it has been started.
|
||||
i2c.stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
// Wait till start condition is transmitted.
|
||||
for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
|
||||
}
|
||||
|
||||
// Write 7-bit shifted peripheral address.
|
||||
address <<= 1
|
||||
if !write {
|
||||
address |= 1 // set read flag
|
||||
}
|
||||
i2c.writeByte(address)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Configure the UART on the AVR. Defaults to 9600 baud on Arduino.
|
||||
func (uart UART) Configure(config UARTConfig) {
|
||||
if config.BaudRate == 0 {
|
||||
config.BaudRate = 9600
|
||||
}
|
||||
|
||||
// Set baud rate based on prescale formula from
|
||||
// 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)
|
||||
|
||||
// enable RX, TX and RX interrupt
|
||||
*avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0
|
||||
|
||||
// 8-bits data
|
||||
*avr.UCSR0C = 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 {
|
||||
}
|
||||
*avr.UDR0 = avr.RegValue(c) // send char
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:interrupt USART_RX_vect
|
||||
func handleUSART_RX() {
|
||||
// Read register to clear it.
|
||||
data := *avr.UDR0
|
||||
|
||||
// Ensure no error.
|
||||
if (*avr.UCSR0A & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
|
||||
// Put data from UDR register into buffer.
|
||||
bufferPut(byte(data))
|
||||
}
|
||||
}
|
48
src/machine/machine_attiny.go
Обычный файл
48
src/machine/machine_attiny.go
Обычный файл
|
@ -0,0 +1,48 @@
|
|||
// +build avr,attiny
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/avr"
|
||||
)
|
||||
|
||||
// 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
|
||||
} else { // configure input: clear output bit
|
||||
*avr.DDRB &^= 1 << p.Pin
|
||||
}
|
||||
}
|
||||
|
||||
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
||||
func (p GPIO) Set(value bool) {
|
||||
if value { // set bits
|
||||
*avr.PORTB |= 1 << p.Pin
|
||||
} else { // clear bits
|
||||
*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)
|
||||
return (val > 0)
|
||||
}
|
||||
|
||||
// Configure is a dummy implementation. UART has not been implemented for ATtiny
|
||||
// devices.
|
||||
func (uart UART) Configure(config UARTConfig) {
|
||||
}
|
||||
|
||||
// WriteByte is a dummy implementation. UART has not been implemented for ATtiny
|
||||
// devices.
|
||||
func (uart UART) WriteByte(c byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tx is a dummy implementation. I2C has not been implemented for ATtiny
|
||||
// devices.
|
||||
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
||||
return nil
|
||||
}
|
|
@ -13,115 +13,6 @@ const (
|
|||
GPIO_OUTPUT
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
// InitADC initializes the registers needed for ADC.
|
||||
func InitADC() {
|
||||
// set a2d prescaler so we are inside the desired 50-200 KHz range at 16MHz.
|
||||
|
@ -158,159 +49,15 @@ func (a ADC) Get() uint16 {
|
|||
return uint16(low) | uint16(high<<8)
|
||||
}
|
||||
|
||||
// I2C on the Arduino.
|
||||
// I2C on AVR.
|
||||
type I2C struct {
|
||||
}
|
||||
|
||||
// I2C0 is the only I2C interface on the Arduino.
|
||||
// I2C0 is the only I2C interface on most AVRs.
|
||||
var I2C0 = I2C{}
|
||||
|
||||
// I2CConfig is used to store config info for I2C.
|
||||
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
|
||||
}
|
||||
|
||||
// Tx does a single I2C transaction at the specified address.
|
||||
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
||||
// bytes and stores them in r, and generates a stop condition on the bus.
|
||||
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
||||
if len(w) != 0 {
|
||||
i2c.start(uint8(addr), true) // start transmission for writing
|
||||
for _, b := range w {
|
||||
i2c.writeByte(b)
|
||||
}
|
||||
}
|
||||
if len(r) != 0 {
|
||||
i2c.start(uint8(addr), false) // re-start transmission for reading
|
||||
for i := range r { // read each char
|
||||
r[i] = i2c.readByte()
|
||||
}
|
||||
}
|
||||
if len(w) != 0 || len(r) != 0 {
|
||||
// Stop the transmission after it has been started.
|
||||
i2c.stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
// Wait till start condition is transmitted.
|
||||
for (*avr.TWCR & avr.TWCR_TWINT) == 0 {
|
||||
}
|
||||
|
||||
// Write 7-bit shifted peripheral address.
|
||||
address <<= 1
|
||||
if !write {
|
||||
address |= 1 // set read flag
|
||||
}
|
||||
i2c.writeByte(address)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// UART
|
||||
var (
|
||||
// UART0 is the hardware serial port on the AVR.
|
||||
UART0 = &UART{}
|
||||
)
|
||||
|
||||
// Configure the UART on the AVR. Defaults to 9600 baud on Arduino.
|
||||
func (uart UART) Configure(config UARTConfig) {
|
||||
if config.BaudRate == 0 {
|
||||
config.BaudRate = 9600
|
||||
}
|
||||
|
||||
// Set baud rate based on prescale formula from
|
||||
// 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)
|
||||
|
||||
// enable RX, TX and RX interrupt
|
||||
*avr.UCSR0B = avr.UCSR0B_RXEN0 | avr.UCSR0B_TXEN0 | avr.UCSR0B_RXCIE0
|
||||
|
||||
// 8-bits data
|
||||
*avr.UCSR0C = 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 {
|
||||
}
|
||||
*avr.UDR0 = avr.RegValue(c) // send char
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:interrupt USART_RX_vect
|
||||
func handleUSART_RX() {
|
||||
// Read register to clear it.
|
||||
data := *avr.UDR0
|
||||
|
||||
// Ensure no error.
|
||||
if (*avr.UCSR0A & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
|
||||
// Put data from UDR register into buffer.
|
||||
bufferPut(byte(data))
|
||||
}
|
||||
}
|
||||
|
|
35
src/runtime/runtime_atmega.go
Обычный файл
35
src/runtime/runtime_atmega.go
Обычный файл
|
@ -0,0 +1,35 @@
|
|||
// +build avr,atmega
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"device/avr"
|
||||
)
|
||||
|
||||
// Sleep for a given period. The period is defined by the WDT peripheral, and is
|
||||
// on most chips (at least) 3 bits wide, in powers of two from 16ms to 2s
|
||||
// (0=16ms, 1=32ms, 2=64ms...). Note that the WDT is not very accurate: it can
|
||||
// be off by a large margin depending on temperature and supply voltage.
|
||||
//
|
||||
// TODO: disable more peripherals etc. to reduce sleep current.
|
||||
func sleepWDT(period uint8) {
|
||||
// Configure WDT
|
||||
avr.Asm("cli")
|
||||
avr.Asm("wdr")
|
||||
// Start timed sequence.
|
||||
*avr.WDTCSR |= avr.WDTCSR_WDCE | avr.WDTCSR_WDE
|
||||
// Enable WDT and set new timeout
|
||||
*avr.WDTCSR = avr.WDTCSR_WDIE | avr.RegValue(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
|
||||
|
||||
// go to sleep
|
||||
avr.Asm("sleep")
|
||||
|
||||
// disable sleep
|
||||
*avr.SMCR = 0
|
||||
}
|
16
src/runtime/runtime_attiny.go
Обычный файл
16
src/runtime/runtime_attiny.go
Обычный файл
|
@ -0,0 +1,16 @@
|
|||
// +build avr,attiny
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"device/avr"
|
||||
)
|
||||
|
||||
func sleepWDT(period uint8) {
|
||||
// TODO: use the watchdog timer instead of a busy loop.
|
||||
for i := 0x45; i != 0; i-- {
|
||||
for i := 0xff; i != 0; i-- {
|
||||
avr.Asm("nop")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -83,34 +83,6 @@ func sleepTicks(d timeUnit) {
|
|||
}
|
||||
}
|
||||
|
||||
// Sleep for a given period. The period is defined by the WDT peripheral, and is
|
||||
// on most chips (at least) 3 bits wide, in powers of two from 16ms to 2s
|
||||
// (0=16ms, 1=32ms, 2=64ms...). Note that the WDT is not very accurate: it can
|
||||
// be off by a large margin depending on temperature and supply voltage.
|
||||
//
|
||||
// TODO: disable more peripherals etc. to reduce sleep current.
|
||||
func sleepWDT(period uint8) {
|
||||
// Configure WDT
|
||||
avr.Asm("cli")
|
||||
avr.Asm("wdr")
|
||||
// Start timed sequence.
|
||||
*avr.WDTCSR |= avr.WDTCSR_WDCE | avr.WDTCSR_WDE
|
||||
// Enable WDT and set new timeout (0.5s)
|
||||
*avr.WDTCSR = avr.WDTCSR_WDIE | avr.RegValue(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
|
||||
|
||||
// go to sleep
|
||||
avr.Asm("sleep")
|
||||
|
||||
// disable sleep
|
||||
*avr.SMCR = 0
|
||||
}
|
||||
|
||||
func ticks() timeUnit {
|
||||
return currentTime
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"inherits": ["avr"],
|
||||
"llvm-target": "avr-atmel-none",
|
||||
"build-tags": ["arduino", "atmega328p", "atmega", "avr5", "avr", "js", "wasm"],
|
||||
"linker": "avr-gcc",
|
||||
"build-tags": ["arduino", "atmega328p", "atmega", "avr5"],
|
||||
"pre-link-args": [
|
||||
"-nostartfiles",
|
||||
"-mmcu=avr5",
|
||||
|
@ -13,6 +13,5 @@
|
|||
"targets/avr.S",
|
||||
"src/device/avr/atmega328p.s"
|
||||
],
|
||||
"objcopy": "avr-objcopy",
|
||||
"flash": "avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}"
|
||||
}
|
||||
|
|
5
targets/avr.json
Обычный файл
5
targets/avr.json
Обычный файл
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"build-tags": ["avr", "js", "wasm"],
|
||||
"linker": "avr-gcc",
|
||||
"objcopy": "avr-objcopy"
|
||||
}
|
17
targets/digispark.json
Обычный файл
17
targets/digispark.json
Обычный файл
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"inherits": ["avr"],
|
||||
"llvm-target": "avr-atmel-none",
|
||||
"build-tags": ["digispark", "attiny85", "attiny", "avr2", "avr25"],
|
||||
"pre-link-args": [
|
||||
"-nostartfiles",
|
||||
"-mmcu=attiny85",
|
||||
"-Wl,--defsym=_bootloader_size=2180",
|
||||
"-Wl,--defsym=_stack_size=128",
|
||||
"-T", "src/device/avr/attiny85.ld",
|
||||
"-T", "targets/avr.ld",
|
||||
"-Wl,--gc-sections",
|
||||
"targets/avr.S",
|
||||
"src/device/avr/attiny85.s"
|
||||
],
|
||||
"flash": "micronucleus --run {hex}"
|
||||
}
|
|
@ -93,10 +93,16 @@ def readATDF(path):
|
|||
continue
|
||||
|
||||
for bitfieldEl in regEl.getElementsByTagName('bitfield'):
|
||||
mask = bitfieldEl.getAttribute('mask')
|
||||
if len(mask) == 2:
|
||||
# Two devices (ATtiny102 and ATtiny104) appear to have
|
||||
# an error in the bitfields, leaving out the '0x'
|
||||
# prefix.
|
||||
mask = '0x' + mask
|
||||
reg['bitfields'].append({
|
||||
'name': regName + '_' + bitfieldEl.getAttribute('name'),
|
||||
'description': bitfieldEl.getAttribute('caption'),
|
||||
'value': int(bitfieldEl.getAttribute('mask'), 0),
|
||||
'value': int(mask, 0),
|
||||
})
|
||||
|
||||
if regName in allRegisters:
|
||||
|
@ -112,6 +118,11 @@ def readATDF(path):
|
|||
|
||||
peripheral['registers'].append(reg)
|
||||
|
||||
ramSize = 0 # for devices with no RAM
|
||||
for ramSegmentName in ['IRAM', 'INTERNAL_SRAM', 'SRAM']:
|
||||
if ramSegmentName in memorySizes['data']['segments']:
|
||||
ramSize = memorySizes['data']['segments'][ramSegmentName]
|
||||
|
||||
device.metadata = {
|
||||
'file': os.path.basename(path),
|
||||
'descriptorSource': 'http://packs.download.atmel.com/',
|
||||
|
@ -121,7 +132,7 @@ def readATDF(path):
|
|||
'arch': arch,
|
||||
'family': family,
|
||||
'flashSize': memorySizes['prog']['size'],
|
||||
'ramSize': memorySizes['data']['segments'].get('IRAM', memorySizes['data']['segments'].get('INTERNAL_SRAM')),
|
||||
'ramSize': ramSize,
|
||||
'numInterrupts': len(device.interrupts),
|
||||
}
|
||||
|
||||
|
@ -228,15 +239,21 @@ __vector_default:
|
|||
'''.format(**device.metadata))
|
||||
num = 0
|
||||
for intr in device.interrupts:
|
||||
jmp = 'jmp'
|
||||
if device.metadata['flashSize'] <= 8 * 1024:
|
||||
# When a device has 8kB or less flash, rjmp (2 bytes) must be used
|
||||
# instead of jmp (4 bytes).
|
||||
# https://www.avrfreaks.net/forum/rjmp-versus-jmp
|
||||
jmp = 'rjmp'
|
||||
if intr['index'] < num:
|
||||
# Some devices have duplicate interrupts, probably for historical
|
||||
# reasons.
|
||||
continue
|
||||
while intr['index'] > num:
|
||||
out.write(' jmp __vector_default\n')
|
||||
out.write(' {jmp} __vector_default\n'.format(jmp=jmp))
|
||||
num += 1
|
||||
num += 1
|
||||
out.write(' jmp __vector_{name}\n'.format(**intr))
|
||||
out.write(' {jmp} __vector_{name}\n'.format(jmp=jmp, **intr))
|
||||
|
||||
out.write('''
|
||||
; Define default implementations for interrupts, redirecting to
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче