Skip to content

Commit 426521c

Browse files
committed
sd: overhaul type names; SdCardPeripheral, sdCard, state.
1 parent c812a1b commit 426521c

File tree

5 files changed

+178
-178
lines changed

5 files changed

+178
-178
lines changed

sd/sd_card.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
//go:generate stringer -type state
2+
3+
package sd
4+
5+
import "fmt"
6+
7+
type state uint8
8+
9+
// states
10+
const (
11+
sCommand state = iota // expect command
12+
sArgument // expect argument
13+
sChecksum // expect checksum
14+
sData // sending data until misoQueue empty.
15+
)
16+
17+
const (
18+
r1_ready = 0x00
19+
r1_idle = 0x01
20+
)
21+
22+
const (
23+
// blockSize isn't strictly constant, but...
24+
blockSize = 512
25+
)
26+
27+
// sdCard is the state of SD protocol (layer above SPI protocol).
28+
type sdCard struct {
29+
state state
30+
acmd bool // next command is an application-specific command
31+
cmd uint8
32+
arg uint32
33+
argByte uint8
34+
misoQueue []byte // data waiting to be sent from card.
35+
prevCmd uint8
36+
prevAcmd uint8
37+
data []byte
38+
}
39+
40+
func newSdCard() (sd *sdCard) {
41+
return &sdCard{
42+
misoQueue: make([]byte, 0, 1024),
43+
}
44+
}
45+
46+
func (sd *sdCard) enter(state state) {
47+
fmt.Printf("SD state %s -> %s\n", sd.state, state)
48+
sd.state = state
49+
}
50+
51+
func (sd *sdCard) consumeByte(b byte) {
52+
switch sd.state {
53+
case sCommand:
54+
if b>>6 == 1 {
55+
sd.cmd = b & (0xFF >> 2)
56+
sd.enter(sArgument)
57+
sd.arg = 0x00000000
58+
sd.argByte = 0
59+
}
60+
case sArgument:
61+
sd.arg |= uint32(b) << ((3 - sd.argByte) * 8)
62+
if sd.argByte == 3 {
63+
sd.enter(sChecksum)
64+
} else {
65+
sd.argByte++
66+
}
67+
case sChecksum:
68+
if sd.acmd {
69+
sd.handleAcmd()
70+
} else {
71+
sd.handleCmd()
72+
}
73+
case sData:
74+
// ignore; data it being sent.
75+
76+
default:
77+
panic(fmt.Errorf("Unhandled state: %d", sd.state))
78+
}
79+
}
80+
81+
func (sd *sdCard) handleCmd() {
82+
fmt.Printf("SD CMD%d arg: 0x%08X\n", sd.cmd, sd.arg)
83+
switch sd.cmd {
84+
case 0: // GO_IDLE_STATE
85+
fmt.Println("SD CMD0 response: r1_idle")
86+
sd.queueMisoBytes(0xFF, 0xFF, r1_idle) // busy then idle
87+
sd.enter(sCommand)
88+
case 17: // READ_SINGLE_BLOCK
89+
fmt.Println("SD CMD17 response: r1_ready, data start block, data")
90+
sd.queueMisoBytes(0xFF, 0xFF, r1_ready) // busy then ready
91+
sd.queueMisoBytes(0xFF, 0xFF, 0xFF, 0xFF) // time before data block
92+
sd.queueMisoBytes(0xFE) // data start block
93+
sd.queueMisoBytes(sd.readBlock(sd.arg)...)
94+
sd.enter(sData)
95+
case 55: // APP_CMD
96+
fmt.Println("SD CMD55 response: r1_idle")
97+
sd.queueMisoBytes(r1_idle) // busy then idle
98+
sd.acmd = true
99+
sd.enter(sCommand)
100+
default:
101+
panic(fmt.Sprintf("Unhandled CMD%d", sd.cmd))
102+
}
103+
sd.prevCmd = sd.cmd
104+
}
105+
106+
func (sd *sdCard) handleAcmd() {
107+
fmt.Printf("SD ACMD%d arg: 0x%08X\n", sd.cmd, sd.arg)
108+
switch sd.cmd {
109+
case 41: // SD_SEND_OP_COND
110+
if sd.prevAcmd == 41 {
111+
// on second attempt, busy, busy, then ready.
112+
fmt.Println("SD ACMD41 response: r1_ready")
113+
sd.queueMisoBytes(0xFF, 0xFF, r1_ready)
114+
} else {
115+
// on first attempt, busy, busy, then idle (not yet ready).
116+
fmt.Println("SD ACMD41 response: r1_idle")
117+
sd.queueMisoBytes(0xFF, 0xFF, r1_idle)
118+
}
119+
sd.enter(sCommand)
120+
default:
121+
panic(fmt.Sprintf("Unhandled ACMD%d", sd.cmd))
122+
}
123+
sd.prevAcmd = sd.cmd
124+
sd.acmd = false
125+
}
126+
127+
func (sd *sdCard) queueMisoBytes(bytes ...byte) {
128+
sd.misoQueue = append(sd.misoQueue, bytes...)
129+
}
130+
131+
func (sd *sdCard) shiftMiso() (b byte) {
132+
if len(sd.misoQueue) > 0 {
133+
b = sd.misoQueue[0]
134+
sd.misoQueue = sd.misoQueue[1:len(sd.misoQueue)]
135+
if len(sd.misoQueue) == 0 && sd.state == sData {
136+
// transition from sData to sCommand when all data sent.
137+
sd.enter(sCommand)
138+
}
139+
} else {
140+
b = 0x00 // default to low for empty buffer.
141+
}
142+
return
143+
}
144+
145+
func (sd *sdCard) readBlock(start uint32) []byte {
146+
// TODO: bounds checking
147+
// TODO: zero-fill remainder of last page in sd.data?
148+
return sd.data[start : start+blockSize]
149+
}

