reading multiple analog Inputs
I wrote the attached code to read multiple analog inputs ( a max of 32 ) . Each is sampled eight times and then averaged then stored for calculation. Then the endpoints for each sensor are used to calculate the full scale reading. My problem is that one analog input works fine, two work fine, but the third reads a abnormally high number in the middle of the range. I have moved the inputs so that the sensor I am reading functions fine when only two sensors are read. I have even run two cogs with the same code and two inputs works on one cog while the third is on a different cog and it works fine. Am I going crazy or what?
Comments
I just drove home from DEF CON, so my mind is a little mushy -- fair warning to take these suggestions as potentially questionable.
These lines:
...can be replaced with:
longmove(@start_pin, @s_pin, 4) ' copy pins
I'm pretty sure you could change this:
mov ptr_out, ptra add ptr_out, #20
...to:
mov ptr_out ptra[5]
I don't know if this has anything to do with your problem, but you have this line
jmp #end_prog
...that jumps to the end -- it doesn't loop back to the top. I assume your PASM constants and vars are being treated as code. If your goal is to stop the code in it's tracks, you could do this:
jmp #$
Jon,
Thanks for your reply, I apologize for the length of the code but it didn't feel right to leave anything out. I am a big fan of your work with Parallax. I tried the ptra[5] syntax but the propeller tool gave me an error. I will look at the ending that could be the issue.
The
jmp #end_prog
is a big no-no. It falls off the end into data. If you don't need this to loop then may as well just have it as a called subroutine of the main spin program instead of starting a cog. Or at the very least issue a COGSTOP. As is, that cog is crashing.I changed the ending to loop endlessly after setting cmd to 0. I am still having the issue it is like the pin is not configured correctly, I am recieving changing values but they don't match the voltage at the pin. I put debug statements all over this routine to see what it happening, but I came up with no smoking gun.
Is this a run-once cog? Or is it the start of something bigger that will need to run in a loop to handle other commands? If the latter, you might consider a simple structure like this at the top of your pasm code.
org 0 entry setq #5-1 ' get 5 parameter from hub rdlong cmd, ptra jmp #check_cmd1 get_cmd rdlong cmd, ptra tjz cmd, #get_cmd check_cmd1 cmp cmd, #CMD_1 wcz if_e jmp #do_cmd1 check_cmd2 cmp cmd, #CMD_2 wcz if_e jmp #do_cmd2 check_cmd3 cmp cmd, #CMD_3 wcz if_e jmp #do_cmd3 bad_cmd wrlong #0, ptra jmp #get_cmd
This code should really be running all the time endlessly. Your code definitely looks more readable and I will be sure to add it, but I think I found it. I have yet to test this out but my counting variables j and k are added to pin each cycle. that means the pin would be added with 0 the first cycle, 1 the second cycle, then 2 the third cycle. That would be one pin over from where I wanted to read hence my bogus reading.
Is the process:
-- wait for read command
-- iterate through pins
-- calibrate and read each pin
-- return average for each pin to hub
-- back to top
?
BTW, if you have a lot of commands, and they are contiguous, 1 to n, you can do a structure like this:
entry setq #5-1 ' get 5 parameter from hub rdlong cmd, ptra jmp #check_cmd get_cmd rdlong cmd, ptra ' check for command tjz cmd, #get_cmd check_cmd fge cmd, #0 ' limit range fle cmd, #4 ' commands + 1 add cmd, #jmp_table ' prep for jump jmp cmd ' do it jmp_table jmp #done ' 0 jmp #do_cmd1 jmp #do_cmd2 jmp #do_cmd3 ' jmp #done ' 4 done wrlong #0, ptra jmp #get_cmd
Jon,
Thanks for the help. I will definitely put your suggestions into practice. Whatever makes this easier to read will help next time I have to touch it. It was designed to read some contiguous pins analog inputs average each of them to clean them up then scale them to a full scale value and zero of my choice.
Do you want to read them on demand or automatically (once the cog is started). I have used both approaches, usually with JonyJib camera controls where we have lots of analog inputs (joysticks, etc).
Automatically
You want to start a cog that you give a base pin, # of pins, low and high scaled values, and pointer to a buffer to drop the results. Then you want to have that cog take eight samples for every pin, average and scale them, and then write to the assigned hub location? I'm asking because I've done this with a physical ADC chip on the P1, and this would be a good mental exercise. If this is all about automatic reading, it doesn't seem like the command value is needed. Or am I missing something?
While on a break I put this together. It's simple (simplistic?) and, perhaps, overwrought, but I think it does the job. It does compile, but I don't have time to test right now which is why I didn't attach a file (after testing, I will).
dat org 0 entry setq #5-1 ' get 5 parameter from hub rdlong basepin, ptra mov ch, #0 an8_loop mov chpin, basepin add chpin, ch read_ch mov rdnum, #0 mov rawacc, #0 .loop call #get_cal_lo call #get_cal_hi call #get_raw add rawacc, rawval incmod rdnum, #7 ' do 8 samples tjnz rdnum, #.loop shr rawacc, #3 ' average call #get_scaled mov t1, ch shl t1, #2 add t1, hub wrlong scaledval, t1 mov t1, npins sub t1, #1 incmod ch, t1 jmp #an8_loop get_cal_lo fltl chpin wrpin ##(P_ADC | P_ADC_GIO), chpin wxpin #%00_1101, chpin wypin #0, chpin dirh chpin waitx ##(8192 << 2) rdpin callo, chpin ret get_cal_hi fltl chpin wrpin ##(P_ADC | P_ADC_GIO), chpin wxpin #%00_1101, chpin wypin #0, chpin dirh chpin waitx ##(8192 << 2) rdpin calhi, chpin ret get_raw fltl chpin wrpin ##(P_ADC | P_ADC_1X), chpin wxpin #%00_1101, chpin wypin #0, chpin dirh chpin waitx ##(8192 << 2) rdpin rawval, chpin ret get_scaled mov t1, rawacc sub t1, callo mov t2, uhi sub t2, ulo qmul t1, t2 getqx t1 mov t2, calhi sub t2, callo qdiv t1, t2 getqx scaledval add scaledval, ulo fge scaledval, ulo fle scaledval, uhi ret ' -------------------------------------------------------------------------------------------------- basepin res 1 ' first pin in group npins res 1 ' number of pins in group ulo res 1 ' user value for 0.0v uhi res 1 ' user value for 3.3v hub res 1 ' pointer to user output array ch res 1 ' active channel chpin res 1 ' active pin rdnum res 1 ' active reading callo res 1 ' analog level at ground calhi res 1 ' analog level at 3.3v rawval res 1 ' raw reading rawacc res 1 ' raw accumulator scaledval res 1 ' scaled to user range t1 res 1 ' work vars t2 res 1 t3 res 1 fit 496
Jon,
Thank you for going through this trouble. I figured the calibrate portion should be done only once then readings forever after that. I guess I see your point now that I could just loop forever over the read portion after the cal is done and continuously update the readings.
Jon,
I noticed you used some P2 commands that I am not used to yet, as well as a better use of memory in total. I am still learning how to write efficient P2 code. I had not written too much in the way of assembly using the P1, but I knew I wanted to use the new capabilities of the P2 once it came out. I am waiting for a good book on using the P2 and a Propeller Live Forum youtube video(s) on P2 assembly language programming. I am building a simple roverbot with IR sensors for avoidance probably way overkill to use a P2 Edge board, but I am certainly having a lot of fun. Especially using the debug windows in Propeller Tool for inspecting values in my assembly code.
I try to make code very modular. You could do one cal (low and high) per read cycle -- that would be an easy mod with the way the code is laid out. To me, code should be like Legos: build small, useful "bricks" and then assemble them as required. This style lends itself to debugging as well. I have had a busy week after being out of town at DEF CON; perhaps tonight I can run my code on a JonnyMac to see if it's working.