diff --git a/.gitignore b/.gitignore
index 17287e7..3843d7f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,9 @@
*.sublime-workspace
F1/client-term/client
*.bk
+*.config
+*.creator
+*.creator.user*
+*.files
+*.includes
+
diff --git a/F0-nolib/Servo/Readme.md b/F0-nolib/Servo/Readme.md
index 571e922..9a04c37 100644
--- a/F0-nolib/Servo/Readme.md
+++ b/F0-nolib/Servo/Readme.md
@@ -2,22 +2,13 @@ Servo motors SG-90 management
=============================
## GPIO
-
-- PA0 - (ADC_IN0) - Servo1 control,
-- PA1 - (ADC_IN1) - Servo2 control,
-- PA2 - (ADC_IN2) - Servo3 control,
-- PA3 - (ADC_IN3) - external analogue signal,
-- PA4 - (PullUp in) - ext. input 0,
-- PA5 - (PullUp in) - ext. input 1,
+- PA0..PA3 - 4 ADC inputs
- PA6 - (TIM3_CH1) - Servo1,
- PA7 - (TIM3_CH2) - Servo2,
- PA9 - (USART_Tx) - TX,
- PA10 - (USART_Rx) - RX,
-- PA13 - (PullUp in) - Jumper 0,
-- PA14 - (PullUp in) - Jumper 1,
- PB1 - (TIM3_CH4) - Servo3,
-- PF0 - (OpenDrain) - Buzzer,
-- PF1 - (OpenDrain) - External LED (or weak laser module).
+- PF1 - (OpenDrain) - external LED or laser (0 - active)
## UART
115200N1, not more than 100ms between data bytes in command.
diff --git a/F0-nolib/Servo/Servo.creator.user b/F0-nolib/Servo/Servo.creator.user
index f804542..7865f38 100644
--- a/F0-nolib/Servo/Servo.creator.user
+++ b/F0-nolib/Servo/Servo.creator.user
@@ -1,6 +1,6 @@
-
+
EnvironmentId
@@ -54,10 +54,7 @@
ProjectExplorer.Project.PluginSettings
-
-
- true
-
+
ProjectExplorer.Project.Target.0
@@ -78,7 +75,6 @@
false
- false
true
Сборка
@@ -97,7 +93,6 @@
false
- false
true
Сборка
@@ -172,19 +167,18 @@
2
+
- Особая программа
+
+
ProjectExplorer.CustomExecutableRunConfiguration
-
3768
false
true
false
false
true
-
-
1
@@ -195,10 +189,10 @@
ProjectExplorer.Project.Updater.FileVersion
- 20
+ 18
Version
- 20
+ 18
diff --git a/F0-nolib/Servo/Servo.creator.user.20 b/F0-nolib/Servo/Servo.creator.user.20
new file mode 100644
index 0000000..a077e0d
--- /dev/null
+++ b/F0-nolib/Servo/Servo.creator.user.20
@@ -0,0 +1,204 @@
+
+
+
+
+
+ EnvironmentId
+ {7bd84e39-ca37-46d3-be9d-99ebea85bc0d}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ KOI8-R
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ 1
+ true
+ false
+ true
+ false
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop
+ {65a14f9e-e008-4c1b-89df-4eaa4774b6e3}
+ 0
+ 0
+ 0
+
+ /Big/Data/00__Electronics/STM32/F0-nolib/Servo
+
+
+
+ all
+
+ false
+
+
+ false
+ true
+ Сборка
+
+ GenericProjectManager.GenericMakeStep
+
+ 1
+ Сборка
+
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+ clean
+
+ false
+
+
+ false
+ true
+ Сборка
+
+ GenericProjectManager.GenericMakeStep
+
+ 1
+ Очистка
+
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ По умолчанию
+ По умолчанию
+ GenericProjectManager.GenericBuildConfiguration
+
+ 1
+
+
+ 0
+ Установка
+
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+ Конфигурация установки
+
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+
+ false
+ false
+ 1000
+
+ true
+
+ false
+ false
+ false
+ false
+ true
+ 0.01
+ 10
+ true
+ 1
+ 25
+
+ 1
+ true
+ false
+ true
+ valgrind
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+
+ 2
+
+
+ Особая программа
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+ 3768
+ false
+ true
+ false
+ false
+ true
+
+
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 1
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 20
+
+
+ Version
+ 20
+
+
diff --git a/F0-nolib/Servo/Servo.files b/F0-nolib/Servo/Servo.files
index a21f58e..612e7b0 100644
--- a/F0-nolib/Servo/Servo.files
+++ b/F0-nolib/Servo/Servo.files
@@ -1,11 +1,11 @@
Makefile
adc.c
adc.h
+effects.c
+effects.h
hardware.c
hardware.h
main.c
-mainloop.c
-mainloop.h
protocol.c
protocol.h
usart.c
diff --git a/F0-nolib/Servo/adc.c b/F0-nolib/Servo/adc.c
index ede9f9e..ca6872c 100644
--- a/F0-nolib/Servo/adc.c
+++ b/F0-nolib/Servo/adc.c
@@ -20,7 +20,7 @@
/**
* @brief ADC_array - array for ADC channels with median filtering:
- * 0..3 - external NTC
+ * 0..3 - external channels
* 4 - internal Tsens
* 5 - Vref
*/
diff --git a/F0-nolib/Servo/effects.c b/F0-nolib/Servo/effects.c
new file mode 100644
index 0000000..254edd0
--- /dev/null
+++ b/F0-nolib/Servo/effects.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the Servo project.
+ * Copyright 2019 Edward 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 "effects.h"
+#include "hardware.h"
+#include "usart.h"
+
+static effect_t current_ef[3] = {EFF_NONE, EFF_NONE, EFF_NONE};
+
+#define SPD_STP (25)
+
+static void eff_madwipe(int n){
+ static uint32_t speed[3] = {SPD_STP, SPD_STP, SPD_STP};
+ if(onposition(n)){ // move back
+ if((speed[n]+=SPD_STP) > SG90_STEP) speed[n] = SPD_STP;
+ int val = 0;
+ if(getPWM(n) < SG90_MIDPULSE) val = 1;
+ setPWM(n, val, speed[n]);
+ }
+}
+
+static void eff_wipe(int n){
+ static uint8_t cntr = 0;
+ if(onposition(n)){ // move back
+ int val = 0;
+ if(getPWM(n) < SG90_MIDPULSE) val = 1;
+ if(++cntr < 4){ // stay a little in outermost positions
+ setPWM(n, getPWM(n), SG90_STEP/2);
+ }else{
+ cntr = 0;
+ setPWM(n, val, SG90_STEP/2);
+ }
+ }
+}
+
+static void eff_pendulum(int n){
+ const uint16_t steps[41] = {0, 10, 21, 33, 47, 62, 79, 97, 117, 140, 165, 193, 224, 258, 295, 337, 383, 434,
+ 490, 552, 621, 697, 766, 828, 884, 935, 981, 1023, 1060, 1094, 1125, 1153, 1178,
+ 1201, 1221, 1239, 1256, 1271, 1285, 1297, 1308};
+ static int8_t cntr = 0, dir = 1;
+ if(onposition(n)){
+ setPWM(n, SG90_MINPULSE + steps[cntr], SG90_STEP);
+ cntr += dir;
+ if(cntr == -1){ // min position
+ dir = 1;
+ cntr = 0; // repeat zero position one time
+ }else if(cntr == 41){ // max position
+ dir = -1;
+ cntr = 40; // and this position needs to repeat too
+ }
+ }
+}
+
+static void eff_pendsm(int n){
+ const uint16_t steps[19] = {0, 6, 10, 15, 22, 30, 40, 52, 66, 82, 101, 123, 148, 177, 210, 247, 289, 336, 389};
+ static int8_t cntr = 0, dir = 1;
+ if(onposition(n)){
+ setPWM(n, SG90_MINPULSE + steps[cntr], SG90_STEP);
+ cntr += dir;
+ if(cntr == -1){ // min position
+ dir = 1;
+ cntr = 1;
+ }else if(cntr == 19){ // max position
+ dir = -1;
+ cntr = 18;
+ }
+ }
+}
+
+void proc_effect(){
+ for(int i = 0; i < 3; ++i){
+ switch(current_ef[i]){
+ case EFF_WIPE:
+ eff_wipe(i);
+ break;
+ case EFF_MADWIPE:
+ eff_madwipe(i);
+ break;
+ case EFF_PENDULUM:
+ eff_pendulum(i);
+ break;
+ case EFF_SMPENDULUM:
+ eff_pendsm(i);
+ break;
+ case EFF_NONE:
+ default:
+ break;
+ }
+ }
+}
+
+effect_t set_effect(int n, effect_t eff){
+ if(n < 0 || n > 3) return EFF_NONE;
+ current_ef[n] = eff;
+ return eff;
+}
diff --git a/F0-nolib/Servo/effects.h b/F0-nolib/Servo/effects.h
new file mode 100644
index 0000000..f72d94b
--- /dev/null
+++ b/F0-nolib/Servo/effects.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the Servo project.
+ * Copyright 2019 Edward Emelianov .
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#ifndef EFFECTS_H__
+#define EFFECTS_H__
+
+#include "stm32f0.h"
+
+typedef enum{
+ EFF_NONE,
+ EFF_WIPE,
+ EFF_MADWIPE,
+ EFF_PENDULUM,
+ EFF_SMPENDULUM
+} effect_t;
+
+void proc_effect();
+effect_t set_effect(int n, effect_t eff);
+
+#endif // EFFECTS_H__
diff --git a/F0-nolib/Servo/hardware.c b/F0-nolib/Servo/hardware.c
index 938c63b..d4cd5cc 100644
--- a/F0-nolib/Servo/hardware.c
+++ b/F0-nolib/Servo/hardware.c
@@ -15,9 +15,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
+#include "adc.h"
+#include "effects.h"
#include "hardware.h"
#include "usart.h"
-#include "adc.h"
+
+uint32_t sg90step = SG90DEFSTEP;
static inline void iwdg_setup(){
/* Enable the peripheral clock RTC */
@@ -99,13 +103,10 @@ static inline void adc_setup(){
/**
* @brief gpio_setup - setup GPIOs for external IO
* GPIO pinout:
- * PA5 - floating input - Ef of TLE5205
- * PA13 - open drain - IN1 of TLE5205
- * PA14 - open drain - IN2 of TLE5205
- * PF0 - floating input - water level alert
- * PF1 - push-pull - external alarm
+ * PF1 - open drain - ext. LED/laser
* PA0..PA3 - ADC_IN0..3
- * PA4, PA6, PA7 - PWM outputs
+ * PA4 - open drain - onboard LED (always ON when board works)
+ * PB1, PA6, PA7 - Alt. F. - PWM outputs
* Registers
* MODER - input/output/alternate/analog (2 bit)
* OTYPER - 0 pushpull, 1 opendrain
@@ -120,67 +121,54 @@ static inline void adc_setup(){
static inline void gpio_setup(){
// Enable clocks to the GPIO subsystems
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOFEN;
- GPIOA->MODER =
- GPIO_MODER_MODER13_O | GPIO_MODER_MODER14_O |
- GPIO_MODER_MODER4_AF | GPIO_MODER_MODER6_AF |
- GPIO_MODER_MODER7_AF |
+ // PA6/7 - AF; PB1 - AF
+ GPIOA->MODER = GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF |
GPIO_MODER_MODER0_AI | GPIO_MODER_MODER1_AI |
- GPIO_MODER_MODER2_AI | GPIO_MODER_MODER3_AI;
- RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // enable syscfg clock for EXTI
- GPIOA->OTYPER = 3 << 13; // 13/14 opendrain
+ GPIO_MODER_MODER2_AI | GPIO_MODER_MODER3_AI |
+ GPIO_MODER_MODER4_O;
+ GPIOA->OTYPER = GPIO_OTYPER_OT_4;
+ GPIOB->MODER = GPIO_MODER_MODER1_AF;
+ //RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // enable syscfg clock for EXTI
+ GPIOF->ODR = 1<<1;
GPIOF->MODER = GPIO_MODER_MODER1_O;
- // PB1 - interrupt input
- /* (2) Select Port B for pin 1 external interrupt by writing 0001 in EXTI1*/
- /* (3) Configure the corresponding mask bit in the EXTI_IMR register */
- /* (4) Configure the Trigger Selection bits of the Interrupt line on rising edge*/
- /* (5) Configure the Trigger Selection bits of the Interrupt line on falling edge*/
- SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI1_PB; /* (2) */
- EXTI->IMR = EXTI_IMR_MR1; /* (3) */
- //EXTI->RTSR = 0x0000; /* (4) */
- EXTI->FTSR = EXTI_FTSR_TR1; /* (5) */
- /* (6) Enable Interrupt on EXTI0_1 */
- /* (7) Set priority for EXTI0_1 */
- NVIC_EnableIRQ(EXTI0_1_IRQn); /* (6) */
- NVIC_SetPriority(EXTI0_1_IRQn, 3); /* (7) */
+ GPIOF->OTYPER = GPIO_OTYPER_OT_1;
// alternate functions:
- // PA4 - TIM14_CH1 (AF4)
- // PA6 - TIM16_CH1 (AF5), PA7 - TIM17_CH1 (AF5)
- GPIOA->AFR[0] = (GPIOA->AFR[0] &~ (GPIO_AFRL_AFRL4 | GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) \
- | (4 << (4 * 4)) | (5 << (6 * 4)) | (5 << (7 * 4));
+ // PA6 - TIM3_CH1, PA7 - TIM3_CH2, PB1 - TIM3_CH4 (all - AF1)
+ GPIOA->AFR[0] = (GPIOA->AFR[0] &~ (GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) \
+ | (1 << (6 * 4)) | (1 << (7 * 4));
+ GPIOB->AFR[0] = (GPIOB->AFR[0] &~ (GPIO_AFRL_AFRL1)) \
+ | (1 << (1 * 4)) ;
+}
+
+// change period of PWM
+// MAX freq - 200Hz!!!
+void setTIM3T(uint32_t T){
+ if(T < 1000 || T > 65536) return;
+ TIM3->ARR = T - 1;
+ // step = ampl / freq(Hz) * 3
+ sg90step = SG90_AMPL * T;
+ sg90step >>= 18; // /262144
}
static inline void timers_setup(){
- // timer 14 ch1 - cooler PWM
- // timer 16 ch1 - heater PWM
- // timer 17 ch1 - pump PWM
- RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM14EN; // enable clocking for timers 3 and 14
- RCC->APB2ENR |= RCC_APB2ENR_TIM16EN | RCC_APB2ENR_TIM17EN; // & timers 16/17
- // PWM mode 1 (active -> inactive)
- TIM14->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
- TIM16->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
- TIM17->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
+ // timer 3 ch1, 2, 4 PWM for three servos
+ RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
+ // PWM mode 1 (active -> inactive) on all three channels
+ TIM3->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 |
+ TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1;
+ TIM3->CCMR2 = TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1;
// frequency
- TIM14->PSC = 59; // 0.8MHz for 3kHz PWM
- TIM16->PSC = 18749; // 2.56kHz for 10Hz PWM
- TIM17->PSC = 5; // 8MHz for 31kHz PWM
+ TIM3->PSC = 47; // 1MHz -> 1us per tick
// ARR for 8-bit PWM
- TIM14->ARR = 254;
- TIM16->ARR = 254;
- TIM17->ARR = 254;
- // start in OFF state
- // TIM14->CCR1 = 0; and so on
+ TIM3->ARR = 19999; // 50Hz
// enable main output
- TIM14->BDTR |= TIM_BDTR_MOE;
- TIM16->BDTR |= TIM_BDTR_MOE;
- TIM17->BDTR |= TIM_BDTR_MOE;
+ TIM3->BDTR |= TIM_BDTR_MOE;
// enable PWM output
- TIM14->CCER = TIM_CCER_CC1E;
- TIM16->CCER = TIM_CCER_CC1E;
- TIM17->CCER = TIM_CCER_CC1E;
- // enable timers
- TIM14->CR1 |= TIM_CR1_CEN;
- TIM16->CR1 |= TIM_CR1_CEN;
- TIM17->CR1 |= TIM_CR1_CEN;
+ TIM3->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC4E;
+ TIM3->DIER = TIM_DIER_UIE; //TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC4IE;
+ // enable timer & ARR buffering
+ TIM3->CR1 |= TIM_CR1_CEN | TIM_CR1_ARPE;
+ NVIC_EnableIRQ(TIM3_IRQn);
}
void hw_setup(){
@@ -192,10 +180,79 @@ void hw_setup(){
iwdg_setup();
}
+static uint32_t target_Val[3] = {SG90_MIDPULSE, SG90_MIDPULSE, SG90_MIDPULSE};
+static uint32_t target_Speed[3] = {SG90DEFSTEP, SG90DEFSTEP, SG90DEFSTEP};
+static uint8_t onpos[3] = {0,0,0};
+volatile uint32_t *addr[3] = {&TIM3->CCR1, &TIM3->CCR2, &TIM3->CCR4};
+int32_t getPWM(int nch){
+ return *addr[nch];
+}
+
+// return current value
+int32_t setPWM(int nch, uint32_t val, uint32_t speed){
+ if(nch < 0 || nch > 2) return 0;
+ if(speed > 0){
+ if(speed > SG90_STEP) speed = SG90_STEP;
+ target_Speed[nch] = speed;
+ }
+ uint8_t ch = 1;
+ if(val >= SG90_MINPULSE && val <= SG90_MAXPULSE) target_Val[nch] = val;
+ else if(val == 0) target_Val[nch] = SG90_MINPULSE;
+ else if(val == 1) target_Val[nch] = SG90_MAXPULSE;
+ else if(val == 2) target_Val[nch] = SG90_MIDPULSE;
+ else ch = 0;
+ if(ch){
+ onpos[nch] = 0;
+ }
+ return *addr[nch];
+}
+
+uint8_t onposition(int nch){
+ return onpos[nch];
+}
+
+static void chkPWM(int n){
+ if(n < 0 || n > 2) return;
+ uint32_t cur = *addr[n], tg = target_Val[n];
+ if(cur == tg){
+ onpos[n] = 1;
+ return;
+ }
+ uint32_t diff = tg - cur;
+ int sign = 1;
+ if(cur > tg){
+ diff = cur - tg;
+ sign = -1;
+ }
+ if(diff > target_Speed[n]) diff = target_Speed[n];
+ *addr[n] = cur + sign*diff;
+}
+
+void tim3_isr(){
+ /*
+ if(TIM3->SR & TIM_SR_CC1IF){ // 1st channel
+ chkPWM(0);
+ }
+ if(TIM3->SR & TIM_SR_CC2IF){ // 2nd channel
+ chkPWM(1);
+ }
+ if(TIM3->SR & TIM_SR_CC4IF){ // 3rd channel
+ chkPWM(2);
+ }*/
+ if(TIM3->SR & TIM_SR_UIF){
+ chkPWM(0);
+ chkPWM(1);
+ chkPWM(2);
+ }
+ TIM3->SR = 0;
+}
+
+/*
void exti0_1_isr(){
if (EXTI->PR & EXTI_PR_PR1){
- EXTI->PR |= EXTI_PR_PR1; /* Clear the pending bit */
+ EXTI->PR |= EXTI_PR_PR1; // Clear the pending bit
;
}
}
+*/
diff --git a/F0-nolib/Servo/hardware.h b/F0-nolib/Servo/hardware.h
index 6e1a37a..1a12013 100644
--- a/F0-nolib/Servo/hardware.h
+++ b/F0-nolib/Servo/hardware.h
@@ -20,59 +20,21 @@
#define HARDWARE_H
#include "stm32f0.h"
-// measure flow sensor data each 1 second
-#define FLOW_RATE_MS (999)
-// previous as string constant
-#define FLOWRATESTR "1"
-
-// each TMEASURE_MS ms calculate temperatures & check them
-#define TMEASURE_MS (1000)
-// each TCHECK_MS ms check cooler state and regulate temperature
-#define TCHECK_MS (10000)
-
-/*
- temperature limits and tolerances
- */
-// tolerance: +-1.5degrC
-#define TEMP_TOLERANCE (15)
-// dT tolerance: +-0.5degrC
-#define DT_TOLERANCE (5)
-// maximal heater temperature - 80degrC; normal - <60
-#define MAX_HEATER_T (800)
-#define NORMAL_HEATER_T (600)
-// maximal output temperature - 45degrC; minimal - 10
-#define MAX_OUTPUT_T (450)
-#define MIN_OUTPUT_T (100)
-// temperature working values: from 15 to 30degrC
-#define OUTPUT_T_H (300)
-#define OUTPUT_T_L (150)
-
-/*
- other limits & tolerances
-*/
-// minimal flow rate - 0.2l per minute
-#define MIN_FLOW_RATE (20)
-// normal flow rate
-#define NORMAL_FLOW_RATE (30)
-// minimal PWM values when motors should work
-#define MIN_PUMP_PWM (90)
-#define MIN_COOLER_PWM (90)
-
-// PWM setters and getters
-#define SET_COOLER_PWM(N) do{TIM14->CCR1 = (uint32_t)N;}while(0)
-#define GET_COOLER_PWM() (uint16_t)(TIM14->CCR1)
-#define SET_HEATER_PWM(N) do{TIM16->CCR1 = (uint32_t)N;}while(0)
-#define GET_HEATER_PWM() (uint16_t)(TIM16->CCR1)
-#define SET_PUMP_PWM(N) do{TIM17->CCR1 = (uint32_t)N;}while(0)
-#define GET_PUMP_PWM() (uint16_t)(TIM17->CCR1)
-
-// ext. alarm states
-#define ALARM_ON() pin_set(GPIOF, 2)
-#define ALARM_OFF() pin_clear(GPIOF, 2)
-#define ALARM_STATE() pin_read(GPIOF, 2)
+// minimal and maximal pulse length for SG90
+#define SG90_MINPULSE (700)
+#define SG90_MAXPULSE (2100)
+#define SG90_MIDPULSE ((SG90_MINPULSE+SG90_MAXPULSE)/2)
+#define SG90_AMPL (SG90_MAXPULSE-SG90_MINPULSE)
+#define SG90DEFSTEP (100)
+#define SG90_STEP (sg90step)
extern volatile uint32_t Tms;
+extern uint32_t sg90step;
void hw_setup(void);
+int32_t setPWM(int nch, uint32_t val, uint32_t speed);
+int32_t getPWM(int nch);
+uint8_t onposition(int nch);
+void setTIM3T(uint32_t T);
#endif // HARDWARE_H
diff --git a/F0-nolib/Servo/main.c b/F0-nolib/Servo/main.c
index 63eebf4..00f1c6d 100644
--- a/F0-nolib/Servo/main.c
+++ b/F0-nolib/Servo/main.c
@@ -19,8 +19,8 @@
* MA 02110-1301, USA.
*/
#include "adc.h"
+#include "effects.h"
#include "hardware.h"
-#include "mainloop.h"
#include "protocol.h"
#include "usart.h"
#include // memcpy
@@ -38,12 +38,12 @@ int main(void){
char *txt;
hw_setup();
SysTick_Config(6000, 1);
- SEND_BLK("Servos controller v0.1\n");
+ SEND("Servos controller v0.1\n");
if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
- SEND_BLK("WDGRESET=1");
+ SEND("WDGRESET=1\n");
}
if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured
- SEND_BLK("SOFTRESET=1");
+ SEND("SOFTRESET=1\n");
}
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
while (1){
@@ -56,7 +56,7 @@ int main(void){
IWDG->KR = IWDG_REFRESH;
}
}
- mainloop();
+ proc_effect();
IWDG->KR = IWDG_REFRESH;
usart1_sendbuf();
}
diff --git a/F0-nolib/Servo/protocol.c b/F0-nolib/Servo/protocol.c
index 52f8c85..335518f 100644
--- a/F0-nolib/Servo/protocol.c
+++ b/F0-nolib/Servo/protocol.c
@@ -15,81 +15,170 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+#include "adc.h"
+#include "effects.h"
#include "hardware.h"
#include "protocol.h"
#include "usart.h"
-#include "adc.h"
-#include "mainloop.h"
+
+
extern uint8_t crit_error;
#ifdef EBUG
+static void putADC(int n){
+ put_string("ADC");
+ put_char('0' + n);
+ put_string(" value: ");
+ put_uint(getADCval(n));
+ put_char('\n');
+// while(LINE_BUSY == usart1_sendbuf());
+}
+
/**
* @brief debugging_proc - debugging functions
* @param command - rest of cmd
*/
static void debugging_proc(const char *command){
- const char *ptr = command;
+ char ch;
int i;
- switch(*ptr++){
+ switch(*command++){
case 'w':
- usart1_send("Test watchdog", 0);
+ SEND("Test watchdog\n");
while(1){nop();}
break;
case 'A': // raw ADC values depending on next symbol
- i = *ptr++ - '0';
- if(i < 0 || i > NUMBER_OF_ADC_CHANNELS){
- usart1_send("Wrong channel nuber!", 0);
- return;
+ ch = *command;
+ if(ch == 'A' || ch == 'B'){
+ for(i = 0; i < NUMBER_OF_ADC_CHANNELS; ++i){
+ putADC(i);
+ }
+ }else{
+ i = ch - '0';
+ if(i < 0 || i >= NUMBER_OF_ADC_CHANNELS){
+ SEND("Wrong channel nuber!\n");
+ }else putADC(i);
}
- put_string("ADC value: ");
- put_uint(getADCval(i));
- put_string(", ");
- usart1_sendbuf();
+ break;
+ case 'B':
+ SEND("B command\n");
break;
default:
+ SEND("wrong command\n");
break;
}
+ while(LINE_BUSY == usart1_sendbuf()){nop();};
}
#endif
+static void chPWM(const char *command){
+ int n = *command++ - '1';
+ if(n < 0 || n > 2){
+ put_string("Wrong PWM channel number");
+ return;
+ }
+ int32_t CCR = getPWM(n);
+ if((command = getnum(command, &CCR))){
+ set_effect(n, EFF_NONE);
+ int32_t speed = SG90_STEP;
+ if(*command++ == ','){
+ getnum(command, &speed);
+ }
+ CCR = setPWM(n, CCR, speed);
+ }
+ put_string("pulse");
+ put_char('1' + n);
+ put_char('=');
+ put_int(CCR);
+ put_char('\n');
+}
+
+static void set_servoT(const char *buf){
+ int32_t T;
+ if(!getnum(buf, &T) || T < 1000 || T > 65535){
+ put_string("Bad period value\n");
+ usart1_sendbuf();
+ return;
+ }
+ put_string("Set period to ");
+ put_int(T);
+ put_string(" us\n");
+ setTIM3T(T);
+ usart1_sendbuf();
+}
+
+static void chk_effect(const char *cmd, effect_t eff, const char *name){
+ if(set_effect(*(++cmd)-'1', eff) == eff){
+ put_string("Turn on ");
+ put_string(name);
+ put_string(" effect\n");
+ }else put_string("err\n");
+}
+
/**
* @brief process_command - command parser
* @param command - command text (all inside [] without spaces)
* @return text to send over terminal or NULL
*/
char *process_command(const char *command){
- const char *ptr = command;
char *ret = NULL;
usart1_sendbuf(); // send buffer (if it is already filled)
- switch(*ptr++){
+ switch(*command){
case '?': // help
SEND_BLK(
+ "1-3[pos[,speed]]- set/get xth pulse length (us) (0,1,2 - min, max, mid)\n"
+ "fx - servo period (us)"
+ "Mn - set Mad Wipe effect\n"
+ "Pn - set Pendulum effect\n"
"R - reset\n"
+ "Sn - set Small Pendulum effect\n"
"t - get MCU temperature (approx.)\n"
- "V - get Vdd"
+ "V - get Vdd\n"
+ "Wn - set Wipe effect\n"
);
#ifdef EBUG
SEND_BLK("d -> goto debug:\n"
- "\tAx - get raw ADCx value\n"
- "\tw - test watchdog"
+ "\tAx - get raw ADCx value (A for all)\n"
+ "\tw - test watchdog\n"
);
#endif
break;
+ case '1':
+ case '2':
+ case '3':
+ chPWM(command);
+ break;
+ case 'f':
+ set_servoT(++command);
+ break;
+ case 'M':
+ chk_effect(command, EFF_MADWIPE, "mad wipe");
+ break;
+ case 'P':
+ chk_effect(command, EFF_PENDULUM, "pendulum");
+ break;
case 'R': // reset MCU
NVIC_SystemReset();
break;
+ case 'S':
+ chk_effect(command, EFF_SMPENDULUM, "small pendulum");
+ break;
case 't': // get mcu T
put_string("MCUTEMP10=");
put_int(getMCUtemp());
+ put_char('\n');
break;
case 'V': // get Vdd
put_string("VDD100=");
put_uint(getVdd());
+ put_char('\n');
+ break;
+ case 'W':
+ chk_effect(command, EFF_WIPE, "wipe");
break;
#ifdef EBUG
case 'd':
- debugging_proc(ptr);
+ debugging_proc(++command);
return NULL;
break;
#endif
diff --git a/F0-nolib/Servo/servo.bin b/F0-nolib/Servo/servo.bin
index c00bb13..1c373a4 100755
Binary files a/F0-nolib/Servo/servo.bin and b/F0-nolib/Servo/servo.bin differ
diff --git a/F0-nolib/Servo/usart.c b/F0-nolib/Servo/usart.c
index ec54a86..7ab5e22 100644
--- a/F0-nolib/Servo/usart.c
+++ b/F0-nolib/Servo/usart.c
@@ -42,7 +42,8 @@ static int trbufidx = 0;
int put_char(char c){
if(trbufidx >= UARTBUFSZ - 1){
- if(ALL_OK != usart1_sendbuf()) return 1;
+ for(int i = 0; i < 72000000 && ALL_OK != usart1_sendbuf(); ++i)
+ if(i == 72000000) return 1;
}
trbuf[trbufidx++] = c;
return 0;
@@ -84,10 +85,11 @@ int put_uint(uint32_t N){
*/
TXstatus usart1_sendbuf(){
int len = trbufidx;
- trbufidx = 0;
if(len == 0) return ALL_OK;
else if(len > UARTBUFSZ) len = UARTBUFSZ;
- return usart1_send(trbuf, len);
+ TXstatus s = usart1_send(trbuf, len);
+ if(s == ALL_OK) trbufidx = 0;
+ return s;
}
void USART1_config(){
@@ -125,8 +127,14 @@ void USART1_config(){
NVIC_EnableIRQ(USART1_IRQn); /* (4) */
}
+#ifdef EBUG
+#define TMO 0
+#else
+#define TMO 1
+#endif
+
void usart1_isr(){
- static uint8_t timeout = 1 // == 0 for human interface without timeout
+ static uint8_t timeout = TMO // == 0 for human interface without timeout
,nctr = 0 // counter of '#' received
,incmd = 0 // ==1 - inside command
;
@@ -235,7 +243,7 @@ TXstatus usart1_send(const char *str, int len){
if(len == 0) return ALL_OK;
DMA1_Channel2->CCR &= ~DMA_CCR_EN;
memcpy(tbuf, str, len);
- tbuf[len++] = '\n';
+// tbuf[len++] = '\n';
DMA1_Channel2->CNDTR = len;
DMA1_Channel2->CCR |= DMA_CCR_EN; // start transmission
return ALL_OK;
@@ -252,7 +260,7 @@ TXstatus usart1_send_blocking(const char *str, int len){
USART1->TDR = *str++;
while(!(USART1->ISR & USART_ISR_TXE));
}
- USART1->TDR = '\n';
+// USART1->TDR = '\n';
while(!(USART1->ISR & USART_ISR_TC));
txrdy = 1;
return ALL_OK;
diff --git a/F0-nolib/Servo/usart.h b/F0-nolib/Servo/usart.h
index 9b7f8dd..55fd101 100644
--- a/F0-nolib/Servo/usart.h
+++ b/F0-nolib/Servo/usart.h
@@ -38,8 +38,8 @@ typedef enum{
#define usart1ovr() (bufovr)
// send constant string
-#define SEND_BLK(x) do{while(LINE_BUSY == usart1_send_blocking(x, sizeof(x)-1));}while(0)
-#define SEND(x) do{while(LINE_BUSY == usart1_send(x, sizeof(x)-1));}while(0)
+#define SEND_BLK(x) do{while(LINE_BUSY == usart1_send_blocking(x, sizeof(x)-1)) IWDG->KR = IWDG_REFRESH;}while(0)
+#define SEND(x) do{while(LINE_BUSY == usart1_send(x, sizeof(x)-1)) IWDG->KR = IWDG_REFRESH;}while(0)
extern uint8_t bufovr;