Close

More SD Card Write Details

A project log for 3-Chip Z80 Design

Combining a Z80 retro design with a modern PSoC CPU.

land-boardscomland-boards.com 10/26/2019 at 14:100 Comments

Had to dig into the FPGA code for the SD card. Using Neal Crook's documentation of Grant Searle's version (longer pedigree on the page).

The status register values are:

// SD_Status bit values from Neal Crook's documentation of Grant's SD card
// b7     Write Data Byte can be accepted
// b6     Read Data Byte available
// b5     Block Busy
// b4     Init Busy
// b3     Unused. Read 0
// b2     Unused. Read 0
// b1     Unused. Read 0
// b0     Unused. Read 0

This translates into defines:

#define SD_CARD_WR_RDY      0x80    // 128 dec
#define SD_CARD_RD_DATA_RDY 0x40
#define SD_CARD_BLOCK_BUSY  0x20
#define SD_CARD_INIT_BUSY   0x10
// Composite values
#define SD_CARD_READY       0x80    // 128 dec
#define SD_CARD_TX_BUSY     0xA0    // 160 dec
#define SD_CARD_RX_BUSY     0xE0    // 224 dec

I'm still getting this error when I write to the SD card.

Close error

Not sure if the error is because I am not returning a good status or not. in the CP/M code [CBIOS128.LST] file the function that does the SD block write is writehst:. At the end of the routine a status value is returned in the erflag variable. The variable is read by the calling routine. Not sure which routine is calling the writehst function but rwmove is the only function which reads it.. Not sure yet what I have to do to tell the host that the write completed but it has to be something inside of witehst that does it.

Here's the wrthst routine (again):

0754   EAC4             ;================================================================================================
0755   EAC4             ; Write physical sector to host
0756   EAC4             ;================================================================================================
0757   EAC4             
0758   EAC4             writehst:
0759   EAC4 F5                  PUSH     AF
0760   EAC5 C5                  PUSH     BC
0761   EAC6 E5                  PUSH     HL
0762   EAC7             
0763   EAC7 DB 89       wrWait1: IN    A,(SD_STATUS)
0764   EAC9 FE 80               CP    128
0765   EACB 20 FA               JR    NZ,wrWait1
0766   EACD             
0767   EACD CD 2B EA            CALL     setLBAaddr
0768   EAD0                     
0769   EAD0 3E 01               LD    A,$01    ; 01 = Write block
0770   EAD2 D3 89               OUT    (SD_CONTROL),A
0771   EAD4                 
0772   EAD4 0E 04               LD     c,4
0773   EAD6 21 D2 FB            LD     HL,hstbuf
0774   EAD9             wr4secs:
0775   EAD9 06 80               LD     b,128
0776   EADB             wrByte:
0777   EADB                 
0778   EADB DB 89       wrWait2: IN    A,(SD_STATUS)
0779   EADD FE A0               CP    160 ; Write buffer empty
0780   EADF 20 FA               JR    NZ,wrWait2
0781   EAE1             
0782   EAE1 7E                  LD     A,(HL)
0783   EAE2 D3 88               OUT    (SD_DATA),A
0784   EAE4 23                  INC     HL
0785   EAE5 05                  dec     b
0786   EAE6 20 F3               JR     NZ, wrByte
0787   EAE8             
0788   EAE8 0D                  dec     c
0789   EAE9 20 EE               JR     NZ,wr4secs
0790   EAEB             
0791   EAEB E1                  POP     HL
0792   EAEC C1                  POP     BC
0793   EAED F1                  POP     AF
0794   EAEE                     
0795   EAEE AF                  XOR     a
0796   EAEF 32 CC FB            ld    (erflag),a
0797   EAF2 C9                  RET

The routine puts the complement of the a register contents into erflag. before the XOR a would have had the last character so the routine would have sent out the complement of the last byte sent out. I don't think this is the source of the error message since the Z80_PSOC card has no control over the return value.

I can't find any use of the string "Close error" in the BIOS file. Does it come out of the CPM code? I wonder if I broke the card with bad writes? I think I will try the card in one of the FPGA boards that  have an SD interface that works. Here's what the directory looks like from on the FPGA card within PuTTY.

CP/M BIOS 2.0 by G. Searle 2013

CP/M 2.2 (c) 1979 by Digital Research

A>dir
A: DOWNLOAD COM : LOAD     COM : PIP      COM : STAT     COM
A: SUBMIT   COM : DDT      COM : DISPLAY  COM : DUMP     COM
A: ED       COM : ASM      COM : BBCBASIC COM : POWER    COM
A: MBASIC   COM : BAS      BAS : BLINKLED BAS : blinkled bas
A: 0@@@  : .@@@  : 2@@@  : 2@@@
A:   : MYBAS4   BAS
A>

So, I was able to write to the card from the FPGA CP/M machine.  Not sure yet what the difference is. There are more files than shown above which only show up in the VGA display for the FPGA card. PuTTY must filter them out.

Writes must be at least partly working since the directory does have the added items. But they are wrong. Not sure what it would take to clean up the card since it's not accessible from Windoze being formatted as a CP/M card.

The error is probably coming out of the function, CLOSEIT: which is found in the CPM22.LST file.

Looked up the XOR A instruction and found it does an XOR of itself so it will always return a status of 0. So I'm even more sure that it's not the block write command which is returning an error.

However, a bad block write could cause the error at a higher level in CP/M if the write didn't work properly. And I've still not verified the write worked properly so back to the PSoC monitor code that I used to test the read blocks. Adding a command to write a pattern to a block which can then be read by the read block routine. But I probably should use a block which is above the 128MB region of the disk drives.

128MB/512 bytes per block would be block 256K or  block 0x4000. The SD card is 2 GB so I think I'll work with the block at 1 GB to be safe. Hopefully I won't kill the card, but if I do I have several other cards.

I've got another reason to think it's the SD write routine because of the directory being messed up. There has to be some difference between the block read which seems to work and the block write which sorta works.

Long enough for now, so I will be picking this up in the next log post.

Discussions