PIN Mapping: nrf51 to Arduino


#1

Hi everyone!

Forgive me if this is not the correct category, I am new and I’ve just signed up.

I tried to program my nrf51422 DK using PlatformIO with the Arduino Framework. My test program is very simple: I just want to define a random GPIO as Output and make an LED blink. This LED is, of course, connected with the GPIO (I randomly chose pin 14):

Vcc — LED ---- GPIO_14

My code:

#include <Arduino.h>

#define MYLED 14

void setup() {
// put your setup code here, to run once:
pinMode(MYLED, OUTPUT);
}

void loop() {
// put your main code here, to run repeatedly:

digitalWrite(MYLED, HIGH);
delay(1000);
digitalWrite(MYLED, LOW);
delay(1000);
}

But nothing is happening. With this code, is it really the pin 14 on my nrf51422 DK? Is this “14” a pin on the Arduino board? If yes, is there a Pin Map, such that I can directly use the nrf51 pins?

A serial output like Serial.println(“Hello”) was possible, which means that I can flash it. And also it was possible to blink the built in led with: LED_BUILTIN. But where exactly do I find the definitions of LED_BUILTIN anyway? And

When I flash the nrf51422 DK with my MYLED 14 (from above) using the Keil IDE, then it works. Which means that nothing is physically borken.

Can anyone help please?


#2

