Blame view

RIOT/tests/periph_spi/main.c 13 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  /*
   * Copyright (C) 2014 Freie Universitรคt Berlin
   *
   * This file is subject to the terms and conditions of the GNU Lesser General
   * Public License v2.1. See the file LICENSE in the top level directory for more
   * details.
   */
  
  /**
   * @ingroup tests
   * @{
   *
   * @file
   * @brief       Application for testing low-level SPI driver implementations
   *
   * This implementation covers both, master and slave configurations.
   *
   * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
   *
   * @}
   */
  
  #include <stdio.h>
  #include <string.h>
  #include <stdlib.h>
  
  #include "xtimer.h"
  #include "shell.h"
  #include "periph/spi.h"
  
  /**
   * @brief   Some parameters used for benchmarking
   */
  #define BENCH_REDOS             (1000)
  #define BENCH_SMALL             (2)
  #define BENCH_LARGE             (100)
  #define BENCH_PAYLOAD           ('b')
  #define BENCH_REGADDR           (0x23)
  
  #define BUF_SIZE                (512U)
  
  /**
   * @brief   Benchmark buffers
   */
  static uint8_t bench_wbuf[BENCH_LARGE];
  static uint8_t bench_rbuf[BENCH_LARGE];
  
  /**
   * @brief   Generic buffer used for receiving
   */
  static uint8_t buf[BUF_SIZE];
  
  static struct {
      spi_t dev;
      spi_mode_t mode;
      spi_clk_t clk;
      spi_cs_t cs;
  } spiconf;
  
  void print_bytes(char* title, uint8_t* data, size_t len)
  {
      printf("%4s\n", title);
      for (size_t i = 0; i < len; i++) {
          printf("  %2i ", (int)i);
      }
      printf("\n ");
      for (size_t i = 0; i < len; i++) {
          printf(" 0x%02x", (int)data[i]);
      }
      printf("\n ");
      for (size_t i = 0; i < len; i++) {
          if (data[i] < ' ' || data[i] > '~') {
              printf("  ?? ");
          }
          else {
              printf("   %c ", (char)data[i]);
          }
      }
      printf("\n\n");
  }
  
  int cmd_init(int argc, char **argv)
  {
      int dev, mode, clk, port, pin, tmp;
  
      if (argc < 5) {
          printf("usage: %s <dev> <mode> <clk> <cs port> <cs pin>\n", argv[0]);
          puts("\tdev:");
          for (int i = 0; i < (int)SPI_NUMOF; i++) {
              printf("\t\t%i: SPI_DEV(%i)\n", i, i);
          }
          puts("\tmode:");
          puts("\t\t0: POL:0, PHASE:0 - on first rising edge");
          puts("\t\t1: POL:0, PHASE:1 - on second rising edge");
          puts("\t\t2: POL:1, PHASE:0 - on first falling edge");
          puts("\t\t3: POL:1, PHASE:1 - on second falling edge");
          puts("\tclk:");
          puts("\t\t0: 100 KHz");
          puts("\t\t1: 400 KHz");
          puts("\t\t2: 1 MHz");
          puts("\t\t3: 5 MHz");
          puts("\t\t4: 10 MHz");
          puts("\tcs port:");
          puts("\t\tPort of the CS pin, set to -1 for hardware chip select");
          puts("\tcs pin:");
          puts("\t\tPin used for chip select. If hardware chip select is enabled,\n"
               "\t\tthis value specifies the internal HWCS line");
          return 1;
      }
  
      /* parse the given SPI device */
      dev = atoi(argv[1]);
      if (dev < 0 || dev >= SPI_NUMOF) {
          puts("error: invalid SPI device specified");
          return 1;
      }
      spiconf.dev = SPI_DEV(dev);
  
      /* parse the SPI mode */
      mode = atoi(argv[2]);
      switch (mode) {
          case 0: spiconf.mode = SPI_MODE_0; break;
          case 1: spiconf.mode = SPI_MODE_1; break;
          case 2: spiconf.mode = SPI_MODE_2; break;
          case 3: spiconf.mode = SPI_MODE_3; break;
          default:
              puts("error: invalid SPI mode specified");
              return 1;
      }
  
      /* parse the targeted clock speed */
      clk = atoi(argv[3]);
      switch (clk) {
          case 0: spiconf.clk = SPI_CLK_100KHZ; break;
          case 1: spiconf.clk = SPI_CLK_400KHZ; break;
          case 2: spiconf.clk = SPI_CLK_1MHZ;   break;
          case 3: spiconf.clk = SPI_CLK_5MHZ;   break;
          case 4: spiconf.clk = SPI_CLK_10MHZ;  break;
          default:
              puts("error: invalid bus speed specified");
              return 1;
      }
  
      /* parse chip select port and pin */
      port = atoi(argv[4]);
      pin = atoi(argv[5]);
      if (pin < 0 || port < -1) {
          puts("error: invalid CS port/pin combination specified");
      }
      if (port == -1) {                    /* hardware chip select line */
          spiconf.cs = SPI_HWCS(pin);
      }
      else {
          spiconf.cs = (spi_cs_t)GPIO_PIN(port, pin);
      }
  
      /* test setup */
      tmp = spi_init_cs(spiconf.dev, spiconf.cs);
      if (tmp != SPI_OK) {
          puts("error: unable to initialize the given chip select line");
          return 1;
      }
      tmp = spi_acquire(spiconf.dev, spiconf.cs, spiconf.mode, spiconf.clk);
      if (tmp == SPI_NOMODE) {
          puts("error: given SPI mode is not supported");
          return 1;
      }
      else if (tmp == SPI_NOCLK) {
          puts("error: targeted clock speed is not supported");
          return 1;
      }
      else if (tmp != SPI_OK) {
          puts("error: unable to acquire bus with given parameters");
          return 1;
      }
      spi_release(spiconf.dev);
  
      printf("SPI_DEV(%i) initialized: mode: %i, clk: %i, cs_port: %i, cs_pin: %i\n",
             dev, mode, clk, port, pin);
  
      return 0;
  }
  
  int cmd_transfer(int argc, char **argv)
  {
      size_t len;
  
      if (argc < 2) {
          printf("usage: %s <data>\n", argv[0]);
          return 1;
      }
  
      if (spiconf.dev == SPI_UNDEF) {
          puts("error: SPI is not initialized, please initialize bus first");
          return 1;
      }
  
      /* get bus access */
      if (spi_acquire(spiconf.dev, spiconf.cs,
                      spiconf.mode, spiconf.clk) != SPI_OK) {
          puts("error: unable to acquire the SPI bus");
          return 1;
      }
  
      /* transfer data */
      len = strlen(argv[1]);
      memset(buf, 0, sizeof(buf));
      spi_transfer_bytes(spiconf.dev, spiconf.cs, false, argv[1], buf, len);
  
      /* release the bus */
      spi_release(spiconf.dev);
  
      /* print results */
      print_bytes("Sent bytes", (uint8_t *)argv[1], len);
      print_bytes("Received bytes", buf, len);
  
      return 0;
  }
  
  int cmd_bench(int argc, char **argv)
  {
      (void)argc;
      (void)argv;
  
      uint32_t start, stop;
      uint32_t sum = 0;
      uint8_t in;
      uint8_t out = (uint8_t)BENCH_PAYLOAD;
  
      if (spiconf.dev == SPI_UNDEF) {
          puts("error: SPI is not initialized, please initialize bus first");
          return 1;
      }
  
      /* prepare buffer */
      memset(bench_wbuf, BENCH_PAYLOAD, BENCH_LARGE);
  
      /* get access to the bus */
      if (spi_acquire(spiconf.dev, spiconf.cs,
                      spiconf.mode, spiconf.clk) != SPI_OK) {
          puts("error: unable to acquire the SPI bus");
          return 1;
      }
  
      puts("### Running some benchmarks, all values in [us] ###\n");
  
      /* 1 - write 1000 times 1 byte */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          in = spi_transfer_byte(spiconf.dev, spiconf.cs, false, out);
          (void)in;
      }
      stop = xtimer_now_usec();
      printf(" 1 - write %i times %i byte:", BENCH_REDOS, 1);
      printf("\t\t\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 2 - write 1000 times 2 byte */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
                             bench_wbuf, NULL, BENCH_SMALL);
      }
      stop = xtimer_now_usec();
      printf(" 2 - write %i times %i byte:", BENCH_REDOS, BENCH_SMALL);
      printf("\t\t\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 3 - write 1000 times 100 byte */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
                             bench_wbuf, NULL, BENCH_LARGE);
      }
      stop = xtimer_now_usec();
      printf(" 3 - write %i times %i byte:", BENCH_REDOS, BENCH_LARGE);
      printf("\t\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 4 - write 1000 times 1 byte to register */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          in = spi_transfer_reg(spiconf.dev, spiconf.cs, BENCH_REGADDR, out);
          (void)in;
      }
      stop = xtimer_now_usec();
      printf(" 4 - write %i times %i byte to register:", BENCH_REDOS, 1);
      printf("\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 5 - write 1000 times 2 byte to register */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
                            bench_wbuf, NULL, BENCH_SMALL);
      }
      stop = xtimer_now_usec();
      printf(" 5 - write %i times %i byte to register:", BENCH_REDOS, BENCH_SMALL);
      printf("\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 6 - write 1000 times 100 byte to register */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
                            bench_wbuf, NULL, BENCH_LARGE);
      }
      stop = xtimer_now_usec();
      printf(" 6 - write %i times %i byte to register:", BENCH_REDOS, BENCH_LARGE);
      printf("\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 7 - read 1000 times 2 byte */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
                             NULL, bench_rbuf, BENCH_SMALL);
      }
      stop = xtimer_now_usec();
      printf(" 7 - read %i times %i byte:", BENCH_REDOS, BENCH_SMALL);
      printf("\t\t\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 8 - read 1000 times 100 byte */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
                             NULL, bench_rbuf, BENCH_LARGE);
      }
      stop = xtimer_now_usec();
      printf(" 8 - read %i times %i byte:", BENCH_REDOS, BENCH_LARGE);
      printf("\t\t\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 9 - read 1000 times 2 byte from register */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
                            NULL, bench_rbuf, BENCH_SMALL);
      }
      stop = xtimer_now_usec();
      printf(" 9 - read %i times %i byte from register:", BENCH_REDOS, BENCH_SMALL);
      printf("\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 10 - read 1000 times 100 byte from register */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
                            NULL, bench_rbuf, BENCH_LARGE);
      }
      stop = xtimer_now_usec();
      printf("10 - read %i times %i byte from register:", BENCH_REDOS, BENCH_LARGE);
      printf("\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 11 - transfer 1000 times 2 byte */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
                             bench_wbuf, bench_rbuf, BENCH_SMALL);
      }
      stop = xtimer_now_usec();
      printf("11 - transfer %i times %i byte:", BENCH_REDOS, BENCH_SMALL);
      printf("\t\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 12 - transfer 1000 times 100 byte */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_bytes(spiconf.dev, spiconf.cs, false,
                             bench_wbuf, bench_rbuf, BENCH_LARGE);
      }
      stop = xtimer_now_usec();
      printf("12 - transfer %i times %i byte:", BENCH_REDOS, BENCH_LARGE);
      printf("\t\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 13 - transfer 1000 times 2 byte from/to register */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
                            bench_wbuf, bench_rbuf, BENCH_SMALL);
      }
      stop = xtimer_now_usec();
      printf("13 - transfer %i times %i byte to register:", BENCH_REDOS, BENCH_SMALL);
      printf("\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      /* 14 - transfer 1000 times 100 byte from/to register */
      start = xtimer_now_usec();
      for (int i = 0; i < BENCH_REDOS; i++) {
          spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR,
                            bench_wbuf, bench_rbuf, BENCH_LARGE);
      }
      stop = xtimer_now_usec();
      printf("14 - transfer %i times %i byte to register:", BENCH_REDOS, BENCH_LARGE);
      printf("\t%i\n", (int)(stop - start));
      sum += (stop - start);
  
      printf("-- - SUM:\t\t\t\t\t%i\n", (int)sum);
  
      spi_release(spiconf.dev);
      puts("\n### All runs complete ###");
  
      return 0;
  }
  
  static const shell_command_t shell_commands[] = {
      { "init", "Setup a particular SPI configuration", cmd_init },
      { "send", "Transfer string to slave", cmd_transfer },
      { "bench", "Runs some benchmarks", cmd_bench },
      { NULL, NULL, NULL }
  };
  
  int main(void)
  {
      puts("Manual SPI peripheral driver test");
      puts("Refer to the README.md file for more information.\n");
  
      printf("There are %i SPI devices configured for your platform.\n",
             (int)SPI_NUMOF);
  
      /* reset local SPI configuration */
      spiconf.dev = SPI_UNDEF;
  
      /* run the shell */
      char line_buf[SHELL_DEFAULT_BUFSIZE];
      shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
  
      return 0;
  }