tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/flash/transport_spi.go (about)

     1  package flash
     2  
     3  import (
     4  	"machine"
     5  )
     6  
     7  type transport interface {
     8  	configure(config *DeviceConfig)
     9  	supportQuadMode() bool
    10  	setClockSpeed(hz uint32) (err error)
    11  	runCommand(cmd byte) (err error)
    12  	readCommand(cmd byte, rsp []byte) (err error)
    13  	writeCommand(cmd byte, data []byte) (err error)
    14  	eraseCommand(cmd byte, address uint32) (err error)
    15  	readMemory(addr uint32, rsp []byte) (err error)
    16  	writeMemory(addr uint32, data []byte) (err error)
    17  }
    18  
    19  // NewSPI returns a pointer to a flash device that uses a SPI peripheral to
    20  // communicate with a serial memory chip.
    21  func NewSPI(spi *machine.SPI, sdo, sdi, sck, cs machine.Pin) *Device {
    22  	return &Device{
    23  		trans: &spiTransport{
    24  			spi: spi,
    25  			sdo: sdo,
    26  			sdi: sdi,
    27  			sck: sck,
    28  			ss:  cs,
    29  		},
    30  	}
    31  }
    32  
    33  type spiTransport struct {
    34  	spi *machine.SPI
    35  	sdo machine.Pin
    36  	sdi machine.Pin
    37  	sck machine.Pin
    38  	ss  machine.Pin
    39  }
    40  
    41  func (tr *spiTransport) configure(config *DeviceConfig) {
    42  	// Configure spi bus
    43  	tr.setClockSpeed(5000000)
    44  
    45  	// Configure chip select pin
    46  	tr.ss.Configure(machine.PinConfig{Mode: machine.PinOutput})
    47  	tr.ss.High()
    48  }
    49  
    50  func (tr *spiTransport) setClockSpeed(hz uint32) error {
    51  	// TODO: un-hardcode this max speed; it is probably a sensible
    52  	//       default maximum for atsamd and nrf at least
    53  	if hz > 24*1e6 {
    54  		hz = 24 * 1e6
    55  	}
    56  	tr.spi.Configure(machine.SPIConfig{
    57  		Frequency: hz,
    58  		SDI:       tr.sdi,
    59  		SDO:       tr.sdo,
    60  		SCK:       tr.sck,
    61  		LSBFirst:  false,
    62  		Mode:      0,
    63  	})
    64  	return nil
    65  }
    66  
    67  func (tr *spiTransport) supportQuadMode() bool {
    68  	return false
    69  }
    70  
    71  func (tr *spiTransport) runCommand(cmd byte) (err error) {
    72  	tr.ss.Low()
    73  	_, err = tr.spi.Transfer(byte(cmd))
    74  	tr.ss.High()
    75  	return
    76  }
    77  
    78  func (tr *spiTransport) readCommand(cmd byte, rsp []byte) (err error) {
    79  	tr.ss.Low()
    80  	if _, err := tr.spi.Transfer(byte(cmd)); err == nil {
    81  		err = tr.readInto(rsp)
    82  	}
    83  	tr.ss.High()
    84  	return
    85  }
    86  
    87  func (tr *spiTransport) readCommandByte(cmd byte) (rsp byte, err error) {
    88  	tr.ss.Low()
    89  	if _, err := tr.spi.Transfer(byte(cmd)); err == nil {
    90  		rsp, err = tr.spi.Transfer(0xFF)
    91  	}
    92  	tr.ss.High()
    93  	return
    94  }
    95  
    96  func (tr *spiTransport) writeCommand(cmd byte, data []byte) (err error) {
    97  	tr.ss.Low()
    98  	if _, err := tr.spi.Transfer(byte(cmd)); err == nil {
    99  		err = tr.writeFrom(data)
   100  	}
   101  	tr.ss.High()
   102  	return
   103  }
   104  
   105  func (tr *spiTransport) eraseCommand(cmd byte, address uint32) (err error) {
   106  	tr.ss.Low()
   107  	err = tr.sendAddress(cmd, address)
   108  	tr.ss.High()
   109  	return
   110  }
   111  
   112  func (tr *spiTransport) readMemory(addr uint32, rsp []byte) (err error) {
   113  	tr.ss.Low()
   114  	if err = tr.sendAddress(cmdRead, addr); err == nil {
   115  		err = tr.readInto(rsp)
   116  	}
   117  	tr.ss.High()
   118  	return
   119  }
   120  
   121  func (tr *spiTransport) writeMemory(addr uint32, data []byte) (err error) {
   122  	tr.ss.Low()
   123  	if err = tr.sendAddress(cmdPageProgram, addr); err == nil {
   124  		err = tr.writeFrom(data)
   125  	}
   126  	tr.ss.High()
   127  	return
   128  }
   129  
   130  func (tr *spiTransport) sendAddress(cmd byte, addr uint32) error {
   131  	_, err := tr.spi.Transfer(byte(cmd))
   132  	if err == nil {
   133  		_, err = tr.spi.Transfer(byte((addr >> 16) & 0xFF))
   134  	}
   135  	if err == nil {
   136  		_, err = tr.spi.Transfer(byte((addr >> 8) & 0xFF))
   137  	}
   138  	if err == nil {
   139  		_, err = tr.spi.Transfer(byte(addr & 0xFF))
   140  	}
   141  	return err
   142  }
   143  
   144  func (tr *spiTransport) readInto(rsp []byte) (err error) {
   145  	for i, c := 0, len(rsp); i < c && err == nil; i++ {
   146  		rsp[i], err = tr.spi.Transfer(0xFF)
   147  	}
   148  	return
   149  }
   150  
   151  func (tr *spiTransport) writeFrom(data []byte) (err error) {
   152  	for i, c := 0, len(data); i < c && err == nil; i++ {
   153  		_, err = tr.spi.Transfer(data[i])
   154  	}
   155  	return
   156  }