sd/sd_card_peripheral.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ import (
77
)
88

99
type SdCardPeripheral struct {
10-
state *sdState
11-
spi *spi.Slave
10+
card *sdCard
11+
spi *spi.Slave
1212
}
1313

1414
// SdFromFile creates a new SdCardPeripheral based on the contents of a file.
1515
func NewSdCardPeripheral(pm spi.PinMap) (sd *SdCardPeripheral, err error) {
1616
sd = &SdCardPeripheral{
17-
state: newSdState(),
18-
spi: spi.NewSlave(pm),
17+
card: newSdCard(),
18+
spi: spi.NewSlave(pm),
1919
}
2020

2121
// two busy bytes, then ready.
22-
sd.state.queueMisoBytes(0x00, 0x00, 0xFF)
22+
sd.card.queueMisoBytes(0x00, 0x00, 0xFF)
2323

2424
return
2525
}
@@ -30,7 +30,7 @@ func (sd *SdCardPeripheral) LoadFile(path string) (err error) {
3030
if err != nil {
3131
return
3232
}
33-
sd.state.data = data
33+
sd.card.data = data
3434
return
3535
}
3636

@@ -56,9 +56,9 @@ func (sd *SdCardPeripheral) Write(data byte) {
5656
// mosi, mosi, sd.spi.Miso, sd.spi.Miso)
5757

5858
// consume the byte read, queue miso bytes internally
59-
sd.state.consumeByte(mosi)
59+
sd.card.consumeByte(mosi)
6060
// dequeues one miso byte, or a default byte if queue empty.
61-
sd.spi.QueueMisoBits(sd.state.shiftMiso())
61+
sd.spi.QueueMisoBits(sd.card.shiftMiso())
6262
}
6363
}
6464
}

sd/sd_state.go

Lines changed: 0 additions & 149 deletions
This file was deleted.

sd/sdstatecode_string.go

Lines changed: 0 additions & 21 deletions
This file was deleted.

sd/state_string.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// generated by stringer -type state; DO NOT EDIT
2+
3+
package sd
4+
5+
import "fmt"
6+
7+
const _state_name = "sCommandsArgumentsChecksumsData"
8+
9+
var _state_index = [...]uint8{8, 17, 26, 31}
10+
11+
func (i state) String() string {
12+
if i >= state(len(_state_index)) {
13+
return fmt.Sprintf("state(%d)", i)
14+
}
15+
hi := _state_index[i]
16+
lo := uint8(0)
17+
if i > 0 {
18+
lo = _state_index[i-1]
19+
}
20+
return _state_name[lo:hi]
21+
}

0 commit comments

Comments
 (0)