Thursday, July 25, 2019

Prepared to process telemetry downlink data from the Apollo Guidance Computer running Luminary 99


Apollo spacecraft stream telemetry information down to the ground as part of the Unified S-band radio link. Data is collected from sensors throughout the spacecraft, covering items like propellent quantity, EKG readings, and the state of various switches. A part of the data to be sent down comes from the Apollo Guidance Computer.

The circuitry that is sequencing the different data onto the downlink will poll the AGC for its data when the proper slot in the stream is reached. It does this by triggering a downlink start pulse, sending forty data sync pulses and then emitting a downlink stop pulse. The rate of polling is fifty times per second, with each set of data from the AGC taking a bit over 800 microseconds.

The AGC produces a master clock signal at 1MHz which is used to synchronize other spacecraft systems including the downlink controller which does the polling. The controller sends the pulses roughly once per 20 us with each pulse lasting about 4us.

After each downlink data sync pulse is received, the AGC either sends out a pulse to indicate a zero bit value or does nothing to indicate a one value. This pulse occurs a bit later than the data sync pulse but well within the 20 us alloted to each pulse.


This would be trivial to do in hardware, such as an FPGA or even discrete TTL logic, but I am already traveling for the demonstration tour and only have a spare Arduino Mega in my luggage. I therefore have to find a way to produce pulses of 4us, timed around 20us apart, with relationship to the 1MHz master clock timing

The approaches I used exploit parts of the ATMEL processor that are not normally accessed by Arduino programmers using the development environment, but this gives me the control over timing and low overhead that is essential to have the controller keep up with the demands. As a 16MHz system and with an interrupt typically taking about 16 instructions to process, the 1MHZ master clock from the AGC would keep the Arduino pegged at 100% without doing anything useful for me.

The overhead of the usual Arduino method of timing in microsecond ranges, the micros() call, has a resolution of 8 us which is too crude for our purposes. Too, the Arduino sets up a timer to keep track of micros and milliseconds - these take cycles and can shift the accuracy of outputs if you use these for timing.

The chip on the Mega 2560 has six timer/counters built in, with two of them able to be stepped by external pulses rather than the internal 16MHZ clock. I will wire up the AGC master clock to one of them (timer 5) and it will step at 1MHz rate and synchronized to the AGC.

Outputs that I emit based on the interrupts will occur about 1 us behind the actual clock. Since it takes a few instructions to set the output state, I will be lagging the timer change by something on the order of half a microsecond. To compensate for this, I will have the timer step based on the falling edge of the AGC master clock, which puts my delayed output very near the rising edge of the next pulse.

I chose three output pins that are on the same ATMEL port (PORTA) so that I can pass in a bit mask to the interrupt routine which will just OR or AND it with the PORT to flip the pin states. I can choose externally which of the three pulse types we are producing at any time. This keeps the instruction count in the interrupt routine down on the order of half a microsecond duration.

To detect whether the AGC has sent in a pulse, indicating 0 value, or did not, for a 1 value, I hooked that signal up to pin 2 which is wired to an interrupt routine that will fire on a rising edge. Thus, during the time that we are asking for a data bit (one of the forty data sync intervals of 20 us), I will latch in a flag if the pulse arrives from the AGC. The main routine, at the end of the 20 us period, looks at the latched flag to tell if the bit returned was 0 or 1.

A simple integer based state machine will move from idle through the 42 pulses to be sent. Its states are idle, start, sync1, sync2 . . . sync40, and stop. I set up the bit masks to use with PORTA based on whether I am in start, stop, or one of the sync states. At idle, I disable the timer so it doesn't interrupt until we begin the next round of forty bits for the downlink.

It is a simple matter to save the forty bits as they are detected and then write them out on a serial link over USB during the 20 milliseconds we wait before starting the state machine again. This gives us the 50 polls per second rate that the downlink controller would request.

Using external clocks, timer routines, rising edge interrupts and tight coding with direct port access is the key to making this task feasible on an Arduino. I finished the coding over the first couple of days of the trip and hoped to plug it into the AGC to begin testing.

Unfortunately, the pace was more hectic than we had imagined. It took almost two hours to set up for a demonstration, with assembly of panels, cabling and checkout. The demonstrations themselves were public and demanded all our attention. Teardown and packing began immediately after the demonstration time ended.

I never did get to cable the downlink system into the panel while we were running the AGC software. It will have to wait for a future session where we once again are running the computer.

No comments:

Post a Comment