The SD root directory can only be read if a trailing slash is given, but subdirectories only if it is not given.
Relatedly, I think the true root directory / can not be enumerated at all?
I didn't notice this / - no / difference in Basic, but I was unable (?) to list / so I decided to not go there in the player (and forget about this). There was also problem with lack of .. (up-dir) directory listed. I had to add it artificially to the directory list. Then getting current directory was also not working as I expected. Maybe it is now corrected but the player keeps the current directory itself.
I have LFN enabled in the compiler ( -DFF_USE_LFN) . This is 21st century, LFNs are everywhere, so maybe this should be the default option, and -DFF_DISABLE_LFN if someone don't want it and needs several KB of HUB instead. I even added LFN reading to P1's KyeFAT for use in P1 player several years ago.
What should be available and useful for file handling in the application like the multimedia player is:
I'd like to see some more test results from others using sysclock/6. The source code needs changed to set that divider though ... at the end of disk_initialize() in the sd_mm.cc file, replace the code with this:
Just tried the speed test (at its default 250 MHz, current flexspin master, -O1 (-O2 chokes on something)).
Seems busted to me, on P2EDGE-32MB with a SanDisk Ultra 16GB.
Okay, I've identified an improvement for my code too: Remove the P_SYNC_IO from the tx pin mode at higher sysclocks for small dividers ...
I should have done this earlier. There is definitely an extra tick of lag being injected in the tx pin timing. Here's a capture of the prop2 output timings using the existing tx mode settings running at 350 MHz sysclock and clock divider of 6, 0x0002_0006
Orange trace is SPI clock
Blue trace is tx data (DI)
So, the second falling edge of clock is 6 sysclocks from the first. The tx output should match this edge but is aprox 3 ns behind - one sysclock tick!
And here's the same test again but with P_SYNC_IO removed from tx pin mode:
I guess loading on the clock pin impacts this ... but shouldn't be more than +1 lag. None of these should be enough to create errors. There's a space of four sysclock ticks to the subsequent rising clock edge.
Nothing's perfect I'm afraid. The propagation times of I/O signals synchronising with the internal sysclock are creating havoc. I'm definitely getting frustrated. I don't know what's the slowest area in the I/O. It might not be the I/O pins themselves.
That spreadsheet with the propagations listed had some really large values stated, like 8.0 to 10.0 ns. My best guess is those numbers were referring to the routes from each pin into the first stage I/O flops, with I/O registering turned off. But even given that scenario those are really big numbers for a 200 MHz rated part. I would have expected nothing larger than 5.0 ns.
End result is allowing more leeway is needed.
Please run the speed test at 250 MHz and at 350 MHz using the latest code above. Those should be the two worst cases.
Here's a demo of what's going on. This is 155 MHz sysclock, with SPI clock divider of 4, 0x0002_0004. The amount of lag is four sysclock ticks (Best a smartpin can do) at slower clock rates but as you can see it's jittering between four and five.
And here's same again but at 160 MHz sysclock. It's now cleanly at five lag.
Using P_SYNC_IO on the clock pin mode helps by raising the sensitive jitter threshold from 150 MHz area to 250 MHz area, but it don't eliminate the problem. And adding P_SCHMITT_A on the clock pin moves it down a little to 240 MHz.
Ha, it's just dawned on me it meets the 200 MHz rating when using P_SYNC_IO. Anything more is an overclock.
Orange is SPI clock from the prop2.
Blue is SPI DO back to the prop2.
Ignore the filled blue section. The important factors are the phase lag from falling clock edge to data edge, and the curved slope of the data. Both these combine to add latency to the data arriving at the rx smartpin. This example still works reliably. But this example is only 100 MHz sysclock (With SPI clock divider of 4).
A sync serial smartpin is limited in its ability to handle such a phase shift. Namely, it samples the data pin either the sysclock tick after rising clock detection, X[5]=1, or it samples on the prior sysclock tick, X[5]=0.
Both those two options fail quite early in the 200-350 MHz frequency range. There is, however, one bonus tick that can be added to the sampling phase. The clock input, smartB, to the rx smartpin can also have a delay added to it, thereby giving the external clock a head start. I didn't work this out until having tested it. This is done by registering the clock pin.
Ooo, ah, I just realised I might be able to remove the effect that this registering also imposes on the tx smartpin ... bugger, nope. The routes exist but the mode select bits don't cater for it. I thought maybe the partnered pin's low level pinB could be directed to IN but the only way that can happen is via the comparator against pinA, which is in use as the SD card enable.
PS: The setup in this example, with clock pin registered and x[5]=1 and only 100 MHz sysclock, the rx smartpin sampling point will be the rising clock edge + 2 sysclock ticks. Which is the beginning of the following falling clock edge. One whole SPI clock cycle of grace. Perfect for a divider of 4.
Different story as the frequency climbs and the rising clock edge takes longer than one sysclock tick.
PPS: I guess it goes without saying, pointing out the drive strength of the SD data out is quite weak. I presume this is by design to reduce noise while meeting the 25 MHz requirement of basic speed. That trace is from the Adata but the Sandisk Extreme's trace looks exactly the same. (EDIT: It actually looks more attenuated!) Attenuation is going to be bad at 50 MHz SPI clock rate. So, it kind of looks like the SD card has to be told to up its game if we want better performance.
Some experimenting later ... It's not terribly great news. Although CMD6 is mandatory for SPI interface, the parameters can all be locked to base defaults. Which most are on most cards. The Sandisk in particular has everything locked to default for SPI.
And those that do support switching to high-speed mode seem to just shift DO to the rising clock edge. The drive strength looks the same at first glance ...
The 00 64 is 100 mA (or 360 mW). This value doubles when HS mode is set.
The five repeating 80 01 means base default support for each of those five parameters.
The final 80 03 means it supports both the base standard-speed and also high-speed.
The Sandisk's status is this: CMD6 GET status block: 00 64 80 01 80 01 80 01 80 01 c0 01 80 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
And attempts to tell it to try other than base settings results in error responses and no change of mode.
PS: The c0 01 means support for base and "Vendor Specific". That particular parameter is for changing the "command system". To me that says need proprietary documentation. And probably nothing to do with interface speed.
Well, I've now got three profiles built. The new one runs up to 60 MHz SPI clock when high-speed mode is available.
But there is a caveat! It assumes SPI high-speed simply shifts the SD card's DO clock edge from falling to rising. It just so happens that is an advantage for smartpins. I can drop the use of registering the clock pin because rx smartpin now has more time to sample the data. This in turn frees up the tx smartpin to reduce its lag back to 4 ticks.
If the SD card's DO doesn't change its clocking edge for SPI high-speed mode then this'll immediately go splat. Possibly over top the FAT file system.
Everyone: Please test this again. It might make a mess, so do use a card that you won't mind having to reformat afterwards. PS: Debug is turned on. I'll be interested in reported output from various SD cards.
[broken file removed]
@evanh Sounds like the same fundamental input delay timing issue we had to solve for reading from external memory, possibly compounded a bit more by the weak drive strength of some SD cards, and timing tweaks will be needed at different frequency ranges. Unfortuantely this is likely to plague any IO driver design when operating at high speed, and it's not going away.
Yep. Main difference is the latencies are relative to SPI clock input to the rx and tx smartpins rather than from software. Less stages. But on the flip side there is less opportunity to compensate.
The variation with edge switching is peculiar to SPI high-speed mode as empirically discovered. So , the problem here is possibly not all SD cards do this for SPI high-speed mode.
The lack of true synchronous I/O registers in the propellers means that we rely on asynchronous over-sampling instead. To be fair, I have no idea how much trouble it is to implement direct clocking of an I/O register. I'm guessing some sort of minimal FIFO, maybe just double buffering, is needed to interface between internal clocking and arbitrary synchronous I/O.
Hmm, no, SPI High-Speed mode ain't gonna be a reliable approach at all. Not really implemented seriously by any card. Only way to get stronger pin drive is start using SD protocol instead of SPI. EDIT: And that ain't gonna happen any time soon - partly because it's just overkill for any Prop2 memory sizes.
I think it might be time to tidy up and trim back what I've got ...
EDIT: Okay, final smartpins edition: Please, everyone give this a thorough test to ensure timing is robust.
EDIT2: Already a fix
Thanks @evanh and @iseries for your suggestions and code. I've merged Evan's smartpin code into the flexspin libraries, and following Mike's suggestions I've updated the FAT file system code to the newest FatFs. All of this is checked into the spin2cpp (and flexprop) github now. Thank you!
@ersmith said:
Thanks @evanh and @iseries for your suggestions and code. I've merged Evan's smartpin code into the flexspin libraries, and following Mike's suggestions I've updated the FAT file system code to the newest FatFs. All of this is checked into the spin2cpp (and flexprop) github now. Thank you!
With that added and all the PRs dealt with, it perhaps is time to bundle up a release version....
EDIT: Speaking of, with the new optimizations and the LLVM port being a thing, perhaps it is also time for some light-hearted benchmarking action.
Started some careful probing of streamer ops tonight and found they aren't quite as I was expecting. I was expecting an equivalent period cycling to how the pulse mode smartpins work. Where, once started, the period metronomically cycles even when no pulses are presenting to the pin.
Well, with a streamer, when data runs out, the XFRQ period seems to halt ... resuming on the next XCONT/XZERO. What this means is there is no delay from instruction to first bit output. Whereas, the smartpin pulse modes wait until the current idling period is completed before a new pulse will be output.
I was hoping to phase align the two systems with each other on the same period. Eliminating the need to realign on every command. But, alas, not to be.
Yes, the restarting of the clock smartpin is the critical element. So it needs also an earlier DIRL (or FLTL). I was hoping to find a way to not need that mechanism beyond initial setup. Alas, the streamer and smartpin internals are too different.
I've also used another, slightly more complicated, method in the past. Where the pulse period is adjusted to stretch the first clock, or a stretched initial blank streamer bit, to achieve fine control of the phase alignment. This method has no adjustment gaps in the full 360 degrees. Which makes it more useful if wanting to handle multiple sysclock ratios.
Hmm, the only fully flexible method I can see is this: EDIT2: Turns out the smaller WAITX method can handle variable ratios too.
// preambled bitstream
setq xfrq1
xinit pmode, #0 // phase delay at sysclock/1 (unbuffered command), length is dependent on spec'd rate
setq xfrq2
xcont txmode, haddr // data out at spec'd rate (buffered command)
dirh #spi_ck // restart clock period at spec'd rate
wypin clocks, #spi_ck // produce clock pulses beginning from next period
EDIT: This works for both SPI clock mode 0 (CPOL=0, CPHA=0) and mode 3 (CPOL=1, CPHA=1)
For SPI mode = 0: pmode[15..0] for sysclock/2 to sysclock/20: 8,7,9, 8,9,9,11, 10,11,11,12, 12,13,13,15, 14,15,15,16
For SPI mode = 3: pmode[15..0] for sysclock/2 to sysclock/20: 9,9,11, 11,12,13,15, 15,16,17,18, 19,20,21,23, 23,24,25,26
There is a faster version just for SPI clock mode 3: pmode[15..0] for sysclock/2 to sysclock/20: 7,7,9, 7,10,6,9, 10,12,14,16, 18,6,7,9, 9,10,11,12
// preambled bitstream
dirh #spi_ck // restart clock period at spec'd rate
setq xfrq1
xinit pmode, #0 // phase delay at sysclock/1 (unbuffered command), length is dependent on spec'd rate
setq xfrq2
xcont txmode, haddr // data out at spec'd rate (buffered command)
wypin clocks, #spi_ck // produce clock pulses beginning from next period
I can achieve a practical solution of your WAITX method by using data pin registration to introduce a one-sysclock lag on streamer output. This allows a way to avoid the timing limitation of that method. And as it turns out, the same +1 lag works fine at every sysclock ratio.
Here's the pdelay needed for sysclock/2 to sysclock/20: 0,0,0, 1,3,5,0, 0,1,2,3, 4,5,6,8, 8,9,10,11
PS: SPI clock mode = 3 (CPOL=1, CPHA=1) ... further experimenting ... looks like it's not possible to do this as mode 0, only the lucky sysclock/4 works out.
EDIT: Ha, lol, solved by removing the pin registration. So, SPI clock mode = 0 (CPOL=0, CPHA=0), pdelay for sysclock/2 to sysclock/20: 0,2,3, 4,1,2,5, 5,7,8,10, 11,13,14,1, 0,1,1,2
Some notes on findings in the above couple of posts:
SPI clock smartpin uses the pulse mode, therefore can have uneven high/low times:
either P_PULSE | P_OE | P_INVERT_OUTPUT (CPOL=1)
or P_PULSE | P_OE (CPOL=0)
When building the streamer pdelay tables I noticed sometimes the first bit output from the streamer was consistently extended by one sysclock tick. I have no explanation for this but it never changed for each timing. I mention it because I think it explains the quirkiness of the table values. Some entries are one sysclock tick smaller than otherwise expected ... not that I've confirmed this point. Oh, looking more carefully, they're all the non-powers-of-two. So only streamer clock dividers of 2,4,8,16,32,... have the ideal startup. That explains the consistency at least.
Comments
I didn't notice this / - no / difference in Basic, but I was unable (?) to list / so I decided to not go there in the player (and forget about this). There was also problem with lack of .. (up-dir) directory listed. I had to add it artificially to the directory list. Then getting current directory was also not working as I expected. Maybe it is now corrected but the player keeps the current directory itself.
I have LFN enabled in the compiler ( -DFF_USE_LFN) . This is 21st century, LFNs are everywhere, so maybe this should be the default option, and -DFF_DISABLE_LFN if someone don't want it and needs several KB of HUB instead. I even added LFN reading to P1's KyeFAT for use in P1 player several years ago.
What should be available and useful for file handling in the application like the multimedia player is:
@ersmith ,
Test program for SD card:
Mike
I've updated the speed test program a little along the way.
- speed calculation is now much higher precision
- compare now reports where the mismatch occurred
https://forums.parallax.com/discussion/comment/1537616/#Comment_1537616
I'd like to see some more test results from others using sysclock/6. The source code needs changed to set that divider though ... at the end of
disk_initialize()
in the sd_mm.cc file, replace the code with this:The report of interest is for 350 MHz sysclock (58 MHz SPI clock).
@evanh ,
I wasn't using the speed test as a benchmark but rather a line in the sand to compare results of changes to the code.
Mike
Here is some code to show the directory functions and file operations:
Mike
Yes, same. But it wasn't very precise at small durations. Some tests were only a few milliseconds, so I fixed that anyway.
Just tried the speed test (at its default 250 MHz, current flexspin master, -O1 (-O2 chokes on something)).
Seems busted to me, on P2EDGE-32MB with a SanDisk Ultra 16GB.
I've tried building megayume with it and it seems to work fine in there (at it's 325-ish MHz) for some reason. Significant speedup there.
Thanks Ada ...
In particular, it seems that CSE chokes on P_SYNC_IO for some reason...
Compiler bug I presume.
Okay, I've identified an improvement for my code too: Remove the P_SYNC_IO from the tx pin mode at higher sysclocks for small dividers ...
I should have done this earlier. There is definitely an extra tick of lag being injected in the tx pin timing. Here's a capture of the prop2 output timings using the existing tx mode settings running at 350 MHz sysclock and clock divider of 6,
0x0002_0006
Orange trace is SPI clock
Blue trace is tx data (DI)
So, the second falling edge of clock is 6 sysclocks from the first. The tx output should match this edge but is aprox 3 ns behind - one sysclock tick!
And here's the same test again but with P_SYNC_IO removed from tx pin mode:
I guess loading on the clock pin impacts this ... but shouldn't be more than +1 lag. None of these should be enough to create errors. There's a space of four sysclock ticks to the subsequent rising clock edge.
Worth further real tests anyway ...
Ah, but what about bounce/reflections crossing VIO/2 threshold incorrectly ... time for P_SCHMITT_A ...
Try this everyone:
Updated: A little looser timings. Run tests at 150 MHz, 200 MHz, 280 MHz, and 350 MHz.
Nothing's perfect I'm afraid. The propagation times of I/O signals synchronising with the internal sysclock are creating havoc. I'm definitely getting frustrated. I don't know what's the slowest area in the I/O. It might not be the I/O pins themselves.
That spreadsheet with the propagations listed had some really large values stated, like 8.0 to 10.0 ns. My best guess is those numbers were referring to the routes from each pin into the first stage I/O flops, with I/O registering turned off. But even given that scenario those are really big numbers for a 200 MHz rated part. I would have expected nothing larger than 5.0 ns.
End result is allowing more leeway is needed.
Please run the speed test at 250 MHz and at 350 MHz using the latest code above. Those should be the two worst cases.
Here's a demo of what's going on. This is 155 MHz sysclock, with SPI clock divider of 4,
0x0002_0004
. The amount of lag is four sysclock ticks (Best a smartpin can do) at slower clock rates but as you can see it's jittering between four and five.And here's same again but at 160 MHz sysclock. It's now cleanly at five lag.
Using P_SYNC_IO on the clock pin mode helps by raising the sensitive jitter threshold from 150 MHz area to 250 MHz area, but it don't eliminate the problem. And adding P_SCHMITT_A on the clock pin moves it down a little to 240 MHz.
Ha, it's just dawned on me it meets the 200 MHz rating when using P_SYNC_IO. Anything more is an overclock.
EDIT: Updated again - https://forums.parallax.com/discussion/comment/1537713/#Comment_1537713
And here's the other part of the puzzle:
Orange is SPI clock from the prop2.
Blue is SPI DO back to the prop2.
Ignore the filled blue section. The important factors are the phase lag from falling clock edge to data edge, and the curved slope of the data. Both these combine to add latency to the data arriving at the rx smartpin. This example still works reliably. But this example is only 100 MHz sysclock (With SPI clock divider of 4).
A sync serial smartpin is limited in its ability to handle such a phase shift. Namely, it samples the data pin either the sysclock tick after rising clock detection, X[5]=1, or it samples on the prior sysclock tick, X[5]=0.
Both those two options fail quite early in the 200-350 MHz frequency range. There is, however, one bonus tick that can be added to the sampling phase. The clock input, smartB, to the rx smartpin can also have a delay added to it, thereby giving the external clock a head start. I didn't work this out until having tested it. This is done by registering the clock pin.
Ooo, ah, I just realised I might be able to remove the effect that this registering also imposes on the tx smartpin ... bugger, nope. The routes exist but the mode select bits don't cater for it. I thought maybe the partnered pin's low level pinB could be directed to IN but the only way that can happen is via the comparator against pinA, which is in use as the SD card enable.
PS: The setup in this example, with clock pin registered and x[5]=1 and only 100 MHz sysclock, the rx smartpin sampling point will be the rising clock edge + 2 sysclock ticks. Which is the beginning of the following falling clock edge. One whole SPI clock cycle of grace. Perfect for a divider of 4.
Different story as the frequency climbs and the rising clock edge takes longer than one sysclock tick.
PPS: I guess it goes without saying, pointing out the drive strength of the SD data out is quite weak. I presume this is by design to reduce noise while meeting the 25 MHz requirement of basic speed. That trace is from the Adata but the Sandisk Extreme's trace looks exactly the same. (EDIT: It actually looks more attenuated!) Attenuation is going to be bad at 50 MHz SPI clock rate. So, it kind of looks like the SD card has to be told to up its game if we want better performance.
Started investigating using CMD6 to switch to High-Speed mode - https://forums.parallax.com/discussion/comment/1537797/#Comment_1537797
Some experimenting later ... It's not terribly great news. Although CMD6 is mandatory for SPI interface, the parameters can all be locked to base defaults. Which most are on most cards. The Sandisk in particular has everything locked to default for SPI.
And those that do support switching to high-speed mode seem to just shift DO to the rising clock edge. The drive strength looks the same at first glance ...
Here's an example debug output, for the Apacer card:
CMD6 GET status block: 00 64 80 01 80 01 80 01 80 01 80 01 80 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
The
00 64
is 100 mA (or 360 mW). This value doubles when HS mode is set.The five repeating
80 01
means base default support for each of those five parameters.The final
80 03
means it supports both the base standard-speed and also high-speed.The Sandisk's status is this:
CMD6 GET status block: 00 64 80 01 80 01 80 01 80 01 c0 01 80 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
And attempts to tell it to try other than base settings results in error responses and no change of mode.
PS: The
c0 01
means support for base and "Vendor Specific". That particular parameter is for changing the "command system". To me that says need proprietary documentation. And probably nothing to do with interface speed.Well, I've now got three profiles built. The new one runs up to 60 MHz SPI clock when high-speed mode is available.
But there is a caveat! It assumes SPI high-speed simply shifts the SD card's DO clock edge from falling to rising. It just so happens that is an advantage for smartpins. I can drop the use of registering the clock pin because rx smartpin now has more time to sample the data. This in turn frees up the tx smartpin to reduce its lag back to 4 ticks.
If the SD card's DO doesn't change its clocking edge for SPI high-speed mode then this'll immediately go splat. Possibly over top the FAT file system.
Everyone: Please test this again. It might make a mess, so do use a card that you won't mind having to reformat afterwards.
PS: Debug is turned on. I'll be interested in reported output from various SD cards.
[broken file removed]
@evanh Sounds like the same fundamental input delay timing issue we had to solve for reading from external memory, possibly compounded a bit more by the weak drive strength of some SD cards, and timing tweaks will be needed at different frequency ranges. Unfortuantely this is likely to plague any IO driver design when operating at high speed, and it's not going away.
Yep. Main difference is the latencies are relative to SPI clock input to the rx and tx smartpins rather than from software. Less stages. But on the flip side there is less opportunity to compensate.
The variation with edge switching is peculiar to SPI high-speed mode as empirically discovered. So , the problem here is possibly not all SD cards do this for SPI high-speed mode.
The lack of true synchronous I/O registers in the propellers means that we rely on asynchronous over-sampling instead. To be fair, I have no idea how much trouble it is to implement direct clocking of an I/O register. I'm guessing some sort of minimal FIFO, maybe just double buffering, is needed to interface between internal clocking and arbitrary synchronous I/O.
Hmm, no, SPI High-Speed mode ain't gonna be a reliable approach at all. Not really implemented seriously by any card. Only way to get stronger pin drive is start using SD protocol instead of SPI. EDIT: And that ain't gonna happen any time soon - partly because it's just overkill for any Prop2 memory sizes.
I think it might be time to tidy up and trim back what I've got ...
EDIT: Okay, final smartpins edition: Please, everyone give this a thorough test to ensure timing is robust.
EDIT2: Already a fix
Thanks @evanh and @iseries for your suggestions and code. I've merged Evan's smartpin code into the flexspin libraries, and following Mike's suggestions I've updated the FAT file system code to the newest FatFs. All of this is checked into the spin2cpp (and flexprop) github now. Thank you!
With that added and all the PRs dealt with, it perhaps is time to bundle up a release version....
EDIT: Speaking of, with the new optimizations and the LLVM port being a thing, perhaps it is also time for some light-hearted benchmarking action.
Cool! Now I have to wait to get home. Silly I didn't take a board with me.
Although SD cards are missing drive strength adjustment in SPI mode, I've since learnt SD drive strength wasn't what is slowing the DO signal down. It's because of an inline 240 ohm protection resistor in case of collisions with the EEPROM - https://forums.parallax.com/discussion/169233/boot-issue-accessing-spi-flash-after-sd-access/p1
Started some careful probing of streamer ops tonight and found they aren't quite as I was expecting. I was expecting an equivalent period cycling to how the pulse mode smartpins work. Where, once started, the period metronomically cycles even when no pulses are presenting to the pin.
Well, with a streamer, when data runs out, the XFRQ period seems to halt ... resuming on the next XCONT/XZERO. What this means is there is no delay from instruction to first bit output. Whereas, the smartpin pulse modes wait until the current idling period is completed before a new pulse will be output.
I was hoping to phase align the two systems with each other on the same period. Eliminating the need to realign on every command. But, alas, not to be.
The Way(tm) (at aleast for HyperRAM and it's sysclk/4 clock pin) looks a bit like this:
Not sure if it works like that for other dividers (maybe with an appropriate WAITX between DRVL and XINIT?).
Yes, the restarting of the clock smartpin is the critical element. So it needs also an earlier DIRL (or FLTL). I was hoping to find a way to not need that mechanism beyond initial setup. Alas, the streamer and smartpin internals are too different.
I've also used another, slightly more complicated, method in the past. Where the pulse period is adjusted to stretch the first clock, or a stretched initial blank streamer bit, to achieve fine control of the phase alignment. This method has no adjustment gaps in the full 360 degrees. Which makes it more useful if wanting to handle multiple sysclock ratios.
Hmm, the only fully flexible method I can see is this: EDIT2: Turns out the smaller WAITX method can handle variable ratios too.
EDIT: This works for both SPI clock mode 0 (CPOL=0, CPHA=0) and mode 3 (CPOL=1, CPHA=1)
For SPI mode = 0:
pmode[15..0]
for sysclock/2 to sysclock/20:8,7,9, 8,9,9,11, 10,11,11,12, 12,13,13,15, 14,15,15,16
For SPI mode = 3:
pmode[15..0]
for sysclock/2 to sysclock/20:9,9,11, 11,12,13,15, 15,16,17,18, 19,20,21,23, 23,24,25,26
There is a faster version just for SPI clock mode 3:
pmode[15..0]
for sysclock/2 to sysclock/20:7,7,9, 7,10,6,9, 10,12,14,16, 18,6,7,9, 9,10,11,12
I can achieve a practical solution of your WAITX method by using data pin registration to introduce a one-sysclock lag on streamer output. This allows a way to avoid the timing limitation of that method. And as it turns out, the same +1 lag works fine at every sysclock ratio.
Here's the
pdelay
needed for sysclock/2 to sysclock/20:0,0,0, 1,3,5,0, 0,1,2,3, 4,5,6,8, 8,9,10,11
PS: SPI clock mode = 3 (CPOL=1, CPHA=1) ... further experimenting ... looks like it's not possible to do this as mode 0, only the lucky sysclock/4 works out.
EDIT: Ha, lol, solved by removing the pin registration. So, SPI clock mode = 0 (CPOL=0, CPHA=0),
pdelay
for sysclock/2 to sysclock/20:0,2,3, 4,1,2,5, 5,7,8,10, 11,13,14,1, 0,1,1,2
Some notes on findings in the above couple of posts:
SPI clock smartpin uses the pulse mode, therefore can have uneven high/low times:
P_PULSE | P_OE | P_INVERT_OUTPUT
(CPOL=1)P_PULSE | P_OE
(CPOL=0)When building the streamer
pdelay
tables I noticed sometimes the first bit output from the streamer was consistently extended by one sysclock tick. I have no explanation for this but it never changed for each timing. I mention it because I think it explains the quirkiness of the table values. Some entries are one sysclock tick smaller than otherwise expected ... not that I've confirmed this point. Oh, looking more carefully, they're all the non-powers-of-two. So only streamer clock dividers of 2,4,8,16,32,... have the ideal startup. That explains the consistency at least.