Compare commits
63 Commits
6c013d5aa3
...
v0.1-hardw
Author | SHA1 | Date | |
---|---|---|---|
a7c91cee0e | |||
acbde24c2f | |||
47d8df052a | |||
3705cc09d1 | |||
ecd8d2537d | |||
56439a3b13 | |||
137e846cf2 | |||
78417e0c8c | |||
62a3e06baa | |||
485b887b54 | |||
fe75b93ec7 | |||
ab157bfb5a | |||
f0bf10d91d | |||
cbd28f9a12 | |||
a33154b2d0 | |||
828b47f3be | |||
7b426c93c9 | |||
20fd7b41e6 | |||
f60545f664 | |||
679d4534cb | |||
372be53471 | |||
0cdc7448e4 | |||
43b4fd1e77 | |||
d178910594 | |||
6f4363e021 | |||
0fca4c6c20 | |||
7595e6ced8 | |||
2547c134f2 | |||
a6dc4f9b46 | |||
e627cb67a5 | |||
d6e489bb61 | |||
3b2d8c14c3 | |||
9f0d81cc76 | |||
b9c1968dc4 | |||
7553cfa310 | |||
af04da6eca | |||
949d16cd03 | |||
917497e7e4 | |||
7db5f02067 | |||
3c3715effa | |||
a016681d08 | |||
5fc4220ecf | |||
70730fd0f0 | |||
c63986e271 | |||
9615fdb39d | |||
fc2372f754 | |||
92c0c5cd8c | |||
25bb341fa4 | |||
0d44d25ec9 | |||
6b4029f8c2 | |||
76f5a4e9be | |||
f493b823b3 | |||
d508402aa8 | |||
6477950eea | |||
5819a0736c | |||
f956968cb4 | |||
1751db31c5 | |||
e659c6d097 | |||
355e81ba44 | |||
c18acba48b | |||
e97092042b | |||
dc8beefb63 | |||
b9b899b4f6 |
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -5,3 +5,7 @@
|
|||||||
path = c-style-checker
|
path = c-style-checker
|
||||||
url = https://git.shimatta.de/mhu/c-style-checker.git
|
url = https://git.shimatta.de/mhu/c-style-checker.git
|
||||||
branch = master
|
branch = master
|
||||||
|
[submodule "reflow-controller-temp-profile-lang"]
|
||||||
|
path = reflow-controller-temp-profile-lang
|
||||||
|
url = https://git.shimatta.de/mhu/reflow-controller-temp-profile-lang.git
|
||||||
|
branch = master
|
||||||
|
@@ -391,7 +391,12 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"print(calc_temp(1000.6)-calc_temp(1000.4))\n",
|
"print(calc_temp(1000.6)-calc_temp(1000.4))\n",
|
||||||
"print(1/4096*2500)"
|
"\n",
|
||||||
|
"adc_min_res = 1/4095*2500\n",
|
||||||
|
"print('Min res: ', adc_min_res)\n",
|
||||||
|
"\n",
|
||||||
|
"print(calc_temp(2000))\n",
|
||||||
|
"print(calc_temp(2000+adc_min_res))"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
1
reflow-controller-temp-profile-lang
Submodule
1
reflow-controller-temp-profile-lang
Submodule
Submodule reflow-controller-temp-profile-lang added at c369231e42
@@ -5,15 +5,15 @@
|
|||||||
#Add Files and Folders below#########################################################
|
#Add Files and Folders below#########################################################
|
||||||
CFILES = main.c syscalls.c setup/system_stm32f4xx.c systick.c
|
CFILES = main.c syscalls.c setup/system_stm32f4xx.c systick.c
|
||||||
ASFILES = boot/startup_stm32f4xx.S
|
ASFILES = boot/startup_stm32f4xx.S
|
||||||
INCLUDEPATH = -Icmsis -Iinclude
|
INCLUDEPATH = -Iinclude
|
||||||
|
|
||||||
OBJDIR = obj
|
OBJDIR_BASE = obj
|
||||||
target = reflow-controller
|
TARGET_BASE = reflow-controller
|
||||||
LIBRARYPATH = -L. -Lmathlib
|
LIBRARYPATH = -L. -Lmathlib
|
||||||
LIBRARIES = -larm_cortexM4lf_math -lm
|
LIBRARIES = -larm_cortexM4lf_math -lm
|
||||||
|
|
||||||
DEFINES = -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DHSE_VALUE=8000000UL
|
DEFINES = -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DHSE_VALUE=8000000UL
|
||||||
mapfile = memory-mapping
|
MAPFILE_BASE = memory-mapping
|
||||||
|
|
||||||
export GIT_VER = $(shell git describe --always --dirty --tags)
|
export GIT_VER = $(shell git describe --always --dirty --tags)
|
||||||
DEFINES += -DGIT_VER=$(GIT_VER)
|
DEFINES += -DGIT_VER=$(GIT_VER)
|
||||||
@@ -41,27 +41,59 @@ CFILES += calibration.c
|
|||||||
CFILES += temp-converter.c
|
CFILES += temp-converter.c
|
||||||
CFILES += rotary-encoder.c button.c
|
CFILES += rotary-encoder.c button.c
|
||||||
CFILES += stack-check.c
|
CFILES += stack-check.c
|
||||||
CFILES += ui/lcd.c ui/menu.c
|
CFILES += ui/lcd.c ui/menu.c reflow-menu.c
|
||||||
#CFILES += onewire-temp-sensors.c
|
#CFILES += onewire-temp-sensors.c
|
||||||
CFILES += fatfs/diskio.c fatfs/ff.c fatfs/ffsystem.c fatfs/ffunicode.c fatfs/shimatta_sdio_driver/shimatta_sdio.c
|
CFILES += fatfs/diskio.c fatfs/ff.c fatfs/ffsystem.c fatfs/ffunicode.c fatfs/shimatta_sdio_driver/shimatta_sdio.c
|
||||||
CFILES += pid-controller.c oven-driver.c
|
CFILES += pid-controller.c oven-driver.c
|
||||||
CFILES += settings/settings.c settings/settings-sd-card.c
|
CFILES += settings/settings.c settings/settings-sd-card.c
|
||||||
|
CFILES += safety-adc.c
|
||||||
|
|
||||||
DEFINES += -DDEBUGBUILD
|
DEBUG_DEFINES = -DDEBUGBUILD
|
||||||
|
RELEASE_DEFINES =
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
CC=arm-none-eabi-gcc
|
ifeq ($(CROSS_COMPILE),)
|
||||||
OBJCOPY=arm-none-eabi-objcopy
|
CROSS_COMPILE=arm-none-eabi-
|
||||||
OBJDUMP=arm-none-eabi-objdump
|
endif
|
||||||
SIZE=arm-none-eabi-size
|
|
||||||
|
|
||||||
LFLAGS = -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
CC=$(CROSS_COMPILE)gcc
|
||||||
|
OBJCOPY=$(CROSS_COMPILE)objcopy
|
||||||
|
OBJDUMP=$(CROSS_COMPILE)objdump
|
||||||
|
SIZE=$(CROSS_COMPILE)size
|
||||||
|
|
||||||
|
CFLAGS_RELEASE = -O3 -g
|
||||||
|
CFLAGS_DEBUG = -O0 -g
|
||||||
|
|
||||||
|
LFLAGS_RELEASE = -Wl,--gc-sections
|
||||||
|
LFLAGS_DEBUG =
|
||||||
|
|
||||||
|
CFLAGS =
|
||||||
|
LFLAGS =
|
||||||
|
|
||||||
|
ifneq ($(DEBUGBUILD),true)
|
||||||
|
DEFINES += $(RELEASE_DEFINES)
|
||||||
|
CFLAGS += $(CFLAGS_RELEASE)
|
||||||
|
LFLAGS += $(LFLAGS_RELEASE)
|
||||||
|
target = $(TARGET_BASE)-release
|
||||||
|
OBJDIR = $(OBJDIR_BASE)/release
|
||||||
|
MAPFILE = $(MAPFILE_BASE)-release
|
||||||
|
else
|
||||||
|
DEFINES += $(DEBUG_DEFINES)
|
||||||
|
target = $(TARGET_BASE)-debug
|
||||||
|
CFLAGS += $(CFLAGS_DEBUG)
|
||||||
|
LFLAGS += $(LFLAGS_DEBUG)
|
||||||
|
OBJDIR = $(OBJDIR_BASE)/debug
|
||||||
|
MAPFILE = $(MAPFILE_BASE)-debug
|
||||||
|
endif
|
||||||
|
|
||||||
|
LFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
||||||
LFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles
|
LFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles
|
||||||
LFLAGS += -Tstm32f407vet6_flash.ld -Wl,-Map=$(mapfile).map
|
LFLAGS += -Tstm32f407vet6_flash.ld -Wl,-Map=$(MAPFILE).map
|
||||||
|
|
||||||
CFLAGS = -c -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
CFLAGS += -c -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
|
||||||
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -O0 -g
|
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles
|
||||||
CFLAGS += -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter -Wimplicit-fallthrough=3 -Wsign-compare
|
CFLAGS += -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter -Wimplicit-fallthrough=3 -Wsign-compare
|
||||||
|
|
||||||
####################################################################################
|
####################################################################################
|
||||||
|
|
||||||
OBJ = $(CFILES:%.c=$(OBJDIR)/%.c.o)
|
OBJ = $(CFILES:%.c=$(OBJDIR)/%.c.o)
|
||||||
@@ -69,6 +101,14 @@ ASOBJ += $(ASFILES:%.S=$(OBJDIR)/%.S.o)
|
|||||||
|
|
||||||
default: $(target).elf
|
default: $(target).elf
|
||||||
|
|
||||||
|
all: debug release
|
||||||
|
|
||||||
|
release:
|
||||||
|
$(QUIET)$(MAKE) DEBUGBUILD=false
|
||||||
|
|
||||||
|
debug:
|
||||||
|
$(QUIET)$(MAKE) DEBUGBUILD=true
|
||||||
|
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
$(QUIET)$(OBJCOPY) -O binary $^ $@
|
$(QUIET)$(OBJCOPY) -O binary $^ $@
|
||||||
%.hex: %.elf
|
%.hex: %.elf
|
||||||
@@ -94,7 +134,10 @@ $(ASOBJ):
|
|||||||
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.S.o=%.S)
|
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.S.o=%.S)
|
||||||
|
|
||||||
|
|
||||||
.PHONY: qtproject clean mrproper objcopy disassemble program
|
.PHONY: qtproject-legacy qtproject qtproject-debug clean mrproper objcopy disassemble program program-debug
|
||||||
|
|
||||||
|
program-debug:
|
||||||
|
$(QUIET)$(MAKE) DEBUGBUILD=true program
|
||||||
|
|
||||||
program: $(target).elf
|
program: $(target).elf
|
||||||
./program-device.sh $<
|
./program-device.sh $<
|
||||||
@@ -105,14 +148,23 @@ disassemble: $(target).elf
|
|||||||
objcopy: $(target).bin $(target).hex
|
objcopy: $(target).bin $(target).hex
|
||||||
|
|
||||||
mrproper: clean
|
mrproper: clean
|
||||||
$(QUIET)rm -f $(target).pro
|
@echo "Purging project files..."
|
||||||
|
$(QUIET)rm -f $(target).pro $(target).creator $(target).files $(target).cflags $(target).cxxflags $(target).includes $(target).config
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo "Cleaning up derived files..."
|
@echo -n "Cleaning up derived files for "
|
||||||
|
ifneq ($(DEBUGBUILD),true)
|
||||||
|
@echo "RELEASE build"
|
||||||
|
else
|
||||||
|
@echo "DEBUG build"
|
||||||
|
endif
|
||||||
$(QUIET)rm -f $(target).elf $(target).bin $(target).hex $(OBJ) $(ASOBJ) $(mapfile).map $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
|
$(QUIET)rm -f $(target).elf $(target).bin $(target).hex $(OBJ) $(ASOBJ) $(mapfile).map $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
|
||||||
$(QUIET)rm -rf $(OBJDIR)/*
|
$(QUIET)rm -rf $(OBJDIR)/*
|
||||||
|
ifneq ($(DEBUGBUILD),true)
|
||||||
|
$(QUIET)$(MAKE) DEBUGBUILD=true clean
|
||||||
|
endif
|
||||||
|
|
||||||
qtproject:
|
qtproject-legacy:
|
||||||
echo -e "TEMPLATE = app\nCONFIG -= console app_bundle qt" > $(target).pro
|
echo -e "TEMPLATE = app\nCONFIG -= console app_bundle qt" > $(target).pro
|
||||||
echo -e "SOURCES += $(CFILES) $(ASFILES)" >> $(target).pro
|
echo -e "SOURCES += $(CFILES) $(ASFILES)" >> $(target).pro
|
||||||
echo -ne "INCLUDEPATH += " >> $(target).pro
|
echo -ne "INCLUDEPATH += " >> $(target).pro
|
||||||
@@ -122,4 +174,26 @@ qtproject:
|
|||||||
echo -ne "\nDEFINES += " >> $(target).pro
|
echo -ne "\nDEFINES += " >> $(target).pro
|
||||||
echo "$(DEFINES)" | sed "s/-D//g" >> $(target).pro
|
echo "$(DEFINES)" | sed "s/-D//g" >> $(target).pro
|
||||||
|
|
||||||
|
qtproject-debug:
|
||||||
|
@echo "Generating debug build project"
|
||||||
|
$(QUIET)$(MAKE) DEBUGBUILD=true qtproject
|
||||||
|
|
||||||
|
qtproject:
|
||||||
|
$(QUIET)rm -f $(target).files $(target).cflags $(target).config $(target).creator $(target).includes $(target).creator.user
|
||||||
|
@echo "Generating source file list"
|
||||||
|
$(QUIET)echo "$(CFILES)" | tr ' ' '\n' > $(target).files
|
||||||
|
@echo -n "Appending found header files from folders "
|
||||||
|
@echo `echo $(INCLUDEPATH) | sed "s/-I//g"`
|
||||||
|
$(QUIET)for dir in `echo $(INCLUDEPATH) | sed "s/-I//g"`; do \
|
||||||
|
find `echo "$${dir}"` -name "*.h" >> $(target).files; \
|
||||||
|
done
|
||||||
|
@echo "Generating $(target).cflags"
|
||||||
|
$(QUIET)echo "" > $(target).cflags
|
||||||
|
@echo "Generating $(target).includes"
|
||||||
|
$(QUIET)echo $(INCLUDEPATH) | sed "s/-I/,/g" | tr , '\n' | sed "/^$$/d" > $(target).includes;
|
||||||
|
@echo "Generating $(target).config"
|
||||||
|
$(QUIET)echo $(DEFINES) | sed "s/-D/,#define /g" | tr , '\n' | sed "/^$$/d" > $(target).config
|
||||||
|
@echo "Generating $(target).creator"
|
||||||
|
$(QUIET)echo "[GENERAL]" > $(target).creator
|
||||||
|
|
||||||
-include $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
|
-include $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)
|
||||||
|
@@ -70,12 +70,12 @@ static inline void adc_pt1000_setup_sample_frequency_timer()
|
|||||||
|
|
||||||
static inline void adc_pt1000_disable_adc()
|
static inline void adc_pt1000_disable_adc()
|
||||||
{
|
{
|
||||||
ADC1->CR2 &= ~ADC_CR2_ADON;
|
ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON;
|
||||||
DMA2_Stream0->CR = 0;
|
DMA2_Stream0->CR = 0;
|
||||||
|
|
||||||
pt1000_error |= ADC_PT1000_INACTIVE;
|
pt1000_error |= ADC_PT1000_INACTIVE;
|
||||||
|
|
||||||
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
|
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN));
|
||||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ static inline void adc_pt1000_enable_dma_stream()
|
|||||||
DMA2_Stream0->M0AR = (uint32_t)dma_sample_buffer;
|
DMA2_Stream0->M0AR = (uint32_t)dma_sample_buffer;
|
||||||
|
|
||||||
/* Source is the ADC data register */
|
/* Source is the ADC data register */
|
||||||
DMA2_Stream0->PAR = (uint32_t)&ADC1->DR;
|
DMA2_Stream0->PAR = (uint32_t)&ADC_PT1000_PERIPH->DR;
|
||||||
|
|
||||||
/* Transfer size is ADC_PT1000_DMA_AVG_SAMPLES */
|
/* Transfer size is ADC_PT1000_DMA_AVG_SAMPLES */
|
||||||
DMA2_Stream0->NDTR = ADC_PT1000_DMA_AVG_SAMPLES;
|
DMA2_Stream0->NDTR = ADC_PT1000_DMA_AVG_SAMPLES;
|
||||||
@@ -112,7 +112,7 @@ static inline void adc_pt1000_enable_dma_stream()
|
|||||||
* Todo: Maybe use twice as big of a buffer and also use half-fill interrupt in order to prevent overruns
|
* Todo: Maybe use twice as big of a buffer and also use half-fill interrupt in order to prevent overruns
|
||||||
*/
|
*/
|
||||||
DMA2_Stream0->CR = DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC |
|
DMA2_Stream0->CR = DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_MINC |
|
||||||
DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_EN;
|
DMA_SxCR_CIRC | DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_EN | ((ADC_PT1000_CHANNEL & 0x7)<<25);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void adc_pt1000_disable_dma_stream()
|
static inline void adc_pt1000_disable_dma_stream()
|
||||||
@@ -129,32 +129,32 @@ static inline void adc_pt1000_disable_dma_stream()
|
|||||||
|
|
||||||
void adc_pt1000_setup_meas()
|
void adc_pt1000_setup_meas()
|
||||||
{
|
{
|
||||||
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC1EN));
|
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN));
|
||||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
|
||||||
|
|
||||||
ADC_PT1000_PORT->MODER |= ANALOG(ADC_PT1000_PIN);
|
ADC_PT1000_PORT->MODER |= ANALOG(ADC_PT1000_PIN);
|
||||||
|
|
||||||
/* Set S&H time for PT1000 ADC channel */
|
/* Set S&H time for PT1000 ADC channel */
|
||||||
#if ADC_PT1000_CHANNEL < 10
|
#if ADC_PT1000_CHANNEL < 10
|
||||||
ADC1->SMPR2 |= (7U << (3*ADC_PT1000_CHANNEL));
|
ADC_PT1000_PERIPH->SMPR2 |= (7U << (3*ADC_PT1000_CHANNEL));
|
||||||
#else
|
#else
|
||||||
ADC1->SMPR1 |= (7U << (3*(ADC_PT1000_CHANNEL-10)));
|
ADC_PT1000_PERIPH->SMPR1 |= (7U << (3*(ADC_PT1000_CHANNEL-10)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ADC->CCR |= (0x2<<16);
|
ADC->CCR |= (0x3<<16);
|
||||||
|
|
||||||
/* Set watchdog limits */
|
/* Set watchdog limits */
|
||||||
ADC1->HTR = ADC_PT1000_UPPER_WATCHDOG;
|
ADC_PT1000_PERIPH->HTR = ADC_PT1000_UPPER_WATCHDOG;
|
||||||
ADC1->LTR = ADC_PT1000_LOWER_WATCHDOG;
|
ADC_PT1000_PERIPH->LTR = ADC_PT1000_LOWER_WATCHDOG;
|
||||||
|
|
||||||
/* Set length of sequence to 1 */
|
/* Set length of sequence to 1 */
|
||||||
ADC1->SQR1 = (0UL<<20);
|
ADC_PT1000_PERIPH->SQR1 = (0UL<<20);
|
||||||
|
|
||||||
/* Set channel as 1st element in sequence */
|
/* Set channel as 1st element in sequence */
|
||||||
ADC1->SQR3 = (ADC_PT1000_CHANNEL<<0);
|
ADC_PT1000_PERIPH->SQR3 = (ADC_PT1000_CHANNEL<<0);
|
||||||
|
|
||||||
ADC1->CR1 = ADC_CR1_OVRIE | ADC_CR1_AWDEN | ADC_CR1_AWDIE;
|
ADC_PT1000_PERIPH->CR1 = ADC_CR1_OVRIE | ADC_CR1_AWDEN | ADC_CR1_AWDIE;
|
||||||
ADC1->CR2 = ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
|
ADC_PT1000_PERIPH->CR2 = ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS;
|
||||||
|
|
||||||
adc_pt1000_set_moving_average_filter_param(ADC_PT1000_FILTER_WEIGHT);
|
adc_pt1000_set_moving_average_filter_param(ADC_PT1000_FILTER_WEIGHT);
|
||||||
adc_pt1000_set_resistance_calibration(0, 0, false);
|
adc_pt1000_set_resistance_calibration(0, 0, false);
|
||||||
@@ -324,17 +324,17 @@ void ADC_IRQHandler(void)
|
|||||||
{
|
{
|
||||||
uint32_t adc1_sr;
|
uint32_t adc1_sr;
|
||||||
|
|
||||||
adc1_sr = ADC1->SR;
|
adc1_sr = ADC_PT1000_PERIPH->SR;
|
||||||
|
|
||||||
if (adc1_sr & ADC_SR_OVR) {
|
if (adc1_sr & ADC_SR_OVR) {
|
||||||
ADC1->SR &= ~ADC_SR_OVR;
|
ADC_PT1000_PERIPH->SR &= ~ADC_SR_OVR;
|
||||||
pt1000_error |= ADC_PT1000_OVERFLOW;
|
pt1000_error |= ADC_PT1000_OVERFLOW;
|
||||||
/* Disable ADC in case of overrrun*/
|
/* Disable ADC in case of overrrun*/
|
||||||
adc_pt1000_disable();
|
adc_pt1000_disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adc1_sr & ADC_SR_AWD) {
|
if (adc1_sr & ADC_SR_AWD) {
|
||||||
ADC1->SR &= ~ADC_SR_AWD;
|
ADC_PT1000_PERIPH->SR &= ~ADC_SR_AWD;
|
||||||
adc_watchdog_counter++;
|
adc_watchdog_counter++;
|
||||||
if (adc_watchdog_counter >= ADC_PT1000_WATCHDOG_SAMPLE_COUNT)
|
if (adc_watchdog_counter >= ADC_PT1000_WATCHDOG_SAMPLE_COUNT)
|
||||||
pt1000_error |= ADC_PT1000_WATCHDOG_ERROR;
|
pt1000_error |= ADC_PT1000_WATCHDOG_ERROR;
|
||||||
|
@@ -99,6 +99,12 @@ LoopFillZerobss:
|
|||||||
//bl __libc_init_array
|
//bl __libc_init_array
|
||||||
/* Call the application's entry point.*/
|
/* Call the application's entry point.*/
|
||||||
|
|
||||||
|
/* Enable FPU hard */
|
||||||
|
LDR.W R0, =0xE000ED88
|
||||||
|
LDR R1, [R0]
|
||||||
|
ORR R1, R1, #(0xF << 20)
|
||||||
|
STR R1, [R0]
|
||||||
|
|
||||||
bl main
|
bl main
|
||||||
bx lr
|
bx lr
|
||||||
.size Reset_Handler, .-Reset_Handler
|
.size Reset_Handler, .-Reset_Handler
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
static const uint8_t digio_pins[] = {DIGIO_PINS};
|
static const uint8_t digio_pins[] = {DIGIO_PINS};
|
||||||
static const uint8_t digio_default_io[] = {DIGIO_INOUT_DEFAULT};
|
static const uint8_t digio_default_io[] = {DIGIO_INOUT_DEFAULT};
|
||||||
static const uint8_t digio_default_altfunc[] = {DIGIO_ALTFUNC_DEFAULT};
|
static const uint8_t digio_default_altfunc[] = {DIGIO_ALTFUNC_DEFAULT};
|
||||||
|
static uint16_t loudspeaker_val;
|
||||||
|
|
||||||
static void digio_setup_pin_int(uint8_t bit_no, uint8_t in_out, uint8_t alt_func)
|
static void digio_setup_pin_int(uint8_t bit_no, uint8_t in_out, uint8_t alt_func)
|
||||||
{
|
{
|
||||||
@@ -118,6 +119,19 @@ int led_get(uint8_t num)
|
|||||||
return ((LED_PORT->ODR & (1<<led_pins[num])) ? 1 : 0);
|
return ((LED_PORT->ODR & (1<<led_pins[num])) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loudspeaker_freq_timer_init(void)
|
||||||
|
{
|
||||||
|
#if LOUDSPEAKER_MULTIFREQ
|
||||||
|
rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB1ENR_TIM7EN));
|
||||||
|
TIM7->CR1 = 0UL;
|
||||||
|
TIM7->CR2 = 0UL;
|
||||||
|
TIM7->PSC = 1000;
|
||||||
|
TIM7->DIER = TIM_DIER_UIE;
|
||||||
|
NVIC_EnableIRQ(TIM7_IRQn);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void loudspeaker_setup()
|
void loudspeaker_setup()
|
||||||
{
|
{
|
||||||
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(LOUDSPEAKER_RCC_MASK));
|
rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(LOUDSPEAKER_RCC_MASK));
|
||||||
@@ -125,16 +139,56 @@ void loudspeaker_setup()
|
|||||||
LOUDSPEAKER_PORT->MODER &= MODER_DELETE(LOUDSPEAKER_PIN);
|
LOUDSPEAKER_PORT->MODER &= MODER_DELETE(LOUDSPEAKER_PIN);
|
||||||
LOUDSPEAKER_PORT->MODER |= OUTPUT(LOUDSPEAKER_PIN);
|
LOUDSPEAKER_PORT->MODER |= OUTPUT(LOUDSPEAKER_PIN);
|
||||||
|
|
||||||
loudspeaker_set(0);
|
loudspeaker_freq_timer_init();
|
||||||
|
loudspeaker_set(0U);
|
||||||
}
|
}
|
||||||
void loudspeaker_set(int val)
|
|
||||||
|
static void loudspeaker_start_beep(uint16_t val)
|
||||||
{
|
{
|
||||||
if (val)
|
#if LOUDSPEAKER_MULTIFREQ
|
||||||
|
TIM7->ARR = val;
|
||||||
|
TIM7->CNT = 0UL;
|
||||||
|
TIM7->CR1 |= TIM_CR1_CEN;
|
||||||
|
#else
|
||||||
|
(void)val;
|
||||||
LOUDSPEAKER_PORT->ODR |= (1<<LOUDSPEAKER_PIN);
|
LOUDSPEAKER_PORT->ODR |= (1<<LOUDSPEAKER_PIN);
|
||||||
else
|
#endif
|
||||||
LOUDSPEAKER_PORT->ODR &= ~(1<<LOUDSPEAKER_PIN);
|
|
||||||
}
|
}
|
||||||
int loudspeaker_get()
|
|
||||||
|
static void loudspeaker_stop_beep(void)
|
||||||
{
|
{
|
||||||
return ((LOUDSPEAKER_PORT->ODR & (1<<LOUDSPEAKER_PIN)) ? 1 : 0);
|
#if LOUDSPEAKER_MULTIFREQ
|
||||||
|
TIM7->CR1 &= ~TIM_CR1_CEN;
|
||||||
|
__DSB();
|
||||||
|
TIM7->SR = 0UL;
|
||||||
|
__DSB();
|
||||||
|
LOUDSPEAKER_PORT->ODR &= ~(1<<LOUDSPEAKER_PIN);
|
||||||
|
#else
|
||||||
|
LOUDSPEAKER_PORT->ODR &= ~(1<<LOUDSPEAKER_PIN);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loudspeaker_set(uint16_t val)
|
||||||
|
{
|
||||||
|
loudspeaker_val = val;
|
||||||
|
|
||||||
|
if (!val) {
|
||||||
|
loudspeaker_stop_beep();
|
||||||
|
} else {
|
||||||
|
loudspeaker_start_beep(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t loudspeaker_get()
|
||||||
|
{
|
||||||
|
return loudspeaker_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LOUDSPEAKER_MULTIFREQ
|
||||||
|
void TIM7_IRQHandler(void)
|
||||||
|
{
|
||||||
|
TIM7->SR = 0UL;
|
||||||
|
__DSB();
|
||||||
|
LOUDSPEAKER_PORT->ODR ^= (1<<LOUDSPEAKER_PIN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -238,6 +238,8 @@ static int sdio_check_status_register_cmd13(uint16_t rca, uint32_t *status)
|
|||||||
uint32_t response;
|
uint32_t response;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
*status = 0UL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
sdio_send_cmd(13, (rca<<16)&0xFFFF0000, SHORT_ANS);
|
sdio_send_cmd(13, (rca<<16)&0xFFFF0000, SHORT_ANS);
|
||||||
if (!(res = sdio_get_response(13, SHORT_ANS, &response))) {
|
if (!(res = sdio_get_response(13, SHORT_ANS, &response))) {
|
||||||
@@ -465,10 +467,14 @@ static int sdio_send_select_card_cmd7(uint16_t rca) {
|
|||||||
} while(--timeout > 0);
|
} while(--timeout > 0);
|
||||||
|
|
||||||
/* Check, if card in in TRANS state */
|
/* Check, if card in in TRANS state */
|
||||||
if (sdio_check_status_register_cmd13(rca, &(status.value)))
|
if (sdio_check_status_register_cmd13(rca, &status.value)) {
|
||||||
res = -1;
|
res = -1;
|
||||||
|
goto ret_val;
|
||||||
|
}
|
||||||
if (status.statusstruct.CURRENT_STATE != CURRENT_STATE_TRAN)
|
if (status.statusstruct.CURRENT_STATE != CURRENT_STATE_TRAN)
|
||||||
res = -2;
|
res = -2;
|
||||||
|
|
||||||
|
ret_val:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,9 +711,10 @@ DRESULT sdio_disk_write(const BYTE *buff, DWORD sector, UINT count)
|
|||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
do {
|
do {
|
||||||
sdio_check_status_register_cmd13(card_info.rca, &status.value);
|
ret = sdio_check_status_register_cmd13(card_info.rca, &status.value);
|
||||||
} while (status.statusstruct.CURRENT_STATE == CURRENT_STATE_PRG ||
|
} while (status.statusstruct.CURRENT_STATE == CURRENT_STATE_PRG ||
|
||||||
status.statusstruct.CURRENT_STATE == CURRENT_STATE_RCV);
|
status.statusstruct.CURRENT_STATE == CURRENT_STATE_RCV ||
|
||||||
|
!ret);
|
||||||
|
|
||||||
if (status.statusstruct.CURRENT_STATE == CURRENT_STATE_STBY) {
|
if (status.statusstruct.CURRENT_STATE == CURRENT_STATE_STBY) {
|
||||||
if (sdio_send_select_card_cmd7(card_info.rca))
|
if (sdio_send_select_card_cmd7(card_info.rca))
|
||||||
|
@@ -24,6 +24,11 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stm32/stm32f4xx.h>
|
#include <stm32/stm32f4xx.h>
|
||||||
|
|
||||||
|
/*If this is changed, change DMA code to fit the channel assignment! */
|
||||||
|
#define ADC_PT1000_PERIPH ADC3
|
||||||
|
#define ADC_PT1000_DMA2_STREAM0_CHANNEL 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Moving average filter coefficient for PT1000 measurement
|
* @brief Moving average filter coefficient for PT1000 measurement
|
||||||
*/
|
*/
|
||||||
|
@@ -58,10 +58,11 @@ int led_get(uint8_t num);
|
|||||||
#define LOUDSPEAKER_PORT GPIOB
|
#define LOUDSPEAKER_PORT GPIOB
|
||||||
#define LOUDSPEAKER_RCC_MASK RCC_AHB1ENR_GPIOBEN
|
#define LOUDSPEAKER_RCC_MASK RCC_AHB1ENR_GPIOBEN
|
||||||
#define LOUDSPEAKER_PIN 1
|
#define LOUDSPEAKER_PIN 1
|
||||||
|
#define LOUDSPEAKER_MULTIFREQ 1
|
||||||
|
|
||||||
void loudspeaker_setup();
|
void loudspeaker_setup();
|
||||||
void loudspeaker_set(int val);
|
void loudspeaker_set(uint16_t val);
|
||||||
int loudspeaker_get();
|
uint16_t loudspeaker_get();
|
||||||
|
|
||||||
|
|
||||||
#endif /* __DIGIO_H__ */
|
#endif /* __DIGIO_H__ */
|
||||||
|
@@ -22,6 +22,35 @@
|
|||||||
#define __OVEN_DRIVER_H__
|
#define __OVEN_DRIVER_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <reflow-controller/pid-controller.h>
|
||||||
|
|
||||||
|
enum oven_pid_error_report {
|
||||||
|
OVEN_PID_NO_ERROR = 0,
|
||||||
|
OVEN_PID_ERR_PT1000_ADC_WATCHDOG = (1<<0),
|
||||||
|
OVEN_PID_ERR_PT1000_ADC_OFF = (1<<1),
|
||||||
|
OVEN_PID_ERR_PT1000_OTHER = (1<<2),
|
||||||
|
OVEN_PID_ERR_VREF_TOL = (1<<3),
|
||||||
|
OVEN_PID_ERR_OVERTEMP = (1<<4),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct oven_pid_errors {
|
||||||
|
bool generic_error;
|
||||||
|
bool pt1000_adc_watchdog;
|
||||||
|
bool pt1000_adc_off;
|
||||||
|
bool pt1000_other;
|
||||||
|
bool vref_tol;
|
||||||
|
bool controller_overtemp;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct oven_pid_status {
|
||||||
|
bool active;
|
||||||
|
bool error_set;
|
||||||
|
struct oven_pid_errors error_flags;
|
||||||
|
float target_temp;
|
||||||
|
float current_temp;
|
||||||
|
uint64_t timestamp_last_run;
|
||||||
|
};
|
||||||
|
|
||||||
void oven_driver_init(void);
|
void oven_driver_init(void);
|
||||||
|
|
||||||
@@ -29,4 +58,16 @@ void oven_driver_set_power(uint8_t power);
|
|||||||
|
|
||||||
void oven_driver_disable(void);
|
void oven_driver_disable(void);
|
||||||
|
|
||||||
|
void oven_pid_ack_errors(void);
|
||||||
|
|
||||||
|
void oven_pid_init(struct pid_controller *controller_to_copy);
|
||||||
|
|
||||||
|
void oven_pid_handle(float target_temp);
|
||||||
|
|
||||||
|
void oven_pid_stop();
|
||||||
|
|
||||||
|
void oven_pid_report_error(enum oven_pid_error_report report);
|
||||||
|
|
||||||
|
const struct oven_pid_status *oven_pid_get_status(void);
|
||||||
|
|
||||||
#endif /* __OVEN_DRIVER_H__ */
|
#endif /* __OVEN_DRIVER_H__ */
|
||||||
|
@@ -0,0 +1,38 @@
|
|||||||
|
/* Reflow Oven Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*
|
||||||
|
* This file is part of the Reflow Oven Controller Project.
|
||||||
|
*
|
||||||
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SAFETY_ADC_HWCFG_H__
|
||||||
|
#define __SAFETY_ADC_HWCFG_H__
|
||||||
|
|
||||||
|
#include <stm32/stm32f4xx.h>
|
||||||
|
|
||||||
|
#define SAFETY_ADC_ADC_PERIPHERAL ADC1
|
||||||
|
#define SAFETY_ADC_ADC_RCC_MASK RCC_APB2ENR_ADC1EN
|
||||||
|
#define TEMP_CHANNEL_NUM (16)
|
||||||
|
#define INT_REF_CHANNEL_NUM (17)
|
||||||
|
|
||||||
|
#define SAFETY_ADC_INT_REF_MV 1210.0f
|
||||||
|
|
||||||
|
#define SAFETY_ADC_TEMP_NOM 25.0f
|
||||||
|
#define SAFETY_ADC_TEMP_NOM_MV 760.0f
|
||||||
|
#define SAFETY_ADC_TEMP_MV_SLOPE 2.5f
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __SAFETY_ADC_HWCFG_H__ */
|
@@ -25,15 +25,19 @@ struct pid_controller {
|
|||||||
float k_deriv;
|
float k_deriv;
|
||||||
float k_int;
|
float k_int;
|
||||||
float k_p;
|
float k_p;
|
||||||
|
float k_int_t;
|
||||||
|
float k_deriv_t;
|
||||||
float output_sat_max;
|
float output_sat_max;
|
||||||
float output_sat_min;
|
float output_sat_min;
|
||||||
float integral_max;
|
float integral_max;
|
||||||
|
float sample_period;
|
||||||
volatile float control_output;
|
volatile float control_output;
|
||||||
volatile float last_in;
|
volatile float last_in;
|
||||||
volatile float integral;
|
volatile float integral;
|
||||||
|
volatile float derivate;
|
||||||
};
|
};
|
||||||
|
|
||||||
void pid_init(struct pid_controller *pid, float k_deriv, float k_int, float k_p, float output_sat_min, float output_sat_max, float integral_max);
|
void pid_init(struct pid_controller *pid, float k_deriv, float k_int, float k_p, float output_sat_min, float output_sat_max, float integral_max, float sample_period);
|
||||||
|
|
||||||
void pid_zero(struct pid_controller *pid);
|
void pid_zero(struct pid_controller *pid);
|
||||||
|
|
||||||
@@ -41,4 +45,6 @@ float pid_sample(struct pid_controller *pid, float deviation);
|
|||||||
|
|
||||||
float pid_get_control_output(const struct pid_controller *pid);
|
float pid_get_control_output(const struct pid_controller *pid);
|
||||||
|
|
||||||
|
int pid_copy(struct pid_controller *dest, const struct pid_controller *src);
|
||||||
|
|
||||||
#endif /* __PID_CONTROLLER_H__ */
|
#endif /* __PID_CONTROLLER_H__ */
|
||||||
|
32
stm-firmware/include/reflow-controller/reflow-menu.h
Normal file
32
stm-firmware/include/reflow-controller/reflow-menu.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* Reflow Oven Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*
|
||||||
|
* This file is part of the Reflow Oven Controller Project.
|
||||||
|
*
|
||||||
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __REFLOW_MENU_H__
|
||||||
|
#define __REFLOW_MENU_H__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle the reflow controller's LCD Menu
|
||||||
|
* @return 0 if no delay is requested, 1 if delay is requested
|
||||||
|
*/
|
||||||
|
int reflow_menu_handle(void);
|
||||||
|
|
||||||
|
void reflow_menu_init(void);
|
||||||
|
|
||||||
|
#endif /* __REFLOW_MENU_H__ */
|
@@ -39,4 +39,6 @@ int32_t rotary_encoder_get_change_val(void);
|
|||||||
|
|
||||||
void rotary_encoder_stop(void);
|
void rotary_encoder_stop(void);
|
||||||
|
|
||||||
|
void rotary_encoder_zero(void);
|
||||||
|
|
||||||
#endif /* __ROTARY_ENCODER_H__ */
|
#endif /* __ROTARY_ENCODER_H__ */
|
||||||
|
70
stm-firmware/include/reflow-controller/safety-adc.h
Normal file
70
stm-firmware/include/reflow-controller/safety-adc.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* Reflow Oven Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*
|
||||||
|
* This file is part of the Reflow Oven Controller Project.
|
||||||
|
*
|
||||||
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SAFETY_ADC_H__
|
||||||
|
#define __SAFETY_ADC_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define SAFETY_ADC_VREF_MVOLT (2500.0f)
|
||||||
|
#define SAFETY_ADC_VREF_TOL_MVOLT (100.0f)
|
||||||
|
#define SAFETY_ADC_TEMP_LOW_LIM (0.0f)
|
||||||
|
#define SAFETY_ADC_TEMP_HIGH_LIM (65.0f)
|
||||||
|
|
||||||
|
enum safety_adc_meas_channel {SAFETY_ADC_MEAS_VREF, SAFETY_ADC_MEAS_TEMP};
|
||||||
|
enum safety_adc_check_result {
|
||||||
|
SAFETY_ADC_CHECK_OK = 0UL,
|
||||||
|
SAFETY_ADC_CHECK_VREF_LOW = (1U<<0),
|
||||||
|
SAFETY_ADC_CHECK_VREF_HIGH = (1U<<1),
|
||||||
|
SAFETY_ADC_CHECK_TEMP_LOW = (1U<<2),
|
||||||
|
SAFETY_ADC_CHECK_TEMP_HIGH = (1U<<3),
|
||||||
|
SAFETY_ADC_INTERNAL_ERROR = (1U<<4),
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum safety_adc_check_result global_safety_adc_status;
|
||||||
|
|
||||||
|
enum safety_adc_check_result safety_adc_get_errors();
|
||||||
|
|
||||||
|
void safety_adc_clear_errors(void);
|
||||||
|
|
||||||
|
void safety_adc_init();
|
||||||
|
|
||||||
|
void safety_adc_deinit();
|
||||||
|
|
||||||
|
void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll ADC result.
|
||||||
|
* @param results adc results
|
||||||
|
* @return 1 if measurement successful, 0 if not ready, -1 if ADC aborted or not started
|
||||||
|
*/
|
||||||
|
int safety_adc_poll_result(uint16_t *adc_result);
|
||||||
|
|
||||||
|
enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint16_t temp_result,
|
||||||
|
float *vref_calculated, float *temp_calculated);
|
||||||
|
|
||||||
|
enum safety_adc_check_result handle_safety_adc();
|
||||||
|
|
||||||
|
float safety_adc_get_temp();
|
||||||
|
|
||||||
|
float safety_adc_get_vref();
|
||||||
|
|
||||||
|
#endif /* __SAFETY_ADC_H__ */
|
@@ -32,9 +32,9 @@
|
|||||||
* @brief Reload value for the systick timer.
|
* @brief Reload value for the systick timer.
|
||||||
*
|
*
|
||||||
* This value has to be configured to set the systick to a one milliscond tick interval
|
* This value has to be configured to set the systick to a one milliscond tick interval
|
||||||
* The default value is 168000, which results in a 1ms tick for 168 MHz CPU speed
|
* The default value is 16800, which results in a 100us tick for 168 MHz CPU speed
|
||||||
*/
|
*/
|
||||||
#define SYSTICK_RELOAD (168000UL)
|
#define SYSTICK_RELOAD (16800UL)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Variable used by the systick_wait_ms function
|
* @brief Variable used by the systick_wait_ms function
|
||||||
@@ -45,10 +45,15 @@ extern volatile uint32_t wait_tick_ms;
|
|||||||
* @brief Systemclock in milliseconds.
|
* @brief Systemclock in milliseconds.
|
||||||
*
|
*
|
||||||
* This value must not be reset during the whole runtime.
|
* This value must not be reset during the whole runtime.
|
||||||
*
|
* @warning In order to use this, you must assure that the read access is atomic.
|
||||||
*/
|
*/
|
||||||
extern volatile uint64_t global_tick_ms;
|
extern volatile uint64_t global_tick_ms;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait counter for the display. This must not be used anywhere else
|
||||||
|
*/
|
||||||
|
extern volatile uint32_t lcd_tick_100us;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Setup the Systick timer to generate a 1 ms tick
|
* @brief Setup the Systick timer to generate a 1 ms tick
|
||||||
*/
|
*/
|
||||||
@@ -66,6 +71,8 @@ void systick_wait_ms(uint32_t ms);
|
|||||||
|
|
||||||
uint64_t systick_get_global_tick();
|
uint64_t systick_get_global_tick();
|
||||||
|
|
||||||
|
void systick_get_uptime_from_tick(uint32_t *days, uint32_t *hours, uint32_t *minutes, uint32_t *seconds);
|
||||||
|
|
||||||
bool systick_ticks_have_passed(uint64_t start_timestamp, uint64_t ticks);
|
bool systick_ticks_have_passed(uint64_t start_timestamp, uint64_t ticks);
|
||||||
|
|
||||||
#endif /* __SYSTICK_H__ */
|
#endif /* __SYSTICK_H__ */
|
||||||
|
@@ -31,6 +31,15 @@
|
|||||||
#define LCD_RS_MASK (1U << LCD_RS)
|
#define LCD_RS_MASK (1U << LCD_RS)
|
||||||
#define LCD_E_MASK (1U << LCD_E)
|
#define LCD_E_MASK (1U << LCD_E)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define LCD_CHAR_WIDTH 16
|
||||||
|
#define LCD_ROW_COUNT 4
|
||||||
|
|
||||||
|
#define LCD_SHIMATTA_STRING "\xBC\xCF\xAF\xC0"
|
||||||
|
#define LCD_DEGREE_SYMBOL_STRING "\xDF"
|
||||||
|
#define LCD_DEGREE_SYMBOL_CHAR '\xDF'
|
||||||
|
|
||||||
enum lcd_fsm_ret {LCD_FSM_NOP, LCD_FSM_CALL_AGAIN, LCD_FSM_WAIT_CALL};
|
enum lcd_fsm_ret {LCD_FSM_NOP, LCD_FSM_CALL_AGAIN, LCD_FSM_WAIT_CALL};
|
||||||
|
|
||||||
void lcd_init(void);
|
void lcd_init(void);
|
||||||
|
@@ -21,4 +21,67 @@
|
|||||||
#ifndef __MENU_H__
|
#ifndef __MENU_H__
|
||||||
#define __MENU_H__
|
#define __MENU_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <reflow-controller/button.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct lcd_menu;
|
||||||
|
|
||||||
|
enum menu_entry_func_entry {MENU_ENTRY_FIRST_ENTER, MENU_ENTRY_CONTINUE, MENU_ENTRY_DROPBACK};
|
||||||
|
|
||||||
|
typedef void (*menu_func_t)(struct lcd_menu *menu, enum menu_entry_func_entry entry_type,
|
||||||
|
void *parent);
|
||||||
|
|
||||||
|
struct menu_inputs {
|
||||||
|
int16_t rotary_encoder_delta;
|
||||||
|
enum button_state push_button;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lcd_menu {
|
||||||
|
menu_func_t active_entry;
|
||||||
|
menu_func_t root_entry;
|
||||||
|
enum menu_entry_func_entry active_entry_type;
|
||||||
|
menu_func_t init_parent;
|
||||||
|
struct menu_inputs inputs;
|
||||||
|
void (*update_display)(uint8_t row, const char *data);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct menu_list {
|
||||||
|
void (*update_display)(uint8_t row, const char *data);
|
||||||
|
const char * const * entry_names;
|
||||||
|
uint32_t entry_count;
|
||||||
|
uint32_t currently_selected;
|
||||||
|
const menu_func_t *submenu_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
void menu_handle(struct lcd_menu *menu, int16_t rotary_encoder_delta, enum button_state push_button);
|
||||||
|
|
||||||
|
void menu_init(struct lcd_menu *menu, menu_func_t root_node, void (*display_update)(uint8_t row, const char *data));
|
||||||
|
|
||||||
|
void menu_ack_rotary_delta(struct lcd_menu *menu);
|
||||||
|
|
||||||
|
void menu_display_clear(struct lcd_menu *menu);
|
||||||
|
|
||||||
|
void menu_entry_dropback(struct lcd_menu *menu, menu_func_t parent_func);
|
||||||
|
|
||||||
|
void menu_entry_enter(struct lcd_menu *menu, menu_func_t entry, bool handle_immediately);
|
||||||
|
|
||||||
|
void menu_lcd_output(struct lcd_menu *menu, uint8_t row_num, const char *text);
|
||||||
|
|
||||||
|
void menu_lcd_outputf(struct lcd_menu *menu, uint8_t row_num, const char *format, ...);
|
||||||
|
|
||||||
|
void menu_list_display(struct menu_list *list, uint32_t top_row, uint32_t bottom_row);
|
||||||
|
|
||||||
|
int16_t menu_get_rotary_delta(const struct lcd_menu *menu);
|
||||||
|
|
||||||
|
enum button_state menu_get_button_state(const struct lcd_menu *menu);
|
||||||
|
|
||||||
|
void menu_list_compute_count(struct menu_list *list);
|
||||||
|
|
||||||
|
void menu_list_scroll_down(struct menu_list *list);
|
||||||
|
|
||||||
|
void menu_list_scroll_up(struct menu_list *list);
|
||||||
|
|
||||||
|
void menu_list_enter_selected_entry(struct menu_list *list, struct lcd_menu *menu);
|
||||||
|
|
||||||
#endif /* __MENU_H__ */
|
#endif /* __MENU_H__ */
|
||||||
|
@@ -34,22 +34,20 @@
|
|||||||
#include <reflow-controller/systick.h>
|
#include <reflow-controller/systick.h>
|
||||||
#include <reflow-controller/adc-meas.h>
|
#include <reflow-controller/adc-meas.h>
|
||||||
#include <reflow-controller/shell.h>
|
#include <reflow-controller/shell.h>
|
||||||
#include <reflow-controller/ui/lcd.h>
|
|
||||||
#include <reflow-controller/digio.h>
|
#include <reflow-controller/digio.h>
|
||||||
#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h"
|
#include "fatfs/shimatta_sdio_driver/shimatta_sdio.h"
|
||||||
#include <reflow-controller/temp-converter.h>
|
|
||||||
#include <reflow-controller/rotary-encoder.h>
|
|
||||||
#include <reflow-controller/pid-controller.h>
|
|
||||||
#include <stm-periph/stm32-gpio-macros.h>
|
#include <stm-periph/stm32-gpio-macros.h>
|
||||||
#include <stm-periph/clock-enable-manager.h>
|
#include <stm-periph/clock-enable-manager.h>
|
||||||
#include <stm-periph/uart.h>
|
#include <stm-periph/uart.h>
|
||||||
#include <reflow-controller/shell-uart-config.h>
|
#include <reflow-controller/shell-uart-config.h>
|
||||||
#include <helper-macros/helper-macros.h>
|
|
||||||
#include <reflow-controller/button.h>
|
|
||||||
#include <reflow-controller/oven-driver.h>
|
#include <reflow-controller/oven-driver.h>
|
||||||
|
#include <reflow-controller/safety-adc.h>
|
||||||
#include <fatfs/ff.h>
|
#include <fatfs/ff.h>
|
||||||
|
#include <reflow-controller/reflow-menu.h>
|
||||||
|
|
||||||
static void setup_nvic_priorities()
|
bool global_error_state;
|
||||||
|
|
||||||
|
static void setup_nvic_priorities(void)
|
||||||
{
|
{
|
||||||
/* No sub priorities */
|
/* No sub priorities */
|
||||||
NVIC_SetPriorityGrouping(2);
|
NVIC_SetPriorityGrouping(2);
|
||||||
@@ -60,18 +58,10 @@ static void setup_nvic_priorities()
|
|||||||
NVIC_SetPriority(DMA2_Stream7_IRQn, 3);
|
NVIC_SetPriority(DMA2_Stream7_IRQn, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process parameters are defined static globally to be watched in debugger from any context */
|
|
||||||
static float pt1000_value;
|
|
||||||
static volatile int pt1000_value_status;
|
|
||||||
static uint32_t rot;
|
|
||||||
static float target_temperature;
|
|
||||||
static struct pid_controller pid;
|
|
||||||
static volatile enum button_state button;
|
|
||||||
|
|
||||||
FATFS fs;
|
FATFS fs;
|
||||||
FATFS *fs_ptr = &fs;
|
FATFS * const fs_ptr = &fs;
|
||||||
|
|
||||||
static inline void uart_gpio_config()
|
static inline void uart_gpio_config(void)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* In case the application is build in debug mode, use the TX/RX Pins on the debug header
|
* In case the application is build in debug mode, use the TX/RX Pins on the debug header
|
||||||
@@ -98,7 +88,7 @@ static shellmatta_retCode_t write_shell_callback(const char *data, uint32_t len)
|
|||||||
return SHELLMATTA_OK;
|
return SHELLMATTA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setup_sell_uart(struct stm_uart *uart)
|
static inline void setup_shell_uart(struct stm_uart *uart)
|
||||||
{
|
{
|
||||||
uart->rx = 1;
|
uart->rx = 1;
|
||||||
uart->tx = 1;
|
uart->tx = 1;
|
||||||
@@ -131,32 +121,16 @@ static bool mount_sd_card_if_avail(bool mounted)
|
|||||||
|
|
||||||
if (!sdio_check_inserted() && !mounted) {
|
if (!sdio_check_inserted() && !mounted) {
|
||||||
res = f_mount(fs_ptr, "0:/", 1);
|
res = f_mount(fs_ptr, "0:/", 1);
|
||||||
if (res == FR_OK) {
|
if (res == FR_OK)
|
||||||
return true;
|
return true;
|
||||||
} else {
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return mounted;
|
return mounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int32_t handle_pid_controller(struct pid_controller *pid, float target_temperature,
|
static void setup_unused_pins(void)
|
||||||
float current_pt1000_resistance)
|
|
||||||
{
|
|
||||||
float current_temperature;
|
|
||||||
int32_t pid_out;
|
|
||||||
|
|
||||||
(void)temp_converter_convert_resistance_to_temp(current_pt1000_resistance, (float *)¤t_temperature);
|
|
||||||
pid_out = (int32_t)pid_sample(pid, target_temperature - current_temperature);
|
|
||||||
|
|
||||||
/* Blink green LED */
|
|
||||||
led_set(1, !led_get(1));
|
|
||||||
|
|
||||||
return pid_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_unused_pins()
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -166,7 +140,7 @@ static void setup_unused_pins()
|
|||||||
GPIOE->PUPDR |= PULLDOWN(i);
|
GPIOE->PUPDR |= PULLDOWN(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setup_system()
|
static inline void setup_system(void)
|
||||||
{
|
{
|
||||||
setup_nvic_priorities();
|
setup_nvic_priorities();
|
||||||
systick_setup();
|
systick_setup();
|
||||||
@@ -176,12 +150,11 @@ static inline void setup_system()
|
|||||||
digio_setup_default_all();
|
digio_setup_default_all();
|
||||||
led_setup();
|
led_setup();
|
||||||
loudspeaker_setup();
|
loudspeaker_setup();
|
||||||
rotary_encoder_setup();
|
reflow_menu_init();
|
||||||
button_init();
|
safety_adc_init();
|
||||||
lcd_init();
|
|
||||||
|
|
||||||
uart_gpio_config();
|
uart_gpio_config();
|
||||||
setup_sell_uart(&shell_uart);
|
setup_shell_uart(&shell_uart);
|
||||||
|
|
||||||
setup_unused_pins();
|
setup_unused_pins();
|
||||||
}
|
}
|
||||||
@@ -192,89 +165,101 @@ static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
|
|||||||
const char *uart_input;
|
const char *uart_input;
|
||||||
size_t uart_input_len;
|
size_t uart_input_len;
|
||||||
|
|
||||||
/* Handle uart input for shell */
|
/* Handle UART input for shell */
|
||||||
uart_receive_status = uart_receive_data_with_dma(&shell_uart, &uart_input, &uart_input_len);
|
uart_receive_status = uart_receive_data_with_dma(&shell_uart, &uart_input, &uart_input_len);
|
||||||
if (uart_receive_status >= 0)
|
if (uart_receive_status >= 0)
|
||||||
shell_handle_input(shell_handle, uart_input, uart_input_len);
|
shell_handle_input(shell_handle, uart_input, uart_input_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
static void zero_ccm_ram(void)
|
||||||
|
{
|
||||||
|
/* These extern variables are placed in the linker script */
|
||||||
|
extern char _sccmram;
|
||||||
|
extern char _eccmram;
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t *ptr = (uint32_t *)&_sccmram;
|
||||||
|
|
||||||
|
len = (uint32_t)&_eccmram - (uint32_t)&_sccmram;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
ptr[i] = 0UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function sets the appropriate error flags in the oven PID controller
|
||||||
|
* depending on the Safety ADC measurements.
|
||||||
|
* The PID controller's error flags have to be cleared via the GUI by either starting a new RUN or explicitly
|
||||||
|
* ack'ing these errors.
|
||||||
|
*/
|
||||||
|
static void propagate_safety_adc_error_to_oven_pid(void)
|
||||||
|
{
|
||||||
|
enum safety_adc_check_result safety_adc_result;
|
||||||
|
|
||||||
|
safety_adc_result = safety_adc_get_errors();
|
||||||
|
|
||||||
|
if (safety_adc_result & SAFETY_ADC_CHECK_TEMP_LOW ||
|
||||||
|
safety_adc_result & SAFETY_ADC_CHECK_TEMP_HIGH)
|
||||||
|
oven_pid_report_error(OVEN_PID_ERR_OVERTEMP);
|
||||||
|
|
||||||
|
if (safety_adc_result & SAFETY_ADC_CHECK_VREF_LOW ||
|
||||||
|
safety_adc_result & SAFETY_ADC_CHECK_VREF_HIGH)
|
||||||
|
oven_pid_report_error(OVEN_PID_ERR_VREF_TOL);
|
||||||
|
|
||||||
|
if (safety_adc_result & SAFETY_ADC_INTERNAL_ERROR)
|
||||||
|
oven_pid_report_error(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
{
|
{
|
||||||
bool sd_card_mounted = false;
|
bool sd_card_mounted = false;
|
||||||
shellmatta_handle_t shell_handle;
|
shellmatta_handle_t shell_handle;
|
||||||
|
int menu_wait_request;
|
||||||
|
uint64_t quarter_sec_timestamp = 0ULL;
|
||||||
|
const struct oven_pid_status *pid_status;
|
||||||
|
enum adc_pt1000_error pt1000_status;
|
||||||
|
|
||||||
uint64_t pid_timestamp = 0ULL;
|
zero_ccm_ram();
|
||||||
bool pid_controller_active = false;
|
|
||||||
int32_t pid_controller_output;
|
|
||||||
uint64_t display_timestamp = 0ULL;
|
|
||||||
char disp[4][21] = {0};
|
|
||||||
enum lcd_fsm_ret lcd_ret = LCD_FSM_NOP;
|
|
||||||
|
|
||||||
target_temperature = 25.0f;
|
|
||||||
|
|
||||||
setup_system();
|
setup_system();
|
||||||
|
|
||||||
|
global_error_state = false;
|
||||||
|
|
||||||
shell_handle = shell_init(write_shell_callback);
|
shell_handle = shell_init(write_shell_callback);
|
||||||
shell_print_motd(shell_handle);
|
shell_print_motd(shell_handle);
|
||||||
|
|
||||||
pid_init(&pid, 0.1, 0.1, 4.0, 0.0, 100.0, 40.0);
|
|
||||||
pid_zero(&pid);
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted);
|
sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted);
|
||||||
|
|
||||||
snprintf(&disp[0][0], 17, "SD %smounted", sd_card_mounted ? "" : "un");
|
pid_status = oven_pid_get_status();
|
||||||
|
|
||||||
pt1000_value_status = adc_pt1000_get_current_resistance(&pt1000_value);
|
if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) {
|
||||||
|
quarter_sec_timestamp = systick_get_global_tick();
|
||||||
|
|
||||||
if (systick_ticks_have_passed(pid_timestamp, 250)) {
|
(void)handle_safety_adc();
|
||||||
pid_timestamp = systick_get_global_tick();
|
propagate_safety_adc_error_to_oven_pid();
|
||||||
if (pt1000_value_status >= 0 && pid_controller_active)
|
|
||||||
pid_controller_output = handle_pid_controller(&pid, target_temperature, pt1000_value);
|
|
||||||
|
|
||||||
/* Blink red led in case of temp error */
|
if (global_error_state)
|
||||||
if (pt1000_value_status < 0)
|
|
||||||
led_set(0, !led_get(0));
|
led_set(0, !led_get(0));
|
||||||
else
|
else
|
||||||
led_set(0, 0);
|
led_set(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle error in case PID controller should be active, but temperature measurement failed */
|
pt1000_status = adc_pt1000_check_error();
|
||||||
if (pid_controller_active && pt1000_value_status < 0) {
|
global_error_state = pid_status->error_set || !!safety_adc_get_errors() || !!pt1000_status;
|
||||||
/* Disable the oven controller */
|
|
||||||
|
menu_wait_request = reflow_menu_handle();
|
||||||
|
|
||||||
|
/* Deactivate oven output in case of error! */
|
||||||
|
if (!pid_status->active || global_error_state)
|
||||||
oven_driver_set_power(0U);
|
oven_driver_set_power(0U);
|
||||||
|
|
||||||
/* Activate loundspeaker permanently */
|
|
||||||
loudspeaker_set(1);
|
|
||||||
} else if (pid_controller_active) {
|
|
||||||
/* In case temperature measurement is okay and controlelr is working, write output power */
|
|
||||||
oven_driver_set_power(pid_controller_output < 0 ? 0U : (uint8_t)pid_controller_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
button = button_read_event();
|
|
||||||
rot = rotary_encoder_get_abs_val();
|
|
||||||
|
|
||||||
oven_driver_set_power(rot > 100U ? 100U : rot);
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: handle gui */
|
|
||||||
snprintf(&disp[1][0], 17, "Rotary: %u", (unsigned int)rot);
|
|
||||||
snprintf(&disp[2][0], 17, "Button: %s", (button == BUTTON_SHORT ? "SHORT" : (button == BUTTON_LONG ? "LONG" : "")));
|
|
||||||
|
|
||||||
handle_shell_uart_input(shell_handle);
|
handle_shell_uart_input(shell_handle);
|
||||||
|
|
||||||
if (systick_ticks_have_passed(display_timestamp, 2) || lcd_ret == LCD_FSM_CALL_AGAIN) {
|
if (menu_wait_request)
|
||||||
lcd_ret = lcd_fsm_write_buffer(disp);
|
|
||||||
display_timestamp = systick_get_global_tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lcd_ret == LCD_FSM_CALL_AGAIN) {
|
|
||||||
/* Nothing */
|
|
||||||
} else {
|
|
||||||
__WFI();
|
__WFI();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdio_wait_ms(uint32_t ms)
|
void sdio_wait_ms(uint32_t ms)
|
||||||
@@ -282,12 +267,12 @@ void sdio_wait_ms(uint32_t ms)
|
|||||||
systick_wait_ms(ms);
|
systick_wait_ms(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA2_Stream7_IRQHandler()
|
void DMA2_Stream7_IRQHandler(void)
|
||||||
{
|
{
|
||||||
uint32_t hisr = DMA2->HISR;
|
uint32_t hisr = DMA2->HISR;
|
||||||
|
|
||||||
DMA2->HIFCR = hisr;
|
DMA2->HIFCR = hisr;
|
||||||
|
|
||||||
if (hisr & DMA_HISR_TCIF7) {
|
if (hisr & DMA_HISR_TCIF7)
|
||||||
uart_tx_dma_complete_int_callback(&shell_uart);
|
uart_tx_dma_complete_int_callback(&shell_uart);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,19 @@
|
|||||||
#include <reflow-controller/oven-driver.h>
|
#include <reflow-controller/oven-driver.h>
|
||||||
#include <reflow-controller/periph-config/oven-driver-hwcfg.h>
|
#include <reflow-controller/periph-config/oven-driver-hwcfg.h>
|
||||||
#include <stm-periph/clock-enable-manager.h>
|
#include <stm-periph/clock-enable-manager.h>
|
||||||
|
#include <reflow-controller/systick.h>
|
||||||
|
#include <reflow-controller/adc-meas.h>
|
||||||
|
#include <reflow-controller/temp-converter.h>
|
||||||
|
|
||||||
|
static struct pid_controller oven_pid;
|
||||||
|
|
||||||
|
static struct oven_pid_status oven_pid_current_status = {
|
||||||
|
.active = false,
|
||||||
|
.error_set = false,
|
||||||
|
.target_temp = 0.0f,
|
||||||
|
.current_temp = 0.0f,
|
||||||
|
.timestamp_last_run = 0ULL
|
||||||
|
};
|
||||||
|
|
||||||
void oven_driver_init()
|
void oven_driver_init()
|
||||||
{
|
{
|
||||||
@@ -57,3 +70,94 @@ void oven_driver_disable()
|
|||||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_PORT_RCC_MASK));
|
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_PORT_RCC_MASK));
|
||||||
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_TIM_RCC_MASK));
|
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_TIM_RCC_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void oven_pid_ack_errors(void)
|
||||||
|
{
|
||||||
|
oven_pid_current_status.error_set = false;
|
||||||
|
oven_pid_current_status.error_flags.vref_tol = false;
|
||||||
|
oven_pid_current_status.error_flags.pt1000_other = false;
|
||||||
|
oven_pid_current_status.error_flags.generic_error = false;
|
||||||
|
oven_pid_current_status.error_flags.pt1000_adc_off = false;
|
||||||
|
oven_pid_current_status.error_flags.controller_overtemp = false;
|
||||||
|
oven_pid_current_status.error_flags.pt1000_adc_watchdog = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oven_pid_init(struct pid_controller *controller_to_copy)
|
||||||
|
{
|
||||||
|
pid_copy(&oven_pid, controller_to_copy);
|
||||||
|
oven_pid.output_sat_min = 0.0f;
|
||||||
|
oven_pid.output_sat_max = 100.0f;
|
||||||
|
oven_pid_current_status.timestamp_last_run = 0ULL;
|
||||||
|
oven_pid_current_status.active = true;
|
||||||
|
oven_pid_ack_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
void oven_pid_handle(float target_temp)
|
||||||
|
{
|
||||||
|
float pid_out;
|
||||||
|
float current_temp;
|
||||||
|
int resistance_status;
|
||||||
|
enum adc_pt1000_error pt1000_error;
|
||||||
|
|
||||||
|
if (oven_pid_current_status.active && !oven_pid_current_status.error_set) {
|
||||||
|
if (systick_ticks_have_passed(oven_pid_current_status.timestamp_last_run,
|
||||||
|
(uint64_t)(oven_pid.sample_period * 1000))) {
|
||||||
|
|
||||||
|
resistance_status = adc_pt1000_get_current_resistance(¤t_temp);
|
||||||
|
if (resistance_status < 0) {
|
||||||
|
oven_driver_set_power(0);
|
||||||
|
pt1000_error = adc_pt1000_check_error();
|
||||||
|
if (pt1000_error & ADC_PT1000_WATCHDOG_ERROR)
|
||||||
|
oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_WATCHDOG);
|
||||||
|
if (pt1000_error & ADC_PT1000_INACTIVE)
|
||||||
|
oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_OFF);
|
||||||
|
if (pt1000_error & ADC_PT1000_OVERFLOW)
|
||||||
|
oven_pid_report_error(OVEN_PID_ERR_PT1000_OTHER);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)temp_converter_convert_resistance_to_temp(current_temp, ¤t_temp);
|
||||||
|
|
||||||
|
pid_out = pid_sample(&oven_pid, target_temp - current_temp);
|
||||||
|
oven_driver_set_power((uint8_t)pid_out);
|
||||||
|
oven_pid_current_status.timestamp_last_run = systick_get_global_tick();
|
||||||
|
oven_pid_current_status.target_temp = target_temp;
|
||||||
|
oven_pid_current_status.current_temp = current_temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oven_pid_report_error(enum oven_pid_error_report report)
|
||||||
|
{
|
||||||
|
struct oven_pid_errors *e = &oven_pid_current_status.error_flags;
|
||||||
|
|
||||||
|
oven_pid_current_status.active = false;
|
||||||
|
oven_pid_current_status.error_set = true;
|
||||||
|
|
||||||
|
if (report == 0) {
|
||||||
|
e->generic_error = true;
|
||||||
|
}
|
||||||
|
if (report & OVEN_PID_ERR_OVERTEMP)
|
||||||
|
e->controller_overtemp = true;
|
||||||
|
if (report & OVEN_PID_ERR_VREF_TOL)
|
||||||
|
e->controller_overtemp = true;
|
||||||
|
if (report & OVEN_PID_ERR_PT1000_OTHER)
|
||||||
|
e->pt1000_other = true;
|
||||||
|
if (report & OVEN_PID_ERR_PT1000_ADC_OFF)
|
||||||
|
e->pt1000_adc_off = true;
|
||||||
|
if (report & OVEN_PID_ERR_PT1000_ADC_WATCHDOG)
|
||||||
|
e->pt1000_adc_watchdog = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct oven_pid_status *oven_pid_get_status()
|
||||||
|
{
|
||||||
|
return &oven_pid_current_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oven_pid_stop()
|
||||||
|
{
|
||||||
|
oven_pid_current_status.active = false;
|
||||||
|
oven_pid_current_status.target_temp = 0.0f;
|
||||||
|
oven_pid_current_status.current_temp = 0.0f;
|
||||||
|
}
|
||||||
|
@@ -19,19 +19,34 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <reflow-controller/pid-controller.h>
|
#include <reflow-controller/pid-controller.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void pid_init(struct pid_controller *pid, float k_deriv, float k_int, float k_p, float output_sat_min, float output_sat_max, float integral_max)
|
void pid_init(struct pid_controller *pid, float k_deriv, float k_int, float k_p, float output_sat_min, float output_sat_max, float integral_max, float sample_period)
|
||||||
{
|
{
|
||||||
if (!pid)
|
if (!pid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
pid->sample_period = sample_period;
|
||||||
pid->k_p = k_p;
|
pid->k_p = k_p;
|
||||||
pid->k_int = k_int;
|
pid->k_int = k_int;
|
||||||
pid->k_deriv = k_deriv;
|
pid->k_deriv = k_deriv;
|
||||||
|
pid->k_int_t = pid->k_int * pid->sample_period * 0.5f;
|
||||||
|
pid->k_deriv_t = pid->k_deriv * 2.0f / pid->sample_period;
|
||||||
pid->output_sat_max = output_sat_max;
|
pid->output_sat_max = output_sat_max;
|
||||||
pid->output_sat_min = output_sat_min;
|
pid->output_sat_min = output_sat_min;
|
||||||
pid->control_output = 0;
|
|
||||||
pid->integral_max = integral_max;
|
pid->integral_max = integral_max;
|
||||||
|
|
||||||
|
pid_zero(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pid_copy(struct pid_controller *dest, const struct pid_controller *src)
|
||||||
|
{
|
||||||
|
if (!dest || !src)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memcpy(dest, src, sizeof(struct pid_controller));
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pid_zero(struct pid_controller *pid)
|
void pid_zero(struct pid_controller *pid)
|
||||||
@@ -43,12 +58,13 @@ void pid_zero(struct pid_controller *pid)
|
|||||||
|
|
||||||
static void calculate_integral(struct pid_controller *pid, float deviation)
|
static void calculate_integral(struct pid_controller *pid, float deviation)
|
||||||
{
|
{
|
||||||
pid->integral += deviation * pid->k_int;
|
pid->integral = pid->integral + pid->k_int_t * (deviation + pid->last_in);
|
||||||
|
|
||||||
|
/* Saturate integral term to spoecified maximum */
|
||||||
if (pid->integral > pid->integral_max) {
|
if (pid->integral > pid->integral_max) {
|
||||||
pid->integral = pid->integral_max;
|
pid->integral = pid->integral_max;
|
||||||
} else if (pid->integral < -pid->integral_max) {
|
} else if (pid->integral < -pid->integral_max){
|
||||||
pid->integral = -pid->integral_max;
|
pid->integral = - pid->integral_max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,17 +82,20 @@ float pid_sample(struct pid_controller *pid, float deviation)
|
|||||||
calculate_integral(pid, deviation);
|
calculate_integral(pid, deviation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate derivative part */
|
||||||
|
pid->derivate = pid->k_deriv_t * (deviation - pid->last_in) - pid->derivate;
|
||||||
|
|
||||||
|
output += pid->derivate;
|
||||||
output += pid->integral;
|
output += pid->integral;
|
||||||
output -= (deviation - pid->last_in) * pid->k_deriv;
|
|
||||||
|
|
||||||
pid->last_in = deviation;
|
/* Saturate output */
|
||||||
|
|
||||||
if (output > pid->output_sat_max)
|
|
||||||
output = pid->output_sat_max;
|
|
||||||
if (output < pid->output_sat_min)
|
if (output < pid->output_sat_min)
|
||||||
output = pid->output_sat_min;
|
output = pid->output_sat_min;
|
||||||
|
else if (output > pid->output_sat_max)
|
||||||
|
output = pid->output_sat_max;
|
||||||
|
|
||||||
pid->control_output = output;
|
pid->control_output = output;
|
||||||
|
pid->last_in = deviation;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
285
stm-firmware/reflow-menu.c
Normal file
285
stm-firmware/reflow-menu.c
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
/* Reflow Oven Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*
|
||||||
|
* This file is part of the Reflow Oven Controller Project.
|
||||||
|
*
|
||||||
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <reflow-controller/reflow-menu.h>
|
||||||
|
#include <reflow-controller/ui/menu.h>
|
||||||
|
#include <reflow-controller/ui/lcd.h>
|
||||||
|
#include <reflow-controller/rotary-encoder.h>
|
||||||
|
#include <reflow-controller/systick.h>
|
||||||
|
#include <reflow-controller/adc-meas.h>
|
||||||
|
#include <reflow-controller/safety-adc.h>
|
||||||
|
#include <reflow-controller/temp-converter.h>
|
||||||
|
#include <helper-macros/helper-macros.h>
|
||||||
|
#include <stm-periph/unique-id.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
static char __attribute__((section(".ccmram"))) display_buffer[4][21] = {0};
|
||||||
|
static struct lcd_menu reflow_menu;
|
||||||
|
static struct lcd_menu * const reflow_menu_ptr = &reflow_menu;
|
||||||
|
|
||||||
|
static void update_display_buffer(uint8_t row, const char *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (row > 4)
|
||||||
|
return;
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; data[i] && i < LCD_CHAR_WIDTH; i++) {
|
||||||
|
display_buffer[row][i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
display_buffer[row][i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reflow_menu_monitor(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
|
||||||
|
{
|
||||||
|
static void *my_parent;
|
||||||
|
static uint64_t my_timestamp = 0;
|
||||||
|
char line[17];
|
||||||
|
float tmp;
|
||||||
|
int res;
|
||||||
|
const char *prefix;
|
||||||
|
|
||||||
|
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
|
||||||
|
my_parent = parent;
|
||||||
|
menu_display_clear(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (systick_ticks_have_passed(my_timestamp, 250)) {
|
||||||
|
my_timestamp = systick_get_global_tick();
|
||||||
|
adc_pt1000_get_current_resistance(&tmp);
|
||||||
|
snprintf(line, sizeof(line), "Res: %.1f", tmp);
|
||||||
|
menu->update_display(0, line);
|
||||||
|
|
||||||
|
res = temp_converter_convert_resistance_to_temp(tmp, &tmp);
|
||||||
|
switch (res) {
|
||||||
|
case -1:
|
||||||
|
prefix = "<";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
prefix = ">";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
prefix = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(line, sizeof(line), "Temp: %s%.1f " LCD_DEGREE_SYMBOL_STRING "C", prefix, tmp);
|
||||||
|
menu->update_display(1, line);
|
||||||
|
|
||||||
|
tmp = safety_adc_get_temp();
|
||||||
|
snprintf(line, sizeof(line), "Tj: %.1f " LCD_DEGREE_SYMBOL_STRING "C", tmp);
|
||||||
|
menu->update_display(2, line);
|
||||||
|
|
||||||
|
tmp = safety_adc_get_vref();
|
||||||
|
snprintf(line, sizeof(line), "Vref: %.1f mV", tmp);
|
||||||
|
menu->update_display(3, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu->inputs.push_button == BUTTON_SHORT_RELEASED || menu->inputs.push_button == BUTTON_LONG) {
|
||||||
|
menu_entry_dropback(menu, my_parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reflow_menu_about(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
|
||||||
|
{
|
||||||
|
static void *my_parent;
|
||||||
|
static bool button_ready;
|
||||||
|
static int page = 0;
|
||||||
|
static uint32_t uptime_secs;
|
||||||
|
uint32_t new_uptime_secs;
|
||||||
|
uint32_t uptime_mins;
|
||||||
|
uint32_t uptime_hours;
|
||||||
|
uint32_t uptime_days;
|
||||||
|
int16_t rot_delta;
|
||||||
|
uint32_t ser1, ser2, ser3;
|
||||||
|
enum button_state push_button;
|
||||||
|
|
||||||
|
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
|
||||||
|
uptime_secs = 0ULL;
|
||||||
|
page = 0;
|
||||||
|
my_parent = parent;
|
||||||
|
button_ready = false;
|
||||||
|
menu_display_clear(menu);
|
||||||
|
menu_ack_rotary_delta(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
rot_delta = menu_get_rotary_delta(menu);
|
||||||
|
if (rot_delta >= 4) {
|
||||||
|
menu_ack_rotary_delta(menu);
|
||||||
|
if (page < 4) {
|
||||||
|
page++;
|
||||||
|
menu_display_clear(menu);
|
||||||
|
}
|
||||||
|
} else if (rot_delta <= -4) {
|
||||||
|
menu_ack_rotary_delta(menu);
|
||||||
|
if (page > 0) {
|
||||||
|
page--;
|
||||||
|
menu_display_clear(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (page) {
|
||||||
|
case 0:
|
||||||
|
menu_lcd_output(menu, 0, LCD_SHIMATTA_STRING " Shimatta");
|
||||||
|
menu_lcd_output(menu, 1, "Oven Controller");
|
||||||
|
menu_lcd_output(menu, 2, "(c) Mario H\xF5ttel");
|
||||||
|
menu_lcd_output(menu, 3, "Page 1/5");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
menu_lcd_output(menu, 0, "Version Number:");
|
||||||
|
menu_lcd_outputf(menu, 1, "%.*s", LCD_CHAR_WIDTH, xstr(GIT_VER));
|
||||||
|
if (strlen(xstr(GIT_VER)) > LCD_CHAR_WIDTH) {
|
||||||
|
menu_lcd_outputf(menu, 2, "%s", &xstr(GIT_VER)[LCD_CHAR_WIDTH]);
|
||||||
|
}
|
||||||
|
#ifdef DEBUGBUILD
|
||||||
|
menu_lcd_output(menu, 3, "Page 2/5 [DEBUG]");
|
||||||
|
#else
|
||||||
|
menu_lcd_output(menu, 3, "Page 2/5");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
menu_lcd_output(menu, 0, "Compile Info");
|
||||||
|
menu_lcd_output(menu, 1, __DATE__);
|
||||||
|
menu_lcd_output(menu, 2, __TIME__);
|
||||||
|
menu_lcd_output(menu, 3, "Page 3/5");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
unique_id_get(&ser1, &ser2, &ser3);
|
||||||
|
|
||||||
|
menu_lcd_outputf(menu, 0, "Serial: %08X", ser1);
|
||||||
|
menu_lcd_outputf(menu, 1, " %08X", ser2);
|
||||||
|
menu_lcd_outputf(menu, 2, " %08X", ser3);
|
||||||
|
menu_lcd_output(menu, 3, "Page 4/5");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
systick_get_uptime_from_tick(&uptime_days, &uptime_hours, &uptime_mins, &new_uptime_secs);
|
||||||
|
if (new_uptime_secs != uptime_secs) {
|
||||||
|
uptime_secs = new_uptime_secs;
|
||||||
|
menu_lcd_output(menu, 0, "Uptime:");
|
||||||
|
menu_lcd_outputf(menu, 1, "%lu day%s %02lu:%02lu:%02lu",
|
||||||
|
uptime_days, (uptime_days == 1 ? "" : "s"), uptime_hours, uptime_mins, uptime_secs);
|
||||||
|
menu_lcd_output(menu, 3, "Page 5/5");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
page = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
push_button = menu_get_button_state(menu);
|
||||||
|
|
||||||
|
if (push_button == BUTTON_IDLE)
|
||||||
|
button_ready = true;
|
||||||
|
|
||||||
|
if (button_ready &&
|
||||||
|
(push_button == BUTTON_SHORT_RELEASED || push_button == BUTTON_LONG)) {
|
||||||
|
menu_entry_dropback(menu, my_parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reflow_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent)
|
||||||
|
{
|
||||||
|
(void)parent;
|
||||||
|
static struct menu_list list;
|
||||||
|
static bool button_valid;
|
||||||
|
static const char * const root_entry_names[] = {
|
||||||
|
"About",
|
||||||
|
"Monitoring",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const menu_func_t root_entry_funcs[] = {
|
||||||
|
reflow_menu_about,
|
||||||
|
reflow_menu_monitor
|
||||||
|
};
|
||||||
|
enum button_state push_button;
|
||||||
|
int16_t rot_delta;
|
||||||
|
|
||||||
|
if (entry_type != MENU_ENTRY_CONTINUE) {
|
||||||
|
menu_display_clear(menu);
|
||||||
|
update_display_buffer(0, "Main Menu");
|
||||||
|
menu_ack_rotary_delta(menu);
|
||||||
|
if (entry_type == MENU_ENTRY_FIRST_ENTER) {
|
||||||
|
button_valid = false;
|
||||||
|
list.entry_names = root_entry_names;
|
||||||
|
list.submenu_list = root_entry_funcs;
|
||||||
|
list.update_display = menu->update_display;
|
||||||
|
list.currently_selected = 0;
|
||||||
|
menu_list_compute_count(&list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push_button = menu_get_button_state(menu);
|
||||||
|
rot_delta = menu_get_rotary_delta(menu);
|
||||||
|
|
||||||
|
if (push_button == BUTTON_IDLE) {
|
||||||
|
button_valid = true;
|
||||||
|
} else if (button_valid && push_button == BUTTON_SHORT_RELEASED) {
|
||||||
|
/* Enter currently selected menu_entry */
|
||||||
|
menu_list_enter_selected_entry(&list, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rot_delta >= 4) {
|
||||||
|
menu_list_scroll_down(&list);
|
||||||
|
menu_ack_rotary_delta(menu);
|
||||||
|
} else if (rot_delta <= -4) {
|
||||||
|
menu_list_scroll_up(&list);
|
||||||
|
menu_ack_rotary_delta(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_list_display(&list, 1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
int reflow_menu_handle()
|
||||||
|
{
|
||||||
|
int32_t rot_delta;
|
||||||
|
enum button_state button;
|
||||||
|
static enum lcd_fsm_ret lcd_ret = LCD_FSM_NOP;
|
||||||
|
|
||||||
|
rot_delta = rotary_encoder_get_change_val();
|
||||||
|
button = button_read_event();
|
||||||
|
|
||||||
|
menu_handle(reflow_menu_ptr, (int16_t)rot_delta, button);
|
||||||
|
|
||||||
|
if (lcd_ret == LCD_FSM_CALL_AGAIN || lcd_tick_100us >= 5) {
|
||||||
|
lcd_ret = lcd_fsm_write_buffer(display_buffer);
|
||||||
|
lcd_tick_100us = 0UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lcd_ret == LCD_FSM_CALL_AGAIN)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reflow_menu_init()
|
||||||
|
{
|
||||||
|
rotary_encoder_setup();
|
||||||
|
button_init();
|
||||||
|
lcd_init();
|
||||||
|
|
||||||
|
menu_init(reflow_menu_ptr, reflow_menu_root_entry, update_display_buffer);
|
||||||
|
}
|
@@ -83,3 +83,8 @@ void rotary_encoder_stop(void)
|
|||||||
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(ROTARY_ENCODER_TIMER_RCC_MASK));
|
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(ROTARY_ENCODER_TIMER_RCC_MASK));
|
||||||
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ROTARY_ENCODER_RCC_MASK));
|
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ROTARY_ENCODER_RCC_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rotary_encoder_zero(void)
|
||||||
|
{
|
||||||
|
ROTARY_ENCODER_TIMER->CNT = 0UL;
|
||||||
|
}
|
||||||
|
188
stm-firmware/safety-adc.c
Normal file
188
stm-firmware/safety-adc.c
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/* Reflow Oven Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*
|
||||||
|
* This file is part of the Reflow Oven Controller Project.
|
||||||
|
*
|
||||||
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <reflow-controller/safety-adc.h>
|
||||||
|
#include <reflow-controller/periph-config/safety-adc-hwcfg.h>
|
||||||
|
#include <helper-macros/helper-macros.h>
|
||||||
|
#include <stm-periph/clock-enable-manager.h>
|
||||||
|
|
||||||
|
enum safety_adc_check_result global_safety_adc_status;
|
||||||
|
|
||||||
|
enum safety_adc_check_result safety_adc_get_errors()
|
||||||
|
{
|
||||||
|
return global_safety_adc_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void safety_adc_clear_errors(void)
|
||||||
|
{
|
||||||
|
global_safety_adc_status = SAFETY_ADC_CHECK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void safety_adc_init()
|
||||||
|
{
|
||||||
|
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
|
||||||
|
|
||||||
|
safety_adc_clear_errors();
|
||||||
|
|
||||||
|
/* Enable temperature and VREFINT measurement */
|
||||||
|
ADC->CCR |= ADC_CCR_TSVREFE;
|
||||||
|
|
||||||
|
/* Set sample time for channels 16 and 17 */
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 |= ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16;
|
||||||
|
|
||||||
|
/* Standard sequence. One measurement */
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->SQR1 = 0UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void safety_adc_deinit()
|
||||||
|
{
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL;
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL;
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL;
|
||||||
|
rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint16_t temp_result,
|
||||||
|
float *vref_calculated, float *temp_calculated)
|
||||||
|
{
|
||||||
|
enum safety_adc_check_result res = SAFETY_ADC_CHECK_OK;
|
||||||
|
float vref;
|
||||||
|
float temp;
|
||||||
|
|
||||||
|
|
||||||
|
vref = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result;
|
||||||
|
if (vref_calculated) {
|
||||||
|
*vref_calculated = vref;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = (((float)temp_result / 4095.0f * 2500.0f -
|
||||||
|
SAFETY_ADC_TEMP_NOM_MV) / SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
|
||||||
|
if (temp_calculated) {
|
||||||
|
*temp_calculated = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ABS(vref - SAFETY_ADC_VREF_MVOLT) > SAFETY_ADC_VREF_TOL_MVOLT) {
|
||||||
|
if (vref > SAFETY_ADC_VREF_MVOLT)
|
||||||
|
res |= SAFETY_ADC_CHECK_VREF_HIGH;
|
||||||
|
else
|
||||||
|
res |= SAFETY_ADC_CHECK_VREF_LOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp < SAFETY_ADC_TEMP_LOW_LIM)
|
||||||
|
res |= SAFETY_ADC_CHECK_TEMP_LOW;
|
||||||
|
else if (temp < SAFETY_ADC_CHECK_TEMP_HIGH)
|
||||||
|
res |= SAFETY_ADC_CHECK_TEMP_HIGH;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safety_adc_poll_result(uint16_t *adc_result)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!adc_result)
|
||||||
|
return -1000;
|
||||||
|
|
||||||
|
if (!(SAFETY_ADC_ADC_PERIPHERAL->CR2 & ADC_CR2_ADON)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SAFETY_ADC_ADC_PERIPHERAL->SR & ADC_SR_EOC) {
|
||||||
|
*adc_result = (uint16_t)SAFETY_ADC_ADC_PERIPHERAL->DR;
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 &= ~ADC_CR2_ADON;
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement)
|
||||||
|
{
|
||||||
|
switch (measurement) {
|
||||||
|
case SAFETY_ADC_MEAS_TEMP:
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->SQR3 = TEMP_CHANNEL_NUM;
|
||||||
|
break;
|
||||||
|
case SAFETY_ADC_MEAS_VREF:
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->SQR3 = INT_REF_CHANNEL_NUM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_ADON;
|
||||||
|
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_SWSTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t safety_vref_meas_raw;
|
||||||
|
static bool safety_vref_valid = false;
|
||||||
|
static uint16_t safety_temp_meas_raw;
|
||||||
|
static bool safety_temp_valid = false;
|
||||||
|
static float safety_vref;
|
||||||
|
static float safety_temp;
|
||||||
|
|
||||||
|
enum safety_adc_check_result handle_safety_adc()
|
||||||
|
{
|
||||||
|
static enum safety_adc_meas_channel safety_meas_channel = SAFETY_ADC_MEAS_VREF;
|
||||||
|
enum safety_adc_check_result check_result;
|
||||||
|
uint16_t result;
|
||||||
|
int poll_status;
|
||||||
|
|
||||||
|
poll_status = safety_adc_poll_result(&result);
|
||||||
|
|
||||||
|
if (poll_status < 0) {
|
||||||
|
safety_adc_trigger_meas(safety_meas_channel);
|
||||||
|
} else if (poll_status > 0) {
|
||||||
|
switch (safety_meas_channel) {
|
||||||
|
case SAFETY_ADC_MEAS_TEMP:
|
||||||
|
safety_temp_meas_raw = result;
|
||||||
|
safety_temp_valid = true;
|
||||||
|
safety_meas_channel = SAFETY_ADC_MEAS_VREF;
|
||||||
|
break;
|
||||||
|
case SAFETY_ADC_MEAS_VREF:
|
||||||
|
safety_vref_meas_raw = result;
|
||||||
|
safety_vref_valid = true;
|
||||||
|
safety_meas_channel = SAFETY_ADC_MEAS_TEMP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
safety_meas_channel = SAFETY_ADC_MEAS_VREF;
|
||||||
|
return SAFETY_ADC_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (safety_temp_valid && safety_vref_valid) {
|
||||||
|
check_result = safety_adc_check_results(safety_vref_meas_raw, safety_temp_meas_raw, &safety_vref, &safety_temp);
|
||||||
|
global_safety_adc_status |= check_result;
|
||||||
|
} else {
|
||||||
|
check_result = SAFETY_ADC_CHECK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return check_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float safety_adc_get_temp()
|
||||||
|
{
|
||||||
|
return safety_temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
float safety_adc_get_vref()
|
||||||
|
{
|
||||||
|
return safety_vref;
|
||||||
|
}
|
@@ -35,6 +35,7 @@
|
|||||||
#include <fatfs/ff.h>
|
#include <fatfs/ff.h>
|
||||||
#include <reflow-controller/stack-check.h>
|
#include <reflow-controller/stack-check.h>
|
||||||
#include <reflow-controller/rotary-encoder.h>
|
#include <reflow-controller/rotary-encoder.h>
|
||||||
|
#include <reflow-controller/safety-adc.h>
|
||||||
|
|
||||||
#ifndef GIT_VER
|
#ifndef GIT_VER
|
||||||
#define GIT_VER "VERSION NOT SET"
|
#define GIT_VER "VERSION NOT SET"
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
extern struct stm_uart shell_uart;
|
extern struct stm_uart shell_uart;
|
||||||
static shellmatta_instance_t shell;
|
static shellmatta_instance_t shell;
|
||||||
static char shell_buffer[512];
|
static char shell_buffer[512];
|
||||||
static char history_buffer[1024];
|
static char history_buffer[600];
|
||||||
|
|
||||||
static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
|
static shellmatta_retCode_t shell_cmd_ver(const shellmatta_handle_t handle,
|
||||||
const char *arguments,
|
const char *arguments,
|
||||||
@@ -188,8 +189,18 @@ static shellmatta_retCode_t shell_cmd_uptime(const shellmatta_handle_t handle,
|
|||||||
{
|
{
|
||||||
(void)arguments;
|
(void)arguments;
|
||||||
(void)length;
|
(void)length;
|
||||||
|
uint32_t days;
|
||||||
|
uint32_t hours;
|
||||||
|
uint32_t mins;
|
||||||
|
uint32_t secs;
|
||||||
|
|
||||||
shellmatta_printf(handle, "Uptime: %llu secs", global_tick_ms/1000);
|
systick_get_uptime_from_tick(&days, &hours, &mins, &secs);
|
||||||
|
|
||||||
|
shellmatta_printf(handle, "Uptime: %u day%s %02u:%02u:%02u",
|
||||||
|
days, (days == 1 ? "" : "s"),
|
||||||
|
hours,
|
||||||
|
mins,
|
||||||
|
secs);
|
||||||
return SHELLMATTA_OK;
|
return SHELLMATTA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,11 +249,10 @@ static shellmatta_retCode_t shell_cmd_rot(const shellmatta_handle_t handle,
|
|||||||
(void)length;
|
(void)length;
|
||||||
|
|
||||||
uint32_t rot_val;
|
uint32_t rot_val;
|
||||||
int32_t delta;
|
|
||||||
|
|
||||||
rot_val = rotary_encoder_get_abs_val();
|
rot_val = rotary_encoder_get_abs_val();
|
||||||
delta = rotary_encoder_get_change_val();
|
//delta = rotary_encoder_get_change_val();
|
||||||
shellmatta_printf(handle, "Rotary encoder value: %u, delta: %d\r\n", rot_val, delta);
|
shellmatta_printf(handle, "Rotary encoder value: %u\r\n", rot_val);
|
||||||
|
|
||||||
return SHELLMATTA_OK;
|
return SHELLMATTA_OK;
|
||||||
}
|
}
|
||||||
@@ -342,6 +352,32 @@ static shellmatta_retCode_t shell_cmd_cat(const shellmatta_handle_t handle, cons
|
|||||||
return SHELLMATTA_OK;
|
return SHELLMATTA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static shellmatta_retCode_t shell_cmd_safety_adc(const shellmatta_handle_t handle, const char *arguments,
|
||||||
|
uint32_t length)
|
||||||
|
{
|
||||||
|
(void)length;
|
||||||
|
(void)arguments;
|
||||||
|
|
||||||
|
shellmatta_printf(handle, "VREF:\t%8.2f\tmV\r\n", safety_adc_get_vref());
|
||||||
|
shellmatta_printf(handle, "TEMP:\t%8.2f\tdeg. Celsius\r\n", safety_adc_get_temp());
|
||||||
|
|
||||||
|
shellmatta_printf(handle, "Errors:\t%X", safety_adc_get_errors());
|
||||||
|
|
||||||
|
return SHELLMATTA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static shellmatta_retCode_t shell_cmd_safety_adc_clear_error(const shellmatta_handle_t handle, const char *arguments,
|
||||||
|
uint32_t length)
|
||||||
|
{
|
||||||
|
(void)length;
|
||||||
|
(void)arguments;
|
||||||
|
(void)handle;
|
||||||
|
|
||||||
|
safety_adc_clear_errors();
|
||||||
|
|
||||||
|
return SHELLMATTA_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//typedef struct shellmatta_cmd
|
//typedef struct shellmatta_cmd
|
||||||
//{
|
//{
|
||||||
// char *cmd; /**< command name */
|
// char *cmd; /**< command name */
|
||||||
@@ -352,7 +388,7 @@ static shellmatta_retCode_t shell_cmd_cat(const shellmatta_handle_t handle, cons
|
|||||||
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */
|
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */
|
||||||
//} shellmatta_cmd_t;
|
//} shellmatta_cmd_t;
|
||||||
|
|
||||||
static shellmatta_cmd_t cmd[13] = {
|
static shellmatta_cmd_t cmd[15] = {
|
||||||
{
|
{
|
||||||
.cmd = "version",
|
.cmd = "version",
|
||||||
.cmdAlias = "ver",
|
.cmdAlias = "ver",
|
||||||
@@ -455,8 +491,24 @@ static shellmatta_cmd_t cmd[13] = {
|
|||||||
.helpText = "Print file contents",
|
.helpText = "Print file contents",
|
||||||
.usageText = "cat <path>",
|
.usageText = "cat <path>",
|
||||||
.cmdFct = shell_cmd_cat,
|
.cmdFct = shell_cmd_cat,
|
||||||
|
.next = &cmd[13],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = "safety-adc",
|
||||||
|
.cmdAlias = NULL,
|
||||||
|
.helpText = "",
|
||||||
|
.usageText = "",
|
||||||
|
.cmdFct = shell_cmd_safety_adc,
|
||||||
|
.next = &cmd[14],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = "safety-adc-clear-error",
|
||||||
|
.cmdAlias = NULL,
|
||||||
|
.helpText = "",
|
||||||
|
.usageText = "",
|
||||||
|
.cmdFct = shell_cmd_safety_adc_clear_error,
|
||||||
.next = NULL,
|
.next = NULL,
|
||||||
}
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -112,13 +112,8 @@ SECTIONS
|
|||||||
|
|
||||||
_siccmram = LOADADDR(.ccmram);
|
_siccmram = LOADADDR(.ccmram);
|
||||||
|
|
||||||
/* CCM-RAM section
|
/* CCM-RAM section */
|
||||||
*
|
.ccmram (NOLOAD):
|
||||||
* IMPORTANT NOTE!
|
|
||||||
* If initialized variables will be placed in this section,
|
|
||||||
* the startup code needs to be modified to copy the init-values.
|
|
||||||
*/
|
|
||||||
.ccmram :
|
|
||||||
{
|
{
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_sccmram = .; /* create a global symbol at ccmram start */
|
_sccmram = .; /* create a global symbol at ccmram start */
|
||||||
@@ -126,7 +121,7 @@ SECTIONS
|
|||||||
*(.ccmram*)
|
*(.ccmram*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_eccmram = .; /* create a global symbol at ccmram end */
|
_eccmram = .; /* create a global symbol at ccmram end */
|
||||||
} >CCM AT> FLASH
|
} >CCM
|
||||||
|
|
||||||
_sidata = LOADADDR(.data);
|
_sidata = LOADADDR(.data);
|
||||||
|
|
||||||
|
@@ -26,12 +26,13 @@
|
|||||||
#include <stm32/stm32f4xx.h>
|
#include <stm32/stm32f4xx.h>
|
||||||
#include <cmsis/core_cm4.h>
|
#include <cmsis/core_cm4.h>
|
||||||
|
|
||||||
volatile uint32_t wait_tick_ms;
|
volatile uint32_t wait_tick_ms = 0UL;
|
||||||
volatile uint64_t global_tick_ms;
|
volatile uint64_t global_tick_ms = 0ULL;
|
||||||
|
volatile uint32_t lcd_tick_100us = 0UL;
|
||||||
|
|
||||||
void systick_setup(void)
|
void systick_setup(void)
|
||||||
{
|
{
|
||||||
/* Setup Systick for 1ms tick @ 168 MHz Clock Speed */
|
/* Setup Systick for 100us tick @ 168 MHz Clock Speed */
|
||||||
SysTick_Config(SYSTICK_RELOAD);
|
SysTick_Config(SYSTICK_RELOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +44,42 @@ void systick_wait_ms(uint32_t ms)
|
|||||||
|
|
||||||
uint64_t systick_get_global_tick()
|
uint64_t systick_get_global_tick()
|
||||||
{
|
{
|
||||||
return global_tick_ms;
|
uint64_t temp;
|
||||||
|
|
||||||
|
__disable_irq();
|
||||||
|
temp = global_tick_ms;
|
||||||
|
__enable_irq();
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void systick_get_uptime_from_tick(uint32_t *days, uint32_t *hours, uint32_t *minutes, uint32_t *seconds)
|
||||||
|
{
|
||||||
|
uint64_t tick_secs;
|
||||||
|
uint32_t secs;
|
||||||
|
uint32_t mins;
|
||||||
|
uint32_t hs;
|
||||||
|
uint32_t ds;
|
||||||
|
|
||||||
|
|
||||||
|
tick_secs = systick_get_global_tick() / 1000;
|
||||||
|
secs = tick_secs % 60;
|
||||||
|
tick_secs /= 60;
|
||||||
|
mins = tick_secs % 60;
|
||||||
|
tick_secs /= 60;
|
||||||
|
hs = tick_secs % 60;
|
||||||
|
tick_secs /= 24;
|
||||||
|
ds = tick_secs;
|
||||||
|
|
||||||
|
if (days)
|
||||||
|
*days = ds;
|
||||||
|
if (hours)
|
||||||
|
*hours = hs;
|
||||||
|
if (minutes)
|
||||||
|
*minutes = mins;
|
||||||
|
if (seconds)
|
||||||
|
*seconds = secs;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __attribute__((optimize("O3"))) systick_ticks_have_passed(uint64_t start_timestamp, uint64_t ticks)
|
bool __attribute__((optimize("O3"))) systick_ticks_have_passed(uint64_t start_timestamp, uint64_t ticks)
|
||||||
@@ -75,7 +111,14 @@ bool __attribute__((optimize("O3"))) systick_ticks_have_passed(uint64_t start_ti
|
|||||||
*/
|
*/
|
||||||
void __attribute__((optimize("O3"))) SysTick_Handler()
|
void __attribute__((optimize("O3"))) SysTick_Handler()
|
||||||
{
|
{
|
||||||
|
static uint32_t pre_tick = 0UL;
|
||||||
|
|
||||||
|
pre_tick++;
|
||||||
|
if (pre_tick == 10) {
|
||||||
|
pre_tick = 0;
|
||||||
/* Increase tick counters */
|
/* Increase tick counters */
|
||||||
wait_tick_ms++;
|
wait_tick_ms++;
|
||||||
global_tick_ms++;
|
global_tick_ms++;
|
||||||
|
}
|
||||||
|
lcd_tick_100us++;
|
||||||
}
|
}
|
||||||
|
@@ -31,8 +31,6 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LCD_CHAR_WIDTH 16
|
|
||||||
|
|
||||||
static void lcd_port_clear(void)
|
static void lcd_port_clear(void)
|
||||||
{
|
{
|
||||||
LCD_DPORT->ODR &= ~(LCD_E_MASK);
|
LCD_DPORT->ODR &= ~(LCD_E_MASK);
|
||||||
@@ -151,7 +149,7 @@ static void lcd_command(uint8_t data)
|
|||||||
// Set DD RAM Address --------- 0b1xxxxxxx (Display Data RAM)
|
// Set DD RAM Address --------- 0b1xxxxxxx (Display Data RAM)
|
||||||
#define LCD_SET_DDADR 0x80
|
#define LCD_SET_DDADR 0x80
|
||||||
|
|
||||||
static char shadow_display[4][21];
|
static char __attribute__((section(".ccmram"))) shadow_display[4][21];
|
||||||
|
|
||||||
void lcd_clear(void)
|
void lcd_clear(void)
|
||||||
{
|
{
|
||||||
@@ -307,12 +305,22 @@ static void lcd_fsm_enable(bool en)
|
|||||||
__ASM("nop");
|
__ASM("nop");
|
||||||
__ASM("nop");
|
__ASM("nop");
|
||||||
__ASM("nop");
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
if (en)
|
if (en)
|
||||||
LCD_DPORT->ODR |= LCD_E_MASK;
|
LCD_DPORT->ODR |= LCD_E_MASK;
|
||||||
else
|
else
|
||||||
LCD_DPORT->ODR &= ~LCD_E_MASK;
|
LCD_DPORT->ODR &= ~LCD_E_MASK;
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
|
__ASM("nop");
|
||||||
__ASM("nop");
|
__ASM("nop");
|
||||||
__ASM("nop");
|
__ASM("nop");
|
||||||
__ASM("nop");
|
__ASM("nop");
|
||||||
@@ -395,10 +403,10 @@ enum lcd_fsm_ret lcd_fsm_write_buffer(const char (*display_buffer)[21])
|
|||||||
state_cnt++;
|
state_cnt++;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if (!systick_ticks_have_passed(timestamp, 5)) {
|
if (!systick_ticks_have_passed(timestamp, 4)) {
|
||||||
ret = LCD_FSM_WAIT_CALL;
|
ret = LCD_FSM_WAIT_CALL;
|
||||||
} else {
|
} else {
|
||||||
ret = LCD_FSM_WAIT_CALL;
|
ret = LCD_FSM_CALL_AGAIN;
|
||||||
state_cnt++;
|
state_cnt++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -410,7 +418,7 @@ enum lcd_fsm_ret lcd_fsm_write_buffer(const char (*display_buffer)[21])
|
|||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
lcd_fsm_enable(false);
|
lcd_fsm_enable(false);
|
||||||
ret = LCD_FSM_CALL_AGAIN;
|
ret = LCD_FSM_WAIT_CALL;
|
||||||
state_cnt++;
|
state_cnt++;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
|
@@ -19,5 +19,237 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <reflow-controller/ui/menu.h>
|
#include <reflow-controller/ui/menu.h>
|
||||||
#include <reflow-controller/ui/lcd.h>
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
void menu_handle(struct lcd_menu *menu, int16_t rotary_encoder_delta, enum button_state push_button)
|
||||||
|
{
|
||||||
|
menu_func_t tmp;
|
||||||
|
|
||||||
|
if (!menu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu->inputs.push_button = push_button;
|
||||||
|
menu->inputs.rotary_encoder_delta += rotary_encoder_delta;
|
||||||
|
|
||||||
|
if (menu->active_entry == NULL)
|
||||||
|
menu->active_entry = menu->root_entry;
|
||||||
|
|
||||||
|
tmp = menu->active_entry;
|
||||||
|
|
||||||
|
|
||||||
|
if (menu->active_entry_type == MENU_ENTRY_FIRST_ENTER) {
|
||||||
|
menu->active_entry(menu, menu->active_entry_type, menu->init_parent);
|
||||||
|
} else {
|
||||||
|
menu->active_entry(menu, menu->active_entry_type, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu->active_entry_type != MENU_ENTRY_CONTINUE && tmp == menu->active_entry) {
|
||||||
|
menu->active_entry_type = MENU_ENTRY_CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_init(struct lcd_menu *menu, menu_func_t root_node, void (*display_update)(uint8_t row, const char *data))
|
||||||
|
{
|
||||||
|
if (!menu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu->root_entry = root_node;
|
||||||
|
menu->active_entry = root_node;
|
||||||
|
menu->init_parent = NULL;
|
||||||
|
menu->inputs.push_button = BUTTON_IDLE;
|
||||||
|
menu->inputs.rotary_encoder_delta = 0;
|
||||||
|
menu->active_entry_type = MENU_ENTRY_FIRST_ENTER;
|
||||||
|
menu->update_display = display_update;
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_entry_dropback(struct lcd_menu *menu, menu_func_t parent_func)
|
||||||
|
{
|
||||||
|
if (!menu)
|
||||||
|
return;
|
||||||
|
if (parent_func)
|
||||||
|
menu->active_entry = parent_func;
|
||||||
|
else
|
||||||
|
menu->active_entry = menu->root_entry;
|
||||||
|
|
||||||
|
menu->active_entry_type = MENU_ENTRY_DROPBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_entry_enter(struct lcd_menu *menu, menu_func_t entry, bool handle_immediately)
|
||||||
|
{
|
||||||
|
if (!menu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu->init_parent = menu->active_entry;
|
||||||
|
menu->active_entry_type = MENU_ENTRY_FIRST_ENTER;
|
||||||
|
menu->active_entry = entry;
|
||||||
|
|
||||||
|
if (handle_immediately)
|
||||||
|
menu_handle(menu, menu->inputs.rotary_encoder_delta, menu->inputs.push_button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_lcd_output(struct lcd_menu *menu, uint8_t row_num, const char *text)
|
||||||
|
{
|
||||||
|
if (!menu || !menu->update_display)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu->update_display(row_num, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_lcd_outputf(struct lcd_menu *menu, uint8_t row_num, const char *format, ...)
|
||||||
|
{
|
||||||
|
char buff[64];
|
||||||
|
va_list valist;
|
||||||
|
|
||||||
|
va_start(valist, format);
|
||||||
|
vsnprintf(buff, sizeof(buff), format, valist);
|
||||||
|
buff[sizeof(buff) - 1] = '\0';
|
||||||
|
menu_lcd_output(menu, row_num, buff);
|
||||||
|
va_end(valist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_list_display(struct menu_list *list, uint32_t top_row, uint32_t bottom_row)
|
||||||
|
{
|
||||||
|
uint8_t row_count;
|
||||||
|
uint32_t mid_row;
|
||||||
|
uint32_t count_above_mid;
|
||||||
|
uint32_t count_below_mid;
|
||||||
|
uint32_t start_index;
|
||||||
|
uint32_t current_row;
|
||||||
|
uint32_t current_idx;
|
||||||
|
char workbuff[64];
|
||||||
|
|
||||||
|
if (!list || !list->update_display)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bottom_row < top_row)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (list->entry_count == 0) {
|
||||||
|
for (current_row = top_row; current_row <= bottom_row; current_row++) {
|
||||||
|
list->update_display((uint8_t)current_row, "");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate list parameters */
|
||||||
|
row_count = bottom_row - top_row + 1;
|
||||||
|
mid_row = (top_row + bottom_row) / 2;
|
||||||
|
count_above_mid = mid_row - top_row;
|
||||||
|
count_below_mid = bottom_row - mid_row;
|
||||||
|
|
||||||
|
/* Check if there are more elements above the and below the currently selected one that can be displayed. in this case position
|
||||||
|
* active entry in center
|
||||||
|
*/
|
||||||
|
if (list->currently_selected > count_above_mid && (list->entry_count - list->currently_selected - 1) > count_below_mid) {
|
||||||
|
start_index = list->currently_selected - count_above_mid;
|
||||||
|
} else if (list->currently_selected < count_above_mid) {
|
||||||
|
start_index = 0;
|
||||||
|
} else if ((list->entry_count - list->currently_selected - 1) <= count_below_mid) {
|
||||||
|
if (list->entry_count < row_count)
|
||||||
|
start_index = 0;
|
||||||
|
else
|
||||||
|
start_index = list->entry_count - row_count;
|
||||||
|
} else {
|
||||||
|
start_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (current_row = top_row, current_idx = start_index; current_row <= bottom_row; current_row++, current_idx++) {
|
||||||
|
if (current_idx >= list->entry_count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
snprintf(workbuff, sizeof(workbuff), "%c%s", (current_idx == list->currently_selected ? '>' : ' '),
|
||||||
|
list->entry_names[current_idx]);
|
||||||
|
workbuff[sizeof(workbuff)-1] = 0;
|
||||||
|
list->update_display((uint8_t)current_row, workbuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_list_compute_count(struct menu_list *list)
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (count = 0; list->entry_names[count] != NULL; count++);
|
||||||
|
list->entry_count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_list_scroll_down(struct menu_list *list)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (list->currently_selected < list->entry_count - 1) {
|
||||||
|
list->currently_selected++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_list_enter_selected_entry(struct menu_list *list, struct lcd_menu *menu)
|
||||||
|
{
|
||||||
|
menu_func_t entry;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!list->submenu_list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entry = list->submenu_list[list->currently_selected];
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu_entry_enter(menu, entry, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_list_scroll_up(struct menu_list *list)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (list->currently_selected > 0)
|
||||||
|
list->currently_selected--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_ack_rotary_delta(struct lcd_menu *menu)
|
||||||
|
{
|
||||||
|
if (!menu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu->inputs.rotary_encoder_delta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t menu_get_rotary_delta(const struct lcd_menu *menu)
|
||||||
|
{
|
||||||
|
int16_t ret = 0;
|
||||||
|
|
||||||
|
if (menu)
|
||||||
|
ret = menu->inputs.rotary_encoder_delta;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum button_state menu_get_button_state(const struct lcd_menu *menu)
|
||||||
|
{
|
||||||
|
enum button_state ret = BUTTON_IDLE;
|
||||||
|
|
||||||
|
if (menu)
|
||||||
|
ret = menu->inputs.push_button;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void menu_display_clear(struct lcd_menu *menu)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
if (!menu || !menu->update_display)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
menu->update_display(i, "");
|
||||||
|
}
|
||||||
|
279
temp-profile-spec/.gitignore
vendored
279
temp-profile-spec/.gitignore
vendored
@@ -1,279 +0,0 @@
|
|||||||
|
|
||||||
# Created by https://www.gitignore.io/api/latex
|
|
||||||
# Edit at https://www.gitignore.io/?templates=latex
|
|
||||||
|
|
||||||
### LaTeX ###
|
|
||||||
## Core latex/pdflatex auxiliary files:
|
|
||||||
*.aux
|
|
||||||
*.lof
|
|
||||||
*.log
|
|
||||||
*.lot
|
|
||||||
*.fls
|
|
||||||
*.out
|
|
||||||
*.toc
|
|
||||||
*.fmt
|
|
||||||
*.fot
|
|
||||||
*.cb
|
|
||||||
*.cb2
|
|
||||||
.*.lb
|
|
||||||
|
|
||||||
## Intermediate documents:
|
|
||||||
*.dvi
|
|
||||||
*.xdv
|
|
||||||
*-converted-to.*
|
|
||||||
# these rules might exclude image files for figures etc.
|
|
||||||
# *.ps
|
|
||||||
# *.eps
|
|
||||||
# *.pdf
|
|
||||||
|
|
||||||
## Generated if empty string is given at "Please type another file name for output:"
|
|
||||||
specification.pdf
|
|
||||||
|
|
||||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
|
||||||
*.bbl
|
|
||||||
*.bcf
|
|
||||||
*.blg
|
|
||||||
*-blx.aux
|
|
||||||
*-blx.bib
|
|
||||||
*.run.xml
|
|
||||||
|
|
||||||
## Build tool auxiliary files:
|
|
||||||
*.fdb_latexmk
|
|
||||||
*.synctex
|
|
||||||
*.synctex(busy)
|
|
||||||
*.synctex.gz
|
|
||||||
*.synctex.gz(busy)
|
|
||||||
*.pdfsync
|
|
||||||
|
|
||||||
## Build tool directories for auxiliary files
|
|
||||||
# latexrun
|
|
||||||
latex.out/
|
|
||||||
|
|
||||||
## Auxiliary and intermediate files from other packages:
|
|
||||||
# algorithms
|
|
||||||
*.alg
|
|
||||||
*.loa
|
|
||||||
|
|
||||||
# achemso
|
|
||||||
acs-*.bib
|
|
||||||
|
|
||||||
# amsthm
|
|
||||||
*.thm
|
|
||||||
|
|
||||||
# beamer
|
|
||||||
*.nav
|
|
||||||
*.pre
|
|
||||||
*.snm
|
|
||||||
*.vrb
|
|
||||||
|
|
||||||
# changes
|
|
||||||
*.soc
|
|
||||||
|
|
||||||
# comment
|
|
||||||
*.cut
|
|
||||||
|
|
||||||
# cprotect
|
|
||||||
*.cpt
|
|
||||||
|
|
||||||
# elsarticle (documentclass of Elsevier journals)
|
|
||||||
*.spl
|
|
||||||
|
|
||||||
# endnotes
|
|
||||||
*.ent
|
|
||||||
|
|
||||||
# fixme
|
|
||||||
*.lox
|
|
||||||
|
|
||||||
# feynmf/feynmp
|
|
||||||
*.mf
|
|
||||||
*.mp
|
|
||||||
*.t[1-9]
|
|
||||||
*.t[1-9][0-9]
|
|
||||||
*.tfm
|
|
||||||
|
|
||||||
#(r)(e)ledmac/(r)(e)ledpar
|
|
||||||
*.end
|
|
||||||
*.?end
|
|
||||||
*.[1-9]
|
|
||||||
*.[1-9][0-9]
|
|
||||||
*.[1-9][0-9][0-9]
|
|
||||||
*.[1-9]R
|
|
||||||
*.[1-9][0-9]R
|
|
||||||
*.[1-9][0-9][0-9]R
|
|
||||||
*.eledsec[1-9]
|
|
||||||
*.eledsec[1-9]R
|
|
||||||
*.eledsec[1-9][0-9]
|
|
||||||
*.eledsec[1-9][0-9]R
|
|
||||||
*.eledsec[1-9][0-9][0-9]
|
|
||||||
*.eledsec[1-9][0-9][0-9]R
|
|
||||||
|
|
||||||
# glossaries
|
|
||||||
*.acn
|
|
||||||
*.acr
|
|
||||||
*.glg
|
|
||||||
*.glo
|
|
||||||
*.gls
|
|
||||||
*.glsdefs
|
|
||||||
|
|
||||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
|
||||||
# *.ist
|
|
||||||
|
|
||||||
# gnuplottex
|
|
||||||
*-gnuplottex-*
|
|
||||||
|
|
||||||
# gregoriotex
|
|
||||||
*.gaux
|
|
||||||
*.gtex
|
|
||||||
|
|
||||||
# htlatex
|
|
||||||
*.4ct
|
|
||||||
*.4tc
|
|
||||||
*.idv
|
|
||||||
*.lg
|
|
||||||
*.trc
|
|
||||||
*.xref
|
|
||||||
|
|
||||||
# hyperref
|
|
||||||
*.brf
|
|
||||||
|
|
||||||
# knitr
|
|
||||||
*-concordance.tex
|
|
||||||
# TODO Comment the next line if you want to keep your tikz graphics files
|
|
||||||
*.tikz
|
|
||||||
*-tikzDictionary
|
|
||||||
|
|
||||||
# listings
|
|
||||||
*.lol
|
|
||||||
|
|
||||||
# luatexja-ruby
|
|
||||||
*.ltjruby
|
|
||||||
|
|
||||||
# makeidx
|
|
||||||
*.idx
|
|
||||||
*.ilg
|
|
||||||
*.ind
|
|
||||||
|
|
||||||
# minitoc
|
|
||||||
*.maf
|
|
||||||
*.mlf
|
|
||||||
*.mlt
|
|
||||||
*.mtc[0-9]*
|
|
||||||
*.slf[0-9]*
|
|
||||||
*.slt[0-9]*
|
|
||||||
*.stc[0-9]*
|
|
||||||
|
|
||||||
# minted
|
|
||||||
_minted*
|
|
||||||
*.pyg
|
|
||||||
|
|
||||||
# morewrites
|
|
||||||
*.mw
|
|
||||||
|
|
||||||
# nomencl
|
|
||||||
*.nlg
|
|
||||||
*.nlo
|
|
||||||
*.nls
|
|
||||||
|
|
||||||
# pax
|
|
||||||
*.pax
|
|
||||||
|
|
||||||
# pdfpcnotes
|
|
||||||
*.pdfpc
|
|
||||||
|
|
||||||
# sagetex
|
|
||||||
*.sagetex.sage
|
|
||||||
*.sagetex.py
|
|
||||||
*.sagetex.scmd
|
|
||||||
|
|
||||||
# scrwfile
|
|
||||||
*.wrt
|
|
||||||
|
|
||||||
# sympy
|
|
||||||
*.sout
|
|
||||||
*.sympy
|
|
||||||
sympy-plots-for-*.tex/
|
|
||||||
|
|
||||||
# pdfcomment
|
|
||||||
*.upa
|
|
||||||
*.upb
|
|
||||||
|
|
||||||
# pythontex
|
|
||||||
*.pytxcode
|
|
||||||
pythontex-files-*/
|
|
||||||
|
|
||||||
# tcolorbox
|
|
||||||
*.listing
|
|
||||||
|
|
||||||
# thmtools
|
|
||||||
*.loe
|
|
||||||
|
|
||||||
# TikZ & PGF
|
|
||||||
*.dpth
|
|
||||||
*.md5
|
|
||||||
*.auxlock
|
|
||||||
|
|
||||||
# todonotes
|
|
||||||
*.tdo
|
|
||||||
|
|
||||||
# vhistory
|
|
||||||
*.hst
|
|
||||||
*.ver
|
|
||||||
|
|
||||||
# easy-todo
|
|
||||||
*.lod
|
|
||||||
|
|
||||||
# xcolor
|
|
||||||
*.xcp
|
|
||||||
|
|
||||||
# xmpincl
|
|
||||||
*.xmpi
|
|
||||||
|
|
||||||
# xindy
|
|
||||||
*.xdy
|
|
||||||
|
|
||||||
# xypic precompiled matrices
|
|
||||||
*.xyc
|
|
||||||
|
|
||||||
# endfloat
|
|
||||||
*.ttt
|
|
||||||
*.fff
|
|
||||||
|
|
||||||
# Latexian
|
|
||||||
TSWLatexianTemp*
|
|
||||||
|
|
||||||
## Editors:
|
|
||||||
# WinEdt
|
|
||||||
*.bak
|
|
||||||
*.sav
|
|
||||||
|
|
||||||
# Texpad
|
|
||||||
.texpadtmp
|
|
||||||
|
|
||||||
# LyX
|
|
||||||
*.lyx~
|
|
||||||
|
|
||||||
# Kile
|
|
||||||
*.backup
|
|
||||||
|
|
||||||
# KBibTeX
|
|
||||||
*~[0-9]*
|
|
||||||
|
|
||||||
# auto folder when using emacs and auctex
|
|
||||||
./auto/*
|
|
||||||
*.el
|
|
||||||
|
|
||||||
# expex forward references with \gathertags
|
|
||||||
*-tags.tex
|
|
||||||
|
|
||||||
# standalone packages
|
|
||||||
*.sta
|
|
||||||
|
|
||||||
### LaTeX Patch ###
|
|
||||||
# glossaries
|
|
||||||
*.glstex
|
|
||||||
|
|
||||||
# Version File
|
|
||||||
*.ver
|
|
||||||
*.commit
|
|
||||||
*.branch
|
|
||||||
# End of https://www.gitignore.io/api/latex
|
|
@@ -1,10 +0,0 @@
|
|||||||
target=specification
|
|
||||||
|
|
||||||
.PHONY: $(target).pdf all clean
|
|
||||||
|
|
||||||
all: $(target).pdf
|
|
||||||
|
|
||||||
$(target).pdf: $(target).tex
|
|
||||||
latexmk -pdf -pdflatex="pdflatex -interaction=nostopmode -shell-escape" -use-make $^
|
|
||||||
clean:
|
|
||||||
latexmk -CA
|
|
Binary file not shown.
@@ -1,172 +0,0 @@
|
|||||||
\documentclass[12pt,a4paper,oneside,notitlepage, numbers=noenddot,openany]{scrreprt}
|
|
||||||
\usepackage[a4paper]{geometry}
|
|
||||||
\geometry{verbose,tmargin=2.5cm,bmargin=4.5cm,lmargin=2.5cm,rmargin=2.5cm}
|
|
||||||
\setlength{\parindent}{0cm}
|
|
||||||
\usepackage{array}
|
|
||||||
\usepackage{textcomp}
|
|
||||||
\usepackage{float}
|
|
||||||
\usepackage{graphicx}
|
|
||||||
\usepackage{caption}
|
|
||||||
%\usepackage{subcaption}
|
|
||||||
%\usepackage{textgreek}
|
|
||||||
\usepackage{setspace}
|
|
||||||
\usepackage{nomencl}
|
|
||||||
\usepackage{listing}
|
|
||||||
\usepackage{tabularx}
|
|
||||||
\PassOptionsToPackage{hyphens}{url}
|
|
||||||
\usepackage[%
|
|
||||||
pdftitle={Temperature Profile File Specification},%
|
|
||||||
pdfauthor={Mario Huettel},%
|
|
||||||
pdfsubject={},%
|
|
||||||
pdfcreator={pdflatex, LaTeX with KOMA-Script},%
|
|
||||||
pdfpagemode=UseOutlines, % Beim Oeffnen Inhaltsverzeichnis anzeigen
|
|
||||||
pdfdisplaydoctitle=true, % Dokumenttitel statt Dateiname anzeigen.
|
|
||||||
pdflang=de, % Sprache des Dokuments.
|
|
||||||
%plainpages=false,
|
|
||||||
]{hyperref}
|
|
||||||
|
|
||||||
\immediate\write18{git describe --always --long --dirty > \jobname.ver}
|
|
||||||
\immediate\write18{git rev-parse --verify HEAD > \jobname.commit}
|
|
||||||
\immediate\write18{git rev-parse --abbrev-ref HEAD > \jobname.branch}
|
|
||||||
|
|
||||||
\usepackage[automark,headsepline,plainheadsepline,footsepline,plainfootsepline,autooneside=true]{scrlayer-scrpage}
|
|
||||||
\clearpairofpagestyles
|
|
||||||
|
|
||||||
|
|
||||||
\hypersetup{%
|
|
||||||
colorlinks=true, % Aktivieren von farbigen Links im Dokument
|
|
||||||
linkcolor=blue, % Farbe festlegen
|
|
||||||
citecolor=green,
|
|
||||||
%filecolor,
|
|
||||||
%menucolor=black,
|
|
||||||
%urlcolor=cyan,
|
|
||||||
bookmarksnumbered=true%, % Überschriftsnummerierung im PDF Inhalt anzeigen.
|
|
||||||
%hidelinks=false
|
|
||||||
}
|
|
||||||
|
|
||||||
\usepackage{CJKutf8}
|
|
||||||
\newenvironment{Japanese}{%
|
|
||||||
\CJKfamily{min}%
|
|
||||||
\CJKtilde
|
|
||||||
\CJKnospace}{}
|
|
||||||
|
|
||||||
\usepackage{booktabs}
|
|
||||||
|
|
||||||
\usepackage{color}
|
|
||||||
%\usepackage{cite}
|
|
||||||
\usepackage{blindtext}
|
|
||||||
\usepackage[utf8]{inputenc}
|
|
||||||
\usepackage{multicol}
|
|
||||||
\usepackage{lastpage}
|
|
||||||
\usepackage[american]{babel}
|
|
||||||
\usepackage{amssymb}
|
|
||||||
\usepackage{datetime}
|
|
||||||
\usepackage[withpage,printonlyused]{acronym}
|
|
||||||
\usepackage{amsmath}
|
|
||||||
\usepackage{mathtools}
|
|
||||||
\usepackage{forloop}
|
|
||||||
\usepackage{csvsimple}
|
|
||||||
\usepackage{xspace}
|
|
||||||
%\setcounter{secnumdepth}{3}
|
|
||||||
%\setcounter{tocdepth}{3}
|
|
||||||
%\usepackage{apacite}
|
|
||||||
%\usepackage{natbib}
|
|
||||||
%\usepackage[babel,german=quotes]{csquotes}
|
|
||||||
\usepackage{xspace}
|
|
||||||
\usepackage{nth}
|
|
||||||
%\usepackage[backend=biber, style=apa, natbib, bibencoding=utf8]{biblatex}
|
|
||||||
%
|
|
||||||
%
|
|
||||||
%
|
|
||||||
%\addbibresource{lit.bib}
|
|
||||||
%\DeclareLanguageMapping{ngerman}{ngerman-apa}
|
|
||||||
%
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\usepackage{enumitem}
|
|
||||||
\newcounter{reqcount}
|
|
||||||
\newlist{requirements}{description}{1}
|
|
||||||
\setlist[requirements,1]{%
|
|
||||||
before={%
|
|
||||||
\renewcommand*\thereqcount{\arabic{reqcount}}},
|
|
||||||
font={\bfseries\stepcounter{reqcount}REQ-\thereqcount:}
|
|
||||||
}
|
|
||||||
|
|
||||||
\newcommand{\newreq}{\bfseries\stepcounter{reqcount}REQ-\thereqcount:~}
|
|
||||||
|
|
||||||
|
|
||||||
\usepackage{xargs} % Use more than one optional parameter in a new commands
|
|
||||||
\usepackage[colorinlistoftodos,prependcaption,textsize=tiny]{todonotes}
|
|
||||||
\newcommandx{\unsure}[2][1=]{\todo[noline,linecolor=red,backgroundcolor=red!25,bordercolor=red,#1]{#2}}
|
|
||||||
\newcommandx{\miscite}[1][1=]{\todo[noline,linecolor=black,backgroundcolor=black!25,bordercolor=black]{Missing citation! #1}}
|
|
||||||
\newcommandx{\change}[2][1=]{\todo[noline,linecolor=blue,backgroundcolor=blue!25,bordercolor=blue,#1]{#2}}
|
|
||||||
\newcommandx{\info}[2][1=]{\todo[noline,linecolor=OliveGreen,backgroundcolor=OliveGreen!25,bordercolor=OliveGreen,#1]{#2}}
|
|
||||||
\newcommandx{\improvement}[2][1=]{\todo[noline,linecolor=Plum,backgroundcolor=Plum!25,bordercolor=Plum,#1]{#2}}
|
|
||||||
\newcommandx{\thiswillnotshow}[2][1=]{\todo[disable,#1]{#2}}
|
|
||||||
|
|
||||||
|
|
||||||
%Figure, table and listing enumeration style
|
|
||||||
\captionsetup{labelfont=bf}
|
|
||||||
\usepackage{chngcntr}
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
\clubpenalty10000
|
|
||||||
\widowpenalty10000
|
|
||||||
\displaywidowpenalty10000
|
|
||||||
|
|
||||||
%\counterwithout{figure}{part}
|
|
||||||
|
|
||||||
\ihead[Spec]{Spec}
|
|
||||||
|
|
||||||
\chead[\input{\jobname.ver}]{\input{\jobname.ver}}
|
|
||||||
\ohead{\headmark}
|
|
||||||
\ofoot[\pagemark]{\pagemark}
|
|
||||||
\cfoot[\url{https://git.shimatta.de/mhu/reflow-oven-control-sw}]{\url{https://git.shimatta.de/mhu/reflow-oven-control-sw}}
|
|
||||||
\setheadsepline{.5pt}
|
|
||||||
\setfootsepline{.5pt}
|
|
||||||
\BeforeStartingTOC{\thispagestyle{scrheadings}}
|
|
||||||
\pagestyle{scrheadings}
|
|
||||||
\thispagestyle{scrheadings}
|
|
||||||
\raggedbottom
|
|
||||||
\begin{document}
|
|
||||||
\pagenumbering{roman}
|
|
||||||
\begin{titlepage}
|
|
||||||
\begin{center}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\begin{figure}[H]
|
|
||||||
\centering
|
|
||||||
\resizebox{5cm}{!}{
|
|
||||||
\includegraphics{img/shimatta-logo}}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
\vspace{10em}
|
|
||||||
|
|
||||||
\begin{Huge}
|
|
||||||
\sffamily\textbf{Temperature Profile File Specification}
|
|
||||||
\end{Huge}
|
|
||||||
|
|
||||||
\vspace{1cm}
|
|
||||||
|
|
||||||
\textbf{Version: \input{\jobname.ver}}
|
|
||||||
|
|
||||||
\vspace{3em}
|
|
||||||
|
|
||||||
\small\texttt{\input{\jobname.commit}/ \input{\jobname.branch}}
|
|
||||||
|
|
||||||
|
|
||||||
\end{center}
|
|
||||||
|
|
||||||
|
|
||||||
\end{titlepage}
|
|
||||||
|
|
||||||
\tableofcontents
|
|
||||||
\newpage
|
|
||||||
\thispagestyle{scrheadings}
|
|
||||||
\pagenumbering{arabic}
|
|
||||||
|
|
||||||
\chapter{Test}
|
|
||||||
|
|
||||||
\end{document}
|
|
Reference in New Issue
Block a user