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

Add analog support for RP2040 #19453

merged 8 commits into from
Jan 18, 2023

Conversation

sigprof
Copy link
Contributor

@sigprof sigprof commented Dec 31, 2022

Description

Add analog support for RP2040.

The low-level driver is already present in ChibiOS-Contrib, but the fix from ChibiOS/ChibiOS-Contrib#355 is required to make it actually work; without that fix the code will compile, but adc_read() will work only once (on the second call it will lockup).

TODO:

  • Add RP_IRQ_ADC1_PRIORITY to the default mcuconf.h files.
  • Update documentation for the supported pins and driver configuration options.

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Keyboard (addition or update)
  • Keymap/layout/userspace (addition or update)
  • Documentation

Checklist

  • My code follows the code style of this project: C, Python
  • I have read the PR Checklist document and have made the appropriate changes.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

@KarlK90
Copy link
Member

KarlK90 commented Jan 13, 2023

With #17915 being merged to develop the ADC fixes are now available in QMK 🎉.

The ADCv2 bodge defined `ADC_CFGR1_RES_10BIT` and other similar
constants, so that the same code as on STM32 could be used.
@sigprof sigprof marked this pull request as ready for review January 15, 2023 22:15
@sigprof
Copy link
Contributor Author

sigprof commented Jan 15, 2023

The joystick code also builds and works with the fix from #19602.

The temperature sensor could be read with adc_read(TO_MUX(4, 0)), but the results are not really precise (the datasheet says that the precision greatly depends on the reference voltage, which in most cases is generated by some LDO not intended to be used as an analog reference). However, the sensor needs to be enabled by adcRPEnableTS(&ADCD1);, and that call works only after the ADC initialization (e.g., after a dummy adc_read()). Because the sensor has some non-zero power consumption, and probably nobody would actually want to use it, that initialization is left to the user.

@drashna drashna requested review from KarlK90 and a team January 16, 2023 09:33
Also change the priority from 2 to 3 to match the ChibiOS tests.
@sigprof
Copy link
Contributor Author

sigprof commented Jan 16, 2023

I changed the priority to 3 to match the value used by ChibiOS tests:

lib/chibios-contrib/testhal/RP/RP2040/RT-RP2040-PICO-ADC/cfg/mcuconf.h:#define RP_IRQ_ADC1_PRIORITY                3
lib/chibios-contrib/testhal/RP/RP2040/RT-RP2040-PICO-I2C-24AA01/cfg/mcuconf.h:#define RP_IRQ_ADC1_PRIORITY                3
platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h:#define RP_IRQ_ADC1_PRIORITY                3
platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h:#define RP_IRQ_ADC1_PRIORITY                3
platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h:#define RP_IRQ_ADC1_PRIORITY                3

This should still work, but I can't actually test this at the moment.

docs/adc_driver.md Outdated Show resolved Hide resolved
docs/adc_driver.md Outdated Show resolved Hide resolved
@tzarc
Copy link
Member

tzarc commented Jan 16, 2023

This should still work, but I can't actually test this at the moment.

Works fine.

Copy link
Member

@KarlK90 KarlK90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update the rp2040 platform dev line about the ADC driver? https://github.com/qmk/qmk_firmware/blob/master/docs/platformdev_rp2040.md#L7 The other changes LGTM.

@sigprof
Copy link
Contributor Author

sigprof commented Jan 17, 2023

Also I suppose that the QMK_PM2040 board should now have RP_ADC_USE_ADC1 and HAL_USE_ADC enabled for the benefit of converters?

What about the GENERIC_PROMICRO_RP2040 board (which is apparently the default one selected for "processor": "RP2040")? Apparently that board now has RP_SIO_USE_UART0, RP_SPI_USE_SPI0, RP_I2C_USE_I2C1 enabled, but the corresponding HAL options are not enabled anywhere; it probably should have RP_ADC_USE_ADC1 enabled too?

@sigprof
Copy link
Contributor Author

sigprof commented Jan 17, 2023

Looks like it is possible to get something like qmk compile -kb handwired/onekey/promicro -km adc -e CONVERT_TO=elite_pi to build, but it requires an additional change to analog.c, because the GPxx defines are not available when a converter is used:

diff --git a/platforms/chibios/drivers/analog.c b/platforms/chibios/drivers/analog.c
index 84ca99be3c..a8ce21bb6d 100644
--- a/platforms/chibios/drivers/analog.c
+++ b/platforms/chibios/drivers/analog.c
@@ -241,10 +241,10 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
         // 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 GP26: return TO_MUX(0, 0);
-        case GP27: return TO_MUX(1, 0);
-        case GP28: return TO_MUX(2, 0);
-        case GP29: return TO_MUX(3, 0);
+        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
     }

Would this be acceptable? (If it would, then the STM32 cases above should probably be changed to use something like PAL_LINE(GPIOA, 0) too.)

