mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-19 14:14:00 +00:00
sdcard: add support for fatfs
This commit is contained in:
@@ -195,6 +195,8 @@ endif
|
|||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/tinyfs/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
|
||||||
DRIVERS = $(wildcard */)
|
DRIVERS = $(wildcard */)
|
||||||
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func main() {
|
|||||||
|
|
||||||
## Currently supported devices
|
## Currently supported devices
|
||||||
|
|
||||||
The following 65 devices are supported.
|
The following 66 devices are supported.
|
||||||
|
|
||||||
| Device Name | Interface Type |
|
| Device Name | Interface Type |
|
||||||
|----------|-------------|
|
|----------|-------------|
|
||||||
@@ -106,6 +106,7 @@ The following 65 devices are supported.
|
|||||||
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
|
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
|
||||||
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||||
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
|
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
|
||||||
|
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
|
||||||
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
||||||
| [SSD1331 TFT color display](https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/) | SPI |
|
| [SSD1331 TFT color display](https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/) | SPI |
|
||||||
| [SSD1351 OLED display](https://download.mikroe.com/documents/datasheets/ssd1351-revision-1.3.pdf) | SPI |
|
| [SSD1351 OLED display](https://download.mikroe.com/documents/datasheets/ssd1351-revision-1.3.pdf) | SPI |
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ func xxdfprint(w io.Writer, offset uint32, b []byte) {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
|
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
|
||||||
for j, n := 0, l-i; j < 16; j++ {
|
for j, n := 0, l-i; j < 16; j++ {
|
||||||
if j >= n || !strconv.IsPrint(rune(b[i+j])) || b[i+j] >= 0xFE {
|
if j >= n || !strconv.IsPrint(rune(b[i+j])) || b[i+j] >= 0x80 {
|
||||||
buf16[j] = '.'
|
buf16[j] = '.'
|
||||||
} else {
|
} else {
|
||||||
buf16[j] = b[i+j]
|
buf16[j] = b[i+j]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build feather_m4 feather_m4_can
|
// +build feather_m4 feather_m4_can feather_nrf52840
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -8,15 +8,9 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
spi = machine.SPI0
|
spi = machine.SPI0
|
||||||
spi.Configure(machine.SPIConfig{
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
SCK: machine.SPI0_SCK_PIN,
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
SDO: machine.SPI0_SDO_PIN,
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
SDI: machine.SPI0_SDI_PIN,
|
|
||||||
Frequency: 24000000,
|
|
||||||
LSBFirst: false,
|
|
||||||
Mode: 0, // phase=0, polarity=0
|
|
||||||
})
|
|
||||||
|
|
||||||
csPin = machine.D10
|
csPin = machine.D10
|
||||||
|
|
||||||
ledPin = machine.LED
|
ledPin = machine.LED
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build grandcentral-m4
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI1
|
||||||
|
sckPin = machine.SDCARD_SCK_PIN
|
||||||
|
sdoPin = machine.SDCARD_SDO_PIN
|
||||||
|
sdiPin = machine.SDCARD_SDI_PIN
|
||||||
|
csPin = machine.SDCARD_CS_PIN
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build atsamd21
|
// +build atsamd21,!p1am_100
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -8,15 +8,9 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
spi = machine.SPI0
|
spi = machine.SPI0
|
||||||
spi.Configure(machine.SPIConfig{
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
SCK: machine.SPI0_SCK_PIN,
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
SDO: machine.SPI0_SDO_PIN,
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
SDI: machine.SPI0_SDI_PIN,
|
|
||||||
Frequency: 24000000,
|
|
||||||
LSBFirst: false,
|
|
||||||
Mode: 0, // phase=0, polarity=0
|
|
||||||
})
|
|
||||||
|
|
||||||
csPin = machine.D2
|
csPin = machine.D2
|
||||||
|
|
||||||
ledPin = machine.LED
|
ledPin = machine.LED
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
spi machine.SPI
|
spi machine.SPI
|
||||||
|
sckPin machine.Pin
|
||||||
|
sdoPin machine.Pin
|
||||||
|
sdiPin machine.Pin
|
||||||
csPin machine.Pin
|
csPin machine.Pin
|
||||||
ledPin machine.Pin
|
ledPin machine.Pin
|
||||||
)
|
)
|
||||||
@@ -21,7 +24,7 @@ func main() {
|
|||||||
led := ledPin
|
led := ledPin
|
||||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
|
||||||
sd := sdcard.New(spi, csPin)
|
sd := sdcard.New(spi, sckPin, sdoPin, sdiPin, csPin)
|
||||||
err := sd.Configure()
|
err := sd.Configure()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%s\r\n", err.Error())
|
fmt.Printf("%s\r\n", err.Error())
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build p1am_100
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SDCARD_SPI
|
||||||
|
sckPin = machine.SDCARD_SCK_PIN
|
||||||
|
sdoPin = machine.SDCARD_SDO_PIN
|
||||||
|
sdiPin = machine.SDCARD_SDI_PIN
|
||||||
|
csPin = machine.SDCARD_SS_PIN
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build pygamer
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI0
|
||||||
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
|
csPin = machine.D4
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -8,15 +8,9 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
spi = machine.SPI0
|
spi = machine.SPI0
|
||||||
spi.Configure(machine.SPIConfig{
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
SCK: machine.SPI0_SCK_PIN,
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
SDO: machine.SPI0_SDO_PIN,
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
SDI: machine.SPI0_SDI_PIN,
|
|
||||||
Frequency: 24000000,
|
|
||||||
LSBFirst: false,
|
|
||||||
Mode: 0, // phase=0, polarity=0
|
|
||||||
})
|
|
||||||
|
|
||||||
csPin = machine.D32 // SD_CS
|
csPin = machine.D32 // SD_CS
|
||||||
|
|
||||||
ledPin = machine.LED
|
ledPin = machine.LED
|
||||||
|
|||||||
@@ -8,15 +8,9 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
spi = machine.SPI2
|
spi = machine.SPI2
|
||||||
spi.Configure(machine.SPIConfig{
|
sckPin = machine.SCK2
|
||||||
SCK: machine.SCK2,
|
sdoPin = machine.SDO2
|
||||||
SDO: machine.SDO2,
|
sdiPin = machine.SDI2
|
||||||
SDI: machine.SDI2,
|
|
||||||
Frequency: 24000000,
|
|
||||||
LSBFirst: false,
|
|
||||||
Mode: 0, // phase=0, polarity=0
|
|
||||||
})
|
|
||||||
|
|
||||||
csPin = machine.SS2
|
csPin = machine.SS2
|
||||||
|
|
||||||
ledPin = machine.LED
|
ledPin = machine.LED
|
||||||
|
|||||||
@@ -0,0 +1,519 @@
|
|||||||
|
// +build tinygo
|
||||||
|
|
||||||
|
package console
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"machine"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinyfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const consoleBufLen = 64
|
||||||
|
|
||||||
|
const startBlock = 0
|
||||||
|
const blockCount = 0
|
||||||
|
|
||||||
|
var (
|
||||||
|
debug = false
|
||||||
|
|
||||||
|
input [consoleBufLen]byte
|
||||||
|
|
||||||
|
console = machine.Serial
|
||||||
|
readyLED = machine.LED
|
||||||
|
|
||||||
|
flashdev tinyfs.BlockDevice
|
||||||
|
fs tinyfs.Filesystem
|
||||||
|
|
||||||
|
currdir = "/"
|
||||||
|
|
||||||
|
commands = map[string]cmdfunc{
|
||||||
|
"": noop,
|
||||||
|
"dbg": dbg,
|
||||||
|
"lsblk": lsblk,
|
||||||
|
"mount": mount,
|
||||||
|
"umount": umount,
|
||||||
|
"format": format,
|
||||||
|
"xxd": xxd,
|
||||||
|
"ls": ls,
|
||||||
|
"samples": samples,
|
||||||
|
"mkdir": mkdir,
|
||||||
|
"cat": cat,
|
||||||
|
"create": create,
|
||||||
|
"write": write,
|
||||||
|
"rm": rm,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type cmdfunc func(argv []string)
|
||||||
|
|
||||||
|
const (
|
||||||
|
StateInput = iota
|
||||||
|
StateEscape
|
||||||
|
StateEscBrc
|
||||||
|
StateCSI
|
||||||
|
)
|
||||||
|
|
||||||
|
func RunFor(dev tinyfs.BlockDevice, filesys tinyfs.Filesystem) {
|
||||||
|
flashdev = dev
|
||||||
|
fs = filesys
|
||||||
|
|
||||||
|
readyLED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
readyLED.High()
|
||||||
|
|
||||||
|
readyLED.Low()
|
||||||
|
println("SPI Configured. Reading flash info")
|
||||||
|
|
||||||
|
/*
|
||||||
|
lfsConfig := flashlfs.NewConfig()
|
||||||
|
if blockCount == 0 {
|
||||||
|
lfsConfig.BlockCount = (flashdev.Attrs().TotalSize / lfsConfig.BlockSize) - startBlock
|
||||||
|
} else {
|
||||||
|
lfsConfig.BlockCount = blockCount
|
||||||
|
}
|
||||||
|
println("Start block:", startBlock)
|
||||||
|
println("Block count:", lfsConfig.BlockCount)
|
||||||
|
|
||||||
|
blockdev = flashlfs.NewBlockDevice(flashdev, startBlock, lfsConfig.BlockSize)
|
||||||
|
*/
|
||||||
|
|
||||||
|
prompt()
|
||||||
|
|
||||||
|
var state = StateInput
|
||||||
|
|
||||||
|
for i := 0; ; {
|
||||||
|
if console.Buffered() > 0 {
|
||||||
|
data, _ := console.ReadByte()
|
||||||
|
if debug {
|
||||||
|
fmt.Printf("\rdata: %x\r\n\r", data)
|
||||||
|
prompt()
|
||||||
|
console.Write(input[:i])
|
||||||
|
}
|
||||||
|
switch state {
|
||||||
|
case StateInput:
|
||||||
|
switch data {
|
||||||
|
case 0x8:
|
||||||
|
fallthrough
|
||||||
|
case 0x7f: // this is probably wrong... works on my machine tho :)
|
||||||
|
// backspace
|
||||||
|
if i > 0 {
|
||||||
|
i -= 1
|
||||||
|
console.Write([]byte{0x8, 0x20, 0x8})
|
||||||
|
}
|
||||||
|
case 13:
|
||||||
|
// return key
|
||||||
|
if console.Buffered() > 0 {
|
||||||
|
data, _ := console.ReadByte()
|
||||||
|
if data != 10 {
|
||||||
|
println("\r\nunexpected: \r", int(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.Write([]byte("\r\n"))
|
||||||
|
runCommand(string(input[:i]))
|
||||||
|
prompt()
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
continue
|
||||||
|
case 27:
|
||||||
|
// escape
|
||||||
|
state = StateEscape
|
||||||
|
default:
|
||||||
|
// anything else, just echo the character if it is printable
|
||||||
|
if strconv.IsPrint(rune(data)) {
|
||||||
|
if i < (consoleBufLen - 1) {
|
||||||
|
console.WriteByte(data)
|
||||||
|
input[i] = data
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case StateEscape:
|
||||||
|
switch data {
|
||||||
|
case 0x5b:
|
||||||
|
state = StateEscBrc
|
||||||
|
default:
|
||||||
|
state = StateInput
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// TODO: handle escape sequences
|
||||||
|
state = StateInput
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCommand(line string) {
|
||||||
|
argv := strings.SplitN(strings.TrimSpace(line), " ", -1)
|
||||||
|
cmd := argv[0]
|
||||||
|
cmdfn, ok := commands[cmd]
|
||||||
|
if !ok {
|
||||||
|
println("unknown command: " + line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmdfn(argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func noop(argv []string) {}
|
||||||
|
|
||||||
|
func dbg(argv []string) {
|
||||||
|
if debug {
|
||||||
|
debug = false
|
||||||
|
println("Console debugging off")
|
||||||
|
} else {
|
||||||
|
debug = true
|
||||||
|
println("Console debugging on")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lsblk(argv []string) {
|
||||||
|
fmt.Printf("lsblk : not implement\r\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func mount(argv []string) {
|
||||||
|
if err := fs.Mount(); err != nil {
|
||||||
|
println("Could not mount LittleFS filesystem: " + err.Error() + "\r\n")
|
||||||
|
} else {
|
||||||
|
println("Successfully mounted LittleFS filesystem.\r\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func format(argv []string) {
|
||||||
|
if err := fs.Format(); err != nil {
|
||||||
|
println("Could not format LittleFS filesystem: " + err.Error() + "\r\n")
|
||||||
|
} else {
|
||||||
|
println("Successfully formatted LittleFS filesystem.\r\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func umount(argv []string) {
|
||||||
|
if err := fs.Unmount(); err != nil {
|
||||||
|
println("Could not unmount LittleFS filesystem: " + err.Error() + "\r\n")
|
||||||
|
} else {
|
||||||
|
println("Successfully unmounted LittleFS filesystem.\r\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
var err error
|
||||||
|
if fatfs == nil {
|
||||||
|
fatfs, err = fat.New(fatdisk)
|
||||||
|
if err != nil {
|
||||||
|
fatfs = nil
|
||||||
|
println("could not load FAT filesystem: " + err.Error() + "\r\n")
|
||||||
|
}
|
||||||
|
fmt.Printf("loaded fs\r\n")
|
||||||
|
}
|
||||||
|
if rootdir == nil {
|
||||||
|
rootdir, err = fatfs.RootDir()
|
||||||
|
if err != nil {
|
||||||
|
rootdir = nil
|
||||||
|
println("could not load rootdir: " + err.Error() + "\r\n")
|
||||||
|
}
|
||||||
|
fmt.Printf("loaded rootdir\r\n")
|
||||||
|
}
|
||||||
|
if currdir == nil {
|
||||||
|
currdir = rootdir
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func ls(argv []string) {
|
||||||
|
path := "/"
|
||||||
|
if len(argv) > 1 {
|
||||||
|
path = strings.TrimSpace(argv[1])
|
||||||
|
}
|
||||||
|
dir, err := fs.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Could not open directory %s: %v\r\n", path, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
infos, err := dir.Readdir(0)
|
||||||
|
_ = infos
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Could not read directory %s: %v\r\n", path, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, info := range infos {
|
||||||
|
s := "-rwxrwxrwx"
|
||||||
|
if info.IsDir() {
|
||||||
|
s = "drwxrwxrwx"
|
||||||
|
}
|
||||||
|
fmt.Printf("%s %5d %s\r\n", s, info.Size(), info.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkdir(argv []string) {
|
||||||
|
tgt := ""
|
||||||
|
if len(argv) == 2 {
|
||||||
|
tgt = strings.TrimSpace(argv[1])
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Trying mkdir to " + tgt)
|
||||||
|
}
|
||||||
|
if tgt == "" {
|
||||||
|
println("Usage: mkdir <target dir>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := fs.Mkdir(tgt, 0777)
|
||||||
|
if err != nil {
|
||||||
|
println("Could not mkdir " + tgt + ": " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rm(argv []string) {
|
||||||
|
tgt := ""
|
||||||
|
if len(argv) == 2 {
|
||||||
|
tgt = strings.TrimSpace(argv[1])
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Trying rm to " + tgt)
|
||||||
|
}
|
||||||
|
if tgt == "" {
|
||||||
|
println("Usage: rm <target dir>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := fs.Remove(tgt)
|
||||||
|
if err != nil {
|
||||||
|
println("Could not rm " + tgt + ": " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func samples(argv []string) {
|
||||||
|
buf := make([]byte, 90)
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
name := fmt.Sprintf("file%d.txt", i)
|
||||||
|
if bytes, err := createSampleFile(name, buf); err != nil {
|
||||||
|
fmt.Printf("%s\r\n", err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
fmt.Printf("wrote %d bytes to %s\r\n", bytes, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func create(argv []string) {
|
||||||
|
tgt := ""
|
||||||
|
if len(argv) == 2 {
|
||||||
|
tgt = strings.TrimSpace(argv[1])
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Trying create to " + tgt)
|
||||||
|
}
|
||||||
|
buf := make([]byte, 90)
|
||||||
|
if bytes, err := createSampleFile(tgt, buf); err != nil {
|
||||||
|
fmt.Printf("%s\r\n", err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
fmt.Printf("wrote %d bytes to %s\r\n", bytes, tgt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func write(argv []string) {
|
||||||
|
tgt := ""
|
||||||
|
if len(argv) == 2 {
|
||||||
|
tgt = strings.TrimSpace(argv[1])
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Trying receive to " + tgt)
|
||||||
|
}
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
f, err := fs.OpenFile(tgt, os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error opening %s: %s\r\n", tgt, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
var n int
|
||||||
|
for {
|
||||||
|
if console.Buffered() > 0 {
|
||||||
|
data, _ := console.ReadByte()
|
||||||
|
switch data {
|
||||||
|
case 0x04:
|
||||||
|
fmt.Printf("wrote %d bytes to %s\r\n", n, tgt)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
// anything else, just echo the character if it is printable
|
||||||
|
if strconv.IsPrint(rune(data)) {
|
||||||
|
console.WriteByte(data)
|
||||||
|
}
|
||||||
|
buf[0] = data
|
||||||
|
if _, err := f.Write(buf); err != nil {
|
||||||
|
fmt.Printf("\nerror writing: %s\r\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSampleFile(name string, buf []byte) (int, error) {
|
||||||
|
for j := uint8(0); j < uint8(len(buf)); j++ {
|
||||||
|
buf[j] = 0x20 + j
|
||||||
|
}
|
||||||
|
f, err := fs.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("error opening %s: %s", name, err.Error())
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
bytes, err := f.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("error writing %s: %s", name, err.Error())
|
||||||
|
}
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func cd(argv []string) {
|
||||||
|
|
||||||
|
if fatfs == nil || rootdir == nil {
|
||||||
|
mnt(nil)
|
||||||
|
}
|
||||||
|
if len(argv) == 1 {
|
||||||
|
currdir = rootdir
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tgt := ""
|
||||||
|
if len(argv) == 2 {
|
||||||
|
tgt = strings.TrimSpace(argv[1])
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Trying to cd to " + tgt)
|
||||||
|
}
|
||||||
|
if tgt == "" {
|
||||||
|
println("Usage: cd <target dir>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Getting entry")
|
||||||
|
}
|
||||||
|
entry := currdir.Entry(tgt)
|
||||||
|
if entry == nil {
|
||||||
|
println("File not found: " + tgt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !entry.IsDir() {
|
||||||
|
println("Not a directory: " + tgt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Getting dir")
|
||||||
|
}
|
||||||
|
cd, err := entry.Dir()
|
||||||
|
if err != nil {
|
||||||
|
println("Could not cd to " + tgt + ": " + err.Error())
|
||||||
|
}
|
||||||
|
currdir = cd
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func cat(argv []string) {
|
||||||
|
tgt := ""
|
||||||
|
if len(argv) == 2 {
|
||||||
|
tgt = strings.TrimSpace(argv[1])
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Trying to cat to " + tgt)
|
||||||
|
}
|
||||||
|
if tgt == "" {
|
||||||
|
println("Usage: cat <target dir>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
println("Getting entry")
|
||||||
|
}
|
||||||
|
f, err := fs.Open(tgt)
|
||||||
|
if err != nil {
|
||||||
|
println("Could not open: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
if f.IsDir() {
|
||||||
|
println("Not a file: " + tgt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
off := 0x0
|
||||||
|
buf := make([]byte, 64)
|
||||||
|
for {
|
||||||
|
n, err := f.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
println("Error reading " + tgt + ": " + err.Error())
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
xxdfprint(os.Stdout, uint32(off), buf[:n])
|
||||||
|
off += n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func xxd(argv []string) {
|
||||||
|
var err error
|
||||||
|
var addr uint64 = 0x0
|
||||||
|
var size int = 64
|
||||||
|
switch len(argv) {
|
||||||
|
case 3:
|
||||||
|
if size, err = strconv.Atoi(argv[2]); err != nil {
|
||||||
|
println("Invalid size argument: " + err.Error() + "\r\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if size > 512 || size < 1 {
|
||||||
|
fmt.Printf("Size of hexdump must be greater than 0 and less than %d\r\n", 512)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 2:
|
||||||
|
/*
|
||||||
|
if argv[1][:2] != "0x" {
|
||||||
|
println("Invalid hex address (should start with 0x)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
|
||||||
|
println("Invalid address: " + err.Error() + "\r\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 1:
|
||||||
|
// no args supplied, so nothing to do here, just use the defaults
|
||||||
|
default:
|
||||||
|
println("usage: xxd <hex address, ex: 0xA0> <size of hexdump in bytes>\r\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf := make([]byte, size)
|
||||||
|
//bsz := uint64(flash.SectorSize)
|
||||||
|
//blockdev.ReadBlock(uint32(addr/bsz), uint32(addr%bsz), buf)
|
||||||
|
flashdev.ReadAt(buf, int64(addr))
|
||||||
|
xxdfprint(os.Stdout, uint32(addr), buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func xxdfprint(w io.Writer, offset uint32, b []byte) {
|
||||||
|
var l int
|
||||||
|
var buf16 = make([]byte, 16)
|
||||||
|
for i, c := 0, len(b); i < c; i += 16 {
|
||||||
|
l = i + 16
|
||||||
|
if l >= c {
|
||||||
|
l = c
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
|
||||||
|
for j, n := 0, l-i; j < 16; j++ {
|
||||||
|
if j >= n || !strconv.IsPrint(rune(b[i+j])) || b[i+j] >= 0x80 {
|
||||||
|
buf16[j] = '.'
|
||||||
|
} else {
|
||||||
|
buf16[j] = b[i+j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.Write(buf16)
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func prompt() {
|
||||||
|
print("==> ")
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build feather_m4 feather_m4_can feather_nrf52840
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI0
|
||||||
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
|
csPin = machine.D10
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build grandcentral-m4
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI1
|
||||||
|
sckPin = machine.SDCARD_SCK_PIN
|
||||||
|
sdoPin = machine.SDCARD_SDO_PIN
|
||||||
|
sdiPin = machine.SDCARD_SDI_PIN
|
||||||
|
csPin = machine.SDCARD_CS_PIN
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build atsamd21,!p1am_100
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI0
|
||||||
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
|
csPin = machine.D2
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tinygo-org/tinyfs/fatfs"
|
||||||
|
"tinygo.org/x/drivers/examples/sdcard/tinyfs/console"
|
||||||
|
"tinygo.org/x/drivers/sdcard"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
spi machine.SPI
|
||||||
|
sckPin machine.Pin
|
||||||
|
sdoPin machine.Pin
|
||||||
|
sdiPin machine.Pin
|
||||||
|
csPin machine.Pin
|
||||||
|
ledPin machine.Pin
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
sd := sdcard.New(spi, sckPin, sdoPin, sdiPin, csPin)
|
||||||
|
err := sd.Configure()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\r\n", err.Error())
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Hour)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesystem := fatfs.New(&sd)
|
||||||
|
|
||||||
|
// Configure FATFS with sector size (must match value in ff.h - use 512)
|
||||||
|
filesystem.Configure(&fatfs.Config{
|
||||||
|
SectorSize: 512,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.RunFor(&sd, filesystem)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build p1am_100
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SDCARD_SPI
|
||||||
|
sckPin = machine.SDCARD_SCK_PIN
|
||||||
|
sdoPin = machine.SDCARD_SDO_PIN
|
||||||
|
sdiPin = machine.SDCARD_SDI_PIN
|
||||||
|
csPin = machine.SDCARD_SS_PIN
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build pygamer
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI0
|
||||||
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
|
csPin = machine.D4
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build pyportal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI0
|
||||||
|
sckPin = machine.SPI0_SCK_PIN
|
||||||
|
sdoPin = machine.SPI0_SDO_PIN
|
||||||
|
sdiPin = machine.SPI0_SDI_PIN
|
||||||
|
csPin = machine.D32 // SD_CS
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
spi = machine.SPI2
|
||||||
|
sckPin = machine.SCK2
|
||||||
|
sdoPin = machine.SDO2
|
||||||
|
sdiPin = machine.SDI2
|
||||||
|
csPin = machine.SS2
|
||||||
|
|
||||||
|
ledPin = machine.LED
|
||||||
|
}
|
||||||
@@ -5,4 +5,5 @@ go 1.15
|
|||||||
require (
|
require (
|
||||||
github.com/eclipse/paho.mqtt.golang v1.2.0
|
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||||
github.com/frankban/quicktest v1.10.2
|
github.com/frankban/quicktest v1.10.2
|
||||||
|
github.com/tinygo-org/tinyfs v0.0.0-20210514090915-924e60a7bcf8
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,5 +9,10 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/tinygo-org/tinyfs v0.0.0-20210514004344-b02c062d12c9 h1:66or7MohOph3xr3gMGCXceLkd+MBoUbV/rPPjl8iQOU=
|
||||||
|
github.com/tinygo-org/tinyfs v0.0.0-20210514004344-b02c062d12c9/go.mod h1:HGuyo42bGd1zWSuS1gwgyyjN36ZZMlEpwM0vSrglmXc=
|
||||||
|
github.com/tinygo-org/tinyfs v0.0.0-20210514090915-924e60a7bcf8 h1:pYwuKe1XuNeJnGV1UjeZ0FhuZ5+lapIq1NUmGacbBwo=
|
||||||
|
github.com/tinygo-org/tinyfs v0.0.0-20210514090915-924e60a7bcf8/go.mod h1:HGuyo42bGd1zWSuS1gwgyyjN36ZZMlEpwM0vSrglmXc=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# SPI sdcard/mmc driver
|
||||||
|
|
||||||
|
This package provides the driver for sdcard/mmc with SPI connection.
|
||||||
|
`examples/sdcard/console` shows a low-level access example.
|
||||||
|
`examples/sdcard/tinyfs` shows an example of using fatfs to read FAT32.
|
||||||
|
|
||||||
|
If you use this package, you need to set `default-stack-size` in `targets/*.json`.
|
||||||
|
For example, `targets/wioterminal.json` has the following configuration.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"inherits": ["atsamd51p19a"],
|
||||||
|
"build-tags": ["wioterminal"],
|
||||||
|
"flash-1200-bps-reset": "true",
|
||||||
|
"flash-method": "msd",
|
||||||
|
"msd-volume-name": "Arduino",
|
||||||
|
"msd-firmware-name": "firmware.uf2",
|
||||||
|
"default-stack-size": 2048
|
||||||
|
}
|
||||||
|
```
|
||||||
+61
-26
@@ -23,8 +23,15 @@ const (
|
|||||||
SD_CARD_TYPE_SDHC = 3 // High Capacity SD card
|
SD_CARD_TYPE_SDHC = 3 // High Capacity SD card
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dummy [512]byte
|
||||||
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus machine.SPI
|
bus machine.SPI
|
||||||
|
sck machine.Pin
|
||||||
|
sdo machine.Pin
|
||||||
|
sdi machine.Pin
|
||||||
cs machine.Pin
|
cs machine.Pin
|
||||||
cmdbuf []byte
|
cmdbuf []byte
|
||||||
dummybuf []byte
|
dummybuf []byte
|
||||||
@@ -34,10 +41,13 @@ type Device struct {
|
|||||||
CSD *CSD
|
CSD *CSD
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(b machine.SPI, cs machine.Pin) Device {
|
func New(b machine.SPI, sck, sdo, sdi, cs machine.Pin) Device {
|
||||||
return Device{
|
return Device{
|
||||||
bus: b,
|
bus: b,
|
||||||
cs: cs,
|
cs: cs,
|
||||||
|
sck: sck,
|
||||||
|
sdo: sdo,
|
||||||
|
sdi: sdi,
|
||||||
cmdbuf: make([]byte, 6),
|
cmdbuf: make([]byte, 6),
|
||||||
dummybuf: make([]byte, 512),
|
dummybuf: make([]byte, 512),
|
||||||
tokenbuf: make([]byte, 1),
|
tokenbuf: make([]byte, 1),
|
||||||
@@ -50,26 +60,38 @@ func (d *Device) Configure() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) initCard() error {
|
func (d *Device) initCard() error {
|
||||||
|
d.bus.Configure(machine.SPIConfig{
|
||||||
|
SCK: d.sck,
|
||||||
|
SDO: d.sdo,
|
||||||
|
SDI: d.sdi,
|
||||||
|
Frequency: 250000,
|
||||||
|
LSBFirst: false,
|
||||||
|
Mode: 0, // phase=0, polarity=0
|
||||||
|
})
|
||||||
|
|
||||||
// set pin modes
|
// set pin modes
|
||||||
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
d.cs.High()
|
d.cs.High()
|
||||||
|
|
||||||
// clock card at least 100 cycles with cs high
|
for i := range dummy {
|
||||||
for i := 0; i < 16; i++ {
|
dummy[i] = 0xFF
|
||||||
d.bus.Transfer(byte(0xFF))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clock card at least 100 cycles with cs high
|
||||||
|
d.bus.Tx(dummy[:10], nil)
|
||||||
|
|
||||||
d.cs.Low()
|
d.cs.Low()
|
||||||
|
d.bus.Tx(dummy[:], nil)
|
||||||
|
|
||||||
// CMD0: init card; sould return _R1_IDLE_STATE (allow 5 attempts)
|
// CMD0: init card; sould return _R1_IDLE_STATE (allow 5 attempts)
|
||||||
ok := false
|
ok := false
|
||||||
for i := 0; i < 2000; i++ {
|
tm := setTimeout(0, 2*time.Second)
|
||||||
|
for !tm.expired() {
|
||||||
// Wait up to 2 seconds to be the same as the Arduino
|
// Wait up to 2 seconds to be the same as the Arduino
|
||||||
if d.cmd(CMD0_GO_IDLE_STATE, 0, 0x95) == _R1_IDLE_STATE {
|
if d.cmd(CMD0_GO_IDLE_STATE, 0, 0x95) == _R1_IDLE_STATE {
|
||||||
ok = true
|
ok = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("no SD card")
|
return fmt.Errorf("no SD card")
|
||||||
@@ -115,20 +137,21 @@ func (d *Device) initCard() error {
|
|||||||
|
|
||||||
// check for timeout
|
// check for timeout
|
||||||
ok = false
|
ok = false
|
||||||
for i := 0; i < 2000; i++ {
|
tm = setTimeout(0, 2*time.Second)
|
||||||
|
for !tm.expired() {
|
||||||
if d.acmd(ACMD41_SD_APP_OP_COND, arg) == 0 {
|
if d.acmd(ACMD41_SD_APP_OP_COND, arg) == 0 {
|
||||||
ok = true
|
ok = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("SD_CARD_ERROR_ACMD41")
|
return fmt.Errorf("SD_CARD_ERROR_ACMD41")
|
||||||
}
|
}
|
||||||
|
|
||||||
// if SD2 read OCR register to check for SDHC card
|
// if SD2 read OCR register to check for SDHC card
|
||||||
if d.sdCardType == SD_CARD_TYPE_SD2 {
|
if d.sdCardType == SD_CARD_TYPE_SD2 {
|
||||||
if d.cmd(CMD58_READ_OCR, 0, 0) != 0 {
|
if d.cmd(CMD58_READ_OCR, 0, 0xFF) != 0 {
|
||||||
return fmt.Errorf("SD_CARD_ERROR_CMD58")
|
return fmt.Errorf("SD_CARD_ERROR_CMD58")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +168,10 @@ func (d *Device) initCard() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.cmd(CMD16_SET_BLOCKLEN, 0x0200, 0xFF) != 0 {
|
||||||
|
return fmt.Errorf("SD_CARD_ERROR_CMD16")
|
||||||
|
}
|
||||||
|
|
||||||
var buf [16]byte
|
var buf [16]byte
|
||||||
// read CID
|
// read CID
|
||||||
err := d.ReadCID(buf[:])
|
err := d.ReadCID(buf[:])
|
||||||
@@ -162,19 +189,28 @@ func (d *Device) initCard() error {
|
|||||||
|
|
||||||
d.cs.High()
|
d.cs.High()
|
||||||
|
|
||||||
|
d.bus.Configure(machine.SPIConfig{
|
||||||
|
SCK: d.sck,
|
||||||
|
SDO: d.sdo,
|
||||||
|
SDI: d.sdi,
|
||||||
|
Frequency: 4000000,
|
||||||
|
LSBFirst: false,
|
||||||
|
Mode: 0, // phase=0, polarity=0
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Device) acmd(cmd byte, arg uint32) byte {
|
func (d Device) acmd(cmd byte, arg uint32) byte {
|
||||||
d.cmd(CMD55_APP_CMD, 0, 0)
|
d.cmd(CMD55_APP_CMD, 0, 0xFF)
|
||||||
return d.cmd(cmd, arg, 0)
|
return d.cmd(cmd, arg, 0xFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Device) cmd(cmd byte, arg uint32, crc byte) byte {
|
func (d Device) cmd(cmd byte, arg uint32, crc byte) byte {
|
||||||
d.cs.Low()
|
d.cs.Low()
|
||||||
|
|
||||||
if cmd != 12 {
|
if cmd != 12 {
|
||||||
d.waitNotBusy(300)
|
d.waitNotBusy(300 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and send the command
|
// create and send the command
|
||||||
@@ -209,8 +245,9 @@ func (d Device) cmd(cmd byte, arg uint32, crc byte) byte {
|
|||||||
return 0xFF // -1
|
return 0xFF // -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Device) waitNotBusy(timeoutMs int) error {
|
func (d Device) waitNotBusy(timeout time.Duration) error {
|
||||||
for i := 0; i < timeoutMs; i++ {
|
tm := setTimeout(1, timeout)
|
||||||
|
for !tm.expired() {
|
||||||
r, err := d.bus.Transfer(byte(0xFF))
|
r, err := d.bus.Transfer(byte(0xFF))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -218,8 +255,6 @@ func (d Device) waitNotBusy(timeoutMs int) error {
|
|||||||
if r == 0xFF {
|
if r == 0xFF {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -227,7 +262,8 @@ func (d Device) waitNotBusy(timeoutMs int) error {
|
|||||||
func (d Device) waitStartBlock() error {
|
func (d Device) waitStartBlock() error {
|
||||||
status := byte(0xFF)
|
status := byte(0xFF)
|
||||||
|
|
||||||
for i := 0; i < 3000; i++ {
|
tm := setTimeout(0, 300*time.Millisecond)
|
||||||
|
for !tm.expired() {
|
||||||
var err error
|
var err error
|
||||||
status, err = d.bus.Transfer(byte(0xFF))
|
status, err = d.bus.Transfer(byte(0xFF))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -237,7 +273,6 @@ func (d Device) waitStartBlock() error {
|
|||||||
if status != 0xFF {
|
if status != 0xFF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Microsecond)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if status != 254 {
|
if status != 254 {
|
||||||
@@ -259,7 +294,7 @@ func (d Device) ReadCID(csd []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d Device) readRegister(cmd uint8, dst []byte) error {
|
func (d Device) readRegister(cmd uint8, dst []byte) error {
|
||||||
if d.cmd(cmd, 0, 0) != 0 {
|
if d.cmd(cmd, 0, 0xFF) != 0 {
|
||||||
return fmt.Errorf("SD_CARD_ERROR_READ_REG")
|
return fmt.Errorf("SD_CARD_ERROR_READ_REG")
|
||||||
}
|
}
|
||||||
if err := d.waitStartBlock(); err != nil {
|
if err := d.waitStartBlock(); err != nil {
|
||||||
@@ -290,14 +325,14 @@ func (d Device) ReadData(block uint32, dst []byte) error {
|
|||||||
if d.sdCardType != SD_CARD_TYPE_SDHC {
|
if d.sdCardType != SD_CARD_TYPE_SDHC {
|
||||||
block <<= 9
|
block <<= 9
|
||||||
}
|
}
|
||||||
if d.cmd(CMD17_READ_SINGLE_BLOCK, block, 0) != 0 {
|
if d.cmd(CMD17_READ_SINGLE_BLOCK, block, 0xFF) != 0 {
|
||||||
return fmt.Errorf("CMD17 error")
|
return fmt.Errorf("CMD17 error")
|
||||||
}
|
}
|
||||||
if err := d.waitStartBlock(); err != nil {
|
if err := d.waitStartBlock(); err != nil {
|
||||||
return fmt.Errorf("waitStartBlock()")
|
return fmt.Errorf("waitStartBlock()")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := d.bus.Tx(nil, dst)
|
err := d.bus.Tx(dummy[:512], dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -318,7 +353,7 @@ func (d Device) WriteMultiStart(block uint32) error {
|
|||||||
if d.sdCardType != SD_CARD_TYPE_SDHC {
|
if d.sdCardType != SD_CARD_TYPE_SDHC {
|
||||||
block <<= 9
|
block <<= 9
|
||||||
}
|
}
|
||||||
if d.cmd(CMD25_WRITE_MULTIPLE_BLOCK, block, 0) != 0 {
|
if d.cmd(CMD25_WRITE_MULTIPLE_BLOCK, block, 0xFF) != 0 {
|
||||||
return fmt.Errorf("CMD25 error")
|
return fmt.Errorf("CMD25 error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +390,7 @@ func (d Device) WriteMulti(buf []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait no busy
|
// wait no busy
|
||||||
err = d.waitNotBusy(600)
|
err = d.waitNotBusy(600 * time.Millisecond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("SD_CARD_ERROR_WRITE_TIMEOUT")
|
return fmt.Errorf("SD_CARD_ERROR_WRITE_TIMEOUT")
|
||||||
}
|
}
|
||||||
@@ -373,7 +408,7 @@ func (d Device) WriteMultiStop() error {
|
|||||||
// skip 1 byte
|
// skip 1 byte
|
||||||
d.bus.Transfer(byte(0xFF))
|
d.bus.Transfer(byte(0xFF))
|
||||||
|
|
||||||
err := d.waitNotBusy(600)
|
err := d.waitNotBusy(600 * time.Millisecond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -391,7 +426,7 @@ func (d Device) WriteData(block uint32, src []byte) error {
|
|||||||
if d.sdCardType != SD_CARD_TYPE_SDHC {
|
if d.sdCardType != SD_CARD_TYPE_SDHC {
|
||||||
block <<= 9
|
block <<= 9
|
||||||
}
|
}
|
||||||
if d.cmd(CMD24_WRITE_BLOCK, block, 0) != 0 {
|
if d.cmd(CMD24_WRITE_BLOCK, block, 0xFF) != 0 {
|
||||||
return fmt.Errorf("CMD24 error")
|
return fmt.Errorf("CMD24 error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +453,7 @@ func (d Device) WriteData(block uint32, src []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait no busy
|
// wait no busy
|
||||||
err = d.waitNotBusy(600)
|
err = d.waitNotBusy(600 * time.Millisecond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("SD_CARD_ERROR_WRITE_TIMEOUT")
|
return fmt.Errorf("SD_CARD_ERROR_WRITE_TIMEOUT")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package sdcard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var timeoutTimer [2]timer
|
||||||
|
|
||||||
|
type timer struct {
|
||||||
|
start int64
|
||||||
|
timeout int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTimeout(timerID int, timeout time.Duration) *timer {
|
||||||
|
timeoutTimer[timerID].start = time.Now().UnixNano()
|
||||||
|
timeoutTimer[timerID].timeout = timeout.Nanoseconds()
|
||||||
|
return &timeoutTimer[timerID]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t timer) expired() bool {
|
||||||
|
return time.Now().UnixNano() > (t.start + t.timeout)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user