diff --git a/ports/stm32f4/Makefile b/ports/stm32f4/Makefile index 4b660f244f..2727ea954f 100755 --- a/ports/stm32f4/Makefile +++ b/ports/stm32f4/Makefile @@ -121,7 +121,7 @@ LIBS += -lm endif # TinyUSB defines -CFLAGS += -DHSE_VALUE=8000000 -DCFG_TUSB_MCU=OPT_MCU_STM32F4 -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=4096 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_MIDI_TX_BUFSIZE=128 +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_STM32F4 -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=4096 -DCFG_TUD_MIDI_RX_BUFSIZE=128 -DCFG_TUD_MIDI_TX_BUFSIZE=128 ###################################### diff --git a/ports/stm32f4/boards/feather_f405/stm32f4xx_hal_conf.h b/ports/stm32f4/boards/feather_f405/stm32f4xx_hal_conf.h index a13e5ecfa3..7a1a9428f8 100644 --- a/ports/stm32f4/boards/feather_f405/stm32f4xx_hal_conf.h +++ b/ports/stm32f4/boards/feather_f405/stm32f4xx_hal_conf.h @@ -61,7 +61,7 @@ /* #define HAL_SD_MODULE_ENABLED */ /* #define HAL_MMC_MODULE_ENABLED */ #define HAL_SPI_MODULE_ENABLED -/* #define HAL_TIM_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED #define HAL_UART_MODULE_ENABLED /* #define HAL_USART_MODULE_ENABLED */ /* #define HAL_IRDA_MODULE_ENABLED */ diff --git a/ports/stm32f4/common-hal/pulseio/PWMOut.c b/ports/stm32f4/common-hal/pulseio/PWMOut.c index 78f7b212d7..ba5fc06c1d 100644 --- a/ports/stm32f4/common-hal/pulseio/PWMOut.c +++ b/ports/stm32f4/common-hal/pulseio/PWMOut.c @@ -4,6 +4,8 @@ * The MIT License (MIT) * * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2019 Lucian Copeland for Adafruit Industries + * Utilizes code from Micropython, Copyright (c) 2013-2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +31,32 @@ #include "common-hal/pulseio/PWMOut.h" #include "shared-bindings/pulseio/PWMOut.h" #include "supervisor/shared/translate.h" +#include "stm32f4xx_hal.h" + +#define PWM_MAX_FREQ 1000000 + +// Get the frequency (in Hz) of the source clock for the given timer. +// On STM32F405/407/415/417 there are 2 cases for how the clock freq is set. +// If the APB prescaler is 1, then the timer clock is equal to its respective +// APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its +// respective APB clock. See DM00031020 Rev 4, page 115. +static uint32_t timer_get_source_freq(uint32_t tim_id) { + uint32_t source, clk_div; + if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { + // TIM{1,8,9,10,11} are on APB2 + source = HAL_RCC_GetPCLK2Freq(); + clk_div = RCC->CFGR & RCC_CFGR_PPRE2; + } else { + // TIM{2,3,4,5,6,7,12,13,14} are on APB1 + source = HAL_RCC_GetPCLK1Freq(); + clk_div = RCC->CFGR & RCC_CFGR_PPRE1; + } + if (clk_div != 0) { + // APB prescaler for this timer is > 1 + source *= 2; + } + return source; +} void pwmout_reset(void) { } @@ -44,29 +72,56 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, uint16_t duty, uint32_t frequency, bool variable_frequency) { + //Using PB08: Tim4 Ch3 for testing + int tim_num = 10; + int tim_chan = TIM_CHANNEL_1; - __HAL_RCC_TIM4_CLK_ENABLE(); + GPIO_InitTypeDef GPIO_InitStruct = {0}; + GPIO_InitStruct.Pin = pin_mask(pin->number); + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = 3;//2; //2 is timer 4 + HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct); + + //__HAL_RCC_TIM4_CLK_ENABLE(); + __HAL_RCC_TIM10_CLK_ENABLE(); + + uint32_t source_freq = timer_get_source_freq(tim_num); + uint32_t period = PWM_MAX_FREQ/frequency; + mp_printf(&mp_plat_print, "SysCoreClock: %d\n", SystemCoreClock); + mp_printf(&mp_plat_print, "Source Freq: %d\n", source_freq); + mp_printf(&mp_plat_print, "Timer Freq: %d\n", source_freq/(source_freq / PWM_MAX_FREQ)); + mp_printf(&mp_plat_print, "Actual Freq: %d\n", (source_freq/(source_freq / PWM_MAX_FREQ))/period); + mp_printf(&mp_plat_print, "Period: %d\n", (PWM_MAX_FREQ/frequency)); TIM_HandleTypeDef tim = {0}; - tim.Instance = TIM4; - tim.Init.Period = LED_PWM_TIM_PERIOD - 1; - tim.Init.Prescaler = timer_get_source_freq(pwm_cfg->tim_id) / 1000000 - 1; // TIM runs at 1MHz + tim.Instance = TIM10; + tim.Init.Period = period - 1; + tim.Init.Prescaler = (source_freq / PWM_MAX_FREQ) - 1; // TIM runs at 16MHz tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; tim.Init.CounterMode = TIM_COUNTERMODE_UP; tim.Init.RepetitionCounter = 0; - HAL_TIM_PWM_Init(&tim); + if(HAL_TIM_PWM_Init(&tim) == HAL_OK) { + mp_printf(&mp_plat_print, "Tim Init Success\n"); + } // PWM configuration TIM_OC_InitTypeDef oc_init; oc_init.OCMode = TIM_OCMODE_PWM1; - oc_init.Pulse = 0; // off - oc_init.OCPolarity = MICROPY_HW_LED_INVERTED ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH; + oc_init.Pulse = (period*duty)/100 - 1; + oc_init.OCPolarity = TIM_OCPOLARITY_LOW; oc_init.OCFastMode = TIM_OCFAST_DISABLE; - oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH; // needed for TIM1 and TIM8 + oc_init.OCNPolarity = TIM_OCNPOLARITY_LOW; // needed for TIM1 and TIM8 oc_init.OCIdleState = TIM_OCIDLESTATE_SET; // needed for TIM1 and TIM8 oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET; // needed for TIM1 and TIM8 - HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, pwm_cfg->tim_channel); - HAL_TIM_PWM_Start(&tim, pwm_cfg->tim_channel); + if(HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, tim_chan) == HAL_OK) { + mp_printf(&mp_plat_print, "Channel Config Success\n"); + } + if(HAL_TIM_PWM_Start(&tim, tim_chan) == HAL_OK) { + mp_printf(&mp_plat_print, "Start Success\n"); + } + return PWMOUT_OK; } diff --git a/ports/stm32f4/mpconfigport.mk b/ports/stm32f4/mpconfigport.mk index ffe586898e..bce68f99f4 100644 --- a/ports/stm32f4/mpconfigport.mk +++ b/ports/stm32f4/mpconfigport.mk @@ -20,6 +20,7 @@ CIRCUITPY_DIGITALIO = 1 CIRCUITPY_ANALOGIO = 1 CIRCUITPY_MICROCONTROLLER = 1 CIRCUITPY_BUSIO = 1 +CIRCUITPY_PULSEIO = 1 CIRCUITPY_OS = 1 CIRCUITPY_STORAGE = 1 CIRCUITPY_RANDOM = 1