Skip to content

Commit

Permalink
Merge pull request #114 from davidgiven/fixing1
Browse files Browse the repository at this point in the history
Add support for measuring signal line voltages.
  • Loading branch information
davidgiven authored Dec 10, 2019
2 parents 8ee6eed + 32bb956 commit ed0d578
Show file tree
Hide file tree
Showing 12 changed files with 967 additions and 323 deletions.
584 changes: 292 additions & 292 deletions FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex

Large diffs are not rendered by default.

416 changes: 412 additions & 4 deletions FluxEngine.cydsn/FluxEngine.cyprj

Large diffs are not rendered by default.

Binary file modified FluxEngine.cydsn/TopDesign/TopDesign.cysch
Binary file not shown.
163 changes: 140 additions & 23 deletions FluxEngine.cydsn/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ static void start_motor(void)
CyWdtClear();
}

static void stop_motor(void)
{
if (motor_on)
{
MOTOR_REG_Write(0);
motor_on = false;
}
}

static void wait_until_writeable(int ep)
{
while (USBFS_GetEPState(ep) != USBFS_IN_BUFFER_EMPTY)
Expand Down Expand Up @@ -138,25 +147,36 @@ static void cmd_get_version(struct any_frame* f)

static void step(int dir)
{
STEP_REG_Write(dir);
CyDelayUs(1);
STEP_REG_Write(dir | 2);
CyDelayUs(1);
STEP_REG_Write(dir);
STEP_REG_Write(dir); /* step high */
CyDelayUs(6);
STEP_REG_Write(dir | 2); /* step low */
CyDelayUs(6);
STEP_REG_Write(dir); /* step high again, drive moves now */
CyDelay(STEP_INTERVAL_TIME);
}

static void home(void)
{
for (int i=0; i<100; i++)
{
/* Don't keep stepping forever, because if a drive's
* not connected bad things happen. */
if (TRACK0_REG_Read())
break;
step(STEP_TOWARDS0);
}

/* Step to -1, which should be a nop, to reset the disk on disk change. */
step(STEP_TOWARDS0);
}

static void seek_to(int track)
{
start_motor();
if (!homed)
if (!homed || (track == 0))
{
print("homing");
while (!TRACK0_REG_Read())
step(STEP_TOWARDS0);

/* Step to -1, which should be a nop, to reset the disk on disk change. */
step(STEP_TOWARDS0);
home();

homed = true;
current_track = 0;
Expand All @@ -167,11 +187,7 @@ static void seek_to(int track)
while (track != current_track)
{
if (TRACK0_REG_Read())
{
if (current_track != 0)
print("unexpectedly detected track 0");
current_track = 0;
}

if (track > current_track)
{
Expand Down Expand Up @@ -606,19 +622,113 @@ static void cmd_erase(struct erase_frame* f)
send_reply((struct any_frame*) &r);
}

static void cmd_set_drive(struct set_drive_frame* f)
static void set_drive_flags(uint8_t flags)
{
if (current_drive_flags != f->drive_flags)
{
current_drive_flags = f->drive_flags;
DRIVE_REG_Write(current_drive_flags);
if (current_drive_flags != flags)
homed = false;
}

current_drive_flags = flags;
DRIVESELECT_REG_Write((flags & 1) ? 2 : 1); /* select drive 1 or 0 */
DENSITY_REG_Write(flags >> 1); /* density bit */
}

static void cmd_set_drive(struct set_drive_frame* f)
{
set_drive_flags(f->drive_flags);

DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_SET_DRIVE_REPLY);
send_reply((struct any_frame*) &r);
}


static uint16_t read_output_voltage_mv(void)
{
OUTPUT_VOLTAGE_ADC_StartConvert();
OUTPUT_VOLTAGE_ADC_IsEndConversion(OUTPUT_VOLTAGE_ADC_WAIT_FOR_RESULT);
uint16_t samples = OUTPUT_VOLTAGE_ADC_GetResult16();
return OUTPUT_VOLTAGE_ADC_CountsTo_mVolts(samples);
}

static void read_output_voltages(struct voltages* v)
{
SIDE_REG_Write(1); /* set DIR to low (remember this is inverted) */
CyDelay(100);
v->logic0_mv = read_output_voltage_mv();

SIDE_REG_Write(0);
CyDelay(100);
v->logic1_mv = read_output_voltage_mv();
}

static uint16_t read_input_voltage_mv(void)
{
INPUT_VOLTAGE_ADC_StartConvert();
INPUT_VOLTAGE_ADC_IsEndConversion(INPUT_VOLTAGE_ADC_WAIT_FOR_RESULT);
uint16_t samples = INPUT_VOLTAGE_ADC_GetResult16();
return INPUT_VOLTAGE_ADC_CountsTo_mVolts(samples);
}

static void read_input_voltages(struct voltages* v)
{
home();
CyDelay(50);
v->logic0_mv = read_input_voltage_mv();

step(STEP_AWAYFROM0);
CyDelay(50);
v->logic1_mv = read_input_voltage_mv();
}

static void cmd_measure_voltages(void)
{
stop_motor();
INPUT_VOLTAGE_ADC_Start();
INPUT_VOLTAGE_ADC_SetPower(INPUT_VOLTAGE_ADC__HIGHPOWER);
OUTPUT_VOLTAGE_ADC_Start();
OUTPUT_VOLTAGE_ADC_SetPower(OUTPUT_VOLTAGE_ADC__HIGHPOWER);

DECLARE_REPLY_FRAME(struct voltages_frame, F_FRAME_MEASURE_VOLTAGES_REPLY);

CyWdtClear();
MOTOR_REG_Write(0); /* should be ignored anyway */
DRIVESELECT_REG_Write(0); /* deselect both drives */
CyDelay(200); /* wait for things to settle */
read_output_voltages(&r.output_both_off);
read_input_voltages(&r.input_both_off);

CyWdtClear();
DRIVESELECT_REG_Write(1); /* select drive 0 */
CyDelay(50);
read_output_voltages(&r.output_drive_0_selected);
read_input_voltages(&r.input_drive_0_selected);
MOTOR_REG_Write(1);
CyDelay(300);
CyWdtClear();
read_output_voltages(&r.output_drive_0_running);
read_input_voltages(&r.input_drive_0_running);
MOTOR_REG_Write(0);
CyDelay(300);

CyWdtClear();
DRIVESELECT_REG_Write(2); /* select drive 1 */
CyDelay(50);
read_output_voltages(&r.output_drive_1_selected);
read_input_voltages(&r.input_drive_1_selected);
MOTOR_REG_Write(1);
CyDelay(300);
CyWdtClear();
read_output_voltages(&r.output_drive_1_running);
read_input_voltages(&r.input_drive_1_running);
MOTOR_REG_Write(0);
CyDelay(300);

CyWdtClear();
DRIVESELECT_REG_Write(0);
homed = false;
INPUT_VOLTAGE_ADC_Stop();
OUTPUT_VOLTAGE_ADC_Stop();
send_reply((struct any_frame*) &r);
}

static void handle_command(void)
{
static uint8_t input_buffer[FRAME_SIZE];
Expand Down Expand Up @@ -663,6 +773,10 @@ static void handle_command(void)
case F_FRAME_SET_DRIVE_CMD:
cmd_set_drive((struct set_drive_frame*) f);
break;

case F_FRAME_MEASURE_VOLTAGES_CMD:
cmd_measure_voltages();
break;

default:
send_error(F_ERROR_BAD_COMMAND);
Expand All @@ -677,7 +791,9 @@ int main(void)
INDEX_IRQ_StartEx(&index_irq_cb);
CAPTURE_DMA_FINISHED_IRQ_StartEx(&capture_dma_finished_irq_cb);
SEQUENCER_DMA_FINISHED_IRQ_StartEx(&replay_dma_finished_irq_cb);
DRIVE_REG_Write(0);
INPUT_VOLTAGE_ADC_Stop();
OUTPUT_VOLTAGE_ADC_Stop();
DRIVESELECT_REG_Write(0);
UART_Start();
USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);

Expand Down Expand Up @@ -710,6 +826,7 @@ int main(void)

if (USBFS_GetEPState(FLUXENGINE_CMD_OUT_EP_NUM) == USBFS_OUT_BUFFER_FULL)
{
set_drive_flags(current_drive_flags);
handle_command();
USBFS_EnableOutEP(FLUXENGINE_CMD_OUT_EP_NUM);
print("idle");
Expand Down
7 changes: 5 additions & 2 deletions doc/using.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ In order to do anything useful, you have to plug it in to a floppy disk drive (o
rpm for a 3.5" disk, or 360 rpm for a 5.25" disk. If it doesn't, please
[get in touch](https://github.com/davidgiven/fluxengine/issues/new).

7. Do `fluxengine testbulktransport` from the shell. It'll measure your USB
7. Do `fluxengine test bulktransport` from the shell. It'll measure your USB
bandwidth. Ideally you should be getting above 900kB/s. FluxEngine needs
about 850kB/s, so if you're getting less than this, try a different USB
port.
Expand Down Expand Up @@ -213,10 +213,13 @@ directory.
- `fluxengine seek`: moves the head. Mainly useful for finding out whether
your drive can seek to track 82. (Mine can't.)
- `fluxengine testbulktransport`: measures your USB throughput. You need
- `fluxengine test bulktransport`: measures your USB throughput. You need
about 600kB/s for FluxEngine to work. You don't need a disk in the drive
for this one.
- `fluxengine test voltages`: measures your FDD bus signal voltages, which
is useful for testing for termination issues.
- `fluxengine upgradefluxfile`: occasionally I need to upgrade the flux
file format in a non-backwards-compatible way; this tool will upgrade flux
files to the new format.
Expand Down
34 changes: 34 additions & 0 deletions lib/usb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,37 @@ void usbSetDrive(int drive, bool high_density)
await_reply<struct any_frame>(F_FRAME_SET_DRIVE_REPLY);
}

/* Hacky: the board always operates in little-endian mode. */
static uint16_t read_short_from_usb(uint16_t usb)
{
uint8_t* p = (uint8_t*)&usb;
return p[0] | (p[1] << 8);
}

static void convert_voltages_from_usb(const struct voltages& vin, struct voltages& vout)
{
vout.logic0_mv = read_short_from_usb(vin.logic0_mv);
vout.logic1_mv = read_short_from_usb(vin.logic1_mv);
}

void usbMeasureVoltages(struct voltages_frame* voltages)
{
usb_init();

struct any_frame f = {
{ .type = F_FRAME_MEASURE_VOLTAGES_CMD, .size = sizeof(f) },
};
usb_cmd_send(&f, f.f.size);

struct voltages_frame* r = await_reply<struct voltages_frame>(F_FRAME_MEASURE_VOLTAGES_REPLY);
convert_voltages_from_usb(r->input_both_off, voltages->input_both_off);
convert_voltages_from_usb(r->input_drive_0_selected, voltages->input_drive_0_selected);
convert_voltages_from_usb(r->input_drive_1_selected, voltages->input_drive_1_selected);
convert_voltages_from_usb(r->input_drive_0_running, voltages->input_drive_0_running);
convert_voltages_from_usb(r->input_drive_1_running, voltages->input_drive_1_running);
convert_voltages_from_usb(r->output_both_off, voltages->output_both_off);
convert_voltages_from_usb(r->output_drive_0_selected, voltages->output_drive_0_selected);
convert_voltages_from_usb(r->output_drive_1_selected, voltages->output_drive_1_selected);
convert_voltages_from_usb(r->output_drive_0_running, voltages->output_drive_0_running);
convert_voltages_from_usb(r->output_drive_1_running, voltages->output_drive_1_running);
}
1 change: 1 addition & 0 deletions lib/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ extern Bytes usbRead(int side, int revolutions);
extern void usbWrite(int side, const Bytes& bytes);
extern void usbErase(int side);
extern void usbSetDrive(int drive, bool high_density);
extern void usbMeasureVoltages(struct voltages_frame* voltages);

#endif
1 change: 1 addition & 0 deletions mkninja.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ buildlibrary libfrontend.a \
src/fe-scptoflux.cc \
src/fe-seek.cc \
src/fe-testbulktransport.cc \
src/fe-testvoltages.cc \
src/fe-upgradefluxfile.cc \
src/fe-writebrother.cc \
src/fe-writeflux.cc \
Expand Down
23 changes: 23 additions & 0 deletions protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ enum
F_FRAME_RECALIBRATE_REPLY, /* any_frame */
F_FRAME_SET_DRIVE_CMD, /* setdrive_frame */
F_FRAME_SET_DRIVE_REPLY, /* any_frame */
F_FRAME_MEASURE_VOLTAGES_CMD, /* any_frame */
F_FRAME_MEASURE_VOLTAGES_REPLY, /* voltages_frame */
};

enum
Expand Down Expand Up @@ -146,4 +148,25 @@ struct set_drive_frame
uint8_t drive_flags;
};

struct voltages
{
uint16_t logic0_mv;
uint16_t logic1_mv;
};

struct voltages_frame
{
struct frame_header f;
struct voltages output_both_off;
struct voltages output_drive_0_selected;
struct voltages output_drive_1_selected;
struct voltages output_drive_0_running;
struct voltages output_drive_1_running;
struct voltages input_both_off;
struct voltages input_drive_0_selected;
struct voltages input_drive_1_selected;
struct voltages input_drive_0_running;
struct voltages input_drive_1_running;
};

#endif
1 change: 0 additions & 1 deletion src/fe-readmx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "sector.h"
#include "sectorset.h"
#include "record.h"
#include <fmt/format.h>

static FlagGroup flags { &readerFlags };

Expand Down
47 changes: 47 additions & 0 deletions src/fe-testvoltages.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "globals.h"
#include "flags.h"
#include "usb.h"
#include "protocol.h"
#include <fmt/format.h>

static FlagGroup flags;

static std::string display_voltages(struct voltages& v)
{
return fmt::format(
" Logic 1 / 0: {:.2f}V / {:.2f}V\n",
v.logic0_mv / 1000.0,
v.logic1_mv / 1000.0);
}

int mainTestVoltages(int argc, const char* argv[])
{
flags.parseFlags(argc, argv);
struct voltages_frame f;
usbMeasureVoltages(&f);

std::cout << "Output voltages:\n"
<< " Both drives deselected\n"
<< display_voltages(f.output_both_off)
<< " Drive 0 selected\n"
<< display_voltages(f.output_drive_0_selected)
<< " Drive 1 selected\n"
<< display_voltages(f.output_drive_1_selected)
<< " Drive 0 running\n"
<< display_voltages(f.output_drive_0_running)
<< " Drive 1 running\n"
<< display_voltages(f.output_drive_1_running)
<< "Input voltages:\n"
<< " Both drives deselected\n"
<< display_voltages(f.input_both_off)
<< " Drive 0 selected\n"
<< display_voltages(f.input_drive_0_selected)
<< " Drive 1 selected\n"
<< display_voltages(f.input_drive_1_selected)
<< " Drive 0 running\n"
<< display_voltages(f.input_drive_0_running)
<< " Drive 1 running\n"
<< display_voltages(f.input_drive_1_running);

return 0;
}
Loading

0 comments on commit ed0d578

Please sign in to comment.