Shop OBEX P1 Docs P2 Docs Learn Events
Can SpinBasic provide microsecond accuracy? — Parallax Forums

Can SpinBasic provide microsecond accuracy?

CuriousOneCuriousOne Posts: 931
edited 2013-08-05 13:51 in General Discussion
Hello.

For some time critical applications, I need basic language programmable mcu. As I started with basic stamp, I shortly discovered it is no good for high speed measurements. So I migrated to Melabs Picbasic Pro, which is very basic stamp syntax compatible (most basic stamp code can be directly copy-pasted), but since being compiler, offers far better speeds. At least I though so, but recently, I needed very simple task to do:

1. pulsout PIN 1
2. wait 100 microseconds
3. pulsout PIN 2

The real life tests showed totally disappointing results.

PIC16F628A - took about 270 microseconds before ending of pulse on PIN 1 and begining of new pulse on PIN 2.

OK I tested the 1 microsecond delay. It took 200 microseconds on PIC16F628A @ 4Mhz, and 48 microseconds on PIC12F683 @ 4mhz!

So, this is total flop, so now I'm seeking for another, more precise solution, but with basic language. Will SpinBasic handle such tasks?
«1

Comments

  • PublisonPublison Posts: 12,366
    edited 2013-08-01 12:07
    CuriousOne wrote: »
    Hello.

    For some time critical applications, I need basic language programmable mcu. As I started with basic stamp, I shortly discovered it is no good for high speed measurements. So I migrated to Melabs Picbasic Pro, which is very basic stamp syntax compatible (most basic stamp code can be directly copy-pasted), but since being compiler, offers far better speeds. At least I though so, but recently, I needed very simple task to do:

    1. pulsout PIN 1
    2. wait 100 microseconds
    3. pulsout PIN 2

    The real life tests showed totally disappointing results.

    PIC16F628A - took about 270 microseconds before ending of pulse on PIN 1 and begining of new pulse on PIN 2.

    OK I tested the 1 microsecond delay. It took 200 microseconds on PIC16F628A @ 4Mhz, and 48 microseconds on PIC12F683 @ 4mhz!

    So, this is total flop, so now I'm seeking for another, more precise solution, but with basic language. Will SpinBasic handle such tasks?

    I think you mean PropBasic.

    I generates assembly code that does 12.5 ns resolution. Is that good enough?
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-01 12:17
    It all depends, how accurate it is. The Picbasic Pro also has "resolution", but above example shows how "precise" it is.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-01 12:50
    To get the maximum precision, you really have to look at the assembly instructions generated by PropBasic. The timing instructions (mostly WAITCNT) take a specific amount of time to execute and WAITCNT has a resolution of 12.5ns with the normal system clock speed (80MHz). There may be some additional instructions generated which normally take 50ns each. Generating a pulse on an I/O pin works much the same way. Typically, you'd set the appropriate bit in the I/O output register to 1, wait for the desired pulse width, then set the bit to 0. This can be done in assembly with a resolution of 12.5ns. I don't know exactly what instructions are generated for this in PropBasic, but you can look at the generated code and figure it out. Since the WAITCNT uses the built-in system clock counter, you can associate actions with specific times, all referenced to a particular starting time so the edges of the pulses all are locked into a precise time relative to the start time.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-08-01 12:53
    I have been recently working with microsec accuracy in pfth on the Propeller.

    By calling Waitcnt, one can get pretty darn small. But there is a limit due to the interpreter's overhead of looking up words in the Forth dictionary.

    I figure the lower limit was about 2500 clocks on a 80Mhz crystal. You can figure out exactly how many microseconds that is.

    You do have to deduct a constant factor for the call to the word. I was using something like 324 clocks. If you are interested I need to write up a procedure for getting precise delays to the exact number of cycles desired. But it is doable and verifiable in pfth.

    So you can get an exact number, but the crystal will vary by as much as 3% due to temperature changes. To control that is a whole separate issue.

    pfth is ANSI Forth, not Basic or a Basic-like language.
    Code in PASM will take it to the most precise limit.
  • pmrobertpmrobert Posts: 677
    edited 2013-08-01 12:54
    I use a couple of PropBasic apps everyday in my business. I require very accurate pulse timing and PropBasic has worked very well. Why don't you download it and run a couple of test cases? You can ask opinions all day long and get numerous anecdotes but in the end you are the one who will be able to determine it's suitability or lack thereof. BTW, Publison didn't pull the 12.5 ns number out of his , uhhh...., out of thin air. The Prop running PASM code is precise with excellent resolution, that's certainly not up for debate.

    Edit: Mike Green is awesome. What he said!
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-02 07:41
    Well, I provided the sample code above. Will PropBasic provide it working correctly?
  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-02 08:27
    Attached are the PropBasic source for your timing task and the generated assembly code. The PAUSEUS statement has about 100ns of overhead which is less than the granularity of the delay (us). The PULSOUT has about 300ns of overhead, also less than the granularity of the pulse width (us), but larger than that of PAUSEUS. This can all be tightened up and PropBasic allows snippets of assembly to be included with the Basic code so the timing could be done precisely to a 12.5ns accuracy within a larger and more complex program.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-02 11:29
    Thanks.

    Regarding the assembly code, I can say, I can do same with picbasic pro, and in fact, I can arm timers, enable interrupts and so on, so get precise 100us delay there also, but this all requires so called "low level" programming, which I don't want to do.

    And for PropBasic, say I did some complicated realtime code. When being compiled, will compiler analyze my code for speed issues and will say when experience something difficult "hey, this can't be run in time fragment your code requries?"
  • PublisonPublison Posts: 12,366
    edited 2013-08-02 11:38
    CuriousOne wrote: »
    Thanks.

    Regarding the assembly code, I can say, I can do same with picbasic pro, and in fact, I can arm timers, enable interrupts and so on, so get precise 100us delay there also, but this all requires so called "low level" programming, which I don't want to do.

    And for PropBasic, say I did some complicated realtime code. When being compiled, will compiler analyze my code for speed issues and will say when experience something difficult "hey, this can't be run in time fragment your code requires?"

    I think you would have to ask Bean directly in this forum:

    http://forums.parallax.com/showthread.php/118611-Download-PropBASIC-here...-00.01.14-July-27-2011?highlight=PropBasic

    Here's a search for other good links:

    http://forums.parallax.com/search.php?searchid=1380959


  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-02 11:45
    No. PropBasic is a very simple compiler and it does no significant optimization nor does it do analysis for timing. That said, PropBasic is very simple and the statements compile pretty directly into straightforward code. The timing mechanisms in the Propeller (mostly WAITCNT) are designed specifically to do very precise timing easily and the generated code makes use of this. The Propeller's cogs are very fast, executing one instruction every 50ns except for a handful of instructions that interact with the hub and can take up to about 300ns depending on where the cog is in the "round-robin" for hub access.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-02 12:58
    Ok thanks, and for the Spin, are such "time evaluating compilation" included?

    i.e. can compiler say, this code will run in defined speed values or not?
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-03 05:09
    Thanks. According to this from document you've provided: "Using an oscilloscope to
    monitor a toggling I/O pin is occasionally the handiest way to time Spin or Propeller
    Assembly code. " There is no way to use so called 8 "cogs" to guarantee specified timing outputs, right?
  • Cluso99Cluso99 Posts: 18,069
    edited 2013-08-03 05:35
    You will have to give us some more information of what you are trying to do. You may be able to use a separate cog to do the critical timing job and that may be a very small pasm (assembler) program that you could get help with on this forum. There may even be an object that does what you require.
    Remember, we don't have interrupts to spoil the timing. And we have 2 very capable timers per cog and we can even use the vga to generate outputs too.
    Each pasm instruction takes 50ns but we can wait on a pin change or timer with a 12.5ns resolution. There are a few instructions that take longer, but all are deterministic.
    All the higher level languages have overheads and are much harder to time. But if you divide your code carefully into sections, then most likely there will only be a tiny part that needs pasm, and you place this in its own cog.
    So more info please.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-03 06:28
    Currently, I'm just looking to what to select, to solve the tasks I have in simple and effective way. One of such tasks:

    - Monitor PIN 1, if it gets high, in no less than 1 microsecond, pulse PIN 2 with 10 microsecond pulse.
    - Count the time from the PIN 2 rising edge, and when it reaches 1/2/4/8/16/etc (pre-defined by user) microseconds, pulse PIN 3 with 10 microsecond pulse.
    - Loop

    I was able to solve this task using cheap PIC microcontroller, but I needed usage of digital scope, and fine hand tuning of timings to get the desired result.

    The question is, whenever there is such a solution, which, without usage of expensive or complicated microcontrollers, will allow me to directly write code with timings shown and above, and timings will be correct, no need for further tweaking or usage of scope?
  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-03 07:41
    Here's a first try at the code needed for your timing. There are some small errors. For example, I don't remember exactly when the WAITCNT releases after the time matches the system clock. I also don't remember off hand exactly when the output register (outa) is updated. I think it's in the last phase of instruction execution (4 clocks per instruction). The OR and ANDN instructions will change the output register a few clocks after the computed time, probably 62.5ns later. The initial count (in the ADD) can be adjusted to compensate. Similarly, CNT is saved a few clocks before the TEST accesses the input pin and the initial count should be adjusted to compensate. Since these two compensation factors are in opposite directions (one early and one late), they may counteract each other.

    You'll need a little more code than this ... to set the predefined time delay needed ... to initialize the I/O pins ... to make sure pin 1 is low before starting the loop ... stuff like that.

    The test for pin 1 high has a granularity of 3 x 4 x 12.5ns = 150ns. This could be trimmed to 100ns with a little effort.
    waitForPin1:
                    mov       startTime,cnt   ' save time
                    test      pin1Mask, ina     wc   ' wait for pin 1 to go high
             if_nc   jmp       #waitForPin1
                    add       startTime, #80   ' compute time 1us from pin test
                    waitcnt   startTime, tenMicrosec   ' wait for 1us, set up time for 10us
                    or        outa, pin2Mask   ' set pin 2 high
                    waitcnt   startTime, predefined   ' wait for 10us, set up predefined user time
                    andn      outa, pin2Mask   ' set pin 2 low
                    waitcnt   startTime, tenMicrosec   ' wait for user defined time, set up time for 10us
                    or        outa, pin3Mask   ' set pin 3 high
                    waitcnt   startTime, #0   ' wait for 10us, no need to compute future time
                    andn      startTime, pin3Mask   ' set pin 3 low
                    jmp       #waitForPin1
    
    tenMicrosec  long      800   ' 10us in 12.5ns units
    predefined  long      80   ' 1us in 12.5ns units
    pin1Mask  long      |< 1   ' mask for I/O pin 1
    pin2Mask  long      |< 2   ' mask for I/O pin 2
    pin3Mask  long      |< 3   ' mask for I/O pin 3
    
    startTime res       1   ' for timekeeping
    
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-03 08:31
    Thank you very much for your support, but I think I was misunderstood. I was just asking, will propeller compiler or whatsoever take care of timings I require, or I have to manually hand-tune them?
  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-03 08:47
    I was just demonstrating that, even though none of the Propeller compilers will manage execution timing for you and you have to do it manually, the process of doing that is fairly simple and straightforward and mostly it involves the WAITCNT instruction which stalls the processor until a specified absolute time occurs (using a 32-bit system clock counter normally with a granularity of 12.5ns).
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-08-03 08:49
    Well, I think everyone is trying to just explain that the more you know, the better your results will be.

    The Propeller has a very simple and easy method of controlling timing. But without understanding what it is and how it works, microseconds can be a bit tricky.

    IN PASM, you get exactly what you want.

    But in all higher level languages, there is some overhead that creeps in and needs to reconciled. It is not hard to do.

    If you feel that someone else should just make all that go away, you are likely to always be a bit disappointed by any computer language you use.

    If that example is all you need to do inside a PIC, it isn't much to program that in assembly.

    I get down to about 31.25 usecs with exact result in pfth, but if I need better I would have to use PASM.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-03 08:58
    Well, I don't think that I'm asking for too much. Just an IDE/Compiler whatsoever, which will optimize code along cogs/cores/bores/etc, and if I insert command "pause 10 usec" between two pulses, I will be sure that pause really will be 10usec.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-03 09:05
    Saying even simpler. In basic stamp, say PAUSE 100 and PAUSE 1000 provide quite reliable results. Can I have same, but for Microseconds?
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-08-03 09:08
    "Pause 10 usec" may seem like you are not asking too much.

    Maybe it can be provided in a compiled language. But when I created a word to do that in pfth, there is a constant amount of system overhead added to the 10usec delay.

    The nice thing about Forth is that I don't have to use a scope to see this. I can just do it interactively. Once I determine the overhead that crept in, I just can deduct that amount from my delay and have precise repeatable results.

    At 1 msec, the overhead is insignificant and nobody seems to care... but at 10usec, the same overhead is a large addition to the timing.

    ++++
    The bottom line is whether you want to learn to use what the Propeller offers or wait for someone to write the 'prefect pause' for you. You might wait quite long as the people that need precise timing tend find life simpler in PASM than in BASIC.

    The smaller your delay interval, the bigger the potential error is. What may seem like a nice flat line to you is really a very flat curve with long delays and big hook at the usec end of the curve.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-03 09:25
    Well, I don't have propeller at all. I'm just looking, if such solution exists. If it does not, I did quite a lot in Z80 ASM programming, so I think I can learn ASM for PIC or whatsoever. Generally, why I asked here? I was attracted by loud PR such as "8 cores, parallel execution", and so on. When dug deeper, all that looks like marketing PR ?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-08-03 09:43
    CuriousOne wrote: »
    Well, I don't have propeller at all. I'm just looking, if such solution exists. If it does not, I did quite a lot in Z80 ASM programming, so I think I can learn ASM for PIC or whatsoever. Generally, why I asked here? I was attracted by loud PR such as "8 cores, parallel execution", and so on. When dug deeper, all that looks like marketing PR ?

    What?

    There are 8 cores and you can have parallel execution. How does the compilers inability to write the low level code you want make any of that marketing PR?
  • PublisonPublison Posts: 12,366
    edited 2013-08-03 09:53
    Duane Degn wrote: »
    What?

    There are 8 cores and you can have parallel execution. How does the compilers inability to write the low level code you want make any of that marketing PR?

    I wondered the same thing.

    8 cores, parallel processing IS the hardware. No marketing hype.

    All Application Notes are available here:

    http://www.parallaxsemiconductor.com/appnotes


  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-03 10:26
    The Propeller was designed to make this sort of precise timing easy. With the small time delays involved (microseconds), it's very difficult to generate code automatically from a high-level language. Most such coding involves small pieces of hand optimized code to do the precise timing and a larger (and more complex) framework that's for the most part time independent to tie the pieces together using a high-level language. The Propeller Tool combines a Spin compiler and native assembler to do just this. PropBasic provides for in-line assembly for the same reason.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-08-03 11:42
    A rather silly thread. One tries to help and finds that the user wants a replacement for his PIC Basic Pro. As I recall, that was a very expensive software package that claimed to be excellent, but maybe just claimed more than it was.

    Try www.piclist.com for PIC solutions. Mike Prego wrote a good book on programing PICs in assembler... buy it used as it is out of print.

    Parallax provides the software for FREE, and has worked with precise timing in the Propeller from the start. It even does video. But the reality is that if you want to mess around with usecs, you are going to have to assembler to get it right.

    Still, you won't get as much performance out of a PIC16F84 as a Propeller. The Propeller has more of everything.
  • CuriousOneCuriousOne Posts: 931
    edited 2013-08-03 12:09
    So, if I have to mess with assembler anyway, than why should I choose "8 cores" instead of at least 5x cheaper solution, if I have to deal with ASM ? :)
  • Mike GreenMike Green Posts: 23,101
    edited 2013-08-03 12:20
    For the benefit of others, I've used PIC Basic Pro and it works pretty well as a BS2 PBasic replacement. Like the BS2, there's a lot of overhead in doing what it has to do and operations on the order of less than a millisecond are problematic and even operations on the order of milliseconds require care in programming. Some of the non-BS2 PBasic extensions still were buggy in the copy I bought a few years ago, but overall it's a good product.

    I've written a lot of code for the Propeller including some doing sub-microsecond timing and I've been impressed with how straightforward and reliable it is.

    If you don't need the multi-processing, sure ... why pay for it? If you have to deal with ASM, you can certainly do it cheaper. On the other hand, the Propeller has a good instruction set, very straightforward. As mentioned, it's designed for precise timing and signal processing type applications, among others. I like its ability to do debugging on-chip. I can run a TV video text driver in one cog and display data from other cogs with small snippets of code added to my code. Similarly, I can run a PS/2 keyboard interface in another cog and store data in memory for my routines to use ... change parameters on the fly, etc. It's not quite the sort of symbolic debugger you can run on a PC, but it's close and more than adequate. Although it's not free (but cheap), Hanno's ViewPort is a nice PC-based debugger that can function as a logic analyzer and can be used to monitor variables and change parameters as well.

    If you're into it, you can run the Propeller as a stand-alone system using Sphinx which works with a TV, PS/2 keyboard, and an SD card or micro-SD card for mass storage. It includes a Spin compiler and an assembler. The TV / keyboard interface needs a couple of resistors and capacitors and the SD card interface just needs a socket.
  • AribaAriba Posts: 2,690
    edited 2013-08-03 17:18
    The CNT system timer and the WAITCNT instruction which waits for an exact system counter value makes such exact timing very easy in any language on the Propeller that support WAITCNT.

    In Spin you can do it like that:
    CON
       _clkmode        = xtal1 + pll16x
       _xinfreq        = 5_000_000
       us100 = 80*100           'cnt clocks for 100us and 10us
       us20  = 80*20
       pin = 0                  'pin number to use
    
    PUB Main : now
    
     dira[pin] := 1             'pin = output
     repeat
       now := cnt               'reference point for exact timing
       outa[pin] := 1           'high
       waitcnt(now += us20)     'wait until exactly 20us from reference point
       outa[pin] := 0           'low
       waitcnt(now += us100)    'wait until exactly 120us from reference point
       outa[pin] := 1           'high
       waitcnt(now += us20)     'wait until exactly 140us from reference point    
       outa[pin] := 0           'low
    
       waitcnt(clkfreq/100+cnt) 'wait ~10ms before next loop
    '
    
    The pulse and pause times will be precise to ~200ns because Spin executes from HubRam and has to synchronize to the Hub slot for the cog.
    There will be a minimal pause time in Spin (maybe 2us), and the compiler will not warn you if you go lower, but then you can do the same in Assembly down to maybe 100ns minimal time).

    Andy
Sign In or Register to comment.