altos/chaoskey: Add another USB endpoint to read raw data
authorKeith Packard <keithp@keithp.com>
Wed, 2 Mar 2016 21:54:58 +0000 (13:54 -0800)
committerKeith Packard <keithp@keithp.com>
Wed, 2 Mar 2016 21:59:21 +0000 (13:59 -0800)
This replaces having the single output switch based on a pin value and
allows us to box the device and still fetch raw data.

For now, this will use a special libusb2 program, ao-chaosread, to
pull bits as I haven't figure out how to make linux provide two
/dev entries for one USB device.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/chaoskey-v0.1/ao_pins.h
src/drivers/ao_trng_send.c
src/kernel/ao_product.c
src/kernel/ao_usb.h
src/stmf0/ao_arch_funcs.h
src/stmf0/ao_usb_stm.c

index 6ec582a994606a4895122012915e0ea78670168c..73f763071df5ae1c04059bf89372211159155401 100644 (file)
@@ -50,7 +50,9 @@
 #define AO_USB_INTERFACE_CLASS_DATA    0xff
 #define AO_USB_HAS_OUT                 0
 #define AO_USB_HAS_IN                  1
+#define AO_USB_HAS_IN2                 1
 #define AO_USB_HAS_INT                 0
+#define USE_USB_STDIO                  0
 #define AO_USB_SELF_POWER              0
 #define AO_USB_DEVICE_ID_SERIAL                1
 
index f82229934c177f11e724d773afebd54433f7e82a..171a345fbe2db047feebaab19c25a55ba03410e9 100644 (file)
 #include <ao_exti.h>
 #include <ao_power.h>
 
+static struct ao_task  ao_trng_send_task, ao_trng_send_raw_task;
 static uint8_t         trng_running;
 static AO_TICK_TYPE    trng_power_time;
 
-/* Make sure there's at least 8 bits of variance in the samples */
-#define MIN_VARIANCE           (128 * 128)
-
-#define DECLARE_STATS  int32_t sum = 0, sum2 = 0
-
-#define ADD_STATS(value) do {                  \
-               sum += (value);                 \
-               sum2 += (value) * (value);      \
-       } while(0)
-
-#define GOOD_STATS(i)  (((sum2 - (sum * sum) / i) / i) >= MIN_VARIANCE)
-
 #define TRNG_ENABLE_DELAY      AO_MS_TO_TICKS(100)
 
-static int
-ao_trng_send_raw(uint16_t *buf)
+static uint8_t         random_mutex;
+
+static void
+ao_trng_get_raw(uint16_t *buf)
 {
        uint16_t        i;
        uint16_t        t;
        uint16_t        v;
 
-       DECLARE_STATS;
-
        t = ao_adc_get(AO_USB_IN_SIZE>>1);      /* one 16-bit value per two output bytes */
        for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
                v = ao_adc_ring[t];
                *buf++ = v;
                t = (t + 1) & (AO_ADC_RING_SIZE - 1);
+       }
+       ao_adc_ack(AO_USB_IN_SIZE>>1);
+}
+
+static void
+ao_trng_send_raw(void)
+{
+       static uint16_t *buffer[2];
+       int             usb_buf_id;
 
-               ADD_STATS(v);
+       if (!buffer[0]) {
+               buffer[0] = ao_usb_alloc();
+               buffer[1] = ao_usb_alloc();
+               if (!buffer[0])
+                       ao_exit();
+       }
+
+       usb_buf_id = 0;
+
+       for (;;) {
+               ao_mutex_get(&random_mutex);
+               if (!trng_running) {
+                       AO_TICK_TYPE    delay;
+
+                       delay = trng_power_time + TRNG_ENABLE_DELAY - ao_time();
+                       if (delay > TRNG_ENABLE_DELAY)
+                               delay = TRNG_ENABLE_DELAY;
+
+                       /* Delay long enough for the HV power supply
+                        * to stabilize so that the first bits we read
+                        * aren't of poor quality
+                        */
+                       ao_delay(delay);
+                       trng_running = TRUE;
+               }
+#ifdef AO_LED_TRNG_RAW
+               ao_led_on(AO_LED_TRNG_RAW);
+#endif
+               ao_trng_get_raw(buffer[usb_buf_id]);
+#ifdef AO_LED_TRNG_RAW
+               ao_led_off(AO_LED_TRNG_RAW);
+#endif
+               ao_mutex_put(&random_mutex);
+               ao_usb_write2(buffer[usb_buf_id], AO_USB_IN_SIZE);
+               usb_buf_id = 1-usb_buf_id;
        }
-       return GOOD_STATS(AO_USB_IN_SIZE / sizeof (uint16_t));
 }
 
