add a little (ADC2 don't work - it's weird)

This commit is contained in:
Edward Emelianov 2023-03-22 23:43:51 +03:00
parent 6902b60020
commit 6832befb4a
14 changed files with 630 additions and 42 deletions

View File

@ -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

View File

@ -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]) ;

View File

@ -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;
}

View File

@ -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);

View 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, &reg, 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*)&reg16, 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);
}

View 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);

View File

@ -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");

View File

@ -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">

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "2" #define BUILD_NUMBER "24"
#define BUILD_DATE "2023-03-22" #define BUILD_DATE "2023-03-22"

View File

@ -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);