Mistake on this page?
Report an issue in GitHub or email us
test_utils.h
1 /*
2  * Copyright (c) 2019, Arm Limited and affiliates.
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef TEST_UTILS_H
19 #define TEST_UTILS_H
20 
21 #include <list>
22 
23 #define UART_NAME "UART"
24 #define UARTNOFC_NAME "UART-no-FC"
25 #define ANALOGOUT_NAME "DAC"
26 #define ANALOGIN_NAME "ADC"
27 #define PWM_NAME "PWM"
28 #define I2C_NAME "I2C"
29 #define SPI_NAME "SPI"
30 #define SPISLAVE_NAME "SPISlave"
31 #define GPIO_NAME "GPIO"
32 #define GPIO_IRQ_NAME "GPIO_IRQ"
33 
34 // test function prototypes
35 typedef void (*TF1)(PinName p0);
36 typedef void (*TF2)(PinName p0, PinName p1);
37 typedef void (*TF3)(PinName p0, PinName p1, PinName p2);
38 typedef void (*TF4)(PinName p0, PinName p1, PinName p2, PinName p3);
39 typedef void (*TF5)(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4);
40 
41 template<typename PortType, typename FunctionType, FunctionType f>
43 
44 };
45 
46 template<typename PortType, TF1 f>
47 struct FunctionCaller<PortType, TF1, f> {
48  void operator()(PortType &port)
49  {
50  f(port.pins[0]);
51  }
52 };
53 
54 template<typename PortType, TF2 f>
55 struct FunctionCaller<PortType, TF2, f> {
56  void operator()(PortType &port)
57  {
58  f(port.pins[0], port.pins[1]);
59  }
60 };
61 
62 template<typename PortType, TF3 f>
63 struct FunctionCaller<PortType, TF3, f> {
64  void operator()(PortType &port)
65  {
66  f(port.pins[0], port.pins[1], port.pins[2]);
67  }
68 };
69 
70 template<typename PortType, TF4 f>
71 struct FunctionCaller<PortType, TF4, f> {
72  void operator()(PortType &port)
73  {
74  f(port.pins[0], port.pins[1], port.pins[2], port.pins[3]);
75  }
76 };
77 
78 template<typename PortType, TF5 f>
79 struct FunctionCaller<PortType, TF5, f> {
80  void operator()(PortType &port)
81  {
82  f(port.pins[0], port.pins[1], port.pins[2], port.pins[3], port.pins[4]);
83  }
84 };
85 
86 template <typename PortType>
87 bool peripheral_comparator(const PortType &port1, const PortType &port2)
88 {
89  return port1.peripheral == port2.peripheral;
90 }
91 
92 template <typename PortType>
93 bool peripheral_less(const PortType &port1, const PortType &port2)
94 {
95  return port1.peripheral < port2.peripheral;
96 }
97 
98 template<typename PortType, typename FormFactorType>
99 static bool find_port_pins(PortType &port)
100 {
101  return pinmap_find_peripheral_pins(FormFactorType::pins(), FormFactorType::restricted_pins(),
102  port.peripheral, PortType::PinMap::maps, port.ppins, PortType::pin_count);
103 }
104 
105 template<typename PortType, typename FormFactorType>
106 void find_ports(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
107 {
108  // Loop through every pin type
109  for (uint32_t i = 0; i < PortType::pin_count; i++) {
110  const PinMap *map = PortType::PinMap::maps[i];
111  const char *pin_type = PortType::PinMap::pin_type_names[i];
112 
113  // Loop through each pin of a given type
114  for (uint32_t j = 0; j < FormFactorType::pins()->count; j++) {
115  PortType port;
116 
117  if (FormFactorType::pins()->pins[j] == NC) {
118  continue;
119  }
120 
121  // Set pin being tested
122  port.pins[i] = FormFactorType::pins()->pins[j];
123  port.peripheral = pinmap_find_peripheral(port.pins[i], map);
124 
125  // Don't test restricted pins
126  if (pinmap_list_has_pin(FormFactorType::restricted_pins(), port.pins[i])) {
127  utest_printf("Skipping (restricted pin) %s pin %s (%i)\r\n", pin_type,
128  FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
129  continue;
130  }
131 
132  if (!strcmp(PortType::PinMap::name, GPIO_IRQ_NAME) || !strcmp(PortType::PinMap::name, GPIO_NAME)) {
133  // Don't test restricted gpio pins
134  if (pinmap_list_has_pin(pinmap_gpio_restricted_pins(), port.pins[i])) {
135  utest_printf("Skipping (restricted gpio pin) %s pin %s (%i)\r\n", pin_type,
136  FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
137  continue;
138  }
139  }
140 
141 #if DEVICE_SERIAL
142  if (!strcmp(PortType::PinMap::name, UART_NAME) || !strcmp(PortType::PinMap::name, UARTNOFC_NAME)) {
144  utest_printf("Skipping (restricted uart peripheral) %s peripheral 0x%x with pin %s (%x)\r\n", pin_type,
145  port.peripheral, FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
146  continue;
147  }
148  }
149 #endif
150 
151  // skipp pin searching if single pin port type
152  if (PortType::pin_count > 1) {
153  find_port_pins<PortType, FormFactorType>(port);
154  }
155  if (port.empty()) {
156  not_matched_ports.push_back(port);
157  } else {
158  matched_ports.push_back(port);
159  }
160  }
161  }
162 }
163 
164 
165 template<typename PortType, typename FormFactorType, typename FunctionType, FunctionType f>
166 void test_all_ports(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
167 {
168  typedef typename std::list<PortType>::iterator Iter;
169  utest_printf("***Testing %s on all form factor ports***\n", PortType::PinMap::name);
170  const PinList *ff_pins = FormFactorType::pins();
172 
173  if (matched_ports.empty() && not_matched_ports.empty()) {
174  utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
175  return;
176  }
177 
178  for (uint32_t i = 0; i < ff_pins->count; i++) {
179  if (ff_pins->pins[i] != NC) {
180  for (Iter it = matched_ports.begin(); it != matched_ports.end(); ++it) {
181  PortType &port = *it;
182  for (uint32_t j = 0; j < PortType::pin_count; j++) {
183  if (ff_pins->pins[i] == port.pins[j]) {
184  utest_printf("%3s - %s pin tested on port: %s...", FormFactorType::pin_to_string(ff_pins->pins[i]),
185  PortType::PinMap::pin_type_names[j], port.str());
186  if (port.status == PortType::StatusNotTested) {
187  call(port);
188  port.status = PortType::StatusPass;
189  } else {
190  utest_printf("test already done...");
191  }
192  utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
193  goto end_port_iteration;
194  }
195  }
196  }
197  for (Iter it = not_matched_ports.begin(); it != not_matched_ports.end(); ++it) {
198  PortType &port = *it;
199  for (uint32_t j = 0; j < PortType::pin_count; j++) {
200  if (ff_pins->pins[i] == port.pins[j]) {
201  utest_printf("%3s - Could not find pins to test %s pin %s (%d)\n",
202  FormFactorType::pin_to_string(ff_pins->pins[i]),
203  PortType::PinMap::pin_type_names[j],
204  FormFactorType::pin_to_string(ff_pins->pins[i]),
205  ff_pins->pins[i]);
206  goto end_port_iteration;
207  }
208  }
209  }
210  }
211 end_port_iteration:
212  ;
213  }
214 }
215 
216 template<typename PortType, typename FunctionType, FunctionType f>
217 void test_peripheral(PortType &port)
218 {
219  if (port.empty()) {
220  if (port.peripheral != NC) {
221  utest_printf("0x%x - Could not find pins to test peripheral\n", port.peripheral);
222  }
223  } else {
224  utest_printf("0x%x - peripheral tested on port: %s...", port.peripheral, port.str());
225  if (port.status == PortType::StatusNotTested) {
227  call(port); // run test
228  port.status = PortType::StatusPass;
229  }
230  utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
231  }
232 }
233 
234 template<typename PortType, typename FunctionType, FunctionType f>
235 void test_all_peripherals(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
236 {
237  typedef typename std::list<PortType>::iterator Iter;
238  utest_printf("***Testing all %s peripherals***\n", PortType::PinMap::name);
239 
240  if (matched_ports.empty() && not_matched_ports.empty()) {
241  utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
242  return;
243  }
244 
245  matched_ports.sort(peripheral_less<PortType>);
246  not_matched_ports.sort(peripheral_less<PortType>);
247 
248  for (Iter m_it = matched_ports.begin(), nm_it = not_matched_ports.begin();
249  m_it != matched_ports.end() || nm_it != not_matched_ports.end();) {
250  if (m_it != matched_ports.end() && nm_it != not_matched_ports.end()) {
251  if ((*m_it).peripheral < (*nm_it).peripheral) {
252  test_peripheral<PortType, FunctionType, f>(*m_it);
253  ++m_it;
254  } else {
255  test_peripheral<PortType, FunctionType, f>(*nm_it);
256  ++nm_it;
257  }
258  } else if (m_it != matched_ports.end()) {
259  test_peripheral<PortType, FunctionType, f>(*m_it);
260  ++m_it;
261  } else if (nm_it != not_matched_ports.end()) {
262  test_peripheral<PortType, FunctionType, f>(*nm_it);
263  ++nm_it;
264  }
265  }
266 }
267 
268 /**
269  * Test function for all pinouts of all peripherals of a given type
270  *
271  * This template function takes in three template parameters:
272  * - PortType - The type of peripheral to test
273  * - FormFactorType - The form factor to test on
274  * - f - The test function to run.
275  *
276  * This function calls the test function multiple times with
277  * the appropriate combinations of pins.
278  */
279 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
280 void all_ports()
281 {
282  std::list<PortType> matched_ports, not_matched_ports;
283  find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
284  matched_ports.unique();
285  not_matched_ports.unique();
286  test_all_ports<PortType, FormFactorType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
287 }
288 
289 /**
290  * Test function for one pinout of all peripherals of a given type
291  *
292  * This template function takes in three template parameters:
293  * - PortType - The type of peripheral to test
294  * - FormFactorType - The form factor to test on
295  * - f - The test function to run.
296  *
297  * This function calls the test function once for each peripheral
298  * of the given type.
299  */
300 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
301 void all_peripherals()
302 {
303  std::list<PortType> matched_ports, not_matched_ports;
304  find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
305 
306  matched_ports.sort(peripheral_less<PortType>);
307  not_matched_ports.sort(peripheral_less<PortType>);
308  matched_ports.unique(peripheral_comparator<PortType>);
309  not_matched_ports.unique(peripheral_comparator<PortType>);
310 
311  test_all_peripherals<PortType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
312 }
313 
314 /**
315  * Test function for one pinout of one peripheral of a given type
316  *
317  * This template function takes in three template parameters:
318  * - PortType - The type of peripheral to test
319  * - FormFactorType - The form factor to test on
320  * - f - The test function to run.
321  *
322  * This function calls the test function once for one peripheral
323  * of the given type.
324  */
325 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
326 void one_peripheral()
327 {
328 #ifdef FPGA_FORCE_ALL_PORTS
329  utest_printf("*** FPGA_FORCE_ALL_PORTS ***\n");
330  all_ports<PortType, FormFactorType, f>();
331 #else
332  std::list<PortType> matched_ports, not_matched_ports;
333  find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
334 
335  utest_printf("***Testing one %s pin configuration***\n", PortType::PinMap::name);
336  if (matched_ports.empty()) {
337  utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
338  } else {
339  test_peripheral<PortType, typename PortType::TestFunctionType, f>(matched_ports.front());
340  }
341 #endif
342 }
343 
344 template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
345 class Port;
346 
347 template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
350 
351 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
352 class Port {
353 public:
354  int peripheral;
355  PinName pins[N];
356  PinName *ppins[N];
357 
358  static const uint32_t pin_count = N;
359  typedef PinMapType PinMap;
360  typedef FunctionType TestFunctionType;
361 
362  enum Status { StatusPass, StatusFail, StatusNotTested };
363  Status status;
364 
365  Port(): peripheral(NC), status(StatusNotTested)
366  {
367  init_pins();
368  }
369 
370  Port(const Port &port)
371  {
372  init_pins();
373  copy_from(port);
374  }
375 
376  void init_pins()
377  {
378  for (uint32_t i = 0; i < N; i++) {
379  pins[i] = NC;
380  ppins[i] = &pins[i];
381  }
382  }
383 
384  void copy_from(const Port &port)
385  {
386  peripheral = port.peripheral;
387  status = port.status;
388  for (uint32_t i = 0; i < N; i++) {
389  pins[i] = port.pins[i];
390  }
391  }
392 
393  bool empty()
394  {
395  if (peripheral == NC) {
396  return true;
397  }
398  for (uint32_t i = 0; i < N; i++) {
399  if (pins[i] == NC) {
400  return true;
401  }
402  }
403  return false;
404  }
405 
406  const char *str()
407  {
408  static char port_str[128];
409  char pin_str[32];
410  sprintf(port_str, "peripheral=(0x%x) ", peripheral);
411  for (uint32_t i = 0; i < N; i++) {
412  sprintf(pin_str, "%s=(%s) ", PinMap::pin_type_names[i], FormFactorType::pin_to_string(pins[i]));
413  strcat(port_str, pin_str);
414  }
415  return port_str;
416  }
417 
419 };
420 
421 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
423 
424 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
426 {
427  if (port1.peripheral != port2.peripheral) {
428  return false;
429  }
430  for (uint32_t i = 0; i < N; i++) {
431  if (port1.pins[i] != port2.pins[i]) {
432  return false;
433  }
434  }
435  return true;
436 }
437 
438 /**
439  * This is a convenience class for use with the above templates
440  *
441  * This class can be passed as a template parameter to all_ports,
442  * all_peripherals or one_peripheral to choose test pins from
443  * the default form factor.
444  */
446 public:
447  static const PinList *pins()
448  {
449  return pinmap_ff_default_pins();
450  }
451 
452  static const PinList *restricted_pins()
453  {
454  return pinmap_restricted_pins();
455  }
456 
457  static const char *pin_to_string(PinName pin)
458  {
459  return pinmap_ff_default_pin_to_string(pin);
460  }
461 };
462 
463 /*
464  * Peripheral port declarations are given below
465  *
466  * Each Port type represents a set of pins used by a peripheral.
467  * The Port typedef is used as a template parameter to the functions
468  * all_ports, all_peripherals and one_peripheral to select the peripheral
469  * pin set to use for testing.
470  */
471 
472 struct GPIOMaps {
473  static const PinMap *maps[];
474  static const char *const pin_type_names[];
475  static const char *const name;
476 };
477 const PinMap *GPIOMaps::maps[] = { gpio_pinmap() };
478 const char *const GPIOMaps::pin_type_names[] = { "IO" };
479 const char *const GPIOMaps::name = GPIO_NAME;
481 
482 #if DEVICE_INTERRUPTIN
483 #include "gpio_irq_api.h"
484 struct GPIOIRQMaps {
485  static const PinMap *maps[];
486  static const char *const pin_type_names[];
487  static const char *const name;
488 };
489 const PinMap *GPIOIRQMaps::maps[] = { gpio_irq_pinmap() };
490 const char *const GPIOIRQMaps::pin_type_names[] = { "IRQ_IN" };
491 const char *const GPIOIRQMaps::name = GPIO_IRQ_NAME;
493 #endif
494 
495 #if DEVICE_SPI
496 #include "spi_api.h"
497 struct SPIMaps {
498  static const PinMap *maps[];
499  static const char *const pin_type_names[];
500  static const char *const name;
501 };
502 const PinMap *SPIMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap(), spi_master_cs_pinmap() };
503 const char *const SPIMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
504 const char *const SPIMaps::name = SPI_NAME;
506 
507 struct SPINoCSMaps {
508  static const PinMap *maps[];
509  static const char *const pin_type_names[];
510  static const char *const name;
511 };
512 const PinMap *SPINoCSMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap()};
513 const char *const SPINoCSMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK" };
514 const char *const SPINoCSMaps::name = SPI_NAME;
516 
517 struct SPISlaveMaps {
518  static const PinMap *maps[];
519  static const char *const pin_type_names[];
520  static const char *const name;
521 };
522 const PinMap *SPISlaveMaps::maps[] = { spi_slave_mosi_pinmap(), spi_slave_miso_pinmap(), spi_slave_clk_pinmap(), spi_slave_cs_pinmap() };
523 const char *const SPISlaveMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
524 const char *const SPISlaveMaps::name = SPISLAVE_NAME;
526 #endif
527 
528 #if DEVICE_I2C
529 #include "i2c_api.h"
530 struct I2CMaps {
531  static const PinMap *maps[];
532  static const char *const pin_type_names[];
533  static const char *const name;
534 };
535 const PinMap *I2CMaps::maps[] = { i2c_master_sda_pinmap(), i2c_master_scl_pinmap() };
536 const char *const I2CMaps::pin_type_names[] = { "SDA", "SCL" };
537 const char *const I2CMaps::name = I2C_NAME;
539 #endif
540 
541 #if DEVICE_PWMOUT
542 #include "pwmout_api.h"
543 struct PWMMaps {
544  static const PinMap *maps[];
545  static const char *const pin_type_names[];
546  static const char *const name;
547 };
548 const PinMap *PWMMaps::maps[] = { pwmout_pinmap() };
549 const char *const PWMMaps::pin_type_names[] = { "PWM_OUT" };
550 const char *const PWMMaps::name = PWM_NAME;
552 #endif
553 
554 #if DEVICE_ANALOGIN
555 #include "analogin_api.h"
556 struct AnaloginMaps {
557  static const PinMap *maps[];
558  static const char *const pin_type_names[];
559  static const char *const name;
560 };
561 const PinMap *AnaloginMaps::maps[] = { analogin_pinmap() };
562 const char *const AnaloginMaps::pin_type_names[] = { "ADC_IN" };
563 const char *const AnaloginMaps::name = ANALOGIN_NAME;
565 #endif
566 
567 #if DEVICE_ANALOGOUT
568 #include "analogout_api.h"
570  static const PinMap *maps[];
571  static const char *const pin_type_names[];
572  static const char *const name;
573 };
574 const PinMap *AnalogoutMaps::maps[] = { analogout_pinmap() };
575 const char *const AnalogoutMaps::pin_type_names[] = { "DAC_OUT" };
576 const char *const AnalogoutMaps::name = ANALOGOUT_NAME;
578 #endif
579 
580 #if DEVICE_SERIAL
581 #if DEVICE_SERIAL_FC
582 #include "hal/serial_api.h"
583 struct UARTMaps {
584  static const PinMap *maps[];
585  static const char *const pin_type_names[];
586  static const char *const name;
587 };
588 const PinMap *UARTMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap(), serial_cts_pinmap(), serial_rts_pinmap() };
589 const char *const UARTMaps::pin_type_names[] = { "TX", "RX", "CTS", "RTS" };
590 const char *const UARTMaps::name = UART_NAME;
592 #endif
593 
594 struct UARTNoFCMaps {
595  static const PinMap *maps[];
596  static const char *const pin_type_names[];
597  static const char *const name;
598 };
599 const PinMap *UARTNoFCMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap() };
600 const char *const UARTNoFCMaps::pin_type_names[] = { "TX", "RX" };
601 const char *const UARTNoFCMaps::name = UARTNOFC_NAME;
603 #endif
604 #endif
const PinMap * serial_tx_pinmap(void)
Get the pins that support Serial TX.
const PinMap * i2c_master_scl_pinmap(void)
Get the pins that support I2C SCL.
const PinMap * spi_master_mosi_pinmap(void)
Get the pins that support SPI MOSI.
This is a convenience class for use with the above templates.
Definition: test_utils.h:445
const PinMap * i2c_master_sda_pinmap(void)
Get the pins that support I2C SDA.
Definition: pinmap.h:37
bool pinmap_list_has_peripheral(const PeripheralList *list, int peripheral)
Check if the peripheral is in the list.
const PinMap * gpio_pinmap(void)
Get the pins that support all GPIO tests.
bool pinmap_find_peripheral_pins(const PinList *whitelist, const PinList *blacklist, int per, const PinMap *const *maps, PinName **pins, uint32_t count)
Find a combination of pins suitable for use given the constraints.
const PinMap * serial_cts_pinmap(void)
Get the pins that support Serial CTS.
const PinMap * spi_master_miso_pinmap(void)
Get the pins that support SPI MISO.
const PinMap * spi_master_cs_pinmap(void)
Get the pins that support SPI CS.
bool pinmap_list_has_pin(const PinList *list, PinName pin)
Check if the pin is in the list.
const PinMap * spi_master_clk_pinmap(void)
Get the pins that support SPI CLK.
const PinMap * gpio_irq_pinmap(void)
Get the pins that support all GPIO IRQ tests.
const PinMap * pwmout_pinmap(void)
Get the pins that support PWM.
const PinMap * serial_rts_pinmap(void)
Get the pins that support Serial RTS.
const PinMap * serial_rx_pinmap(void)
Get the pins that support Serial RX.
void operator==(const SafeBool< T > &lhs, const SafeBool< U > &rhs)
Avoid conversion to bool between different classes.
const PinList * pinmap_gpio_restricted_pins(void)
Get the pin list of pins to avoid during GPIO/GPIO_IRQ testing.
const PinMap * spi_slave_cs_pinmap(void)
Get the pins that support SPI CS.
const PinMap * spi_slave_mosi_pinmap(void)
Get the pins that support SPI MOSI.
Definition: pinmap.h:31
const PinList * pinmap_restricted_pins(void)
Get the pin list of pins to avoid during testing.
const PinMap * analogout_pinmap(void)
Get the pins that support analogout.
const PeripheralList * pinmap_uart_restricted_peripherals(void)
Get the pin list of peripherals per interface to avoid during testing.
const PinMap * spi_slave_clk_pinmap(void)
Get the pins that support SPI CLK.
const PinMap * spi_slave_miso_pinmap(void)
Get the pins that support SPI MISO.
const PinMap * analogin_pinmap(void)
Get the pins that support analogin.
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.