mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 10:45:11 +03:00
add a little (ADC2 don't work - it's weird)
This commit is contained in:
parent
6902b60020
commit
6832befb4a
@ -202,3 +202,15 @@ Automated liquid nitrogen flooding machine
|
|||||||
| 10 | PF9 | - | - | |
|
| 10 | PF9 | - | - | |
|
||||||
| 11 | PF10 | VadcON | slow out | turn ON ADC power|
|
| 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
|
||||||
|
|||||||
@ -25,9 +25,9 @@
|
|||||||
* @brief ADCx_array - arrays for ADC channels with median filtering:
|
* @brief ADCx_array - arrays for ADC channels with median filtering:
|
||||||
* ADC1:
|
* ADC1:
|
||||||
* 0..9 - AIN0..9 (ADC1_IN1..10)
|
* 0..9 - AIN0..9 (ADC1_IN1..10)
|
||||||
* 4 - internal Tsens - ADC1_IN16
|
* 10 - internal Tsens - ADC1_IN16
|
||||||
* ADC2:
|
* ADC2:
|
||||||
* 6 - AINext - (ADC2 in 1)
|
* 11 - AINext - (ADC2 in 1)
|
||||||
*/
|
*/
|
||||||
static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ TRUE_INLINE void enADC(ADC_TypeDef *chnl){
|
|||||||
* ADC1 - DMA1_ch1
|
* ADC1 - DMA1_ch1
|
||||||
* ADC2 - DMA2_ch1
|
* ADC2 - DMA2_ch1
|
||||||
*/
|
*/
|
||||||
// Setup ADC and DAC
|
// Setup ADC
|
||||||
void adc_setup(){
|
void adc_setup(){
|
||||||
RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable clocking
|
RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable clocking
|
||||||
ADC12_COMMON->CCR = ADC_CCR_TSEN | ADC_CCR_CKMODE; // enable Tsens, HCLK/4
|
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->SMPR1 = ADC_SMPR1_SMP1;
|
||||||
ADC2->SQR1 = (1<<6) | (NUMBER_OF_ADC2_CHANNELS-1);
|
ADC2->SQR1 = (1<<6) | (NUMBER_OF_ADC2_CHANNELS-1);
|
||||||
// configure DMA for ADC
|
// configure DMA for ADC
|
||||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN;
|
|
||||||
ADC1->CFGR = ADC_CFGR_CONT | ADC_CFGR_DMAEN | ADC_CFGR_DMACFG;
|
ADC1->CFGR = ADC_CFGR_CONT | ADC_CFGR_DMAEN | ADC_CFGR_DMACFG;
|
||||||
ADC2->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->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_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
|
||||||
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
|
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
|
||||||
uint16_t p[9];
|
uint16_t p[9];
|
||||||
int adval = (nch >= NUMBER_OF_ADC1_CHANNELS) ? NUMBER_OF_ADC2_CHANNELS : NUMBER_OF_ADC1_CHANNELS;
|
int addr = nch, adval = NUMBER_OF_ADC1_CHANNELS;
|
||||||
int addr = (nch >= NUMBER_OF_ADC1_CHANNELS) ? nch - NUMBER_OF_ADC2_CHANNELS + ADC2START: nch;
|
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
|
for(int i = 0; i < 9; ++i, addr += adval) // first we should prepare array for optmed
|
||||||
p[i] = ADC_array[addr];
|
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[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
|
||||||
|
|||||||
@ -17,19 +17,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
int LEDsON = 0;
|
int LEDsON = 0;
|
||||||
|
|
||||||
// setup here ALL GPIO pins (due to table in Readme.md)
|
// 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
|
// leave SWD as default AF; high speed for CLK and some other AF; med speed for some another AF
|
||||||
TRUE_INLINE void gpio_setup(){
|
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 |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN
|
||||||
| RCC_AHBENR_GPIOEEN | RCC_AHBENR_GPIOFEN;
|
| RCC_AHBENR_GPIOEEN | RCC_AHBENR_GPIOFEN;
|
||||||
// enable PWM timer TIM3
|
// enable PWM timer TIM3
|
||||||
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
|
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
|
||||||
for(int i = 0; i < 10000; ++i) nop();
|
for(int i = 0; i < 10000; ++i) nop();
|
||||||
// PORT A (PA13/14 - SWDIO/SWCLK - AF0)
|
// PORT A (PA13/14 - SWDIO/SWCLK - AF0)
|
||||||
GPIOA->ODR = 0;
|
//GPIOA->ODR = 0;
|
||||||
GPIOA->AFR[0] = 0;
|
GPIOA->AFR[0] = 0;
|
||||||
GPIOA->AFR[1] = AFRf(4, 9) | AFRf(4, 10) | AFRf(14, 11) | AFRf(14,12);
|
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) |
|
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
|
GPIOA->PUPDR = PUPD_PU(13) | PUPD_PD(14); // SWDIO - pullup, SDCLK - pulldown
|
||||||
|
|
||||||
// PORT B
|
// PORT B
|
||||||
GPIOB->ODR = 0;
|
//GPIOB->ODR = 0;
|
||||||
GPIOB->AFR[0] = AFRf(4, 6) | AFRf(4, 7);
|
GPIOB->AFR[0] = AFRf(4, 6) | AFRf(4, 7);
|
||||||
GPIOB->AFR[1] = AFRf(5, 13) | AFRf(5, 14) | AFRf(5, 15);
|
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)
|
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;
|
GPIOB->PUPDR = 0;
|
||||||
|
|
||||||
// PORT C
|
// PORT C
|
||||||
GPIOC->ODR = 0;
|
//GPIOC->ODR = 0;
|
||||||
GPIOC->AFR[0] = 0;
|
GPIOC->AFR[0] = 0;
|
||||||
GPIOC->AFR[1] = AFRf(7, 10) | AFRf(7, 11);
|
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);
|
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;
|
GPIOC->PUPDR = 0;
|
||||||
|
|
||||||
// PORT D
|
// 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[0] = AFRf(7, 0) | AFRf(7, 1) | AFRf(7, 5) | AFRf(7, 6);
|
||||||
GPIOD->AFR[1] = 0;
|
GPIOD->AFR[1] = 0;
|
||||||
GPIOD->MODER = MODER_AF(0) | MODER_AF(1) | MODER_O(4) | MODER_AF(5) | MODER_AF(6) | MODER_I(9)
|
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);
|
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
|
// PORT E
|
||||||
GPIOE->ODR = 0;
|
//GPIOE->ODR = 0;
|
||||||
GPIOE->AFR[0] = 0;
|
GPIOE->AFR[0] = 0;
|
||||||
GPIOE->AFR[1] = AFRf(2, 2) | AFRf(2, 3) | AFRf(2, 4) | AFRf(2, 5);
|
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);
|
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;
|
GPIOE->PUPDR = 0;
|
||||||
|
|
||||||
// PORT F
|
// PORT F
|
||||||
GPIOF->ODR = 0;
|
//GPIOF->ODR = 0;
|
||||||
GPIOF->AFR[0] = 0;
|
GPIOF->AFR[0] = 0;
|
||||||
GPIOF->AFR[1] = 0;
|
GPIOF->AFR[1] = 0;
|
||||||
GPIOF->MODER = MODER_AI(2) | MODER_O(10);
|
GPIOF->MODER = MODER_AI(2) | MODER_O(10);
|
||||||
@ -86,6 +90,19 @@ TRUE_INLINE void gpio_setup(){
|
|||||||
GPIOF->PUPDR = 0;
|
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
|
#ifndef EBUG
|
||||||
TRUE_INLINE void iwdg_setup(){
|
TRUE_INLINE void iwdg_setup(){
|
||||||
uint32_t tmout = 16000000;
|
uint32_t tmout = 16000000;
|
||||||
@ -112,9 +129,50 @@ TRUE_INLINE void iwdg_setup(){
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void hw_setup(){
|
void hw_setup(){
|
||||||
|
RCC->AHBENR |= RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN;
|
||||||
gpio_setup();
|
gpio_setup();
|
||||||
|
i2c_setup(HIGH_SPEED);
|
||||||
|
pwm_setup();
|
||||||
#ifndef EBUG
|
#ifndef EBUG
|
||||||
iwdg_setup();
|
iwdg_setup();
|
||||||
#endif
|
#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;
|
||||||
|
}
|
||||||
|
|||||||
@ -60,8 +60,22 @@
|
|||||||
// state 0 - pressed, 1 - released
|
// state 0 - pressed, 1 - released
|
||||||
#define BTN_state(x) (BTNs_port->IDR & 1<<(9+x) ? 0 : 1)
|
#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 volatile uint32_t Tms;
|
||||||
extern int LEDsON;
|
extern int LEDsON;
|
||||||
|
|
||||||
uint8_t MSB(uint16_t val);
|
uint8_t MSB(uint16_t val);
|
||||||
void hw_setup();
|
void hw_setup();
|
||||||
|
|
||||||
|
void setPWM(int nch, uint8_t val);
|
||||||
|
uint8_t getPWM(int nch);
|
||||||
|
|||||||
313
F3:F303/NitrogenFlooding/i2c.c
Normal file
313
F3:F303/NitrogenFlooding/i2c.c
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the nitrogen project.
|
||||||
|
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stm32f3.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
50
F3:F303/NitrogenFlooding/i2c.h
Normal file
50
F3:F303/NitrogenFlooding/i2c.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the nitrogen project.
|
||||||
|
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.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 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);
|
||||||
@ -21,6 +21,7 @@
|
|||||||
//#include "can.h"
|
//#include "can.h"
|
||||||
//#include "flash.h"
|
//#include "flash.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
#include "i2c.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "usb.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();
|
USB_proc();
|
||||||
int l = USB_receivestr(inbuff, MAXSTRLEN);
|
int l = USB_receivestr(inbuff, MAXSTRLEN);
|
||||||
if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n");
|
if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n");
|
||||||
|
|||||||
Binary file not shown.
@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 8.0.2, 2023-03-22T12:09:09. -->
|
<!-- Written by QtCreator 8.0.2, 2023-03-22T23:42:03. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
<value type="QByteArray">{7bd84e39-ca37-46d3-be9d-99ebea85bc0d}</value>
|
||||||
</data>
|
</data>
|
||||||
<data>
|
<data>
|
||||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||||
@ -38,32 +38,43 @@
|
|||||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||||
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||||
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
|
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
<value type="bool" key="EditorConfiguration.cleanIndentation">false</value>
|
||||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||||
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||||
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||||
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||||
</valuemap>
|
</valuemap>
|
||||||
</data>
|
</data>
|
||||||
<data>
|
<data>
|
||||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||||
<valuemap type="QVariantMap">
|
<valuemap type="QVariantMap">
|
||||||
|
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||||
|
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||||
|
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||||
|
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||||
<valuemap type="QVariantMap" key="ClangTools">
|
<valuemap type="QVariantMap" key="ClangTools">
|
||||||
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||||
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
<value type="int" key="ClangTools.ParallelJobs">2</value>
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||||
@ -77,12 +88,12 @@
|
|||||||
<value type="QString" key="DeviceType">Desktop</value>
|
<value type="QString" key="DeviceType">Desktop</value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{65a14f9e-e008-4c1b-89df-4eaa4774b6e3}</value>
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/ELECTRONICS/STM32/F3-srcs/NitrogenFlooding</value>
|
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Big/Data/00__Electronics/STM32/F303-nolib/NitrogenFlooding</value>
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
|||||||
@ -14,6 +14,8 @@ hashgen/hashgen.c
|
|||||||
hashgen/hdr.c
|
hashgen/hdr.c
|
||||||
hashgen/hdr.h
|
hashgen/hdr.h
|
||||||
hashgen/test.c
|
hashgen/test.c
|
||||||
|
i2c.c
|
||||||
|
i2c.h
|
||||||
main.c
|
main.c
|
||||||
pdnuart.c
|
pdnuart.c
|
||||||
pdnuart.h
|
pdnuart.h
|
||||||
|
|||||||
@ -16,7 +16,9 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "adc.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
#include "i2c.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "strfunc.h"
|
#include "strfunc.h"
|
||||||
#include "version.inc"
|
#include "version.inc"
|
||||||
@ -24,15 +26,36 @@
|
|||||||
#include <stm32f3.h>
|
#include <stm32f3.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
static uint8_t I2Caddress = 0;
|
||||||
|
|
||||||
// parno - number of parameter (or -1); cargs - string with arguments (after '=') (==NULL for getter), iarg - integer argument
|
// 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;
|
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(parno < 0){ // enable/disable all
|
||||||
if(c){ LEDsON = i ? 1 : 0;}
|
if(c){
|
||||||
USB_sendstr("LED="); USB_sendstr(u2str(LEDsON));
|
LEDsON = (i ? 1 : 0);
|
||||||
|
if(!LEDsON) for(int _ = 0; _ < 4; ++_) LED_off(_);
|
||||||
|
}
|
||||||
|
sendkey("LEDon", -1, LEDsON);
|
||||||
}else{
|
}else{
|
||||||
if(parno >= LEDS_AMOUNT) return RET_WRONGARG;
|
if(parno >= LEDS_AMOUNT) return RET_WRONGARG;
|
||||||
if(c) switch(i){
|
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;
|
case 1: LED_on(parno); break;
|
||||||
default: LED_off(parno);
|
default: LED_off(parno);
|
||||||
}
|
}
|
||||||
USB_sendstr("LED"); USB_putbyte('0' + parno);
|
sendkey(cmd, parno, LED_get(parno));
|
||||||
USB_putbyte('='); USB_sendstr(u2str(LED_get(parno))); newline();
|
|
||||||
}
|
}
|
||||||
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;
|
return RET_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
int (*fn)(int, const char*, int32_t);
|
int (*fn)(const char*, int, const char*, int32_t);
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
const char *help;
|
const char *help;
|
||||||
} commands;
|
} commands;
|
||||||
|
|
||||||
commands cmdlist[] = {
|
commands cmdlist[] = {
|
||||||
{goodstub, "stub", "simple stub"},
|
{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)"},
|
{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}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void printhelp(){
|
static void printhelp(){
|
||||||
commands *c = cmdlist;
|
commands *c = cmdlist;
|
||||||
USB_sendstr("https://github.com/eddyem/stm32samples/tree/master/F3:F303/NitrogenFlooding build#" BUILD_NUMBER " @ " BUILD_DATE "\n");
|
USB_sendstr("https://github.com/eddyem/stm32samples/tree/master/F3:F303/NitrogenFlooding build#" BUILD_NUMBER " @ " BUILD_DATE "\n");
|
||||||
while(c->fn){
|
while(c->cmd){
|
||||||
|
if(!c->fn){ // header
|
||||||
|
USB_sendstr("\n ");
|
||||||
|
USB_sendstr(c->cmd);
|
||||||
|
USB_putbyte(':');
|
||||||
|
}else{
|
||||||
USB_sendstr(c->cmd);
|
USB_sendstr(c->cmd);
|
||||||
USB_sendstr(" - ");
|
USB_sendstr(" - ");
|
||||||
USB_sendstr(c->help);
|
USB_sendstr(c->help);
|
||||||
|
}
|
||||||
newline();
|
newline();
|
||||||
++c;
|
++c;
|
||||||
}
|
}
|
||||||
@ -73,6 +180,7 @@ static void printhelp(){
|
|||||||
|
|
||||||
static int parsecmd(const char *str){
|
static int parsecmd(const char *str){
|
||||||
char cmd[CMD_MAXLEN + 1];
|
char cmd[CMD_MAXLEN + 1];
|
||||||
|
//USB_sendstr("cmd="); USB_sendstr(str); USB_sendstr("__\n");
|
||||||
if(!str || !*str) return RET_CMDNOTFOUND;
|
if(!str || !*str) return RET_CMDNOTFOUND;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(*str > '@' && i < CMD_MAXLEN){ cmd[i++] = *str++; }
|
while(*str > '@' && i < CMD_MAXLEN){ cmd[i++] = *str++; }
|
||||||
@ -88,10 +196,13 @@ static int parsecmd(const char *str){
|
|||||||
str = omit_spaces(++str);
|
str = omit_spaces(++str);
|
||||||
getint(str, &iarg);
|
getint(str, &iarg);
|
||||||
}
|
}
|
||||||
}
|
}else str = NULL;
|
||||||
commands *c = cmdlist;
|
commands *c = cmdlist;
|
||||||
while(c->fn){
|
while(c->cmd){
|
||||||
if(strcmp(c->cmd, cmd) == 0) return c->fn(parno, str, iarg);
|
if(strcmp(c->cmd, cmd) == 0){
|
||||||
|
if(!c->fn) return RET_CMDNOTFOUND;
|
||||||
|
return c->fn(cmd, parno, str, iarg);
|
||||||
|
}
|
||||||
++c;
|
++c;
|
||||||
}
|
}
|
||||||
return RET_CMDNOTFOUND;
|
return RET_CMDNOTFOUND;
|
||||||
@ -105,6 +216,7 @@ static int parsecmd(const char *str){
|
|||||||
const char *cmd_parser(const char *txt){
|
const char *cmd_parser(const char *txt){
|
||||||
int ret = parsecmd(txt);
|
int ret = parsecmd(txt);
|
||||||
switch(ret){
|
switch(ret){
|
||||||
|
case RET_WRONGPARNO: return "Wrong parameter number\n"; break;
|
||||||
case RET_CMDNOTFOUND: printhelp(); return NULL; break;
|
case RET_CMDNOTFOUND: printhelp(); return NULL; break;
|
||||||
case RET_WRONGARG: return "Wrong command parameters\n"; break;
|
case RET_WRONGARG: return "Wrong command parameters\n"; break;
|
||||||
case RET_GOOD: return NULL; break;
|
case RET_GOOD: return NULL; break;
|
||||||
|
|||||||
@ -30,10 +30,11 @@
|
|||||||
#define CMD_MAXLEN (32)
|
#define CMD_MAXLEN (32)
|
||||||
|
|
||||||
enum{
|
enum{
|
||||||
RET_CMDNOTFOUND = -2,
|
RET_WRONGPARNO = -3, // wrong parameter number
|
||||||
RET_WRONGARG = -1,
|
RET_CMDNOTFOUND = -2, // command not found
|
||||||
RET_GOOD = 0,
|
RET_WRONGARG = -1, // wrong argument
|
||||||
RET_BAD = 1
|
RET_GOOD = 0, // all OK
|
||||||
|
RET_BAD = 1 // something wrong
|
||||||
};
|
};
|
||||||
|
|
||||||
#define printu(x) do{USB_sendstr(u2str(x));}while(0)
|
#define printu(x) do{USB_sendstr(u2str(x));}while(0)
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "2"
|
#define BUILD_NUMBER "24"
|
||||||
#define BUILD_DATE "2023-03-22"
|
#define BUILD_DATE "2023-03-22"
|
||||||
|
|||||||
@ -2,6 +2,7 @@ MEMORY
|
|||||||
{
|
{
|
||||||
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
|
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
|
||||||
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 40K
|
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 40K
|
||||||
|
ccmram (rwx) : ORIGIN = 0x10000000, LENGTH = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
PROVIDE(_BLOCKSIZE = 2048);
|
PROVIDE(_BLOCKSIZE = 2048);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user