mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-08-14 20:19:35 +03:00
Compare commits
3 Commits
b8f3e5a695
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
811d8bda5d | ||
|
|
40d0605218 | ||
|
|
970d73dc38 |
13
G4:G431/CORDIC/Makefile
Normal file
13
G4:G431/CORDIC/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
BINARY := cordic
|
||||
PREFIX := /usr/bin/arm-none-eabi
|
||||
CFLAGS = -std=c23
|
||||
CPPFLAGS = -std=c++11
|
||||
# MCU code
|
||||
MCU := G431xx
|
||||
# change this linking script depending on particular MCU model,
|
||||
LDSCRIPT := stm32g431xb.ld
|
||||
LDLIBS += -lm
|
||||
|
||||
include ../makefile.g4
|
||||
include ../../makefile.stm32
|
||||
|
||||
204
G4:G431/CORDIC/astro.c
Normal file
204
G4:G431/CORDIC/astro.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "astro.h"
|
||||
#include "cordic.h"
|
||||
|
||||
static int sincosflag = 0; // math.h
|
||||
// longitude/latitude + in rad/hrs
|
||||
//static float longitude = 41.44143375f, latitude = 43.6535278f;
|
||||
static float lat_rad = 43.6535278f * M_PIf / 180.f;
|
||||
static float long_hrs = 41.44143375f / 15.f;
|
||||
|
||||
static void sincosf_m(float angle, float *s, float *c){
|
||||
if(s) *s = sin(angle);
|
||||
if(c) *c = cos(angle);
|
||||
}
|
||||
|
||||
static void (*sincosf)(float, float*, float*) = sincosf_m;
|
||||
|
||||
void set_sincos(int iscordic){
|
||||
if(iscordic) sincosf = cordic_sincos;
|
||||
else sincosf = sincosf_m;
|
||||
sincosflag = iscordic;
|
||||
}
|
||||
|
||||
int get_sincos(){ return sincosflag; }
|
||||
|
||||
/* Helper functions for angle normalization (single precision) */
|
||||
static float normalize_degrees(float angle){
|
||||
angle = fmodf(angle, 360.0f);
|
||||
if (angle < 0.0f) angle += 360.0f;
|
||||
return angle;
|
||||
}
|
||||
|
||||
static float normalize_hours(float hours){
|
||||
hours = fmodf(hours, 24.0f);
|
||||
if (hours < 0.0f) hours += 24.0f;
|
||||
return hours;
|
||||
}
|
||||
|
||||
/* 1. Compute Modified Julian Date from UNIX time (seconds since 1970-01-01 00:00:00 UTC) */
|
||||
float MJD_from_unix(uint32_t t){
|
||||
return 40587.f + (float)t / 86400.0f;
|
||||
}
|
||||
|
||||
float LST_from_unix(uint32_t t){
|
||||
uint32_t days = t / 86400;
|
||||
uint32_t sec = t % 86400;
|
||||
|
||||
float mjd_int = 40587.0f + (float)days;
|
||||
|
||||
float T = (mjd_int - 51544.5f) / 36525.0f, T2 = T*T, T3 = T2*T;
|
||||
float gmst0_sec = 24110.54841f + 8640184.812866f*T + 0.093104f*T2 - 6.2e-6f*T3;
|
||||
float ut1_sec = (float)sec * 1.00273790935f;
|
||||
float gmst_sec = gmst0_sec + ut1_sec;
|
||||
float lst_hours = gmst_sec / 3600.0f + long_hrs;
|
||||
return normalize_hours(lst_hours);
|
||||
}
|
||||
|
||||
/* 3. Convert Hour Angle (HA) to Right Ascension (RA) and vice versa.
|
||||
All angles in degrees. LST is Local Sidereal Time in degrees. */
|
||||
float ha_to_ra(float ha, float lst){
|
||||
float ra = lst - ha;
|
||||
return normalize_degrees(ra);
|
||||
}
|
||||
|
||||
float ra_to_ha(float ra, float lst){
|
||||
float ha = lst - ra;
|
||||
// Hour angle is usually in range [-180,180)
|
||||
ha = normalize_degrees(ha);
|
||||
if (ha > 180.0f) ha -= 360.0f;
|
||||
return ha;
|
||||
}
|
||||
|
||||
/* 4. Convert Altitude-Azimuth coordinates to Equatorial (Hour Angle, Declination)
|
||||
and back. All angles in degrees. Azimuth is measured from North through East. */
|
||||
void altaz_to_hadec(float alt_deg, float az_deg, float *ha_deg, float *dec_deg){
|
||||
float alt = alt_deg * M_PIf / 180.0f;
|
||||
float az = az_deg * M_PIf / 180.0f;
|
||||
|
||||
float sin_alt, cos_alt, sin_az, cos_az, sin_lat, cos_lat;
|
||||
sincosf(alt, &sin_alt, &cos_alt);
|
||||
sincosf(az, &sin_az, &cos_az);
|
||||
sincosf(lat_rad, &sin_lat, &cos_lat);
|
||||
|
||||
/* Declination */
|
||||
float sin_dec = sin_alt * sin_lat + cos_alt * cos_lat * cos_az;
|
||||
float dec = asinf(sin_dec);
|
||||
|
||||
/* Hour angle (using atan2f for sign determination) */
|
||||
float x = sin_alt * cos_lat - cos_alt * sin_lat * cos_az;
|
||||
float y = -cos_alt * sin_az;
|
||||
float ha = atan2f(y, x); // radians
|
||||
|
||||
*ha_deg = ha * 180.0f / M_PIf;
|
||||
*dec_deg = dec * 180.0f / M_PIf;
|
||||
}
|
||||
|
||||
void hadec_to_altaz(float ha_deg, float dec_deg, float *alt_deg, float *az_deg){
|
||||
float ha = ha_deg * M_PIf / 180.0f;
|
||||
float dec = dec_deg * M_PIf / 180.0f;
|
||||
|
||||
float sin_dec, cos_dec, sin_ha, cos_ha, sin_lat, cos_lat;
|
||||
sincosf(dec, &sin_dec, &cos_dec);
|
||||
sincosf(ha, &sin_ha, &cos_ha);
|
||||
sincosf(lat_rad, &sin_lat, &cos_lat);
|
||||
|
||||
/* Altitude */
|
||||
float sin_alt = sin_lat * sin_dec + cos_lat * cos_dec * cos_ha;
|
||||
float alt = asinf(sin_alt);
|
||||
|
||||
/* Azimuth (from North through East) */
|
||||
float x = sin_dec * cos_lat - cos_dec * sin_lat * cos_ha;
|
||||
float y = -cos_dec * sin_ha;
|
||||
float az = atan2f(y, x); // radians, [-π, π]
|
||||
|
||||
*alt_deg = alt * 180.0f / M_PIf;
|
||||
*az_deg = az * 180.0f / M_PIf;
|
||||
if (*az_deg < 0.0f) *az_deg += 360.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate refraction constants A and B for the model dZ = A*tan(Z) + B*tan^3(Z)
|
||||
*
|
||||
* This is a single-precision adaptation of the SOFA iauRefco / ERFA eraRefco function.
|
||||
* Optimized for microcontrollers without hardware double-precision support (e.g., STM32G431).
|
||||
*
|
||||
* @param phpa Pressure at the observer (hPa = mbar)
|
||||
* @param tc Ambient temperature at the observer (degrees C)
|
||||
* @param rh Relative humidity at the observer (range 0-1)
|
||||
* @param wl Wavelength (micrometers). Use 0.55 for optical, >100 for radio.
|
||||
* @param refa Output: tan(Z) coefficient (radians)
|
||||
* @param refb Output: tan^3(Z) coefficient (radians)
|
||||
*/
|
||||
static void refco_f32(float phpa, float tc, float rh, float wl, float *refa, float *refb) {
|
||||
// Restrict input parameters to safe values (clamp)
|
||||
float t = tc;
|
||||
if(t < -150.0f) t = -150.0f;
|
||||
if(t > 200.0f) t = 200.0f;
|
||||
|
||||
float p = phpa;
|
||||
if(p < 0.0f) p = 0.0f;
|
||||
if(p > 10000.0f) p = 10000.0f;
|
||||
|
||||
float r = rh;
|
||||
if(r < 0.0f) r = 0.0f;
|
||||
if(r > 1.0f) r = 1.0f;
|
||||
|
||||
float w = wl;
|
||||
if(w < 0.1f) w = 0.1f;
|
||||
if(w > 10.0f) w = 10.0f;
|
||||
|
||||
// Water vapour pressure at the observer
|
||||
float pw = 0.0f;
|
||||
if(p > 0.0f){
|
||||
// Saturation vapour pressure (empirical formula)
|
||||
float ps = powf(10.0f, (0.7859f + 0.03477f * t) / (1.0f + 0.00412f * t))
|
||||
* (1.0f + p * (4.5e-6f + 6e-10f * t * t));
|
||||
pw = r * ps / (1.0f - (1.0f - r) * ps / p);
|
||||
}
|
||||
|
||||
// Temperature in Kelvin
|
||||
float tk = t + 273.15f;
|
||||
|
||||
// Refractive index minus 1 at the observer (gamma = (n - 1) at the observer)
|
||||
float gamma;
|
||||
// Optical/IR: wavelength-dependent formula
|
||||
float wlsq = w * w;
|
||||
gamma = ((77.53484e-6f + (4.39108e-7f + 3.666e-9f / wlsq) / wlsq) * p
|
||||
- 11.2684e-6f * pw) / tk;
|
||||
|
||||
// Beta coefficient (from Stone, with empirical adjustments)
|
||||
float beta = 4.4474e-6f * tk;
|
||||
|
||||
// Refraction constants (from Green)
|
||||
if(refa) *refa = gamma * (1.0f - beta);
|
||||
if(refb) *refb = -gamma * (beta - gamma / 2.0f);
|
||||
}
|
||||
|
||||
//alt_corrected = alt_apparent + refraction
|
||||
float refraction(float phpa, float tc, float rh, float Z_rad){
|
||||
float A, B;
|
||||
refco_f32(phpa, tc, rh, 0.55, &A, &B);
|
||||
float tanZ = tanf(Z_rad);
|
||||
return A * tanZ + B * tanZ * tanZ * tanZ;
|
||||
}
|
||||
32
G4:G431/CORDIC/astro.h
Normal file
32
G4:G431/CORDIC/astro.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void set_sincos(int iscordic);
|
||||
int get_sincos();
|
||||
float MJD_from_unix(uint32_t t);
|
||||
//float LST_from_mjd(float mjd);
|
||||
float LST_from_unix(uint32_t t);
|
||||
float ha_to_ra(float ha, float lst);
|
||||
float ra_to_ha(float ra, float lst);
|
||||
void altaz_to_hadec(float alt_deg, float az_deg, float *ha_deg, float *dec_deg);
|
||||
void hadec_to_altaz(float ha_deg, float dec_deg, float *alt_deg, float *az_deg);
|
||||
float refraction(float phpa, float tc, float rh, float Z_rad);
|
||||
266
G4:G431/CORDIC/commproto.cpp
Normal file
266
G4:G431/CORDIC/commproto.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
extern "C"{
|
||||
#include <math.h>
|
||||
#include <stm32g4.h>
|
||||
|
||||
#include "astro.h"
|
||||
#include "commproto.h"
|
||||
#include "cordic.h"
|
||||
#include "hardware.h"
|
||||
#include "strfunc.h"
|
||||
#include "test.h"
|
||||
}
|
||||
|
||||
// sending function
|
||||
static int (*SEND)(const char *str) = nullptr;
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
|
||||
//static uint8_t curbuf[MAXSTRLEN];
|
||||
|
||||
// COMMAND(USART, "Read USART data or send (USART=hex)")
|
||||
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
|
||||
// list of all commands and handlers
|
||||
#define COMMAND_TABLE \
|
||||
COMMAND(help, "show this help") \
|
||||
COMMAND(sets, "set sin-cos to cordic (1) or math (0)") \
|
||||
COMMAND(sincos, "calculate sin/cos for given angle in degrees") \
|
||||
COMMAND(testc, "test CORDIC function: sincos, sin, cos, atan, sqrt, log") \
|
||||
COMMAND(testm, "test math function: sin, cos, atan, sqrt, log") \
|
||||
COMMAND(time, "show MJD and LST for given UNIX-time") \
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
} CmdInfo;
|
||||
|
||||
// prototypes
|
||||
#define COMMAND(name, desc) static errcodes_t cmd_ ## name(const char*, char*);
|
||||
COMMAND_TABLE
|
||||
#undef COMMAND
|
||||
|
||||
static const CmdInfo cmdInfo[] = { // command name, description - for `help`
|
||||
#define COMMAND(name, desc) { #name, desc },
|
||||
COMMAND_TABLE
|
||||
#undef COMMAND
|
||||
};
|
||||
|
||||
static const char* errtxt[ERR_AMOUNT] = {
|
||||
[ERR_OK] = "OK\n",
|
||||
[ERR_BADCMD] = "BADCMD\n",
|
||||
[ERR_BADPAR] = "BADPAR\n",
|
||||
[ERR_BADVAL] = "BADVAL\n",
|
||||
[ERR_WRONGLEN] = "WRONGLEN\n",
|
||||
[ERR_CANTRUN] = "CANTRUN\n",
|
||||
[ERR_BUSY] = "BUSY\n",
|
||||
[ERR_OVERFLOW] = "OVERFLOW\n",
|
||||
};
|
||||
|
||||
const char *EQ = " = "; // equal sign for getters
|
||||
|
||||
// send `command = `
|
||||
#define CMDEQ() do{SEND(cmd); SEND(EQ);}while(0)
|
||||
// send `commandXXX = `
|
||||
#define CMDEQP(x) do{SEND(cmd); SEND(u2str((uint32_t)x)); SEND(EQ);}while(0)
|
||||
// the same as last but with command as option and uint value
|
||||
#define SHOWPARU(cmd, x, val) do{SEND(cmd); SEND(u2str((uint32_t)x)); SEND(EQ); SEND(u2str(val));}while(0)
|
||||
|
||||
/**
|
||||
* @brief splitargs - get command parameter and setter from `args`
|
||||
* @param args (i) - rest of string after command (like `1 = PU OD OUT`)
|
||||
* @param parno (o) - parameter number or -1 if none
|
||||
* @return setter (part after `=` without leading spaces) or NULL if none
|
||||
*/
|
||||
static char *splitargs(char *args, int32_t *parno){
|
||||
if(!args) return NULL;
|
||||
uint32_t U32;
|
||||
char *next = getnum(args, &U32);
|
||||
int p = -1;
|
||||
if(next != args && U32 <= MAXPARNO) p = U32;
|
||||
if(parno) *parno = p;
|
||||
next = strchr(next, '=');
|
||||
if(next){
|
||||
if(*(++next)) next = omit_spaces(next);
|
||||
if(*next == 0) next = NULL;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief argsvals - split `args` into `parno` and setter's value
|
||||
* @param args - rest of string after command
|
||||
* @param parno (o) - parameter number or -1 if none
|
||||
* @param parval - integer setter's value
|
||||
* @return false if no setter or it's not a number, true - got setter's num
|
||||
*/
|
||||
static bool argsvals(char *args, int32_t *parno, int32_t *parval){
|
||||
char *setter = splitargs(args, parno);
|
||||
if(!setter) return false;
|
||||
int32_t I32;
|
||||
char *next = getint(setter, &I32);
|
||||
if(next != setter){
|
||||
if(parval) *parval = I32;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static errcodes_t cmd_help(const char*, char*){
|
||||
SEND(REPOURL);
|
||||
for(size_t i = 0; i < sizeof(cmdInfo)/sizeof(cmdInfo[0]); i++){
|
||||
SEND(cmdInfo[i].name);
|
||||
SEND(" - ");
|
||||
SEND(cmdInfo[i].desc); SEND("\n");
|
||||
}
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
static const char* parse_func_name(char *args){
|
||||
char *setter = splitargs(args, NULL);
|
||||
if(!setter) return nullptr;
|
||||
// remove trailing spaces
|
||||
char *p = setter;
|
||||
while(*p && *p > ' ') ++p;
|
||||
*p = 0;
|
||||
return setter;
|
||||
}
|
||||
|
||||
// calculate sin/cos
|
||||
static errcodes_t cmd_sincos(const char *, char *args){
|
||||
char *setter = splitargs(args, NULL);
|
||||
float f;
|
||||
if(!setter || !getfloat(setter, &f)) return ERR_BADVAL;
|
||||
f = f/180.f * M_PIf;
|
||||
SEND("mathsin="); SEND(float2str(sinf(f), 7));
|
||||
SEND("\nmathcos="); SEND(float2str(cosf(f), 7));
|
||||
float s, c;
|
||||
cordic_sincos(f, &s, &c);
|
||||
SEND("\ncordicsin="); SEND(float2str(s, 7));
|
||||
SEND("\ncordiccos="); SEND(float2str(c, 7));
|
||||
SEND("\n");
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
// test math function
|
||||
static errcodes_t cmd_testm(const char*, char *args){
|
||||
const char *fname = parse_func_name(args);
|
||||
if(!fname) return ERR_BADPAR;
|
||||
uint32_t elapsed = 0;
|
||||
bool ok = true;
|
||||
if(strcmp(fname, "sin") == 0){
|
||||
elapsed = test_math_sin();
|
||||
}else if(strcmp(fname, "cos") == 0){
|
||||
elapsed = test_math_cos();
|
||||
}else if(strcmp(fname, "atan") == 0){
|
||||
elapsed = test_math_atan();
|
||||
}else if(strcmp(fname, "sqrt") == 0){
|
||||
elapsed = test_math_sqrt();
|
||||
}else if(strcmp(fname, "log") == 0){
|
||||
elapsed = test_math_log();
|
||||
}else{
|
||||
ok = false;
|
||||
}
|
||||
if(!ok) return ERR_BADVAL;
|
||||
SEND("TIMEus=");
|
||||
SEND(u2str(elapsed));
|
||||
SEND("\n");
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
|
||||
// test CORDIC function
|
||||
static errcodes_t cmd_testc(const char*, char *args){
|
||||
const char *fname = parse_func_name(args);
|
||||
if(!fname) return ERR_BADPAR;
|
||||
uint32_t elapsed = 0;
|
||||
bool ok = true;
|
||||
if(strcmp(fname, "sincos") == 0){
|
||||
elapsed = test_cordic_sincos();
|
||||
}
|
||||
else if(strcmp(fname, "sin") == 0){
|
||||
elapsed = test_cordic_sin();
|
||||
}else if(strcmp(fname, "cos") == 0){
|
||||
elapsed = test_cordic_cos();
|
||||
}else if(strcmp(fname, "atan") == 0){
|
||||
elapsed = test_cordic_atan();
|
||||
}else if(strcmp(fname, "sqrt") == 0){
|
||||
elapsed = test_cordic_sqrt();
|
||||
}else if(strcmp(fname, "log") == 0){
|
||||
elapsed = test_cordic_log();
|
||||
}else{
|
||||
ok = false;
|
||||
}
|
||||
if(!ok) return ERR_BADVAL;
|
||||
SEND("TIMEus=");
|
||||
SEND(u2str(elapsed));
|
||||
SEND("\n");
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
static errcodes_t cmd_time(const char *, char *args){
|
||||
char *setter = splitargs(args, NULL);
|
||||
if(!setter) return ERR_BADVAL;
|
||||
uint32_t unix_time;
|
||||
if(setter == getnum(setter, &unix_time)) return ERR_BADVAL;
|
||||
float mjd = MJD_from_unix(unix_time);
|
||||
SEND("MJD="); SEND(float2str(mjd, 7));
|
||||
SEND("\nLST="); SEND(float2str(LST_from_unix(unix_time), 7));
|
||||
SEND("\n");
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
static errcodes_t cmd_sets(const char *cmd, char *args){
|
||||
int32_t val;
|
||||
if(argsvals(args, NULL, &val)) set_sincos(val);
|
||||
CMDEQ();
|
||||
if(get_sincos()) SEND("CORDIC\n");
|
||||
else SEND("MATH\n");
|
||||
return ERR_AMOUNT;
|
||||
}
|
||||
|
||||
constexpr uint32_t hash(const char* str, uint32_t h = 0){
|
||||
return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h;
|
||||
}
|
||||
|
||||
const char *parse_cmd(int (*sendfun)(const char *), char *str){
|
||||
SEND = sendfun;
|
||||
char command[CMD_MAXLEN+1];
|
||||
int i = 0;
|
||||
while(*str > '@' && i < CMD_MAXLEN){ command[i++] = *str++; }
|
||||
command[i] = 0;
|
||||
while(*str && *str <= ' ') ++str;
|
||||
char *restof = (char*) str;
|
||||
uint32_t h = hash(command);
|
||||
errcodes_t ecode = ERR_AMOUNT;
|
||||
switch(h){
|
||||
#define COMMAND(name, desc) case hash(#name): ecode = cmd_ ## name(command, restof); break;
|
||||
COMMAND_TABLE
|
||||
#undef COMMAND
|
||||
default: SEND("Unknown command, try 'help'\n"); break;
|
||||
}
|
||||
if(ecode < ERR_AMOUNT) return errtxt[ecode];
|
||||
return NULL;
|
||||
}
|
||||
53
G4:G431/CORDIC/commproto.h
Normal file
53
G4:G431/CORDIC/commproto.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "version.inc"
|
||||
|
||||
#ifdef EBUG
|
||||
#define RLSDBG "debug"
|
||||
#else
|
||||
#define RLSDBG "release"
|
||||
#endif
|
||||
|
||||
#define REPOURL "https://github.com/eddyem/stm32samples/tree/master/TODO " RLSDBG " build #" BUILD_NUMBER "@" BUILD_DATE "\n"
|
||||
|
||||
|
||||
// error codes for answer message
|
||||
typedef enum{
|
||||
ERR_OK, // all OK
|
||||
ERR_BADCMD, // wrong command
|
||||
ERR_BADPAR, // wrong parameter
|
||||
ERR_BADVAL, // wrong value (for setter)
|
||||
ERR_WRONGLEN, // wrong message length
|
||||
ERR_CANTRUN, // can't run given command due to bad parameters or other
|
||||
ERR_BUSY, // target interface busy, try later
|
||||
ERR_OVERFLOW, // string was too long -> overflow
|
||||
ERR_AMOUNT // amount of error codes or "send nothing"
|
||||
} errcodes_t;
|
||||
|
||||
// maximal length of command (without trailing zero)
|
||||
#define CMD_MAXLEN 15
|
||||
// maximal available parameter number
|
||||
#define MAXPARNO 255
|
||||
// maximal string length includint terminating zero
|
||||
#define MAXSTRLEN 256
|
||||
|
||||
extern const char *EQ;
|
||||
const char *parse_cmd(int (*sendfun)(const char*), char *buf);
|
||||
BIN
G4:G431/CORDIC/cordic.bin
Executable file
BIN
G4:G431/CORDIC/cordic.bin
Executable file
Binary file not shown.
151
G4:G431/CORDIC/cordic.c
Normal file
151
G4:G431/CORDIC/cordic.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stm32g4.h>
|
||||
#include <math.h>
|
||||
#include "cordic.h"
|
||||
|
||||
// default CSR settings
|
||||
#define CORDIC_CSR_DEF (5 << CORDIC_CSR_PRECISION_Pos)
|
||||
|
||||
// enable CORDIC
|
||||
static void cordic_enable(void){
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_CORDICEN;
|
||||
__DSB();
|
||||
}
|
||||
|
||||
// Convert float to Q1.31 in [-1, 1)
|
||||
static int32_t float_to_q31(float x){
|
||||
if(x >= 1.0f) x = 1.0f - 1e-6f;
|
||||
if(x <= -1.0f) x = -1.0f + 1e-6f;
|
||||
return (int32_t)(x * Q31_BASE);
|
||||
}
|
||||
|
||||
// Convert Q1.31 to float
|
||||
static float q31_to_float(int32_t q){
|
||||
return (float)q / Q31_BASE;
|
||||
}
|
||||
|
||||
static void cordic_init(void){
|
||||
static bool inited = false;
|
||||
if(!inited){
|
||||
cordic_enable();
|
||||
inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Common function for one arg (sin, cos, sqrt, log)
|
||||
static float cordic_scalar(uint32_t func_mode, float x, int arg_count){
|
||||
cordic_init();
|
||||
CORDIC->CSR = (func_mode << CORDIC_CSR_FUNC_Pos) |
|
||||
CORDIC_CSR_INSIZE_1 | // in Q1.31
|
||||
CORDIC_CSR_OUTSIZE_0; // out Q1.31
|
||||
if(arg_count == 1){
|
||||
CORDIC->WDATA = float_to_q31(x);
|
||||
} else {
|
||||
...
|
||||
}
|
||||
cordic_wait_ready();
|
||||
int32_t res = CORDIC->RDATA;
|
||||
return q31_to_float(res);
|
||||
}
|
||||
#endif
|
||||
|
||||
// sincos
|
||||
void cordic_sincos(float angle, float *s, float *c){
|
||||
float norm = angle / M_PIf;
|
||||
if(norm > 1.0f) norm = 1.0f;
|
||||
if(norm < -1.0f) norm = -1.0f;
|
||||
cordic_init();
|
||||
CORDIC->CSR = (CORDIC_CSR_FUNC_SIN << CORDIC_CSR_FUNC_Pos) | CORDIC_CSR_DEF | CORDIC_CSR_NRES;
|
||||
CORDIC->WDATA = float_to_q31(norm);
|
||||
int32_t res = CORDIC->RDATA;
|
||||
if(s) *s = q31_to_float(res);
|
||||
res = CORDIC->RDATA;
|
||||
if(c) *c = q31_to_float(res);
|
||||
}
|
||||
|
||||
// sin
|
||||
float cordic_sin(float angle){
|
||||
float norm = angle / M_PIf;
|
||||
if(norm > 1.0f) norm = 1.0f;
|
||||
if(norm < -1.0f) norm = -1.0f;
|
||||
cordic_init();
|
||||
CORDIC->CSR = (CORDIC_CSR_FUNC_SIN << CORDIC_CSR_FUNC_Pos) | CORDIC_CSR_DEF;
|
||||
CORDIC->WDATA = float_to_q31(norm);
|
||||
int32_t res = CORDIC->RDATA;
|
||||
return q31_to_float(res);
|
||||
}
|
||||
|
||||
// cos
|
||||
float cordic_cos(float angle){
|
||||
float norm = angle / M_PIf;
|
||||
if(norm > 1.0f) norm = 1.0f;
|
||||
if(norm < -1.0f) norm = -1.0f;
|
||||
cordic_init();
|
||||
CORDIC->CSR = (CORDIC_CSR_FUNC_COS << CORDIC_CSR_FUNC_Pos) | CORDIC_CSR_DEF;
|
||||
CORDIC->WDATA = float_to_q31(norm);
|
||||
int32_t res = CORDIC->RDATA; // cos
|
||||
return q31_to_float(res);
|
||||
}
|
||||
|
||||
// atan2
|
||||
float cordic_atan(float val){
|
||||
if(val > 1.f || val < -1.f) return NAN;
|
||||
cordic_init();
|
||||
CORDIC->CSR = (CORDIC_CSR_FUNC_ATAN << CORDIC_CSR_FUNC_Pos) | CORDIC_CSR_DEF;
|
||||
CORDIC->WDATA = float_to_q31(val);
|
||||
int32_t res = CORDIC->RDATA;
|
||||
return q31_to_float(res) * M_PIf;
|
||||
}
|
||||
|
||||
// sqrt
|
||||
float cordic_sqrt(float x){
|
||||
if(x < 0.0f) x = 0.0f;
|
||||
float scale = 1.0f;
|
||||
if(x > 1.0f){
|
||||
if(x < 100.f){ scale = 10.f; x /= 100.f;}
|
||||
else if(x < 1e4f){ scale = 100.f; x /= 1e4f;}
|
||||
else if(x < 1e6f){ scale = 1e3f; x /= 1e6f;}
|
||||
else if(x < 1e10f){ scale = 1e5f; x /= 1e10f;}
|
||||
else return NAN; // number is too big
|
||||
}
|
||||
cordic_init();
|
||||
CORDIC->CSR = (CORDIC_CSR_FUNC_SQRT << CORDIC_CSR_FUNC_Pos) | CORDIC_CSR_DEF;
|
||||
CORDIC->WDATA = float_to_q31(x);
|
||||
int32_t res = CORDIC->RDATA;
|
||||
return scale * q31_to_float(res);
|
||||
}
|
||||
|
||||
// log
|
||||
float cordic_log(float x){
|
||||
if(x <= 0.0f) x = 0.00001f;
|
||||
float add = 0.f;
|
||||
if(x > 1.0f){
|
||||
if(x < 1000.f){ add = 6.907755279f; x /= 1000.f; }
|
||||
else if(x < 1e6f){ add = 13.815510558f; x /= 1e6f; }
|
||||
else if(x < 1e12f){ add = 27.63102112f; x /= 1e12f; }
|
||||
else return NAN;
|
||||
}
|
||||
cordic_init();
|
||||
CORDIC->CSR = (CORDIC_CSR_FUNC_LOG << CORDIC_CSR_FUNC_Pos) | CORDIC_CSR_DEF;
|
||||
CORDIC->WDATA = float_to_q31(x);
|
||||
int32_t res = CORDIC->RDATA;
|
||||
return q31_to_float(res) * 0.6931471805599453f + add;
|
||||
}
|
||||
1
G4:G431/CORDIC/cordic.cflags
Normal file
1
G4:G431/CORDIC/cordic.cflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c23
|
||||
3
G4:G431/CORDIC/cordic.config
Normal file
3
G4:G431/CORDIC/cordic.config
Normal file
@@ -0,0 +1,3 @@
|
||||
#define EBUG
|
||||
#define STM32G4
|
||||
#define STM32G431xx
|
||||
1
G4:G431/CORDIC/cordic.creator
Normal file
1
G4:G431/CORDIC/cordic.creator
Normal file
@@ -0,0 +1 @@
|
||||
[General]
|
||||
1
G4:G431/CORDIC/cordic.cxxflags
Normal file
1
G4:G431/CORDIC/cordic.cxxflags
Normal file
@@ -0,0 +1 @@
|
||||
-std=c++23
|
||||
21
G4:G431/CORDIC/cordic.files
Normal file
21
G4:G431/CORDIC/cordic.files
Normal file
@@ -0,0 +1,21 @@
|
||||
astro.c
|
||||
astro.h
|
||||
commproto.cpp
|
||||
commproto.h
|
||||
cordic.c
|
||||
cordic.h
|
||||
flash.c
|
||||
flash.h
|
||||
hardware.c
|
||||
hardware.h
|
||||
main.c
|
||||
ringbuffer.c
|
||||
ringbuffer.h
|
||||
servo.c
|
||||
servo.h
|
||||
strfunc.c
|
||||
strfunc.h
|
||||
test.c
|
||||
test.h
|
||||
usart.c
|
||||
usart.h
|
||||
47
G4:G431/CORDIC/cordic.h
Normal file
47
G4:G431/CORDIC/cordic.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef M_PIf
|
||||
#define M_PIf 3.141592653589793f
|
||||
#endif
|
||||
|
||||
#define Q31_BASE 2147483648.0f
|
||||
|
||||
// functions
|
||||
enum {
|
||||
CORDIC_CSR_FUNC_COS = 0,
|
||||
CORDIC_CSR_FUNC_SIN,
|
||||
CORDIC_CSR_FUNC_PHASE,
|
||||
CORDIC_CSR_FUNC_MOD,
|
||||
CORDIC_CSR_FUNC_ATAN,
|
||||
CORDIC_CSR_FUNC_COSH,
|
||||
CORDIC_CSR_FUNC_ATANH,
|
||||
CORDIC_CSR_FUNC_LOG,
|
||||
CORDIC_CSR_FUNC_SQRT
|
||||
};
|
||||
|
||||
void cordic_sincos(float angle, float *s, float *c);
|
||||
float cordic_sin(float angle);
|
||||
float cordic_cos(float angle);
|
||||
float cordic_atan(float val);
|
||||
float cordic_sqrt(float x);
|
||||
float cordic_log(float x);
|
||||
4
G4:G431/CORDIC/cordic.includes
Normal file
4
G4:G431/CORDIC/cordic.includes
Normal file
@@ -0,0 +1,4 @@
|
||||
.
|
||||
../inc
|
||||
../inc/Fx
|
||||
../inc/cm
|
||||
69
G4:G431/CORDIC/hardware.c
Normal file
69
G4:G431/CORDIC/hardware.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stm32g4.h>
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
volatile uint32_t Tms = 0;
|
||||
|
||||
/* Called when systick fires */
|
||||
void sys_tick_handler(){
|
||||
++Tms;
|
||||
}
|
||||
|
||||
static void timer_setup(){
|
||||
RCC->APB1ENR1 |= RCC_APB1ENR1_TIM3EN;
|
||||
__DSB();
|
||||
TIM3->CR1 = 0; // disable counter
|
||||
TIM3->PSC = 84; // 85 MHz / 85 = 1 MHz
|
||||
TIM3->ARR = 0xFFFFFFFF; // 32-bit auto-reload (maximum)
|
||||
}
|
||||
|
||||
void timer_start(){
|
||||
TIM3->CNT = 0;
|
||||
TIM3->CR1 = TIM_CR1_CEN;
|
||||
}
|
||||
|
||||
void timer_stop(){
|
||||
TIM3->CR1 = 0;
|
||||
}
|
||||
|
||||
uint32_t timer_read(){
|
||||
return TIM3->CNT;
|
||||
}
|
||||
|
||||
void gpio_setup(){
|
||||
RCC->AHB2ENR = RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOCEN;
|
||||
__DSB();
|
||||
// PC6 as output, PC13 as input with pulldown
|
||||
GPIOC->MODER = (0xffffffff & ~(GPIO_MODER_MODE6 | GPIO_MODER_MODE13)) | MODER_O(6) | MODER_I(13);
|
||||
GPIOC->PUPDR = PUPD_PD(13);
|
||||
GPIOC->OTYPER = OTYPER_PP(6);
|
||||
// PA9 (Tx), PA10 (Rx) as alternate functions (for USART1)
|
||||
GPIOA->MODER = (0xabffffff & ~(GPIO_MODER_MODE9 | GPIO_MODER_MODE10)) |
|
||||
MODER_AF(9) | MODER_AF(10);
|
||||
GPIOA->AFR[1] = AFRf(7, 9) | AFRf(7, 10);
|
||||
// count milliseconds
|
||||
SysTick_Config(SysFreq / 1000);
|
||||
|
||||
// Setup TIM3 for microsecond counting
|
||||
timer_setup();
|
||||
}
|
||||
|
||||
|
||||
43
G4:G431/CORDIC/hardware.h
Normal file
43
G4:G431/CORDIC/hardware.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// KEY (intpullup->0) - PC13
|
||||
// LED - PC6
|
||||
#define KEY_PORT GPIOC
|
||||
#define KEY_PIN (1<<13)
|
||||
#define LED_PORT GPIOC
|
||||
#define LED_PIN (1<<6)
|
||||
#define KEY_PRESSED() (pin_read(KEY_PORT, KEY_PIN) == 1)
|
||||
#define LED_ON() do{pin_set(LED_PORT, LED_PIN);}while(0)
|
||||
#define LED_OFF() do{pin_clear(LED_PORT, LED_PIN);}while(0)
|
||||
#define LED_TOGG() do{pin_toggle(LED_PORT, LED_PIN);}while(0)
|
||||
|
||||
#define SERVO_AMOUNT 4
|
||||
|
||||
#define MIN_USART_SPEED 1200
|
||||
#define MAX_USART_SPEED 3000000
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
|
||||
void gpio_setup();
|
||||
|
||||
void timer_start();
|
||||
void timer_stop();
|
||||
uint32_t timer_read();
|
||||
71
G4:G431/CORDIC/main.c
Normal file
71
G4:G431/CORDIC/main.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stm32g4.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "commproto.h"
|
||||
#include "hardware.h"
|
||||
#include "strfunc.h"
|
||||
#include "usart.h"
|
||||
|
||||
// 40ms for debouncing
|
||||
#define TDEBOUNCE (40)
|
||||
|
||||
int main(void){
|
||||
StartHSE();
|
||||
// init storage first to take base values
|
||||
gpio_setup();
|
||||
usart_setup(115200);
|
||||
bool pressed = false;
|
||||
uint32_t Tblink = 0, Tkey = 0; // blink and key pressed time
|
||||
uint32_t Tpressed = 0;
|
||||
while(1){
|
||||
USART_flags_t f = usart_process();
|
||||
if(f.rxovrfl) usart_sendstr("Rx buffer overflow!\n");
|
||||
if(f.txerr) usart_sendstr("Tx error!\n");
|
||||
char *str = usart_getline();
|
||||
if(str){
|
||||
const char *ans = parse_cmd(usart_sendstr, str);
|
||||
if(ans) usart_sendstr(ans);
|
||||
}
|
||||
if(Tms - Tblink > 499){
|
||||
LED_TOGG();
|
||||
Tblink = Tms;
|
||||
}
|
||||
if(KEY_PRESSED()){
|
||||
if(!pressed){ // new event
|
||||
pressed = true;
|
||||
usart_sendstr("Key pressed\n");
|
||||
timer_start();
|
||||
Tpressed = Tms;
|
||||
}
|
||||
Tkey = Tms;
|
||||
}else{ // key released
|
||||
if(pressed && (Tms - Tkey) > TDEBOUNCE){ // wait for debounce
|
||||
timer_stop();
|
||||
uint32_t micros = timer_read();
|
||||
uint32_t millis = Tms - Tpressed;
|
||||
pressed = false;
|
||||
usart_sendstr("Key released\n");
|
||||
usart_sendstr("Tms="); usart_sendstr(u2str(millis));
|
||||
usart_sendstr("\nTus="); usart_sendstr(u2str(micros)); usart_sendstr("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4
G4:G431/CORDIC/openocd.cfg
Normal file
4
G4:G431/CORDIC/openocd.cfg
Normal file
@@ -0,0 +1,4 @@
|
||||
set FLASH_SIZE 0x20000
|
||||
|
||||
source [find interface/stlink-v2-1.cfg]
|
||||
source [find target/stm32g4x.cfg]
|
||||
203
G4:G431/CORDIC/ringbuffer.c
Normal file
203
G4:G431/CORDIC/ringbuffer.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stm32g4.h>
|
||||
#include "ringbuffer.h"
|
||||
|
||||
#define CHK(b) do{if(!b) return -1;}while(0)
|
||||
|
||||
static int datalen(ringbuffer *b){
|
||||
if(b->tail >= b->head) return (b->tail - b->head);
|
||||
else return (b->length - b->head + b->tail);
|
||||
}
|
||||
|
||||
// stored data length
|
||||
int RB_datalen(ringbuffer *b){
|
||||
CHK(b);
|
||||
if(0 == datalen(b)) return 0; // don't block for empty RO operations
|
||||
if(b->busy) return -1;
|
||||
b->busy = true;
|
||||
int l = datalen(b);
|
||||
b->busy = false;
|
||||
return l;
|
||||
}
|
||||
|
||||
static int hasbyte(ringbuffer *b, uint8_t byte){
|
||||
if(b->head == b->tail) return -1; // no data in buffer
|
||||
int startidx = b->head;
|
||||
if(b->head > b->tail){ //
|
||||
for(int found = b->head; found < b->length; ++found)
|
||||
if(b->data[found] == byte) return found;
|
||||
startidx = 0;
|
||||
}
|
||||
for(int found = startidx; found < b->tail; ++found)
|
||||
if(b->data[found] == byte) return found;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RB_hasbyte - check if buffer has given byte stored
|
||||
* @param b - buffer
|
||||
* @param byte - byte to find
|
||||
* @return index if found, -1 if none or busy
|
||||
*/
|
||||
int RB_hasbyte(ringbuffer *b, uint8_t byte){
|
||||
CHK(b);
|
||||
if(b->busy) return -1;
|
||||
b->busy = true;
|
||||
int ret = hasbyte(b, byte);
|
||||
b->busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// increment head or tail
|
||||
TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){
|
||||
*what += n;
|
||||
if(*what >= b->length) *what -= b->length;
|
||||
}
|
||||
|
||||
static int read(ringbuffer *b, uint8_t *s, int len){
|
||||
int l = datalen(b);
|
||||
if(!l) return 0;
|
||||
if(l > len) l = len;
|
||||
int _1st = b->length - b->head;
|
||||
if(_1st > l) _1st = l;
|
||||
if(_1st > len) _1st = len;
|
||||
memcpy(s, b->data + b->head, _1st);
|
||||
if(_1st < len && l > _1st){
|
||||
memcpy(s+_1st, b->data, l - _1st);
|
||||
incr(b, &b->head, l);
|
||||
return l;
|
||||
}
|
||||
incr(b, &b->head, _1st);
|
||||
return _1st;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RB_read - read data from ringbuffer
|
||||
* @param b - buffer
|
||||
* @param s - array to write data
|
||||
* @param len - max len of `s`
|
||||
* @return bytes read or -1 if busy
|
||||
*/
|
||||
int RB_read(ringbuffer *b, uint8_t *s, int len){
|
||||
CHK(b);
|
||||
if(!s || len < 1) return -1;
|
||||
if(0 == datalen(b)) return 0;
|
||||
if(b->busy) return -1;
|
||||
b->busy = true;
|
||||
int r = read(b, s, len);
|
||||
b->busy = false;
|
||||
return r;
|
||||
}
|
||||
|
||||
// length of data from current position to `byte` (including byte)
|
||||
static int lento(ringbuffer *b, uint8_t byte){
|
||||
int idx = hasbyte(b, byte);
|
||||
if(idx < 0) return 0;
|
||||
int partlen = idx + 1 - b->head;
|
||||
// now calculate length of new data portion
|
||||
if(idx < b->head) partlen += b->length;
|
||||
return partlen;
|
||||
}
|
||||
|
||||
static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
|
||||
int partlen = lento(b, byte);
|
||||
if(!partlen) return 0;
|
||||
if(partlen > len) return -1;
|
||||
return read(b, s, partlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RB_readto fill array `s` with data until byte `byte` (with it)
|
||||
* @param b - ringbuffer
|
||||
* @param byte - check byte
|
||||
* @param s - buffer to write data or NULL to clear data
|
||||
* @param len - length of `s` or 0 to clear data
|
||||
* @return amount of bytes written (negative, if len<data in buffer or buffer is busy)
|
||||
*/
|
||||
int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
|
||||
CHK(b);
|
||||
if(!s || len < 1) return -1;
|
||||
if(0 == datalen(b)) return 0;
|
||||
if(b->busy) return -1;
|
||||
b->busy = true;
|
||||
int n = 0;
|
||||
if(s && len > 0){
|
||||
n = readto(b, byte, s, len);
|
||||
}else{
|
||||
incr(b, &b->head, lento(b, byte)); // just throw data out
|
||||
}
|
||||
b->busy = false;
|
||||
return n;
|
||||
}
|
||||
|
||||
int RB_datalento(ringbuffer *b, uint8_t byte){
|
||||
CHK(b);
|
||||
if(0 == datalen(b)) return 0;
|
||||
if(b->busy) return -1;
|
||||
b->busy = true;
|
||||
int n = lento(b, byte);
|
||||
b->busy = false;
|
||||
return n;
|
||||
}
|
||||
|
||||
// if l < rest of buffer, truncate and return actually written bytes
|
||||
static int write(ringbuffer *b, const uint8_t *str, int l){
|
||||
int r = b->length - 1 - datalen(b); // rest length
|
||||
if(r < 1) return 0;
|
||||
if(l > r) l = r;
|
||||
int _1st = b->length - b->tail;
|
||||
if(_1st > l) _1st = l;
|
||||
memcpy(b->data + b->tail, str, _1st);
|
||||
if(_1st < l){ // add another piece from start
|
||||
memcpy(b->data, str+_1st, l-_1st);
|
||||
}
|
||||
incr(b, &b->tail, l);
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RB_write - write some data to ringbuffer
|
||||
* @param b - buffer
|
||||
* @param str - data
|
||||
* @param l - length
|
||||
* @return amount of bytes written or -1 if busy
|
||||
*/
|
||||
int RB_write(ringbuffer *b, const uint8_t *str, int l){
|
||||
CHK(b);
|
||||
if(!str || l < 1) return -1;
|
||||
if(b->length - datalen(b) < 2) return 0;
|
||||
if(b->busy) return -1;
|
||||
b->busy = true;
|
||||
int w = write(b, str, l);
|
||||
b->busy = false;
|
||||
return w;
|
||||
}
|
||||
|
||||
// just delete all information in buffer `b`
|
||||
int RB_clearbuf(ringbuffer *b){
|
||||
CHK(b);
|
||||
if(b->busy) return -1;
|
||||
b->busy = true;
|
||||
b->head = 0;
|
||||
b->tail = 0;
|
||||
memset(b->data, 0, b->length);
|
||||
b->busy = false;
|
||||
return 1;
|
||||
}
|
||||
36
G4:G431/CORDIC/ringbuffer.h
Normal file
36
G4:G431/CORDIC/ringbuffer.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct{
|
||||
uint8_t *data; // data buffer
|
||||
const int length; // its length
|
||||
int head; // head index
|
||||
int tail; // tail index
|
||||
volatile bool busy; // == TRUE if buffer is busy now
|
||||
} ringbuffer;
|
||||
|
||||
int RB_read(ringbuffer *b, uint8_t *s, int len);
|
||||
int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len);
|
||||
int RB_hasbyte(ringbuffer *b, uint8_t byte);
|
||||
int RB_write(ringbuffer *b, const uint8_t *str, int l);
|
||||
int RB_datalen(ringbuffer *b);
|
||||
int RB_datalento(ringbuffer *b, uint8_t byte);
|
||||
int RB_clearbuf(ringbuffer *b);
|
||||
378
G4:G431/CORDIC/strfunc.c
Normal file
378
G4:G431/CORDIC/strfunc.c
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h> // isnan/isinf
|
||||
#include <stm32g4.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief hexdump - dump hex array by 16 bytes in string
|
||||
* @param arr - array to dump
|
||||
* @param len - length of `arr`
|
||||
*/
|
||||
void hexdump(int (*sendfun)(const char *), uint8_t *arr, uint16_t len){
|
||||
char buf[52], *bptr = buf;
|
||||
for(uint16_t l = 0; l < len; ++l, ++arr){
|
||||
for(int16_t j = 1; j > -1; --j){
|
||||
register uint8_t half = (*arr >> (4*j)) & 0x0f;
|
||||
if(half < 10) *bptr++ = half + '0';
|
||||
else *bptr++ = half - 10 + 'a';
|
||||
}
|
||||
if(l % 16 == 15){
|
||||
*bptr++ = '\n';
|
||||
*bptr = 0;
|
||||
sendfun(buf);
|
||||
bptr = buf;
|
||||
}else *bptr++ = ' ';
|
||||
}
|
||||
if(bptr != buf){
|
||||
*bptr++ = '\n';
|
||||
*bptr = 0;
|
||||
sendfun(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief _2str - convert value into string buffer
|
||||
* @param val - |value|
|
||||
* @param minus - ==0 if value > 0
|
||||
* @return buffer with number
|
||||
*/
|
||||
static char *_2str(uint32_t val, uint8_t minus){
|
||||
static char strbuf[12];
|
||||
char *bufptr = &strbuf[11];
|
||||
*bufptr = 0;
|
||||
if(!val){
|
||||
*(--bufptr) = '0';
|
||||
}else{
|
||||
while(val){
|
||||
uint32_t x = val / 10;
|
||||
*(--bufptr) = (val - 10*x) + '0';
|
||||
val = x;
|
||||
}
|
||||
}
|
||||
if(minus) *(--bufptr) = '-';
|
||||
return bufptr;
|
||||
}
|
||||
|
||||
// return string with number `val`
|
||||
char *u2str(uint32_t val){
|
||||
return _2str(val, 0);
|
||||
}
|
||||
char *i2str(int32_t i){
|
||||
uint8_t minus = 0;
|
||||
uint32_t val;
|
||||
if(i < 0){
|
||||
minus = 1;
|
||||
val = -i;
|
||||
}else val = i;
|
||||
return _2str(val, minus);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief uhex2str - print 32bit unsigned int as hex
|
||||
* @param val - value
|
||||
* @return string with number
|
||||
*/
|
||||
char *uhex2str(uint32_t val){
|
||||
static char buf[12] = "0x";
|
||||
int npos = 2;
|
||||
uint8_t *ptr = (uint8_t*)&val + 3;
|
||||
int8_t i, j, z=1;
|
||||
for(i = 0; i < 4; ++i, --ptr){
|
||||
if(*ptr == 0){ // omit leading zeros
|
||||
if(i == 3) z = 0;
|
||||
if(z) continue;
|
||||
}
|
||||
else z = 0;
|
||||
for(j = 1; j > -1; --j){
|
||||
uint8_t half = (*ptr >> (4*j)) & 0x0f;
|
||||
if(half < 10) buf[npos++] = half + '0';
|
||||
else buf[npos++] = half - 10 + 'a';
|
||||
}
|
||||
}
|
||||
buf[npos] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief omit_spaces - eliminate leading spaces and other trash in string
|
||||
* @param buf - string
|
||||
* @return - pointer to first character in `buf` > ' '
|
||||
*/
|
||||
char *omit_spaces(char *buf){
|
||||
while(*buf){
|
||||
if(*buf > ' ') break;
|
||||
++buf;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getdec - read decimal number & return pointer to next non-number symbol
|
||||
* @param buf - string
|
||||
* @param N - number read
|
||||
* @return Next non-number symbol. In case of overflow return `buf` and N==0xffffffff
|
||||
*/
|
||||
static char *getdec(char *buf, uint32_t *N){
|
||||
char *start = (char*)buf;
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
if(c < '0' || c > '9'){
|
||||
break;
|
||||
}
|
||||
if(num > 429496729 || (num == 429496729 && c > '5')){ // overflow
|
||||
*N = 0xffffff;
|
||||
return start;
|
||||
}
|
||||
num *= 10;
|
||||
num += c - '0';
|
||||
++buf;
|
||||
}
|
||||
*N = num;
|
||||
return buf;
|
||||
}
|
||||
// read hexadecimal number (without 0x prefix!)
|
||||
char *gethex(char *buf, uint32_t *N){
|
||||
char *start = buf;
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
uint8_t M = 0;
|
||||
if(c >= '0' && c <= '9'){
|
||||
M = '0';
|
||||
}else if(c >= 'A' && c <= 'F'){
|
||||
M = 'A' - 10;
|
||||
}else if(c >= 'a' && c <= 'f'){
|
||||
M = 'a' - 10;
|
||||
}
|
||||
if(M){
|
||||
if(num & 0xf0000000){ // overflow
|
||||
*N = 0xffffff;
|
||||
return start;
|
||||
}
|
||||
num <<= 4;
|
||||
num += c - M;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
++buf;
|
||||
}
|
||||
*N = num;
|
||||
return buf;
|
||||
}
|
||||
// read octal number (without 0 prefix!)
|
||||
static char *getoct(char *buf, uint32_t *N){
|
||||
char *start = (char*)buf;
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
if(c < '0' || c > '7'){
|
||||
break;
|
||||
}
|
||||
if(num & 0xe0000000){ // overflow
|
||||
*N = 0xffffff;
|
||||
return start;
|
||||
}
|
||||
num <<= 3;
|
||||
num += c - '0';
|
||||
++buf;
|
||||
}
|
||||
*N = num;
|
||||
return buf;
|
||||
}
|
||||
// read binary number (without b prefix!)
|
||||
static char *getbin(char *buf, uint32_t *N){
|
||||
char *start = (char*)buf;
|
||||
uint32_t num = 0;
|
||||
while(*buf){
|
||||
char c = *buf;
|
||||
if(c < '0' || c > '1'){
|
||||
break;
|
||||
}
|
||||
if(num & 0x80000000){ // overflow
|
||||
*N = 0xffffff;
|
||||
return start;
|
||||
}
|
||||
num <<= 1;
|
||||
if(c == '1') num |= 1;
|
||||
++buf;
|
||||
}
|
||||
*N = num;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111)
|
||||
* @param buf - buffer with number and so on
|
||||
* @param N - the number read
|
||||
* @return pointer to first non-number symbol in buf
|
||||
* (if it is == buf, there's no number or if *N==0xffffffff there was overflow)
|
||||
*/
|
||||
char *getnum(char *txt, uint32_t *N){
|
||||
char *nxt = NULL;
|
||||
char *s = omit_spaces(txt);
|
||||
if(*s == '0'){ // hex, oct or 0
|
||||
if(s[1] == 'x' || s[1] == 'X'){ // hex
|
||||
nxt = gethex(s+2, N);
|
||||
if(nxt == s+2) nxt = (char*)txt;
|
||||
}else if(s[1] > '0'-1 && s[1] < '8'){ // oct
|
||||
nxt = getoct(s+1, N);
|
||||
if(nxt == s+1) nxt = (char*)txt;
|
||||
}else{ // 0
|
||||
nxt = s+1;
|
||||
*N = 0;
|
||||
}
|
||||
}else if(*s == 'b' || *s == 'B'){
|
||||
nxt = getbin(s+1, N);
|
||||
if(nxt == s+1) nxt = (char*)txt;
|
||||
}else{
|
||||
nxt = getdec(s, N);
|
||||
if(nxt == s) nxt = (char*)txt;
|
||||
}
|
||||
return nxt;
|
||||
}
|
||||
|
||||
// get signed integer
|
||||
char *getint(char *txt, int32_t *I){
|
||||
char *s = omit_spaces(txt);
|
||||
int32_t sign = 1;
|
||||
uint32_t U;
|
||||
if(*s == '-'){
|
||||
sign = -1;
|
||||
++s;
|
||||
}
|
||||
char *nxt = getnum(s, &U);
|
||||
if(nxt == s) return txt;
|
||||
if(U & 0x80000000) return txt; // overfull
|
||||
*I = sign * (int32_t)U;
|
||||
return nxt;
|
||||
}
|
||||
|
||||
// be careful: if pow10 would be bigger you should change str[] size!
|
||||
static const float pwr10[] = {1.f, 10.f, 100.f, 1000.f, 10000.f, 100000.f, 1000000.f, 10000000.f};
|
||||
static const float rounds[] = {0.5f, 0.05f, 0.005f, 0.0005f, 0.00005f, 0.000005f, 0.0000005f, 0.00000005f};
|
||||
#define P10L (sizeof(pwr10)/sizeof(float) - 1)
|
||||
char *float2str(float x, uint8_t prec){
|
||||
static char str[16] = {0}; // -117.5494E-36\0 - 14 symbols max!
|
||||
if(prec > P10L) prec = P10L;
|
||||
if(isnan(x)){ memcpy(str, "NAN", 4); return str;}
|
||||
else{
|
||||
int i = isinf(x);
|
||||
if(i){memcpy(str, "-INF", 5); if(i == 1) return str+1; else return str;}
|
||||
}
|
||||
char *s = str + 14; // go to end of buffer
|
||||
uint8_t minus = 0;
|
||||
if(x < 0){
|
||||
x = -x;
|
||||
minus = 1;
|
||||
}
|
||||
int pow = 0; // xxxEpow
|
||||
// now convert float to 1.xxxE3y
|
||||
while(x > 1000.f){
|
||||
x /= 1000.f;
|
||||
pow += 3;
|
||||
}
|
||||
if(x > 0.) while(x < 1.){
|
||||
x *= 1000.f;
|
||||
pow -= 3;
|
||||
}
|
||||
// print Eyy
|
||||
if(pow){
|
||||
uint8_t m = 0;
|
||||
if(pow < 0){pow = -pow; m = 1;}
|
||||
while(pow){
|
||||
int p10 = pow/10;
|
||||
*s-- = '0' + (pow - 10*p10);
|
||||
pow = p10;
|
||||
}
|
||||
if(m) *s-- = '-';
|
||||
*s-- = 'E';
|
||||
}
|
||||
// now our number is in [1, 1000]
|
||||
uint32_t units;
|
||||
if(prec){
|
||||
units = (uint32_t) x;
|
||||
uint32_t decimals = (uint32_t)((x-units+rounds[prec])*pwr10[prec]);
|
||||
// print decimals
|
||||
while(prec){
|
||||
int d10 = decimals / 10;
|
||||
*s-- = '0' + (decimals - 10*d10);
|
||||
decimals = d10;
|
||||
--prec;
|
||||
}
|
||||
// decimal point
|
||||
*s-- = '.';
|
||||
}else{ // without decimal part
|
||||
units = (uint32_t) (x + 0.5);
|
||||
}
|
||||
// print main units
|
||||
if(units == 0) *s-- = '0';
|
||||
else while(units){
|
||||
uint32_t u10 = units / 10;
|
||||
*s-- = '0' + (units - 10*u10);
|
||||
units = u10;
|
||||
}
|
||||
if(minus) *s-- = '-';
|
||||
return s+1;
|
||||
}
|
||||
|
||||
char *getfloat(char *str, float *f){
|
||||
str = omit_spaces(str);
|
||||
int isminus = 0;
|
||||
if(*str == '-'){
|
||||
isminus = 1;
|
||||
++str;
|
||||
}else if (*str == '+'){
|
||||
++str;
|
||||
}
|
||||
float result = 0.0f;
|
||||
while(*str >= '0' && *str <= '9'){
|
||||
result = result * 10.0f + (float)(*str - '0');
|
||||
++str;
|
||||
}
|
||||
if(*str != '.') goto retn;
|
||||
|
||||
++str; // omit point
|
||||
float frac = 0.0f;
|
||||
float divisor = 1.0f;
|
||||
|
||||
while(*str >= '0' && *str <= '9'){
|
||||
divisor *= 10.0f;
|
||||
frac = frac * 10.0f + (float)(*str - '0');
|
||||
++str;
|
||||
}
|
||||
|
||||
if(divisor > 1.0f){
|
||||
result += frac / divisor;
|
||||
}
|
||||
|
||||
if(*str == 'e' || *str == 'E'){ // exp
|
||||
++str;
|
||||
int32_t E;
|
||||
if(str != getint(str, &E)){
|
||||
if(E > 0) while(E-- > 0) result *= 10.f;
|
||||
else while(E++ < 0) result /= 10.f;
|
||||
}
|
||||
}
|
||||
|
||||
retn:
|
||||
if(f) *f = (isminus) ? -result : result;
|
||||
return str;
|
||||
}
|
||||
|
||||
31
G4:G431/CORDIC/strfunc.h
Normal file
31
G4:G431/CORDIC/strfunc.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
char *omit_spaces(char *buf);
|
||||
void hexdump(int (*sendfun)(const char*), uint8_t *arr, uint16_t len);
|
||||
char *u2str(uint32_t val);
|
||||
char *i2str(int32_t i);
|
||||
char *float2str(float x, uint8_t prec);
|
||||
char *uhex2str(uint32_t val);
|
||||
char *gethex(const char *buf, uint32_t *N);
|
||||
char *getnum(char *txt, uint32_t *N);
|
||||
char *getint(char *txt, int32_t *I);
|
||||
char *getfloat(char *str, float *f);
|
||||
127
G4:G431/CORDIC/test.c
Normal file
127
G4:G431/CORDIC/test.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stm32g4.h>
|
||||
|
||||
#include "test.h"
|
||||
#include "hardware.h"
|
||||
#include "cordic.h"
|
||||
|
||||
// amount of iterations over test
|
||||
#define N_TESTS 1000
|
||||
|
||||
static float arr[N_TESTS];
|
||||
|
||||
|
||||
// RNG
|
||||
static uint32_t rand_state = 123456789;
|
||||
static uint32_t next_rand(){
|
||||
rand_state = rand_state * 1664525 + 1013904223;
|
||||
return rand_state;
|
||||
}
|
||||
|
||||
// fill array with random angles
|
||||
static void fill_random_sin_cos(){
|
||||
for(int i = 0; i < N_TESTS; ++i){
|
||||
// angle from -pi to +pi
|
||||
arr[i] = (float)(next_rand() % 62831853) / 10000000.0f - 3.14159265f;
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_random_atan(){
|
||||
for(int i = 0; i < N_TESTS; ++i){
|
||||
arr[i] = (float)(next_rand() % 2000000) / 1e6f - 1e6f; // [-1,1]
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_random_sqrt(){
|
||||
for(int i = 0; i < N_TESTS; ++i){
|
||||
arr[i] = (float)(next_rand() % 10000) / 100.0f; // [0,100]
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_random_log(){
|
||||
for(int i = 0; i < N_TESTS; ++i){
|
||||
arr[i] = (float)(next_rand() % 10000 + 1) / 100.0f; // [0.01, 100]
|
||||
}
|
||||
}
|
||||
|
||||
// main test template
|
||||
static uint32_t run_test(void (*gen)(), float (*func)(float)){
|
||||
gen();
|
||||
volatile float result = 0.0f; // don't let gcc to optimize this cycle
|
||||
timer_start();
|
||||
for(int i = 0; i < N_TESTS; ++i){
|
||||
result = func(arr[i]);
|
||||
(void) result;
|
||||
}
|
||||
timer_stop();
|
||||
return timer_read();
|
||||
}
|
||||
|
||||
static uint32_t run_test2(void (*gen)(), void (*func)(float, float*, float*)){
|
||||
gen();
|
||||
volatile float result1 = 0.f, result2 = 0.f; // don't let gcc to optimize this cycle
|
||||
timer_start();
|
||||
for(int i = 0; i < N_TESTS; ++i){
|
||||
func(arr[i], (float*)&result1, (float*)&result2);
|
||||
(void) result1;
|
||||
(void) result2;
|
||||
}
|
||||
timer_stop();
|
||||
return timer_read();
|
||||
}
|
||||
|
||||
// ------------- math.h tests -------------
|
||||
uint32_t test_math_sin(){
|
||||
return run_test(fill_random_sin_cos, sinf);
|
||||
}
|
||||
uint32_t test_math_cos(){
|
||||
return run_test(fill_random_sin_cos, cosf);
|
||||
}
|
||||
uint32_t test_math_atan(){
|
||||
return run_test(fill_random_atan, atanf);
|
||||
}
|
||||
uint32_t test_math_sqrt(){
|
||||
return run_test(fill_random_sqrt, sqrtf);
|
||||
}
|
||||
uint32_t test_math_log(){
|
||||
return run_test(fill_random_log, logf);
|
||||
}
|
||||
|
||||
// ------------- CORDIC tests -------------
|
||||
uint32_t test_cordic_sincos(){
|
||||
return run_test2(fill_random_sin_cos, cordic_sincos);
|
||||
}
|
||||
uint32_t test_cordic_sin(){
|
||||
return run_test(fill_random_sin_cos, cordic_sin);
|
||||
}
|
||||
uint32_t test_cordic_cos(){
|
||||
return run_test(fill_random_sin_cos, cordic_cos);
|
||||
}
|
||||
uint32_t test_cordic_atan(){
|
||||
return run_test(fill_random_atan, cordic_atan);
|
||||
}
|
||||
uint32_t test_cordic_sqrt(){
|
||||
return run_test(fill_random_sqrt, cordic_sqrt);
|
||||
}
|
||||
uint32_t test_cordic_log(){
|
||||
return run_test(fill_random_log, cordic_log);
|
||||
}
|
||||
36
G4:G431/CORDIC/test.h
Normal file
36
G4:G431/CORDIC/test.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// libmath tests
|
||||
uint32_t test_math_sin();
|
||||
uint32_t test_math_cos();
|
||||
uint32_t test_math_atan();
|
||||
uint32_t test_math_sqrt();
|
||||
uint32_t test_math_log();
|
||||
|
||||
// CORDIC tests
|
||||
uint32_t test_cordic_sincos();
|
||||
uint32_t test_cordic_sin();
|
||||
uint32_t test_cordic_cos();
|
||||
uint32_t test_cordic_atan();
|
||||
uint32_t test_cordic_sqrt();
|
||||
uint32_t test_cordic_log();
|
||||
257
G4:G431/CORDIC/usart.c
Normal file
257
G4:G431/CORDIC/usart.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stm32g4.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hardware.h" // Tms
|
||||
#include "ringbuffer.h"
|
||||
#include "usart.h"
|
||||
|
||||
// USART for text-based protocol, each data portion ends with '\n'
|
||||
// RX works over circular DMA
|
||||
|
||||
// USART-depending part ------->
|
||||
// USART1 @ PA9 (Tx) - MUX25 - and PA10 (Rx) - MUX24
|
||||
// select USART and its DMA channels
|
||||
#define USARTx USART1
|
||||
#define USARTxAPB APB2ENR
|
||||
#define USARTxEN RCC_APB2ENR_USART1EN
|
||||
#define USART_APBEN RCC_APB2
|
||||
// DMAMUX channels: 24 - USART1Rx, 25 - USART1Tx
|
||||
#define DMAMUXRXN (24)
|
||||
#define DMAMUXTXN (25)
|
||||
// DMA channels: 1 (0 in MUX) - Rx, 2 (1 in MUX) - Tx; TC and error flags
|
||||
// use DMA ch2/3 because they both have single IRQ
|
||||
#define DMAx DMA1
|
||||
#define DMAxEN (RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_DMAMUX1EN)
|
||||
#define DMACHRX DMA1_Channel1
|
||||
#define DMARXTCF DMA_ISR_TCIF1
|
||||
#define DMARXEF DMA_ISR_TEIF1
|
||||
#define DMACHTX DMA1_Channel2
|
||||
#define DMATXTCF DMA_ISR_TCIF2
|
||||
#define DMATXEF DMA_ISR_TEIF2
|
||||
#define DMAMUXRX DMAMUX1_Channel0
|
||||
#define DMAMUXTX DMAMUX1_Channel1
|
||||
#define USARTIRQn USART1_IRQn
|
||||
#define DMARXIRQ DMA1_Channel1_IRQn
|
||||
#define DMATXIRQ DMA1_Channel2_IRQn
|
||||
|
||||
// interrupt aliases
|
||||
static void usart_isr();
|
||||
static void dmatx_isr();
|
||||
static void dmarx_isr();
|
||||
void usart1_isr() __attribute__ ((alias ("usart_isr")));
|
||||
void dma1_channel1_isr() __attribute__ ((alias ("dmarx_isr")));
|
||||
void dma1_channel2_isr() __attribute__ ((alias ("dmatx_isr")));
|
||||
// <-------- USART-depending part
|
||||
|
||||
// RX/TX DMA->CCR without EN flag
|
||||
#define DMARXCCR (DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_TEIE)
|
||||
#define DMATXCCR (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_TEIE)
|
||||
|
||||
static volatile bool gotstring = true; // got '\n' in input stream -> force data reading to inbuf
|
||||
static volatile bool txrdy = true; // Tx DMA not busy
|
||||
static volatile USART_flags_t curflags; // current flags (cleared in `usart_process`)
|
||||
// rx/tx DMA buffers
|
||||
static uint8_t dmarxbuf[USARTRXDMABUFSZ];
|
||||
static uint8_t dmatxbuf[USARTTXDMABUFSZ];
|
||||
// index of last DMA read position
|
||||
static uint32_t dma_read_idx = 0;
|
||||
// for ringbuffer
|
||||
static uint8_t rbrxbuf[USARTRXBUFSZ], rbtxbuf[USARTTXBUFSZ];
|
||||
static ringbuffer TxRB = {.data = rbtxbuf, .length = USARTTXBUFSZ};
|
||||
static ringbuffer RxRB = {.data = rbrxbuf, .length = USARTRXBUFSZ};
|
||||
|
||||
#define USART_BRR(speed) ((SysFreq + (speed)/2) / (speed))
|
||||
|
||||
static void reinit_rx_dma(){
|
||||
dma_read_idx = 0;
|
||||
RB_clearbuf(&RxRB);
|
||||
DMACHRX->CCR = DMARXCCR; // stop to reload
|
||||
DMACHRX->CNDTR = USARTRXDMABUFSZ;
|
||||
DMACHRX->CMAR = (uint32_t) dmarxbuf;
|
||||
DMACHRX->CCR = DMARXCCR | DMA_CCR_EN;
|
||||
}
|
||||
|
||||
void usart_setup(uint32_t speed){
|
||||
RCC->AHB1ENR |= DMAxEN; // enable DMA
|
||||
// enable USART clocking
|
||||
RCC->USARTxAPB |= USARTxEN;
|
||||
// baudrate
|
||||
USARTx->BRR = USART_BRR(speed);
|
||||
// eol character: '/n'
|
||||
USARTx->CR2 = USART_CR2_ADD_VAL('\n');
|
||||
// enable DMA transmission
|
||||
USARTx->CR3 = USART_CR3_DMAT | USART_CR3_DMAR;
|
||||
// set up DMA channels
|
||||
// Tx channel: mem++, mem->periph, 8bit, compl.&err. irq
|
||||
DMACHTX->CCR = DMATXCCR;
|
||||
DMACHTX->CPAR = (uint32_t) &USARTx->TDR; // peripherial address
|
||||
// Rx channel: mem++, periph->mem, 8bit, compl.&err. irq
|
||||
DMACHRX->CCR = DMARXCCR;
|
||||
DMACHRX->CPAR = (uint32_t) &USARTx->RDR; // peripherial address
|
||||
// set up DMAMUX channels
|
||||
// enumeration of DMAMUX starts from 0 (DMA - from 1)!
|
||||
DMAMUXRX->CCR = DMAMUXRXN;
|
||||
DMAMUXTX->CCR = DMAMUXTXN;
|
||||
// charmatch interrupt, enable transmitter and receiver, enable usart
|
||||
USARTx->CR1 = USART_CR1_CMIE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
|
||||
USARTx->ICR = 0xffffffff; // clear all flags
|
||||
reinit_rx_dma();
|
||||
NVIC_EnableIRQ(USARTIRQn);
|
||||
NVIC_EnableIRQ(DMARXIRQ);
|
||||
NVIC_EnableIRQ(DMATXIRQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief usart_sendbuf - send next data portion
|
||||
* @return true if sent something
|
||||
*/
|
||||
static bool usart_sendbuf(){
|
||||
if(!txrdy) return false;
|
||||
int rd = RB_read(&TxRB, dmatxbuf, USARTTXDMABUFSZ);
|
||||
if(rd < 1) return false; // nothing to write or busy
|
||||
// set up DMA
|
||||
DMACHTX->CCR = DMATXCCR;
|
||||
DMACHTX->CMAR = (uint32_t) dmatxbuf;
|
||||
DMACHTX->CNDTR = rd;
|
||||
USARTx->ICR = USART_ICR_TCCF; // clear TC flag
|
||||
txrdy = false;
|
||||
// activate DMA
|
||||
DMACHTX->CCR = DMATXCCR | DMA_CCR_EN;
|
||||
return true;
|
||||
}
|
||||
|
||||
int usart_send(const char *str, int len){
|
||||
if(!str || len < 1) return 0;
|
||||
uint32_t t = Tms;
|
||||
int sent = 0;
|
||||
do{
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
int put = RB_write(&TxRB, (uint8_t*)str, len);
|
||||
if(put < 0) continue; // busy
|
||||
else if(put == 0){
|
||||
usart_sendbuf(); // no place
|
||||
t = Tms;
|
||||
}else{
|
||||
len -= put;
|
||||
sent += put;
|
||||
str += put;
|
||||
}
|
||||
}while(len && (Tms - t) < USARTBLKTMOUT); // not more than `block` ms!
|
||||
return sent;
|
||||
}
|
||||
|
||||
int usart_sendstr(const char *str){
|
||||
int l = strlen(str);
|
||||
return usart_send(str, l);
|
||||
}
|
||||
|
||||
static void addtoreadidx(int adder){
|
||||
dma_read_idx += adder;
|
||||
if(dma_read_idx >= USARTRXDMABUFSZ) dma_read_idx -= USARTRXDMABUFSZ;
|
||||
}
|
||||
|
||||
// return current flags
|
||||
USART_flags_t usart_process(){
|
||||
static uint32_t Tlast = 0;
|
||||
USART_flags_t flags = curflags;
|
||||
curflags.all = 0;
|
||||
if(RB_datalento(&TxRB, '\n') > 1 || Tms - Tlast >= USARTSENDTMOUT){ // send buffer as we found '\n' or each 10ms
|
||||
if(usart_sendbuf()) Tlast = Tms;
|
||||
}
|
||||
int remained = DMACHRX->CNDTR;
|
||||
int write_idx = USARTRXDMABUFSZ - remained; // next symbol to be written
|
||||
int available = (write_idx - dma_read_idx); // length of data available
|
||||
if(available < 0) available += USARTRXDMABUFSZ; // write to the left of read
|
||||
if(available == 0) return flags;
|
||||
// add next data portion to RX ring buffer
|
||||
if(available >= (USARTRXDMABUFSZ / 2) || gotstring){
|
||||
// copy data in one or two chunks (wrap handling)
|
||||
// check if we can write to RB `available` bytes
|
||||
int rballow = RxRB.length - 1 - RB_datalen(&RxRB);
|
||||
if(rballow < available){
|
||||
if(available > USARTRXDMABUFSZ - 2){ // near overfull
|
||||
flags.rxovrfl = 1;
|
||||
reinit_rx_dma();
|
||||
RB_clearbuf(&RxRB);
|
||||
return flags;
|
||||
}
|
||||
if(rballow < 1) return flags;
|
||||
available = rballow; // read at least as we can
|
||||
}
|
||||
if(dma_read_idx + available <= USARTRXDMABUFSZ){ // head before tail
|
||||
int written = RB_write(&RxRB, &dmarxbuf[dma_read_idx], available);
|
||||
if(written == available && dmarxbuf[dma_read_idx+available-1] == '\n') gotstring = 0;
|
||||
if(written > 0) addtoreadidx(written);
|
||||
}else{ // head after tail - two chunks
|
||||
int first = USARTRXDMABUFSZ - dma_read_idx;
|
||||
int written = RB_write(&RxRB, &dmarxbuf[dma_read_idx], first);
|
||||
if(written != first){ // could write only part - just increase read index
|
||||
if(written > 0) addtoreadidx(written);
|
||||
}else{
|
||||
dma_read_idx = 0;
|
||||
int last = available - first;
|
||||
written = RB_write(&RxRB, dmarxbuf, last);
|
||||
if(written == last && dmarxbuf[last-1] == '\n') gotstring = 0;
|
||||
if(written > 0) addtoreadidx(written);
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
char *usart_getline(){
|
||||
static char buff[MAX_INPLEN];
|
||||
int l = RB_datalento(&RxRB, '\n');
|
||||
if(l < 1){
|
||||
l = RB_datalen(&RxRB); // Rx ringbuffer could be near overflow but without '\n'
|
||||
if(l < MAX_INPLEN-1) return NULL; // allow to wait for last symbols
|
||||
}
|
||||
if(l > MAX_INPLEN-1){ // overflow -> read at least part of the string
|
||||
l = MAX_INPLEN-1;
|
||||
}
|
||||
if(l != RB_read(&RxRB, (uint8_t*)buff, l)) return NULL;
|
||||
buff[l] = 0; // return with '\n' at end of line (so user can detect non-finished overflowed lines)
|
||||
return buff;
|
||||
}
|
||||
|
||||
// interrupt by '\n'
|
||||
static void usart_isr(){
|
||||
if(USARTx->ISR & USART_ISR_CMF){ // got '\n' @ USARTx
|
||||
gotstring = true;
|
||||
}
|
||||
USARTx->ICR = 0xffffffff; // clear all flags
|
||||
}
|
||||
|
||||
static void dmarx_isr(){
|
||||
volatile uint32_t isr = DMAx->ISR;
|
||||
if(isr & DMARXEF){ // error
|
||||
reinit_rx_dma();
|
||||
curflags.rxovrfl = 1;
|
||||
}
|
||||
DMAx->IFCR = DMARXEF; // clear all flags
|
||||
}
|
||||
|
||||
static void dmatx_isr(){
|
||||
volatile uint32_t isr = DMAx->ISR;
|
||||
if(isr & DMATXTCF) txrdy = true;
|
||||
if(isr & DMATXEF) curflags.txerr = 1;
|
||||
DMAx->IFCR = DMATXTCF | DMATXEF; // clear all flags
|
||||
}
|
||||
49
G4:G431/CORDIC/usart.h
Normal file
49
G4:G431/CORDIC/usart.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the cordic project.
|
||||
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// maximal length of input string (including '\n' and terminating zero)
|
||||
#define MAX_INPLEN (128)
|
||||
// Rx/Tx ring buffer size
|
||||
#define USARTTXBUFSZ (512)
|
||||
#define USARTRXBUFSZ (512)
|
||||
// Rx/Tx DMA buffer size
|
||||
#define USARTTXDMABUFSZ (256)
|
||||
#define USARTRXDMABUFSZ (256)
|
||||
|
||||
// blocking timeout - not more than 5ms
|
||||
#define USARTBLKTMOUT (5)
|
||||
// send buffer each 10ms
|
||||
#define USARTSENDTMOUT (10)
|
||||
|
||||
typedef union{
|
||||
struct{
|
||||
uint8_t txerr : 1; // transmit error
|
||||
uint8_t rxovrfl : 1; // receive buffer overflow
|
||||
};
|
||||
uint8_t all;
|
||||
} USART_flags_t;
|
||||
|
||||
void usart_setup(uint32_t speed);
|
||||
int usart_send(const char *str, int len);
|
||||
char *usart_getline();
|
||||
int usart_sendstr(const char *str);
|
||||
USART_flags_t usart_process();
|
||||
2
G4:G431/CORDIC/version.inc
Normal file
2
G4:G431/CORDIC/version.inc
Normal file
@@ -0,0 +1,2 @@
|
||||
#define BUILD_NUMBER "48"
|
||||
#define BUILD_DATE "2026-08-12"
|
||||
@@ -49,11 +49,10 @@ LIB_DIR := $(INC_DIR)/ld
|
||||
|
||||
###############################################################################
|
||||
# C flags
|
||||
CFLAGS += -D__thumb2__=1 -MD
|
||||
CFLAGS += -Wall -Wextra -Wshadow -Wdouble-promotion
|
||||
CFLAGS += -fshort-enums -ffunction-sections -fdata-sections
|
||||
#CFLAGS += -fno-common -fno-stack-protector
|
||||
CFLAGS += $(ARCH_FLAGS)
|
||||
FLAGS := -D__thumb2__=1 -MD -Wall -Wextra -Wshadow -Wdouble-promotion -fshort-enums -ffunction-sections -fdata-sections
|
||||
# -fno-common -fno-stack-protector
|
||||
CFLAGS += $(FLAGS) $(ARCH_FLAGS)
|
||||
CPPFLAGS += $(FLAGS) $(ARCH_FLAGS)
|
||||
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
@@ -130,6 +129,8 @@ $(VERSION_FILE): *.[ch]
|
||||
@sed -i "s/#define BUILDNO.*/#define BUILDNO $(NEXTVER)/" $(VERSION_FILE)
|
||||
@sed -i "s/#define BUILD_DATE.*/#define BUILD_DATE \"$(BUILDDATE)\"/" $(VERSION_FILE)
|
||||
|
||||
$(OBJDIR)/commproto.o: commproto.cpp $(VERSION_FILE)
|
||||
|
||||
$(OBJDIR)/proto.o: proto.c $(VERSION_FILE)
|
||||
|
||||
$(OBJDIR)/usb_dev.o: CFLAGS := $(filter-out -flto,$(CFLAGS)) -fno-lto
|
||||
@@ -140,7 +141,7 @@ $(OBJDIR)/%.o: %.c
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
@echo " C++ $<"
|
||||
$(CPP) -c $(CFLAGS) -std=c++11 -fno-exceptions -fno-rtti -Wl,--trace-symbol=_sbrk $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
$(CPP) -c $(CPPFLAGS) -fno-exceptions -fno-rtti -Wl,--trace-symbol=_sbrk $(DEFS) $(INCLUDE) -o $@ -c $<
|
||||
|
||||
$(BIN): $(ELF)
|
||||
@echo " OBJCOPY $(BIN)"
|
||||
|
||||
Reference in New Issue
Block a user