+/* Make sure there's at least 8 bits of variance in the samples */
+#define MIN_VARIANCE           (128 * 128)
+
+/* Make sure the signal is spread around a bit */
+#define MAX_VARIANCE           (512 * 512)
+
+#define ADD_STATS(value) do {                  \
+               sum += (value);                 \
+               sum2 += (value) * (value);      \
+       } while(0)
+
+#define VARIANCE(n)    ((sum2 - (sum / (n) * sum)) / (n))
+
 static int
-ao_trng_send_cooked(uint16_t *buf)
+ao_trng_get_cooked(uint16_t *buf)
 {
        uint16_t        i;
        uint16_t        t;
        uint32_t        *rnd = (uint32_t *) ao_adc_ring;
+       int32_t         sum, sum2, var;
 
-       DECLARE_STATS;
-
+       sum = sum2 = 0;
        t = ao_adc_get(AO_USB_IN_SIZE) >> 1;            /* one 16-bit value per output byte */
-
        for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
                uint32_t        v;
                uint16_t        v1, v2;
@@ -86,14 +129,13 @@ ao_trng_send_cooked(uint16_t *buf)
                ADD_STATS(v1);
                ADD_STATS(v2);
        }
-       return GOOD_STATS(2 * AO_USB_IN_SIZE / sizeof (uint16_t));
+       ao_adc_ack(AO_USB_IN_SIZE);
+       var = VARIANCE(2 * AO_USB_IN_SIZE / sizeof (uint16_t));
+       return var >= MIN_VARIANCE && var <= MAX_VARIANCE;
 }
 
-static inline int
-ao_send_raw(void)
-{
-       return !ao_gpio_get(AO_RAW_PORT, AO_RAW_BIT, AO_RAW_PIN);
-}
+#define AO_TRNG_START_WAIT     1024
+#define AO_TRNG_START_CHECK    32
 
 static void
 ao_trng_send(void)
@@ -101,13 +143,14 @@ ao_trng_send(void)
        static uint16_t *buffer[2];
        int     usb_buf_id;
        int     good_bits;
-       int     failed = 0;
+       int     failed;
+       int     s;
 
        if (!buffer[0]) {
                buffer[0] = ao_usb_alloc();
                buffer[1] = ao_usb_alloc();
                if (!buffer[0])
-                       return;
+                       ao_exit();
        }
 
        usb_buf_id = 0;
@@ -119,7 +162,33 @@ ao_trng_send(void)
 
        ao_crc_reset();
 
