10 KiB
STM32 Astronomy & CORDIC Test Project
Introduction
This project is designed for STM32G4 microcontrollers (specifically the STM32G431) and provides a framework for:
- Astronomical coordinate transformations (Alt-Az vs HA-Dec, RA/HA, Local Sidereal Time).
- Atmospheric refraction modelling using a single-precision adaptation of SOFA/ERFA algorithms.
- Performance comparison between standard
math.hfunctions and the hardware-accelerated CORDIC unit built into the STM32G4. - Interactive control via a serial (UART) command interface.
- Precise timing measurements using a 32-bit timer.
All calculations are performed in single-precision floating-point for speed on microcontrollers without hardware double-precision support.
Hardware Platform
- MCU: STM32G431 (or any STM32G4 with CORDIC).
- Clock: HSE oscillator, system frequency defined by
SysFreq(usually 170 MHz). - GPIO:
- PC6 - LED (active high).
- PC13 - User button (pull-down, pressed = high).
- USART1:
- PA9 - TX (alternate function 7).
- PA10 - RX (alternate function 7).
- Timers:
- SysTick - 1-ms system tick (
Tms). - TIM2 - 32-bit counter running at 1-MHz for microsecond measurements.
- SysTick - 1-ms system tick (
Building and Flashing
The project is intended for use with GCC ARM toolchain. Key build definitions:
SysFreq- system clock frequency in Hz (e.g., 170000000).BUILD_NUMBERandBUILD_DATEare defined inversion.inc(generated bymake).
Flashing can be done via SWD using st-link (make flash), via DFU (make dfuboot) or via USART1 bootloader
(make boot).
Software Architecture
The system runs an infinite loop in main() that:
- Services the UART (receiving and sending data).
- Parses incoming commands via
parse_cmd(). - Blinks the LED every 500 ms.
- Detects button presses and measures press/release duration using TIM2.
Module Descriptions
1. hardware.c/h - Low-level initialisation
gpio_setup(): configures GPIOs, enables SysTick (1 ms interrupt), and initialises TIM2 for microsecond counting.- Provides macros for LED and key handling:
LED_ON(),LED_OFF(),LED_TOGG()KEY_PRESSED()- returns true if PC13 is high.
timer_start(),timer_stop(),timer_read()- control TIM2 for precise time measurements.
2. usart.c/h - UART1 with DMA and ring buffers
- Uses circular DMA for RX and normal DMA for TX.
- RX buffer size: 256 bytes (DMA) + 512 bytes (ring buffer).
- TX buffer size: 512 bytes (ring buffer) + 256 bytes (DMA).
- Interrupts:
- USART1 interrupt - detects end-of-line (
\n) and triggers line processing. - DMA1 Channel 1 (RX) - handles receive error (buffer overflow).
- DMA1 Channel 2 (TX) - signals transmit completion.
- USART1 interrupt - detects end-of-line (
- Functions:
usart_setup(uint32_t baud)- initialises UART at the given baud rate.usart_sendstr(const char*)- queues a string for transmission.usart_getline()- returns a pointer to a null-terminated buffer containing one line (ends with\n), orNULLif no complete line.usart_process()- must be called frequently to feed the TX buffer and move RX data from DMA to the ring buffer; returns status flags.
3. commproto.cpp - Command protocol
- Parses commands of the form:
command [args] [= value] - Built-in commands and variables (see Usage below).
- Uses a hash table (compile-time hashing) to dispatch commands efficiently.
- Supports getter and setter for floating-point variables (az, dec, ha, ra, zd, humid, press, temp).
- Command results are sent back via the UART send function.
- Error codes are defined in
commproto.h.
4. astro.c/h - Astronomical calculations
All angles are in degrees unless otherwise noted.
- Time:
MJD_from_unix(uint32_t t)- converts Unix time (seconds since 1970-01-01) to Modified Julian Date (MJD).LST_from_unix(uint32_t t)- computes Local Sidereal Time (in hours) for the observer's longitude (long_hrs).
- Coordinate transformations:
altaz_to_hadec()- convert Alt-Az to HA-Dec.hadec_to_altaz()- convert HA-Dec to Alt-Az.ha_to_ra()andra_to_ha()- convert between Hour Angle and Right Ascension given LST.
- Refraction (single-precision adaptation of ERFA
eraRefco):refco_f32(float P, float T, float RH, float wavelength, float *refa, float *refb)- computes A and B coefficients for the refraction model:
dz = A*tan(z) + B*tan(z)^3(z = zenith distance).refraction(float P, float T, float RH, float zd)- returns the refraction correction in degrees.
- The observer's latitude and longitude are fixed in the code (
lat_radandlong_hrs). They may be changed by editingastro.c.
5. cordic.c/h - Hardware CORDIC wrappers
- Interfaces with the STM32G4 CORDIC coprocessor.
- Functions:
cordic_sincos(float angle, float *sin, float *cos)- computes sine and cosine in one call.cordic_sin(float angle),cordic_cos(float angle)- individual functions.cordic_atan(float x)- returns atan(x), x in [-1,1].cordic_sqrt(float x)- returns sqrt(x) for x > 0.cordic_log(float x)- returns natural logarithm of x (x > 0).
- Precision: Q1.31 fixed-point (32-bit) with 5 iterations (
CORDIC_CSR_PRECISION = 5). - Input scaling and normalisation are handled inside each function.
6. strfunc.c/h - String utilities
- Number formatting:
u2str(),i2str(),uhex2str()- convert integers to strings.float2str(float x, uint8_t prec)- convert float to a compact string with optional scientific notation.
- Number parsing:
getnum(),getint(),getfloat()- parse numbers (decimal, hex, binary, signed, floating with exponent).
omit_spaces()- skip leading whitespace.
7. ringbuffer.c/h - Circular buffer
- Generic ring buffer for arbitrary data.
- Functions:
RB_write(),RB_read(),RB_readto()(read until a delimiter),RB_hasbyte(),RB_datalen(),RB_clearbuf().
8. test.c/h - Performance tests
- Runs a fixed number of iterations (
N_TESTS = 1000) on random data. - Measures execution time using TIM2 (microseconds).
- Tests available:
mathfunctions:sinf,cosf,atanf,sqrtf,logf.CORDICfunctions:sincos,sin,cos,atan,sqrt,log.- Astronomy tests:
- Coordinate transformations (Alt-Az vs HA-Dec) - measures time per conversion.
- Refraction cycle (ha-dec to alt-az, apply refraction and convert back) - includes
refraction(). - LST calculation - measures time per LST computation.
Usage: UART Commands
Connect to the USART1 (default baud rate 115200, 8N1) using a terminal program. The device echoes responses to commands.
General syntax:
command [args] [= value]
- Without
= value, the command acts as a getter (prints current value) or command that don't needs argument. - With
= value, it acts as a setter.
All floating-point values are printed with 7 decimal places.
Available Commands
| Command | Description |
|---|---|
help |
Show this help message. |
testtimer |
Test the microsecond timer for 1 second (prints elapsed us). |
testc = <func> |
Test CORDIC function: sincos, sin, cos, atan, sqrt, log. Prints time in us. |
testm = <func> |
Test math.h function: sin, cos, atan, sqrt, log. Prints time in us. |
sincos = <angle> |
Compute sin/cos for given angle (degrees) using both math.h and CORDIC, print results. |
testastro = <func> |
Test astronomy functions: coords (transform cycle), lst (LST calculation), refr (refraction cycle). Prints time in us and ms. |
sets [= 0/1] |
Choose sine/cos implementation: 0 = math.h, 1 = CORDIC. |
time [= unix_sec] |
Show current Unix time, MJD, and LST. If = unix_sec is given, sets the system time. |
az [= value] |
Azimuth (degrees, -180..180). |
dec [= value] |
Declination (degrees, -90..90). |
ha [= value] |
Hour Angle (degrees, -180..180). |
ra [= value] |
Right Ascension (degrees, 0..360). |
zd [= value] |
Zenith Distance (degrees, 0..90). |
humid [= value] |
Relative humidity (0..1). |
press [= value] |
Atmospheric pressure (hPa, 0..1200). |
temp [= value] |
Temperature (degC, -273.15..100). |
hara = 0/1 |
Convert HA to RA (0) or RA to HA (1) using current LST. Updates the corresponding variable. |
azhd = 0/1 |
Convert Alt-Az to HA-Dec (0) or HA-Dec to Alt-Az (1). Updates relevant variables (az, zd or ha, dec, ra). |
refr |
Compute refraction (arcseconds) for current zd, pressure, temperature, humidity. Also prints A/B coefficients. |
Note: The azhd and hara commands automatically use the current system time (from the last time setter) to compute LST.
Testing and Performance
The test commands (testc, testm, testastro) measure execution time over 1000 iterations on random input
data. This allows you to compare the speed of hardware CORDIC against software math.h and evaluate the
overall efficiency of the astronomical pipeline.
Example outputs (typical for STM32G4 @ 170 MHz):
testc = sincos
TIMEus=425
testm = sin
TIMEus=884
testastro = coords
TIMEus=159680
TIMEms=159
These numbers help in optimising real-time applications such as telescope control.
Notes and Customisation
- Observer coordinates: The latitude (43.6535278deg) and longitude (41.44143375deg) are hard-coded in
astro.caslat_radandlong_hrs. Modify these for your location. - CORDIC precision: The number of iterations is set to 5 (
CORDIC_CSR_DEF). You can increase it for better accuracy at the cost of speed. - Refraction model: The model works best for zenith distances up to ~80deg. It uses a wavelength of 0.55um (optical) by default.
- Baud rate: Default is 115200. Change the argument to
usart_setup()inmain()if needed. - DMA buffers: Sizes are defined in
usart.h. Adjust if you experience overruns.
License
This project is released under the GNU General Public License v3. See the header of each source file for details.