Advertisement
manitou

w5100.cpp

May 27th, 2012
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.73 KB | None | 0 0
  1. /* thd DMA version
  2. * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
  3. *
  4. * This file is free software; you can redistribute it and/or modify
  5. * it under the terms of either the GNU General Public License version 2
  6. * or the GNU Lesser General Public License version 2.1, both as
  7. * published by the Free Software Foundation.
  8. */
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12. //#include <avr/interrupt.h>
  13.  
  14. #include "wirish.h"
  15. #include "w5100.h"
  16.  
  17. // DMA config stuff
  18. // SPI1 DMA1 RX CH2 TX CH3
  19. // SPI2 DMA1 RX CH4 TX CH5
  20. #include "dma.h"
  21. #define DMA_RX DMA_CH4
  22. #define DMA_TX DMA_CH5
  23. // make DMA_THRESHOLD big, e.g. 9999 if you don't want DMA
  24. #define DMA_THRESHOLD 4
  25. static uint8_t req[] = {0}; // don't use DMA_MINC_MODE
  26. static bool dmaActive;
  27.  
  28. // W5100 controller instance
  29. W5100Class W5100;
  30.  
  31. #define TX_RX_MAX_BUF_SIZE 2048
  32. #define TX_BUF 0x1100
  33. #define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)
  34.  
  35. #ifdef W5200
  36. #define TXBUF_BASE 0x8000
  37. #define RXBUF_BASE 0xC000
  38. #else
  39. #define TXBUF_BASE 0x4000
  40. #define RXBUF_BASE 0x6000
  41. #endif
  42.  
  43. static DEF_SPI_PORT;
  44.  
  45. // DMA support routines
  46. inline void DMAEvent(){
  47. dma_irq_cause event = dma_get_irq_cause(DMA1, DMA_TX);
  48. switch(event) {
  49. case DMA_TRANSFER_COMPLETE:
  50. dma_detach_interrupt(DMA1, DMA_RX);
  51. dma_detach_interrupt(DMA1, DMA_TX);
  52. dmaActive = false;
  53. break;
  54. case DMA_TRANSFER_ERROR:
  55. SerialUSB.println("DMA Error - read/write data might be corrupted");
  56. break;
  57. }
  58. }
  59.  
  60. static void dma_read(uint8_t *dst, uint16_t count)
  61. {
  62. // we send a dummy byte to get a byte of data from device
  63. // we don't use MINC since we're sending same byte
  64.  
  65. dma_setup_transfer(DMA1, DMA_RX, &SPI2->regs->DR, DMA_SIZE_8BITS, dst, DMA_SIZE_8BITS,
  66. (DMA_MINC_MODE | DMA_TRNS_CMPLT | DMA_TRNS_ERR));
  67. dma_attach_interrupt(DMA1, DMA_RX, DMAEvent);
  68. dma_setup_transfer(DMA1, DMA_TX, &SPI2->regs->DR, DMA_SIZE_8BITS, req, DMA_SIZE_8BITS,
  69. ( DMA_FROM_MEM));
  70. dma_set_priority(DMA1, DMA_RX, DMA_PRIORITY_VERY_HIGH);
  71. dma_set_priority(DMA1, DMA_TX, DMA_PRIORITY_VERY_HIGH);
  72. dma_set_num_transfers(DMA1, DMA_RX, count);
  73. dma_set_num_transfers(DMA1, DMA_TX, count);
  74.  
  75. dmaActive = true;
  76. dma_enable(DMA1, DMA_TX);
  77. dma_enable(DMA1, DMA_RX);
  78.  
  79. while(dmaActive) delayMicroseconds(1);
  80. dma_disable(DMA1, DMA_TX);
  81. dma_disable(DMA1, DMA_RX);
  82. }
  83.  
  84. static void dma_write(uint8_t *src, uint16_t count)
  85. {
  86. // while writing to device we just ignore the data coming back from device
  87.  
  88. dma_setup_transfer(DMA1, DMA_TX, &SPI2->regs->DR, DMA_SIZE_8BITS, src, DMA_SIZE_8BITS,
  89. (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT | DMA_TRNS_ERR ));
  90. dma_attach_interrupt(DMA1, DMA_TX, DMAEvent);
  91. dma_set_priority(DMA1, DMA_TX, DMA_PRIORITY_VERY_HIGH);
  92. dma_set_num_transfers(DMA1, DMA_TX, count);
  93.  
  94. dmaActive = true;
  95. dma_enable(DMA1, DMA_TX);
  96.  
  97. while(dmaActive) delayMicroseconds(1);
  98. dma_disable(DMA1, DMA_TX);
  99. }
  100.  
  101.  
  102. void W5100Class::init(void)
  103. {
  104. delay(300);
  105.  
  106. SPI.begin(ETHERNET_SPI_FREQ, MSBFIRST,0);
  107. dma_init(DMA1);
  108. spi_rx_dma_enable(SPI2); //enable SPI over DMA
  109. spi_tx_dma_enable(SPI2);
  110. dmaActive = false; //DMA activity control
  111.  
  112. initSS();
  113.  
  114. writeMR(1<<RST);
  115.  
  116. #ifdef W5200
  117. for (int i=0; i<MAX_SOCK_NUM; i++) {
  118. write((0x4000 + i * 0x100 + 0x001F), 2);
  119. write((0x4000 + i * 0x100 + 0x001E), 2);
  120. }
  121. #else
  122. writeTMSR(0x55);
  123. writeRMSR(0x55);
  124. #endif
  125.  
  126. for (int i=0; i<MAX_SOCK_NUM; i++) {
  127. SBASE[i] = TXBUF_BASE + SSIZE * i;
  128. RBASE[i] = RXBUF_BASE + RSIZE * i;
  129. }
  130. }
  131.  
  132. uint16_t W5100Class::getTXFreeSize(SOCKET s)
  133. {
  134. uint16_t val=0, val1=0;
  135. do {
  136. val1 = readSnTX_FSR(s);
  137. if (val1 != 0)
  138. val = readSnTX_FSR(s);
  139. }
  140. while (val != val1);
  141. return val;
  142. }
  143.  
  144. uint16_t W5100Class::getRXReceivedSize(SOCKET s)
  145. {
  146. uint16_t val=0,val1=0;
  147. do {
  148. val1 = readSnRX_RSR(s);
  149. if (val1 != 0)
  150. val = readSnRX_RSR(s);
  151. }
  152. while (val != val1);
  153. return val;
  154. }
  155.  
  156.  
  157. void W5100Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len)
  158. {
  159. // This is same as having no offset in a call to send_data_processing_offset
  160. send_data_processing_offset(s, 0, data, len);
  161. }
  162.  
  163. void W5100Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len)
  164. {
  165. uint16_t ptr = readSnTX_WR(s);
  166. ptr += data_offset;
  167. uint16_t offset = ptr & SMASK;
  168. uint16_t dstAddr = offset + SBASE[s];
  169.  
  170. if (offset + len > SSIZE)
  171. {
  172. // Wrap around circular buffer
  173. uint16_t size = SSIZE - offset;
  174. write(dstAddr, data, size);
  175. write(SBASE[s], data + size, len - size);
  176. }
  177. else {
  178. write(dstAddr, data, len);
  179. }
  180.  
  181. ptr += len;
  182. writeSnTX_WR(s, ptr);
  183. }
  184.  
  185.  
  186. void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek)
  187. {
  188. uint16_t ptr;
  189. ptr = readSnRX_RD(s);
  190. read_data(s, (uint8_t *)ptr, data, len);
  191. if (!peek)
  192. {
  193. ptr += len;
  194. writeSnRX_RD(s, ptr);
  195. }
  196. }
  197.  
  198. void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len)
  199. {
  200. uint16_t size;
  201. uint16_t src_mask;
  202. uint16_t src_ptr;
  203.  
  204. src_mask = (uint16_t)((uint32_t)src & RMASK);
  205. src_ptr = RBASE[s] + src_mask;
  206.  
  207. if( (src_mask + len) > RSIZE )
  208. {
  209. size = RSIZE - src_mask;
  210. read(src_ptr, (uint8_t *)dst, size);
  211. dst += size;
  212. read(RBASE[s], (uint8_t *) dst, len - size);
  213. }
  214. else
  215. read(src_ptr, (uint8_t *) dst, len);
  216. }
  217.  
  218.  
  219. uint8_t W5100Class::write(uint16_t _addr, uint8_t _data)
  220. {
  221. setSS();
  222.  
  223. #ifdef W5200
  224. SPI.transfer(_addr >> 8);
  225. SPI.transfer(_addr & 0xFF);
  226. SPI.transfer(0x80);
  227. SPI.transfer(0x01);
  228. #else
  229. SPI.transfer(0xF0);
  230. SPI.transfer(_addr >> 8);
  231. SPI.transfer(_addr & 0xFF);
  232. #endif
  233.  
  234. SPI.transfer(_data);
  235. resetSS();
  236. return 1;
  237. }
  238.  
  239. uint16_t W5100Class::write(uint16_t _addr,const uint8_t *_buf, uint16_t _len)
  240. {
  241.  
  242. #ifdef W5200
  243. setSS();
  244. SPI.transfer(_addr >> 8);
  245. SPI.transfer(_addr & 0xFF);
  246. SPI.transfer((0x80 | ((_len & 0x7F00) >> 8)));
  247. SPI.transfer(_len & 0x00FF);
  248.  
  249. if(_len > DMA_THRESHOLD) dma_write((uint8_t *)_buf,_len);
  250. else for (uint16_t i=0; i<_len; i++)
  251. {
  252. SPI.transfer(_buf[i]);
  253.  
  254. }
  255. resetSS();
  256. #else
  257.  
  258. for (uint16_t i=0; i<_len; i++)
  259. {
  260. setSS();
  261. SPI.transfer(0xF0);
  262. SPI.transfer(_addr >> 8);
  263. SPI.transfer(_addr & 0xFF);
  264. _addr++;
  265. SPI.transfer(_buf[i]);
  266. resetSS();
  267. }
  268. #endif
  269.  
  270. return _len;
  271. }
  272.  
  273. uint8_t W5100Class::read(uint16_t _addr)
  274. {
  275. setSS();
  276. #ifdef W5200
  277. SPI.transfer(_addr >> 8);
  278. SPI.transfer(_addr & 0xFF);
  279. SPI.transfer(0x00);
  280. SPI.transfer(0x01);
  281. #else
  282. SPI.transfer(0x0F);
  283. SPI.transfer(_addr >> 8);
  284. SPI.transfer(_addr & 0xFF);
  285. #endif
  286.  
  287. uint8_t _data = SPI.transfer(0);
  288. resetSS();
  289. return _data;
  290. }
  291.  
  292. uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
  293. {
  294. #ifdef W5200
  295. setSS();
  296. SPI.transfer(_addr >> 8);
  297. SPI.transfer(_addr & 0xFF);
  298. SPI.transfer((0x00 | ((_len & 0x7F00) >> 8)));
  299. SPI.transfer(_len & 0x00FF);
  300.  
  301. if (_len > DMA_THRESHOLD) dma_read(_buf,_len);
  302. else for (uint16_t i=0; i<_len; i++)
  303. {
  304. _buf[i] = SPI.transfer(0);
  305.  
  306. }
  307. resetSS();
  308.  
  309. #else
  310.  
  311. for (uint16_t i=0; i<_len; i++)
  312. {
  313. setSS();
  314. SPI.transfer(0x0F);
  315. SPI.transfer(_addr >> 8);
  316. SPI.transfer(_addr & 0xFF);
  317. _addr++;
  318. _buf[i] = SPI.transfer(0);
  319. resetSS();
  320. }
  321. #endif
  322. return _len;
  323. }
  324.  
  325. void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) {
  326. // Send command to socket
  327. writeSnCR(s, _cmd);
  328. // Wait for command to complete
  329. while (readSnCR(s))
  330. ;
  331. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement