Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

li9341: change to use the standard SPI #242

Closed
wants to merge 2 commits into from
Closed

Conversation

sago35
Copy link
Member

@sago35 sago35 commented Mar 29, 2021

The following changes make the SPI faster, so you can now use the standard SPI.

tinygo-org/tinygo#1453

The FPS of examples/ili9341/pyportal_boing is as follows, with acceptable performance.

  • feather-m4 + ili9341 320x240 spi
  • org
    • 42 - 41 fps
  • new
    • 42 - 40fps

However, FillRectangle(), which uses write16n(), is very slow.
For example, it is used in examples/ili9341/basic.
It is visibly slow.
The following is the waveform during FillRectangle(), the new one is very slow with a gap of less than 500ns.

org:
fillscreen (320x240) == 51.38ms
image

new:
fillscreen (320x240) == 380.70ms
image

@sago35 sago35 marked this pull request as draft March 29, 2021 02:33
@sago35
Copy link
Member Author

sago35 commented Mar 29, 2021

The problem of slow write16n() is due to the multiple calls to SPI.
SPI.Tx() now waits for the SPI to finish sending/receiving at the end of SPI.Tx() to simplify the process.

SPI.TxN(w, r []byte, n int) to try it out, and the speed was the same as before the change.

I would like to add TxN() to the machine package (and tinygo-org/drivers.SPI interface), what do you think?
Please let me know if there is a better way.
Perhaps it would also be useful when using SPI with DMA.

func (spi SPI) TxN(w, r []byte, n int) error {
	// At this time, it can only transmit.
	for i := 0; i < len(w)*n; i++ {
		for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_DRE) {
		}
		spi.Bus.DATA.Set(uint32(w[i%len(w)]))
	}
	for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_TXC) {
	}

	// read to clear RXC register
	for spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
		spi.Bus.DATA.Get()
	}

	return nil
}

}
}
display.DrawRGBBitmap(0, j, frameBuffer[0:w], w, 1)
display.DrawRGBBitmap8(0, j, frameBuffer[0:w*2], w, 1)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is necessary.
When using the standard SPI, it is not possible to send while converting endianness.
The same problem will occur in the future when converting to DMA, so it is necessary to use byte-by-byte endianness-aware arrays.

@sago35 sago35 force-pushed the ili9341-stdspi-samd51 branch from b3759d5 to 6378baa Compare April 30, 2021 14:23
@sago35 sago35 changed the title li9341 atsamd51: change to use the standard SPI li9341: change to use the standard SPI Apr 30, 2021
Comment on lines +46 to +57
func (pd *spiDriver) write16n(data uint16, n int) {
for i := 0; i < len(buf); i += 2 {
buf[i] = uint8(data >> 8)
buf[i+1] = uint8(data)
}

for i := 0; i < (n >> 5); i++ {
pd.bus.Tx(buf[:], nil)
}

pd.bus.Tx(buf[:n%64], nil)
}
Copy link
Member Author

@sago35 sago35 Apr 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPI.Tx() every 64 bytes at most, with minimal slowdown
SPI.TxN() is not necessary.

@sago35
Copy link
Member Author

sago35 commented Apr 30, 2021

Checked with feather-m4 (atsamd51) and xiao (atsamd21).

However, it does not work at 24MHz on xiao at this time.
This seems to be a problem with the implementation of machine_atsamd21.go.
I will try to fix it later.

It will probably work on other chips, such as nrf and teensy.
I'll check this part later as well.

@sago35
Copy link
Member Author

sago35 commented May 1, 2021

I have confirmed that feather-m4, feather-nrf52840 and feather-stm32f405 work with exactly the same code by loading the following files.

// +build feather_m4 feather_m4_can feather_nrf52840 feather_stm32f405

package main

import (
	"machine"

	"tinygo.org/x/drivers/ili9341"
)

var (
	display = ili9341.NewSPI(
		machine.SPI0,
		machine.D10, // LCD_DC,
		machine.D11, // LCD_SS_PIN,
		machine.D12, // LCD_RESET,
	)

	backlight = machine.D13 // LCD_BACKLIGHT
)

func init() {
	machine.SPI0.Configure(machine.SPIConfig{
		SCK:       machine.SPI0_SCK_PIN,
		SDO:       machine.SPI0_SDO_PIN,
		SDI:       machine.SPI0_SDI_PIN,
		Frequency: 40000000,
	})
}

The fps is as follows.
It is possible to improve the speed a bit more by modifying the Frequency a bit for each board.

  • feather-m4 (atsamd51)
    • 40 fps
  • feather-nrf52840 (nrf52840)
    • 23 fps
  • feather-stm32f405 (stm32f405)
    • 30 fps

The following picture shows it running on stm32f405.
image

@sago35
Copy link
Member Author

sago35 commented May 1, 2021

However, according to #196, the spi driver for stm32f405 seems to have a speed of 68 - 88 fps.
#196 (comment)

I think this can be solved by using DMA on the SPI driver side.

@sago35
Copy link
Member Author

sago35 commented May 1, 2021

The standard spi-driver is inevitably slow.
The following pictures are from stm32f405.

image

@sago35 sago35 force-pushed the ili9341-stdspi-samd51 branch from 6378baa to 3dd7136 Compare May 5, 2021 12:51
@sago35
Copy link
Member Author

sago35 commented Jun 10, 2021

I've changed my approach to #274, so I'm closing this PR.

@sago35 sago35 closed this Jun 10, 2021
@deadprogram deadprogram deleted the ili9341-stdspi-samd51 branch April 22, 2022 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant