mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-19 22:23:58 +00:00
microbitmatrix: add support for brightness of led pixels
Inspired by brightness levels in micro:bit MicroPython
This commit is contained in:
committed by
Ron Evans
parent
8a39bb7aae
commit
89770a7d05
@@ -52,7 +52,7 @@ const (
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
pin [ledCols + ledRows]machine.Pin
|
pin [ledCols + ledRows]machine.Pin
|
||||||
buffer [ledRows][ledCols]bool
|
buffer [ledRows][ledCols]int8
|
||||||
rotation uint8
|
rotation uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const (
|
|||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
pin [ledCols + ledRows]machine.Pin
|
pin [ledCols + ledRows]machine.Pin
|
||||||
buffer [ledRows][ledCols]bool
|
buffer [ledRows][ledCols]int8
|
||||||
rotation uint8
|
rotation uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,20 +43,53 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
//
|
//
|
||||||
// Valid values for rotation:
|
// Valid values for rotation:
|
||||||
//
|
//
|
||||||
// 0: regular orientation, (0 degree rotation)
|
// 0: regular orientation, (0 degree rotation)
|
||||||
// 1: 90 degree rotation clock wise
|
// 1: 90 degree rotation clock wise
|
||||||
// 2: 180 degree rotation clock wise
|
// 2: 180 degree rotation clock wise
|
||||||
// 3: 270 degree rotation clock wise
|
// 3: 270 degree rotation clock wise
|
||||||
func (d *Device) SetRotation(rotation uint8) {
|
func (d *Device) SetRotation(rotation uint8) {
|
||||||
d.rotation = rotation % 4
|
d.rotation = rotation % 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Source:
|
||||||
|
// https://github.com/bbcmicrobit/micropython/blob/1252f887ddc790676bf9314a136bd17650b9c36c/source/microbit/microbitdisplay.cpp#L282
|
||||||
|
var renderTimings = []time.Duration{
|
||||||
|
0, // Bright, Ticks Duration, Relative power
|
||||||
|
2, // 1, 2, 32µs, inf
|
||||||
|
2, // 2, 4, 64µs, 200%
|
||||||
|
4, // 3, 8, 128µs, 200%
|
||||||
|
7, // 4, 15, 240µs, 187%
|
||||||
|
13, // 5, 28, 448µs, 187%
|
||||||
|
25, // 6, 53, 848µs, 189%
|
||||||
|
49, // 7, 102, 1632µs, 192%
|
||||||
|
97, // 8, 199, 3184µs, 195%
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source:
|
||||||
|
// https://github.com/bbcmicrobit/micropython/blob/1252f887ddc790676bf9314a136bd17650b9c36c/source/microbit/microbitdisplay.cpp#L368
|
||||||
|
const tickDuration = 16 * time.Microsecond
|
||||||
|
|
||||||
const (
|
const (
|
||||||
rowIdx = 0
|
rowIdx = 0
|
||||||
colIdx = 1
|
colIdx = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetPixel modifies the internal buffer in a single pixel.
|
// SetPixel modifies the internal buffer in a single pixel.
|
||||||
|
//
|
||||||
|
// The alpha channel of the RGBA is used to control the brightness of the LED
|
||||||
|
// in 9 different levels.
|
||||||
|
//
|
||||||
|
// alpha channel, brightness level
|
||||||
|
// 0 - 27, 9 (no transparency = highest brightness)
|
||||||
|
// 28 - 55, 8
|
||||||
|
// 56 - 83, 7
|
||||||
|
// 84 - 111, 6
|
||||||
|
// 112 - 139, 5
|
||||||
|
// 140 - 167, 4
|
||||||
|
// 168 - 195, 3
|
||||||
|
// 196 - 223, 2
|
||||||
|
// 224 - 251, 1 (very high transparency = lowest brightness)
|
||||||
|
// 252 - 255, 0 (full transparency = off)
|
||||||
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
|
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
|
||||||
if x < 0 || x >= 5 || y < 0 || y >= 5 {
|
if x < 0 || x >= 5 || y < 0 || y >= 5 {
|
||||||
return
|
return
|
||||||
@@ -64,12 +97,37 @@ func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
|
|||||||
col := x
|
col := x
|
||||||
row := y
|
row := y
|
||||||
if c.R != 0 || c.G != 0 || c.B != 0 {
|
if c.R != 0 || c.G != 0 || c.B != 0 {
|
||||||
d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = true
|
d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = brightness(c.A)
|
||||||
} else {
|
} else {
|
||||||
d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = false
|
d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
brightnessLevels = 9
|
||||||
|
brightnessDivider = int8(255 / brightnessLevels)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Brightness0 = color.RGBA{R: 0, G: 0, B: 0, A: 0}
|
||||||
|
Brightness1 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*1}
|
||||||
|
Brightness2 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*2}
|
||||||
|
Brightness3 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*3}
|
||||||
|
Brightness4 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*4}
|
||||||
|
Brightness5 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*5}
|
||||||
|
Brightness6 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*6}
|
||||||
|
Brightness7 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*7}
|
||||||
|
Brightness8 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*8}
|
||||||
|
Brightness9 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*9}
|
||||||
|
|
||||||
|
BrightnessOff = Brightness0
|
||||||
|
BrightnessFull = Brightness9
|
||||||
|
)
|
||||||
|
|
||||||
|
func brightness(alpha uint8) int8 {
|
||||||
|
return brightnessLevels - int8(alpha/uint8(brightnessDivider))
|
||||||
|
}
|
||||||
|
|
||||||
// GetPixel returns if the specific pixels is enabled.
|
// GetPixel returns if the specific pixels is enabled.
|
||||||
func (d *Device) GetPixel(x int16, y int16) bool {
|
func (d *Device) GetPixel(x int16, y int16) bool {
|
||||||
if x < 0 || x >= 5 || y < 0 || y >= 5 {
|
if x < 0 || x >= 5 || y < 0 || y >= 5 {
|
||||||
@@ -77,26 +135,46 @@ func (d *Device) GetPixel(x int16, y int16) bool {
|
|||||||
}
|
}
|
||||||
col := x
|
col := x
|
||||||
row := y
|
row := y
|
||||||
return d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]]
|
return d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayRefreshDelay = 8 * time.Millisecond
|
const displayRefreshDelay = 8 * time.Millisecond
|
||||||
|
|
||||||
// Display sends the buffer (if any) to the screen.
|
// Display sends the buffer (if any) to the screen.
|
||||||
func (d *Device) Display() error {
|
func (d *Device) Display() error {
|
||||||
|
var displayBuffer [ledRows][ledCols]int8
|
||||||
|
for row := 0; row < ledRows; row++ {
|
||||||
|
for col := 0; col < ledCols; col++ {
|
||||||
|
displayBuffer[row][col] = d.buffer[row][col]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for row := 0; row < ledRows; row++ {
|
for row := 0; row < ledRows; row++ {
|
||||||
d.DisableAll()
|
d.DisableAll()
|
||||||
d.pin[ledCols+row].Low()
|
d.pin[ledCols+row].High()
|
||||||
|
|
||||||
for col := 0; col < ledCols; col++ {
|
for col := 0; col < ledCols; col++ {
|
||||||
if d.buffer[row][col] {
|
if displayBuffer[row][col] > 0 {
|
||||||
d.pin[col].High()
|
|
||||||
} else {
|
|
||||||
d.pin[col].Low()
|
d.pin[col].Low()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(time.Millisecond * 4)
|
|
||||||
|
then := time.Now()
|
||||||
|
var offset time.Duration = 0
|
||||||
|
for _, ticks := range renderTimings {
|
||||||
|
for time.Since(then).Nanoseconds() < int64(ticks*tickDuration+offset) {
|
||||||
|
time.Sleep(offset / 10)
|
||||||
|
}
|
||||||
|
offset += ticks + tickDuration
|
||||||
|
for col := 0; col < ledCols; col++ {
|
||||||
|
displayBuffer[row][col]--
|
||||||
|
if displayBuffer[row][col] <= 0 {
|
||||||
|
d.pin[col].High()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
time.Sleep(displayRefreshDelay)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +182,7 @@ func (d *Device) Display() error {
|
|||||||
func (d *Device) ClearDisplay() {
|
func (d *Device) ClearDisplay() {
|
||||||
for row := 0; row < ledRows; row++ {
|
for row := 0; row < ledRows; row++ {
|
||||||
for col := 0; col < ledCols; col++ {
|
for col := 0; col < ledCols; col++ {
|
||||||
d.buffer[row][col] = false
|
d.buffer[row][col] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user