Skip to content

begin adding SDIO #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rp2-pio/piolib/all_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ var errTimeout = errors.New("piolib:timeout")
//go:generate pioasm -o go spi.pio spi_pio.go
//go:generate pioasm -o go ws2812.pio ws2812_pio.go
//go:generate pioasm -o go i2s.pio i2s_pio.go
//go:generate pioasm -o go sdio.pio sdio_pio.go

func gosched() {
runtime.Gosched()
}
235 changes: 235 additions & 0 deletions rp2-pio/piolib/sdio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
//go:build rp2040

package piolib

import (
"device/rp"

pio "github.com/tinygo-org/pio/rp2-pio"
)

const bw_wide = 4

type SDIO struct {
pio *pio.PIO
smDat, smClk, smCmd uint8
progOffset uint8 // Program offset.
sdMask uint32
lenByte uint16
busWidth uint8
}

type SDIOConfig struct {
}

func NewSDIO(smDat, smClk pio.StateMachine, cfg SDIOConfig) (*SDIO, error) {
// sm.Claim() // SM should be claimed beforehand, we just guarantee it's claimed.
// Pio := smDat.PIO()
panic("NOT IMPLEMENTED")
}

func (sd *SDIO) startRead(smidx uint8, enable bool) error {
sm := sd.pio.StateMachine(smidx)
sd.assert()
bitLength := sd.lenByte * 8
if smidx == sd.smDat {
if sd.isWide() {
bitLength += 64
} else {
bitLength += 16
}
}
err := safeWaitTxNotFull(sm)
if err != nil {
return err
}
if sd.isWide() && smidx != sd.smCmd {
sm.TxPut(sd.pioCmd(sdCmdOrDatoffset_stateRxBits, uint16(bitLength)/4-1))
// Note -1 since wrap values are on the last instruction before wrap.
sm.SetWrap(sdCmdOrDatoffset_wrapTargetFor4bitRx, sdCmdOrDatoffset_wrapFor4bitRx-1)
} else {
sm.TxPut(sd.pioCmd(sdCmdOrDatoffset_stateRxBits, uint16(bitLength)-1))
sm.SetWrap(sdCmdOrDatWrapTarget, sdCmdOrDatWrap)
}
sd.deassert()
sd.assert()
if enable {
sm.SetEnabled(true)
}
if bitLength&31 != 0 {
err = safeWaitTxNotFull(sm)
if err != nil {
return err
}
sm.TxPut(sd.pioCmd(sdCmdOrDatoffset_stateInlineInstruction,
pio.EncodeIn(pio.SrcDestNull, 32-(bitLength&31))))
}
err = safeWaitTxNotFull(sm)
if err != nil {
return err
}

var instr uint16
if smidx == sd.smDat {
instr = sdCmdOrDatoffset_noArgStateWaitForCmdBits
} else {
instr = sdCmdOrDatoffset_noArgStateWaitHigh
}

sm.TxPut(sd.pioCmd(sdCmdOrDatoffset_noArgStateWaitForCmdBits, pio.EncodeJmp(instr)))
sd.deassert()
return nil
}

func (sd *SDIO) pioCmd(cmd, param uint16) uint32 {
if cmd <= uint16(len(sdCmdOrDatInstructions)) {
panic("sdio:bad cmd")
}
return uint32(pio.EncodeJmp(cmd))<<16 | uint32(param)
}

func (sd *SDIO) isWide() bool {
return sd.busWidth == bw_wide
}

func (sd *SDIO) assert() {
rp.SIO.GPIO_OUT_SET.Set(sd.sdMask)
}
func (sd *SDIO) deassert() {
rp.SIO.GPIO_OUT_CLR.Set(sd.sdMask)
}

const sdMaxWait = 1000000

func safeWaitTxNotFull(sm pio.StateMachine) error {
wooble := 0
for sm.IsTxFIFOFull() {
wooble++
if wooble > sdMaxWait {
return errTimeout
}
}
return nil
}

func safeWaitTxEmpty(sm pio.StateMachine) error {
wooble := 0
for !sm.IsTxFIFOEmpty() {
wooble++
if wooble > sdMaxWait {
return errTimeout
}
}
return nil
}

