Skip to content

Commit

Permalink
FF.CFG: New option 'motor-delay = ignore | 0-1000'
Browse files Browse the repository at this point in the history
Allows to enable processing of MOTOR input signal, and modify
READY and INDEX output behaviours accordingly.

RDATA does not respect MOTOR: Probably noone cares.
  • Loading branch information
keirf committed May 17, 2019
1 parent 6f8016e commit bf36c6c
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -86,7 +86,7 @@ all:
endif

BAUD=115200
DEV=/dev/ttyUSB0
DEV=/dev/ttyUSB1

flash:
sudo stm32flash -b $(BAUD) -w FF_Gotek-$(VER).hex $(DEV)
Expand Down
1 change: 1 addition & 0 deletions attic/pins.txt
Expand Up @@ -8,6 +8,7 @@ GPIn: (all must be 5v tolerant, *=not)
PB9 WGATE
PB4 SIDE
PA15 MOTOR [Enhanced Boards only]
PB15 MOTOR [Standard board mod: pin 5 of SPI Flash footprint]
GPOut:
PB7 CHNG
PB8 INDEX
Expand Down
7 changes: 7 additions & 0 deletions examples/FF.CFG
Expand Up @@ -73,6 +73,13 @@ index-suppression = yes
# Values: 0 <= N <= 255
head-settle-ms = 12

# Milliseconds delay from motor-on to drive ready.
# On a standard unmodified Gotek the motor signal is not connected and a
# non-default value here will have no effect. Most systems and software do
# not care about correct motor behaviour, and default (ignore) works fine.
# Values: ignore | 0 <= N <= 1000
motor-delay = ignore

##
## STARTUP / INITIALISATION

Expand Down
2 changes: 2 additions & 0 deletions inc/config.h
Expand Up @@ -134,6 +134,8 @@ struct __packed ff_cfg {
#define SORT_always 1
#define SORT_small 2
uint8_t folder_sort;
#define MOTOR_ignore 0xff
uint8_t motor_delay; /* / 10ms */
};

extern struct ff_cfg ff_cfg;
Expand Down
1 change: 1 addition & 0 deletions inc/floppy.h
Expand Up @@ -246,6 +246,7 @@ struct track_info {
};
void floppy_get_track(struct track_info *ti);
void floppy_set_fintf_mode(void);
void floppy_set_motor_delay(void);

/*
* Local variables:
Expand Down
5 changes: 5 additions & 0 deletions scripts/mk_config.py
Expand Up @@ -59,6 +59,11 @@ def main(argv):
val = "NAVMODE_" + val
elif opt == "folder-sort":
val = "SORT_" + val
elif opt == "motor-delay":
if val == 'ignore':
val = "MOTOR_" + val
else:
val = (int(val) + 9) // 10
else:
val = {
'no': 'FALSE',
Expand Down
35 changes: 32 additions & 3 deletions src/floppy.c
Expand Up @@ -17,6 +17,7 @@

/* A soft IRQ for handling lower priority work items. */
static void drive_step_timer(void *_drv);
static void motor_spinup_timer(void *_drv);
void IRQ_43(void) __attribute__((alias("IRQ_soft")));
#define FLOPPY_SOFTIRQ 43

Expand Down Expand Up @@ -62,6 +63,14 @@ static struct drive {
bool_t sel;
bool_t index_suppressed; /* disable IDX while writing to USB stick */
uint8_t outp;
volatile bool_t inserted;
struct {
struct timer timer;
#define MOTOR_off 0
#define MOTOR_on 1
#define MOTOR_spun_up 2
volatile uint8_t state;
} motor;
struct {
#define STEP_started 1 /* started by hi-pri IRQ */
#define STEP_latched 2 /* latched by lo-pri IRQ */
Expand Down Expand Up @@ -222,7 +231,6 @@ void floppy_cancel(void)

/* Immediately change outputs that we control entirely from the main loop.
* Asserting WRPROT prevents any further calls to wdata_start(). */
drive_change_output(drv, outp_rdy, FALSE);
drive_change_output(drv, outp_wrprot, TRUE);
drive_change_output(drv, outp_hden, FALSE);
update_amiga_id(FALSE);
Expand All @@ -240,12 +248,14 @@ void floppy_cancel(void)
barrier(); /* cancel index.timer /then/ clear soft state */
drv->index_suppressed = FALSE;
drv->image = NULL;
drv->inserted = FALSE;
max_read_us = 0;
image = NULL;
dma_rd = dma_wr = NULL;
index.fake_fired = FALSE;
barrier(); /* clear soft state /then/ cancel index.timer_deassert */
timer_cancel(&index.timer_deassert);
IRQx_set_pending(FLOPPY_MOTOR_IRQ); /* update RDY + motor state */

/* Set outputs for empty drive. */
barrier();
Expand Down Expand Up @@ -335,6 +345,7 @@ void floppy_init(void)
board_floppy_init();

timer_init(&drv->step.timer, drive_step_timer, drv);
timer_init(&drv->motor.timer, motor_spinup_timer, drv);

gpio_configure_pin(gpio_out, pin_02, GPO_bus);
gpio_configure_pin(gpio_out, pin_08, GPO_bus);
Expand Down Expand Up @@ -375,6 +386,8 @@ void floppy_init(void)

timer_init(&index.timer, index_assert, NULL);
timer_init(&index.timer_deassert, index_deassert, NULL);

floppy_set_motor_delay();
}

void floppy_insert(unsigned int unit, struct slot *slot)
Expand Down Expand Up @@ -541,10 +554,12 @@ void floppy_insert(unsigned int unit, struct slot *slot)
DMA_CCR_EN);

