mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-16 02:33:28 +00:00
esp32c3/esp32s3: refactoring and corrections for SPI implementation
This refactors and corrects the SPI implentation for the ESP32C3 and ESP32S3 processors. There was a lot of duplicated code, as well as some errors such as incorrectly calculating speed on the esp32c3 implementation. This will also be helpful when adding additional processors that use very similar peripheral registers. Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
@@ -16,11 +16,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
SPI_MODE0 = uint8(0)
|
||||
SPI_MODE1 = uint8(1)
|
||||
SPI_MODE2 = uint8(2)
|
||||
SPI_MODE3 = uint8(3)
|
||||
|
||||
FSPICLK_IN_IDX = uint32(63)
|
||||
FSPICLK_OUT_IDX = uint32(63)
|
||||
FSPIQ_IN_IDX = uint32(64)
|
||||
@@ -56,64 +51,6 @@ var (
|
||||
SPI0 = SPI2
|
||||
)
|
||||
|
||||
// SPIConfig is used to store config info for SPI.
|
||||
type SPIConfig struct {
|
||||
Frequency uint32
|
||||
SCK Pin // Serial Clock
|
||||
SDO Pin // Serial Data Out (MOSI)
|
||||
SDI Pin // Serial Data In (MISO)
|
||||
CS Pin // Chip Select (optional)
|
||||
LSBFirst bool // MSB is default
|
||||
Mode uint8 // SPI_MODE0 is default
|
||||
}
|
||||
|
||||
// Compute the SPI bus frequency from the CPU frequency.
|
||||
func freqToClockDiv(hz uint32) uint32 {
|
||||
fcpu := CPUFrequency()
|
||||
if hz >= fcpu { // maximum frequency
|
||||
return 1 << 31
|
||||
}
|
||||
if hz < (fcpu / (16 * 64)) { // minimum frequency
|
||||
return 15<<18 | 63<<12 | 31<<6 | 63 // pre=15, n=63
|
||||
}
|
||||
|
||||
// iterate looking for an exact match
|
||||
// or iterate all 16 prescaler options
|
||||
// looking for the smallest error
|
||||
var bestPre, bestN, bestErr uint32
|
||||
bestN = 1
|
||||
bestErr = 0xffffffff
|
||||
q := uint32(float32(pplClockFreq)/float32(hz) + float32(0.5))
|
||||
for p := uint32(0); p < 16; p++ {
|
||||
n := q/(p+1) - 1
|
||||
if n < 1 { // prescaler became too large, stop enum
|
||||
break
|
||||
}
|
||||
if n > 63 { // prescaler too small, skip to next
|
||||
continue
|
||||
}
|
||||
|
||||
freq := fcpu / ((p + 1) * (n + 1))
|
||||
if freq == hz { // exact match
|
||||
return p<<18 | n<<12 | (n/2)<<6 | n
|
||||
}
|
||||
|
||||
var err uint32
|
||||
if freq < hz {
|
||||
err = hz - freq
|
||||
} else {
|
||||
err = freq - hz
|
||||
}
|
||||
if err < bestErr {
|
||||
bestErr = err
|
||||
bestPre = p
|
||||
bestN = n
|
||||
}
|
||||
}
|
||||
|
||||
return bestPre<<18 | bestN<<12 | (bestN/2)<<6 | bestN
|
||||
}
|
||||
|
||||
// Configure and make the SPI peripheral ready to use.
|
||||
func (spi *SPI) Configure(config SPIConfig) error {
|
||||
// right now this is only setup to work for the esp32c3 spi2 bus
|
||||
@@ -172,16 +109,16 @@ func (spi *SPI) Configure(config SPIConfig) error {
|
||||
|
||||
// set spi2 data mode
|
||||
switch config.Mode {
|
||||
case SPI_MODE0:
|
||||
case Mode0:
|
||||
spi.Bus.SetMISC_CK_IDLE_EDGE(0)
|
||||
spi.Bus.SetUSER_CK_OUT_EDGE(0)
|
||||
case SPI_MODE1:
|
||||
case Mode1:
|
||||
spi.Bus.SetMISC_CK_IDLE_EDGE(0)
|
||||
spi.Bus.SetUSER_CK_OUT_EDGE(1)
|
||||
case SPI_MODE2:
|
||||
case Mode2:
|
||||
spi.Bus.SetMISC_CK_IDLE_EDGE(1)
|
||||
spi.Bus.SetUSER_CK_OUT_EDGE(1)
|
||||
case SPI_MODE3:
|
||||
case Mode3:
|
||||
spi.Bus.SetMISC_CK_IDLE_EDGE(1)
|
||||
spi.Bus.SetUSER_CK_OUT_EDGE(0)
|
||||
default:
|
||||
@@ -254,36 +191,7 @@ func (spi *SPI) Tx(w, r []byte) error {
|
||||
|
||||
// Fill tx buffer.
|
||||
transferWords := (*[16]volatile.Register32)(unsafe.Pointer(uintptr(unsafe.Pointer(&spi.Bus.W0))))
|
||||
if len(w) >= 64 {
|
||||
// We can fill the entire 64-byte transfer buffer with data.
|
||||
// This loop is slightly faster than the loop below.
|
||||
for i := 0; i < 16; i++ {
|
||||
word := uint32(w[i*4]) | uint32(w[i*4+1])<<8 | uint32(w[i*4+2])<<16 | uint32(w[i*4+3])<<24
|
||||
transferWords[i].Set(word)
|
||||
}
|
||||
} else {
|
||||
// We can't fill the entire transfer buffer, so we need to be a bit
|
||||
// more careful.
|
||||
// Note that parts of the transfer buffer that aren't used still
|
||||
// need to be set to zero, otherwise we might be transferring
|
||||
// garbage from a previous transmission if w is smaller than r.
|
||||
for i := 0; i < 16; i++ {
|
||||
var word uint32
|
||||
if i*4+3 < len(w) {
|
||||
word |= uint32(w[i*4+3]) << 24
|
||||
}
|
||||
if i*4+2 < len(w) {
|
||||
word |= uint32(w[i*4+2]) << 16
|
||||
}
|
||||
if i*4+1 < len(w) {
|
||||
word |= uint32(w[i*4+1]) << 8
|
||||
}
|
||||
if i*4+0 < len(w) {
|
||||
word |= uint32(w[i*4+0]) << 0
|
||||
}
|
||||
transferWords[i].Set(word)
|
||||
}
|
||||
}
|
||||
spiTxFillBuffer(transferWords, w)
|
||||
|
||||
// Do the transfer.
|
||||
spi.Bus.SetMS_DLEN_MS_DATA_BITLEN(uint32(chunkSize)*8 - 1)
|
||||
|
||||
Reference in New Issue
Block a user