parport: add support for the jtag_khz command.
authorJonas Horberg <jhorberg@sauer-danfoss.com>
Thu, 12 Nov 2009 20:39:37 +0000 (12:39 -0800)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Thu, 12 Nov 2009 20:39:37 +0000 (12:39 -0800)
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>
doc/openocd.texi
src/jtag/parport.c

index 475482df9c92d5a1dcdc6117f52aa5a920a35b00..8547fda4d8cf2630ab4450c0546d30bdd7c8748e 100644 (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.
 @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)
 This will configure the parallel driver to write a known
 cable-specific value to the parallel interface on exiting OpenOCD
index fdf7df4da0de60a4bc31c1010f8f77f60ae6c146..9b20290237e87e5f6b4f3aa84e989d758807b852 100644 (file)
@@ -105,6 +105,8 @@ static cable_t cables[] =
 static char* parport_cable = NULL;
 static uint16_t parport_port;
 static int parport_exit = 0;
+static uint32_t parport_toggling_time_ns = 1000;
+static int wait_states;
 
 /* interface variables
  */
@@ -152,7 +154,7 @@ static __inline__ void parport_write_data(void)
 
 static void parport_write(int tck, int tms, int tdi)
 {
-       int i = jtag_get_speed() + 1;
+       int i = wait_states + 1;
 
        if (tck)
                dataport_value |= cable->TCK_MASK;
@@ -204,6 +206,26 @@ static void parport_led(int on)
 
 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;
 }
 
@@ -364,6 +386,8 @@ static int parport_init(void)
 
        bitbang_interface = &parport_bitbang;
 
+       wait_states = jtag_get_speed();
+
        return ERROR_OK;
 }
 
@@ -438,6 +462,32 @@ static int parport_handle_write_on_exit_command(struct command_context_s *cmd_ct
        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)
 {
        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 "
                        "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;
 }
 
 jtag_interface_t parport_interface = {
-               .name = "parport",
-               .register_commands = &parport_register_commands,
-               .init = &parport_init,
-               .quit = &parport_quit,
-               .speed = &parport_speed,
-               .execute_queue = &bitbang_execute_queue,
-       };
+       .name =                 "parport",
+       .register_commands =    parport_register_commands,
+       .init =                 parport_init,
+       .quit =                 parport_quit,
+       .khz =                  parport_khz,
+       .speed_div =            parport_speed_div,
+       .speed =                parport_speed,
+       .execute_queue =        bitbang_execute_queue,
+};