+       ao_delay(TRNG_ENABLE_DELAY);
+
+       for (s = 0; s < AO_TRNG_START_WAIT; s++) {
+               if (ao_trng_get_cooked(buffer[0]))
+                       break;
+               ao_delay(AO_MS_TO_TICKS(10));
+       }
+
+       /* Validate the hardware before enabling USB */
+       failed = 0;
+       for (s = 0; s < AO_TRNG_START_CHECK; s++) {
+               if (!ao_trng_get_cooked(buffer[0])) {
+                       failed++;
+                       ao_delay(AO_MS_TO_TICKS(10));
+               }
+       }
+       if (failed > AO_TRNG_START_CHECK / 4)
+               ao_panic(AO_PANIC_DMA);
+
+       ao_add_task(&ao_trng_send_raw_task, ao_trng_send_raw, "trng_send_raw");
+
+#ifdef AO_USB_START_DISABLED
+       ao_usb_enable();
+#endif
+
        for (;;) {
+               ao_mutex_get(&random_mutex);
                if (!trng_running) {
                        AO_TICK_TYPE    delay;
 
@@ -134,16 +203,14 @@ ao_trng_send(void)
                        ao_delay(delay);
                        trng_running = TRUE;
                }
-               if (ao_send_raw()) {
-                       ao_led_on(AO_LED_TRNG_RAW);
-                       good_bits = ao_trng_send_raw(buffer[usb_buf_id]);
-                       ao_led_off(AO_LED_TRNG_RAW);
-               } else {
-                       ao_led_on(AO_LED_TRNG_COOKED);
-                       good_bits = ao_trng_send_cooked(buffer[usb_buf_id]);
-                       ao_led_off(AO_LED_TRNG_COOKED);
-               }
-               ao_adc_ack(AO_USB_IN_SIZE);
+#ifdef AO_LED_TRNG_COOKED
+               ao_led_on(AO_LED_TRNG_COOKED);
+#endif
+               good_bits = ao_trng_get_cooked(buffer[usb_buf_id]);
+#ifdef AO_LED_TRNG_COOKED
+               ao_led_off(AO_LED_TRNG_COOKED);
+#endif
+               ao_mutex_put(&random_mutex);
                if (good_bits) {
                        ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE);
                        usb_buf_id = 1-usb_buf_id;
@@ -159,8 +226,6 @@ ao_trng_send(void)
        }
 }
 
-static struct ao_task ao_trng_send_task;
-
 #if AO_POWER_MANAGEMENT
 
 static void ao_trng_suspend(void *arg)
index 4769d86efef2efe38c9f1f8eae87695d66d2ec99..3a829b3a654736e58539a7b57d22f7cc7239ed4d 100644 (file)
@@ -54,7 +54,7 @@ const char ao_product[] = AO_iProduct_STRING;
 
 #define HEADER_LEN             9
 #define CONTROL_CLASS_LEN      35
-#define DATA_LEN               (9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN)
+#define DATA_LEN               (9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN + 7 * AO_USB_HAS_IN2)
 
 #define TOTAL_LENGTH           (HEADER_LEN + AO_USB_HAS_INT * CONTROL_CLASS_LEN + DATA_LEN)
 #define NUM_INTERFACES         (AO_USB_HAS_INT + 1)
@@ -140,7 +140,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] =
        AO_USB_DESC_INTERFACE,
        AO_USB_HAS_INT,                 /* bInterfaceNumber */
        0x00,                           /* bAlternateSetting */
-       AO_USB_HAS_OUT + AO_USB_HAS_IN, /* bNumEndPoints */
+       AO_USB_HAS_OUT + AO_USB_HAS_IN + AO_USB_HAS_IN2,        /* bNumEndPoints */
        AO_USB_INTERFACE_CLASS_DATA,    /* bInterfaceClass = data */
        0x00,                           /* bInterfaceSubClass */
        0x00,                           /* bInterfaceProtocol */
@@ -166,6 +166,16 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] =
        0x00,                   /* bInterval */
 #endif
 
+#if AO_USB_HAS_IN2
+       /* Data EP in 2 */
+       0x07,
+       AO_USB_DESC_ENDPOINT,
+       AO_USB_IN2_EP|0x80,     /* bEndpointAddress */
+       0x02,                   /* bmAttributes = bulk */
+       LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */
+       0x00,                   /* bInterval */
+#endif
+
        /* String descriptors */
        0x04,
        AO_USB_DESC_STRING,
index 773b5cb7eca054b0d283f0b5ef67dbd4367d4e17..8f3e7813f4ed308b2f0ef937d8f8f0aec0af72cd 100644 (file)
@@ -105,6 +105,7 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
 #ifndef AO_USB_OUT_EP
 #define AO_USB_OUT_EP          4
 #define AO_USB_IN_EP           5
