stm32: Add support for Nation N32G45x mcus (#6116)

N32G452/G455 are mostly compatible with STM32F103 but have M4 core and different ADC.

Signed-off-by: Alexey Golyshin <stas2z@gmail.com>
This commit is contained in:
Alexey
2023-04-07 19:20:14 +03:00
committed by GitHub
parent 27dab0ee51
commit 23e82d37f1
10 changed files with 845 additions and 10 deletions

View File

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

View File

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

View File

@@ -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)},

185
src/stm32/n32g45x_adc.c Normal file
View File

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

View File

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