|
@@ -12,50 +12,95 @@
|
|
|
#define O_FALSE 1
|
|
|
#define O_TRUE 0
|
|
|
|
|
|
-#define GPO_bus GPO_opendrain(_2MHz,O_FALSE)
|
|
|
-#define AFO_bus AFO_opendrain(_2MHz)
|
|
|
-static unsigned int GPI_bus;
|
|
|
+#define GPO_bus GPO_pushpull(_2MHz,O_FALSE)
|
|
|
+#define AFO_bus AFO_pushpull(_2MHz)
|
|
|
+#define GPI_bus GPI_floating
|
|
|
|
|
|
/* Input pins */
|
|
|
#define gpio_index gpiob
|
|
|
-#define pin_index 6 /* PB6 */
|
|
|
+#define pin_index 10 /* PB10 */
|
|
|
#define gpio_trk0 gpiob
|
|
|
-#define pin_trk0 7 /* PB7 */
|
|
|
+#define pin_trk0 4 /* PB4 */
|
|
|
#define gpio_wrprot gpiob
|
|
|
-#define pin_wrprot 8 /* PB8 */
|
|
|
+#define pin_wrprot 3 /* PB3 */
|
|
|
|
|
|
/* Output pins. */
|
|
|
-#define gpio_densel gpiob
|
|
|
-#define pin_densel 9 /* PB9 */
|
|
|
-#define gpio_sel gpiob
|
|
|
-#define pin_sel 10 /* PB10 */
|
|
|
-#define gpio_mot gpiob
|
|
|
-#define pin_mot 11 /* PB11 */
|
|
|
#define gpio_dir gpiob
|
|
|
-#define pin_dir 12 /* PB12 */
|
|
|
+#define pin_dir 8 /* PB8 */
|
|
|
#define gpio_step gpiob
|
|
|
-#define pin_step 13 /* PB13 */
|
|
|
+#define pin_step 6 /* PB6 */
|
|
|
#define gpio_wgate gpiob
|
|
|
-#define pin_wgate 14 /* PB14 */
|
|
|
+#define pin_wgate 7 /* PB7 */
|
|
|
#define gpio_head gpiob
|
|
|
-#define pin_head 15 /* PB15 */
|
|
|
+#define pin_head 5 /* PB5 */
|
|
|
|
|
|
-/* RDATA: Pin B3, Timer 2 Channel 2, DMA1 Channel 7. */
|
|
|
-#define gpio_rdata gpiob
|
|
|
-#define pin_rdata 3
|
|
|
+/* RDATA: Pin A15, Timer 2 Channel 1, DMA1 Channel 5. */
|
|
|
+#define gpio_rdata gpioa
|
|
|
+#define pin_rdata 15
|
|
|
#define tim_rdata (tim2)
|
|
|
-#define dma_rdata (dma1->ch7)
|
|
|
+#define dma_rdata (dma1->ch5)
|
|
|
|
|
|
-/* WDATA: Pin B4, Timer 3 Channel 1, DMA1 Channel 3. */
|
|
|
-#define gpio_wdata gpiob
|
|
|
-#define pin_wdata 4
|
|
|
-#define tim_wdata (tim3)
|
|
|
-#define dma_wdata (dma1->ch3)
|
|
|
+/* WDATA: Pin A2, Timer 2 Channel 3, DMA1 Channel 2. */
|
|
|
+#define gpio_wdata gpioa
|
|
|
+#define pin_wdata 2
|
|
|
+#define tim_wdata (tim2)
|
|
|
+#define dma_wdata (dma1->ch2)
|
|
|
|
|
|
typedef uint16_t timcnt_t;
|
|
|
|
|
|
-#define irq_index 23
|
|
|
-void IRQ_23(void) __attribute__((alias("IRQ_INDEX_changed"))); /* EXTI9_5 */
|
|
|
+#define irq_index 40
|
|
|
+void IRQ_40(void) __attribute__((alias("IRQ_INDEX_changed"))); /* EXTI15_10 */
|
|
|
+
|
|
|
+enum { _A = 0, _B, _C, _D, _E, _F, _G };
|
|
|
+
|
|
|
+struct pin_mapping {
|
|
|
+ uint8_t pin_id;
|
|
|
+ uint8_t gpio_bank;
|
|
|
+ uint8_t gpio_pin;
|
|
|
+};
|
|
|
+
|
|
|
+const static struct pin_mapping msel_pins[] = {
|
|
|
+ { 10, _A, 3 },
|
|
|
+ { 12, _B, 9 },
|
|
|
+ { 14, _A, 4 },
|
|
|
+ { 16, _A, 1 },
|
|
|
+ { 0, 0, 0 }
|
|
|
+};
|
|
|
+
|
|
|
+const static struct pin_mapping user_pins[] = {
|
|
|
+ { 2, _A, 6 },
|
|
|
+ { 4, _A, 5 },
|
|
|
+ { 6, _A, 7 },
|
|
|
+ { 0, 0, 0 }
|
|
|
+};
|
|
|
+
|
|
|
+GPIO gpio_from_id(uint8_t id)
|
|
|
+{
|
|
|
+ switch (id) {
|
|
|
+ case _A: return gpioa;
|
|
|
+ case _B: return gpiob;
|
|
|
+ case _C: return gpioc;
|
|
|
+ }
|
|
|
+ ASSERT(0);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+uint8_t write_mapped_pin(
|
|
|
+ const struct pin_mapping *map, int pin_id, bool_t level)
|
|
|
+{
|
|
|
+ const struct pin_mapping *pin;
|
|
|
+
|
|
|
+ for (pin = map; pin->pin_id != 0; pin++)
|
|
|
+ if (pin->pin_id == pin_id)
|
|
|
+ goto found;
|
|
|
+
|
|
|
+ return ACK_BAD_PIN;
|
|
|
+
|
|
|
+found:
|
|
|
+ gpio_write_pin(gpio_from_id(pin->gpio_bank), pin->gpio_pin, level);
|
|
|
+ return ACK_OKAY;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
/* We sometimes cast u_buf to uint32_t[], hence the alignment constraint. */
|
|
|
#define U_BUF_SZ 8192
|
|
@@ -63,28 +108,32 @@ static uint8_t u_buf[U_BUF_SZ] aligned(4);
|
|
|
|
|
|
static void floppy_mcu_init(void)
|
|
|
{
|
|
|
- /* Determine whether input pins must be internally pulled down. */
|
|
|
- configure_pin(index, GPI_pull_down);
|
|
|
- delay_us(10);
|
|
|
- GPI_bus = (get_index() == LOW) ? GPI_pull_up : GPI_floating;
|
|
|
- printk("Floppy Inputs: %sternal Pullup\n",
|
|
|
- (GPI_bus == GPI_pull_up) ? "In" : "Ex");
|
|
|
+ const struct pin_mapping *mpin;
|
|
|
+ const struct pin_mapping *upin;
|
|
|
|
|
|
- /* Remap timers to RDATA/WDATA pins. */
|
|
|
- afio->mapr |= (AFIO_MAPR_TIM2_REMAP_PARTIAL_1
|
|
|
- | AFIO_MAPR_TIM3_REMAP_PARTIAL);
|
|
|
+ /* Map PA15 -> TIM2 Ch1. */
|
|
|
+ afio->mapr = (AFIO_MAPR_SWJ_ON_JTAG_OFF
|
|
|
+ | AFIO_MAPR_TIM2_REMAP_PARTIAL_1);
|
|
|
|
|
|
- /* Set up EXTI mapping for INDEX: PB[15:0] -> EXT[15:0] */
|
|
|
- afio->exticr1 = afio->exticr2 = afio->exticr3 = afio->exticr4 = 0x1111;
|
|
|
+ /* Enable clock for Timer 2. */
|
|
|
+ rcc->apb1enr |= RCC_APB1ENR_TIM2EN;
|
|
|
|
|
|
configure_pin(rdata, GPI_bus);
|
|
|
|
|
|
+ /* Configure user-modifiable pins. */
|
|
|
+ for (upin = user_pins; upin->pin_id != 0; upin++) {
|
|
|
+ gpio_configure_pin(gpio_from_id(upin->gpio_bank), upin->gpio_pin,
|
|
|
+ GPO_bus);
|
|
|
+ }
|
|
|
+
|
|
|
/* Configure SELECT/MOTOR lines. */
|
|
|
- configure_pin(sel, GPO_bus);
|
|
|
- configure_pin(mot, GPO_bus);
|
|
|
+ for (mpin = msel_pins; mpin->pin_id != 0; mpin++) {
|
|
|
+ gpio_configure_pin(gpio_from_id(mpin->gpio_bank), mpin->gpio_pin,
|
|
|
+ GPO_bus);
|
|
|
+ }
|
|
|
|
|
|
- /* Configure user-modifiable lines. */
|
|
|
- configure_pin(densel, GPO_bus);
|
|
|
+ /* Set up EXTI mapping for INDEX: PB[11:8] -> EXT[11:8] */
|
|
|
+ afio->exticr3 = 0x1111;
|
|
|
}
|
|
|
|
|
|
static void rdata_prep(void)
|
|
@@ -92,20 +141,20 @@ static void rdata_prep(void)
|
|
|
/* RDATA Timer setup:
|
|
|
* The counter runs from 0x0000-0xFFFF inclusive at SAMPLE rate.
|
|
|
*
|
|
|
- * Ch.2 (RDATA) is in Input Capture mode, sampling on every clock and with
|
|
|
+ * Ch.1 (RDATA) is in Input Capture mode, sampling on every clock and with
|
|
|
* no input prescaling or filtering. Samples are captured on the falling
|
|
|
* edge of the input (CCxP=1). DMA is used to copy the sample into a ring
|
|
|
* buffer for batch processing in the DMA-completion ISR. */
|
|
|
tim_rdata->psc = TIM_PSC-1;
|
|
|
tim_rdata->arr = 0xffff;
|
|
|
- tim_rdata->ccmr1 = TIM_CCMR1_CC2S(TIM_CCS_INPUT_TI1);
|
|
|
- tim_rdata->dier = TIM_DIER_CC2DE;
|
|
|
+ tim_rdata->ccmr1 = TIM_CCMR1_CC1S(TIM_CCS_INPUT_TI1);
|
|
|
+ tim_rdata->dier = TIM_DIER_CC1DE;
|
|
|
tim_rdata->cr2 = 0;
|
|
|
tim_rdata->egr = TIM_EGR_UG; /* update CNT, PSC, ARR */
|
|
|
tim_rdata->sr = 0; /* dummy write */
|
|
|
|
|
|
/* RDATA DMA setup: From the RDATA Timer's CCRx into a circular buffer. */
|
|
|
- dma_rdata.par = (uint32_t)(unsigned long)&tim_rdata->ccr2;
|
|
|
+ dma_rdata.par = (uint32_t)(unsigned long)&tim_rdata->ccr1;
|
|
|
dma_rdata.cr = (DMA_CR_PL_HIGH |
|
|
|
DMA_CR_MSIZE_16BIT |
|
|
|
DMA_CR_PSIZE_16BIT |
|
|
@@ -114,7 +163,7 @@ static void rdata_prep(void)
|
|
|
DMA_CR_DIR_P2M |
|
|
|
DMA_CR_EN);
|
|
|
|
|
|
- tim_rdata->ccer = TIM_CCER_CC2E | TIM_CCER_CC2P;
|
|
|
+ tim_rdata->ccer = TIM_CCER_CC1E | TIM_CCER_CC1P;
|
|
|
}
|
|
|
|
|
|
static void wdata_prep(void)
|
|
@@ -122,15 +171,15 @@ static void wdata_prep(void)
|
|
|
/* WDATA Timer setup:
|
|
|
* The counter is incremented at SAMPLE rate.
|
|
|
*
|
|
|
- * Ch.1 (WDATA) is in PWM mode 1. It outputs O_TRUE for 400ns and then
|
|
|
+ * Ch.3 (WDATA) is in PWM mode 1. It outputs O_TRUE for 400ns and then
|
|
|
* O_FALSE until the counter reloads. By changing the ARR via DMA we alter
|
|
|
* the time between (fixed-width) O_TRUE pulses, mimicking floppy drive
|
|
|
* timings. */
|
|
|
tim_wdata->psc = TIM_PSC-1;
|
|
|
- tim_wdata->ccmr1 = (TIM_CCMR1_CC1S(TIM_CCS_OUTPUT) |
|
|
|
- TIM_CCMR1_OC1M(TIM_OCM_PWM1));
|
|
|
- tim_wdata->ccer = TIM_CCER_CC1E | ((O_TRUE==0) ? TIM_CCER_CC1P : 0);
|
|
|
- tim_wdata->ccr1 = sample_ns(400);
|
|
|
+ tim_wdata->ccmr2 = (TIM_CCMR2_CC3S(TIM_CCS_OUTPUT) |
|
|
|
+ TIM_CCMR2_OC3M(TIM_OCM_PWM1));
|
|
|
+ tim_wdata->ccer = TIM_CCER_CC3E | ((O_TRUE==0) ? TIM_CCER_CC3P : 0);
|
|
|
+ tim_wdata->ccr3 = sample_ns(400);
|
|
|
tim_wdata->dier = TIM_DIER_UDE;
|
|
|
tim_wdata->cr2 = 0;
|
|
|
}
|
|
@@ -148,48 +197,164 @@ static void dma_wdata_start(void)
|
|
|
|
|
|
static void drive_deselect(void)
|
|
|
{
|
|
|
- write_pin(sel, FALSE);
|
|
|
+ int pin = -1;
|
|
|
+ uint8_t rc;
|
|
|
+
|
|
|
+ if (unit_nr == -1)
|
|
|
+ return;
|
|
|
+
|
|
|
+ switch (bus_type) {
|
|
|
+ case BUS_IBMPC:
|
|
|
+ switch (unit_nr) {
|
|
|
+ case 0: pin = 14; break;
|
|
|
+ case 1: pin = 12; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case BUS_SHUGART:
|
|
|
+ switch (unit_nr) {
|
|
|
+ case 0: pin = 10; break;
|
|
|
+ case 1: pin = 12; break;
|
|
|
+ case 2: pin = 14; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = write_mapped_pin(msel_pins, pin, O_FALSE);
|
|
|
+ ASSERT(rc == ACK_OKAY);
|
|
|
+
|
|
|
unit_nr = -1;
|
|
|
}
|
|
|
|
|
|
static uint8_t drive_select(uint8_t nr)
|
|
|
{
|
|
|
- write_pin(sel, TRUE);
|
|
|
- unit_nr = 0;
|
|
|
+ int pin = -1;
|
|
|
+ uint8_t rc;
|
|
|
+
|
|
|
+ if (nr == unit_nr)
|
|
|
+ return ACK_OKAY;
|
|
|
+
|
|
|
+ drive_deselect();
|
|
|
+
|
|
|
+ switch (bus_type) {
|
|
|
+ case BUS_IBMPC:
|
|
|
+ switch (nr) {
|
|
|
+ case 0: pin = 14; break;
|
|
|
+ case 1: pin = 12; break;
|
|
|
+ default: return ACK_BAD_UNIT;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case BUS_SHUGART:
|
|
|
+ switch (nr) {
|
|
|
+ case 0: pin = 10; break;
|
|
|
+ case 1: pin = 12; break;
|
|
|
+ case 2: pin = 14; break;
|
|
|
+ default: return ACK_BAD_UNIT;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return ACK_NO_BUS;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = write_mapped_pin(msel_pins, pin, O_TRUE);
|
|
|
+ if (rc != ACK_OKAY)
|
|
|
+ return ACK_BAD_UNIT;
|
|
|
+
|
|
|
+ unit_nr = nr;
|
|
|
delay_us(delay_params.select_delay);
|
|
|
+
|
|
|
return ACK_OKAY;
|
|
|
}
|
|
|
|
|
|
static uint8_t drive_motor(uint8_t nr, bool_t on)
|
|
|
{
|
|
|
- if (unit[0].motor == on)
|
|
|
- return ACK_OKAY;
|
|
|
+ int pin = -1;
|
|
|
+ uint8_t rc;
|
|
|
|
|
|
- write_pin(mot, on);
|
|
|
- unit[0].motor = on;
|
|
|
+ switch (bus_type) {
|
|
|
+ case BUS_IBMPC:
|
|
|
+ if (nr >= 2)
|
|
|
+ return ACK_BAD_UNIT;
|
|
|
+ if (unit[nr].motor == on)
|
|
|
+ return ACK_OKAY;
|
|
|
+ switch (nr) {
|
|
|
+ case 0: pin = 10; break;
|
|
|
+ case 1: pin = 16; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case BUS_SHUGART:
|
|
|
+ if (nr >= 3)
|
|
|
+ return ACK_BAD_UNIT;
|
|
|
+ /* All shugart units share one motor line. Alias them all to unit 0. */
|
|
|
+ nr = 0;
|
|
|
+ if (unit[nr].motor == on)
|
|
|
+ return ACK_OKAY;
|
|
|
+ pin = 16;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return ACK_NO_BUS;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = write_mapped_pin(msel_pins, pin, on ? O_TRUE : O_FALSE);
|
|
|
+ if (rc != ACK_OKAY)
|
|
|
+ return ACK_BAD_UNIT;
|
|
|
+
|
|
|
+ unit[nr].motor = on;
|
|
|
if (on)
|
|
|
delay_ms(delay_params.motor_delay);
|
|
|
|
|
|
return ACK_OKAY;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static uint8_t mcu_get_floppy_pin(unsigned int pin, uint8_t *p_level)
|
|
|
+{
|
|
|
+ if (pin == 34) {
|
|
|
+ *p_level = gpio_read_pin(gpiob, 15);
|
|
|
+ return ACK_OKAY;
|
|
|
+ }
|
|
|
+ return ACK_BAD_PIN;
|
|
|
}
|
|
|
|
|
|
static uint8_t set_user_pin(unsigned int pin, unsigned int level)
|
|
|
{
|
|
|
- if (pin != 2)
|
|
|
- return ACK_BAD_PIN;
|
|
|
- gpio_write_pin(gpio_densel, pin_densel, level);
|
|
|
+ const struct pin_mapping *upin;
|
|
|
+
|
|
|
+ for (upin = user_pins; upin->pin_id != 0; upin++) {
|
|
|
+ if (upin->pin_id == pin)
|
|
|
+ goto found;
|
|
|
+ }
|
|
|
+ return ACK_BAD_PIN;
|
|
|
+
|
|
|
+found:
|
|
|
+ gpio_write_pin(gpio_from_id(upin->gpio_bank), upin->gpio_pin, level);
|
|
|
return ACK_OKAY;
|
|
|
}
|
|
|
|
|
|
static void reset_user_pins(void)
|
|
|
{
|
|
|
- write_pin(densel, FALSE);
|
|
|
+ const struct pin_mapping *upin;
|
|
|
+
|
|
|
+ for (upin = user_pins; upin->pin_id != 0; upin++)
|
|
|
+ gpio_write_pin(gpio_from_id(upin->gpio_bank), upin->gpio_pin, O_FALSE);
|
|
|
}
|
|
|
|
|
|
-/* No Flippy-modded drive support on F1 boards. */
|
|
|
-#define flippy_trk0_sensor_disable() ((void)0)
|
|
|
-#define flippy_trk0_sensor_enable() ((void)0)
|
|
|
-#define flippy_detect() FALSE
|
|
|
+static void flippy_trk0_sensor(bool_t level)
|
|
|
+{
|
|
|
+ gpio_write_pin(gpiob, 14, level);
|
|
|
+ delay_us(10);
|
|
|
+}
|
|
|
+
|
|
|
+#define flippy_trk0_sensor_disable() flippy_trk0_sensor(HIGH)
|
|
|
+#define flippy_trk0_sensor_enable() flippy_trk0_sensor(LOW)
|
|
|
+
|
|
|
+static bool_t flippy_detect(void)
|
|
|
+{
|
|
|
+ bool_t is_flippy;
|
|
|
+ flippy_trk0_sensor_disable();
|
|
|
+ is_flippy = (get_trk0() == HIGH);
|
|
|
+ flippy_trk0_sensor_enable();
|
|
|
+ return is_flippy;
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
* Local variables:
|