Sign in to follow this  
Followers 0
EirikV

Memory managing in CPM1A (Stacks, adress pointers and the like)

14 posts in this topic

Hi guys, I'm struggling here with a Omron CPM1A-40CDR-A trying to do something that I'm pretty sure it isn't ment to be able to do, but here it goes. I have 16-bit register that get a value between $00 and $FF fed into it from a MAD01 Analouge module. I'm scaling it down to $00 - $C8 (0 - 200) using the built in scale function. Oh, wait! There is no built in scale function! :-P Anyway, now I want to write a routine that allocates an array of 16-bit registers and does the following: Write the start value ($00 - $C8) into the first register and then subtract $01 from the value, then move the result into the next register and repeat the action until it's done a 199 times. Then I want to scale the results between $00 and $FF again (well, I could maybe just forget the scaling in the first place, and just work with the original values, makes no difference really. It's just a little bit easier to work with). Now I want to move the value of the first register to the MAD01 analouge output, and when a certain event occur I want to move the value of the next register to the analouge output. This I want to do 200 times (until I reach $01). I could write the whole thing by hand, but that is to say the least; a bit tideous. Is it possible to do this in a Omron CPM1A-40CDR-A? Is there some hidden adress pointer or similar that I could use? I found a COLL(81) instruction that may be usable, but I see it wants me to tell it what to do by using BCD, and I absolutley can't stand BCD! Anyway, thanks for any suggestions! - Eirik

Share this post


Link to post
Share on other sites
You could just use the pointer functionality: move the address you want to start from to DM0 for instance and then just move the value you want to write to *DM0 and increment DM0 and decrement the write value. this you do until the written value equals 1 As far as I recall CPM1 supports pointers (*DM500 for instance) Beegee Edited by beegee

Share this post


Link to post
Share on other sites
Welcome to the forum. To "load" your table of registers you will need to use the DIST instruction. To move the values to the analog output would use the COLL instruction. The data value does not have to be BCD. The "pointer/control word" must be a BCD value. This should not be a problem as the DM area is addressed in a BCD fashion. I would suggest you look at indirect addressing for this application. Also guessing you will need to use differentiation (one shot) on the instructions. You may also want to look at the INC instruction. The CPM1A has 1000 data memory location, so you should have enough memory for your application. Do you have the programming manual? It is the W353 manual and it can be downloaded. I would agree you are pushing the CPM1A, but it should work. Hope this will help.

Share this post


Link to post
Share on other sites
@beegee Ah! So indirect adressing is possible. Never thought of trying that Thanks! Edited by EirikV

Share this post


Link to post
Share on other sites
There are some great examples in this tutorial by Jay Hughes. Indirect Addressing

Share this post


Link to post
Share on other sites
@gtsuport Thanks! I'll look into it @IO_Rack I'll have a look, thanks Edited by EirikV

Share this post


Link to post
Share on other sites
Is there an easy way to loop a subroutine a certain number of times in the CPM1A?

Share this post