Yes, the SDK re-maps the pin argument to a different pin. The files in which this is done can be found in your .platformio (in your home folder, Linux /home/<username>, Windows C:\Usesr\<Usersname>\ folder in, packages/framework-arduinonordicnrf5/variants/nRF51Dongle/variant.h and variant.cpp, as well es in the core/nRF5/wiring_digital.c file.

from variant.h

// Number of pins defined in PinDescription array
#define PINS_COUNT           (11u)
#define NUM_DIGITAL_PINS     (11u)
#define NUM_ANALOG_INPUTS    (6u)
#define NUM_ANALOG_OUTPUTS   (0u)

// LEDs
#define PIN_LED1                (21)
#define PIN_LED2                (22)
#define PIN_LED3                (23)

#define LED_BUILTIN             PIN_LED1

from variant.cpp:

const uint32_t g_ADigitalPinMap[] = {
  //LEDs
  21,
  22,
  23,
  //A0-6
  15,
  16,
  17,
  18,
  19,
  20,
  //Serial
  9,
  11
};

from wiring_digital.c:


void digitalWrite( uint32_t ulPin, uint32_t ulVal )
{
  if (ulPin >= PINS_COUNT) {
    return;
  }

  ulPin = g_ADigitalPinMap[ulPin];

  switch ( ulVal )
  {
    case LOW:
      NRF_GPIO->OUTCLR = (1UL << ulPin);
    break ;

    default:
      NRF_GPIO->OUTSET = (1UL << ulPin);
    break ;
  }

  return ;
}

So, when you want GPIO14, this is “A1”, so can you give “A1” as the pinMode and digitalWrite argument?


#3

Sorry for above answer, I messed up the GPIO numbers. The number 14 does not seem to be in the g_ADigitalPinMap? Can you give some pin documentation on your board? I found http://infocenter.nordicsemi.com/pdf/nRF51_DK_UG_v1.0.pdf and on page 15 it tells you the Arduino Pin numbers. Do you mean “PD_14”, which is digital pin 2 ("D2)?


#4

Thanks I found the files. But I cannot find a mapping for the Nordic NRF51 DK.
If I try to use the pin numbers defined in the files for the Dongle, it does not work. The same with RedBearLab DK.

The only thing that I managed to do so far is just blinking the PIN_LED1, PIN_LED2 or PIN_LED3.
That’s it.

  1. Where is the exact mapping for the Nordic NRF51 DK?

  2. On the DK there pin numbers like P0.18, which is ACTUALLY pin26 on the Chip itself. I guess the definitions in these variant files are the P0.xx numbers. But how for example can I use the array g_ADigitalPinMap[] directly? Just as g_ADigitalPinMap[0], g_ADigitalPinMap[1], …?

One can check the pin numbers on page 11 here:

  1. When I tried to flash my Nordic NRF51 DK with the program that uses PIN_A0, it says that PIN_A0 is not defined. Why not? How can I know?

Sry, really confusing… :-/


#5

Pin numbers on the physical package of the chip should not be relevant. The numbers should be referring to the GPIO number, i.e. the P0.X part.

Is it now “GPIO14” or “P0.18”? Where does it say GPIO14? You gave me a manual for the chip, but not for the exact board you’re using, do you have a manual for that?

Also, Can you try the code with direct register manipulation? The problem might be that P0.18 is not included in the port map and thus un-modifyable by pinMode() and digitalWrite().

#include "nrf.h"
#include "Arduino.h"

/* P0.X number */
#define MYLED 18

void setup() {
    //Stolen from pinMode() but without internal pin mapping conversion.
      NRF_GPIO->PIN_CNF[MYLED] = ((uint32_t)GPIO_PIN_CNF_DIR_Output       << GPIO_PIN_CNF_DIR_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_PULL_Disabled    << GPIO_PIN_CNF_PULL_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
                               | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
 }
void loop() {
//stolen from digitalWrite() without checks and pin mapping
NRF_GPIO->OUTSET = (1UL << MYLED);
delay(1000);
NRF_GPIO->OUTCLR = (1UL << MYLED);
delay(1000);
 }


#6

I dont mean specifically PO.14, this was just an example. I want to make any pin go high/low in order to make an LED blink.

This is the board I am using:
https://images.google.ch/imgres?imgurl=https%3A%2F%2Fos.mbed.com%2Fmedia%2Fuploads%2Fgamnes%2Fnrf51-dk_v1.2.0_top_pin_information_with_logo.png&imgrefurl=https%3A%2F%2Fos.mbed.com%2Fplatforms%2FNordic-nRF51-DK%2F&docid=42injPyADWm0DM&tbnid=7XePNZMogT1xVM%3A&vet=1&w=5302&h=3995&hl=en-ch&source=sh%2Fx%2Fim

Thank you for your last reply I will have to check it out asap. Haven’t yet.

But let’s say it’s really the variant files for the “dongle”. Are the pins defined in “g_ADigitalPinMap” the only ones available? If yes, is it possible to add pins to this map / to variant.cpp & varaiant.h?


#7

Okay, sorry for this to getting a little bit confusing. I’ve create a project myself using pio init -b nrf51_dk --ide=eclipse. After compiling a test program I realized that it uses the variant.cpp in variants\PCA1000X\variant.cpp with the macro PCA10000 defined… (execute pio settings set force_verbose Yes to see all gcc/g++ build commands).

arm-none-eabi-g++ -o .pioenvs\nrf51_dk\FrameworkArduinoVariant\variant.o -c -fno-rtti -fno-exceptions -std=gnu++11 -fno-threadsafe-statics -Os -ffunction-sections -fdata-sections -Wall -mthumb -nostdlib -mcpu=cortex-m0 --param max-inline-insns-single=500 -DPLATFORMIO=30502 -DPCA10000 -DARDUINO=10805 -DF_CPU=16000000L -DARDUINO__NRF5 -DNRF5 -DNRF51 -DUSE_LFXO -IC:\Users\Maxi\.platformio\packages\framework-arduinonordicnrf5\cores\nRF5 -IC:\Users\Maxi\.platformio\packages\framework-arduinonordicnrf5\cores\nRF5\SDK\components\drivers_nrf\delay -IC:\Users\Maxi\.platformio\packages\framework-arduinonordicnrf5\cores\nRF5\SDK\components\device -IC:\Users\Maxi\.platformio\packages\framework-arduinonordicnrf5\cores\nRF5\SDK\components\toolchain -IC:\Users\Maxi\.platformio\packages\framework-arduinonordicnrf5\cores\nRF5\SDK\components\toolchain\CMSIS\Include -IC:\Users\Maxi\.platformio\packages\framework-arduinonordicnrf5\variants\PCA1000X C:\Users\Maxi\.platformio\packages\framework-arduinonordicnrf5\variants\PCA1000X\variant.cpp

Initially I just guessed it was the nRF51Dongle variant that was selected, but it’s the PCA1000X that gets selected here. Which means that we’re actually looking at a completely different pin map. Which doesn’t seem to match the board you’ve linked in… Only has 7 digital pins and 0 analog pins, obviously wrong. (see PCA1000X\variant.cpp and PCA1000X\variant.h).

const uint32_t g_ADigitalPinMap[] = {
  8,  // RTS
  9,  // TxD
  10, // CTS
  11, // RxD
  21, // LED Red
  22, // LED Green
  23, // LED Blue
};

@ivankravets, a little help here? The compiled pin definitions in the variant.h/cpp for the nrf51_dk device do not match up with the board (https://os.mbed.com/platforms/Nordic-nRF51-DK/)?

You can manually manipulate the pin definitions in that map, of course, but I would wait for confirmation and an official fix. And yes, with the pinMode, digitalWrite and digitalRead functions, since it remaps the argument using the g_ADigitalPinMap object, you can only use the pins defined inside that map. Or you duplicate the function like I did above without any checks and remapping present. See if above test sketch works.


#8

We use this Arduino Core nRF5 https://github.com/sandeepmistry/arduino-nRF5. If you see a bug here, please file them new issue.


#9

Hi @ivankravets

If I follow the installation guide on https://github.com/sandeepmistry/arduino-nRF5
(which actually tells me how to install it for the Arduino IDE) will I be able to use it within PlatformIO (which I use along with Atom)?

If not, how can I install it for PlatformIO?


#10

You are already using above Arduino-core. The github repo is exactly what’s inside your .platformio/package/framework-arduinonordicnrf5 folder. If you install it for your Arduino IDE, you will just be able to use the same Arduino core from there. Your Arduino IDE will installations not affect platformio.

I also tested the current core against the Arduino-IDE and if you use the board “Nordic nRF51X22 Development Kit(PCA1000X)” with the board variant “PCA10000”, it results in the exact same pin-mapping for digital pins as I posted before. Board variants “PCA10001” and “PCA1000X” result in the generic pin mapping where all 32 pins are available by their “P.0X” numbering (i.e., pin map doesn’t change anything). Which exact PCAXXXX board do you have?

Did you also try the direct register manipulation example?


#11

Ok I can finally make the LEDs blink on my devboard which by the way is PCA10028.
I am using the PCA1000X\variant.cpp and I managed to find out that this is the map that is correct:

#else
  /* PCA10000
   * *********/

  #define PINS_COUNT           (7u)
  #define NUM_DIGITAL_PINS     (7u)
  #define NUM_ANALOG_INPUTS    (0u)
  #define NUM_ANALOG_OUTPUTS   (0u)

  // LEDs
  #define PIN_LED1                (4)
  #define PIN_LED2                (5)
  #define PIN_LED3                (6)
  #define LED_BUILTIN             PIN_LED1

  /*
   * Serial interfaces
   */
  #define PIN_SERIAL_RX       (3)
  #define PIN_SERIAL_CTS      (2)
  #define PIN_SERIAL_TX       (1)
  #define PIN_SERIAL_RTS      (0)
#endif

which uses this map:

#ifdef PCA10000
const uint32_t g_ADigitalPinMap[] = {
  8,  // RTS
  9,  // TxD
  10, // CTS
  11, // RxD
  21, // LED Red
  22, // LED Green
  23, // LED Blue
};

So obviously in my case, the macro PCA10000 is defined. The other map however (when the macro PCA10000 is NOT defined) seems to include ALL pins and not only 8, 9, 10, 11 and the three LEDs.

  1. Am I correct?

  2. Where exactly is the macro PCA10000 defined and how can I, let’s say, undefine it so that I can use the other case (= all pins) without changing PCA1000X\variant.cpp myself. Or do I have to change that file myself?

P.S. Thank you @maxgerhardt so much for your patience and support.


EDIT:

  1. I just swtiched from #ifndef to #ifdef and vice versa in the files. I can finally make ANY led blink (yeaaah lol). But how can I know now, which ones are the SDA SCL pins for sensors?

There are these definitions:

  #define WIRE_INTERFACES_COUNT 1

  #define PIN_WIRE_SDA         (25u)
  #define PIN_WIRE_SCL         (24u)

  static const uint8_t SDA = PIN_WIRE_SDA;
  static const uint8_t SCL = PIN_WIRE_SCL;

So what does this mean? SDA is pin 25 and SCL is pin 24?


#12

For 1.: Yes, you are correct. If you undefine that macro it will use that generic pin map from 0 to 31, but when you undefine it you also lose some definitions for other LED and button pins, and I2C I think.
For 2.: The macro definitions gets inserted at compile time. The g++/gcc commands include a -DMACRO_VALUE option to define the macro. You can undefine the macro definition by adding a build_unflags setting in your platformio.ini file, which will exclude flags from the build command. You can execute pio settings set force_verbose Yes and then compile the project to see gcc commands. Then you can find out what the exact -D ... option is that is inserted here, which you can set to your build_unflags part. See the documentation.
For 3.). Yes, the SDA and SCL pins refer to “P0.X” GPIO number According to some docs and the datasheet you have 2 TWI (two-wire-interface, aka I2C), which can be “chosen from any GPIO pin” (sec. 4.11 page 34). You also have 3 SPI peripherals which can also be used with any GPIO pin (page 34). The reference manual gives you a list of which pins are hard-connected to what on the board (to 4 LEDs, 4 buttons, serial interfaces,…). Does the board connect any sensors over I2C? Then you should trace those pin and choose them. Else just any 2 free pins you like.


#13

btw 2 last questions:

  1. is there any differenc between the two definitions:

#define PIN_LED1 (21)
and
#define PIN_LED1 (21u)

or also between

#define PIN_WIRE_SDA (25)
and
#define PIN_WIRE_SDA (25u)
?

And my second one:

  1. If I use this map:

const uint32_t g_ADigitalPinMap[] = {
8, // RTS
9, // TxD
10, // CTS
11, // RxD
21, // LED Red
22, // LED Green
23, // LED Blue
};

Do I then define my Pins according to that Map then? Meaning that if I want to define MYLED to, let’s say GPIO 8, then according to this g_ADigitalPinMap array it should be:

#define MYLED (0)

is that correct? if yes, how is the Preprocessor aware that (0) means something like g_ADigitalPinMap[0]?


#14

1.: Appendung u (or also U, UL, ULL, L and LL) changes the type of the number from standard int to unsigned int, unsigned long, unsigned long long, long or long long respectively. This is sometimes needed for functions which explicitly need a different integer type or due to integer width.
2.: First part: Correct, since 8 is the 0th element of the g_ADigitalPinMap array, calling functions like pinMode(0, OUTPUT) will use g_ADigitalPinMap[0] = 8.
Second part: The preprocessor will, if you do #define PIN_LED (0) only substitute every occurance of PIN_LED with (0). It’s a simple search-and-replace. The functions digitalWrite, digitalRead and pinMode (and possibly otehrs) will then utilize the g_ADigitalPinMap to map the given number to the GPIO pin, as you can see in the code of these functions above.


#15

hi , I am using arduino ide core sandeep mistry nrf
so I need to change the variants as I want to change default spi pins for redbearlab nrf1822 board
SS- 10 // P014 for nRF51422 board PCA10028
SCK- 16 //P025
MISO- 17 ///P022
MOSI - 18//P030
I get the data by this pin configuration but I want to change this pin configuration to :
SS- 10 //P014
SCK- //P020
MISO-17//P022
MOSI-4//P021
@maxgerhardt How do I change my default pin configuration to the one I need ??
I tried to clone it locally and change the files in documents-arduino- hardware-arduino-nrf5-master-variants-redbearlab_nrf51822-variants but I dont find any change
I also changed packages-sandeepmistry-hardware-nRF5-0.5.1-variants-RedBearLab_nRF51822-variants
Can anyone help me regarding this? my hardware has special requirement that is why I need to change this pins, board am using is PCA10028
I also changed variants for the same.


#16

Hi Devanshi,
The quickest way to solve the problem is to edit file variant.h, which you can find in C:\Users"You Windows Profile".platformio\packages\framework-arduinonordicnrf5\variants\ and chose folder with Board you already have set in PlatformIO.
If you want to sets PINs same way as variables, drop me a private message.
Happy coding.


#17

@espin there is no .platformio folder… I think it is because I am doing in arduino ide thats why so I found packages folder in users-profile-appdata-local-arduino15-pacakages-sandeepmistry-variants…
Still I could not get desired outcome


#18

For the Arduino GUI PIN definition, I am using https://github.com/mysensors/ArduinoHwNRF5 - works nicely.
“MyBoardNRF5.h file allows you to change the pins of internal hardware”
Happy coding


#19

Hey I tried to run the code by connecting pins

#define SPI_INTERFACES_COUNT 1

#define PIN_SPI_MISO (2)// P02
#define PIN_SPI_MOSI (3)//P03
#define PIN_SPI_SCK (4)//P04
#define PIN_SPI_SS (5)//P05

By doing this I get LED 3 on. It is some indication I guess.
as mentioned in myboardnrf5 but I am not getting data on serial port

@espin1 May I get your email or contact? I dont know I cant find option for private message here.


#20

Pins are set before your code starts. In others words, Arduino GUI sets the PINs and then reads your code (the same for PlatformIO), so setting them in the code has no effect. You have to change them in variant.h or use ArduinoHwNRF5 plugin. Took me weeks to understand this. Changing PIN definition in variant.h have global impact, using ArduinoHwNRF5 have impact per “.ino” (your code) folder.
Happy coding