aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2021-06-22 21:10:12 -0400
committerKevin O'Connor <kevin@koconnor.net>2021-07-04 10:11:02 -0400
commit59fe8782415718b03eb89dd00f25ed1d6cb1ac32 (patch)
treed324ef31d976634fb2fc3e27c8f10434b79a42f5 /src
parent045bfa4e8d177ca934815dd16fa8700543578328 (diff)
downloadkutter-59fe8782415718b03eb89dd00f25ed1d6cb1ac32.tar.gz
kutter-59fe8782415718b03eb89dd00f25ed1d6cb1ac32.tar.xz
kutter-59fe8782415718b03eb89dd00f25ed1d6cb1ac32.zip
rp2040: Add initial adc support
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src')
-rw-r--r--src/rp2040/Kconfig1
-rw-r--r--src/rp2040/Makefile2
-rw-r--r--src/rp2040/adc.c88
-rw-r--r--src/rp2040/gpio.h8
-rw-r--r--src/rp2040/main.c8
5 files changed, 105 insertions, 2 deletions
diff --git a/src/rp2040/Kconfig b/src/rp2040/Kconfig
index 6375a7ff..3edebc47 100644
--- a/src/rp2040/Kconfig
+++ b/src/rp2040/Kconfig
@@ -6,6 +6,7 @@ config RP2040_SELECT
bool
default y
select HAVE_GPIO
+ select HAVE_GPIO_ADC
select HAVE_GPIO_BITBANGING
select HAVE_STRICT_TIMING
diff --git a/src/rp2040/Makefile b/src/rp2040/Makefile
index 1491b419..4ffecbd1 100644
--- a/src/rp2040/Makefile
+++ b/src/rp2040/Makefile
@@ -13,7 +13,7 @@ CFLAGS_klipper.elf += -T $(OUT)src/rp2040/rp2040_link.ld
$(OUT)klipper.elf: $(OUT)stage2.o $(OUT)src/rp2040/rp2040_link.ld
# Add source files
-src-y += rp2040/main.c rp2040/gpio.c generic/crc16_ccitt.c
+src-y += rp2040/main.c rp2040/gpio.c rp2040/adc.c generic/crc16_ccitt.c
src-y += generic/armcm_boot.c generic/armcm_irq.c generic/armcm_reset.c
src-y += generic/timer_irq.c rp2040/timer.c
src-$(CONFIG_SERIAL) += rp2040/serial.c generic/serial_irq.c
diff --git a/src/rp2040/adc.c b/src/rp2040/adc.c
new file mode 100644
index 00000000..2daf380a
--- /dev/null
+++ b/src/rp2040/adc.c
@@ -0,0 +1,88 @@
+// ADC functions on rp2040
+//
+// Copyright (C) 2021 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "board/misc.h" // timer_from_us
+#include "command.h" // shutdown
+#include "gpio.h" // gpio_adc_setup
+#include "hardware/structs/adc.h" // adc_hw
+#include "hardware/structs/padsbank0.h" // padsbank0_hw
+#include "hardware/structs/resets.h" // RESETS_RESET_ADC_BITS
+#include "internal.h" // enable_pclock
+#include "sched.h" // sched_shutdown
+
+DECL_CONSTANT("ADC_MAX", 4095);
+
+#define ADC_TEMPERATURE_PIN 0xfe
+DECL_ENUMERATION("pin", "ADC_TEMPERATURE", ADC_TEMPERATURE_PIN);
+
+struct gpio_adc
+gpio_adc_setup(uint32_t pin)
+{
+ if ((pin < 26 || pin > 29) && pin != ADC_TEMPERATURE_PIN)
+ shutdown("Not a valid ADC pin");
+
+ // Enable the ADC
+ if (!is_enabled_pclock(RESETS_RESET_ADC_BITS)) {
+ enable_pclock(RESETS_RESET_ADC_BITS);
+ adc_hw->cs = ADC_CS_EN_BITS;
+ }
+
+ uint8_t chan;
+ if (pin == ADC_TEMPERATURE_PIN) {
+ chan = 4;
+ adc_hw->cs |= ADC_CS_TS_EN_BITS;
+ } else {
+ chan = pin - 26;
+ padsbank0_hw->io[pin] = PADS_BANK0_GPIO0_OD_BITS;
+ }
+
+ return (struct gpio_adc){ .chan = chan };
+}
+
+enum { ADC_DUMMY=0xff };
+static uint8_t last_analog_read = ADC_DUMMY;
+
+// Try to sample a value. Returns zero if sample ready, otherwise
+// returns the number of clock ticks the caller should wait before
+// retrying this function.
+uint32_t
+gpio_adc_sample(struct gpio_adc g)
+{
+ uint32_t cs = adc_hw->cs;
+ if (!(cs & ADC_CS_READY_BITS))
+ // ADC is busy
+ goto need_delay;
+ if (last_analog_read == g.chan)
+ // Sample now ready
+ return 0;
+ if (last_analog_read != ADC_DUMMY)
+ // Sample on another channel in progress
+ goto need_delay;
+
+ // Begin sample
+ last_analog_read = g.chan;
+ adc_hw->cs = ((cs & ADC_CS_TS_EN_BITS) | ADC_CS_START_ONCE_BITS
+ | ADC_CS_EN_BITS | (g.chan << ADC_CS_AINSEL_LSB));
+
+need_delay:
+ return timer_from_us(5); // Sample takes 2us but provide extra time
+}
+
+// Read a value; use only after gpio_adc_sample() returns zero
+uint16_t
+gpio_adc_read(struct gpio_adc g)
+{
+ last_analog_read = ADC_DUMMY;
+ return adc_hw->result;
+}
+
+// Cancel a sample that may have been started with gpio_adc_sample()
+void
+gpio_adc_cancel_sample(struct gpio_adc g)
+{
+ if (last_analog_read == g.chan)
+ last_analog_read = ADC_DUMMY;
+}
diff --git a/src/rp2040/gpio.h b/src/rp2040/gpio.h
index 0f8507bd..50b6302c 100644
--- a/src/rp2040/gpio.h
+++ b/src/rp2040/gpio.h
@@ -19,4 +19,12 @@ struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
void gpio_in_reset(struct gpio_in g, int8_t pull_up);
uint8_t gpio_in_read(struct gpio_in g);
+struct gpio_adc {
+ uint8_t chan;
+};
+struct gpio_adc gpio_adc_setup(uint32_t pin);
+uint32_t gpio_adc_sample(struct gpio_adc g);
+uint16_t gpio_adc_read(struct gpio_adc g);
+void gpio_adc_cancel_sample(struct gpio_adc g);
+
#endif // gpio.h
diff --git a/src/rp2040/main.c b/src/rp2040/main.c
index 35e4f55d..7b36856a 100644
--- a/src/rp2040/main.c
+++ b/src/rp2040/main.c
@@ -42,6 +42,7 @@ DECL_INIT(watchdog_init);
#define FREQ_XOSC 12000000
#define FREQ_SYS 125000000
+#define FREQ_USB 48000000
void
enable_pclock(uint32_t reset_bit)
@@ -126,8 +127,13 @@ clock_setup(void)
while (!(csys->selected & (1 << 1)))
;
- // Setup clk_peri
+ // Setup pll_usb
+ enable_pclock(RESETS_RESET_PLL_USB_BITS);
+ pll_setup(pll_usb_hw, 40, 40*FREQ_XOSC/FREQ_USB);
+
+ // Setup clk_peri and clk_adc
clk_aux_setup(clk_peri, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS);
+ clk_aux_setup(clk_adc, CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB);
// Enable watchdog tick (at 12Mhz)
cref->div = 1<<CLOCKS_CLK_REF_DIV_INT_LSB;