@sigprof
Copy link
Contributor Author

sigprof commented Jan 17, 2023

The converter support overrides _pin_defs.h with the converter version that defines only the pin names for the source MCU, so the pin names for the conversion target MCU are not available (and in general they may even conflict with the pin names for the source MCU, so there is no way to get them both). So apparently if the driver code needs to refer to some specific target MCU pins (as is the case for pinToMux() in the ADC driver), the only option to make that kind of code work with converters is to use something else instead of the QMK pin names.

Most other drivers don't have this problem, because the pin names are passed externally in defines (which, BTW, would contain the source pin names in case a converter is used), and the only places where explicit pin names are used in the driver code are some defaults which the converters override anyway.

According to docs/platformdev_rp2040.md, the `GENERIC_PROMICRO_RP2040`
board should enable the peripherals that match the Sparkfun Pro Micro
RP2040 pinout in `mcuconf.h`, but leave the corresponding options in
`halconf.h` disabled (so the options that enable the peripherals don't
actually do anything in the default state, but just enabling the options
in `halconf.h` is enough to make the Pro Micro compatible peripherals
work).  Make the ADC feature behave the same way: enable the
`RP_ADC_USE_ADC1` option in the board config, so that just enabling
`HAL_USE_ADC` would be enough to use the ADC.

After this change the `handwired/onekey/rp2040` keyboard no longer needs
the ADC configuration in `mcuconf.h`, so it is removed again.
With this change keyboards using Pro Micro or Elite-C that were also
using analog input on the F4…F7 pins could work with RP2040-based
converters that map the GP26…GP29 pins to the same locations.
Unfortulately, some keyboards could be using analog input on other pins
(the Pro Micro pinout has 9 pins which support analog input on
ATmega32U4, and the Elite-C pinout adds 2 more such pins, but RP2040 has
only 4 analog pins), and those keyboards won't work with RP2040-based
controllers, but that problem won't be detected at compile time (ADC
reads for unsupported pins would just return 0 at runtime).

The `analog.c` code needs to be changed to use raw pin numbers instead
of the `GPxx` defines, because those defines are not available when
using a converter.
@KarlK90
Copy link
Member

KarlK90 commented Jan 17, 2023

Also I suppose that the QMK_PM2040 board should now have RP_ADC_USE_ADC1 and HAL_USE_ADC enabled for the benefit of converters?

To be inline with the expectation that a converter "just works" this should be done.

What about the GENERIC_PROMICRO_RP2040 board (which is apparently the default one selected for "processor": "RP2040")? Apparently that board now has RP_SIO_USE_UART0, RP_SPI_USE_SPI0, RP_I2C_USE_I2C1 enabled, but the corresponding HAL options are not enabled anywhere; it probably should have RP_ADC_USE_ADC1 enabled too?

Yes, I think the ADC peripheral should be enabled as well without activating the HAL driver.

@KarlK90
Copy link
Member

KarlK90 commented Jan 17, 2023

The whole analog.c/adc handling could probably see a overhaul, but I think the way it is handled in the scope of RP2040 support is fine for now.

@tzarc
Copy link
Member

tzarc commented Jan 17, 2023

The whole analog.c/adc handling could probably see a overhaul, but I think the way it is handled in the scope of RP2040 support is fine for now.

It's been ripe for replacing SRC += analog.c with ANALOG_ENABLE = yes for quite some time. Adding the defines for enabling board-specific ADCs at that point would be relatively trivial.

@zvecr
Copy link
Member

zvecr commented Jan 18, 2023

From my perspective, I dont care too much if converters fail. Long term it would be expected to work, but it shouldnt be a blocker for getting ADC support in.

@sigprof
Copy link
Contributor Author

sigprof commented Jan 18, 2023

Actually the converters should work with the latest code here. The only issue is that some keyboards may use analog inputs on Pro Micro/Elite-C pins outside of the F4F7 range, and compiling that code with CONVERT_TO=some_rp2040_controller would silently give a broken firmware, because the unsupported pin usage could be detected only at runtime. But I don't see any good way around that (even if we add some analogReadPin() wrapper using __builtin_constant_p() to have a compile time check if the argument is constant, that won't help in cases when the pin is passed indirectly, such as when using the joystick feature). Maybe that's a mostly theoretical issue though (apparently all existing boards that use the joystick feature use pins from the F4F7 range, and boards that use other pins might actually be using a custom PCB, not a replaceable controller).

@KarlK90
Copy link
Member

KarlK90 commented Jan 18, 2023

So this sounds like the PR is ready to go in?! The refactoring should be done in a separate PR imho.

@tzarc tzarc merged commit 272281f into qmk:develop Jan 18, 2023
@tzarc
Copy link
Member

tzarc commented Jan 18, 2023

Can iterate on later PRs if required.

omikronik pushed a commit to omikronik/qmk_firmware that referenced this pull request Jan 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants