Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Continuation from cog31s GPS issue.
Page 2 of 3 | |||||
Author | Message | ||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
thank. Yes it is a good idea to use your function for my relays. In this case, I have always same time for external pulse. |
||||
robert.rozee Guru Joined: 31/12/2012 Location: New ZealandPosts: 2290 |
the following piece of code may be helpful, it is adapted from something i wrote a while back: SetPin 26, inth, trimISR Do Print count, Str$(E,3,2), Str$(I,3,2),, trim, Time$, Timer Do: Loop Until flag flag = 0 ' comment out this line to consume computrons Loop trimISR: count = Timer Mod 1000 E = 500 - count I = ((I * 0.8) + (E * 0.2)) trim = Fix((E * 0.3) + (I * 0.7)) If trim < -31 Then trim = -31 If trim > 31 Then trim = 31 Option clocktrim trim flag = 1 IReturn wire up the 1pps output line from your GPS module to pin 26. after running for a few tens of seconds the micromite's internal timer functions will become synchronized to the 1pps pulse from the GPS module. you can then just read the value of timer in your main loop and take action on it. something like: do print "waiting" loop until button is pressed turn on relay and set t0%=timer do print timer-t0% if timer>(t0%+1800000) then turn off relay loop until relay is off cheers, rob :-) |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
uart_interrupt.zip |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
Hi Robert.rozee Thanks for your help. Your program is very interesting (I just try it) but not quite adapted to my needs. In fact I especially need my relay to switch to "00 sec" of the GPS and it displays the time immediately after (currently it displays the time with several hundreds of miiliseconds after), and finally that it fall back the relay after 20ms. Peter's function is excellent for that. however, I keep your idea and try to understand it so that I can use it for another application that I have in mind. |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3661 |
How does that deal with the issues raised? Is it the code used by MMBasic? John |
||||
panky Guru Joined: 02/10/2012 Location: AustraliaPosts: 1095 |
Regarding the interrupt timing, I ran the following code on a 170 and fed characters into it from a terminal. The delay between the end of the stop bit and the Rx interrupt service routine activity starting was around 80uS - it varied a little by 5uS or so and this is because there is no way of determining EXACTLY where in the do/loop sequence the interrupt occurs. This is exactly in line with what you would expect as each MMBasic line interpretted takes on average 30uS so the jump to the interrupt service routine then get the character with INPUT then pulse the pin ~ jump time + 30uS + 30us. If you omit the INPUT statement, the lag is less than 10uS between the end of the stop bit in the received character and the leading edge of the pulse This is absolutely repeatable so any delays in servicing an interrupt are solely due to what other activities the 170/MMBasic is trying to do at the time the interrupt occurs. Looking at the interrupt priority order, only higher priorities will break into the processing of the COM interrupt service routine. SETPIN 18,DOUT PIN(18) = 0 OPEN "COM1:9600,512,COM_Int" AS #1 DO LOOP SUB COM_Int A$ = INPUT$(1,#1) ' with this statement in, lag is roughly 80uS PIN(18) = 1 ' - with it out, lag is less than 10uS PIN(18) = 0 END SUB panky ... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it! |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
Hi Panky very good job! thanks! my problem is that I receive 470 to 500 bytes each second. And I must do something with this byte (not only read). Minimum to do is to store, and after that, background tasks can work with frames stored in asynchronuis time, they have time to do that. In industrial realtime process it work (very well) like that (see modbus protocol with 128 byte max for each frame) my minmal subroutine sub spcomrec4 Local tx$ As string 'length 3 Local i1 As integer Local i2 As integer Local a$ As string length 1 local vai as integer i1=Loc(#2) if i1=0 then exit sub else tx$=Input$(i1,#2) For i2=1 To i1 a$=Mid$(tx$,i2,1) vai=asc(a$) if a$="$" then ptWrite=ptWrite+1 if ptWrite>cnbbuf then ptWrite=1 tmbuf(ptWrite)="" flgtmbuf(ptWrite)=1 end if if vai=10 then flgtmbuf(ptWrite)=2 else if vai>31 then tmbuf(ptWrite)=tmbuf(ptWrite)+a$ end if next i2 end if end sub if time to execute 1 line basic, is 30us, I don't understand. You can see that in recept, I have just to know where are begin and end of frame. It mean that for first byte, I "use" 18 lines (18*30=540us) each millisec, for last byte i "use" 12 lines (13*30=360us) each millisec, and for all others byte I "use" 240us (8*30us) each millisec . It mean that during reception of all frames, I have 50% to 75% time free to continue my others tasks. In this case, why main loop is executed in 600ms?? remenber that in realtime, execution time of 2 tasks is not an simple time addition of each, but it depend of free time given by most priority task. If main loop task execute routine in 100ms and priority task use 50% of CPU time, that mean that main prog is executed in 200ms, if priority task use 10%, main task execut in 110ms. In my case com sub give (max) 50% free time. it mean that my main loop must be executed in 100ms when i receiv frames, and in 50ms when there is not frames. tomoroow I connect my scope, and I put pin relay at "on" in begin of routine com, and at "off" on exit sub, to know how many time I spend in my sub Edited 2019-10-10 12:29 by goc30 |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3661 |
Some thoughts: 1. each individual Local takes time that could be reduced by combining them (a sensible thing to do in time-critical code) 2. for testing I would check whether Loc(#2) is ever zero - it should not be! 3. for testing I would check whether Loc(#2) is ever more than one - it should not be! 4. however, coding for both is fair to include in a working system 5. even so, the code can be made faster by avoiding Mid$ - remove the tx$=Input$(i1,#2), remove a$=Mid$(tx$,i2,1) and replace it with a$=Input$(1,#2) 6. that means you do not need tx$ so can remove it completely and it will also speed up its Local 7. the code is not optimal for input of "$" - you could change tmbuf(ptWrite)="" to tmbuf(ptWrite)=a$ and add an exit sub 8. also, it is likely faster to change the if a$="$" then into if vai=36 then - but less readable and probably not important John Edited 2019-10-10 17:49 by JohnS |
||||
panky Guru Joined: 02/10/2012 Location: AustraliaPosts: 1095 |
Right on on the money John. Further to that, it might be worth considering using the long string cfunction - that way, you could set the interrupt to trigger at something like 470 characters or so (which is around a full frame of the 8 gps records), use the interrupt to just grab them into a long string and return, . Then you can analyse the complete stream in your main loop. panky. ... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it! |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3661 |
I think he's trying to do precision timing so that probably rules that out. It occurs to me that the string concatenation tmbuf(ptWrite)=tmbuf(ptWrite)+a$ may take a while. I don't know how long but the worst case (length 10 it seems) ought to be checked. John Edited 2019-10-10 20:03 by JohnS |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
hi John 1. each individual Local takes time that could be reduced by combining them (a sensible thing to do in time-critical code) 2. for testing I would check whether Loc(#2) is ever zero - it should not be! 3. for testing I would check whether Loc(#2) is ever more than one - it should not be! 4. however, coding for both is fair to include in a working system 5. even so, the code can be made faster by avoiding Mid$ - remove the tx$=Input$(i1,#2), remove a$=Mid$(tx$,i2,1) and replace it with a$=Input$(1,#2) 6. that means you do not need tx$ so can remove it completely and it will also speed up its Local 7. the code is not optimal for input of "$" - you could change tmbuf(ptWrite)="" to tmbuf(ptWrite)=a$ and add an exit sub 8. also, it is likely faster to change the if a$="$" then into if vai=36 then - but less readable and probably not important John the problem of the management of a gps is not in the most general case, but in the particular cases which do not have to leave the program on an error. (2) when we start the program, we have either a chain too long in the uart buffer (too much time between setup and the first interruption), or an incomplete string starting in the middle of a frame, or an incomprehensible string (frame error). (3-4-5-6) indeed this is the problem, why when receiving an interrupt "character in buffer" I have several characters and not one. In the case of the module that I put above, I have 3 or 4 characters in the buffer, from which the obligation of the $ tx and the loop of reading and storage. And if I'm just reading (without doing anything else), I sometimes have 2 characters in the buffer. (7). no it is not ideal, because in your solution, I would have to add a test to know if I treat the first character (which in your example, would already be in the buffer), and in this case, I do not add it, or not and there I add it, so 1 "if / then" for each character, to add (8), the conversion of the character to its ascii code is used twice (vai> 31, and vai = 10), so it is simpler and faster to convert it once at the reception, and to use the value already converted in the 2 tests, rather than converting each time. |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
hi panky . Then you can analyse the complete stream in your main loop. panky. "GPS" frames are not sames. It depend of: 1 - sat signal level: If you have no sat, frames are very shorts (max 50/70 bytes) 2 - if you have an complete news modules, you can receive more frames (gps and clonass, and galileo, and chines "gps") 3 - with best gps (and more expensives) modules GPs, you can change com speed, and, more important, you can say what type of frame you want to receive (ex just RMC frames and not others) it is for thoses reasons, that I must work byte by byte an frames by frames. After that I have time to process frames. I want to have only one subroutine who can process all of my app (who use gps signal) |
||||
robert.rozee Guru Joined: 31/12/2012 Location: New ZealandPosts: 2290 |
the fundamental problem seems to be that: 1. while the 1pps pulse is generated accurately on the second, 2. the NMEA data strings occur and are decoded some indeterminate time after this pulse. there is no way to tame this indeterminacy, as it arises from several different sources, none of which you can control - the GPS receiver, the MMbasic interpreter, the other hardware attached to the mx170. i feel you should be using the 1pps signal to obtain an accurate marker for the start of each second (one way being to trim the micromite millisecond timer using this pulse as shown earlier), and then - if you really do need to - use the NMEA string to obtain the H:M:S data. is it the case that you want to build several boxes that are synchronized? if so, you can combine the NMEA values for H:M:S with timer mod 1000 (for the milliseconds). this should allow you to obtain synchronization within +/-1ms between units as long as they have a good GPS time signal. cheers, rob :-) Edited 2019-10-10 22:41 by robert.rozee |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3661 |
To fetch any chars on program start, just call spcomrec4 as long as loc(#2) is not zero. I really would worry if you ever find after that the situations I mentioned (call with loc as zero or greater than one) for both mean you have a serious fault. Regardless, it makes sense to test if vai=36 rather than a$="$", combine the Locals and check the worst case string concatenation. If it still isn't fast enough then I suspect you have a problem in the rest of your code (maybe a higher priority interrupt taking too long) or you should do less work in spcomrec4. If you can make sure loc(#2) is only ever one in spcomrec4 (when used as an interrupt) you can then remove the FOR loop and simplify the code. The initial situation on program start where loc(#2) may be greater than one can then be a loop until it's zero. John |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
YESSSSS stop all!!!, I have found problem I send (with other mx170) 2 frames equals, first with 80* char "U", and second with 80* chr$(170). That make 1 frame with all hex$=55 and second frame with all hex=AA time between 2 frame is 10ms (pause(10)) and each 2 frames are send each second. my subroutine com first versus (sub 1) sub spcomrec4 pin(26)=1 Local tx$ As string 'length 3 Local i1 As integer Local i2 As integer Local a$ As string length 1 local vai as integer i1=Loc(#2) if i1=0 then print "error i1=";str$(i1) exit sub else tx$=Input$(i1,#2) nbcar=nbcar+i1 'print i1 'i1=number of char in receive buffer 'print tx$; end if pin(26)=0 end sub result time 0.233 nb char=166 <----- time 0.059 nb char=0 time 0.059 nb char=0 time 0.059 nb char=0 you can see that sometimes I spend in main loop more time than frame length time without frames is main loop time (59ms to 61ms) second versus (sub 2) Dim tx$ As string 'length 3 Dim i1 As integer Dim i2 As integer Dim a$ As string length 1 Dim vai as integer '..... main loop '...... sub spcomrec4 pin(26)=1 i1=Loc(#2) if i1=0 then print "error i1=";str$(i1) exit sub else tx$=Input$(i1,#2) nbcar=nbcar+i1 'print i1 'i1=number of char in receive buffer 'print tx$; end if pin(26)=0 end sub result time 0.061 nb char=16 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.102 nb char=166 <----- time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.065 nb char=11 <---- time 0.086 nb char=150 <---- time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.082 nb char=46 <---- time 0.069 nb char=115 <---- time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.097 nb char=80 <---- time 0.061 nb char=81 <---- you can see that in second case, it work very very well, (as i want) the difference between sub1 and sub2, I use "Locale" or "Dim" function it seem that local var are created each time subroutine is called, and this is too long (it may bee more than 1 ms) time without frames is main loop time (61ms) p.s: the test "if loc(2) =0" is necessary. i receive often, but this is an other probleme. time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.102 nb char=91 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 time 0.061 nb char=16 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.102 nb char=166 time 0.061 nb char=0 finally that mean that in interrupt or fast subroutine, never use "Local" vars thank to all for your help Edited 2019-10-11 18:10 by goc30 |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 8592 |
Geoff may correct me on this but if you really want maximum speed in the interrupt: Dimension the variables used in the interrupt at the very top of the main program. Use very short variable names, preferably different single letters. Avoid %, !, or $. Remove all non-mandatory spaces and all comments and blank lines from the interrupt Doing this will ensure the parser finds the variables as fast as possible in the interrupt. You can also investigate the use of STATIC variables in the interrupt which will be faster than LOCAL but not as fast as GLOBAL variables declared first. Edited 2019-10-12 00:35 by matherp |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
Hi peter Dimension the variables used in the interrupt at the very top of the main program. Use very short variable names, preferably different single letters. Avoid %, !, or $. good idea, I change my prog Remove all non-mandatory spaces and all comments and blank lines from the interrupt Doing this will ensure the parser finds the variables as fast as possible in the interrupt. I do that in final step, when prog is ok You can also investigate the use of STATIC variables in the interrupt which will be faster than LOCAL but not as fast as GLOBAL variables declared first. in interpreted basic, I don't understand the utility of "static" vars in subroutine. in compiled, I understant because vars are not initialized at each call and keep value, but in MMbasic, I think that is not possible |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
Hello all I come back with my gps problems. and of courses, a new problem my pb is false timing of "settick" function. I explain I have my uart interrupt (who work weel), and hardware interrupt (from gps module tick 1 sec). and I need an timer internal interrupt, for that , I use "SETTICK 10, sub1,1" instruction. if I close my com port (without interrupts), it work normally (100 call each seconde) if I use Com port in interrupt mode (to receive gps frames), sub1 work only 41 to 43 time each second and most important,some time it can take 600ms between 2 calls. my question is: can an tick interrupt be masked by other interrupt and in this case, interrupt is lost, or tick interrupt is buffered and when most priority interrupt is finish, tick interrupt is send to programm?? |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3661 |
time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.102 nb char=91 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 error i1=0 time 0.061 nb char=16 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.061 nb char=0 time 0.102 nb char=166 time 0.061 nb char=0 I think that error means something is wrong. Are you perhaps, due to going around your FOR loop, removing an extra character which has flagged an interrupt? I suspect so, i.e. by having the loop you then cause the error. John |
||||
goc30 Guru Joined: 12/04/2017 Location: FrancePosts: 425 |
I think that error means something is wrong. Are you perhaps, due to going around your FOR loop, removing an extra character which has flagged an interrupt? I suspect so, i.e. by having the loop you then cause the error. John uart interrupt is send when one (minimum) char is in buffer. if I receive interrupt and "loc(#n)" say there is no char, this is wrong!! my code sub spcomrec5 ai1=Loc(#2) if ai1=0 then print "error i1=";str$(ai1) exit sub else dtx$=Input$(ai1,#2) nbcar=nbcar+ai1 end if end sub ir give > run error i1=0 0.012 0.012 error i1=0 0.014 error i1=0 error i1=0 error i1=0 0.013 error i1=0 0.014 error i1=0 error i1=0 error i1=0 error i1=0 0.012 where is FOR loop ?? |
||||
Page 2 of 3 |
Print this page |