You can find the source code for the QRSS version of the controller firmware in two files:
You can use or modify this software as long as it's not for commercial use – there's a specific copyright rider in the controller.asm source file.
The source code is heavily commented and should be fairly clear with the following notes.
- If you compare the IO assignments in the software with the schematic in my last post, you will see that some of the IO has been moved around hardware wise. For example, the Modulation LED shown in the schematic as port C, bit 3 is Port B, bit 0 in the software. The hardware was changed after this software was written to accommodate new features (integrating the GPS in this case).
- There is no Heater LED shown in the schematic – it was originally controlled from Port C, bit 3 – shown as the new modulation LED in the schematic.
Source code overview
For simplicity, no interrupts are used in the QRSS controller code. All operation depends on the real time clock (Timer1) that runs from the 32.768 KHz clock – the timer divisor is set so that the clock overflows once every second.
Two code blocks control the operation of the software:
- mainloop – After initialization, the code executes this loop until the transmitter is enabled by setting TXInhibit (port A, bit 2) false. You can think of mainloop as the idle loop for the software.
During the "idle" the bulk of time is spent in Wait1Sec which is a procedure that waits until Timer1 overflows – once each second. When Wait1Sec returns, the heater control loop is called via HeatCtrl – this updates the control algorithm for the crystal oven heater – determining whether to turn the heater on or off and for how long. After this is completed, a check is made to see if TXInhibit has been removed – if it has, control returns to the top of mainloop.
- MEPT – this loop controls the transmitter, the state of the attenuator realys and invokes SENDID, the procedure which sends the QRSS modulation. SENDID returns 1 in the W register if transmission is interrupted by TXInhibit being asserted. After a successful transmission, output power is reduced by turning on one (or both) of the relays controlling the external attenuators and SENDID is called again. MEPT cycles through three different output power levels and continues to transmit until TXInhibit is asserted.
SENDID processes the packed modulation data that is stored in program memory as the ID table. SENDID determines whether the next symbol to send is a space, a dot or a dash. It sets two variables (sLen and modOn) to control the modulation. sLen is the length of the symbol in seconds and modOn controls whether to set the FSK modulation to a 1 or a 0.
SENDID spends most of its time in the code block Sloop – this calls Wait1Sec and HeatCtrl while it waiting for the next second to complete. TXInhibit is checked once each second and if asserted, causes SENDID to return with 1 in the W register to signal the interruption.
The longest section of code is HeatCL – the control loop that manages the heater control. This is the first generation of the control algorithm – it works but is messy. The C version in the WSPR version of the controller source code works a little better and is a lot cleaner! The changes I made really ought to be retro-fitted to the QRSS version but at this point, I keep the assembler version for posterity value – if I go back to pure QRSS, I'll re-implement the control software using interrupts and in C!