Totally new in this and need a basic question answered.. (How to map device pin with pin numbers in Arduino Code

Following PINMAP:
//#define BAT_READ 14 // P0_14 = 14 Reads battery voltage from divider on signal board. (PIN_VBAT is reading voltage divider on XIAO and is program pin 32 / or P0.31)
#define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED
#define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge

Question: I do not even see PIN 17 or 23 in the actual Drawing of the device…
How to map actual Device pin with the above pin numbers? cant find a reference…
Please help;;

There is a pin definition in the onboard package, you can check it.


I do not see a CHARGE_LED (Yellow LED) pin defined…
I see some BLE SENSE Codes are using

For example i see some Example Code in the forum has the below two lines:
#define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED
#define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge

But the pins_arduino.h file doesnt have the above pins defined…


// LEDs
// ----
#define PIN_LED (11u)
#define LEDR (11u)
#define LEDG (12u)
#define LEDB (13u)
#define LED_PWR (11u)

// Analog pins
// -----------
#define PIN_A0 (0u)
#define PIN_A1 (1u)
#define PIN_A2 (2u)
#define PIN_A3 (3u)
#define PIN_A4 (4u)
#define PIN_A5 (5u)
#define PIN_VBAT (32u)
//#define PIN_A6 (6u)
//#define PIN_A7 (u)
static const uint8_t A0 = PIN_A0;
static const uint8_t A1 = PIN_A1;
static const uint8_t A2 = PIN_A2;
static const uint8_t A3 = PIN_A3;
static const uint8_t A4 = PIN_A4;
static const uint8_t A5 = PIN_A5;
//static const uint8_t A6 = PIN_A6;
//static const uint8_t A7 = PIN_A7;

Don’t know about the charge LED question

Looks like the sample code is not directly usable on the Xiao, as you note the pins are not defined in the header file. You will need to update the code to reflect your boards capabilities.

[/Begin Editorial Comment]
When I first ran a few examples in my brand new XIAO BLE boards a couple of months ago, I was disappointed to see non-working examples throughout the web, including Seeed examples. I piddled around and fiddled around until I got something more-or-less useful. Then I drew some non-valid generalizations from my experience and moved on. A few things bugged me, but I had other things to spend my time on, so I kind of left things for later.

Now, during these long Summer days and short Summer nights, my curiosity got the better of me (See Footnote), so I decided to try to find out what really is happening. And, in particular, why Seeed’s examples now tell you to use board package 1.0.0, but they left 2.7.2 ‘out there’ for us to stumble over.

I’m thinking I have found the source of the problem. The source of the problem is software tools developers who aren’t aware of anything outside of their own little sandbox and are not forced into a discipline of regression testing that tries to prevent new releases from breaking existing software. (Or, at least, documenting what changes must be made by real customers to keep their products on the air.)
[/End Editorial Comment]

To the Original Poster: Your #define statements are from examples that are using board package 1.0.0.

There is a table in the variants directory (in variants.cpp) that is used by the software to translate the Arduino pin number to a form that is used by the compiler to access a particular pin of a particular hardware port.

There are two hardware ports: Port 0 and Port 1
The nrf52 hardware has 32 bits defined for Port 0 and 16 for Port 1

Not all of these GPIO pins are connected in the XIAO BLE boards. There are 33 Arduino pins that are defined for the hardware pins that are connected. Most of the Arduino pins that are not connected to external XIAO BLE pins don’t have names #defined in the variants.h file (or pins_arduino.h for some board packages).

The Arduino table for the XIAO BLE Sense has 33 entries that translate an Arduino pin (0, 1, …, 32) to a GPIO pin. The numeric value of a particular GPIO pin is translated like this: GPIO Pin Number = (Port Number * 32) + Pin Number where Port Number is 0 or 1.

When you do something like digitalWrite(1), it uses the number 1 as an index into this table to obtain the compiler’s GPIO pin value for that Arduino pin

For example (using the Port.Pin notation as shown on the schematic):
Arduino pin 1 gets translated to Port.Pin P0.03, which is GPIO 3 (0 * 32+3)
Arduino pin 8 gets translated to Port.Pin P1.13, which is GPIO 45 (1 * 32+13)

Here’s the table for XIAO BLE board package 1.0.0:

const uint32_t g_ADigitalPinMap[] =
  // D0 .. D13
   2,  // D0  is P0.02 (A0)
   3,  // D1  is P0.03 (A1)
  28,  // D2  is P0.28 (A2)
  29,  // D3  is P0.29 (A3)
   4,  // D4  is P0.04 (A4,SDA) 
   5,  // D5  is P0.05 (A5,SCL)
  43,  // D6  is P1.11 (TX)
  44,  // D7  is P1.12 (RX)
  45,  // D8  is P1.13 (SCK)
  46,  // D9  is P1.14 (MISO)
  47,  // D10 is P1.15 (MOSI)
  // LEDs
  26,  // D11 is P0.26 (LED RED)
   6,  // D12 is P0.06 (LED BLUE) 
  30,  // D13 is P0.30 (LED GREEN) 
  14,  // D14 is P0.14 (READ_BAT)

  // LSM6DS3TR
  40,  // D15 is P1.08 (6D_PWR)
  27,  // D16 is P0.27 (6D_I2C_SCL)
   7,  // D17 is P0.07 (6D_I2C_SDA)
  11,  // D18 is P0.11 (6D_INT1)

  // MIC
  42,//17,//42,  // D19 is P1.10 (MIC_PWR)
  32,//26,//32,  // D20 is P1.00 (PDM_CLK)
  16,//25,//16,  // D21 is P0.16 (PDM_DATA)

  // BQ25100
  13,  // D22 is P0.13 (HICHG)
  17,  // D23 is P0.17 (~CHG)

  21,  // D24 is P0.21 (QSPI_SCK)
  25,  // D25 is P0.25 (QSPI_CSN)
  20,  // D26 is P0.20 (QSPI_SIO_0 DI)
  24,  // D27 is P0.24 (QSPI_SIO_1 DO)
  22,  // D28 is P0.22 (QSPI_SIO_2 WP)
  23,  // D29 is P0.23 (QSPI_SIO_3 HOLD)

  // NFC
   9,  // D30 is P0.09 (NFC1)
  10,  // D31 is P0.10 (NFC2)
  // VBAT
  31,  // D32 is P0.10 (VBAT) //From davekw7x: Typo in comment! Should be P0.31

Note: From this table D23 becomes GPIO17, corresponding to P0.17

Here’s a sketch that causes the LED on P0.17 to flash every second:

 * XIAO BLE Sense
 * Test to illustrate difference between 1.0.0 and 2.7.2 for
 * the LED on P0.17 (Indicating that charging is enabled)
 * July, 2022
 * davekw7x

 // Uncomment exactly one of the following '#define CHARGE_LED' directives,
 // depending on which version of the XIAO BLE boards package you have
 // installed.  If you do it right, the Blue LED on chip pin P0.17 will
 // flash briefly every second
 // For board package 2.7.2 uncomment the following
 //#define CHARGE_LED 22

// For board package 1.0.0 uncomment  the following
#define CHARGE_LED 23

// The LED is connected in an active-low configuration
#define LED_ON  LOW
#define LED_OFF HIGH
void setup()
  while (!Serial)
  // I give it a little time for things to settle down before printing
  Serial.println("\nCompiled by davekw7x on " __DATE__ " at " __TIME__);
  Serial.print("CHARGE_LED is on Arduino pin ");Serial.println(CHARGE_LED);
}  // End of setup()

