application: add frequency measurement in monitor single mode
This commit is contained in:
parent
97818981fb
commit
16cb734f6f
|
@ -42,6 +42,7 @@ to stop monitoring, press any key.
|
|||
to monitor the activity of a single channel, use the `monitor_single` command.
|
||||
provide as argument the channel you want to monitor.
|
||||
this works like the `monitor` command, but has the advantage to detect high voltages down to 1.5V (ideal for 1.8V logic).
|
||||
it will also show the (maximum) frequency of the signal (useful to clock and baud rate measurement).
|
||||
|
||||
you can also reset the target board if you connected to target reset pin to the SWJ finder.
|
||||
you can select of to drive the reset pin (OD for open-drain, PP for push-pull) and active level (H for high, L for low) using the `reset [ODL|ODH|PPL|PPH]` command.
|
||||
|
|
|
@ -75,7 +75,15 @@ static uint8_t channel_start = 0; /**< first signal of range to probe */
|
|||
static uint8_t channel_stop = CHANNEL_NUMBERS - 1; /**< last signal of range to probe */
|
||||
|
||||
/** timer ID for timer to measure activity timing */
|
||||
#define MONITOR_TIMER 2
|
||||
#define MONITOR_TIMER 3
|
||||
/** timer to measure frequency and baud rate
|
||||
* @note PA3/USART2_RX/TIM2_CH4 (PA2/USART2_TX/TIM2_CH3 could also be used)
|
||||
* @{
|
||||
*/
|
||||
#define FREQUENCY_TIMER 2 /**< timer peripheral ID */
|
||||
#define FREQUENCY_CHANNEL 4 /**< timer channel to capture edges */
|
||||
#define FREQUENCY_AF GPIO_AF1 /**< alternate function for UART pin to use as timer channel */
|
||||
/** @} */
|
||||
|
||||
/** UART peripheral for signal reading (TX and RX are connected together)
|
||||
* @{
|
||||
|
@ -525,6 +533,34 @@ static void command_monitor(void* argument)
|
|||
rcc_periph_clock_disable(RCC_TIM(MONITOR_TIMER)); // disable clock for timer peripheral
|
||||
}
|
||||
|
||||
volatile bool pulse_flag = false; /**< set when a small pulse time is detected */
|
||||
volatile uint32_t pulse_duration = UINT32_MAX; /**< smallest pulse duration measured */
|
||||
|
||||
/** timer ISR to measure edge timing */
|
||||
void TIM_ISR(FREQUENCY_TIMER)(void)
|
||||
{
|
||||
static uint32_t pulse = UINT32_MAX; // measured pulse duration (MAX is an invalid value)
|
||||
if (timer_get_flag(TIM(FREQUENCY_TIMER), TIM_SR_UIF)) { // overflow update event happened
|
||||
timer_clear_flag(TIM(FREQUENCY_TIMER), TIM_SR_UIF); // clear flag
|
||||
pulse = UINT32_MAX; // timer 2 is already a 32-bit timer, no need to count the overflow
|
||||
}
|
||||
if (timer_get_flag(TIM(FREQUENCY_TIMER), TIM_SR_CCOF(FREQUENCY_CHANNEL))) { // capture overflow occurred
|
||||
timer_clear_flag(TIM(FREQUENCY_TIMER), TIM_SR_CCOF(FREQUENCY_CHANNEL)); // clear flag
|
||||
pulse = UINT32_MAX; // invalidate measured pulse
|
||||
}
|
||||
if (timer_get_flag(TIM(FREQUENCY_TIMER), TIM_SR_CCIF(FREQUENCY_CHANNEL))) {
|
||||
uint16_t edge = TIM_CCR(FREQUENCY_TIMER, FREQUENCY_CHANNEL); // retrieve captured value (clears flag)
|
||||
if (UINT32_MAX != pulse) { // only calculate pulse if previous edge is valid
|
||||
pulse = ((pulse & 0xffff0000) + edge) - (pulse & 0xffff); // calculate pulse duration
|
||||
if (pulse < pulse_duration) { // save new pulse duration if smaller
|
||||
pulse_duration = pulse; // save measurement for user
|
||||
pulse_flag = true; // notify user we got a measurement
|
||||
}
|
||||
}
|
||||
pulse = edge; // replace with current edge time
|
||||
}
|
||||
}
|
||||
|
||||
/** monitor single channel for activity
|
||||
* @param[in] argument channel number
|
||||
*/
|
||||
|
@ -558,7 +594,8 @@ static void command_monitor_single(void* argument)
|
|||
|
||||
// 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)
|
||||
gpio_mode_setup(GPIO_PORT(UART_RX), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(UART_RX)); // use as input for the timer (it is pulled up by level shifter)
|
||||
gpio_set_af(GPIO_PORT(UART_RX), FREQUENCY_AF, GPIO_PIN(UART_RX)); // set alternate function to timer channel
|
||||
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
|
||||
|
||||
|
@ -566,9 +603,29 @@ static void command_monitor_single(void* argument)
|
|||
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");
|
||||
puts("time (s) CH freq. (Hz)\n");
|
||||
|
||||
// setup timer to measure milliseconds
|
||||
// setup timer to measure frequency
|
||||
rcc_periph_clock_enable(RCC_TIM(FREQUENCY_TIMER)); // enable clock for timer peripheral
|
||||
rcc_periph_reset_pulse(RST_TIM(FREQUENCY_TIMER)); // reset timer state
|
||||
timer_disable_counter(TIM(FREQUENCY_TIMER)); // disable timer to configure it
|
||||
timer_set_mode(TIM(FREQUENCY_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(FREQUENCY_TIMER), 0); // don't use prescale so to get the most precise measurement
|
||||
timer_ic_set_input(TIM(FREQUENCY_TIMER), TIM_IC(FREQUENCY_CHANNEL), TIM_IC_IN_TI(FREQUENCY_CHANNEL)); // configure the input capture ICx to use the right channel TIn
|
||||
timer_ic_set_filter(TIM(FREQUENCY_TIMER), TIM_IC(FREQUENCY_CHANNEL), TIM_IC_OFF); // use no filter input to keep precise timing
|
||||
timer_ic_set_polarity(TIM(FREQUENCY_TIMER), TIM_IC(FREQUENCY_CHANNEL), TIM_IC_FALLING); // capture on falling edge
|
||||
timer_ic_set_prescaler(TIM(FREQUENCY_TIMER), TIM_IC(FREQUENCY_CHANNEL), TIM_IC_PSC_OFF); // don't use any prescaler since we want to capture every pulse
|
||||
timer_ic_enable(TIM(FREQUENCY_TIMER), TIM_IC(FREQUENCY_CHANNEL)); // enable capture interrupt
|
||||
timer_clear_flag(TIM(FREQUENCY_TIMER), TIM_SR_CCIF(FREQUENCY_CHANNEL)); // clear input compare flag
|
||||
timer_enable_irq(TIM(FREQUENCY_TIMER), TIM_DIER_CCIE(FREQUENCY_CHANNEL)); // enable capture interrupt
|
||||
timer_update_on_overflow(TIM(FREQUENCY_TIMER)); // only use counter overflow as UEV source (use overflow to measure longer times)
|
||||
timer_clear_flag(TIM(FREQUENCY_TIMER), TIM_SR_UIF); // clear overflow flag
|
||||
timer_enable_irq(TIM(FREQUENCY_TIMER), TIM_DIER_UIE); // enable update interrupt for timer
|
||||
nvic_enable_irq(NVIC_TIM_IRQ(FREQUENCY_TIMER)); // catch interrupts for this timer
|
||||
pulse_duration = UINT32_MAX; // reset pulse duration
|
||||
timer_enable_counter(TIM(FREQUENCY_TIMER)); // enable timer
|
||||
|
||||
// setup timer to measure 0.1 seconds
|
||||
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
|
||||
|
@ -607,6 +664,12 @@ static void command_monitor_single(void* argument)
|
|||
} else {
|
||||
putc('0');
|
||||
}
|
||||
if (pulse_flag) { // frequency measurement worked
|
||||
const uint32_t freq = rcc_ahb_frequency / pulse_duration;
|
||||
printf(" %u", freq);
|
||||
pulse_duration = UINT32_MAX; // clear measurement
|
||||
pulse_flag = false; // clear flag
|
||||
}
|
||||
puts("\n");
|
||||
channel_changes = 0; // clear changes
|
||||
}
|
||||
|
@ -626,6 +689,13 @@ static void command_monitor_single(void* argument)
|
|||
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
|
||||
timer_disable_counter(TIM(FREQUENCY_TIMER)); // disable timer
|
||||
nvic_disable_irq(NVIC_TIM_IRQ(FREQUENCY_TIMER)); // catch interrupts for this timer
|
||||
timer_disable_irq(TIM(FREQUENCY_TIMER), TIM_DIER_UIE); // disable update interrupt for timer
|
||||
timer_disable_irq(TIM(FREQUENCY_TIMER), TIM_DIER_CCIE(FREQUENCY_CHANNEL)); // disable capture interrupt
|
||||
timer_ic_disable(TIM(FREQUENCY_TIMER), TIM_IC(FREQUENCY_CHANNEL)); // disable capture interrupt
|
||||
rcc_periph_reset_pulse(RST_TIM(FREQUENCY_TIMER)); // reset timer state
|
||||
rcc_periph_clock_disable(RCC_TIM(FREQUENCY_TIMER)); // disable clock for timer peripheral
|
||||
}
|
||||
|
||||
/** set first channel of range to scan
|
||||
|
|
Loading…
Reference in New Issue