I tested how is the grade of portability of Arduino C language on STM Core microcontroller board.
I’m going to show what happen when you use Arduino C programming language on a STM32F401RE Nucleo board.
In the Arduino IDE are built in simple examples like:
- change the state of a GPIO pin (BLINK a LED)
- measure the voltage on a Digital input pin (BUTTON)
- measure a voltage by internal ADC converter
- send an information trough a Serial port
- show some data on a LCD display
You can find that programs example on:
- FILE -> EXAMPLES -> BASICS -> Blink
- FILE -> EXAMPLES -> BASICS -> DigitalReadSerial
- FILE -> EXAMPLES -> BASICS -> AnalogReadSerial
- FILE -> EXAMPLES -> LiquidCrystal -> HelloWorld
Installing STM32 Core devices on Arduino IDE
Before to use STM32 Core microcontroller by Arduino IDE editing and programming platform, you have to upload as a new Device the STM32 Core Devices.
To perform this task follow link: STM32Duino getting started
Pin compatibility to Nucleo STM32F401RE
The image below assign some STM32 Nucleo F401RE version board pin as used on Arduino UNO board (Green coloured labels). More info on Nucleo development board following link:
STM32 Nucleo-64 development board with STM32F401RE MCU, supports Arduino

Blink example
By powering On and Off alternatively one Arduino D13 aka Nucleo PA5 pin, you should see Green LED2 blinking (I noticed a labeling error on the official image above. LD1 is not attached to PA5/D13 pin, instead LD2).
//#define LED2 13 // Arduino pin
#define LED2 PA5 // STM32F401 pin
//
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED2, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED2, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a 100 millisecond
digitalWrite(LED2, LOW); // turn the LED off by making the voltage LOW
delay(100); // wait for a 100 millisecond
}
How fast is the pure blinking (no delay added). I measured 2us per high + low transition as in the image below.

The speed of Arduino UNO pin is 7us per high + low transition as in the image below.

DigitalReadSerial example
Nucleo board read pin PC13 attached to “user B1” button. While button B1 is pressed LED2 is lit.
#define pushButton PC13 // digital pin Nucleo STM32F401RE
#define LED2 PA5 // digital pin Nucleo STM32F401RE
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// make the pushbutton’s pin an input:
pinMode(pushButton, INPUT);
// make the LED2’s pin an output:
pinMode(LED2, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input pin:
int buttonState = digitalRead(pushButton);
// light the LED2 if button pressed
if(buttonState) digitalWrite(LED2, LOW);
else digitalWrite(LED2, HIGH);
// print out the state of the button:
Serial.println(buttonState);
delay(1); // delay in between reads for stability
}
If I try to use Serial monitor, Arduino IDE prompt an error. No communication is established. In my case could be due to:
- I’m using a Mac OS computer
- Nucleo board STLink is not updated
- some setting error
I spent some hours around this communication problem and I’m embarrassed to say I was not able to fix it.
AnalogReadSerial example
The ADC converter work fine as expected, but the resolution is limited to 1023 point as Arduino UNO AD converter. Whole 12 bit ADC native resolution of STM32F401RE microcontroller it seem not to be used. Full scale input voltage is 3.3 V instead of 5 V.
In accordance with STM32F401RE datasheet there are 16 ADC inputs wired on pins (from my test only 11 ADC pin are usable):
- ADC_0 pin –> PA0 OK –> Arduino A0 (same reading showed on PA3)
- ADC_1 pin –> PA1 OK –> Arduino A1 (same reading showed on PA2)
- ADC_2 pin –> PA2 NA (no reading because connected to Serial Tx ???)
- ADC_3 pin –> PA3 NA (no reading because connected to Serial Rx ???)
- ADC_4 pin –> PA4 OK –> Arduino A2
- ADC_5 pin –> PA5 NA (no reading ???)
- ADC_6 pin –> PA6 NA (no reading ???)
- ADC_7 pin –> PA7 NA (no reading ???)
- ADC_8 pin –> PB0 OK –> Arduino A3
- ADC_9 pin –> PB1 OK (same reading showed on PA7)
- ADC_10 pin –> PC0 OK –> Arduino A5
- ADC_11 pin –> PC1 OK –> Arduino A4
- ADC_12 pin –> PC2 OK
- ADC_13 pin –> PC3 OK
- ADC_14 pin –> PC4 OK
- ADC_15 pin –> PC5 OK
All this pins are accessible by morpho connector, the twin double raw pin connectors located at the far left and right of Nucleo board.

Program used on this example Follow (I used Adafruit library because U8g2 library has not correctly showed characters):
/********************************************************************* This is an example for our Monochrome OLEDs based on SSD1306 drivers Pick one up today in the adafruit shop! ------> http://www.adafruit.com/category/63_98 This example is for a 128x64 size display using I2C to communicate 3 pins are required to interface (2 I2C and one reset) Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, check license.txt for more information All text above, and the splash screen must be included in any redistribution *********************************************************************/ #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); unsigned int getAnalog (unsigned int port){ pinMode(port, INPUT); return analogRead(port); } void setup() { // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64) // init done } void loop() { display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(0,0); display.print("ADCs test"); display.setCursor(0,16); display.setTextSize(1); display.print("A0:"); display.print(getAnalog (PA0)); display.print(" A1:");display.print(getAnalog (PA1)); display.print(" A2:");display.println(getAnalog (PA2)); display.print("A3:");display.print(getAnalog (PA3)); display.print(" A4:");display.print(getAnalog (PA4)); display.print(" A5:");display.println(getAnalog (PA5)); display.print("A6:");display.print(getAnalog (PA6)); display.print(" A7:");display.print(getAnalog (PA7)); display.print(" B0:");display.println(getAnalog (PB0)); display.print("B1:");display.print(getAnalog (PB1)); display.print(" C0:");display.print(getAnalog (PC0)); display.print(" C1:");display.println(getAnalog (PC1)); display.print("C2:");display.print(getAnalog (PC2)); display.print(" C3:");display.print(getAnalog (PC3)); display.print(" C4:");display.println(getAnalog (PC4)); display.print("C5:");display.print(getAnalog (PC5)); display.display(); delay(200); }
HelloWorld example
I hooked up a common LCD to my Nucleo board as in accordance with LCD Arduino tutorial.
I used an OLED SSD1306 display too. My display was an I2C data communication version, 128×64 pixel wide. You can find info, example and library at Adafruit link: OLED SSD1306 getting started. I used adafruit Arduino library and U8g2 Arduino library too. You can add this library directly from Arduino IDE.
This example program worked fine with U8g2 library .
#include <Arduino.h> #include <U8x8lib.h> #ifdef U8X8_HAVE_HW_SPI #include <SPI.h> #endif // Please UNCOMMENT one of the contructor lines below // U8x8 Contructor List // The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8x8setupcpp // Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected //U8X8_NULL u8x8; // null device, a 8x8 pixel display which does nothing //U8X8_SSD1306_128X64_NONAME_4W_SW_SPI u8x8(/* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); //U8X8_SSD1306_128X64_NONAME_4W_HW_SPI u8x8(/* cs=*/ 6, /* dc=*/ 4, /* reset=*/ 12); // Arduboy (DevKit) //U8X8_SSD1306_128X64_NONAME_4W_HW_SPI u8x8(/* cs=*/ 12, /* dc=*/ 4, /* reset=*/ 6); // Arduboy 10 (Production, Kickstarter Edition) //U8X8_SSD1306_128X64_NONAME_4W_HW_SPI u8x8(/* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); //U8X8_SSD1306_128X64_NONAME_3W_SW_SPI u8x8(/* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* reset=*/ 8); U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); //U8X8_SSD1306_128X64_ALT0_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); // same as the NONAME variant, but may solve the "every 2nd line skipped" problem //U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ 2, /* data=*/ 0, /* reset=*/ U8X8_PIN_NONE); // Digispark ATTiny85 //U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // OLEDs without Reset of the Display //U8X8_SSD1306_128X64_VCOMH0_4W_HW_SPI u8x8(/* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but maximizes setContrast() range //U8X8_SSD1306_128X64_ALT0_4W_HW_SPI u8x8(/* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); // same as the NONAME variant, but may solve the "every 2nd line skipped" problem //U8X8_SSD1306_128X32_UNIVISION_SW_I2C u8x8(/* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather ESP8266/32u4 Boards + FeatherWing OLED //U8X8_SSD1306_128X32_UNIVISION_SW_I2C u8x8(/* clock=*/ 21, /* data=*/ 20, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather M0 Basic Proto + FeatherWing OLED //U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED //U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA); // pin remapping with ESP8266 HW I2C //U8X8_SSD1306_64X48_ER_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); // EastRising 0.66" OLED breakout board, Uno: A4=SDA, A5=SCL, 5V powered //U8X8_SSD1306_48X64_WINSTAR_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); //U8X8_SSD1306_64X32_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); //U8X8_SSD1306_64X32_1F_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); //U8X8_SSD1306_96X16_ER_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); // EastRising 0.69" //U8X8_SSD1306_128X64_NONAME_6800 u8x8(13, 11, 2, 3, 4, 5, 6, A4, /*enable=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8); //U8X8_SSD1306_128X64_NONAME_8080 u8x8(13, 11, 2, 3, 4, 5, 6, A4, /*enable=*/ 7, /*cs=*/ 10, /*dc=*/ 9, /*reset=*/ 8); // End of constructor list void setup(void) { u8x8.begin(); u8x8.setPowerSave(0); } void loop(void) { u8x8.setFont(u8x8_font_chroma48medium8_r); u8x8.drawString(0,0,"--Hello World!--"); u8x8.drawString(0,1,"0123456789ABCDEF"); u8x8.drawString(0,2,"AaBbCcDcEeFfIiLl"); u8x8.drawString(0,3,"MmNnOoPpQqRrSsTt"); u8x8.drawString(0,4,"--Hello World!--"); u8x8.drawString(0,5,"0123456789ABCDEF"); u8x8.drawString(0,6,"AaBbCcDcEeFfIiLl"); u8x8.drawString(0,7,"MmNnOoPpQqRrSsTt"); u8x8.refreshDisplay(); // only required for SSD1606/7 delay(2000); }