func acquiesce(sm pio.StateMachine) error {
err := safeWaitTxEmpty(sm)
if err != nil {
return err
}
foo := 0
timeout := sdMaxWait
for timeout > 0 {
timeout--
addr := sm.HW().ADDR.Get()
foo |= 1 << addr
if addr == sdCmdOrDatoffset_noArgStateWaitForCmdBits {
break
}
}
if timeout <= 0 {
return errTimeout
}
return nil
}

func sdMakeCommand(cmd, b0, b1, b2, b3 uint8) (rc uint64) {
cmd |= 0x40

var crc uint8
crc = crc7Table[crc^cmd]
crc = crc7Table[crc^b0]
crc = crc7Table[crc^b1]
crc = crc7Table[crc^b2]
crc = crc7Table[crc^b3]

rc = uint64(b3)
rc = (rc << 8) | uint64(crc) | 1 // crc and stop bit
rc = (rc << 16) | sdCmdOrDatoffset_noArgStateWaitHigh // wtf?
rc = (rc << 8) | uint64(cmd)
rc = (rc << 8) | uint64(b0)
rc = (rc << 8) | uint64(b1)
rc = (rc << 8) | uint64(b2)
return rc
}

var crc7Table = [256]uint8{
0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e,
0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee,
0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c,
0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc,
0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a,
0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a,
0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28,
0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8,
0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6,
0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26,
0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84,
0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14,
0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2,
0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42,
0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0,
0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70,
0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc,
0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c,
0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce,
0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e,
0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98,
0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08,
0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa,
0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a,
0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34,
0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4,
0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06,
0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96,
0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50,
0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0,
0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62,
0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2,
}

var crcITU_Table = [256]uint16{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
}
70 changes: 70 additions & 0 deletions rp2-pio/piolib/sdio.pio
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
; https://github.com/raspberrypi/pico-extras/blob/master/src/rp2_common/pico_sd_card/sd_card.pio
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;

; NOTE IT IS IMPERATIVE THAT YOU DON"T SCREW UP THE CLOCK EVEN FOR ONE HALF CYCLE, OTHERWISE THE DEVICE WILL LIKELY BE DISPLEASED AND MAY SEND GARBAGE (EVEN IF IT ISN"T DOING ANYTHING IMPORTANT WHEN YOU DO SO)

.define sd_irq_num 7

.program sdClk
.side_set 1
.wrap_target
irq sd_irq_num side 1
irq clear sd_irq_num side 0
.wrap


.program sdCmdOrDat
.origin 0 ; must load at zero (offsets are hardcoded in instruction stream)
public noArgStateWaitHigh: ; this is a no arg state which means it must always appear in the second half of a word
; make sure pins are hi when we set output dir (note if we are 1 bit we'll be configured for 1 pin only, so sending 0b1111 is fine)
set pins, 0b1111
set pindirs, 0b1111

public noArgStateWaitForCmdBits:
out exec, 16 ; expected to be a jmp to a state

public stateSendBits:
out x, 16
wait 0 irq sd_irq_num
send_loop1:
out pins, 1
jmp x-- send_loop1

public stateInlineInstruction:
out exec, 16 ; may be any instruction
.wrap_target
out exec, 16 ; expected to be a jmp to a state

public stateRxBits:
out x, 16
set pindirs, 0
wait 1 pin, 0
wait 0 pin, 0
wait 0 irq sd_irq_num
; note we use wrap setup to configure receive bit/nibble transfers
public wrapFor4bitRx:
receive_loop1:
in pins, 1
jmp x-- receive_loop1
.wrap

; #if INCLUDE_4BIT
public wrapTargetFor4bitRx:
receive_loop4:
in pins, 4
jmp x-- receive_loop4
out exec, 16 ; expected to be a jmp to a state
; #endif

% go {
//go:build rp2040
package piolib

import (
pio "github.com/tinygo-org/pio/rp2-pio"
)
%}
69 changes: 69 additions & 0 deletions rp2-pio/piolib/sdio_pio.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.