Fully understand pins_arduino.h for the Nano 33 BLE

I would like to fully understand pins_arduino.h for the Nano 33 BLE. I have several issues:

  1. The numbers and letters and brackets, u (unsigned) and ul (unsigned long)
    example:

#define PIN_SERIAL_RX (1ul)
#define PIN_INT_APDS (26u)
#define PIN_PDM_PWR (27)

In the above example defines, I assume everything is needed, but why do some have u, some ul and some just a number in brackets?

  1. The nrf52840 SOC has pins (~83 of them) labelled in multiple ways but some are like: P0.06 and P1.06. Also pins are labelled GPIO12, GPIO15 etc. Is there anyway to convert these numbers to #define numbers or do I need more reference information?

  2. Can't find #define pins for +3V3, +5V RESET, GND, VIN, AREF

  3. Several #define's don't seem to have physical pins. (Fine with that but do they have have physical pins somewhere?)


(22u) LEDR 
(23u) LEDG 
(24u) LEDB 
(25u) LED_PWR 
(26u) PIN_INT_APDS 
(27) PIN_PDM_PWR 
(28) PIN_PDM_CLK 
(29) PIN_PDM_DIN 
(30u) PIN_WIRE_SDA1 
(31u) PIN_WIRE_SCL1 
(32u) PIN_ENABLE_SENSORS_3V3 
(33u) PIN_ENABLE_I2C_PULLUP 

Here is an image of the Nano 33 BLE pinout with additions for the pins_arduino.h

The link is:

Hopefully this image shows up.

Here is a copy of the pins_arduino.h file


#pragma once
#include "mbed_config.h"
#include <stdint.h>
#include <macros.h>

#ifndef __PINS_ARDUINO__
#define __PINS_ARDUINO__

// Frequency of the board main oscillator
#define VARIANT_MAINOSC (32768ul)

// Master clock frequency
#define VARIANT_MCK (64000000ul)

// Pins
// ----

// Number of pins defined in PinDescription array
#ifdef __cplusplus
extern "C" unsigned int PINCOUNT_fn();
#endif
#define PINS_COUNT (PINCOUNT_fn())
#define NUM_DIGITAL_PINS (21u)
#define NUM_ANALOG_INPUTS (7u)
#define NUM_ANALOG_OUTPUTS (0u)

// LEDs
// ----
#define PIN_LED (13u)
#define LED_BUILTIN PIN_LED
#define LEDR (22u)
#define LEDG (23u)
#define LEDB (24u)
#define LED_PWR (25u)

// Analog pins
// -----------
#define PIN_A0 (14u)
#define PIN_A1 (15u)
#define PIN_A2 (16u)
#define PIN_A3 (17u)
#define PIN_A4 (18u)
#define PIN_A5 (19u)
#define PIN_A6 (20u)
#define PIN_A7 (21u)
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;
#define ADC_RESOLUTION 12

/*
* Serial interfaces
*/
// Serial (EDBG)
#define PIN_SERIAL_RX (1ul)
#define PIN_SERIAL_TX (0ul)

// SPI
#define PIN_SPI_MISO (12u)
#define PIN_SPI_MOSI (11u)
#define PIN_SPI_SCK (13u)
#define PIN_SPI_SS (10u)

static const uint8_t SS = PIN_SPI_SS; // SPI Slave SS not used. Set here only for reference.
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;

// Wire
#define PIN_WIRE_SDA (18u)
#define PIN_WIRE_SCL (19u)

#define PIN_WIRE_SDA1 (30u)
#define PIN_WIRE_SCL1 (31u)

#define PIN_ENABLE_SENSORS_3V3 (32u)
#define PIN_ENABLE_I2C_PULLUP (33u)

#define PIN_INT_APDS (26u)

// PDM Interfaces
// ---------------
#define PIN_PDM_PWR (27)
#define PIN_PDM_CLK (28)
#define PIN_PDM_DIN (29)

// These serial port names are intended to allow libraries and architecture-neutral
// sketches to automatically default to the correct port name for a particular type
// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
// the first hardware serial port whose RX/TX pins are not dedicated to another use.
//
// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor
//
// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
//
// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library
//
// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
//
// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX
// pins are NOT connected to anything by default.
#define SERIAL_PORT_USBVIRTUAL SerialUSB
#define SERIAL_PORT_MONITOR SerialUSB
#define SERIAL_PORT_HARDWARE Serial1
#define SERIAL_PORT_HARDWARE_OPEN Serial1

// Mbed specific defines
#define SERIAL_HOWMANY 1
#define SERIAL1_TX (digitalPinToPinName(PIN_SERIAL_TX))
#define SERIAL1_RX (digitalPinToPinName(PIN_SERIAL_RX))

#define SERIAL_CDC 1
#define HAS_UNIQUE_ISERIAL_DESCRIPTOR
#define BOARD_VENDORID 0x2341
#define BOARD_PRODUCTID 0x805a
#define BOARD_NAME "Nano 33 BLE"

