rp2040: Add initial adc support

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2021-06-22 21:10:12 -04:00
parent 045bfa4e8d
commit 59fe878241
6 changed files with 109 additions and 2 deletions

View File

@ -62,6 +62,7 @@ class PrinterTemperatureMCU:
self.mcu_type = mcu.get_constants().get("MCU", "") self.mcu_type = mcu.get_constants().get("MCU", "")
# Run MCU specific configuration # Run MCU specific configuration
cfg_funcs = [ cfg_funcs = [
('rp2040', self.config_rp2040),
('sam3', self.config_sam3), ('sam4', self.config_sam4), ('sam3', self.config_sam3), ('sam4', self.config_sam4),
('samd21', self.config_samd21), ('samd51', self.config_samd51), ('samd21', self.config_samd21), ('samd51', self.config_samd51),
('stm32f1', self.config_stm32f1), ('stm32f2', self.config_stm32f2), ('stm32f1', self.config_stm32f1), ('stm32f2', self.config_stm32f2),
@ -89,6 +90,9 @@ class PrinterTemperatureMCU:
def config_unknown(self): def config_unknown(self):
raise self.printer.config_error("MCU temperature not supported on %s" raise self.printer.config_error("MCU temperature not supported on %s"
% (self.mcu_type,)) % (self.mcu_type,))
def config_rp2040(self):
self.slope = 3.3 / -0.001721
self.base_temperature = self.calc_base(27., 0.706 / 3.3)
def config_sam3(self): def config_sam3(self):
self.slope = 3.3 / .002650 self.slope = 3.3 / .002650
self.base_temperature = self.calc_base(27., 0.8 / 3.3) self.base_temperature = self.calc_base(27., 0.8 / 3.3)

View File

@ -6,6 +6,7 @@ config RP2040_SELECT
bool bool
default y default y
select HAVE_GPIO select HAVE_GPIO
select HAVE_GPIO_ADC
select HAVE_GPIO_BITBANGING select HAVE_GPIO_BITBANGING
select HAVE_STRICT_TIMING select HAVE_STRICT_TIMING

View File

@ -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 $(OUT)klipper.elf: $(OUT)stage2.o $(OUT)src/rp2040/rp2040_link.ld
# Add source files # 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/armcm_boot.c generic/armcm_irq.c generic/armcm_reset.c
src-y += generic/timer_irq.c rp2040/timer.c src-y += generic/timer_irq.c rp2040/timer.c
src-$(CONFIG_SERIAL) += rp2040/serial.c generic/serial_irq.c src-$(CONFIG_SERIAL) += rp2040/serial.c generic/serial_irq.c

88
src/rp2040/adc.c Normal file
View File

@ -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;
}

View File

@ -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); void gpio_in_reset(struct gpio_in g, int8_t pull_up);
uint8_t gpio_in_read(struct gpio_in g); 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 #endif // gpio.h

View File

@ -42,6 +42,7 @@ DECL_INIT(watchdog_init);
#define FREQ_XOSC 12000000 #define FREQ_XOSC 12000000
#define FREQ_SYS 125000000 #define FREQ_SYS 125000000
#define FREQ_USB 48000000
void void
enable_pclock(uint32_t reset_bit) enable_pclock(uint32_t reset_bit)
@ -126,8 +127,13 @@ clock_setup(void)
while (!(csys->selected & (1 << 1))) 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_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) // Enable watchdog tick (at 12Mhz)
cref->div = 1<<CLOCKS_CLK_REF_DIV_INT_LSB; cref->div = 1<<CLOCKS_CLK_REF_DIV_INT_LSB;