stm32l4: add stm32l412 support with adc,i2c,spi,usb
Signed-off-by: Matt Baker <baker.matt.j@gmail.com>
This commit is contained in:
parent
57b0eb5d43
commit
d9c917b950
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include "stm32g0xx.h"
|
||||
#elif CONFIG_MACH_STM32H7
|
||||
#include "stm32h7xx.h"
|
||||
#elif CONFIG_MACH_STM32L4
|
||||
#include "stm32l4xx.h"
|
||||
#endif
|
||||
|
||||
// gpio.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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue