aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/printer-voxelab-aquila-2021.cfg83
-rw-r--r--lib/README4
-rw-r--r--lib/n32g45x/include/n32g45x_adc.h331
-rw-r--r--lib/n32g45x/n32g45x_adc.c211
-rw-r--r--src/stm32/Kconfig23
-rw-r--r--src/stm32/Makefile13
-rw-r--r--src/stm32/hard_pwm.c2
-rw-r--r--src/stm32/n32g45x_adc.c185
-rw-r--r--src/stm32/usbfs.c2
-rw-r--r--test/klippy/printers.test1
10 files changed, 845 insertions, 10 deletions
diff --git a/config/printer-voxelab-aquila-2021.cfg b/config/printer-voxelab-aquila-2021.cfg
new file mode 100644
index 00000000..892e32e6
--- /dev/null
+++ b/config/printer-voxelab-aquila-2021.cfg
@@ -0,0 +1,83 @@
+# This file contains pin mappings for the Voxelab Aquila
+# with the FFP0173 1.0.1 mainboard. To use this config, during
+# "make menuconfig" select the STM32F103 for STM32/G32, or
+# Nation N32G452 for N32 version, 28KB boot, serial PA9/PA10.
+# See docs/Config_Reference.md for a description of parameters.
+
+[stepper_x]
+step_pin: PC2
+dir_pin: PB9
+enable_pin: !PC3
+microsteps: 16
+rotation_distance: 40
+endstop_pin: ^PA5
+position_endstop: 0
+position_max: 235
+homing_speed: 50
+
+[stepper_y]
+step_pin: PB8
+dir_pin: PB7
+enable_pin: !PC3
+microsteps: 16
+rotation_distance: 40
+endstop_pin: ^PA6
+position_endstop: 0
+position_max: 235
+homing_speed: 50
+
+[stepper_z]
+step_pin: PB6
+dir_pin: !PB5
+enable_pin: !PC3
+microsteps: 16
+rotation_distance: 8
+endstop_pin: ^PA7
+position_endstop: 0.0
+position_max: 250
+
+[extruder]
+max_extrude_only_distance: 100.0
+step_pin: PB4
+dir_pin: PB3
+enable_pin: !PC3
+microsteps: 16
+rotation_distance: 34.406
+nozzle_diameter: 0.400
+filament_diameter: 1.750
+heater_pin: PA1
+sensor_type: EPCOS 100K B57560G104F
+sensor_pin: PC5
+control: pid
+# tuned for stock hardware with 200 degree Celsius target
+pid_Kp: 21.527
+pid_Ki: 1.063
+pid_Kd: 108.982
+min_temp: 0
+max_temp: 250
+
+[heater_bed]
+heater_pin: PA2
+sensor_type: EPCOS 100K B57560G104F
+sensor_pin: PC4
+control: pid
+# tuned for stock hardware with 50 degree Celsius target
+pid_Kp: 54.027
+pid_Ki: 0.770
+pid_Kd: 948.182
+min_temp: 0
+max_temp: 130
+
+[fan]
+pin: PA0
+
+[mcu]
+serial: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0
+restart_method: command
+
+[printer]
+kinematics: cartesian
+max_velocity: 300
+max_accel: 3000
+max_z_velocity: 5
+max_z_accel: 100
diff --git a/lib/README b/lib/README
index 848cd039..84bfcb56 100644
--- a/lib/README
+++ b/lib/README
@@ -160,3 +160,7 @@ revision 177b0073fe6f19281ee7f7fdbe9599e32d1b4b8b.
The Huada HC32F460 directory contains code from:
https://www.hdsc.com.cn/Category83-1490
version 2.2 DDL minus example directory, empty/extra files
+
+The n32g45x directory contains parts of code from:
+ https://github.com/RT-Thread/rt-thread/tree/master/bsp/n32g452xx/Libraries/N32_Std_Driver
+version v1.0.1 (77638c17877c4b6b0b81e189a36bb08b3384923b)
diff --git a/lib/n32g45x/include/n32g45x_adc.h b/lib/n32g45x/include/n32g45x_adc.h
new file mode 100644
index 00000000..ab929feb
--- /dev/null
+++ b/lib/n32g45x/include/n32g45x_adc.h
@@ -0,0 +1,331 @@
+/*****************************************************************************
+ * Copyright (c) 2019, Nations Technologies Inc.
+ *
+ * All rights reserved.
+ * ****************************************************************************
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Nations' name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ****************************************************************************/
+
+#ifndef ____N32G45x_ADC____
+#define ____N32G45x_ADC____
+
+#define __IO volatile
+
+typedef struct
+{
+ uint32_t WorkMode;
+ uint32_t MultiChEn;
+ uint32_t ContinueConvEn;
+ uint32_t ExtTrigSelect;
+ uint32_t DatAlign;
+ uint8_t ChsNumber;
+} ADC_InitType;
+
+typedef struct
+{
+ __IO uint32_t STS;
+ __IO uint32_t CTRL1;
+ __IO uint32_t CTRL2;
+ __IO uint32_t SAMPT1;
+ __IO uint32_t SAMPT2;
+ __IO uint32_t JOFFSET1;
+ __IO uint32_t JOFFSET2;
+ __IO uint32_t JOFFSET3;
+ __IO uint32_t JOFFSET4;
+ __IO uint32_t WDGHIGH;
+ __IO uint32_t WDGLOW;
+ __IO uint32_t RSEQ1;
+ __IO uint32_t RSEQ2;
+ __IO uint32_t RSEQ3;
+ __IO uint32_t JSEQ;
+ __IO uint32_t JDAT1;
+ __IO uint32_t JDAT2;
+ __IO uint32_t JDAT3;
+ __IO uint32_t JDAT4;
+ __IO uint32_t DAT;
+ __IO uint32_t DIFSEL;
+ __IO uint32_t CALFACT;
+ __IO uint32_t CTRL3;
+ __IO uint32_t SAMPT3;
+} ADC_Module;
+
+#define NS_ADC1_BASE ((uint32_t)0x40020800)
+#define NS_ADC2_BASE ((uint32_t)0x40020c00)
+#define NS_ADC3_BASE ((uint32_t)0x40021800)
+#define NS_ADC4_BASE ((uint32_t)0x40021c00)
+
+#define NS_ADC1 ((ADC_Module *)NS_ADC1_BASE)
+#define NS_ADC2 ((ADC_Module *)NS_ADC2_BASE)
+#define NS_ADC3 ((ADC_Module *)NS_ADC3_BASE)
+#define NS_ADC4 ((ADC_Module *)NS_ADC4_BASE)
+
+#define ADC_RCC_BASE ((uint32_t)0x40021000)
+#define ADC_RCC_CTRL *((uint32_t *)(ADC_RCC_BASE + 0x00))
+#define ADC_RCC_CFG *((uint32_t *)(ADC_RCC_BASE + 0x04))
+#define ADC_RCC_CLKINT *((uint32_t *)(ADC_RCC_BASE + 0x08))
+#define ADC_RCC_APB2PRST *((uint32_t *)(ADC_RCC_BASE + 0x0c))
+#define ADC_RCC_APB1PRST *((uint32_t *)(ADC_RCC_BASE + 0x10))
+#define ADC_RCC_AHBPCLKEN *((uint32_t *)(ADC_RCC_BASE + 0x14))
+#define ADC_RCC_APB2PCLKEN *((uint32_t *)(ADC_RCC_BASE + 0x18))
+#define ADC_RCC_APB1PCLKEN *((uint32_t *)(ADC_RCC_BASE + 0x1c))
+#define ADC_RCC_BDCTRL *((uint32_t *)(ADC_RCC_BASE + 0x20))
+#define ADC_RCC_CTRLSTS *((uint32_t *)(ADC_RCC_BASE + 0x24))
+#define ADC_RCC_AHBPRST *((uint32_t *)(ADC_RCC_BASE + 0x28))
+#define ADC_RCC_CFG2 *((uint32_t *)(ADC_RCC_BASE + 0x2c))
+#define ADC_RCC_CFG3 *((uint32_t *)(ADC_RCC_BASE + 0x30))
+
+/* CFG2 register bit mask */
+#define CFG2_TIM18CLKSEL_SET_MASK ((uint32_t)0x20000000)
+#define CFG2_TIM18CLKSEL_RESET_MASK ((uint32_t)0xDFFFFFFF)
+#define CFG2_RNGCPRES_SET_MASK ((uint32_t)0x1F000000)
+#define CFG2_RNGCPRES_RESET_MASK ((uint32_t)0xE0FFFFFF)
+#define CFG2_ADC1MSEL_SET_MASK ((uint32_t)0x00000400)
+#define CFG2_ADC1MSEL_RESET_MASK ((uint32_t)0xFFFFFBFF)
+#define CFG2_ADC1MPRES_SET_MASK ((uint32_t)0x0000F800)
+#define CFG2_ADC1MPRES_RESET_MASK ((uint32_t)0xFFFF07FF)
+#define CFG2_ADCPLLPRES_SET_MASK ((uint32_t)0x000001F0)
+#define CFG2_ADCPLLPRES_RESET_MASK ((uint32_t)0xFFFFFE0F)
+#define CFG2_ADCHPRES_SET_MASK ((uint32_t)0x0000000F)
+#define CFG2_ADCHPRES_RESET_MASK ((uint32_t)0xFFFFFFF0)
+
+#define RCC_ADCPLLCLK_DISABLE ((uint32_t)0xFFFFFEFF)
+#define RCC_ADCPLLCLK_DIV1 ((uint32_t)0x00000100)
+#define RCC_ADCPLLCLK_DIV2 ((uint32_t)0x00000110)
+#define RCC_ADCPLLCLK_DIV4 ((uint32_t)0x00000120)
+#define RCC_ADCPLLCLK_DIV6 ((uint32_t)0x00000130)
+#define RCC_ADCPLLCLK_DIV8 ((uint32_t)0x00000140)
+#define RCC_ADCPLLCLK_DIV10 ((uint32_t)0x00000150)
+#define RCC_ADCPLLCLK_DIV12 ((uint32_t)0x00000160)
+#define RCC_ADCPLLCLK_DIV16 ((uint32_t)0x00000170)
+#define RCC_ADCPLLCLK_DIV32 ((uint32_t)0x00000180)
+#define RCC_ADCPLLCLK_DIV64 ((uint32_t)0x00000190)
+#define RCC_ADCPLLCLK_DIV128 ((uint32_t)0x000001A0)
+#define RCC_ADCPLLCLK_DIV256 ((uint32_t)0x000001B0)
+#define RCC_ADCPLLCLK_DIV_OTHERS ((uint32_t)0x000001C0)
+
+#define RCC_ADCHCLK_DIV1 ((uint32_t)0x00000000)
+#define RCC_ADCHCLK_DIV2 ((uint32_t)0x00000001)
+#define RCC_ADCHCLK_DIV4 ((uint32_t)0x00000002)
+#define RCC_ADCHCLK_DIV6 ((uint32_t)0x00000003)
+#define RCC_ADCHCLK_DIV8 ((uint32_t)0x00000004)
+#define RCC_ADCHCLK_DIV10 ((uint32_t)0x00000005)
+#define RCC_ADCHCLK_DIV12 ((uint32_t)0x00000006)
+#define RCC_ADCHCLK_DIV16 ((uint32_t)0x00000007)
+#define RCC_ADCHCLK_DIV32 ((uint32_t)0x00000008)
+#define RCC_ADCHCLK_DIV_OTHERS ((uint32_t)0x00000008)
+
+#define RCC_ADC1MCLK_SRC_HSI ((uint32_t)0x00000000)
+#define RCC_ADC1MCLK_SRC_HSE ((uint32_t)0x00000400)
+
+#define RCC_ADC1MCLK_DIV1 ((uint32_t)0x00000000)
+#define RCC_ADC1MCLK_DIV2 ((uint32_t)0x00000800)
+#define RCC_ADC1MCLK_DIV3 ((uint32_t)0x00001000)
+#define RCC_ADC1MCLK_DIV4 ((uint32_t)0x00001800)
+#define RCC_ADC1MCLK_DIV5 ((uint32_t)0x00002000)
+#define RCC_ADC1MCLK_DIV6 ((uint32_t)0x00002800)
+#define RCC_ADC1MCLK_DIV7 ((uint32_t)0x00003000)
+#define RCC_ADC1MCLK_DIV8 ((uint32_t)0x00003800)
+#define RCC_ADC1MCLK_DIV9 ((uint32_t)0x00004000)
+#define RCC_ADC1MCLK_DIV10 ((uint32_t)0x00004800)
+#define RCC_ADC1MCLK_DIV11 ((uint32_t)0x00005000)
+#define RCC_ADC1MCLK_DIV12 ((uint32_t)0x00005800)
+#define RCC_ADC1MCLK_DIV13 ((uint32_t)0x00006000)
+#define RCC_ADC1MCLK_DIV14 ((uint32_t)0x00006800)
+#define RCC_ADC1MCLK_DIV15 ((uint32_t)0x00007000)
+#define RCC_ADC1MCLK_DIV16 ((uint32_t)0x00007800)
+#define RCC_ADC1MCLK_DIV17 ((uint32_t)0x00008000)
+#define RCC_ADC1MCLK_DIV18 ((uint32_t)0x00008800)
+#define RCC_ADC1MCLK_DIV19 ((uint32_t)0x00009000)
+#define RCC_ADC1MCLK_DIV20 ((uint32_t)0x00009800)
+#define RCC_ADC1MCLK_DIV21 ((uint32_t)0x0000A000)
+#define RCC_ADC1MCLK_DIV22 ((uint32_t)0x0000A800)
+#define RCC_ADC1MCLK_DIV23 ((uint32_t)0x0000B000)
+#define RCC_ADC1MCLK_DIV24 ((uint32_t)0x0000B800)
+#define RCC_ADC1MCLK_DIV25 ((uint32_t)0x0000C000)
+#define RCC_ADC1MCLK_DIV26 ((uint32_t)0x0000C800)
+#define RCC_ADC1MCLK_DIV27 ((uint32_t)0x0000D000)
+#define RCC_ADC1MCLK_DIV28 ((uint32_t)0x0000D800)
+#define RCC_ADC1MCLK_DIV29 ((uint32_t)0x0000E000)
+#define RCC_ADC1MCLK_DIV30 ((uint32_t)0x0000E800)
+#define RCC_ADC1MCLK_DIV31 ((uint32_t)0x0000F000)
+#define RCC_ADC1MCLK_DIV32 ((uint32_t)0x0000F800)
+
+#define RCC_AHB_PERIPH_ADC1 ((uint32_t)0x00001000)
+#define RCC_AHB_PERIPH_ADC2 ((uint32_t)0x00002000)
+#define RCC_AHB_PERIPH_ADC3 ((uint32_t)0x00004000)
+#define RCC_AHB_PERIPH_ADC4 ((uint32_t)0x00008000)
+
+#define SAMPT1_SMP_SET ((uint32_t)0x00000007)
+#define SAMPT2_SMP_SET ((uint32_t)0x00000007)
+
+#define SQR4_SEQ_SET ((uint32_t)0x0000001F)
+#define SQR3_SEQ_SET ((uint32_t)0x0000001F)
+#define SQR2_SEQ_SET ((uint32_t)0x0000001F)
+#define SQR1_SEQ_SET ((uint32_t)0x0000001F)
+
+#define CTRL1_CLR_MASK ((uint32_t)0xFFF0FEFF)
+#define RSEQ1_CLR_MASK ((uint32_t)0xFF0FFFFF)
+#define CTRL2_CLR_MASK ((uint32_t)0xFFF1F7FD)
+
+#define ADC_CH_0 ((uint8_t)0x00)
+#define ADC_CH_1 ((uint8_t)0x01)
+#define ADC_CH_2 ((uint8_t)0x02)
+#define ADC_CH_3 ((uint8_t)0x03)
+#define ADC_CH_4 ((uint8_t)0x04)
+#define ADC_CH_5 ((uint8_t)0x05)
+#define ADC_CH_6 ((uint8_t)0x06)
+#define ADC_CH_7 ((uint8_t)0x07)
+#define ADC_CH_8 ((uint8_t)0x08)
+#define ADC_CH_9 ((uint8_t)0x09)
+#define ADC_CH_10 ((uint8_t)0x0A)
+#define ADC_CH_11 ((uint8_t)0x0B)
+#define ADC_CH_12 ((uint8_t)0x0C)
+#define ADC_CH_13 ((uint8_t)0x0D)
+#define ADC_CH_14 ((uint8_t)0x0E)
+#define ADC_CH_15 ((uint8_t)0x0F)
+#define ADC_CH_16 ((uint8_t)0x10)
+#define ADC_CH_17 ((uint8_t)0x11)
+#define ADC_CH_18 ((uint8_t)0x12)
+
+#define ADC_WORKMODE_INDEPENDENT ((uint32_t)0x00000000)
+#define ADC_WORKMODE_REG_INJECT_SIMULT ((uint32_t)0x00010000)
+#define ADC_WORKMODE_REG_SIMULT_ALTER_TRIG ((uint32_t)0x00020000)
+#define ADC_WORKMODE_INJ_SIMULT_FAST_INTERL ((uint32_t)0x00030000)
+#define ADC_WORKMODE_INJ_SIMULT_SLOW_INTERL ((uint32_t)0x00040000)
+#define ADC_WORKMODE_INJ_SIMULT ((uint32_t)0x00050000)
+#define ADC_WORKMODE_REG_SIMULT ((uint32_t)0x00060000)
+#define ADC_WORKMODE_FAST_INTERL ((uint32_t)0x00070000)
+#define ADC_WORKMODE_SLOW_INTERL ((uint32_t)0x00080000)
+#define ADC_WORKMODE_ALTER_TRIG ((uint32_t)0x00090000)
+
+#define ADC_EXT_TRIGCONV_T1_CC1 \
+ ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
+#define ADC_EXT_TRIGCONV_T1_CC2 \
+ ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */
+#define ADC_EXT_TRIGCONV_T2_CC2 \
+ ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
+#define ADC_EXT_TRIGCONV_T1_CC3 \
+ ((uint32_t)0x00040000) /*!< For ADC1, ADC2 , ADC3 and ADC4 */
+#define ADC_EXT_TRIGCONV_NONE \
+ ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 , ADC3 and ADC4 */
+
+#define ADC_DAT_ALIGN_R ((uint32_t)0x00000000)
+#define ADC_DAT_ALIGN_L ((uint32_t)0x00000800)
+
+#define ADC_FLAG_RDY ((uint8_t)0x20)
+#define ADC_FLAG_PD_RDY ((uint8_t)0x40)
+
+#define CTRL2_AD_ON_SET ((uint32_t)0x00000001)
+#define CTRL2_AD_ON_RESET ((uint32_t)0xFFFFFFFE)
+
+#define CTRL2_CAL_SET ((uint32_t)0x00000004)
+
+/* ADC Software start mask */
+#define CTRL2_EXT_TRIG_SWSTART_SET ((uint32_t)0x00500000)
+#define CTRL2_EXT_TRIG_SWSTART_RESET ((uint32_t)0xFFAFFFFF)
+
+#define ADC_SAMP_TIME_1CYCLES5 ((uint8_t)0x00)
+#define ADC_SAMP_TIME_7CYCLES5 ((uint8_t)0x01)
+#define ADC_SAMP_TIME_13CYCLES5 ((uint8_t)0x02)
+#define ADC_SAMP_TIME_28CYCLES5 ((uint8_t)0x03)
+#define ADC_SAMP_TIME_41CYCLES5 ((uint8_t)0x04)
+#define ADC_SAMP_TIME_55CYCLES5 ((uint8_t)0x05)
+#define ADC_SAMP_TIME_71CYCLES5 ((uint8_t)0x06)
+#define ADC_SAMP_TIME_239CYCLES5 ((uint8_t)0x07)
+
+#define ADC_FLAG_AWDG ((uint8_t)0x01)
+#define ADC_FLAG_ENDC ((uint8_t)0x02)
+#define ADC_FLAG_JENDC ((uint8_t)0x04)
+#define ADC_FLAG_JSTR ((uint8_t)0x08)
+#define ADC_FLAG_STR ((uint8_t)0x10)
+#define ADC_FLAG_EOC_ANY ((uint8_t)0x20)
+#define ADC_FLAG_JEOC_ANY ((uint8_t)0x40)
+
+#define ADC_STS_AWDG ((uint8_t)0x01) /*!< Analog watchdog flag */
+#define ADC_STS_ENDC ((uint8_t)0x02) /*!< End of conversion */
+#define ADC_STS_JENDC \
+ ((uint8_t)0x04) /*!< Injected channel end of conversion */
+#define ADC_STS_JSTR ((uint8_t)0x08) /*!< Injected channel Start flag */
+#define ADC_STS_STR ((uint8_t)0x10) /*!< Regular channel Start flag */
+#define ADC_STS_ENDCA ((uint8_t)0x20) /*!< Any end of conversion */
+#define ADC_STS_JENDCA \
+ ((uint8_t)0x40) /*!< Any injected channel end of conversion */
+
+/* ADC DMA mask */
+#define CTRL2_DMA_SET ((uint32_t)0x00000100)
+#define CTRL2_DMA_RESET ((uint32_t)0xFFFFFEFF)
+
+#define CTRL2_TSVREFE_SET ((uint32_t)0x00800000)
+#define CTRL2_TSVREFE_RESET ((uint32_t)0xFF7FFFFF)
+#define VREF1P2_CTRL (*(uint32_t *)(0x40001800 + 0x20))
+/******************* Bit definition for ADC_CTRL2 register
+ * ********************/
+#define ADC_CTRL2_ON ((uint32_t)0x00000001) /*!< A/D Converter ON / OFF */
+#define ADC_CTRL2_CTU ((uint32_t)0x00000002) /*!< Continuous Conversion */
+#define ADC_CTRL2_ENCAL ((uint32_t)0x00000004) /*!< A/D Calibration */
+#define ADC_CTRL2_ENDMA \
+ ((uint32_t)0x00000100) /*!< Direct Memory access mode */
+#define ADC_CTRL2_ALIG ((uint32_t)0x00000800) /*!< Data Alignment */
+
+#define ADC_CTRL2_EXTJSEL \
+ ((uint32_t)0x00007000) /*!< INJ_EXT_SEL[2:0] bits (External event select \
+ for injected group) */
+#define ADC_CTRL2_EXTJSEL_0 ((uint32_t)0x00001000) /*!< Bit 0 */
+#define ADC_CTRL2_EXTJSEL_1 ((uint32_t)0x00002000) /*!< Bit 1 */
+#define ADC_CTRL2_EXTJSEL_2 ((uint32_t)0x00004000) /*!< Bit 2 */
+
+#define ADC_CTRL2_EXTJTRIG \
+ ((uint32_t)0x00008000) /*!< External Trigger Conversion mode for injected \
+ channels */
+
+#define ADC_CTRL2_EXTRSEL \
+ ((uint32_t)0x000E0000) /*!< EXTSEL[2:0] bits (External Event Select for \
+ regular group) */
+#define ADC_CTRL2_EXTRSEL_0 ((uint32_t)0x00020000) /*!< Bit 0 */
+#define ADC_CTRL2_EXTRSEL_1 ((uint32_t)0x00040000) /*!< Bit 1 */
+#define ADC_CTRL2_EXTRSEL_2 ((uint32_t)0x00080000) /*!< Bit 2 */
+
+#define ADC_CTRL2_EXTRTRIG \
+ ((uint32_t)0x00100000) /*!< External Trigger Conversion mode for regular \
+ channels */
+#define ADC_CTRL2_SWSTRJCH \
+ ((uint32_t)0x00200000) /*!< Start Conversion of injected channels */
+#define ADC_CTRL2_SWSTRRCH \
+ ((uint32_t)0x00400000) /*!< Start Conversion of regular channels */
+#define ADC_CTRL2_TEMPEN \
+ ((uint32_t)0x00800000) /*!< Temperature Sensor and VREFINT Enable */
+
+#define ADC_CTRL3_VABTMEN_MSK ((uint32_t)0x01L << 11)
+#define ADC_CTRL3_DPWMOD_MSK ((uint32_t)0x01L << 10)
+#define ADC_CTRL3_JENDCAIEN_MSK ((uint32_t)0x01L << 9)
+#define ADC_CTRL3_ENDCAIEN_MSK ((uint32_t)0x01L << 8)
+#define ADC_CTRL3_BPCAL_MSK ((uint32_t)0x01L << 7)
+#define ADC_CTRL3_PDRDY_MSK ((uint32_t)0x01L << 6)
+#define ADC_CTRL3_RDY_MSK ((uint32_t)0x01L << 5)
+#define ADC_CTRL3_CKMOD_MSK ((uint32_t)0x01L << 4)
+#define ADC_CTRL3_CALALD_MSK ((uint32_t)0x01L << 3)
+#define ADC_CTRL3_CALDIF_MSK ((uint32_t)0x01L << 2)
+#define ADC_CTRL3_RES_MSK ((uint32_t)0x03L << 0)
+
+void ADC_Init(ADC_Module* ADCx, ADC_InitType* ADC_InitStruct);
+void ADC_ConfigRegularChannel(ADC_Module* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
+#endif \ No newline at end of file
diff --git a/lib/n32g45x/n32g45x_adc.c b/lib/n32g45x/n32g45x_adc.c
new file mode 100644
index 00000000..6621bcb2
--- /dev/null
+++ b/lib/n32g45x/n32g45x_adc.c
@@ -0,0 +1,211 @@
+/*****************************************************************************
+ * Copyright (c) 2019, Nations Technologies Inc.
+ *
+ * All rights reserved.
+ * ****************************************************************************
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Nations' name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ****************************************************************************/
+
+#include "stdint.h"
+#include "n32g45x_adc.h"
+
+/**
+ * @brief Initializes the ADCx peripheral according to the specified parameters
+ * in the ADC_InitStruct.
+ * @param ADCx where x can be 1, 2 ,3 or 4 to select the ADC peripheral.
+ * @param ADC_InitStruct pointer to an ADC_InitType structure that contains
+ * the configuration information for the specified ADC peripheral.
+ */
+void ADC_Init(ADC_Module* ADCx, ADC_InitType* ADC_InitStruct)
+{
+ uint32_t tmpreg1 = 0;
+ uint8_t tmpreg2 = 0;
+
+ /*---------------------------- ADCx CTRL1 Configuration -----------------*/
+ /* Get the ADCx CTRL1 value */
+ tmpreg1 = ADCx->CTRL1;
+ /* Clear DUALMOD and SCAN bits */
+ tmpreg1 &= CTRL1_CLR_MASK;
+ /* Configure ADCx: Dual mode and scan conversion mode */
+ /* Set DUALMOD bits according to WorkMode value */
+ /* Set SCAN bit according to MultiChEn value */
+ tmpreg1 |= (uint32_t)(ADC_InitStruct->WorkMode | ((uint32_t)ADC_InitStruct->MultiChEn << 8));
+ /* Write to ADCx CTRL1 */
+ ADCx->CTRL1 = tmpreg1;
+
+ /*---------------------------- ADCx CTRL2 Configuration -----------------*/
+ /* Get the ADCx CTRL2 value */
+ tmpreg1 = ADCx->CTRL2;
+ /* Clear CONT, ALIGN and EXTSEL bits */
+ tmpreg1 &= CTRL2_CLR_MASK;
+ /* Configure ADCx: external trigger event and continuous conversion mode */
+ /* Set ALIGN bit according to DatAlign value */
+ /* Set EXTSEL bits according to ExtTrigSelect value */
+ /* Set CONT bit according to ContinueConvEn value */
+ tmpreg1 |= (uint32_t)(ADC_InitStruct->DatAlign | ADC_InitStruct->ExtTrigSelect
+ | ((uint32_t)ADC_InitStruct->ContinueConvEn << 1));
+ /* Write to ADCx CTRL2 */
+ ADCx->CTRL2 = tmpreg1;
+
+ /*---------------------------- ADCx RSEQ1 Configuration -----------------*/
+ /* Get the ADCx RSEQ1 value */
+ tmpreg1 = ADCx->RSEQ1;
+ /* Clear L bits */
+ tmpreg1 &= RSEQ1_CLR_MASK;
+ /* Configure ADCx: regular channel sequence length */
+ /* Set L bits according to ChsNumber value */
+ tmpreg2 |= (uint8_t)(ADC_InitStruct->ChsNumber - (uint8_t)1);
+ tmpreg1 |= (uint32_t)tmpreg2 << 20;
+ /* Write to ADCx RSEQ1 */
+ ADCx->RSEQ1 = tmpreg1;
+}
+
+
+/**
+ * @brief Configures for the selected ADC regular channel its corresponding
+ * rank in the sequencer and its sample time.
+ * @param ADCx where x can be 1, 2, 3 or 4 to select the ADC peripheral.
+ * @param ADC_Channel the ADC channel to configure.
+ * This parameter can be one of the following values:
+ * @arg ADC_CH_0 ADC Channel0 selected
+ * @arg ADC_CH_1 ADC Channel1 selected
+ * @arg ADC_CH_2 ADC Channel2 selected
+ * @arg ADC_CH_3 ADC Channel3 selected
+ * @arg ADC_CH_4 ADC Channel4 selected
+ * @arg ADC_CH_5 ADC Channel5 selected
+ * @arg ADC_CH_6 ADC Channel6 selected
+ * @arg ADC_CH_7 ADC Channel7 selected
+ * @arg ADC_CH_8 ADC Channel8 selected
+ * @arg ADC_CH_9 ADC Channel9 selected
+ * @arg ADC_CH_10 ADC Channel10 selected
+ * @arg ADC_CH_11 ADC Channel11 selected
+ * @arg ADC_CH_12 ADC Channel12 selected
+ * @arg ADC_CH_13 ADC Channel13 selected
+ * @arg ADC_CH_14 ADC Channel14 selected
+ * @arg ADC_CH_15 ADC Channel15 selected
+ * @arg ADC_CH_16 ADC Channel16 selected
+ * @arg ADC_CH_17 ADC Channel17 selected
+ * @arg ADC_CH_18 ADC Channel18 selected
+ * @param Rank The rank in the regular group sequencer. This parameter must be between 1 to 16.
+ * @param ADC_SampleTime The sample time value to be set for the selected channel.
+ * This parameter can be one of the following values:
+ * @arg ADC_SAMP_TIME_1CYCLES5 Sample time equal to 1.5 cycles
+ * @arg ADC_SAMP_TIME_7CYCLES5 Sample time equal to 7.5 cycles
+ * @arg ADC_SAMP_TIME_13CYCLES5 Sample time equal to 13.5 cycles
+ * @arg ADC_SAMP_TIME_28CYCLES5 Sample time equal to 28.5 cycles
+ * @arg ADC_SAMP_TIME_41CYCLES5 Sample time equal to 41.5 cycles
+ * @arg ADC_SAMP_TIME_55CYCLES5 Sample time equal to 55.5 cycles
+ * @arg ADC_SAMP_TIME_71CYCLES5 Sample time equal to 71.5 cycles
+ * @arg ADC_SAMP_TIME_239CYCLES5 Sample time equal to 239.5 cycles
+ */
+
+void ADC_ConfigRegularChannel(ADC_Module* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
+{
+ uint32_t tmpreg1 = 0, tmpreg2 = 0;
+
+ if (ADC_Channel == ADC_CH_18)
+ {
+ tmpreg1 = ADCx->SAMPT3;
+ tmpreg1 &= (~0x00000007);
+ tmpreg1 |= ADC_SampleTime;
+ ADCx->SAMPT3 = tmpreg1;
+ }
+ else if (ADC_Channel > ADC_CH_9) /* if ADC_CH_10 ... ADC_CH_17 is selected */
+ {
+ /* Get the old register value */
+ tmpreg1 = ADCx->SAMPT1;
+ /* Calculate the mask to clear */
+ tmpreg2 = SAMPT1_SMP_SET << (3 * (ADC_Channel - 10));
+ /* Clear the old channel sample time */
+ tmpreg1 &= ~tmpreg2;
+ /* Calculate the mask to set */
+ tmpreg2 = (uint32_t)ADC_SampleTime << (3 * (ADC_Channel - 10));
+ /* Set the new channel sample time */
+ tmpreg1 |= tmpreg2;
+ /* Store the new register value */
+ ADCx->SAMPT1 = tmpreg1;
+ }
+ else /* ADC_Channel include in ADC_Channel_[0..9] */
+ {
+ /* Get the old register value */
+ tmpreg1 = ADCx->SAMPT2;
+ /* Calculate the mask to clear */
+ tmpreg2 = SAMPT2_SMP_SET << (3 * ADC_Channel);
+ /* Clear the old channel sample time */
+ tmpreg1 &= ~tmpreg2;
+ /* Calculate the mask to set */
+ tmpreg2 = (uint32_t)ADC_SampleTime << (3 * ADC_Channel);
+ /* Set the new channel sample time */
+ tmpreg1 |= tmpreg2;
+ /* Store the new register value */
+ ADCx->SAMPT2 = tmpreg1;
+ }
+ /* For Rank 1 to 6 */
+ if (Rank < 7)
+ {
+ /* Get the old register value */
+ tmpreg1 = ADCx->RSEQ3;
+ /* Calculate the mask to clear */
+ tmpreg2 = SQR3_SEQ_SET << (5 * (Rank - 1));
+ /* Clear the old SQx bits for the selected rank */
+ tmpreg1 &= ~tmpreg2;
+ /* Calculate the mask to set */
+ tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 1));
+ /* Set the SQx bits for the selected rank */
+ tmpreg1 |= tmpreg2;
+ /* Store the new register value */
+ ADCx->RSEQ3 = tmpreg1;
+ }
+ /* For Rank 7 to 12 */
+ else if (Rank < 13)
+ {
+ /* Get the old register value */
+ tmpreg1 = ADCx->RSEQ2;
+ /* Calculate the mask to clear */
+ tmpreg2 = SQR2_SEQ_SET << (5 * (Rank - 7));
+ /* Clear the old SQx bits for the selected rank */
+ tmpreg1 &= ~tmpreg2;
+ /* Calculate the mask to set */
+ tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 7));
+ /* Set the SQx bits for the selected rank */
+ tmpreg1 |= tmpreg2;
+ /* Store the new register value */
+ ADCx->RSEQ2 = tmpreg1;
+ }
+ /* For Rank 13 to 16 */
+ else
+ {
+ /* Get the old register value */
+ tmpreg1 = ADCx->RSEQ1;
+ /* Calculate the mask to clear */
+ tmpreg2 = SQR1_SEQ_SET << (5 * (Rank - 13));
+ /* Clear the old SQx bits for the selected rank */
+ tmpreg1 &= ~tmpreg2;
+ /* Calculate the mask to set */
+ tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 13));
+ /* Set the SQx bits for the selected rank */
+ tmpreg1 |= tmpreg2;
+ /* Store the new register value */
+ ADCx->RSEQ1 = tmpreg1;
+ }
+}
+
diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig
index 94384ec3..30b2e48d 100644
--- a/src/stm32/Kconfig
+++ b/src/stm32/Kconfig
@@ -97,6 +97,14 @@ choice
config MACH_STM32L412
bool "STM32L412"
select MACH_STM32L4
+ config MACH_N32G452
+ bool "Nation N32G452"
+ select MACH_N32G45x
+ select MACH_STM32F1
+ config MACH_N32G455
+ bool "Nation N32G455"
+ select MACH_N32G45x
+ select MACH_STM32F1
endchoice
config MACH_STM32F103x6
@@ -127,10 +135,12 @@ config MACH_STM32F4x5 # F405, F407, F429 series
bool
config MACH_STM32L4
bool
+config MACH_N32G45x
+ bool
config HAVE_STM32_USBFS
bool
default y if MACH_STM32F0x2 || MACH_STM32G0Bx || MACH_STM32L4 || MACH_STM32G4
- default y if (MACH_STM32F103 || MACH_STM32F070) && !STM32_CLOCK_REF_INTERNAL
+ default y if (MACH_STM32F1 || MACH_STM32F070) && !STM32_CLOCK_REF_INTERNAL
config HAVE_STM32_USBOTG
bool
default y if MACH_STM32F2 || MACH_STM32F4 || MACH_STM32H7
@@ -144,7 +154,7 @@ config HAVE_STM32_USBCANBUS
bool
depends on HAVE_STM32_USBFS || HAVE_STM32_USBOTG
depends on HAVE_STM32_CANBUS || HAVE_STM32_FDCANBUS
- depends on !MACH_STM32F103
+ depends on !MACH_STM32F1
default y
config MCU
@@ -169,6 +179,7 @@ config MCU
default "stm32h743xx" if MACH_STM32H743
default "stm32h750xx" if MACH_STM32H750
default "stm32l412xx" if MACH_STM32L412
+ default "stm32f103xe" if MACH_N32G45x
config CLOCK_FREQ
int
@@ -183,6 +194,8 @@ config CLOCK_FREQ
default 150000000 if MACH_STM32G431
default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports
default 80000000 if MACH_STM32L412
+ default 64000000 if MACH_N32G45x && STM32_CLOCK_REF_INTERNAL
+ default 128000000 if MACH_N32G45x
config FLASH_SIZE
hex
@@ -195,6 +208,7 @@ config FLASH_SIZE
default 0x20000 if MACH_STM32G0 || MACH_STM32G431
default 0x20000 if MACH_STM32H750
default 0x200000 if MACH_STM32H743
+ default 0x20000 if MACH_N32G45x
config FLASH_BOOT_ADDRESS
hex
@@ -219,6 +233,7 @@ config RAM_SIZE
default 0x9000 if MACH_STM32G07x
default 0x24000 if MACH_STM32G0Bx
default 0x20000 if MACH_STM32H7
+ default 0x10000 if MACH_N32G45x
config STACK_SIZE
int
@@ -251,11 +266,11 @@ config STM32_DFU_ROM_ADDRESS
choice
prompt "Bootloader offset"
config STM32_FLASH_START_2000
- bool "8KiB bootloader" if MACH_STM32F103 || MACH_STM32F070 || MACH_STM32G0 || MACH_STM32F0x2
+ bool "8KiB bootloader" if MACH_STM32F1 || MACH_STM32F070 || MACH_STM32G0 || MACH_STM32F0x2
config STM32_FLASH_START_5000
bool "20KiB bootloader" if MACH_STM32F103
config STM32_FLASH_START_7000
- bool "28KiB bootloader" if MACH_STM32F103
+ bool "28KiB bootloader" if MACH_STM32F1
config STM32_FLASH_START_8000
bool "32KiB bootloader" if MACH_STM32F1 || MACH_STM32F2 || MACH_STM32F4
config STM32_FLASH_START_8800
diff --git a/src/stm32/Makefile b/src/stm32/Makefile
index fac9ed4a..e5dac2aa 100644
--- a/src/stm32/Makefile
+++ b/src/stm32/Makefile
@@ -6,6 +6,7 @@ CROSS_PREFIX=arm-none-eabi-
dirs-y += src/stm32 src/generic lib/fast-hash
dirs-$(CONFIG_MACH_STM32F0) += lib/stm32f0
dirs-$(CONFIG_MACH_STM32F1) += lib/stm32f1
+dirs-$(CONFIG_MACH_N32G45x) += lib/n32g45x
dirs-$(CONFIG_MACH_STM32F2) += lib/stm32f2
dirs-$(CONFIG_MACH_STM32F4) += lib/stm32f4
dirs-$(CONFIG_MACH_STM32G0) += lib/stm32g0
@@ -17,7 +18,9 @@ MCU := $(shell echo $(CONFIG_MCU))
MCU_UPPER := $(shell echo $(CONFIG_MCU) | tr a-z A-Z | tr X x)
CFLAGS-$(CONFIG_MACH_STM32F0) += -mcpu=cortex-m0 -Ilib/stm32f0/include
-CFLAGS-$(CONFIG_MACH_STM32F1) += -mcpu=cortex-m3 -Ilib/stm32f1/include
+CFLAGS-$(CONFIG_MACH_STM32F103) += -mcpu=cortex-m3
+CFLAGS-$(CONFIG_MACH_N32G45x) += -mcpu=cortex-m4 -Ilib/n32g45x/include
+CFLAGS-$(CONFIG_MACH_STM32F1) += -Ilib/stm32f1/include
CFLAGS-$(CONFIG_MACH_STM32F2) += -mcpu=cortex-m3 -Ilib/stm32f2/include
CFLAGS-$(CONFIG_MACH_STM32F4) += -mcpu=cortex-m4 -Ilib/stm32f4/include
CFLAGS-$(CONFIG_MACH_STM32G0) += -mcpu=cortex-m0plus -Ilib/stm32g0/include
@@ -38,9 +41,11 @@ src-$(CONFIG_MACH_STM32F0) += ../lib/stm32f0/system_stm32f0xx.c
src-$(CONFIG_MACH_STM32F0) += generic/timer_irq.c stm32/stm32f0_timer.c
src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c stm32/gpioperiph.c
src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0_adc.c stm32/stm32f0_i2c.c
-src-$(CONFIG_MACH_STM32F1) += ../lib/stm32f1/system_stm32f1xx.c
-src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c generic/armcm_timer.c
-src-$(CONFIG_MACH_STM32F1) += stm32/adc.c stm32/i2c.c
+src-$(CONFIG_MACH_STM32F103) += ../lib/stm32f1/system_stm32f1xx.c
+src-$(CONFIG_MACH_STM32F103) += stm32/adc.c
+src-$(CONFIG_MACH_N32G45x) += ../lib/stm32f1/system_stm32f1xx.c
+src-$(CONFIG_MACH_N32G45x) += ../lib/n32g45x/n32g45x_adc.c stm32/n32g45x_adc.c
+src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c generic/armcm_timer.c stm32/i2c.c
src-$(CONFIG_MACH_STM32F2) += ../lib/stm32f2/system_stm32f2xx.c
src-$(CONFIG_MACH_STM32F2) += stm32/stm32f4.c generic/armcm_timer.c
src-$(CONFIG_MACH_STM32F2) += stm32/gpioperiph.c stm32/adc.c stm32/i2c.c
diff --git a/src/stm32/hard_pwm.c b/src/stm32/hard_pwm.c
index 0aafe7d4..6f7d8d08 100644
--- a/src/stm32/hard_pwm.c
+++ b/src/stm32/hard_pwm.c
@@ -20,7 +20,7 @@ struct gpio_pwm_info {
};
static const struct gpio_pwm_info pwm_regs[] = {
-#if CONFIG_MACH_STM32F103
+#if CONFIG_MACH_STM32F103 || CONFIG_MACH_N32G45x
{TIM2, GPIO('A', 0), 1, GPIO_FUNCTION(2)},
{TIM2, GPIO('A', 1), 2, GPIO_FUNCTION(2)},
{TIM2, GPIO('A', 2), 3, GPIO_FUNCTION(2)},
diff --git a/src/stm32/n32g45x_adc.c b/src/stm32/n32g45x_adc.c
new file mode 100644
index 00000000..d27e70c9
--- /dev/null
+++ b/src/stm32/n32g45x_adc.c
@@ -0,0 +1,185 @@
+// ADC functions on N32G45x
+//
+// Copyright (C) 2022-2023 Alexey Golyshin <stas2z@gmail.com>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "board/irq.h" // irq_save
+#include "board/misc.h" // timer_from_us
+#include "command.h" // shutdown
+#include "compiler.h" // ARRAY_SIZE
+#include "generic/armcm_timer.h" // udelay
+#include "gpio.h" // gpio_adc_setup
+#include "internal.h" // GPIO
+#include "sched.h" // sched_shutdown
+#include "n32g45x_adc.h" // ADC
+
+DECL_CONSTANT("ADC_MAX", 4095);
+
+#define ADC_TEMPERATURE_PIN 0xfe
+DECL_ENUMERATION("pin", "ADC_TEMPERATURE", ADC_TEMPERATURE_PIN);
+
+static const uint8_t adc_pins[] = {
+ // ADC1
+ 0, GPIO('A', 0), GPIO('A', 1), GPIO('A', 6),
+ GPIO('A', 3), GPIO('F', 4), 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ ADC_TEMPERATURE_PIN, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ // ADC2
+ 0, GPIO('A', 4), GPIO('A', 5), GPIO('B', 1),
+ GPIO('A', 7), GPIO('C', 4), GPIO('C', 0), GPIO('C', 1),
+ GPIO('C', 2), GPIO('C', 3), GPIO('F', 2), GPIO('A', 2),
+ GPIO('C', 5), GPIO('B', 2), 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+#if CONFIG_MACH_N32G455 // ADC3/4 for G455 only
+ // ADC3
+ 0, GPIO('B', 11), GPIO('E', 9), GPIO('E', 13),
+ GPIO('E', 12), GPIO('B', 13), GPIO('E', 8), GPIO('D', 10),
+ GPIO('D', 11), GPIO('D', 12), GPIO('D', 13), GPIO('D', 14),
+ GPIO('B', 0), GPIO('E', 7), GPIO('E', 10), GPIO('E', 11),
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ // ADC4
+ 0, GPIO('E', 14), GPIO('E', 15), GPIO('B', 12),
+ GPIO('B', 14), GPIO('B', 15), 0, 0,
+ 0, 0, 0, 0,
+ GPIO('D', 8), GPIO('D', 9), 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+#endif
+};
+
+// Perform calibration
+static void
+adc_calibrate(ADC_Module *adc)
+{
+ adc->CTRL2 = CTRL2_AD_ON_SET;
+ while (!(adc->CTRL3 & ADC_FLAG_RDY))
+ ;
+ adc->CTRL3 &= (~ADC_CTRL3_BPCAL_MSK);
+ udelay(10);
+ adc->CTRL2 = CTRL2_AD_ON_SET | CTRL2_CAL_SET;
+ while (adc->CTRL2 & CTRL2_CAL_SET)
+ ;
+}
+
+struct gpio_adc
+gpio_adc_setup(uint32_t pin)
+{
+ // Find pin in adc_pins table
+ int chan;
+ for (chan=0; ; chan++) {
+ if (chan >= ARRAY_SIZE(adc_pins))
+ shutdown("Not a valid ADC pin");
+ if (adc_pins[chan] == pin)
+ break;
+ }
+
+ // Determine which ADC block to use
+ ADC_Module *adc;
+ if ((chan >> 5) == 0)
+ adc = NS_ADC1;
+ if ((chan >> 5) == 1)
+ adc = NS_ADC2;
+ if ((chan >> 5) == 2)
+ adc = NS_ADC3;
+ if ((chan >> 5) == 3)
+ adc = NS_ADC4;
+ chan &= 0x1F;
+
+ // Enable the ADC
+ uint32_t reg_temp;
+ reg_temp = ADC_RCC_AHBPCLKEN;
+ reg_temp |= (RCC_AHB_PERIPH_ADC1 | RCC_AHB_PERIPH_ADC2 |
+ RCC_AHB_PERIPH_ADC3 | RCC_AHB_PERIPH_ADC4);
+ ADC_RCC_AHBPCLKEN = reg_temp;
+
+ reg_temp = ADC_RCC_CFG2;
+ reg_temp &= CFG2_ADCPLLPRES_RESET_MASK;
+ reg_temp |= RCC_ADCPLLCLK_DIV1;
+ reg_temp &= RCC_ADCPLLCLK_DISABLE;
+ ADC_RCC_CFG2 = reg_temp;
+
+ reg_temp = ADC_RCC_CFG2;
+ reg_temp &= CFG2_ADCHPRES_RESET_MASK;
+ reg_temp |= RCC_ADCHCLK_DIV16;
+ ADC_RCC_CFG2 = reg_temp;
+
+ ADC_InitType ADC_InitStructure;
+ ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT;
+ ADC_InitStructure.MultiChEn = 0;
+ ADC_InitStructure.ContinueConvEn = 0;
+ ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE;
+ ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R;
+ ADC_InitStructure.ChsNumber = 1;
+ ADC_Init(adc, &ADC_InitStructure);
+
+ adc_calibrate(adc);
+
+ if (pin == ADC_TEMPERATURE_PIN) {
+ NS_ADC1->CTRL2 |= CTRL2_TSVREFE_SET;
+ VREF1P2_CTRL |= (1<<10);
+ } else {
+ gpio_peripheral(pin, GPIO_ANALOG, 0);
+ }
+
+ return (struct gpio_adc){ .adc = adc, .chan = chan };
+}
+
+// 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)
+{
+ ADC_Module *adc = g.adc;
+ uint32_t sr = adc->STS;
+ if (sr & ADC_STS_STR) {
+ if (!(sr & ADC_STS_ENDC) || adc->RSEQ3 != g.chan)
+ // Conversion still in progress or busy on another channel
+ goto need_delay;
+ // Conversion ready
+ return 0;
+ }
+ // ADC timing: clock=4Mhz, Tconv=12.5, Tsamp=41.5, total=13.500us
+ ADC_ConfigRegularChannel(adc, g.chan, 1, ADC_SAMP_TIME_41CYCLES5);
+ adc->CTRL2 |= CTRL2_AD_ON_SET;
+ adc->CTRL2 |= CTRL2_EXT_TRIG_SWSTART_SET;
+
+need_delay:
+ return timer_from_us(20);
+}
+
+// Read a value; use only after gpio_adc_sample() returns zero
+uint16_t
+gpio_adc_read(struct gpio_adc g)
+{
+ ADC_Module *adc = g.adc;
+ adc->STS &= ~ADC_STS_ENDC;
+ adc->STS &= ~ADC_STS_STR;
+ adc->CTRL2 &= CTRL2_EXT_TRIG_SWSTART_RESET;
+ uint16_t result = adc->DAT;
+ return result;
+}
+
+// Cancel a sample that may have been started with gpio_adc_sample()
+void
+gpio_adc_cancel_sample(struct gpio_adc g)
+{
+ ADC_Module *adc = g.adc;
+ irqstatus_t flag = irq_save();
+ if (adc->STS & ADC_STS_STR)
+ gpio_adc_read(g);
+ irq_restore(flag);
+}
diff --git a/src/stm32/usbfs.c b/src/stm32/usbfs.c
index f7559efd..f2c3057f 100644
--- a/src/stm32/usbfs.c
+++ b/src/stm32/usbfs.c
@@ -15,7 +15,7 @@
#include "internal.h" // GPIO
#include "sched.h" // DECL_INIT
-#if CONFIG_MACH_STM32F103 || CONFIG_MACH_STM32G4
+#if CONFIG_MACH_STM32F103 || CONFIG_MACH_STM32G4 || CONFIG_MACH_N32G45x
// Transfer memory is accessed with 32bits, but contains only 16bits of data
typedef volatile uint32_t epmword_t;
#define WSIZE 2
diff --git a/test/klippy/printers.test b/test/klippy/printers.test
index 1e4b0e67..431bb8f5 100644
--- a/test/klippy/printers.test
+++ b/test/klippy/printers.test
@@ -196,6 +196,7 @@ CONFIG ../../config/printer-tronxy-xy-2-Pro-2020.cfg
CONFIG ../../config/printer-twotrees-sapphire-plus-sp-5-v1-2020.cfg
CONFIG ../../config/printer-twotrees-sapphire-plus-sp-5-v1.1-2021.cfg
CONFIG ../../config/printer-twotrees-sapphire-pro-sp-3-2020.cfg
+CONFIG ../../config/printer-voxelab-aquila-2021.cfg
# Printers using the stm32f401
DICTIONARY stm32f401.dict