/* Drive is ready. Set output signals appropriately. */
drive_change_output(drv, outp_rdy, TRUE);
update_amiga_id(im->stk_per_rev > stk_ms(300));
if (!(slot->attributes & AM_RDO))
drive_change_output(drv, outp_wrprot, FALSE);
barrier();
drv->inserted = TRUE;
IRQx_set_pending(FLOPPY_MOTOR_IRQ); /* update RDY + motor state */
}

static unsigned int drive_calc_track(struct drive *drv)
Expand Down Expand Up @@ -982,7 +997,8 @@ static void index_assert(void *dat)
struct drive *drv = &drive;
index.prev_time = index.timer.deadline;
if (!drv->index_suppressed
&& !(drv->step.state && ff_cfg.index_suppression)) {
&& !(drv->step.state && ff_cfg.index_suppression)
&& (drv->motor.state == MOTOR_on)) {
drive_change_output(drv, outp_index, TRUE);
timer_set(&index.timer_deassert, index.prev_time + time_ms(2));
}
Expand Down Expand Up @@ -1024,6 +1040,14 @@ static void drive_step_timer(void *_drv)
}
}

static void motor_spinup_timer(void *_drv)
{
struct drive *drv = _drv;

drv->motor.state = MOTOR_spun_up;
IRQx_set_pending(FLOPPY_SOFTIRQ);
}

static void IRQ_soft(void)
{
struct drive *drv = &drive;
Expand All @@ -1038,6 +1062,11 @@ static void IRQ_soft(void)
index.fake_fired = FALSE;
timer_set(&index.timer_deassert, time_now() + time_us(500));
}

if (drv->motor.state == MOTOR_spun_up) {
drv->motor.state = MOTOR_on;
drive_change_output(drv, outp_rdy, TRUE);
}
}

static void IRQ_rdata_dma(void)
Expand Down
70 changes: 61 additions & 9 deletions src/gotek/floppy.c
Expand Up @@ -13,14 +13,14 @@
#define O_TRUE 0

/* Input pins: DIR=PB0, STEP=PA1, SELA=PA0, SELB=PA3, WGATE=PB9, SIDE=PB4,
* MOTOR=PA15 */
* MOTOR=PA15/PB15 */
#define pin_dir 0 /* PB0 */
#define pin_step 1 /* PA1 */
#define pin_sel0 0 /* PA0 */
#define pin_sel1 3 /* PA3 */
#define pin_wgate 9 /* PB9 */
#define pin_side 4 /* PB4 */
#define pin_motor 15 /* PA15 */
#define pin_motor 15 /* PA15 or PB15 */

/* Output pins. */
#define gpio_out gpiob
Expand Down Expand Up @@ -51,11 +51,14 @@ void IRQ_13(void) __attribute__((alias("IRQ_rdata_dma")));
void IRQ_7(void) __attribute__((alias("IRQ_STEP_changed"))); /* EXTI1 */
void IRQ_10(void) __attribute__((alias("IRQ_SIDE_changed"))); /* EXTI4 */
void IRQ_23(void) __attribute__((alias("IRQ_WGATE_changed"))); /* EXTI9_5 */
void IRQ_40(void) __attribute__((alias("IRQ_MOTOR_changed"))); /* EXTI15_10 */
#define FLOPPY_MOTOR_IRQ 40
static const struct exti_irq exti_irqs[] = {
{ 6, FLOPPY_IRQ_SEL_PRI, 0 },
{ 7, FLOPPY_IRQ_STEP_PRI, m(pin_step) },
{ 10, FLOPPY_IRQ_SIDE_PRI, 0 },
{ 23, FLOPPY_IRQ_WGATE_PRI, 0 }
{ 23, FLOPPY_IRQ_WGATE_PRI, 0 },
{ 40, FLOPPY_SOFTIRQ_PRI, 0 }
};

