From 2cc06884b476c52daf7fca721e82d03f8a15191d Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Thu, 16 Feb 2023 20:08:27 +0300 Subject: [PATCH] Add some more --- F3:F303/Multistepper/Readme.md | 7 +- F3:F303/Multistepper/adc.c | 153 ++++++++++++++++++++++++ F3:F303/Multistepper/adc.h | 45 +++++++ F3:F303/Multistepper/buttons.c | 90 ++++++++++++++ F3:F303/Multistepper/buttons.h | 40 +++++++ F3:F303/Multistepper/can.c | 63 ++++++++++ F3:F303/Multistepper/commonproto.c | 50 ++++++-- F3:F303/Multistepper/hardware.c | 130 ++++++++++++++++++++ F3:F303/Multistepper/hardware.h | 14 +++ F3:F303/Multistepper/main.c | 6 +- F3:F303/Multistepper/multistepper.bin | Bin 16836 -> 20800 bytes F3:F303/Multistepper/multistepper.files | 4 + F3:F303/Multistepper/proto.c | 108 ++++++++++++++--- F3:F303/Multistepper/strfunc.c | 71 +++++++++++ F3:F303/Multistepper/strfunc.h | 1 + F3:F303/Multistepper/version.inc | 4 +- 16 files changed, 758 insertions(+), 28 deletions(-) create mode 100644 F3:F303/Multistepper/adc.c create mode 100644 F3:F303/Multistepper/adc.h create mode 100644 F3:F303/Multistepper/buttons.c create mode 100644 F3:F303/Multistepper/buttons.h diff --git a/F3:F303/Multistepper/Readme.md b/F3:F303/Multistepper/Readme.md index 07a30e8..64abe75 100644 --- a/F3:F303/Multistepper/Readme.md +++ b/F3:F303/Multistepper/Readme.md @@ -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. \ No newline at end of file +## DMA usage + +* ADC1 - DMA1_ch1 +* ADC2 - DMA2_ch1 + diff --git a/F3:F303/Multistepper/adc.c b/F3:F303/Multistepper/adc.c new file mode 100644 index 0000000..f9aa6e1 --- /dev/null +++ b/F3:F303/Multistepper/adc.c @@ -0,0 +1,153 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#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; +} diff --git a/F3:F303/Multistepper/adc.h b/F3:F303/Multistepper/adc.h new file mode 100644 index 0000000..32711bd --- /dev/null +++ b/F3:F303/Multistepper/adc.h @@ -0,0 +1,45 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once +#include + +#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); diff --git a/F3:F303/Multistepper/buttons.c b/F3:F303/Multistepper/buttons.c new file mode 100644 index 0000000..8544978 --- /dev/null +++ b/F3:F303/Multistepper/buttons.c @@ -0,0 +1,90 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#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; +} diff --git a/F3:F303/Multistepper/buttons.h b/F3:F303/Multistepper/buttons.h new file mode 100644 index 0000000..896a2e4 --- /dev/null +++ b/F3:F303/Multistepper/buttons.h @@ -0,0 +1,40 @@ +/* + * This file is part of the multistepper project. + * Copyright 2023 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once + +#include + +// 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); + diff --git a/F3:F303/Multistepper/can.c b/F3:F303/Multistepper/can.c index 9e87afc..e8284fb 100644 --- a/F3:F303/Multistepper/can.c +++ b/F3:F303/Multistepper/can.c @@ -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 } diff --git a/F3:F303/Multistepper/commonproto.c b/F3:F303/Multistepper/commonproto.c index 3eedd1c..41df7bb 100644 --- a/F3:F303/Multistepper/commonproto.c +++ b/F3:F303/Multistepper/commonproto.c @@ -16,7 +16,10 @@ * along with this program. If not, see . */ +#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, diff --git a/F3:F303/Multistepper/hardware.c b/F3:F303/Multistepper/hardware.c index 14edb49..c79e38a 100644 --- a/F3:F303/Multistepper/hardware.c +++ b/F3:F303/Multistepper/hardware.c @@ -16,17 +16,79 @@ * along with this program. If not, see . */ +#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<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; +} diff --git a/F3:F303/Multistepper/hardware.h b/F3:F303/Multistepper/hardware.h index b9c4222..365af27 100644 --- a/F3:F303/Multistepper/hardware.h +++ b/F3:F303/Multistepper/hardware.h @@ -20,6 +20,11 @@ #include +// 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(); diff --git a/F3:F303/Multistepper/main.c b/F3:F303/Multistepper/main.c index 4d3a56f..9153a29 100644 --- a/F3:F303/Multistepper/main.c +++ b/F3:F303/Multistepper/main.c @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#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(); } } diff --git a/F3:F303/Multistepper/multistepper.bin b/F3:F303/Multistepper/multistepper.bin index 457e329e3d1adf88814078b2fc8018f391592b75..2dec223184bd2115daa10ec8e86c0a7f148f6383 100755 GIT binary patch delta 9962 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 delta 5870 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 Wt3>x#3n2}L|E=4Z>tn{`$o~KkdUpc= diff --git a/F3:F303/Multistepper/multistepper.files b/F3:F303/Multistepper/multistepper.files index 9527b27..a4821f4 100644 --- a/F3:F303/Multistepper/multistepper.files +++ b/F3:F303/Multistepper/multistepper.files @@ -1,3 +1,7 @@ +adc.c +adc.h +buttons.c +buttons.h can.c can.h commonproto.c diff --git a/F3:F303/Multistepper/proto.c b/F3:F303/Multistepper/proto.c index b2ce29d..14b22d0 100644 --- a/F3:F303/Multistepper/proto.c +++ b/F3:F303/Multistepper/proto.c @@ -19,6 +19,8 @@ #include #include +#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) /** diff --git a/F3:F303/Multistepper/strfunc.c b/F3:F303/Multistepper/strfunc.c index c006e59..13ba940 100644 --- a/F3:F303/Multistepper/strfunc.c +++ b/F3:F303/Multistepper/strfunc.c @@ -1,4 +1,6 @@ #include +#include +#include /** * @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; diff --git a/F3:F303/Multistepper/strfunc.h b/F3:F303/Multistepper/strfunc.h index a067ff8..7712bf7 100644 --- a/F3:F303/Multistepper/strfunc.h +++ b/F3:F303/Multistepper/strfunc.h @@ -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); diff --git a/F3:F303/Multistepper/version.inc b/F3:F303/Multistepper/version.inc index 5141e3b..f3c69a2 100644 --- a/F3:F303/Multistepper/version.inc +++ b/F3:F303/Multistepper/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "20" -#define BUILD_DATE "2023-02-13" +#define BUILD_NUMBER "30" +#define BUILD_DATE "2023-02-16"