From ab012697de9d52c43776c74fe6ed88e191e9a9ff Mon Sep 17 00:00:00 2001 From: ardnew Date: Tue, 1 Sep 2020 21:54:04 -0500 Subject: [PATCH 1/4] add STM32F4 SPI driver for ILI9341, pyportal_boing demo for feather-stm32f405 --- .../pyportal_boing/feather-stm32f405.go | 31 ++++ ili9341/spi_stm32f4.go | 142 ++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 examples/ili9341/pyportal_boing/feather-stm32f405.go create mode 100644 ili9341/spi_stm32f4.go diff --git a/examples/ili9341/pyportal_boing/feather-stm32f405.go b/examples/ili9341/pyportal_boing/feather-stm32f405.go new file mode 100644 index 000000000..fce225534 --- /dev/null +++ b/examples/ili9341/pyportal_boing/feather-stm32f405.go @@ -0,0 +1,31 @@ +// +build feather_stm32f405 + +package main + +import ( + "machine" + + "tinygo.org/x/drivers/ili9341" +) + +var ( + csPin = machine.D12 + dcPin = machine.D11 + display = ili9341.NewSpi( + machine.SPI0, + dcPin, + csPin, + machine.D8, + ) + + backlight = machine.D9 +) + +func init() { + machine.SPI0.Configure(machine.SPIConfig{ + SCK: machine.SPI0_SCK_PIN, + SDO: machine.SPI0_SDO_PIN, + SDI: machine.SPI0_SDI_PIN, + Frequency: 40000000, + }) +} diff --git a/ili9341/spi_stm32f4.go b/ili9341/spi_stm32f4.go new file mode 100644 index 000000000..e537fbc4b --- /dev/null +++ b/ili9341/spi_stm32f4.go @@ -0,0 +1,142 @@ +// +build stm32f4 + +package ili9341 + +import ( + "device/stm32" + "machine" +) + +type spiDriver struct { + bus machine.SPI +} + +func NewSpi(bus machine.SPI, dc, cs, rst machine.Pin) *Device { + return &Device{ + dc: dc, + cs: cs, + rst: rst, + rd: machine.NoPin, + driver: &spiDriver{ + bus: bus, + }, + } +} + +func (pd *spiDriver) configure(config *Config) { +} + +func (pd *spiDriver) write8(b byte) { + if !pd.bus.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { + pd.bus.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) + } + + pd.setWord(b, true, true) + + pd.bus.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) +} + +func (pd *spiDriver) write8n(b byte, n int) { + if !pd.bus.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { + pd.bus.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) + } + + for i := 0; i < n-1; i++ { + pd.setWord(b, i == 0, i+1 == n) + } + + pd.bus.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) +} + +func (pd *spiDriver) write8sl(b []byte) { + if !pd.bus.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { + pd.bus.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) + } + + for i, w := range b { + pd.setWord(w, i == 0, i+1 == len(b)) + } + + pd.bus.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) +} + +func (pd *spiDriver) write16(data uint16) { + if !pd.bus.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { + pd.bus.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) + } + + pd.setWord(uint8(data>>8), true, false) + pd.setWord(uint8(data), false, true) + + pd.bus.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) +} + +func (pd *spiDriver) write16n(data uint16, n int) { + if !pd.bus.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { + pd.bus.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) + } + + for i := 0; i < n; i++ { + pd.setWord(uint8(data>>8), i == 0, false) + pd.setWord(uint8(data), false, i+1 == n) + } + + pd.bus.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) +} + +func (pd *spiDriver) write16sl(data []uint16) { + if !pd.bus.Bus.CR1.HasBits(stm32.SPI_CR1_SPE) { + pd.bus.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) + } + + for i, w := range data { + pd.setWord(uint8(w>>8), i == 0, false) + pd.setWord(uint8(w), false, i+1 == len(data)) + } + + pd.bus.Bus.CR1.ClearBits(stm32.SPI_CR1_SPE) +} + +// puts a single 8-bit word in the SPI data register (DR). +// if first (first word being transmitted) is false, waits for the SPI transmit +// buffer empty bit (TXE) is set before putting the word in DR. +// if last (last word being transmitted) is true, waits for the SPI transmit +// buffer empty bit (TXE) is set and SPI bus busy bit (BSY) is clear before +// returning. +// for all wait operations, a fixed number of wait iterations (const tryMax) are +// performed before a timeout is assumed. +// if timeout occurs, returns false. otherwise, returns true. +func (pd *spiDriver) setWord(word uint8, first bool, last bool) bool { + + const tryMax = 10000 + + canWrite := first + for i := 0; (!canWrite) && (i < tryMax); i++ { + canWrite = pd.bus.Bus.SR.HasBits(stm32.SPI_SR_TXE) + } + if !canWrite { + return false // timeout + } + + pd.bus.Bus.DR.Set(uint32(word)) + + if last { + canReturn := false + for i := 0; (!canReturn) && (i < tryMax); i++ { + canReturn = pd.bus.Bus.SR.HasBits(stm32.SPI_SR_TXE) + } + if !canReturn { + return false // timeout + } + + canReturn = false + for i := 0; (!canReturn) && (i < tryMax); i++ { + canReturn = !pd.bus.Bus.SR.HasBits(stm32.SPI_SR_BSY) + } + if !canReturn { + return false // timeout + } + } + + return true +} From 4a2d86cb55d2cf40b21dd434e4a294d80227c3d3 Mon Sep 17 00:00:00 2001 From: ardnew Date: Sat, 5 Sep 2020 14:23:26 -0500 Subject: [PATCH 2/4] add init delay before continuing with screen drawing --- examples/ili9341/pyportal_boing/feather-stm32f405.go | 7 +++++-- examples/ili9341/pyportal_boing/main.go | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/ili9341/pyportal_boing/feather-stm32f405.go b/examples/ili9341/pyportal_boing/feather-stm32f405.go index fce225534..3fcddae4b 100644 --- a/examples/ili9341/pyportal_boing/feather-stm32f405.go +++ b/examples/ili9341/pyportal_boing/feather-stm32f405.go @@ -10,14 +10,17 @@ import ( var ( csPin = machine.D12 - dcPin = machine.D11 + dcPin = machine.D10 display = ili9341.NewSpi( machine.SPI0, dcPin, csPin, - machine.D8, + machine.D8, // if wired to 3.3, pick an unused pin ) + // ILI9341's LED pin. set this to an unused pin (but not NoPin!) if + // wired via resistor straight to 3.3V. the boing example tries to + // set this pin and will panic if NoPin is used. backlight = machine.D9 ) diff --git a/examples/ili9341/pyportal_boing/main.go b/examples/ili9341/pyportal_boing/main.go index 6b3cfe120..b73898dbe 100644 --- a/examples/ili9341/pyportal_boing/main.go +++ b/examples/ili9341/pyportal_boing/main.go @@ -58,6 +58,7 @@ func main() { backlight.High() display.SetRotation(ili9341.Rotation270) + time.Sleep(50 * time.Millisecond) DrawBackground() startTime = time.Now().UnixNano() From 30bf08afeb174ea3fe39f9a58ae1b94581a1f9fb Mon Sep 17 00:00:00 2001 From: ardnew Date: Sun, 6 Sep 2020 13:34:25 -0500 Subject: [PATCH 3/4] rename initializer to NewSPI per Go convention see: https://github.com/tinygo-org/drivers/pull/196#pullrequestreview-483096061 --- examples/ili9341/pyportal_boing/feather-stm32f405.go | 6 +++--- ili9341/spi_stm32f4.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/ili9341/pyportal_boing/feather-stm32f405.go b/examples/ili9341/pyportal_boing/feather-stm32f405.go index 3fcddae4b..941353da0 100644 --- a/examples/ili9341/pyportal_boing/feather-stm32f405.go +++ b/examples/ili9341/pyportal_boing/feather-stm32f405.go @@ -11,17 +11,17 @@ import ( var ( csPin = machine.D12 dcPin = machine.D10 - display = ili9341.NewSpi( + display = ili9341.NewSPI( machine.SPI0, dcPin, csPin, - machine.D8, // if wired to 3.3, pick an unused pin + machine.D8, // if wired to 3.3V, pick an unused pin ) // ILI9341's LED pin. set this to an unused pin (but not NoPin!) if // wired via resistor straight to 3.3V. the boing example tries to // set this pin and will panic if NoPin is used. - backlight = machine.D9 + backlight = machine.D13 ) func init() { diff --git a/ili9341/spi_stm32f4.go b/ili9341/spi_stm32f4.go index e537fbc4b..efcfc5695 100644 --- a/ili9341/spi_stm32f4.go +++ b/ili9341/spi_stm32f4.go @@ -11,7 +11,7 @@ type spiDriver struct { bus machine.SPI } -func NewSpi(bus machine.SPI, dc, cs, rst machine.Pin) *Device { +func NewSPI(bus machine.SPI, dc, cs, rst machine.Pin) *Device { return &Device{ dc: dc, cs: cs, From dc5d27123234fbdd911e3618a287e1729d1c8bb8 Mon Sep 17 00:00:00 2001 From: ardnew Date: Sun, 6 Sep 2020 13:54:29 -0500 Subject: [PATCH 4/4] fix write8n loop range accidentally leftover from expanded impl --- ili9341/spi_stm32f4.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ili9341/spi_stm32f4.go b/ili9341/spi_stm32f4.go index efcfc5695..866c8f46b 100644 --- a/ili9341/spi_stm32f4.go +++ b/ili9341/spi_stm32f4.go @@ -41,7 +41,7 @@ func (pd *spiDriver) write8n(b byte, n int) { pd.bus.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) } - for i := 0; i < n-1; i++ { + for i := 0; i < n; i++ { pd.setWord(b, i == 0, i+1 == n) }