mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-04 06:57:48 +00:00
Compare commits
2 Commits
apds9930
...
st7789-async
| Author | SHA1 | Date | |
|---|---|---|---|
| c3d0697dbc | |||
| 9b5840e3cd |
@@ -70,6 +70,54 @@ func (img Image[T]) LimitHeight(height int) Image[T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split the buffer into two buffers that can be used independently.
|
||||||
|
// The top half is split just like LimitHeight. The bottom half is made out of
|
||||||
|
// the remaining buffer area and can be zero. The topHeight parameter must not
|
||||||
|
// be larger than the height of the buffer.
|
||||||
|
//
|
||||||
|
// Always check the height of the bottom half: it may be zero due to alignment
|
||||||
|
// issues.
|
||||||
|
func (img Image[T]) Split(topHeight int) (top, bottom Image[T]) {
|
||||||
|
if topHeight < 0 || topHeight > int(img.height) {
|
||||||
|
panic("Image.Split: out of bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The top half of the buffer, the same as LimitHeight.
|
||||||
|
top = Image[T]{
|
||||||
|
width: img.width,
|
||||||
|
height: int16(topHeight),
|
||||||
|
data: img.data,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the bottom half of the buffer.
|
||||||
|
// This is a bit more complicated since it's possible that the bottom half
|
||||||
|
// can't have all the other bytes: the top half pixels might cross a byte
|
||||||
|
// boundary (for example with RGB444). So instead we calculate the size of
|
||||||
|
// the buffer we have, the size of the buffer that the top half will use
|
||||||
|
// (which is rounded up to a byte boundary), and then calculate the
|
||||||
|
// remaining bytes at the bottom.
|
||||||
|
// In practice, I expect it's unlikely that the top half will cross a byte
|
||||||
|
// boundary since a typical split buffer will have a width that's a nice
|
||||||
|
// round number, but it's possible so we have to avoid this edge case.
|
||||||
|
var zeroColor T
|
||||||
|
dataBytes := (int(img.width)*int(img.height)*zeroColor.BitsPerPixel() + 7) / 8
|
||||||
|
topDataBytes := (int(img.width)*int(topHeight)*zeroColor.BitsPerPixel() + 7) / 8
|
||||||
|
bottomDataBytes := dataBytes - topDataBytes
|
||||||
|
if bottomDataBytes < 0 {
|
||||||
|
// No buffer remaining (not sure whether this is possible in practice
|
||||||
|
// but guarding just in case).
|
||||||
|
bottomDataBytes = 0
|
||||||
|
}
|
||||||
|
bottomHeight := (bottomDataBytes * 8 / zeroColor.BitsPerPixel()) / int(img.width)
|
||||||
|
bottom = Image[T]{
|
||||||
|
width: img.width,
|
||||||
|
height: int16(bottomHeight),
|
||||||
|
data: unsafe.Add(img.data, topDataBytes),
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Len returns the number of pixels in this image buffer.
|
// Len returns the number of pixels in this image buffer.
|
||||||
func (img Image[T]) Len() int {
|
func (img Image[T]) Len() int {
|
||||||
return int(img.width) * int(img.height)
|
return int(img.width) * int(img.height)
|
||||||
|
|||||||
@@ -11,3 +11,12 @@ type SPI interface {
|
|||||||
// If you want to transfer multiple bytes, it is more efficient to use Tx instead.
|
// If you want to transfer multiple bytes, it is more efficient to use Tx instead.
|
||||||
Transfer(b byte) (byte, error)
|
Transfer(b byte) (byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsyncSPI is a SPI bus that also implements async operations (using DMA,
|
||||||
|
// probably).
|
||||||
|
type AsyncSPI interface {
|
||||||
|
SPI
|
||||||
|
IsAsync() bool
|
||||||
|
StartTx(tx, rx []byte) error
|
||||||
|
Wait() error
|
||||||
|
}
|
||||||
|
|||||||
+48
-3
@@ -45,7 +45,7 @@ type Device = DeviceOf[pixel.RGB565BE]
|
|||||||
// DeviceOf is a generic version of Device. It supports multiple different pixel
|
// DeviceOf is a generic version of Device. It supports multiple different pixel
|
||||||
// formats.
|
// formats.
|
||||||
type DeviceOf[T Color] struct {
|
type DeviceOf[T Color] struct {
|
||||||
bus drivers.SPI
|
bus drivers.AsyncSPI
|
||||||
dcPin machine.Pin
|
dcPin machine.Pin
|
||||||
resetPin machine.Pin
|
resetPin machine.Pin
|
||||||
csPin machine.Pin
|
csPin machine.Pin
|
||||||
@@ -83,13 +83,13 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
||||||
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
func New(bus drivers.AsyncSPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
||||||
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
||||||
// wire must already be configured.
|
// wire must already be configured.
|
||||||
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
func NewOf[T Color](bus drivers.AsyncSPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
||||||
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
@@ -404,6 +404,51 @@ func (d *DeviceOf[T]) DrawBitmap(x, y int16, bitmap pixel.Image[T]) error {
|
|||||||
return d.DrawRGBBitmap8(x, y, bitmap.RawBuffer(), int16(width), int16(height))
|
return d.DrawRGBBitmap8(x, y, bitmap.RawBuffer(), int16(width), int16(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAsync returns whether the underlying SPI bus supports async operations.
|
||||||
|
func (d *DeviceOf[T]) IsAsync() bool {
|
||||||
|
return d.bus.IsAsync()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartDrawBitmap starts sending the given bitmap to the screen.
|
||||||
|
// After calling StartDrawBitmap, you can only call Wait() or another
|
||||||
|
// StartDrawBitmap. Calling any other method may result in incorrect behavior.
|
||||||
|
// The bitmap passed to StartDrawBitmap may not be written to until Wait() has
|
||||||
|
// been called.
|
||||||
|
func (d *DeviceOf[T]) StartDrawBitmap(x, y int16, bitmap pixel.Image[T]) error {
|
||||||
|
// Check that the provided buffer is drawn entirely inside the image.
|
||||||
|
width, height := bitmap.Size()
|
||||||
|
displayWidth, displayHeight := d.Size()
|
||||||
|
if uint(int(x)+width) > uint(int(displayWidth)) || uint(int(y)+height) > uint(int(displayHeight)) {
|
||||||
|
return errOutOfBounds
|
||||||
|
}
|
||||||
|
if width <= 0 || height <= 0 {
|
||||||
|
return nil // no bitmap to send
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the previous buffer has been fully sent.
|
||||||
|
err := d.bus.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the next buffer.
|
||||||
|
d.startWrite()
|
||||||
|
d.setWindow(x, y, int16(width), int16(height))
|
||||||
|
d.bus.StartTx(bitmap.RawBuffer(), nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until all previous transfers have completed. After this call, the bitmap
|
||||||
|
// passed to StartDrawBitmap can be reused.
|
||||||
|
func (d *DeviceOf[T]) Wait() error {
|
||||||
|
err := d.bus.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.endWrite()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// FillRectangleWithBuffer fills buffer with a rectangle at a given coordinates.
|
// FillRectangleWithBuffer fills buffer with a rectangle at a given coordinates.
|
||||||
func (d *DeviceOf[T]) FillRectangleWithBuffer(x, y, width, height int16, buffer []color.RGBA) error {
|
func (d *DeviceOf[T]) FillRectangleWithBuffer(x, y, width, height int16, buffer []color.RGBA) error {
|
||||||
i, j := d.Size()
|
i, j := d.Size()
|
||||||
|
|||||||
Reference in New Issue
Block a user