mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 18:55:13 +03:00
Add some more
This commit is contained in:
parent
617daf62c7
commit
2cc06884b4
@ -217,5 +217,8 @@ _SW_ used as debugging/sewing; also (I remember about USB pullup only after end
|
||||
| 11 | PF10 | M0 EN | slow out | l-s 0 or CS of SPI |
|
||||
|
||||
|
||||
# Debug with SWD
|
||||
Press both _BTN0_ and _BTN1_ and turn on device. In this case the USB won't be activated and you can use SWD. If both these buttons not pressed on poweron, device will use _SWDIO_ as USB pullup, so SWD connection in this mode won't be available.
|
||||
## DMA usage
|
||||
|
||||
* ADC1 - DMA1_ch1
|
||||
* ADC2 - DMA2_ch1
|
||||
|
||||
|
||||
153
F3:F303/Multistepper/adc.c
Normal file
153
F3:F303/Multistepper/adc.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* This file is part of the multistepper 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 "adc.h"
|
||||
|
||||
/**
|
||||
* @brief ADCx_array - arrays for ADC channels with median filtering:
|
||||
* ADC1:
|
||||
* 0..3 - AIN0..3 (ADC1_IN1..4)
|
||||
* 4 - internal Tsens - ADC1_IN16
|
||||
* 5 - Vref - ADC1_IN18
|
||||
* ADC2:
|
||||
* 6 - AIN4 (ADC2_IN1)
|
||||
* 7 - AIN5 (ADC2_IN10)
|
||||
*/
|
||||
static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
||||
|
||||
TRUE_INLINE void calADC(ADC_TypeDef *chnl){
|
||||
// calibration
|
||||
// enable voltage regulator
|
||||
chnl->CR = 0;
|
||||
chnl->CR = ADC_CR_ADVREGEN_0;
|
||||
// wait for 10us
|
||||
uint16_t ctr = 0;
|
||||
while(++ctr < 1000){nop();}
|
||||
// ADCALDIF=0 (single channels)
|
||||
if((chnl->CR & ADC_CR_ADEN)){
|
||||
chnl->CR |= ADC_CR_ADSTP;
|
||||
chnl->CR |= ADC_CR_ADDIS;
|
||||
}
|
||||
chnl->CR |= ADC_CR_ADCAL;
|
||||
while((chnl->CR & ADC_CR_ADCAL) != 0 && ++ctr < 0xfff0){};
|
||||
chnl->CR = ADC_CR_ADVREGEN_0;
|
||||
// enable ADC
|
||||
ctr = 0;
|
||||
do{
|
||||
chnl->CR |= ADC_CR_ADEN;
|
||||
}while((chnl->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0);
|
||||
}
|
||||
|
||||
TRUE_INLINE void enADC(ADC_TypeDef *chnl){
|
||||
// ADEN->1, wait ADRDY
|
||||
chnl->CR |= ADC_CR_ADEN;
|
||||
uint16_t ctr = 0;
|
||||
while(!(chnl->ISR & ADC_ISR_ADRDY) && ++ctr < 0xffff){}
|
||||
chnl->CR |= ADC_CR_ADSTART; /* start the ADC conversions */
|
||||
}
|
||||
|
||||
/**
|
||||
* ADC1 - DMA1_ch1
|
||||
* ADC2 - DMA2_ch1
|
||||
*/
|
||||
// Setup ADC and DAC
|
||||
void adc_setup(){
|
||||
RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable clocking
|
||||
ADC12_COMMON->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN | ADC_CCR_CKMODE; // enable Tsens and Vref, HCLK/4
|
||||
calADC(ADC1);
|
||||
calADC(ADC2);
|
||||
// ADC1: channels 1,2,3,4,16,18; ADC2: channels 1,10
|
||||
ADC1->SMPR1 = ADC_SMPR1_SMP1 | ADC_SMPR1_SMP2 | ADC_SMPR1_SMP3 | ADC_SMPR1_SMP4;
|
||||
ADC1->SMPR2 = ADC_SMPR2_SMP16 | ADC_SMPR2_SMP18;
|
||||
// 4 conversions in group: 1->2->3->4->16->18
|
||||
ADC1->SQR1 = (1<<6) | (2<<12) | (3<<18) | (4<<24) | (NUMBER_OF_ADC1_CHANNELS-1);
|
||||
ADC1->SQR2 = (16<<6) | (18<<12);
|
||||
ADC2->SMPR1 = ADC_SMPR1_SMP1;
|
||||
ADC2->SMPR2 = ADC_SMPR2_SMP10;
|
||||
ADC2->SQR1 = (1<<6) | (10<<12) | (NUMBER_OF_ADC2_CHANNELS-1);
|
||||
// configure DMA for ADC
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN;
|
||||
ADC1->CFGR = ADC_CFGR_CONT | ADC_CFGR_DMAEN | ADC_CFGR_DMACFG;
|
||||
ADC2->CFGR = ADC_CFGR_CONT | ADC_CFGR_DMAEN | ADC_CFGR_DMACFG;
|
||||
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR));
|
||||
DMA1_Channel1->CMAR = (uint32_t)(ADC_array);
|
||||
DMA1_Channel1->CNDTR = NUMBER_OF_ADC1_CHANNELS * 9;
|
||||
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC;
|
||||
DMA1_Channel1->CCR |= DMA_CCR_EN;
|
||||
|
||||
DMA2_Channel1->CPAR = (uint32_t) (&(ADC2->DR));
|
||||
DMA2_Channel1->CMAR = (uint32_t)(&ADC_array[ADC2START]);
|
||||
DMA2_Channel1->CNDTR = NUMBER_OF_ADC2_CHANNELS * 9;
|
||||
DMA2_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC;
|
||||
DMA2_Channel1->CCR |= DMA_CCR_EN;
|
||||
|
||||
enADC(ADC1);
|
||||
enADC(ADC2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getADCval - calculate median value for `nch` channel
|
||||
* @param nch - number of channel
|
||||
* @return
|
||||
*/
|
||||
uint16_t getADCval(int nch){
|
||||
register uint16_t temp;
|
||||
#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
|
||||
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
|
||||
uint16_t p[9];
|
||||
int adval = (nch >= NUMBER_OF_ADC1_CHANNELS) ? NUMBER_OF_ADC2_CHANNELS : NUMBER_OF_ADC1_CHANNELS;
|
||||
int addr = (nch >= NUMBER_OF_ADC1_CHANNELS) ? nch - NUMBER_OF_ADC2_CHANNELS + ADC2START: nch;
|
||||
for(int i = 0; i < 9; ++i, addr += adval) // first we should prepare array for optmed
|
||||
p[i] = ADC_array[addr];
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ;
|
||||
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||
PIX_SORT(p[0], p[3]) ; PIX_SORT(p[5], p[8]) ; PIX_SORT(p[4], p[7]) ;
|
||||
PIX_SORT(p[3], p[6]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[2], p[5]) ;
|
||||
PIX_SORT(p[4], p[7]) ; PIX_SORT(p[4], p[2]) ; PIX_SORT(p[6], p[4]) ;
|
||||
PIX_SORT(p[4], p[2]) ;
|
||||
return p[4];
|
||||
#undef PIX_SORT
|
||||
#undef PIX_SWAP
|
||||
}
|
||||
|
||||
// get voltage @input nch (V)
|
||||
float getADCvoltage(int nch){
|
||||
float v = getADCval(nch);
|
||||
v *= getVdd();
|
||||
v /= 4096.f; // 12bit ADC
|
||||
return v;
|
||||
}
|
||||
|
||||
// return MCU temperature (degrees of celsius)
|
||||
float getMCUtemp(){
|
||||
// make correction on Vdd value
|
||||
int32_t ADval = getADCval(ADC_TS);
|
||||
float temperature = (float) *TEMP30_CAL_ADDR - ADval;
|
||||
temperature *= (110.f - 30.f);
|
||||
temperature /= (float)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR);
|
||||
temperature += 30.f;
|
||||
return(temperature);
|
||||
}
|
||||
|
||||
// return Vdd (V)
|
||||
float getVdd(){
|
||||
float vdd = ((float) *VREFINT_CAL_ADDR) * 3.3f; // 3.3V
|
||||
vdd /= getADCval(ADC_VREF);
|
||||
return vdd;
|
||||
}
|
||||
45
F3:F303/Multistepper/adc.h
Normal file
45
F3:F303/Multistepper/adc.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the multistepper 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stm32f3.h>
|
||||
|
||||
#define NUMBER_OF_ADC1_CHANNELS (6)
|
||||
#define NUMBER_OF_ADC2_CHANNELS (2)
|
||||
// total number of channels - for array
|
||||
#define NUMBER_OF_ADC_CHANNELS ((NUMBER_OF_ADC1_CHANNELS+NUMBER_OF_ADC2_CHANNELS))
|
||||
|
||||
|
||||
// AIN0-3: ADC1_IN1..4; AIN4 - ADC2_IN1; AIN5 - ADC2_IN10
|
||||
// channels of ADC in array
|
||||
#define ADC_AIN0 (0)
|
||||
#define ADC_AIN1 (1)
|
||||
#define ADC_AIN2 (2)
|
||||
#define ADC_AIN3 (3)
|
||||
#define ADC_TS (4)
|
||||
#define ADC_VREF (5)
|
||||
#define ADC_AIN4 (6)
|
||||
#define ADC_AIN5 (7)
|
||||
// starting index of ADC2
|
||||
#define ADC2START (9*NUMBER_OF_ADC1_CHANNELS)
|
||||
|
||||
void adc_setup();
|
||||
float getMCUtemp();
|
||||
float getVdd();
|
||||
uint16_t getADCval(int nch);
|
||||
float getADCvoltage(int nch);
|
||||
90
F3:F303/Multistepper/buttons.c
Normal file
90
F3:F303/Multistepper/buttons.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of the multistepper 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 "buttons.h"
|
||||
#include "hardware.h"
|
||||
|
||||
typedef struct{
|
||||
keyevent event; // current key event
|
||||
int16_t counter; // press/release counter
|
||||
uint32_t lastTms; // time of last event change
|
||||
} keybase;
|
||||
|
||||
static keybase allkeys[BTNSNO] = {0}; // array for buttons' states
|
||||
|
||||
uint32_t lastUnsleep = 0; // last keys activity time
|
||||
|
||||
void process_keys(){
|
||||
static uint32_t lastT = 0;
|
||||
if(Tms == lastT) return;
|
||||
uint16_t d = (uint16_t)(Tms - lastT);
|
||||
lastT = Tms;
|
||||
for(int i = 0; i < BTNSNO; ++i){
|
||||
keybase *k = &allkeys[i];
|
||||
keyevent e = k->event;
|
||||
if(BTN_state(i)){ // key is in pressed state
|
||||
switch(e){
|
||||
case EVT_NONE: // just pressed
|
||||
case EVT_RELEASE:
|
||||
if((k->counter += d) > PRESSTHRESHOLD){
|
||||
k->event = EVT_PRESS;
|
||||
}
|
||||
break;
|
||||
case EVT_PRESS: // hold
|
||||
if((k->counter += d)> HOLDTHRESHOLD){
|
||||
k->event = EVT_HOLD;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}else{ // released
|
||||
if(e == EVT_PRESS || e == EVT_HOLD){ // released
|
||||
if(k->counter > PRESSTHRESHOLD) k->counter = PRESSTHRESHOLD;
|
||||
else if((k->counter -= d) < 0){
|
||||
k->event = EVT_RELEASE; // button released
|
||||
}
|
||||
}
|
||||
}
|
||||
if(e != k->event){
|
||||
k->lastTms = Tms;
|
||||
lastUnsleep = Tms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief keystate - curent key state
|
||||
* @param k - key number
|
||||
* @param T - last event changing time
|
||||
* @return key event
|
||||
*/
|
||||
keyevent keystate(uint8_t k, uint32_t *T){
|
||||
if(k >= BTNSNO) return EVT_NONE;
|
||||
keyevent evt = allkeys[k].event;
|
||||
// change state `release` to `none` after 1st check
|
||||
if(evt == EVT_RELEASE) allkeys[k].event = EVT_NONE;
|
||||
if(T) *T = allkeys[k].lastTms;
|
||||
return evt;
|
||||
}
|
||||
|
||||
// getter of keyevent for allkeys[]
|
||||
keyevent keyevt(uint8_t k){
|
||||
if(k >= BTNSNO) return EVT_NONE;
|
||||
return allkeys[k].event;
|
||||
}
|
||||
40
F3:F303/Multistepper/buttons.h
Normal file
40
F3:F303/Multistepper/buttons.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the multistepper 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stm32f3.h>
|
||||
|
||||
// threshold in ms for press/hold
|
||||
#define PRESSTHRESHOLD (9)
|
||||
#define HOLDTHRESHOLD (199)
|
||||
|
||||
// events
|
||||
typedef enum{
|
||||
EVT_NONE, // no events with given key
|
||||
EVT_PRESS, // pressed (hold more than PRESSTHRESHOLD ms)
|
||||
EVT_HOLD, // hold more than HOLDTHRESHOLD ms
|
||||
EVT_RELEASE // released after press or hold state
|
||||
} keyevent;
|
||||
|
||||
extern uint32_t lastUnsleep; // last keys activity time
|
||||
|
||||
void process_keys();
|
||||
keyevent keystate(uint8_t k, uint32_t *T);
|
||||
keyevent keyevt(uint8_t k);
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
*/
|
||||
|
||||
#include "can.h"
|
||||
#include "commonproto.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
#include "strfunc.h"
|
||||
#include "usb.h"
|
||||
@ -302,6 +304,66 @@ uint32_t CAN_speed(){
|
||||
return oldspeed;
|
||||
}
|
||||
|
||||
static void formerr(CAN_message *msg, errcodes err){
|
||||
if(msg->length < 4) msg->length = 4;
|
||||
msg->data[3] = (uint8_t)err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief parseCANcommand - parser
|
||||
* @param msg - incoming message @ my CANID
|
||||
* FORMAT:
|
||||
* 0 1 2 3 4 5 6 7
|
||||
* [CMD][PAR][errcode][VALUE]
|
||||
* CMD - uint16_t, PAR - uint8_t, errcode - one of CAN_errcodes, VALUE - int32_t
|
||||
* `errcode` of incoming message doesn't matter
|
||||
*/
|
||||
TRUE_INLINE void parseCANcommand(CAN_message *msg){
|
||||
int N = 1000;
|
||||
// we don't check msg here as it cannot be NULL
|
||||
#ifdef EBUG
|
||||
DBG("Get data");
|
||||
for(int i = 0; i < msg->length; ++i){
|
||||
USB_sendstr(uhex2str(msg->data[i])); USB_putbyte(' ');
|
||||
}
|
||||
newline();
|
||||
#endif
|
||||
if(msg->length == 0) goto sendmessage; // PING
|
||||
uint16_t Index = *(uint16_t*)msg->data;
|
||||
#ifdef EBUG
|
||||
USB_sendstr("Index = "); USB_sendstr(u2str(Index)); newline();
|
||||
#endif
|
||||
if(Index >= CCMD_AMOUNT){
|
||||
formerr(msg, ERR_BADCMD);
|
||||
goto sendmessage;
|
||||
}
|
||||
msg->data[3] = ERR_OK;
|
||||
uint8_t par = msg->data[2];
|
||||
if(par & 0x80){
|
||||
formerr(msg, ERR_BADPAR);
|
||||
goto sendmessage;
|
||||
}
|
||||
int32_t *val = (int32_t *)(&msg->data[4]);
|
||||
if(msg->length == 8) par |= 0x80;
|
||||
else if(msg->length == 2) par = CANMESG_NOPAR; // no parameter
|
||||
else if(msg->length != 3){ // wrong length
|
||||
formerr(msg, ERR_WRONGLEN);
|
||||
goto sendmessage;
|
||||
}
|
||||
#ifdef EBUG
|
||||
USB_sendstr("Run command\n");
|
||||
#endif
|
||||
errcodes ec = cancmdlist[Index](par, val);
|
||||
if(ec != ERR_OK){
|
||||
formerr(msg, ec);
|
||||
}else{
|
||||
msg->length = 8;
|
||||
}
|
||||
sendmessage:
|
||||
while(CAN_BUSY == CAN_send(msg->data, msg->length, the_conf.CANID))
|
||||
if(--N == 0) break;
|
||||
}
|
||||
|
||||
static void can_process_fifo(uint8_t fifo_num){
|
||||
if(fifo_num > 1) return;
|
||||
CAN_FIFOMailBox_TypeDef *box = &CAN->sFIFOMailBox[fifo_num];
|
||||
@ -348,6 +410,7 @@ static void can_process_fifo(uint8_t fifo_num){
|
||||
dat[0] = lb & 0xff;
|
||||
}
|
||||
}
|
||||
if(msg.ID == the_conf.CANID) parseCANcommand(&msg);
|
||||
if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later
|
||||
*RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message
|
||||
}
|
||||
|
||||
@ -16,7 +16,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "buttons.h"
|
||||
#include "commonproto.h"
|
||||
#include "hardware.h"
|
||||
#include "hdr.h"
|
||||
#include "proto.h"
|
||||
#include "usb.h"
|
||||
@ -45,16 +48,51 @@ static errcodes cu_time(uint8_t par, int32_t *val){
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
errcodes cu_mcut(uint8_t par, int32_t *val){
|
||||
NOPARCHK(par);
|
||||
float f = getMCUtemp();
|
||||
*val = (uint32_t)(f*10.f);
|
||||
return ERR_OK;
|
||||
}
|
||||
errcodes cu_mcuvdd(uint8_t par, int32_t *val){
|
||||
NOPARCHK(par);
|
||||
float f = getVdd();
|
||||
*val = (uint32_t)(f*10.f);
|
||||
return ERR_OK;
|
||||
}
|
||||
errcodes cu_adc(uint8_t par, int32_t *val){
|
||||
uint8_t n = PARBASE(par);
|
||||
if(n > NUMBER_OF_ADC_CHANNELS-1) return ERR_BADPAR;
|
||||
*val = getADCval(n);
|
||||
return ERR_OK;
|
||||
}
|
||||
// NON-STANDARD COMMAND!!!!!!!
|
||||
// errcode == keystate, value = last time!!!!
|
||||
errcodes cu_button(uint8_t par, int32_t *val){
|
||||
uint8_t n = PARBASE(par);
|
||||
if(n > BTNSNO-1){
|
||||
*val = CANMESG_NOPAR; // the only chance to understand error
|
||||
return ERR_BADPAR;
|
||||
}
|
||||
return (uint8_t) keystate(n, (uint32_t*)val);
|
||||
}
|
||||
|
||||
// par - motor number, val - 0/1 for ESW0/1
|
||||
errcodes cu_esw(uint8_t par, int32_t *val){
|
||||
uint8_t n = PARBASE(par), l = *val;
|
||||
if(n >= MOTORSNO || l > 1){
|
||||
*val = CANMESG_NOPAR; // the only chance to understand error
|
||||
return ERR_BADPAR;
|
||||
}
|
||||
*val = ESW_state(n, l);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
errcodes cu_abspos(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_accel(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_adc(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_button(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_canid(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_diagn(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_emstop(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_eraseflash(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_esw(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_eswreact(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_goto(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_gotoz(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
@ -62,8 +100,6 @@ errcodes cu_gpio(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_gpioconf(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_maxspeed(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_maxsteps(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_mcut(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_mcuvdd(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_microsteps(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_minspeed(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_motflags(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
@ -81,7 +117,7 @@ errcodes cu_udata(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
errcodes cu_usartstatus(_U_ uint8_t par, _U_ int32_t *val){return ERR_BADCMD;}
|
||||
|
||||
|
||||
const fpointer cmdlist[CCMD_AMOUNT] = {
|
||||
const fpointer cancmdlist[CCMD_AMOUNT] = {
|
||||
// different commands
|
||||
[CCMD_PING] = cu_ping,
|
||||
[CCMD_RELAY] = cu_nosuchfn,
|
||||
|
||||
@ -16,17 +16,79 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
|
||||
// Buttons: PA9, PA10, PF6, PD3, PD4, PD5, pullup (active - 0)
|
||||
volatile GPIO_TypeDef* const BTNports[BTNSNO] = {GPIOA, GPIOA, GPIOF, GPIOD, GPIOD, GPIOD};
|
||||
const uint32_t BTNpins[BTNSNO] = {1<<9, 1<<10, 1<<6, 1<<3, 1<<4, 1<<5};
|
||||
|
||||
// Limit switches: 0:PC14/PC13, 1:PB9/PB7, 2:PD7/PD6, 3:PC10/PC11, 4:PC7/PD15,
|
||||
// 5:PD11/PD10, 6:PE11/PE10, 7:PE7/PE8
|
||||
volatile GPIO_TypeDef *ESWports[MOTORSNO][ESWNO] = {
|
||||
{GPIOC, GPIOC}, // 0
|
||||
{GPIOB, GPIOB},
|
||||
{GPIOD, GPIOD}, // 2
|
||||
{GPIOC, GPIOC},
|
||||
{GPIOC, GPIOD}, // 4
|
||||
{GPIOD, GPIOD},
|
||||
{GPIOE, GPIOE}, // 6
|
||||
{GPIOE, GPIOE},
|
||||
};
|
||||
const uint32_t ESWpins[MOTORSNO][ESWNO] = {
|
||||
{1<<14, 1<<13},
|
||||
{1<<9, 1<<7}, // 1
|
||||
{1<<7, 1<<6},
|
||||
{1<<10, 1<<11}, // 3
|
||||
{1<<7, 1<<15},
|
||||
{1<<11, 1<<10}, // 5
|
||||
{1<<11, 1<<10},
|
||||
{1<<7, 1<<8}, // 7
|
||||
};
|
||||
|
||||
// motors: DIR/EN
|
||||
// EN: 0:PF10, 1:PE1, 2:PB6, 3:PD2, 4:PC9, 5:PD14, 6:PE13, 7:PB1
|
||||
volatile GPIO_TypeDef *ENports[MOTORSNO] = {
|
||||
GPIOF, GPIOE, GPIOB, GPIOD, GPIOC, GPIOD, GPIOE, GPIOB};
|
||||
const uint32_t ENpins[MOTORSNO] = {
|
||||
1<<10, 1<<1, 1<<6, 1<<2, 1<<9, 1<<14, 1<<13, 1<<1};
|
||||
// DIR: 0:PC15, 1:PE0, 2:PB4, 3:PC12, 4:PC8, 5:PD13, 6:PE12, 7:PB2
|
||||
volatile GPIO_TypeDef *DIRports[MOTORSNO] = {
|
||||
GPIOC, GPIOE, GPIOB, GPIOC, GPIOC, GPIOD, GPIOE, GPIOB};
|
||||
const uint32_t DIRpins[MOTORSNO] = {
|
||||
1<<15, 1<<0, 1<<4, 1<<12, 1<<8, 1<<13, 1<<12, 1<<2};
|
||||
// timers for motors: 0:t15c1, 1:t16c1, 2:t17c1, 3:t2ch1, 4:t8ch1, 5:t4c1, 6:t1c1, 7:t3c3
|
||||
volatile TIM_TypeDef *mottimers[MOTORSNO] = {
|
||||
TIM15, TIM16, TIM17, TIM2, TIM8, TIM4, TIM1, TIM3};
|
||||
const uint8_t mottchannels[MOTORSNO] = {1,1,1,1,1,1,1,3};
|
||||
static IRQn_Type motirqs[MOTORSNO] = {
|
||||
TIM15_IRQn, TIM16_IRQn, TIM17_IRQn, TIM2_IRQn, TIM8_CC_IRQn, TIM4_IRQn, TIM1_CC_IRQn, TIM3_IRQn};
|
||||
|
||||
// state 1 - pressed, 0 - released (pin active is zero)
|
||||
uint8_t ESW_state(uint8_t MOTno, uint8_t ESWno){
|
||||
uint8_t val = ((ESWports[MOTno][ESWno]->IDR & ESWpins[MOTno][ESWno]) ? 0 : 1);
|
||||
if(the_conf.motflags[ESWno].eswinv) val = !val;
|
||||
return val;
|
||||
}
|
||||
|
||||
// calculate MSB position of value `val`
|
||||
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
static const uint8_t bval[] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3};
|
||||
uint8_t MSB(uint16_t val){
|
||||
register uint8_t r = 0;
|
||||
if(val & 0xff00){r += 8; val >>= 8;}
|
||||
if(val & 0x00f0){r += 4; val >>= 4;}
|
||||
return ((uint8_t)r + bval[val]);
|
||||
}
|
||||
|
||||
// setup here ALL GPIO pins (due to table in Readme.md)
|
||||
// leave SWD as default AF; high speed for CLK and some other AF; med speed for some another AF
|
||||
TRUE_INLINE void gpio_setup(){
|
||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN
|
||||
| RCC_AHBENR_GPIOEEN | RCC_AHBENR_GPIOFEN;
|
||||
// enable timers: 1,2,3,4,8,15,16,17
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM4EN;
|
||||
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM8EN | RCC_APB2ENR_TIM15EN | RCC_APB2ENR_TIM16EN | RCC_APB2ENR_TIM17EN;
|
||||
for(int i = 0; i < 10000; ++i) nop();
|
||||
GPIOA->ODR = 0;
|
||||
GPIOA->AFR[0] = AFRf(5, 5) | AFRf(5, 6) | AFRf(5, 7);
|
||||
@ -111,10 +173,78 @@ TRUE_INLINE void iwdg_setup(){
|
||||
}
|
||||
#endif
|
||||
|
||||
// motor's PWM
|
||||
static void setup_mpwm(int i){
|
||||
volatile TIM_TypeDef *TIM = mottimers[i];
|
||||
TIM->CR1 = TIM_CR1_ARPE; // buffered ARR
|
||||
TIM->PSC = MOTORTIM_PSC; // 16MHz
|
||||
// PWM mode 1 (active -> inactive)
|
||||
uint8_t n = mottchannels[i];
|
||||
switch(n){
|
||||
case 1:
|
||||
TIM->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
|
||||
break;
|
||||
case 2:
|
||||
TIM->CCMR1 = TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1;
|
||||
break;
|
||||
case 3:
|
||||
TIM->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1;
|
||||
break;
|
||||
default:
|
||||
TIM->CCMR2 = TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1;
|
||||
}
|
||||
#if MOTORTIM_ARRMIN < 5
|
||||
#error "change the code!"
|
||||
#endif
|
||||
TIM->CCR1 = MOTORTIM_ARRMIN - 3; // ~10us for pulse duration
|
||||
TIM->ARR = 0xffff;
|
||||
// TIM->EGR = TIM_EGR_UG; // generate update to refresh ARR
|
||||
TIM->BDTR |= TIM_BDTR_MOE; // enable main output
|
||||
TIM->CCER = 1<<((n-1)*4); // turn it on, active high
|
||||
TIM->DIER = 1<<n; // allow CC interrupt (we should count steps)
|
||||
NVIC_EnableIRQ(motirqs[i]);
|
||||
}
|
||||
|
||||
|
||||
void hw_setup(){
|
||||
gpio_setup();
|
||||
for(int i = 0; i < MOTORSNO; ++i) setup_mpwm(i);
|
||||
#ifndef EBUG
|
||||
iwdg_setup();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// timers for motors: 0:t15c1, 1:t16c1, 2:t17c1, 3:t2ch1, 4:t8ch1, 5:t4c1, 6:t1c1, 7:t3c3
|
||||
void tim1_cc_isr(){
|
||||
// addmicrostep(6);
|
||||
TIM1->SR = 0;
|
||||
}
|
||||
void tim2_isr(){
|
||||
// addmicrostep(3);
|
||||
TIM2->SR = 0;
|
||||
}
|
||||
void tim3_isr(){
|
||||
// addmicrostep(7);
|
||||
TIM3->SR = 0;
|
||||
}
|
||||
void tim4_isr(){
|
||||
// addmicrostep(5);
|
||||
TIM4->SR = 0;
|
||||
}
|
||||
void tim8_cc_isr(){
|
||||
// addmicrostep(4);
|
||||
TIM8->SR = 0;
|
||||
}
|
||||
void tim1_brk_tim15_isr(){
|
||||
// addmicrostep(0);
|
||||
TIM15->SR = 0;
|
||||
}
|
||||
void tim1_up_tim16_isr(){
|
||||
// addmicrostep(1);
|
||||
TIM16->SR = 0;
|
||||
}
|
||||
void tim1_trg_com_tim17_isr(){
|
||||
// addmicrostep(2);
|
||||
TIM17->SR = 0;
|
||||
}
|
||||
|
||||
@ -20,6 +20,11 @@
|
||||
|
||||
#include <stm32f3.h>
|
||||
|
||||
// motors' timer PSC = PCLK/Tfreq - 1, Tfreq=16MHz
|
||||
#define MOTORTIM_PSC (2)
|
||||
// minimal ARR value - 99 for 5000 steps per second @ 32 microsteps/step
|
||||
#define MOTORTIM_ARRMIN (99)
|
||||
|
||||
// USB pullup: PA8
|
||||
#define USBPU_port GPIOA
|
||||
#define USBPU_pin (1<<8)
|
||||
@ -40,7 +45,16 @@ extern const uint32_t BTNpins[BTNSNO];
|
||||
// motors amount
|
||||
#define MOTORSNO (8)
|
||||
|
||||
// Limit switches: 2 for each motor
|
||||
#define ESWNO (2)
|
||||
// ESW ports & pins
|
||||
extern volatile GPIO_TypeDef *ESWports[MOTORSNO][ESWNO];
|
||||
extern const uint32_t ESWpins[MOTORSNO][ESWNO];
|
||||
|
||||
|
||||
extern volatile uint32_t Tms;
|
||||
|
||||
uint8_t ESW_state(uint8_t MOTno, uint8_t ESWno);
|
||||
uint8_t MSB(uint16_t val);
|
||||
void hw_setup();
|
||||
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adc.h"
|
||||
#include "buttons.h"
|
||||
#include "can.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
@ -42,8 +44,9 @@ int main(void){
|
||||
hw_setup(); // GPIO, ADC, timers, watchdog etc.
|
||||
USBPU_OFF(); // make a reconnection
|
||||
USB_setup();
|
||||
USBPU_ON();
|
||||
CAN_setup(the_conf.CANspeed);
|
||||
adc_setup();
|
||||
USBPU_ON();
|
||||
uint32_t ctr = 0;
|
||||
CAN_message *can_mesg;
|
||||
while(1){
|
||||
@ -79,5 +82,6 @@ int main(void){
|
||||
const char *ans = cmd_parser(inbuff);
|
||||
if(ans) USB_sendstr(ans);
|
||||
}
|
||||
process_keys();
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@ -1,3 +1,7 @@
|
||||
adc.c
|
||||
adc.h
|
||||
buttons.c
|
||||
buttons.h
|
||||
can.c
|
||||
can.h
|
||||
commonproto.c
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
#include <stm32f3.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "adc.h"
|
||||
#include "buttons.h"
|
||||
#include "can.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
@ -417,11 +419,29 @@ int fn_dumperr(_U_ uint32_t hash, _U_ char *args){ // "dumperr" (1223989764)
|
||||
return RET_GOOD;
|
||||
}
|
||||
|
||||
int fn_canid(_U_ uint32_t hash, char *args){ // "canid" (2040257924)
|
||||
if(args && *args){
|
||||
int good = FALSE;
|
||||
uint32_t N;
|
||||
const char *eq = getnum(args, &N);
|
||||
if(eq != args && N < 0xfff){
|
||||
the_conf.CANID = (uint16_t)N;
|
||||
CAN_reinit(the_conf.CANspeed);
|
||||
good = TRUE;
|
||||
}
|
||||
if(!good) USB_sendstr("CANID setter format: `canid=ID`, ID is 11bit\n");
|
||||
}
|
||||
USB_sendstr("canid="); USB_sendstr(uhex2str(the_conf.CANID));
|
||||
newline();
|
||||
return RET_GOOD;
|
||||
}
|
||||
|
||||
static int canusb_function(uint32_t hash, char *args){
|
||||
errcodes e = ERR_BADCMD;
|
||||
uint32_t N;
|
||||
int32_t val = 0;
|
||||
uint8_t par = CANMESG_NOPAR;
|
||||
float f;
|
||||
if(*args){
|
||||
const char *n = getnum(args, &N);
|
||||
if(n != args){ // get parameter
|
||||
@ -444,6 +464,63 @@ static int canusb_function(uint32_t hash, char *args){
|
||||
case CMD_PING:
|
||||
e = cu_ping(par, &val);
|
||||
break;
|
||||
case CMD_MCUT:
|
||||
f = getMCUtemp();
|
||||
USB_sendstr("T=");
|
||||
USB_sendstr(float2str(f, 1));
|
||||
newline();
|
||||
return RET_GOOD;
|
||||
break;
|
||||
case CMD_MCUVDD:
|
||||
f = getVdd();
|
||||
USB_sendstr("VDD=");
|
||||
USB_sendstr(float2str(f, 1));
|
||||
newline();
|
||||
return RET_GOOD;
|
||||
break;
|
||||
case CMD_ADC:
|
||||
par = PARBASE(par);
|
||||
if(par >= NUMBER_OF_ADC_CHANNELS){
|
||||
USB_sendstr("Wrong channel number\n");
|
||||
return RET_BAD;
|
||||
}
|
||||
USB_sendstr("ADC"); USB_putbyte('0'+par);
|
||||
USB_putbyte('='); USB_sendstr(u2str(getADCval(par)));
|
||||
f = getADCvoltage(par);
|
||||
USB_sendstr("\nADCv");USB_putbyte('0'+par);
|
||||
USB_putbyte('='); USB_sendstr(float2str(f, 1));
|
||||
newline();
|
||||
return RET_GOOD;
|
||||
break;
|
||||
case CMD_BUTTON:
|
||||
e = cu_button(par, &val);
|
||||
if(val == CANMESG_NOPAR){
|
||||
USB_sendstr("Wrong button number\n");
|
||||
return RET_BAD;
|
||||
}
|
||||
const char *kstate = "none";
|
||||
switch(e){
|
||||
case EVT_PRESS:
|
||||
kstate = "press";
|
||||
break;
|
||||
case EVT_HOLD:
|
||||
kstate = "hold";
|
||||
break;
|
||||
case EVT_RELEASE:
|
||||
kstate = "release";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
USB_sendstr("KEY"); USB_putbyte('0'+PARBASE(par));
|
||||
USB_putbyte('='); USB_sendstr(kstate);
|
||||
USB_sendstr("KEYTIME="); USB_sendstr(u2str(val));
|
||||
newline();
|
||||
return RET_GOOD;
|
||||
break;
|
||||
case CMD_ESW:
|
||||
e = cu_esw(par, &val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -464,41 +541,40 @@ static int canusb_function(uint32_t hash, char *args){
|
||||
#define AL __attribute__ ((alias ("canusb_function")))
|
||||
|
||||
// COMMON with CAN
|
||||
int fn_ping(_U_ uint32_t hash, _U_ char *args) AL; //* "ping" (10561715)
|
||||
int fn_ping(_U_ uint32_t hash, _U_ char *args) AL; // "ping" (10561715)
|
||||
// not realized yet
|
||||
int fn_abspos(_U_ uint32_t hash, _U_ char *args) AL; //* "abspos" (3056382221)
|
||||
int fn_accel(_U_ uint32_t hash, _U_ char *args) AL; //* "accel" (1490521981)
|
||||
int fn_adc(_U_ uint32_t hash, _U_ char *args) AL; //* "adc" (2963026093)
|
||||
int fn_button(_U_ uint32_t hash, _U_ char *args) AL; //* "button" (1093508897)
|
||||
int fn_canid(_U_ uint32_t hash, _U_ char *args) AL; // "canid" (2040257924)
|
||||
int fn_diagn(_U_ uint32_t hash, _U_ char *args) AL; // "diagn" (2334137736)
|
||||
int fn_adc(_U_ uint32_t hash, _U_ char *args) AL; // "adc" (2963026093)
|
||||
int fn_button(_U_ uint32_t hash, _U_ char *args) AL; // "button" (1093508897)
|
||||
int fn_diagn(_U_ uint32_t hash, _U_ char *args) AL; //* "diagn" (2334137736)
|
||||
int fn_emstop(_U_ uint32_t hash, _U_ char *args) AL; //* "emstop" (2965919005)
|
||||
int fn_eraseflash(_U_ uint32_t hash, _U_ char *args) AL; // "eraseflash" (3177247267)
|
||||
int fn_esw(_U_ uint32_t hash, _U_ char *args) AL; //* "esw" (2963094612)
|
||||
int fn_eraseflash(_U_ uint32_t hash, _U_ char *args) AL; //* "eraseflash" (3177247267)
|
||||
int fn_esw(_U_ uint32_t hash, _U_ char *args) AL; // "esw" (2963094612)
|
||||
int fn_eswreact(_U_ uint32_t hash, _U_ char *args) AL; //* "eswreact" (1614224995)
|
||||
int fn_goto(_U_ uint32_t hash, _U_ char *args) AL; // "goto" (4286309438)
|
||||
int fn_goto(_U_ uint32_t hash, _U_ char *args) AL; //* "goto" (4286309438)
|
||||
int fn_gotoz(_U_ uint32_t hash, _U_ char *args) AL; //* "gotoz" (3178103736)
|
||||
int fn_gpio(_U_ uint32_t hash, _U_ char *args) AL; //* "gpio" (4286324660)
|
||||
int fn_gpioconf(_U_ uint32_t hash, _U_ char *args) AL; // "gpioconf" (1309721562)
|
||||
int fn_gpioconf(_U_ uint32_t hash, _U_ char *args) AL; //* "gpioconf" (1309721562)
|
||||
int fn_maxspeed(_U_ uint32_t hash, _U_ char *args) AL; //* "maxspeed" (1498078812)
|
||||
int fn_maxsteps(_U_ uint32_t hash, _U_ char *args) AL; //* "maxsteps" (1506667002)
|
||||
int fn_mcut(_U_ uint32_t hash, _U_ char *args) AL; //* "mcut" (4022718)
|
||||
int fn_mcuvdd(_U_ uint32_t hash, _U_ char *args) AL; //* "mcuvdd" (2517587080)
|
||||
int fn_mcut(_U_ uint32_t hash, _U_ char *args) AL; // "mcut" (4022718)
|
||||
int fn_mcuvdd(_U_ uint32_t hash, _U_ char *args) AL; // "mcuvdd" (2517587080)
|
||||
int fn_microsteps(_U_ uint32_t hash, _U_ char *args) AL; //* "microsteps" (3974395854)
|
||||
int fn_minspeed(_U_ uint32_t hash, _U_ char *args) AL; //* "minspeed" (3234848090)
|
||||
int fn_motflags(_U_ uint32_t hash, _U_ char *args) AL; //* "motflags" (2153634658)
|
||||
int fn_motmul(_U_ uint32_t hash, _U_ char *args) AL; // "motmul" (1543400099)
|
||||
int fn_motmul(_U_ uint32_t hash, _U_ char *args) AL; //* "motmul" (1543400099)
|
||||
int fn_motreinit(_U_ uint32_t hash, _U_ char *args) AL; //* "motreinit" (199682784)
|
||||
int fn_relpos(_U_ uint32_t hash, _U_ char *args) AL; //* "relpos" (1278646042)
|
||||
int fn_relslow(_U_ uint32_t hash, _U_ char *args) AL; //* "relslow" (1742971917)
|
||||
int fn_saveconf(_U_ uint32_t hash, _U_ char *args) AL; //* "saveconf" (141102426)
|
||||
int fn_screen(_U_ uint32_t hash, _U_ char *args) AL; // "screen" (2100809349)
|
||||
int fn_screen(_U_ uint32_t hash, _U_ char *args) AL; //* "screen" (2100809349)
|
||||
int fn_speedlimit(_U_ uint32_t hash, _U_ char *args) AL; //* "speedlimit" (1654184245)
|
||||
int fn_state(_U_ uint32_t hash, _U_ char *args) AL; //* "state" (2216628902)
|
||||
int fn_stop(_U_ uint32_t hash, _U_ char *args) AL; //* "stop" (17184971)
|
||||
int fn_tmcbus(_U_ uint32_t hash, _U_ char *args) AL; // "tmcbus" (1906135955)
|
||||
int fn_udata(_U_ uint32_t hash, _U_ char *args) AL; // "udata" (2736127636)
|
||||
int fn_usartstatus(_U_ uint32_t hash, _U_ char *args) AL; // "usartstatus" (4007098968)
|
||||
int fn_tmcbus(_U_ uint32_t hash, _U_ char *args) AL; //* "tmcbus" (1906135955)
|
||||
int fn_udata(_U_ uint32_t hash, _U_ char *args) AL; //* "udata" (2736127636)
|
||||
int fn_usartstatus(_U_ uint32_t hash, _U_ char *args) AL; //* "usartstatus" (4007098968)
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
#include <stm32f3.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief hexdump - dump hex array by 16 bytes in string
|
||||
@ -248,6 +250,75 @@ const char *getint(const char *txt, int32_t *I){
|
||||
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};
|
||||
static const float rounds[] = {0.5f, 0.05f, 0.005f, 0.0005f, 0.00005f};
|
||||
#define P10L (sizeof(pwr10)/sizeof(uint32_t) - 1)
|
||||
const 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){
|
||||
register 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){
|
||||
register 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){
|
||||
register uint32_t u10 = units / 10;
|
||||
*s-- = '0' + (units - 10*u10);
|
||||
units = u10;
|
||||
}
|
||||
if(minus) *s-- = '-';
|
||||
return s+1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void mymemcpy(char *dest, const char *src, int len){
|
||||
if(len < 1) return;
|
||||
|
||||
@ -10,4 +10,5 @@ char *uhex2str(uint32_t val);
|
||||
const char *getnum(const char *txt, uint32_t *N);
|
||||
const char *omit_spaces(const char *buf);
|
||||
const char *getint(const char *txt, int32_t *I);
|
||||
const char *float2str(float x, uint8_t prec);
|
||||
//void mymemcpy(char *dest, const char *src, int len);
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
#define BUILD_NUMBER "20"
|
||||
#define BUILD_DATE "2023-02-13"
|
||||
#define BUILD_NUMBER "30"
|
||||
#define BUILD_DATE "2023-02-16"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user