diff --git a/Makefile b/Makefile index 76f527c..9d4b473 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ DEFS = -DSTM32L1 -FP_FLAGS ?= -msoft-float +FP_FLAGS ?= -msoft-float -mfloat-abi=soft ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd LDSCRIPT = stm32l100rc.ld @@ -21,8 +21,10 @@ OBJS += utils/usart.o OBJS += utils/timebase.o OBJS += utils/debounce.o OBJS += utils/nvic.o +OBJS += utils/str_utils.o OBJS += init.o OBJS += blink.o +OBJS += capture.o OBJS += lib/common.o ################################################################ diff --git a/capture.c b/capture.c new file mode 100644 index 0000000..aeff424 --- /dev/null +++ b/capture.c @@ -0,0 +1,56 @@ +#include "capture.h" +#include "utils/timebase.h" + +uint16_t adc_measure(uint8_t channel) +{ + ADC1_SQR5 = channel; // select n-th channel + ADC1_SQR1 = 0; // sets length to 1 (0000) + + ADC1_CR2 |= ADC_CR2_SWSTART; // start conversion + + // wait for end of conversion + while (!(ADC1_SR & ADC_SR_EOC)); + return ADC1_DR; +} + + +float measure_angle(void) +{ + uint16_t d = adc_measure(18); + return -135 + 270 * (d / 4095.0f); +} + + +float measure_exposure(void) +{ + uint16_t d = adc_measure(8); + float alpha = d / 4095.0f; + return alpha * 100; // % +} + + +float measure_resistance(void) +{ + uint16_t d = adc_measure(9); + + float alpha = d / 4095.0f; + float ref_r = 330; + + return (ref_r * alpha) / (1 - alpha); +} + + +float measure_temp(void) +{ + uint16_t ts_data = adc_measure(ADC_CH_TEMP); + + // temperature calibration constants for L100 are undocumented, + // probably because the sensor is broken. + + // Temperature sensor is unstable and unreliable. + + uint16_t ts_cal1 = MMIO16(0x1FF800FA); + uint16_t ts_cal2 = MMIO16(0x1FF800FE); + + return ((80.0f / (ts_cal2 - ts_cal1)) * (ts_data - ts_cal1) + 30.0f); +} diff --git a/capture.h b/capture.h new file mode 100644 index 0000000..9549e1e --- /dev/null +++ b/capture.h @@ -0,0 +1,8 @@ +#pragma once +#include + +uint16_t adc_measure(uint8_t channel); +float measure_temp(void); +float measure_angle(void); +float measure_resistance(void); +float measure_exposure(void); diff --git a/doc/controls.txt b/doc/controls.txt new file mode 100644 index 0000000..fc41a49 --- /dev/null +++ b/doc/controls.txt @@ -0,0 +1,3 @@ +b,d - změna střídy PWM, krok 50 (rozsah 0-1000) +m,n - změna hodnoty DAC, krok 117 (rozsah 0-4095) +g - nulovat počítadlo závory diff --git a/doc/output.txt b/doc/output.txt new file mode 100644 index 0000000..a596df0 --- /dev/null +++ b/doc/output.txt @@ -0,0 +1 @@ +T -179.6°C | An -6.6° | R 589.2 | L 1.8% | G 0, #0 | DA 4095 | PWM 1000 diff --git a/init.c b/init.c index c4745a2..52c35ac 100644 --- a/init.c +++ b/init.c @@ -13,6 +13,8 @@ void init_gpios(void) // LEDs gpio_set_mode(GPIOC, BIT8 | BIT9, MODER_OUTPUT); + + gpio_set_mode(GPIOC, BIT11, MODER_INPUT); } @@ -67,24 +69,71 @@ void init_systick(void) void init_adc(void) { - gpio_set_mode(GPIOB, BIT12, MODER_ANALOG); + // B1 ... AN9 Vcc o--[330R]--(B1)--[?R]--| GND + // B0 ... AN8 fototransistor + // B12 .. AN18 "angle" potentiometer + // C5 ... AN15 + + gpio_set_mode(GPIOB, BIT1 | BIT0 | BIT12, MODER_ANALOG); + //gpio_set_mode(GPIOC, BIT5, MODER_ANALOG); + + // enable clock for ADC + RCC_APB2ENR |= RCC_APB2ENR_ADC1EN; + + // 12-bit, right aligned + ADC1_CR1 = 0; + ADC1_CR2 = 0; + + // enable internal temperature sensor (16) & voltage reference (17) + ADC_CCR |= ADC_CCR_TSVREFE; - // TODO + ADC1_SMPR3 = 0b100; // sample time + + // turn ADC on + ADC1_CR2 |= ADC_CR2_ADON; + // Wait for ADONS + while (!(ADC1_SR & ADC_SR_ADONS)); } +void init_dac(void) +{ + RCC_APB1ENR |= RCC_APB1ENR_DACEN; // enable DAC + gpio_set_mode(GPIOA, BIT4, MODER_ANALOG); // PA4 - DAC CH1 out + DAC_CR |= DAC_CR_EN1; // enable first channel +} +void init_pwm1(void) +{ + // enable clock for the timer + RCC_APB1ENR |= RCC_APB1ENR_TIM3EN; + // using timer 3, channel 1 + gpio_set_af(GPIOA, BIT6, AF2); + patch_register(&TIM3_CCMR1, TIM_CCMR1_OC1M, TIM_OCM_PWM1); // set PWM1 mode + TIM3_CCMR1 |= TIM_CCMR1_OC1PE; // preload enable + TIM3_CR1 |= TIM_CR1_ARPE; // auto reload is buffered + TIM3_CCER |= TIM_CCER_CC1E; // enable output compare (PWM output) + patch_register(&TIM3_CR1, TIM_CR1_CMS, TIM_CMS_EDGE); // centering mode + patch_register(&TIM3_CR1, TIM_CR1_DIR, 0); // count upwards only + // frequency set to 16 kHz + TIM3_PSC = 0; // prescaller + TIM3_ARR = 1000; // sets frequency + TIM3_CCR1 = 0; // duty cycle + // generate update event to latch the value registers + TIM3_EGR |= TIM_EGR_UG; + TIM3_CR1 |= TIM_CR1_CEN; // enable timer. +} diff --git a/init.h b/init.h index 0ee49fd..a8d62f6 100644 --- a/init.h +++ b/init.h @@ -6,3 +6,5 @@ void init_gpios(void); void init_usart(void); void init_systick(void); void init_adc(void); +void init_dac(void); +void init_pwm1(void); diff --git a/lib/common.c b/lib/common.c index 729b031..0dd7ad0 100644 --- a/lib/common.c +++ b/lib/common.c @@ -9,3 +9,10 @@ inline uint32_t __RBIT(uint32_t value) return (result); } + +__attribute__((always_inline)) +inline void patch_register(io32_t reg, uint32_t mask, uint32_t replacement) +{ + *reg &= ~mask; + *reg |= replacement << __CTZ(mask); +} diff --git a/lib/common.h b/lib/common.h index 6d8cc63..d157e6a 100644 --- a/lib/common.h +++ b/lib/common.h @@ -30,6 +30,7 @@ typedef volatile uint64_t* io64_t; #define wait_for_interrupt() __asm__("WFI") #define __CLZ(div) __builtin_clz(div) +#define __CTZ(div) __builtin_ctz(div) #define count_leading_zeros(div) __CLZ(div) #define __REV(x) __builtin_bswap32(x) @@ -86,6 +87,9 @@ uint32_t __RBIT(uint32_t value); // defined in c file as inline asm #define BIT31 BIT(31) +void patch_register(io32_t reg, uint32_t mask, uint32_t replacement); + + #include "defs_base.h" #include "defs_gpio.h" diff --git a/lib/defs_adc.h b/lib/defs_adc.h index bdde6a4..f217f72 100644 --- a/lib/defs_adc.h +++ b/lib/defs_adc.h @@ -20,6 +20,10 @@ // ADC1 +// internal channels +#define ADC_CH_TEMP 16 +#define ADC_CH_VREF 17 + #define ADC1_SR MMIO32(ADC1_BASE + 0x00) // ADC status register, #define ADC1_CR1 MMIO32(ADC1_BASE + 0x04) // ADC control register 1, #define ADC1_CR2 MMIO32(ADC1_BASE + 0x08) // ADC control register 2, @@ -46,7 +50,6 @@ #define ADC1_SMPR0 MMIO32(ADC1_BASE + 0x5C) // ADC sample time register 0, - //**************************************************************************** //* //* BIT MASKS AND DEFINITIONS diff --git a/lib/defs_base.h b/lib/defs_base.h index fdc2b78..9626643 100644 --- a/lib/defs_base.h +++ b/lib/defs_base.h @@ -114,10 +114,12 @@ #define DESIG_UNIQUE_ID2 MMIO32(DESIG_UNIQUE_ID_BASE + 0x14) /* ST provided factory calibration values @ 3.0V */ -#define ST_VREFINT_CAL MMIO16(0x1FF80078) -#define ST_TSENSE_CAL1_30C MMIO16(0x1FF8007A) -#define ST_TSENSE_CAL2_110C MMIO16(0x1FF8007E) - +//#define ST_VREFINT_CAL MMIO16(0x1FF80078) +//#define ST_TSENSE_CAL1_30C MMIO16(0x1FF8007A) +//#define ST_TSENSE_CAL2_110C MMIO16(0x1FF8007E) +#define ST_VREFINT_CAL MMIO16(0x1FF800F8) +#define ST_TSENSE_CAL1_30C MMIO16(0x1FF800FA) +#define ST_TSENSE_CAL2_110C MMIO16(0x1FF800FE) // ---- ARMv7M+ only ---- diff --git a/lib/defs_timers.h b/lib/defs_timers.h index a296230..20979d4 100644 --- a/lib/defs_timers.h +++ b/lib/defs_timers.h @@ -253,6 +253,13 @@ #define TIM_CR1_CMS_0 0x0020 // Bit 0 #define TIM_CR1_CMS_1 0x0040 // Bit 1 +enum TIM_CenterAlignMode { + TIM_CMS_EDGE = 0, + TIM_CMS_CENTER_FLAGS_UP = 1, + TIM_CMS_CENTER_FLAGS_DOWN = 2, + TIM_CMS_CENTER_FLAGS_BOTH = 3, +}; + #define TIM_CR1_ARPE 0x0080 // Auto-reload preload enable #define TIM_CR1_CKD 0x0300 // CKD[1:0] bits (clock division) @@ -344,6 +351,17 @@ #define TIM_CCMR1_OC1M_1 0x0020 // Bit 1 #define TIM_CCMR1_OC1M_2 0x0040 // Bit 2 +enum TIM_OutputCompareMode { + TIM_OCM_FROZEN = 0, + TIM_OCM_HIGH_ON_MATCH = 1, + TIM_OCM_LOW_ON_MATCH = 2, + TIM_OCM_TOGGLE_ON_MATCH = 3, + TIM_OCM_FORCE_LOW = 4, + TIM_OCM_FORCE_HIGH = 5, + TIM_OCM_PWM1 = 6, + TIM_OCM_PWM2 = 7, +}; + #define TIM_CCMR1_OC1CE 0x0080 // Output Compare 1Clear Enable #define TIM_CCMR1_CC2S 0x0300 // CC2S[1:0] bits (Capture/Compare 2 Selection) diff --git a/main.c b/main.c index b04e67a..c020ac6 100644 --- a/main.c +++ b/main.c @@ -1,16 +1,19 @@ #include +#include + #include "utils/usart.h" #include "utils/timebase.h" #include "utils/debounce.h" +#include "utils/str_utils.h" #include "init.h" #include "blink.h" +#include "capture.h" -void say_hello(void) -{ - usart_tx_string(USART3, "HELLO\r\n"); -} +// Gate state +static bool gate_closed = false; +static uint32_t gate_cnt = 0; /** IRQ */ @@ -24,8 +27,34 @@ void USART2_IRQHandler(void) if (USART2_SR & USART_SR_RXNE) { blue_blink(); + // handle incoming char. char c = usart_rx_char(USART2); - usart_tx_char(USART2, c); + + switch (c) { + case 'g': // nulovat pocitadlo preruseni + gate_cnt = 0; + break; + + case 'm': // zvysit DAC hodnotu + if (DAC_DHR12R1 < 4095) DAC_DHR12R1 += 117; + break; + + case 'n': // snizit DAC hodnotu + if (DAC_DHR12R1 > 0) DAC_DHR12R1 -= 117; + break; + + case 'b': // zvysit PWM stridu + if (TIM3_CCR1 < 1000) TIM3_CCR1 += 50; + break; + + case 'd': // snizit PWM stridu + if (TIM3_CCR1 > 0) TIM3_CCR1 -= 50; + break; + + default: + break; + } + USART2_SR ^= USART_SR_RXNE; } @@ -33,7 +62,21 @@ void USART2_IRQHandler(void) -/** Called by startup script, before main() */ +// Gate close handler +void gate_close(void) +{ + gate_closed = 1; + gate_cnt++; +} + +// Gate open handler +void gate_open(void) +{ + gate_closed = 0; +} + + +/** Init peripherals; Called by startup script, before main() */ void SystemInit(void) { init_clock(); @@ -41,12 +84,62 @@ void SystemInit(void) init_gpios(); init_usart(); init_adc(); + init_dac(); + init_pwm1(); + + register_periodic_task(green_toggle, 1000); // indicate running state - register_periodic_task(green_toggle, 1000); + register_debounced_pin(GPIOB, 11, gate_close, gate_open); // gate handler } + int main(void) { - while (1); + char buf[200]; + + usart_tx_string(USART2, "DAQ system started.\n"); + + while (1) { + delay_ms(200); + + float cels = measure_temp(); + float angle = measure_angle(); + float resis = measure_resistance(); + float expos = measure_exposure(); + + buf_reset(buf); + buf_append_str(buf, "T "); + buf_append_flt(buf, cels, 1); + buf_append_str(buf, "°C | "); + + buf_append_str(buf, "An "); + buf_append_flt(buf, angle, 1); + buf_append_str(buf, "° | "); + + buf_append_str(buf, "R "); + buf_append_flt(buf, resis, 1); + buf_append_str(buf, " | "); + + buf_append_str(buf, "L "); + buf_append_flt(buf, expos, 1); + buf_append_str(buf, "% | "); + + buf_append_str(buf, "G "); + buf_append_str(buf, gate_closed ? "1" : "0"); + buf_append_str(buf, ", #"); + buf_append_int(buf, gate_cnt); + buf_append_str(buf, " | "); + + buf_append_str(buf, "DA "); + buf_append_int(buf, DAC_DHR12R1); + buf_append_str(buf, " | "); + + buf_append_str(buf, "PWM "); + buf_append_int(buf, TIM3_CCR1); + + buf_append_str(buf, "\n"); + + usart_tx_string(USART2, buf); + } } diff --git a/proj.pro b/proj.pro index 682cbe0..dd82eab 100644 --- a/proj.pro +++ b/proj.pro @@ -31,7 +31,9 @@ SOURCES += \ utils/debounce.c \ blink.c \ lib/common.c \ - utils/nvic.c + utils/nvic.c \ + capture.c \ + utils/str_utils.c HEADERS += \ lib/common.h \ @@ -58,5 +60,7 @@ HEADERS += \ lib/defs_spi.h \ lib/defs_timers.h \ lib/defs_nvic.h \ - utils/nvic.h + utils/nvic.h \ + capture.h \ + utils/str_utils.h diff --git a/utils/str_utils.c b/utils/str_utils.c new file mode 100644 index 0000000..1d5ef67 --- /dev/null +++ b/utils/str_utils.c @@ -0,0 +1,79 @@ +#include "str_utils.h" +#include +#include +#include + + +void buf_reset(char *buf) +{ + buf[0] = 0; +} + + +void buf_append_int(char *buf, int d) +{ + buf += strlen(buf); + sprintf(buf, "%d", d); +} + + +void buf_append_flt(char *buf, float f, uint8_t places) +{ + buf += strlen(buf); + + if (isnan(f)) { + sprintf(buf, "NAN"); + return; + } + + if (isinf(f)) { + sprintf(buf, "INF"); + return; + } + + if (isinf(f) && f < 0) { + sprintf(buf, "-INF"); + return; + } + + bool minus = 0; + if (f < 0) { + minus = 1; + f = -f; + } + + int ones = 0, dec = 0; + + ones = (int)f; + f -= ones; + + if (minus) { + buf[0] = '-'; + buf++; + } + + switch (places) { + case 0: + sprintf(buf, "%d", ones); + return; + case 1: + dec = (f * 10); + sprintf(buf, "%d.%01d", ones, dec); + return; + case 2: + dec = (f * 100); + sprintf(buf, "%d.%02d", ones, dec); + return; + default: + case 3: + dec = (f * 1000); + sprintf(buf, "%d.%03d", ones, dec); + return; + } +} + + +void buf_append_str(char *buf, const char *app) +{ + sprintf(buf + strlen(buf), "%s", app); +} diff --git a/utils/str_utils.h b/utils/str_utils.h new file mode 100644 index 0000000..ff35ec9 --- /dev/null +++ b/utils/str_utils.h @@ -0,0 +1,10 @@ +#pragma once +#include + +void buf_reset(char *buf); + +void buf_append_flt(char *buf, float f, uint8_t places); + +void buf_append_str(char *buf, const char *app); + +void buf_append_int(char *buf, int d);