Browse Source

AT32F415: Port floppy interface

Keir Fraser 4 years ago
parent
commit
a2085a96d5
4 changed files with 251 additions and 86 deletions
  1. 2 0
      inc/mcu/stm32/f1_regs.h
  2. 8 2
      src/mcu/at32f415/board.c
  3. 232 67
      src/mcu/at32f415/floppy.c
  4. 9 17
      src/mcu/at32f415/stm32.c

+ 2 - 0
inc/mcu/stm32/f1_regs.h

@@ -156,6 +156,7 @@ struct rcc {
 #define RCC_APB2ENR_TIM1EN   (1u<<11)
 #define RCC_APB2ENR_ADC2EN   (1u<<10)
 #define RCC_APB2ENR_ADC1EN   (1u<< 9)
+#define RCC_APB2ENR_IOPFEN   (1u<< 7)
 #define RCC_APB2ENR_IOPEEN   (1u<< 6)
 #define RCC_APB2ENR_IOPDEN   (1u<< 5)
 #define RCC_APB2ENR_IOPCEN   (1u<< 4)
@@ -228,6 +229,7 @@ struct afio {
     uint32_t mapr2;      /* 1C: AF remap and debug I/O configuration #2 */
 };
 
+#define AFIO_MAPR_SWJ_ON_JTAG_OFF      (2u<<24)
 #define AFIO_MAPR_SWJ_CFG_DISABLED     (4u<<24)
 #define AFIO_MAPR_TIM4_REMAP_FULL      (1u<<12)
 #define AFIO_MAPR_TIM3_REMAP_FULL      (3u<<10)

+ 8 - 2
src/mcu/at32f415/board.c

@@ -14,9 +14,15 @@
 
 static void mcu_board_init(void)
 {
-    gpio_pull_up_pins(gpioa, 0xe1fe); /* PA1-8,13-15 */
-    gpio_pull_up_pins(gpiob, 0x0027); /* PB0-2,5 */
+    gpio_pull_up_pins(gpioa, 0x0101); /* PA0,8 */
+    gpio_pull_up_pins(gpiob, 0xdc03); /* PB0-1,10-12,14-15 */
     gpio_pull_up_pins(gpioc, 0xffff); /* PC0-15 */
+
+    /* Flippy TRK0_DISABLE output: Set inactive (LOW). */
+    gpio_configure_pin(gpiob, 14, GPO_pushpull(IOSPD_LOW, LOW));
+
+    /* /RDY input line is externally pulled up. */
+    gpio_configure_pin(gpiob, 15, GPI_floating);
 }
 
 /*

+ 232 - 67
src/mcu/at32f415/floppy.c

@@ -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:

+ 9 - 17
src/mcu/at32f415/stm32.c

@@ -39,30 +39,22 @@ static void clock_init(void)
     rcc->cr &= ~RCC_CR_HSION;
 }
 
-static void gpio_init(GPIO gpio)
-{
-    /* Floating Input. Reference Manual states that JTAG pins are in PU/PD
-     * mode at reset, so ensure all PU/PD are disabled. */
-    gpio->crl = gpio->crh = 0x44444444u;
-}
-
 static void peripheral_init(void)
 {
-    /* Enable basic GPIO and AFIO clocks, all timers, and DMA. */
-    rcc->apb1enr = (RCC_APB1ENR_TIM2EN |
-                    RCC_APB1ENR_TIM3EN |
-                    RCC_APB1ENR_TIM4EN);
+    /* Enable basic GPIO and AFIO clocks, and DMA. */
+    rcc->apb1enr = 0;
     rcc->apb2enr = (RCC_APB2ENR_IOPAEN |
                     RCC_APB2ENR_IOPBEN |
                     RCC_APB2ENR_IOPCEN |
-                    RCC_APB2ENR_AFIOEN |
-                    RCC_APB2ENR_TIM1EN);
+                    RCC_APB2ENR_IOPFEN |
+                    RCC_APB2ENR_AFIOEN);
     rcc->ahbenr = RCC_AHBENR_DMA1EN;
 
-    /* All pins in a stable state. */
-    gpio_init(gpioa);
-    gpio_init(gpiob);
-    gpio_init(gpioc);
+    /* Reclaim JTAG pins. */
+    afio->mapr = AFIO_MAPR_SWJ_ON_JTAG_OFF;
+    gpio_configure_pin(gpioa, 15, GPI_floating);
+    gpio_configure_pin(gpiob,  3, GPI_floating);
+    gpio_configure_pin(gpiob,  4, GPI_floating);
 }
 
 void stm32_init(void)