 So, I have been trying to port emutos to my AlphaSmart Dana portable laptop thingamajig. What I was doing last week was trying to get the SD card interface to work. It talks to two different SD cards via SPI and this ought to provide a pretty convenient and fast way of getting data on and off the device. Effectively, you have two removable hard disks, which would be great. However, I will be bloated if I can make the damn thing work. Anyway, since last time I did a bit of picking away at it offline and I discovered a number of rather interesting things. The first one of which is that I was getting the transfer size field wrong. The transfer size field indicates how many bits to transfer in each SPI transaction. And this should be a byte, so 8 bits. And I misread the lookup table here. The lookup table is actually... The value in the register is the number of bits minus 1, so this should be in a 7 and not an 8. Having an 8 present meant that it would read 16 bit values from the TX register and send the bottom 9 bits of them, which would basically turn all my data into garbage. With this 7 in place, I can now see actual bytes show up on the logic analyzer. And that brings me to the second interesting thing I discovered, which is that the pins and the SD card interface are devastatingly fragile. And by plugging the SD card... By plugging the logic analyzer into them, I actually bent some of them. And as a result, the slot is not working very well. I've attempted to bend them back again, but I will have to pause periodically to make sure that they're all still making contact. So I've had to use a different hookup strategy, and I only have two available data lines that I can connect up, which doesn't involve connecting to the SD card pins. So here they are, currently connected to S-Clock and chip select. The third interesting thing is that if I go over here to Gidra, I have managed to figure out how to get it to... Let me just try and find the relevant bit of code. I wanted hardware SPI open, I believe, this one. No, it's not that. I wanted SPI bus awake. Yeah, here it is. So there were these trap instructions periodically. Here was one. There was a trap followed by two bytes, which was the Palmer system call, or rather the Palmer system call number. I've figured out how to tell Gidra to patch the machine code to turn that into a knob, because previously the disassembly was hitting the invalid instruction here and just dying. So this enables it to actually decompile the entire function, which shows a rather more complicated SPI in its sequence than I was originally expecting. So that gives us something we could try. I also found a table of system call numbers, so I know what those traps are now doing. So this one here is actually pausing for hex 28 somethings. And of course, if all else fails, we can go and look at the Linux source code, which should be doing something like this. And if that fails, we can always disable the SPI interface completely and bit bang it using GPIOs, which shouldn't actually be too slow on this machine. Yes. Anyway, let's have a bit of a look at what's going on. Now, this code is what I think is supposed to be waking up the SPI bus when there's been a power down, so it should put the state back the way it was. I'm a little bit dubious, because if we follow the call graph, and that wasn't the one we were looking for, and this one. Okay, this is not it. But I did find a place that suggested that SPI wake was being called when the system was powering down, which was odd. But I do know that the power line is energized. And that was done using this code as far as I can tell. And in fact, I will just take a moment to double check that the power line to the SD card is actually energized. Yes, it is energized. So this stuff is working. And if we go over here, we can see, in fact, the decompiler is doing a substantially terrible job of figuring out what all these volatile registers are doing. So, you know, these variables here do not actually exist. It's failing to translate these ands and ores. So maybe I should be doing that rather than using C. That's another thing to try. So here is the power on code. And immediately preceding it, it fiddled with pportj, which controls the assignment of the SPI pins. Then it decided which device here I was enabling or disabling. So for device zero, it fiddles with the portj pins again. Then it fiddles with the portd pins, which I believe is to do with SPIO interrupts, so I can ignore them, I hope, and then it powers on. But then, down here, it does more stuff. Now, this piece of code, which it's failed to decompile completely, is actually it writes an ff to the transmit register, it then starts an exchange, it waits for the exchange to complete, and it reads a byte back. So what it's done is it's written a dummy value in order to get a valid value back. It's reading a byte from the SPI device. So why is it doing it there? And it's always doing it to the currently selected SPI device, because we have two drives multiplexed onto a single SPI interface here. But it does all this stuff, including fiddling with all the pins again, and doing stuff with the SPI control registers. Then it fiddles with portj again. And then, guess what? It does even more fiddling with portj. It's not setting the pins to a particular state, it keeps adjusting them. So I think this is doing some rather more complex initialization. This seems to think something is in D3. Oh yeah, it's the old value of SPI Comp1. So this piece of code is returning whatever this is returning. So that's D0 as a word. So let's just teach this about D0. Yeah, see now it knows what it's doing. It's just reading a value from the Rx register. We also want to teach this that it's a word. So why hasn't it come up with something? Oh yeah, the decompiler is confused by this loop here. It thinks that SPI Comp1 here is a normal variable. So obviously, since there is no code that modifies this, this is going to loop forever. Now we can actually work around that. If you go to the memory map, I can tell it that registers are all volatile. And that does now do the right thing, but it produces this garbage de-compilation. Which while it does seem to be more or less valid, like this or with SPI Comp1 is actually producing these four instructions. A read, a write, and then two reads again. Which may actually be technically what the CP was doing, but that's not helping me much. But at least you can see that it is correctly figured out that this function is returning whatever that returns. But let me just put that back. So if we back up to here, this seems to be discarding the result of this. So it's done a dummy read of a single byte. Why? I don't know. So this is a delay. Okay, actually let's just put that aside for a bit and let's try going through this. So this is clearing the bottom three bits of the pull-up register. So disabling the pull-up registers of these three bits. So that adds a comment. PJ dear sets the direction and this is setting them to be inputs. PJ cell is setting the bottom three bits. So this is setting them to be dedicated functions. Okay, so we are interested in device zero. So it's taking this code branch. So we're now down here at PGPU and again. So this is clearing top bit. This is setting the CS bit to zero, which is an input. CS is not an input. This is setting the CS bit to the dedicated to the SPI interface. So that will, it's now mapped that pin to the internal chip select line generation, which is interesting. Okay, I don't care about PD. I hope I don't care about PD. So these are all port D. So this is actually enabling the chip select line, except the chip select line is set to be the SPI interface. So that should do nothing, but it's an input, but it's the SPI interface. I'm confused. Dedicated function pins are connected. No, no, no, I've got that wrong. One is the IO, yeah, that's setting it. So this is actually setting that to a GPIO. Right, that makes much more sense. So this is then setting the CS bit and then this is the power on sequence that we know works. Interesting. All right, well, this is the other device, which you don't care about. So we are down here. Well, first it's doing some stuff with PF, then it's doing some stuff with PJ. So I think that this is the equivalent code for both things. So anyway, let's go here. Oh, yeah. And yes, so that is setting these also to GPIO. Right, so we are now here. So we set the bottom three pins to 101. So this is going to enable set because it's shorter. Mozi and SPI clock one. And that was the wrong kind of comment. Actually, you know what? With this narrow window, that will actually do fine. So this one is set the direction to output PJ cell. We are again setting the select bits, which is one to the GPIOs GPIO. I need to remember to turn my multimeter off. Okay, A is 1010. So that is clearing the UN bits for Mozi and SPI clock one. UN is pull up, pull up, right. Disable pull ups on Mozi, SPI clock one. And then we do it again. Disable pull ups on D is 1101. So that is disabling the pull ups on MISO. So in fact, these could be combined, which is odd. So this is clearing the direction bit on MISO, which sets it to an input. And then we are setting the GPIO bit for MISO. So what we've done in a very long winded way is we've set all three pins to GPIOs with no pull ups, as far as I can tell. Okay, what's next? Well, we read the SPI control register. We clear these bits E00FE is 1110. So that's cleared out the data rate. And F is the bit count at the bottom. Then 630 is setting 6 is 11003 is 0011. So that is enabling it. Setting this mysterious bit 10 that is not documented and setting the phase bits. And then we write it back to the control register. So SPI SPC, I'm looking at the second SPI control register. What's this one? That's more like it. So that is setting master mode. Okay, SPC1 is sample period control register. I completely missed this before. Periods inserted between data transactions in master mode. Huh, maybe this was what I needed. So this is setting int cs is the interrupt control register. This has been set to a zero. So right now we save the old control register value. And then we set this. So this is enable set, what was it? PHA pole master, but the SPI interface is not actually connected to the outside world because of what we've done here. So pj, port j. Let's just double check that one more time since I have a talent for misreading stuff. Port j, pj cell, the bits are being set therefore they are turning into GPIO pins. So the only possible effect this will do is just to push a few bytes through the SPI interface which will then get discarded. But why would you want to do that? Well now we're doing some more stuff with pj which was a keyboard shortcut for this. So let me double check again, un, the bits are being set to zero. F8 means all the bits are set from seven to three, so these three are zero. This connects the SPI interface up. SPI, the direction is zero to their input. I suppose one of the things I could be doing wrong is not setting them as inputs because depending on the exact implementation that could cause them to be, if they're set to an output, they could be being driven high even if the SPI interface is still connected. What does this mean? The bits control or report the data when cell is high. When the direction bits are high, the x bits control the pins. When they're low, the bits report the signals. The x bits can be written at any time. Okay, right. What that's meaning is there's an internal latch that contains the output state of each pin and writing to this register will always update the latch but the latch may not be connected to the outside world. And likewise, when you read the register, you're not reading the state of the latch. You're reading the state of the pins. So what was I looking for? PJ, dear. So we are clearing, yeah, we're setting them to inputs. Mozzie, Miso, and SPI clock one to inputs. Then we set this one to an output. Then we raise Mozzie and then we do even more fiddling with port J. Okay. All right. The comments appeared above the label. The direction is, I think that's an output output and minus nine is F7, disable pull-ups on these and then we go on to port D. So what we've got now is a relatively straightforward setup. However, Mozzie is a GPIO. Okay, I actually think this has got nothing to do with configuring the SD card. I think what this is doing is it's toggling bits in such a way that if the card is an SPIO card and it's gone to sleep due to a power down status, then it wakes up. But the stuff here we've done with port B has actually just powered the card on. So the card has reset. They're going to have to somehow wake it up. So we've also got this SPIO function, which is doing a bunch of stuff. Oh yeah, this was the thing I was trying to find earlier. Why does it seem to be putting the bus to sleep for both devices? I don't really know. Maybe it's powering the cards down and then up again later to wake them up. You can see it doing things like registering the interrupt handler. What's this? This is Trap A016. Where's my table of traps? A016 is sys trap mem pointer size. So if I turn that into a knob and now this suddenly we get more stuff here. What's this one? A027 sys trap mem set. I'm going to bet that this is mem alloc. No, it's not. A013, all right. This one is mem alloc. Ah, this looks promising. So what this is doing is if this variable is null, then we allocate some memory, stach that in the pointer and configure it. So I'm going to guess that that is Moc workspace. So where's our trap? This is a short way of pushing the value hex 778 onto the stack. So I think that is how big the structure is going to be. So I can rename this to MMC workspace. And I did a bit of type stuff. So yeah, it already knows it's a struct MMC, but I don't know what any of the fields instruct MMCR. So we get to here and we do a bunch of stuff. This is setting up the interrupt handler, more interrupt things, port D, port P. I think these, well, I know that port D is, no, they're all port D. Yeah, that is where I think the IOCard interrupts go. And then we get to here, port J, our old friend. So PJ data is lower Mozzie, MISO, SBI, clock one, set CS to output, set CS to GPIO. This one is disable pull up on CS. Okay, but we haven't configured any of the other bits. And that's all we've done, but it has called bus asleep. It hasn't called bus awake. So this is, this is powering up the bus. Because it's setting bit five, which is the power pin. And then here, so I know it's not, this is powering down the bus because the data bit, this line here is clearing that bit. And then this is just setting it as a GPIO. So I'm going to bet that this is turn off card one. And then we get to here, if we're powered off, if both cards are powered off, then turn off the SPI interface, I bet. Yes, because this is clearing the, yeah, okay, turn off, this is clearing the enabled bit. So therefore this piece of code is, yeah, that's disabling the GPIOs. Okay, so that is disabling the SPI bus. So that is doing what I thought it was. And this is just doing it for both buses, one after the other. Yes, the decompilation has figured out the parameters. But that only happens when this is set. PUVAR5 is, it's the thing that our memory allocation came up with. So I should be able to tell it, it's a struct MMC. Hmm, I'm not sure that did what I wanted. Okay, I think I can do this one. So this is the MMC workspace. So this is pulling a field out of the MMC workspace and saying, you see this, if we're, if we've gone down this code path, then we know that there was no workspace previously. Because I was thinking that what this would be doing is shutting down the MMC interface if there was previously one. That would be why it would be putting the bus to sleep. What are these doing? Right, this is initializing the interrupt system. Then it puts the bus to sleep. I'm confused. So this is a zero, that suggests that's a flag. Here is my data type manager. Let's put that over here. Here is our struct MMC. We know there's a field at address two, which looks like it's a word. So you see now this becomes a structure lookup. Okay, I don't think that was a word. I think that was a int. So if we go back to here, we can then change this to an int. Okay, now it's now producing much more elegant looking code. Although that was an offset to here. This is at a different office. Oh, right. This is confused because this offset it's expressing in C terms. So this is four lots of MMC workspace. Well, we know that the size of the MMC workspace is 778. I'm not sure I know how to, is this going to work? Wow, that puts in a lot of fields. Okay, right. But this is now looking at particular fields, which is nice. Can I retype this? And to find int. Wow, that works. I'm impressed. So we don't know what it is, but anyway. So this is a short, this is a word. This is a byte, I think. Yep. But it's not really helping us get anything done, I have to say. But this does seem to be, this seems to be initializing the PowerMOS device driver. It's not doing very much to the interface. It's calling this bus is asleep thing. And it's doing this, which is configuring CS. But that's about it. Okay, so I don't think that this is actually doing terribly much, but okay. So let's take a look at our code here and see what this is doing. And let's just rephrase this slightly better. So we want to set, we want to set the the SPI function pins to zero, but the chip select line to high. We want, again, we want the function pins to be zero inputs. Where did I put my data sheet? So inputs, but we want the chip select line to be an output. We want no pull up resistors. And we want the bottom three bits to be the SPI interface and the top bit to be chip select. So I think that this is actually the same code that we had before. Now we are going to hear SPI SPC is going to be zero in case for some reason it's not because we were seeing the wake code do it SPI bus awake. And we're also going to clear SPI and CS. This is all good practice anyway, to be honest. Okay, SPI can't one control register data rate unset. Data ready control unset. Mode master enabled. No exchange happening at his idle. SS low SS control low phase. Now I did see the wake code setting the phase high. I don't think that makes a difference, to be honest. Well, I'd rather I think that zero is the right value. Okay, we do need to put SPI SPC in 708. Okay, well, let's flash that and see what happens. I'm going to think that nothing will have changed. I also had a sudden thought and I found some better test clips. So maybe we'll get a full set of logic probe. So run, execute, stop. All right. Well, that didn't work as what I expected. But let's see what we are actually getting out. And I've moved all the data lines around. So I'll have to change the names. So this is clock. This is chip select. So this is these ones will be Mozi and Miso. I think this one is Mozi and this one is Miso. Although could be wrong. Actually one, two, three, four, five, six, seven. I think this is Mozi. So I think we've got here. All these are all these FFs are the reset sequence. And in fact, we should be able to add the SPI decoder in. And let's see if that comes up with anything useful. The answer is not really. Let me just double check that this is clock. Miso, Mozi, chip select. Okay, but we can see FF, FF, FF, FF, FF. That is our code asking the chip to initialize itself. Which it then seems to be ignoring. We do see some stuff coming back, but it looks like garbage. I am extremely suspicious about the SD card protocol analyzer. let's give that a try just to see what it does. You can see here it's identified the the reset command and it's picked up a reply of zero. Is that right? But I am very curious about this stuff here. Now if I go look at the actual code there's sdcheck. So this is the the code that's supposed to actually initialize the card. And what it does is we de-assert chip select. So chip select goes high. Then we send 10 bytes. Then we assert chip select and then we do our initialization. So our logic analyzer isn't showing all of this. And I am thinking about that delay in the code here. This trap is delaying for 20 hex to 8 whatever's 40 some things. And I don't know what that is. And maybe it's waiting for something to power up. That seems like a plausible option. So this is the emutos code for delaying one millisecond. So let's stick a delay for 40 milliseconds maybe. And let's see what this does shall we. Reset the board and write. Okay so start the analyzer hit return. Still doesn't work. Stop. Alright what did we get? Well we're still only getting a few bytes here. You see the way that mozzie comes up from noise to something. This just makes me think that this is a gradual increment as it powers up. I'm also thinking about that dummy write well read and write that was happening here. This code very carefully turns off the sd card turns off the SPI. Let me start that again. This code is carefully disconnecting the SPI interface from the bus. Then it pushes a byte through the SPI interface then it reconnects it again. Chip select is high unasserted so let's just push some bytes through and throw them away and see what happens. We are not in C99 mode which is honestly the only mode worth using in C. Okay and let's give this a try. Okay run, run, stop. Well it still didn't work but what are we getting here? Interesting. Well here's our go idle. This is exactly the same. We're not getting anything different because we haven't set the clock rate. Without the clock rate set it will go at top speed which is 8 megahertz which is far too fast for the 2 megahertz sample rate here to produce. I bet that this weird noise here is it sending the bytes at 8 megahertz and nothing is and there's the logic analyzer just failing completely to detect them. So we call SPI clock ident here to put the clock into the slow identification mode and we reset the board and we try it again. Okay so hit run and logic analyzer go. Still doesn't work but what have we got? Still nothing. Remember to build it did I? Yes I did. So this is setting the exchange bit to start a exchange and it waits for the exchange bit to go away again so the fact that it's doing this indicates that it is doing something. This is 0x08 so he is setting chip select. Chip select is high. Do I need a longer delay? Have we actually like has this actually been called? Alright so prepare for execution run execute that's called SPI unit lots of times rather than just once and we still have our weird noise here. It was called it multiple times and we go up to one of them retries tried to do a command 4a so command 0 command 4a command 10 command 0 command 10 so the second time through we are getting our 10 dummy bytes 1 2 3 4 5 6 7 8 9 10 then chip select goes low and it sends the command 0 and then we get a one response from the card that's different than the one we were getting before and if you look at the tracing I can actually see command 0 has failed failed but we're not seeing the one being received by the code here of course I don't know if this is actually the the R1 response and what's it doing next then it does a command 10 to which it also replies with a 1 then command 9 this is actually working this is talking to the card the card has just returned garbage for the chip so the chip data description thing that does it again keeps doing it and we get a command 10 look you can see here me so is slowly crawling up okay so let's delay a whole second and try that so we power on the card and then we just sit there and wait to for hopefully the voltage levels to stabilize alright now it's possible that the delay isn't working properly because of you know something else I did wrong but so run execute well you can see each batch of work happening and again me so starts as noisy garbage until the second time through see reset the card then we get a one I mean it does look like the card is talking to us but here is the first time through and it's go idle state and the response we get back is a zero fact that see me so normally drifts normally idols high maybe I need to put the delay after I've enabled the SPI interface I'm also interested to know why we're getting SPI initialized being called multiple times so that's happening in here in SDH SD check so SD command appears to be returning as RC what it saw where's SD command here we go so figures out the length of the command based on the type and for us we're five bytes send a send a bite before the command then we send the command itself then we keep reading bites until we get a response so we keep reading bites until we see a bite with the top bit clear so I would expect the this to be the response here and it's actually nicely broken down the response for us so we got a zero which may or may not be natural valid data so this is the see we send the command we send the CRC we send an end bit sorry the CRC is seven bits so the end bit is the eighth bit of the CRC bite that's fine then we so here's the CRC with the end bit stop transmission always discard the first bite but they are a command zero so we're not doing that we look are we look for the response we get a bite with the eight zero bit clear you see I think it's this one but this code seems to be discarding it let me take a look at the physics code and see what that's doing colonel lib colonel drove dev dev SD there we go I'm talking unit card is in the unit code is in dev SD discard so here is the code for initializing the drive SD SPI in it so raise CS set slow clock this is sending twice as many dummy bites as we need which is fine we send a command and we expect to get a one response so this does actually seem to be what the card is telling us at least in subsequent transactions so if we scroll out to three milliseconds reset the card we get a one and then it starts doing other things so SD send command this is in here okay so wait for ready appears to be the stuff here the sending this stuff here so send the command packet so it sends the bite then we send the argument which is four bytes then it sends the CRC which is the last bite receive the command response skip a stuff bite when stopping reading right we are think this code is not doing that keep waiting until we see a bite with the top bit clear and then return it this does not appear to be this code the emu toss code does not appear to be skipping the stuff bite so you can see the same logic here is present but emu but physics has disabled the test for command 12 let's try this okay so prepare to execute run run that got some data that is talking to the card and mostly failing horribly so all right this is this is a complete sectors worth of data in a tooltip so what is this doing well we go idle we skip the stuff bite we receive a response which is zero which I don't think is right but it seems to be going ahead anyway we send a command eight and get a one we then reset the card again it does seem a little bit confused that may be some of my code so so this is the output command 480001 aah seven stuff bite which we ignore response which here looks like an oh eight see the one bit is set no way that's us sending this is the response yes that is that is well confused why is it trying to send at the same time it's receiving let's fast forward to the next time round rather decoder is is completely confused now great but here you can see 4000000095 we then want to keep reading bytes until we see a response then an FF going out means that we're reading so we skip the first one and this is the response this is 00 which is not valid so why are we then going away and doing the command eight because it's trying to read the rest of the command okay let's take a look at that physics code again because it's got a nice link to the documentation oh I hate SD cards you have to go through this nonsense every time you want to bring up a new device okay initialization procedure so the command zero CS low card sample CS on command lows received successfully and SPI mode and response R1 within idle bit step 01 so how long is a command zero it's an R1 type so it returns a single fight so we've got back and oh oh so we are sorry I said earlier we were response length five no that we're outgoing five plus CRC so we are in fact an R1 type response length one so we keep reading bytes until we get a valid response there are no more bites to fetch so we don't do that we are not an R1 B so we immediately return okay so we should be here so we should be getting back a zero in RC because that's what it said therefore we should have been seeing this error here which we weren't so let's just put that in where is response I bet that's a pointer to a buffer yeah there it is let's also take this stuff out if it's going to keep calling initialize then do I need to power off the car wait a bit and power it on again probably but I don't know why this is calling SD check more than once well do it for each driver suppose no it won't drive has to be zero SD check is called from in here actually SD in it see if we need to reinitialize the card after a previous error right that's why it's reinitializing so yes we are going to have to power off the car to reset it do we or do we just need to ping it with a command zero not sure to be honest get disk info okay I feel like we should be powering down the card well that's easily done so this needs to be set to that these four lines will initialize the power pin except data is zero we are now going to pause for a bit power on the card pause for a bit and do I want to put some more tracing in I think I do this is so what this code is doing is it's trying to figure out what kind of card it is because they're always slightly different so this is the command eight that's appearing over here but we shouldn't have it shouldn't have actually done that because assuming that the protocol decode for the SPI is correct which I am not convinced it is looking at what's coming out of the SD card up here then it should be receiving a zero for the response byte and therefore seeing that the card has not gone into idle SPI mode and is therefore they okay let's try this this should give us at least bit more data all right start capture go well that was interesting we have been apparently been receiving a we did actually receive a reply of one this is saying zero something here is not match up so I can see it writing here's the command zero stuff bite ignored zero R1 zero have I successfully connected this to me so what is something else just wondering if the logic analyzer is just completely wrong the this has got the pin out in it somewhere here we go me so is data out I want this one data out pin seven yeah that should be connected to D1 on the logic analyzers which D1 me so so that's peculiar I'm not entirely convinced by this logic analyzer to be honest however this does seem to be getting a one it then tries to fetch stuff from the it tries to do a command eight sends the CRC reads a stuff bite gets back what is this now saying it's a one when this is because I'm looking at this yeah that is indeed a one however why have we just sent an eight that's not right okay where's so what's this doing SD command stuff bite SPI receive bite is my code it's here we are sending an FF look I told it here that's arriving in the TX register sorry I've lost my logic analyzer oh I know what's happening I think I know what's happening of course a transmitter see both happen at the same time so when a command goes out a command a when a bite goes out a bite comes in always so when we send this for zero this shows up in the input register so when we send a bite I think we need to make sure that the receive FIFO is empty because I think what's happening here is that every time every time we send a bite a bite stash gets stacked up in the receive FIFO so when we receive the bite we are not receiving the correct one in fact in fact we've got two functions here but that's not right we should have a single send and receive bite a single send and receive function that pushes out a bite so this then waits for the exchange to complete we now know there is a bite in the FIFO waiting because it just got there from here therefore we do this so sending a bite is send and receive and discard the result receiving a bite is send and receive OXFF like that I think this might produce better or at least different results okay so let us give this a go let's see what happens you to execute okay run execute stop okay it's still not happy that's out of the way but I think it is now less unhappy where hang on where are we going where is our unit code is it over here okay I do not believe this decode is valid 3 4 5 6 7 8 yeah it's not valid it somehow it thinks there are 7 bit bites I think it's thinking yeah I think it's confused by this glitched clock there and again to see my earlier comments but expecting to see more dummy bites with chip select high which seems peculiar but command not failed RC equals minus one response use FF so output bite is for zero that's our come that's our command it also does not look like a full zero it's most significant bit first so so this would be bit zero bit one zero one zero zero zero zero zero zero zero let's go and find the next command well hopefully it should be in sync again hang on what's happening here all right it's given up and tried again so we should have a re-sync here are our 10 dummy bites 4 4 0 9 5 4 0 0 0 0 0 0 0 9 5 then we get a FF which is our stuff bite sorry we we send an FF and receive a 3 F and then we get back a actual response which looks valid that's a one then we do our command 8 and this time it's actually the protocol analyzer has actually found it and we get back a one then we do a command 41 and get back a one this is a valid conversation command 55 is a shift it means the next command is a different command they ran out of op codes yes yes does seem to be doing this several times yeah it's got it's got itself is quite a loop and eventually it just gives up that is the least better okay I'm going to change this to a 20 to match physics so here you can see command 0 rc equals 1 and then it seems to have successfully fetched the card info card type card version card features 223 okay I'm gonna have to find more documentation for this but I think those look right so I assume it's getting into SPI now that's changes the clock speed this type here is what kind of type what kind of card it is a type 2 is SD right it's actually figured out it's an SD card so this does look like it is correctly initialized the card this is it changing the clock speed I think in the interest of debugging let's just not do that it may be that this is too fast for it which I doubt they'd make a herds is quite slow for us SD card at least in my experience however we are going to who's going who calls SD read SD RW who calls SD RW I'm looking for block device you go I'm looking for block device tracing yeah that's better that's what we want so let's turn this on and try this okay so execute command line run go right what's this done well it's figured out it's a disk and then it seems to be re-initting I'm gonna stop that seems to be re-initializing the card a lot so we got here command naught go idle response one correct command 8 protocol analyzer does not seem to have spotted a response so it's waiting for a but a return bite with zero in the top bit and here it is seven seven wait we've sent a seven seven one two three four five six seven eight nine ten chip select is high yeah it's just given up and has reset the is resetting the card but why here are ten in it bytes command zero command eight which is a 48 the command send I interface condition check voltage range and it returns a r7 response the r3 r7 response which is an r1 status byte plus trailing 32 bit data so we then send the four bytes of argument then you get the CRC and then we want to wait until we get something back so I would assume that this this is the stuff bite we ignore then we wait for a response then we get a 32 bit trailing response then what would this be okay so when is this calling command 8 here command 8 1 a a followed by an 8 7 that is what we're seeing isn't it yes it is and it is an r7 which means it's 5 byte response and response bite so r7 it is indeed a response length of 5 SD command timeout is this is the number of bytes it weighs eight I think that is way too short what does physics do okay send the command so this is waiting for 20 bytes and I also think that I'm going to wherever the SD command has gone we go I'm going to dump the response like so okay all right run go and stop and I should probably dump the output command as well just to be sure that this is behaving sensibly so reset command on a one then we have a longer pause than usual which is probably almost certainly due to printing this message here then we get a command one send HCS info and didn't we get a command eight last time and one reset chip select is down shouldn't chip select be going up between commands sure that any deferred rights of it yes it should be going up between commands so SD card type is also doing a command I will actually I am going to have I'm gonna have to rework this I think so looking at the physics code here when we want to transfer a sector either in or out we send the command 17 or a command 24 and then we send or receive the data so I think the SD send command function yeah is we lower CS we do the command and we leave CS asserted release here raises CS yeah I am going to have to rework all of this I'm not sure how this ever works to be honest that's correct we want to get rid of that okay so we need a Boolean do we have do we have Boolean types apparently do and we're just going to copy release from physics so this is going to I can't remember what the what this thing is called SPI receive a bite okay so we're actually going to leave if we look at the physics code rays doesn't happen very often it happens at the beginning of a command so where is your command and she'lls at least one bite is clocked up or sending the command cleans up any residual data that the command might be sending well SD wait for ready what does this do eup that's the code here so I think that is okay and we can now want to to go with release we're also going to want probably call this something else to be honest so there should be one place where lower CS is called which happens in send command and several places where release is called this is some physics code to allow writes to complete in the background mixing slightly faster so we're doing a release immediately after a read so I think we want here we go so we do a read we call do the command to receive the data and let's do that and the right yeah okay that we do want to do that this is doing the right thing right what this should be doing here is waiting for the right to complete in physics this happens in the background happen so only when chip select needs to be released do we actually check to make sure the right succeeded however I believe that will be happening in SD send data in this code yeah so that's good we can do that so does this build it does not we need prototypes yes we'll be calling SD assert not CS assert so we want SD command like so okay and let's give this a try and see what happens okay so run go well it still isn't working and getting that card info didn't work you should see CS go up and down now which we are so what have we got go idle state response our one which is correct go idle state why is it doing that so we have it's done the command and I can see the response come back which is a one I think it may then be trying to do the card info except it never actually gets as far as sending a command chip select stays down until after all the serial stuff happens goes up goes down and we should see one dummy byte go out this these clocks still very bad now this is spurious this isn't a real command you can look at see the argument here and the CRC is wrong the analyzer is confused okay let's dump the command so command argument CRC so terming card type and function so this calls SD command command eight and gets back a response then looks at the response what does SD wait for not idle do right this this sends a command so that will de-assert chip select run go and stop right what do we see here request card info card reset to which we get back a 01 response which is correct then over here we do a command eight to which we get back a 37 doesn't look quite right to me but here we can see that the transfer then we get lots of f's and then eventually we time out how many f's are there probably 20 21 because of course there's the stuffing byte first well and I'm willing to bet that this no wait this is an output yeah I'm willing to bet that what we're seeing here is the response so the 77 is the response bite so parameter error address error a raise sequence error no command CRC illegal command array state in idle state that doesn't seem quite right to me but that does look like a response it may be upset by toggling CS there so okay so run and go fabulous so it's sending the the command eight well it's sending the OH request whatever that is so here we see it go idle end of command chip select goes up chip select goes down here are the dummy bits that go go out when chip select is up is that correct or should they be should they happen when chip select is down again release lower okay release raises CS and then sends eight clocks then we lower CS and I think we should now be oh yes we are we await here is the the FF going out which is happening here so this is the same we're doing the same thing in emu tasks as foosixes so then there's a pause while we dump the request to the console then we dump lots of FF that doesn't look right then we toggle CS oh right arm I think my SD command is booked so wait for ready is supposed to be okay it spins waiting for until we get something it's not an FF right so what does SD SPI wait to do on physics so there's two versions of this one is it wanting an FF the other is it's not wanting an FF or is wanting something is not an FF and we do want an FF right that's why it's failing it's reading this is spinning waiting for something that's this is spinning waiting for an FF this is spinning waiting for an FF and then it returns the byte it read so yeah I think that is fine so we then send the request you can see that happening here I don't think it's ever showing up so is the request just disappearing off into the ether I would expect that well it's printed out the request line therefore it should be calling SPI send byte therefore I would definitely expect something to be coming out so unless yeah um don't know how that could be failing then okay all right well that seems to have failed quite a lot and always on line 547 here so it sends the data and not received a response well what are we getting here command 0 now we get a command 8 fantastic followed by lots and lots of f's so I think this is our 200 to be honest until eventually we give up and race yes well the card is accepting the reset we can see that happening there which makes me think that ACS is going high but then we're not getting our pad bits physics release always does a receive bite so we are always doing a receive bite so for so here CS is going high but then we're not getting a transfer are there any other places where unassert is being called in it code and that is it so what will be happening is that this unassert is a call to SPI in it which raises the well which power cycles the card how long is this not long so that's not long enough for either of these I think what's happening is that it thinks it's sending the command here but then nothing is coming back from the card and it keeps spinning indefinitely until it gives up and tries again that suggests that something's not right here hang on a minute this is after the command this is after the reset also why are we sending an 01 here we should be sending an FF I am now actually wondering whether this is or so invalid and the card is not accepting the yeah me Mozzie and me so seem to be the same throughout you're gonna laugh my two probes are touching each other one moment so so I jostled the board and the what I've done is I've clipped two things on to the pins connecting the SD card connector to the motherboard so I'm not actually are connecting anything to the SD card pins themselves but the ends are bare and they must have shifted and touched each other well we don't have to download it again run execute look look it found the partition table it's talking to the board finally finally finally okay so let's take out some of the debugging that's worth keeping that's not that's worth keeping these aren't okay so let's turn that off build and rerun be very glad to put the lid back on this thing and remove the logic analyzer and be right okay right run execute and it's found the nbr but there are no partitions here yet but that does look like it's working finally so if we go look here commands replies yes yes yes all looks normal doesn't even be calling this one quite a lot the command 41 oh right it's looping here waiting for the card to wake up which happens here so this is returning a one five five oh one four one zero zero okay then we do the five eight what's a five eight read OCR command ten is send the card ID expect to be something after that there's a pause while it thinks send CSD and then we do get a big block of data which is nice and here is command 17 read single block and there this green thing is our very first sector of our own and it's the partition table and then nothing else happens because there are no Atari partitions on this card alright well that took forever and I am not entirely convinced of oh you do this need to test this first I'm not entirely convinced that my changes to the SD card stuff the SD card logic is right but it's it is very suspicious that it's not twiddling CS between commands because I'm pretty sure that the card needs it SD cards are picky as all hell and it's possible to ever wrote the original code for the for immutos simply had a card that was a bit more easygoing than mine but you do have to do everything right and I trust the physics code because that seems pretty solid in my experience plus doing lazy releases of chip select allows you to do things like do deferred writes where the right to the card you send the data to the card and the card thinks about it as it erases a sector and programs and a sector if necessary before the right finally completes if you can do that in the background while your program is continuing to run that's a good thing okay so execute no errors interesting that we're no longer getting the drive a message but I think I will sure I got we got a different message last time this interesting and yeah you know what I'm gonna leave those disabled for now I'm gonna check all this stuff in I'm just quickly scan the diffs this is the Dana code and I think this can go down to let's call it 20 these subroutines should be renamed something a little bit more consistent can happen next time that can be okay so fantastic okay so next time I will have made myself a card with an actual Atari partition on it and put the lid back on my computer and hopefully we should be able to get the CLI running and then we can start on the interesting bit which is to get screen and the graphic system up and running and that should allow us to see the console on the screen and possibly even see gem start if we're really really lucky we won't be able to interact with it as there's no keyboard interface or touchscreen interface but it will be nice to see nevertheless I hope you've enjoyed this video let me know what you think in the comments