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

Add analog support for RP2040 #19453

Merged
merged 8 commits into from
Jan 18, 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
17 changes: 17 additions & 0 deletions docs/adc_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Then place this include at the top of your code:

### ARM

#### STM32

Note that some of these pins are doubled-up on ADCs with the same channel. This is because the pins can be used for either ADC.

Also note that the F0 and F3 use different numbering schemes. The F0 has a single ADC and the channels are 0-indexed, whereas the F3 has 4 ADCs and the channels are 1-indexed. This is because the F0 uses the `ADCv1` implementation of the ADC, whereas the F3 uses the `ADCv3` implementation.
Expand Down Expand Up @@ -121,6 +123,21 @@ Also note that the F0 and F3 use different numbering schemes. The F0 has a singl

<sup>² Not all STM32F4xx devices have ADC2 and/or ADC3, therefore some configurations shown in this table may be unavailable; in particular, pins `F4`…`F10` cannot be used as ADC inputs on devices which do not have ADC3. Check the device datasheet to confirm which pin functions are supported.</sup>

#### RP2040

RP2040 has only a single ADC (`ADCD1` in ChibiOS); in the QMK API the index for that ADC is 0.

|Channel|Pin |
|-------|-------------------|
|0 |`GP26` |
|1 |`GP27` |
|2 |`GP28` |
|3 |`GP29` |
|4 |Temperature sensor*|


<sup>* The temperature sensor is disabled by default and needs to be enabled by the RP2040-specific function: `adcRPEnableTS(&ADCD1)`. The ADC must be initialized before calling that function; an easy way to ensure that is to perform a dummy conversion.</sup>

## Functions

### AVR
Expand Down
2 changes: 1 addition & 1 deletion docs/platformdev_rp2040.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The following table shows the current driver status for peripherals on RP2040 MC

