View previous topic :: View next topic |
Author |
Message |
ccsfred
Joined: 15 Jun 2016 Posts: 33
|
Best way to multitasking |
Posted: Mon Oct 16, 2017 7:32 am |
|
|
Hi,
I'm writing some code to measure a LVDT's output over stroke.
Working:
* Excitation frequency generation & voltage adjustment
* Two channel Sample and hold
* Serial commands to set V & F, start and stop readings
* Reading encoder position over serial from another pic on another board
* Outputting channel A & B Voltage from Sample and hold & current position over serial
The readings are received by PC and subsequently drawn on a graph to show output V over
position.
My issue is at 3KHz I can only sample every 10th pulse because my serial string
is too long, "Axxx Bxxx Pxxxx" at 921600Bd.
So for example when LVDT is static the output is good, and if I move the LVDT slowly I
get a nice straight output line. If I move quicker the output line will dip.
How can I use sample continuously and send the serial out in the "background" somehow please?
I tried using the CCS RTOS this morning, but can't get it to sample enough due to
serial Max time, whilst allowing the serial tasks enough Max time.
Any recommendations please?
Thanks! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19524
|
|
Posted: Mon Oct 16, 2017 7:48 am |
|
|
If you are sending at 921600bps, then each character will take 1/92160 second (assuming 8bit). For the string you show, assuming there is a LF at the end, there are 17 character, so the physical transmission alone will take just on 1/5000th second. Now this can be going on while you are doing other jobs, by simply using a serial TX ISR. There is an example with the complier (ST_ISR.c), or you can use the TX_ISR option in the #USE RS232 driver now. However there is a big caveat, that you still have to generate the serial string. If you are sending this as decimal, then 'reconsider' and send as hex, which has the advantage of reducing the amount of calculation needed to send the data, and reducing the transmitted length as well. It is also pointless to be sending A, B & P, and the spaces between.
A packet like:
<STX>HHHHHHHHHH<LF><ETX>, sends 13 characters and can have two 12bit hex values and a 16bit hex value using much less time. It is easy to both encode and decode. |
|
|
ccsfred
Joined: 15 Jun 2016 Posts: 33
|
|
Posted: Mon Oct 16, 2017 9:53 am |
|
|
Thanks Ttelmah, I used the ex_stisr.c example and reducing the serial string as you suggested, I can see on the scope it's working. I just need to amend the c# code to decode the new hex string and hopefully this will solve the problem!
Thanks again |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19524
|
|
Posted: Mon Oct 16, 2017 10:33 am |
|
|
Well done.
Even on a PC, hex decodes faster than decimal, so it'll help here (provided you design the layout to suit - depends on the sizes of the numbers involved etc..). |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 16, 2017 12:52 pm |
|
|
If you want to do multi-tasking in the future, look at this thread for
techniques:
http://www.ccsinfo.com/forum/viewtopic.php?t=54043
Also, use the forum's search page to search for: multi-tasking
There are several threads on how to do it. |
|
|
ccsfred
Joined: 15 Jun 2016 Posts: 33
|
|
Posted: Tue Oct 17, 2017 10:13 am |
|
|
Dear Guru's,
Linked to my previous question, I now need a solution for the incoming encoder position, as the rate of data coming in when moving LVDT faster is putting my S & H timing off. I've tried disabling and enabling int_rda2 when sampling, which improves the timing, but misses positions being sent. Also tried adding RECEIVE_BUFFER=1024.
Is there an example of incoming buffer anywhere please? I've looked in the examples dir & in the code library? Or try and work out the xmit buffer and rewrite for rcv?
Thanks! |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9231 Location: Greensville,Ontario
|
|
Posted: Tue Oct 17, 2017 2:20 pm |
|
|
ex_sisr.c is the CCS example of an ISR driven serial receive. It's in the 'examples' folder. A fair amount of discussion about it so maybe 'search sisr' and see what pops up.
I did a test using a slightly modified version, on an 18F46K22 using both serial ports and 'blasted' away to a PC at 115K200, never lost a byte though the test only ran 2 weeks.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19524
|
|
Posted: Tue Oct 17, 2017 11:53 pm |
|
|
Honestly though a lot depends on just how fast things have to be.
It is enormously easier to take advantage of hardware. For instance it is relatively easy (couple of logic gates), to build a circuit to give two pulse trains from an encoder, one for each direction. This can be fed into hardware counters. Or some PICs have quadrature counters built in. Or US digital do quadrature decoder IC's.
The critical thing is to start working out what timings genuinely are involved....
For example, if you have an encoder with (say) 512 lines, and it turns at 1000RPM, this potentially gives 8533 lines per second ((512*1000)/60). However a quadrature encoder produces four state changes per line, so 34133 interrupts per second to handle this without loss. Now even if you write efficient assembly code directly for a high priority interrupt handler, you are talking at least perhaps 20 instructions to handle an interrupt. Do it instead using a general handler and you are talking at least perhaps 80 instructions. Now if all your interrupts are at the same hardware priority (from the data rate involved I am assuming you do have a PIC18 or better), then you have to potentially complete any other interrupt handler you have, if it does happen to get called just a moment before a change on the encoder. This in part is why it is so critical to get out of interrupt handlers ASAP, if other things are being handled.
You need to start with things that must be handled. Encoder edges are such things. Calculate the minimum interval involved (as shown above). This then gives a time that the handler has to cope with. Then list other time events that have 'margins'. So (for instance), serial receipt. You have just fractionally under two character times before the UART will overflow. Is there enough time to handle all the edges, and still have some service time left for this?. All of these things have to happen before you have any time left for the 'main' code. If the timings look 'tight', then tweaking may improve a little. However if the timings are not even in the same 'ballpark', then you need to be looking at hardware solutions to give the margins needed. Something like the LFLS7366R connected to the SPI interface on a PIC makes encoder counting a 'doddle', and leaves time for other things.
Some calculations are needed to see what is really practical. |
|
|
ccsfred
Joined: 15 Jun 2016 Posts: 33
|
|
Posted: Wed Oct 18, 2017 9:43 am |
|
|
Thanks for the advice, which caused me to rethink what I'm doing. I've now linked the CH A & B of encoder from the motion board to the analogue board, so I can read in hardware into the QEI and working well. These are only proto's so can respin the change in next build.
Thanks again! |
|
|
guy
Joined: 21 Oct 2005 Posts: 297
|
|
Posted: Thu Oct 19, 2017 1:34 pm |
|
|
Hi ccsfred,
You didn't mention what PIC you are using but I just wanted to share with you - I ordered a couple of samples of dsPIC33EV256GM002.
I was surprised that within 15 minutes I had it connected and running a blinking led, CPU running at 70 MIPS (140MHz internal clock)! Powerful 5V beast easily tamed with the CCS compiler.
The 16-bit MCUs (and now some of the newer 8 bit) also have DMA which means you can transmit, receive AND sample simultaneously, all done IN THE BACKGROUND while your main code is running. This solves many of the difficulties of the project you describe.
* Disclaimer - from my experience if you choose this path be prepared that the compiler might have a few bugs which will require you to go to low level registers. |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Fri Oct 20, 2017 1:30 am |
|
|
Now this is useful information. A dsPic running of 5V. Will make my life so much easier. Using current sensing chips that are only available in 5 V now have to use opamp and divider to go to 3v. And the best are that I am using the EP128GM, so absolutely code and pin compatable.
Just when programming the EP on an old board with the chip selected as EV128GM, aaaarg |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19524
|
|
Posted: Fri Oct 20, 2017 5:30 am |
|
|
There are a few chips like this appearing now. They are basically CPU cores at a low voltage (typically only a couple of volts), with buffered I/O provided, and an internal regulator for the core. Very nice for a lot of things.
Be aware that the DMA is limited by the capabilities of the memory bus. By default the CPU has priority, and if you perform operations doing rapid RAM I/O, the DMA may almost stall. Normally there is plenty of time for the other device(s) while you are doing things like jumps, which don't involve RAM accesses, but it is possible to find the DMA doesn't help as much as you may think it should... |
|
|
guy
Joined: 21 Oct 2005 Posts: 297
|
|
Posted: Fri Oct 20, 2017 9:07 am |
|
|
Ttelmah, does this apply to UARTS, ADC etc? These peripherals need the DMA for a single byte/word transfer per thousands of machine cycles, isn't it? Please describe your experience with the subject.
I love the fact that DMA doesn't require an interrupt for each transfer - saves cycles, stack, and usually code complexity. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19524
|
|
Posted: Fri Oct 20, 2017 2:01 pm |
|
|
It applies to all DMA.
There is only one RAM bus. There is an arbiter between the DMA and the processor that (by default) gives priority to the CPU. The DMA can only pull data on the RAM bus on cycles where the CPU is not using the bus. Now normally there are enough cycles when the CPU doesn't use the bus at all (jumps etc.), for the DMA to merrily proceed. However I was using a DMA SPI 'flat out', and at the same time a DMA based MSD USB implementation (basically relaying SD card data via the PIC to a PC), and proceeded to do a large memcpy, and found the DMA bottlenecked when I did this.
Now for something that is only transferring low data rates relative to the CPU, 'no problem', but it does have limits.
As a [spam] example, using DMA to drive an SPI ADC, and it is lovely. Instead of having to interrupt every byte and transfer the next, just program it have the bytes that need to be sent coming from one area of RAM, and the result fed to another, and interrupt when all the bytes have been transferred. Brilliant. Far less overhead than repeatedly calling an interrupt handler, and in normal code flow at the reasonably low SPI rate involved, the transfer finishes only a very few machine cycles longer than the theoretical 'max'. |
|
|
ccsfred
Joined: 15 Jun 2016 Posts: 33
|
|
Posted: Tue Oct 24, 2017 9:55 am |
|
|
Hi Guy,
I'm using a dspic33fj256mc710A, thanks I shall read up about DMA not used before! |
|
|
|