Zhengdian Atom embedded Linux driver development – Linux DAC driver

In the last note, I learned about the ADC driver. STM32MP157 also has DAC peripherals. The IIO driver framework also used by DAC. In this chapter, we will learn how to use the DAC on STM32MP157 under Linux as follows.

Introduction to DAC

ADC is an analog-to-digital converter, responsible for converting external analog signals into digital signals. DAC is just the opposite. It is a digital-to-analog converter, which is responsible for converting the digital signal of the SOC into an analog signal.

The DAC module (digital/analog conversion module) of STM32MP157 is a 12-bit digital input, voltage output type DAC. The DAC can be configured in 8-bit or 12-bit mode and can also be used with a DMA controller. DAC operates in 12-bit mode
, the data can be set to left or right alignment. The DAC module has 2 output channels, each channel has an independent converter. In dual DAC mode, the 2 channels can be converted independently, or they can be converted simultaneously and update the output of the 2 channels synchronously. The DAC can input the reference voltage Vref + (shared with the ADC) through the pin to obtain more accurate conversion results. The main features of the STM32MP157 DAC module are:

  1. 1 DAC interface, up to two DAC output channels.
  2. In 12-bit mode, data is left-justified or right-justified.
  3. Synchronous update function.
  4. Noise wave and triangle waveform generation.
  5. External trigger.
  6. Dual DAC channels can be converted simultaneously or separately.
  7. Each channel has DMA function.
  8. Input reference voltage VREF +.

The STM32MP157 DAC block diagram is shown below:

DAC structure block diagram

In the figureVDDA and VSSA are the power supplies for the analog part of the DAC module, and VREF + is the reference voltage of the DAC module. DAC_OUT1/2 are the two output channels of the DAC. DAC_OUT1 corresponds to the PA4 pin and DAC_OUT2 corresponds to the PA5 pin. The STM32MP157 development board uses DAC_OUT1, and the pin is PA4.

DAC driver source code analysis

DAC node under the device tree

The dac node information in the stm32mp151.dtsi file is as follows:

dac node

In line 2, the compatible attribute value is “st,stm32h7-dac-core”, so search for this string in the entire Linux source code to find the DAC driver core file of STM32MP157. This file is drivers/iio/dac/ stm32-dac-core.c.

Lines 11 and 18, the compatible attribute value is “st,stm32-dac”. Search this string to find the ADC driver file. This file is drivers/iio/dac/stm32-dac.c.

For more detailed information about the DAC node of STM32MP157, please refer to the corresponding binding document: Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt. Next, briefly analyze the binding document. Later, you need to modify the device tree according to the binding document and enable the channel corresponding to the DAC.

DAC first requires a root node. The attributes of the DAC root node are as follows:

1. Necessary attributes

  • compatible: Compatibility attribute, required, can be set to “st,stm32h7-dac-core”.
  • reg: DAC controller register information.
  • clocks: clocks.
  • clock-names: clock names, must be “pclk”.
  • vref-supply: This attribute corresponds to the vref reference voltage handle.
  • address-cells: Set to 1.
  • size-cells: Set to 0.

2. Optional attributes

  • : pinctrl pin configuration information.
  • resets: reset handle.

STM32MP157 has two DAC channels, each DAC channel corresponds to a sub-node, and the related attributes of the DAC sub-node
as follows:

  • Compatible: Compatibility attribute, required, can be set to “st, stm32-dac”.
  • reg: Different ADC controller register address offset information.
  • io-channel-cells: Set to 1.

DAC driver source code analysis

There are alsotwo STM32MP157 DAC driver files: stm32-dac-core.c and stm32-dac.c. stm32-dac-core.c is the DAC core layer, mainly used for initialization of DAC clock, power supply, etc.. What needs to be focused on is the file stm32-dac.c. The main framework of stm32-adc.c is the platform, which cooperates with the IIO driver framework to implement the DAC driver.

stm32_dac structure

First, let’s take a look at the stm32_dac structure, which is as follows:

stm32_dac structure

The stm32_dac structure is very simple, much simpler than the stm32_adc structure in the previous chapter. There is only one stm32_dac_common member variable, with the following content:

stm32_dac_common structure

It can be seen that the DAC driver also uses the regmap API.

stm32_dac_probe function

Next, take a look at the stm32_dac_probe function. The content is as follows (some are omitted):

