From 6832befb4ae01888676441e4fcd180550be06ee3 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Wed, 22 Mar 2023 23:43:51 +0300 Subject: [PATCH] add a little (ADC2 don't work - it's weird) --- F3:F303/NitrogenFlooding/Readme.md | 12 + F3:F303/NitrogenFlooding/adc.c | 14 +- F3:F303/NitrogenFlooding/hardware.c | 70 +++- F3:F303/NitrogenFlooding/hardware.h | 14 + F3:F303/NitrogenFlooding/i2c.c | 313 ++++++++++++++++++ F3:F303/NitrogenFlooding/i2c.h | 50 +++ F3:F303/NitrogenFlooding/main.c | 12 + F3:F303/NitrogenFlooding/nitrogen.bin | Bin 6180 -> 10228 bytes .../NitrogenFlooding/nitrogen.creator.user | 31 +- F3:F303/NitrogenFlooding/nitrogen.files | 2 + F3:F303/NitrogenFlooding/proto.c | 142 +++++++- F3:F303/NitrogenFlooding/proto.h | 9 +- F3:F303/NitrogenFlooding/version.inc | 2 +- F3:F303/inc/ld/stm32f302xB.ld | 1 + 14 files changed, 630 insertions(+), 42 deletions(-) create mode 100644 F3:F303/NitrogenFlooding/i2c.c create mode 100644 F3:F303/NitrogenFlooding/i2c.h diff --git a/F3:F303/NitrogenFlooding/Readme.md b/F3:F303/NitrogenFlooding/Readme.md index 19388ee..063860b 100644 --- a/F3:F303/NitrogenFlooding/Readme.md +++ b/F3:F303/NitrogenFlooding/Readme.md @@ -202,3 +202,15 @@ Automated liquid nitrogen flooding machine | 10 | PF9 | - | - | | | 11 | PF10 | VadcON | slow out | turn ON ADC power| |---------|-------------|-------------|-------------|------------------| + + +## DMA usage +### DMA1 + +- Channel 1 - ADC1 +- Channel 6 - I2C1 Tx +- Channel 7 - I2C1 Rx + +### DMA2 + +- Channel 2 - ADC2 diff --git a/F3:F303/NitrogenFlooding/adc.c b/F3:F303/NitrogenFlooding/adc.c index e28f50b..9247386 100644 --- a/F3:F303/NitrogenFlooding/adc.c +++ b/F3:F303/NitrogenFlooding/adc.c @@ -25,9 +25,9 @@ * @brief ADCx_array - arrays for ADC channels with median filtering: * ADC1: * 0..9 - AIN0..9 (ADC1_IN1..10) - * 4 - internal Tsens - ADC1_IN16 + * 10 - internal Tsens - ADC1_IN16 * ADC2: - * 6 - AINext - (ADC2 in 1) + * 11 - AINext - (ADC2 in 1) */ static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9]; @@ -66,7 +66,7 @@ TRUE_INLINE void enADC(ADC_TypeDef *chnl){ * ADC1 - DMA1_ch1 * ADC2 - DMA2_ch1 */ -// Setup ADC and DAC +// Setup ADC void adc_setup(){ RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable clocking ADC12_COMMON->CCR = ADC_CCR_TSEN | ADC_CCR_CKMODE; // enable Tsens, HCLK/4 @@ -83,7 +83,6 @@ void adc_setup(){ ADC2->SMPR1 = ADC_SMPR1_SMP1; ADC2->SQR1 = (1<<6) | (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)); @@ -112,8 +111,11 @@ uint16_t getADCval(int nch){ #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; + int addr = nch, adval = NUMBER_OF_ADC1_CHANNELS; + if(nch >= NUMBER_OF_ADC1_CHANNELS){ + adval = NUMBER_OF_ADC2_CHANNELS; + addr += ADC2START; + } 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]) ; diff --git a/F3:F303/NitrogenFlooding/hardware.c b/F3:F303/NitrogenFlooding/hardware.c index fdd6b9f..3d2da1f 100644 --- a/F3:F303/NitrogenFlooding/hardware.c +++ b/F3:F303/NitrogenFlooding/hardware.c @@ -17,19 +17,23 @@ */ #include "hardware.h" +#include "i2c.h" int LEDsON = 0; // 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(){ + BUZZER_OFF(); + ADCON(0); + pin_set(LEDs_port, 0xf<<8); // turn off LEDs RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN | RCC_AHBENR_GPIOEEN | RCC_AHBENR_GPIOFEN; // enable PWM timer TIM3 RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; for(int i = 0; i < 10000; ++i) nop(); // PORT A (PA13/14 - SWDIO/SWCLK - AF0) - GPIOA->ODR = 0; + //GPIOA->ODR = 0; GPIOA->AFR[0] = 0; GPIOA->AFR[1] = AFRf(4, 9) | AFRf(4, 10) | AFRf(14, 11) | AFRf(14,12); GPIOA->MODER = MODER_AI(0) | MODER_AI(1) | MODER_AI(2) | MODER_AI(3) | MODER_AI(4) | @@ -39,7 +43,7 @@ TRUE_INLINE void gpio_setup(){ GPIOA->PUPDR = PUPD_PU(13) | PUPD_PD(14); // SWDIO - pullup, SDCLK - pulldown // PORT B - GPIOB->ODR = 0; + //GPIOB->ODR = 0; GPIOB->AFR[0] = AFRf(4, 6) | AFRf(4, 7); GPIOB->AFR[1] = AFRf(5, 13) | AFRf(5, 14) | AFRf(5, 15); GPIOB->MODER = MODER_O(0) | MODER_AF(6) | MODER_AF(7) | MODER_O(10) | MODER_O(11) | MODER_O(12) | MODER_AF(13) @@ -49,7 +53,7 @@ TRUE_INLINE void gpio_setup(){ GPIOB->PUPDR = 0; // PORT C - GPIOC->ODR = 0; + //GPIOC->ODR = 0; GPIOC->AFR[0] = 0; GPIOC->AFR[1] = AFRf(7, 10) | AFRf(7, 11); GPIOC->MODER = MODER_AI(0) | MODER_AI(1) | MODER_AI(2) | MODER_AI(3) | MODER_O(9) | MODER_AF(10) | MODER_AF(11); @@ -58,7 +62,7 @@ TRUE_INLINE void gpio_setup(){ GPIOC->PUPDR = 0; // PORT D - GPIOD->ODR = 0; + //GPIOD->ODR = 0; GPIOD->AFR[0] = AFRf(7, 0) | AFRf(7, 1) | AFRf(7, 5) | AFRf(7, 6); GPIOD->AFR[1] = 0; GPIOD->MODER = MODER_AF(0) | MODER_AF(1) | MODER_O(4) | MODER_AF(5) | MODER_AF(6) | MODER_I(9) @@ -68,7 +72,7 @@ TRUE_INLINE void gpio_setup(){ GPIOD->PUPDR = PUPD_PU(9) | PUPD_PU(10) | PUPD_PU(11) | PUPD_PU(12) | PUPD_PU(13) | PUPD_PU(14) | PUPD_PU(15); // PORT E - GPIOE->ODR = 0; + //GPIOE->ODR = 0; GPIOE->AFR[0] = 0; GPIOE->AFR[1] = AFRf(2, 2) | AFRf(2, 3) | AFRf(2, 4) | AFRf(2, 5); GPIOE->MODER = MODER_AF(2) | MODER_AF(3) | MODER_AF(4) | MODER_AF(5) | MODER_O(8) | MODER_O(9) | MODER_O(10) | MODER_O(11); @@ -77,7 +81,7 @@ TRUE_INLINE void gpio_setup(){ GPIOE->PUPDR = 0; // PORT F - GPIOF->ODR = 0; + //GPIOF->ODR = 0; GPIOF->AFR[0] = 0; GPIOF->AFR[1] = 0; GPIOF->MODER = MODER_AI(2) | MODER_O(10); @@ -86,6 +90,19 @@ TRUE_INLINE void gpio_setup(){ GPIOF->PUPDR = 0; } +TRUE_INLINE void pwm_setup(){ + TIM3->CR1 = TIM_CR1_ARPE; + TIM3->PSC = 1999; // 48M/2000 = 24kHz + // PWM mode 1 (active -> inactive) + TIM3->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1; + TIM3->CCMR2 = TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1; + TIM3->CCR1 = 0; + TIM3->ARR = 255; // 8bit PWM + TIM3->BDTR |= TIM_BDTR_MOE; // enable main output + TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E; + TIM3->CR1 |= TIM_CR1_CEN; +} + #ifndef EBUG TRUE_INLINE void iwdg_setup(){ uint32_t tmout = 16000000; @@ -112,9 +129,50 @@ TRUE_INLINE void iwdg_setup(){ #endif void hw_setup(){ + RCC->AHBENR |= RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN; gpio_setup(); + i2c_setup(HIGH_SPEED); + pwm_setup(); #ifndef EBUG iwdg_setup(); #endif } +void setPWM(int nch, uint8_t val){ + switch(nch){ + case 0: + TIM3->CCR1 = val; + break; + case 1: + TIM3->CCR2 = val; + break; + case 2: + TIM3->CCR3 = val; + break; + case 3: + TIM3->CCR4 = val; + break; + default: + break; + } +} + +uint8_t getPWM(int nch){ + switch(nch){ + case 0: + return TIM3->CCR1; + break; + case 1: + return TIM3->CCR2; + break; + case 2: + return TIM3->CCR3; + break; + case 3: + return TIM3->CCR4; + break; + default: + break; + } + return 0; +} diff --git a/F3:F303/NitrogenFlooding/hardware.h b/F3:F303/NitrogenFlooding/hardware.h index 40f55ec..53792e9 100644 --- a/F3:F303/NitrogenFlooding/hardware.h +++ b/F3:F303/NitrogenFlooding/hardware.h @@ -60,8 +60,22 @@ // state 0 - pressed, 1 - released #define BTN_state(x) (BTNs_port->IDR & 1<<(9+x) ? 0 : 1) +// buzzer, ADC voltage +#define BUZZER_port GPIOB +#define BUZZER_pin (1<<0) +#define BUZZER_ON() do{pin_clear(BUZZER_port, BUZZER_pin);}while(0) +#define BUZZER_OFF() do{pin_set(BUZZER_port, BUZZER_pin);}while(0) +#define BUZZER_STATE() (BUZZER_port->IDR & BUZZER_pin ? 0 : 1) +#define ADCON_port GPIOF +#define ADCON_pin (1<<10) +#define ADCON(x) do{if(x==0) pin_set(ADCON_port, ADCON_pin); else pin_clear(ADCON_port, ADCON_pin);}while(0) +#define ADCONSTATE() (ADCON_port->IDR & ADCON_pin ? 0 : 1) + extern volatile uint32_t Tms; extern int LEDsON; uint8_t MSB(uint16_t val); void hw_setup(); + +void setPWM(int nch, uint8_t val); +uint8_t getPWM(int nch); diff --git a/F3:F303/NitrogenFlooding/i2c.c b/F3:F303/NitrogenFlooding/i2c.c new file mode 100644 index 0000000..41e85c9 --- /dev/null +++ b/F3:F303/NitrogenFlooding/i2c.c @@ -0,0 +1,313 @@ +/* + * This file is part of the nitrogen 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 +#include + +#include "i2c.h" +#include "strfunc.h" // hexdump +#include "usb.h" + +I2C_SPEED curI2Cspeed = LOW_SPEED; +extern volatile uint32_t Tms; +static uint32_t cntr; +static uint8_t i2c_got_DMA_Rx = 0; +volatile uint8_t I2C_scan_mode = 0; // == 1 when I2C is in scan mode +static uint8_t i2caddr = I2C_ADDREND; // current address in scan mode +static volatile int I2Cbusy = 0, goterr = 0; // busy==1 when DMA active, goterr==1 if 't was error @ last sent +static uint8_t I2Cbuf[256], i2cbuflen = 0; // buffer for DMA tx/rx and its len + +// macros for I2C rx/tx +#define DMARXCCR (DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE) +#define DMATXCCR (DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_TEIE) +// macro for I2CCR1 +#define I2CCR1 (I2C_CR1_PE | I2C_CR1_RXDMAEN | I2C_CR1_TXDMAEN) + +// return 1 if I2Cbusy is set & timeout reached +static inline int isI2Cbusy(){ + cntr = Tms; + do{ + if(Tms - cntr > I2C_TIMEOUT){ USND("Timeout, DMA transfer in progress?\n"); return 1;} + }while(I2Cbusy); + return 0; +} + +// GPIO Resources: I2C1_SCL - PB6 (AF4), I2C1_SDA - PB7 (AF4) +void i2c_setup(I2C_SPEED speed){ + if(speed >= CURRENT_SPEED){ + speed = curI2Cspeed; + }else{ + curI2Cspeed = speed; + } + RCC->AHBENR |= RCC_AHBENR_GPIOBEN; + I2C1->CR1 = 0; + I2C1->ICR = 0x3f38; // clear all errors + GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) | + AFRf(4, 6) | AFRf(4, 7); + GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) | + GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF; + GPIOB->PUPDR = (GPIOB->PUPDR & !(GPIO_PUPDR_PUPDR6 | GPIO_PUPDR_PUPDR7)) | + GPIO_PUPDR6_PU | GPIO_PUPDR7_PU; // pullup (what if there's no external pullup?) + GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7; // both open-drain outputs + // I2C (default timing from PCLK - 64MHz) + RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // clocking + if(speed == LOW_SPEED){ // 10kHz + // PRESC=F, SCLDEL=4, SDADEL=2, SCLH=0xC3, SCLL=0xC7 + I2C1->TIMINGR = (0xF<<28) | (4<<20) | (2<<16) | (0xC3<<8) | (0xC7); + }else if(speed == HIGH_SPEED){ // 100kHz + I2C1->TIMINGR = (0xF<<28) | (4<<20) | (2<<16) | (0xF<<8) | (0x13); + }else{ // VERYLOW_SPEED - the lowest speed by STM register: ~7.7kHz + I2C1->TIMINGR = (0xF<<28) | (4<<20) | (2<<16) | (0xff<<8) | (0xff); + } + I2C1->CR1 = I2CCR1; + RCC->AHBENR |= RCC_AHBENR_DMA1EN; + NVIC_EnableIRQ(DMA1_Channel6_IRQn); + NVIC_EnableIRQ(DMA1_Channel7_IRQn); + I2Cbusy = 0; +} + +// setup DMA for rx (tx==0) or tx (tx==1) +// DMA channels: 7 - I2C1_Rx, 6 - I2C1_Tx +static void i2cDMAsetup(int tx, uint8_t len){ + if(tx){ + DMA1_Channel6->CCR = DMATXCCR; + DMA1_Channel6->CPAR = (uint32_t) &I2C1->TXDR; + DMA1_Channel6->CMAR = (uint32_t) I2Cbuf; + DMA1_Channel6->CNDTR = i2cbuflen = len; + }else{ + DMA1_Channel7->CCR = DMARXCCR; + DMA1_Channel7->CPAR = (uint32_t) &I2C1->RXDR; + DMA1_Channel7->CMAR = (uint32_t) I2Cbuf; + DMA1_Channel7->CNDTR = i2cbuflen = len; + } +} + +static uint8_t i2c_start(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 + }} + return 1; +} + +// start writing +static uint8_t i2c_startw(uint8_t addr, uint8_t nbytes, uint8_t stop){ + if(!i2c_start(1)) return 0; + I2C1->CR2 = nbytes << 16 | addr; + if(stop) I2C1->CR2 |= I2C_CR2_AUTOEND; // autoend + // now start transfer + I2C1->CR2 |= I2C_CR2_START; + return 1; +} + +/** + * 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){ + if(!i2c_startw(addr, nbytes, stop)) return 0; + 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 + } + cntr = Tms; + // 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){ + if(isI2Cbusy()) return 0; + return write_i2cs(addr, data, nbytes, 1); +} + +uint8_t write_i2c_dma(uint8_t addr, uint8_t *data, uint8_t nbytes){ + if(!data || nbytes < 1) return 0; + if(isI2Cbusy()) return 0; + memcpy((char*)I2Cbuf, (char*)data, nbytes); + i2cDMAsetup(1, nbytes); + goterr = 0; + if(!i2c_startw(addr, nbytes, 1)) return 0; + I2Cbusy = 1; + DMA1_Channel6->CCR = DMATXCCR | DMA_CCR_EN; // start transfer + return 1; +} + +// start reading +static uint8_t i2c_startr(uint8_t addr, uint8_t nbytes, uint8_t busychk){ + if(!i2c_start(busychk)) return 0; + // read N bytes + I2C1->CR2 = (nbytes<<16) | addr | 1 | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN; + I2C1->CR2 |= I2C_CR2_START; + return 1; +} + +/** + * read nbytes of data from I2C line + * all functions with `addr` should have addr = address << 1 + * `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(!i2c_startr(addr, nbytes, busychk)) return 0; + 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){ + if(isI2Cbusy()) return 0; + return read_i2cb(addr, data, nbytes, 1); +} + +uint8_t read_i2c_dma(uint8_t addr, uint8_t nbytes){ + if(nbytes < 1) return 0; + if(isI2Cbusy()) return 0; + i2cDMAsetup(0, nbytes); + goterr = 0; + if(!i2c_startr(addr, nbytes, 1)) return 0; + I2Cbusy = 1; + DMA1_Channel7->CCR = DMARXCCR | DMA_CCR_EN; // start transfer + return 1; +} + + +// read register reg +uint8_t read_i2c_reg(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t nbytes){ + if(isI2Cbusy()) return 0; + if(!write_i2cs(addr, ®, 1, 0)) return 0; + return read_i2cb(addr, data, nbytes, 0); +} + +// read 16bit register reg +uint8_t read_i2c_reg16(uint8_t addr, uint16_t reg16, uint8_t *data, uint8_t nbytes){ + if(isI2Cbusy()) return 0; + if(!write_i2cs(addr, (uint8_t*)®16, 2, 0)) return 0; + return read_i2cb(addr, data, nbytes, 0); +} + +void i2c_init_scan_mode(){ + i2caddr = 1; // start from 1 as 0 is a broadcast address + 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){ + if(isI2Cbusy()) return 0; + *addr = i2caddr; + if(i2caddr == I2C_ADDREND){ + *addr = I2C_ADDREND; + I2C_scan_mode = 0; + return 0; + } + /*while(!u3txrdy); + USND("Addr: "); USND(uhex2str(i2caddr)); USND("\n"); + usart3_sendbuf();*/ + uint8_t byte; + if(!read_i2c((i2caddr++)<<1, &byte, 1)) return 0; + return 1; +} + +// dump I2Cbuf +void i2c_bufdudump(){ + if(goterr){ + USND("Last transfer ends with error!\n"); + goterr = 0; + } + USND("I2C buffer:\n"); + hexdump(USB_sendstr, I2Cbuf, i2cbuflen); +} + +void i2c_have_DMA_Rx(){ + if(!i2c_got_DMA_Rx) return; + i2c_got_DMA_Rx = 0; + i2c_bufdudump(); +} + +int i2cdma_haderr(){ + int r = goterr; + goterr = 0; + return r; +} + +// Rx (7) /Tx (6) interrupts +static void I2C_isr(int rx){ + uint32_t isr = DMA1->ISR; + DMA_Channel_TypeDef *ch = (rx) ? DMA1_Channel7 : DMA1_Channel6; + if(isr & (DMA_ISR_TEIF6 | DMA_ISR_TEIF6)) goterr = 1; + if(rx) i2c_got_DMA_Rx = 1; // last transfer was Rx + ch->CCR = 0; + I2Cbusy = 0; + DMA1->IFCR = 0x0ff00000; // clear all flags for channel6/7 +} + +void dma1_channel6_isr(){ + I2C_isr(0); +} + +void dma1_channel7_isr(){ + I2C_isr(1); +} diff --git a/F3:F303/NitrogenFlooding/i2c.h b/F3:F303/NitrogenFlooding/i2c.h new file mode 100644 index 0000000..3545af7 --- /dev/null +++ b/F3:F303/NitrogenFlooding/i2c.h @@ -0,0 +1,50 @@ +/* + * This file is part of the nitrogen 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 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 read_i2c_reg16(uint8_t addr, uint16_t reg16, uint8_t *data, uint8_t nbytes); +uint8_t write_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes); +uint8_t write_i2c_dma(uint8_t addr, uint8_t *data, uint8_t nbytes); +uint8_t read_i2c_dma(uint8_t addr, uint8_t nbytes); + +void i2c_bufdudump(); +void i2c_have_DMA_Rx(); +int i2cdma_haderr(); + +void i2c_init_scan_mode(); +int i2c_scan_next_addr(uint8_t *addr); diff --git a/F3:F303/NitrogenFlooding/main.c b/F3:F303/NitrogenFlooding/main.c index 5998afc..04857b7 100644 --- a/F3:F303/NitrogenFlooding/main.c +++ b/F3:F303/NitrogenFlooding/main.c @@ -21,6 +21,7 @@ //#include "can.h" //#include "flash.h" #include "hardware.h" +#include "i2c.h" #include "proto.h" #include "usb.h" @@ -75,6 +76,17 @@ int main(void){ } } }*/ + if(I2C_scan_mode){ + uint8_t addr; + int ok = i2c_scan_next_addr(&addr); + if(addr == I2C_ADDREND) USND("Scan ends"); + else if(ok){ + USB_sendstr(uhex2str(addr)); + USB_sendstr(" ("); USB_sendstr(u2str(addr)); + USB_sendstr(") - found device\n"); + } + } + i2c_have_DMA_Rx(); // check if there's DMA Rx complete USB_proc(); int l = USB_receivestr(inbuff, MAXSTRLEN); if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n"); diff --git a/F3:F303/NitrogenFlooding/nitrogen.bin b/F3:F303/NitrogenFlooding/nitrogen.bin index ec501e00be80b96137f614132f1f22fdf422d686..4f0e0ee1c932e14be2f059e530de63b69d9de941 100755 GIT binary patch literal 10228 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 BUGM+^ diff --git a/F3:F303/NitrogenFlooding/nitrogen.creator.user b/F3:F303/NitrogenFlooding/nitrogen.creator.user index 4a03d2d..6472914 100644 --- a/F3:F303/NitrogenFlooding/nitrogen.creator.user +++ b/F3:F303/NitrogenFlooding/nitrogen.creator.user @@ -1,10 +1,10 @@ - + EnvironmentId - {cf63021e-ef53-49b0-b03b-2f2570cdf3b6} + {7bd84e39-ca37-46d3-be9d-99ebea85bc0d} ProjectExplorer.Project.ActiveTarget @@ -38,32 +38,43 @@ true 1 false - false + true false - 1 + 0 true true 0 8 true false - 2 + 1 true - true + false true *.md, *.MD, Makefile - true + false true ProjectExplorer.Project.PluginSettings + + true + false + true + true + true + true + + + 0 + true true true Builtin.DefaultTidyAndClazy - 4 + 2 @@ -77,12 +88,12 @@ Desktop Desktop Desktop - {91347f2c-5221-46a7-80b1-0a054ca02f79} + {65a14f9e-e008-4c1b-89df-4eaa4774b6e3} 0 0 0 - /home/eddy/Docs/SAO/ELECTRONICS/STM32/F3-srcs/NitrogenFlooding + /Big/Data/00__Electronics/STM32/F303-nolib/NitrogenFlooding diff --git a/F3:F303/NitrogenFlooding/nitrogen.files b/F3:F303/NitrogenFlooding/nitrogen.files index 6a5d842..0b934c7 100644 --- a/F3:F303/NitrogenFlooding/nitrogen.files +++ b/F3:F303/NitrogenFlooding/nitrogen.files @@ -14,6 +14,8 @@ hashgen/hashgen.c hashgen/hdr.c hashgen/hdr.h hashgen/test.c +i2c.c +i2c.h main.c pdnuart.c pdnuart.h diff --git a/F3:F303/NitrogenFlooding/proto.c b/F3:F303/NitrogenFlooding/proto.c index 3612d17..5f702f5 100644 --- a/F3:F303/NitrogenFlooding/proto.c +++ b/F3:F303/NitrogenFlooding/proto.c @@ -16,7 +16,9 @@ * along with this program. If not, see . */ +#include "adc.h" #include "hardware.h" +#include "i2c.h" #include "proto.h" #include "strfunc.h" #include "version.inc" @@ -24,15 +26,36 @@ #include #include +static uint8_t I2Caddress = 0; + // parno - number of parameter (or -1); cargs - string with arguments (after '=') (==NULL for getter), iarg - integer argument -static int goodstub(int _U_ parno, const char _U_ *carg, int32_t _U_ iarg){ +static int goodstub(const char _U_ *cmd, int _U_ parno, const char _U_ *carg, int32_t _U_ iarg){ return RET_GOOD; } -static int leds(int parno, const char *c, int32_t i){ +static void sendkey(const char *cmd, int parno, int32_t i){ + USB_sendstr(cmd); + if(parno > -1) USB_sendstr(u2str((uint32_t)parno)); + USB_putbyte('='); USB_sendstr(i2str(i)); newline(); +} +static void sendkeyf(const char *cmd, int parno, float f){ + USB_sendstr(cmd); + if(parno > -1) USB_sendstr(u2str((uint32_t)parno)); + USB_putbyte('='); USB_sendstr(float2str(f, 2)); newline(); +} +static void sendkeyu(const char *cmd, int parno, uint32_t u){ + USB_sendstr(cmd); + if(parno > -1) USB_sendstr(u2str((uint32_t)parno)); + USB_putbyte('='); USB_sendstr(u2str(u)); newline(); +} + +static int leds(const char *cmd, int parno, const char *c, int32_t i){ if(parno < 0){ // enable/disable all - if(c){ LEDsON = i ? 1 : 0;} - USB_sendstr("LED="); USB_sendstr(u2str(LEDsON)); + if(c){ + LEDsON = (i ? 1 : 0); + if(!LEDsON) for(int _ = 0; _ < 4; ++_) LED_off(_); + } + sendkey("LEDon", -1, LEDsON); }else{ if(parno >= LEDS_AMOUNT) return RET_WRONGARG; if(c) switch(i){ @@ -40,32 +63,116 @@ static int leds(int parno, const char *c, int32_t i){ case 1: LED_on(parno); break; default: LED_off(parno); } - USB_sendstr("LED"); USB_putbyte('0' + parno); - USB_putbyte('='); USB_sendstr(u2str(LED_get(parno))); newline(); + sendkey(cmd, parno, LED_get(parno)); } - newline(); + return RET_GOOD; +} + +static int buzzer(const char *cmd, int _U_ parno, const char _U_ *c, int32_t i){ + if(c){ + if(i > 0) BUZZER_ON(); + else BUZZER_OFF(); + } + sendkey(cmd, -1, BUZZER_STATE()); + return RET_GOOD; +} + +static int i2scan(const char _U_ *cmd, int _U_ parno, const char _U_ *c, int32_t _U_ i){ + i2c_init_scan_mode(); + return RET_GOOD; +} +static int i2addr(const char *cmd, int _U_ parno, const char *c, int32_t i){ + if(c){ + if(i < 0 || i>= I2C_ADDREND) return RET_WRONGARG; + I2Caddress = (uint8_t) i; + } + sendkey(cmd, -1, I2Caddress); + return RET_GOOD; +} + +static int adcon(const char *cmd, int _U_ parno, const char *c, int32_t i){ + if(c) ADCON(i); + sendkey(cmd, -1, ADCONSTATE()); + return RET_GOOD; +} +static int adcval(const char *cmd, int parno, const char _U_ *c, int32_t i){ + if(parno >= NUMBER_OF_ADC_CHANNELS) return RET_WRONGPARNO; + if(parno < 0){ // all channels + for(i = 0; i < NUMBER_OF_ADC_CHANNELS; ++i) sendkey(cmd, i, getADCval(i)); + }else + sendkey(cmd, parno, getADCval(parno)); + return RET_GOOD; +} +static int adcvoltage(const char *cmd, int parno, const char _U_ *c, int32_t i){ + if(parno >= NUMBER_OF_ADC_CHANNELS) return RET_WRONGPARNO; + if(parno < 0){ // all channels + for(i = 0; i < NUMBER_OF_ADC_CHANNELS; ++i) sendkeyf(cmd, i, getADCvoltage(i)); + }else + sendkeyf(cmd, parno, getADCvoltage(parno)); + return RET_GOOD; +} +static int mcut(const char *cmd, int _U_ parno, const char _U_ *c, int32_t _U_ i){ + sendkeyf(cmd, -1, getMCUtemp()); + return RET_GOOD; +} + +static int reset(const char _U_ *cmd, int _U_ parno, const char _U_ *c, int32_t _U_ i){ + USB_sendstr("RESET!!!\n"); + USB_sendall(); + NVIC_SystemReset(); + return RET_GOOD; // never reached +} + +static int tms(const char _U_ *cmd, int _U_ parno, const char _U_ *c, int32_t _U_ i){ + sendkeyu(cmd, -1, Tms); + return RET_GOOD; +} + +static int pwm(const char *cmd, int parno, const char *c, int32_t i){ + if(parno < 0 || parno > 3) return RET_WRONGPARNO; + if(c) setPWM(parno, (uint8_t)i); + sendkeyu(cmd, -1, getPWM(parno)); return RET_GOOD; } typedef struct{ - int (*fn)(int, const char*, int32_t); + int (*fn)(const char*, int, const char*, int32_t); const char *cmd; const char *help; } commands; commands cmdlist[] = { {goodstub, "stub", "simple stub"}, + {NULL, "Different commands", NULL}, + {buzzer, "buzzer", "get/set (0 - off, 1 - on) buzzer"}, {leds, "LED", "LEDx=y; where x=0..3 to work with single LED (then y=1-set, 0-reset, 2-toggle), absent to work with all (y=0 - disable, 1-enable)"}, + {pwm, "pwm", "set/get x channel (0..3) pwm value (0..255)"}, + {reset, "reset", "reset MCU"}, + {tms, "tms", "print Tms"}, + {NULL, "I2C commands", NULL}, + {i2addr, "iicaddr", "set/get I2C address"}, + {i2scan, "iicscan", "scan I2C bus"}, + {NULL, "ADC commands", NULL}, + {adcval, "ADC", "get ADCx value (without x - for all)"}, + {adcvoltage, "ADCv", "get ADCx voltage (without x - for all)"}, + {mcut, "mcut", "get MCU temperature"}, + {adcon, "sensv", "turn on (1) or off (0) Tsens voltage"}, {NULL, NULL, NULL} }; static void printhelp(){ commands *c = cmdlist; USB_sendstr("https://github.com/eddyem/stm32samples/tree/master/F3:F303/NitrogenFlooding build#" BUILD_NUMBER " @ " BUILD_DATE "\n"); - while(c->fn){ - USB_sendstr(c->cmd); - USB_sendstr(" - "); - USB_sendstr(c->help); + while(c->cmd){ + if(!c->fn){ // header + USB_sendstr("\n "); + USB_sendstr(c->cmd); + USB_putbyte(':'); + }else{ + USB_sendstr(c->cmd); + USB_sendstr(" - "); + USB_sendstr(c->help); + } newline(); ++c; } @@ -73,6 +180,7 @@ static void printhelp(){ static int parsecmd(const char *str){ char cmd[CMD_MAXLEN + 1]; + //USB_sendstr("cmd="); USB_sendstr(str); USB_sendstr("__\n"); if(!str || !*str) return RET_CMDNOTFOUND; int i = 0; while(*str > '@' && i < CMD_MAXLEN){ cmd[i++] = *str++; } @@ -88,10 +196,13 @@ static int parsecmd(const char *str){ str = omit_spaces(++str); getint(str, &iarg); } - } + }else str = NULL; commands *c = cmdlist; - while(c->fn){ - if(strcmp(c->cmd, cmd) == 0) return c->fn(parno, str, iarg); + while(c->cmd){ + if(strcmp(c->cmd, cmd) == 0){ + if(!c->fn) return RET_CMDNOTFOUND; + return c->fn(cmd, parno, str, iarg); + } ++c; } return RET_CMDNOTFOUND; @@ -105,6 +216,7 @@ static int parsecmd(const char *str){ const char *cmd_parser(const char *txt){ int ret = parsecmd(txt); switch(ret){ + case RET_WRONGPARNO: return "Wrong parameter number\n"; break; case RET_CMDNOTFOUND: printhelp(); return NULL; break; case RET_WRONGARG: return "Wrong command parameters\n"; break; case RET_GOOD: return NULL; break; diff --git a/F3:F303/NitrogenFlooding/proto.h b/F3:F303/NitrogenFlooding/proto.h index cbe22cc..6cd9e1a 100644 --- a/F3:F303/NitrogenFlooding/proto.h +++ b/F3:F303/NitrogenFlooding/proto.h @@ -30,10 +30,11 @@ #define CMD_MAXLEN (32) enum{ - RET_CMDNOTFOUND = -2, - RET_WRONGARG = -1, - RET_GOOD = 0, - RET_BAD = 1 + RET_WRONGPARNO = -3, // wrong parameter number + RET_CMDNOTFOUND = -2, // command not found + RET_WRONGARG = -1, // wrong argument + RET_GOOD = 0, // all OK + RET_BAD = 1 // something wrong }; #define printu(x) do{USB_sendstr(u2str(x));}while(0) diff --git a/F3:F303/NitrogenFlooding/version.inc b/F3:F303/NitrogenFlooding/version.inc index f53810e..230edd2 100644 --- a/F3:F303/NitrogenFlooding/version.inc +++ b/F3:F303/NitrogenFlooding/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "2" +#define BUILD_NUMBER "24" #define BUILD_DATE "2023-03-22" diff --git a/F3:F303/inc/ld/stm32f302xB.ld b/F3:F303/inc/ld/stm32f302xB.ld index 41dfe30..0fd92d5 100644 --- a/F3:F303/inc/ld/stm32f302xB.ld +++ b/F3:F303/inc/ld/stm32f302xB.ld @@ -2,6 +2,7 @@ MEMORY { rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 40K + ccmram (rwx) : ORIGIN = 0x10000000, LENGTH = 0 } PROVIDE(_BLOCKSIZE = 2048);