Assembly - Main RAM access
sbergren
Posts: 12
in Propeller 1
I'm fairly new to this. I'm sure it's been answered somewhere, but I can't find it.
My ultimate goal is to sample audio input and store it in Main RAM so it can be later used to send to a speaker, saved to SDcard, etc.
I understand how to pass an address to the cog and write a single value back to it. However, what I'm needing is an array of hundreds or thousands of samples. How to I set up an an array in Spin that I can then send the address of to the assembly cog to do this sampling, and how to I address and write the sampled values back to main RAM?
My ultimate goal is to sample audio input and store it in Main RAM so it can be later used to send to a speaker, saved to SDcard, etc.
I understand how to pass an address to the cog and write a single value back to it. However, what I'm needing is an array of hundreds or thousands of samples. How to I set up an an array in Spin that I can then send the address of to the assembly cog to do this sampling, and how to I address and write the sampled values back to main RAM?
Comments
The cogs only have 2KBytes (512 longs) each, of which only 16 longs are in use. Hub ram is 32KBytes so you could store up to 16,384 16 bit samples which is at most only a second or two of audio. To store any more samples would require external ram.
You would have the address in one of the cog registers (lets call it "address") and add 1, 2, or 4 to the address depending on whether you are writing a byte, word, or long to the address.
For example 8 bit values would be:
How many bits of resolution are you storing?
Declare an array in hub ram and pass the address when you start the cog. WRBYTE, WRWORD AND WRLONG will write bytes, words and longs to hub RAM. RDBYTE, RDWORD and RDLONG will read them. I believe that deSilva said that he thought, to his mind, the source and destination fields were reversed. I've gotten it to work properly after playing with it for a while. At least you know it's possible now.
Sandy
Here are the needed snippets for a word array and assembler writes to it: Andy
Suppose I have one cog that is constantly checking the status of something (button press, etc.) and sending that value back to main ram. Now I have a second cog that I want to take samples of that value that the first cog sent back.
I would THINK it would work just like in Ariba's example, but when I start the second cog, I also send it @buffer in the parameter.
But something isn't working. I've verified that the first cog is writing back to store correctly. And I've verified that the second cog can write SOMETHING back to buffer correctly. However, I'm unable to read store in @sampler. I'm parsing PAR correctly, so that's not the problem. I know the whole point of putting stuff back into main ram is to be able to share it between cogs but I am not doing that successfully.
Thanks for your help so far!
There are times when your example wouldn't work correctly. You need to make sure the address passed with par is long aligned.
Depending on what other variables are defined in the VAR section, the buffer array may or may not be long aligned.
There are several ways to insure a word (or byte) array is long aligned. Here are couple of methods I use. Both of these methods define the array in a DAT section.
Make sure you use another org to start your PASM code so the addressing is done correctly.
There's also a problem with this bit of code:
The value 4096 will need to be assigned to a variable accessed indirectly.
The source field in a PASM statement is limited to 9-bits.
This last error would have been caught by the compiler.
So are there any little simple rules that I should know that might be throwing things off? For instance, do I need to do an ORG before DAT sections that will be done by separate cogs? Do my data and reserveds for the different PASM "modules" need to be "with" their module, or all at the bottom of the DAT? I found that if I had one data item at the end (before the RES still) that it did weird things, but when it was just under the section of code for that cog, it worked fine. Should I just throw all my code up here so you can see what I'm doing wrong?
From what I see, the above code will set _Parameter[3] to zero.
I haven't followed the code closely, but my guess is you intended to pass the address of "mem" rather than the value of the first element.
Should the line be the following?
Sorry for the bad suggestion.
I'm still not clear what this line of code is supposed to do.
So others know what we're discussing, here's were the arrays and variables are defined.
Below is the code where the array is filled.
The Parameter array only has three elements so the element "_Parameter[3]" is out of bounds.
"_Parameter[3]" is another name for "mem[0]".
As the arrays are defined, the line "_Parameter[3] := mem" doesn't serve any useful purpose.
Is the array "_Parameter" supposed to have four elements instead of three?
I'm guessing there's a mistake in the way the "_Parameter" array is used. Hopefully this is a hint towards finding your bug.
That didn't fix my problem, though. Still trying to sample a value and store it to mem.
The first cog is there just to generate input. Imagine its like an ADC and it stores its current value in "buttons_value." The second cog "Record" is trying to read the value of "buttons_value" at a regular interval and write the value to a memory array.
The problem seems to be that Record is unable to "see" the current value of "buttons_value" and I'm not sure why. I pass the address of "buttons_value" in _Parameter, so I would think I could just rdlong at that address and get the value. It just doesn't seem to be happening.
I'm still wondering if you're missing an "@" symbol somewhere.
Do you know you can "cheat" and poke the values of address into PASM variables instead of using par?
If you change:
to
You can set the value of "button_state_address" before you launch the cog.
I'm not sure what you're trying to do, so I'm not sure where you're missing an address symbol but I think you are missing at least one.
If you attach you're latest code, I'll look at again.
I wrote this from scratch, based on what I think you want. It launches a "sampler" cog that will scan the QS pads at a rate that you specify (between 50 and 1000ms). When all the samples are taken, the sampler cog alerts the foreground and shuts itself down. From that point, the demo program plays the samples back at the same rate.
The program is fully functional. You may find it educational.
Things to remember:
-- keep your formatting neat & tidy, using a consistent style (mine mimics C style)
-- make code (even PASM) as modular as you can so that it's easier to re-use
-- PASM labels really should be in column 1
-- when you do a jmp or call you must prefix the label with # (PASM address), else it will treat the value in the variable you reference as an address
-- when possible, make your code system frequency agnostic
Additionally, I don't understand something about the code that I think may be the big thing I am missing. You pass scog to sampler. But then you skip over it and get the #samples. How do you know that's at the next long? What sets that structure?
Beside that, the button sample methode you use seems to not work well for my fingers.
So I have made a simplified version of your code with my own way to read the buttons:
This works on my Quickstart board.
Andy
Johnny, I'm going to try yours out again. I didn't change anything in it and assumed I didn't need to. But you know what they say when you assume...
(Edited: Oh, yeah, I figured it out. Open the terminal and hit a button. DOH!)