IoT Nordic nRF54L15-DK Zephyr PWM Control de un Servo

El propósito de este artículo es demostrar como se controla via el módulo de modulación de ancho de pulso conocido como PWM a un servo conectado a el kit IoT Nordic nRF54L15-DK,

image

Antes de proceder con estre demo, por favor sigua los pasos del previo artículo de los pasos a seguir para instalar el Nordic nRF54L15-DK Zephyr Linux

La siguiente table del Nordic kit nRF54L15-DK fue usada para derivar cual PIN en el kit de Nordic nRF54L15-DK se puede usar para conectar la señal del modula de PWM para controlar un servo externo,

P1 signal Function Default connected on P1
P1.00 32.768 kHz, XL1 No. Solder bridges must be configured.
P1.01 32.768 kHz, XL2 No. Solder bridges must be configured.
P1.02 NFC1 No. 0R resistors must be configured.
P1.03 NFC2 No. 0R resistors must be configured.
P1.04 UART1_TXD Yes.
P1.05 UART1_RXD Yes.
P1.06 UART1_RST Yes.
P1.07 UART1_CTS Yes.
P1.08 Button 2 Yes.
P1.09 Button 1 Yes.
P1.10 LED 1 Yes.
P1.11 Yes.
P1.12 Yes.
P1.13 Button 0 Yes.
P1.14 LED 3 Yes.

Como el P1.11 esta disponible, se va a utilizar en este demo de control de servo. En el previo artículo IoT Nordic nRF54L15-DK Zephyr PWM LED P1.10 se uso para conectar la señal PWM a el LED1 en el kit IoT de Nordic nRF54L15-DK. Ahora se crea el siguiente archivo de configuración de Zephyr llamado proj.conf en el directorio de su preferencia,

CONFIG_LOG=y
CONFIG_LED=y
CONFIG_LED_PWM=y

Por el proceso standard de desarollo de Zephyr, se incluye el archivo llamado CMakeLists.txt dentro del directorio del projecto,

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(spi)

target_sources(app PRIVATE src/main.c)

También se incluye el siguiente archivo overlay de Zephyr llamado nrf54l15dk_nrf54l15.overlay

/{
    pwmleds {
        compatible = "pwm-leds";
        pwm_led0: pwm_led_0 {
            pwms = <&pwm20 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        };
    };
};

&pwm20 {
    status = "okay";
    pinctrl-0 = <&pwm20_custom>;
    pinctrl-1 = <&pwm20_csleep>;
    pinctrl-names = "default", "sleep";
};

&pinctrl {
    pwm20_custom: pwm20_custom {
        group1 {
            psels = <NRF_PSEL(PWM_OUT0, 1, 11)>;
            nordic,invert;
        };
    };

    pwm20_csleep: pwm20_csleep {
        group1 {
            psels = <NRF_PSEL(PWM_OUT0, 1, 11)>;
            low-power-enable;
        };
    };
};

Aquí en DigiKey se desarrollo una version para ilustrar como se controla un servo externo con el siguiente código main.c,

/* DigiKey Coffee Cup Servo Control Version **/

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pwm.h>

LOG_MODULE_REGISTER(DigiKey_Coffee_Cup, LOG_LEVEL_INF);

#define PWM_PERIOD                   PWM_MSEC(20)
#define PWM_SERVO_MIN_PULSE_WIDTH    PWM_USEC(100)
#define PWM_SERVO_MAX_PULSE_WIDTH    PWM_USEC(1100)

#define PWM_LED0    DT_ALIAS(pwm_led0)

static const struct pwm_dt_spec pwm_led0 = PWM_DT_SPEC_GET(PWM_LED0);

int set_motor_angle(uint32_t pulse_width_ns)
{
    int err;
    
    err = pwm_set_dt(&pwm_led0, PWM_PERIOD, pulse_width_ns);
    if (err) {
        LOG_ERR("pwm_set_dt_returned %d", err);
    }
    return err;
}

int main(void)
{
    int err;

    if (!pwm_is_ready_dt(&pwm_led0)) {
        LOG_ERR("Error: PWM device %s is not ready", pwm_led0.dev->name);
        return 0;
	}
    
    err = pwm_set_dt(&pwm_led0, PWM_PERIOD, PWM_SERVO_MIN_PULSE_WIDTH );
    if (err) {
	LOG_ERR("Error in pwm_set_dt(), err: %d", err);
	return 0;
    }

    while(1)
    {
         err = set_motor_angle(PWM_SERVO_MIN_PULSE_WIDTH);
         if (err) {
            LOG_ERR("Error: couldn't set duty cycle, err %d", err);
        }

        k_msleep(1000);

         err = set_motor_angle(PWM_SERVO_MAX_PULSE_WIDTH);
         if (err) {
            LOG_ERR("Error: couldn't set duty cycle, err %d", err);
        }

        k_msleep(1000);
  
   }
    
    return 0;
}

El directorio del projecto de Zephyr es como se muestra a continuación,

|-- CMakeLists.txt
|-- nrf54l15dk_nrf54l15.overlay
|-- prj.conf
`-- src
    |-- main.c

Ahora se procede a construir el projecto de Zephyr así,

digikey_coffee_cup (venv) $  west build -p always -b nrf54l15dk/nrf54l15/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=nrf54l15dk_nrf54l15.overlay

Finalmente se conecta el Nordic IoT nRF54L15-DK vía la interfaz de USB para programarlo así,

digikey_coffee_cup (venv) $  west flash

Antes de conectar el servo a el Nordic nRF54L15-DK kit, el Sparkfun 8-channel USB Logic Analyzer fue conectado a el Port 1 - Pin 11 en la plataforma para observar la señal de PWM. Los aspectos importantes de la señal de PWM signal relevantes a este demo de control del servo fueron previamente definidas en el código main.c son,

#define PWM_PERIOD                   PWM_MSEC(20)
#define PWM_SERVO_MIN_PULSE_WIDTH    PWM_USEC(100)
#define PWM_SERVO_MAX_PULSE_WIDTH    PWM_USEC(1100)

Estos parámetros (para propósitos de ilustración solamente) definen un periodo de 20 ms de la señal de PWM con un máximo ancho de pulso de 1.1 ms y un ancho mínimo de 100 us. Estos dos anchos son las señales de PWM que se usan para controlar el servo en este demo. La próxima captura del Analizador Lógico USB de 8-canales de Sparkfun muestra que las características de la señal de PWM estan de acuerdo con las especificaciones del código main.c, un periodo de 20 ms de la señal de PWM para ambos estados (1.1 ms y 100 us) como se muestra aquí,

Caso de 1.1 ms con un periodo de 20 ms

Caso de 100 us con un periodo de 20 ms

acercando la captura de estos eventos con el Analizador Lógico USB de 8-canales de Sparkfun se muestran a continuación,

(Acercamiento) Caso de ancho de pulso de 1.1 ms con un periodo de 20 ms

(Acercamiento) Caso de ancho de pulso de 100 us con un periodo de 20 ms

El Analizador Lógico USB de 8-canales de Sparkfun se puede usar para medir los anchos de estos pulsos como se demonstro anteriormente. Estos dos estados del módulo de PWM fueron definidos en el código main.c usando las siguientes llamadas a la función de establecer el ángulo del servo, uno para el mínimo ancho del pulso y otro para el máximo ancho de pulso, correspondientes a el “duty cycle” mínimo y otro para el “duty cycle” máximo ,

set_motor_angle(PWM_SERVO_MIN_PULSE_WIDTH);

set_motor_angle(PWM_SERVO_MAX_PULSE_WIDTH);

Estos parámetros fueron usados para propósitos ilustrativos solamente, se pueden optimizar y cambiar como sea necesario, dependiendo del servo usado en la aplicación. Hemos demostrado como controlar un servo usando el sistema operativo Zephyrcon el kit IoT Nordic nRF54L15-DK. El kit IoT Nordic nRF54L15-DK de es una excelente plataforma para desarollar aplicaciones IoT.

image

y está disponible en DigiKey. Que tenga buen día.

This article is also available in english here.

Este artículo está disponible en inglés aquí.

1 Like