+#define AO_USB_IN2_EP          6
 #endif
 
 #ifndef AO_USB_HAS_OUT
@@ -119,6 +120,10 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
 #define AO_USB_HAS_INT 1
 #endif
 
+#ifndef AO_USB_HAS_IN2
+#define AO_USB_HAS_IN2 0
+#endif
+
 /*
  * USB bulk packets can only come in 8, 16, 32 and 64
  * byte sizes, so we'll use 64 for everything
index 8d585f80cdddd22a2f3bd163b912f4b2aeb8c9d0..4e3ef0189601f9267d2bdee5fe8cf81eb8446ef0 100644 (file)
@@ -413,6 +413,9 @@ ao_usb_free(uint16_t *buffer);
 
 void
 ao_usb_write(uint16_t *buffer, uint16_t len);
+
+void
+ao_usb_write2(uint16_t *buffer, uint16_t len);
 #endif /* AO_USB_DIRECTIO */
 
 #endif /* _AO_ARCH_FUNCS_H_ */
index 17e8709cf959095d1d089fd1a79fd909f86d2b80..e68da8eb2adea8f5fe8faad28cec367641635931 100644 (file)
@@ -89,23 +89,42 @@ static uint16_t     ao_usb_sram_addr;
 static uint16_t        *ao_usb_ep0_tx_buffer;
 static uint16_t        *ao_usb_ep0_rx_buffer;
 
+#if AO_USB_HAS_INT
 /* Pointer to interrupt buffer in USB memory */
 static uint16_t ao_usb_int_tx_offset;
+#endif
 
 /* Pointer to bulk data tx/rx buffers in USB memory */
+#if AO_USB_HAS_IN
 static uint16_t ao_usb_in_tx_offset;
 static uint16_t        *ao_usb_in_tx_buffer;
-static uint16_t ao_usb_out_rx_offset;
-static uint16_t        *ao_usb_out_rx_buffer;
 
 /* System ram shadow of USB buffer; writing individual bytes is
  * too much of a pain (sigh) */
 static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE];
 static uint8_t ao_usb_tx_count;
 
+#endif
+#if AO_USB_HAS_OUT
+static uint16_t ao_usb_out_rx_offset;
+static uint16_t        *ao_usb_out_rx_buffer;
+
+/* System ram shadow of USB buffer; writing individual bytes is
+ * too much of a pain (sigh) */
 static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE];
 static uint8_t ao_usb_rx_count, ao_usb_rx_pos;
 
+#endif
+#if AO_USB_HAS_IN2
+static uint16_t ao_usb_in2_tx_offset;
+static uint16_t *ao_usb_in2_tx_buffer;
+
+/* System ram shadow of USB buffer; writing individual bytes is
+ * too much of a pain (sigh) */
+static uint8_t ao_usb_tx2_buffer[AO_USB_IN_SIZE];
+static uint8_t ao_usb_tx2_count;
+#endif
+
 /*
  * End point register indices
  */
@@ -114,6 +133,7 @@ static uint8_t      ao_usb_rx_count, ao_usb_rx_pos;
 #define AO_USB_INT_EPR         1
 #define AO_USB_OUT_EPR         2
 #define AO_USB_IN_EPR          3
+#define AO_USB_IN2_EPR         4
 
 /* Marks when we don't need to send an IN packet.
  * This happens only when the last IN packet is not full,
@@ -128,6 +148,16 @@ static uint8_t     ao_usb_in_flushed;
  */
 static uint8_t ao_usb_in_pending;
 
+#if AO_USB_HAS_IN2
+/* Marks when we have delivered an IN packet to the hardware
+ * and it has not been received yet. ao_sleep on this address
+ * to wait for it to be delivered.
+ */
+static uint8_t ao_usb_in2_pending;
+static uint16_t        in2_count;
+static uint8_t ao_usb_in2_flushed;
+#endif
+
 /* Marks when an OUT packet has been received by the hardware
  * but not pulled to the shadow buffer.
  */
