From 3802f7d2cb5ae4b0002d50eb954330419a998e20 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Tue, 10 Mar 2026 22:40:45 +0300 Subject: [PATCH] add ADC & ADC monitoring --- F0:F030,F042,F072/usbcan_gpio/Readme.md | 3 + F0:F030,F042,F072/usbcan_gpio/adc.c | 158 ++++++++++++++++++ F0:F030,F042,F072/usbcan_gpio/adc.h | 30 ++++ F0:F030,F042,F072/usbcan_gpio/canproto.c | 6 +- F0:F030,F042,F072/usbcan_gpio/gpio.c | 64 ++++++- F0:F030,F042,F072/usbcan_gpio/gpio.h | 12 +- F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp | 72 ++++++-- F0:F030,F042,F072/usbcan_gpio/gpioproto.h | 3 + F0:F030,F042,F072/usbcan_gpio/hardware.c | 16 +- F0:F030,F042,F072/usbcan_gpio/hardware.h | 2 +- F0:F030,F042,F072/usbcan_gpio/main.c | 2 +- F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin | Bin 19140 -> 20564 bytes .../usbcan_gpio/usbcangpio.creator.user | 2 +- .../usbcan_gpio/usbcangpio.files | 2 + F0:F030,F042,F072/usbcan_gpio/version.inc | 2 +- 15 files changed, 338 insertions(+), 36 deletions(-) create mode 100644 F0:F030,F042,F072/usbcan_gpio/adc.c create mode 100644 F0:F030,F042,F072/usbcan_gpio/adc.h diff --git a/F0:F030,F042,F072/usbcan_gpio/Readme.md b/F0:F030,F042,F072/usbcan_gpio/Readme.md index f5a8006..f0291a7 100644 --- a/F0:F030,F042,F072/usbcan_gpio/Readme.md +++ b/F0:F030,F042,F072/usbcan_gpio/Readme.md @@ -10,3 +10,6 @@ The old USB-CAN is available as earlier by /dev/USB-CANx, also you can see new d New interface allows you to configure GPIO and use it's base functions: in/out/ADC. +## DMA channels + +DMA1 channel1: ADC. \ No newline at end of file diff --git a/F0:F030,F042,F072/usbcan_gpio/adc.c b/F0:F030,F042,F072/usbcan_gpio/adc.c new file mode 100644 index 0000000..3c25fe7 --- /dev/null +++ b/F0:F030,F042,F072/usbcan_gpio/adc.c @@ -0,0 +1,158 @@ +/* + * This file is part of the usbcangpio project. + * Copyright 2026 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 + +#include "adc.h" + +/** + * @brief ADC_array - array for ADC channels with median filtering: + * 0..3 - external channels + * 4 - internal Tsens + * 5 - Vref + */ +#define TSENS_CHAN (NUM_EXT_ADC_CH) +#define VREF_CHAN (NUM_EXT_ADC_CH + 1) +static uint16_t ADC_array[MAX_ADC_CHANNELS*9]; + +/* + * ADC channels: + * IN0 - V12 + * IN1 - V5 + * IN16- temperature sensor + * IN17- vref + */ +void adc_setup(){ + uint16_t ctr = 0; // 0xfff0 - more than 1.3ms + // Enable clocking + /* (1) Enable the peripheral clock of the ADC */ + /* (2) Start HSI14 RC oscillator */ + /* (3) Wait HSI14 is ready */ + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* (1) */ + RCC->CR2 |= RCC_CR2_HSI14ON; /* (2) */ + while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0 && ++ctr < 0xfff0){}; /* (3) */ + // calibration + /* (1) Ensure that ADEN = 0 */ + /* (2) Clear ADEN */ + /* (3) Launch the calibration by setting ADCAL */ + /* (4) Wait until ADCAL=0 */ + if ((ADC1->CR & ADC_CR_ADEN) != 0){ /* (1) */ + ADC1->CR &= (uint32_t)(~ADC_CR_ADEN); /* (2) */ + } + ADC1->CR |= ADC_CR_ADCAL; /* (3) */ + ctr = 0; // ADC calibration time is 5.9us + while ((ADC1->CR & ADC_CR_ADCAL) != 0 && ++ctr < 0xfff0){}; /* (4) */ + // enable ADC + ctr = 0; + do{ + ADC1->CR |= ADC_CR_ADEN; + }while ((ADC1->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0); + // configure ADC + /* (1) Select HSI14 by writing 00 in CKMODE (reset value) */ + /* (2) Select the continuous mode */ + /* (3) Select CHSEL0-9 - all ADC inputs, 16,17 - t. sensor and vref */ + /* (4) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us */ + /* (5) Wake-up the VREFINT and Temperature sensor (only for VBAT, Temp sensor and VRefInt) */ + // ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */ + ADC1->CFGR1 |= ADC_CFGR1_CONT; /* (2)*/ + ADC1->CHSELR = (0x3FF << 0) | ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; /* (3)*/ + ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */ + ADC->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN; /* (5) */ + // configure DMA for ADC + // DMA for AIN + /* (1) Enable the peripheral clock on DMA */ + /* (2) Enable DMA transfer on ADC and circular mode */ + /* (3) Configure the peripheral data register address */ + /* (4) Configure the memory address */ + /* (5) Configure the number of DMA tranfer to be performs on DMA channel 1 */ + /* (6) Configure increment, size, interrupts and circular mode */ + /* (7) Enable DMA Channel 1 */ + RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* (1) */ + ADC1->CFGR1 |= ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; /* (2) */ + DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); /* (3) */ + DMA1_Channel1->CMAR = (uint32_t)(ADC_array); /* (4) */ + DMA1_Channel1->CNDTR = MAX_ADC_CHANNELS * 9; /* (5) */ + DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC; /* (6) */ + DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */ + ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversions */ +} + + +/** + * @brief getADCval - calculate median value for `nch` channel + * @param nch - number of channel + * @return + */ +uint16_t getADCval(int nch){ + int i, addr = 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]; + for(i = 0; i < 9; ++i, addr += MAX_ADC_CHANNELS) // 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 +} + +// return MCU temperature (degrees of celsius * 10) +int32_t getMCUtemp(){ + int32_t ADval = getADCval(TSENS_CHAN); + int32_t temperature = (int32_t) *TEMP30_CAL_ADDR - ADval; + temperature *= (int32_t)(1100 - 300); + temperature /= (int32_t)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR); + temperature += 300; + return(temperature); +} + +// return Vdd * 100 (V) +uint32_t getVdd(){ + uint32_t vdd = ((uint32_t) *VREFINT_CAL_ADDR) * (uint32_t)330; // 3.3V + vdd /= getADCval(VREF_CHAN); + return vdd; +} + +static inline uint32_t Ufromadu(uint8_t nch, uint32_t vdd){ + uint32_t ADU = getADCval(nch); + ADU *= vdd; + ADU >>= 12; // /4096 + return ADU; +} + +/** + * @brief getUval - calculate U12/U5 + * @return array with members: + * 0 - V12 * 100V (U12 = 12Vin/4.93) + * 1 - V5 * 100V (U5 = 5Vin /2) + */ +uint16_t *getUval(){ + static uint16_t Uval[4]; + uint32_t vdd = getVdd(); + uint32_t val = Ufromadu(0, vdd) * 493; + Uval[0] = (uint16_t)(val / 100); + Uval[1] = (uint16_t)(Ufromadu(1, vdd) << 1); + return Uval; +} diff --git a/F0:F030,F042,F072/usbcan_gpio/adc.h b/F0:F030,F042,F072/usbcan_gpio/adc.h new file mode 100644 index 0000000..11ecbe4 --- /dev/null +++ b/F0:F030,F042,F072/usbcan_gpio/adc.h @@ -0,0 +1,30 @@ +/* + * This file is part of the usbcangpio project. + * Copyright 2026 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 + +// 10 ADC ins + VDD + MCUt +#define NUM_EXT_ADC_CH 10 +#define MAX_ADC_CHANNELS (NUM_EXT_ADC_CH+2) + +int32_t getMCUtemp(); +uint32_t getVdd(); +uint16_t getADCval(int nch); +void adc_setup(); +uint16_t *getUval(); diff --git a/F0:F030,F042,F072/usbcan_gpio/canproto.c b/F0:F030,F042,F072/usbcan_gpio/canproto.c index 2f6da31..cacfe94 100644 --- a/F0:F030,F042,F072/usbcan_gpio/canproto.c +++ b/F0:F030,F042,F072/usbcan_gpio/canproto.c @@ -337,11 +337,11 @@ TRUE_INLINE void getcanstat(){ } /** - * @brief cmd_parser - command parsing + * @brief CommandParser - command parsing * @param txt - buffer with commands & data * @param isUSB - == 1 if data got from USB */ -static void cmd_parser(char *txt){ +static void CommandParser(char *txt){ char _1st = txt[0]; ++txt; /* @@ -479,5 +479,5 @@ void CANUSB_process(){ } int l = RECV(inbuff, MAXSTRLEN); if(l < 0) SEND("ERROR: USB buffer overflow or string was too long\n"); - else if(l) cmd_parser(inbuff); + else if(l) CommandParser(inbuff); } diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.c b/F0:F030,F042,F072/usbcan_gpio/gpio.c index 5b222c9..8df5540 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpio.c +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.c @@ -19,10 +19,11 @@ #include #include +#include "adc.h" #include "flash.h" #include "gpio.h" -static uint16_t monitor_mask[2] = {0}; // pins to monitor == 1 (ONLY GPIO!!!) +static uint16_t monitor_mask[2] = {0}; // pins to monitor == 1 (ONLY GPIO and ADC) static uint16_t oldstates[2][16] = {0}; // previous state (16 bits - as some pins could be analog) // strings for keywords @@ -134,6 +135,22 @@ int set_pinfunc(uint8_t port, uint8_t pin, pinconfig_t *pcfg){ return TRUE; } +/** + * @brief get_adc_channel - get ADC channel number for given pin + * @param port - 0/1 (GPIOA/GPIOB) + * @param pin - 0..16 + * @return ADC channel number or -1 + */ +TRUE_INLINE int8_t get_adc_channel(uint8_t port, uint8_t pin){ + if(port == 0){ // GPIOA + if (pin <= 7) return pin; // PA0..PA7 -> IN0..IN7 + }else{ // GPIOB + if(pin == 0) return 8; // PB0 -> IN8 + if(pin == 1) return 9; // PB1 -> IN9 + } + return -1; // No ADC channel on this pin +} + // reinit all GPIO registers due to config; also configure (if need) USART1/2, SPI1 and I2C1 int gpio_reinit(){ bzero(monitor_mask, sizeof(monitor_mask)); @@ -167,7 +184,19 @@ int gpio_reinit(){ int shift4 = (pin - 8) << 4; gpio->AFR[1] = (gpio->AFR[1] & ~(0xf << shift4)) | (cfg->afno << shift4); } - if(cfg->monitor && cfg->mode != MODE_AF) monitor_mask[port] |= (1 << pin); + if(cfg->monitor && cfg->mode != MODE_AF){ + monitor_mask[port] |= (1 << pin); + if(cfg->mode == MODE_ANALOG){ + if(cfg->threshold > 4095) cfg->threshold = 4095; // no threshold + int8_t chan = get_adc_channel(port, pin); + if(chan >= 0){ + oldstates[port][pin] = getADCval(chan); + } + }else{ + // цифровой режим  сохраняем текущее состояние IDR + oldstates[port][pin] = (gpio->IDR >> pin) & 1; + } + } } } // TODO: configure USART, SPI etc @@ -216,8 +245,14 @@ int16_t pin_in(uint8_t port, uint8_t pin){ if(GPIOx->IDR & (1<= 0){ + return (int16_t)getADCval(chan); // getADCval возвращает uint16_t + } + } + break; + default: break; } return val; @@ -241,11 +276,22 @@ uint16_t gpio_alert(uint8_t port){ uint8_t curm = moder & 3; if((curm == MODE_AF) || 0 == (monitor_mask[port] & curpinbit)) continue; // monitor also OUT (if OD) // TODO: add AIN - if(curm == MODE_ANALOG) continue; - uint16_t curval = (GPIOx->IDR & curpinbit) ? 1 : 0; - if(oldstate[pin] != curval){ - oldstate[pin] = curval; - alert |= curpinbit; + if(curm == MODE_ANALOG){ + int8_t chan = get_adc_channel(port, pin); + if(chan < 0) continue; // can't be in normal case + uint16_t cur = getADCval(chan); + uint16_t thresh = the_conf.pinconfig[port][pin].threshold; + uint16_t diff = (cur > oldstate[pin]) ? (cur - oldstate[pin]) : (oldstate[pin] - cur); + if(diff > thresh){ + oldstate[pin] = cur; + alert |= curpinbit; + } + }else{ + uint16_t curval = (GPIOx->IDR & curpinbit) ? 1 : 0; + if(oldstate[pin] != curval){ + oldstate[pin] = curval; + alert |= curpinbit; + } } } return alert; diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.h b/F0:F030,F042,F072/usbcan_gpio/gpio.h index a35c602..10ce618 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpio.h +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.h @@ -78,14 +78,15 @@ typedef union{ } funcvalues_t; */ typedef struct{ - uint8_t enable : 1; // [immutable!] pin config avialable (==1 for PA0-PA3, PA5-PA7, PA9, PA10, PB0-PB7, PB10, PB11, ==0 for rest) + uint8_t enable : 1; // [immutable!] pin config avialable (==1 for PA0-PA3, PA5-PA7, PA9, PA10, PB0-PB7, PB10, PB11, ==0 for rest) pinmode_t mode : 2; pinpull_t pull : 2; pinout_t otype : 1; pinspeed_t speed : 2; - uint8_t afno : 3; // alternate function number (only if mode == MODE_AF) - uint8_t af : 3; // alternate function name (`FuncNames`) - uint8_t monitor : 1; // monitor changes + uint8_t afno : 3; // alternate function number (only if mode == MODE_AF) + uint8_t af : 3; // alternate function name (`FuncNames`) + uint8_t monitor : 1; // monitor changes + uint16_t threshold; // threshold for ADC measurement } pinconfig_t; typedef struct{ @@ -119,7 +120,8 @@ KW(OD) \ KW(USART) \ KW(SPI) \ KW(I2C) \ -KW(MONITOR) +KW(MONITOR) \ +KW(THRESHOLD) enum{ // indexes of string keywords #define KW(k) STR_ ## k, diff --git a/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp b/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp index 8f6d180..26763bf 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp +++ b/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp @@ -22,6 +22,7 @@ extern "C"{ #include +#include "adc.h" #include "can.h" #include "flash.h" #include "gpioproto.h" @@ -43,6 +44,7 @@ extern volatile uint32_t Tms; COMMAND(dumpconf, "dump current configuration") \ COMMAND(eraseflash, "erase full flash storage") \ COMMAND(help, "show this help") \ + COMMAND(mcutemp, "get MCU temperature (degC*10)") \ COMMAND(mcureset, "reset MCU") \ COMMAND(PA, "GPIOA setter/getter (type PA0=help for further info)") \ COMMAND(PB, "GPIOB setter/getter") \ @@ -52,7 +54,8 @@ extern volatile uint32_t Tms; COMMAND(sendcan, "send all after '=' to CAN USB interface") \ COMMAND(setiface, "set/get name of interface x (0 - CAN, 1 - GPIO)") \ COMMAND(storeconf, "save config to flash") \ - COMMAND(time, "show current time (ms)") + COMMAND(time, "show current time (ms)") \ + COMMAND(vdd, "get approx Vdd value (V*100)") // COMMAND(USART, "Read USART data or send (USART=hex)") // COMMAND(usartconf, "set USART params (e.g. usartconf=115200 8N1)") @@ -93,6 +96,7 @@ enum KeywordGroup { enum MiscValues{ MISC_MONITOR = 1, + MISC_THRESHOLD }; static const Keyword keywords[] = { @@ -110,6 +114,7 @@ static const Keyword keywords[] = { KEY(SPI, GROUP_FUNC, FUNC_SPI) KEY(I2C, GROUP_FUNC, FUNC_I2C) KEY(MONITOR, GROUP_MISC, MISC_MONITOR) + KEY(THRESHOLD, GROUP_MISC, MISC_THRESHOLD) #undef K }; #define NUM_KEYWORDS (sizeof(keywords)/sizeof(keywords[0])) @@ -129,11 +134,18 @@ static const char *pinhelp = " PULL: PU, PD or FL (pullup, pulldown, no pull - floating)\n" " OTYPE: PP or OD (push-pull or open-drain)\n" " FUNC: USART or SPI (enable alternate function and configure peripheal)\n" - " MISC: MONITOR (send data by USB as only state changed)\n\n" + " MISC: MONITOR - send data by USB as only state changed\n" + " THRESHOLD (ADC only) - monitoring threshold, ADU\n" + "\n" ; static 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) + /** * @brief splitargs - get command parameter and setter from `args` * @param args (i) - rest of string after command (like `1 = PU OD OUT`) @@ -201,8 +213,19 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ // complex setter: parse properties uint8_t mode_set = 0xFF, pull_set = 0xFF, otype_set = 0xFF, func_set = 0xFF; bool monitor = false; + uint16_t *pending_num = NULL; // pointer to UINT16 value, if !NULL, next token should be a number + pinconfig_t curconf = the_conf.pinconfig[port][pin]; // copy old config char *saveptr, *token = strtok_r(setter, " ,", &saveptr); while(token){ + if(pending_num){ + int32_t val; + char *end = getint(token, &val); + if(end == token || val < 0 || val > 0xFFFF) return ERR_BADVAL; + *pending_num = (uint16_t)val; + pending_num = NULL; // reset + token = strtok_r(NULL, " ,", &saveptr); + continue; + } size_t i = 0; for(; i < NUM_KEYWORDS; i++){ if(strcmp(token, str_keywords[keywords[i].index]) == 0){ @@ -229,8 +252,14 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ break; case GROUP_MISC: DBG("GROUP_MISC\n"); - if(keywords[i].value == MISC_MONITOR) monitor = true; - break; + switch(keywords[i].value){ + case MISC_MONITOR: + monitor = true; + break; + case MISC_THRESHOLD: + pending_num = &curconf.threshold; + break; + } } break; } @@ -238,6 +267,7 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ if(i == NUM_KEYWORDS) return ERR_BADVAL; // not found token = strtok_r(NULL, " ,", &saveptr); } + if(pending_num) return ERR_BADVAL; // no number that we waiting for if(func_set != 0xFF) mode_set = MODE_AF; if(mode_set == 0xFF) return ERR_BADVAL; // user forgot to set mode // set defaults @@ -245,7 +275,6 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ if(otype_set == 0xFF) otype_set = OUTPUT_PP; // can also do something with `speed_set`, then remove SPEED_MEDIUM from `curconfig` // check that current parameters combination is acceptable for current pin - pinconfig_t curconf; curconf.mode = static_cast (mode_set); curconf.pull = static_cast (pull_set); curconf.otype = static_cast (otype_set); @@ -301,12 +330,14 @@ static errcodes_t cmd_canspeed(const char *cmd, char *args){ if(S < CAN_MIN_SPEED || S > CAN_MAX_SPEED) return ERR_BADVAL; the_conf.CANspeed = S; } - SEND(cmd); PUTCHAR('='); SENDn(u2str(the_conf.CANspeed)); + CMDEQ(); + SENDn(u2str(the_conf.CANspeed)); return ERR_AMOUNT; } static errcodes_t cmd_curcanspeed(const char *cmd, char _U_ *args){ - SEND(cmd); PUTCHAR('='); SENDn(u2str(CAN_getspeed())); + CMDEQ(); + SENDn(u2str(CAN_getspeed())); return ERR_AMOUNT; } @@ -350,6 +381,11 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){ break; case MODE_ANALOG: S(AIN); + if(p->threshold){ + SP(THRESHOLD); + PUTCHAR(' '); + SEND(u2str(p->threshold)); + } break; case MODE_AF: switch(p->af){ @@ -430,7 +466,7 @@ static errcodes_t cmd_setiface(const char* cmd, char *args){ } } // getter - SEND(cmd); PUTCHAR('='); + CMDEQP(N); char *ptr = (char*) the_conf.iInterface[N]; int l = the_conf.iIlengths[N] / 2; for(int j = 0; j < l; ++j){ @@ -446,11 +482,13 @@ static errcodes_t cmd_sendcan(const char _U_ *cmd, char *args){ char *setter = splitargs(args, NULL); if(!setter) return ERR_BADVAL; if(USB_sendstr(ICAN, setter)) return ERR_OK; + USB_putbyte(ICAN, '\n'); return ERR_CANTRUN; } static errcodes_t cmd_time(const char *cmd, char _U_ *args){ - SEND(cmd); PUTCHAR('='); SENDn(u2str(Tms)); + CMDEQ(); + SENDn(u2str(Tms)); return ERR_AMOUNT; } @@ -474,6 +512,18 @@ static errcodes_t cmd_eraseflash(const char _U_ *cmd, char _U_ *args){ return ERR_OK; } +static errcodes_t cmd_mcutemp(const char *cmd, char _U_ *args){ + CMDEQ(); + SENDn(i2str(getMCUtemp())); + return ERR_AMOUNT; +} + +static errcodes_t cmd_vdd(const char *cmd, char _U_ *args){ + CMDEQ(); + SENDn(u2str(getVdd())); + return ERR_AMOUNT; +} + static errcodes_t cmd_help(const char _U_ *cmd, char _U_ *args){ SEND(REPOURL); for(size_t i = 0; i < sizeof(cmdInfo)/sizeof(cmdInfo[0]); i++){ @@ -490,7 +540,7 @@ constexpr uint32_t hash(const char* str, uint32_t h = 0){ // TODO: add checking real command length! -static const char *cmd_parser(char *str){ +static const char *CommandParser(char *str){ char command[CMD_MAXLEN+1]; int i = 0; while(*str > '@' && i < CMD_MAXLEN){ command[i++] = *str++; } @@ -524,7 +574,7 @@ void GPIO_process(){ if(l == 0) return; if(l < 0) SEND("ERROR: USB buffer overflow or string was too long\n"); else{ - const char *ans = cmd_parser(inbuff); + const char *ans = CommandParser(inbuff); if(ans) SENDn(ans); } } diff --git a/F0:F030,F042,F072/usbcan_gpio/gpioproto.h b/F0:F030,F042,F072/usbcan_gpio/gpioproto.h index ff5390c..6f5478e 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpioproto.h +++ b/F0:F030,F042,F072/usbcan_gpio/gpioproto.h @@ -34,4 +34,7 @@ typedef enum{ // maximal available parameter number #define MAXPARNO 255 +// default threshold for monitoring +#define ADC_THRES_DEFAULT 100 + void GPIO_process(); diff --git a/F0:F030,F042,F072/usbcan_gpio/hardware.c b/F0:F030,F042,F072/usbcan_gpio/hardware.c index a64c064..eae568c 100644 --- a/F0:F030,F042,F072/usbcan_gpio/hardware.c +++ b/F0:F030,F042,F072/usbcan_gpio/hardware.c @@ -16,22 +16,30 @@ * along with this program. If not, see . */ +#include "adc.h" +#include "gpio.h" #include "hardware.h" uint8_t ledsON = 0; -void gpio_setup(void){ - // enable all active GPIO clocking - RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; +TRUE_INLINE void gpio_setup(){ // setup some common GPIO // Set LEDS (PB15/PA8) as output pin_set(LED0_port, LED0_pin); // clear LEDs pin_set(LED1_port, LED1_pin); GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER15)) | - GPIO_MODER_MODER15_O; + GPIO_MODER_MODER15_O; GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER8)) | GPIO_MODER_MODER8_O; } +void hardware_setup(){ + // enable all active GPIO clocking + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; + gpio_setup(); + //gpio_reinit(); + adc_setup(); +} + void iwdg_setup(){ uint32_t tmout = 16000000; /* Enable the peripheral clock RTC */ diff --git a/F0:F030,F042,F072/usbcan_gpio/hardware.h b/F0:F030,F042,F072/usbcan_gpio/hardware.h index d93dccc..d70d44d 100644 --- a/F0:F030,F042,F072/usbcan_gpio/hardware.h +++ b/F0:F030,F042,F072/usbcan_gpio/hardware.h @@ -44,7 +44,7 @@ extern volatile uint32_t Tms; extern uint8_t ledsON; -void gpio_setup(void); +void hardware_setup(); void iwdg_setup(); #ifdef STM32F072xB void Jump2Boot(); diff --git a/F0:F030,F042,F072/usbcan_gpio/main.c b/F0:F030,F042,F072/usbcan_gpio/main.c index 9c6a9e2..e9ce141 100644 --- a/F0:F030,F042,F072/usbcan_gpio/main.c +++ b/F0:F030,F042,F072/usbcan_gpio/main.c @@ -33,7 +33,7 @@ int main(void){ sysreset(); SysTick_Config(6000, 1); flashstorage_init(); - gpio_setup(); + hardware_setup(); USB_setup(); CAN_setup(the_conf.CANspeed); RCC->CSR |= RCC_CSR_RMVF; // remove reset flags diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin index 0dab055305a08a5541c7f857a0ed8eb210f4b7b3..3e42d3714016d5d70aec5bbbac1c85a9f1671a01 100755 GIT binary patch delta 10048 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 delta 8524 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 F{{>JRh%o>F diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user index 3ba89ad..407bc5f 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user +++ b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files index 5101e54..a18589b 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files +++ b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files @@ -1,3 +1,5 @@ +adc.c +adc.h can.c can.h canproto.c diff --git a/F0:F030,F042,F072/usbcan_gpio/version.inc b/F0:F030,F042,F072/usbcan_gpio/version.inc index d504585..e4c8082 100644 --- a/F0:F030,F042,F072/usbcan_gpio/version.inc +++ b/F0:F030,F042,F072/usbcan_gpio/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "125" +#define BUILD_NUMBER "132" #define BUILD_DATE "2026-03-10"