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  utest_printf("Skipping (NC pin) %s pin %s (%i)\r\n", pin_type,
119  FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
120  continue;
121  }
122 
123  // Set pin being tested
124  port.pins[i] = FormFactorType::pins()->pins[j];
125  port.peripheral = pinmap_find_peripheral(port.pins[i], map);
126 
127  // Don't test restricted pins
128  if (pinmap_list_has_pin(FormFactorType::restricted_pins(), port.pins[i])) {
129  utest_printf("Skipping (restricted pin) %s pin %s (%i)\r\n", pin_type,
130  FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
131  continue;
132  }
133 
134  if (!strcmp(PortType::PinMap::name, GPIO_IRQ_NAME) || !strcmp(PortType::PinMap::name, GPIO_NAME)) {
135  // Don't test restricted gpio pins
136  if (pinmap_list_has_pin(pinmap_gpio_restricted_pins(), port.pins[i])) {
137  utest_printf("Skipping (restricted gpio pin) %s pin %s (%i)\r\n", pin_type,
138  FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
139  continue;
140  }
141  }
142 
143 #if DEVICE_SERIAL
144  if (!strcmp(PortType::PinMap::name, UART_NAME) || !strcmp(PortType::PinMap::name, UARTNOFC_NAME)) {
146  utest_printf("Skipping (restricted uart peripheral) %s peripheral %i with pin %s (%i)\r\n", pin_type,
147  port.peripheral, FormFactorType::pin_to_string(port.pins[i]), port.pins[i]);
148  continue;
149  }
150  }
151 #endif
152 
153  // skipp pin searching if single pin port type
154  if (PortType::pin_count > 1) {
155  find_port_pins<PortType, FormFactorType>(port);
156  }
157  if (port.empty()) {
158  not_matched_ports.push_back(port);
159  } else {
160  matched_ports.push_back(port);
161  }
162  }
163  }
164 }
165 
166 
167 template<typename PortType, typename FormFactorType, typename FunctionType, FunctionType f>
168 void test_all_ports(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
169 {
170  typedef typename std::list<PortType>::iterator Iter;
171  utest_printf("***Testing %s on all form factor ports***\n", PortType::PinMap::name);
172  const PinList *ff_pins = FormFactorType::pins();
174 
175  if (matched_ports.empty() && not_matched_ports.empty()) {
176  utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
177  return;
178  }
179 
180  for (uint32_t i = 0; i < ff_pins->count; i++) {
181  for (Iter it = matched_ports.begin(); it != matched_ports.end(); ++it) {
182  PortType &port = *it;
183  for (uint32_t j = 0; j < PortType::pin_count; j++) {
184  if (ff_pins->pins[i] == port.pins[j]) {
185  utest_printf("%3s - %s pin tested on port: %s...", FormFactorType::pin_to_string(ff_pins->pins[i]),
186  PortType::PinMap::pin_type_names[j], port.str());
187  if (port.status == PortType::StatusNotTested) {
188  call(port);
189  port.status = PortType::StatusPass;
190  }
191  utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
192  goto end_port_iteration;
193  }
194  }
195  }
196  for (Iter it = not_matched_ports.begin(); it != not_matched_ports.end(); ++it) {
197  PortType &port = *it;
198  for (uint32_t j = 0; j < PortType::pin_count; j++) {
199  if (ff_pins->pins[i] == port.pins[j]) {
200  utest_printf("%3s - Could not find pins to test %s pin %s (%d)\n",
201  FormFactorType::pin_to_string(ff_pins->pins[i]),
202  PortType::PinMap::pin_type_names[j],
203  FormFactorType::pin_to_string(ff_pins->pins[i]),
204  ff_pins->pins[i]);
205  goto end_port_iteration;
206  }
207  }
208  }
209 end_port_iteration:
210  ;
211  }
212 }
213 
214 template<typename PortType, typename FunctionType, FunctionType f>
215 void test_peripheral(PortType &port)
216 {
217  if (port.empty()) {
218  utest_printf("%d - Could not find pins to test peripheral\n", port.peripheral);
219  } else {
220  utest_printf("%d - peripheral tested on port: %s...", port.peripheral, port.str());
221  if (port.status == PortType::StatusNotTested) {
223  call(port); // run test
224  port.status = PortType::StatusPass;
225  }
226  utest_printf("%s\n", port.status == PortType::StatusPass ? "succeeded" : "failed");
227  }
228 }
229 
230 template<typename PortType, typename FunctionType, FunctionType f>
231 void test_all_peripherals(std::list<PortType> &matched_ports, std::list<PortType> &not_matched_ports)
232 {
233  typedef typename std::list<PortType>::iterator Iter;
234  utest_printf("***Testing all %s peripherals***\n", PortType::PinMap::name);
235 
236  if (matched_ports.empty() && not_matched_ports.empty()) {
237  utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
238  return;
239  }
240 
241  matched_ports.sort(peripheral_less<PortType>);
242  not_matched_ports.sort(peripheral_less<PortType>);
243 
244  for (Iter m_it = matched_ports.begin(), nm_it = not_matched_ports.begin();
245  m_it != matched_ports.end() || nm_it != not_matched_ports.end();) {
246  if (m_it != matched_ports.end() && nm_it != not_matched_ports.end()) {
247  if ((*m_it).peripheral < (*nm_it).peripheral) {
248  test_peripheral<PortType, FunctionType, f>(*m_it);
249  ++m_it;
250  } else {
251  test_peripheral<PortType, FunctionType, f>(*nm_it);
252  ++nm_it;
253  }
254  } else if (m_it != matched_ports.end()) {
255  test_peripheral<PortType, FunctionType, f>(*m_it);
256  ++m_it;
257  } else if (nm_it != not_matched_ports.end()) {
258  test_peripheral<PortType, FunctionType, f>(*nm_it);
259  ++nm_it;
260  }
261  }
262 }
263 
264 /**
265  * Test function for all pinouts of all peripherals of a given type
266  *
267  * This template function takes in three template parameters:
268  * - PortType - The type of peripheral to test
269  * - FormFactorType - The form factor to test on
270  * - f - The test function to run.
271  *
272  * This function calls the test function multiple times with
273  * the appropriate combinations of pins.
274  */
275 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
276 void all_ports()
277 {
278  std::list<PortType> matched_ports, not_matched_ports;
279  find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
280  matched_ports.unique();
281  not_matched_ports.unique();
282  test_all_ports<PortType, FormFactorType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
283 }
284 
285 /**
286  * Test function for one pinout of all peripherals of a given type
287  *
288  * This template function takes in three template parameters:
289  * - PortType - The type of peripheral to test
290  * - FormFactorType - The form factor to test on
291  * - f - The test function to run.
292  *
293  * This function calls the test function once for each peripheral
294  * of the given type.
295  */
296 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
297 void all_peripherals()
298 {
299  std::list<PortType> matched_ports, not_matched_ports;
300  find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
301 
302  matched_ports.sort(peripheral_less<PortType>);
303  not_matched_ports.sort(peripheral_less<PortType>);
304  matched_ports.unique(peripheral_comparator<PortType>);
305  not_matched_ports.unique(peripheral_comparator<PortType>);
306 
307  test_all_peripherals<PortType, typename PortType::TestFunctionType, f>(matched_ports, not_matched_ports);
308 }
309 
310 /**
311  * Test function for one pinout of one peripheral of a given type
312  *
313  * This template function takes in three template parameters:
314  * - PortType - The type of peripheral to test
315  * - FormFactorType - The form factor to test on
316  * - f - The test function to run.
317  *
318  * This function calls the test function once for one peripheral
319  * of the given type.
320  */
321 template<typename PortType, typename FormFactorType, typename PortType::TestFunctionType f>
322 void one_peripheral()
323 {
324 #ifdef FPGA_FORCE_ALL_PORTS
325  utest_printf("*** FPGA_FORCE_ALL_PORTS ***\n");
326  all_ports<PortType, FormFactorType, f>();
327 #else
328  std::list<PortType> matched_ports, not_matched_ports;
329  find_ports<PortType, FormFactorType>(matched_ports, not_matched_ports);
330 
331  utest_printf("***Testing one %s pin configuration***\n", PortType::PinMap::name);
332  if (matched_ports.empty()) {
333  utest_printf("Could not find pins for %s testing \n", PortType::PinMap::name);
334  } else {
335  test_peripheral<PortType, typename PortType::TestFunctionType, f>(matched_ports.front());
336  }
337 #endif
338 }
339 
340 template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
341 class Port;
342 
343 template <uint32_t N, typename PinMapType, typename FormFactorType, typename TestFunctionType>
346 
347 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
348 class Port {
349 public:
350  int peripheral;
351  PinName pins[N];
352  PinName *ppins[N];
353 
354  static const uint32_t pin_count = N;
355  typedef PinMapType PinMap;
356  typedef FunctionType TestFunctionType;
357 
358  enum Status { StatusPass, StatusFail, StatusNotTested };
359  Status status;
360 
361  Port(): peripheral(NC), status(StatusNotTested)
362  {
363  init_pins();
364  }
365 
366  Port(const Port &port)
367  {
368  init_pins();
369  copy_from(port);
370  }
371 
372  void init_pins()
373  {
374  for (uint32_t i = 0; i < N; i++) {
375  pins[i] = NC;
376  ppins[i] = &pins[i];
377  }
378  }
379 
380  void copy_from(const Port &port)
381  {
382  peripheral = port.peripheral;
383  status = port.status;
384  for (uint32_t i = 0; i < N; i++) {
385  pins[i] = port.pins[i];
386  }
387  }
388 
389  bool empty()
390  {
391  if (peripheral == NC) {
392  return true;
393  }
394  for (uint32_t i = 0; i < N; i++) {
395  if (pins[i] == NC) {
396  return true;
397  }
398  }
399  return false;
400  }
401 
402  const char *str()
403  {
404  static char port_str[128];
405  char pin_str[32];
406  sprintf(port_str, "peripheral=(%d) ", peripheral);
407  for (uint32_t i = 0; i < N; i++) {
408  sprintf(pin_str, "%s=(%s) ", PinMap::pin_type_names[i], FormFactorType::pin_to_string(pins[i]));
409  strcat(port_str, pin_str);
410  }
411  return port_str;
412  }
413 
415 };
416 
417 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
419 
420 template <uint32_t N, typename PinMapType, typename FormFactorType, typename FunctionType>
422 {
423  if (port1.peripheral != port2.peripheral) {
424  return false;
425  }
426  for (uint32_t i = 0; i < N; i++) {
427  if (port1.pins[i] != port2.pins[i]) {
428  return false;
429  }
430  }
431  return true;
432 }
433 
434 /**
435  * This is a convenience class for use with the above templates
436  *
437  * This class can be passed as a template parameter to all_ports,
438  * all_peripherals or one_peripheral to choose test pins from
439  * the default form factor.
440  */
442 public:
443  static const PinList *pins()
444  {
445  return pinmap_ff_default_pins();
446  }
447 
448  static const PinList *restricted_pins()
449  {
450  return pinmap_restricted_pins();
451  }
452 
453  static const char *pin_to_string(PinName pin)
454  {
455  return pinmap_ff_default_pin_to_string(pin);
456  }
457 };
458 
459 /*
460  * Peripheral port declarations are given below
461  *
462  * Each Port type represents a set of pins used by a peripheral.
463  * The Port typedef is used as a template parameter to the functions
464  * all_ports, all_peripherals and one_peripheral to select the peripheral
465  * pin set to use for testing.
466  */
467 
468 struct GPIOMaps {
469  static const PinMap *maps[];
470  static const char *const pin_type_names[];
471  static const char *const name;
472 };
473 const PinMap *GPIOMaps::maps[] = { gpio_pinmap() };
474 const char *const GPIOMaps::pin_type_names[] = { "IO" };
475 const char *const GPIOMaps::name = GPIO_NAME;
477 
478 #if DEVICE_INTERRUPTIN
479 #include "gpio_irq_api.h"
480 struct GPIOIRQMaps {
481  static const PinMap *maps[];
482  static const char *const pin_type_names[];
483  static const char *const name;
484 };
485 const PinMap *GPIOIRQMaps::maps[] = { gpio_irq_pinmap() };
486 const char *const GPIOIRQMaps::pin_type_names[] = { "IRQ_IN" };
487 const char *const GPIOIRQMaps::name = GPIO_IRQ_NAME;
489 #endif
490 
491 #if DEVICE_SPI
492 #include "spi_api.h"
493 struct SPIMaps {
494  static const PinMap *maps[];
495  static const char *const pin_type_names[];
496  static const char *const name;
497 };
498 const PinMap *SPIMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap(), spi_master_cs_pinmap() };
499 const char *const SPIMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
500 const char *const SPIMaps::name = SPI_NAME;
502 
503 struct SPINoCSMaps {
504  static const PinMap *maps[];
505  static const char *const pin_type_names[];
506  static const char *const name;
507 };
508 const PinMap *SPINoCSMaps::maps[] = { spi_master_mosi_pinmap(), spi_master_miso_pinmap(), spi_master_clk_pinmap()};
509 const char *const SPINoCSMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK" };
510 const char *const SPINoCSMaps::name = SPI_NAME;
512 
513 struct SPISlaveMaps {
514  static const PinMap *maps[];
515  static const char *const pin_type_names[];
516  static const char *const name;
517 };
518 const PinMap *SPISlaveMaps::maps[] = { spi_slave_mosi_pinmap(), spi_slave_miso_pinmap(), spi_slave_clk_pinmap(), spi_slave_cs_pinmap() };
519 const char *const SPISlaveMaps::pin_type_names[] = { "MOSI", "MISO", "SCLK", "SSEL" };
520 const char *const SPISlaveMaps::name = SPISLAVE_NAME;
522 #endif
523 
524 #if DEVICE_I2C
525 #include "i2c_api.h"
526 struct I2CMaps {
527  static const PinMap *maps[];
528  static const char *const pin_type_names[];
529  static const char *const name;
530 };
531 const PinMap *I2CMaps::maps[] = { i2c_master_sda_pinmap(), i2c_master_scl_pinmap() };
532 const char *const I2CMaps::pin_type_names[] = { "SDA", "SCL" };
533 const char *const I2CMaps::name = I2C_NAME;
535 #endif
536 
537 #if DEVICE_PWMOUT
538 #include "pwmout_api.h"
539 struct PWMMaps {
540  static const PinMap *maps[];
541  static const char *const pin_type_names[];
542  static const char *const name;
543 };
544 const PinMap *PWMMaps::maps[] = { pwmout_pinmap() };
545 const char *const PWMMaps::pin_type_names[] = { "PWM_OUT" };
546 const char *const PWMMaps::name = PWM_NAME;
548 #endif
549 
550 #if DEVICE_ANALOGIN
551 #include "analogin_api.h"
552 struct AnaloginMaps {
553  static const PinMap *maps[];
554  static const char *const pin_type_names[];
555  static const char *const name;
556 };
557 const PinMap *AnaloginMaps::maps[] = { analogin_pinmap() };
558 const char *const AnaloginMaps::pin_type_names[] = { "ADC_IN" };
559 const char *const AnaloginMaps::name = ANALOGIN_NAME;
561 #endif
562 
563 #if DEVICE_ANALOGOUT
564 #include "analogout_api.h"
566  static const PinMap *maps[];
567  static const char *const pin_type_names[];
568  static const char *const name;
569 };
570 const PinMap *AnalogoutMaps::maps[] = { analogout_pinmap() };
571 const char *const AnalogoutMaps::pin_type_names[] = { "DAC_OUT" };
572 const char *const AnalogoutMaps::name = ANALOGOUT_NAME;
574 #endif
575 
576 #if DEVICE_SERIAL
577 #if DEVICE_SERIAL_FC
578 #include "hal/serial_api.h"
579 struct UARTMaps {
580  static const PinMap *maps[];
581  static const char *const pin_type_names[];
582  static const char *const name;
583 };
584 const PinMap *UARTMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap(), serial_cts_pinmap(), serial_rts_pinmap() };
585 const char *const UARTMaps::pin_type_names[] = { "TX", "RX", "CLS", "RTS" };
586 const char *const UARTMaps::name = UART_NAME;
588 #endif
589 
590 struct UARTNoFCMaps {
591  static const PinMap *maps[];
592  static const char *const pin_type_names[];
593  static const char *const name;
594 };
595 const PinMap *UARTNoFCMaps::maps[] = { serial_tx_pinmap(), serial_rx_pinmap() };
596 const char *const UARTNoFCMaps::pin_type_names[] = { "TX", "RX" };
597 const char *const UARTNoFCMaps::name = UARTNOFC_NAME;
599 #endif
600 #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:441
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.