parport: add support for the jtag_khz command.

Add the khz and speed_div functions to the parport interface driver.
Add the parport_toggling_time function that tells the parport driver
how long (in nanoseconds) it takes for the hardware to toggle TCK.

[dbrownell@users.sourceforge.net: tweak doc for clarity, mention
multimeter, and whitespace fixes]

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
__archive__
Jonas Horberg 2009-11-12 12:39:37 -08:00 committed by David Brownell
parent 5723e54fa9
commit de735d375b
2 changed files with 100 additions and 8 deletions

View File

@ -1975,6 +1975,42 @@ When using PPDEV to access the parallel port, use the number of the parallel por
you may encounter a problem. you may encounter a problem.
@end deffn @end deffn
@deffn Command {parport_toggling_time} [nanoseconds]
Displays how many nanoseconds the hardware needs to toggle TCK;
the parport driver uses this value to obey the
@command{jtag_khz} configuration.
When the optional @var{nanoseconds} parameter is given,
that setting is changed before displaying the current value.
The default setting should work reasonably well on commodity PC hardware.
However, you may want to calibrate for your specific hardware.
@quotation Tip
To measure the toggling time with a logic analyzer or a digital storage
oscilloscope, follow the procedure below:
@example
> parport_toggling_time 1000
> jtag_khz 500
@end example
This sets the maximum JTAG clock speed of the hardware, but
the actual speed probably deviates from the requested 500 kHz.
Now, measure the time between the two closest spaced TCK transitions.
You can use @command{runtest 1000} or something similar to generate a
large set of samples.
Update the setting to match your measurement:
@example
> parport_toggling_time <measured nanoseconds>
@end example
Now the clock speed will be a better match for @command{jtag_khz rate}
commands given in OpenOCD scripts and event handlers.
You can do something similar with many digital multimeters, but note
that you'll probably need to run the clock continuously for several
seconds before it decides what clock rate to show. Adjust the
toggling time up or down until the measured clock rate is a good
match for the jtag_khz rate you specified; be conservative.
@end quotation
@end deffn
@deffn {Config Command} {parport_write_on_exit} (on|off) @deffn {Config Command} {parport_write_on_exit} (on|off)
This will configure the parallel driver to write a known This will configure the parallel driver to write a known
cable-specific value to the parallel interface on exiting OpenOCD cable-specific value to the parallel interface on exiting OpenOCD

View File

@ -105,6 +105,8 @@ static cable_t cables[] =
static char* parport_cable = NULL; static char* parport_cable = NULL;
static uint16_t parport_port; static uint16_t parport_port;
static int parport_exit = 0; static int parport_exit = 0;
static uint32_t parport_toggling_time_ns = 1000;
static int wait_states;
/* interface variables /* interface variables
*/ */
@ -152,7 +154,7 @@ static __inline__ void parport_write_data(void)
static void parport_write(int tck, int tms, int tdi) static void parport_write(int tck, int tms, int tdi)
{ {
int i = jtag_get_speed() + 1; int i = wait_states + 1;
if (tck) if (tck)
dataport_value |= cable->TCK_MASK; dataport_value |= cable->TCK_MASK;
@ -204,6 +206,26 @@ static void parport_led(int on)
static int parport_speed(int speed) static int parport_speed(int speed)
{ {
wait_states = speed;
return ERROR_OK;
}
static int parport_khz(int khz, int* jtag_speed)
{
if (khz == 0) {
LOG_DEBUG("RCLK not supported");
return ERROR_FAIL;
}
*jtag_speed = 499999 / (khz * parport_toggling_time_ns);
return ERROR_OK;
}
static int parport_speed_div(int speed, int* khz)
{
uint32_t denominator = (speed + 1) * parport_toggling_time_ns;
*khz = (499999 + denominator) / denominator;
return ERROR_OK; return ERROR_OK;
} }
@ -364,6 +386,8 @@ static int parport_init(void)
bitbang_interface = &parport_bitbang; bitbang_interface = &parport_bitbang;
wait_states = jtag_get_speed();
return ERROR_OK; return ERROR_OK;
} }
@ -438,6 +462,32 @@ static int parport_handle_write_on_exit_command(struct command_context_s *cmd_ct
return ERROR_OK; return ERROR_OK;
} }
static int
parport_handle_parport_toggling_time_command(struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc)
{
if (argc == 1) {
uint32_t ns;
int retval = parse_u32(args[0], &ns);
if (ERROR_OK != retval)
return retval;
if (ns == 0) {
LOG_ERROR("0 ns is not a valid parport toggling time");
return ERROR_FAIL;
}
parport_toggling_time_ns = ns;
wait_states = jtag_get_speed();
}
command_print(cmd_ctx, "parport toggling time = %" PRIu32 " ns",
parport_toggling_time_ns);
return ERROR_OK;
}
static int parport_register_commands(struct command_context_s *cmd_ctx) static int parport_register_commands(struct command_context_s *cmd_ctx)
{ {
register_command(cmd_ctx, NULL, "parport_port", register_command(cmd_ctx, NULL, "parport_port",
@ -455,14 +505,20 @@ static int parport_register_commands(struct command_context_s *cmd_ctx)
"configure the parallel driver to write " "configure the parallel driver to write "
"a known value to the parallel interface"); "a known value to the parallel interface");
register_command(cmd_ctx, NULL, "parport_toggling_time",
parport_handle_parport_toggling_time_command, COMMAND_ANY,
"time <ns> it takes for the hardware to toggle TCK");
return ERROR_OK; return ERROR_OK;
} }
jtag_interface_t parport_interface = { jtag_interface_t parport_interface = {
.name = "parport", .name = "parport",
.register_commands = &parport_register_commands, .register_commands = parport_register_commands,
.init = &parport_init, .init = parport_init,
.quit = &parport_quit, .quit = parport_quit,
.speed = &parport_speed, .khz = parport_khz,
.execute_queue = &bitbang_execute_queue, .speed_div = parport_speed_div,
}; .speed = parport_speed,
.execute_queue = bitbang_execute_queue,
};