Menu

timer for code timing

2020-06-03
2020-06-08
1 2 > >> (Page 1 of 2)
  • stan cartwright

    stan cartwright - 2020-06-03

    I looked fot a simple equivelent of
    start-time
    code
    end-time
    print time

    time would be a long var.

    I did try a 50Hz interrupt that increased a variable but it didn't work with iliglcd.
    dim tim as long
    TCCR1A = 0x80;
    TCCR1B = 0x0A;
    OCR1AH = 0x9c;
    OCR1AL = 0x3f;
    On Interrupt Timer1Match1 call ISR

    tim=0
    code
    print tim
    end

    sub ISR
    tim=tim+1
    end sub

     
  • Chris Roper

    Chris Roper - 2020-06-04

    Depending on your needs it may be easier to use the Millis() function.
    It is timer based, Interrupt driven and device independent.

    The drawback though in your case is that it has a minimum resolution of 1mS.

    If the code you are timing takes several mS then the Millis function is fine, but if less than 1mS accuracy is needed then you would have to read the timer directly and compare.

     
  • George Towler

    George Towler - 2020-06-04

    An alternate approch is to use a single bit of i/o and a data analyzer (super cheap clone, £5 on ebay) set the bit hi to mark the start etc.

     
  • stan cartwright

    stan cartwright - 2020-06-04

    Thanks. I tried adding #include "millis.h" where millis.h is in gcb includes but got this error-
    myline3.gcb (5): Warning: Cannot find C:\Users\stanley555\Documents\GCBasic stuff\arduino-new\millis.h
    Should millis.h be in same folder as the program using it?
    I want to test the speed of a line draw routine by drawing 1000 lines and timing it.
    As an alternative I thought turn a port on, draw the line,turn port off then monitor the port on a scope and see the port frequency. The faster the line code the higher the port frequency...I might try that.
    edit. I did using

    for cntr=1 to 65535
     set DIGITAL_6 on
    ; line (0,0,319,239,ILI9341_White) ;gcb line gave 17.19Hz 
     draw (1,1,320,240,ILI9341_White) ;new line gave 16.88Hz
     set DIGITAL_6 off
    next
    

    not much difference but gcb faster.

     

    Last edit: stan cartwright 2020-06-04
    • Chris Roper

      Chris Roper - 2020-06-05

      from the help:

      There are two forms of include; absolute and relative.
      
      Absolute is used to refer to files in the ..\GreatCowBASIC\include directory. The name of the file is specified in between < and > symbols. For instance, to include the file srf04.h, the directive is:
      
          #include <srf04.h>
      Relative is used to read files in the same folder as the currently selected program. Filenames are given enclosed in quotation marks, such as where mycode.h is the name of the file that is to be read.
      
          #include "mycode.h"
      

      So:
      this error-
      myline3.gcb (5): Warning: Cannot find C:\Users\stanley555\Documents\GCBasic stuff\arduino-new\millis.h

      is a syntax error on your part just change :

      #include "millis.h"
      

      to

      #include <millis.h>
      

      Cheers
      Chris

       

      Last edit: Chris Roper 2020-06-05
      • stan cartwright

        stan cartwright - 2020-06-05

        Thanks Chris, it works well.
        I used

        tim= millis()
        for cntr=1 to 100
         line (0,0,319,239,ILI9341_White)
        ; draw (1,1,320,240,ILI9341_White)
        next
        tim = millis() - tim
        GLCDprint (1,200,tim,ILI9341_White)
        

        gcb line (0,0,319,239,ILI9341_White) took 5024
        my draw (1,1,320,240,ILI9341_White) took 5928
        gcb clear winner.

        I seem to remember an every command in one basic I used,maybe amstrad.
        It set up an interrupt that every x ms jumped to a subroutine.
        That would be handy in gcb as I find interrupts at the desired frequency complicated to set up.

         
        • Chris Roper

          Chris Roper - 2020-06-05

          I seem to remember an every command in one basic I used,maybe amstrad.
          It set up an interrupt that every x ms jumped to a subroutine.
          That would be handy in gcb as I find interrupts at the desired frequency complicated to set up.

          Here is a crude Task scheduler using millis that may help, it is just a skeleton so you could flesh it out to suit your needs:

          ' Interrupt based Task Scheduling with millis() function
          #Chip 'mydevice'
          #Option Explicit
          #Include <Millis.h>
          
          #Define Slice 10 ' Time Slice in mS range 1 - 255
          #Define Tasks  5 ' Number of tasks
          
          Dim Tick, Task as Byte
          
          Do
            Tick = millis()
            if Tick >= Slice then
              Select Case Task
                Case 1  ' Task 1
                  task1()
                  ' ...
                Case 2  ' Task 2
                  task2()
                  ' ...
                Case 3  ' Task 3
                  task3()
                  ' ...
                Case 4  ' Task 4
                  Task(4)
                  ' ...
                Case Else
          
              end select
              Task = Task + 1
              If Task = Tasks then Task = 0
              Tick = 0
            end if
          Loop
          
          Sub Task1()
          ' ...
          end Sub
          
          Sub Task2()
          ' ...
          end Sub
          
          Sub Task3()
          ' ...
          end Sub
          
          Sub Task4()
          ' ...
          end Sub
          
          Sub Task5()
          ' ...
          end Sub
          
           
          • stan cartwright

            stan cartwright - 2020-06-05

            Nice Chris but not what I was thinking of.
            millis is a useful addition to gcb.
            It was a thought that there must be a program pointer that is pushed when an interrupt happens then popped but I don't know avr/pic hardware.
            If I wanted a 50Hz interrupt I could use millis in the program loop and check if 20ms had passed...as long as the program loop was less than 20ms.

            I will look at the millis.h again as an insight to interrupts.
            nice one,stan

             
  • stan cartwright

    stan cartwright - 2020-06-04

    I wondered what happens when you include glcd.h
    does it install all of it or just the bits you use?
    like if you don't use circle or triangle are they installed or only installed if you use them?

     
    • Chris Roper

      Chris Roper - 2020-06-05

      Just the bits you use.

       
  • Chris Roper

    Chris Roper - 2020-06-05

    Whilst I don't know much about the Amstrad or its BASIC implementation, it should be possible to create a DoEvery() type function with millis().

    Here is my rough idea but as it is after midnight here and I am not in my Office It is not tested:

    macro DoEvery mS2Count, CurCount, SubName
      CurCount = millis()
      if CurCount >= mSCount then
        CurCount = 0
        Call SubName
      end if
    end Macro
    

    This is an example of how I would envisage it being used:

    '
    ' example of DoEvery
    '
    #Chip 'mychip'
    #Include <millis.h>
    #Define MyLED PortC.4
    Do
    
      DoEvery 250, LEDTime, LEDTgl()   Flash LED 
    
    loop
    
    sub LEDTgl()
      MYLED = ~MYLED
    end sub
    

    It is not an interrupt so it would have to be polled in the main loop as shown but it should meet most needs.
    I will test it in the morning and if it works I may expand on the idea and include it in the millis library.

     
  • Chris Roper

    Chris Roper - 2020-06-05

    I just had a thought of how it could be done as an actual timer interrupt.

    I could build it into the existing millis interrupt so that no additional timer is needed and use #define to conditionally include code, that way no code is generated or memory used if no DoEvery events are set.

    From the user perspective it would look something like this:

    #include <millis.h>
    #define DoEvery1 20,  MySubCall()
    #define DoEvery2 250, LEDTgl(MyLED)
    

    There would be nothing in the main loop but the user program would obviously have to define the target functions, in this case:

      Sub MySubCall()
      Macro LEDTgl(MyLED)
    

    An interesting concept Stan, and well worth a bit more research on my part.
    Time to go and sleep on it.

    Cheers
    Chris

     

    Last edit: Chris Roper 2020-06-05
    • stan cartwright

      stan cartwright - 2020-06-06

      I looked up every command and it was in locomotive basic used on amstrad z80 machines.
      I'm thinking if you #include <millis> it starts and runs even if you don't use millis() in the program.
      A command like every 20 subname and the millis would every 20ms store the program counter, jump to the named sub then at the end sub restore the program counter... I will look up if there is a program counter or how interrupts work at hardware level.</millis>

      Quote from locomotive basic command guide:-
      BASIC branches to the subroutine at line ln EVERY (reccuring) i/50 seconds. (see also "AFTER i[,t] GOSUB line")
      There are 4 delay timers from 0 to 3 which can be specified with ‹timer number›. If omitted ‹timer number› defaults to 0.
      In the case of parallel task has 3 the highest and 0 the lowest priority.
      With DI or EI you can disable or enable the timing interrupt. With REMAIN <timer number=""> you can also disable an AFTER or EVERY construct and stores the "remaining" time (> REMAIN)
      Interrupts run as long as the main loop / program runs, even the main programm is paused > press ESC only once not twice for a break.
      It is important to know or realise that low-priority-interrupts which occurs simultanously to higher-priority-interrupts are not lost. Their task remains or handled again after finishing the higher-prio interrupt.
      10 REM > interrupts
      20 EVERY 50,0 GOSUB 100: REM > lowest priority
      30 EVERY 100,1 GOSUB 200
      40 EVERY 200,2 GOSUB 300:
      50 AFTER 1000,3 GOSUB 400: REM > highest priority
      60 WHILE flag=0
      70 a=a+1:print a
      80 WEND
      90 END
      100 REM #0
      110 PEN 2:PRINT "timer 0":PEN 1
      120 RETURN
      200 REM #1
      210 PEN 2:PRINT "timer 1":PEN 1
      220 RETURN
      300 REM #2
      310 PEN 2:PRINT "timer 2":PEN 1
      320 RETURN
      400 REM #3
      410 flag=1:PEN 2:PRINT "no more interrupts..."
      420 RETURN
      Hint: Timing with interrupts is important, especially if more than one interrupts run. If the interval of a subroutine driven by an interrupt is too long than the processor can never get back to deal the main program again. Work out timing by measuring the subroutine or by trial and error.
      There are system internal interrupts (highest level) which cannot be influenced by BASIC interrupts (e.g. keyboard scan > BREAK key.)
      The next level of sytem internal interrupts CAN be influenced by BASIC interrupts. For example the sound queue which will be created by "ON SQ <chanel> GOSUB <line>". Those sound interrupts have an independent time tricker but their priority is parallel to the second priority times of BASICs interrupts. Therefore interrupts with timer 3 could "interrupt" them.</line></chanel></timer>

       
  • stan cartwright

    stan cartwright - 2020-06-06

    http://iamtechnical.com/program-counter-and-program-rom-space-pic
    Thinking..the program counter would be in the millis.h not the main program which is what would be needed. Like a normal interrupt does.
    I don't know how millis.h would know where in the main program the every occurred.
    edit- if in the millis.h interrupt a gosub in main program could be called then it would return to the millis.h then that would what?? I have not a clue about this.
    Interrupts need an update in gcb help. so many different chips. avr is different to pic.
    reference to calculators that are for other basics or c.
    interrupts are cool when you get them to work...like a robot I'm building and it uses stepper motors for wheels and the interrupt sends the rotating drive pattern to the motors with speed as every so many interrupts
    so many uses...rc type servos need refreshing every 20ms

     

    Last edit: stan cartwright 2020-06-06
  • Chris Roper

    Chris Roper - 2020-06-06

    Thanks Stan,

    It looks like I was on the correct track then.
    We don't have all of the resources of a Z80 unfortunately, and the code needs to execute on quite a few different devices including both PIC and AVR but still the syntax I chose is similar to what you posted above.

    Here is a working test program using a tested first draft of a new “millis.h”:

    #Chip 16f18855, 32
    #option Explicit
    #include "millis.h"
    Init_MsCtr_Int
    
    #define MyLED1 PortA.0
    #define MyLED2 PortA.1
    Dir MyLED1 Out
    Dir MyLED2 Out
    
    #define DoEvery1 (250, BitTgl(MyLED1)) ' Flash LED1 at a rate of 250 mS
    #define DoEvery2 (175, BitTgl(MyLED2)) ' Flash LED2 at a rate of 175 mS
    
      Do
        ' Main loop is empty
      Loop
    
    End
    
    Macro BitTgl(BitAdr)
      BitAdr = !BitAdr
    end Macro
    

    The above flashes two LED’s on the Xpress Board at different rates and independent of the main loop. In fact the main loop is empty and only exists to prevent the Device going to sleep.

    I think it is close to your initial description and as a proof of concept I am happy with the result.
    I will have a look now at the documentation you posted to see what needs adding or changing to suit.

    Cheers
    Chris

     

    Last edit: Chris Roper 2020-06-06
  • stan cartwright

    stan cartwright - 2020-06-06

    Brill,I'll check it out. What is asm ShowDebug Call_SetTimer_Millis_macro ???
    ie asm showdebug.
    It is in millis.h and don't know what it does. Is it documented in help?ie is it a script or macro thing?

    will this work ie syntax?

    #chip mega328p,16
    #option explicit
    #include <uno_mega328p.h >
    #include "millis.h"
    Init_MsCtr_Int
    Dir digital_6 Out
    #define DoEvery1 (20, servo)
      Do
        ' Main loop is empty
      Loop
    End
    Macro servo
      set digital_6 on
      set digital_6 off
    end Macro
    
     

    Last edit: stan cartwright 2020-06-06
  • Chris Roper

    Chris Roper - 2020-06-06

    Rather don't poke around with that stuff Stan.

    ‘asm ShowDebug’ is not Documented in Help as it is not user facing code.
    It is part of the compiler and allows debug information to be displayed in the asm Listings.
    There are a lot of cryptic things including Scripts, Macros, raw ASM code and obscure compiler derivatives, they are there to allow for portability and differing Clock speeds etc.
    Even a simple change can cause a cascading error in that file so rather DO NOT ATTEMPT to edit it.

    When I have something ready to test I will post working code and a replacement millis.h.

    Cheers
    Chris

    edit:
    thanks for theArduino example code I will try it here on a simulaton or, if I can find it, an ARDUINO Mega, to see if it works as part of my testing

     

    Last edit: Chris Roper 2020-06-06
  • stan cartwright

    stan cartwright - 2020-06-06

    If I mess up experimenting...it is not unusual :) not broken forever...couldn't spell permenantly.
    I was just looking at adding your changes to a copy of millis but I guess I can wait...honest.
    the mega328p test was to scope if it was 50 Hz
    it would be
    Macro servo
    pulseout servopin,servopos
    end Macro
    where servopos would be 750 us to 2250 us which I know works as an interrupt..my first post but to find that...it's not in help or demos.
    don't break a leg. I wish I could help.
    ps there's a uno..and other pic, simulator posted on the forum called picsimlab which might not handle intterupts...or maybe does. Not used it much..I use breadboard
    cheers stan
    pps unos cheap as chips

     

    Last edit: stan cartwright 2020-06-06
    • Chris Roper

      Chris Roper - 2020-06-06

      It is just not ready Stan.

      My proof of concept is working but I am still trying to find a timing method that works for all supported architectures and minimises RAM use. At the moment, whilst I can get independent control of two LED's, when connected to a Frequency counter the signal timing is way off the mark.

      I have a lot more work to do before it is ready for you to test. If I give it to you as it is, it will probably let the smoke out of your Servo Motor.

      It is after midnight again so I will pack in for now and work on it again tomorrow.

      Sleeping on the problems often generates innovative solutions anyway. It certainly helped make the major breakthrough that I achieved this morning and greatly simplified syntax and User implementation.

      Cheers
      Chris

       
  • stan cartwright

    stan cartwright - 2020-06-06

    there's no fun in programming if you're feeling under pressure but you aren't. it's just a thought for gcb. surprise us one day!
    I got lots to do myself with like a h-bridge arrived today so to build a robot vehicle with v53l0x.
    had one of these bridges and they got inhibit pin you can apply pwm to,nice.

    thing is millis works so if an event is in code when compiled it would just set vars for the ifdef doevery time and sub. a check that it has reached the event time,goto sub,reset doevery time and count again until it reached the doevery time

    but to do that is probably not in help

     
  • Chris Roper

    Chris Roper - 2020-06-07

    Progress report - Timing is starting to look good and RAM footprint is reduced.

    I have all 4 channels running simultaneously on the Target board.
    Here is the Timing capture of DoEvery0, DoEvery1 and DoEvery2 .

    Do Every3 is running a Countable LED pulse that is too slow for the analyzer to capture.

    Here is the code, as you can see the syntax has changed slightly.

    #Chip 16f18855, 32
    #option Explicit
    #include "millis.h"
    
    #define MyLED0 PortA.0
    #define MyLED1 PortA.1
    #define MyLED2 PortA.2
    #define MyLED3 PortA.3
    Dir MyLED0 Out
    Dir MyLED1 Out
    Dir MyLED2 Out
    Dir MyLED3 Out
    
    #define DoEvery0  40, MyLED0 = !MyLED0
    #define DoEvery1  10, MyLED1 = !MyLED1
    #define DoEvery2  20, MyLED2 = !MyLED2
    #define DoEvery3 250, MyLED3 = !MyLED3
    
    Init_MsCtr_Int
    
      Do
        ' Main loop is empty
      Loop
    
    End
    

    Not bad for a morning's work, especially as I have not had my second cup of coffee.
    I still need to look at the Priority handling and code initialization but feel a lot more positive now.

    Cheers
    Chris

     
  • stan cartwright

    stan cartwright - 2020-06-07

    Brill work @Chris !
    In #define DoEvery0 40, MyLED0 = !MyLED0
    can MyLED0 = !MyLED0 still be a sub call?
    ie #define DoEvery0 40, sub mycode

     
    • Chris Roper

      Chris Roper - 2020-06-07

      Yes it can be a command, a subroutine call, a macro or a line of colon seperated code, the main thing though is that whatever is called is quick to execute as it is executing within the interrupt handler.

      I have spent most of the day learning Locomotive BASIC and in particular the Amstrad CPC464 Computer.

      The documentation is not very forthcoming on the internal workings but with a Simulator and z80 debugger/disassembler I am starting to see how they have implemented it and am quite far into reverse engineering their “Interrupt” implementation.

      The main consideration is that the Amstrad BASIC language guide is misleading in that it talks of Timers, Interrupts, Priorities etc almost implying they are hardware functions, but in reality they use a single system clock to drive 4 software timers and use a Software interrupt.

      Their tick rate is also strange, a period of 200 in the Always function is not, as I expected, 200 mS it is defined rather as 200 x 1/50th of one second. So it is 4 Seconds not 200 mS and would explain why they can use print statements in their examples.
      Something that I would never recommend in a hardware interrupt routine.

      More to come as I excavate this Rabbit hole - DoAlways will not be the only offshoot of this.

       
  • stan cartwright

    stan cartwright - 2020-06-07

    Errr....Wow!! I never thought you would bother with locomotive basic...good job I never said every is a unix command.
    The cpc every was every 20ms minimum in basic use from what I quoted.
    I had a 464 but never used every but did some asm and z80 was nice at the time.
    No hardware graphics but z80 had ldir which shifted memory fast. What sinclair should have been.
    Both used a ula and z80, cpc basic was better than sinclair. Nostalgia.

    When I first mentioned this idea I was thinking of just one event although the basic quote shows 3.
    As you said and it said in the quote, watch the sub time. Things like printing to a lcd could take too long. Other things like running servo motors that need a rotating pattern to rotate would be fast enough.

    I was asked to convert jim bowens bullseye from bbc basic to amstrad but the company wanted it in machine code which was daft as they were given the bbc code,graphics,sound.
    I did it and just looked it up and found this review which is honest...i took the money and ran. It has swearing in it sorry. https://www.youtube.com/watch?v=hMYI8kHtfmU

    the 464 was a bbc micro contender. I liked the z80 more than 6502.
    The bbc micro was for posh people...it had a rs232 port.

    You'll find systems with a ula are different to a bbc micro. The ula is the system not the cpu.

     

    Last edit: stan cartwright 2020-06-08
  • Chris Roper

    Chris Roper - 2020-06-08


    I needed to test the tape loader .......

     

    Last edit: Chris Roper 2020-06-08
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.