#define DFU_MAGIC_SERIAL_ONLY_RESET 0xb0

#define I2C_SDA (digitalPinToPinName(PIN_WIRE_SDA))
#define I2C_SCL (digitalPinToPinName(PIN_WIRE_SCL))
#define I2C_SDA1 (digitalPinToPinName(PIN_WIRE_SDA1))
#define I2C_SCL1 (digitalPinToPinName(PIN_WIRE_SCL1))

#define SPI_MISO (digitalPinToPinName(PIN_SPI_MISO))
#define SPI_MOSI (digitalPinToPinName(PIN_SPI_MOSI))
#define SPI_SCK (digitalPinToPinName(PIN_SPI_SCK))

#define digitalPinToPort(P) (digitalPinToPinName(P)/32)

uint8_t getUniqueSerialNumber(uint8_t* name);
void _ontouch1200bps_();

#endif //__PINS_ARDUINO__

  1. Can't find #define pins for +3V3, +5V RESET, GND, VIN, AREF

Power pins are not accessible by software, so they are not defined.

  1. Several #define's don't seem to have physical pins. (Fine with that but do they have have physical pins somewhere?)

The controller has more physical pins than the module/pcb. Some of these pins are connected on the pcb. For instance there is a RGB LED right next to the BLE module.

  1. The numbers and letters and brackets, u (unsigned) and ul (unsigned long)

I suspect copy and paste from different sources.

Klaus_K:
Power pins are not accessible by software, so they are not defined.

The controller has more physical pins than the module/pcb. Some of these pins are connected on the pcb. For instance there is a RGB LED right next to the BLE module.

I suspect copy and paste from different sources.

Thanks Klaus_K.
Your answers are very useful. I was suspecting the copy and paste from different sources, as I tried (3u), (3), 3 and all seemed to work for redefining something.

I am also starting to understand the labeling.

Example:

GPIOs Nano # Port # Description #define Nano 33 BLE Pin Label

GPIO21 #21 P1.12 D3- (3u) D3

The variant.cpp file has some interesting information about this topic

#include "Arduino.h"

PinDescription g_APinDescription[] = {
// D0 - D7
P1_3, NULL, NULL, // D0/TX
P1_10, NULL, NULL, // D1/RX
P1_11, NULL, NULL, // D2
P1_12, NULL, NULL, // D3
P1_15, NULL, NULL, // D4
P1_13, NULL, NULL, // D5
P1_14, NULL, NULL, // D6
P0_23, NULL, NULL, // D7

// D8 - D13
P0_21, NULL, NULL, // D8
P0_27, NULL, NULL, // D9
P1_2, NULL, NULL, // D10
P1_1, NULL, NULL, // D11/MOSI
P1_8, NULL, NULL, // D12/MISO
P0_13, NULL, NULL, // D13/SCK/LED

// A0 - A7
P0_4, NULL, NULL, // A0
P0_5, NULL, NULL, // A1
P0_30, NULL, NULL, // A2
P0_29, NULL, NULL, // A3
P0_31, NULL, NULL, // A4/SDA
P0_2, NULL, NULL, // A5/SCL
P0_28, NULL, NULL, // A6
P0_3, NULL, NULL, // A7

// LEDs
P0_24, NULL, NULL, // LED R
P0_16, NULL, NULL, // LED G
P0_6, NULL, NULL, // LED B
P1_9, NULL, NULL, // LED PWR

P0_19, NULL, NULL, // INT APDS

// PDM
P0_17, NULL, NULL, // PDM PWR
P0_26, NULL, NULL, // PDM CLK
P0_25, NULL, NULL, // PDM DIN

// Internal I2C
P0_14, NULL, NULL, // SDA2
P0_15, NULL, NULL, // SCL2

// Internal I2C
P1_0, NULL, NULL, // I2C_PULL
P0_22, NULL, NULL, // VDD_ENV_ENABLE
};

extern "C" {
unsigned int PINCOUNT_fn() {
return (sizeof(g_APinDescription) / sizeof(g_APinDescription[0]));
}
}

#include "nrf_rtc.h"

