all: add compiler support for interrupts

This commit lets the compiler know about interrupts and allows
optimizations to be performed based on that: interrupts are eliminated
when they appear to be unused in a program. This is done with a new
pseudo-call (runtime/interrupt.New) that is treated specially by the
compiler.
This commit is contained in:
Ayke van Laethem
2019-12-15 14:16:22 +01:00
committed by Ron Evans
parent 3729fcfa9e
commit a5ed993f8d
36 changed files with 766 additions and 199 deletions
+7 -11
View File
@@ -2,7 +2,10 @@
package machine
import "device/sam"
import (
"device/sam"
"runtime/interrupt"
)
// UART1 on the Arduino Nano 33 connects to the onboard NINA-W102 WiFi chip.
var (
@@ -13,11 +16,6 @@ var (
}
)
//go:export SERCOM3_IRQHandler
func handleUART1() {
defaultUART1Handler()
}
// UART2 on the Arduino Nano 33 connects to the normal TX/RX pins.
var (
UART2 = UART{
@@ -27,11 +25,9 @@ var (
}
)
//go:export SERCOM5_IRQHandler
func handleUART2() {
// should reset IRQ
UART2.Receive(byte((UART2.Bus.DATA.Get() & 0xFF)))
UART2.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INTFLAG_RXC)
func init() {
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM3, UART1.handleInterrupt)
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM5, UART2.handleInterrupt)
}
// I2C on the Arduino Nano 33.
+6 -5
View File
@@ -2,7 +2,10 @@
package machine
import "device/stm32"
import (
"device/stm32"
"runtime/interrupt"
)
// https://wiki.stm32duino.com/index.php?title=File:Bluepillpinout.gif
const (
@@ -61,14 +64,12 @@ var (
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART1,
IRQVal: stm32.IRQ_USART1,
}
UART1 = &UART0
)
//go:export USART1_IRQHandler
func handleUART1() {
UART1.Receive(byte((UART1.Bus.DR.Get() & 0xFF)))
func init() {
UART0.Interrupt = interrupt.New(stm32.IRQ_USART1, UART0.handleInterrupt)
}
// SPI pins
@@ -2,7 +2,10 @@
package machine
import "device/sam"
import (
"device/sam"
"runtime/interrupt"
)
// UART1 on the Circuit Playground Express.
var (
@@ -13,9 +16,8 @@ var (
}
)
//go:export SERCOM1_IRQHandler
func handleUART1() {
defaultUART1Handler()
func init() {
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM4, UART1.handleInterrupt)
}
// I2C on the Circuit Playground Express.
+6 -4
View File
@@ -2,7 +2,10 @@
package machine
import "device/sam"
import (
"device/sam"
"runtime/interrupt"
)
// used to reset into bootloader
const RESET_MAGIC_VALUE = 0xf01669ef
@@ -60,9 +63,8 @@ var (
}
)
//go:export SERCOM1_IRQHandler
func handleUART1() {
defaultUART1Handler()
func init() {
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM1, UART1.handleInterrupt)
}
// I2C pins
+3 -3
View File
@@ -4,6 +4,7 @@ package machine
import (
"device/sam"
"runtime/interrupt"
)
// used to reset into bootloader
@@ -62,9 +63,8 @@ var (
}
)
//go:export SERCOM1_IRQHandler
func handleUART1() {
defaultUART1Handler()
func init() {
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM1, UART1.handleInterrupt)
}
// I2C pins
+6 -5
View File
@@ -2,7 +2,10 @@
package machine
import "device/stm32"
import (
"device/stm32"
"runtime/interrupt"
)
const (
PA0 = portA + 0
@@ -100,14 +103,12 @@ var (
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART2,
IRQVal: stm32.IRQ_USART2,
}
UART2 = &UART0
)
//go:export USART2_IRQHandler
func handleUART2() {
UART2.Receive(byte((UART2.Bus.DR.Get() & 0xFF)))
func init() {
UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, UART0.handleInterrupt)
}
// SPI pins
+6 -4
View File
@@ -2,7 +2,10 @@
package machine
import "device/sam"
import (
"device/sam"
"runtime/interrupt"
)
// used to reset into bootloader
const RESET_MAGIC_VALUE = 0xf01669ef
@@ -51,9 +54,8 @@ var (
}
)
//go:export SERCOM1_IRQHandler
func handleUART1() {
defaultUART1Handler()
func init() {
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM0, UART1.handleInterrupt)
}
// SPI pins
+13 -12
View File
@@ -4,6 +4,7 @@ package machine
import (
"device/avr"
"runtime/interrupt"
"runtime/volatile"
)
@@ -232,6 +233,18 @@ func (uart UART) Configure(config UARTConfig) {
config.BaudRate = 9600
}
// Register the UART interrupt.
interrupt.New(avr.IRQ_USART_RX, func(intr interrupt.Interrupt) {
// Read register to clear it.
data := avr.UDR0.Get()
// Ensure no error.
if !avr.UCSR0A.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) {
// Put data from UDR register into buffer.
UART0.Receive(byte(data))
}
})
// 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)
@@ -254,15 +267,3 @@ func (uart UART) WriteByte(c byte) error {
avr.UDR0.Set(c) // send char
return nil
}
//go:interrupt USART_RX_vect
func handleUSART_RX() {
// Read register to clear it.
data := avr.UDR0.Get()
// Ensure no error.
if !avr.UCSR0A.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) {
// Put data from UDR register into buffer.
UART0.Receive(byte(data))
}
}
+14 -14
View File
@@ -11,6 +11,7 @@ import (
"device/arm"
"device/sam"
"errors"
"runtime/interrupt"
"unsafe"
)
@@ -292,9 +293,10 @@ func waitADCSync() {
// UART on the SAMD21.
type UART struct {
Buffer *RingBuffer
Bus *sam.SERCOM_USART_Type
SERCOM uint8
Buffer *RingBuffer
Bus *sam.SERCOM_USART_Type
SERCOM uint8
Interrupt interrupt.Interrupt
}
var (
@@ -401,10 +403,7 @@ func (uart UART) Configure(config UARTConfig) error {
uart.Bus.INTENSET.Set(sam.SERCOM_USART_INTENSET_RXC)
// Enable RX IRQ.
// IRQ lines are in the same order as SERCOM instance numbers on SAMD21
// chips, so the IRQ number can be trivially determined from the SERCOM
// number.
arm.EnableIRQ(sam.IRQ_SERCOM0 + uint32(uart.SERCOM))
uart.Interrupt.Enable()
return nil
}
@@ -432,11 +431,12 @@ func (uart UART) WriteByte(c byte) error {
return nil
}
// defaultUART1Handler handles the UART1 IRQ.
func defaultUART1Handler() {
// handleInterrupt should be called from the appropriate interrupt handler for
// this UART instance.
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
// should reset IRQ
UART1.Receive(byte((UART1.Bus.DATA.Get() & 0xFF)))
UART1.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INTFLAG_RXC)
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INTFLAG_RXC)
}
// I2C on the SAMD21.
@@ -1368,7 +1368,8 @@ func (usbcdc USBCDC) Configure(config UARTConfig) {
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
// enable IRQ
arm.EnableIRQ(sam.IRQ_USB)
intr := interrupt.New(sam.IRQ_USB, handleUSB)
intr.Enable()
}
func handlePadCalibration() {
@@ -1414,8 +1415,7 @@ func handlePadCalibration() {
sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
}
//go:export USB_IRQHandler
func handleUSB() {
func handleUSB(intr interrupt.Interrupt) {
// reset all interrupt flags
flags := sam.USB_DEVICE.INTFLAG.Get()
sam.USB_DEVICE.INTFLAG.Set(flags)
+7 -26
View File
@@ -11,6 +11,7 @@ import (
"device/arm"
"device/sam"
"errors"
"runtime/interrupt"
"unsafe"
)
@@ -1547,11 +1548,11 @@ func (usbcdc USBCDC) Configure(config UARTConfig) {
// enable USB
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
// enable IRQ
arm.EnableIRQ(sam.IRQ_USB_OTHER)
arm.EnableIRQ(sam.IRQ_USB_SOF_HSOF)
arm.EnableIRQ(sam.IRQ_USB_TRCPT0)
arm.EnableIRQ(sam.IRQ_USB_TRCPT1)
// enable IRQ at highest priority
interrupt.New(sam.IRQ_USB_OTHER, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable()
}
func handlePadCalibration() {
@@ -1597,27 +1598,7 @@ func handlePadCalibration() {
sam.USB_DEVICE.PADCAL.SetBits(calibTrim << sam.USB_DEVICE_PADCAL_TRIM_Pos)
}
//go:export USB_OTHER_IRQHandler
func handleUSBOther() {
handleUSBIRQ()
}
//go:export USB_SOF_HSOF_IRQHandler
func handleUSBSOFHSOF() {
handleUSBIRQ()
}
//go:export USB_TRCPT0_IRQHandler
func handleUSBTRCPT0() {
handleUSBIRQ()
}
//go:export USB_TRCPT1_IRQHandler
func handleUSBTRCPT1() {
handleUSBIRQ()
}
func handleUSBIRQ() {
func handleUSBIRQ(interrupt.Interrupt) {
// reset all interrupt flags
flags := sam.USB_DEVICE.INTFLAG.Get()
sam.USB_DEVICE.INTFLAG.Set(flags)
+5 -4
View File
@@ -3,9 +3,9 @@
package machine
import (
"device/arm"
"device/nrf"
"errors"
"runtime/interrupt"
)
var (
@@ -88,8 +88,9 @@ func (uart UART) Configure(config UARTConfig) {
nrf.UART0.INTENSET.Set(nrf.UART_INTENSET_RXDRDY_Msk)
// Enable RX IRQ.
arm.SetPriority(nrf.IRQ_UART0, 0xc0) // low priority
arm.EnableIRQ(nrf.IRQ_UART0)
intr := interrupt.New(nrf.IRQ_UART0, UART0.handleInterrupt)
intr.SetPriority(0xc0) // low priority
intr.Enable()
}
// SetBaudRate sets the communication speed for the UART.
@@ -116,7 +117,7 @@ func (uart UART) WriteByte(c byte) error {
return nil
}
func (uart UART) handleInterrupt() {
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
if nrf.UART0.EVENTS_RXDRDY.Get() != 0 {
uart.Receive(byte(nrf.UART0.RXD.Get()))
nrf.UART0.EVENTS_RXDRDY.Set(0x0)
-5
View File
@@ -20,11 +20,6 @@ func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSELRXD.Set(uint32(rx))
}
//go:export UART0_IRQHandler
func handleUART0() {
UART0.handleInterrupt()
}
func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSELSCL.Set(uint32(scl))
i2c.Bus.PSELSDA.Set(uint32(sda))
-5
View File
@@ -21,11 +21,6 @@ func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSELRXD.Set(uint32(rx))
}
//go:export UARTE0_UART0_IRQHandler
func handleUART0() {
UART0.handleInterrupt()
}
func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSELSCL.Set(uint32(scl))
i2c.Bus.PSELSDA.Set(uint32(sda))
-5
View File
@@ -77,11 +77,6 @@ func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSEL.RXD.Set(uint32(rx))
}
//go:export UARTE0_UART0_IRQHandler
func handleUART0() {
UART0.handleInterrupt()
}
func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSEL.SCL.Set(uint32(scl))
i2c.Bus.PSEL.SDA.Set(uint32(sda))
+12 -6
View File
@@ -5,9 +5,9 @@ package machine
// Peripheral abstraction layer for the stm32.
import (
"device/arm"
"device/stm32"
"errors"
"runtime/interrupt"
)
func CPUFrequency() uint32 {
@@ -111,9 +111,9 @@ func (p Pin) Get() bool {
// UART
type UART struct {
Buffer *RingBuffer
Bus *stm32.USART_Type
IRQVal uint32
Buffer *RingBuffer
Bus *stm32.USART_Type
Interrupt interrupt.Interrupt
}
// Configure the UART.
@@ -155,8 +155,8 @@ func (uart UART) Configure(config UARTConfig) {
uart.Bus.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE)
// Enable RX IRQ
arm.SetPriority(uart.IRQVal, 0xc0)
arm.EnableIRQ(uart.IRQVal)
uart.Interrupt.SetPriority(0xc0)
uart.Interrupt.Enable()
}
// SetBaudRate sets the communication speed for the UART.
@@ -182,6 +182,12 @@ func (uart UART) WriteByte(c byte) error {
return nil
}
// handleInterrupt should be called from the appropriate interrupt handler for
// this UART instance.
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
uart.Receive(byte((uart.Bus.DR.Get() & 0xFF)))
}
// SPI on the STM32.
type SPI struct {
Bus *stm32.SPI_Type
+6 -8
View File
@@ -5,8 +5,8 @@ package machine
// Peripheral abstraction layer for the stm32.
import (
"device/arm"
"device/stm32"
"runtime/interrupt"
)
func CPUFrequency() uint32 {
@@ -203,8 +203,11 @@ func (uart UART) Configure(config UARTConfig) {
stm32.USART2.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE)
// Enable RX IRQ.
arm.SetPriority(stm32.IRQ_USART2, 0xc0)
arm.EnableIRQ(stm32.IRQ_USART2)
intr := interrupt.New(stm32.IRQ_USART2, func(interrupt.Interrupt) {
UART1.Receive(byte((stm32.USART2.DR.Get() & 0xFF)))
})
intr.SetPriority(0xc0)
intr.Enable()
}
// WriteByte writes a byte of data to the UART.
@@ -215,8 +218,3 @@ func (uart UART) WriteByte(c byte) error {
}
return nil
}
//go:export USART2_IRQHandler
func handleUSART2() {
UART1.Receive(byte((stm32.USART2.DR.Get() & 0xFF)))
}