spi.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * CNC-remote-control
  3. * SPI primitives
  4. *
  5. * Copyright (C) 2011 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include "spi.h"
  17. #include <avr/wdt.h>
  18. #include <avr/interrupt.h>
  19. #if SPI_HAVE_ASYNC
  20. static struct spi_async_state {
  21. uint8_t flags;
  22. uint8_t wait_ms;
  23. uint8_t wait_ms_left;
  24. uint8_t bytes_left;
  25. const uint8_t *txbuf;
  26. uint8_t *rxbuf;
  27. } async_state;
  28. static void spi_transfer_async(void)
  29. {
  30. uint8_t txbyte;
  31. if (async_state.flags & SPI_ASYNC_TXPROGMEM) {
  32. const uint8_t PROGPTR *p = (const uint8_t PROGPTR *)async_state.txbuf;
  33. txbyte = pgm_read_byte(p);
  34. } else
  35. txbyte = *async_state.txbuf;
  36. async_state.txbuf++;
  37. async_state.bytes_left--;
  38. mb();
  39. SPDR = txbyte;
  40. }
  41. ISR(SPI_STC_vect)
  42. {
  43. uint8_t rxbyte;
  44. rxbyte = SPDR;
  45. *async_state.rxbuf = rxbyte;
  46. async_state.rxbuf++;
  47. if (async_state.bytes_left) {
  48. if (async_state.wait_ms)
  49. async_state.wait_ms_left =
  50. (uint8_t)(async_state.wait_ms + 1u);
  51. else
  52. spi_transfer_async();
  53. } else {
  54. SPCR = (uint8_t)(SPCR & ~(1u << SPIE));
  55. spi_slave_select(0);
  56. mb();
  57. async_state.flags = (uint8_t)(async_state.flags & ~SPI_ASYNC_RUNNING);
  58. spi_async_done();
  59. }
  60. }
  61. void spi_async_start(void *rxbuf, const void *txbuf,
  62. uint8_t nr_bytes, uint8_t flags, uint8_t wait_ms)
  63. {
  64. BUG_ON(ATOMIC_LOAD(async_state.flags) & SPI_ASYNC_RUNNING);
  65. BUG_ON(!nr_bytes);
  66. async_state.flags = flags | SPI_ASYNC_RUNNING;
  67. async_state.bytes_left = nr_bytes;
  68. async_state.wait_ms = wait_ms;
  69. async_state.wait_ms_left = 0;
  70. async_state.txbuf = txbuf;
  71. async_state.rxbuf = rxbuf;
  72. mb();
  73. (void)SPSR; /* clear state */
  74. (void)SPDR; /* clear state */
  75. SPCR |= (1 << SPIE);
  76. spi_slave_select(1);
  77. spi_transfer_async();
  78. }
  79. bool spi_async_running(void)
  80. {
  81. return !!(ATOMIC_LOAD(async_state.flags) & SPI_ASYNC_RUNNING);
  82. }
  83. void spi_async_ms_tick(void)
  84. {
  85. bool send_next = 0;
  86. irq_disable();
  87. if (!(async_state.flags & SPI_ASYNC_RUNNING)) {
  88. irq_enable();
  89. return;
  90. }
  91. if (async_state.wait_ms_left == 0) {
  92. irq_enable();
  93. return;
  94. }
  95. async_state.wait_ms_left--;
  96. if (async_state.wait_ms_left == 0)
  97. send_next = 1;
  98. irq_enable();
  99. if (send_next)
  100. spi_transfer_async();
  101. }
  102. #endif /* SPI_HAVE_ASYNC */
  103. uint8_t spi_transfer_sync(uint8_t tx)
  104. {
  105. SPDR = tx;
  106. while (!(SPSR & (1 << SPIF)));
  107. return SPDR;
  108. }
  109. uint8_t spi_transfer_slowsync(uint8_t tx)
  110. {
  111. _delay_ms(10);
  112. return spi_transfer_sync(tx);
  113. }
  114. void spi_lowlevel_exit(void)
  115. {
  116. SPCR = 0;
  117. SPSR = 0;
  118. SPDR = 0;
  119. (void)SPSR; /* clear state */
  120. (void)SPDR; /* clear state */
  121. DDRB = 0;
  122. }
  123. void spi_lowlevel_init(void)
  124. {
  125. spi_slave_select(0);
  126. DDRB = (uint8_t)(DDRB | (1u << 5/*MOSI*/) |
  127. (1u << 7/*SCK*/) |
  128. (1u << 4/*SS*/));
  129. DDRB = (uint8_t)(DDRB & ~(1u << 6/*MISO*/));
  130. SPI_MASTER_TRANSIRQ_DDR = (uint8_t)(SPI_MASTER_TRANSIRQ_DDR &
  131. ~(1u << SPI_MASTER_TRANSIRQ_BIT));
  132. SPI_MASTER_TRANSIRQ_PORT = (uint8_t)(SPI_MASTER_TRANSIRQ_PORT &
  133. ~(1u << SPI_MASTER_TRANSIRQ_BIT));
  134. GICR = (uint8_t)(GICR & ~(1u << SPI_MASTER_TRANSIRQ_INT));
  135. SPCR = (1u << SPE) | (1u << MSTR) |
  136. (0u << CPOL) | (0u << CPHA) |
  137. (0u << SPR0) | (1u << SPR1);
  138. SPSR = 0u;
  139. long_delay_ms(150);
  140. (void)SPSR; /* clear state */
  141. (void)SPDR; /* clear state */
  142. }