application: add command to probe for UART RX pin
This commit is contained in:
parent
3ba5b95061
commit
c98e82fedf
|
@ -8,7 +8,7 @@ summary
|
|||
|
||||
this tools allow to identify if channels (e.g. lines) are inputs or outputs.
|
||||
up to 16 channels can be identified at once.
|
||||
it also allows to monitor the channel activity.
|
||||
it also allows to monitor the channel activity, identify UART TX and RX signals.
|
||||
|
||||
usage
|
||||
-----
|
||||
|
@ -51,6 +51,11 @@ the configuration is displayed as it finds a better match.
|
|||
it will also show the decoded data.
|
||||
this mainly works for ASCII based communication (e.g. human readable debug logs), and might not give correct results for binary communication.
|
||||
|
||||
to find the corresponding UART RX pin (e.g. once UART TX pin has been identified using the `uart_auto` command), use the `uart_rx` commands.
|
||||
provide as argument the channel for the UART TX pin, and the UART baud rate and frame settings (e.g. 115200 8N1).
|
||||
data will be transmitted on the channels to probe and if we received the echo back on the TX, we fond the RX.
|
||||
this detection method only works if the target echoes back the data (e.g. on login screens).
|
||||
|
||||
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.
|
||||
to assert or release the reset, us the `reset 1` or `reset 0` commands.
|
||||
|
|
204
application.c
204
application.c
|
@ -1005,6 +1005,202 @@ static void command_uart_autodetect(void* argument)
|
|||
rcc_periph_clock_disable(RCC_USART(UART_ID)); // disable clock for USART peripheral
|
||||
}
|
||||
|
||||
/** find the RX UART pin
|
||||
* @param TX channel, baud rate, data bits parity and stop bits
|
||||
*/
|
||||
static void command_uart_probe(void* argument)
|
||||
{
|
||||
char* line = (char*)argument; // get line of arguments
|
||||
if (NULL == argument || 0 == strlen(line)) { // ensure argument is provided
|
||||
goto command_uart_probe_error;
|
||||
return;
|
||||
}
|
||||
|
||||
// get channel
|
||||
const char* delimiter = " "; // words are separated by spaces
|
||||
char* word = strtok(line, delimiter); // get first word
|
||||
if (!word) {
|
||||
goto command_uart_probe_error;
|
||||
return;
|
||||
}
|
||||
const int32_t channel = strtol(word, NULL, 10); // get signed integer
|
||||
if ((channel < 0) || (channel >= CHANNEL_NUMBERS)) { // verify argument
|
||||
printf("channel %d out of range (0-%u)\n", channel, CHANNEL_NUMBERS - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// get baud rate
|
||||
word = strtok(NULL, delimiter); // get second word
|
||||
if (!word) {
|
||||
goto command_uart_probe_error;
|
||||
return;
|
||||
}
|
||||
const int32_t baudrate = strtol(word, NULL, 10); // get signed integer
|
||||
if ((baudrate < 1200) || (baudrate >= 2000000)) { // verify argument
|
||||
printf("baud rate %d out of range (1200-2000000 bps)\n", baudrate);
|
||||
return;
|
||||
}
|
||||
|
||||
// get frame format (data bits, parity, stop bits
|
||||
word = strtok(NULL, delimiter); // get third word
|
||||
if (!word || 3 != strlen(word)) {
|
||||
printf("unknown frame format %s\n", word);
|
||||
goto command_uart_probe_error;
|
||||
return;
|
||||
}
|
||||
// data bits
|
||||
if (word[0] < '5' || word[0] > '8') {
|
||||
printf("unknown data bits %c\n", word[0]);
|
||||
goto command_uart_probe_error;
|
||||
return;
|
||||
}
|
||||
const uint8_t databits = word[0] - '0';
|
||||
// parity
|
||||
enum usart_enhanced_parity_t parity;
|
||||
switch(word[1]) {
|
||||
case 'N':
|
||||
case 'n':
|
||||
parity = USART_ENHANCED_PARITY_NONE;
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
parity = USART_ENHANCED_PARITY_EVEN;
|
||||
break;
|
||||
case 'O':
|
||||
case 'o':
|
||||
parity = USART_ENHANCED_PARITY_ODD;
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
parity = USART_ENHANCED_PARITY_MARK;
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
parity = USART_ENHANCED_PARITY_SPACE;
|
||||
break;
|
||||
default:
|
||||
printf("unknown parity %c\n", word[1]);
|
||||
goto command_uart_probe_error;
|
||||
return;
|
||||
}
|
||||
// stop bits
|
||||
if (word[2] < '1' || word[2] > '2') {
|
||||
printf("unknown stop bits %c\n", word[2]);
|
||||
goto command_uart_probe_error;
|
||||
return;
|
||||
}
|
||||
const uint8_t stopbits = word[2] - '0';
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// configure UART
|
||||
rcc_periph_clock_enable(GPIO_RCC(UART_TX)); // enable clock for USART TX pin port peripheral
|
||||
gpio_mode_setup(GPIO_PORT(UART_TX), GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN(UART_TX)); // use pin for UART data (normally output, but in half duplex it can become input)
|
||||
gpio_set_af(GPIO_PORT(UART_TX), UART_AF, GPIO_PIN(UART_TX)); // set alternate function to UART
|
||||
gpio_clear(GPIO_PORT(SHIFT_EN_PIN), GPIO_PIN(SHIFT_EN_PIN)); // connect target voltage to level shifters pull-up
|
||||
rcc_periph_clock_enable(RCC_USART(UART_ID)); // enable USART peripheral
|
||||
rcc_periph_reset_pulse(RST_USART(FREQUENCY_TIMER)); // reset USART peripheral
|
||||
usart_set_baudrate(USART(UART_ID), baudrate); // configure UART to slowest baud rate
|
||||
if (2 == stopbits) {
|
||||
usart_set_stopbits(USART(UART_ID), USART_STOPBITS_2); // ensure we have 2 stop bits
|
||||
} else {
|
||||
usart_set_stopbits(USART(UART_ID), USART_STOPBITS_1); // 1 stop-bits also complies to 2 stop-bits when receiving
|
||||
}
|
||||
usart_enhanced_config(USART(UART_ID), databits, parity); // set data bits and parity using enhanced library to support more modes
|
||||
usart_set_mode(USART(UART_ID), USART_MODE_TX_RX); // we will send and receive data
|
||||
USART_CR3(USART(UART_ID)) |= USART_CR3_HDSEL; // we will use the half-duplex mode to use the TX pin as RX
|
||||
usart_enable(USART(UART_ID)); // ensure UART is enabled
|
||||
|
||||
// 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
|
||||
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)
|
||||
timer_one_shot_mode(TIM(MONITOR_TIMER)); // use timer one to count down once
|
||||
timer_enable_counter(TIM(MONITOR_TIMER)); // start timer have the setting take effect (else the first oneshot is too short)
|
||||
|
||||
// probe each channel
|
||||
const char cs[] = {' ', '0', 'X'}; // characters to send
|
||||
bool found = false; // to remember if we found an RX channel
|
||||
printf("probing for UART RX on CH%02u-CH%02u\n", channel_start, channel_stop);
|
||||
while (!timer_get_flag(TIM(MONITOR_TIMER), TIM_SR_UIF)); // wait for oneshot to complete
|
||||
timer_disable_counter(TIM(MONITOR_TIMER)); // ensure the timer if off (should be in one shot)
|
||||
for (uint8_t ch = channel_start; ch <= channel_stop; ch++) { // go through each channel (it might also be the one we are sending from)
|
||||
putc('.');
|
||||
uint8_t success = 0; // count how often the characters has been echoed back
|
||||
for (uint8_t i = 0; i < LENGTH(cs); i++) { // send each character
|
||||
if (wakeup_flag || second_flag) {
|
||||
iwdg_reset(); // kick the dog
|
||||
wakeup_flag = false; // clear flag
|
||||
second_flag = false; // clear flag
|
||||
}
|
||||
mux_select(ch); // select channel to transmit
|
||||
USART_DR(USART(UART_ID)); // empty receive buffer
|
||||
usart_get_flag(USART(UART_ID), USART_SR_TC); // read flag to clear it by writing to DR
|
||||
usart_enhanced_send(USART(UART_ID), cs[i]); // send probing character (also clears TC flag)
|
||||
while (!usart_get_flag(USART(UART_ID), USART_SR_TC)); // wait until transmission completed
|
||||
mux_select(channel); // select channel to receive
|
||||
while (!usart_get_flag(USART(UART_ID), USART_SR_RXNE)); // wait for own echo because we are in half duplex
|
||||
USART_DR(USART(UART_ID)); // empty receive buffer
|
||||
timer_clear_flag(TIM(MONITOR_TIMER), TIM_SR_UIF); // clear timer flag
|
||||
timer_set_counter(TIM(MONITOR_TIMER), 0); // restart counter
|
||||
timer_enable_counter(TIM(MONITOR_TIMER)); // start timer
|
||||
while (!timer_get_flag(TIM(MONITOR_TIMER), TIM_SR_UIF)); // wait until 0.1 second has passed (it could be optimised by checking if data has been received)
|
||||
timer_disable_counter(TIM(MONITOR_TIMER)); // ensure the timer if off (should be in one shot)
|
||||
timer_clear_flag(TIM(MONITOR_TIMER), TIM_SR_UIF); // clear timer flag
|
||||
if (usart_get_flag(USART(UART_ID), USART_SR_RXNE) && cs[i] == usart_enhanced_recv(USART(UART_ID))) { // data has been echoed back
|
||||
success++; // remember data has been echoed back
|
||||
}
|
||||
}
|
||||
if (success > 1) {
|
||||
printf("\nUART RX found on CH%02u\n", ch); // show found channel to user
|
||||
found = true; // remember we found a channel
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
puts("\nUART RX not found");
|
||||
}
|
||||
putc('\n');
|
||||
|
||||
// clean up
|
||||
gpio_set(GPIO_PORT(SHIFT_EN_PIN), GPIO_PIN(SHIFT_EN_PIN)); // remove power from level shifters pull-up
|
||||
gpio_mode_setup(GPIO_PORT(UART_RX), GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN(UART_RX)); // put pin back to safe floating mode
|
||||
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
|
||||
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
|
||||
|
||||
return;
|
||||
command_uart_probe_error:
|
||||
puts("arguments: TX_channel baudrate DatabitsParityStopbits\n");
|
||||
printf("TX_channel: 0-%u\n", CHANNEL_NUMBERS - 1);
|
||||
puts("baudrate: 1200-2000000 (bps)\n");
|
||||
puts("DatabitsParityStopbits: 5-8 databits, N=none/E=even/O=odd/M=mark/S=space, 1-2:stopbits\n");
|
||||
puts("example: 01 115200 8N1\n");
|
||||
}
|
||||
|
||||
/** set first channel of range to scan
|
||||
* @param[in] argument optional pointer to first channel number
|
||||
*/
|
||||
|
@ -1207,6 +1403,14 @@ static const struct menu_command_t menu_commands[] = {
|
|||
.argument_description = "CH",
|
||||
.command_handler = &command_uart_autodetect,
|
||||
},
|
||||
{
|
||||
.shortcut = 'u',
|
||||
.name = "uart_rx",
|
||||
.command_description = "find UART RX pin",
|
||||
.argument = MENU_ARGUMENT_STRING,
|
||||
.argument_description = "TX_CH baudrate DatabitsParityStopbits",
|
||||
.command_handler = &command_uart_probe,
|
||||
},
|
||||
{
|
||||
.shortcut = 'c',
|
||||
.name = "start",
|
||||
|
|
Loading…
Reference in New Issue