|
- #include "config.h"
- #include "adc.h"
-
- /* The ADC (AD7846) is tricky, as new conversions start
- automatically when the previous data read finishes.
- To allow more control over start/read, we stretch the
- read indefinitely by delaying the final SCK edge.
- This means we can't have the hardware do SPI for us. */
-
- /* External serial clock, 2-wire I/O -- tie /EXT low,
- tie SDI for rate selection, tie /CS low, use BUSY for
- interrupt notification if desired */
-
- #define TRIS_SDO TRISEbits.TRISE7
- #define R_SDO PORTEbits.RE7
- #define TRIS_SCK TRISEbits.TRISE6
- #define LAT_SCK LATEbits.LATE6
-
- /* Short delays */
- #define wait_200ns() do { \
- nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); \
- } while(0)
- #define wait_25ns() nop()
-
- /* Initialize ADC */
- void adc_init(void)
- {
- int i;
-
- TRIS_SDO = 1;
- LAT_SCK = 0;
- TRIS_SCK = 0;
-
- /* Startup delay CS down to SCK high t4 = 5000ns */
- for (i = 0; i < 5000 / 25; i++)
- wait_25ns();
-
- /* Trigger a dummy read so we're prepared for the
- next conversion */
- (void) adc_read();
- }
-
- /* Start a conversion if it hasn't already been started.
- Wait for conversion to finish.
- Read the result. */
- uint32_t adc_read(void)
- {
- uint32_t val;
- int i;
-
- /* Start conversion by completing previous read */
- LAT_SCK = 0;
-
- /* Wait tKQMAX for SCK down to SDO valid */
- wait_200ns();
-
- /* Wait for conversion to finish */
- while (R_SDO == 1)
- continue;
-
- /* Read it out */
- val = 0;
- for (i = 0; i < 32; i++) {
- /* SCK low tLESCK = 25ns */
- wait_25ns();
- LAT_SCK = 1;
-
- /* SCK high tHESCK = 25ns, but
- we also have SCK down to SDO valid tKQMAX = 200ns?
- Probably misspecified but wait tKQMAX anyway. */
- wait_200ns();
-
- val <<= 1;
- if (R_SDO)
- val |= 1;
- /* Leave SCK high on final bit to delay new conversion */
- if (i < 31)
- LAT_SCK = 0;
- }
-
- /* Done */
- return val;
- }
-
- /* Start a new conversion. If a conversion was already started
- but the result was not read, this does nothing. */
- void adc_start_conversion(void)
- {
- /* Start conversion by completing previous read */
- LAT_SCK = 0;
-
- /* Wait tKQMAX for SCK down to SDO valid in case we
- call adc_is_conversion_finished right away. */
- wait_200ns();
- }
-
- /* Return 1 if a conversion is in progress, 0 otherwise */
- int adc_is_conversion_finished(void)
- {
- if (LAT_SCK == 0 && R_SDO == 1)
- return 1;
- return 0;
- }
|