application: add single channel monitoring

This commit is contained in:
King Kévin 2021-05-06 10:51:05 +02:00
parent 611f5f6683
commit 3370e35dc5
1 changed files with 120 additions and 0 deletions

View File

@ -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",