clkdiv: added clkdiv
authorAlan Green <avg@google.com>
Mon, 14 Sep 2020 07:30:33 +0000 (17:30 +1000)
committerAlan Green <avg@google.com>
Mon, 14 Sep 2020 07:50:30 +0000 (17:50 +1000)
This change allows arbitrary divider values to be used for the 6MHz FTDI
SPI/JTAG clock.

I find that, on the Lattice NX Evaluation Board, the FTDI clock divider
needs to be set to a value of 3 or higher in order to program the flash
rom. This may be because the board uses an ES (Early Silicon/Engineering
Sample) CrossLink/NX-40. I see similar behavior with the Radiant
programmer where a divisor of 2 or higher is needed.

With a slower clock divider, ecpprog is also able to verify programmed
flash rom content.

ecpprog/ecpprog.c
ecpprog/jtag.h
ecpprog/jtag_tap.c
ecpprog/mpsse.c
ecpprog/mpsse.h

index f366e9b6b4a868b3bf132bea2b6e03bb457f5a8a..eba15e4044b20c6f8d013a8a84b372b2b876db40 100644 (file)
@@ -631,7 +631,10 @@ static void help(const char *progname)
        fprintf(stderr, "  -o <offset in bytes>  start address for read/write [default: 0]\n");
        fprintf(stderr, "                          (append 'k' to the argument for size in kilobytes,\n");
        fprintf(stderr, "                          or 'M' for size in megabytes)\n");
-       fprintf(stderr, "  -s                    slow SPI (50 kHz instead of 6 MHz)\n");
+       fprintf(stderr, "  -k <divider>          divider for SPI clock [default: 1]\n");
+       fprintf(stderr, "                          clock speed is 6MHz/divider");
+       fprintf(stderr, "  -s                    slow SPI. (50 kHz instead of 6 MHz)\n");
+       fprintf(stderr, "                          Equivalent to -k 30\n");
        fprintf(stderr, "  -v                    verbose output\n");
        fprintf(stderr, "  -i [4,32,64]          select erase block size [default: 64k]\n");
        fprintf(stderr, "\n");
@@ -685,6 +688,7 @@ int main(int argc, char **argv)
        int erase_block_size = 64;
        int erase_size = 0;
        int rw_offset = 0;
+       int clkdiv = 1;
 
        bool read_mode = false;
        bool check_mode = false;
@@ -693,7 +697,6 @@ int main(int argc, char **argv)
        bool dont_erase = false;
        bool prog_sram = false;
        bool test_mode = false;
-       bool slow_clock = false;
        bool disable_protect = false;
        bool disable_verify = false;
        const char *filename = NULL;
@@ -713,7 +716,7 @@ int main(int argc, char **argv)
        /* Decode command line parameters */
        int opt;
        char *endptr;
