/Buderus/network/enc28j60.c

https://bitbucket.org/googy/buderus · C · 268 lines · 189 code · 45 blank · 34 comment · 14 complexity · bb1eb0c61740ed0a6186fd3659c6e762 MD5 · raw file

  1. #include "enc28j60.h"
  2. /*
  3. * SPI
  4. */
  5. uint8_t enc28j60_current_bank = 0;
  6. uint16_t enc28j60_rxrdpt = 0;
  7. #define enc28j60_select() ENC28J60_SPI_PORT &= ~ENC28J60_SPI_CS
  8. #define enc28j60_release() ENC28J60_SPI_PORT |= ENC28J60_SPI_CS
  9. uint8_t enc28j60_rxtx(uint8_t data)
  10. {
  11. SPDR = data;
  12. while(!(SPSR & (1<<SPIF)))
  13. ;
  14. return SPDR;
  15. }
  16. #define enc28j60_rx() enc28j60_rxtx(0xff)
  17. #define enc28j60_tx(data) enc28j60_rxtx(data)
  18. // Generic SPI read command
  19. uint8_t enc28j60_read_op(uint8_t cmd, uint8_t adr)
  20. {
  21. uint8_t data;
  22. enc28j60_select();
  23. enc28j60_tx(cmd | (adr & ENC28J60_ADDR_MASK));
  24. if(adr & 0x80) // throw out dummy byte
  25. enc28j60_rx(); // when reading MII/MAC register
  26. data = enc28j60_rx();
  27. enc28j60_release();
  28. return data;
  29. }
  30. // Generic SPI write command
  31. void enc28j60_write_op(uint8_t cmd, uint8_t adr, uint8_t data)
  32. {
  33. enc28j60_select();
  34. enc28j60_tx(cmd | (adr & ENC28J60_ADDR_MASK));
  35. enc28j60_tx(data);
  36. enc28j60_release();
  37. }
  38. // Initiate software reset
  39. void enc28j60_soft_reset()
  40. {
  41. enc28j60_select();
  42. enc28j60_tx(ENC28J60_SPI_SC);
  43. enc28j60_release();
  44. enc28j60_current_bank = 0;
  45. _delay_ms(1); // Wait until device initializes
  46. }
  47. /*
  48. * Memory access
  49. */
  50. // Set register bank
  51. void enc28j60_set_bank(uint8_t adr)
  52. {
  53. uint8_t bank;
  54. if( (adr & ENC28J60_ADDR_MASK) < ENC28J60_COMMON_CR )
  55. {
  56. bank = (adr >> 5) & 0x03; //BSEL1|BSEL0=0x03
  57. if(bank != enc28j60_current_bank)
  58. {
  59. enc28j60_write_op(ENC28J60_SPI_BFC, ECON1, 0x03);
  60. enc28j60_write_op(ENC28J60_SPI_BFS, ECON1, bank);
  61. enc28j60_current_bank = bank;
  62. }
  63. }
  64. }
  65. // Read register
  66. uint8_t enc28j60_rcr(uint8_t adr)
  67. {
  68. enc28j60_set_bank(adr);
  69. return enc28j60_read_op(ENC28J60_SPI_RCR, adr);
  70. }
  71. // Read register pair
  72. uint16_t enc28j60_rcr16(uint8_t adr)
  73. {
  74. enc28j60_set_bank(adr);
  75. return enc28j60_read_op(ENC28J60_SPI_RCR, adr) |
  76. (enc28j60_read_op(ENC28J60_SPI_RCR, adr+1) << 8);
  77. }
  78. // Write register
  79. void enc28j60_wcr(uint8_t adr, uint8_t arg)
  80. {
  81. enc28j60_set_bank(adr);
  82. enc28j60_write_op(ENC28J60_SPI_WCR, adr, arg);
  83. }
  84. // Write register pair
  85. void enc28j60_wcr16(uint8_t adr, uint16_t arg)
  86. {
  87. enc28j60_set_bank(adr);
  88. enc28j60_write_op(ENC28J60_SPI_WCR, adr, arg);
  89. enc28j60_write_op(ENC28J60_SPI_WCR, adr+1, arg>>8);
  90. }
  91. // Clear bits in register (reg &= ~mask)
  92. void enc28j60_bfc(uint8_t adr, uint8_t mask)
  93. {
  94. enc28j60_set_bank(adr);
  95. enc28j60_write_op(ENC28J60_SPI_BFC, adr, mask);
  96. }
  97. // Set bits in register (reg |= mask)
  98. void enc28j60_bfs(uint8_t adr, uint8_t mask)
  99. {
  100. enc28j60_set_bank(adr);
  101. enc28j60_write_op(ENC28J60_SPI_BFS, adr, mask);
  102. }
  103. // Read Rx/Tx buffer (at ERDPT)
  104. void enc28j60_read_buffer(uint8_t *buf, uint16_t len)
  105. {
  106. enc28j60_select();
  107. enc28j60_tx(ENC28J60_SPI_RBM);
  108. while(len--)
  109. *(buf++) = enc28j60_rx();
  110. enc28j60_release();
  111. }
  112. // Write Rx/Tx buffer (at EWRPT)
  113. void enc28j60_write_buffer(uint8_t *buf, uint16_t len)
  114. {
  115. enc28j60_select();
  116. enc28j60_tx(ENC28J60_SPI_WBM);
  117. while(len--)
  118. enc28j60_tx(*(buf++));
  119. enc28j60_release();
  120. }
  121. // Read PHY register
  122. uint16_t enc28j60_read_phy(uint8_t adr)
  123. {
  124. enc28j60_wcr(MIREGADR, adr);
  125. enc28j60_bfs(MICMD, MICMD_MIIRD);
  126. while(enc28j60_rcr(MISTAT) & MISTAT_BUSY)
  127. ;
  128. enc28j60_bfc(MICMD, MICMD_MIIRD);
  129. return enc28j60_rcr16(MIRD);
  130. }
  131. // Write PHY register
  132. void enc28j60_write_phy(uint8_t adr, uint16_t data)
  133. {
  134. enc28j60_wcr(MIREGADR, adr);
  135. enc28j60_wcr16(MIWR, data);
  136. while(enc28j60_rcr(MISTAT) & MISTAT_BUSY)
  137. ;
  138. }
  139. /*
  140. * Init & packet Rx/Tx
  141. */
  142. void enc28j60_init(uint8_t *macadr)
  143. {
  144. // Initialize SPI
  145. ENC28J60_SPI_DDR |= ENC28J60_SPI_CS|ENC28J60_SPI_MOSI|ENC28J60_SPI_SCK;
  146. ENC28J60_SPI_DDR &= ~ENC28J60_SPI_MISO;
  147. enc28j60_release();
  148. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);
  149. //SPSR |= (1<<SPI2X); // Maximum speed
  150. // Reset ENC28J60
  151. enc28j60_soft_reset();
  152. // Setup Rx/Tx buffer
  153. enc28j60_wcr16(ERXST, ENC28J60_RXSTART);
  154. enc28j60_wcr16(ERXRDPT, ENC28J60_RXSTART);
  155. enc28j60_wcr16(ERXND, ENC28J60_RXEND);
  156. enc28j60_rxrdpt = ENC28J60_RXSTART;
  157. // Setup MAC
  158. enc28j60_wcr(MACON1, MACON1_TXPAUS| // Enable flow control
  159. MACON1_RXPAUS|MACON1_MARXEN); // Enable MAC Rx
  160. enc28j60_wcr(MACON2, 0); // Clear reset
  161. enc28j60_wcr(MACON3, MACON3_PADCFG0| // Enable padding,
  162. MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX); // Enable crc & frame len chk
  163. enc28j60_wcr16(MAMXFL, ENC28J60_MAXFRAME);
  164. enc28j60_wcr(MABBIPG, 0x15); // Set inter-frame gap
  165. enc28j60_wcr(MAIPGL, 0x12);
  166. enc28j60_wcr(MAIPGH, 0x0c);
  167. enc28j60_wcr(MAADR5, macadr[0]); // Set MAC address
  168. enc28j60_wcr(MAADR4, macadr[1]);
  169. enc28j60_wcr(MAADR3, macadr[2]);
  170. enc28j60_wcr(MAADR2, macadr[3]);
  171. enc28j60_wcr(MAADR1, macadr[4]);
  172. enc28j60_wcr(MAADR0, macadr[5]);
  173. // Setup PHY
  174. enc28j60_write_phy(PHCON1, PHCON1_PDPXMD); // Force full-duplex mode
  175. enc28j60_write_phy(PHCON2, PHCON2_HDLDIS); // Disable loopback
  176. enc28j60_write_phy(PHLCON, PHLCON_LACFG2| // Configure LED ctrl
  177. PHLCON_LBCFG2|PHLCON_LBCFG1|PHLCON_LBCFG0|
  178. PHLCON_LFRQ0|PHLCON_STRCH);
  179. // Enable Rx packets
  180. enc28j60_bfs(ECON1, ECON1_RXEN);
  181. }
  182. void enc28j60_send_packet(uint8_t *data, uint16_t len)
  183. {
  184. while(enc28j60_rcr(ECON1) & ECON1_TXRTS)
  185. {
  186. // TXRTS may not clear - ENC28J60 bug. We must reset
  187. // transmit logic in cause of Tx error
  188. if(enc28j60_rcr(EIR) & EIR_TXERIF)
  189. {
  190. enc28j60_bfs(ECON1, ECON1_TXRST);
  191. enc28j60_bfc(ECON1, ECON1_TXRST);
  192. }
  193. }
  194. enc28j60_wcr16(EWRPT, ENC28J60_TXSTART);
  195. enc28j60_write_buffer((uint8_t*)"\x00", 1);
  196. enc28j60_write_buffer(data, len);
  197. enc28j60_wcr16(ETXST, ENC28J60_TXSTART);
  198. enc28j60_wcr16(ETXND, ENC28J60_TXSTART + len);
  199. enc28j60_bfs(ECON1, ECON1_TXRTS); // Request packet send
  200. }
  201. uint16_t enc28j60_recv_packet(uint8_t *buf, uint16_t buflen)
  202. {
  203. uint16_t len = 0, rxlen, status, temp;
  204. if(enc28j60_rcr(EPKTCNT))
  205. {
  206. enc28j60_wcr16(ERDPT, enc28j60_rxrdpt);
  207. enc28j60_read_buffer((void*)&enc28j60_rxrdpt, sizeof(enc28j60_rxrdpt));
  208. enc28j60_read_buffer((void*)&rxlen, sizeof(rxlen));
  209. enc28j60_read_buffer((void*)&status, sizeof(status));
  210. if(status & 0x80) //success
  211. {
  212. len = rxlen - 4; //throw out crc
  213. if(len > buflen) len = buflen;
  214. enc28j60_read_buffer(buf, len);
  215. }
  216. // Set Rx read pointer to next packet
  217. temp = (enc28j60_rxrdpt - 1) & ENC28J60_BUFEND;
  218. enc28j60_wcr16(ERXRDPT, temp);
  219. // Decrement packet counter
  220. enc28j60_bfs(ECON2, ECON2_PKTDEC);
  221. }
  222. return len;
  223. }