Arduino Nano RP2040 Connect: инструкция, примеры использования и документация

Используйте платформу Nano RP2040 Connect для создания электронных гаджетов, метеостанций, роботов и других изобретений. Плата программируется на языке C++ или MicroPython и отлично подойдёт как начинающим мейкерам, так и опытным разработчикам.

Программирование на C++

Рассмотрим программирование Nano RP2040 Connect на языке C++ в среде Arduino IDE на компьютере под управлением Windows.

Подключение и настройка

  1. Запишите загрузчик Arduino в плату Nano RP2040. Если вы только купили плату или использовали её только в Arduino IDE, загрузчик записывать не нужно.
  2. По умолчанию среда программирования настроена только на AVR-платы. Для работы с платформой Nano RP2040 Connect добавьте в менеджере плат поддержку платформ Mbed OS Nano Boards.
  3. Выберите плату Nano RP2040 Connect в IDE: Инструменты Плата Arduino Mbed OS Nano Boards Arduino Nano RP2040 Connect
  4. Выберите COM-порт в IDE: Инструменты Порт COMx, где x — номер текущего порта.
  5. Это значит, всё получилось и можно смело переходить к примерам работы.

Примеры работы

Рассмотрим несколько примеров программирования Nano RP2040 Connect на C++ через Arduino IDE.

Библиотеки, которые используют в своём коде программируемый ввод-вывод PIO, используют нумерацию GPIO микроконтроллера RP2040 вместо Arduino. Подробности по нумерацию читайте в разделе Распиновка.

Для стабильной работы примеров обновите все сторонние библиотеки до последней версии в менеджере библиотек.

Маячок

Для начала мигнём встроенным светодиодом LED на 13 пине.

Код для Arduino
Blink.ino
// Даём имя встроенному светодиоду на 13 пине
constexpr uint8_t LED_ARDUINO_PIN = 13;
 
void setup() {
  // Настраиваем пин со светодиодом в режим выхода
  pinMode(LED_PIN, OUTPUT);
}
 
void loop() {
  // Зажигаем светодиод
  digitalWrite(LED_PIN, HIGH);
  // Ждём 1 секунду
  delay(1000);
  // Гасим светодиод 
  digitalWrite(LED_PIN, LOW);
  // Ждём 1 секунду
  delay(1000);
}

После прошивки скетча светодиод начнёт мигать раз в секунду.

Гирлянда

Главная фишка Nano RP2040 — это микроконтроллер, который поддерживает возможность программируемого ввода-вывода через блоки PIO, на которых можно реализовать произвольный интерфейс. В следующем примере заставим Arduino рулить светодиодами WS2812.

Что понадобится
Схема устройства

Код для Arduino

Для работы примера скачайте и установите библиотеку Adafruit NeoPixel.

WS2812Rainbow.ino
// Библиотека для работы со светодиодами WS2812
#include <Adafruit_NeoPixel.h>
 
// Номер пина, к которому подключена матрица WS2812
// Библиотека <Adafruit_NeoPixel.h> использует блок PIO,
// который в свою очередь использует нумерацию
// микроконтроллера RP2040, а не Arduino. 
constexpr uint8_t PIN_GPIO_WS2812 = 25;
 
// Количество светодиодов в матрице
constexpr uint8_t LED_COUNT = 16;
 
// Создаём объект для работы со светодиодной матрицей
Adafruit_NeoPixel matrix = Adafruit_NeoPixel(LED_COUNT, PIN_GPIO_WS2812, NEO_GRB + NEO_KHZ800);
 
void setup() {
  // Инициализация матрицы
  matrix.begin();
  // Устанавливаем яркость светодиодов
  // Диапазон значений от 0 до 255
  matrix.setBrightness(40);
}
 
void loop() {
  // Заполняем матрицу по сегментам «бегущий огонь» красного цвета
  colorWipe(matrix.Color(255, 0, 0), 100);
  // Заполняем матрицу по сегментам «бегущий огонь» зелёного цвета
  colorWipe(matrix.Color(0, 255, 0), 100);
  // Заполняем матрицу по сегментам «бегущий огонь» синего цвета
  colorWipe(matrix.Color(0, 0, 255), 100);
  // Гасим матрицу по сегментам «бегущая тень»
  colorWipe(matrix.Color(0, 0, 0), 100);
}
 
