I am looking for help to update a specific functional area of the compiler.
Delays (time) at 31k clock frequency.
Currently, the compiler calculates the delays very well for a very wide range of frequencies. However, for 31k and other low frequencies the delays are not correct.
The task is to resolve make delay timings work as expected for these slower frequencies.
Additonal changes/fixes
There is always some overhead - the delay you set comes out as the delay+time required to set up the delay loop (using small delays and/or slow clock rates makes this quite significant).
There is a discontinuity when using WORD variables when 255-->256 as an extra loop is invoked.
Support for chip frequency switching. Add a compiler directive to support this.
Ping me if you have the time to help.
Evan
The tools and software is all available and I can help you create the development environment. All very simple.
Last edit: Anobium 2021-11-15
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Evan, if I can be of any help, I’m available.
At your disposal and among other things I have:
Siglent SDS 1202X-E Oscilloscope
Keysight Infiniivision 1052A unlocked Oscilloscope
Agilent 33120A Function Generator
Agilent 53181A Frequency Counter with a calibrated high stability rubidium reference
DSlogic Plus 16ch 400mhz Logic Analyzer
Cheap 8ch 25Mhz Logic Analyzer
Currently I have at hand PIC’s 18f45k50 and 18f4550; but I think that wouldn’t be suitable for your needs, if you tell me what is your target device I can start sourcing it.
Best regards.
Angel
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You have the same scope as I do. And with your other equipment should be more than able to do accurate measurements.
The Issue: Wait times are inaccurate at 31K System Clock ( PIC's)
Examples:
Wait 1 ms in source code will result in a measured wait of 2.7 ms
Wait 10 ms in source code will result in a measured wait of 15.48 ms
Wait 100ms in source code result in a measured wait of 143.20ms
To see how GCB handles waits you will need to look at source file ==>Preprocessor.bi
The relevant code begins at line 238
Here is some background info:
@ 31Khz System Clock((FOSC), .... 1 "Instruction Cycle" = 4 System Clock cycles
1 Instruction Cycle in Microseconds = 1 / ( .031 MHz * 4) = 129.0322 us
1 instruction cycle (~129us) is the shortest wait possible @31K
So microseconds waits are not really possible.
@31K Instructions per ms are 1000us/129us = 7.75 ( not an integer)
@31K Instructions per 100ms 100000/129us = = 7750
@31K Instructions per second are 1000000us/129us = 7,750
GCB generates wait code depending upon the values of "L" that can be seen in Line 244 . It tests for a positive integer. So no code will be generated for Wait_Us with ChipMhz = 31K .
Relevant Code seems to start in the ms section at line 321. This seems to do some tests to determine how best to generate the code. Whether to put some "nop's inline or to generate a loop or nested loop.
This section of code needs to be debugged to determine root cause of the wait time inaccuracy when 31K is used for ChipMHz. Example: #Chip 18F27Q43, 31K
With ms waits, we should theoretically be able to get a resolution of ~129us
Side Note:
GCB uses LFINTOSC as the clock source for 31K. The accuracy of this clock source is not perfect and can vary significantly from chip to chip. LFINTOSC cannot be calibrated or adjusted with OSCTUNE
My test chip, a Pic 18F27Q43 , measures 7.79572 KHz at the CLKOUT pin.
Actual speed = 7.79572 * 4 = 31.18288KHz
William
Last edit: William Roth 2021-10-29
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi William, thank you for your response, since yesterday, when I see your post, I started working. I have been able to setup my PIC’s in stock and reproduce the problem.
I’m using PIC 18F45K50 as DUT’s, I prepared 2 devices and 3 small codes
First device without crystal runs on:
RCINTOSC whit CLK Out 31.25khz [30.84678khz actual] (same as your LFINTOSC, as far as I know, both are resistor capacitor oscillators running close to 31.25khz that can’t be tuned whit OSCTUNE as you say)
HFINTOSC whit CLK Out 31.25khz [31.26592 actual] ( in this case my chip is able to divide by 512 the 16mhz frequency of this oscillator, not by the compiler alone but by register bits; it is better calibrated and can be tuned by OSCTUNE, also by the shape of the frequency over time curve, I suspect this is another resistor capacitor oscillator, but it have half of the standard deviation over time compared to RCINTOSC. I will explain later why I prepared and tested this mode.
Second device whit 20mhz crystal runs on:
High Speed Crystal 20mhz [20.00028mhz actual] (just as a baseline device to measure the delays whit a more stable frequency source and a higher speed when the bug doesn’t happen)
As operating frequencies are low, the execution of instructions have more impact in the delay timing, for this I put on purpose various pin changes and delays before the loop to be able of measure the time used in the loop in respect from the actual delay
Also, when testing I saw that the LFINTOSC isn’t very stable and at those lower frequencies of operation it impacts more the accuracy of the delay, by almost 3 orders of magnitude in comparison whit the crystal oscillator rig. This is why I prepared the second configuration whit the HFINTOSC and the divider (Obviously it does not affect the bug, it is only for a better methodology and to lower a little the uncertainty of the delay measurement.)
NOTE: For a simpler reading I will divide the information in two posts’, the following will be part of the methodology and information logged in the case of being of interest (so you can skip it at this time if you wish and go to the next post) and in the next post, my current questions.
All the following measures were tacked at a controlled ambient temp. of 23 degree Celsius.
I powered up the PIC for a warm up period of 30 min for stabilization of the oscillator before measure.
Measures of frequency and period made whit the frequency counter, all others made whit oscilloscope and logic analyzer.
Period of delay must be divided by 2, as the frequency counter measures the 1 and 0 full cycle.
Statistics data section displayed in Hertz and Seconds as in the chart.
Characterization of LFINTOSC:
210 samples
2500 samples
Characterization of HFINTOSC:
210 samples
2500 samples
Characterization of 20Mhz Xtal:
210 samples
2500 samples
Delay period and stability comparison (31khz LFINTOSC Top / 20mhz HS Crystal Bottom):
Comparison between possible delay whit loop and alone:
Data available in ccv format on attached zip file.
Ok, now I’m starting reading the code of preprocessor.bi
At first glance, I can see that at the micro seconds portion of code, you where accounting for the time needed for loops.
Line 302 – 306
'Need to delay for 10 us'L = number of cycles to waste' = cycles in 10 us, minus cycles at start and end of loop'3 cycles at end of loopL=10*ChipMhz \ 4-3
And in the milli seconds they aren’t.
Line 334 – 336
'Calculate required number of wasted cycles
ReqCycles = 1000 * ChipMhz / 4
BestDiff = ReqCycles
Take this as a grain of salt as I’m not yet familiarized whit the code. Another thing that I see, is that:
ReqCycles = 1000 * ChipMhz / 4
Will be 1000 * 0.031 / 4 = 7.75
Also you can see that the division operator are different in both parts of the code, I don’t know if this language treats it different like great cow basic do.
7.75 isn’t a integer and when tested in “If ThisTime < ReqCycles Then” we will probably need to round up to the closest number to the delay be the closest of 1ms as can be seen in the next screen capture of pulseview:
Every CLKOUT is 4 internal cycles and 1 instruction is 4 cycles so every full cycle on CLKOUT is 1 instruction, the closest instruction to the 1ms is the 8 cycle and it will give a delay around 1037us the closest we can get of 1ms at 31khz.
So. As you can see at this stage, I may be talking non sense 😊, I will need to test and familiarize more whit the code, and I have the following questions:
I suppose that this code is written on Free Basic, is that correct?
Maybe I need to create a dev env to start debugging and testing. Can I be pointed in the right direction?
Have a nice day.
Angel.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
What are the capabilities of 31k in the context of Great Cow BASIC. This is not a question of the accuracy of the internal clocks.
The issue seems to be the usage of 31k. Example... trying hardware USART will work at 300bps but other frequencies not - so, there is an accuracy issue when calculating delays.
So far I know the US timing calculations only work when the US delay / 4 is an integer result - therefore 4,8,12,16 etc. This is because the delay timing cycle needs to be an integer value to work.
I have ONLY examined basic USART operations and US delays - I have not looked beyond this. But, the usage constraints I found with US delays may/or may not be similar to other delay calculations.
31k
So, this is a question of how 31k works in the context of Great Cow BASIC. What works and what does not work and the rational.
This example above is a good example - the Help would read as the following:
waitnnUS
When operating at 31k to ensure accuracy of the wait the value of nn must be an integer result when divided by 4. As is 4,8,12,16 etc.
Yes, we can add masses of code to the compiler to create delays specific to the 31k (and the other related frequencies ( 31k/2, /4 /8 etc) but this surely not worth the efforts.
wait4US
I think we need to understand what works, and why.
@31K chipMhz the shortest delay is ~129us using instruction cycles , so I think "wait us" is not feasible at that Chip Frequency. Should only consider MS wait at 31Ks. However looking at the code in Preprocessor. bi, It always generates a 4 level nested loop, based upon the integer result of 7.5. This is 15 or 16 instructions when the Call and Return added in ... and we need only 7.
An algorithm should be doable with a 2 level loop where the remainder is added back in for non integer values . The math is somewhat complex but I am working on it. We have to allow 3 instructions per loop as well as the instructions for the call and return. It would have been nice if the code had been commented to explain the maths in preprocessor.bi lines 331- 359. But I think that section needs a do over or a separate section for ChipMhz < 1. That will cover ChipMhz .31 / .125 / .250/ and .500.
100 ms = 775 instructions
Each loop = 3 instructions
Example to get a 100 ms delay ....
repeat(775/3)Endrepeat
The resultant ASM has a 2 level loop because 775/3 is > 255
This is fairly accurate if placed inline. If we make it a sub it will be off by a few more instruction cycles.
Work in progress.
William
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
About the lines 331- 359 mentioned in your post, I was testing the values of BestD1 and BestD2 generated from the compiler that are the number of inner and outer loops. And at 31k the compiler always calculated it as D1=1 and D2=1 (the shortest delay possible by the actual loops) because the needed instruction cycles are always lower than 1 inner and 1 outer loops, then at line 421-465 the same thing happens when using 10ms, I think this was the reason for the inaccurate delays.
Greetings to both.
Angel
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Also, the number of cycles calculated by the compiler is 12 when BestD1=1 and BestD2=1, and the ReqCycles is correctly calculated at 8 (for every ms wait)
Cycles = 5 + BestD2 * (3 * BestD1 + 4)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello Evan and William, I have news, I modified the code from the preprocessor to work in the following manner:
When the chip is working below 1mhz the preprocessor doesn’t use the first loop of the wait code and calculates the value of BestD1 accordingly, this permits us to do 8 cycle loops (the minimum needed fort 31k) at 1mhz it calculates for BestD1 = 82 so is far away of the 255 max value.
And if the chip is working upwards from 1mhz the preprocessor returns to the normal operation whit both loops.
I tested the following speeds:
31khz
125khz^
250khz
500khz
1mhz
2mhz ^^
^125khz it’s the only tested frequency where the code doesn’t work, but I let the compiler do the adjustments for chip speed so I’m not certain if in reality the chip is operating at that speed, need to do a separate test for that speed.
^^Tested at 2mhz to verify the correct return to the normal operation
Notes:
Edited and compiled from commit r1284.
Added debug code to print Calculated cycles, Required Cycles, BestD1 and BestD2, this will be deleted at the end.
At lower speeds different from 31khz expect little inaccuracies from the differences of Calculated Cycles and Required Cycles (the preprocessor tries to do the best match)
If using 1 ms delay at 31khz like in the next example:
porta.0=1wait1msporta.0=0wait1msporta.0=1
The signal will look like if it was of 2 ms because of the clock cycles used for the port change instructions at higher waits it looks better (also remember that 8 instructions aren’t exactly 1ms but very close).
The preprocessor file right now is only modified at the Delay_ms.
I will attach the file, and copy the modified portion at the end of this post.
Please test and give me feedback and your thoughts.
I will test more, I hope it continues to work and that I have not only been falsely excited.
Best regards.
Angel
'Delay_MS 'Repeat20(wait50)SBC+=1Subroutine(SBC)=NewSubroutine("Delay_MS")CurrPos=Subroutine(SBC)->CodeStartGetMetaData(CurrPos)->IsLabel=-1DimAsIntegerD1,D2,BestD1,BestD2,ThisTime,ReqCycles,DiffFromReq,BestDiffIfModePICThen'Cycles for code below: '1+(2+(2+Inner*3-1)*(Outer*3)-1)+Time*3'Calculate required number of wasted cycles ReqCycles = 1000 * ChipMhz / 4 BestDiff = ReqCycles 'FindbestvaluesfordelayForD1=1To255IfChipMhz>1thenForD2=1To255'Calc how long current D1, D2 values will give ThisTime = 5 + D2 * (3 * D1 + 4) 'ChecktoseehowcloseitistotherequireddelayIfThisTime<ReqCyclesThenDiffFromReq=ReqCycles-ThisTimeElseIfThisTime>ReqCyclesThenDiffFromReq=ThisTime-ReqCyclesEnd If'If it'sthebest,recordIfDiffFromReq<BestDiffThenBestD1=D1BestD2=D2BestDiff=DiffFromReqEnd IfNextelse'Calc how long current D1, values will give ThisTime = 5 + (3 * D1 ) 'ChecktoseehowcloseitistotherequireddelayIfThisTime<ReqCyclesThenDiffFromReq=ReqCycles-ThisTimeElseIfThisTime>ReqCyclesThenDiffFromReq=ThisTime-ReqCyclesEnd If'If it'sthebest,recordIfDiffFromReq<BestDiffThenBestD1=D1BestD2=0BestDiff=DiffFromReqEnd Ifend ifNextOuterLoop=Str(BestD2)InnerLoop=Str(BestD1)' Debug code starts If ChipMhz > 1 then print "Calccycles=" + Str(5 + BestD2 * (3 * BestD1 + 4)) else print "Calccycles=" + Str(5 + (3 * BestD1 )) end if print "ReqCycles=" + Str(ReqCycles) print "BestD1=" + Str(BestD1) print "BestD2=" + Str(BestD2) print "test#36"'DebugcodeendsCurrPos=LinkedListInsert(CurrPos," incf SysWaitTempMS_H, F")CurrPos=LinkedListInsert(CurrPos,"DMS_START")GetMetaData(CurrPos)->IsLabel=-1IfChipMhz>1thenCurrPos=LinkedListInsert(CurrPos,"DELAYTEMP2 = "+OuterLoop)CurrPos=LinkedListInsert(CurrPos,"DMS_OUTER")end ifGetMetaData(CurrPos)->IsLabel=-1CurrPos=LinkedListInsert(CurrPos,"DELAYTEMP = "+InnerLoop)CurrPos=LinkedListInsert(CurrPos,"DMS_INNER")GetMetaData(CurrPos)->IsLabel=-1CurrPos=LinkedListInsert(CurrPos," decfsz DELAYTEMP, F")CurrPos=LinkedListInsert(CurrPos," goto DMS_INNER")IfChipMhz>1thenCurrPos=LinkedListInsert(CurrPos," decfsz DELAYTEMP2, F")CurrPos=LinkedListInsert(CurrPos," goto DMS_OUTER")end ifCurrPos=LinkedListInsert(CurrPos," decfsz SysWaitTempMS, F")CurrPos=LinkedListInsert(CurrPos," goto DMS_START")CurrPos=LinkedListInsert(CurrPos," decfsz SysWaitTempMS_H, F")CurrPos=LinkedListInsert(CurrPos," goto DMS_START")
When testing can you a view on using the clock divider on the 31k/LFINTOSC clock source. At the moment we can set to 31k automatically, and, hopefully you have resolved the timing issues. This is a question 'if the user used NDIV clock divider on the 31k clock source - what is the impact on these timing issues?'
Evan
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Added one “Nop” line to the compiled ASM code when working below 1mhz to fine tune the timings.
Attached the modified preprocessor.bi and the PulseView capture file.
First thing first:
31k was tested whit LFINTOSC and HFINTOSC/Divider same performance on both, timings working good to me.
Today, all tests were done by manually selecting the divisor.
The PIC 18F45k50 doesn’t have a 125khz option in the HFINTOSC/Divider so this may be an error of the data file 18f45k50.dat on lines 28-29:
'This constant is exposed with only the first parameter (if more than one)IntOsc=48,32,24,16,8,4,2,1,0.5,0.25,0.125
From Datasheet:
that was the reason why yesterday it did not work well when selecting that speed.
The PulseView captures of this post corresponds to LFINTOSC @ 31k
255 ms Delay
200 ms Delay
100 ms Delay
50 ms Delay
25 ms Delay
20 ms Delay
10 ms Delay
2 ms Delay
1 ms Delay
As you can see, at 1ms and 2ms delays, there are present some instructions that precede the delay function (the preprocessor code only acounts for the delay function), this isn’t a problem at frequency’s greater than 31k, or longer delays.
Something worries me. ChipMhz > 1 why? Should the adaption only be applicable to 31k? My concern is that users who have existing code will be impacted by this change. Existing users may have specific timing using the existing time method and ChipMhz > 1 will impact them.
We can use ChipMhz > 1 but we need to consider the wider impact of changing other frequencies.
Your thoughts?
And, the source contains debug... remove?
Evan
Last edit: Anobium 2021-11-13
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Angel - I have tested on a Q43. I am getting the same results (therefore the same error rate). The objective here was to get the timing to be presentative of the required timing - you have achieved this. Users we have to be careful at 31k as each chip will have very different results in terms of these delays.
This is a huge improvement.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
[ChipData]';All items in the ChipData section are available to user programs as constants';The constants have the prefix of Chip: See the examples below'31kSupport is exposed as Chip31Kconfig, Chip31Kregister, Chip31KValue31kSupport=INTOSCIO,OSCCON,2.....
You are right; when I first start to reproduce the bug, I noted that the delays don’t work at 31k and at 125k. I was partially wrong (because the PIC dint run at 125k in the first place), then when I read the William post whit the following text:
An algorithm should be doable with a 2 level loop where the remainder is added back in for non integer values . The math is somewhat complex but I am working on it. We have to allow 3 instructions per loop as well as the instructions for the call and return. It would have been nice if the code had been commented to explain the maths in preprocessor.bi lines 331- 359. But I think that section needs a do over or a separate section for ChipMhz < 1. That will cover ChipMhz .31 / .125 / .250/ and .500.
It sounded logical to me too, to use the code for frequency’s below 1mhz.
Today, I changed the config of the test GCB code to use an external clock input, programmed my Function Generator to produce a 0 to +5v square wave signal to use as the clock signal for the PIC, and started compiling code back and forth in the modified compiler and the untouched version of the compiler to find at what frequency the code is needed.
Long story short: we need the modified code below 96khz, up from there and the original code works well, below from that and the original code starts to show the bug.
I changed the switch frequency in the preprocessor.bi
Also remember that the modified code will not work below 28khz
Yes, that part is going to be removed when finished, now it also helps you out to compare the needed cycles vs the function cycles at different frequencies.
Also, I need to test the other delays 10MS, Sec, Min and Hour, I don’t know if those are dependent of ms delay, I’m going to check.
About: DAT file
I will modify it whit your code and test.
Important:
Attached the updated preprocessor.bi whit the changed switch frecuency to 96khz
I tested the 10ms, 1s and 1m delays and I see acceptable results for the capabilities of the controller at 31khz (just less than half second error at 1 minute), I deleted the debug code. So, I think that you should good to go.
Also, I tested the mod to the DAT file and it worked flawlessly.
Attached final preprocessor.bi without debug code.
Can you review/edit the change 1050 (row 557) in the change log. Is this correct summary? Edit the EXCEL data please. If you cannot let me know and I will resolve for you.
@Angel - I have sent you the WRITE URL to the EXCEL change log.
THANK YOU!!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Resolved.
I am looking for help to update a specific functional area of the compiler.
Delays (time) at 31k clock frequency.
Currently, the compiler calculates the delays very well for a very wide range of frequencies. However, for 31k and other low frequencies the delays are not correct.
The task is to resolve make delay timings work as expected for these slower frequencies.
Additonal changes/fixes
There is always some overhead - the delay you set comes out as the delay+time required to set up the delay loop (using small delays and/or slow clock rates makes this quite significant).
There is a discontinuity when using WORD variables when 255-->256 as an extra loop is invoked.
Support for chip frequency switching. Add a compiler directive to support this.
Ping me if you have the time to help.
Evan
The tools and software is all available and I can help you create the development environment. All very simple.
Last edit: Anobium 2021-11-15
Hi Evan, if I can be of any help, I’m available.
At your disposal and among other things I have:
Siglent SDS 1202X-E Oscilloscope
Keysight Infiniivision 1052A unlocked Oscilloscope
Agilent 33120A Function Generator
Agilent 53181A Frequency Counter with a calibrated high stability rubidium reference
DSlogic Plus 16ch 400mhz Logic Analyzer
Cheap 8ch 25Mhz Logic Analyzer
Currently I have at hand PIC’s 18f45k50 and 18f4550; but I think that wouldn’t be suitable for your needs, if you tell me what is your target device I can start sourcing it.
Best regards.
Angel
Hi Angel,
Evan is a bit busy, so I will reply.
You have the same scope as I do. And with your other equipment should be more than able to do accurate measurements.
The Issue: Wait times are inaccurate at 31K System Clock ( PIC's)
Examples:
Wait 1 ms in source code will result in a measured wait of 2.7 ms
Wait 10 ms in source code will result in a measured wait of 15.48 ms
Wait 100ms in source code result in a measured wait of 143.20ms
To see how GCB handles waits you will need to look at source file ==>Preprocessor.bi
The relevant code begins at line 238
Here is some background info:
@ 31Khz System Clock((FOSC), .... 1 "Instruction Cycle" = 4 System Clock cycles
1 Instruction Cycle in Microseconds = 1 / ( .031 MHz * 4) = 129.0322 us
1 instruction cycle (~129us) is the shortest wait possible @31K
So microseconds waits are not really possible.
@31K Instructions per ms are 1000us/129us = 7.75 ( not an integer)
@31K Instructions per 100ms 100000/129us = = 7750
@31K Instructions per second are 1000000us/129us = 7,750
GCB generates wait code depending upon the values of "L" that can be seen in Line 244 . It tests for a positive integer. So no code will be generated for Wait_Us with ChipMhz = 31K .
Relevant Code seems to start in the ms section at line 321. This seems to do some tests to determine how best to generate the code. Whether to put some "nop's inline or to generate a loop or nested loop.
This section of code needs to be debugged to determine root cause of the wait time inaccuracy when 31K is used for ChipMHz. Example: #Chip 18F27Q43, 31K
With ms waits, we should theoretically be able to get a resolution of ~129us
Side Note:
GCB uses LFINTOSC as the clock source for 31K. The accuracy of this clock source is not perfect and can vary significantly from chip to chip. LFINTOSC cannot be calibrated or adjusted with OSCTUNE
My test chip, a Pic 18F27Q43 , measures 7.79572 KHz at the CLKOUT pin.
Actual speed = 7.79572 * 4 = 31.18288KHz
William
Last edit: William Roth 2021-10-29
Hi William, thank you for your response, since yesterday, when I see your post, I started working. I have been able to setup my PIC’s in stock and reproduce the problem.
I’m using PIC 18F45K50 as DUT’s, I prepared 2 devices and 3 small codes
First device without crystal runs on:
RCINTOSC whit CLK Out 31.25khz [30.84678khz actual] (same as your LFINTOSC, as far as I know, both are resistor capacitor oscillators running close to 31.25khz that can’t be tuned whit OSCTUNE as you say)
HFINTOSC whit CLK Out 31.25khz [31.26592 actual] ( in this case my chip is able to divide by 512 the 16mhz frequency of this oscillator, not by the compiler alone but by register bits; it is better calibrated and can be tuned by OSCTUNE, also by the shape of the frequency over time curve, I suspect this is another resistor capacitor oscillator, but it have half of the standard deviation over time compared to RCINTOSC. I will explain later why I prepared and tested this mode.
Second device whit 20mhz crystal runs on:
High Speed Crystal 20mhz [20.00028mhz actual] (just as a baseline device to measure the delays whit a more stable frequency source and a higher speed when the bug doesn’t happen)
The simple test code I’m using:
As operating frequencies are low, the execution of instructions have more impact in the delay timing, for this I put on purpose various pin changes and delays before the loop to be able of measure the time used in the loop in respect from the actual delay
Also, when testing I saw that the LFINTOSC isn’t very stable and at those lower frequencies of operation it impacts more the accuracy of the delay, by almost 3 orders of magnitude in comparison whit the crystal oscillator rig. This is why I prepared the second configuration whit the HFINTOSC and the divider (Obviously it does not affect the bug, it is only for a better methodology and to lower a little the uncertainty of the delay measurement.)
The 3 different config portions of the code:
NOTE: For a simpler reading I will divide the information in two posts’, the following will be part of the methodology and information logged in the case of being of interest (so you can skip it at this time if you wish and go to the next post) and in the next post, my current questions.
All the following measures were tacked at a controlled ambient temp. of 23 degree Celsius.
I powered up the PIC for a warm up period of 30 min for stabilization of the oscillator before measure.
Measures of frequency and period made whit the frequency counter, all others made whit oscilloscope and logic analyzer.
Period of delay must be divided by 2, as the frequency counter measures the 1 and 0 full cycle.
Statistics data section displayed in Hertz and Seconds as in the chart.
Characterization of LFINTOSC:


210 samples
2500 samples
Characterization of HFINTOSC:


210 samples
2500 samples
Characterization of 20Mhz Xtal:


210 samples
2500 samples
Delay period and stability comparison (31khz LFINTOSC Top / 20mhz HS Crystal Bottom):


Comparison between possible delay whit loop and alone:


Data available in ccv format on attached zip file.
As always, forget my bad English.
Angel.
Last edit: Angel Mier 2021-10-31
Ok, now I’m starting reading the code of preprocessor.bi
At first glance, I can see that at the micro seconds portion of code, you where accounting for the time needed for loops.
Line 302 – 306
And in the milli seconds they aren’t.
Line 334 – 336
Take this as a grain of salt as I’m not yet familiarized whit the code. Another thing that I see, is that:
ReqCycles = 1000 * ChipMhz / 4
Will be 1000 * 0.031 / 4 = 7.75
Also you can see that the division operator are different in both parts of the code, I don’t know if this language treats it different like great cow basic do.
7.75 isn’t a integer and when tested in “If ThisTime < ReqCycles Then” we will probably need to round up to the closest number to the delay be the closest of 1ms as can be seen in the next screen capture of pulseview:
Every CLKOUT is 4 internal cycles and 1 instruction is 4 cycles so every full cycle on CLKOUT is 1 instruction, the closest instruction to the 1ms is the 8 cycle and it will give a delay around 1037us the closest we can get of 1ms at 31khz.
So. As you can see at this stage, I may be talking non sense 😊, I will need to test and familiarize more whit the code, and I have the following questions:
I suppose that this code is written on Free Basic, is that correct?
Maybe I need to create a dev env to start debugging and testing. Can I be pointed in the right direction?
Have a nice day.
Angel.
Good to see you get started!
The question is...
What are the capabilities of 31k in the context of Great Cow BASIC. This is not a question of the accuracy of the internal clocks.
The issue seems to be the usage of 31k. Example... trying hardware USART will work at 300bps but other frequencies not - so, there is an accuracy issue when calculating delays.
So far I know the US timing calculations only work when the US delay / 4 is an integer result - therefore 4,8,12,16 etc. This is because the delay timing cycle needs to be an integer value to work.
I have ONLY examined basic USART operations and US delays - I have not looked beyond this. But, the usage constraints I found with US delays may/or may not be similar to other delay calculations.
31k
So, this is a question of how 31k works in the context of Great Cow BASIC. What works and what does not work and the rational.
This example above is a good example - the Help would read as the following:
When operating at 31k to ensure accuracy of the wait the value of nn must be an integer result when divided by 4. As is 4,8,12,16 etc.
Yes, we can add masses of code to the compiler to create delays specific to the 31k (and the other related frequencies ( 31k/2, /4 /8 etc) but this surely not worth the efforts.
I think we need to understand what works, and why.
Dev environment
Re a dev environment see, https://github.com/Anobium/Great-Cow-BASIC-Help/blob/master/source/DeveloperGuideForCompiler.adoc
Latest build
And, you MUST ensure you have the latest build. Very critical as I fixed the compiler a few days ago with respect to delay calc.
Evan
Last edit: Anobium 2021-10-31
@31K chipMhz the shortest delay is ~129us using instruction cycles , so I think "wait us" is not feasible at that Chip Frequency. Should only consider MS wait at 31Ks. However looking at the code in Preprocessor. bi, It always generates a 4 level nested loop, based upon the integer result of 7.5. This is 15 or 16 instructions when the Call and Return added in ... and we need only 7.
An algorithm should be doable with a 2 level loop where the remainder is added back in for non integer values . The math is somewhat complex but I am working on it. We have to allow 3 instructions per loop as well as the instructions for the call and return. It would have been nice if the code had been commented to explain the maths in preprocessor.bi lines 331- 359. But I think that section needs a do over or a separate section for ChipMhz < 1. That will cover ChipMhz .31 / .125 / .250/ and .500.
100 ms = 775 instructions
Each loop = 3 instructions
Example to get a 100 ms delay ....
The resultant ASM has a 2 level loop because 775/3 is > 255
This is fairly accurate if placed inline. If we make it a sub it will be off by a few more instruction cycles.
Work in progress.
William
I agree with your analysis. If you can code then I can port to the compiler.
About the lines 331- 359 mentioned in your post, I was testing the values of BestD1 and BestD2 generated from the compiler that are the number of inner and outer loops. And at 31k the compiler always calculated it as D1=1 and D2=1 (the shortest delay possible by the actual loops) because the needed instruction cycles are always lower than 1 inner and 1 outer loops, then at line 421-465 the same thing happens when using 10ms, I think this was the reason for the inaccurate delays.
Greetings to both.
Angel
Also, the number of cycles calculated by the compiler is 12 when BestD1=1 and BestD2=1, and the ReqCycles is correctly calculated at 8 (for every ms wait)
Cycles = 5 + BestD2 * (3 * BestD1 + 4)
Angel - agree.
If we can determine a method to sort this out - I can code it.
So, we will end up with the same ASM functions for these delays when at sub 1mhz freq ... easily done once we have the method.
Hello Evan and William, I have news, I modified the code from the preprocessor to work in the following manner:
When the chip is working below 1mhz the preprocessor doesn’t use the first loop of the wait code and calculates the value of BestD1 accordingly, this permits us to do 8 cycle loops (the minimum needed fort 31k) at 1mhz it calculates for BestD1 = 82 so is far away of the 255 max value.
And if the chip is working upwards from 1mhz the preprocessor returns to the normal operation whit both loops.
I tested the following speeds:
31khz
125khz^
250khz
500khz
1mhz
2mhz ^^
^125khz it’s the only tested frequency where the code doesn’t work, but I let the compiler do the adjustments for chip speed so I’m not certain if in reality the chip is operating at that speed, need to do a separate test for that speed.
^^Tested at 2mhz to verify the correct return to the normal operation
Notes:
Edited and compiled from commit r1284.
Added debug code to print Calculated cycles, Required Cycles, BestD1 and BestD2, this will be deleted at the end.
At lower speeds different from 31khz expect little inaccuracies from the differences of Calculated Cycles and Required Cycles (the preprocessor tries to do the best match)
If using 1 ms delay at 31khz like in the next example:
The signal will look like if it was of 2 ms because of the clock cycles used for the port change instructions at higher waits it looks better (also remember that 8 instructions aren’t exactly 1ms but very close).
The preprocessor file right now is only modified at the Delay_ms.
I will attach the file, and copy the modified portion at the end of this post.
Please test and give me feedback and your thoughts.
I will test more, I hope it continues to work and that I have not only been falsely excited.
Best regards.
Angel
Last edit: Angel Mier 2021-11-12
Example of ASM delay function compiled at normal (more than 1Mhz) operation:
Example of ASM delay function compiled at 1Mhz or lower operation:
The approach looks sound. Great work.
sting and let us know the result.
When testing can you a view on using the clock divider on the 31k/LFINTOSC clock source. At the moment we can set to 31k automatically, and, hopefully you have resolved the timing issues. This is a question 'if the user used NDIV clock divider on the 31k clock source - what is the impact on these timing issues?'
Evan
Ok, so, I did more tests today.
Important: updated preprocessor.bi
Added one “Nop” line to the compiled ASM code when working below 1mhz to fine tune the timings.
Attached the modified preprocessor.bi and the PulseView capture file.
First thing first:
31k was tested whit LFINTOSC and HFINTOSC/Divider same performance on both, timings working good to me.
Today, all tests were done by manually selecting the divisor.
The PIC 18F45k50 doesn’t have a 125khz option in the HFINTOSC/Divider so this may be an error of the data file 18f45k50.dat on lines 28-29:
From Datasheet:

that was the reason why yesterday it did not work well when selecting that speed.
The PulseView captures of this post corresponds to LFINTOSC @ 31k
255 ms Delay
200 ms Delay
100 ms Delay
50 ms Delay
25 ms Delay
20 ms Delay
10 ms Delay
2 ms Delay
1 ms Delay
As you can see, at 1ms and 2ms delays, there are present some instructions that precede the delay function (the preprocessor code only acounts for the delay function), this isn’t a problem at frequency’s greater than 31k, or longer delays.
ASM
5 cycles @ 2ms
5 cycles @ 1ms
1 ms Delay @ 250khz
Test GCB Code LFINTOSC @ 31k
Tested on:
31khz LFINTOSC
31khz HFINTOSC
250khz HFINTOSC
500khz HFINTOSC
1000khz HFINTOSC
2000khz HFINTOSC
Last edit: Angel Mier 2021-11-13
Looking good/great/smart!
Something worries me. ChipMhz > 1 why? Should the adaption only be applicable to 31k? My concern is that users who have existing code will be impacted by this change. Existing users may have specific timing using the existing time method and ChipMhz > 1 will impact them.
We can use ChipMhz > 1 but we need to consider the wider impact of changing other frequencies.
Your thoughts?
And, the source contains debug... remove?
Evan
Last edit: Anobium 2021-11-13
Angel - I have tested on a Q43. I am getting the same results (therefore the same error rate). The objective here was to get the timing to be presentative of the required timing - you have achieved this. Users we have to be careful at 31k as each chip will have very different results in terms of these delays.
This is a huge improvement.
Hi Angel,
Yes, the datafile is in error. .125MHz is not supported on K50 chips. However 31K is supported by K50 family chips, but not by the compiler.
We can easily correct the K50 datfiles to remove .125MHz , but will need to look at system.ini to see if 31K can be implemented for these chips.
But I see that you figured out like I did how to set 31K manually.
Good Work on the code. I will give it a go tomorrow.
William
Re K50 31k support.
Add the following to the DAT file in the ChipData section.
If this resolves then I need to update the .DAT file database for all the K50s. So, let me know if this works,
Tested change to DAT as follows - works correctly.
Please validate and I will update all the K50 chips.
Evan
DAT file.
ASM looks correct
Last edit: Anobium 2021-11-13
About: ChipMhz > 1
You are right; when I first start to reproduce the bug, I noted that the delays don’t work at 31k and at 125k. I was partially wrong (because the PIC dint run at 125k in the first place), then when I read the William post whit the following text:
It sounded logical to me too, to use the code for frequency’s below 1mhz.
Today, I changed the config of the test GCB code to use an external clock input, programmed my Function Generator to produce a 0 to +5v square wave signal to use as the clock signal for the PIC, and started compiling code back and forth in the modified compiler and the untouched version of the compiler to find at what frequency the code is needed.
Long story short: we need the modified code below 96khz, up from there and the original code works well, below from that and the original code starts to show the bug.
I changed the switch frequency in the preprocessor.bi
Also remember that the modified code will not work below 28khz
GCB code used to test whit external clock:
About: And, the source contains debug... remove?
Yes, that part is going to be removed when finished, now it also helps you out to compare the needed cycles vs the function cycles at different frequencies.
Also, I need to test the other delays 10MS, Sec, Min and Hour, I don’t know if those are dependent of ms delay, I’m going to check.
About: DAT file
I will modify it whit your code and test.
Important:
Attached the updated preprocessor.bi whit the changed switch frecuency to 96khz
Greetings to both.
Angel.
Very clear. Look forward to the test results. I got acceptable results here on the previous code.
When you are ready I will merge this code into the code repository and make a release,
:-)
I tested the 10ms, 1s and 1m delays and I see acceptable results for the capabilities of the controller at 31khz (just less than half second error at 1 minute), I deleted the debug code. So, I think that you should good to go.
Also, I tested the mod to the DAT file and it worked flawlessly.
Attached final preprocessor.bi without debug code.
Have a nice day.
Angel
Excellent.
Can you review/edit the change 1050 (row 557) in the change log. Is this correct summary? Edit the EXCEL data please. If you cannot let me know and I will resolve for you.
@Angel - I have sent you the WRITE URL to the EXCEL change log.
THANK YOU!!
Modified the Excel file. Also added the warnings in the “wait.adoc” help file, opened a pull request.
Text Added:
Angel