altos/stmf0: Have fast ADC ring buffer code use wrap-around
authorKeith Packard <keithp@keithp.com>
Fri, 20 Mar 2015 22:09:20 +0000 (15:09 -0700)
committerKeith Packard <keithp@keithp.com>
Fri, 20 Mar 2015 22:09:20 +0000 (15:09 -0700)
Instead of requiring that the whole set of returned values fit
precisely in the ring, allow for wrap-around so that we can fetch an
odd number of ADC values. The previous version required that the fetch
amount always be a factor of the ADC buffer size.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/drivers/ao_trng.c
src/drivers/ao_trng_send.c
src/stmf0/ao_adc_fast.c
src/stmf0/ao_adc_fast.h

index db7429282620fac4fef34aa00c216cba4b9d8bf3..e69cd30b3f8d37ec883aba669e3ef33d8a36c1de 100644 (file)
@@ -29,7 +29,8 @@ ao_trng_fetch(void)
        int             usb_buf_id;
        uint16_t        i;
        uint16_t        *buf;
-       uint32_t        *rnd;
+       uint16_t        t;
+       uint32_t        *rnd = (uint32_t *) ao_adc_ring;
 
        if (!buffer[0]) {
                buffer[0] = ao_usb_alloc();
@@ -50,10 +51,12 @@ ao_trng_fetch(void)
 
        ao_led_on(AO_LED_TRNG_READ);
        while (count--) {
-               rnd = (uint32_t *) ao_adc_get(AO_USB_IN_SIZE);  /* one 16-bit value per output byte */
+               t = ao_adc_get(AO_USB_IN_SIZE) >> 1;    /* one 16-bit value per output byte */
                buf = buffer[usb_buf_id];
-               for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++)
-                       *buf++ = ao_crc_in_32_out_16(*rnd++);
+               for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
+                       *buf++ = ao_crc_in_32_out_16(rnd[t]);
+                       t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1);
+               }
                ao_adc_ack(AO_USB_IN_SIZE);
                ao_led_toggle(AO_LED_TRNG_READ|AO_LED_TRNG_WRITE);
                ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE);
index 34a8a981bb866406e76a690b355c6e7548be5764..bac6035cd8dbde1b09fdb929debc5fc4b67a8c80 100644 (file)
@@ -27,7 +27,8 @@ ao_trng_send(void)
        int             usb_buf_id;
        uint16_t        i;
        uint16_t        *buf;
-       uint32_t        *rnd;
+       uint16_t        t;
+       uint32_t        *rnd = (uint32_t *) ao_adc_ring;
 
        if (!buffer[0]) {
                buffer[0] = ao_usb_alloc();
@@ -42,10 +43,12 @@ ao_trng_send(void)
 
        for (;;) {
                ao_led_on(AO_LED_TRNG_ACTIVE);
-               rnd = (uint32_t *) ao_adc_get(AO_USB_IN_SIZE);  /* one 16-bit value per output byte */
+               t = ao_adc_get(AO_USB_IN_SIZE) >> 1;    /* one 16-bit value per output byte */
                buf = buffer[usb_buf_id];
-               for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++)
-                       *buf++ = ao_crc_in_32_out_16(*rnd++);
+               for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
+                       *buf++ = ao_crc_in_32_out_16(rnd[t]);
+                       t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1);
+               }
                ao_adc_ack(AO_USB_IN_SIZE);
                ao_led_off(AO_LED_TRNG_ACTIVE);
                ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE);
index 7d2a4fd7e005df9f684de464d3ef431d6326238e..26e6691c914c87169d72905dbcdfe06ea393cca1 100644 (file)
@@ -23,7 +23,7 @@ uint16_t ao_adc_ring[AO_ADC_RING_SIZE] __attribute__((aligned(4)));
 /* Maximum number of samples fetched per _ao_adc_start call */
 #define AO_ADC_RING_CHUNK      (AO_ADC_RING_SIZE >> 1)
 
-uint16_t ao_adc_ring_head, ao_adc_ring_tail;
+uint16_t ao_adc_ring_head, ao_adc_ring_remain;
 uint16_t ao_adc_running;
 
 /*
@@ -36,6 +36,7 @@ static void ao_adc_dma_done(int index)
 {
        (void) index;
        ao_adc_ring_head += ao_adc_running;
+       ao_adc_ring_remain += ao_adc_running;
        if (ao_adc_ring_head == AO_ADC_RING_SIZE)
                ao_adc_ring_head = 0;
        ao_adc_running = 0;
index ca5f7fb9fc5a9d5ed864f3990b533adb25e9be90..c6903e9fcccb3b1d618eb29793bf861e87d6f659 100644 (file)
@@ -31,52 +31,53 @@ extern uint16_t     ao_adc_ring[AO_ADC_RING_SIZE];
 
 #define ao_adc_ring_step(pos,inc)      (((pos) + (inc)) & (AO_ADC_RING_SIZE - 1))
 
-extern uint16_t        ao_adc_ring_head, ao_adc_ring_tail;
+extern uint16_t        ao_adc_ring_head, ao_adc_ring_remain;
 extern uint16_t        ao_adc_running;
 
-void
-_ao_adc_start(void);
-
+/*
+ * Place to start fetching values from
+ */
 static inline uint16_t
-_ao_adc_remain(void)
+ao_adc_ring_tail(void)
 {
-       if (ao_adc_ring_tail > ao_adc_ring_head)
-               return AO_ADC_RING_SIZE - ao_adc_ring_tail;
-       return ao_adc_ring_head - ao_adc_ring_tail;
+       return (ao_adc_ring_head - ao_adc_ring_remain) & (AO_ADC_RING_SIZE - 1);
 }
 
+void
+_ao_adc_start(void);
+
+/*
+ * Space available to write ADC values into
+ */
 static inline uint16_t
 _ao_adc_space(void)
 {
-       if (ao_adc_ring_head >= ao_adc_ring_tail)
+       /* Free to end of buffer? */
+       if (ao_adc_ring_remain <= ao_adc_ring_head)
                return AO_ADC_RING_SIZE - ao_adc_ring_head;
-       return ao_adc_ring_tail - ao_adc_ring_head;
+
+       /* no, return just the unused entries beyond head */
+       return AO_ADC_RING_SIZE - ao_adc_ring_remain;
 }
 
-static inline uint16_t *
+static inline uint16_t
 ao_adc_get(uint16_t n)
 {
-       if (ao_adc_ring_tail + n > AO_ADC_RING_SIZE)
-               ao_panic(AO_PANIC_ADC);
        ao_arch_block_interrupts();
-       while (_ao_adc_remain() < n) {
+       while (ao_adc_ring_remain < n) {
                if (!ao_adc_running)
                        _ao_adc_start();
                ao_sleep(&ao_adc_ring_head);
        }
        ao_arch_release_interrupts();
-       return &ao_adc_ring[ao_adc_ring_tail];
+       return ao_adc_ring_tail();
 }
 
 static inline void
 ao_adc_ack(uint16_t n)
 {
-       if (ao_adc_ring_tail + n > AO_ADC_RING_SIZE)
-               ao_panic(AO_PANIC_ADC);
        ao_arch_block_interrupts();
-       ao_adc_ring_tail += n;
-       if (ao_adc_ring_tail == AO_ADC_RING_SIZE)
-               ao_adc_ring_tail = 0;
+       ao_adc_ring_remain -= n;
        if (!ao_adc_running)
                _ao_adc_start();
        ao_arch_release_interrupts();