// Функция заполнения каждого сегмента
void colorWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < matrix.numPixels(); i++) {
    // Заполняем текущий сегмент выбранным цветом
    matrix.setPixelColor(i, c);
    matrix.show();
    // Ждём
    delay(wait);
  }
}

После прошивки управляющей платформы вы увидите заполнение по очереди каждого светодиода матрицы из красного, зелёного и синего цветов.

Вывод информации на дисплей

А теперь попробуем подружить плату с дисплеем и отобразить простой текст.

Что понадобится
Схема устройства

Код для Arduino

Для работы примера скачайте и установите библиотеку TroykaTextLCD.

PrintTextLCD.ino
// Библиотека для работы с дисплеем
#include <TroykaTextLCD.h>
 
// Номер пина, к которому подключена подсветка дисплея
constexpr uint8_t PIN_ARDUINO_LCD_BACKLIGHT = A3;
// I²C-адрес дисплея
constexpr uint8_t LCD_SLAVE_ADDRESS = 0x3E;
 
// Создаём объект для работы с дисплеем
// передаём ему объект I²C, I²C-адрес и пин подсветки
TroykaTextLCD lcd(&Wire, LCD_SLAVE_ADDRESS, PIN_ARDUINO_LCD_BACKLIGHT);
 
void setup() {
  // Устанавливаем количество столбцов и строк экрана
  lcd.begin(16, 2);
  // Устанавливаем контрастность в диапазоне от 0 до 63
  lcd.setContrast(45);
  // Устанавливаем яркость в диапазоне от 0 до 255
  lcd.setBrightness(255);
  // Устанавливаем курсор в колонку 0, строку 0
  lcd.setCursor(0, 0);
  // Печатаем первую строку
  lcd.print("Hello, world!");
  // Устанавливаем курсор в колонку 0, строку 1
  lcd.setCursor(0, 1);
  // Печатаем вторую строку
  lcd.print("Arduino RP2040");
}
 
void loop() {
}

После прошивки управляющей платформы на дисплее отобразится приветствующий текст.

Звуковая волна

Пришло время пошуметь, будем считывать звук со встроенного микрофона и выводить полученные данные в Serial Plotter.

Код для Arduino

Для работы примера скачайте и установите библиотеку PDM.

MicrophoneSerialPlotter.ino
// Библиотека для работы с микрофоном
#include <PDM.h>
 
// Количество аудио каналов
constexpr uint8_t channels = 1;
 
// Частота дискретизации
constexpr uint32_t frequency = 16000;
 
// Буфер для хранения семплов
short sampleBuffer[512];
 
// Счётчик пришедших семплов
volatile int samplesRead;
 
// Границы верхнего и нижнего диапазона выводимого семпла
// Для наглядной визуализации звуковой волны в Serial Plotter
constexpr int32_t sampleLimitUpper = 3000;
constexpr int32_t sampleLimitLower = -3000;
 
void setup() {
  // Открываем Serial-порт
  Serial.begin(115200);
  while (!Serial);
 
  // Выполняем конфигурацию
  PDM.onReceive(onPDMdata);
 
  // Устанавливаем усиление сигнала
  PDM.setGain(1);
 
  // Инициализируем PDM
  if (!PDM.begin(channels, frequency)) {
    Serial.println("Failed to start PDM!");
    while (1);
  }
}
 
void loop() {
  // Ожидаем семплы для считывания
  if (samplesRead) {
 
    // Печатаем семплы в Serial-порт
    for (int i = 0; i < samplesRead; i++) {
        Serial.print(sampleLimitLower);
        Serial.print("\t");
        Serial.print(sampleBuffer[i]);
        Serial.print("\t");
        Serial.println(sampleLimitUpper);
    }
 
    // сбрасываем счётчик семплов
    samplesRead = 0;
  }
}
 
// Функция для обработки данных с микрофона
void onPDMdata() {
  // Запрашиваем количество пришедших байтов
  int bytesAvailable = PDM.available();
 
  // Считываем данные в буфер
  PDM.read(sampleBuffer, bytesAvailable);
 
  // 16 бит, 2 байта на семпл
  samplesRead = bytesAvailable / 2;
}

После прошивки скетча запустите Serial Plotter. А затем попробуйте пошуметь — например, хлопнуть в ладоши или включить музыку.

Визуализация объекта в пространстве

В продолжение приведём пример отображения платы в пространстве в виде самолёта, а для этого нам поможет встроенный IMU-сенсор. Для запуска примера необходимо прошить платформу Nano RP2040 кодом ниже и настроить графическую среду Processing.

Код для Arduino

Для работы примера скачайте и установите библиотеку LSM6DSOX.

IMUVisualization6DOF.ino
// Библиотека для работы фильтра Madgwick
#include <TroykaIMU.h>
// Библиотека для работы IMU-сенсора LSM6DSOXTR
#include <Arduino_LSM6DSOX.h>
 
// Создаём объект для фильтра Madgwick
Madgwick filter;
 
// Переменные для данных с гироскопа и акселерометра
float gx, gy, gz, ax, ay, az;
 
// Переменные для хранения самолётных углов ориентации
float yaw, pitch, roll;
 
// Переменная для хранения частоты выборок фильтра
float sampleRate = 100;
 
void setup() {
    // Открываем последовательный порт
    Serial.begin(9600);
    // Выводим сообщение об неудачной инициализации IMU
    if (!IMU.begin()) {
      Serial.println("Failed to initialize IMU!");
    }
    // Выводим сообщение об удачной инициализации IMU
    Serial.println("Success to initialize IMU");
    // Инициализируем фильтр
    filter.begin();
}
 
void loop() {
    // Запоминаем текущее время
    unsigned long startMillis = millis();
 
    // Считываем данные с акселерометра в единицах G
    if (IMU.accelerationAvailable()) {
      IMU.readAcceleration(ax, ay, az);
    }
    // Считываем данные с гироскопа в градусах
    if (IMU.gyroscopeAvailable()) {
      IMU.readGyroscope(gx, gy, gz);
    }
    // Переводим показания гироскопа изградусов в радианы в секунду
    gx *= DEG_TO_RAD;
    gy *= DEG_TO_RAD;
    gz *= DEG_TO_RAD;
    // Устанавливаем частоту фильтра
    filter.setFrequency(sampleRate);
    // Обновляем входные данные в фильтр
    filter.update(gx, gy, gz, ax, ay, az);
 
    if (Serial.available() > 0) {
        int val = Serial.read();
        // Если пришёл символ 's'
        if (val == 's') {
            float q0, q1, q2, q3;
            filter.readQuaternion(q0, q1, q2, q3);
            // Выводим кватернион в serial-порт
            Serial.print(q0);
            Serial.print(",");
            Serial.print(q1);
            Serial.print(",");
            Serial.print(q2);
            Serial.print(",");
            Serial.println(q3);
        }
    }
    // Вычисляем затраченное время на обработку данных
    unsigned long deltaMillis = millis() - startMillis;
    // Вычисляем частоту обработки фильтра
    sampleRate = 1000 / deltaMillis;
}
Настройка Processing
Код для Processing
IMUVisualization6DOFProcessing.pde
import processing.serial.*;
import toxi.geom.*;
import toxi.processing.*;
 
// NOTE: requires ToxicLibs to be installed in order to run properly.
// 1. Download from http://toxiclibs.org/downloads
// 2. Extract into [userdir]/Processing/libraries
//    (location may be different on Mac/Linux)
// 3. Run and bask in awesomeness
 
// The serial port
Serial port;                         
 
String message;
 
float[] q = new float[4];
Quaternion quat = new Quaternion(1, 0, 0, 0);
// New line character in ASCII
final char newLine = '\n';
String [] massQ = new String [4];
float[] ypr = new float[3];
 
void setup()  {
    // Size form 400x400
    size(400, 400, P3D); 
    // Open serial port
    // Replace "COM7" with the COM port on which your arduino is connected
    port = new Serial(this, "COM7", 9600);
}
 
void draw()  {
    // Read and parse incoming serial message
    serialEvent();
    // Set background to black
    background(0);
    printQuaternions();
    printYawPitchRoll();
    // Set position to centre
    translate(width / 2, height / 2);
    // Begin object
    pushMatrix();
    float[] axis = quat.toAxisAngle();
    rotate(axis[0], axis[2], axis[3], axis[1]);
    // Draw main body in red
    drawBody();
    // Draw front-facing tip in blue
    drawCylinder();
    // Draw Triangles
    drawTriangles();
    // Draw Quads
    drawQuads();
    // End of object
    popMatrix();
    // Send character 's' to Arduino
    port.write('s');
}
 
void serialEvent() {
    // Read from port until new line (ASCII code 13)
    message = port.readStringUntil(newLine);
    if (message != null) {
        // Split message by commas and store in String array 
        massQ = split(message, ",");
        q[0] = float(massQ[0]);
        q[1] = float(massQ[1]);
        q[2] = float(massQ[2]);
        q[3] = float(massQ[3]);
    }
    // Print values to console
    print(q[0]);
    print("\t");
    print(q[1]); 
    print("\t");
    print(q[2]);   
    print("\t");
    print(q[3]);   
    println("\t");
    // Set our toxilibs quaternion to new data
    quat.set(q[0], q[1], q[2], q[3]);
 
}
 
void drawCylinder() {
    float topRadius = 0;
    float bottomRadius = 20;
    float tall = 20;
    int sides = 8;
    // Begin object
    pushMatrix();
    translate(0, 0, -120);
    rotateX(PI/2);
    fill(0, 0, 255, 200);
 
    float angle = 0;
    float angleIncrement = TWO_PI / sides;
    beginShape(QUAD_STRIP);
        for (int i = 0; i < sides + 1; ++i) {
        vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
        vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
        angle += angleIncrement;
    }
 
    endShape();
 
    // if it is not a cone, draw the circular top cap
    if (topRadius != 0) {
        angle = 0;
        beginShape(TRIANGLE_FAN);
        // Center point
        vertex(0, 0, 0);
        for (int i = 0; i < sides + 1; i++) {
            vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
            angle += angleIncrement;
        }
        endShape();
    }
 
    // If it is not a cone, draw the circular bottom cap
    if (bottomRadius != 0) {
        angle = 0;
        beginShape(TRIANGLE_FAN);
        // Center point
        vertex(0, tall, 0);
        for (int i = 0; i < sides + 1; i++) {
            vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
            angle += angleIncrement;
        }
        endShape();
    }
    popMatrix(); 
}
 
void drawBody() {
    fill(255, 0, 0, 200);
    box(10, 10, 200);
}
 
void drawTriangles() {
    // Draw wings and tail fin in green
    fill(0, 255, 0, 200);
    beginShape(TRIANGLES);
    // Wing top layer
    vertex(-100,  2, 30); vertex(0,  2, -80); vertex(100,  2, 30);
    // Wing bottom layer
    vertex(-100, -2, 30); vertex(0, -2, -80); vertex(100, -2, 30);
    // Tail left layer
    vertex(-2, 0, 98); vertex(-2, -30, 98); vertex(-2, 0, 70);
    // Tail right layer
    vertex( 2, 0, 98); vertex( 2, -30, 98); vertex( 2, 0, 70);
    endShape();
}
 
void drawQuads() {
    beginShape(QUADS);
    vertex(-100, 2, 30); vertex(-100, -2, 30); vertex(  0, -2, -80); vertex(  0, 2, -80);
    vertex( 100, 2, 30); vertex( 100, -2, 30); vertex(  0, -2, -80); vertex(  0, 2, -80);
    vertex(-100, 2, 30); vertex(-100, -2, 30); vertex(100, -2,  30); vertex(100, 2,  30);
    vertex(-2,   0, 98); vertex(2,   0, 98); vertex(2, -30, 98); vertex(-2, -30, 98);
    vertex(-2,   0, 98); vertex(2,   0, 98); vertex(2,   0, 70); vertex(-2,   0, 70);
    vertex(-2, -30, 98); vertex(2, -30, 98); vertex(2,   0, 70); vertex(-2,   0, 70);
    endShape();
}
 
