Hello everyone. This is my first time programming in GCBASIC.
I built a digital frequency display for an old tube-based amateur radio transceiver, the Drake TR-4C. The hardware is controlled by firmware I wrote, but I am having trouble with the formatted frequency display.
The value is correct coming out of the frequency measurement and correction routines, but something goes wrong after executing the Str32() function. Str32() is used to convert the value of the FREQUENZA variable into the 10-character string variable FREQ_STRING.
The three attached photos show:
1-the correct value contained in the FREQUENZA variable;
2-the value displayed after executing FREQ_STRING = Str32(FREQUENZA);
3-the resulting corrupted formatted value.
Does anyone have any idea why this is happening?
I initially used a PIC16F648 and, thinking I might be hitting RAM limits, I migrated the project to the higher-capacity PIC16F1847, but the result remained exactly the same.
The interesting point is that Str32() works correctly when used with constants, but produces this problem when the argument is the dynamically calculated Long variable FREQUENZA.
I also tried LongToString(FREQUENZA) as you suggested, but unfortunately it produces exactly the same incorrect result as Str32(FREQUENZA).
I then performed some additional tests to try to isolate the problem.
FREQUENZA is correct when it comes out of the MISURA_FREQUENZA routine, and it is not altered by Str32() or by LongToString() at that point. IF_REALE is also correct, and both Print IF_REALE and Str32(IF_REALE) work correctly.
The problem appears when FREQUENZA is processed through CORREGGI_CALCOLA.
I tested this step by step. With the 10-meter (10C, 10B, 10A) and 15-meter correction routines active, everything still works. When the 40-meter routine is added, the error appears. Removing any one of those routines makes the error disappear again.
The same effect occurs with the PTO section: when enough conditional code and nested routine calls are added, the problem appears. This makes me wonder whether the problem may be related to the amount or structure of code generated by the compiler, rather than to the Str32() or LongToString() functions themselves.
I also added #option explicit as you suggested. The compiler then reported only one undeclared item: CMCON, which was simply a leftover from the previous PIC16F648 version during the migration to the PIC16F1847. I replaced it with the appropriate ANSELA configuration, and the program then compiled without any other #option explicit errors.
I hope these additional tests and the ASM/source code can help identify what is happening.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
After pulling the current version of string.h, Str32()/LongToString() now use a rewritten implementation (Do While SysValTemp > 0: Mod 10, /10 : Loop, reversing the digit string at the end) instead of the old chain of divisions by large constants (1,000,000,000 down to 10) through SYSDIVSUB32.
Compiles clean
Checked the generated .asm — FN_STR32 ( which is really LongToString) now only ever divides by the constant 10, so the old large-divisor path issue is no more
You still need to confirm on the actual board, but the compile-time evidence lines up with what I suspected.
The attachment goes in your C:\GCstudio\gcbasic\include\lowlevel folder.
I replaced string.h with the updated version you provided and recompiled the complete project. The code size decreased from about 41,9 % to 37,7%, so the new Str32()/LongToString() implementation is definitely being used. However, on the real 16F1847 target I still get exactly the same incorrect result.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok. Write me a test program. Just the essential code to show the bug. Hard code values as I do not have the sensors etc. Just enough code so I can run here.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I tried to reduce the program to a minimal test case, but the problem cannot be reproduced in the reduced version. Even with the simulated frequency calculation, the complete correction routines and the gestione_IF routine, LongToString() works correctly. The problem only appears in the full application.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I need to values that i can test against. I need to hard code some values.
Are there other values that need to be hard coded?
RAW_FREQUENCY = ????
FREQUENCY = ????
' =====================================================================
' FINAL FREQUENCY RECONSTRUCTION (DWORD / LONG)
' =====================================================================
FREQUENCY = TIMER1 ' Read 16-bit value via #define
TEMP_OV = OVERFLOWS * 65536 ' Sum accumulated overflows (65536 per full cycle)
FREQUENCY = FREQUENCY + TEMP_OV
FREQUENCY = (FREQUENCY * 125) / 10 ' Mathematical calculation based on gate and external prescaler /10
RAW_FREQUENCY = FREQUENCY
RAW_FREQUENCY =
FREQUENCY =
End Sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I can see that your test uses a changing FREQUENCY value, but it is not generated by the MISURA_FREQUENZA calculation. In my case, the problematic value is produced at runtime by the Timer1 measurement routine on RB6/T1CKI. FREQUENZA is built from TIMER1 and OVERFLOWS, then multiplied/divided before entering CORREGGI_CALCOLA. A directly assigned or otherwise externally changing FREQUENCY does not reproduce the fault on my PIC16F1847.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes, I agree; the problem isn't the STR32 function. The input signal is sinusoidal and is taken from the radio's mixer. Essentially, there is a VFO—which Drake calls a PTO—that generates a frequency; depending on the band switch position, this frequency is either added to or subtracted from the intermediate frequency (IF) value of 9,000,000 Hz. The PTO frequency ranges from 4,900,000 to 5,500,000 Hz. When the band switch is set to 80m, an optocoupler activates and pulls PIN_FOTO to logic low (zero); in this case, the software calculates FREQUENCY = 9,000,000 - PTO, resulting in a displayed frequency range of 3,500,000 to 4,100,000 Hz. For the 20m band, the optocoupler is off and PIN_FOTO goes to logic high (1); here, the software adds the IF to the PTO frequency, resulting in a displayed range of 13,900,000 to 14,500,000 Hz. For the other bands (15m, 40m, and 10m), local oscillators are used, from which both the PTO frequency and the intermediate frequency are subtracted. So, let's assume the radio is set to 80m and the frequency reading at Port B, Pin 6 is 5,100,000 Hz; the captured frequency value won't be exactly 5,100,000 Hz—it will differ slightly due to delays and so on. This captured value must first be corrected before being used in the calculation involving the intermediate frequency. And here the problem arises: if I read the FREQUENCY output from the frequency measurement routine, it is what I expect—for instance, if the input frequency at pin RB6 is 5,300,000, the value inside FREQUENCY is 5,301,600. This 1,600 Hz difference is subtracted when the signal enters the correggi_calcola (correct/calculate) routine, and then—depending on the value of PIN_FOTO—it is either subtracted from or added to the intermediate frequency. Therefore, the following calculation should take place inside the correggi_calcola routine:
9,000,000 - (5,301,600 - 1,600) = 3,700,000 Hz
However, the resulting value is 3,695,851 Hz. If I comment out the correction blocks (10a, 10b, and 10c) within the correggi_calcola routine, the frequency returns to the correct 3,700,000 Hz. I’ve gone into a bit of detail, but I had no other choice.
I forgot to mention that, naturally, the frequency taken from the radio isn't applied directly to pin 6 of Port B; instead, it is first passed through a J310 FET buffer, then a 74HC14 Schmitt trigger wave-shaper, and finally a divide-by-10 circuit—so an input frequency of 5,300,000 Hz enters the PIC at 530,000 Hz.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
TIMER1 is simply an alias for the 16-bit Timer1 value (TMR1H:TMR1L). I use #define TIMER1 = TMR1L.Word so that FREQUENZA = TIMER1 reads the complete 16-bit Timer1 counter value in one operation.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I followed your instructions: I removed #define TIMER1 = TMR1L.Word and corrected T1CON to T1CON = 0b10000101, but it still throws an error. The only thing left is to use ROTATE instead of TEMP_OV = OVERFLOWS * 65536, but I don't understand how to do that.
Could you show me the exact GCBASIC syntax you mean for replacing TEMP_OV = OVERFLOWS * 65536 with ROTATE?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
//! TEMP_OV = OVERFLOWS * 65536 ' Add accumulated overflows (65536 for each full cycle)TEMP_OV=OVERFLOWS' Widen a Long (0-extended) Repeat 16 '*65536=shiftleftdi16bit(piu'economicodiunamoltiplicazioneLong)SetCOffRotateTEMP_OVLeftEndRepeat
Last edit: Anobium 5 days ago
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Not related to the measurement routine but a bug found.
The 10a/10b/10c frequency windows overlap each other (37.5–37.6 MHz and 38.0–38.2 MHz are each claimed by two blocks). Since correggi_calcola uses independent Ifs rather than ElseIf, a raw reading in either overlap zone would run two correction subs back-to-back, subtracting IF_REALE twice and giving a badly wrong result. Worth tightening those boundaries (e.g. 37.6 exclusive lower bound on 10b) even though it's not what's hurting you right now.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello everyone. This is my first time programming in GCBASIC.
I built a digital frequency display for an old tube-based amateur radio transceiver, the Drake TR-4C. The hardware is controlled by firmware I wrote, but I am having trouble with the formatted frequency display.
The value is correct coming out of the frequency measurement and correction routines, but something goes wrong after executing the Str32() function. Str32() is used to convert the value of the FREQUENZA variable into the 10-character string variable FREQ_STRING.
The three attached photos show:
1-the correct value contained in the FREQUENZA variable;
2-the value displayed after executing FREQ_STRING = Str32(FREQUENZA);
3-the resulting corrupted formatted value.
Does anyone have any idea why this is happening?
I initially used a PIC16F648 and, thinking I might be hitting RAM limits, I migrated the project to the higher-capacity PIC16F1847, but the result remained exactly the same.
The interesting point is that Str32() works correctly when used with constants, but produces this problem when the argument is the dynamically calculated Long variable FREQUENZA.
Hello, We can resolve.
Before I make any guess, please share your ASM file generated. This will tell me lots about your setup/versions.
Anobium
Thank you very much for your interest and for taking the time to investigate this issue. I really appreciate your help.
Thank you. I know your build now and your setup
Can you post your code?
Certainly, here it is.
Please use LongToString() this may resolve. I will check tomorrow if we have updated that function.
You should add #option explicit to your program. This will highlight another issue. ♧
Follow-up test results
I also tried LongToString(FREQUENZA) as you suggested, but unfortunately it produces exactly the same incorrect result as Str32(FREQUENZA).
I then performed some additional tests to try to isolate the problem.
FREQUENZA is correct when it comes out of the MISURA_FREQUENZA routine, and it is not altered by Str32() or by LongToString() at that point. IF_REALE is also correct, and both Print IF_REALE and Str32(IF_REALE) work correctly.
The problem appears when FREQUENZA is processed through CORREGGI_CALCOLA.
I tested this step by step. With the 10-meter (10C, 10B, 10A) and 15-meter correction routines active, everything still works. When the 40-meter routine is added, the error appears. Removing any one of those routines makes the error disappear again.
The same effect occurs with the PTO section: when enough conditional code and nested routine calls are added, the problem appears. This makes me wonder whether the problem may be related to the amount or structure of code generated by the compiler, rather than to the Str32() or LongToString() functions themselves.
I also added #option explicit as you suggested. The compiler then reported only one undeclared item: CMCON, which was simply a leftover from the previous PIC16F648 version during the migration to the PIC16F1847. I replaced it with the appropriate ANSELA configuration, and the program then compiled without any other #option explicit errors.
I hope these additional tests and the ASM/source code can help identify what is happening.
Update: should be is resolved.
After pulling the current version of string.h, Str32()/LongToString() now use a rewritten implementation (Do While SysValTemp > 0: Mod 10, /10 : Loop, reversing the digit string at the end) instead of the old chain of divisions by large constants (1,000,000,000 down to 10) through SYSDIVSUB32.
You still need to confirm on the actual board, but the compile-time evidence lines up with what I suspected.
The attachment goes in your C:\GCstudio\gcbasic\include\lowlevel folder.
Last edit: Anobium 6 days ago
and, amazing really. Two you with the same issue within a few days.
See https://sourceforge.net/p/gcbasic/discussion/629990/thread/9e3d0e8410/?limit=250#dbae
I replaced string.h with the updated version you provided and recompiled the complete project. The code size decreased from about 41,9 % to 37,7%, so the new Str32()/LongToString() implementation is definitely being used. However, on the real 16F1847 target I still get exactly the same incorrect result.
Ok. Write me a test program. Just the essential code to show the bug. Hard code values as I do not have the sensors etc. Just enough code so I can run here.
I tried to reduce the program to a minimal test case, but the problem cannot be reproduced in the reduced version. Even with the simulated frequency calculation, the complete correction routines and the gestione_IF routine, LongToString() works correctly. The problem only appears in the full application.
I need to values that i can test against. I need to hard code some values.
Are there other values that need to be hard coded?
' =====================================================================
' FINAL FREQUENCY RECONSTRUCTION (DWORD / LONG)
' =====================================================================
FREQUENCY = TIMER1 ' Read 16-bit value via #define
TEMP_OV = OVERFLOWS * 65536 ' Sum accumulated overflows (65536 per full cycle)
FREQUENCY = FREQUENCY + TEMP_OV
FREQUENCY = (FREQUENCY * 125) / 10 ' Mathematical calculation based on gate and external prescaler /10
RAW_FREQUENCY = FREQUENCY
RAW_FREQUENCY =
FREQUENCY =
End Sub
I hard code
FREQUENCY = 4900002and I getWhat should I get?
Last edit: Anobium 6 days ago
Struggling to understand the issue here.
For a fixed FREQUENCY the number is calculated as 4101473 and the String of that is "4101473" and that on the LCD.
Info put out via Serial port.
Num: 4101473
Str: 4101473
Num: 4101473
Str: 4101473
And, see https://1drv.ms/v/c/2f87ffe77f3dbec7/IQDYt32KK5PlQ442tDSw5J8kAf0igCKPhFlXcB_IQ4IXrHs?e=avO9MU
Last edit: Anobium 6 days ago
I can see that your test uses a changing FREQUENCY value, but it is not generated by the MISURA_FREQUENZA calculation. In my case, the problematic value is produced at runtime by the Timer1 measurement routine on RB6/T1CKI. FREQUENZA is built from TIMER1 and OVERFLOWS, then multiplied/divided before entering CORREGGI_CALCOLA. A directly assigned or otherwise externally changing FREQUENCY does not reproduce the fault on my PIC16F1847.
Would you agree this is not a LongToString issue?
What is the input signal signal frequency and type?
Yes, I agree; the problem isn't the STR32 function. The input signal is sinusoidal and is taken from the radio's mixer. Essentially, there is a VFO—which Drake calls a PTO—that generates a frequency; depending on the band switch position, this frequency is either added to or subtracted from the intermediate frequency (IF) value of 9,000,000 Hz. The PTO frequency ranges from 4,900,000 to 5,500,000 Hz. When the band switch is set to 80m, an optocoupler activates and pulls PIN_FOTO to logic low (zero); in this case, the software calculates FREQUENCY = 9,000,000 - PTO, resulting in a displayed frequency range of 3,500,000 to 4,100,000 Hz. For the 20m band, the optocoupler is off and PIN_FOTO goes to logic high (1); here, the software adds the IF to the PTO frequency, resulting in a displayed range of 13,900,000 to 14,500,000 Hz. For the other bands (15m, 40m, and 10m), local oscillators are used, from which both the PTO frequency and the intermediate frequency are subtracted. So, let's assume the radio is set to 80m and the frequency reading at Port B, Pin 6 is 5,100,000 Hz; the captured frequency value won't be exactly 5,100,000 Hz—it will differ slightly due to delays and so on. This captured value must first be corrected before being used in the calculation involving the intermediate frequency. And here the problem arises: if I read the FREQUENCY output from the frequency measurement routine, it is what I expect—for instance, if the input frequency at pin RB6 is 5,300,000, the value inside FREQUENCY is 5,301,600. This 1,600 Hz difference is subtracted when the signal enters the
correggi_calcola(correct/calculate) routine, and then—depending on the value of PIN_FOTO—it is either subtracted from or added to the intermediate frequency. Therefore, the following calculation should take place inside thecorreggi_calcolaroutine:9,000,000 - (5,301,600 - 1,600) = 3,700,000 Hz
However, the resulting value is 3,695,851 Hz. If I comment out the correction blocks (10a, 10b, and 10c) within the
correggi_calcolaroutine, the frequency returns to the correct 3,700,000 Hz. I’ve gone into a bit of detail, but I had no other choice.I forgot to mention that, naturally, the frequency taken from the radio isn't applied directly to pin 6 of Port B; instead, it is first passed through a J310 FET buffer, then a 74HC14 Schmitt trigger wave-shaper, and finally a divide-by-10 circuit—so an input frequency of 5,300,000 Hz enters the PIC at 530,000 Hz.
Thank you
However, what is
#define TIMER1 = TMR1L.Wordmeant to do?TIMER1 is simply an alias for the 16-bit Timer1 value (TMR1H:TMR1L). I use #define TIMER1 = TMR1L.Word so that FREQUENZA = TIMER1 reads the complete 16-bit Timer1 counter value in one operation.
#define TIMER1 = TMR1L.Worddoes not do that. I am surprised it compiled. Remove it.TIMER1 is already an alias to TMR1H and TMR1L. See the Help.
The issue must lay in the measure_frequency() method.
Examine it carefully.
Replace TEMP_OV = OVERFLOWS * 65536 with a ROTATE it will be a lot faster.
I would look very carefully at T1CON.
All I can do for today.
Evan
I followed your instructions: I removed
#define TIMER1 = TMR1L.Wordand correctedT1CONtoT1CON = 0b10000101, but it still throws an error. The only thing left is to useROTATEinstead ofTEMP_OV = OVERFLOWS * 65536, but I don't understand how to do that.Could you show me the exact GCBASIC syntax you mean for replacing TEMP_OV = OVERFLOWS * 65536 with ROTATE?
What throws an error? A compiler message?
You must use #option explicit
Last edit: Anobium 5 days ago
Just look at the code again.
Not related to the measurement routine but a bug found.
The 10a/10b/10c frequency windows overlap each other (37.5–37.6 MHz and 38.0–38.2 MHz are each claimed by two blocks). Since correggi_calcola uses independent
Ifsrather thanElseIf, a raw reading in either overlap zone would run two correction subs back-to-back, subtracting IF_REALE twice and giving a badly wrong result. Worth tightening those boundaries (e.g. 37.6 exclusive lower bound on 10b) even though it's not what's hurting you right now.