void initVariant() {
// turn power LED on
pinMode(LED_PWR, OUTPUT);
digitalWrite(LED_PWR, HIGH);

// Errata Nano33BLE - I2C pullup is on SWO line, need to disable TRACE
// was being enabled by nrfx_clock_anomaly_132
CoreDebug->DEMCR = 0;
NRF_CLOCK->TRACECONFIG = 0;

// FIXME: bootloader enables interrupt on COMPARE[0], which we don't handle
// Disable it here to avoid getting stuck when OVERFLOW irq is triggered
nrf_rtc_event_disable(NRF_RTC1, NRF_RTC_INT_COMPARE0_MASK);
nrf_rtc_int_disable(NRF_RTC1, NRF_RTC_INT_COMPARE0_MASK);

// FIXME: always enable I2C pullup and power @startup
// Change for maximum powersave
pinMode(PIN_ENABLE_SENSORS_3V3, OUTPUT);
pinMode(PIN_ENABLE_I2C_PULLUP, OUTPUT);

digitalWrite(PIN_ENABLE_SENSORS_3V3, HIGH);
digitalWrite(PIN_ENABLE_I2C_PULLUP, HIGH);

NRF_PWM_Type* PWM[] = {
NRF_PWM0, NRF_PWM1, NRF_PWM2
#ifdef NRF_PWM3
,NRF_PWM3
#endif
};

for (unsigned int i = 0; i < (sizeof(PWM)/sizeof(PWM[0])); i++) {
PWM*->ENABLE = 0;*
_ PWM*->PSEL.OUT[0] = 0xFFFFFFFFUL;*_
_* }*_ 
_*}*_
<em>*#ifdef SERIAL_CDC*</em>
<em><em>static void utox8(uint32_t val, uint8_t* s) {</em></em>
_* for (int i = 0; i < 16; i=i+2) {*_
_* int d = val & 0XF;*_
_* val = (val >> 4);*_
_* s[15 - i -1] = d > 9 ? 'A' + d - 10 : '0' + d;*_
_* s[15 - i] = '\0';*_
_* }*_
_*}*_
<em><em>uint8_t getUniqueSerialNumber(uint8_t* name) {</em></em>
<em>* #define SERIAL_NUMBER_WORD_0 NRF_FICR->DEVICEADDR[1]*</em>
<em>* #define SERIAL_NUMBER_WORD_1 NRF_FICR->DEVICEADDR[0]*</em>
<em>* utox8(SERIAL_NUMBER_WORD_0, &name[0]);*</em>
<em>* utox8(SERIAL_NUMBER_WORD_1, &name[16]);*</em>
_* return 32;*_
_*}*_
<em>*void _ontouch1200bps_() {*</em>
<em>* __disable_irq();*</em>
<em>* NRF_POWER->GPREGRET = DFU_MAGIC_SERIAL_ONLY_RESET;*</em>
<em>* NVIC_SystemReset();*</em>
_*}*_
_*#endif*_
_*```*_

Also is there some reason why Arduino does not set the digital pins with defines? Unlike other Arduinos which use numbers for the main digital pins, on the Nano 33 the pins are labelled as D2, D3 etc.

#define D0 0
#define D1 1
#define D2 2
#define D3 3
#define D4 4
#define D5 5
#define D6 6
#define D7 7
#define D8 8
#define D9 9
#define D10 10
#define D11 11
#define D12 12
#define D13 13

I would not bother too much about reasons. The Arduino software is a playground and put together from all kinds of sources. They try to make software portable as much as possible to allow beginners to write simple sketches without the need to know what is going on underneath.

jerteach:
Also is there some reason why Arduino does not set the digital pins with defines? Unlike other Arduinos which use numbers for the main digital pins, on the Nano 33 the pins are labelled as D2, D3 etc.

This is how it's been done since the beginning of Arduino, and before that with the Wiring framework that Arduino was forked from. At this point, the system has been thoroughly established this way and that has propagated into many 3rd party boards definitions, and thus would be very hard to change universally. Adding these macros in only some packages will lead to people publishing code that won't compile for other boards that don't have these macros. This has already happened to some extent due to the ESP8266 adding these macros (but only for some boards).

I would rather it had gone the other way, where we don't have these An style names for the "analog pins". That leads people to think these pins are only usable for analog. Instead, I would prefer that all pins were referred to by integers. Different pins have different properties. Some have an ADC, some have PWM, some are I2C, SPI, UART, etc. That should all be documented, but not in the pin name.

I definitely agree that it's not beginner friendly that some pins are labeled the the An notation that you can use in your code, while other pins are labeled with the Dn notation that you can't use in your code. I would just prefer that was fixed on the silkscreen and documentation, rather than in the code.

pert:
I would rather it had gone the other way, where we don't have these An style names for the "analog pins".

Thanks Pert, I now understand that part, so if my PR to add the D# defines is rejected I wont be frustrated.

Klaus_K:
I would not bother too much about reasons.

Thanks Klaus_K, that also strangely helps. :confused:

Now for the big question: and I guess a bit of explanation. I have been doing a bit of platform mixing (each platform seems to have a few useful BLE examples), running the Nano33Ble on the Nordic platform and both the Nordic, Makerdiary and Particle Mesh boards (Xenon and Argon) on the Arduino platform (Yes this is very cool and I will make a youtube video eventually).

Both Nordic and Particle nRF52840 boards use most of the same pin names (on different pins but that is OK using #defines to change them) but a few pins are completely different.

Is defining a pin that isn't used on the Nano33Ble an easy change in my sketch or a horrible hex # path of pain to descend down?

On the MakerDiary nRF52840 Dongle these pins are the only ones different than on the Nano33BLE

P0.08
P0.26
P1.04
P1.05
P1.06