Skip to content

Commit

Permalink
hc32f460: Add support for hc32f460 micro-controllers
Browse files Browse the repository at this point in the history
Signed-off-by: Steven Gotthardt <gotthardt@gmail.com>
  • Loading branch information
SteveGotthardt authored and KevinOConnor committed Feb 13, 2023
1 parent 94cbf5f commit 72b6bd7
Show file tree
Hide file tree
Showing 11 changed files with 928 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ choice
bool "LPC176x (Smoothieboard)"
config MACH_STM32
bool "STMicroelectronics STM32"
config MACH_HC32F460
bool "Huada Semiconductor HC32F460"
config MACH_RP2040
bool "Raspberry Pi RP2040"
config MACH_PRU
Expand All @@ -35,6 +37,7 @@ source "src/atsam/Kconfig"
source "src/atsamd/Kconfig"
source "src/lpc176x/Kconfig"
source "src/stm32/Kconfig"
source "src/hc32f460/Kconfig"
source "src/rp2040/Kconfig"
source "src/pru/Kconfig"
source "src/linux/Kconfig"
Expand Down
79 changes: 79 additions & 0 deletions src/hc32f460/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Kconfig settings for Huada HC32F460 processor

if MACH_HC32F460

config HC32F460_SELECT
bool
default y
select HAVE_GPIO
select HAVE_GPIO_ADC
select HAVE_GPIO_BITBANGING
select HAVE_STRICT_TIMING
select HAVE_GPIO_HARD_PWM
select HAVE_STEPPER_BOTH_EDGE

config BOARD_DIRECTORY
string
default "hc32f460"


######################################################################
# Communication interface
######################################################################

choice
prompt "Communication interface"
config HC32F460_SERIAL_PA7_PA8
bool "Serial (PA7 & PA8) - Creality Ender 2 PRO"
select SERIAL
config HC32F460_SERIAL_PA3_PA2
bool "Serial (PA3 & PA2) - Anycube"
select SERIAL
config HC32F460_SERIAL_PA15_PA9
bool "Serial (PA15 & PA09) - Voxelab"
select SERIAL
config HC32F460_SERIAL_PC0_PC1
bool "Serial (PC0 & PC1) - on LCD connector"
select SERIAL
endchoice


######################################################################
# Bootloader
# bootloader moves code and then VTOR.RESET points here:
######################################################################
config FLASH_SIZE
hex
default 0x40000

config FLASH_APPLICATION_ADDRESS
default 0x8000 # Aquila is 0xC000

config FLASH_BOOT_ADDRESS
hex
default 0x0

config RAM_SIZE
hex
default 0x8000

# use the fast RAM in the HC32F460
config RAM_START
hex
default 0x1fff8000

config STACK_SIZE
int
default 1024


config CLOCK_FREQ
int
default 200000000 # Voxelab uses 168000000


config MCU
string
default "HC32F460"

endif
37 changes: 37 additions & 0 deletions src/hc32f460/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# hc32f460 build rules

# Setup the toolchain
CROSS_PREFIX=arm-none-eabi-

dirs-y += src/hc32f460 src/generic lib/hc32f460/driver/src lib/hc32f460/mcu/common

CFLAGS += -mthumb -mcpu=cortex-m4 -Isrc/hc32f460 -Ilib/hc32f460/driver/inc -Ilib/hc32f460/mcu/common -Ilib/cmsis-core -DHC32F460

CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs
CFLAGS_klipper.elf += -T $(OUT)src/generic/armcm_link.ld
$(OUT)klipper.elf: $(OUT)src/generic/armcm_link.ld

# Add source files
src-y += hc32f460/main.c
src-y += hc32f460/interrupts.c
src-y += hc32f460/gpio.c
src-y += ../lib/hc32f460/mcu/common/system_hc32f460.c
src-y += ../lib/hc32f460/driver/src/hc32f460_clk.c
src-y += ../lib/hc32f460/driver/src/hc32f460_efm.c
src-y += ../lib/hc32f460/driver/src/hc32f460_sram.c
src-y += ../lib/hc32f460/driver/src/hc32f460_utility.c
src-y += ../lib/hc32f460/driver/src/hc32f460_gpio.c
src-y += ../lib/hc32f460/driver/src/hc32f460_pwc.c
src-$(CONFIG_HAVE_GPIO_ADC) += hc32f460/adc.c ../lib/hc32f460/driver/src/hc32f460_adc.c
src-$(CONFIG_SERIAL) += hc32f460/serial.c generic/serial_irq.c ../lib/hc32f460/driver/src/hc32f460_usart.c
src-$(CONFIG_HAVE_GPIO_HARD_PWM) += hc32f460/hard_pwm.c ../lib/hc32f460/driver/src/hc32f460_timera.c
src-y += generic/armcm_boot.c generic/armcm_irq.c generic/armcm_timer.c
src-y += generic/armcm_reset.c generic/crc16_ccitt.c


# Build the additional bin output file
target-y += $(OUT)klipper.bin