| System | Support |
| ---------------------------------------------------------------- | ---------------------------------------------- |
| [ADC driver](adc_driver.md) | Support planned (no ETA) |
| [ADC driver](adc_driver.md) | :heavy_check_mark: |
| [Audio](audio_driver.md#pwm-hardware) | :heavy_check_mark: |
| [Backlight](feature_backlight.md) | :heavy_check_mark: |
| [I2C driver](i2c_driver.md) | :heavy_check_mark: |
Expand Down
2 changes: 2 additions & 0 deletions keyboards/handwired/onekey/rp2040/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@
#define AUDIO_PIN GP16
#define AUDIO_PWM_DRIVER PWMD0
#define AUDIO_PWM_CHANNEL RP2040_PWM_CHANNEL_A

#define ADC_PIN GP26
1 change: 1 addition & 0 deletions keyboards/handwired/onekey/rp2040/halconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@

#define HAL_USE_I2C TRUE
#define HAL_USE_PWM TRUE
#define HAL_USE_ADC TRUE

#include_next <halconf.h>
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#define RP_IRQ_TIMER_ALARM1_PRIORITY 2
#define RP_IRQ_TIMER_ALARM2_PRIORITY 2
#define RP_IRQ_TIMER_ALARM3_PRIORITY 2
#define RP_IRQ_ADC1_PRIORITY 3
#define RP_IRQ_UART0_PRIORITY 3
#define RP_IRQ_UART1_PRIORITY 3
#define RP_IRQ_SPI0_PRIORITY 2
Expand All @@ -57,7 +58,7 @@
/*
* ADC driver system settings.
*/
#define RP_ADC_USE_ADC1 FALSE
#define RP_ADC_USE_ADC1 TRUE

/*
* SIO driver system settings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#define RP_IRQ_TIMER_ALARM1_PRIORITY 2
#define RP_IRQ_TIMER_ALARM2_PRIORITY 2
#define RP_IRQ_TIMER_ALARM3_PRIORITY 2
#define RP_IRQ_ADC1_PRIORITY 3
#define RP_IRQ_UART0_PRIORITY 3
#define RP_IRQ_UART1_PRIORITY 3
#define RP_IRQ_SPI0_PRIORITY 2
Expand Down
1 change: 1 addition & 0 deletions platforms/chibios/boards/QMK_PM2040/configs/halconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#define HAL_USE_ADC TRUE
#define HAL_USE_I2C TRUE
#define HAL_USE_SPI TRUE

Expand Down
3 changes: 2 additions & 1 deletion platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#define RP_IRQ_TIMER_ALARM1_PRIORITY 2
#define RP_IRQ_TIMER_ALARM2_PRIORITY 2
#define RP_IRQ_TIMER_ALARM3_PRIORITY 2
#define RP_IRQ_ADC1_PRIORITY 3
#define RP_IRQ_UART0_PRIORITY 3
#define RP_IRQ_UART1_PRIORITY 3
#define RP_IRQ_SPI0_PRIORITY 2
Expand All @@ -57,7 +58,7 @@
/*
* ADC driver system settings.
*/
#define RP_ADC_USE_ADC1 FALSE
#define RP_ADC_USE_ADC1 TRUE

/*
* SIO driver system settings.
Expand Down
21 changes: 15 additions & 6 deletions platforms/chibios/drivers/analog.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
#endif

#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4 && !WB32_ADC_USE_ADC1
# error "You need to set one of the 'STM32_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
#if !RP_ADC_USE_ADC1 && !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4 && !WB32_ADC_USE_ADC1
# error "You need to set one of the 'xxx_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
#endif

#if STM32_ADC_DUAL_MODE
Expand All @@ -42,7 +42,7 @@
#endif

// BODGE to make v2 look like v1,3 and 4
#ifdef USE_ADCV2
#if defined(USE_ADCV2) || defined(RP2040)
# if !defined(ADC_SMPR_SMP_1P5) && defined(ADC_SAMPLE_3)
# define ADC_SMPR_SMP_1P5 ADC_SAMPLE_3
# define ADC_SMPR_SMP_7P5 ADC_SAMPLE_15
Expand Down Expand Up @@ -74,7 +74,7 @@

/* User configurable ADC options */
#ifndef ADC_COUNT
# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
# if defined(RP2040) || defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
# define ADC_COUNT 1
# elif defined(STM32F3XX)
# define ADC_COUNT 4
Expand Down Expand Up @@ -126,6 +126,8 @@ static ADCConversionGroup adcConversionGroup = {
# endif
.smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
.smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),
#elif defined(RP2040)
// RP2040 does not have any extra config here
#else
.cfgr = ADC_CFGR_CONT | ADC_RESOLUTION,
.smpr = {ADC_SMPR1_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN9(ADC_SAMPLING_RATE), ADC_SMPR2_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN15(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN16(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN17(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN18(ADC_SAMPLING_RATE)},
Expand Down Expand Up @@ -238,6 +240,11 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
case C5: return TO_MUX( ADC_CHANNEL_IN15, 0 );
// STM32F103x[C-G] in 144-pin packages also have analog inputs on F6...F10, but they are on ADC3, and the
// ChibiOS ADC driver for STM32F1xx currently supports only ADC1, therefore these pins are not usable.
#elif defined(RP2040)
case 26U: return TO_MUX(0, 0);
case 27U: return TO_MUX(1, 0);
case 28U: return TO_MUX(2, 0);
case 29U: return TO_MUX(3, 0);
#endif
}

Expand All @@ -248,7 +255,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {

static inline ADCDriver* intToADCDriver(uint8_t adcInt) {
switch (adcInt) {
#if STM32_ADC_USE_ADC1 || WB32_ADC_USE_ADC1
#if RP_ADC_USE_ADC1 || STM32_ADC_USE_ADC1 || WB32_ADC_USE_ADC1
case 0:
return &ADCD1;
#endif
Expand Down Expand Up @@ -296,6 +303,8 @@ int16_t adc_read(adc_mux mux) {
adcConversionGroup.chselr = 1 << mux.input; /*no macro to convert N to ADC_CHSELR_CHSEL1*/
#elif defined(USE_ADCV2)
adcConversionGroup.sqr3 = ADC_SQR3_SQ1_N(mux.input);
#elif defined(RP2040)
adcConversionGroup.channel_mask = 1 << mux.input;
#else
adcConversionGroup.sqr[0] = ADC_SQR1_SQ1_N(mux.input);
#endif
Expand All @@ -310,7 +319,7 @@ int16_t adc_read(adc_mux mux) {
return 0;
}

#ifdef USE_ADCV2
#if defined(USE_ADCV2) || defined(RP2040)
// fake 12-bit -> N-bit scale
return (*sampleBuffer) >> (12 - ADC_RESOLUTION);
#else
Expand Down