stm32_dac_probe function

Line 12, call the devm_iio_device_alloc function to apply for iio_dev, and also apply for stm32_dac memory here.
.

Line 17, call the iio_priv function to get the stm32_dac first address from iio_dev.

Lines 19-23, initialize iio_dev, focusing on stm32_dac_iio_info on line 22, because reading or setting DAC data in user space is ultimately completed by stm32_dac_iio_info.

Line 25, calls the stm32_dac_chan_of_init function to set the DAC channel.

Line 36 calls the iio_device_register function to register iio_dev with the kernel.

The core of the same stm32_dac_probe function is to initialize the DAC and then establish the IIO driver framework of the DAC.

stm32_dac_iio_info structure

The contents of the stm32_dac_iio_info structure are as follows:

stm32_dac_iio_info structure

Line 2, the stm32_dac_read_raw function is used to read DAC information, read DAC original data values, resolution, etc.

Line 3, the stm32_dac_write_raw function is used to set the DAC value.

The stm32_dac_read_raw and stm32_dac_write_raw function contents are as follows:

stm32_dac_read_raw and stm32_dac_write_raw functions

Lines 1-17, stm32_dac_read_raw function, reads the original value and resolution of the DAC, which is very simple.

Lines 19-31, stm32_dac_write_raw function, writes the original value to the DAC, which is to set the DAC.

Hardware schematic analysis

The DAC schematic diagram is as follows:

DAC schematic

When I talked about ADC in the previous chapter, I mentioned that JP2 is a 3P pin header, which is used to set the ADC to connect the adjustable potentiometer and the DAC. This chapter learns to use the DAC, so you can use a jumper cap to connect pins 1 and 2 of JP2. That is, connect the DAC and ADC together, as shown in the figure below:

DAC jumper cap setting

You can write an application to set up the DAC and then use the ADC to capture it back. The Zhengdian Atom STM32MP157 development board uses DAC channel 1, and the pin is PA4.

DAC driver writing

Modify device tree

The DAC driver ST has been written, you just need to modify the device tree. First add the PA4 pin configuration information used by the DAC in the stm32mp15-pinctrl.dtsi file:

Sample code 58.4.1.1 PA4 pin configuration information
1 dac_ch1_pins_a: dac-ch1 {<!-- -->
2 pins {<!-- -->
3 pinmux = <STM32_PINMUX('A', 4, ANALOG)>;
4};
5};

Next, add vdd sub-node information to the root node in the stm32mp157d-atk.dts file, the content is as follows:

Sample code 58.4.1.2 vdd child node
1 v3v3: regulator-3p3v {<!-- -->
2 compatible = "regulator-fixed";
3 regulator-name = "v3v3";
4 regulator-min-microvolt = <3300000>;
5 regulator-max-microvolt = <3300000>;
6 regulator-always-on;
7 regulator-boot-on;
8 };

Finally, add some content to the adc node in the stm32mp157d-atk.dts file, as follows:

Sample code 58.4.1.3 adc node
1 &dac {<!-- -->
2 pinctrl-names = "default";
3 pinctrl-0 = < & amp;dac_ch1_pins_a>;
4 vref-supply = < & amp;v3v3>;
5 status = "okay";
6 dac1: dac@1 {<!-- -->
7 status = "okay";
8     };
9 };

Line 3, configure the dac pin.

Line 4, set the voltage properties.

Lines 6-8, dac1 sub-node, the setting is very simple, just set the status attribute to “okay”.

Enable DAC driver

Similarly, enable the ST32MP157 DAC driver in the Linux kernel, open the Linux kernel configuration interface, and configure the path
The diameter is as follows:

-> Device Drivers
-> Industrial I/O support (IIO [=y])
-> Digital to analog converters
-> <*>STMicroelectronics STM32 DAC //Enable STM32 DAC

As shown below:

DAC configuration item

Write a test APP

Compile the modified device tree, and then start the system using the new device tree. Enter the /sys/bus/iio/devices directory. There is an iio device corresponding to the DAC in this directory: iio:deviceX. The routine in this chapter is as shown below:

DAC iio device

There are two IIO devices in the above picture: iio:device0 and iio:device1. You can enter these two directories in order to check.
See what peripherals they correspond to. In the development board currently used in the tutorial, iio:device0 is the ADC (the ADC driver enabled in the experiment in the previous chapter), and iio:device1 is the DAC device enabled in this chapter.