@@ -343,16 +373,29 @@ ao_usb_alloc_buffers(void)
        ao_usb_ep0_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
        ao_usb_sram_addr += AO_USB_CONTROL_SIZE;
 
+
+#if AO_USB_HAS_INT
        ao_usb_int_tx_offset = ao_usb_sram_addr;
        ao_usb_sram_addr += AO_USB_INT_SIZE;
+#endif
 
+#if AO_USB_HAS_OUT
        ao_usb_out_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
        ao_usb_out_rx_offset = ao_usb_sram_addr;
        ao_usb_sram_addr += AO_USB_OUT_SIZE;
+#endif
 
+#if AO_USB_HAS_IN
        ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
        ao_usb_in_tx_offset = ao_usb_sram_addr;
        ao_usb_sram_addr += AO_USB_IN_SIZE;
+#endif
+
+#if AO_USB_HAS_IN2
+       ao_usb_in2_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr);
+       ao_usb_in2_tx_offset = ao_usb_sram_addr;
+       ao_usb_sram_addr += AO_USB_IN_SIZE;
+#endif
 }
 
 static void
@@ -438,6 +481,18 @@ ao_usb_set_configuration(void)
                       STM_USB_EPR_STAT_TX_NAK);
 #endif
 
+#if AO_USB_HAS_IN2
+       /* Set up the IN2 end point */
+       ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in2_tx_offset;
+       ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = 0;
+
+       ao_usb_init_ep(AO_USB_IN2_EPR,
+                      AO_USB_IN2_EP,
+                      STM_USB_EPR_EP_TYPE_BULK,
+                      STM_USB_EPR_STAT_RX_DISABLED,
+                      STM_USB_EPR_STAT_TX_NAK);
+#endif
+
        ao_usb_running = 1;
 #if AO_USB_DIRECTIO
        ao_wakeup(&ao_usb_running);
@@ -581,7 +636,7 @@ hex_to_ucs2(uint32_t in, uint8_t *out)
 
        for (i = 28; i >= 0; i -= 4) {
                uint8_t bits = (in >> i) & 0xf;
-               *out++ = (bits < 10) ? ('0' + bits) : ('a' + bits);
+               *out++ = ((bits < 10) ? '0' : ('a' - 10)) + bits;
                *out++ = 0;
        }
 }
@@ -835,6 +890,16 @@ stm_usb_isr(void)
                                ao_wakeup(&ao_usb_in_pending);
                        }
                        break;
+#if AO_USB_HAS_IN2
+               case AO_USB_IN2_EPR:
+                       ++in2_count;
+                       _tx_dbg1("TX2 ISR", epr);
+                       if (ao_usb_epr_ctr_tx(epr)) {
+                               ao_usb_in2_pending = 0;
+                               ao_wakeup(&ao_usb_in2_pending);
+                       }
+                       break;
+#endif
                case AO_USB_INT_EPR:
                        ++int_count;
                        if (ao_usb_epr_ctr_tx(epr))
@@ -861,6 +926,7 @@ stm_usb_isr(void)
 #endif
 }
 
+#if AO_USB_HAS_IN
 /* Queue the current IN buffer for transmission */
 static void
 _ao_usb_in_send(void)
@@ -939,7 +1005,90 @@ ao_usb_putchar(char c)
        }
        ao_arch_release_interrupts();
 }
+#endif
+
+#if AO_USB_HAS_IN
+/* Queue the current IN buffer for transmission */
+static void
+_ao_usb_in2_send(void)
+{
+       _tx_dbg0("in2_send start");
+       debug ("send2 %d\n", ao_usb_tx_count);
+       while (ao_usb_in2_pending)
+               ao_sleep(&ao_usb_in2_pending);
+       ao_usb_in2_pending = 1;
+       if (ao_usb_tx2_count != AO_USB_IN_SIZE)
+               ao_usb_in2_flushed = 1;
+       ao_usb_copy_tx(ao_usb_tx2_buffer, ao_usb_in2_tx_buffer, ao_usb_tx2_count);
+       ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in_tx_offset;
+       ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = ao_usb_tx_count;
+       ao_usb_tx2_count = 0;
+       _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID);
+       _tx_dbg0("in2_send end");
+}
+
+/* Wait for a free IN buffer. Interrupts are blocked */
+static void
+_ao_usb_in2_wait(void)
+{
+       for (;;) {
+               /* Check if the current buffer is writable */
+               if (ao_usb_tx2_count < AO_USB_IN_SIZE)
+                       break;
+
+               _tx_dbg0("in2_wait top");
+               /* Wait for an IN buffer to be ready */
+               while (ao_usb_in2_pending)
+                       ao_sleep(&ao_usb_in2_pending);
+               _tx_dbg0("in_wait bottom");
+       }
+}
+
+void
+ao_usb_flush2(void)
+{
+       if (!ao_usb_running)
+               return;
+
+       /* Anytime we've sent a character since
+        * the last time we flushed, we'll need
+        * to send a packet -- the only other time
+        * we would send a packet is when that
+        * packet was full, in which case we now
+        * want to send an empty packet
+        */
+       ao_arch_block_interrupts();
+       while (!ao_usb_in2_flushed) {
+               _tx_dbg0("flush2 top");
+               _ao_usb_in2_send();
+               _tx_dbg0("flush2 end");
+       }
+       ao_arch_release_interrupts();
+}
+
+void
+ao_usb_putchar2(char c)
+{
+       if (!ao_usb_running)
+               return;
+
+       ao_arch_block_interrupts();
+       _ao_usb_in2_wait();
+
+       ao_usb_in2_flushed = 0;
+       ao_usb_tx2_buffer[ao_usb_tx2_count++] = (uint8_t) c;
+
+       /* Send the packet when full */
+       if (ao_usb_tx2_count == AO_USB_IN_SIZE) {
+               _tx_dbg0("putchar2 full");
+               _ao_usb_in2_send();
+               _tx_dbg0("putchar2 flushed");
+       }
+       ao_arch_release_interrupts();
+}
+#endif
 
+#if AO_USB_HAS_OUT
 static void
 _ao_usb_out_recv(void)
 {
@@ -996,6 +1145,7 @@ ao_usb_getchar(void)
        ao_arch_release_interrupts();
        return c;
 }
+#endif
 
 #if AO_USB_DIRECTIO
 uint16_t *
@@ -1050,6 +1200,43 @@ ao_usb_write(uint16_t *buffer, uint16_t len)
        _ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID);
        ao_arch_release_interrupts();
 }
+
+#if AO_USB_HAS_IN2
+void
+ao_usb_write2(uint16_t *buffer, uint16_t len)
+{
+       ao_arch_block_interrupts();
+
+       /* Wait for everything to be ready at the same time */
+       for (;;) {
+               /* Make sure USB is connected */
+               if (!ao_usb_running) {
+                       ao_sleep(&ao_usb_running);
+                       continue;
+               }
+
+               /* Flush any pending regular I/O */
+               if (ao_usb_tx2_count) {
+                       _ao_usb_in2_send();
+                       continue;
+               }
+
+               /* Wait for an idle IN buffer */
+               if (ao_usb_in2_pending) {
+                       ao_sleep(&ao_usb_in2_pending);
+                       continue;
+               }
+               break;
+       }
+
+       ao_usb_in2_pending = 1;
+       ao_usb_in2_flushed = (len != AO_USB_IN_SIZE);
+       ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_packet_buffer_offset(buffer);
+       ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = len;
+       _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID);
+       ao_arch_release_interrupts();
+}
+#endif
 #endif
 
 void
@@ -1180,7 +1367,9 @@ ao_usb_init(void)
        /* Set PA11/PA12 remapping bit */
        stm_syscfg.cfgr1 |= (AO_PA11_PA12_RMP << STM_SYSCFG_CFGR1_PA11_PA12_RMP);
 
+#ifndef AO_USB_START_DISABLED
        ao_usb_enable();
+#endif
 
 #if AO_USB_DEVICE_ID_SERIAL
        ao_usb_serial_init();