NRF54L15 ADC CHANNEL SET -134 ERROR

I am currently working in project with nrf54l15dk and 3.0.2 sdk. I'm trying to work with peripherals and I want my project to do the following:
-Have 2 PWM outputs that used for IN1 and IN2 for DC motor.

-Have 1 ADC input that measure the current of the motor and led blink when it is more than the threshold current.

But I have come across with an issue while I was setting the adc within my code.

Here is my whole main.c: 

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/util.h>
#include <inttypes.h>
#include <zephyr/drivers/pwm.h> //PWM ekledik
#include <zephyr/drivers/adc.h> //ADC ekledik
#include <zephyr/logging/log.h> // log için
LOG_MODULE_REGISTER(main);


//ADC İÇİN DEĞİŞKENLER BUNLAR: 
#define MotorAkimSinir  0.96f // VStall (1.2a) dan biraz küçük normal çalışma(0.3a) akımından büyük.

// IPROPI pininden toprağa bağladığınız direncin Ohm cinsinden değeri.
// Datasheet'teki örnekte 8.45 kΩ kullanılmış, siz kendi devrenizdeki değeri yazmalısınız.
#define R_IPROPI 6675.0f // Kendi devrenizdeki R_IPROPI direncini Ohm cinsinden yazın. 6675ohm 
 

// Motor akımı kazanç faktörü (A_IPROPI).
// Bu değer, donanımınızdaki GAINSEL pininin nasıl bağlandığına göre seçilmelidir.
// Datasheet Tablo 8-3'e göre aşağıdaki 3 seçenekten SADECE BİRİNİ seçin.
// Diğer ikisini yoruma alın.

// Seçenek 1: GAINSEL pini LOW (GND) ise (350mA - 2A arası akımlar için önerilir)
//#define A_IPROPI 0.000205f // 205 µA/A 

// Seçenek 2: GAINSEL pini FLOATING (boşta) ise (60mA - 350mA arası akımlar için önerilir)
 //#define A_IPROPI 0.001050f // 1050 µA/A

// Seçenek 3: GAINSEL pini HIGH (VCC) ise (10mA - 60mA arası akımlar için önerilir)
 #define A_IPROPI 0.004900f // 4900 µA/A

#define adc_max_value 16383.0f // 14-bit ADC için maksimum değer
#define vref 0.6f // referans voltaj
#define GAIN              (1.0f / 4.0f)


static int led_acikMi=0; //led başlangıçta kapalı
static struct k_timer led_timer;


// IN1 VE IN2 İÇİN TANIMLAMA
#define PWM_IN1_NODE     DT_NODELABEL(motor)
#define PWM_IN2_NODE    DT_NODELABEL(motor2)
static const struct pwm_dt_spec pwm_in1 = PWM_DT_SPEC_GET(PWM_IN1_NODE);
static const struct pwm_dt_spec pwm_in2 = PWM_DT_SPEC_GET(PWM_IN2_NODE);
int current_direction = 0; // 0: dur, 1: ileri, 2: geri


static const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET(DT_PATH(zephyr_user)); //adc için kanal tanımlama
#define SLEEP_TIME_MS 50 //adc okuma aralığı


/* Buton alias’ları */
#define BTN0_NODE DT_ALIAS(sw0)
#define BTN1_NODE DT_ALIAS(sw1)
#define BTN2_NODE DT_ALIAS(sw2)
#define BTN3_NODE DT_ALIAS(sw3)

static const struct gpio_dt_spec buttons[] = {
	GPIO_DT_SPEC_GET_OR(BTN0_NODE, gpios, {0}),
	GPIO_DT_SPEC_GET_OR(BTN1_NODE, gpios, {0}),
	GPIO_DT_SPEC_GET_OR(BTN2_NODE, gpios, {0}),
	GPIO_DT_SPEC_GET_OR(BTN3_NODE, gpios, {0}),
};

static struct gpio_callback button_cb_data[4];

/* --- Prototipler (buton görevleri) --- */
void button1_action(void);
void button2_action(void);
void button3_action(void);
void button4_action(void);
void led_timer_handler(struct k_timer *timer_id); // Forward declaration for led_timer_handler
void led_timer_stop_handler(struct k_timer *timer_id);

// BUNLAR HEP Mikro SANİYE CİNSİNDEN
#define PWM_PERIOD_USEC 10 // 1/25KHZ = 40us periyot 1/100khz = 10us periyot
#define PWM_PULSE_LOW   0
#define PWM_PULSE_HIGH  5 // %50 duty cycle BU DEĞİŞECEK.
//25khz için statik atadım.
#define PWM_MIN_PULSE_WIDTH  2   // %10 doluluk µs
#define PWM_MAX_PULSE_WIDTH  9  // %90 doluluk oldu µs

int pwm_pulse_high = PWM_PULSE_HIGH; // global değişken yaptık ki butonlara göre değiştirebilelim.



/* --- Tek handler: hangi buton basıldıysa ilgili fonksiyonu çağırır --- */
void button_handler(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
	for (int i = 0; i < 4; i++) {
		if (pins & BIT(buttons[i].pin)) {
			LOG_INF("Buton %d basıldı\n", i );
			switch (i) {
			case 0: button1_action(); break;
			case 1: button2_action(); break;
			case 2: button3_action(); break;
			case 3: button4_action(); break;
			default: break;
			}
		}
	}
}

 
/*
 Bu ledi adc ile okuma yaparken kullanacağım. */
static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {0});
				 

int main(void)
{	LOG_INF("Başladı");
	LOG_INF("ADC device: %s, channel: %d\n", adc_channel.dev->name, adc_channel.channel_id);
	int ret;
	int err;
	int16_t buffer; //adc okuma bufferı
	//adc hazır mı bak. 
	
	if (!adc_is_ready_dt(&adc_channel)) {
		LOG_ERR("ADC Kontrol Cihazı %s hazır değil.", adc_channel.dev->name);
		return 0;
	}

	err = adc_channel_setup_dt(&adc_channel); //channel ayarla
	if (err < 0) {
		LOG_ERR("Adc kanali ayarlanmadi = #%d (%d)", 0, err);
		return 0;
	}

	struct adc_sequence sequence = {
		.buffer = &buffer, //burası adc sayısal değerini tutacak bunu çevireceğim.
		// buffer size in bytes, 
		.buffer_size = sizeof(buffer),
		.channels = BIT(adc_channel.channel_id),
	};

	LOG_INF("ADC Hazır. Kanal %d\n", adc_channel.channel_id);

	k_timer_init(&led_timer, led_timer_handler,led_timer_stop_handler); //led timerı başlat

	// PWM cihazlarının hazır olup olmadığını kontrol et 
	if (!pwm_is_ready_dt(&pwm_in1) || !pwm_is_ready_dt(&pwm_in2)) {
		LOG_INF("PWM'ler hazır değil!\n");
		return 0;
	}

	/* PWM çıkışlarını başlangıçta sıfırla */
	pwm_set_pulse_dt(&pwm_in1, 0);
	pwm_set_pulse_dt(&pwm_in2, 0);

	// Tüm Butonların interruptlarını ayarla 
	for (int i = 0; i < 4; i++) {
		if (!gpio_is_ready_dt(&buttons[i])) {
			LOG_INF("Buton %d hazır değil!\n", i);
			continue;
		}

		ret = gpio_pin_configure_dt(&buttons[i], GPIO_INPUT);
		if (ret) {
			LOG_INF("Buton %d yapılandırma hatası (%d)\n", i, ret);
			continue;
		}

		ret = gpio_pin_interrupt_configure_dt(&buttons[i], GPIO_INT_EDGE_TO_ACTIVE);
		if (ret) {
			LOG_INF("Buton %d interrupt hatası (%d)\n", i, ret);
			continue;
		}
		//HER FONKSİYONA CALLBACKLER ATANDI.
		gpio_init_callback(&button_cb_data[i], button_handler, BIT(buttons[i].pin));
		gpio_add_callback(buttons[i].port, &button_cb_data[i]);

		LOG_INF("Buton %d -> %s pin %d\n", i , buttons[i].port->name, buttons[i].pin);
	}

	LOG_INF("Kurulum tamamlandı. 4 buton aktif.\n");

	while (1) {
		err = adc_read(adc_channel.dev, &sequence);
		k_msleep(5); //küçük bir bekleme ekledim adc patlamasın diye
		if (err < 0) {
			LOG_ERR("Gerilimi Okumadi: (%d)", err);
			continue;
		}
		int16_t adc_raw = buffer;
    	float v_ipropi = ((adc_raw / adc_max_value) * vref) / GAIN; //formül böyle gerilim için
    	// 2. Datasheet'teki formülü kullanarak motor akımını hesapla.
        // I_MOTOR = V_IPROPI / (R_IPROPI * A_IPROPI)
        float motor_current = v_ipropi / (R_IPROPI * A_IPROPI); //oranlı direnç V=IR den formül
		if(motor_current > MotorAkimSinir){
			k_timer_start(&led_timer, K_MSEC(0), K_MSEC(100)); // 100ms yansön yapcak
		}
		else{
			k_timer_stop(&led_timer);
			gpio_pin_set_dt(&led, 0); //ledi kapat.
		}

		k_sleep(K_MSEC(SLEEP_TIME_MS)); //50ms de bir okuma yapacak
	}
}

/* Buton Fonksiyonları */

void button1_action(void)
{
	//SSOLA DÖNSÜN IN1 AKTİF
	current_direction = 1; // sola dönüyor
    pwm_set_dt(&pwm_in1, PWM_USEC(PWM_PERIOD_USEC), PWM_USEC(pwm_pulse_high)); //IN1 İÇİN
    pwm_set_dt(&pwm_in2, PWM_USEC(PWM_PERIOD_USEC), PWM_USEC(PWM_PULSE_LOW)); //IN2 İÇİN
    LOG_INF("Sola git (IN1 aktif)\n");
}

void button2_action(void)
{
	current_direction = 2; // sağa dönüyor
	pwm_set_dt(&pwm_in1, PWM_USEC(PWM_PERIOD_USEC), PWM_USEC(PWM_PULSE_LOW)); //IN1 İÇİN LOW 
    pwm_set_dt(&pwm_in2, PWM_USEC(PWM_PERIOD_USEC), PWM_USEC(pwm_pulse_high)); //IN2 İÇİN HIGH VERECEK Kİ SAĞA DÖNSÜN
    LOG_INF("Sağa git (IN2 aktif)\n");
}

void button3_action(void)
{
	//YAVAŞLATMA
	LOG_INF("Button 3 YAVAŞLAMA\n");
	pwm_pulse_high -= 1;
	if (pwm_pulse_high < PWM_MIN_PULSE_WIDTH) {
		pwm_pulse_high = PWM_MIN_PULSE_WIDTH; // Minimum değerden aşmasın
	}
	// Değişikliği anında uygula
    if (current_direction == 1) { // Eğer sola dönüyorsa
        pwm_set_pulse_dt(&pwm_in1, PWM_USEC(pwm_pulse_high));
    } else if (current_direction == 2) { // Eğer sağa dönüyorsa
        pwm_set_pulse_dt(&pwm_in2, PWM_USEC(pwm_pulse_high));
    }
}

void button4_action(void)
{
	//HIZLANDIRMA
	LOG_INF("Button 4 HIZLANMA\n");
	pwm_pulse_high += 1;
	if (pwm_pulse_high > PWM_MAX_PULSE_WIDTH) {
		pwm_pulse_high = PWM_MAX_PULSE_WIDTH; // Maksimum değeri aşmasın
	}
	// Değişikliği anında uygula
    if (current_direction == 1) { // Eğer sola dönüyorsa
        pwm_set_pulse_dt(&pwm_in1, PWM_USEC(pwm_pulse_high));
    } else if (current_direction == 2) { // Eğer sağa dönüyorsa
        pwm_set_pulse_dt(&pwm_in2, PWM_USEC(pwm_pulse_high));
    }	
}

void led_timer_handler(struct k_timer *timer_id)
{
    led_acikMi = !led_acikMi; //led durumunu değiştir
    gpio_pin_set_dt(&led, led_acikMi); //ledi aç/kapa
}

void led_timer_stop_handler(struct k_timer *timer_id)
{
	led_acikMi = 0; //ledi kapatır.
    gpio_pin_set_dt(&led, 0); // LED'i kapat
}

And thats my .overlay file:

// To get started, press Ctrl+Space to bring up the completion menu and view the available nodes.

// You can also use the buttons in the sidebar to perform actions on nodes.
// Actions currently available include:

// * Enabling / disabling the node
// * Adding the bus to a bus
// * Removing the node
// * Connecting ADC channels

// For more help, browse the DeviceTree documentation at https://docs.zephyrproject.org/latest/guides/dts/index.html
// You can also visit the nRF DeviceTree extension documentation at https://docs.nordicsemi.com/bundle/nrf-connect-vscode/page/guides/ncs_configure_app.html#devicetree-support-in-the-extension

//adc için de ekleme yaptık. 
//nodeismi motor oldu. pwm-motor ile compatible, pwm21 ve pwm22 ile sürülecek. 20ms periyodu var, max ve min pulseları da 1ms ve 2ms
/ {
    motor: motor {
        compatible = "pwm-motor";
        pwms = <&pwm21 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        min-pulse = <PWM_USEC(1000)>;
        max-pulse = <PWM_USEC(2000)>;
    }; //buradan almıyorum min ve max pulse 

    motor2: motor2 {
        compatible = "pwm-motor";
        pwms = <&pwm22 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        min-pulse = <PWM_USEC(1000)>;
        max-pulse = <PWM_USEC(2000)>;
    };
      zephyr,user{
        // io-channels hem ADC'yi hem de kullanılacak pini belirtir.
        io-channels = <&adc 7>;

        // Tüm kanal ayarlarını buraya taşıyoruz:
        zephyr,gain = "ADC_GAIN_1_4"; 
        zephyr,reference = "ADC_REF_INTERNAL";
        zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
        zephyr,resolution = <14>;
        status = "okay";
    };
};

  
&adc {
    status = "okay";
};

// PWM 21 P1.11 İÇİN:
&pwm21 {
    status = "okay";
    pinctrl-0 = <&pwm21_custom_motor>;
    pinctrl-1 = <&pwm21_csleep_motor>;
    pinctrl-names = "default", "sleep";
};

// PWM 22 P1.12 İÇİN:
&pwm22 {
    status = "okay";
    pinctrl-0 = <&pwm22_custom_motor2>;
    pinctrl-1 = <&pwm22_csleep_motor2>;
    pinctrl-names = "default", "sleep";
};




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

    pwm21_csleep_motor: pwm21_csleep_motor {
        group1 {
            psels = <NRF_PSEL(PWM_OUT0, 1, 11)>;
            low-power-enable;
        };
    };
      pwm22_custom_motor2: pwm22_custom_motor2 {
        group1 {
            psels = <NRF_PSEL(PWM_OUT0, 1, 12)>;
            nordic,invert;
        };
    };

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


// Çakışan aygıtları devre dışı bırakıyoruz.
&led2 {
    status = "disabled";
};
&led3 {
    status = "disabled";
};
&led1 {
    status = "disabled";
};

I always get : 

*** Booting nRF Connect SDK v3.0.2-89ba1294ac9b ***
*** Using Zephyr OS v4.0.99-f791c49f492c ***
[00:00:00.002,005] <dbg> os: k_sched_unlock: scheduler unlocked (0x200007b0:0)
[00:00:00.002,010] <inf> main: Başladı
[00:00:00.002,023] <inf> main: ADC device: adc@d5000, channel: 7

[00:00:00.002,028] <err> main: Adc kanali ayarlanmadi = #0 (-134) this output that says ADC CHANNEL DIDNT GET SET!

Can you please help me with that?

I already tried changing the pin and gain but it didn't work.

  • Hi mertpalaoglu1,

    Have you setup the ADC channel in Devicetree? That doesn't seem done in your overlay file.

    You need to setup something like this (replace CHANNEL_NUM with your selected channel):

    / {
    	zephyr,user {
    		io-channels = <&adc CHANNEL_NUM>;
    	};
    };
    &adc {
    	#address-cells = <1>;
    	#size-cells = <0>;
    	status = "okay";
    	channel@CHANNEL_NUM {
    		reg = <CHANNEL_NUM>; // 54L15 for example below..
    		zephyr,gain = "ADC_GAIN_1_4";
    		zephyr,reference = "ADC_REF_INTERNAL";
    		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
    		zephyr,input-positive = <NRF_SAADC_AIN4>; /* P1.11 for the nRF54L15 DK, BOOST/VOUT on pmic */
    		zephyr,resolution = <14>;
    	};
    };

    Hieu

  • I was trying to do this setup under zephyr,user{}. But it supposed to be under &adc{} I guess.

    That did solve the channel set issue !  Many thanks for your answer!  

Related