Files
drivers/ws2812/ws2812-asm_cortexm.go
T
Ayke van Laethem b3af3f594e ws2812: generate assembly instead of handwriting it
Previously, a new implementation had to be written for each processor
speed. This is tedious and error-prone, therefore I've rewritten all of
the assembly code using a tool that will calculate exactly how many NOP
instructions are required.

I've also switched from build tags to a switch statement over all
processor speeds.

All in all, this means that:
  - Chips with a supported CPU performance will automatically be
    supported (no build tags necessary).
  - Adding a new chip is as easy as adding the MHz count to the
    generator script and to the switch statement.

Right now this is only for the Cortex-M, but it's certainly feasible to
extend this to other architectures such as the AVR.
2021-09-07 18:00:55 +02:00

355 lines
5.4 KiB
Go

// +build cortexm
package ws2812
// Warning: autogenerated file. Instead of modifying this file, change
// gen-ws2812-arm.go and run "go generate".
import (
"device"
"runtime/interrupt"
)
func (d Device) writeByte16(c byte) {
portSet, maskSet := d.Pin.PortMaskSet()
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 4 - 6 cycles or 250.0ns - 375.0ns
// T1H: 9 - 11 cycles or 562.5ns - 687.5ns
// TLD: 8 - cycles or 500.0ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
1: @ send_bit
str {maskSet}, {portSet} @ [2] T0H and T0L start here
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{
"value": value,
"i": 8,
"maskSet": maskSet,
"portSet": portSet,
"maskClear": maskClear,
"portClear": portClear,
})
interrupt.Restore(mask)
}
func (d Device) writeByte48(c byte) {
portSet, maskSet := d.Pin.PortMaskSet()
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 10 - 12 cycles or 208.3ns - 250.0ns
// T1H: 27 - 29 cycles or 562.5ns - 604.2ns
// TLD: 22 - cycles or 458.3ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
1: @ send_bit
str {maskSet}, {portSet} @ [2] T0H and T0L start here
nop
nop
nop
nop
nop
nop
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{
"value": value,
"i": 8,
"maskSet": maskSet,
"portSet": portSet,
"maskClear": maskClear,
"portClear": portClear,
})
interrupt.Restore(mask)
}
func (d Device) writeByte64(c byte) {
portSet, maskSet := d.Pin.PortMaskSet()
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 13 - 15 cycles or 203.1ns - 234.4ns
// T1H: 36 - 38 cycles or 562.5ns - 593.8ns
// TLD: 29 - cycles or 453.1ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
1: @ send_bit
str {maskSet}, {portSet} @ [2] T0H and T0L start here
nop
nop
nop
nop
nop
nop
nop
nop
nop
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{
"value": value,
"i": 8,
"maskSet": maskSet,
"portSet": portSet,
"maskClear": maskClear,
"portClear": portClear,
})
interrupt.Restore(mask)
}
func (d Device) writeByte120(c byte) {
portSet, maskSet := d.Pin.PortMaskSet()
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 24 - 26 cycles or 200.0ns - 216.7ns
// T1H: 66 - 68 cycles or 550.0ns - 566.7ns
// TLD: 54 - cycles or 450.0ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
1: @ send_bit
str {maskSet}, {portSet} @ [2] T0H and T0L start here
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{
"value": value,
"i": 8,
"maskSet": maskSet,
"portSet": portSet,
"maskClear": maskClear,
"portClear": portClear,
})
interrupt.Restore(mask)
}