| /* |
| * Copyright (c) 2020 Libre Solar Technologies GmbH |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /* |
| * @addtogroup test_dac_loopback |
| * @{ |
| * @defgroup t_dac_basic_loopback test_dac_loopback |
| * @brief TestPurpose: read back DAC driver output with ADC |
| * @} |
| */ |
| |
| #include <zephyr/drivers/dac.h> |
| #include <zephyr/drivers/adc.h> |
| #include <zephyr/kernel.h> |
| #include <zephyr/ztest.h> |
| |
| /* |
| * We need to define an ADC channel to read back the output generated by the |
| * ADC. The two pins need to be connected with a jumper in order to pass the |
| * test in actual hardware. |
| * |
| * ADC and DAC need to use the same reference voltage, as the test sampling |
| * point is at half of the full scale voltage. |
| */ |
| |
| #if defined(CONFIG_BOARD_NUCLEO_L152RE) || \ |
| defined(CONFIG_BOARD_STM32F3_DISCO) || \ |
| defined(CONFIG_BOARD_STM32L562E_DK) || \ |
| defined(CONFIG_BOARD_NUCLEO_L552ZE_Q) || \ |
| defined(CONFIG_BOARD_NUCLEO_WL55JC) || \ |
| defined(CONFIG_BOARD_RONOTH_LODEV) |
| |
| /* |
| * DAC output on PA4 (Arduino A2 pin of Nucleo board) |
| * ADC input read from PA1 (Arduino A1 pin of Nucleo board) |
| */ |
| |
| #define DAC_DEVICE_NODE DT_NODELABEL(dac1) |
| #define DAC_CHANNEL_ID 1 |
| #define DAC_RESOLUTION 12 |
| |
| #define ADC_DEVICE_NODE DT_NODELABEL(adc1) |
| #if defined(CONFIG_BOARD_STM32L562E_DK) |
| #define ADC_CHANNEL_ID 13 |
| #else |
| #define ADC_CHANNEL_ID 1 |
| #endif /* CONFIG_BOARD_STM32L562E_DK */ |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1 |
| #define ADC_REFERENCE ADC_REF_INTERNAL |
| /* The STM32L562E_DK does not accept ADC_ACQ_TIME_DEFAULT (=0) but the MAX one */ |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_MAX |
| |
| |
| #elif defined(CONFIG_BOARD_NUCLEO_L073RZ) || \ |
| defined(CONFIG_BOARD_NUCLEO_F207ZG) || \ |
| defined(CONFIG_BOARD_NUCLEO_F429ZI) || \ |
| defined(CONFIG_BOARD_NUCLEO_F746ZG) || \ |
| defined(CONFIG_BOARD_NUCLEO_G071RB) |
| /* |
| * DAC output on PA4 |
| * ADC input read from PA0 |
| */ |
| |
| #define DAC_DEVICE_NODE DT_NODELABEL(dac1) |
| #define DAC_CHANNEL_ID 1 |
| #define DAC_RESOLUTION 12 |
| |
| #define ADC_DEVICE_NODE DT_NODELABEL(adc1) |
| #define ADC_CHANNEL_ID 0 |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1 |
| #define ADC_REFERENCE ADC_REF_INTERNAL |
| /* The NUCLEO_G071RB does not accept ADC_ACQ_TIME_DEFAULT (=0) but the MAX one */ |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_MAX |
| |
| #elif defined(CONFIG_BOARD_TWR_KE18F) |
| |
| /* |
| * DAC0 output is internally available on ADC0_SE23 when test output |
| * is enabled. |
| */ |
| |
| #define DAC_DEVICE_NODE DT_NODELABEL(dac0) |
| #define DAC_RESOLUTION 12 |
| #define DAC_CHANNEL_ID 0 |
| |
| #define ADC_DEVICE_NODE DT_NODELABEL(adc0) |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1 |
| #define ADC_REFERENCE ADC_REF_INTERNAL |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT |
| #define ADC_CHANNEL_ID 23 |
| |
| #elif defined(CONFIG_BOARD_FRDM_K64F) |
| |
| /* DAC0 output is internally available on ADC0_SE23 */ |
| |
| #define DAC_DEVICE_NODE DT_NODELABEL(dac0) |
| #define DAC_RESOLUTION 12 |
| #define DAC_CHANNEL_ID 0 |
| |
| #define ADC_DEVICE_NODE DT_NODELABEL(adc0) |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1 |
| #define ADC_REFERENCE ADC_REF_INTERNAL |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT |
| #define ADC_CHANNEL_ID 23 |
| |
| #elif defined(CONFIG_BOARD_FRDM_K22F) |
| |
| /* DAC0 output is internally available on ADC0_SE23 */ |
| |
| #define DAC_DEVICE_NODE DT_NODELABEL(dac0) |
| #define DAC_RESOLUTION 12 |
| #define DAC_CHANNEL_ID 0 |
| |
| #define ADC_DEVICE_NODE DT_NODELABEL(adc0) |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1 |
| #define ADC_REFERENCE ADC_REF_INTERNAL |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT |
| #define ADC_CHANNEL_ID 23 |
| |
| #elif defined(CONFIG_BOARD_LPCXPRESSO55S36) |
| |
| /* DAC0 output is internally available on ADC0_SE4 */ |
| |
| #define DAC_DEVICE_NODE DT_NODELABEL(dac0) |
| #define DAC_RESOLUTION 12 |
| #define DAC_CHANNEL_ID 0 |
| |
| #define ADC_DEVICE_NODE DT_NODELABEL(adc0) |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1 |
| #define ADC_REFERENCE ADC_REF_EXTERNAL0 |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT |
| #define ADC_CHANNEL_ID 0 |
| #define ADC_1ST_CHANNEL_INPUT 4 |
| |
| #elif defined(CONFIG_BOARD_BL652_DVK) || \ |
| defined(CONFIG_BOARD_BL653_DVK) || \ |
| defined(CONFIG_BOARD_BL654_DVK) || \ |
| defined(CONFIG_BOARD_BL5340_DVK) |
| #include <hal/nrf_saadc.h> |
| /* DAC output from MCP4725 pin 1 |
| * On BL65x ADC_1 input is read from pin SIO_3 |
| * On BL5340 ADC_1 input is read from pin SIO_5 |
| * Note external DAC MCP4725 is not populated on BL652_DVK, BL653_DVK and |
| * BL654_DVK at factory |
| */ |
| |
| #define DAC_DEVICE_NODE DT_NODELABEL(dac0) |
| #define DAC_RESOLUTION 12 |
| #define DAC_CHANNEL_ID 0 |
| |
| #define ADC_DEVICE_NODE DT_NODELABEL(adc) |
| #define ADC_RESOLUTION 12 |
| #define ADC_GAIN ADC_GAIN_1_4 |
| #define ADC_REFERENCE ADC_REF_VDD_1_4 |
| #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT |
| #define ADC_CHANNEL_ID 1 |
| #define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1 |
| |
| #else |
| #error "Unsupported board." |
| #endif |
| |
| static const struct dac_channel_cfg dac_ch_cfg = { |
| .channel_id = DAC_CHANNEL_ID, |
| .resolution = DAC_RESOLUTION, |
| .buffered = true |
| }; |
| |
| static const struct adc_channel_cfg adc_ch_cfg = { |
| .gain = ADC_GAIN, |
| .reference = ADC_REFERENCE, |
| .acquisition_time = ADC_ACQUISITION_TIME, |
| .channel_id = ADC_CHANNEL_ID, |
| |
| #if defined(CONFIG_BOARD_BL652_DVK) || \ |
| defined(CONFIG_BOARD_BL653_DVK) || \ |
| defined(CONFIG_BOARD_BL654_DVK) || \ |
| defined(CONFIG_BOARD_BL5340_DVK) || \ |
| defined(CONFIG_BOARD_LPCXPRESSO55S36) |
| .input_positive = ADC_1ST_CHANNEL_INPUT, |
| #endif |
| }; |
| |
| static const struct device *init_dac(void) |
| { |
| int ret; |
| const struct device *const dac_dev = DEVICE_DT_GET(DAC_DEVICE_NODE); |
| |
| zassert_true(device_is_ready(dac_dev), "DAC device is not ready"); |
| |
| ret = dac_channel_setup(dac_dev, &dac_ch_cfg); |
| zassert_equal(ret, 0, |
| "Setting up of the first channel failed with code %d", ret); |
| |
| return dac_dev; |
| } |
| |
| /* ADC necessary to read back the value from DAC */ |
| static const struct device *init_adc(void) |
| { |
| int ret; |
| const struct device *const adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE); |
| |
| zassert_true(device_is_ready(adc_dev), "ADC device is not ready"); |
| |
| ret = adc_channel_setup(adc_dev, &adc_ch_cfg); |
| zassert_equal(ret, 0, |
| "Setting up of the ADC channel failed with code %d", ret); |
| |
| return adc_dev; |
| } |
| |
| /* |
| * test_dac_loopback |
| */ |
| static int test_task_loopback(void) |
| { |
| int ret; |
| |
| const struct device *dac_dev = init_dac(); |
| const struct device *adc_dev = init_adc(); |
| |
| if (!dac_dev || !adc_dev) { |
| return TC_FAIL; |
| } |
| |
| /* write a value of half the full scale resolution */ |
| ret = dac_write_value(dac_dev, DAC_CHANNEL_ID, |
| (1U << DAC_RESOLUTION) / 2); |
| zassert_equal(ret, 0, "dac_write_value() failed with code %d", ret); |
| |
| /* wait to let DAC output settle */ |
| k_sleep(K_MSEC(10)); |
| |
| static int16_t m_sample_buffer[1]; |
| static const struct adc_sequence sequence = { |
| .channels = BIT(ADC_CHANNEL_ID), |
| .buffer = m_sample_buffer, |
| .buffer_size = sizeof(m_sample_buffer), |
| .resolution = ADC_RESOLUTION, |
| }; |
| |
| ret = adc_read(adc_dev, &sequence); |
| zassert_equal(ret, 0, "adc_read() failed with code %d", ret); |
| zassert_within(m_sample_buffer[0], |
| (1U << ADC_RESOLUTION) / 2, 32, |
| "Value %d read from ADC does not match expected range.", |
| m_sample_buffer[0]); |
| |
| return TC_PASS; |
| } |
| |
| ZTEST(dac_loopback, test_dac_loopback) |
| { |
| zassert_true(test_task_loopback() == TC_PASS); |
| } |
| |
| ZTEST_SUITE(dac_loopback, NULL, NULL, NULL, NULL, NULL); |