Created
June 14, 2024 18:31
-
-
Save jkominek/a812b2b3c37d7ded47e8143c54de4c1f to your computer and use it in GitHub Desktop.
FTDI 232H synchronous mode Verilog + libftdi1 example code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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