Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Klipper3d/klipper.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Baker <baker.matt.j@gmail.com>2021-04-22 23:44:39 +0300
committerKevinOConnor <kevin@koconnor.net>2022-09-15 18:51:26 +0300
commitd9c917b95099617b32dfaca4ae90c9e2dd641fff (patch)
treea6a7adb3fec7d84a5fa0bbb75432a229b1ee7699
parent57b0eb5d43e4324c2c52282925ddc63fc36df783 (diff)
stm32l4: add stm32l412 support with adc,i2c,spi,usb
Signed-off-by: Matt Baker <baker.matt.j@gmail.com>
-rw-r--r--klippy/extras/temperature_mcu.py1
-rw-r--r--lib/README5
-rwxr-xr-xscripts/flash_usb.py3
-rw-r--r--src/stm32/Kconfig15
-rw-r--r--src/stm32/Makefile6
-rw-r--r--src/stm32/internal.h2
-rw-r--r--src/stm32/spi.c4
-rw-r--r--src/stm32/stm32f0_i2c.c29
-rw-r--r--src/stm32/stm32h7_adc.c104
-rw-r--r--src/stm32/stm32l4.c175
-rw-r--r--src/stm32/usbfs.c2
11 files changed, 313 insertions, 33 deletions
diff --git a/klippy/extras/temperature_mcu.py b/klippy/extras/temperature_mcu.py
index e82761b58..bf57bd192 100644
--- a/klippy/extras/temperature_mcu.py
+++ b/klippy/extras/temperature_mcu.py
@@ -72,6 +72,7 @@ class PrinterTemperatureMCU:
('stm32f070', self.config_stm32f070),
('stm32f072', self.config_stm32f0x2),
('stm32g0', self.config_stm32g0),
+ ('stm32l4', self.config_stm32g0),
('stm32h7', self.config_stm32h7),
('', self.config_unknown)]
for name, func in cfg_funcs:
diff --git a/lib/README b/lib/README
index eac029ff0..49f279263 100644
--- a/lib/README
+++ b/lib/README
@@ -68,6 +68,11 @@ The stm32g0 directory contains code from:
version v1.4.1 (5cb06333a6a43cefbe145f10a5aa98d3cc4cffee). Contents
taken from the Drivers/CMSIS/Device/ST/STM32G0xx/ directory.
+The stm32l4 directory contains code from:
+ https://github.com/STMicroelectronics/STM32CubeL4
+version v1.17.0 (5e1553e07706491bd11f4edd304e093b6e4b83a4). Contents
+taken from the Drivers/CMSIS/Device/ST/STM32L4xx/ directory.
+
The stm32h7 directory contains code from:
https://github.com/STMicroelectronics/STM32CubeH7
version v1.7.0 (79196b09acfb720589f58e93ccf956401b18a191). Contents
diff --git a/scripts/flash_usb.py b/scripts/flash_usb.py
index 3d62a643e..bf820de30 100755
--- a/scripts/flash_usb.py
+++ b/scripts/flash_usb.py
@@ -340,7 +340,8 @@ MCUTYPES = {
'same70': flash_atsam4, 'lpc176': flash_lpc176x, 'stm32f103': flash_stm32f1,
'stm32f4': flash_stm32f4, 'stm32f042': flash_stm32f4,
'stm32f072': flash_stm32f4, 'stm32g0b1': flash_stm32f4,
- 'stm32h7': flash_stm32f4, 'rp2040': flash_rp2040
+ 'stm32h7': flash_stm32f4, 'rp2040': flash_rp2040,
+ 'stm32l4': flash_stm32f4
}
diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig
index 96383ce39..8faa662dd 100644
--- a/src/stm32/Kconfig
+++ b/src/stm32/Kconfig
@@ -74,6 +74,9 @@ choice
config MACH_STM32H750
bool "STM32H750"
select MACH_STM32H7
+ config MACH_STM32L412
+ bool "STM32L412"
+ select MACH_STM32L4
endchoice
config MACH_STM32F103x6
@@ -96,9 +99,11 @@ config MACH_STM32F0x2 # F042, F072 series
bool
config MACH_STM32F4x5 # F405, F407, F429 series
bool
+config MACH_STM32L4
+ bool
config HAVE_STM32_USBFS
bool
- default y if MACH_STM32F0x2 || MACH_STM32G0
+ default y if MACH_STM32F0x2 || MACH_STM32G0 || MACH_STM32L4
default y if (MACH_STM32F103 || MACH_STM32F070) && !STM32_CLOCK_REF_INTERNAL
config HAVE_STM32_USBOTG
bool
@@ -132,6 +137,7 @@ config MCU
default "stm32g0b1xx" if MACH_STM32G0B1
default "stm32h743xx" if MACH_STM32H743
default "stm32h750xx" if MACH_STM32H750
+ default "stm32l412xx" if MACH_STM32L412
config CLOCK_FREQ
int
@@ -144,13 +150,14 @@ config CLOCK_FREQ
default 180000000 if MACH_STM32F446
default 64000000 if MACH_STM32G0
default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports
+ default 80000000 if MACH_STM32L412
config FLASH_SIZE
hex
default 0x4000 if MACH_STM32F031
default 0x8000 if MACH_STM32F042
default 0x20000 if MACH_STM32F070 || MACH_STM32F072
- default 0x10000 if MACH_STM32F103 # Flash size of stm32f103x8 (64KiB)
+ default 0x10000 if MACH_STM32F103 || MACH_STM32L412 # Flash size of stm32f103x8 (64KiB)
default 0x40000 if MACH_STM32F2 || MACH_STM32F401
default 0x80000 if MACH_STM32F4x5 || MACH_STM32F446
default 0x20000 if MACH_STM32G0B1
@@ -169,6 +176,7 @@ config RAM_SIZE
default 0x4000 if MACH_STM32F070 || MACH_STM32F072
default 0x2800 if MACH_STM32F103x6
default 0x5000 if MACH_STM32F103 && !MACH_STM32F103x6 # Ram size of stm32f103x8
+ default 0xa000 if MACH_STM32L412
default 0x20000 if MACH_STM32F207
default 0x10000 if MACH_STM32F401
default 0x20000 if MACH_STM32F4x5 || MACH_STM32F446
@@ -260,6 +268,8 @@ choice
bool "12 MHz crystal"
config STM32_CLOCK_REF_16M
bool "16 MHz crystal"
+ config STM32_CLOCK_REF_20M
+ bool "20 MHz crystal"
config STM32_CLOCK_REF_25M
bool "25 MHz crystal"
config STM32_CLOCK_REF_INTERNAL
@@ -268,6 +278,7 @@ endchoice
config CLOCK_REF_FREQ
int
default 25000000 if STM32_CLOCK_REF_25M
+ default 20000000 if STM32_CLOCK_REF_20M
default 16000000 if STM32_CLOCK_REF_16M
default 12000000 if STM32_CLOCK_REF_12M
default 1 if STM32_CLOCK_REF_INTERNAL
diff --git a/src/stm32/Makefile b/src/stm32/Makefile
index 2ff04f691..58132b062 100644
--- a/src/stm32/Makefile
+++ b/src/stm32/Makefile
@@ -10,6 +10,7 @@ dirs-$(CONFIG_MACH_STM32F2) += lib/stm32f2
dirs-$(CONFIG_MACH_STM32F4) += lib/stm32f4
dirs-$(CONFIG_MACH_STM32G0) += lib/stm32g0
dirs-$(CONFIG_MACH_STM32H7) += lib/stm32h7
+dirs-$(CONFIG_MACH_STM32L4) += lib/stm32l4
MCU := $(shell echo $(CONFIG_MCU))
MCU_UPPER := $(shell echo $(CONFIG_MCU) | tr a-z A-Z | tr X x)
@@ -20,6 +21,7 @@ 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
CFLAGS-$(CONFIG_MACH_STM32H7) += -mcpu=cortex-m7 -Ilib/stm32h7/include
+CFLAGS-$(CONFIG_MACH_STM32L4) += -mcpu=cortex-m4 -Ilib/stm32l4/include
CFLAGS += $(CFLAGS-y) -D$(MCU_UPPER) -mthumb -Ilib/cmsis-core -Ilib/fast-hash
CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs
@@ -48,6 +50,10 @@ src-$(CONFIG_MACH_STM32G0) += stm32/stm32f0_adc.c stm32/stm32f0_i2c.c
src-$(CONFIG_MACH_STM32H7) += ../lib/stm32h7/system_stm32h7xx.c
src-$(CONFIG_MACH_STM32H7) += stm32/stm32h7.c generic/armcm_timer.c
src-$(CONFIG_MACH_STM32H7) += stm32/gpioperiph.c stm32/stm32h7_adc.c
+src-$(CONFIG_MACH_STM32L4) += ../lib/stm32l4/system_stm32l4xx.c
+src-$(CONFIG_MACH_STM32L4) += stm32/stm32l4.c generic/armcm_timer.c
+src-$(CONFIG_MACH_STM32L4) += stm32/gpioperiph.c
+src-$(CONFIG_MACH_STM32L4) += stm32/stm32h7_adc.c stm32/stm32f0_i2c.c
spi-src-y := stm32/spi.c
spi-src-$(CONFIG_MACH_STM32H7) := stm32/stm32h7_spi.c
src-$(CONFIG_HAVE_GPIO_SPI) += $(spi-src-y)
diff --git a/src/stm32/internal.h b/src/stm32/internal.h
index f0535ab9f..38d005aef 100644
--- a/src/stm32/internal.h
+++ b/src/stm32/internal.h
@@ -16,6 +16,8 @@
#include "stm32g0xx.h"
#elif CONFIG_MACH_STM32H7
#include "stm32h7xx.h"
+#elif CONFIG_MACH_STM32L4
+#include "stm32l4xx.h"
#endif
// gpio.c
diff --git a/src/stm32/spi.c b/src/stm32/spi.c
index 3afe342ad..52ec69e1d 100644
--- a/src/stm32/spi.c
+++ b/src/stm32/spi.c
@@ -79,8 +79,8 @@ spi_setup(uint32_t bus, uint8_t mode, uint32_t rate)
gpio_peripheral(spi_bus[bus].mosi_pin, spi_bus[bus].function, 0);
gpio_peripheral(spi_bus[bus].sck_pin, spi_bus[bus].function, 0);
- // Configure CR2 on stm32f0
-#if CONFIG_MACH_STM32F0 || CONFIG_MACH_STM32G0
+ // Configure CR2 on stm32 f0/g0/l4
+#if CONFIG_MACH_STM32F0 || CONFIG_MACH_STM32G0 || CONFIG_MACH_STM32L4
spi->CR2 = SPI_CR2_FRXTH | (7 << SPI_CR2_DS_Pos);
#endif
}
diff --git a/src/stm32/stm32f0_i2c.c b/src/stm32/stm32f0_i2c.c
index 4c68779d0..418e1c1ec 100644
--- a/src/stm32/stm32f0_i2c.c
+++ b/src/stm32/stm32f0_i2c.c
@@ -27,13 +27,21 @@ DECL_ENUMERATION("i2c_bus", "i2c1", 0);
DECL_CONSTANT_STR("BUS_PINS_i2c1", "PB6,PB7");
DECL_ENUMERATION("i2c_bus", "i2c1a", 1);
DECL_CONSTANT_STR("BUS_PINS_i2c1a", "PF1,PF0");
-#elif CONFIG_MACH_STM32G0
+
+#elif CONFIG_MACH_STM32G0 || CONFIG_MACH_STM32L4
DECL_ENUMERATION("i2c_bus", "i2c1_PB6_PB7", 0);
DECL_CONSTANT_STR("BUS_PINS_i2c1_PB6_PB7", "PB6,PB7");
DECL_ENUMERATION("i2c_bus", "i2c1_PB8_PB9", 1);
DECL_CONSTANT_STR("BUS_PINS_i2c1_PB8_PB9", "PB8,PB9");
+#if CONFIG_MACH_STM32G0
+#define GPIO_AF_INDEX 6
DECL_ENUMERATION("i2c_bus", "i2c3_PB3_PB4", 2);
DECL_CONSTANT_STR("BUS_PINS_i2c3_PB3_PB4", "PB3,PB4");
+#elif CONFIG_MACH_STM32L4
+#define GPIO_AF_INDEX 4
+DECL_ENUMERATION("i2c_bus", "i2c3_PA7_PB4", 2);
+DECL_CONSTANT_STR("BUS_PINS_i2c3_PA7_PB4", "PA7,PB4");
+#endif
DECL_ENUMERATION("i2c_bus", "i2c2_PB10_PB11", 3);
DECL_CONSTANT_STR("BUS_PINS_i2c2_PB10_PB11", "PB10,PB11");
DECL_ENUMERATION("i2c_bus", "i2c2_PB13_PB14", 4);
@@ -47,13 +55,18 @@ static const struct i2c_info i2c_bus[] = {
{ I2C1, GPIO('B', 6), GPIO('B', 7), GPIO_FUNCTION(1) },
{ I2C1, GPIO('F', 1), GPIO('F', 0), GPIO_FUNCTION(1) },
{ I2C1, GPIO('B', 8), GPIO('B', 9), GPIO_FUNCTION(1) },
-#elif CONFIG_MACH_STM32G0
- { I2C1, GPIO('B', 6), GPIO('B', 7), GPIO_FUNCTION(6) },
- { I2C1, GPIO('B', 8), GPIO('B', 9), GPIO_FUNCTION(6) },
- { I2C3, GPIO('B', 3), GPIO('B', 4), GPIO_FUNCTION(6) },
- { I2C2, GPIO('B', 10), GPIO('B', 11), GPIO_FUNCTION(6) },
- { I2C2, GPIO('B', 13), GPIO('B', 14), GPIO_FUNCTION(6) },
- { I2C1, GPIO('A', 9), GPIO('A', 10), GPIO_FUNCTION(6) },
+
+#elif CONFIG_MACH_STM32G0 || CONFIG_MACH_STM32L4
+ { I2C1, GPIO('B', 6), GPIO('B', 7), GPIO_FUNCTION(GPIO_AF_INDEX) },
+ { I2C1, GPIO('B', 8), GPIO('B', 9), GPIO_FUNCTION(GPIO_AF_INDEX) },
+#if CONFIG_MACH_STM32G0
+ { I2C3, GPIO('B', 3), GPIO('B', 4), GPIO_FUNCTION(GPIO_AF_INDEX) },
+#elif CONFIG_MACH_STM32L4
+ { I2C3, GPIO('A', 7), GPIO('B', 4), GPIO_FUNCTION(GPIO_AF_INDEX) },
+#endif
+ { I2C2, GPIO('B', 10), GPIO('B', 11), GPIO_FUNCTION(GPIO_AF_INDEX) },
+ { I2C2, GPIO('B', 13), GPIO('B', 14), GPIO_FUNCTION(GPIO_AF_INDEX) },
+ { I2C1, GPIO('A', 9), GPIO('A', 10), GPIO_FUNCTION(GPIO_AF_INDEX) },
#endif
};
diff --git a/src/stm32/stm32h7_adc.c b/src/stm32/stm32h7_adc.c
index 00be6209e..d873dfb83 100644
--- a/src/stm32/stm32h7_adc.c
+++ b/src/stm32/stm32h7_adc.c
@@ -13,14 +13,36 @@
#include "internal.h" // GPIO
#include "sched.h" // sched_shutdown
+#if CONFIG_MACH_STM32H7
+#define ADCIN_BANK_SIZE (20)
+#define RCC_AHBENR_ADC (RCC->AHB1ENR)
+#define RCC_AHBENR_ADCEN (RCC_AHB1ENR_ADC12EN)
+#define ADC_CKMODE (0b11)
+#define ADC_ATICKS (0b101)
+#define ADC_RES (0b110)
+#define ADC_TS (ADC3_COMMON)
+
// Number of samples is 2^OVERSAMPLES_EXPONENT (exponent can be 0-10)
#define OVERSAMPLES_EXPONENT 3
#define OVERSAMPLES (1 << OVERSAMPLES_EXPONENT)
+#define ADC_MEAS_DELAY (1 + 2.3666*OVERSAMPLES)
// LDORDY registers are missing from CMSIS (only available on revision V!)
-#define ADC_ISR_LDORDY_Pos (12U)
-#define ADC_ISR_LDORDY_Msk (0x1UL << ADC_ISR_LDORDY_Pos)
-#define ADC_ISR_LDORDY ADC_ISR_LDORDY_Msk
+#define ADC_ISR_LDORDY_Pos (12U)
+#define ADC_ISR_LDORDY_Msk (0x1UL << ADC_ISR_LDORDY_Pos)
+#define ADC_ISR_LDORDY ADC_ISR_LDORDY_Msk
+
+#else // stm32l4
+#define RCC_AHBENR_ADC (RCC->AHB2ENR)
+#define RCC_AHBENR_ADCEN (RCC_AHB2ENR_ADCEN)
+#define ADC_CKMODE (0)
+#define ADC_ATICKS (0b100)
+#define ADC_RES (0b00)
+#define ADC_TS (ADC12_COMMON)
+
+#define OVERSAMPLES (0)
+#define ADC_MEAS_DELAY (10)
+#endif
#define ADC_TEMPERATURE_PIN 0xfe
DECL_ENUMERATION("pin", "ADC_TEMPERATURE", ADC_TEMPERATURE_PIN);
@@ -30,6 +52,7 @@ DECL_CONSTANT("ADC_MAX", 4095);
// GPIOs like A0_C are not covered!
// This always gives the pin connected to the positive channel
static const uint8_t adc_pins[] = {
+#if CONFIG_MACH_STM32H7
// ADC1
0, // PA0_C ADC12_INP0
0, // PA1_C ADC12_INP1
@@ -93,6 +116,27 @@ static const uint8_t adc_pins[] = {
0, // Vbat/4
ADC_TEMPERATURE_PIN,// VSENSE
0, // VREFINT
+#else // stm32l4
+ 0, // vref
+ GPIO('C', 0), // ADC12_IN1 .. 16
+ GPIO('C', 1),
+ GPIO('C', 2),
+ GPIO('C', 3),
+ GPIO('A', 0),
+ GPIO('A', 1),
+ GPIO('A', 2),
+ GPIO('A', 3),
+ GPIO('A', 4),
+ GPIO('A', 5),
+ GPIO('A', 6),
+ GPIO('A', 7),
+ GPIO('C', 4),
+ GPIO('C', 5),
+ GPIO('B', 0),
+ GPIO('B', 1),
+ ADC_TEMPERATURE_PIN, // temp
+ 0, // vbat
+#endif
};
@@ -115,25 +159,29 @@ gpio_adc_setup(uint32_t pin)
// (SYSCLK 480Mhz) /HPRE(2) /CKMODE divider(4) /additional divider(2)
// (ADC clock 30Mhz)
ADC_TypeDef *adc;
- if (chan >= 40){
+#ifdef ADC3
+ if (chan >= 2 * ADCIN_BANK_SIZE){
adc = ADC3;
if (!is_enabled_pclock(ADC3_BASE)) {
enable_pclock(ADC3_BASE);
}
MODIFY_REG(ADC3_COMMON->CCR, ADC_CCR_CKMODE_Msk,
- 0b11 << ADC_CCR_CKMODE_Pos);
- } else if (chan >= 20){
+ ADC_CKMODE << ADC_CCR_CKMODE_Pos);
+ chan -= 2 * ADCIN_BANK_SIZE;
+ } else if (chan >= ADCIN_BANK_SIZE){
adc = ADC2;
- RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN;
+ RCC_AHBENR_ADC |= RCC_AHBENR_ADCEN;
MODIFY_REG(ADC12_COMMON->CCR, ADC_CCR_CKMODE_Msk,
- 0b11 << ADC_CCR_CKMODE_Pos);
- } else{
+ ADC_CKMODE << ADC_CCR_CKMODE_Pos);
+ chan -= ADCIN_BANK_SIZE;
+ } else
+#endif
+ {
adc = ADC1;
- RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN;
+ RCC_AHBENR_ADC |= RCC_AHBENR_ADCEN;
MODIFY_REG(ADC12_COMMON->CCR, ADC_CCR_CKMODE_Msk,
- 0b11 << ADC_CCR_CKMODE_Pos);
+ ADC_CKMODE << ADC_CCR_CKMODE_Pos);
}
- chan %= 20;
// Enable the ADC
if (!(adc->CR & ADC_CR_ADEN)){
@@ -142,16 +190,27 @@ gpio_adc_setup(uint32_t pin)
MODIFY_REG(adc->CR, ADC_CR_DEEPPWD_Msk, 0);
// Switch on voltage regulator
adc->CR |= ADC_CR_ADVREGEN;
+#ifdef ADC_ISR_LDORDY
while(!(adc->ISR & ADC_ISR_LDORDY))
;
+#else // stm32l4 lacks ldordy, delay to spec instead
+ uint32_t end = timer_read_time() + timer_from_us(20);
+ while (timer_is_before(timer_read_time(), end))
+ ;
+#endif
+
// Set Boost mode for 25Mhz < ADC clock <= 50Mhz
+#ifdef ADC_CR_BOOST
MODIFY_REG(adc->CR, ADC_CR_BOOST_Msk, 0b11 << ADC_CR_BOOST_Pos);
+#endif
// Calibration
// Set calibration mode to Single ended (not differential)
MODIFY_REG(adc->CR, ADC_CR_ADCALDIF_Msk, 0);
// Enable linearity calibration
+#ifdef ADC_CR_ADCALLIN
MODIFY_REG(adc->CR, ADC_CR_ADCALLIN_Msk, ADC_CR_ADCALLIN);
+#endif
// Start the calibration
MODIFY_REG(adc->CR, ADC_CR_ADCAL_Msk, ADC_CR_ADCAL);
while(adc->CR & ADC_CR_ADCAL)
@@ -160,13 +219,14 @@ gpio_adc_setup(uint32_t pin)
// Enable ADC
// "Clear the ADRDY bit in the ADC_ISR register by writing ‘1’"
adc->ISR |= ADC_ISR_ADRDY;
+ adc->ISR; // Dummy read to make sure write is flushed
adc->CR |= ADC_CR_ADEN;
while(!(adc->ISR & ADC_ISR_ADRDY))
;
// Set 64.5 ADC clock cycles sample time for every channel
// (Reference manual pg.940)
- uint32_t aticks = 0b101;
+ uint32_t aticks = ADC_ATICKS;
// Channel 0-9
adc->SMPR1 = (aticks | (aticks << 3) | (aticks << 6)
| (aticks << 9) | (aticks << 12) | (aticks << 15)
@@ -180,23 +240,29 @@ gpio_adc_setup(uint32_t pin)
// Disable Continuous Mode
MODIFY_REG(adc->CFGR, ADC_CFGR_CONT_Msk, 0);
// Set to 12 bit
- MODIFY_REG(adc->CFGR, ADC_CFGR_RES_Msk, 0b110 << ADC_CFGR_RES_Pos);
+ MODIFY_REG(adc->CFGR, ADC_CFGR_RES_Msk, ADC_RES << ADC_CFGR_RES_Pos);
+#if CONFIG_MACH_STM32H7
// Set hardware oversampling
MODIFY_REG(adc->CFGR2, ADC_CFGR2_ROVSE_Msk, ADC_CFGR2_ROVSE);
MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSR_Msk,
(OVERSAMPLES - 1) << ADC_CFGR2_OVSR_Pos);
MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSS_Msk,
OVERSAMPLES_EXPONENT << ADC_CFGR2_OVSS_Pos);
+#else // stm32l4
+ adc->CFGR |= ADC_CFGR_JQDIS | ADC_CFGR_OVRMOD;
+#endif
}
if (pin == ADC_TEMPERATURE_PIN) {
- ADC3_COMMON->CCR |= ADC_CCR_TSEN;
+ ADC_TS->CCR |= ADC_CCR_TSEN;
} else {
gpio_peripheral(pin, GPIO_ANALOG, 0);
}
// Preselect (connect) channel
+#ifdef ADC_PCSEL_PCSEL
adc->PCSEL |= (1 << chan);
+#endif
return (struct gpio_adc){ .adc = adc, .chan = chan };
}
@@ -211,16 +277,16 @@ gpio_adc_sample(struct gpio_adc g)
// EOC flag is cleared by hardware when reading DR
// the channel condition only works if this ist the only channel
// on the sequence and length set to 1 (ADC_SQR1_L = 0000)
- if (adc->ISR & ADC_ISR_EOC && adc->SQR1 == (g.chan << 6))
+ if (adc->ISR & ADC_ISR_EOC && adc->SQR1 == (g.chan << ADC_SQR1_SQ1_Pos))
return 0;
// Conversion started but not ready or wrong channel
if (adc->CR & ADC_CR_ADSTART)
return timer_from_us(10);
// Start sample
- adc->SQR1 = (g.chan << 6);
+ adc->SQR1 = (g.chan << ADC_SQR1_SQ1_Pos);
adc->CR |= ADC_CR_ADSTART;
// Should take 2.3666us, add 1us for clock synchronisation etc.
- return timer_from_us(1 + 2.3666*OVERSAMPLES);
+ return timer_from_us(ADC_MEAS_DELAY);
}
// Read a value; use only after gpio_adc_sample() returns zero
@@ -239,7 +305,7 @@ gpio_adc_cancel_sample(struct gpio_adc g)
irqstatus_t flag = irq_save();
// ADSTART is not as long true as SR_STRT on stm32f4
if ((adc->CR & ADC_CR_ADSTART || adc->ISR & ADC_ISR_EOC)
- && adc->SQR1 == (g.chan << 6))
+ && adc->SQR1 == (g.chan << ADC_SQR1_SQ1_Pos))
gpio_adc_read(g);
irq_restore(flag);
}
diff --git a/src/stm32/stm32l4.c b/src/stm32/stm32l4.c
new file mode 100644
index 000000000..8fb50a23e
--- /dev/null
+++ b/src/stm32/stm32l4.c
@@ -0,0 +1,175 @@
+// Code to setup clocks and gpio on stm32l4
+//
+// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ
+#include "board/armcm_boot.h" // VectorTable
+#include "board/irq.h" // irq_disable
+#include "board/usb_cdc.h" // usb_request_bootloader
+#include "command.h" // DECL_CONSTANT_STR
+#include "internal.h" // enable_pclock
+#include "sched.h" // sched_main
+
+#define FREQ_PERIPH_DIV 1
+#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / FREQ_PERIPH_DIV)
+
+// Map a peripheral address to its enable bits
+struct cline
+lookup_clock_line(uint32_t periph_base)
+{
+ if (periph_base < APB2PERIPH_BASE) {
+ uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400;
+ if (pos < 32) {
+ return (struct cline){.en = &RCC->APB1ENR1,
+ .rst = &RCC->APB1RSTR1,
+ .bit = 1 << pos};
+ } else {
+ return (struct cline){.en = &RCC->APB1ENR2,
+ .rst = &RCC->APB1RSTR2,
+ .bit = 1 << (pos - 32)};
+ }
+ } else if (periph_base < AHB1PERIPH_BASE) {
+ uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400;
+ return (struct cline){.en = &RCC->APB2ENR,
+ .rst = &RCC->APB2RSTR,
+ .bit = 1 << pos};
+
+ } else if (periph_base < AHB2PERIPH_BASE) {
+ uint32_t pos = (periph_base - AHB1PERIPH_BASE) / 0x400;
+ return (struct cline){.en = &RCC->AHB1ENR,
+ .rst = &RCC->AHB1RSTR,
+ .bit = 1 << pos};
+
+ } else if (periph_base == ADC1_BASE) {
+ return (struct cline){.en = &RCC->AHB2ENR,
+ .rst = &RCC->AHB2RSTR,
+ .bit = RCC_AHB2ENR_ADCEN};
+ }
+ return (struct cline){.en = &RCC->AHB2ENR,
+ .rst = &RCC->AHB2RSTR,
+ .bit = 0};
+}
+
+// Return the frequency of the given peripheral clock
+uint32_t
+get_pclock_frequency(uint32_t periph_base)
+{
+ return FREQ_PERIPH;
+}
+
+// Enable a GPIO peripheral clock
+void
+gpio_clock_enable(GPIO_TypeDef *regs)
+{
+ uint32_t rcc_pos = ((uint32_t)regs - GPIOA_BASE) / 0x400;
+ RCC->AHB2ENR |= 1 << rcc_pos;
+ RCC->AHB2ENR;
+}
+
+#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 4096)
+#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT"
+
+// Handle USB reboot requests
+void
+usb_request_bootloader(void)
+{
+ irq_disable();
+ // System DFU Bootloader
+ *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG;
+ NVIC_SystemReset();
+}
+
+void
+bootloader_request(void)
+{
+ usb_request_bootloader();
+}
+
+#if !CONFIG_STM32_CLOCK_REF_INTERNAL
+DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PC14,PC15");
+#endif
+
+static void
+enable_clock_stm32l4(void)
+{
+ uint32_t pll_base = 4000000, pll_freq = CONFIG_CLOCK_FREQ * 2, pllcfgr;
+ if (!CONFIG_STM32_CLOCK_REF_INTERNAL) {
+ // Configure 80Mhz PLL from external crystal (HSE)
+ uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base - 1;
+ RCC->CR |= RCC_CR_HSEON;
+ while (!(RCC->CR & RCC_CR_HSERDY))
+ ;
+ pllcfgr = RCC_PLLCFGR_PLLSRC_HSE | (div << RCC_PLLCFGR_PLLM_Pos);
+ } else {
+ // Configure 80Mhz PLL from internal 16Mhz oscillator (HSI)
+ uint32_t div = 16000000 / pll_base - 1;
+ pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | (div << RCC_PLLCFGR_PLLM_Pos);
+ RCC->CR |= RCC_CR_HSION;
+ while (!(RCC->CR & RCC_CR_HSIRDY))
+ ;
+ }
+ RCC->PLLCFGR = (pllcfgr | ((pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos)
+ | (0 << RCC_PLLCFGR_PLLR_Pos));
+ RCC->CR |= RCC_CR_PLLON;
+
+ // Enable 48Mhz USB clock using clock recovery
+ if (CONFIG_USBSERIAL) {
+ RCC->CRRCR |= RCC_CRRCR_HSI48ON;
+ while (!(RCC->CRRCR & RCC_CRRCR_HSI48RDY))
+ ;
+ enable_pclock(CRS_BASE);
+ CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN;
+ enable_pclock(PWR_BASE);
+ PWR->CR2 |= PWR_CR2_USV;
+ }
+}
+
+// Main clock setup called at chip startup
+static void
+clock_setup(void)
+{
+ enable_clock_stm32l4();
+
+ // Set flash latency
+ uint32_t latency = ((CONFIG_CLOCK_FREQ>64000000) ? FLASH_ACR_LATENCY_4WS :
+ ((CONFIG_CLOCK_FREQ>48000000) ? FLASH_ACR_LATENCY_3WS :
+ ((CONFIG_CLOCK_FREQ>32000000) ? FLASH_ACR_LATENCY_2WS :
+ ((CONFIG_CLOCK_FREQ>16000000) ? FLASH_ACR_LATENCY_1WS :
+ FLASH_ACR_LATENCY_0WS))));
+ FLASH->ACR = (latency | FLASH_ACR_ICEN | FLASH_ACR_DCEN
+ | FLASH_ACR_PRFTEN);
+
+ // Wait for PLL lock
+ while (!(RCC->CR & RCC_CR_PLLRDY))
+ ;
+
+ RCC->PLLCFGR |= RCC_PLLCFGR_PLLREN;
+
+ // Switch system clock to PLL
+ RCC->CFGR = RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE1_DIV1 | RCC_CFGR_PPRE2_DIV1
+ | RCC_CFGR_SW_PLL;
+ while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL)
+ ;
+}
+
+// Main entry point - called from armcm_boot.c:ResetHandler()
+void
+armcm_main(void)
+{
+ if (CONFIG_USBSERIAL && *(uint64_t*)USB_BOOT_FLAG_ADDR == USB_BOOT_FLAG) {
+ *(uint64_t*)USB_BOOT_FLAG_ADDR = 0;
+ uint32_t *sysbase = (uint32_t*)0x1fff0000;
+ asm volatile("mov sp, %0\n bx %1"
+ : : "r"(sysbase[0]), "r"(sysbase[1]));
+ }
+
+ // Run SystemInit() and then restore VTOR
+ SystemInit();
+ SCB->VTOR = (uint32_t)VectorTable;
+
+ clock_setup();
+
+ sched_main();
+}
diff --git a/src/stm32/usbfs.c b/src/stm32/usbfs.c
index 1302d5231..cfe709513 100644
--- a/src/stm32/usbfs.c
+++ b/src/stm32/usbfs.c
@@ -20,7 +20,7 @@
typedef volatile uint32_t epmword_t;
#define WSIZE 2
#define USBx_IRQn USB_LP_IRQn
-#elif CONFIG_MACH_STM32F0
+#elif CONFIG_MACH_STM32F0 || CONFIG_MACH_STM32L4
// Transfer memory is accessed with 16bits and contains 16bits of data
typedef volatile uint16_t epmword_t;
#define WSIZE 2