Enter the “iio:device1” directory, the content is as shown below:

iio:device1 directory file

The standard IIO device file directory only cares about three files:

  • out_voltage1_powerdown: DAC output enable file, write 0 to turn on the DAC, write 1 to turn off the DAC, the default is 1, which means turn off the DAC.
  • out_voltage1_raw: DAC1 channel 1 raw value file.
  • out_voltage1_scale: DAC1 scale file (resolution), unit is mV. Actual output voltage value (mV)=out_voltage1_raw * out_voltage1_scale. The default value of out_voltage1_scale is shown in the figure below:

out_voltage1_scale content

As can be seen from the above figure, out_voltage1_scale defaults to 0.805664062.

DAC1 defaults to 12 bits, so the settable range is 0-4095. Write 2000 to out_voltage1_raw, the command is as follows:

echo 0 > /sys/bus/iio/devices/iio:device1/out_voltage1_powerdown //Enable DAC
echo 2000 > /sys/bus/iio/devices/iio:device1/out_voltage1_raw //Set DAC

At this time, the theoretical voltage value output by the DAC is 2000*0.805664062≈1611.328mV.
So is the DAC output correct? Just use adcAPP.c written in the previous chapter to read the DAC pin voltage value. Note here that you must first connect the two pin headers on the right side of JP2 as shown in the previous connection diagram, that is, connect the DAC and ADC pins together.

Run adcApp.c from the previous chapter, and the result is as shown below:

ADC collection results

As can be seen from the above figure, the voltage collected by the ADC is 1.61V, which is basically consistent with the set theoretical value of the DAC. It should be noted here that DAC1 is 12-bit and ADC is 16-bit, so you can see that their original values will be different.

Next, compile a simple DAC test APP. The APP waits for the user to input the original value of the DAC. Once the user inputs, it calls the ADC to collect the voltage value output by the DAC. Finally, it prints out the theoretical value of the DAC and the actual value collected by the ADC. Check if it is correct.

The process here is basically similar. First set the char character array pointer file_path to place the file path corresponding to the iio framework and the file index corresponding to enum. Then set the device structure of the dac and save raw, scale and act.

Then write file_data_read, which is the same operation. Open fopen and then scan with fscanf. When EOF is encountered, fseek is adjusted to the end and then fclose.

Then write the dac_add_dac_read function to obtain ADC and DAC data. Here is file_data_read and then atoi and atof to get the original value and ratio. After conversion, the actual value is stored in the adc_act member variable of the dac_dev structure pointer dev; then the same method is used to obtain the theory of DAC The real value is stored in dev->dac_act.

Then write dac_enable, which contains system to call the console and enable the DAC. The same goes for dac_disable.

Then write the dac_set function and set the DAC. Here, sprintf converts the incoming value into a string, then fopen opens the file, fseek adjusts the file pointer to the file header, fwrite writes the value converted into a string, and then fclose closes the file.

Finally, write the main function. There is only one argc. First, dac_enable is required to enable the DAC, and then scanf in the while gets the input target dac setting value, and then obtains the input value through fgets. Then dac_set passes this value to the DAC and calls dac_add_dac_read. Get the data and print the current dac and adc values after success.

Run the test

Compile driver and test APP

Enter the following to compile the dacApp.c test program:

arm-none-linux-gnueabihf-gcc -march=armv7-a -mfpu=neon -mfloat-abi=hard dacApp.c -o dacApp

After successful compilation, the dacApp application will be generated.

Run the test

Note that before testing, you must first connect the JP2 jumper cap to the right as shown in the wiring diagram, that is, connect the ADC1_CH19 channel to the DAC1 pin on the development board!

Enter the following command to use dacApp to test the program:

./dacApp

After running, the APP will wait for the input of the DAC value to be set. Each time it is input, it will automatically print out the actual ADC value collected by the ADC and the theoretical value of the DAC, as shown in the figure below:

DAC test results

In the above figure, a total of 6 DAC original values of 0, 500, 1000, 2000, 3000 and 4095 are set. It can be seen that the theoretical value of the DAC setting is basically consistent with the actual value collected by the ADC.

Summary

DAC and ADC are generally very close. ST has officially written the driver. The overall process is platform driver plus regmap and IIO driver.