Skip to content

Instantly share code, notes, and snippets.

@jkominek
Created June 14, 2024 18:31
Show Gist options
  • Save jkominek/a812b2b3c37d7ded47e8143c54de4c1f to your computer and use it in GitHub Desktop.
Save jkominek/a812b2b3c37d7ded47e8143c54de4c1f to your computer and use it in GitHub Desktop.
FTDI 232H synchronous mode Verilog + libftdi1 example code
module bytegen(input clk,
input clkout,
input txe,
output reg [7:0] outdata,
output reg wrb,
output siwu,
output [7:0] led);
reg [19:0] counter = 20'b0;
assign siwu = 1'b1;
reg [2:0] state = 0;
parameter Waiting=0, StrobeWRB=1, Finish=2;
// we're writing at 1/3 of the ftdi's 60MHz clock
// you need some smarter logic than this to get the
// full speed, but this seems to be more reliable
// than async mode, and is more than fast enough for
// my needs.
always @(negedge clkout)
begin
casez(state)
Waiting:
begin
if(~txe)
begin
outdata <= counter[7:0];
state <= StrobeWRB;
end
end
StrobeWRB:
begin
wrb <= 1'b0;
state <= Finish;
end
Finish:
begin
wrb <= 1'b1;
counter <= counter+1;
state <= Waiting;
end
endcase
end
// stuff that was useful at some point in development
assign led[0] = txe;
assign led[1] = wrb;
assign led[6:2] = 5'b0;
assign led[7] = counter[19];
endmodule // bytegen
// started from the libftdi1 example, which was... suspect at best
// this is all targetted at the FTDI 232H. no guarantee for anything else.
// c++ stream_dump.c -o stream_dump `pkg-config --cflags --libs libftdi1`
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <ftdi.h>
// yeah we're c++ now. i'm too lazy
#include <chrono>
int main(int argc, char **argv)
{
struct ftdi_context *ftdi;
int err;
char *descstring = NULL;
if ((ftdi = ftdi_new()) == 0)
{
fprintf(stderr, "ftdi_new failed\n");
return EXIT_FAILURE;
}
if (ftdi_set_interface(ftdi, INTERFACE_A) < 0)
{
fprintf(stderr, "ftdi_set_interface failed\n");
ftdi_free(ftdi);
return EXIT_FAILURE;
}
if (ftdi_usb_open_desc(ftdi, 0x0403, 0x6014, descstring, NULL) < 0)
{
fprintf(stderr,"Can't open ftdi device: %s\n",ftdi_get_error_string(ftdi));
ftdi_free(ftdi);
return EXIT_FAILURE;
}
if (ftdi_set_bitmode(ftdi, 0xff, 0x00) < 0)
{
fprintf(stderr,"Can't reset fifo mode, Error %s\n",ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
// i've seen this mentioned but i suspect it isn't useful
sleep(1);
// this is the magic that flips FT245 async mode into sync mode
if (ftdi_set_bitmode(ftdi, 0xff, 0x40) < 0)
{
fprintf(stderr,"Can't set synchronous fifo mode, Error %s\n",ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
// no idea if this accomplishes anything
if(ftdi_set_latency_timer(ftdi, 2))
{
fprintf(stderr,"Can't set latency, Error %s\n",ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
// pretty sure this doesn't accomplish anything
if(ftdi_setflowctrl(ftdi, SIO_RTS_CTS_HS))
{
fprintf(stderr,"failed to adjust flow control %s\n", ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
// ftdi_streamread seems to be junk, this is a ftdi_read_data loop
// we're both measuring the rate at which we read data, and checking
// to make sure that we're not dropping bytes.
uint8_t previous = 0;
uint32_t processed = 0;
uint32_t mark = 0;
auto start = std::chrono::high_resolution_clock::now();
while(1) {
uint8_t buffer[4096];
int length = ftdi_read_data(ftdi, buffer, 4096);
auto now = std::chrono::high_resolution_clock::now();
if (length < 0) {
fprintf(stderr, "ftdi_read_data error %i %s\n", length, ftdi_get_error_string(ftdi));
exit(1);
}
for(int i=0; i<length; i++) {
if( ((previous+1)%256) != buffer[i] )
printf("mismatch %i %i\n", previous, buffer[i]);
previous = buffer[i];
}
processed += length;
if(processed > (mark * 1024 * 1024)) {
std::chrono::duration<float> diff = now - start;
printf("processed %i / %.2f = %.3fMB/s\n", processed, diff.count(), (processed/diff.count())/(1024*1024));
mark += 1;
}
}
// put it back to the original state? sure why not
if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0)
{
fprintf(stderr,"Can't reset fifo mode, Error %s\n",ftdi_get_error_string(ftdi));
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
ftdi_usb_close(ftdi);
ftdi_free(ftdi);
exit (0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment