stm32l4: add stm32l412 support with adc,i2c,spi,usb

Signed-off-by: Matt Baker <baker.matt.j@gmail.com>
This commit is contained in:
Matt Baker 2021-04-22 13:44:39 -07:00 committed by KevinOConnor
parent 57b0eb5d43
commit d9c917b950
11 changed files with 313 additions and 33 deletions

View File

@ -72,6 +72,7 @@ class PrinterTemperatureMCU:
('stm32f070', self.config_stm32f070), ('stm32f070', self.config_stm32f070),
('stm32f072', self.config_stm32f0x2), ('stm32f072', self.config_stm32f0x2),
('stm32g0', self.config_stm32g0), ('stm32g0', self.config_stm32g0),
('stm32l4', self.config_stm32g0),
('stm32h7', self.config_stm32h7), ('stm32h7', self.config_stm32h7),
('', self.config_unknown)] ('', self.config_unknown)]
for name, func in cfg_funcs: for name, func in cfg_funcs:

View File

@ -68,6 +68,11 @@ The stm32g0 directory contains code from:
version v1.4.1 (5cb06333a6a43cefbe145f10a5aa98d3cc4cffee). Contents version v1.4.1 (5cb06333a6a43cefbe145f10a5aa98d3cc4cffee). Contents
taken from the Drivers/CMSIS/Device/ST/STM32G0xx/ directory. 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: The stm32h7 directory contains code from:
https://github.com/STMicroelectronics/STM32CubeH7 https://github.com/STMicroelectronics/STM32CubeH7
version v1.7.0 (79196b09acfb720589f58e93ccf956401b18a191). Contents version v1.7.0 (79196b09acfb720589f58e93ccf956401b18a191). Contents

View File

@ -340,7 +340,8 @@ MCUTYPES = {
'same70': flash_atsam4, 'lpc176': flash_lpc176x, 'stm32f103': flash_stm32f1, 'same70': flash_atsam4, 'lpc176': flash_lpc176x, 'stm32f103': flash_stm32f1,
'stm32f4': flash_stm32f4, 'stm32f042': flash_stm32f4, 'stm32f4': flash_stm32f4, 'stm32f042': flash_stm32f4,
'stm32f072': flash_stm32f4, 'stm32g0b1': flash_stm32f4, 'stm32f072': flash_stm32f4, 'stm32g0b1': flash_stm32f4,
'stm32h7': flash_stm32f4, 'rp2040': flash_rp2040 'stm32h7': flash_stm32f4, 'rp2040': flash_rp2040,
'stm32l4': flash_stm32f4
} }

View File

@ -74,6 +74,9 @@ choice
config MACH_STM32H750 config MACH_STM32H750
bool "STM32H750" bool "STM32H750"
select MACH_STM32H7 select MACH_STM32H7
config MACH_STM32L412
bool "STM32L412"
select MACH_STM32L4
endchoice endchoice
config MACH_STM32F103x6 config MACH_STM32F103x6
@ -96,9 +99,11 @@ config MACH_STM32F0x2 # F042, F072 series
bool bool
config MACH_STM32F4x5 # F405, F407, F429 series config MACH_STM32F4x5 # F405, F407, F429 series
bool bool
config MACH_STM32L4
bool
config HAVE_STM32_USBFS config HAVE_STM32_USBFS
bool 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 default y if (MACH_STM32F103 || MACH_STM32F070) && !STM32_CLOCK_REF_INTERNAL
config HAVE_STM32_USBOTG config HAVE_STM32_USBOTG
bool bool
@ -132,6 +137,7 @@ config MCU
default "stm32g0b1xx" if MACH_STM32G0B1 default "stm32g0b1xx" if MACH_STM32G0B1
default "stm32h743xx" if MACH_STM32H743 default "stm32h743xx" if MACH_STM32H743
default "stm32h750xx" if MACH_STM32H750 default "stm32h750xx" if MACH_STM32H750
default "stm32l412xx" if MACH_STM32L412
config CLOCK_FREQ config CLOCK_FREQ
int int
@ -144,13 +150,14 @@ config CLOCK_FREQ
default 180000000 if MACH_STM32F446 default 180000000 if MACH_STM32F446
default 64000000 if MACH_STM32G0 default 64000000 if MACH_STM32G0
default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports
default 80000000 if MACH_STM32L412
config FLASH_SIZE config FLASH_SIZE
hex hex
default 0x4000 if MACH_STM32F031 default 0x4000 if MACH_STM32F031
default 0x8000 if MACH_STM32F042 default 0x8000 if MACH_STM32F042
default 0x20000 if MACH_STM32F070 || MACH_STM32F072 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 0x40000 if MACH_STM32F2 || MACH_STM32F401
default 0x80000 if MACH_STM32F4x5 || MACH_STM32F446 default 0x80000 if MACH_STM32F4x5 || MACH_STM32F446
default 0x20000 if MACH_STM32G0B1 default 0x20000 if MACH_STM32G0B1
@ -169,6 +176,7 @@ config RAM_SIZE
default 0x4000 if MACH_STM32F070 || MACH_STM32F072 default 0x4000 if MACH_STM32F070 || MACH_STM32F072
default 0x2800 if MACH_STM32F103x6 default 0x2800 if MACH_STM32F103x6
default 0x5000 if MACH_STM32F103 && !MACH_STM32F103x6 # Ram size of stm32f103x8 default 0x5000 if MACH_STM32F103 && !MACH_STM32F103x6 # Ram size of stm32f103x8
default 0xa000 if MACH_STM32L412
default 0x20000 if MACH_STM32F207 default 0x20000 if MACH_STM32F207
default 0x10000 if MACH_STM32F401 default 0x10000 if MACH_STM32F401
default 0x20000 if MACH_STM32F4x5 || MACH_STM32F446 default 0x20000 if MACH_STM32F4x5 || MACH_STM32F446
@ -260,6 +268,8 @@ choice
bool "12 MHz crystal" bool "12 MHz crystal"
config STM32_CLOCK_REF_16M config STM32_CLOCK_REF_16M
bool "16 MHz crystal" bool "16 MHz crystal"
config STM32_CLOCK_REF_20M
bool "20 MHz crystal"
config STM32_CLOCK_REF_25M config STM32_CLOCK_REF_25M
bool "25 MHz crystal" bool "25 MHz crystal"
config STM32_CLOCK_REF_INTERNAL config STM32_CLOCK_REF_INTERNAL
@ -268,6 +278,7 @@ endchoice
config CLOCK_REF_FREQ config CLOCK_REF_FREQ
int int
default 25000000 if STM32_CLOCK_REF_25M default 25000000 if STM32_CLOCK_REF_25M
default 20000000 if STM32_CLOCK_REF_20M
default 16000000 if STM32_CLOCK_REF_16M default 16000000 if STM32_CLOCK_REF_16M
default 12000000 if STM32_CLOCK_REF_12M default 12000000 if STM32_CLOCK_REF_12M
default 1 if STM32_CLOCK_REF_INTERNAL default 1 if STM32_CLOCK_REF_INTERNAL

View File

@ -10,6 +10,7 @@ dirs-$(CONFIG_MACH_STM32F2) += lib/stm32f2
dirs-$(CONFIG_MACH_STM32F4) += lib/stm32f4 dirs-$(CONFIG_MACH_STM32F4) += lib/stm32f4
dirs-$(CONFIG_MACH_STM32G0) += lib/stm32g0 dirs-$(CONFIG_MACH_STM32G0) += lib/stm32g0
dirs-$(CONFIG_MACH_STM32H7) += lib/stm32h7 dirs-$(CONFIG_MACH_STM32H7) += lib/stm32h7
dirs-$(CONFIG_MACH_STM32L4) += lib/stm32l4
MCU := $(shell echo $(CONFIG_MCU)) MCU := $(shell echo $(CONFIG_MCU))
MCU_UPPER := $(shell echo $(CONFIG_MCU) | tr a-z A-Z | tr X x) 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_STM32F4) += -mcpu=cortex-m4 -Ilib/stm32f4/include
CFLAGS-$(CONFIG_MACH_STM32G0) += -mcpu=cortex-m0plus -Ilib/stm32g0/include CFLAGS-$(CONFIG_MACH_STM32G0) += -mcpu=cortex-m0plus -Ilib/stm32g0/include
CFLAGS-$(CONFIG_MACH_STM32H7) += -mcpu=cortex-m7 -Ilib/stm32h7/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 += $(CFLAGS-y) -D$(MCU_UPPER) -mthumb -Ilib/cmsis-core -Ilib/fast-hash
CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs 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) += ../lib/stm32h7/system_stm32h7xx.c
src-$(CONFIG_MACH_STM32H7) += stm32/stm32h7.c generic/armcm_timer.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_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-y := stm32/spi.c
spi-src-$(CONFIG_MACH_STM32H7) := stm32/stm32h7_spi.c spi-src-$(CONFIG_MACH_STM32H7) := stm32/stm32h7_spi.c
src-$(CONFIG_HAVE_GPIO_SPI) += $(spi-src-y) src-$(CONFIG_HAVE_GPIO_SPI) += $(spi-src-y)

View File

@ -16,6 +16,8 @@
#include "stm32g0xx.h" #include "stm32g0xx.h"
#elif CONFIG_MACH_STM32H7 #elif CONFIG_MACH_STM32H7
#include "stm32h7xx.h" #include "stm32h7xx.h"
#elif CONFIG_MACH_STM32L4
#include "stm32l4xx.h"
#endif #endif
// gpio.c // gpio.c

View File

@ -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].mosi_pin, spi_bus[bus].function, 0);
gpio_peripheral(spi_bus[bus].sck_pin, spi_bus[bus].function, 0); gpio_peripheral(spi_bus[bus].sck_pin, spi_bus[bus].function, 0);
// Configure CR2 on stm32f0 // Configure CR2 on stm32 f0/g0/l4
#if CONFIG_MACH_STM32F0 || CONFIG_MACH_STM32G0 #if CONFIG_MACH_STM32F0 || CONFIG_MACH_STM32G0 || CONFIG_MACH_STM32L4
spi->CR2 = SPI_CR2_FRXTH | (7 << SPI_CR2_DS_Pos); spi->CR2 = SPI_CR2_FRXTH | (7 << SPI_CR2_DS_Pos);
#endif #endif
} }

View File

@ -27,13 +27,21 @@ DECL_ENUMERATION("i2c_bus", "i2c1", 0);
DECL_CONSTANT_STR("BUS_PINS_i2c1", "PB6,PB7"); DECL_CONSTANT_STR("BUS_PINS_i2c1", "PB6,PB7");
DECL_ENUMERATION("i2c_bus", "i2c1a", 1); DECL_ENUMERATION("i2c_bus", "i2c1a", 1);
DECL_CONSTANT_STR("BUS_PINS_i2c1a", "PF1,PF0"); 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_ENUMERATION("i2c_bus", "i2c1_PB6_PB7", 0);
DECL_CONSTANT_STR("BUS_PINS_i2c1_PB6_PB7", "PB6,PB7"); DECL_CONSTANT_STR("BUS_PINS_i2c1_PB6_PB7", "PB6,PB7");
DECL_ENUMERATION("i2c_bus", "i2c1_PB8_PB9", 1); DECL_ENUMERATION("i2c_bus", "i2c1_PB8_PB9", 1);
DECL_CONSTANT_STR("BUS_PINS_i2c1_PB8_PB9", "PB8,PB9"); 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_ENUMERATION("i2c_bus", "i2c3_PB3_PB4", 2);
DECL_CONSTANT_STR("BUS_PINS_i2c3_PB3_PB4", "PB3,PB4"); 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_ENUMERATION("i2c_bus", "i2c2_PB10_PB11", 3);
DECL_CONSTANT_STR("BUS_PINS_i2c2_PB10_PB11", "PB10,PB11"); DECL_CONSTANT_STR("BUS_PINS_i2c2_PB10_PB11", "PB10,PB11");
DECL_ENUMERATION("i2c_bus", "i2c2_PB13_PB14", 4); 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('B', 6), GPIO('B', 7), GPIO_FUNCTION(1) },
{ I2C1, GPIO('F', 1), GPIO('F', 0), GPIO_FUNCTION(1) }, { I2C1, GPIO('F', 1), GPIO('F', 0), GPIO_FUNCTION(1) },
{ I2C1, GPIO('B', 8), GPIO('B', 9), 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) }, #elif CONFIG_MACH_STM32G0 || CONFIG_MACH_STM32L4
{ I2C1, GPIO('B', 8), GPIO('B', 9), GPIO_FUNCTION(6) }, { I2C1, GPIO('B', 6), GPIO('B', 7), GPIO_FUNCTION(GPIO_AF_INDEX) },
{ I2C3, GPIO('B', 3), GPIO('B', 4), GPIO_FUNCTION(6) }, { I2C1, GPIO('B', 8), GPIO('B', 9), GPIO_FUNCTION(GPIO_AF_INDEX) },
{ I2C2, GPIO('B', 10), GPIO('B', 11), GPIO_FUNCTION(6) }, #if CONFIG_MACH_STM32G0
{ I2C2, GPIO('B', 13), GPIO('B', 14), GPIO_FUNCTION(6) }, { I2C3, GPIO('B', 3), GPIO('B', 4), GPIO_FUNCTION(GPIO_AF_INDEX) },
{ I2C1, GPIO('A', 9), GPIO('A', 10), GPIO_FUNCTION(6) }, #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 #endif
}; };

View File

@ -13,14 +13,36 @@
#include "internal.h" // GPIO #include "internal.h" // GPIO
#include "sched.h" // sched_shutdown #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) // Number of samples is 2^OVERSAMPLES_EXPONENT (exponent can be 0-10)
#define OVERSAMPLES_EXPONENT 3 #define OVERSAMPLES_EXPONENT 3
#define OVERSAMPLES (1 << OVERSAMPLES_EXPONENT) #define OVERSAMPLES (1 << OVERSAMPLES_EXPONENT)
#define ADC_MEAS_DELAY (1 + 2.3666*OVERSAMPLES)
// LDORDY registers are missing from CMSIS (only available on revision V!) // LDORDY registers are missing from CMSIS (only available on revision V!)
#define ADC_ISR_LDORDY_Pos (12U) #define ADC_ISR_LDORDY_Pos (12U)
#define ADC_ISR_LDORDY_Msk (0x1UL << ADC_ISR_LDORDY_Pos) #define ADC_ISR_LDORDY_Msk (0x1UL << ADC_ISR_LDORDY_Pos)
#define ADC_ISR_LDORDY ADC_ISR_LDORDY_Msk #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 #define ADC_TEMPERATURE_PIN 0xfe
DECL_ENUMERATION("pin", "ADC_TEMPERATURE", ADC_TEMPERATURE_PIN); DECL_ENUMERATION("pin", "ADC_TEMPERATURE", ADC_TEMPERATURE_PIN);
@ -30,6 +52,7 @@ DECL_CONSTANT("ADC_MAX", 4095);
// GPIOs like A0_C are not covered! // GPIOs like A0_C are not covered!
// This always gives the pin connected to the positive channel // This always gives the pin connected to the positive channel
static const uint8_t adc_pins[] = { static const uint8_t adc_pins[] = {
#if CONFIG_MACH_STM32H7
// ADC1 // ADC1
0, // PA0_C ADC12_INP0 0, // PA0_C ADC12_INP0
0, // PA1_C ADC12_INP1 0, // PA1_C ADC12_INP1
@ -93,6 +116,27 @@ static const uint8_t adc_pins[] = {
0, // Vbat/4 0, // Vbat/4
ADC_TEMPERATURE_PIN,// VSENSE ADC_TEMPERATURE_PIN,// VSENSE
0, // VREFINT 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) // (SYSCLK 480Mhz) /HPRE(2) /CKMODE divider(4) /additional divider(2)
// (ADC clock 30Mhz) // (ADC clock 30Mhz)
ADC_TypeDef *adc; ADC_TypeDef *adc;
if (chan >= 40){ #ifdef ADC3
if (chan >= 2 * ADCIN_BANK_SIZE){
adc = ADC3; adc = ADC3;
if (!is_enabled_pclock(ADC3_BASE)) { if (!is_enabled_pclock(ADC3_BASE)) {
enable_pclock(ADC3_BASE); enable_pclock(ADC3_BASE);
} }
MODIFY_REG(ADC3_COMMON->CCR, ADC_CCR_CKMODE_Msk, MODIFY_REG(ADC3_COMMON->CCR, ADC_CCR_CKMODE_Msk,
0b11 << ADC_CCR_CKMODE_Pos); ADC_CKMODE << ADC_CCR_CKMODE_Pos);
} else if (chan >= 20){ chan -= 2 * ADCIN_BANK_SIZE;
} else if (chan >= ADCIN_BANK_SIZE){
adc = ADC2; adc = ADC2;
RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN; RCC_AHBENR_ADC |= RCC_AHBENR_ADCEN;
MODIFY_REG(ADC12_COMMON->CCR, ADC_CCR_CKMODE_Msk, MODIFY_REG(ADC12_COMMON->CCR, ADC_CCR_CKMODE_Msk,
0b11 << ADC_CCR_CKMODE_Pos); ADC_CKMODE << ADC_CCR_CKMODE_Pos);
} else{ chan -= ADCIN_BANK_SIZE;
} else
#endif
{
adc = ADC1; adc = ADC1;
RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN; RCC_AHBENR_ADC |= RCC_AHBENR_ADCEN;
MODIFY_REG(ADC12_COMMON->CCR, ADC_CCR_CKMODE_Msk, 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 // Enable the ADC
if (!(adc->CR & ADC_CR_ADEN)){ 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); MODIFY_REG(adc->CR, ADC_CR_DEEPPWD_Msk, 0);
// Switch on voltage regulator // Switch on voltage regulator
adc->CR |= ADC_CR_ADVREGEN; adc->CR |= ADC_CR_ADVREGEN;
#ifdef ADC_ISR_LDORDY
while(!(adc->ISR & 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 // 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); MODIFY_REG(adc->CR, ADC_CR_BOOST_Msk, 0b11 << ADC_CR_BOOST_Pos);
#endif
// Calibration // Calibration
// Set calibration mode to Single ended (not differential) // Set calibration mode to Single ended (not differential)
MODIFY_REG(adc->CR, ADC_CR_ADCALDIF_Msk, 0); MODIFY_REG(adc->CR, ADC_CR_ADCALDIF_Msk, 0);
// Enable linearity calibration // Enable linearity calibration
#ifdef ADC_CR_ADCALLIN
MODIFY_REG(adc->CR, ADC_CR_ADCALLIN_Msk, ADC_CR_ADCALLIN); MODIFY_REG(adc->CR, ADC_CR_ADCALLIN_Msk, ADC_CR_ADCALLIN);
#endif
// Start the calibration // Start the calibration
MODIFY_REG(adc->CR, ADC_CR_ADCAL_Msk, ADC_CR_ADCAL); MODIFY_REG(adc->CR, ADC_CR_ADCAL_Msk, ADC_CR_ADCAL);
while(adc->CR & ADC_CR_ADCAL) while(adc->CR & ADC_CR_ADCAL)
@ -160,13 +219,14 @@ gpio_adc_setup(uint32_t pin)
// Enable ADC // Enable ADC
// "Clear the ADRDY bit in the ADC_ISR register by writing 1" // "Clear the ADRDY bit in the ADC_ISR register by writing 1"
adc->ISR |= ADC_ISR_ADRDY; adc->ISR |= ADC_ISR_ADRDY;
adc->ISR; // Dummy read to make sure write is flushed
adc->CR |= ADC_CR_ADEN; adc->CR |= ADC_CR_ADEN;
while(!(adc->ISR & ADC_ISR_ADRDY)) while(!(adc->ISR & ADC_ISR_ADRDY))
; ;
// Set 64.5 ADC clock cycles sample time for every channel // Set 64.5 ADC clock cycles sample time for every channel
// (Reference manual pg.940) // (Reference manual pg.940)
uint32_t aticks = 0b101; uint32_t aticks = ADC_ATICKS;
// Channel 0-9 // Channel 0-9
adc->SMPR1 = (aticks | (aticks << 3) | (aticks << 6) adc->SMPR1 = (aticks | (aticks << 3) | (aticks << 6)
| (aticks << 9) | (aticks << 12) | (aticks << 15) | (aticks << 9) | (aticks << 12) | (aticks << 15)
@ -180,23 +240,29 @@ gpio_adc_setup(uint32_t pin)
// Disable Continuous Mode // Disable Continuous Mode
MODIFY_REG(adc->CFGR, ADC_CFGR_CONT_Msk, 0); MODIFY_REG(adc->CFGR, ADC_CFGR_CONT_Msk, 0);
// Set to 12 bit // 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 // Set hardware oversampling
MODIFY_REG(adc->CFGR2, ADC_CFGR2_ROVSE_Msk, ADC_CFGR2_ROVSE); MODIFY_REG(adc->CFGR2, ADC_CFGR2_ROVSE_Msk, ADC_CFGR2_ROVSE);
MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSR_Msk, MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSR_Msk,
(OVERSAMPLES - 1) << ADC_CFGR2_OVSR_Pos); (OVERSAMPLES - 1) << ADC_CFGR2_OVSR_Pos);
MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSS_Msk, MODIFY_REG(adc->CFGR2, ADC_CFGR2_OVSS_Msk,
OVERSAMPLES_EXPONENT << ADC_CFGR2_OVSS_Pos); OVERSAMPLES_EXPONENT << ADC_CFGR2_OVSS_Pos);
#else // stm32l4
adc->CFGR |= ADC_CFGR_JQDIS | ADC_CFGR_OVRMOD;
#endif
} }
if (pin == ADC_TEMPERATURE_PIN) { if (pin == ADC_TEMPERATURE_PIN) {
ADC3_COMMON->CCR |= ADC_CCR_TSEN; ADC_TS->CCR |= ADC_CCR_TSEN;
} else { } else {
gpio_peripheral(pin, GPIO_ANALOG, 0); gpio_peripheral(pin, GPIO_ANALOG, 0);
} }
// Preselect (connect) channel // Preselect (connect) channel
#ifdef ADC_PCSEL_PCSEL
adc->PCSEL |= (1 << chan); adc->PCSEL |= (1 << chan);
#endif
return (struct gpio_adc){ .adc = adc, .chan = chan }; 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 // EOC flag is cleared by hardware when reading DR
// the channel condition only works if this ist the only channel // the channel condition only works if this ist the only channel
// on the sequence and length set to 1 (ADC_SQR1_L = 0000) // 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; return 0;
// Conversion started but not ready or wrong channel // Conversion started but not ready or wrong channel
if (adc->CR & ADC_CR_ADSTART) if (adc->CR & ADC_CR_ADSTART)
return timer_from_us(10); return timer_from_us(10);
// Start sample // Start sample
adc->SQR1 = (g.chan << 6); adc->SQR1 = (g.chan << ADC_SQR1_SQ1_Pos);
adc->CR |= ADC_CR_ADSTART; adc->CR |= ADC_CR_ADSTART;
// Should take 2.3666us, add 1us for clock synchronisation etc. // 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 // 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(); irqstatus_t flag = irq_save();
// ADSTART is not as long true as SR_STRT on stm32f4 // ADSTART is not as long true as SR_STRT on stm32f4
if ((adc->CR & ADC_CR_ADSTART || adc->ISR & ADC_ISR_EOC) 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); gpio_adc_read(g);
irq_restore(flag); irq_restore(flag);
} }

175
src/stm32/stm32l4.c Normal file
View File

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

View File

@ -20,7 +20,7 @@
typedef volatile uint32_t epmword_t; typedef volatile uint32_t epmword_t;
#define WSIZE 2 #define WSIZE 2
#define USBx_IRQn USB_LP_IRQn #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 // Transfer memory is accessed with 16bits and contains 16bits of data
typedef volatile uint16_t epmword_t; typedef volatile uint16_t epmword_t;
#define WSIZE 2 #define WSIZE 2