application: new complete clock jockey application, untested

This commit is contained in:
King Kévin 2020-01-09 20:46:00 +01:00
parent 0ae3087049
commit ee615e65b1
1 changed files with 108 additions and 14 deletions

View File

@ -37,6 +37,7 @@
#include <libopencm3/stm32/dbgmcu.h> // debug utilities
#include <libopencm3/stm32/desig.h> // design utilities
#include <libopencm3/stm32/flash.h> // flash utilities
#include <libopencm3/stm32/timer.h> // 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
}