You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

137 lines
3.4 KiB

  1. #include "config.h"
  2. #include "adcext.h"
  3. /* The ADC (AD7846) is tricky, as new conversions start
  4. automatically when the previous data read finishes.
  5. To allow more control over start/read, we stretch the
  6. read indefinitely by delaying the final SCK edge.
  7. This means we can't have the hardware do SPI for us. */
  8. /* External serial clock, 2-wire I/O -- tie /EXT low,
  9. tie ADC SDI for rate selection, tie /CS low, use BUSY for
  10. interrupt notification if desired */
  11. #define TRIS_SDO TRISBbits.TRISB5
  12. #define R_SDO PORTBbits.RB5
  13. #define TRIS_SCK TRISBbits.TRISB4
  14. #define LAT_SCK LATBbits.LATB4
  15. #define TRIS_SCS TRISBbits.TRISB3
  16. #define LAT_SCS LATBbits.LATB3
  17. /* Short delays */
  18. #define wait_200ns() do { \
  19. nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); \
  20. } while(0)
  21. #define wait_25ns() nop()
  22. /* Initialize ADC */
  23. void adcext_init(void)
  24. {
  25. int32_t i;
  26. TRIS_SDO = 1;
  27. LAT_SCK = IO_HIGH;
  28. TRIS_SCK = 0;
  29. LAT_SCS = IO_LOW;
  30. TRIS_SCS = 0;
  31. /* Startup delay CS down to SCK high t4 = 5000ns */
  32. for (i = 0; i < 5000 / 25; i++)
  33. wait_25ns();
  34. /* We need to monitor BUSY, I think. With the 2-wire
  35. interface, we never know if we start in the middle of
  36. a data output phase. For now, consider reading broken..
  37. just return early. XXXX */
  38. return;
  39. /* Trigger a dummy read so we're prepared for the
  40. next conversion */
  41. (void) adcext_read();
  42. }
  43. /* Start a conversion if it hasn't already been started.
  44. Wait for conversion to finish.
  45. Read the result and return the raw 32-bit value. */
  46. uint32_t adcext_read(void)
  47. {
  48. uint32_t val;
  49. int i;
  50. /* Start conversion by completing previous read */
  51. LAT_SCK = IO_LOW;
  52. /* Wait tKQMAX for SCK down to SDO valid */
  53. wait_200ns();
  54. /* Wait for conversion to finish */
  55. while (R_SDO == IO_HIGH)
  56. continue;
  57. /* Read it out */
  58. val = 0;
  59. for (i = 0; i < 32; i++) {
  60. /* SCK low tLESCK = 25ns */
  61. wait_25ns();
  62. LAT_SCK = IO_HIGH;
  63. /* SCK high tHESCK = 25ns, but
  64. we also have SCK down to SDO valid tKQMAX = 200ns?
  65. Probably misspecified but wait tKQMAX anyway. */
  66. wait_200ns();
  67. val <<= 1;
  68. if (R_SDO == IO_HIGH)
  69. val |= 1;
  70. /* Leave SCK high on final bit to delay new conversion */
  71. if (i < 31)
  72. LAT_SCK = IO_LOW;
  73. }
  74. /* Done */
  75. return val;
  76. }
  77. /* Convert a raw 32-bit value into a signed 32-bit result.
  78. The return value is full int32 range but only the high
  79. 24 should be significant: low 3 will always be 0,
  80. and the next 5 will be sub-resolution (see datasheet). */
  81. int32_t adcext_convert(uint32_t raw)
  82. {
  83. int sigmsb = (raw >> 28) & 3;
  84. /* If SIG & MSB, it is a positive overflow */
  85. if (sigmsb == 3)
  86. return (int32_t)0x7FFFFFFFL;
  87. /* If !SIG & !MSB, it is a negative overflow */
  88. if (sigmsb == 0)
  89. return (int32_t)0x80000000L;
  90. /* Shift over EOC,DMY,SIG and return */
  91. return ((int32_t)(raw << 3));
  92. }
  93. /* Start a new conversion. If a conversion was already started
  94. but the result was not read, this does nothing. */
  95. void adcext_start_conversion(void)
  96. {
  97. /* If we had a previous conversion ready to read,
  98. read it out so we can start a new conversion instead */
  99. if (adcext_is_conversion_ready())
  100. (void) adcext_read();
  101. /* Start conversion by completing previous read */
  102. LAT_SCK = 0;
  103. /* Wait tKQMAX for SCK down to SDO valid in case we
  104. call adcext_is_conversion_ready right away. */
  105. wait_200ns();
  106. }
  107. /* Return 1 if a conversion is finished and ready to be read, 0 otherwise */
  108. int adcext_is_conversion_ready(void)
  109. {
  110. if (LAT_SCK == 0 && R_SDO == 0)
  111. return 1;
  112. return 0;
  113. }