aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2018-11-20 18:34:14 +0100
committerAyke van Laethem <[email protected]>2018-11-20 18:50:24 +0100
commit9392ef900d3709108f054f2ef48c79435a1f4efe (patch)
tree9870904b128c4fabf0f79f33e526f568da3d2a23
parenta96e2879b2a2d7fdb783e50b043424df41c5637e (diff)
downloadtinygo-9392ef900d3709108f054f2ef48c79435a1f4efe.tar.gz
tinygo-9392ef900d3709108f054f2ef48c79435a1f4efe.zip
avr: add support for the digispark
Blinking the on-board LED works. Nothing else has been tested yet.
-rw-r--r--.travis.yml3
-rw-r--r--Makefile1
-rw-r--r--docs/targets.rst3
-rw-r--r--src/machine/board_digispark.go7
-rw-r--r--src/machine/machine_atmega.go262
-rw-r--r--src/machine/machine_attiny.go48
-rw-r--r--src/machine/machine_avr.go257
-rw-r--r--src/runtime/runtime_atmega.go35
-rw-r--r--src/runtime/runtime_attiny.go16
-rw-r--r--src/runtime/runtime_avr.go28
-rw-r--r--targets/arduino.json5
-rw-r--r--targets/avr.json5
-rw-r--r--targets/digispark.json17
-rwxr-xr-xtools/gen-device-avr.py25
14 files changed, 421 insertions, 291 deletions
diff --git a/.travis.yml b/.travis.yml
index 7a684902c..4ede432f0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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
diff --git a/Makefile b/Makefile
index 283a1414f..01d0f6252 100644
--- a/Makefile
+++ b/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:
diff --git a/docs/targets.rst b/docs/targets.rst
index 6f7c6d96a..741dc3ec1 100644
--- a/docs/targets.rst
+++ b/docs/targets.rst
@@ -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
diff --git a/src/machine/board_digispark.go b/src/machine/board_digispark.go
new file mode 100644
index 000000000..e4065d357
--- /dev/null
+++ b/src/machine/board_digispark.go
@@ -0,0 +1,7 @@
+// +build attiny85,digispark
+
+package machine
+
+const (
+ LED = 1
+)
diff --git a/src/machine/machine_atmega.go b/src/machine/machine_atmega.go
new file mode 100644
index 000000000..ed93fc3eb
--- /dev/null
+++ b/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))
+ }
+}
diff --git a/src/machine/machine_attiny.go b/src/machine/machine_attiny.go
new file mode 100644
index 000000000..eadcee2a5
--- /dev/null
+++ b/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
+}
diff --git a/src/machine/machine_avr.go b/src/machine/machine_avr.go
index dcced7574..5a6c4bab5 100644
--- a/src/machine/machine_avr.go
+++ b/src/machine/machine_avr.go
@@ -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))
- }
-}
diff --git a/src/runtime/runtime_atmega.go b/src/runtime/runtime_atmega.go
new file mode 100644
index 000000000..474f34c40
--- /dev/null
+++ b/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
+}
diff --git a/src/runtime/runtime_attiny.go b/src/runtime/runtime_attiny.go
new file mode 100644
index 000000000..e0f6cc2eb
--- /dev/null
+++ b/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")
+ }
+ }
+}
diff --git a/src/runtime/runtime_avr.go b/src/runtime/runtime_avr.go
index e01d2dce1..deeaa4ed1 100644
--- a/src/runtime/runtime_avr.go
+++ b/src/runtime/runtime_avr.go
@@ -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
}
diff --git a/targets/arduino.json b/targets/arduino.json
index be7c52601..795a99564 100644
--- a/targets/arduino.json
+++ b/targets/arduino.json
@@ -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}"
}
diff --git a/targets/avr.json b/targets/avr.json
new file mode 100644
index 000000000..debb54786
--- /dev/null
+++ b/targets/avr.json
@@ -0,0 +1,5 @@
+{
+ "build-tags": ["avr", "js", "wasm"],
+ "linker": "avr-gcc",
+ "objcopy": "avr-objcopy"
+}
diff --git a/targets/digispark.json b/targets/digispark.json
new file mode 100644
index 000000000..02d9b87e4
--- /dev/null
+++ b/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}"
+}
diff --git a/tools/gen-device-avr.py b/tools/gen-device-avr.py
index 1b7efe3fd..00cf7ba1f 100755
--- a/tools/gen-device-avr.py
+++ b/tools/gen-device-avr.py
@@ -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