-       while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:cbnStvspX", long_options, NULL)) != -1) {
+       while ((opt = getopt_long(argc, argv, "d:i:I:rR:e:o:k:scbnStvpX", long_options, NULL)) != -1) {
                switch (opt) {
                case 'd': /* device string */
                        devstr = optarg;
@@ -788,6 +791,16 @@ int main(int argc, char **argv)
                                return EXIT_FAILURE;
                        }
                        break;
+               case 'k': /* set clock div */
+                       clkdiv = strtol(optarg, &endptr, 0);
+                        if (clkdiv < 1 || clkdiv > 65536) {
+                               fprintf(stderr, "%s: clock divider must be in range 1-65536 `%s' is not a valid divider\n", my_name, optarg);
+                               return EXIT_FAILURE;
+                        }
+                       break;
+               case 's': /* use slow SPI clock */
+                       clkdiv = 30;
+                       break;
                case 'c': /* do not write just check */
                        check_mode = true;
                        break;
@@ -806,9 +819,6 @@ int main(int argc, char **argv)
                case 'v': /* provide verbose output */
                        verbose = true;
                        break;
-               case 's': /* use slow SPI clock */
-                       slow_clock = true;
-                       break;
                case 'p': /* disable flash protect before erase/write */
                        disable_protect = true;
                        break;
@@ -965,7 +975,7 @@ int main(int argc, char **argv)
        // ---------------------------------------------------------
 
        fprintf(stderr, "init..\n");
-       jtag_init(ifnum, devstr, slow_clock);
+       jtag_init(ifnum, devstr, clkdiv);
 
        read_idcode();
        read_status_register();
index 51caa9d2eaddcd607c1558c47962d5ce3aa8198c..ce41925e031fc3793b44f8c92c5f1b9dd8e25780 100644 (file)
@@ -34,7 +34,7 @@ typedef enum e_TAPState
 /**
  * Performs the start-of-day tasks necessary to talk JTAG to our FPGA.
  */
-void jtag_init(int ifnum, const char *devstr, bool slow_clock);
+void jtag_init(int ifnum, const char *devstr, int clkdiv);
 
 
 /**
index 43bb0628375714b32b546da80e9fb7f0a191d305..17f4bfd1c8884fb1c41f0a0b88c52640a3a18ecb 100644 (file)
@@ -130,9 +130,9 @@ void jtag_deinit(){
 /**
  * Performs any start-of-day tasks necessary to talk JTAG to our FPGA.
  */
-void jtag_init(int ifnum, const char *devstr, bool slow_clock)
+void jtag_init(int ifnum, const char *devstr, int clkdiv)
 {
-       mpsse_init(ifnum, devstr, slow_clock);
+       mpsse_init(ifnum, devstr, clkdiv);
 
        jtag_set_current_state(STATE_TEST_LOGIC_RESET);
     jtag_go_to_state(STATE_TEST_LOGIC_RESET);
@@ -200,9 +200,6 @@ static void jtag_shift_bytes(
        }
        //printf("jtag_shift_bytes(0x%08x,0x%08x,%u,%s);\n",input_data, output_data, data_bits, must_end ? "true" : "false");
        uint32_t byte_count = data_bits / 8;
-
-
-
        data[0] = MC_DATA_OUT | MC_DATA_IN | MC_DATA_LSB | MC_DATA_OCN;
        data[1] = (byte_count - 1); 
        data[2] = (byte_count - 1) >> 8;        
index df93e19a4919e98cfe6f78a4b57d4fa75d065b62..339df7e4b4389148ee3e5ea951223d2c21b7a420 100644 (file)
@@ -140,7 +140,7 @@ void mpsse_xfer(uint8_t* data_buffer, uint16_t send_length, uint16_t receive_len
        }
 }
 
-void mpsse_init(int ifnum, const char *devstr, bool slow_clock)
+void mpsse_init(int ifnum, const char *devstr, int clkdiv)
 {
        enum ftdi_interface ftdi_ifnum = INTERFACE_A;
 
@@ -216,17 +216,10 @@ void mpsse_init(int ifnum, const char *devstr, bool slow_clock)
 
        mpsse_send_byte(MC_TCK_X5);
 
-       if (slow_clock) {
-               // set 50 kHz clock
-               mpsse_send_byte(MC_SET_CLK_DIV);
-               mpsse_send_byte(29);
-               mpsse_send_byte(0x00);
-       } else {
-               // set 6 MHz clock
-               mpsse_send_byte(MC_SET_CLK_DIV);
-               mpsse_send_byte(1);
-               mpsse_send_byte(0x00);
-       }
+        // set clock - actual clock is 6MHz/(clkdiv)
+        mpsse_send_byte(MC_SET_CLK_DIV);
+        mpsse_send_byte((clkdiv-1) & 0xff);
+        mpsse_send_byte((clkdiv-1) >> 8);
 
        mpsse_send_byte(MC_SETB_LOW);
        mpsse_send_byte(0x08); /* Value */
@@ -239,4 +232,4 @@ void mpsse_close(void)
        ftdi_disable_bitbang(&mpsse_ftdic);
        ftdi_usb_close(&mpsse_ftdic);
        ftdi_deinit(&mpsse_ftdic);
-}
\ No newline at end of file
+}
index e10601a330dd0e3fc0d0d3a99a189a395e02b9d4..2fa6f701ab7abc7992cd8c15eb8e94c692eb9519 100644 (file)
@@ -113,7 +113,7 @@ int mpsse_readb_low(void);
 int mpsse_readb_high(void);
 void mpsse_send_dummy_bytes(uint8_t n);
 void mpsse_send_dummy_bit(void);
-void mpsse_init(int ifnum, const char *devstr, bool slow_clock);
+void mpsse_init(int ifnum, const char *devstr, int clkdiv);
 void mpsse_close(void);
 
 #endif /* MPSSE_H */