forked from nuttx/nuttx-update
Added ADC to RP2040
This commit is contained in:
parent
7307b8b6d5
commit
aa6ec6518c
17 changed files with 1137 additions and 6 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -26,10 +26,12 @@
|
|||
*.sym
|
||||
*.wsp
|
||||
*.ddc
|
||||
*.dds
|
||||
*~
|
||||
.depend
|
||||
/.config
|
||||
/.config.old
|
||||
/.config.*
|
||||
/.config-*
|
||||
/.config\ *
|
||||
/.cproject
|
||||
/.gdbinit
|
||||
|
|
|
@ -70,6 +70,10 @@ ifeq ($(CONFIG_WS2812),y)
|
|||
CHIP_CSRCS += rp2040_ws2812.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ADC),y)
|
||||
CHIP_CSRCS += rp2040_adc.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP2040_FLASH_BOOT),y)
|
||||
ifneq ($(PICO_SDK_PATH),)
|
||||
include chip/boot2/Make.defs
|
||||
|
|
120
arch/arm/src/rp2040/hardware/rp2040_adc.h
Normal file
120
arch/arm/src/rp2040/hardware/rp2040_adc.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/hardware/rp2040_adc.h
|
||||
*
|
||||
* Generated from rp2040.svd originally provided by
|
||||
* Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_ADC_H
|
||||
#define __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_ADC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include "hardware/rp2040_memorymap.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define RP2040_ADC_CS_OFFSET 0x000000 /* ADC Control and Status register */
|
||||
#define RP2040_ADC_RESULT_OFFSET 0x000004 /* ADC Results register */
|
||||
#define RP2040_ADC_FCS_OFFSET 0x000008 /* ADC FIFO Control and Status register */
|
||||
#define RP2040_ADC_FIFO_OFFSET 0x00000c /* ADC Result FIFO */
|
||||
#define RP2040_ADC_DIV_OFFSET 0x000010 /* ADC Clock Divider register */
|
||||
#define RP2040_ADC_INTR_OFFSET 0x000014 /* ADC Raw Interrupts register */
|
||||
#define RP2040_ADC_INTE_OFFSET 0x000018 /* ADC Interrupt Enable register */
|
||||
#define RP2040_ADC_INTF_OFFSET 0x00001c /* ADC Interrupt Force register */
|
||||
#define RP2040_ADC_INTS_OFFSET 0x000020 /* ADC Interrupt Status register */
|
||||
|
||||
/* Register definitions *****************************************************/
|
||||
|
||||
#define RP2040_ADC_CS (RP2040_ADC_BASE + RP2040_ADC_CS_OFFSET)
|
||||
#define RP2040_ADC_RESULT (RP2040_ADC_BASE + RP2040_ADC_RESULT_OFFSET)
|
||||
#define RP2040_ADC_FCS (RP2040_ADC_BASE + RP2040_ADC_FCS_OFFSET)
|
||||
#define RP2040_ADC_FIFO (RP2040_ADC_BASE + RP2040_ADC_FIFO_OFFSET)
|
||||
#define RP2040_ADC_DIV (RP2040_ADC_BASE + RP2040_ADC_DIV_OFFSET)
|
||||
#define RP2040_ADC_INTR (RP2040_ADC_BASE + RP2040_ADC_INTR_OFFSET)
|
||||
#define RP2040_ADC_INTE (RP2040_ADC_BASE + RP2040_ADC_INTE_OFFSET)
|
||||
#define RP2040_ADC_INTF (RP2040_ADC_BASE + RP2040_ADC_INTF_OFFSET)
|
||||
#define RP2040_ADC_INTS (RP2040_ADC_BASE + RP2040_ADC_INTS_OFFSET)
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
#define RP2040_ADC_CS_RROBIN_SHIFT (16)
|
||||
#define RP2040_ADC_CS_RROBIN_MASK (0x001fl << RPC2040_ADC_CS_RROBIN_SHIFT)
|
||||
#define RP2040_ADC_CS_AINSEL_SHIFT (12)
|
||||
#define RP2040_ADC_CS_AINSEL_MASK (0x0007l << RPC2040_ADC_CS_AINSEL_SHIFT)
|
||||
#define RP2040_ADC_CS_ERR_STICKY (1 << 10)
|
||||
#define RP2040_ADC_CS_ERR (1 << 9)
|
||||
#define RP2040_ADC_CS_READY (1 << 8)
|
||||
#define RP2040_ADC_CS_START_MANY (1 << 3)
|
||||
#define RP2040_ADC_CS_START_ONCE (1 << 2)
|
||||
#define RP2040_ADC_CS_TS_ENA (1 << 1)
|
||||
#define RP2040_ADC_CS_EN (1 << 0)
|
||||
|
||||
#define RP2040_ADC_RESULT_VAL_MASK (0x00000fffl)
|
||||
|
||||
#define RP2040_ADC_FCS_THRESH_SHIFT (24)
|
||||
#define RP2040_ADC_FCS_THRESH_MASK (0x000fl << RP2040_ADC_FCS_THRESH_SHIFT)
|
||||
#define RP2040_ADC_FCS_LEVEL_SHIFT (16)
|
||||
#define RP2040_ADC_FCS_LEVEL_MASK (0x000fl << RP2040_ADC_FCS_LEVEL_SHIFT)
|
||||
#define RP2040_ADC_FCS_OVER (1 << 11)
|
||||
#define RP2040_ADC_FCS_UNDER (1 << 10)
|
||||
#define RP2040_ADC_FCS_FULL (1 << 9)
|
||||
#define RP2040_ADC_FCS_EMPTY (1 << 8)
|
||||
#define RP2040_ADC_FCS_DREQ_EN (1 << 3)
|
||||
#define RP2040_ADC_FCS_ERR (1 << 2)
|
||||
#define RP2040_ADC_FCS_SHIFT (1 << 1)
|
||||
#define RP2040_ADC_FCS_EN (1 << 0)
|
||||
|
||||
#define RP2040_ADC_FIFO_ERR (1 << 15)
|
||||
#define RP2040_ADC_FIFO_VAL_MASK (0x0fffl)
|
||||
|
||||
#define RP2040_ADC_DIV_INT_SHIFT (8)
|
||||
#define RP2040_ADC_DIV_INT_MASK (0x0fffl << RP2040_ADC_DIV_INT_SHIFT)
|
||||
#define RP2040_ADC_DIV_FRAC_SHIFT (0)
|
||||
#define RP2040_ADC_DIV_FRAC_MASK (0x00ffl << RP2040_ADC_DIV_FRAC_MASK)
|
||||
|
||||
#define RP2040_ADC_INTR_FIFO (1 << 0) /* Raw interrupt status */
|
||||
|
||||
#define RP2040_ADC_INTE_FIFO (1 << 0) /* Set to pass interrupts */
|
||||
|
||||
#define RP2040_ADC_INTF_FIFO (1 << 0) /* Write 1 to force the interrupt. */
|
||||
|
||||
#define RP2040_ADC_INTS_FIFO (1 << 0) /* Masked interrupt status */
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_ADC_H */
|
652
arch/arm/src/rp2040/rp2040_adc.c
Normal file
652
arch/arm/src/rp2040/rp2040_adc.c
Normal file
|
@ -0,0 +1,652 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/rp2040_adc.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Notes:
|
||||
* The ADC driver upper-half returns signed values of up to 32-bits to
|
||||
* the user and expects the high-order bits in any result to be
|
||||
* significant. So, while the RP2040 hardware returns an unsigned value
|
||||
* in the low-order 12 bits of the result register, we shift this
|
||||
* value to the high-order bits.
|
||||
*
|
||||
* The result is that to convert a 32-bit value returned from the ADC
|
||||
* driver, you should use V = ADC_AVDD * value / (2^31) where ADC_AVDD
|
||||
* is the analogue reference voltage supplied to the RP2040 chip. If
|
||||
* 8 or 16 bit values are returned the divisor would be (2^15) or (2^7)
|
||||
* respectively.
|
||||
*
|
||||
* Also, if the conversion error bit was set for a particular sample,
|
||||
* the return value will be negated. Any negative return value should
|
||||
* be treated as erroneous.
|
||||
*
|
||||
* -------------
|
||||
*
|
||||
* This lower-half supports multiple drivers (/dev/adc0, /dav/dca1, etc.)
|
||||
* that each may read data from any of the ADC ports. The driver reads
|
||||
* whichever ADC ports are needed by ANY of ther drivers in strict
|
||||
* round-robin fashion, passing the converted values to the drivers that
|
||||
* needed it. Data is only passed if the driver is open.
|
||||
*
|
||||
* --------------
|
||||
*
|
||||
* This code reads the ADC ports at full speed. At the time this comment
|
||||
* was written, the upper-half will throw away any converted values it
|
||||
* receives when the buffer is full; therefor, if the data is not read
|
||||
* for a while, the returned values may be stale when finally read. You
|
||||
* can use the ANIOC_RESET_FIFO ioctl call to flush this stale data.
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <rp2040_adc.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
|
||||
#include <rp2040_gpio.h>
|
||||
|
||||
#include <hardware/rp2040_adc.h>
|
||||
|
||||
#include <nuttx/analog/adc.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
|
||||
#ifdef CONFIG_RP2040_ADC
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define ADC_CHANNEL_COUNT 5
|
||||
#define ADC_TEMP_CHANNEL 4
|
||||
|
||||
/* Get the private data pointer from a device pointer */
|
||||
|
||||
#define PRIV(x) ((FAR struct private_s *)(x)->ad_priv)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
struct private_s
|
||||
{
|
||||
FAR const struct adc_callback_s *callback; /* ADC Callback Structure */
|
||||
FAR FAR struct adc_dev_s *next_device;
|
||||
FAR FAR struct adc_dev_s *prior_device;
|
||||
bool has_channel[ADC_CHANNEL_COUNT];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int interrupt_handler(int irq,
|
||||
FAR void *context,
|
||||
FAR void *arg);
|
||||
|
||||
static void get_next_channel(void);
|
||||
static void add_device(FAR struct adc_dev_s *dev);
|
||||
static void remove_device(FAR struct adc_dev_s *dev);
|
||||
|
||||
/* ADC methods */
|
||||
|
||||
static int my_bind(FAR struct adc_dev_s *dev,
|
||||
FAR const struct adc_callback_s *callback);
|
||||
|
||||
static void my_reset(FAR struct adc_dev_s *dev);
|
||||
static int my_setup(FAR struct adc_dev_s *dev);
|
||||
static void my_shutdown(FAR struct adc_dev_s *dev);
|
||||
static void my_rxint(FAR struct adc_dev_s *dev, bool enable);
|
||||
static int my_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct adc_ops_s g_adcops =
|
||||
{
|
||||
.ao_bind = my_bind, /* Called first during initialization. */
|
||||
.ao_reset = my_reset, /* Called second during intialization. */
|
||||
.ao_setup = my_setup, /* Called during first open. */
|
||||
.ao_shutdown = my_shutdown, /* Called during last close. */
|
||||
.ao_rxint = my_rxint, /* Called to enable/disable interrupts. */
|
||||
.ao_ioctl = my_ioctl, /* Called for custom ioctls. */
|
||||
};
|
||||
|
||||
static const int8_t g_gpio_map[ADC_CHANNEL_COUNT] =
|
||||
{
|
||||
26, 27, 28, 29, -1
|
||||
};
|
||||
|
||||
static FAR struct adc_dev_s *g_first_device = NULL;
|
||||
|
||||
static uint8_t g_current_channel = 0xf0; /* too big */
|
||||
static uint8_t g_active_count = 0;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: interrupt_handler
|
||||
*
|
||||
* Description:
|
||||
* ADC interrupt handler. Note that this one handler is shared between
|
||||
* all ADC devices.
|
||||
*
|
||||
* Note: This is called from inside an interrupt service routine.
|
||||
****************************************************************************/
|
||||
|
||||
static int interrupt_handler(int irq, void *context, void *arg)
|
||||
{
|
||||
FAR struct adc_dev_s *a_device;
|
||||
FAR const struct adc_callback_s *a_callback;
|
||||
int32_t value;
|
||||
bool error_bit_set;
|
||||
|
||||
if (g_active_count == 0)
|
||||
{
|
||||
/* Last device has been removed -- turn off ADC */
|
||||
|
||||
putreg32(0, RP2040_ADC_CS);
|
||||
|
||||
putreg32(0, RP2040_ADC_INTE);
|
||||
|
||||
up_disable_irq(RP2040_ADC_IRQ_FIFO);
|
||||
|
||||
irq_detach(RP2040_ADC_IRQ_FIFO);
|
||||
|
||||
/* Flush the FIFO */
|
||||
|
||||
while (getreg32(RP2040_ADC_FCS) & RP2040_ADC_FCS_LEVEL_MASK)
|
||||
{
|
||||
getreg32(RP2040_ADC_FIFO);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Fetch the data from the FIFO register */
|
||||
|
||||
value = getreg32(RP2040_ADC_FIFO);
|
||||
error_bit_set = (value & RP2040_ADC_FIFO_ERR) != 0;
|
||||
|
||||
/* Shift value to top of signed 32-bit word for upper-halfs benefit. */
|
||||
|
||||
value <<= 19;
|
||||
|
||||
if (error_bit_set)
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
|
||||
for (a_device = g_first_device;
|
||||
a_device != NULL;
|
||||
a_device = PRIV(a_device)->next_device)
|
||||
{
|
||||
a_callback = PRIV(a_device)->callback;
|
||||
|
||||
if (a_callback != NULL && a_callback->au_receive != NULL)
|
||||
{
|
||||
if (PRIV(a_device)->has_channel[g_current_channel])
|
||||
{
|
||||
if (a_callback->au_receive(a_device,
|
||||
g_current_channel,
|
||||
value) != OK)
|
||||
{
|
||||
/* ### TODO ### Upper half buffer overflow */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Start next channel read */
|
||||
|
||||
get_next_channel();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: get_next_channel
|
||||
*
|
||||
* Description:
|
||||
* Update g_current_channel to point to next channel in use and start
|
||||
* the conversion.
|
||||
*
|
||||
* Note: This is called from inside a critical section.
|
||||
****************************************************************************/
|
||||
|
||||
static void get_next_channel(void)
|
||||
{
|
||||
FAR struct adc_dev_s *a_device;
|
||||
uint8_t next = g_current_channel + 1;
|
||||
uint32_t value;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (next >= ADC_CHANNEL_COUNT)
|
||||
{
|
||||
next = 0;
|
||||
}
|
||||
|
||||
for (a_device = g_first_device;
|
||||
a_device != NULL;
|
||||
a_device = PRIV(a_device)->next_device)
|
||||
{
|
||||
if (PRIV(a_device)->has_channel[next])
|
||||
{
|
||||
g_current_channel = next;
|
||||
|
||||
while (getreg32(RP2040_ADC_FCS)
|
||||
& RP2040_ADC_FCS_LEVEL_MASK)
|
||||
{
|
||||
getreg32(RP2040_ADC_FIFO);
|
||||
}
|
||||
|
||||
/* Enable Interrupt on ADC Completion */
|
||||
|
||||
putreg32(RP2040_ADC_INTE_FIFO, RP2040_ADC_INTE);
|
||||
|
||||
/* Configure CS to read one value from current channel */
|
||||
|
||||
value = (g_current_channel << RP2040_ADC_CS_AINSEL_SHIFT)
|
||||
| RP2040_ADC_CS_EN;
|
||||
|
||||
if (g_current_channel == ADC_TEMP_CHANNEL)
|
||||
{
|
||||
value |= RP2040_ADC_CS_TS_ENA;
|
||||
}
|
||||
|
||||
putreg32(value, RP2040_ADC_CS);
|
||||
|
||||
while ((getreg32(RP2040_ADC_CS)
|
||||
& RP2040_ADC_CS_READY) == 0)
|
||||
{
|
||||
/* Wait for ready to go high. The rp2040 docs
|
||||
* say this is only a few clock cycles so we'll
|
||||
* just busy wait.
|
||||
*/
|
||||
}
|
||||
|
||||
/* Start the conversion */
|
||||
|
||||
value += RP2040_ADC_CS_START_ONCE;
|
||||
|
||||
putreg32(value, RP2040_ADC_CS);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we've looped all the way we're in trouble */
|
||||
|
||||
ASSERT(next != g_current_channel);
|
||||
|
||||
/* try another */
|
||||
|
||||
next += 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: add_device
|
||||
*
|
||||
* Description:
|
||||
* This function is called to link the device int the device list.
|
||||
* It also makes sure ADC reads are taking place
|
||||
*
|
||||
* Note: This is called from inside a critical section.
|
||||
****************************************************************************/
|
||||
|
||||
static void add_device(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
g_active_count += 1;
|
||||
|
||||
if (g_first_device != NULL)
|
||||
{
|
||||
PRIV(g_first_device)->prior_device = dev;
|
||||
}
|
||||
|
||||
PRIV(dev)->next_device = g_first_device;
|
||||
PRIV(dev)->prior_device = NULL;
|
||||
|
||||
g_first_device = dev;
|
||||
|
||||
if (PRIV(g_first_device)->next_device == NULL)
|
||||
{
|
||||
/* We just added first device */
|
||||
|
||||
/* Make sure ADC interrupts are disabled */
|
||||
|
||||
putreg32(0, RP2040_ADC_INTE);
|
||||
|
||||
/* Configure FCS to use FIFO and interrupt on first value */
|
||||
|
||||
value = (1 << RP2040_ADC_FCS_THRESH_SHIFT)
|
||||
| RP2040_ADC_FCS_OVER
|
||||
| RP2040_ADC_FCS_UNDER
|
||||
| RP2040_ADC_FCS_ERR
|
||||
| RP2040_ADC_FCS_EN;
|
||||
|
||||
putreg32(value, RP2040_ADC_FCS);
|
||||
|
||||
/* Set up for interrupts */
|
||||
|
||||
irq_attach(RP2040_ADC_IRQ_FIFO, interrupt_handler, NULL);
|
||||
|
||||
up_enable_irq(RP2040_ADC_IRQ_FIFO);
|
||||
|
||||
/* Start conversions on first required channel. */
|
||||
|
||||
get_next_channel();
|
||||
|
||||
ainfo("new cur %d\n", g_current_channel);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: remove_device
|
||||
*
|
||||
* Description:
|
||||
* This function is called to unlink the device from the device list.
|
||||
*
|
||||
* Note: This is called from inside a critical section.
|
||||
****************************************************************************/
|
||||
|
||||
void remove_device(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
FAR struct adc_dev_s *a_device;
|
||||
|
||||
if (dev == g_first_device)
|
||||
{
|
||||
/* Special handling for first device */
|
||||
|
||||
g_first_device = PRIV(g_first_device)->next_device;
|
||||
|
||||
if (g_first_device != NULL)
|
||||
{
|
||||
PRIV(g_first_device)->prior_device = NULL;
|
||||
}
|
||||
|
||||
g_active_count -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure dev is on the change, and unlink if it is. */
|
||||
|
||||
for (a_device = g_first_device;
|
||||
a_device != NULL;
|
||||
a_device = PRIV(a_device)->next_device)
|
||||
{
|
||||
if (a_device == dev)
|
||||
{
|
||||
PRIV(PRIV(dev)->prior_device)->next_device =
|
||||
PRIV(dev)->next_device;
|
||||
|
||||
PRIV(PRIV(dev)->next_device)->prior_device =
|
||||
PRIV(dev)->prior_device;
|
||||
|
||||
g_active_count -= 1;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: my_bind
|
||||
*
|
||||
* Description:
|
||||
* This function is called when a driver is registered. It give us a
|
||||
* chance to bind the upper-half callbacks to our private data structure so
|
||||
* they can be accessed later.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int my_bind(struct adc_dev_s *dev,
|
||||
const struct adc_callback_s *callback)
|
||||
{
|
||||
DEBUGASSERT(PRIV(dev) != NULL);
|
||||
|
||||
ainfo("entered\n");
|
||||
|
||||
PRIV(dev)->callback = callback;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: my_reset
|
||||
*
|
||||
* Description:
|
||||
* This is called by the upper-half as part of the driver registration
|
||||
* process. The upper half documentation also claims that it may
|
||||
* be called as part of an error condition.
|
||||
*
|
||||
* Set the pin for the ADC's to standard GPIO input with no pulls.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void my_reset(struct adc_dev_s *dev)
|
||||
{
|
||||
int a_gpio;
|
||||
|
||||
ainfo("entered\n");
|
||||
|
||||
for (int i = 0; i < ADC_CHANNEL_COUNT; ++i)
|
||||
{
|
||||
a_gpio = g_gpio_map[i];
|
||||
|
||||
if (a_gpio >= 0)
|
||||
{
|
||||
rp2040_gpio_setdir(a_gpio, false);
|
||||
rp2040_gpio_set_function(a_gpio, RP2040_GPIO_FUNC_NULL);
|
||||
rp2040_gpio_set_pulls(a_gpio, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: my_setup
|
||||
*
|
||||
* Description:
|
||||
* This is called when a particular ADC driver is first opened.
|
||||
*
|
||||
* We don't do anything here.
|
||||
*
|
||||
* Note: This is called from inside a critical section.
|
||||
****************************************************************************/
|
||||
|
||||
static int my_setup(struct adc_dev_s *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ainfo("entered: 0x%08lX\n", dev);
|
||||
|
||||
/* Note: We check g_active_count here so we can return an error
|
||||
* in the, probably impossible, case we have too many.
|
||||
*/
|
||||
|
||||
if (g_active_count >= 200)
|
||||
{
|
||||
aerr("Too many active devices.");
|
||||
ret = -EBUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: my_shutdown
|
||||
*
|
||||
* Description:
|
||||
* This is called to shutdown an ADC device. It unlinks the
|
||||
* device from out local chain and turns off ADC interrupts if no
|
||||
* more devices are active.
|
||||
*
|
||||
* Note: This is called from inside a critical section.
|
||||
****************************************************************************/
|
||||
|
||||
static void my_shutdown(FAR struct adc_dev_s *dev)
|
||||
{
|
||||
ainfo("entered: 0x%08lX\n", dev);
|
||||
|
||||
/* Remove adc_dev_s structure from the list */
|
||||
|
||||
remove_device(dev);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: my_rxint
|
||||
*
|
||||
* Description:
|
||||
* Call to enable or disable ADC RX interrupts
|
||||
*
|
||||
* Note: This is called from inside a critical section.
|
||||
****************************************************************************/
|
||||
|
||||
static void my_rxint(struct adc_dev_s *dev, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
ainfo("entered: enable: 0x%08lX\n", dev);
|
||||
|
||||
add_device(dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
ainfo("entered: disable: 0x%08lX\n", dev);
|
||||
|
||||
remove_device(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: my_ioctl
|
||||
*
|
||||
* Description:
|
||||
* All ioctl calls will be routed through this method
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int my_ioctl(struct adc_dev_s *dev,
|
||||
int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
/* No ioctl commands supported */
|
||||
|
||||
ainfo("entered\n");
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ADC
|
||||
|
||||
/****************************************************************************
|
||||
* Name: my_setup
|
||||
*
|
||||
* Description:
|
||||
* Initialize and register the ADC driver.
|
||||
*
|
||||
* Input Parameters:
|
||||
* path - Path to the ws2812 device (e.g. "/dev/adc0")
|
||||
* read_adc0 - This device reads ADC0
|
||||
* read_adc1 - This device reads ADC1
|
||||
* read_adc2 - This device reads ADC3
|
||||
* read_adc3 - This device reads ADC4
|
||||
* read_temp - This device reads the chip temperature.
|
||||
*
|
||||
* Returned Value:
|
||||
* An opaque pointer that can be passed to rp2040_adc_release on
|
||||
* success or NULL (with errno set) on failure
|
||||
****************************************************************************/
|
||||
|
||||
int rp2040_adc_setup(FAR const char *path,
|
||||
bool read_adc0,
|
||||
bool read_adc1,
|
||||
bool read_adc2,
|
||||
bool read_adc3,
|
||||
bool read_temp)
|
||||
{
|
||||
FAR struct adc_dev_s *dev;
|
||||
FAR struct private_s *priv;
|
||||
int ret;
|
||||
|
||||
ainfo("entered\n");
|
||||
|
||||
if (!read_adc0 && !read_adc1 && !read_adc2 && !read_adc3 && !read_temp)
|
||||
{
|
||||
aerr("No ADC inputs selected.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = kmm_zalloc(sizeof(struct adc_dev_s));
|
||||
|
||||
if (dev == NULL)
|
||||
{
|
||||
aerr("Failed to allocate adc_dev_s.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct private_s));
|
||||
|
||||
if (priv == NULL)
|
||||
{
|
||||
aerr("Failed to allocate private_s.\n");
|
||||
kmm_free(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->has_channel[0] = read_adc0;
|
||||
priv->has_channel[1] = read_adc1;
|
||||
priv->has_channel[2] = read_adc2;
|
||||
priv->has_channel[3] = read_adc3;
|
||||
priv->has_channel[4] = read_temp;
|
||||
|
||||
dev->ad_ops = &g_adcops;
|
||||
dev->ad_priv = priv;
|
||||
|
||||
ret = adc_register(path, dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* if CONFIG_ADC */
|
||||
#endif /* if CONFIG_RP2040_ADC */
|
108
arch/arm/src/rp2040/rp2040_adc.h
Normal file
108
arch/arm/src/rp2040/rp2040_adc.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/rp2040_adc.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Note:
|
||||
* The ADC driver upper-half returns signed values of up to 32-bits to
|
||||
* the user and expects the high-order bits in any result to be
|
||||
* significant. So, while the RP2040 hardware returns an unsigned value
|
||||
* in the low-order 12 bits of the result register, we shift this
|
||||
* value to the high-order bits.
|
||||
*
|
||||
* The result is that to convert a 32-bit value returned from the ADC
|
||||
* driver, you should use V = ADC_AVDD * value / (2^31) where ADC_AVDD
|
||||
* is the analogue reference voltage supplied to the RP2040 chip. If
|
||||
* 8 or 16 bit values are returned the divisor would be (2^15) or (2^7)
|
||||
* respectively.
|
||||
*
|
||||
* Also, if the conversion error bit was set for a particular sample,
|
||||
* the return value will be negated. Any negative return value should
|
||||
* be treated as erroneous.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_RP2040_RP2040_ADC_H
|
||||
#define __ARCH_ARM_SRC_RP2040_RP2040_ADC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <debug.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RP2040_ADC
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ADC
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_adc_setup
|
||||
*
|
||||
* Description:
|
||||
* Initialize and register the ADC driver.
|
||||
*
|
||||
* Input Parameters:
|
||||
* path - Path to the ws2812 device (e.g. "/dev/adc0")
|
||||
* read_adc0 - This device reads ADC0
|
||||
* read_adc1 - This device reads ADC1
|
||||
* read_adc2 - This device reads ADC3
|
||||
* read_adc3 - This device reads ADC4
|
||||
* read_temp - This device reads the chip temperature.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success or an ERROR on failure
|
||||
****************************************************************************/
|
||||
|
||||
int rp2040_adc_setup(FAR const char *path,
|
||||
bool read_adc0,
|
||||
bool read_adc1,
|
||||
bool read_adc2,
|
||||
bool read_adc3,
|
||||
bool read_temp);
|
||||
|
||||
#else /* CONFIG_ADC */
|
||||
|
||||
/* ### TODO ### Add programmatic access function. */
|
||||
|
||||
#endif /* CONFIG_ADC */
|
||||
|
||||
#endif /* CONFIG_RP2040_ADC */
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_RP2040_ADC_H */
|
|
@ -92,4 +92,4 @@ int rp2040_ws2812_release(FAR void * driver);
|
|||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_RP2040_I2C_H */
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_RP2040_WS2812_H */
|
||||
|
|
|
@ -3510,6 +3510,9 @@ endif
|
|||
if ARCH_CHIP_STM32
|
||||
source "boards/arm/stm32/common/Kconfig"
|
||||
endif
|
||||
if ARCH_CHIP_RP2040
|
||||
source "boards/arm/rp2040/common/Kconfig"
|
||||
endif
|
||||
endif
|
||||
|
||||
config BOARD_CRASHDUMP
|
||||
|
|
|
@ -14,6 +14,7 @@ Currently only the following devices are supported.
|
|||
- SPI
|
||||
- DMAC
|
||||
- PWM
|
||||
- ADC
|
||||
- USB device
|
||||
- MSC, CDC/ACM serial and these composite device are supported.
|
||||
- CDC/ACM serial device can be used for the console.
|
||||
|
|
|
@ -74,6 +74,10 @@
|
|||
#define HAS_WHITE false
|
||||
#endif /* CONFIG_WS2812_HAS_WHITE */
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
#include "rp2040_adc.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -462,5 +466,46 @@ int rp2040_bringup(void)
|
|||
HAS_WHITE);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL0
|
||||
# define ADC_0 true
|
||||
# else
|
||||
# define ADC_0 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL1
|
||||
# define ADC_1 true
|
||||
# else
|
||||
# define ADC_1 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL2
|
||||
# define ADC_2 true
|
||||
# else
|
||||
# define ADC_2 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL3
|
||||
# define ADC_3 true
|
||||
# else
|
||||
# define ADC_3 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_TEMPERATURE
|
||||
# define ADC_TEMP true
|
||||
# else
|
||||
# define ADC_TEMP false
|
||||
# endif
|
||||
|
||||
ret = rp2040_adc_setup("/dev/adc0", ADC_0, ADC_1, ADC_2, ADC_3, ADC_TEMP);
|
||||
if (ret != OK)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to initialize ADC Driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC) */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ Currently only the following devices are supported.
|
|||
- SPI
|
||||
- DMAC
|
||||
- PWM
|
||||
- ADC
|
||||
- USB device
|
||||
- MSC, CDC/ACM serial and these composite device are supported.
|
||||
- CDC/ACM serial device can be used for the console.
|
||||
|
|
|
@ -74,6 +74,10 @@
|
|||
#define HAS_WHITE false
|
||||
#endif /* CONFIG_WS2812_HAS_WHITE */
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
#include "rp2040_adc.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -462,5 +466,46 @@ int rp2040_bringup(void)
|
|||
HAS_WHITE);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL0
|
||||
# define ADC_0 true
|
||||
# else
|
||||
# define ADC_0 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL1
|
||||
# define ADC_1 true
|
||||
# else
|
||||
# define ADC_1 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL2
|
||||
# define ADC_2 true
|
||||
# else
|
||||
# define ADC_2 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL3
|
||||
# define ADC_3 true
|
||||
# else
|
||||
# define ADC_3 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_TEMPERATURE
|
||||
# define ADC_TEMP true
|
||||
# else
|
||||
# define ADC_TEMP false
|
||||
# endif
|
||||
|
||||
ret = rp2040_adc_setup("/dev/adc0", ADC_0, ADC_1, ADC_2, ADC_3, ADC_TEMP);
|
||||
if (ret != OK)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to initialize ADC Driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC) */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
54
boards/arm/rp2040/common/Kconfig
Normal file
54
boards/arm/rp2040/common/Kconfig
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
if ARCH_BOARD_RASPBERRYPI_PICO
|
||||
|
||||
config RP2040_ADC
|
||||
bool "Enable ADC Support"
|
||||
default n
|
||||
---help---
|
||||
If y, the RP2040 ADC code will be built. For ADC device driver
|
||||
support you must also select "Analog-to-Digital Conversion"
|
||||
under the "Device Driver/Analog Device Support" menu.
|
||||
|
||||
If the ADC device driver is not built, basic functions
|
||||
to programatically access the ADC ports will be added.
|
||||
|
||||
if RP2040_ADC && ADC
|
||||
|
||||
config RPC2040_ADC_CHANNEL0
|
||||
bool "Read ADC channel 0"
|
||||
default n
|
||||
---help---
|
||||
If y, then ADC0 will be read.
|
||||
|
||||
config RPC2040_ADC_CHANNEL1
|
||||
bool "Read ADC channel 1"
|
||||
default n
|
||||
---help---
|
||||
If y, then ADC1 will be read.
|
||||
|
||||
config RPC2040_ADC_CHANNEL2
|
||||
bool "Read ADC channel 2"
|
||||
default n
|
||||
---help---
|
||||
If y, then ADC2 will be read.
|
||||
|
||||
config RPC2040_ADC_CHANNEL3
|
||||
bool "Read ADC channel 3"
|
||||
default n
|
||||
---help---
|
||||
If y, then ADC3 will be read.
|
||||
|
||||
config RPC2040_ADC_TEMPERATURE
|
||||
bool "Read ADC chip temperature channel"
|
||||
default n
|
||||
---help---
|
||||
If y, then the ADC chip temperature
|
||||
will be read.
|
||||
|
||||
endif
|
||||
|
||||
endif
|
|
@ -17,6 +17,7 @@ Currently only the following devices are supported.
|
|||
- SPI
|
||||
- DMAC
|
||||
- PWM
|
||||
- ADC
|
||||
- USB device
|
||||
- MSC, CDC/ACM serial and these composite device are supported.
|
||||
- CDC/ACM serial device can be used for the console.
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
#include "rp2040_pwmdev.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
#include "rp2040_adc.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RP2040_BOARD_HAS_WS2812) && defined(CONFIG_WS2812)
|
||||
#include "rp2040_ws2812.h"
|
||||
#endif
|
||||
|
@ -408,6 +412,49 @@ int rp2040_bringup(void)
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/* Initialize ADC */
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL0
|
||||
# define ADC_0 true
|
||||
# else
|
||||
# define ADC_0 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL1
|
||||
# define ADC_1 true
|
||||
# else
|
||||
# define ADC_1 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL2
|
||||
# define ADC_2 true
|
||||
# else
|
||||
# define ADC_2 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL3
|
||||
# define ADC_3 true
|
||||
# else
|
||||
# define ADC_3 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_TEMPERATURE
|
||||
# define ADC_TEMP true
|
||||
# else
|
||||
# define ADC_TEMP false
|
||||
# endif
|
||||
|
||||
ret = rp2040_adc_setup("/dev/adc0", ADC_0, ADC_1, ADC_2, ADC_3, ADC_TEMP);
|
||||
if (ret != OK)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to initialize ADC Driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC) */
|
||||
|
||||
/* Initialize board neo-pixel */
|
||||
|
||||
#if defined(CONFIG_RP2040_BOARD_HAS_WS2812) && defined(CONFIG_WS2812)
|
||||
|
|
|
@ -14,6 +14,7 @@ Currently only the following devices are supported.
|
|||
- SPI
|
||||
- DMAC
|
||||
- PWM
|
||||
- ADC
|
||||
- USB device
|
||||
- MSC, CDC/ACM serial and these composite device are supported.
|
||||
- CDC/ACM serial device can be used for the console.
|
||||
|
|
|
@ -64,6 +64,10 @@
|
|||
#include "rp2040_pwmdev.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
#include "rp2040_adc.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RP2040_BOARD_HAS_WS2812) && defined(CONFIG_WS2812)
|
||||
#include "rp2040_ws2812.h"
|
||||
#endif
|
||||
|
@ -487,6 +491,49 @@ int rp2040_bringup(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Initialize ADC */
|
||||
|
||||
#if defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC)
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL0
|
||||
# define ADC_0 true
|
||||
# else
|
||||
# define ADC_0 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL1
|
||||
# define ADC_1 true
|
||||
# else
|
||||
# define ADC_1 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL2
|
||||
# define ADC_2 true
|
||||
# else
|
||||
# define ADC_2 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_CHANNEL3
|
||||
# define ADC_3 true
|
||||
# else
|
||||
# define ADC_3 false
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_RPC2040_ADC_TEMPERATURE
|
||||
# define ADC_TEMP true
|
||||
# else
|
||||
# define ADC_TEMP false
|
||||
# endif
|
||||
|
||||
ret = rp2040_adc_setup("/dev/adc0", ADC_0, ADC_1, ADC_2, ADC_3, ADC_TEMP);
|
||||
if (ret != OK)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to initialize ADC Driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_ADC) && defined(CONFIG_RP2040_ADC) */
|
||||
|
||||
/* Initialize board neo-pixel */
|
||||
|
||||
#if defined(CONFIG_RP2040_BOARD_HAS_WS2812) && defined(CONFIG_WS2812)
|
||||
|
|
|
@ -148,14 +148,14 @@ static int adc_open(FAR struct file *filep)
|
|||
/* Finally, Enable the ADC RX interrupt */
|
||||
|
||||
dev->ad_ops->ao_rxint(dev, true);
|
||||
|
||||
/* Save the new open count on success */
|
||||
|
||||
dev->ad_ocount = tmp;
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/* Save the new open count on success */
|
||||
|
||||
dev->ad_ocount = tmp;
|
||||
}
|
||||
|
||||
nxsem_post(&dev->ad_closesem);
|
||||
|
|
Loading…
Reference in a new issue