diff --git a/F0-nolib/F0_testbrd/adc.c b/F0-nolib/F0_testbrd/adc.c index fa786bb..856137c 100644 --- a/F0-nolib/F0_testbrd/adc.c +++ b/F0-nolib/F0_testbrd/adc.c @@ -22,11 +22,12 @@ * @brief ADC_array - array for ADC channels with median filtering: * 0 - Rvar * 1 - Rvar/2 - * 2 - internal Tsens - * 3 - Vref + * 2 - AIN5/DAC_OUT1 + * 3 - internal Tsens + * 4 - Vref */ -#define CHTSENS (2) -#define CHVREF (3) +#define CHTSENS (3) +#define CHVREF (4) uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9]; /** @@ -55,7 +56,7 @@ uint16_t getADCval(int nch){ } // get voltage @input nch (1/100V) -uint32_t getADCvoltate(int nch){ +uint32_t getADCvoltage(int nch){ uint32_t v = getADCval(nch); v *= getVdd(); v /= 0xfff; // 12bit ADC diff --git a/F0-nolib/F0_testbrd/adc.h b/F0-nolib/F0_testbrd/adc.h index d797087..9668c0e 100644 --- a/F0-nolib/F0_testbrd/adc.h +++ b/F0-nolib/F0_testbrd/adc.h @@ -19,12 +19,13 @@ #define ADC_H #include "stm32f0.h" -#define NUMBER_OF_ADC_CHANNELS (4) +#define NUMBER_OF_ADC_CHANNELS (5) extern uint16_t ADC_array[]; + int32_t getMCUtemp(); uint32_t getVdd(); uint16_t getADCval(int nch); -uint32_t getADCvoltate(int nch); +uint32_t getADCvoltage(int nch); #endif // ADC_H diff --git a/F0-nolib/F0_testbrd/hardware.c b/F0-nolib/F0_testbrd/hardware.c index 021ed31..f9a0fa2 100644 --- a/F0-nolib/F0_testbrd/hardware.c +++ b/F0-nolib/F0_testbrd/hardware.c @@ -23,6 +23,7 @@ #include "adc.h" #include "hardware.h" +#include "proto.h" void iwdg_setup(){ uint32_t tmout = 16000000; @@ -50,21 +51,18 @@ void iwdg_setup(){ static inline void gpio_setup(){ // here we turn on clocking for all periph. RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMAEN; - // Set LEDS (PA6-8, PB0/1) as Oun & AF (PWM) - GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7 | GPIO_MODER_MODER8)) | - GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF | GPIO_MODER_MODER8_AF; - GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER0 | GPIO_MODER_MODER1)) | - GPIO_MODER_MODER0_AF | GPIO_MODER_MODER1_AF; + // Set LEDS (PA6-8, PB0/1) as Out & AF (PWM); PA0,1,5 - AIN, PA4 - DAC + GPIOA->MODER = GPIO_MODER_MODER0_AI | GPIO_MODER_MODER1_AI | GPIO_MODER_MODER4_AI | + GPIO_MODER_MODER5_AI | GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF | GPIO_MODER_MODER8_AF; + GPIOB->MODER = GPIO_MODER_MODER0_AF | GPIO_MODER_MODER1_AF; // alternate functions: PA6-8: TIM3CH1,2 and TIM1_CH1 (AF1, AF1, AF2) - // PB0-1: TIM3CH3,4 (AF1, AF1) - GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) | - (1 << (6 * 4)) | (1 << (7 * 4)); - GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH0)) | - (2 << (0 * 4)); - GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL0 | GPIO_AFRL_AFRL1)) | - (1 << (0 * 4)) | (1 << (1 * 4)); + // PB0-1: TIM3CH3,4 (AF1, AF1), + GPIOA->AFR[0] = (1 << (6 * 4)) | (1 << (7 * 4)); + GPIOA->AFR[1] = (2 << (0 * 4)); + GPIOB->AFR[0] = (1 << (0 * 4)) | (1 << (1 * 4)); } +// Setup ADC and DAC static inline void adc_setup(){ uint16_t ctr = 0; // 0xfff0 - more than 1.3ms // Enable clocking @@ -90,15 +88,15 @@ static inline void adc_setup(){ do{ ADC1->CR |= ADC_CR_ADEN; }while ((ADC1->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0); - // configure ADC + // configure ADC to generate a triangle wave on DAC1_OUT synchronized by TIM6 HW trigger /* (1) Select HSI14 by writing 00 in CKMODE (reset value) */ /* (2) Select the continuous mode */ - /* (3) Select CHSEL0,1 - ADC inputs, 16,17 - t. sensor and vref */ + /* (3) Select CHSEL0,1,5 - 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 = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; /* (3)*/ + ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL5 | 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 @@ -118,6 +116,27 @@ static inline void adc_setup(){ 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 */ + // DAC + /* (1) Enable the peripheral clock of the DAC */ + /* (2) Configure WAVEx at 10, + Configure mask amplitude for ch1 (MAMP1) at 1011 for a 4095-bits amplitude + enable the DAC ch1, disable buffer on ch1, + and select TIM6 as trigger by keeping 000 in TSEL1 */ + RCC->APB1ENR |= RCC_APB1ENR_DACEN; /* (1) */ + DAC->CR |= DAC_CR_WAVE1_1 + | DAC_CR_MAMP1_3 | DAC_CR_MAMP1_1 | DAC_CR_MAMP1_0 + | DAC_CR_BOFF1 | DAC_CR_TEN1 | DAC_CR_EN1; /* (2) */ + // configure the Timer 6 to generate an external trigger on TRGO each microsecond + /* (1) Enable the peripheral clock of the TIM6 */ + /* (2) Configure MMS=010 to output a rising edge at each update event */ + /* (3) Select PCLK/2 i.e. 48MHz/2=24MHz */ + /* (4) Set one update event each 1 microsecond */ + /* (5) Enable TIM6 */ + RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; /* (1) */ + TIM6->CR2 |= TIM_CR2_MMS_1; /* (2) */ + TIM6->PSC = 1; /* (3) */ + TIM6->ARR = (uint16_t)24; /* (4) */ + TIM6->CR1 |= TIM_CR1_CEN; /* (5) */ } static inline void pwm_setup(){ diff --git a/F0-nolib/F0_testbrd/i2c.c b/F0-nolib/F0_testbrd/i2c.c new file mode 100644 index 0000000..bd08689 --- /dev/null +++ b/F0-nolib/F0_testbrd/i2c.c @@ -0,0 +1,194 @@ +/* + * geany_encoding=koi8-r + * i2c.c + * + * Copyright 2017 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#include "hardware.h" +#include "i2c.h" +#include "proto.h" +#include "usb.h" + +I2C_SPEED curI2Cspeed = LOW_SPEED; +extern volatile uint32_t Tms; +static uint32_t cntr; +volatile uint8_t I2C_scan_mode = 0; // == 1 when I2C is in scan mode +static uint8_t i2caddr = I2C_ADDREND; // not active + +void i2c_setup(I2C_SPEED speed){ + if(speed >= CURRENT_SPEED){ + speed = curI2Cspeed; + }else{ + curI2Cspeed = speed; + } + I2C1->CR1 = 0; +/* + * GPIO Resources: I2C1_SCL - PB6, I2C1_SDA - PB7 (AF1) + */ + GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) | + 1 << (6 * 4) | 1 << (7 * 4); + GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) | + GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF; + GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7; // both open-drain outputs + // I2C + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // timing + RCC->CFGR3 |= RCC_CFGR3_I2C1SW; // use sysclock for timing + if(speed == LOW_SPEED){ // 10kHz + // PRESC=B, SCLDEL=4, SDADEL=2, SCLH=0xC3, SCLL=0xB0 + I2C1->TIMINGR = (0xB<<28) | (4<<20) | (2<<16) | (0xC3<<8) | (0xB0); + }else if(speed == HIGH_SPEED){ // 100kHz + I2C1->TIMINGR = (0xB<<28) | (4<<20) | (2<<16) | (0x12<<8) | (0x11); + }else{ // VERYLOW_SPEED - the lowest speed by STM register: 5.8kHz (presc = 16-1 = 15; ) + I2C1->TIMINGR = (0xf<<28) | (4<<20) | (2<<16) | (0xff<<8) | (0xff); + } + I2C1->CR1 = I2C_CR1_PE; +} + + +/** + * write command byte to I2C + * @param addr - device address (TSYS01_ADDR0 or TSYS01_ADDR1) + * @param data - bytes to write + * @param nbytes - amount of bytes to write + * @param stop - to set STOP + * @return 0 if error + */ +static uint8_t write_i2cs(uint8_t addr, uint8_t *data, uint8_t nbytes, uint8_t stop){ + cntr = Tms; + I2C1->CR1 = 0; // clear busy flag + I2C1->ICR = 0x3f38; // clear all errors + I2C1->CR1 = I2C_CR1_PE; + while(I2C1->ISR & I2C_ISR_BUSY){ + IWDG->KR = IWDG_REFRESH; + if(Tms - cntr > I2C_TIMEOUT){ + USND("Line busy\n"); + return 0; // check busy + }} + cntr = Tms; + while(I2C1->CR2 & I2C_CR2_START){ + IWDG->KR = IWDG_REFRESH; + if(Tms - cntr > I2C_TIMEOUT){ + return 0; // check start + }} + //I2C1->ICR = 0x3f38; // clear all errors + I2C1->CR2 = nbytes << 16 | addr; + if(stop) I2C1->CR2 |= I2C_CR2_AUTOEND; // autoend + // now start transfer + I2C1->CR2 |= I2C_CR2_START; + for(int i = 0; i < nbytes; ++i){ + cntr = Tms; + while(!(I2C1->ISR & I2C_ISR_TXIS)){ // ready to transmit + IWDG->KR = IWDG_REFRESH; + if(I2C1->ISR & I2C_ISR_NACKF){ + I2C1->ICR |= I2C_ICR_NACKCF; + USND("NAK\n"); + return 0; + } + if(Tms - cntr > I2C_TIMEOUT){ + USND("Timeout\n"); + return 0; + } + } + I2C1->TXDR = data[i]; // send data + } + // wait for data gone + while(I2C1->ISR & I2C_ISR_BUSY){ + IWDG->KR = IWDG_REFRESH; + if(Tms - cntr > I2C_TIMEOUT){break;} + } + return 1; +} + +uint8_t write_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes){ + return write_i2cs(addr, data, nbytes, 1); +} + +/** + * read nbytes of data from I2C line + * `data` should be an array with at least `nbytes` length + * @return 1 if all OK, 0 if NACK or no device found + */ +static uint8_t read_i2cb(uint8_t addr, uint8_t *data, uint8_t nbytes, uint8_t busychk){ + if(busychk){ + cntr = Tms; + while(I2C1->ISR & I2C_ISR_BUSY){ + IWDG->KR = IWDG_REFRESH; + if(Tms - cntr > I2C_TIMEOUT){ + USND("Line busy\n"); + return 0; // check busy + }} + } + cntr = Tms; + while(I2C1->CR2 & I2C_CR2_START){ + IWDG->KR = IWDG_REFRESH; + if(Tms - cntr > I2C_TIMEOUT){ + USND("No start\n"); + return 0; // check start + }} + // read N bytes + I2C1->CR2 = (nbytes<<16) | addr | 1 | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN; + I2C1->CR2 |= I2C_CR2_START; + uint8_t i; + for(i = 0; i < nbytes; ++i){ + cntr = Tms; + while(!(I2C1->ISR & I2C_ISR_RXNE)){ // wait for data + IWDG->KR = IWDG_REFRESH; + if(I2C1->ISR & I2C_ISR_NACKF){ + I2C1->ICR |= I2C_ICR_NACKCF; + USND("NAK\n"); + return 0; + } + if(Tms - cntr > I2C_TIMEOUT){ + USND("Timeout\n"); + return 0; + } + } + *data++ = I2C1->RXDR; + } + return 1; + } + +uint8_t read_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes){ + return read_i2cb(addr, data, nbytes, 1); +} + +// read register reg +uint8_t read_i2c_reg(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t nbytes){ + if(!write_i2cs(addr, ®, 1, 0)) return 0; + return read_i2cb(addr, data, nbytes, 0); +} + +void i2c_init_scan_mode(){ + i2caddr = 0; + I2C_scan_mode = 1; +} + +// return 1 if next addr is active & return in as `addr` +// if addresses are over, return 1 and set addr to I2C_NOADDR +// if scan mode inactive, return 0 and set addr to I2C_NOADDR +int i2c_scan_next_addr(uint8_t *addr){ + *addr = i2caddr; + if(i2caddr == I2C_ADDREND){ + *addr = I2C_ADDREND; + I2C_scan_mode = 0; + return 0; + } + if(!read_i2c_reg((i2caddr++)<<1, 0, NULL, 0)) return 0; + return 1; +} diff --git a/F0-nolib/F0_testbrd/i2c.h b/F0-nolib/F0_testbrd/i2c.h new file mode 100644 index 0000000..dc3bed3 --- /dev/null +++ b/F0-nolib/F0_testbrd/i2c.h @@ -0,0 +1,47 @@ +/* + * This file is part of the F0testbrd project. + * Copyright 2021 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 +#ifndef I2C_H__ +#define I2C_H__ + +#include "stm32f0.h" + +#define I2C_ADDREND (0x80) + +typedef enum{ + VERYLOW_SPEED, + LOW_SPEED, + HIGH_SPEED, + CURRENT_SPEED +} I2C_SPEED; + +extern I2C_SPEED curI2Cspeed; +extern volatile uint8_t I2C_scan_mode; + +// timeout of I2C bus in ms +#define I2C_TIMEOUT (100) + +void i2c_setup(I2C_SPEED speed); +uint8_t read_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes); +uint8_t read_i2c_reg(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t nbytes); +uint8_t write_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes); + +void i2c_init_scan_mode(); +int i2c_scan_next_addr(uint8_t *addr); + +#endif // I2C_H__ diff --git a/F0-nolib/F0_testbrd/main.c b/F0-nolib/F0_testbrd/main.c index ca228e1..1566357 100644 --- a/F0-nolib/F0_testbrd/main.c +++ b/F0-nolib/F0_testbrd/main.c @@ -21,11 +21,15 @@ #include "adc.h" #include "hardware.h" -#include "usart.h" +#include "i2c.h" #include "proto.h" +#include "usart.h" #include "usb.h" #include "usb_lib.h" +// ADC value threshold for meaning it is new +#define ADCthreshold (20) + volatile uint32_t Tms = 0; /* Called when systick fires */ @@ -33,6 +37,9 @@ void sys_tick_handler(void){ ++Tms; } +volatile uint8_t ADCmon = 0; // ==1 to monitor ADC (change PWM of LEDS & show current value) +uint16_t oldADCval = 0; + int main(void){ uint32_t lastT = 0; sysreset(); @@ -48,9 +55,33 @@ int main(void){ while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog if(lastT > Tms || Tms - lastT > 499){ + if(ADCmon){ + uint16_t v = getADCval(0); + int32_t d = v - oldADCval; + if(d < -ADCthreshold || d > ADCthreshold){ + oldADCval = v; + printADCvals(); + v >>= 2; // 10 bits + TIM3->CCR1 = TIM3->CCR2 = TIM3->CCR3 = 0xff; TIM3->CCR4 = 0; + if(v >= 0x300) TIM3->CCR4 = v - 0x300; + else if(v >= 0x200) TIM3->CCR3 = v - 0x200; + else if(v >= 0x100){ TIM3->CCR2 = v - 0x100; TIM3->CCR3 = 0; } + else{ TIM3->CCR1 = v; TIM3->CCR2 = TIM3->CCR3 = 0; } + } + } lastT = Tms; transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s } + if(I2C_scan_mode){ + uint8_t addr; + int ok = i2c_scan_next_addr(&addr); + if(addr == I2C_ADDREND) USND("Scan ends\n"); + else if(ok){ + USB_sendstr(uhex2str(addr)); + USND(" ("); USB_sendstr(u2str(addr)); + USND(") - found device\n"); + } + } usb_proc(); char *txt; if((txt = get_USB())){ diff --git a/F0-nolib/F0_testbrd/pl2303.bin b/F0-nolib/F0_testbrd/pl2303.bin index 72d91b7..5b88d64 100755 Binary files a/F0-nolib/F0_testbrd/pl2303.bin and b/F0-nolib/F0_testbrd/pl2303.bin differ diff --git a/F0-nolib/F0_testbrd/proto.c b/F0-nolib/F0_testbrd/proto.c index b0dbad4..5b05901 100644 --- a/F0-nolib/F0_testbrd/proto.c +++ b/F0-nolib/F0_testbrd/proto.c @@ -17,6 +17,7 @@ */ #include "adc.h" +#include "i2c.h" #include "proto.h" #include "usart.h" #include "usb.h" @@ -29,7 +30,7 @@ void USB_sendstr(const char *str){ USB_send((const uint8_t*)str, l); } -static char *chPWM(volatile uint32_t *reg, char *buf){ +static inline char *chPWM(volatile uint32_t *reg, char *buf){ char *lbuf = buf; lbuf = omit_spaces(lbuf); char cmd = *lbuf; @@ -50,14 +51,14 @@ static char *chPWM(volatile uint32_t *reg, char *buf){ return "OK"; } -static char *TIM3pwm(char *buf){ +static inline char *TIM3pwm(char *buf){ uint8_t channel = *buf - '1'; if(channel > 3) return "Wrong channel number"; volatile uint32_t *reg = &TIM3->CCR1; return chPWM(®[channel], buf+1); } -static char *getPWMvals(){ +static inline char *getPWMvals(){ USND("TIM1CH1: "); USB_sendstr(u2str(TIM1->CCR1)); USND("\nTIM3CH1: "); USB_sendstr(u2str(TIM3->CCR1)); USND("\nTIM3CH2: "); USB_sendstr(u2str(TIM3->CCR2)); @@ -67,7 +68,7 @@ static char *getPWMvals(){ return NULL; } -static char *USARTsend(char *buf){ +static inline char *USARTsend(char *buf){ uint32_t N; if(buf == getnum(buf, &N)) return "Point number of USART"; if(N < 1 || N > USARTNUM) return "Wrong USART number"; @@ -77,20 +78,103 @@ static char *USARTsend(char *buf){ return "OK"; } +static uint8_t i2cinited = 0; +static inline char *setupI2C(char *buf){ + buf = omit_spaces(buf); + if(*buf < '0' || *buf > '2') return "Wrong speed"; + i2c_setup(*buf - '0'); + i2cinited = 1; + return "OK"; +} + +static uint8_t I2Caddress = 0; +static uint8_t I2Cdata[12]; +static inline char *saI2C(char *buf){ + uint32_t addr; + if(!getnum(buf, &addr) || addr > 0x7f) return "Wrong address"; + I2Caddress = (uint8_t) addr << 1; + USND("I2Caddr="); USB_sendstr(uhex2str(addr)); USND("\n"); + return "OK"; +} +static inline void rdI2C(char *buf){ + uint32_t N; + char *nxt = getnum(buf, &N); + if(!nxt || buf == nxt || N > 0xff){ + USND("Bad register number\n"); + return; + } + buf = nxt; + uint8_t reg = N; + nxt = getnum(buf, &N); + if(!nxt || buf == nxt || N > 12){ + USND("Bad length\n"); + return; + } + if(!read_i2c_reg(I2Caddress, reg, I2Cdata, N)){ + USND("Error reading I2C\n"); + return; + } + if(N == 0){ USND("OK"); return; } + USND("Register "); USB_sendstr(uhex2str(reg)); USND(":\n"); + for(uint32_t i = 0; i < N; ++i){ + if(i < 10) USND(" "); + USB_sendstr(u2str(i)); USND(": "); USB_sendstr(uhex2str(I2Cdata[i])); + USND("\n"); + } +} +static inline char *wrI2C(char *buf){ + uint8_t N = 0; + uint32_t D; + char *nxt; + while((nxt = getnum(buf, &D)) && nxt != buf && N < 12){ + buf = nxt; + I2Cdata[N++] = (uint8_t) D&0xff; + USND("add byte: "); USB_sendstr(uhex2str(D&0xff)); USND("\n"); + } + USND("Send "); USB_sendstr(u2str(N)); USND(" bytes\n"); + if(!write_i2c(I2Caddress, I2Cdata, N)) return "Error writing I2C"; + return "OK"; +} + +static inline char *DAC_chval(char *buf){ + uint32_t D; + char *nxt = getnum(buf, &D); + if(!nxt || nxt == buf || D > 4095) return "Wrong DAC amplitude\n"; + DAC->DHR12R1 = D; + return "OK"; +} + const char *helpstring = - "'+'/'-'[num] - increase/decrease TIM1ch1 PWM by 1 or `num`\n" + "+/-[num] - increase/decrease TIM1ch1 PWM by 1 or `num`\n" "1..4'+'/'-'[num] - increase/decrease TIM3chN PWM by 1 or `num`\n" - "'g' - get PWM values\n" - "'A' - get ADC values\n" - "'L' - send long string over USB\n" - "'R' - software reset\n" - "'S' - send short string over USB\n" - "'Ux' - send string to USARTx (1..3)\n" - "'T' - MCU temperature\n" - "'V' - Vdd\n" - "'W' - test watchdog\n" + "A - get ADC values\n" + "dx - change DAC lowcal to x\n" + "g - get PWM values\n" + "i0..3 - setup I2C with lowest..highest speed (5.8, 10 and 100kHz)\n" + "Ia addr - set I2C address\n" + "Iw bytes - send bytes (hex/dec/oct/bin) to I2C\n" + "Ir reg n - read n bytes from I2C reg\n" + "Is - scan I2C bus\n" + "L - send long string over USB\n" + "m - monitor ADC on/off\n" + "R - software reset\n" + "S - send short string over USB\n" + "Ux str - send string to USARTx (1..3)\n" + "T - MCU temperature\n" + "V - Vdd\n" + "W - test watchdog\n" ; +void printADCvals(){ + USND("AIN0: "); USB_sendstr(u2str(getADCval(0))); + USND(" ("); USB_sendstr(u2str(getADCvoltage(0))); + USND("/100 V)\nAIN1: "); USB_sendstr(u2str(getADCval(1))); + USND(" ("); USB_sendstr(u2str(getADCvoltage(1))); + USND("/100 V)\nAIN5: "); USB_sendstr(u2str(getADCval(2))); + USND(" ("); USB_sendstr(u2str(getADCvoltage(2))); + USND("/100 V)\n"); +} + const char *parse_cmd(char *buf){ // "long" commands switch(*buf){ @@ -103,6 +187,21 @@ const char *parse_cmd(char *buf){ case '3': case '4': return TIM3pwm(buf); + break; + case 'd': + return DAC_chval(buf + 1); + case 'i': + return setupI2C(buf + 1); + break; + case 'I': + if(!i2cinited) return "Init I2C first"; + buf = omit_spaces(buf + 1); + if(*buf == 'a') return saI2C(buf + 1); + else if(*buf == 'r'){ rdI2C(buf + 1); return NULL; } + else if(*buf == 'w') return wrI2C(buf + 1); + else if(*buf == 's') i2c_init_scan_mode(); + else return "Command should be 'Ia', 'Iw', 'Ir' or 'Is'\n"; + break; case 'U': return USARTsend(buf + 1); break; @@ -114,17 +213,19 @@ const char *parse_cmd(char *buf){ return getPWMvals(); break; case 'A': - USND("ADC0: "); USB_sendstr(u2str(getADCval(0))); - USND(" ("); USB_sendstr(u2str(getADCvoltate(0))); - USND("/100 V)\nADC1: "); USB_sendstr(u2str(getADCval(1))); - USND(" ("); USB_sendstr(u2str(getADCvoltate(1))); - USND("/100 V)\n"); + printADCvals(); break; case 'L': USND("Very long test string for USB (it's length is more than 64 bytes).\n" "This is another part of the string! Can you see all of this?\n"); return "Long test sent"; break; + case 'm': + ADCmon = !ADCmon; + USND("Monitoring is "); + if(ADCmon) USND("on\n"); + else USND("off\n"); + break; case 'R': USND("Soft reset\n"); //SEND("Soft reset\n"); diff --git a/F0-nolib/F0_testbrd/proto.h b/F0-nolib/F0_testbrd/proto.h index 0318b36..3725fee 100644 --- a/F0-nolib/F0_testbrd/proto.h +++ b/F0-nolib/F0_testbrd/proto.h @@ -19,12 +19,18 @@ #ifndef PROTO_H__ #define PROTO_H__ +#include "stm32f0.h" + #define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0) +extern volatile uint8_t ADCmon; + void USB_sendstr(const char *str); char *get_USB(); const char *parse_cmd(char *buf); +void printADCvals(); + char *u2str(uint32_t val); char *i2str(int32_t i); char *uhex2str(uint32_t val); diff --git a/F0-nolib/F0_testbrd/usart.c b/F0-nolib/F0_testbrd/usart.c index 8c612cd..7a85866 100644 --- a/F0-nolib/F0_testbrd/usart.c +++ b/F0-nolib/F0_testbrd/usart.c @@ -139,6 +139,7 @@ void usart_setup(){ GPIO_MODER_MODER10_AF | GPIO_MODER_MODER11_AF; GPIOB->AFR[1] = (GPIOB->AFR[1] & ~(GPIO_AFRH_AFRH2 | GPIO_AFRH_AFRH3)) | 4 << (2 * 4) | 4 << (3 * 4); // PB10, PB11 + RCC->APB1ENR |= RCC_APB1ENR_USART3EN; #endif for(int i = 0; i < USARTNUM; ++i){ USARTs[i]->ICR = 0xffffffff; // clear all flags @@ -210,7 +211,6 @@ static void usart_IRQ(int usartno){ #endif } } - USARTX->ICR = 0xffffffff; } void usart1_isr(){ diff --git a/F1-nolib/I2Cscan/i2cscan.c b/F1-nolib/I2Cscan/i2cscan.c index 1848ab1..457dc78 100644 --- a/F1-nolib/I2Cscan/i2cscan.c +++ b/F1-nolib/I2Cscan/i2cscan.c @@ -27,7 +27,7 @@ uint8_t getI2Caddr(){ return i2caddr; } -void init_scan_mode(){ +void i2c_init_scan_mode(){ i2caddr = 0; scanmode = 1; } @@ -35,7 +35,7 @@ void init_scan_mode(){ // return 1 if next addr is active & return in as `addr` // if addresses are over, return 1 and set addr to I2C_NOADDR // if scan mode inactive, return 0 and set addr to I2C_NOADDR -int scan_next_addr(uint8_t *addr){ +int i2c_scan_next_addr(uint8_t *addr){ *addr = i2caddr; if(!scanmode || i2caddr == I2C_ADDREND){ *addr = I2C_ADDREND; diff --git a/F1-nolib/I2Cscan/i2cscan.h b/F1-nolib/I2Cscan/i2cscan.h index a9759c4..13099c3 100644 --- a/F1-nolib/I2Cscan/i2cscan.h +++ b/F1-nolib/I2Cscan/i2cscan.h @@ -27,8 +27,8 @@ extern uint8_t scanmode; uint8_t getI2Caddr(); -void init_scan_mode(); -int scan_next_addr(uint8_t *addr); +void i2c_init_scan_mode(); +int i2c_scan_next_addr(uint8_t *addr); int read_reg(uint8_t reg, uint8_t *val, uint8_t N); int write_reg(uint8_t reg, uint8_t val);