How to clear a PASM cog memory address from pub main? (title change)
turbosupra
Posts: 1,088
Hi,
I'm using waitpeq and waitpne to measure a frequency, but there are times that the frequency will stop and I'd like to turn off the cog and clear all values, or at least clear the previous values out that affect the current frequency calculation. Otherwise when the frequency starts back up again all the calcs are hosed and it doesn't measure correctly.
I think if I wasn't using wait commands I could incorporate a timeout. But if I have a waitpeq and the peq=1 doesn't come, I believe it pauses the cog until it does come and I'm not sure how I would handle that with a timeout period. I'd want something like waitpeq unless waitcycles > clkfreq. If >clkfreq, clear values out in cog.
Is there a way to handle this that I haven't thought of or do I need to rewrite and not use waitpeq/waitpne?
I'm using waitpeq and waitpne to measure a frequency, but there are times that the frequency will stop and I'd like to turn off the cog and clear all values, or at least clear the previous values out that affect the current frequency calculation. Otherwise when the frequency starts back up again all the calcs are hosed and it doesn't measure correctly.
I think if I wasn't using wait commands I could incorporate a timeout. But if I have a waitpeq and the peq=1 doesn't come, I believe it pauses the cog until it does come and I'm not sure how I would handle that with a timeout period. I'd want something like waitpeq unless waitcycles > clkfreq. If >clkfreq, clear values out in cog.
Is there a way to handle this that I haven't thought of or do I need to rewrite and not use waitpeq/waitpne?
Comments
Ok, so I'm trying to wrap my head around this. With waitpne, it AND's the mask with the state and makes sure they don't match.
So if I had a pin added to the mask, that representation bit would be a 1. Then I would have whatever was monitoring the timeout go high after a timeout period and the state of the pin would then be 1, ANDed with the mask would also be 1 and it would just hang at waitpeq paused?
What about the memory addresses that have some previous values used for averaging. How would I clear those?
What do you think? How do you get PASM addresses to spin and clear them to 0?
pstPtr10 shows the timing value it should
pstPtr11 shows a constant value of 361, which I believe is a cog ram address. I enabled a long before gapTimingCntTAddr and then recompiled and as expected, the numerical value jumped up by 1 to 362. So, now that I have the cogram address, how is that translated into a memory address location accessible by pub main?
If I can translate it to an address, then I can set that address to a value of 0 when needed
I understand how a cog can update hub memory, I'm looking to do it the other way around but you've said it isn't possible. Since my waitpne/waitpeq's actually pause the operation of the cog, I cannot communicate with it to tell it to clear some values.
Is there a way to read the value of a numeric memory address?
Read from where?
The only way to read memory from a cog (let's call it cog X) is to have cog X write the value to hub RAM (which of course it couldn't do if it were stuck in a waitpxx statement).
You your case, you'll either need to add an additional pin to your waitpne statement or have a different cog (cog Y) monitor when there's no activity in the cog X and issue a cogstop(X) command.
If you had cog X write a value (let's say 1) to a variable in hub RAM, then cog Y could check the variable and if it equals 1 then it know cog X is still active. Cog Y would then write a zero to the variable and recheck it after a set amount of time to see if it had changed back to one. If the veriable had stayed zero, cog Y would know cog X was stuck and cog Y could stop cog x and restart it.
The way that you've stated I have done before after you all taught me that . Your communication between cogs makes sense too except I need to have the child cog checking the parent cogs monitoring output value. The problem with that is if I'm using wait commands which don't allow it to do that. I'd have to remove those commands and rewrite it so that I wasn't using commands that paused the cogs execution, allowing to read the shared hub ram variable that would be changed/written to by pub main.
Let's try this, say I wanted to read memory address (byte) 12460 or hex 3654.
Can I write pst.dec(12460) or something like that?
I'm still confused about what you mean by "read".
"x := byte[12460]" will move (read?) the value of the byte at location 12460 to the variable x.
Is this what you're asking about?
Of if you want to display the value of the byte in memory location 12460 you could use:
"pst.dec(byte[12460])"
Am I getting warm?
Sure you can read or write the contents of a hub location. You'd use BYTE[12460] or WORD[12460] or LONG[12460] depending on what you've got stored there. You can also change that data by using an ordinary assignment with one of those items on the left side of the assignment, but you'll run into problems when another cog is trying to read that value at the same time.
If I understand cog/hub ram correctly. When you start cognew(@func, @par) @func is a memory address and from there to @func + 511 is a block of memory that is allocated to that cog. If this is correct, I don't understand why I can't read from a cog ram variable directly if I can obtain its numeric memory address. I'm sure all of you who are far better at this have tried this, I just want to satisfy this for my own knowledge.
If I know a cog ram long is sitting at memory address 12460, why can't I read it directly from anywhere?
That hub memory is not allocated to the cog. The data in those memory locations are copied to the cog ram. Both hub ram and cog ram then have copies data.
I understand how pointers work and how to use wrlong to write a copy of some data from cog memory to hub memory.
My question is ... you have 32kb of ram. When cognew is used, 2048 bytes of that 32kb of ram are allocated to that cog in the form of 512 longs correct?
If this is correct, why couldn't I read the memory address directly? If it is all part of the same 32kb of ram. I'm sorry if from the other side of things, it seems like I am asking the same dumb question in different ways, I'm not trying to do that.
The whole thing is 0000 to 8000 right?
Let's say cognew(@func, @par) starts at 7D0, it would end at 9CF right?
So why can't I have x := 8A2 or pst.hex(8A2,32) and read the value using memory addressing?
I think the others have gotten you straightened out.
The 2K of each cog's RAM is separate RAM from the hubs.
If you have PASM cog that only needs to be launched once, you can reuse that area of hub ram once the PASM has been copied into a cog.
I was able to greatly increase the rx buffers of Tim Moore's four port serial driver by using reusing the hub RAM that originally held the PASM code. So even though I increased all four rx buffers from 64 bytes to 512 bytes, the size of the program was only increased by a few longs.
Some object can be very confusing since the variable names in the PASM section get used both in Spin and in PASM.
Edit: I missed your last post. The Prop really has 48kB of RAM. The 32K in hub and 2K in each cog. As others have said, the 2K of PASM code gets copied to a cog. The cog doesn't not use the hub's RAM directly once it has been launched. Cogs launched using Spin cog instead of PASM have a Spin interpreter copied into the cog and the interpreter reads the Spin code from the hub and executes it. This is one reason Spin is so much slower, since the code isn't copied all at once to the cog. This is also the reason cogs using Spin code don't have the 2K limit imposed on PASM code.
I think it took me at least a year of reading the forum before I started to make sense of all this hub RAM vs cog RAM stuff. The Prop really is eight individulal little microcontrollers with each processor having its own 2K of RAM with a large chunk (32K) of hub RAM it can use to share data (by writting to and reading from hub RAM).
This is all pretty darn cool, if you ask me.
In one of my cogs I have this
and if I use the following code and increment l_localPtr by 1 (starting around 1690), it will display every one of those numbers in the proper succession. I haven't figured out how this is working yet, but it does every time. Any theories?
Brad, Your code is reading from hub RAM.
Lets say you start some PASM code and you know that the PASM code starts at location 1692 (it has to be a multiple of four (long aligned)).
After you start a cog running the PASM code, you have some Spin code do the following.
"bytefill(1692, 0, 2000)".
So the above line of code should wipe out your PASM code right? Since the PASM has been copied to a cog it still runs just fine in the cog.
However, if you had executed the bytefill command before launching your PASM cog, there wouldn't be any code to execute and your PASM cog wouldn't do anything.
Did you see that part about the Prop having 48KB of RAM?
I did see that part and I did not know that but it makes sense and I understand. So that I understand the rest, every single line in PASM ram is copied to hub ram when the PASM cog is started?
Here is why I asked, I added the bottom line and I am not writing that line to hub ram anywhere in my code, all that I did was add it and then recompile and it did display right after threeHunHzCycles displayed.
So you are saying that it is copied to hub ram when the pasm cog is launched right?
Ok I added
add tester, #1
to my pasm object and it didn't do anything, so I believe what I understood in the previous post is correct or close and I take it there is no way to address the upper 16k of memory directly?
Thanks for everyone's patience, I almost caught my it : )
When a cog is started, the specified block of hub RAM is copied one long word at a time during each hub time slot (every 16 clock cycles) until a total of 512 longs are copied. I believe that the 16 final longs of the cog RAM, called "shadow RAM" are set to copied values from hub RAM while the corresponding special registers are effectively zeroed (some are read-only). PAR is set to the value passed from the COGNEW or COGINIT.
Thanks for the kindness and patience everyone.
I want to throw in a break:
if I remember right you want to measure a frequency. There are ways to do this with the counters.
Counters can count completely independend from the cogs code-execution.
Of course the code has to read/write counter-registers in certain timeframes.
Now it depends on the highest frequency and the precision you want to measure the frequency
which way of measuring the frequency will work.
Can you post a brief specification of the frequency you want to measure including highest frequency that can occur
needed precision, character of the signal considering beeing an always continous signal just changing frequency
or beeing pulsetrains of different or constant length with constant or different times with no signal in between?
best regards
Stefan
It's good to hear from you! I'm using a modified JonnyMac object right now that does use counters, but with wait commands. I'm not very familiar with counter use and will be up front about that.
The minimum frequency would be 240 highs and 240 lows per second, the maximum would be 6600 highs and 6600 lows per second, it is an ever changing frequency. The frequency is 34 highs/34lows and then a -2 which is the equivalent in time domain of 2 highs and 2 lows that is 100% low, and then it starts over. From rising edge to rising edge, the high portion is 43% and the low portion is 57% of the total time. It is a hall effect sensor with a 36-2 trigger wheel.
What brought this about is that when the engine is turned off, the frequency stops and I need a way to clear my values out if a timeout is reached, so that when the signal starts up again (when the engine is started) the old values (averages and a software hysteresis) do not wreck the new signal values being collected and/or exclude them. With the wait commands I cannot do that because they pause the cog and it cannot do anything else while waiting.
Did I answer all of your questions, including the needed precision one, completely?
Thanks Stefan!
If You calculate that Yours engine can run 6600 revolutions per second --- be sure You build Yours device that can measure at least 20% more else You will have BIG problems in real world.
Here is what I calculated. I gave myself an approximate 20% ceiling I believe at 11k, figuring that 9k would be my limit. The 6600hz number is actually ((11000rpm/60seconds per minute)*36teeth per rotation) as I need to measure the teeth and there are 36 highs and 36 lows in a single crank rotation.
Does that sound about right to you?
Yes and no - As I don't know what Yours engine have as highest nominal Revolutions per second.
It is from that You need calculate at least 20% more.
As You need think as if you run CAR downhill it is possible for engine to to much more that it is build for.and Electronic need function even in that circumstances
The cars maximum rpm is a little shy of 9000 (highest nominal Revolutions per second), so I rounded it up to 9000rpm as a round number, even though it is actually a little less. I chose 11,000rpm to give myself the buffer that you are recommending and it turns out that is a 22% buffer, so pretty close inline with your recommended percentage. So based on this, I believe we both have the same idea here as far as a buffer.
That is correct.
My question is now if You understand why? ---
I guess I just applied that experience for mechanical items to what I'm doing here because the philosophy has always been sound when I was building other things.