diff --git a/application.c b/application.c index 0d8078f..87b1b16 100644 --- a/application.c +++ b/application.c @@ -77,6 +77,15 @@ static uint8_t channel_stop = CHANNEL_NUMBERS - 1; /**< last signal of range to /** timer ID for timer to measure activity timing */ #define MONITOR_TIMER 2 +/** UART peripheral for signal reading (TX and RX are connected together) + * @{ + */ +#define UART_ID 2 /**< USART peripheral */ +#define UART_TX PA2 /**< pin used for USART TX */ +#define UART_RX PA3 /**< pin used for USART RX */ +#define UART_AF GPIO_AF7 /**< alternate function for UART pins */ +/** @} */ + size_t putc(char c) { size_t length = 0; // number of characters printed @@ -516,6 +525,109 @@ static void command_monitor(void* argument) rcc_periph_clock_disable(RCC_TIM(MONITOR_TIMER)); // disable clock for timer peripheral } +/** monitor single channel for activity + * @param[in] argument channel number + */ +static void command_monitor_single(void* argument) +{ + (void)argument; // we won't use the argument + + // get input channel + if (NULL == argument) { + puts("provide channel to monitor\n"); + return; + } + const uint32_t channel = *(uint32_t*)argument; // get channel argument + if (!(channel < CHANNEL_NUMBERS)) { // verify argument + printf("channel %u out of range (0-%u)\n", channel, CHANNEL_NUMBERS - 1); + return; + } + + // verify target voltage is OK + const float* voltages = measure_voltages(); // get target voltage + if (voltages[1] < 1.5) { + puts("target voltage too low: "); + print_fpu(voltages[1], 2); + puts(" < 1.5V\n"); + return; + } else { + puts("target voltage: "); + print_fpu(voltages[1], 2); + puts("V\n"); + } + + // select channel + rcc_periph_clock_enable(GPIO_RCC(UART_RX)); // enable clock for USART RX pin port peripheral + gpio_mode_setup(GPIO_PORT(UART_RX), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(UART_RX)); // use as input (it is pulled up by level shifter) + mux_select(channel); // select channel + gpio_clear(GPIO_PORT(SHIFT_EN_PIN), GPIO_PIN(SHIFT_EN_PIN)); // connect target voltage to level shifters pull-up + + // show help + printf("CH%02u is pulled to target voltage by 10 kOhm\n", channel); + puts("high = 1.5-5.5V, 'X' shows multiple changes\n"); + puts("press any key to stop monitoring\n"); + puts("time (s) CH\n"); + + // setup timer to measure milliseconds + rcc_periph_clock_enable(RCC_TIM(MONITOR_TIMER)); // enable clock for timer peripheral + rcc_periph_reset_pulse(RST_TIM(MONITOR_TIMER)); // reset timer state + timer_disable_counter(TIM(MONITOR_TIMER)); // disable timer to configure it + timer_set_mode(TIM(MONITOR_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up + timer_set_prescaler(TIM(MONITOR_TIMER), (rcc_ahb_frequency / 2000) - 1); // generate half millisecond ticks (prescaler is not large enough for milliseconds) + timer_set_period(TIM(MONITOR_TIMER), 200 - 1); // set period to 0.1 seconds + timer_clear_flag(TIM(MONITOR_TIMER), TIM_SR_UIF); // clear update (overflow) flag + timer_update_on_overflow(TIM(MONITOR_TIMER)); // only use counter overflow as UEV source (use overflow as start time or timeout) + uint32_t seconds = 0; // count the 0.1 seconds using the overflow + timer_enable_counter(TIM(MONITOR_TIMER)); // enable timer + + // start monitoring + bool channel_level = gpio_get(GPIO_PORT(UART_RX), GPIO_PIN(UART_RX)); // get initial level + uint8_t channel_changes = 1; // how many times the channel changed + while (!user_input_available) { // run until user breaks it + // time to do periodic checks + if (wakeup_flag || second_flag) { + iwdg_reset(); // kick the dog + wakeup_flag = false; // clear flag + second_flag = false; // clear flag + } + if (timer_get_flag(TIM(MONITOR_TIMER), TIM_SR_UIF)) { // 0.1 second has passed + timer_clear_flag(TIM(MONITOR_TIMER), TIM_SR_UIF); // clear flag + seconds++; // count the 0.1 seconds + if (channel_changes) { // there was some activity + // we print the change every 0.1 s instead of synchronously to rate limit the print (and overfill the buffer) + printf("%04u.%01u ", seconds / 10, seconds % 10); // print current time stamp (change time stamp with 0.1s precision + + if (channel_changes > 1) { // channel changed more than once + putc('X'); // show multiple changes + } else { + putc(' '); // show no or single change + } + if (channel_level) { // high level + putc('1'); + } else { + putc('0'); + } + puts("\n"); + channel_changes = 0; // clear changes + } + } + // check is there is a change on a channel + const bool level_new = gpio_get(GPIO_PORT(UART_RX), GPIO_PIN(UART_RX)); // get new level + if (level_new != channel_level) { // channel changed + channel_changes = addu8_safe(channel_changes, 1); + channel_level = level_new; // save new level + } + } + user_input_get(); // clean input + + // clean up + gpio_set(GPIO_PORT(SHIFT_EN_PIN), GPIO_PIN(SHIFT_EN_PIN)); // remove power from level shifters pull-up + mux_select(-1); // disable multiplexer + timer_disable_counter(TIM(MONITOR_TIMER)); // disable timer + rcc_periph_reset_pulse(RST_TIM(MONITOR_TIMER)); // reset timer state + rcc_periph_clock_disable(RCC_TIM(MONITOR_TIMER)); // disable clock for timer peripheral +} + /** set first channel of range to scan * @param[in] argument optional pointer to first channel number */ @@ -702,6 +814,14 @@ static const struct menu_command_t menu_commands[] = { .argument_description = "[0|3]", .command_handler = &command_monitor, }, + { + .shortcut = 'M', + .name = "monitor_single", + .command_description = "monitor single channel activity", + .argument = MENU_ARGUMENT_UNSIGNED, + .argument_description = "channel", + .command_handler = &command_monitor_single, + }, { .shortcut = 'c', .name = "start",