diff --git a/microbitmatrix/microbitmatrix-v1.go b/microbitmatrix/microbitmatrix-v1.go index c4781b1..f93ad25 100644 --- a/microbitmatrix/microbitmatrix-v1.go +++ b/microbitmatrix/microbitmatrix-v1.go @@ -8,9 +8,12 @@ package microbitmatrix // import "tinygo.org/x/drivers/microbitmatrix" import ( "machine" - "time" ) +// 4 rotation orientations (0, 90, 180, 270), CW (clock wise) +// 5 rows +// 5 cols +// target coordinates in machine rows (y) and cols (x) var matrixRotations = [4][5][5][2]uint8{ { // 0 {{0, 0}, {1, 3}, {0, 1}, {1, 4}, {0, 2}}, @@ -19,7 +22,7 @@ var matrixRotations = [4][5][5][2]uint8{ {{0, 7}, {0, 6}, {0, 5}, {0, 4}, {0, 3}}, {{2, 2}, {1, 6}, {2, 0}, {1, 5}, {2, 1}}, }, - { // 90 CCW + { // 90 CW {{0, 2}, {2, 7}, {1, 0}, {0, 3}, {2, 1}}, {{1, 4}, {2, 6}, {2, 8}, {0, 4}, {1, 5}}, {{0, 1}, {2, 5}, {1, 2}, {0, 5}, {2, 0}}, @@ -42,65 +45,33 @@ var matrixRotations = [4][5][5][2]uint8{ }, } +const ( + ledRows = 3 + ledCols = 9 +) + type Device struct { - pin [12]machine.Pin - buffer [3][9]bool + pin [ledCols + ledRows]machine.Pin + buffer [ledRows][ledCols]bool rotation uint8 } -// Configure sets up the device. -func (d *Device) Configure(cfg Config) { - d.SetRotation(cfg.Rotation) +func (d *Device) assignPins() { + d.pin[0] = machine.LED_COL_1 + d.pin[1] = machine.LED_COL_2 + d.pin[2] = machine.LED_COL_3 + d.pin[3] = machine.LED_COL_4 + d.pin[4] = machine.LED_COL_5 + d.pin[5] = machine.LED_COL_6 + d.pin[6] = machine.LED_COL_7 + d.pin[7] = machine.LED_COL_8 + d.pin[8] = machine.LED_COL_9 - for i := machine.LED_COL_1; i <= machine.LED_ROW_3; i++ { - d.pin[i-machine.LED_COL_1] = i - d.pin[i-machine.LED_COL_1].Configure(machine.PinConfig{Mode: machine.PinOutput}) - } - d.ClearDisplay() - d.DisableAll() -} + d.pin[9] = machine.LED_ROW_1 + d.pin[10] = machine.LED_ROW_2 + d.pin[11] = machine.LED_ROW_3 -// Display sends the buffer (if any) to the screen. -func (d *Device) Display() error { - for row := 0; row < 3; row++ { - d.DisableAll() - d.pin[9+row].High() - - for col := 0; col < 9; col++ { - if d.buffer[row][col] { - d.pin[col].Low() - } - } - time.Sleep(time.Millisecond * 2) - } - return nil -} - -// ClearDisplay erases the internal buffer -func (d *Device) ClearDisplay() { - for row := 0; row < 3; row++ { - for col := 0; col < 9; col++ { - d.buffer[row][col] = false - } - } -} - -// DisableAll disables all the LEDs without modifying the buffer -func (d *Device) DisableAll() { - for i := machine.LED_COL_1; i <= machine.LED_COL_9; i++ { - d.pin[i-machine.LED_COL_1].High() - } - for i := machine.LED_ROW_1; i <= machine.LED_ROW_3; i++ { - d.pin[i-machine.LED_COL_1].Low() - } -} - -// EnableAll enables all the LEDs without modifying the buffer -func (d *Device) EnableAll() { - for i := machine.LED_COL_1; i <= machine.LED_COL_9; i++ { - d.pin[i-machine.LED_COL_1].Low() - } - for i := machine.LED_ROW_1; i <= machine.LED_ROW_3; i++ { - d.pin[i-machine.LED_COL_1].High() + for i := 0; i < len(d.pin); i++ { + d.pin[i].Configure(machine.PinConfig{Mode: machine.PinOutput}) } } diff --git a/microbitmatrix/microbitmatrix-v2.go b/microbitmatrix/microbitmatrix-v2.go index a107fa3..dc7fad7 100644 --- a/microbitmatrix/microbitmatrix-v2.go +++ b/microbitmatrix/microbitmatrix-v2.go @@ -8,50 +8,55 @@ package microbitmatrix // import "tinygo.org/x/drivers/microbitmatrix" import ( "machine" - "time" ) +// 4 rotation orientations (0, 90, 180, 270), CW (clock wise) +// 5 rows +// 5 cols +// target coordinates in machine rows (y) and cols (x) var matrixRotations = [4][5][5][2]uint8{ { // 0 - {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}, - {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}}, - {{0, 2}, {1, 2}, {2, 2}, {3, 2}, {4, 2}}, - {{0, 3}, {1, 3}, {2, 3}, {3, 3}, {4, 3}}, - {{0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4}}, - }, - { // 90 CCW - {{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}}, - {{3, 0}, {3, 1}, {3, 2}, {3, 3}, {3, 4}}, - {{2, 0}, {2, 1}, {2, 2}, {2, 3}, {2, 4}}, - {{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}}, {{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}}, + {{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}}, + {{2, 0}, {2, 1}, {2, 2}, {2, 3}, {2, 4}}, + {{3, 0}, {3, 1}, {3, 2}, {3, 3}, {3, 4}}, + {{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}}, + }, + { // 90 CW + {{0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4}}, + {{0, 3}, {1, 3}, {2, 3}, {3, 3}, {4, 3}}, + {{0, 2}, {1, 2}, {2, 2}, {3, 2}, {4, 2}}, + {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}}, + {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}, }, { // 180 - {{4, 4}, {3, 4}, {2, 4}, {1, 4}, {0, 4}}, - {{4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}}, - {{4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}}, - {{4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}}, - {{4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}}, + {{4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}}, + {{3, 4}, {3, 3}, {3, 2}, {3, 1}, {3, 0}}, + {{2, 4}, {2, 3}, {2, 2}, {2, 1}, {2, 0}}, + {{1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}}, + {{0, 4}, {0, 3}, {0, 2}, {0, 1}, {0, 0}}, }, { // 270 - {{0, 4}, {0, 3}, {0, 2}, {0, 1}, {0, 0}}, - {{1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}}, - {{2, 4}, {2, 3}, {2, 2}, {2, 1}, {2, 0}}, - {{3, 4}, {3, 3}, {3, 2}, {3, 1}, {3, 0}}, - {{4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}}, + {{4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}}, + {{4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}}, + {{4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}}, + {{4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}}, + {{4, 4}, {3, 4}, {2, 4}, {1, 4}, {0, 4}}, }, } +const ( + ledRows = 5 + ledCols = 5 +) + type Device struct { - pin [10]machine.Pin - buffer [5][5]bool + pin [ledCols + ledRows]machine.Pin + buffer [ledRows][ledCols]bool rotation uint8 } -// Configure sets up the device. -func (d *Device) Configure(cfg Config) { - d.SetRotation(cfg.Rotation) - +func (d *Device) assignPins() { d.pin[0] = machine.LED_COL_1 d.pin[1] = machine.LED_COL_2 d.pin[2] = machine.LED_COL_3 @@ -64,53 +69,7 @@ func (d *Device) Configure(cfg Config) { d.pin[8] = machine.LED_ROW_4 d.pin[9] = machine.LED_ROW_5 - for i := 0; i < 10; i++ { + for i := 0; i < len(d.pin); i++ { d.pin[i].Configure(machine.PinConfig{Mode: machine.PinOutput}) } - - d.ClearDisplay() - d.DisableAll() -} - -// Display sends the buffer (if any) to the screen. -func (d *Device) Display() error { - for x := 0; x < 5; x++ { - d.DisableAll() - d.pin[x].Low() - - for y := 0; y < 5; y++ { - if d.buffer[x][y] { - d.pin[5+y].High() - } else { - d.pin[5+y].Low() - } - } - time.Sleep(time.Millisecond * 4) - } - return nil -} - -// ClearDisplay erases the internal buffer -func (d *Device) ClearDisplay() { - for row := 0; row < 5; row++ { - for col := 0; col < 5; col++ { - d.buffer[row][col] = false - } - } -} - -// DisableAll disables all the LEDs without modifying the buffer -func (d *Device) DisableAll() { - for i := 0; i < 5; i++ { - d.pin[i].High() - d.pin[5+i].Low() - } -} - -// EnableAll enables all the LEDs without modifying the buffer -func (d *Device) EnableAll() { - for i := 0; i < 5; i++ { - d.pin[i].Low() - d.pin[5+i].High() - } } diff --git a/microbitmatrix/microbitmatrix.go b/microbitmatrix/microbitmatrix.go index f6a62ef..748e55a 100644 --- a/microbitmatrix/microbitmatrix.go +++ b/microbitmatrix/microbitmatrix.go @@ -1,44 +1,132 @@ -// Package microbitmatrix implements a driver for the BBC micro:bit's LED matrix. -// -// Schematic: https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf package microbitmatrix // import "tinygo.org/x/drivers/microbitmatrix" import ( "image/color" + "time" ) type Config struct { + // Rotation of the LED matrix. + // + // Valid values: + // + // 0: regular orientation, (0 degree rotation) + // 1: 90 degree rotation clock wise + // 2: 180 degree rotation clock wise + // 3: 270 degree rotation clock wise Rotation uint8 } +const ( + RotationNormal = 0 + Rotation90 = 1 + Rotation180 = 2 + Rotation270 = 3 +) + // New returns a new microbitmatrix driver. func New() Device { return Device{} } -// SetRotation changes the rotation of the LED matrix +// Configure sets up the device. +func (d *Device) Configure(cfg Config) { + d.SetRotation(cfg.Rotation) + + d.assignPins() + + d.ClearDisplay() + d.DisableAll() +} + +// SetRotation changes the rotation of the LED matrix. +// +// Valid values for rotation: +// +// 0: regular orientation, (0 degree rotation) +// 1: 90 degree rotation clock wise +// 2: 180 degree rotation clock wise +// 3: 270 degree rotation clock wise func (d *Device) SetRotation(rotation uint8) { d.rotation = rotation % 4 } +const ( + rowIdx = 0 + colIdx = 1 +) + // SetPixel modifies the internal buffer in a single pixel. func (d *Device) SetPixel(x int16, y int16, c color.RGBA) { if x < 0 || x >= 5 || y < 0 || y >= 5 { return } + col := x + row := y if c.R != 0 || c.G != 0 || c.B != 0 { - d.buffer[matrixRotations[d.rotation][y][x][0]][matrixRotations[d.rotation][y][x][1]] = true + d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = true } else { - d.buffer[matrixRotations[d.rotation][y][x][0]][matrixRotations[d.rotation][y][x][1]] = false + d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = false } } -// 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 { if x < 0 || x >= 5 || y < 0 || y >= 5 { return false } - return d.buffer[matrixRotations[d.rotation][y][x][0]][matrixRotations[d.rotation][y][x][1]] + col := x + row := y + return d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] +} + +const displayRefreshDelay = 8 * time.Millisecond + +// Display sends the buffer (if any) to the screen. +func (d *Device) Display() error { + for row := 0; row < ledRows; row++ { + d.DisableAll() + d.pin[ledCols+row].Low() + + for col := 0; col < ledCols; col++ { + if d.buffer[row][col] { + d.pin[col].High() + } else { + d.pin[col].Low() + } + } + time.Sleep(time.Millisecond * 4) + } + return nil +} + +// ClearDisplay erases the internal buffer. +func (d *Device) ClearDisplay() { + for row := 0; row < ledRows; row++ { + for col := 0; col < ledCols; col++ { + d.buffer[row][col] = false + } + } +} + +// DisableAll disables all the LEDs without modifying the buffer. +func (d *Device) DisableAll() { + for i := 0; i < ledCols; i++ { + d.pin[i].High() + } + for i := 0; i < ledRows; i++ { + d.pin[ledCols+i].Low() + } +} + +// EnableAll enables all the LEDs without modifying the buffer. +func (d *Device) EnableAll() { + for i := 0; i < ledCols; i++ { + d.pin[i].Low() + } + for i := 0; i < ledRows; i++ { + d.pin[ledCols+i].High() + } } // Size returns the current size of the display.