void printQuaternions() {
    // Set text mode to shape
    textMode(SHAPE);
    textSize(13);
    fill(255, 255, 255);
    text("Quaternions:", 20, 20, 10);
    text(q[0], 20, 40, 10);
    text(q[1], 20, 60, 10);
    text(q[2], 20, 80, 10);
    text(q[3], 20, 100, 10);
}
 
void printYawPitchRoll() {
    // Calculate yaw/pitch/roll angles
    ypr[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1) * 57.2;
    ypr[1] = atan2(2 * q[2] * q[3] - 2 * q[0] * q[1], 2 * q[0] * q[0] + 2 * q[3] * q[3] - 1) * 57.2;
    ypr[2] = -atan2(2 * (q[0] * q[2] - q[1] * q[3]), 1 - 2 * (q[2] * q[2] + q[1] *q[1])) * 57.2;
 
    text("Yaw:", 150, 20, 10);
    text(ypr[0], 150, 40, 10);
    text("Pitch:", 220, 20, 10);
    text(ypr[1], 220, 40, 10);
    text("Roll:", 290, 20, 10);
    text(ypr[2], 290, 40, 10);
}

При запуске визуализации на Processing откроется окно с графическим отображением платы в виде самолёта. Самолёт на экране будет повторять перемещения IMU-сенсора в пространстве.

Соединение двух плат

Приведём пример, как соединить две платы по беспроводной сети.

Что понадобится
Схема Peripheral Device

Схема Central Device

Код для Peripheral Device
BluetoothPeripheralDevice.ino
// Библиотека для общения устройств по BLE
#include <ArduinoBLE.h>
 
// Номер пина, к которому подключена кнопка
constexpr uint8_t PIN_ARDUINO_BUTTON = 19;
 
// Переменная, для хранения состояния светодиода
boolean ledSwitch;
 
// BLE LED Service
BLEService LEDService("19B10000-E8F2-537E-4F6C-D104768A1214");
 
// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic LEDCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214",
                                        BLERead | BLENotify | BLEWrite);
 
void setup() {
  // Открываем Serial-порт
  Serial.begin(9600);
  // Ожидаем подключение по USB
  // Если не используете отладку, удалите строку
  while (!Serial);
  // Кнопку в режим входа
  pinMode(PIN_ARDUINO_BUTTON, INPUT);
 
  // Инициализируем BLE
  if (!BLE.begin()) {
    Serial.println("Starting BLE failed!");
  }
  // Устанавливаем локальное имя
  BLE.setLocalName("Button Device LED");
  // Устанавливаем службу UUID
  BLE.setAdvertisedService(LEDService);
  // Добавляем характеристику
  LEDService.addCharacteristic(LEDCharacteristic);
  // Добавляем сервис
  BLE.addService(LEDService);
  // Запускаем
  BLE.advertise();
  Serial.println("BLE LED Peripheral, waiting for connections…");
}
void loop() {
  // Слушаем все устройства BLE
  BLEDevice central = BLE.central();
  // Если Central Device подключилось
  if (central) {
    Serial.print("Connected to central: ");
    // Выводим MAC-адрес подключенного устройства
    Serial.println(central.address());
    // Пока Central Device подключено к переферийному
    while (central.connected()) {
      // Считываем состояние кнопки
      bool buttonState = digitalRead(PIN_ARDUINO_BUTTON);
      // Если кнопка нажата
      if (buttonState == LOW) {
        ledSwitch = !ledSwitch;
        delay(500);
        // Если светодиод не горит, включаем его
        // Если светодиод горит, выключаем его
        if (ledSwitch) {
          Serial.println("ON");
          LEDCharacteristic.writeValue((byte)0x01);
        } else {
          LEDCharacteristic.writeValue((byte)0x00);
          Serial.println("OFF");
        }
      }
    }
    // Если Central Device отключилось
    // Выводим сообщение в Serial-порт
    Serial.print(F("Disconnected from central: "));
    Serial.println(central.address());
  }
}
Код для Central Device
BluetoothCentralDevice.ino
// Библиотека для общения устройств по BLE
#include <ArduinoBLE.h>
 
// Номер пина, к которому подключен светодиод
constexpr uint8_t PIN_ARDUINO_LED = 14;
 
void setup() {
  // Открываем Serial-порт
  Serial.begin(9600);
  // Ожидаем подключение по USB
  // Если не используете отладку, удалите строку
  while (!Serial);
  // Светодиод в режим выхода
  pinMode(PIN_ARDUINO_LED, OUTPUT);
 
  // Инициализируем BLE
  BLE.begin();
  Serial.println("BLE Central - LED control");
  // Сканируем все устройства LED BLE peripherals
  BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
}
void loop() {
  // Проверяем было ли найдено Peripheral Device
  BLEDevice peripheral = BLE.available();
  // Если Peripheral Device найдено, выводим информацию в Serial-порт
  if (peripheral) {
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();
    // Если имя Peripheral Device не содержит фразу «LED»
    // Выходим из функции
    if (peripheral.localName().indexOf("LED") < 0) {
      Serial.println("No 'LED' in name");
      return;
    }
    // Останавливаем сканирование
    BLE.stopScan();
    controlLed(peripheral);
    // Если Peripheral Device отключено, продолжаем сканирование
    BLE.scanForUuid("19b10000-e8f2-537e-4f6c-d104768a1214");
  }
}
 
void controlLed(BLEDevice peripheral) {
  // Подключаемся к Peripheral Device
  Serial.println("Connecting ...");
  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }
  // Сканируем свойства Peripheral Device
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }
  // Получаем текущее состояние светодиода
  BLECharacteristic LEDCharacteristic = peripheral.characteristic(
                                        "19b10001-e8f2-537e-4f6c-d104768a1214");
  if (!LEDCharacteristic) {
    Serial.println("Peripheral does not have LED characteristic!");
    peripheral.disconnect();
    return;
  }
  while (peripheral.connected()) {
    if (LEDCharacteristic.canRead()) {
      byte value = LEDCharacteristic.read();
      LEDCharacteristic.readValue(value);
      if (value == 0x01) {
        Serial.println("ON");
        digitalWrite(PIN_ARDUINO_LED, HIGH);
      }
      else if (value == 0x00) {
        digitalWrite(PIN_ARDUINO_LED, LOW);
        Serial.println("OFF");
      }
    }
    delay(500);
  }
  Serial.println("Peripheral disconnected");
}
Запуск эксперимента
  1. Соберите схему двух устройств: Peripheral Device и Central Device
  2. Прошейте оба устройства соответствующим кодом ниже: Peripheral Device и Central Device
  3. Подключите Peripheral Device и Central Device к питанию. Для отладки советуем подключить Peripheral Device к одному ПК по USB, Central Device к другому ПК по USB.
  4. При нажатии на кнопку на Peripheral Device, светодиод на Central Device должен менять своё состояния.

Программирование на MicroPython

Рассмотрим программирование Nano RP2040 Connect на языке MycroPython на компьютере под управлением Windows.

Подключение и настройка

Примеры работы

Рассмотрим несколько примеров программирования Nano RP2040 Connect на MicroPython.

Интерпретатор Python используют нумерацию GPIO микроконтроллера RP2040 вместо Arduino. Подробности про нумерацию читайте в разделе Распиновка.

Маячок

Для начала мигнём встроенным светодиодом LED на плате Nano RP2040. В коде используем нумерацию GPIO.

Код для MicroPython
blink.py
# Библиотека для работы с пинами ввода-вывода
from machine import Pin
# Библиотека для работы с временем
import time
 
# Даём имя встроенному светодиоду
# на 6 пине нумерации GPIO
LED_GPIO_PIN = 6
 
# Светодиод в режим выхода на 6 пине
led = Pin(6, Pin.OUT)
 
while True:
    # Зажигаем светодиод
    led.value(1)
    # Ждём 1 секунду
    time.sleep(1)
    # Гасим светодиод
    led.value(0)
    # Ждём 1 секунду
    time.sleep(1)

После прошивки скетча, светодиод начнёт мигать раз в секунду.

Запись загрузчика

  1. Перетяните файл с прошивкой методом Drag-and-drop в устройство Flash-накопителя с именем RPI-RP2.
  2. Перезагрузите плату, нажав на кнопку RESET.

