Ok so I’m using SX/B, which is BASIC for the SX. Even if you’ve never touched SX/B, it reads very easily, anyone who knows the PIC or other mcu should understand…..
Here’s the logic behind the code:
The main() of the program starts at “start_point” and runs to the end of the file.
Its job is to count the number of stored bits, and if more than 7 are stored, to notify the PC, put the byte on the port, and reset the “shifter” so a new byte of data can start. Very simple. It also waits for the PC to ACK the byte. Notice sh*t hits the fan if the PC hasn’t ack’d the old byte before the new byte is ready. This is OK because I’ve got the PC timing down to less than half of how long it takes the amiga to spit out a byte. See earlier posts on timing!!
The ISR is the other important port of the program. More happens here than in main.
My ISR can be triggered by two methods:
1. Falling-edge triggered by a negative-going 0-volt pulse. Ie a “1” from the drive
2. From a timeout that runs 1.5us from the last time the ISR was triggered, for any reason.
The ISR’s job is to first check to see what triggered it. Whenever the ISR was triggered by an edge, “processedge” is called.
Otherwise, it must have been due to an RTCC rollover timeout condition, and so the default handling is to process a “0.” First we see if we are idle, and if we are just seeing more idle-bits —- which would just be 5v high’s all the time, if so we just ignore and exit the ISR. If we aren’t idle(ie last bit was an edge), then we start storing “0”s into the shifter. exit the ISR.
Processedge simply turns off the idle condition and stores a “1” into the shifter. exit the ISR.
Very simple and elegant. I think.
Guaranteed that my problems are timing related, where the ISR has been triggered due to a timeout, and we miss an edge event. I spend a relatively long time in the ISR — but I think that my current approach is really the best — shortening the time spent in the ISR, where it would make a difference, is just not possible – given the current setup.
Missing an edge event is somewhat tragic because it does one of two things. It either adds extra zeros to the current ‘grouping’ of bits which corrupts the current data and shifts the next data,or it considers valid high-zero’s to be simply an idle condition — in which case we lose the next up to three bits.
See earlier timing discussions where I’ve ruled out other possibilities of problems….
I will look into your code (and will try to familiarize myself with SX programming :)).
In the meanwhile: remember the TI floppy interface link? Commenting his project, Piotr talks about ‘software PLL’ concerning reading MFM – the same job you do.
Quoting Piotr: “Implementing a software equivalent of a phase locked loop to separate read data proved to be too much time consuming. I have considered using an external data separator (for example the FDC9216), but finally decided to do everything in software. The program simply measures distance between the read pulses. This method proved to be very reliable, though not as immune to rotation speed fluctuations as PLL.”
So everything we measure that is longer than 10, 100 and 1000, could be assumed just another 0 (or 1?). See how things will change this way.
Yeah I did read that as well. Yup.
As a matter of fact, I tried to implement such a system FIRST, but there are some minor complications there as well.
I haven’t found the software PLL idea to be bad. Piotr says it’s time consuming, but I wonder if he means time consuming in the sense that it would take a long time to write, or time consuming in that it eats up too many MCU cycles. Or both? I also wonder if he has plenty of CPU and edge-triggered schmitt inputs, etc…..
I think I’m on the right track now though, and I’m not far from getting this to work better.
Besides, have you looked at my code? It’s not really complicated at all. I have to figure out the proper timing between edges and RTCC rollovers — once I find the right spot, it will be much better.
I guess Piotr means the limited number of MCU cycles available. Within his design, 16MHz clock allows for ~32 MCU commands per bit cell (and my 8MHz design halves the number), so coding tight loop becomes tricky.
I have seen your SX code, but can’t tell for sure I understand it all, although your comments are very neat.
And to give you an idea, at 50mhz, I can do 100 instructions per bitcell. This allows me to use something higher level like SX/B and get away with it.
One of the reasons why I went to an SX was because of the speed. I was trying to use a small PIC at 20mhz (but only 5MIPS) and the instruction execution cycle was like 200ns. Now I’m at 50mhz, but 50MIPS, and a 20ns cycle. Much nicer.
The SX also has a lot of built-in features which the smaller PICs didn’t have. You could upgrade to bigger PICs, but then the programmers/debuggers were no longer hobby-priced parts, unlike the SX.
Parallax also has great support, great management, etc. I’m really impressed.
I noticed in your interrupt routine you are doing “RTCC = 0” you should not do that. It will screw up your RETURNINT value.
Bean @ parallax forums.
Thanks for the post — I appreciate the input!
The code linked in this post is a much older version. I will put up the new code if you promise not to laugh. Most of this stuff is sort of “proof of concept”, so its in seriously raw state after many changes.
I think I do a ‘CLR RTCC’ in the current code, though. My idea here (based on something Guenther suggested months ago) was that we want the code to SYNC to each detected edge. I want to reset the 2us counter to the last transition. This appears to work well — but what I really don’t know is whether or not I monkeyed with the returnint values to get the necessary timing right. I don’t think I want a TRULY free running clock, but one sync’d to the data.
Let me throw up the current copies of the code which is mostly ASM at this point.
(I just looked at the code, eeesh, I’m embarrassed.)