From cdc6eb68966ea8dd93b5f0fadf0027d4ed96143e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Thu, 9 Jan 2020 20:46:00 +0100 Subject: [PATCH] application: new complete clock jockey application, untested --- application.c | 122 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 14 deletions(-) diff --git a/application.c b/application.c index ff1a1c6..97c0f99 100644 --- a/application.c +++ b/application.c @@ -37,6 +37,7 @@ #include // debug utilities #include // design utilities #include // flash utilities +#include // timer utilities /* own libraries */ #include "global.h" // board definitions @@ -47,12 +48,16 @@ #include "usb_cdcacm.h" // USB CDC ACM utilities #include "terminal.h" // handle the terminal interface #include "menu.h" // menu utilities +#include "flash_internal.h" // menu utilities -#define WATCHDOG_PERIOD 10000 /**< watchdog period in ms */ +#define WATCHDOG_PERIOD 3000 /**< watchdog period in ms */ /** set to 0 if the RTC is reset when the board is powered on, only indicates the uptime * set to 1 if VBAT can keep the RTC running when the board is unpowered, indicating the date and time */ -#define RTC_DATE_TIME 1 +#define RTC_DATE_TIME 0 + +/** number of RTC ticks per second */ +#define RTC_TICKS 10 /** RTC time when device is started */ static time_t time_start = 0; @@ -63,6 +68,13 @@ static time_t time_start = 0; volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */ /** @} */ +volatile uint32_t tacho_count = 0; /**< tachometer edge count */ +bool tacho_display = false; /**< if the current tachometer count should be displayed */ +#define TACHO_PIN PB11 /**< tachometer input on SWIM pin, pulled up to 3V3 by 680R */ +#define TACHO_TARGET_DEFAULT 40 /**< the default target tachometer count */ +uint32_t tacho_target = TACHO_TARGET_DEFAULT; /**< the target tachometer count (switch SSR on when below, off when above) */ +#define SSR_PIN PB14 /**< pin to control the SSR (active low, open drain to 5V) */ + size_t putc(char c) { size_t length = 0; // number of characters printed @@ -117,6 +129,30 @@ static void command_reset(void* argument); */ static void command_bootloader(void* argument); +static void command_tacho(void* argument) +{ + (void)argument; // we won't use the argument + + if (argument) { // tachometer value has been provided + uint32_t target = *(uint32_t*)argument; // get target tachometer value + printf("setting target tachometer value to %u\n", target); + tacho_target = target; + // save to EEPROM + const uint32_t eeprom_tacho[2] = {tacho_target, tacho_target ^ 0xffffffff}; + const int32_t rc = flash_internal_eeprom_write((uint8_t*)eeprom_tacho, sizeof(eeprom_tacho)); + if (rc != sizeof(eeprom_tacho)) { + printf("could not save value to EEPROM: %d\n", rc); + } + } else { + if (tacho_display) { + tacho_display = false; + } else { + printf("target tachometer value set to %u\n", tacho_target); + tacho_display = true; + } + } +} + /** list of all supported commands */ static const struct menu_command_t menu_commands[] = { { @@ -169,6 +205,14 @@ static const struct menu_command_t menu_commands[] = { .argument_description = NULL, .command_handler = &command_bootloader, }, + { + .shortcut = 't', + .name = "tacho", + .command_description = "set/show/hide tachometer target and current value", + .argument = MENU_ARGUMENT_UNSIGNED, + .argument_description = "[target]", + .command_handler = &command_tacho, + }, }; static void command_help(void* argument) @@ -330,7 +374,7 @@ void main(void) uart_setup(); // setup USART (for printing) #endif usb_cdcacm_setup(); // setup USB CDC ACM (for printing) - puts("\nwelcome to the CuVoodoo STM32F1 example application\n"); // print welcome message + puts("\nwelcome to the CuVoodoo dachboden clock turner\n"); // print welcome message #if DEBUG // show reset cause @@ -374,7 +418,7 @@ void main(void) printf("setup internal RTC: "); #if defined(BLUE_PILL) || defined(STLINKV2) || defined(BLASTER) // for boards without a Low Speed External oscillator // note: the blue pill LSE oscillator is affected when toggling the onboard LED, thus prefer the HSE - rtc_auto_awake(RCC_HSE, 8000000 / 128 - 1); // use High Speed External oscillator (8 MHz / 128) as RTC clock (VBAT can't be used to keep the RTC running) + rtc_auto_awake(RCC_HSE, 8000000 / 128 / RTC_TICKS - 1); // use High Speed External oscillator (8 MHz / 128) as RTC clock (VBAT can't be used to keep the RTC running) #else // for boards with an precise Low Speed External oscillator rtc_auto_awake(RCC_LSE, 32768 - 1); // ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect) #endif @@ -383,6 +427,39 @@ void main(void) time_start = rtc_get_counter_val(); // get start time from internal RTC printf("OK\n"); + printf("setup SSR: "); + rcc_periph_clock_enable(GPIO_RCC(SSR_PIN)); // enable clock for GPIO peripheral + gpio_set(GPIO_PORT(SSR_PIN), GPIO_PIN(TACHO_PIN)); // set high to switch off + gpio_set_mode(GPIO_PORT(SSR_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(SSR_PIN)); // set SSR - control pin to open drain. active low, connected to 5V on the + pin + printf("OK\n"); + + // setup timer to measure motor tachometer + printf("setup tachometer measurer: "); + rcc_periph_clock_enable(GPIO_RCC(TACHO_PIN)); // enable clock for GPIO peripheral + gpio_set_mode(GPIO_PORT(TACHO_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(TACHO_PIN)); // set tachometer pin to input + rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt + exti_select_source(GPIO_EXTI(TACHO_PIN), GPIO_PORT(TACHO_PIN)); // mask external interrupt of this pin only for this port + gpio_set(GPIO_PORT(TACHO_PIN), GPIO_PIN(TACHO_PIN)); // pull up to eliminate noise + exti_set_trigger(GPIO_EXTI(TACHO_PIN), EXTI_TRIGGER_FALLING); // trigger when opto-coupler triggers + exti_enable_request(GPIO_EXTI(TACHO_PIN)); // enable external interrupt + nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(TACHO_PIN)); // enable interrupt + printf("OK\n"); + + // load target tachometer value from EEPROM + uint32_t eeprom_tacho[2]; + flash_internal_eeprom_setup(1); // use 1 page for EEPROM emulation + bool eeprom_read = flash_internal_eeprom_read((uint8_t*)eeprom_tacho, sizeof(eeprom_tacho)); + printf("target tachometer count ("); + if (eeprom_read && eeprom_tacho[0] == (eeprom_tacho[1] ^ 0xffffffff)) { + tacho_target = eeprom_tacho[0]; + printf("set"); + } else { + tacho_target = TACHO_TARGET_DEFAULT; + printf("default"); + } + bool tacho_safety = false; // if the motor is switched of for safety reasons + printf("): %u\n", tacho_target); + // setup terminal terminal_prefix = ""; // set default prefix terminal_process = &process_command; // set central function to process commands @@ -390,7 +467,6 @@ void main(void) // start main loop bool action = false; // if an action has been performed don't go to sleep - button_flag = false; // reset button flag while (true) { // infinite loop iwdg_reset(); // kick the dog if (user_input_available) { // user input is available @@ -399,19 +475,30 @@ void main(void) char c = user_input_get(); // store receive character terminal_send(c); // send received character to terminal } - if (button_flag) { // user pressed button - action = true; // action has been performed - printf("button pressed\n"); - led_toggle(); // toggle LED - for (uint32_t i = 0; i < 1000000; i++) { // wait a bit to remove noise and double trigger - __asm__("nop"); - } - button_flag = false; // reset flag - } if (rtc_internal_tick_flag) { // the internal RTC ticked rtc_internal_tick_flag = false; // reset flag action = true; // action has been performed + uint32_t tacho = tacho_count; // backup before clearing + tacho_count = 0; // restart count led_toggle(); // toggle LED (good to indicate if main function is stuck) + if (!tacho_safety) { + if (tacho < tacho_target) { + gpio_clear(GPIO_PORT(SSR_PIN), GPIO_PIN(TACHO_PIN)); // switch SSR on to provide power + } else { + gpio_set(GPIO_PORT(SSR_PIN), GPIO_PIN(TACHO_PIN)); // switch SSR off to cut power + } + if (0 == tacho && rtc_get_counter_val() > time_start + 5 * RTC_TICKS) { // the motor does not seem to turn, after 5 s + tacho_safety = true; // turn safety on + gpio_set(GPIO_PORT(SSR_PIN), GPIO_PIN(TACHO_PIN)); // switch SSR off to cut power + printf("tachometer does not indicate the motor is turning\n"); + printf("either the tachometer is defective, or the motor is stuck\n"); + printf("switching the motor off for safety\n"); + printf("reboot to retry\n"); + } + } + if (tacho_display) { + printf("%u\n", tacho); // display tachometer frequency + } } if (action) { // go to sleep if nothing had to be done, else recheck for activity action = false; @@ -427,3 +514,10 @@ void rtc_isr(void) rtc_clear_flag(RTC_SEC); // clear flag rtc_internal_tick_flag = true; // notify to show new time } + +/** interrupt service routine called when tachometer edge is detected is pressed */ +void GPIO_EXTI_ISR(TACHO_PIN)(void) +{ + exti_reset_request(GPIO_EXTI(TACHO_PIN)); // reset interrupt + tacho_count++; // increment edge count +}