$(OUT)klipper.bin: $(OUT)klipper.elf
@echo " Creating bin file $@"
$(Q)$(OBJCOPY) -O binary $< $@
155 changes: 155 additions & 0 deletions src/hc32f460/adc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// ADC functions on Huada HC32F460
//
// Copyright (C) 2022 Steven Gotthardt <gotthardt@gmail.com>
//
// This file may be distributed under the terms of the GNU GPLv3 license.

#include "generic/misc.h" // timer_from_us
#include "command.h" // shutdown
#include "board/gpio.h" // gpio_adc_setup
#include "board/internal.h" // GPIO
#include "sched.h" // sched_shutdown

// library
#include "hc32f460_adc.h"
#include "hc32f460_pwc.h"
#include "hc32f460_gpio.h"

#define ADC_RESOLUTION_12BIT (12u)
#define ADC_RESOLUTION_10BIT (10u)
#define ADC_RESOLUTION_8BIT (8u)

#define ADC1_RESOLUTION (ADC_RESOLUTION_12BIT)
#define ADC1_PRECISION (1ul << ADC1_RESOLUTION)

#if ADC1_RESOLUTION == ADC_RESOLUTION_12BIT
#define AdcResolution AdcResolution_12Bit
#elif ADC1_RESOLUTION == ADC_RESOLUTION_10BIT
#define AdcResolution AdcResolution_10Bit
#else
#define AdcResolution AdcResolution_8Bit
#endif


/* Timeout value definitions. Found in example code */
#define TIMEOUT_VAL (30u)

DECL_CONSTANT("ADC_MAX", ADC1_PRECISION-1);

// These pins can be used for ADC
static const uint8_t adc_gpio[] = {
GPIO('A', 0), // Chan 0
GPIO('A', 1), // Chan 1
GPIO('A', 2), // Chan 2
GPIO('A', 3), // Chan 3
GPIO('A', 4), // Chan 4
GPIO('A', 5), // Chan 5
GPIO('A', 6), // Chan 6
GPIO('A', 7), // Chan 7
GPIO('B', 0), // Chan 8
GPIO('B', 1), // Chan 9
GPIO('C', 0), // Chan 10 // TBed on TriGorilla
GPIO('C', 1), // Chan 11 // THead on TriGorilla
GPIO('C', 2), // Chan 12
GPIO('C', 3), // Chan 13
GPIO('C', 4), // Chan 14 // TBed on aquilla
GPIO('C', 5), // Chan 15 // THead on aquilla
};


struct gpio_adc
gpio_adc_setup(uint32_t gpio)
{
// validate pin in adc_pins table
int chan;
for (chan=0; ; chan++)
{
if (chan >= ARRAY_SIZE(adc_gpio))
{
shutdown("Not a valid ADC pin");
}
if (adc_gpio[chan] == gpio)
{
break;
}
}

// set as analog
gpio_peripheral(gpio, Pin_Mode_Ana, 0);

uint8_t sampleTime[ARRAY_SIZE(adc_gpio)] = { TIMEOUT_VAL }; // all chans
stc_adc_ch_cfg_t stcAdcChan;
stcAdcChan.u32Channel = 1 << chan;
stcAdcChan.u8Sequence = ADC_SEQ_A; // all conversions are in SEQ A
stcAdcChan.pu8SampTime = sampleTime;
ADC_AddAdcChannel(M4_ADC1, &stcAdcChan);

return (struct gpio_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)
{
// true if the sequence is finished
if (ADC_GetEocFlag(M4_ADC1, ADC_SEQ_A))
{
// all conversions are done - clear the flag
ADC_ClrEocFlag(M4_ADC1, ADC_SEQ_A);
return 0;
}
else if (M4_ADC1->STR & 1)
{
// running but not done yet
return timer_from_us(TIMEOUT_VAL/2);
}
else
{
// not running - so start
ADC_StartConvert(M4_ADC1);
}

return timer_from_us(TIMEOUT_VAL);
}


// Read a value; use only after gpio_adc_sample() returns zero
uint16_t
gpio_adc_read(struct gpio_adc g)
{
// return the one we want...
return ADC_GetValue(M4_ADC1, g.chan);
}


// Cancel a sample that may have been started with gpio_adc_sample()
void
gpio_adc_cancel_sample(struct gpio_adc g)
{
ADC_StopConvert(M4_ADC1);
}


// The clocks are already set by the loader.
// There is ADC1 and ADC2. Sequences do all channels at once.
void
adc_init(void)
{
// PCLK2 (ADC clock) is 'divide by 4', Max ADC clock is 60MHz
stc_adc_init_t stcAdcInit = {0};
stcAdcInit.enResolution = AdcResolution; // see define above
stcAdcInit.enDataAlign = AdcDataAlign_Right;
stcAdcInit.enAutoClear = AdcClren_Disable;
stcAdcInit.enScanMode = AdcMode_SAOnce;

// power-on ADC
PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);

// only using ADC1
ADC_Init(M4_ADC1, &stcAdcInit);
}

DECL_INIT(adc_init);

0 comments on commit 72b6bd7

Please sign in to comment.