📄 ft2232.c
字号:
cx_cmd_push( cmd_root, SET_BITS_LOW ); cx_cmd_push( cmd_root, BITMASK_SIGNALYZER_nTRST | BITMASK_SIGNALYZER_nSRST ); cx_cmd_push( cmd_root, 0 ); /* Set Data Bits High Byte disable output drivers */ cx_cmd_push( cmd_root, SET_BITS_HIGH ); cx_cmd_push( cmd_root, BITMASK_SIGNALYZER_nTRST | BITMASK_SIGNALYZER_nSRST ); cx_cmd_push( cmd_root, BITMASK_SIGNALYZER_nTRST | BITMASK_SIGNALYZER_nSRST ); /* Set Data Bits High Byte set all to input */ cx_cmd_push( cmd_root, SET_BITS_HIGH ); cx_cmd_push( cmd_root, 0 ); cx_cmd_push( cmd_root, 0 ); cx_xfer( cmd_root, &imm_cmd, cable, COMPLETELY ); generic_usbconn_done( cable );}static voidft2232_clock_schedule( cable_t *cable, int tms, int tdi, int n ){ params_t *params = (params_t *)cable->params; cx_cmd_root_t *cmd_root = &(params->cmd_root); tms = tms ? 0x7f : 0; tdi = tdi ? 1 << 7 : 0; cx_cmd_queue( cmd_root, 0 ); while (n > 0) { /* Clock Data to TMS/CS Pin (no Read) */ cx_cmd_push( cmd_root, MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG ); if (n <= 7) { cx_cmd_push( cmd_root, n-1 ); n = 0; } else { cx_cmd_push( cmd_root, 7-1 ); n -= 7; } cx_cmd_push( cmd_root, tdi | tms ); }}static voidft2232_clock( cable_t *cable, int tms, int tdi, int n ){ params_t *params = (params_t *)cable->params; ft2232_clock_schedule( cable, tms, tdi, n ); cx_xfer( &(params->cmd_root), &imm_cmd, cable, COMPLETELY ); params->last_tdo_valid = 0;}static voidft2232_get_tdo_schedule( cable_t *cable ){ params_t *params = (params_t *)cable->params; cx_cmd_root_t *cmd_root = &(params->cmd_root); /* Read Data Bits Low Byte */ cx_cmd_queue( cmd_root, 1 ); cx_cmd_push( cmd_root, GET_BITS_LOW );}static intft2232_get_tdo_finish( cable_t *cable ){ params_t *params = (params_t *)cable->params; int value; value = ( cx_xfer_recv( cable ) & BITMASK_TDO) ? 1 : 0; params->last_tdo = value; params->last_tdo_valid = 1; return value;}static intft2232_get_tdo( cable_t *cable ){ params_t *params = (params_t *)cable->params; ft2232_get_tdo_schedule( cable ); cx_xfer( &(params->cmd_root), &imm_cmd, cable, COMPLETELY ); return ft2232_get_tdo_finish( cable );}static voidft2232_set_trst_schedule( params_t *params, int trst ){ cx_cmd_root_t *cmd_root = &(params->cmd_root); cx_cmd_queue( cmd_root, 0 ); cx_cmd_push( cmd_root, SET_BITS_HIGH ); cx_cmd_push( cmd_root, trst == 0 ? params->high_byte_value_trst_active : params->high_byte_value_trst_inactive ); cx_cmd_push( cmd_root, params->high_byte_dir );}static intft2232_set_trst( cable_t *cable, int trst ){ params_t *params = (params_t *)cable->params; ft2232_set_trst_schedule( params, trst ); cx_xfer( &(params->cmd_root), &imm_cmd, cable, COMPLETELY ); params->last_tdo_valid = 0; return trst;}static voidft2232_transfer_schedule( cable_t *cable, int len, char *in, char *out ){ params_t *params = (params_t *)cable->params; cx_cmd_root_t *cmd_root = &(params->cmd_root); int in_offset = 0; int bitwise_len; int chunkbytes; /* Set Data Bits Low Byte to lower TMS for transfer TCK = 0, TMS = 0, TDI = 0, nOE = 0 */ cx_cmd_queue( cmd_root, 0 ); cx_cmd_push( cmd_root, SET_BITS_LOW ); cx_cmd_push( cmd_root, params->low_byte_value | 0 ); cx_cmd_push( cmd_root, params->low_byte_dir | BITMASK_TCK | BITMASK_TDI | BITMASK_TMS ); chunkbytes = len >> 3; while (chunkbytes > 0) { int byte_idx; /* reduce chunkbytes to the maximum amount we can receive in one step */ if (out && chunkbytes > FTDX_MAXRECV) chunkbytes = FTDX_MAXRECV; /* restrict chunkbytes to the maximum amount that can be transferred for one single operation */ if (chunkbytes > (1 << 16)) chunkbytes = 1 << 16; /*********************************************************************** * Step 1: * Determine data shifting command (bytewise). * Either with or without read ***********************************************************************/ if (out) { cx_cmd_queue( cmd_root, chunkbytes ); /* Clock Data Bytes In and Out LSB First out on negative edge, in on positive edge */ cx_cmd_push( cmd_root, MPSSE_DO_READ | MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_WRITE_NEG ); } else { cx_cmd_queue( cmd_root, 0 ); /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ cx_cmd_push( cmd_root, MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_WRITE_NEG ); } /* set byte count */ cx_cmd_push( cmd_root, (chunkbytes - 1) & 0xff ); cx_cmd_push( cmd_root, ((chunkbytes - 1) >> 8) & 0xff ); /********************************************************************* * Step 2: * Write TDI data in bundles of 8 bits. *********************************************************************/ for (byte_idx = 0; byte_idx < chunkbytes; byte_idx++) { int bit_idx; unsigned char b = 0; for (bit_idx = 1; bit_idx < 256; bit_idx <<= 1) if (in[in_offset++]) b |= bit_idx; cx_cmd_push( cmd_root, b ); } /* recalc chunkbytes for next round */ chunkbytes = (len - in_offset) >> 3; } /* determine bitwise shift amount */ bitwise_len = (len - in_offset) % 8; if (bitwise_len > 0) { /*********************************************************************** * Step 3: * Determine data shifting command (bitwise). * Either with or without read ***********************************************************************/ if (out) { cx_cmd_queue( cmd_root, 1 ); /* Clock Data Bytes In and Out LSB First out on negative edge, in on positive edge */ cx_cmd_push( cmd_root, MPSSE_DO_READ | MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG ); } else { cx_cmd_queue( cmd_root, 0 ); /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ cx_cmd_push( cmd_root, MPSSE_DO_WRITE | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG ); } /* determine bit count */ cx_cmd_push( cmd_root, bitwise_len - 1 ); /*********************************************************************** * Step 4: * Write TDI data bitwise ***********************************************************************/ { int bit_idx; unsigned char b = 0; for (bit_idx = 1; bit_idx <= 1 << bitwise_len; bit_idx <<= 1) { if (in[in_offset++]) b |= bit_idx; } cx_cmd_push( cmd_root, b ); } } if (out) { /* Read Data Bits Low Byte to get current TDO, Do this only if we'll read out data nonetheless */ cx_cmd_queue( cmd_root, 1 ); cx_cmd_push( cmd_root, GET_BITS_LOW ); params->last_tdo_valid = 1; } else params->last_tdo_valid = 0;}static intft2232_transfer_finish( cable_t *cable, int len, char *out ){ params_t *params = (params_t *)cable->params; int bitwise_len; int chunkbytes; int out_offset = 0; chunkbytes = len >> 3; bitwise_len = len % 8; if (out) { if (chunkbytes > 0) { uint32_t xferred; /********************************************************************* * Step 5: * Read TDO data in bundles of 8 bits if read is requested. *********************************************************************/ xferred = chunkbytes; for (; xferred > 0; xferred--) { int bit_idx; unsigned char b; b = cx_xfer_recv( cable ); for (bit_idx = 1; bit_idx < 256; bit_idx <<= 1) out[out_offset++] = (b & bit_idx) ? 1 : 0; } } if (bitwise_len > 0) { /*********************************************************************** * Step 6: * Read TDO data bitwise if read is requested. ***********************************************************************/ int bit_idx; unsigned char b; b = cx_xfer_recv( cable ); for (bit_idx = (1 << (8 - bitwise_len)); bit_idx < 256; bit_idx <<= 1) out[out_offset++] = (b & bit_idx) ? 1 : 0; } /* gather current TDO */ params->last_tdo = ( cx_xfer_recv( cable ) & BITMASK_TDO) ? 1 : 0; params->last_tdo_valid = 1; } else params->last_tdo_valid = 0; return 0;}static intft2232_transfer( cable_t *cable, int len, char *in, char *out ){ params_t *params = (params_t *)cable->params; ft2232_transfer_schedule( cable, len, in, out ); cx_xfer( &(params->cmd_root), &imm_cmd, cable, COMPLETELY ); return ft2232_transfer_finish( cable, len, out );}static voidft2232_flush( cable_t *cable, cable_flush_amount_t how_much ){ params_t *params = (params_t *)cable->params; if (how_much == OPTIONALLY) return; if (cable->todo.num_items == 0) cx_xfer( &(params->cmd_root), &imm_cmd, cable, how_much ); while (cable->todo.num_items > 0) { int i, j, n; int last_tdo_valid_schedule = params->last_tdo_valid; int last_tdo_valid_finish = params->last_tdo_valid; for (j = i = cable->todo.next_item, n = 0; n < cable->todo.num_items; n++) { switch (cable->todo.data[i].action) { case CABLE_CLOCK: ft2232_clock_schedule( cable, cable->todo.data[i].arg.clock.tms, cable->todo.data[i].arg.clock.tdi, cable->todo.data[i].arg.clock.n ); last_tdo_valid_schedule = 0; break; case CABLE_GET_TDO: if (!last_tdo_valid_schedule) { ft2232_get_tdo_schedule( cable ); last_tdo_valid_schedule = 1; } break; case CABLE_SET_TRST: ft2232_set_trst_schedule( params, cable->todo.data[i].arg.value.trst ); last_tdo_valid_schedule = 0; break; case CABLE_TRANSFER: ft2232_transfer_schedule( cable, cable->todo.data[i].arg.transfer.len, cable->todo.data[i].arg.transfer.in, cable->todo.data[i].arg.transfer.out ); last_tdo_valid_schedule = params->last_tdo_valid; break; default: break; } i++; if (i >= cable->todo.max_items) i = 0; } cx_xfer( &(params->cmd_root), &imm_cmd, cable, how_much ); while (j != i) { switch (cable->todo.data[j].action) { case CABLE_CLOCK: params->last_tdo_valid = last_tdo_valid_finish = 0; break; case CABLE_GET_TDO: { int tdo; int m; if (last_tdo_valid_finish) tdo = params->last_tdo; else tdo = ft2232_get_tdo_finish( cable ); last_tdo_valid_finish = params->last_tdo_valid; m = cable_add_queue_item( cable, &(cable->done) ); cable->done.data[m].action = CABLE_GET_TDO; cable->done.data[m].arg.value.tdo = tdo; break; } case CABLE_SET_TRST: { int m = cable_add_queue_item( cable, &(cable->done) ); cable->done.data[m].action = CABLE_SET_TRST; cable->done.data[m].arg.value.trst = cable->done.data[j].arg.value.trst;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -