978 views|3 replies

257

Posts

4

Resources
The OP
 

[ST NUCLEO-C031C6 development board review] Using the ADC function with a light sensor [Copy link]

1. Hardware Understanding

From the manual, we can know that STM32C0 provides the same excellent ADC support as always:

On the Nucleo-C031C6 development board, the CN8 area is compatible with the Arduino Uno R3 interface and can be used directly as an ADC pin:

Specific corresponding location on the development board:

2. Corresponding configuration in zephyr

In zephyr/boards/arm/nucleo_c031c6/nucleo_c031c6.dts, there is the following configuration:

This defines the basic configuration information of adc1.

In the adc1 channel, you can use pa0, pa1, and pa4 to perform ADC peripheral measurements.

In addition, in zephyr/samples/drivers/adc/boards/nucleo_c031c6.overlay, the configuration of specific channels is provided:

 / {
	zephyr,user {
		/* adjust channel number according to pinmux in board.dts */
		io-channels = <&adc1 0>, <&adc1 1>, <&adc1 4>;
	};
};

&adc1 {
	#address-cells = <1>;
	#size-cells = <0>;

	channel@0 {
		reg = <0>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
	};

	channel[url=home.php?mod=space&uid=490]@1[/url] {
		reg = <1>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
	};

	channel[url=home.php?mod=space&uid=28485]@4[/url] {
		reg = <4>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
	};
};

The regs of channel@0, channel@1, and channel@4 corresponding to the above adc1 correspond to adc1_in0_pa0, adc1_in1_pa1, and adc1_in4_pa4 in dts.

In addition, the resolution in the configuration corresponds to the actual resolution to be used. The available values are shown in the reference manual as follows:

3. Analog Light Sensor

I have a simulated ambient light sensor from DFRobot:

The corresponding pins are as follows:

This analog sensor can use +3~5V DC, which can be borrowed from the 3.3V, GND, and PA0 on the development board:

4. Code Writing

Refer to zephyr/samples/drivers/adc/src/main.c and write the following code:

#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>

#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>

#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
	!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
#error "No suitable devicetree overlay specified"
#endif

#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
	ADC_DT_SPEC_GET_BY_IDX(node_id, idx),

/* Data of ADC io-channels specified in devicetree. */
static const struct adc_dt_spec adc_channels[] = {
	DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,
			     DT_SPEC_AND_COMMA)
};

uint8_t val_to_light(int32_t buf)
{
	float temp = 0;
	temp = 100*((float) buf/4096);
	return (uint8_t)temp;
}

int main(void)
{
	int err;
	uint32_t count = 0;
	uint16_t buf;
	struct adc_sequence sequence = {
		.buffer = &buf,
		/* buffer size in bytes, not number of samples */
		.buffer_size = sizeof(buf),
	};

	/* Configure channels individually prior to sampling. */
	for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
		if (!adc_is_ready_dt(&adc_channels[i])) {
			printk("ADC controller device %s not ready\n", adc_channels[i].dev->name);
			return 0;
		}

		err = adc_channel_setup_dt(&adc_channels[i]);
		if (err < 0) {
			printk("Could not setup channel #%d (%d)\n", i, err);
			return 0;
		}
	}

	struct adc_dt_spec adc_channel = adc_channels[0];
	while (1) {
		printk("ADC reading[%u]:\n", count++);

		int32_t val_mv;
		uint8_t light;

		printk("- %s, channel %d: ",
				adc_channel.dev->name,
				adc_channel.channel_id);

		(void)adc_sequence_init_dt(&adc_channel, &sequence);

		err = adc_read_dt(&adc_channel, &sequence);
		if (err < 0) {
			printk("Could not read (%d)\n", err);
			continue;
		}

		/*
			* If using differential mode, the 16 bit value
			* in the ADC sample buffer should be a signed 2's
			* complement value.
			*/
		if (adc_channel.channel_cfg.differential) {
			val_mv = (int32_t)((int16_t)buf);
		} else {
			val_mv = (int32_t)buf;
		}
		printk("%"PRId32, val_mv);
		light = val_to_light(val_mv);

		err = adc_raw_to_millivolts_dt(&adc_channel,
							&val_mv);
		/* conversion to mV may not be supported, skip if not */
		if (err < 0) {
			printk(" (value in mV not available)\n");
		} else {
			printk(" = %"PRId32" mV", val_mv);
		}

		printk(", Light is %"PRId8"%%\n\n", light);

		k_sleep(K_MSEC(1000));
	}
	return 0;
}

In the above code, zephyr_user / io_channels corresponds to the adc1 channels configured in zephyr/samples/drivers/adc/boards/nucleo_c031c6.overlay.

Then, use adc_is_ready_dt() and adc_channel_setup_dt() to check and configure the device, initialize data reading through adc_sequence_init_dt(), and use adc_read_dt() to read data into sequence.

sequence.buffer corresponds to the buf variable, which is the original value read. Then val_to_light() is used to convert the original value to the brightness percentage. The value range is determined by the resolution in the configuration. The 4096 in val_to_light() is also set according to the resolution, and 2^12 corresponds to 4096.

Finally, adc_raw_to_millivolts_dt() can be called to convert the raw value to a mV value.

5. Output results

After compiling and burning to the development board, you can read the output.

When the photodiode of the simulated light sensor is completely covered, the output is as follows:

Normal placement, the output is as follows:

The weather is rather gloomy today, so the brightness is low.

Turn on the light, or shine a flashlight from your phone, and the output is as follows:

The above results are all for 12-bit resolution, and the corresponding maximum original value is 2^12=4096, and the voltage is 3300mV.

If you change the resolution to 8 bits:

uint8_t val_to_light(int32_t buf)
{
	float temp = 0;

	temp = 100*((float) buf/256);
	return (uint8_t)temp;
}

The normal output is as follows:

VI. Conclusion

The above content is the basic usage of ADC function.

In actual use, the next step of processing can be performed according to the light intensity value. For example, if the light intensity is too low, the light is automatically turned on to provide fill light.

Other similar analog smoke sensors, analog humidity sensors, etc. can measure and process data in a similar manner.

VII. References

This post is from stm32/stm8

Latest reply

You are too modest. From the article written by the gang leader, we can see that Zephyr is very hardworking in cooperating with manufacturers.   Details Published on 2024-2-18 19:39
 

6841

Posts

11

Resources
2
 

The boss has in-depth research on zephyr, which is a great supplement to STM32CubeIDE.

This post is from stm32/stm8

Comments

I'm just starting to learn Zephyr and I'm still feeling my way around it.  Details Published on 2024-2-18 17:56
 
 

257

Posts

4

Resources
3
 
lugl4313820 posted on 2024-2-18 16:09 The boss has done a lot of research on zephyr, which is a great supplement to STM32CubeIDE.

I'm just starting to learn Zephyr and I'm still feeling my way around it.

This post is from stm32/stm8

Comments

You are too modest. From the article written by the gang leader, we can see that Zephyr is very hardworking in cooperating with manufacturers.  Details Published on 2024-2-18 19:39
 
 

6841

Posts

11

Resources
4
 
HonestQiao posted on 2024-2-18 17:56 I just started learning Zephyr and am still trying to figure it out.

You are too modest. From the article written by the gang leader, we can see that Zephyr is very hardworking in cooperating with manufacturers.

This post is from stm32/stm8
 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list