Paparazzi UAS  v5.12_stable-4-g9b43e9b
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
w5100.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 Gerard Toonstra
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi 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  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22 
28 #include "mcu_periph/sys_time.h"
30 #include "mcu_periph/spi.h"
31 #include "mcu_periph/gpio.h"
32 
33 #define TXBUF_BASE 0x4000
34 #define RXBUF_BASE 0x6000
35 #define SOCKETS 4
36 
37 #define CMD_SOCKET 1
38 #define TELEM_SOCKET 0
39 
40 #define SOCK_OPEN 0x01
41 #define SOCK_CLOSE 0x10
42 #define SOCK_SEND 0x20
43 #define SOCK_RECV 0x40
44 #define SNMR_UDP 0x02
45 #define SNMR_MULTI 0x80
46 #define SNIR_SEND_OK 0x10
47 #define SNIR_TIMEOUT 0x08
48 #define CH_BASE 0x0400
49 #define CH_SIZE 0x0100
50 #define SMASK 0x07FF // Tx buffer MASK
51 #define RMASK 0x07FF // Tx buffer MASK
52 
53 #define REG_MR 0x0000
54 #define REG_RX_MEM 0x001A
55 #define REG_TX_MEM 0x001B
56 
57 #define REG_GAR 0x0001
58 #define REG_SUBR 0x0005
59 #define REG_SHAR 0x0009
60 #define REG_SIPR 0x000F
61 
62 #define SOCK_MR 0x0000
63 #define SOCK_CR 0x0001
64 #define SOCK_IR 0x0002
65 #define SOCK_PORT 0x0004
66 #define SOCK_DHAR 0x0006
67 #define SOCK_DIPR 0x000C
68 #define SOCK_DPORT 0x0010
69 #define SOCK_TX_WR 0x0024
70 #define SOCK_RSR 0x0026
71 #define SOCK_RXRD 0x0028
72 
73 #ifndef W5100_SPI_DEV
74 #define W5100_SPI_DEV spi1
75 #endif
76 
77 #ifndef W5100_SLAVE_IDX
78 #define W5100_SLAVE_IDX SPI_SLAVE1
79 #endif
80 
81 #ifndef W5100_DRDY_GPIO
82 #define W5100_DRDY_GPIO GPIOB
83 #endif
84 
85 #ifndef W5100_DRDY_GPIO_PIN
86 #define W5100_DRDY_GPIO_PIN GPIO1
87 #endif
88 
89 struct pprz_w5100_tp;
93 
94 // the media access control (ethernet hardware) address for the shield.
95 static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
96 
97 //the IP address for the shield:
98 static uint8_t ip[] = { W5100_IP };
99 static uint8_t dest[] = { W5100_MULTICAST_IP };
100 static uint8_t subnet[] = { W5100_SUBNET };
101 static uint16_t dport = W5100_MULTICAST_PORT;
102 
103 static const uint8_t RST = 7; // Reset BIT
104 
105 uint16_t SBASE[SOCKETS]; // Tx buffer base address
106 uint16_t RBASE[SOCKETS]; // Rx buffer base address
107 static const uint16_t SSIZE = 2048; // Max Tx buffer size
108 static const uint16_t RSIZE = 2048; // Max Rx buffer size
109 
111 
112 static void w5100_close_socket(uint8_t _s);
113 static void configure_socket(uint8_t _s, uint8_t _flag, uint16_t _lport, uint16_t _dport, uint8_t *_dest);
114 static void w5100_read_data(uint8_t s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len);
115 static uint16_t w5100_read(uint16_t _addr, uint8_t *_buf, uint16_t _len);
116 
117 static inline void w5100_set(uint16_t _reg, uint8_t _val)
118 {
119  w5100_spi.output_buf[0] = 0xF0;
120  w5100_spi.output_buf[1] = _reg >> 8;
121  w5100_spi.output_buf[2] = _reg & 0xFF;
122  w5100_spi.output_buf[3] = _val;
123 
125 
126  // FIXME: no busy waiting! if really needed add a timeout!!!!
127  while (w5100_spi.status != SPITransSuccess);
128 }
129 
130 static inline uint8_t w5100_get(uint16_t _reg)
131 {
132  w5100_spi.output_buf[0] = 0x0F;
133  w5100_spi.output_buf[1] = _reg >> 8;
134  w5100_spi.output_buf[2] = _reg & 0xFF;
135 
137 
138  // FIXME: no busy waiting! if really needed add a timeout!!!!
139  while (w5100_spi.status != SPITransSuccess);
140 
141  return w5100_spi.input_buf[3];
142 }
143 
144 static inline void w5100_set_buffer(uint16_t _reg, volatile uint8_t *_buf, uint16_t _len)
145 {
146  for (int i = 0; i < _len; i++) {
147  w5100_set(_reg, _buf[ i ]);
148  _reg++;
149  }
150 }
151 
152 static inline void w5100_sock_set(uint8_t _sock, uint16_t _reg, uint8_t _val)
153 {
154  w5100_set(CH_BASE + _sock * CH_SIZE + _reg, _val);
155 }
156 
157 static inline uint8_t w5100_sock_get(uint8_t _sock, uint16_t _reg)
158 {
159  return w5100_get(CH_BASE + _sock * CH_SIZE + _reg);
160 }
161 
162 static inline uint16_t w5100_sock_get16(uint8_t _sock, uint16_t _reg)
163 {
164  uint16_t res = w5100_sock_get(_sock, _reg);
165  uint16_t res2 = w5100_sock_get(_sock, _reg + 1);
166  res = res << 8;
167  res2 = res2 & 0xFF;
168  res = res | res2;
169  return res;
170 }
171 
172 // Functions for the generic device API
173 static int true_function(struct w5100_periph *p __attribute__((unused)), long *fd __attribute__((unused)), uint16_t len __attribute__((unused))) { return true; }
174 static void dev_transmit(struct w5100_periph *p __attribute__((unused)), long fd __attribute__((unused)), uint8_t byte) { w5100_transmit(byte); }
175 static void dev_transmit_buffer(struct w5100_periph *p __attribute__((unused)), long fd __attribute__((unused)), uint8_t *data, uint16_t len) { w5100_transmit_buffer(data, len); }
176 static void dev_send(struct w5100_periph *p __attribute__((unused)), long fd __attribute__((unused))) { w5100_send(); }
177 static int dev_char_available(struct w5100_periph *p __attribute__((unused))) { return w5100_ch_available; }
178 static uint8_t dev_getch(struct w5100_periph *p __attribute__((unused)))
179 {
180  uint8_t c = 0;
181  w5100_receive(&c, 1);
182  return c;
183 }
184 
185 void w5100_init(void)
186 {
187 
188  // configure the SPI bus.
198 
200  chip0.curbuf = 0;
203 
204  // wait one second for proper initialization (chip getting powered up).
205  sys_time_usleep(1000000);
206 
207  // set DRDY pin
210  sys_time_usleep(200);
212 
213  // allow some time for the chip to wake up.
214  sys_time_usleep(20000);
215 
216  // write reset bit into mode register
217  w5100_set(REG_MR, 1 << RST);
218 
219  // allow some time to wake up...
220  sys_time_usleep(20000);
221 
222  // receive memory size
223  w5100_set(REG_RX_MEM, 0x55);
224 
225  // transmit memory size
226  w5100_set(REG_TX_MEM, 0x55);
227 
228  // Setting the required socket base addresses for reads and writes to/from sockets
229  for (int i = 0; i < SOCKETS; i++) {
230  SBASE[i] = TXBUF_BASE + SSIZE * i;
231  RBASE[i] = RXBUF_BASE + RSIZE * i;
232  }
233 
234  uint8_t gateway[4];
235  gateway[0] = ip[0];
236  gateway[1] = ip[1];
237  gateway[2] = ip[2];
238  gateway[3] = 1;
239 
240  // configure gateway, subnet, mac and ip on "NIC".
241  w5100_set_buffer(REG_GAR, gateway, 4);
245 
246  // create a socket to send telemetry through.
248 
249  // make dest zero and configure socket to receive data
250  dest[ 0 ] = 0x00;
252 
253  // Configure generic device
254  chip0.device.periph = (void *)(&chip0);
255  chip0.device.check_free_space = (check_free_space_t) true_function;
256  chip0.device.put_byte = (put_byte_t) dev_transmit;
257  chip0.device.put_buffer = (put_buffer_t) dev_transmit_buffer;
258  chip0.device.send_message = (send_message_t) dev_send;
259  chip0.device.char_available = (char_available_t) dev_char_available;
260  chip0.device.get_byte = (get_byte_t) dev_getch;
261 
262  // Init PPRZ transport
263  pprz_transport_init(&pprz_w5100_tp);
264 }
265 
267 {
268 
270 
271  if (temp == chip0.tx_extract_idx[ chip0.curbuf ]) {
272  // no more room in this transaction.
273  return;
274  }
275 
276  // check if in process of sending data
278  chip0.tx_insert_idx[ chip0.curbuf ] = temp;
279 }
280 
282 {
283  int i;
284  for (i = 0; i < len; i++) {
285  w5100_transmit(data[i]);
286  }
287 }
288 
290 {
291  // Now send off spi transaction.
293  uint8_t curbuf = chip0.curbuf;
294 
295  // switch to other buffer to accept more chars.
296  chip0.curbuf++;
297  if (chip0.curbuf >= W5100_BUFFER_NUM) {
298  chip0.curbuf = 0;
299  }
300 
302  uint16_t offset = ptr & SMASK;
303  uint16_t dstAddr = offset + SBASE[ TELEM_SOCKET ];
304 
307 
308  if (offset + len > SSIZE) {
309  // Wrap around circular buffer
310  uint16_t size = SSIZE - offset;
311  w5100_set_buffer(dstAddr, &chip0.tx_buf[curbuf][0], size);
312  w5100_set_buffer(SBASE[ TELEM_SOCKET ], &chip0.tx_buf[curbuf][0] + size, len - size);
313  } else {
314  w5100_set_buffer(dstAddr, &chip0.tx_buf[curbuf][0], len);
315  }
316 
317  // Reset write pointer
318  ptr += len;
320  w5100_sock_set(TELEM_SOCKET, SOCK_TX_WR + 1, ptr & 0xFF);
321 
322  // send
324 
326  while (complete != 0x00) {
327  complete = w5100_sock_get(TELEM_SOCKET, SOCK_CR);
328  }
329 }
330 
332 {
333  uint16_t val = 0, val1 = 0;
334 
335  do {
336  val1 = w5100_sock_get16(_s, SOCK_RSR);
337  if (val1 != 0) {
338  val = w5100_sock_get16(_s, SOCK_RSR);
339  }
340  } while (val != val1);
341  return val;
342 }
343 
345 {
346  // send command to close socket
348  // clear interrupt registers
349  w5100_sock_set(_s, SOCK_IR, 0xFF);
350 }
351 
352 static void configure_socket(uint8_t _s, uint8_t _flag, uint16_t _lport, uint16_t _dport, uint8_t *_dest)
353 {
354  // Configure socket that receives data on 1234
355  w5100_close_socket(_s);
356  // configure type of socket
357  w5100_sock_set(_s, SOCK_MR, SNMR_UDP | _flag);
358  // configure MSB+LSB of local port number
359  w5100_sock_set(_s, SOCK_PORT, _lport >> 8);
360  w5100_sock_set(_s, SOCK_PORT + 1, _lport & 0xFF);
361  if (_dest[0] != 0x00) {
362  // configure destination to send stuff to.
363  w5100_set_buffer(CH_BASE + _s * CH_SIZE + SOCK_DIPR, _dest, 4);
364  }
365 
366  // this mac corresponds to a mac for multicasting....
367  uint8_t mac_multi[] = { 0x01, 0x00, 0x5E, 0x01, 0x01, 0x0B };
368  w5100_set_buffer(CH_BASE + _s * CH_SIZE + SOCK_DHAR, mac_multi, 6);
369 
370  // configure destination port
371  w5100_sock_set(_s, SOCK_DPORT, _dport >> 8);
372  w5100_sock_set(_s, SOCK_DPORT + 1, _dport & 0xFF);
373 
374  // send command to open the socket
376 }
377 
379 {
380  if (w5100_rx_size(CMD_SOCKET) > 0) {
381  return true;
382  }
383  return false;
384 }
385 
386 uint16_t w5100_receive(uint8_t *buf, uint16_t len __attribute__((unused)))
387 {
388  uint8_t head[8];
389  uint16_t data_len = 0;
390  uint16_t ptr = 0;
391 
392  // Get socket read pointer
394  w5100_read_data(CMD_SOCKET, (uint8_t *)ptr, head, 0x08);
395  ptr += 8;
396  data_len = head[6];
397  data_len = (data_len << 8) + head[7];
398 
399  // read data from buffer.
400  w5100_read_data(CMD_SOCKET, (uint8_t *)ptr, buf, data_len); // data copy.
401  ptr += data_len;
402 
403  // update read pointer
404  w5100_sock_set(CMD_SOCKET, SOCK_RXRD, ptr >> 8);
405  w5100_sock_set(CMD_SOCKET, SOCK_RXRD + 1, ptr & 0xFF);
406 
407  // finalize read.
409  return data_len;
410 }
411 
412 static void w5100_read_data(uint8_t s __attribute__((unused)), volatile uint8_t *src, volatile uint8_t *dst,
413  uint16_t len)
414 {
415  uint16_t size;
416  uint16_t src_mask;
417  uint16_t src_ptr;
418 
419  src_mask = (uint16_t)src & RMASK;
420  src_ptr = RBASE[CMD_SOCKET] + src_mask;
421 
422  if ((src_mask + len) > RSIZE) {
423  size = RSIZE - src_mask;
424  w5100_read(src_ptr, (uint8_t *)dst, size);
425  dst += size;
426  w5100_read(RBASE[CMD_SOCKET], (uint8_t *) dst, len - size);
427  } else {
428  w5100_read(src_ptr, (uint8_t *) dst, len);
429  }
430 }
431 
432 static uint16_t w5100_read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
433 {
434  for (int i = 0; i < _len; i++) {
435  _buf[i] = w5100_get(_addr);
436  _addr++;
437  }
438  return _len;
439 }
440 
unsigned short uint16_t
Definition: types.h:16
enum SPIClockPolarity cpol
clock polarity control
Definition: spi.h:149
uint16_t RBASE[SOCKETS]
Definition: w5100.c:106
static void w5100_set(uint16_t _reg, uint8_t _val)
Definition: w5100.c:117
volatile uint8_t work_tx[4]
Definition: w5100.h:57
#define W5100_TX_BUFFER_SIZE
Definition: w5100.h:37
static uint8_t dest[]
Definition: w5100.c:99
static void w5100_sock_set(uint8_t _sock, uint16_t _reg, uint8_t _val)
Definition: w5100.c:152
enum SPIClockDiv cdiv
prescaler of main clock to use as SPI clock
Definition: spi.h:153
#define W5100_SLAVE_IDX
Definition: w5100.c:78
uint16_t output_length
number of data words to write
Definition: spi.h:146
static void gpio_clear(ioportid_t port, uint16_t pin)
Clear a gpio output to low level.
Definition: gpio_arch.h:108
static int true_function(struct w5100_periph *p, long *fd, uint16_t len)
Definition: w5100.c:173
static const uint16_t SSIZE
Definition: w5100.c:107
#define RXBUF_BASE
Definition: w5100.c:34
#define SNMR_MULTI
Definition: w5100.c:45
#define SOCK_MR
Definition: w5100.c:62
uint16_t w5100_rx_size(uint8_t _s)
Definition: w5100.c:331
Some architecture independent helper functions for GPIOs.
void w5100_init(void)
Definition: w5100.c:185
#define SOCK_CLOSE
Definition: w5100.c:41
#define SMASK
Definition: w5100.c:50
#define W5100_DRDY_GPIO
Definition: w5100.c:82
#define REG_MR
Definition: w5100.c:53
#define W5100_SPI_DEV
Definition: w5100.c:74
#define CH_BASE
Definition: w5100.c:48
#define W5100_RX_BUFFER_SIZE
Definition: w5100.h:36
#define CH_SIZE
Definition: w5100.c:49
static uint8_t dev_getch(struct w5100_periph *p)
Definition: w5100.c:178
SPI transaction structure.
Definition: spi.h:142
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition: spi_arch.c:458
uint8_t ck_a
Definition: w5100.c:91
#define SOCK_RECV
Definition: w5100.c:43
static void dev_send(struct w5100_periph *p, long fd)
Definition: w5100.c:176
enum SPIBitOrder bitorder
MSB/LSB order.
Definition: spi.h:152
#define SOCK_RSR
Definition: w5100.c:70
#define W5100_BUFFER_NUM
Definition: w5100.h:38
void gpio_setup_output(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as outputs.
Definition: gpio_arch.c:33
volatile uint8_t * output_buf
pointer to transmit buffer for DMA
Definition: spi.h:144
enum SPISlaveSelect select
slave selection behavior
Definition: spi.h:148
volatile uint8_t tx_buf[W5100_BUFFER_NUM][W5100_TX_BUFFER_SIZE]
Definition: w5100.h:54
#define SOCK_CR
Definition: w5100.c:63
#define REG_SIPR
Definition: w5100.c:60
#define SOCK_PORT
Definition: w5100.c:65
uint16_t w5100_receive(uint8_t *buf, uint16_t len)
Definition: w5100.c:386
static uint8_t w5100_sock_get(uint8_t _sock, uint16_t _reg)
Definition: w5100.c:157
Architecture independent SPI (Serial Peripheral Interface) API.
enum SPIClockPhase cpha
clock phase control
Definition: spi.h:150
void sys_time_usleep(uint32_t us)
sys_time_usleep(uint32_t us)
Definition: sys_time_arch.c:95
static uint8_t ip[]
Definition: w5100.c:98
#define SOCK_RXRD
Definition: w5100.c:71
#define CMD_SOCKET
Definition: w5100.c:37
#define SOCK_TX_WR
Definition: w5100.c:69
#define SOCK_OPEN
Definition: w5100.c:40
Definition: spi.h:84
#define TXBUF_BASE
Definition: w5100.c:33
#define SNMR_UDP
Definition: w5100.c:44
static void dev_transmit_buffer(struct w5100_periph *p, long fd, uint8_t *data, uint16_t len)
Definition: w5100.c:175
#define REG_RX_MEM
Definition: w5100.c:54
static const float offset[]
uint8_t ck_b
Definition: w5100.c:91
Architecture independent timing functions.
static int dev_char_available(struct w5100_periph *p)
Definition: w5100.c:177
volatile uint16_t tx_insert_idx[W5100_BUFFER_NUM]
Definition: w5100.h:55
#define RMASK
Definition: w5100.c:51
#define SOCK_IR
Definition: w5100.c:64
static const uint16_t RSIZE
Definition: w5100.c:108
volatile uint16_t tx_extract_idx[W5100_BUFFER_NUM]
Definition: w5100.h:56
uint16_t val[TCOUPLE_NB]
#define REG_SUBR
Definition: w5100.c:58
volatile uint8_t work_rx[4]
Definition: w5100.h:58
static uint16_t w5100_sock_get16(uint8_t _sock, uint16_t _reg)
Definition: w5100.c:162
enum W5100Status status
Definition: w5100.h:47
#define TELEM_SOCKET
Definition: w5100.c:38
static uint16_t w5100_read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
Definition: w5100.c:432
static void w5100_read_data(uint8_t s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len)
Definition: w5100.c:412
#define SOCK_DPORT
Definition: w5100.c:68
static void w5100_close_socket(uint8_t _s)
Definition: w5100.c:344
struct w5100_periph chip0
Definition: w5100.c:90
CPOL = 0.
Definition: spi.h:77
static void dev_transmit(struct w5100_periph *p, long fd, uint8_t byte)
Definition: w5100.c:174
bool w5100_ch_available()
Definition: w5100.c:378
uint16_t input_length
number of data words to read
Definition: spi.h:145
static uint8_t subnet[]
Definition: w5100.c:100
uint16_t SBASE[SOCKETS]
Definition: w5100.c:105
static void w5100_set_buffer(uint16_t _reg, volatile uint8_t *_buf, uint16_t _len)
Definition: w5100.c:144
#define SOCKETS
Definition: w5100.c:35
#define W5100_DRDY_GPIO_PIN
Definition: w5100.c:86
W5100 ethernet chip I/O.
void w5100_transmit_buffer(uint8_t *data, uint16_t len)
Definition: w5100.c:281
unsigned char uint8_t
Definition: types.h:14
#define SOCK_SEND
Definition: w5100.c:42
#define byte
#define SOCK_DIPR
Definition: w5100.c:67
CPHA = 0.
Definition: spi.h:68
int fd
Definition: serial.c:26
slave is selected before transaction and unselected after
Definition: spi.h:57
#define REG_SHAR
Definition: w5100.c:59
struct spi_transaction w5100_spi
Definition: w5100.c:110
void w5100_send()
Definition: w5100.c:289
enum SPIDataSizeSelect dss
data transfer word size
Definition: spi.h:151
uint8_t w5100_rx_buf[W5100_RX_BUFFER_SIZE]
Definition: w5100.c:92
uint8_t slave_idx
slave id: SPI_SLAVE0 to SPI_SLAVE4
Definition: spi.h:147
Definition: spi.h:119
volatile uint8_t * input_buf
pointer to receive buffer for DMA
Definition: spi.h:143
static float p[2][2]
static uint8_t w5100_get(uint16_t _reg)
Definition: w5100.c:130
static uint16_t dport
Definition: w5100.c:101
void w5100_transmit(uint8_t data)
Definition: w5100.c:266
int curbuf
Definition: w5100.h:48
static uint8_t mac[]
Definition: w5100.c:95
#define REG_TX_MEM
Definition: w5100.c:55
struct link_device device
Generic device interface.
Definition: w5100.h:61
#define SOCK_DHAR
Definition: w5100.c:66
#define REG_GAR
Definition: w5100.c:57
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition: gpio_arch.h:98
static const uint8_t RST
Definition: w5100.c:103
static void configure_socket(uint8_t _s, uint8_t _flag, uint16_t _lport, uint16_t _dport, uint8_t *_dest)
Definition: w5100.c:352
enum SPITransactionStatus status
Definition: spi.h:156