Режимы загрузки

Arduino Nano RP2040 Connect поддерживает два метода загрузки: штатный режим и режим загрузчика.

Штатный режим

Платформа загружается с внешней Flash-памяти, распаянной на плате Arduino Nano RP2040 Connect. В диспетчере устройств OS Windows плата отображается как виртуальный COM-порт с именем Устройство с последовательным интерфейсом USB. Режим служит для загрузки пользовательских программ через Arduino IDE, Thonny Python и друг сред разработки.

Активация режима происходит простым подключением платы по USB.

Режим загрузчика

Платформа загружается с внутренней памяти микроконтроллера RP2040. В диспетчере устройств OS Windows плата отображается как съёмный накопитель с именем RPI-RP2. Режим служит для загрузки прошивки в формате UF2 простым перемещением файла с одного носителя на другой. Активация режима:

  1. Замкните между собой контакты REC и GND. В качестве перемычки используйте джампер или провод «папа-папа».
  2. Подключите плату к компьютеру по USB.
  3. Разомкните между собой контакты REC и GND.

Элементы платы

Микроконтроллер RP2040

Платформа Arduino Nano RP2040 Connect выполнена на одноименном чипе RP2040 от компании Raspberry Pi Foundation. Кристалл содержит двухъядерный процессор на архитектуре ARM Cortex M0+ с тактовой частотой до 133 МГц. На RP2040 также расположились часы реального времени, датчик температуры и SRAM-память на 264 КБ. А Flash-память на 16 МБ расположилась на плате отдельной микросхемой.

Flash-память AT25SF128A-MHB-T

Для хранения программ и сопутствующих статичных ресурсов на плате распаяна внешняя Flash-память AT25SF128A-MHB-T объёмом 16 МБ.

Беспроводной модуль NINA-W102

За беспроводную передачу данных отвечает чип U-blox NINA-W102 со встроенным чипом ESP32 для обмена данными по воздуху в диапазоне 2,4 ГГц по Wi-Fi и Bluetooth. Для работы с модулем используйте библиотеку WiFiNINA.

IMU-сенсор LSM6DSOXTR

Инерционный модуль на чипе LSM6DSOXTR трёхосевой акселерометр и трёхосевой гироскоп для распознавания движений и моушен-функций с жестами. Для работы с модулем используйте библиотеку ArduinoLSM6DSOX.

Микрофон MP34DT05

Встроенный цифровой микрофон MP34DT05 пригодится для распознавания коротких голосовых команд или записи звука. Для работы с модулем используйте библиотеку PDM.

Крипточип ATECC608A

Криптографический сопроцессор Microchip ATECC608A интегрирует протокол безопасности ECDH (Elliptic Curve Diffie Hellman) в сверхзащищённый метод, обеспечивающий согласование ключей для шифрования / дешифрования, наряду с ECDSA (алгоритм цифровой подписи эллиптической кривой) для проверки подлинности с подписью для Интернета вещей (IoT), включая домашнюю автоматизацию, промышленные сети, медицинские услуги, аутентификацию аксессуаров и расходных материалов.

Преобразователь питания MP2332

Понижающий DC-DC преобразователь MP2322 обеспечивает питание микроконтроллера RP2040 и другой логики на плате. Диапазон входного напряжения от 5 до 18 вольт. Выходное напряжение 3,3 В с максимальным выходным током 1 А.

Светодиодная индикация

Имя светодиода Назначение
ON Индикатор питания платформы.
L Пользовательский светодиод, подключенный к пину GPIO6 микроконтроллера RP2040. При задании значения высокого уровня светодиод включается, при низком – выключается. Для управления светодиодом в Arduino IDE используйте нумерацию Arduino — пин 13 или определение LED_BUILTIN. А в среде Thonny Python используйте нумерацию портов микроконтроллера PR2040 — пин 6.
RGB Пользовательский RGB-светодиод с общим анодом. Катоды красного, зелёного и синего цвета выведены на пины GPIO27, GPIO25 и GPIO26 беспроводного модуля NINA-W102. При задании значения высокого уровня светодиоды выключаются, при низком – включаются. Для управления RGB-светодиодом в Arduino IDE используйте библиотеку WiFiNINA и встроенные определения LEDR, LEDG и LEDB.

Порт micro-USB

Разъём USB Micro предназначен для прошивки и питания платформы. Для подключения к ПК понадобится кабель USB (A — Micro USB).

Кнопка сброса

Кнопка предназначена для ручного сброса прошивки — аналог кнопки RESET обычного компьютера.

Распиновка

Принципиальная схема

Габаритный чертеж

Характеристики

  • Модель: Arduino Nano RP2040 Connect (SKU ABX00053)
  • Чипы и периферийные устройства:
    • Микроконтроллер RP2040
    • Внешняя Flash-память AT25SF128A-MHB-T
    • Беспроводной модуль NINA-W102
    • Инерциальный датчик LSM6DSOXTR
    • МЭМС-микрофон MP34DT05
    • Крипто чип ATECC608A
    • RGB-светодиод
  • Входное напряжение питания:
    • Через USB: 5 В
    • Через пин Vin: 5–18 В
  • Напряжение логических уровней: 3,3 В
  • Контакты ввода-вывода: 22
  • Контакты с АЦП: 8
  • Разрядность АЦП: 12 бит
  • Контакты с ШИМ: 20
  • Каналы DMA: 12
  • Аппаратные интерфейсы:
    • 1× UART
    • 1× I²C
    • 1× SPI
  • Программируемый интерфейс PIO:
    • До 8 подпрограмм одновременно
    • До 26 контактов одновременно
  • Размеры: 44,3×17,7×14,2 мм

Микроконтроллер RP2040

  • Модель: Raspberry Pi RP2040
  • Количество ядер: 2× ARM Cortex-M0+ (32 бита)
  • Тактовая частота: 133 МГц
  • Оперативная память: 264 КБ

Внешняя Flash-память AT25SF128A-MHB-T

  • Модель: Adesto Technologies AT25SF128A-MHB-T
  • Объём памяти в чипе: 16 МБ
  • Интерфейс: QSPI
  • Скорость передачи: до 532 Мбит/с
  • Циклы перезаписи: 100000

Беспроводной модуль NINA-W102

  • Модель: U-blox NINA-W102
  • Количество ядер: 2× Tensilica Xtensa LX6 (32 бита)
  • Тактовая частота: до 240 МГц
  • Flash-память: 2 МБ
  • ROM-память: 448 КБ
  • SRAM-память: 520 КБ
  • Частотный диапазон связи: 2,4 ГГц
  • Стандарт Wi-Fi: 802.11b/g/n
  • Стандарт Bluetooth: BLE v4.2 BR/EDR
  • Встроенная антенна: планарная F-образная (PIFA)

IMU-сенсор LSM6DSOXTR

  • Модель: ST LSM6DSOXTR
  • Частота обновления 3-осевого акселерометра: 1,6–6664 Гц
  • Диапазон измерения ускорения: ±2/±4/±8/±16g
  • Частота обновления 3-осевого гироскопа: 12,5–6664 Гц
  • Диапазон измерения поворота: ±125/±250/±500/±1000/±2000 град./с
  • Дополнительные аппаратные возможности:
    • Активация сценариев при наклоне устройства
    • Режим шагомера — продвинутое определение и подсчёт шагов
    • Конечные автоматы (FSM) и ядро машинного обучения для распознавания жестов и сценариев

Микрофон MP34DT05

  • Модель: ST MP34DT05
  • Тип: микроэлектромеханический (MEMS), всенаправленный
  • Точка акустической перегрузки (AOP): 122,5 дБ
  • Чувствительность: -26 дБ
  • Отношение сигнал/шум: 64 дБ

Крипточип ATECC608A

  • Модель: криптографический сопроцессор Microchip ATECC608A
  • Защищённое хранилище для криптографических ключей
  • Аппаратная поддержка симметричных алгоритмов шифрования:
    • SHA-256 / HMAC
    • AES-128
  • Встроенный генератор случайных чисел: NIST SP 800-90A/B/C
  • Безопасная загрузка с цифровой подписью ECDSA

Ресурсы

Полезные статьи

Документация

Библиотеки