void loop()
  while (1) {
    digitalWrite(CHARGE_LED, LED_ON);  // Turn it on briefly
    digitalWrite(CHARGE_LED, LED_OFF); // Turn it off for a somewhat longer time
}  // End of loop()

The translation table for board package 2.7.2 is DIFFERENT from the one used in 1.0.0 for Arduino pins greater than 13.

Here’s the table used in 2.7.2 (It’s in a different format; for this table the first entry in each row is the GPIO number. The important thing is not the format, but the GPIO number for a given position in the table.)

PinDescription g_APinDescription[] = {
  // D0 - D10
  { P0_2,  NULL, NULL, NULL },     // D0/A0
  { P0_3,  NULL, NULL, NULL },     // D1/A1
  { P0_28, NULL, NULL, NULL },     // D2/A2
  { P0_29, NULL, NULL, NULL },     // D3/A3
  { P0_4,  NULL, NULL, NULL },     // D4/A4/SDA
  { P0_5,  NULL, NULL, NULL },     // D5/A5/SCL
  { P1_11, NULL, NULL, NULL },     // D6/TX
  { P1_12, NULL, NULL, NULL },     // D7/RX
  { P1_13, NULL, NULL, NULL },     // D8/SCK
  { P1_14, NULL, NULL, NULL },     // D9/MISO
  { P1_15, NULL, NULL, NULL },     // D10/MOSI
  // LEDs
  { P0_26, NULL, NULL, NULL },     // D11/LED RED
  { P0_30, NULL, NULL, NULL },     // D12/LED GREEN
  { P0_6,  NULL, NULL, NULL },     // D13/LED BLUE

  // LSM6DS3TR
  { P1_8,  NULL, NULL, NULL },     // D14/6D_PWR
  { P0_27, NULL, NULL, NULL },     // D15/6D_I2C_SCL
  { P0_7,  NULL, NULL, NULL },     // D16/6D_I2C_SDA
  { P0_11, NULL, NULL, NULL },     // D17/6D_INT1

  // PDM
  { P1_10, NULL, NULL, NULL },     // D18/PDM PWR
  { P1_0,  NULL, NULL, NULL },     // D19/PDM CLK
  { P0_16, NULL, NULL, NULL },     // D20/PDM DIN

  // BQ25100
  { P0_13, NULL, NULL, NULL },     // D21/HICHG
  { P0_17, NULL, NULL, NULL },     // D22/~CHG

  // QSPI
  { P0_21, NULL, NULL, NULL },     // D23/QSPI_SCK
  { P0_25, NULL, NULL, NULL },     // D24/QSPI_CSN
  { P0_20, NULL, NULL, NULL },     // D25/QSPI_SIO_0 DI
  { P0_24, NULL, NULL, NULL },     // D26/QSPI_SIO_1 DO
  { P0_22, NULL, NULL, NULL },     // D27/QSPI_SIO_2 WP
  { P0_23, NULL, NULL, NULL },     // D28/QSPI_SIO_3 HOLD

  // NFC
  { P0_9,  NULL, NULL, NULL },     // D29/I2C_PULL
  { P0_10, NULL, NULL, NULL },     // D30/VDD_ENV_ENABLE
  // VBAT
  { P0_14, NULL, NULL, NULL },     // D31/VBAT_ENABLE
  { P0_31, NULL, NULL, NULL },     // D32/VBAT_READ

If you look carefully, you will see that Arduino pin numbers greater than 13 and less than 32 feed the compiler different GPIO numbers.

In particular, if you are using 2.7.2, the CHARGE_LED on P0.17 is actually Arduino pin 22, and if you change the #define statement in my little sketch accordingly you will see the LED flash.

Yes. Really! Arduino Sketches written for board package 1.0.0 WILL NOT RUN CORRECTLY with software board package 2.7.2 if you are using Arduino pins 14 through 31. (Note that Arduino pin 32 is P0.31 for both packages, but all the other Arduino pins greater than 13 are off by one. That’s pitiful!)

Sorry to take so much bandwidth, but maybe someone can make enough sense of this to create a better (shorter) explanation. Don’t know how to fix the fact that there are two incompatible board packages in the wild.

Bottom line: I don’t know why (oh, why!) the software guys decided to change the table. I’m thinking that there was a Reason, but I’m not so sure it was a Good Reason.
Especially since we now see sketches that work on one release but not the other. Maybe the low-power guys think it’s worth looking into. (Or, maybe, not—YMMV)

Oh, well…



The cure for boredom is curiosity.
There is no cure for curiosity.

Hi Dave,

You are a breath of FreshAir…

I am an engineer , work for intel corporation, but never tried getting onto these , just didnt need to or didn’t have interest…
Now I am designing a Prosthesis device for my 2 year old son, and need a IMU Device with BLE/WIFI so that i can process those information and take actions… Obviously IMU/BLE/Charging along with Battery needs to be as small as possible so that he can carry that onto his upper arm prosthesis…

If you do not mind I will bug you from time to time, i have to get the electronics part completed for my son even if it takes me years to understand these, just have to…

I havent tested or tried out your explanations yet, will try…

thank you and Appreciate your time!

Different runtimes may be some of the reason. Looks like V1.0.0 uses the Adafruit runtime version while 2.7.2 uses the mbed runtime version.
Beyond that I’ve no clue, but thanks for the post.