There are a couple things you're doing that are probably unintentional:
int val[1000]; // This is declaring an array of integers (4-bytes per int)
[[ snip ]]
// This loop is counting from 1, but should be counting from zero, or you'll write past the end of the array
for(i=1; i<1000+1; i+=2)
{
val[i]=1;
val[i+1]=0;
}
[[ snip ]]
// this loop is writing 1000 4-byte quantities to the file
for(i=1;i<1000+1;i++)
{
fwrite(&val[i], sizeof(val[i]),1,fp);
}
fclose(fp);
Try pasting this into your code in place of your SD file create part and see what happens:
//Generate the file data a clock for the ClearPath motor
for(i=0; i<512; i++ )
{
Buffer[0][i] = i & 15; // write the low 4 bits of the loop index into one of our temp buffers
}
print("Start Program.\n");
//Write data to SD memory
FILE* fp = fopen("test.txt", "wb"); // Open a file for writing
for(i=0;i<1024;i++) // write 512 bytes per iteration to the SD file, for a total of 512kb
{
fwrite(Buffer[0], 1, 512, fp);
}
fclose(fp);
//End writing data to the SD Memory
I do notice one issue in the code that's mine - Once the reader finishes pushing data into the buffer, it sets a flag telling the other thread that it's finished. The other thread will stop running the next time it finishes writing a buffer, even if there is still data to send. Padding the file with 2048 zero bytes will fix that. Replacing these lines in the OutputDataThread function should fix it too, but I'll have to double check when I get home.
// the output loop - keep going until we're told not to, and have no more data to send
while( StopSending == FALSE || BufferFull[bufferToSend] == TRUE )
{
Jason...I made the changes you requested in my memory data write portion of the program and made the change to the "while" instruction in your program.
The scope is monitoring p0 and the signal is also sent to the motor. Everything compiled properly but there are no pulses on the scope and no rotation of the motor.
I think there were two different problems here - One, you were initially testing with very short data bursts that didn't even cycle the buffers once, and I never expected that case would happen in real life, so I didn't code for it.
The second was harder to fix - I think the timing in the inner loop is so tight at 53khz in CMM mode that adding even an extra check was pushing it over the limit and causing it to stall. Compiling as LMM code should fix that, and I changed the print() commands to printi() because they take less code space.
The way I set up the test file, it toggles pins 0, 1, and 2 at different rates, and pin 3 is toggled once per buffer (low, then high) making it easy to see how many 512-byte chunks are being emitted if you have a capture scope.
Jason...Very good, thank you. I will load the code and test it on my equipment.
I imagine you would save data to the SD memory differently as opposed to the Parallax\Learn\SD memory code. Is there an easy way to write data to the SD memory faster?
Jason...The results of the test are:
(1) p3 output immediately goes HIGH
(2) 0123 are printed to the screen
(3) After 1 minute and 48 seconds p0 output goes HIGH
(4) After 2 minutes 42 seconds p1 goes HIGH and p0 goes LOW
(5) After 4 minutes and 44 seconds p2 goes HIGH and p0 goes LOW
(6) After 5 minutes and 36 seconds p0 goes HIGH
(7) As time goes by p0, p1, and p2 change state with several minutes between state changes
(8) LED p26 never illuminates
(9) p3 never goes LOW
(10) Symbols "X" and "E" are never printed
You're going to have to figure out how to put SimpleIDE into "project view mode" then, because you probably need to change a compiler option to enable the optimizer.
As a simpler test, try lowering the output rate to 20000 and see if that behaves as expected. (Just change the 53000 in the output thread to 20000)
Jason...Results are the following:
20000 p0,1,2,3 HIGH p26 HIGH
10000 Signal output on p0,1,2
01230123E p26 pulsed
15000 Same results as 10000
17000 Signal pulses on p0,1,2 p3 always HIGH p26 HIGH
after 2 minutes pulses on p0,1,2 p26 pulsed
01230123E
16000 Same results as 17000
18000 Pulses on p0,1,2 p3 HIGH always
pulsed p26
0123
01230
012301
0123012
01230123
01230123E All occurring about 2 minutes apart
After 10 minutes p0,1,2 went LOW while p3 remained HIGH
After examining all the pop up windows on SimpleIDE, I could not find any way in the world to switch to "project view mode" or change the compiler option to enable the optimizer. They apparently do not exist on this SimpleIDE. Could it be that you have a more sophisticated SimpleIDE than mine?
Do that, then on the compiler options tab you can pick CMM with -O2 (speed), or LMM (faster, but bigger). LMM is probably your best choice, but it eats code space pretty quick.
What's happening is that the loop in the output thread isn't able to run fast enough the way you're compiling it. I record the current clock time, then add the amount of time required for whatever frequency you've chosen. Then I wait for that computed clock time to come around. If the frequency is high enough, the wait time can be quite low. The amount of time to wait before sending the next pulse could be less than the time it takes to complete the loop. If that happens, you miss the computed clock time - it passes before you start waiting, and so you end up waiting for the clock to wrap all the way around. That takes 53 seconds at 80MHz, which explains the super long delays you're seeing.
If you compile the code in LMM, or in CMM with "optimize for speed", it should be fast enough to run 53khz (I had no issues) with those settings.
1 minute 48 seconds (actually 1 minute 47.37 seconds) is the time it takes for the system counter to wrap 2 times at 80 MHz. You must be compiling without optimization. Look at the bottom of the "Project Manager" window, and it shows the optimization level that you are using. You can view the project window by clicking on the icon in the lower left corner of the SimpleIDE window. You should be using -Os or -O2.
I've been following this thread with bewilderment. FSRW and the simple techniques used in .wav players have been mentioned in this thread, even with conversions to C. I'm curious, Jason, on topic of SD card speed, how do these routines you've bitten off for Discovery compare with FSRW/Spin access speeds as achieved in .wav players using pread to fill two buffers and pasm to flip flop between them ?
Attached: typical result from the speed test that comes along with the OBEX version of FSRW 2.6, clkfreq=80MHz.
Jason...This is really excellent work! I and my company would like to pay you for your effort. How can we communicate one-to-one rather than to the whole world?
JasonDorie at gmail is the most direct way. Happy to hear you've finally gotten it working.
Tracy Allen: the reading part is plenty fast enough as is - clocking the data out to the pins in actually the timing sensitive bit - that was the part that was stalling. I was trying to code something simple, without a requirement for Spin or PASM, because the user was trying to use C & SimpleIDE. I'm absolutely sure than something in PASM would be able to push data dramatically faster, but the code posted here is (I hope) relatively simple to understand and modify.
In CMM, compiled with optimizations, the code hits 53khz output with a bit of time left over. At 53khz, there are ~1500 clock cycles between output pulses, which should be enough time to do a decent amount of work. The inner loop is simple enough that it should easily fit in FCache, though I haven't looked to see if it actually gets compiled that way.
That little icon at the bottom left corner is so faint that I kept miss seeing it.
I was able to set the speed at twice and the program runs properly.
I also see where I could have called for compiling in C++.
Discovery, glad you found the project window. In trying to make SimpleIDE as simple as possible, Parallax intentionally made it difficult to enable the project window. I think they were concerned it would confuse novices. The result was that it made it more difficult for anyone beyond the novice stage. Maybe a future version of SimpleIDE will make the icon a little more obvious, and allow SimpleIDE to start up with the project window enabled.
Discovery, glad you found the project window. In trying to make SimpleIDE as simple as possible, Parallax intentionally made it difficult to enable the project window. I think they were concerned it would confuse novices. The result was that it made it more difficult for anyone beyond the novice stage. Maybe a future version of SimpleIDE will make the icon a little more obvious, and allow SimpleIDE to start up with the project window enabled.
Yes, I completely missed that bizarre lower-left icon placement too. Quite unexpected.
I've no idea how anyone can have imagined that was 'a good idea'.
Jason...I changed the limit on the "for" loop for generating data from 512 to 2048 and the "fwrite" statement from 512 to 2048 and the ClearPath motor turned four times longer.
If I increase those two numbers beyond 2048 the program stalls.
Jason...In addition, I increased the output data rate from 53kHz to 100kHz and the ClearPath motor works fine. An output data rate of 150kHz is detected by the motor processor as a fault. So, I will run the motor at 100kHz.
The for loop filing the data is writing to a temporary buffer that is 512 x 4 bytes in size. Changing the loops larger than that will write outside the buffer and wreak havoc. You could increase the number of times the buffer is written to the disk, but don't change the "512" value.
I was under the impression that you had a mechanism already to generate these pulses and were simply looking for a way to play them back. Use your existing path generation to produce step and direction pulses, pack those 4 bits into a byte, write a stream of bytes to the SD card.
It should be noted that writing 2Gb to the SD card is going to take a considerable amount of time if you're doing it from a Propeller chip. Write speed is going to be comparable to read speed, which is about 250kb/sec, or 1mb in 4 seconds.
The simplest way to make the test longer is to change this loop:
//Write data to SD memory
fp = fopen("test.txt", "wb"); // Open a file for writing
//CHANGE BELOW
for(i=0;i<8;i++) // write 512 bytes per iteration to the SD file, for a total of 64kb
{
fwrite(Buffer[0], 1, 512, fp);
}
fclose(fp);
That for loop currently does 8 iterations, writing 512 bytes per loop. Increase the loop count from 8 to 2048 to produce a 1Mb file, or to 20480 to produce a 10Mb file, and so on. 512 bytes is the block size for an SD card, so it doesn't really gain you anything to write in larger chunks.
The C# test app I wrote for the PC ingested GCode and output step and direction pulses based on that. It's very simplistic and doesn't do any motion planning or acceleration handling, but it got the job done.
For your own purposes, you don't really need to pack the data into packets of 512 bytes at a time. The underlying file code will take care of that for you. You get somewhat better throughput if you make fewer calls to the file code, but that's about it.
Your code would need to do something like this:
// Open the file for writing here
FILE * fp = fopen( "movedata.bin", "wb" );
while( ... )
{
// Code to compute motor step / direction values goes here
// [[[ code ]]]
// assuming you now have motorXStep, motorXDir, motorYStep, motorYDir values:
// Step and Dir values are either 0 or 1 - code will fail if other values are used.
char byteToOutput = (motorXStep << 0) | (motorXDir << 1) | (motorYStep<<2) | (motorYDir<<3);
fputc( byteToOutput, fp );
}
fclose( fp );
Comments
Try pasting this into your code in place of your SD file create part and see what happens:
I do notice one issue in the code that's mine - Once the reader finishes pushing data into the buffer, it sets a flag telling the other thread that it's finished. The other thread will stop running the next time it finishes writing a buffer, even if there is still data to send. Padding the file with 2048 zero bytes will fix that. Replacing these lines in the OutputDataThread function should fix it too, but I'll have to double check when I get home.
The scope is monitoring p0 and the signal is also sent to the motor. Everything compiled properly but there are no pulses on the scope and no rotation of the motor.
Discovery
Discovery
I think there were two different problems here - One, you were initially testing with very short data bursts that didn't even cycle the buffers once, and I never expected that case would happen in real life, so I didn't code for it.
The second was harder to fix - I think the timing in the inner loop is so tight at 53khz in CMM mode that adding even an extra check was pushing it over the limit and causing it to stall. Compiling as LMM code should fix that, and I changed the print() commands to printi() because they take less code space.
The way I set up the test file, it toggles pins 0, 1, and 2 at different rates, and pin 3 is toggled once per buffer (low, then high) making it easy to see how many 512-byte chunks are being emitted if you have a capture scope.
I imagine you would save data to the SD memory differently as opposed to the Parallax\Learn\SD memory code. Is there an easy way to write data to the SD memory faster?
Discovery
(1) p3 output immediately goes HIGH
(2) 0123 are printed to the screen
(3) After 1 minute and 48 seconds p0 output goes HIGH
(4) After 2 minutes 42 seconds p1 goes HIGH and p0 goes LOW
(5) After 4 minutes and 44 seconds p2 goes HIGH and p0 goes LOW
(6) After 5 minutes and 36 seconds p0 goes HIGH
(7) As time goes by p0, p1, and p2 change state with several minutes between state changes
(8) LED p26 never illuminates
(9) p3 never goes LOW
(10) Symbols "X" and "E" are never printed
Discovery
As a simpler test, try lowering the output rate to 20000 and see if that behaves as expected. (Just change the 53000 in the output thread to 20000)
20000 p0,1,2,3 HIGH p26 HIGH
10000 Signal output on p0,1,2
01230123E p26 pulsed
15000 Same results as 10000
17000 Signal pulses on p0,1,2 p3 always HIGH p26 HIGH
after 2 minutes pulses on p0,1,2 p26 pulsed
01230123E
16000 Same results as 17000
18000 Pulses on p0,1,2 p3 HIGH always
pulsed p26
0123
01230
012301
0123012
01230123
01230123E All occurring about 2 minutes apart
After 10 minutes p0,1,2 went LOW while p3 remained HIGH
After examining all the pop up windows on SimpleIDE, I could not find any way in the world to switch to "project view mode" or change the compiler option to enable the optimizer. They apparently do not exist on this SimpleIDE. Could it be that you have a more sophisticated SimpleIDE than mine?
Discovery
On my setup you...
In SimpleIDE select tools menu
top of the dropdown menu select project view
Dave
Do that, then on the compiler options tab you can pick CMM with -O2 (speed), or LMM (faster, but bigger). LMM is probably your best choice, but it eats code space pretty quick.
What's happening is that the loop in the output thread isn't able to run fast enough the way you're compiling it. I record the current clock time, then add the amount of time required for whatever frequency you've chosen. Then I wait for that computed clock time to come around. If the frequency is high enough, the wait time can be quite low. The amount of time to wait before sending the next pulse could be less than the time it takes to complete the loop. If that happens, you miss the computed clock time - it passes before you start waiting, and so you end up waiting for the clock to wrap all the way around. That takes 53 seconds at 80MHz, which explains the super long delays you're seeing.
If you compile the code in LMM, or in CMM with "optimize for speed", it should be fast enough to run 53khz (I had no issues) with those settings.
Attached: typical result from the speed test that comes along with the OBEX version of FSRW 2.6, clkfreq=80MHz.
Under SimpleIDE
Tools
Next Tab
Font
Bigger Font
Smaller Font
Update Workspace
Properties
Please note that in this drop down menu THERE IS NO PROJECT VIEW
In the Properties tab there is:
GCC Folders (Browers)
Spin
General Settings (no view options)
Highlight (only colors)
Since I cannot get the settings used in Jason's program...my results don't match his.
Discovery
That little icon at the bottom left corner is so faint that I kept miss seeing it.
I was able to set the speed at twice and the program runs properly.
I also see where I could have called for compiling in C++.
Thank you very much.
Discovery
Discovery
Tracy Allen: the reading part is plenty fast enough as is - clocking the data out to the pins in actually the timing sensitive bit - that was the part that was stalling. I was trying to code something simple, without a requirement for Spin or PASM, because the user was trying to use C & SimpleIDE. I'm absolutely sure than something in PASM would be able to push data dramatically faster, but the code posted here is (I hope) relatively simple to understand and modify.
In CMM, compiled with optimizations, the code hits 53khz output with a bit of time left over. At 53khz, there are ~1500 clock cycles between output pulses, which should be enough time to do a decent amount of work. The inner loop is simple enough that it should easily fit in FCache, though I haven't looked to see if it actually gets compiled that way.
Yes, I completely missed that bizarre lower-left icon placement too. Quite unexpected.
I've no idea how anyone can have imagined that was 'a good idea'.
Discovery
The short burst of data on p0 turns the ClearPath motor quickly but for only a couple of revolutions.
How can I load the SD memory with say a full load of 2 gigabytes and turn a few more revolutions?
Discovery
If I increase those two numbers beyond 2048 the program stalls.
Discovery
A pm is a private message sent from one forum member to another. Click on the letter icon on the home page.
Discovery
I was under the impression that you had a mechanism already to generate these pulses and were simply looking for a way to play them back. Use your existing path generation to produce step and direction pulses, pack those 4 bits into a byte, write a stream of bytes to the SD card.
It should be noted that writing 2Gb to the SD card is going to take a considerable amount of time if you're doing it from a Propeller chip. Write speed is going to be comparable to read speed, which is about 250kb/sec, or 1mb in 4 seconds.
Discovery
That for loop currently does 8 iterations, writing 512 bytes per loop. Increase the loop count from 8 to 2048 to produce a 1Mb file, or to 20480 to produce a 10Mb file, and so on. 512 bytes is the block size for an SD card, so it doesn't really gain you anything to write in larger chunks.
The C# test app I wrote for the PC ingested GCode and output step and direction pulses based on that. It's very simplistic and doesn't do any motion planning or acceleration handling, but it got the job done.
For your own purposes, you don't really need to pack the data into packets of 512 bytes at a time. The underlying file code will take care of that for you. You get somewhat better throughput if you make fewer calls to the file code, but that's about it.
Your code would need to do something like this:
I like the look of the plotter you showed a while ago- mind posting the link to a supplier?
I have seen some similar, but not quite like that.
Thanks
Dave
ps: after searching ebay it looks like a makeblock, but with your own controller?
Discovery