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 }