 The story so far, I am attempting to port Fusix to the ESP8266. After a number of false starts, I have the kernel mostly working. It's running enough to give us a login prompt. I have a interrupt system and a timer working. Except the file system is on the internal flash and is creakingly slow. Let me see if I can. I've rearranged the board and the reset button is less accessible. So here is it booting. It's loading init and friends and it's spending nearly all of its time swapping stuff in and out and it's just really slow on the internal NAND flash. It's still possible that I have failed to configure it correctly. I have found some code that calls this and it didn't seem to do anything. But I originally started using the internal NAND flash for the file system because I couldn't get the SD card stuff to work. So I think I'm going to have to take another look at the SD card code. There we go. Finally we get a login prompt. There is no TTY input yet so we can't do anything with it. So I have hooked up an SD card again and I'm going to investigate to try and see if I can figure out what's going on. I don't have much hope but I do know a lot more about the system now than I did when I started doing this so let's give it a try. So the first thing we need to do is in here where we set up all our devices the SD card is a block device so it shows up as one of the sub devices. So we need to here in device init initialize it and to do that we need to... I think we need to... we need config SD in order to actually configure... in order to actually enable the SD card stuff. And I believe that this will... oh yeah. This is split into the runtime code and the initialization time only code so that some platforms can discard the initialization code. So we want to call SD-SBI init in here. We do this after we initialize the NAND flash so that any devices that it finds will be... will be HDB... we want to call dev-sd init. And SD drive count should be one so we should be able to clean and write and see what happens and it doesn't work because I forgot to include the SD card code here. So dev-sd-discard.c and dev-sd.c. Okay, still not working. And we also... we have included that. Is there a dev library we need? Oh, there is one. Oh, conflicting types. Oh yeah, I remember this. The prototypes are wrong. That should be a fast... that already is a fast. That should be a fast init. You int this... dev-sd-transfer sector is here the transfer function actually turns an int so that should be like this. Fast SPI weight is now going to turn into... this is a fast and our transfer sector now returned an int. Okay, so let's see what this does. Okay, as before, it is trying to talk to the SD card and failing. The way SPI works is you have to clock out ff in order to receive a byte and we can see that this is always receiving the same data that it's sending. So I could have wired it up incorrectly. That's entirely possible. This is the code I have for actually talking to the SPI device. We wait for the device not to be busy. We fill the right buffer with our byte. We tell the system to run. We wait until it's not busy and we read the byte out of the buffer. Some of this feels off to me, I have to say. Last time I worked on this I spent a lot of time fiddling with it and that didn't seem to help. We are using here the Arduino definitions of everything. So let's go and dig up the Arduino code again. There are two interfaces, 0 and 1. 0 is the SPI interface used by the internal NAND flash. We are plugged into 1. This is all SPI 0 stuff. It's always SPI 0. It's not talking to SPI 1 at all. This thing takes care of dealing with which device it is. So wait SPI idle is to do with the internal flash. So here if the interface is 0, turn interrupts off, configure the device, copy the outgoing data to this address. This actually looks like there are multiple words of buffer. That's interesting. Start the transfer. This will be either... I don't know what that is. I'm going to have to look what that thing up is. Wait for the command to complete. We wait until the command bits are no longer set. Read the data back from the right buffer. That does not seem complicated. So we have SPI 0 command here. We give it a pointer system data. A number of bits be set after the command byte. I really don't like this. It's a high level SPI interface that expects to send a command and multiple payload bytes and then receive back a response etc etc. However what Fusix actually wants is to be able to send one byte at a time. And it takes care of framing itself. So we have the command byte and we have up to 64 bits of payload. User defined command. It goes into SPIU. We're setting SPIU to this which is, if I remember correctly, master out slave in, master in slave out that is do a send and receive at the same time. Duplex means do both at the same time. 8 bits of mozi. 8 bits of miso. Yeah, do we want to set the command byte? Do I need to set command to something other than SPI busy? SPI busy is not actually set. SPIU command. No, no, no. So this is the actual, yeah, this is the command byte that is being set. That's not the command byte that's going out on the bus. That's us configuring the SPI interface. So that was SPI command user. How is this defined? It's defined to SPI busy. So there's nothing interesting there at all. We are doing more or less the right thing. Possibly there are some straight bits set. That, I don't think that'll help, to be honest. But it's worth a try. Nope. I do not recall from last time that we were always receiving the same thing we were sending. This might be... It's all the Arduino stuff. This is low level. Do we need this? Move the delay on CS before after SPI clock. What's the try? Use CS hold. Oh, it's being set here. So when we raise CS, we tell the SPI controller that we don't want CS set up, and we don't want it held. And when it's lowered, that is made active. We tell it we do. Okay, send this data from FIFO. There seems to be nothing particularly complicated. Here's a useful looking link, which no longer exists. Now, what I was seeing the last time I was looking at this when I hooked up the logic analyzer is the clock signal was rapidly chopping at several megahertz, which I believe was causing the SD card to get thoroughly confused. Ah, this looks useful. CS set up ensures that your chip select line is pulled lower. A couple of cycles before the SPI clock starts. CS hold. A few cycles after the SPI clock stops. Good. Okay, so this is... Oh! Right, I think I'm doing this all wrong. So on a lower level SPI device, you do a read by doing a write and then seeing what comes back. However, it looks like this device is doing things... It's doing it itself separately. So I think we're going to need two different pieces of code for transmit and receive. So let's copy this. So what we're going to do is to do a transmit. We wait until we're no longer busy. We tell it we want master out to slave in. Is there any reference to duplex in this document? Yes, there is half a duplex. Okay, let's just do that. We can't just set the value. We need to mask out SPIU master in slave out and enable master out slave in. Fill the right buffer. Go. Write and receiving should be exactly the same code, but different. Yes, exactly the same, but not the same in any way. Where we want to enable master out slave in. Disable master out slave in. Enable master in slave out. Don't care about filling the buffer, but we then read our value and return it. So this is going to... Everything there is going to be off. Okay, let's try this and see what happens. And it doesn't work. Can I just delete the transmit function? Yes, I did. Let's get rid of this one. Okay. Undefined function. Exmit. Receive. Exmit. So this wants to be sdsbi.receive.byte. And this wants to be sdsbi.transmit.byte. Let's say round arithmetic in operand of... See, what we don't want is for the... Or to bind to this, because that will make all sorts of bad things happen. Now, I am sure that I've used exactly this idiom laid out like this years and years ago with Geos programming, but if the compiler doesn't like it, let's just try it like this. Well, that's still not happy. So what happens when we initialize the drive? sdsbi init. And we... Yeah, okay. We do lots of clocking out just to wake the card up. Then we send some data, which is the reset command, which is needed to get the thing out of sdcard mode into sbicard mode. And then we wait for a response. So this... This tracing here is our clocking out. This is our command, and then this is us waiting for a response, and then we give up and go home. So the easy thing did not work. I wonder if... Okay, I'm going to have to get the logic analyzer out and wire it up again. I have a slightly better setup, so it should be a bit less insane. And see what's coming out. So I'll go away and do that. Okay, so I've got the logic analyzer hooked up and hopefully working. I say hopefully because if I hit the run button and then hit the reset on the board, what you see coming out here is nothing whatsoever. I have checked for continuity. This D0 is the chip select line. I think it's the chip select line. I've checked for continuity, and it does seem to be wired up correctly, which means that we are completely failing to talk to the device, which is odd. So the most plausible explanation is that we've failed to set the GPO pins correctly. So let's have a look at what the Arduino code does. I don't think we want this file. Oh yes, it's wiring. I remember this. However, I'm not going to look here. I'm going to look at the NodeMCU code. I was hoping that I would be able to just flash the NodeMCU firmware onto the device. Then I can use a few lines of lure to check to make sure the SD card is actually working and it's not a code error at my end. Unfortunately, I can't get copy of the firmware because it's broken. So anyway, NodeMCU source. So we want the... Okay, I did go look up where this was before, but now I've forgotten so I'll have to do it again. So the FAT file system code talks to platform SD card in it, which is in SD card, which in turn talks to the GPIO layer. And it's interesting, this seems to be... This is using a GPIO directly rather than using the chip select that's built into the SPI controller. So somewhere here there should be the code that sets up the GPIO pin modes. This is the chip select line. Oh right, it happens here. So this is actually the expressive SDKs routine, which we are not using. I suppose I can always copy it and see if that makes a difference. I don't see init code actually. Well, I've got the SDK here, so I can search for like SPI set clock div. Oh, it's not there. Am I mistaken about where this stuff lives? SPI transaction. Apparently I am. Interesting. Okay, so this is not referring to the SDK code, which means it must be in here somewhere. Here, platform SPI init. Right, that one's here. My suspicion is that we've actually failed to call raw init, which would actually be kind of stupid. I believe we're not calling SD raw init. No, we are not. Okay, well let's fix that, shall we? And let's try that again. Well, this explains why it was doing nothing at all, it just wasn't turned on. So what's going to happen this time? Again, nothing. We should be able to get some logic analyzer output. So come on, run. I hit the button and stuff happens. Excellent. Okay, so what are we getting? This is boot here and this goes low. I'm not sure why. Denaut is chip select. I am not comfortable about the way this turns itself off after every byte. I think that should be on throughout. This is data, this is clock. That actually all looks reasonable, you know. So these are groups of eight indicating each clock going out. Then this is our command going out. So that's 4095. One, two, four, eight. One, two, four. So four, zero. Lots of zeros. Nine is eight plus one. Five is zero, one, zero, one. Yeah. And then nothing happens. I'm not seeing the glitch clock that we're seeing before. Let's try to try that again at a faster clock rate. Actually triggering this is a little tricky. As I have to use my right hand to push the reset button on the board. That all looks right. And my left hand to click the mouse and the run button. And for some reason it never runs first time. That suggests, yeah, let's just take a look at the, this code. So we've got SD send command raises CS and sends eight clocks. So raises CS and receives a byte to send eight clocks. I did not see that happen. Then we lower CS. Yeah, I'm a bit confused to be honest. So I am seeing that it doesn't, that the code here does not tinker with the chip select line between bytes. So I think it's expecting the bytes to be, it's expecting the chip select line to be left low throughout the entire command. So let's put this back. We were going to be using GPIO. Where did I put the documentation for that? This one, no, not this one. So let's try and find the pin out, which should be here, which is D8. And I actually, this is entirely the wrong document. I want the technical reference. And I believe it's MTMS. Here we go. And now that's the clock. I want MTDO for chip select. So we're actually going to be setting MTDO to the right file. This is not the right file. I want the SDK file, which is in EagleSoc MTDO. So we want to set MTDO to be a GPIO. So that should become Funk GPIO 15. Okay, so now we should be able to enable or disable the GPIO line using these two commands. We do need to set the direction. So I cannot remember how to do that. Install this code from here. Pin Dear Output. So that should set GPIO 15, which is GPIO 15. This one, which is chip select to be a output. And this will set it to be either high or low. And we've got the GPIO out. Yes, it's GPIO reg write GPIO out address like that, I believe. But I'm not sure whether it's enabled. I should be setting for the to turn it on or off and out to enable output or input or the other way around. There is an in address. Yes, it's there. Ah, there is actual documentation. Output enable status bit readable and writable. Output is low level at the same time users should enable the output. OK. So let's set this to enable and set these out and see how that works. And luckily we have the... What's that doing? Nothing. OK. All right. So this is... I'm not sure if this is right at all. So it raises the chip select line. OK, it raises the chip select line. It clocks out some clocks. That's 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22, I believe. Then it sends out a command and then nothing happens. It just occurred to me that I can actually turn off these. This is the SD card so I can say that the clock is... This is the SD card analyzer. It will decode this data and tell me if it's like correct. Master in, slave out is on D2. Master out, slave in is on D1. Chip select is on 0. Right, what have we got? Woohoo! It correctly decoded the command. So we are sending to the device the correct output command. So whatever we were seeing before is no longer happening, which is deeply mysterious but it's still not working. Yes, I did just check and there is a card in the reader. So I would now expect to see a response but we haven't got one. Tell you what, I am going to double check to make sure that the card in the reader works and that the myso line, which is reporting nothing whatsoever, is correctly hooked up. Well, the wiring is correct. I've checked continuity all the way from the microcontroller to the SD card reader. The card works. I've checked the partition table but we should at least be seeing it initialize. So I am wondering, this is currently set at the slowest possible clock speed. I am wondering whether it's in fact too slow. Let's see, can I, timing calculation. Okay, so if I set this to D2, which is the clock. So 700 hertz-ish seems quite slow. So it may be that it's just too slow for the card. I'm just using the default setup so let's see if we can make it faster. Here we go. All right, SPI 1 clock. Now yeah, this was happening in here I believe. Actually setting up the clock was an annoying amount of code. Remember that from the last time I looked at this. Driver lib, driver PI interface. Okay, so if we're in master mode, this is all a constant. Okay, yeah, this is the clock calculation stuff. So this wants to go roughly here. This is the slowest possible speed. This is the fastest possible speed. SPI clock EQ sysclock, which is apparently not defined in that file. This one, sysclock. Yeah, this all looks familiar. So we need this. So one is fast as possible. I do not actually know what the speed value is. Let's take a look at, I think it's include SPI, not flash. This is set up in SPI attr, which is defined in, of course it's defined in SPI interface. So speed, it just says SPI clock. So I'm going to guess that megahertz. However, if you set it to one, then you get the system clock speed. It is worth taking a quick look here to see. Right, there is documentation, but there's not a lot of it. Oh, it's one of these. Okay. Okay, that makes a lot more sense. So let's not set it to 80 megahertz. I'm not sure that will work. Let's set it to a nice saying 10 megahertz and see what happens. And of course it fails to build. I do want that so... Okay, this is just me not setting stuff up. SPI num is of course going to be HSPI. No, it's not HSPI. And of course we are badly mangling. Okay, it's not defined there either. So let's just change this to one. We are badly mangling Arduino style definitions and the SDK style definitions, but I want to see if it works first. So what's this going to do? It does nothing but faster. Okay, I was hoping that would improve things. We do want to not set the clock here. In fact, we can do... Why is this clearing that bit when it's about to write to the peripheral register? I think we can just do SPI one clock equals just formatting a little. It's kind of terrible, but never mind. This isn't going to help, but at least it makes the code simpler. And let's try that again with logic analyzer. So it's faster. It's in fact too fast for the logic analyzer. So let's crank this down to one. That may actually be too fast for the init sequence. That's what this flag is for. So let's actually do... When we're going fast, it's 80. Otherwise, it's slow. Div si3. Oh, apparently it's not there. So we've got the ROM disassembly here. Si3 is there. Let's see what this does. Well, it didn't work whatever it did, but that's rather interesting. We've got the bytes that are very far apart, but they do look valid. It's correctly decoded the command. See, there's our 95 byte, which is the command CRC. There's the end bit. I mean, it's still not working. We're never seeing anything coming out of the myso line. But this does look like we are modally setting the clock speed. What does the timing reckon it is? Two... One megahertz? Yes. So from leading edge of clock to leading edge of clock, it's a thousand nanoseconds, which is one megahertz, which is the right clock speed. I am wondering whether this needs to be relative to the peripheral clock, which of course we've been fiddling with, but it appears not. Well, it's still not working whatever it is. So something about the chip is not initializing. It's never responding to data. It took me ages to get the SD card working on the MSP430, though I now cannot remember any of the details. So what was I doing to actually set this up? So we connect up myso and mozzy. We connect up the clock. 400 kilohertz output clock, which is the slow mode. No interrupts. Do need to set the SPI mode, but there are two different things here. But we are sending what looks like a valid command. The decoder thinks it's a valid command. So why aren't we getting anything out? Like the myso line is just simply not rippling at all. We should be getting the response alongside these clocks here. Are we sending... No, we are sending the most significant bit first because I can tell from this... Well, it's decoded it correctly. I know we're sending the right command, 9.5. 1, 0, 0, 1, 0, 1, 0, 1, 9.5. Here they are. Threewire SPI mode. We want SPI mode 0, which is both these set to 0, which we are doing. I mean they're in these control words. New wire, rewire. Does this mean that... does this mean the data's coming back on myso? And because we're not letting myso float after each command, we're not getting anything. But this says it's connecting up CMO, so... so change CS. Transmit a byte. We put it into the buffer. We wait until we're not busy. Well this is transmit receive and then return what came back. This all looks reasonable. To be honest, I cannot see what might be wrong. The fact that we're not getting anything back from the chip itself suggests that there's something about the configuration that's not right. And they were not sending correct commands. Which given that this has managed to... Hang on a second. Is that the right clock speed? So from from high to high clock is a thousand nanoseconds, which is one megahertz. But we wanted a half megahertz clock. Okay so let's take a look at what we're setting. User is zero. So CS, not doing any of those. Ah when as now we're no longer using the chip select stuff which touches zero, we can simplify this. So if we transmit a byte, master outslaving. Mozi, to receive a byte, master in slave out to MISO. Set all the ones you want. Clear at least SPI flash mode. Yes. Set up, don't care. Phases of the command, don't care. dummy, don't care. All these are off. Okay Mozi line simply output zero while all the data on the MISO line is clocked into the internal SPIWX registers. And that actually reminds me of something. So let's just run that again. Okay we're always receiving Fs. The data is always coming in W0. Okay so there's a number of bits we're writing. But again I know this is working because I can see it on the logic analyzer. Command stuff we don't care about because we're not using that. Once you have everything set up, set the SPI user bit and the SPI command ready to... Yeah we know this. So why is the chip not responding? I have connected it up to power I think. The reader I'm using is a combined LCD screen and SD card reader. So I don't actually know whether it works. I think I should try a different SD card reader. I've got one from the MSP430 actually. Let me go and fetch that. Well I've hooked up the other card reader and done a trace. And this seems to be what comes out. So this by the way is exactly the same as it was before. So yeah. You can see here it appears that this enormous gap between bytes is just how long it takes the kernel's code to write one byte at a time. So it seems to be running awfully slowly. But here is the last byte of the command followed by one byte of response. And the response is all f's. So yeah it's just reading the wrong thing. But that is now hooked up to the other card reader so there's no change there. So what could possibly be wrong? Well my card reader, the new card reader could be connected up incorrectly. But I am wondering whether the myso line needs to be configured low or something like that. This is the schematic of the other card reader. So you can see it's not really complicated. Here's the SD card. They're all connected to these done. Okay so is something in master init setting things up incorrectly? Well there's the SPI mode which should be documented here somewhere. Well here's where it's configuring the pins. So it seems to be the sub mode. That's the interesting bit. So do we actually want mode zero? Well the MSP430 code wanted mode zero. So that does seem to be right. Do we need to tell it we want master mode? I think you get that if a bit's not set here honestly. Yeah you have to explicitly turn on slave mode which we're not in now. So that seems to be setting the slave register to zero. So yeah here are our sub modes. Oh that's interesting. We're not setting that. Oh no hang on these are unsetting bits. So yes both bits are set to zero in both pin. What is pin? I don't see anything here that looks like it. SPI1P, P for pin, SPI1P for zero maybe? I doubt very much that would be it. Phasers, slave mode, SPI pin. This is turning on and off chip select stuff I think. So this is in here. It's not defined here. SPIP idle edge 129 but it's being set to zero anyway. So well let's try it and see what happens. I wonder if by default the chip select line might be set to the same pin as the output. No let's try this again with the logic analyzer and stop. Yeah nothing at all happening in D3. There is actually one possible explanation which is that the pin that D3 is connected to is not actually the miso line and it's set to drive high. And if that's the case it is faintly plausible that the ST card is unable to bring it low. But I can test that by unplugging it from the dev board. So okay so I have pulled pin 6. So let's go over to here. Hit run, hit reset, hit reset, here we go. It's yeah do that again shall we? And nothing. And just to be on the safe side let's turn all these back on again and do it again just in case I plugged it into the wrong pin on the logic analyzer. Nothing. I shall double check continuity to the SD card. Yep I have double check continuity all the way through and it still isn't working. Well I've plugged everything back in again and I've put the clock speed down to the absolute minimum. It's still not going because I want to get a logic analyzer capture to sorry trying to talk and press lots of buttons at the same time. So run, reset. So I am going to try and get some help on this. It's almost certainly something I'm doing wrong with doing the SPI stuff. I just don't know what, I don't have enough experience to be able to tell. But someone who does know what they're doing ought to be able to take one look at this logic trace and figure out what's going on. Actually one thing I have thought to look for is chip select polarity active low. So this is, so it's possible that I'm actually using the wrong settings for these but the analyzer is coping anyway but the card isn't. But this does all seem to be behaving sensibly. Yeah no matter what I set these things to the clock is working. What does NodeMCU set the SPI stuff to? I don't see in it actually. So I'm wondering if this code is configuring the SPI sub mode. See I would expect it to be happening here somewhere. So we set the clock then we just go straight into transactions. So platform SPI setup is where we actually initialize everything. So where is that being called from? Ah you're supposed to do it from your lower script. So there should be a example somewhere which I found. This is the low rent way of wiring it up. I have a natural reader so yes at least it is 3.3 volts and this is all Arduino code. This is the one, no this is more Arduino code. This one maybe, here we go. Low, low clock dividers are 8 and 8. So this is the code that sets up the, this is the lower binding for the setup code. So we have the SPI interface which is 1 for each SPI. We have the mode which is master. We have the clock polarities, 8 data bits. Clock divide of 8 which is 10 megahertz. And duplex mode is defaults to half duplex. Do I need to tell it to be half duplex? No, well I can't. Duplex mode is being passed into here. Okay this decides whether it's reading at the same time as it's writing or whether there's an extra read transaction after the write. Well I think either way what I would be seeing is data showing up on D3 here after the command has finished executing and we're not seeing anything. So we would either see data here as in returning at the same time as the command which I don't think it would because you have to wait for the SD card to think about what it's doing or data showing up later. Let's take a look at the the init code again. So send the command then we send another command to put it into SDHC mode if possible. So we're not even seeing a response to SD command. SD send command so we select the card and wait for it to be ready. We send the command by packet which we know that we're doing to send the command byte itself which is zero in this case I think. Yes zero these eight bits then then there's a gap why is there a gap. That's the gap while the microcontroller is thinking about the next byte. Does the clock need to be released? I'm not sure but then here is the argument plus the check sum so four bytes so it should be six bytes. One two three four five six one two three four five six so the command must the four zero must be command zero must be command zero. Yes it is followed by four zeros which is the payload the argument followed by the CRC which is 4a then so that's where it sent the CRC. This is commented out skip a stuff byte and then keep reading until we see a valid response which we never are. Okay I am completely stumped I am going to have to go and fetch help on this. I spent a lot of time poking at it. I am reasonably certain that the commands are reaching the SD card but the SD card is never replying so there's something I'm not aware of that's wrong probably in the way the command is being sent or the card's being initialized so I'm going to call it for today and go and see if I can find somebody who knows how this stuff works. I hope you enjoyed this video but as nothing actually happened I slightly doubt it please let me know what you think in the comments.