Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/rpx0xx: add initial ADC support #19516

Merged
merged 4 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/rpi-pico/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ config BOARD_RPI_PICO
bool
default y
select CPU_MODEL_RP2040
select HAS_PERIPH_ADC
select HAS_PERIPH_UART

select HAVE_SAUL_GPIO
1 change: 1 addition & 0 deletions boards/rpi-pico/Makefile.features
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
CPU := rpx0xx

# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart
15 changes: 15 additions & 0 deletions boards/rpi-pico/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ static const timer_conf_t timer_config[] = {

#define TIMER_NUMOF ARRAY_SIZE(timer_config)

/**
* @name ADC configuration
*
* The configuration consists simply of a list of channels that should be used
* @{
*/
static const adc_conf_t adc_config[] = {
{ .pin = GPIO_PIN(0, 26), .chan = 0},
{ .pin = GPIO_PIN(0, 27), .chan = 1},
{ .pin = GPIO_PIN(0, 28), .chan = 2},
};

#define ADC_NUMOF ARRAY_SIZE(adc_config)
/** @} */

#ifdef __cplusplus
}
#endif
Expand Down
14 changes: 14 additions & 0 deletions cpu/rpx0xx/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,17 @@ void clock_gpout3_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT3_CTR
io_reg_atomic_set(&PADS_BANK0->GPIO25, 1U << PADS_BANK0_GPIO25_IE_Pos);
gpio_set_function_select(25, FUNCTION_SELECT_CLOCK);
}

void clock_adc_configure(CLOCKS_CLK_ADC_CTRL_AUXSRC_Enum aux)
{
/* Stop the clock generator */
io_reg_atomic_clear(&CLOCKS->CLK_ADC_CTRL,
(1u << CLOCKS_CLK_ADC_CTRL_ENABLE_Pos));
/* Selects the new auxiliary clock source */
io_reg_write_dont_corrupt(&CLOCKS->CLK_ADC_CTRL,
aux << CLOCKS_CLK_ADC_CTRL_AUXSRC_Pos,
CLOCKS_CLK_ADC_CTRL_AUXSRC_Msk);
/* Restart the clock generator */
io_reg_atomic_set(&CLOCKS->CLK_ADC_CTRL,
(1u << CLOCKS_CLK_ADC_CTRL_ENABLE_Pos));
}
8 changes: 8 additions & 0 deletions cpu/rpx0xx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static void _cpu_reset(void)
| RESETS_RESET_pll_usb_Msk
| RESETS_RESET_pll_sys_Msk
| RESETS_RESET_pads_qspi_Msk
| RESETS_RESET_pads_bank0_Msk
| RESETS_RESET_io_qspi_Msk);
periph_reset(rst);
/* Assert that reset has completed except for those components which
Expand Down Expand Up @@ -78,6 +79,13 @@ static void _cpu_reset(void)
clock_gpout0_configure(CLOCK_XOSC, CLOCK_XOSC,
CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_clk_ref);
}

/* Configure USB PLL to deliver 48MHz needed by ADC */
if (IS_USED(MODULE_PERIPH_ADC)) {
pll_start_usb(PLL_USB_REF_DIV, PLL_USB_VCO_FEEDBACK_SCALE,
PLL_USB_POSTDIV1, PLL_USB_POSTDIV2);
clock_adc_configure(CLOCKS_CLK_ADC_CTRL_AUXSRC_clksrc_pll_usb);
}
}

void cpu_init(void)
Expand Down
17 changes: 16 additions & 1 deletion cpu/rpx0xx/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,14 @@ typedef struct {
} gpio_io_ctrl_t;
/** @} */

/**
* @brief ADC channel configuration data
*/
typedef struct {
gpio_t pin; /**< Pin connected to the channel */
uint8_t chan; /**< CPU ADC channel connected to the pin */
} adc_conf_t;

/**
* @brief Configuration details for an UART interface needed by the RPX0XX peripheral
*/
Expand Down Expand Up @@ -613,6 +621,13 @@ void clock_gpout2_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT2_CTR
*/
void clock_gpout3_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT3_CTRL_AUXSRC_Enum aux);

/**
* @brief Configure the ADC clock to run from a dedicated auxiliary
* clock source
*
* @param aux Auxiliary clock source
*/
void clock_adc_configure(CLOCKS_CLK_ADC_CTRL_AUXSRC_Enum aux);
/** @} */

/**
Expand All @@ -636,7 +651,7 @@ void pll_start_sys(uint8_t ref_div,
uint8_t post_div_1, uint8_t post_div_2);

/**
* @brief Start the PLL for the system clock
* @brief Start the PLL for the USB clock
* output[MHz] = f_ref / @p ref_div * @p vco_feedback_scale / @p post_div_1 / @p post_div_2
*
* @note Usual setting should be (12 MHz, 1, 40, 5, 2) to get a 48 MHz USB clock signal
Expand Down
97 changes: 97 additions & 0 deletions cpu/rpx0xx/periph/adc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2023 Mesotic SAS
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup cpu_rpx0xx
* @ingroup drivers_periph_adc
* @{
*
* @file
* @brief Low-level ADC driver implementation
*
* @author Dylan Laduranty <dylan.laduranty@mesotic.com>
* @}
*/

#include <errno.h>
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"

/**
* @brief Lock to prevent concurrency issues when used from different threads
*/
static mutex_t lock;

static inline void _prep(void)
{
mutex_lock(&lock);
}

static inline void _done(void)
{
mutex_unlock(&lock);
}

static void _disable_digital_func(gpio_t pin)
{

const gpio_pad_ctrl_t disable_digital_pad = {
.input_enable = 0,
.output_disable = 1,
};

gpio_set_pad_config(pin, disable_digital_pad);
}

int adc_init(adc_t line)
{
if (line >= ADC_NUMOF) {
return -ENODEV;
}
/* Lock mutex for exclusive access */
_prep();
/* Reset ADC peripheral */
periph_reset(RESETS_RESET_adc_Msk);
periph_reset_done(RESETS_RESET_adc_Msk);

/* Enable ADC peripheral and its clock */
io_reg_atomic_set(&ADC->CS, 1 << ADC_CS_EN_Pos);
/* Disable associated GPIO functionality as requested by datasheet */
_disable_digital_func(adc_config[line].pin);
/* Unlock mutex */
_done();
return 0;
}

int32_t adc_sample(adc_t line, adc_res_t res)
{
int val = 0;

/* rpx0xx MCU only supports 12 bits resolution */
if (res != ADC_RES_12BIT) {
return -EINVAL;
}
/* Lock mutex for exclusive access */
_prep();
/* Select the channel */
io_reg_write_dont_corrupt(&ADC->CS, adc_config[line].chan << ADC_CS_AINSEL_Pos,
ADC_CS_AINSEL_Msk);
/* Wait for ADC to be ready */
while (!(ADC->CS & ADC_CS_READY_Msk)) {}
/* Trigger one-shot sample */
io_reg_atomic_set(&ADC->CS, 1 << ADC_CS_START_ONCE_Pos);
/* Wait for completion */
while (!(ADC->CS & ADC_CS_READY_Msk)) {}
/* Get the result */
val = ADC->RESULT & ADC_RESULT_RESULT_Msk;
/* Unlock mutex */
_done();
return val;
}