bool_t floppy_ribbon_is_reversed(void)
Expand All @@ -82,17 +85,25 @@ static void board_floppy_init(void)
gpio_configure_pin(gpioa, pin_sel0, GPI_bus);
gpio_configure_pin(gpiob, pin_wgate, GPI_bus);
gpio_configure_pin(gpiob, pin_side, GPI_bus);
if (gotek_enhanced()) {
gpio_configure_pin(gpioa, pin_sel1, GPI_bus);
gpio_configure_pin(gpioa, pin_motor, GPI_bus);
}

/* PB[15:2] -> EXT[15:2], PA[1:0] -> EXT[1:0] */
afio->exticr2 = afio->exticr3 = afio->exticr4 = 0x1111;
afio->exticr1 = 0x1100;

if (gotek_enhanced()) {
gpio_configure_pin(gpioa, pin_sel1, GPI_bus);
gpio_configure_pin(gpioa, pin_motor, GPI_bus);
afio->exticr4 = 0x0111; /* Motor = PA15 */
} else {
/* This gives us "motor always on" if the pin is not connected.
* It is safe enough to pull down even if connected direct to 5v,
* will only sink ~0.15mA via the weak internal pulldown. */
gpio_configure_pin(gpiob, pin_motor, GPI_pull_down);
}

exti->imr = exti->rtsr = exti->ftsr =
m(pin_wgate) | m(pin_side) | m(pin_step) | m(pin_sel0);
m(pin_wgate) | m(pin_side) | m(pin_step) | m(pin_sel0) | m(pin_motor);
exti->imr &= ~m(pin_motor);
}

/* Fast speculative entry point for SELA-changed IRQ. We assume SELA has
Expand Down Expand Up @@ -231,7 +242,7 @@ static void IRQ_STEP_changed(void)
return;

/* DSKCHG asserts on any falling edge of STEP. We deassert on any edge. */
if ((drv->outp & m(outp_dskchg)) && (dma_rd != NULL))
if ((drv->outp & m(outp_dskchg)) && drv->inserted)
drive_change_output(drv, outp_dskchg, FALSE);

if (!(idr_a & m(pin_step)) /* Not rising edge on STEP? */
Expand Down Expand Up @@ -306,6 +317,47 @@ static void IRQ_WGATE_changed(void)
}
}

static void IRQ_MOTOR_changed(void)
{
struct drive *drv = &drive;
GPIO gpio = gotek_enhanced() ? gpioa : gpiob;

/* Clear MOTOR-changed flag. */
exti->pr = m(pin_motor);

timer_cancel(&drv->motor.timer);
drv->motor.state = MOTOR_off;

if (!drv->inserted) {
/* No disk inserted -- MOTOR OFF */
drive_change_output(drv, outp_rdy, FALSE);
} else if (ff_cfg.motor_delay == MOTOR_ignore) {
/* Motor signal ignored -- MOTOR ON */
drv->motor.state = MOTOR_on;
drive_change_output(drv, outp_rdy, TRUE);
} else if (gpio->idr & m(pin_motor)) {
/* Motor signal off -- MOTOR OFF */
drive_change_output(drv, outp_rdy, FALSE);
} else {
/* Motor signal on -- MOTOR SPINNING UP */
timer_set(&drv->motor.timer,
time_now() + time_ms(ff_cfg.motor_delay * 10));
}
}

void floppy_set_motor_delay(void)
{
if (ff_cfg.motor_delay != MOTOR_ignore) {
exti->imr |= m(pin_motor);
printk("Motor: Delay %u ms\n", ff_cfg.motor_delay * 10);
} else {
exti->imr &= ~m(pin_motor);
printk("Motor: Ignored\n");
}

IRQx_set_pending(FLOPPY_MOTOR_IRQ);
}

/*
* Local variables:
* mode: C
Expand Down
10 changes: 10 additions & 0 deletions src/main.c
Expand Up @@ -849,6 +849,12 @@ static void read_ff_cfg(void)
ff_cfg.head_settle_ms = strtol(opts.arg, NULL, 10);
break;

case FFCFG_motor_delay:
ff_cfg.motor_delay =
!strcmp(opts.arg, "ignore") ? MOTOR_ignore
: (strtol(opts.arg, NULL, 10) + 9) / 10;
break;

/* STARTUP / INITIALISATION */

case FFCFG_ejected_on_startup:
Expand Down Expand Up @@ -1060,6 +1066,10 @@ static void process_ff_cfg_opts(const struct ff_cfg *old)
|| (ff_cfg.pin34 != old->pin34))
floppy_set_fintf_mode();

/* motor-delay: Inform the floppy subsystem. */
if (ff_cfg.motor_delay != old->motor_delay)
floppy_set_motor_delay();

/* ejected-on-startup: Set the ejected state appropriately. */
if (ff_cfg.ejected_on_startup)
cfg.ejected = TRUE;
Expand Down

0 comments on commit bf36c6c

Please sign in to comment.