Link to post
Share on other sites
You could just increment/decrement each cycle (it will be slow with CPM1A. maybe you should consider buying a CP1L/H (all functionality you have been asking till now is in it and much more)

Share this post


Link to post
Share on other sites
I've tried to do that, but it seems as if the cycles are too quick for i.e the CMP, CNT, and even MOV instruction to react to anything. It may be just bad coding from me... I'm not the one who bought this antique PLC I was just asked to do some of the work. If nothing works, I could propose to buy a newer one, but for now I will see if I can get the sucker to obey I have another Q here; can I use the JMP instruction inside a subroutine to make it loop itself?

Share this post


Link to post
Share on other sites
From reading your oringinal post and subsequent postings... 1. Are you oringinally a computer programmer with a bit of PLC back ground ? 2. As a summary of your oringinal post... you take a snap shot of the analogue input value... then create an array of values based on the analogue value (ie do array[i+1] = array - 1 until array = 0) ... then every time you get an input (event) start at the first index pos array[0] and output that to the analogue output... then increment the pointer so that the next time the event occurs you output arrary[n+1]. 3. If you are doing the what i have said in 2... there are simpler ways to achive this... why not take a snap shot of the analogue value (ie start event @MOV 11 D0) and every time an event occurs do CMP D0 #0, If D0 > #0 then @DEC D0. Finally MOV D0 13.. I am assuming that 11 is an Ain and 13 is Aout.

Share this post


Link to post
Share on other sites
Hehe, to your first question: Well it's probably a bit of both. I've done some 68k assembly, so it's probably from there i picked the terminologys, but I can't say I'm very experienced with either that or PLC programming. I do know the Omron terminology too Second Q: Yes, basically that. There are some scaling involved before and after, but in essence that is what I'm trying to achive. After the values are calculated, they will be moved to the analouge output. The signal out is proportional to the tension applied to a cable coil on a drawing machine. I want to decrease the tension so the tension stays more or less constant as the coil emptys. This I will do with a high speed counter connected to the PLC, which give me 60PPR. With a certain interval I will move the next tension value to the output. The particle clutch applying the tension applies 0 - 200 Nm of braking torque proportional to a 0 - 10 V signal from the PLC. If I start out at 200 I will of course reach 0 later then if I start out at 18, but if I reach 0, I want to apply a constant value of 1 to the output. The start tension can be adjusted by a potmeter in 10 steps. So it is from the start tension specified by the potmeter I will start decreasing. Third Q: I have attached a part of the program where I check if the start tension has changed and call the subroutine. Now the part where I check for changes in start tension works all fine and dandy, but, when the subroutine executes, it's only semi-working. On the first scan I set the adress pointer (DM19) to #14 (DM20). Now the start tension from previous scan (DM15) is AFAIK #0, so the start tension routine is executed (once). The DM13 register contains +18, which is correct, and DM16 contains +17, which is also correct. DM19 (pointer) however, still contains +20, and DM20 is not written to. If I now change the start tension to 255 (199 scaled in DM13) the adress pointer (DM19) is increased to +21 and the decrement data register (DM16) still contains +199. If I now set the input to 0 again, +18 is written to DM13 and DM16, DM16 is decreased to +17 and DM19 is increased to +22. Still none of the registers the address pointer has pointed to gets data written to them. I am having a bit of a hard time understanding exactly why this happens. Probably me messing something up, but I don't exactly see what at the moment. Hope you can shed some light on that. Now, I'll try doing what you suggested. After all it is not nesecary to pre-calculate all the values Thanks Eirik Edited by EirikV

Share this post


Link to post
Share on other sites
Another unexplainable phenomenon has occured Look at the following capture. When the increasing word reaches +25 it starts on +21 again, and when the decreasing word reaches +19 it starts on +23 again. Why is this? Am I mixing binary and BCD?

Share this post


Link to post
Share on other sites
beware.... from what I see in the part of program you put in the post, you don't care too much about datatypes. MLB of two words results in a double word (DIVB also) and as far as I can see you reuse the same areas for the MLB you overwrite D13 (the higher word) immediately afterwards, but I can't see whether you use D14 for example.... so check these issues. When you are using CPM1A I would consider keeping everything in BCD: pointer addresses are also in BCD. Beegee

Share this post


Link to post
Share on other sites
beegee is spot on with the indirect addressing of the MSW of the results of the functions used... a data register can only be &65535 in decimal or #FFFF(Hex)... alternaivey #9999 BCD... so if the result is larger through multiplication then the result flow over into the next word... likewise for division... the answer is the quotient and remainder. personally i would avoid sub routines in your case... there are a number of other contraints and unless you require high speed interupts then i would personally avoid them... for the high speed counter ... simply do a CMPL 248 &1000 for example and the once => OUT 252.00 (high speed counter reset) AND DEC D100 (where D100 is the output prior to scaliing )

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0