diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..f36c94d2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: cpp +compiler: gcc +cache: apt +sudo: required +dist: trusty +addons: + apt: + packages: + - gcc-arm-none-eabi + - libnewlib-arm-none-eabi +env: + +script: + - cd build_all && ./rebuild_all diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/inc/stm32f4xx_iwdg.h b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/inc/stm32f4xx_iwdg.h new file mode 100644 index 00000000..b3ceb1e4 --- /dev/null +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/inc/stm32f4xx_iwdg.h @@ -0,0 +1,131 @@ +/** + ****************************************************************************** + * @file stm32f4xx_iwdg.h + * @author MCD Application Team + * @version V1.6.0 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the IWDG + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_IWDG_H +#define __STM32F4xx_IWDG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx.h" + +/** @addtogroup STM32F4xx_StdPeriph_Driver + * @{ + */ + +/** @addtogroup IWDG + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup IWDG_Exported_Constants + * @{ + */ + +/** @defgroup IWDG_WriteAccess + * @{ + */ +#define IWDG_WriteAccess_Enable ((uint16_t)0x5555) +#define IWDG_WriteAccess_Disable ((uint16_t)0x0000) +#define IS_IWDG_WRITE_ACCESS(ACCESS) (((ACCESS) == IWDG_WriteAccess_Enable) || \ + ((ACCESS) == IWDG_WriteAccess_Disable)) +/** + * @} + */ + +/** @defgroup IWDG_prescaler + * @{ + */ +#define IWDG_Prescaler_4 ((uint8_t)0x00) +#define IWDG_Prescaler_8 ((uint8_t)0x01) +#define IWDG_Prescaler_16 ((uint8_t)0x02) +#define IWDG_Prescaler_32 ((uint8_t)0x03) +#define IWDG_Prescaler_64 ((uint8_t)0x04) +#define IWDG_Prescaler_128 ((uint8_t)0x05) +#define IWDG_Prescaler_256 ((uint8_t)0x06) +#define IS_IWDG_PRESCALER(PRESCALER) (((PRESCALER) == IWDG_Prescaler_4) || \ + ((PRESCALER) == IWDG_Prescaler_8) || \ + ((PRESCALER) == IWDG_Prescaler_16) || \ + ((PRESCALER) == IWDG_Prescaler_32) || \ + ((PRESCALER) == IWDG_Prescaler_64) || \ + ((PRESCALER) == IWDG_Prescaler_128)|| \ + ((PRESCALER) == IWDG_Prescaler_256)) +/** + * @} + */ + +/** @defgroup IWDG_Flag + * @{ + */ +#define IWDG_FLAG_PVU ((uint16_t)0x0001) +#define IWDG_FLAG_RVU ((uint16_t)0x0002) +#define IS_IWDG_FLAG(FLAG) (((FLAG) == IWDG_FLAG_PVU) || ((FLAG) == IWDG_FLAG_RVU)) +#define IS_IWDG_RELOAD(RELOAD) ((RELOAD) <= 0xFFF) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/* Prescaler and Counter configuration functions ******************************/ +void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess); +void IWDG_SetPrescaler(uint8_t IWDG_Prescaler); +void IWDG_SetReload(uint16_t Reload); +void IWDG_ReloadCounter(void); + +/* IWDG activation function ***************************************************/ +void IWDG_Enable(void); + +/* Flag management function ***************************************************/ +FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_IWDG_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/misc.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/misc.c index d9744dc3..20f69403 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/misc.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/misc.c @@ -75,10 +75,6 @@ /* Includes ------------------------------------------------------------------*/ #include "misc.h" -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_adc.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_adc.c index bd990f70..a61a45e2 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_adc.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_adc.c @@ -106,9 +106,6 @@ #include "stm32f4xx_adc.h" #include "stm32f4xx_rcc.h" -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_dma.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_dma.c index 23380989..9308681a 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_dma.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_dma.c @@ -124,10 +124,6 @@ #include "stm32f4xx_dma.h" #include "stm32f4xx_rcc.h" -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_exti.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_exti.c index 5864e8ed..0085a114 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_exti.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_exti.c @@ -67,10 +67,6 @@ /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_exti.h" -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_flash.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_flash.c index a7d7489b..b121fa4b 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_flash.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_flash.c @@ -83,12 +83,6 @@ #define FLASH_OPTCR_BFB2 ((uint32_t)0x00000010) #endif -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - -#define STM32F40_41xxx - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_iwdg.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_iwdg.c new file mode 100644 index 00000000..0534045c --- /dev/null +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_iwdg.c @@ -0,0 +1,266 @@ +/** + ****************************************************************************** + * @file stm32f4xx_iwdg.c + * @author MCD Application Team + * @version V1.6.0 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Independent watchdog (IWDG) peripheral: + * + Prescaler and Counter configuration + * + IWDG activation + * + Flag management + * + @verbatim + =============================================================================== + ##### IWDG features ##### + =============================================================================== + [..] + The IWDG can be started by either software or hardware (configurable + through option byte). + + The IWDG is clocked by its own dedicated low-speed clock (LSI) and + thus stays active even if the main clock fails. + Once the IWDG is started, the LSI is forced ON and cannot be disabled + (LSI cannot be disabled too), and the counter starts counting down from + the reset value of 0xFFF. When it reaches the end of count value (0x000) + a system reset is generated. + The IWDG counter should be reloaded at regular intervals to prevent + an MCU reset. + + The IWDG is implemented in the VDD voltage domain that is still functional + in STOP and STANDBY mode (IWDG reset can wake-up from STANDBY). + + IWDGRST flag in RCC_CSR register can be used to inform when a IWDG + reset occurs. + + Min-max timeout value @32KHz (LSI): ~125us / ~32.7s + The IWDG timeout may vary due to LSI frequency dispersion. STM32F4xx + devices provide the capability to measure the LSI frequency (LSI clock + connected internally to TIM5 CH4 input capture). The measured value + can be used to have an IWDG timeout with an acceptable accuracy. + For more information, please refer to the STM32F4xx Reference manual + + ##### How to use this driver ##### + =============================================================================== + [..] + (#) Enable write access to IWDG_PR and IWDG_RLR registers using + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable) function + + (#) Configure the IWDG prescaler using IWDG_SetPrescaler() function + + (#) Configure the IWDG counter value using IWDG_SetReload() function. + This value will be loaded in the IWDG counter each time the counter + is reloaded, then the IWDG will start counting down from this value. + + (#) Start the IWDG using IWDG_Enable() function, when the IWDG is used + in software mode (no need to enable the LSI, it will be enabled + by hardware) + + (#) Then the application program must reload the IWDG counter at regular + intervals during normal operation to prevent an MCU reset, using + IWDG_ReloadCounter() function. + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_iwdg.h" + +/** @addtogroup STM32F4xx_StdPeriph_Driver + * @{ + */ + +/** @defgroup IWDG + * @brief IWDG driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* KR register bit mask */ +#define KR_KEY_RELOAD ((uint16_t)0xAAAA) +#define KR_KEY_ENABLE ((uint16_t)0xCCCC) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup IWDG_Private_Functions + * @{ + */ + +/** @defgroup IWDG_Group1 Prescaler and Counter configuration functions + * @brief Prescaler and Counter configuration functions + * +@verbatim + =============================================================================== + ##### Prescaler and Counter configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables write access to IWDG_PR and IWDG_RLR registers. + * @param IWDG_WriteAccess: new state of write access to IWDG_PR and IWDG_RLR registers. + * This parameter can be one of the following values: + * @arg IWDG_WriteAccess_Enable: Enable write access to IWDG_PR and IWDG_RLR registers + * @arg IWDG_WriteAccess_Disable: Disable write access to IWDG_PR and IWDG_RLR registers + * @retval None + */ +void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess) +{ + /* Check the parameters */ + assert_param(IS_IWDG_WRITE_ACCESS(IWDG_WriteAccess)); + IWDG->KR = IWDG_WriteAccess; +} + +/** + * @brief Sets IWDG Prescaler value. + * @param IWDG_Prescaler: specifies the IWDG Prescaler value. + * This parameter can be one of the following values: + * @arg IWDG_Prescaler_4: IWDG prescaler set to 4 + * @arg IWDG_Prescaler_8: IWDG prescaler set to 8 + * @arg IWDG_Prescaler_16: IWDG prescaler set to 16 + * @arg IWDG_Prescaler_32: IWDG prescaler set to 32 + * @arg IWDG_Prescaler_64: IWDG prescaler set to 64 + * @arg IWDG_Prescaler_128: IWDG prescaler set to 128 + * @arg IWDG_Prescaler_256: IWDG prescaler set to 256 + * @retval None + */ +void IWDG_SetPrescaler(uint8_t IWDG_Prescaler) +{ + /* Check the parameters */ + assert_param(IS_IWDG_PRESCALER(IWDG_Prescaler)); + IWDG->PR = IWDG_Prescaler; +} + +/** + * @brief Sets IWDG Reload value. + * @param Reload: specifies the IWDG Reload value. + * This parameter must be a number between 0 and 0x0FFF. + * @retval None + */ +void IWDG_SetReload(uint16_t Reload) +{ + /* Check the parameters */ + assert_param(IS_IWDG_RELOAD(Reload)); + IWDG->RLR = Reload; +} + +/** + * @brief Reloads IWDG counter with value defined in the reload register + * (write access to IWDG_PR and IWDG_RLR registers disabled). + * @param None + * @retval None + */ +void IWDG_ReloadCounter(void) +{ + IWDG->KR = KR_KEY_RELOAD; +} + +/** + * @} + */ + +/** @defgroup IWDG_Group2 IWDG activation function + * @brief IWDG activation function + * +@verbatim + =============================================================================== + ##### IWDG activation function ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables IWDG (write access to IWDG_PR and IWDG_RLR registers disabled). + * @param None + * @retval None + */ +void IWDG_Enable(void) +{ + IWDG->KR = KR_KEY_ENABLE; +} + +/** + * @} + */ + +/** @defgroup IWDG_Group3 Flag management function + * @brief Flag management function + * +@verbatim + =============================================================================== + ##### Flag management function ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Checks whether the specified IWDG flag is set or not. + * @param IWDG_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg IWDG_FLAG_PVU: Prescaler Value Update on going + * @arg IWDG_FLAG_RVU: Reload Value Update on going + * @retval The new state of IWDG_FLAG (SET or RESET). + */ +FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_IWDG_FLAG(IWDG_FLAG)); + if ((IWDG->SR & IWDG_FLAG) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + /* Return the flag status */ + return bitstatus; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_rcc.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_rcc.c index 20844dd2..3be4f21f 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_rcc.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_rcc.c @@ -74,10 +74,6 @@ #define RCC_BDCR_LSEMOD ((uint32_t)0x00000008) #endif -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ @@ -261,7 +257,7 @@ void RCC_DeInit(void) RCC->PLLI2SCFGR = 0x20003000; #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F411xE || STM32F446xx || STM32F469_479xx */ -#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx) +#if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx) /* Reset PLLSAICFGR register, only available for STM32F42xxx/43xxx/446xx/469xx/479xx devices */ RCC->PLLSAICFGR = 0x24003000; #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F446xx || STM32F469_479xx */ @@ -827,7 +823,7 @@ void RCC_PLLSAIConfig(uint32_t PLLSAIM, uint32_t PLLSAIN, uint32_t PLLSAIP, uint } #endif /* STM32F446xx */ -#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F411xE) +#if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx) || defined(STM32F411xE) /** * @brief Configures the PLLSAI clock multiplication and division factors. * @@ -1660,7 +1656,7 @@ void RCC_I2SCLKConfig(uint32_t RCC_I2SCLKSource) } #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F411xE || STM32F469_479xx */ -#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F469_479xx) +#if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F469_479xx) /** * @brief Configures SAI1BlockA clock source selection. * diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_syscfg.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_syscfg.c index 1ddb5c95..ce68da6a 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_syscfg.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_syscfg.c @@ -50,10 +50,6 @@ #include "stm32f4xx_syscfg.h" #include "stm32f4xx_rcc.h" -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_tim.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_tim.c index ae347489..9df5c239 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_tim.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_tim.c @@ -119,10 +119,6 @@ #include "stm32f4xx_tim.h" #include "stm32f4xx_rcc.h" -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_wwdg.c b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_wwdg.c index b4c184f0..4d7b7f43 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_wwdg.c +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/src/stm32f4xx_wwdg.c @@ -84,10 +84,6 @@ #include "stm32f4xx_wwdg.h" #include "stm32f4xx_rcc.h" -#ifndef assert_param -#define assert_param(expr) ((void)0) -#endif - /** @addtogroup STM32F4xx_StdPeriph_Driver * @{ */ diff --git a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/stm32lib.mk b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/stm32lib.mk index ca3e95a9..dee65e88 100644 --- a/ChibiOS_3.0.2/ext/stdperiph_stm32f4/stm32lib.mk +++ b/ChibiOS_3.0.2/ext/stdperiph_stm32f4/stm32lib.mk @@ -7,6 +7,7 @@ STM32SRC = ${CHIBIOS}/ext/stdperiph_stm32f4/src/misc.c \ ${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_rcc.c \ ${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_syscfg.c \ ${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_tim.c \ + ${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_iwdg.c \ ${CHIBIOS}/ext/stdperiph_stm32f4/src/stm32f4xx_wwdg.c STM32INC = ${CHIBIOS}/ext/stdperiph_stm32f4/inc diff --git a/ChibiOS_3.0.2/os/ext/CMSIS/ST/stm32f4xx.h b/ChibiOS_3.0.2/os/ext/CMSIS/ST/stm32f4xx.h index 0d165bda..de4a3e0b 100644 --- a/ChibiOS_3.0.2/os/ext/CMSIS/ST/stm32f4xx.h +++ b/ChibiOS_3.0.2/os/ext/CMSIS/ST/stm32f4xx.h @@ -59,7 +59,7 @@ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - + /** @addtogroup Library_configuration_section * @{ */ @@ -125,6 +125,29 @@ #define STM32F407xx #endif +#if defined(STM32F439xx) || defined(STM32F429xx) +#define STM32F429_439xx + +#elif defined(STM32F437xx) || defined(STM32F427xx) +#define STM32F427_437xx + +#elif defined(STM32F405xx) || defined(STM32F415xx) || \ + defined(STM32F407xx) || defined(STM32F417xx) +#define STM32F40_41xxx + +#elif defined(STM32F401xC) || defined(STM32F401xE) +#define STM32F401xx + +#elif defined(STM32F411xE) +#define STM32F411xx + +#elif defined(STM32F2XX) + +#else +#error "STM32F2xx/F4xx device not specified" +#endif + + #if defined(STM32F405xx) #include "stm32f405xx.h" #elif defined(STM32F415xx) @@ -210,6 +233,32 @@ typedef enum #include "stm32f4xx_hal.h" #endif /* USE_HAL_DRIVER */ + +/* Uncomment the line below to expanse the "assert_param" macro in the + Standard Peripheral Library drivers code */ +//#define USE_FULL_ASSERT 1 + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT + +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #ifndef assert_param + #define assert_param(expr) ((void)0) + #endif +#endif /* USE_FULL_ASSERT */ + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/ChibiOS_3.0.2/os/hal/lib/streams/chprintf.c b/ChibiOS_3.0.2/os/hal/lib/streams/chprintf.c index 5f4ae4f8..49949e0e 100644 --- a/ChibiOS_3.0.2/os/hal/lib/streams/chprintf.c +++ b/ChibiOS_3.0.2/os/hal/lib/streams/chprintf.c @@ -73,7 +73,7 @@ static char *ch_ltoa(char *p, long num, unsigned radix) { } #if CHPRINTF_USE_FLOAT -static const long pow10[FLOAT_PRECISION] = { +static const long ch_pow10[FLOAT_PRECISION] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; @@ -82,7 +82,7 @@ static char *ftoa(char *p, double num, unsigned long precision) { if ((precision == 0) || (precision > FLOAT_PRECISION)) precision = FLOAT_PRECISION; - precision = pow10[precision - 1]; + precision = ch_pow10[precision - 1]; l = (long)num; p = long_to_string_with_divisor(p, l, 10, 0); diff --git a/ChibiOS_3.0.2/os/rt/src/chschd.c b/ChibiOS_3.0.2/os/rt/src/chschd.c index b75651d8..25a5701f 100644 --- a/ChibiOS_3.0.2/os/rt/src/chschd.c +++ b/ChibiOS_3.0.2/os/rt/src/chschd.c @@ -295,6 +295,7 @@ static void wakeup(void *p) { /* Falls through. */ case CH_STATE_WTCOND: #endif + /* Falls through. */ case CH_STATE_QUEUED: /* States requiring dequeuing.*/ (void) queue_dequeue(tp); diff --git a/Makefile b/Makefile index 66e04176..83fa6ed1 100644 --- a/Makefile +++ b/Makefile @@ -226,7 +226,7 @@ AOPT = TOPT = -mthumb -DTHUMB # Define C warning options here -CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes +CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes -Wshadow # Define C++ warning options here CPPWARN = -Wall -Wextra -Wundef diff --git a/README.md b/README.md index 6c535f30..da7c51e2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,90 @@ +# VESC firmware + +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) +[![Travis CI Status](https://travis-ci.com/paltatech/bldc.svg?branch=powerdesigns-dev)](https://travis-ci.com/paltatech/bldc) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/92eefb23a0c24b3cbed011b14ca0ffc9)](https://www.codacy.com/app/nitrousnrg/bldc?utm_source=github.com&utm_medium=referral&utm_content=paltatech/bldc&utm_campaign=Badge_Grade) +[![Contributors](https://img.shields.io/github/contributors/vedderb/bldc.svg)](https://github.com/vedderb/bldc/graphs/contributors) +[![Watchers](https://img.shields.io/github/watchers/vedderb/bldc.svg)](https://github.com/vedderb/bldc/watchers) +[![Stars](https://img.shields.io/github/stars/vedderb/bldc.svg)](https://github.com/vedderb/bldc/stargazers) +[![Forks](https://img.shields.io/github/forks/vedderb/bldc.svg)](https://github.com/vedderb/bldc/network/members) + +An open source motor controller firmware. + This is the source code for the VESC DC/BLDC/FOC controller. Read more at -http://vesc-project.com/ +[http://vesc-project.com/](http://vesc-project.com/) + +## Supported boards + +All of them! + +Make sure you select your board in [conf_general.h](conf_general.h) + + +```c +//#define HW_VERSION_40 +//#define HW_VERSION_45 +//#define HW_VERSION_46 // Also for 4.7 +//#define HW_VERSION_48 +//#define HW_VERSION_49 +//#define HW_VERSION_410 // Also for 4.11 and 4.12 +#define HW_VERSION_60 +//#define HW_VERSION_R2 +//#define HW_VERSION_VICTOR_R1A +//#define HW_VERSION_DAS_RS +//#define HW_VERSION_PALTA +//#define HW_VERSION_RH +//#define HW_VERSION_TP +//#define HW_VERSION_75_300 +//#define HW_VERSION_MINI4 +//#define HW_VERSION_DAS_MINI +``` +There are also many other options that can be changed in conf_general.h + + +## Prerequisites + +On an Ubuntu machine, install the gcc-arm-embedded toolchain + + +```bash +sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa +sudo apt update +sudo apt install gcc-arm-embedded +``` + +Add udev rules to use the stlink v2 programmer without being root + + +```bash +wget vedder.se/Temp/49-stlinkv2.rules +sudo mv 49-stlinkv2.rules /etc/udev/rules.d/ +sudo udevadm trigger +``` + +Build and flash the [bootloader](https://github.com/vedderb/bldc-bootloader) + + +## Build + +Clone and build the firmware + +```bash +git clone https://github.com/vedderb/bldc.git vesc_firmware +cd vesc_firmware +make +``` + +Flash it using an STLink SWD debugger + +```bash +make upload +``` + +## Contribute + +Head to the [forums](https://vesc-project.com/forum) to get involved and improve this project. + + +## License + +The software is released under the GNU General Public License version 3.0 diff --git a/applications/app_ppm.c b/applications/app_ppm.c index 0850c79d..df396116 100644 --- a/applications/app_ppm.c +++ b/applications/app_ppm.c @@ -287,13 +287,13 @@ static THD_FUNCTION(ppm_thread, arg) { } if (send_current && config.multi_esc) { - float current = mc_interface_get_tot_current_directional_filtered(); + float current_filtered = mc_interface_get_tot_current_directional_filtered(); for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) { can_status_msg *msg = comm_can_get_status_msg_index(i); if (msg->id >= 0 && UTILS_AGE_S(msg->rx_time) < MAX_CAN_AGE) { - comm_can_set_current(msg->id, current); + comm_can_set_current(msg->id, current_filtered); } } } diff --git a/buffer.c b/buffer.c index ba5dc72b..e3cef895 100644 --- a/buffer.c +++ b/buffer.c @@ -106,7 +106,7 @@ void buffer_append_float32_auto(uint8_t* buffer, float number, int32_t *index) { uint32_t res = ((e & 0xFF) << 23) | (sig_i & 0x7FFFFF); if (sig < 0) { - res |= 1 << 31; + res |= 1U << 31; } buffer_append_uint32(buffer, res, index); @@ -157,7 +157,7 @@ float buffer_get_float32_auto(const uint8_t *buffer, int32_t *index) { int e = (res >> 23) & 0xFF; uint32_t sig_i = res & 0x7FFFFF; - bool neg = res & (1 << 31); + bool neg = res & (1U << 31); float sig = 0.0; if (e != 0 || sig_i != 0) { diff --git a/build_all/PALTA/VESC_default.bin b/build_all/PALTA/VESC_default.bin new file mode 100755 index 00000000..5abeac2b Binary files /dev/null and b/build_all/PALTA/VESC_default.bin differ diff --git a/build_all/rebuild_all b/build_all/rebuild_all index 50ff8a69..cf3c1bf1 100755 --- a/build_all/rebuild_all +++ b/build_all/rebuild_all @@ -217,3 +217,20 @@ cd $FWPATH make clean cd $DIR +#################### HW PALTA ######################## + +COPYDIR=PALTA +rm $COPYDIR/* + +# default +cd $FWPATH +touch conf_general.h +make -j8 build_args='-DHW_SOURCE=\"hw_palta.c\" -DHW_HEADER=\"hw_palta.h\"' +cd $DIR +cp $FWPATH/build/BLDC_4_ChibiOS.bin $COPYDIR/VESC_default.bin + +# Clean +cd $FWPATH +make clean +cd $DIR + diff --git a/comm_can.c b/comm_can.c index ba4965f1..72c8aeb2 100644 --- a/comm_can.c +++ b/comm_can.c @@ -692,6 +692,9 @@ static THD_FUNCTION(cancom_read_thread, arg) { chEvtRegister(&HW_CAN_DEV.rxfull_event, &el, 0); while(!chThdShouldTerminateX()) { + // Feed watchdog + timeout_feed_WDT(THREAD_CANBUS); + if (chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(10)) == 0) { continue; } diff --git a/commands.c b/commands.c index 46a85ab9..b58c2465 100644 --- a/commands.c +++ b/commands.c @@ -472,7 +472,6 @@ void commands_process_packet(unsigned char *data, unsigned int len) { mcconf.m_dc_f_sw = buffer_get_float32_auto(data, &ind); mcconf.m_ntc_motor_beta = buffer_get_float32_auto(data, &ind); mcconf.m_out_aux_mode = data[ind++]; - mcconf.si_motor_poles = data[ind++]; mcconf.si_gear_ratio = buffer_get_float32_auto(data, &ind); mcconf.si_wheel_diameter = buffer_get_float32_auto(data, &ind); @@ -1342,6 +1341,12 @@ void commands_apply_mcconf_hw_limits(mc_configuration *mcconf) { utils_truncate_number(&mcconf->l_temp_fet_start, HW_LIM_TEMP_FET); utils_truncate_number(&mcconf->l_temp_fet_end, HW_LIM_TEMP_FET); #endif +#ifdef HW_LIM_FOC_CTRL_LOOP_FREQ + if (mcconf->foc_sample_v0_v7 == true) + utils_truncate_number(&mcconf->foc_f_sw, HW_LIM_FOC_CTRL_LOOP_FREQ); //control loop executes twice per pwm cycle when sampling in v0 and v7 + else + utils_truncate_number(&mcconf->foc_f_sw, HW_LIM_FOC_CTRL_LOOP_FREQ*2); +#endif #endif } diff --git a/conf_general.c b/conf_general.c index f6dac410..7b3dabf5 100644 --- a/conf_general.c +++ b/conf_general.c @@ -344,6 +344,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) { mc_interface_lock(); RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE); + timeout_configure_IWDT_slowest(); bool is_ok = true; uint8_t *conf_addr = (uint8_t*)conf; @@ -363,6 +364,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) { } RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); + timeout_configure_IWDT(); chThdSleepMilliseconds(100); mc_interface_unlock(); @@ -411,6 +413,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) { mc_interface_lock(); RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE); + timeout_configure_IWDT_slowest(); bool is_ok = true; uint8_t *conf_addr = (uint8_t*)conf; @@ -430,6 +433,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) { } RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); + timeout_configure_IWDT(); chThdSleepMilliseconds(100); mc_interface_unlock(); @@ -799,6 +803,61 @@ bool conf_general_measure_flux_linkage(float current, float duty, return true; } +/* Calculate DTG register */ +uint8_t conf_general_calculate_deadtime(float deadtime_ns, float core_clock_freq) { + uint8_t DTG = 0; + float timebase = 1/(core_clock_freq/1000000.0)*1000.0; + + if (deadtime_ns <= (timebase * 127.0) ) + DTG = deadtime_ns / timebase; + else { + if (deadtime_ns <= ((63.0 + 64.0)*2.0*timebase) ) { + DTG = deadtime_ns / (2.0*timebase) - 64.0; + DTG |= 0x80; + } + else { + if (deadtime_ns <= ((31.0 + 32.0)*8.0*timebase) ) { + DTG = deadtime_ns / (8.0*timebase) - 32.0; + DTG |= 0xC0; + } + else { + if (deadtime_ns <= ((31.0 + 32)*16*timebase) ) { + DTG = deadtime_ns / (16.0*timebase) - 32.0; + DTG |= 0xE0; + } + else { + // Deadtime requested is longer than max achievable. Set deadtime at + // longest possible value + DTG = 0xFF; + assert_param(1); //catch this + } + } + } + } + return DTG; +} + +/** + * Try to measure the motor flux linkage using open loop FOC control. + * + * @param current + * The Q-axis current to spin up the motor. + * + * @param duty + * Duty cycle % to measure at + * + * @param erpm_per_sec + * Acceleration rate + * + * @param res + * The motor phase resistance. + * + * @param linkage + * The calculated flux linkage. + * + * @return + * True for success, false otherwise. + */ bool conf_general_measure_flux_linkage_openloop(float current, float duty, float erpm_per_sec, float res, float *linkage) { bool result = false; @@ -1357,4 +1416,3 @@ int conf_general_detect_apply_all_foc_can(bool detect_can, float max_power_loss, return res; } - diff --git a/conf_general.h b/conf_general.h index 642a1e38..cd2a1c15 100644 --- a/conf_general.h +++ b/conf_general.h @@ -70,8 +70,8 @@ //#define HW_SOURCE "hw_410.c" // Also for 4.11 and 4.12 //#define HW_HEADER "hw_410.h" // Also for 4.11 and 4.12 -#define HW_SOURCE "hw_60.c" -#define HW_HEADER "hw_60.h" +//#define HW_SOURCE "hw_60.c" +//#define HW_HEADER "hw_60.h" //#define HW_SOURCE "hw_r2.c" //#define HW_HEADER "hw_r2.h" @@ -82,8 +82,8 @@ //#define HW_SOURCE "hw_das_rs.c" //#define HW_HEADER "hw_das_rs.h" -//#define HW_SOURCE "hw_palta.c" -//#define HW_HEADER "hw_palta.h" +#define HW_SOURCE "hw_palta.c" +#define HW_HEADER "hw_palta.h" //#define HW_SOURCE "hw_rh.c" //#define HW_HEADER "hw_rh.h" @@ -203,6 +203,16 @@ */ #define BLDC_SPEED_CONTROL_CURRENT 1 +/* + * Run the FOC loop once every N ADC ISR requests. This way the pwm frequency is + * detached from the FOC calculation, which because it takes ~25usec it can't work + * at >40khz. To set a 100kHz pwm FOC_CONTROL_LOOP_FREQ_DIVIDER can be set at 3 + * so it skips 2 ISR calls and execute the control loop in the 3rd call. + */ +#ifndef FOC_CONTROL_LOOP_FREQ_DIVIDER +#define FOC_CONTROL_LOOP_FREQ_DIVIDER 1 +#endif + // Global configuration variables extern bool conf_general_permanent_nrf_found; @@ -218,6 +228,7 @@ bool conf_general_detect_motor_param(float current, float min_rpm, float low_dut float *int_limit, float *bemf_coupling_k, int8_t *hall_table, int *hall_res); bool conf_general_measure_flux_linkage(float current, float duty, float min_erpm, float res, float *linkage); +uint8_t conf_general_calculate_deadtime(float deadtime_ns, float core_clock_freq); bool conf_general_measure_flux_linkage_openloop(float current, float duty, float erpm_per_sec, float res, float *linkage); int conf_general_autodetect_apply_sensors_foc(float current, diff --git a/datatypes.h b/datatypes.h index b203ef60..ec8a727f 100644 --- a/datatypes.h +++ b/datatypes.h @@ -85,7 +85,11 @@ typedef enum { FAULT_CODE_DRV, FAULT_CODE_ABS_OVER_CURRENT, FAULT_CODE_OVER_TEMP_FET, - FAULT_CODE_OVER_TEMP_MOTOR + FAULT_CODE_OVER_TEMP_MOTOR, + FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE, + FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE, + FAULT_CODE_MCU_UNDER_VOLTAGE, + FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET } mc_fault_code; typedef enum { @@ -606,6 +610,7 @@ typedef struct { float current; float current_filtered; float voltage; + float gate_driver_voltage; float duty; float rpm; int tacho; diff --git a/eeprom.c b/eeprom.c index 0d05d31a..c86bc06d 100644 --- a/eeprom.c +++ b/eeprom.c @@ -331,16 +331,23 @@ uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data) { uint16_t Status = 0; - /* Write the variable virtual address and value in the EEPROM */ - Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data); - - /* In case the EEPROM active page is full */ - if (Status == PAGE_FULL) + /* Return error if MCU VDD is below 2.9V */ + if (PWR->CSR & PWR_CSR_PVDO) { - /* Perform Page transfer */ - Status = EE_PageTransfer(VirtAddress, Data); + Status = FLASH_ERROR_PROGRAM; } + else + { + /* Write the variable virtual address and value in the EEPROM */ + Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data); + /* In case the EEPROM active page is full */ + if (Status == PAGE_FULL) + { + /* Perform Page transfer */ + Status = EE_PageTransfer(VirtAddress, Data); + } + } /* Return last operation status */ return Status; } diff --git a/flash_helper.c b/flash_helper.c index 51be09ea..0058b68b 100644 --- a/flash_helper.c +++ b/flash_helper.c @@ -23,6 +23,7 @@ #include "stm32f4xx_conf.h" #include "utils.h" #include "mc_interface.h" +#include "timeout.h" #include "hw.h" #include @@ -90,6 +91,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) { mc_interface_release_motor(); utils_sys_lock_cnt(); RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE); + timeout_configure_IWDT_slowest(); for (int i = 0;i < NEW_APP_SECTORS;i++) { if (new_app_size > flash_addr[NEW_APP_BASE + i]) { @@ -103,6 +105,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) { } RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); + timeout_configure_IWDT(); utils_sys_unlock_cnt(); return FLASH_COMPLETE; @@ -116,6 +119,7 @@ uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_ mc_interface_release_motor(); utils_sys_lock_cnt(); RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE); + timeout_configure_IWDT_slowest(); for (uint32_t i = 0;i < len;i++) { uint16_t res = FLASH_ProgramByte(flash_addr[NEW_APP_BASE] + offset + i, data[i]); @@ -125,6 +129,8 @@ uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_ } RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); + timeout_configure_IWDT(); + utils_sys_unlock_cnt(); return FLASH_COMPLETE; @@ -147,6 +153,7 @@ void flash_helper_jump_to_bootloader(void) { // Disable watchdog RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, DISABLE); + timeout_configure_IWDT_slowest(); chSysDisable(); diff --git a/gpdrive.c b/gpdrive.c index ca3292e5..66f7a371 100644 --- a/gpdrive.c +++ b/gpdrive.c @@ -159,7 +159,7 @@ void gpdrive_init(volatile mc_configuration *configuration) { TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; - TIM_BDTRInitStructure.TIM_DeadTime = HW_DEAD_TIME_VALUE; + TIM_BDTRInitStructure.TIM_DeadTime = conf_general_calculate_deadtime(HW_DEAD_TIME_NSEC, SYSTEM_CORE_CLOCK); TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; diff --git a/hwconf/hw_75_300.h b/hwconf/hw_75_300.h index f361cf83..82a1088d 100644 --- a/hwconf/hw_75_300.h +++ b/hwconf/hw_75_300.h @@ -230,7 +230,7 @@ #define READ_HALL3() palReadPad(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3) // Override dead time. See the stm32f4 reference manual for calculating this value. -#define HW_DEAD_TIME_VALUE 110 +#define HW_DEAD_TIME_NSEC 660.0 // Default setting overrides #ifndef MCCONF_L_MAX_VOLTAGE diff --git a/hwconf/hw_das_mini.h b/hwconf/hw_das_mini.h index 67a152bb..7dd8a15a 100644 --- a/hwconf/hw_das_mini.h +++ b/hwconf/hw_das_mini.h @@ -110,7 +110,7 @@ // Voltage on ADC channel #define ADC_VOLTS(ch) ((float)ADC_Value[ch] / 4096.0 * V_REG) -#define HW_DEAD_TIME_VALUE 20 +#define HW_DEAD_TIME_NSEC 120 // Double samples in beginning and end for positive current measurement. // Useful when the shunt sense traces have noise that causes offset. diff --git a/hwconf/hw_mini4.h b/hwconf/hw_mini4.h index 48d610db..934e6ef4 100644 --- a/hwconf/hw_mini4.h +++ b/hwconf/hw_mini4.h @@ -201,7 +201,7 @@ #define READ_HALL2() palReadPad(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2) #define READ_HALL3() palReadPad(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3) -#define HW_DEAD_TIME_VALUE 20 +#define HW_DEAD_TIME_NSEC 120.0 // Default setting overrides #ifndef MCCONF_DEFAULT_MOTOR_TYPE diff --git a/hwconf/hw_palta.c b/hwconf/hw_palta.c index ec41d27e..84cb7b5f 100644 --- a/hwconf/hw_palta.c +++ b/hwconf/hw_palta.c @@ -20,12 +20,34 @@ #include "ch.h" #include "hal.h" #include "stm32f4xx_conf.h" +#include "stm32f4xx_rcc.h" #include "utils.h" #include "terminal.h" #include "commands.h" +#include "hw_palta_fpga_bitstream.c" //this file ONLY contains the fpga binary blob + +// Defines +#define SPI_SW_MISO_GPIO HW_SPI_PORT_MISO +#define SPI_SW_MISO_PIN HW_SPI_PIN_MISO +#define SPI_SW_MOSI_GPIO HW_SPI_PORT_MOSI +#define SPI_SW_MOSI_PIN HW_SPI_PIN_MOSI +#define SPI_SW_SCK_GPIO HW_SPI_PORT_SCK +#define SPI_SW_SCK_PIN HW_SPI_PIN_SCK +#define SPI_SW_FPGA_CS_GPIO GPIOB +#define SPI_SW_FPGA_CS_PIN 7 + +#define PALTA_FPGA_CLK_PORT GPIOC +#define PALTA_FPGA_CLK_PIN 9 +#define PALTA_FPGA_RESET_PORT GPIOB +#define PALTA_FPGA_RESET_PIN 4 +#define BITSTREAM_SIZE 104090 //ice40up5k +//#define BITSTREAM_SIZE 71338 //ice40LP1K + // Variables static volatile bool i2c_running = false; +//extern unsigned char FPGA_bitstream[BITSTREAM_SIZE]; + // I2C configuration static const I2CConfig i2cfg = { @@ -36,8 +58,24 @@ static const I2CConfig i2cfg = { // Private functions static void terminal_cmd_reset_oc(int argc, const char **argv); +static void spi_transfer(uint8_t *in_buf, const uint8_t *out_buf, int length); +static void spi_begin(void); +static void spi_end(void); +static void spi_delay(void); +void hw_palta_init_FPGA_CLK(void); +void hw_palta_setup_dac(void); +void hw_palta_configure_brownout(uint8_t); +void hw_palta_configure_VDD_undervoltage(void); void hw_init_gpio(void) { + + // Set Brown out to keep mcu under reset until VDD reaches 2.7V + hw_palta_configure_brownout(OB_BOR_LEVEL3); + + // Configure Programmable voltage detector to interrupt the cpu + // when VDD is below 2.9V. + hw_palta_configure_VDD_undervoltage(); + // GPIO clock enable RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); @@ -48,7 +86,7 @@ void hw_init_gpio(void) { palSetPadMode(GPIOB, 2, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); - palSetPadMode(GPIOB, 1, + palSetPadMode(GPIOB, 11, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); @@ -59,12 +97,23 @@ void hw_init_gpio(void) { ENABLE_GATE(); - // OC latch - palSetPadMode(PALTA_OC_CLR_PORT, PALTA_OC_CLR_PIN, - PAL_MODE_OUTPUT_PUSHPULL | - PAL_STM32_OSPEED_HIGHEST); + // FPGA SPI port + palSetPadMode(SPI_SW_MISO_GPIO, SPI_SW_MISO_PIN, PAL_MODE_INPUT); + palSetPadMode(SPI_SW_SCK_GPIO, SPI_SW_SCK_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SPI_SW_FPGA_CS_GPIO, SPI_SW_FPGA_CS_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SPI_SW_MOSI_GPIO, SPI_SW_MOSI_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); - hw_palta_reset_oc(); + // Set FPGA SS to '0' to make it start in slave mode + palClearPad(SPI_SW_FPGA_CS_GPIO, SPI_SW_FPGA_CS_PIN); + + // FPGA RESET + palSetPadMode(PALTA_FPGA_RESET_PORT, PALTA_FPGA_RESET_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); + palClearPad(PALTA_FPGA_RESET_PORT, PALTA_FPGA_RESET_PIN); + chThdSleep(1); + palSetPad(PALTA_FPGA_RESET_PORT, PALTA_FPGA_RESET_PIN); + + //output a 12MHz clock on MCO2 + hw_palta_init_FPGA_CLK(); // GPIOA Configuration: Channel 1 to 3 as alternate function push-pull palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | @@ -101,14 +150,23 @@ void hw_init_gpio(void) { palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_ANALOG); palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG); +#ifdef PALTA_USE_DAC + hw_palta_setup_dac(); +#else + palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); //Temperature bridge A + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); //Temperature bridge B +#endif + palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_ANALOG); //Temperature bridge C + + palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG); //Accel 2 + palSetPadMode(GPIOB, 1, PAL_MODE_INPUT_ANALOG); //Gate driver supply voltage palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 5, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG); //Motor temp + palSetPadMode(GPIOC, 5, PAL_MODE_INPUT_ANALOG); //Accel 1 // Register terminal callbacks terminal_register_command_callback( @@ -116,6 +174,9 @@ void hw_init_gpio(void) { "Reset latched overcurrent fault.", 0, terminal_cmd_reset_oc); + + // Send bitstream over SPI to configure FPGA + hw_palta_configure_FPGA(); } void hw_setup_adc_channels(void) { @@ -124,7 +185,8 @@ void hw_setup_adc_channels(void) { ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 2, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 3, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_15Cycles); - ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 5, ADC_SampleTime_15Cycles); + //ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 5, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 5, ADC_SampleTime_15Cycles); // ADC2 regular channels ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_15Cycles); @@ -152,6 +214,69 @@ void hw_setup_adc_channels(void) { ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_15Cycles); } +void hw_palta_setup_dac(void) { + // GPIOA clock enable + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + + // DAC Periph clock enable + RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); + + // DAC channel 1 & 2 (DAC_OUT1 = PA.4)(DAC_OUT2 = PA.5) configuration + palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); + + // Enable both DAC channels with output buffer disabled to achieve rail-to-rail output + DAC->CR |= DAC_CR_EN1 | DAC_CR_BOFF1 | DAC_CR_EN2 | DAC_CR_BOFF2; + + // Set DAC channels at 1.65V + hw_palta_DAC1_setdata(0x800); + hw_palta_DAC2_setdata(0x800); +} + +void hw_palta_DAC1_setdata(uint16_t data) { + DAC->DHR12R1 = data; +} + +void hw_palta_DAC2_setdata(uint16_t data) { + DAC->DHR12R2 = data; +} + +void hw_palta_configure_brownout(uint8_t BOR_level) { + /* Get BOR Option Bytes */ + if((FLASH_OB_GetBOR() & 0x0C) != BOR_level) + { + /* Unlocks the option bytes block access */ + FLASH_OB_Unlock(); + + /* Select the desired V(BOR) Level -------------------------------------*/ + FLASH_OB_BORConfig(BOR_level); + + /* Launch the option byte loading */ + FLASH_OB_Launch(); + + /* Locks the option bytes block access */ + FLASH_OB_Lock(); + } +} + +void hw_palta_configure_VDD_undervoltage(void) { + + // partially configured in mcuconf.h -> STM32_PVD_ENABLE and STM32_PLS + + // Connect EXTI Line to pin + EXTI_InitTypeDef EXTI_InitStructure; + + // Configure EXTI Line + EXTI_InitStructure.EXTI_Line = EXTI_Line16; //Connected to Programmable Voltage Detector + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + // Enable and set EXTI Line Interrupt to the highest priority + nvicEnableVector(PVD_IRQn, 0); +} + void hw_start_i2c(void) { i2cAcquireBus(&HW_I2C_DEV); @@ -246,17 +371,112 @@ void hw_try_restore_i2c(void) { } } -void hw_palta_reset_oc(void) { - palClearPad(PALTA_OC_CLR_PORT, PALTA_OC_CLR_PIN); - chThdSleep(1); - palSetPad(PALTA_OC_CLR_PORT, PALTA_OC_CLR_PIN); -} - static void terminal_cmd_reset_oc(int argc, const char **argv) { (void)argc; (void)argv; - hw_palta_reset_oc(); + hw_palta_configure_FPGA(); commands_printf("Palta OC latch reset done!"); commands_printf(" "); } + +// Software SPI for FPGA control +static void spi_transfer(uint8_t *in_buf, const uint8_t *out_buf, int length) { + for (int i = 0;i < length;i++) { + uint8_t send = out_buf ? out_buf[i] : 0xFF; + uint8_t recieve = 0; + + for (int bit = 0;bit < 8;bit++) { + palWritePad(HW_SPI_PORT_MOSI, HW_SPI_PIN_MOSI, send >> 7); + send <<= 1; + + spi_delay(); + palSetPad(SPI_SW_SCK_GPIO, SPI_SW_SCK_PIN); + spi_delay(); + +/* + int r1, r2, r3; + r1 = palReadPad(SPI_SW_MISO_GPIO, SPI_SW_MISO_PIN); + __NOP(); + r2 = palReadPad(SPI_SW_MISO_GPIO, SPI_SW_MISO_PIN); + __NOP(); + r3 = palReadPad(SPI_SW_MISO_GPIO, SPI_SW_MISO_PIN); + + recieve <<= 1; + if (utils_middle_of_3_int(r1, r2, r3)) { + recieve |= 1; + } +*/ + + palClearPad(SPI_SW_SCK_GPIO, SPI_SW_SCK_PIN); + spi_delay(); + } + + if (in_buf) { + in_buf[i] = recieve; + } + } +} + +void hw_palta_init_FPGA_CLK(void) { + /* Configure PLLI2S prescalers */ + /* PLLI2S_VCO : VCO_192M */ + /* SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 192/4 = 48 Mhz */ + RCC->PLLI2SCFGR = (192 << 6) | (4 << 28); + /* Enable PLLI2S Clock */ + RCC_PLLI2SCmd(ENABLE); + + /* Wait till PLLI2S is ready */ + while(RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY) == RESET) + { + } + + /* Configure MCO2 pin(PC9) in alternate function */ + palSetPadMode(PALTA_FPGA_CLK_PORT, PALTA_FPGA_CLK_PIN, PAL_MODE_ALTERNATE(GPIO_AF_MCO) | + PAL_STM32_OTYPE_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_PULLUP); + + // HSE clock selected to output on MCO2 pin(PA8) 48MHz/4 = 12MHz + RCC_MCO2Config(RCC_MCO2Source_PLLI2SCLK, RCC_MCO2Div_4); +} + +char hw_palta_configure_FPGA(void) { + spi_begin(); + palSetPad(SPI_SW_SCK_GPIO, SPI_SW_SCK_PIN); + palClearPad(PALTA_FPGA_RESET_PORT, PALTA_FPGA_RESET_PIN); + chThdSleep(10); + palSetPad(PALTA_FPGA_RESET_PORT, PALTA_FPGA_RESET_PIN); + chThdSleep(20); + + spi_transfer(0, FPGA_bitstream, BITSTREAM_SIZE); + + //include 49 extra spi clock cycles, dummy bytes + uint8_t dummy = 0; + spi_transfer(0, &dummy, 7); + + spi_end(); + + // CDONE LED should be set by now + return 0; +} + +static void spi_begin(void) { + palClearPad(SPI_SW_FPGA_CS_GPIO, SPI_SW_FPGA_CS_PIN); +} + +static void spi_end(void) { + palSetPad(SPI_SW_FPGA_CS_GPIO, SPI_SW_FPGA_CS_PIN); +} + +static void spi_delay(void) { + __NOP(); + __NOP(); + __NOP(); + __NOP(); + + __NOP(); + __NOP(); + __NOP(); + __NOP(); +} diff --git a/hwconf/hw_palta.h b/hwconf/hw_palta.h index 294a3c7b..5f75e95e 100644 --- a/hwconf/hw_palta.h +++ b/hwconf/hw_palta.h @@ -22,6 +22,9 @@ #define HW_NAME "PALTA" +#define PALTA_USE_DAC +#define HW_VERSION_PALTA + // HW properties #define HW_HAS_3_SHUNTS #define HW_HAS_PHASE_SHUNTS @@ -35,11 +38,8 @@ #define LED_GREEN_ON() palSetPad(GPIOB, 2) #define LED_GREEN_OFF() palClearPad(GPIOB, 2) -#define LED_RED_ON() palSetPad(GPIOB, 1) -#define LED_RED_OFF() palClearPad(GPIOB, 1) - -#define PALTA_OC_CLR_PORT GPIOB -#define PALTA_OC_CLR_PIN 5 +#define LED_RED_ON() palSetPad(GPIOB, 11) +#define LED_RED_OFF() palClearPad(GPIOB, 11) /* * ADC Vector @@ -73,11 +73,12 @@ #define ADC_IND_CURR2 4 #define ADC_IND_CURR3 5 #define ADC_IND_VIN_SENS 11 +#define ADC_IND_VOUT_GATE_DRV 12 #define ADC_IND_EXT 10 #define ADC_IND_EXT2 6 #define ADC_IND_TEMP_MOS 8 #define ADC_IND_TEMP_MOTOR 9 -#define ADC_IND_VREFINT 12 +//#define ADC_IND_VREFINT 12 // ADC macros and settings @@ -86,16 +87,16 @@ #define V_REG 3.3 #endif #ifndef VIN_R1 -#define VIN_R1 294400.0 //TF RevB = 134.81V/V +#define VIN_R1 184.0 //TF since RevC = 185V/V #endif #ifndef VIN_R2 -#define VIN_R2 2200.0 +#define VIN_R2 1.0 #endif #ifndef CURRENT_AMP_GAIN -#define CURRENT_AMP_GAIN 8.0 +#define CURRENT_AMP_GAIN 0.003761 //Transfer Function [V/A] for ISB-425-A #endif #ifndef CURRENT_SHUNT_RES -#define CURRENT_SHUNT_RES 0.000415 //TF 300A/V +#define CURRENT_SHUNT_RES 1.000 // Unity gain so we use a single transfer function defined as CURRENT_AMP_GAIN #endif // Input voltage @@ -111,6 +112,9 @@ // Voltage on ADC channel #define ADC_VOLTS(ch) ((float)ADC_Value[ch] / 4096.0 * V_REG) +// Gate driver power supply output voltage +#define GET_GATE_DRIVER_SUPPLY_VOLTAGE() ((float)ADC_VOLTS(ADC_IND_VOUT_GATE_DRV) * 11.0) + // Double samples in beginning and end for positive current measurement. // Useful when the shunt sense traces have noise that causes offset. #ifndef CURR1_DOUBLE_SAMPLE @@ -131,8 +135,8 @@ #define HW_UART_GPIO_AF GPIO_AF_USART3 #define HW_UART_TX_PORT GPIOB #define HW_UART_TX_PIN 10 -#define HW_UART_RX_PORT GPIOB -#define HW_UART_RX_PIN 11 +#define HW_UART_RX_PORT GPIOD +#define HW_UART_RX_PIN 9 //Freeing B11 for fault LED. PD9 not available in LQFT64 package // ICU Peripheral for servo decoding #define HW_USE_SERVO_TIM4 @@ -199,10 +203,10 @@ #define HW_SPI_PIN_MISO 11 // Measurement macros -#define ADC_V_L1 ADC_Value[ADC_IND_SENS1] -#define ADC_V_L2 ADC_Value[ADC_IND_SENS2] -#define ADC_V_L3 ADC_Value[ADC_IND_SENS3] -#define ADC_V_ZERO (ADC_Value[ADC_IND_VIN_SENS] / 2) +#define ADC_V_L1 (ADC_Value[ADC_IND_SENS1]-2048) //phase voltages are centered in 1.65V +#define ADC_V_L2 (ADC_Value[ADC_IND_SENS2]-2048) +#define ADC_V_L3 (ADC_Value[ADC_IND_SENS3]-2048) +#define ADC_V_ZERO 0 //(ADC_Value[ADC_IND_VIN_SENS] / 2) // Macros #define READ_HALL1() palReadPad(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1) @@ -210,7 +214,10 @@ #define READ_HALL3() palReadPad(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3) // Override dead time. See the stm32f4 reference manual for calculating this value. -#define HW_DEAD_TIME_VALUE 181 +#define HW_DEAD_TIME_NSEC 1400.0 +#define HW_GATE_DRIVER_SUPPLY_MAX_VOLTAGE 16.0 +#define HW_GATE_DRIVER_SUPPLY_MIN_VOLTAGE 14.0 + // Default setting overrides #ifndef MCCONF_DEFAULT_MOTOR_TYPE @@ -220,17 +227,24 @@ #define MCCONF_FOC_SAMPLE_V0_V7 true // Run control loop in both v0 and v7 (requires phase shunts) #endif -// Setting limits (TODO: Configure these) -//#define HW_LIM_CURRENT -100.0, 100.0 -//#define HW_LIM_CURRENT_IN -100.0, 100.0 -//#define HW_LIM_CURRENT_ABS 0.0, 150.0 -//#define HW_LIM_VIN 6.0, 57.0 -//#define HW_LIM_ERPM -200e3, 200e3 -//#define HW_LIM_DUTY_MIN 0.0, 0.1 -//#define HW_LIM_DUTY_MAX 0.0, 1.0 -//#define HW_LIM_TEMP_FET -40.0, 110.0 +// Execute FOC loop once every "FOC_CONTROL_LOOP_FREQ_DIVIDER" ADC ISR calls +#define FOC_CONTROL_LOOP_FREQ_DIVIDER 1 + +// Setting limits +#define HW_LIM_CURRENT -200.0, 200.0 +#define HW_LIM_CURRENT_IN -100.0, 100.0 +#define HW_LIM_CURRENT_ABS 0.0, 230.0 +#define HW_LIM_VIN 6.0, 85.0 +#define HW_LIM_ERPM -100e3, 100e3 +#define HW_LIM_DUTY_MIN 0.0, 0.1 +#define HW_LIM_DUTY_MAX 0.0, 1.0 +#define HW_LIM_TEMP_FET -40.0, 110.0 +#define HW_LIM_FOC_CTRL_LOOP_FREQ 10000.0, 30000.0 //at around 38kHz the RTOS starts crashing (26us FOC ISR) + // HW-specific functions -void hw_palta_reset_oc(void); +char hw_palta_configure_FPGA(void); +void hw_palta_DAC1_setdata(uint16_t data); +void hw_palta_DAC2_setdata(uint16_t data); #endif /* HW_PALTA_H_ */ diff --git a/hwconf/hw_palta_fpga_bitstream.c b/hwconf/hw_palta_fpga_bitstream.c new file mode 100755 index 00000000..f53a48de --- /dev/null +++ b/hwconf/hw_palta_fpga_bitstream.c @@ -0,0 +1 @@ +const unsigned char FPGA_bitstream[71338] = {0}; diff --git a/irq_handlers.c b/irq_handlers.c index c6f1937c..b8a70069 100644 --- a/irq_handlers.c +++ b/irq_handlers.c @@ -59,3 +59,16 @@ CH_IRQ_HANDLER(TIM8_CC_IRQHandler) { TIM_ClearITPendingBit(TIM8, TIM_IT_CC1); } } + +CH_IRQ_HANDLER(PVD_IRQHandler) { + if (EXTI_GetITStatus(EXTI_Line16) != RESET) { + // Log the fault. Supply voltage dropped below 2.9V, + // could corrupt an ongoing flash programming + mc_interface_fault_stop(FAULT_CODE_MCU_UNDER_VOLTAGE); + + // Clear the PVD pending bit + EXTI_ClearITPendingBit(EXTI_Line16); + EXTI_ClearFlag(EXTI_Line16); + } +} + diff --git a/led_external.c b/led_external.c index d969e480..cc7e9455 100644 --- a/led_external.c +++ b/led_external.c @@ -74,8 +74,8 @@ static THD_FUNCTION(led_thread, arg) { for (int i = 0;i < 50;i++) { scale -= 0.02; uint32_t color = scale_color(COLOR_RED, scale); - for (int i = 0;i < (int)fault;i++) { - set_led_wrapper(i, color); + for (int j = 0;j < (int)fault;j++) { + set_led_wrapper(j, color); } chThdSleepMilliseconds(10); } diff --git a/main.c b/main.c index 5fb30488..e846708f 100644 --- a/main.c +++ b/main.c @@ -171,10 +171,19 @@ static THD_FUNCTION(timer_thread, arg) { for(;;) { packet_timerfunc(); + timeout_feed_WDT(THREAD_TIMER); chThdSleepMilliseconds(1); } } +/* When assertions enabled halve PWM frequency. The control loop ISR runs 40% slower */ +void assert_failed(uint8_t* file, uint32_t line) { + commands_printf("Wrong parameters value: file %s on line %d\r\n", file, line); + mc_interface_release_motor(); + while(1) + chThdSleepMilliseconds(1); +} + int main(void) { halInit(); chSysInit(); @@ -197,6 +206,7 @@ int main(void) { mc_configuration mcconf; conf_general_read_mc_configuration(&mcconf); + mc_interface_init(&mcconf); commands_init(); @@ -228,9 +238,6 @@ int main(void) { } #endif - timeout_init(); - timeout_configure(appconf.timeout_msec, appconf.timeout_brake_current); - #if WS2811_ENABLE ws2811_init(); #if !WS2811_TEST @@ -306,6 +313,9 @@ int main(void) { } #endif + timeout_init(); + timeout_configure(appconf.timeout_msec, appconf.timeout_brake_current); + for(;;) { chThdSleepMilliseconds(10); diff --git a/mc_interface.c b/mc_interface.c index 2b9bf648..995d7bb1 100644 --- a/mc_interface.c +++ b/mc_interface.c @@ -65,6 +65,7 @@ static volatile float m_watt_seconds_charged; static volatile float m_position_set; static volatile float m_temp_fet; static volatile float m_temp_motor; +static volatile float m_gate_driver_voltage; // Sampling variables #define ADC_SAMPLE_MAX_LEN 2000 @@ -78,6 +79,7 @@ __attribute__((section(".ram4"))) static volatile uint8_t m_status_samples[ADC_S __attribute__((section(".ram4"))) static volatile int16_t m_curr_fir_samples[ADC_SAMPLE_MAX_LEN]; __attribute__((section(".ram4"))) static volatile int16_t m_f_sw_samples[ADC_SAMPLE_MAX_LEN]; __attribute__((section(".ram4"))) static volatile int8_t m_phase_samples[ADC_SAMPLE_MAX_LEN]; + static volatile int m_sample_len; static volatile int m_sample_int; static volatile debug_sampling_mode m_sample_mode; @@ -122,6 +124,7 @@ void mc_interface_init(mc_configuration *configuration) { m_last_adc_duration_sample = 0.0; m_temp_fet = 0.0; m_temp_motor = 0.0; + m_gate_driver_voltage = 0.0; m_sample_len = 1000; m_sample_int = 1; @@ -343,6 +346,10 @@ const char* mc_interface_fault_to_string(mc_fault_code fault) { case FAULT_CODE_ABS_OVER_CURRENT: return "FAULT_CODE_ABS_OVER_CURRENT"; break; case FAULT_CODE_OVER_TEMP_FET: return "FAULT_CODE_OVER_TEMP_FET"; break; case FAULT_CODE_OVER_TEMP_MOTOR: return "FAULT_CODE_OVER_TEMP_MOTOR"; break; + case FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE: return "FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE"; break; + case FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE: return "FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE"; break; + case FAULT_CODE_MCU_UNDER_VOLTAGE: return "FAULT_CODE_MCU_UNDER_VOLTAGE"; break; + case FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET: return "FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET"; break; default: return "FAULT_UNKNOWN"; break; } } @@ -1190,6 +1197,7 @@ void mc_interface_fault_stop(mc_fault_code fault) { fdata.current = mc_interface_get_tot_current(); fdata.current_filtered = mc_interface_get_tot_current_filtered(); fdata.voltage = GET_INPUT_VOLTAGE(); + fdata.gate_driver_voltage = m_gate_driver_voltage; fdata.duty = mc_interface_get_duty_cycle_now(); fdata.rpm = mc_interface_get_rpm(); fdata.tacho = mc_interface_get_tachometer_value(false); @@ -1303,6 +1311,16 @@ void mc_interface_mc_timer_isr(void) { mc_interface_fault_stop(FAULT_CODE_DRV); } +#ifdef HW_VERSION_PALTA + if( m_gate_driver_voltage > HW_GATE_DRIVER_SUPPLY_MAX_VOLTAGE) { + mc_interface_fault_stop(FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE); + } + + if( m_gate_driver_voltage < HW_GATE_DRIVER_SUPPLY_MIN_VOLTAGE) { + mc_interface_fault_stop(FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE); + } +#endif + // Watt and ah counters const float f_samp = mc_interface_get_sampling_frequency_now(); if (fabsf(current) > 1.0) { @@ -1498,6 +1516,9 @@ static void update_override_limits(volatile mc_configuration *conf) { UTILS_LP_FAST(m_temp_fet, NTC_TEMP(ADC_IND_TEMP_MOS), 0.1); UTILS_LP_FAST(m_temp_motor, NTC_TEMP_MOTOR(conf->m_ntc_motor_beta), 0.1); +#ifdef HW_VERSION_PALTA + UTILS_LP_FAST(m_gate_driver_voltage, GET_GATE_DRIVER_SUPPLY_VOLTAGE(), 0.01); +#endif const float l_current_min_tmp = conf->l_current_min * conf->l_current_min_scale; const float l_current_max_tmp = conf->l_current_max * conf->l_current_max_scale; diff --git a/mc_interface.h b/mc_interface.h index ded1563c..b5fba7f9 100644 --- a/mc_interface.h +++ b/mc_interface.h @@ -91,8 +91,9 @@ extern volatile uint16_t ADC_Value[]; extern volatile int ADC_curr_norm_value[]; // Common fixed parameters -#ifndef HW_DEAD_TIME_VALUE -#define HW_DEAD_TIME_VALUE 60 // Dead time +#ifndef HW_DEAD_TIME_NSEC +#define HW_DEAD_TIME_NSEC 360.0 // Dead time #endif + #endif /* MC_INTERFACE_H_ */ diff --git a/mcpwm.c b/mcpwm.c index 09a48f18..1ca610b2 100644 --- a/mcpwm.c +++ b/mcpwm.c @@ -30,6 +30,7 @@ #include "utils.h" #include "ledpwm.h" #include "terminal.h" +#include "timeout.h" #include "encoder.h" // Structs @@ -263,7 +264,7 @@ void mcpwm_init(volatile mc_configuration *configuration) { TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; - TIM_BDTRInitStructure.TIM_DeadTime = HW_DEAD_TIME_VALUE; + TIM_BDTRInitStructure.TIM_DeadTime = conf_general_calculate_deadtime(HW_DEAD_TIME_NSEC, SYSTEM_CORE_CLOCK); TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; @@ -468,11 +469,9 @@ void mcpwm_init(volatile mc_configuration *configuration) { chThdCreateStatic(timer_thread_wa, sizeof(timer_thread_wa), NORMALPRIO, timer_thread, NULL); chThdCreateStatic(rpm_thread_wa, sizeof(rpm_thread_wa), NORMALPRIO, rpm_thread, NULL); - // WWDG configuration - RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); - WWDG_SetPrescaler(WWDG_Prescaler_1); - WWDG_SetWindowValue(255); - WWDG_Enable(100); + // Check if the system has resumed from IWDG reset + if (timeout_had_IWDG_reset()) + mc_interface_fault_stop(FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET); // Reset tachometers again tachometer = 0; @@ -1748,7 +1747,7 @@ void mcpwm_adc_int_handler(void *p, uint32_t flags) { update_timer_attempt(); // Reset the watchdog - WWDG_SetCounter(100); + timeout_feed_WDT(THREAD_MCPWM); const float input_voltage = GET_INPUT_VOLTAGE(); int ph1, ph2, ph3; diff --git a/mcpwm_foc.c b/mcpwm_foc.c index 2db28436..47314630 100644 --- a/mcpwm_foc.c +++ b/mcpwm_foc.c @@ -279,7 +279,7 @@ void mcpwm_foc_init(volatile mc_configuration *configuration) { TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; - TIM_BDTRInitStructure.TIM_DeadTime = HW_DEAD_TIME_VALUE; + TIM_BDTRInitStructure.TIM_DeadTime = conf_general_calculate_deadtime(HW_DEAD_TIME_NSEC, SYSTEM_CORE_CLOCK); TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; @@ -449,11 +449,9 @@ void mcpwm_foc_init(volatile mc_configuration *configuration) { timer_thd_stop = false; chThdCreateStatic(timer_thread_wa, sizeof(timer_thread_wa), NORMALPRIO, timer_thread, NULL); - // WWDG configuration - RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); - WWDG_SetPrescaler(WWDG_Prescaler_1); - WWDG_SetWindowValue(255); - WWDG_Enable(100); + // Check if the system has resumed from IWDG reset + if (timeout_had_IWDG_reset()) + mc_interface_fault_stop(FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET); m_init_done = true; } @@ -1044,9 +1042,9 @@ void mcpwm_foc_encoder_detect(float current, bool print, float *offset, float *r for (int i = 0; i < it_rat; i++) { float phase_old = m_phase_now_encoder; float phase_ovr_tmp = m_phase_now_override; - for (float i = phase_ovr_tmp; i < phase_ovr_tmp + (2.0 / 3.0) * M_PI; - i += (2.0 * M_PI) / 500.0) { - m_phase_now_override = i; + for (float j = phase_ovr_tmp; j < phase_ovr_tmp + (2.0 / 3.0) * M_PI; + j += (2.0 * M_PI) / 500.0) { + m_phase_now_override = j; chThdSleepMilliseconds(1); } utils_norm_angle_rad((float*)&m_phase_now_override); @@ -1072,9 +1070,9 @@ void mcpwm_foc_encoder_detect(float current, bool print, float *offset, float *r for (int i = 0; i < it_rat; i++) { float phase_old = m_phase_now_encoder; float phase_ovr_tmp = m_phase_now_override; - for (float i = phase_ovr_tmp; i > phase_ovr_tmp - (2.0 / 3.0) * M_PI; - i -= (2.0 * M_PI) / 500.0) { - m_phase_now_override = i; + for (float j = phase_ovr_tmp; j > phase_ovr_tmp - (2.0 / 3.0) * M_PI; + j -= (2.0 * M_PI) / 500.0) { + m_phase_now_override = j; chThdSleepMilliseconds(1); } utils_norm_angle_rad((float*)&m_phase_now_override); @@ -1133,14 +1131,14 @@ void mcpwm_foc_encoder_detect(float current, bool print, float *offset, float *r chThdSleepMilliseconds(100); - float diff = utils_angle_difference_rad(m_phase_now_encoder, m_phase_now_override); + float angle_diff = utils_angle_difference_rad(m_phase_now_encoder, m_phase_now_override); float s, c; - sincosf(diff, &s, &c); + sincosf(angle_diff, &s, &c); s_sum += s; c_sum += c; if (print) { - commands_printf("%.2f", (double)(diff * 180.0 / M_PI)); + commands_printf("%.2f", (double)(angle_diff * 180.0 / M_PI)); } } @@ -1155,14 +1153,14 @@ void mcpwm_foc_encoder_detect(float current, bool print, float *offset, float *r chThdSleepMilliseconds(100); - float diff = utils_angle_difference_rad(m_phase_now_encoder, m_phase_now_override); + float angle_diff = utils_angle_difference_rad(m_phase_now_encoder, m_phase_now_override); float s, c; - sincosf(diff, &s, &c); + sincosf(angle_diff, &s, &c); s_sum += s; c_sum += c; if (print) { - commands_printf("%.2f", (double)(diff * 180.0 / M_PI)); + commands_printf("%.2f", (double)(angle_diff * 180.0 / M_PI)); } } @@ -1419,9 +1417,7 @@ bool mcpwm_foc_measure_res_ind(float *res, float *ind) { } } - if (i_last < 0.01) { - i_last = (m_conf->l_current_max / 2.0); - } + i_last = (m_conf->l_current_max / 2.0); *res = mcpwm_foc_measure_resistance(i_last, 200); *ind = mcpwm_foc_measure_inductance_current(i_last, 200, 0); @@ -1477,8 +1473,8 @@ bool mcpwm_foc_hall_detect(float current, uint8_t *hall_table) { // Forwards for (int i = 0;i < 3;i++) { - for (int i = 0;i < 360;i++) { - m_phase_now_override = (float)i * M_PI / 180.0; + for (int j = 0;j < 360;j++) { + m_phase_now_override = (float)j * M_PI / 180.0; chThdSleepMilliseconds(5); int hall = read_hall(); @@ -1492,8 +1488,8 @@ bool mcpwm_foc_hall_detect(float current, uint8_t *hall_table) { // Reverse for (int i = 0;i < 3;i++) { - for (int i = 360;i >= 0;i--) { - m_phase_now_override = (float)i * M_PI / 180.0; + for (int j = 360;j >= 0;j--) { + m_phase_now_override = (float)j * M_PI / 180.0; chThdSleepMilliseconds(5); int hall = read_hall(); @@ -1568,6 +1564,12 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { (void)p; (void)flags; + static int skip = 0; + if (++skip == FOC_CONTROL_LOOP_FREQ_DIVIDER) + skip = 0; + else + return; + TIM12->CNT = 0; bool is_v7 = !(TIM1->CR1 & TIM_CR1_DIR); @@ -1585,7 +1587,7 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { } // Reset the watchdog - WWDG_SetCounter(100); + timeout_feed_WDT(THREAD_MCPWM); #ifdef AD2S1205_SAMPLE_GPIO // force a position sample in the AD2S1205 resolver IC (falling edge) @@ -1950,6 +1952,19 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { float c, s; utils_fast_sincos_better(m_motor_state.phase, &s, &c); +#ifdef HW_VERSION_PALTA + // rotate alpha-beta 30 degrees to compensate for line-to-line phase voltage sensing + float x_tmp = m_motor_state.v_alpha; + float y_tmp = m_motor_state.v_beta; + + m_motor_state.v_alpha = x_tmp*COS_MINUS_30_DEG - y_tmp*SIN_MINUS_30_DEG; + m_motor_state.v_beta = x_tmp*SIN_MINUS_30_DEG + y_tmp*COS_MINUS_30_DEG; + + // compensate voltage amplitude + m_motor_state.v_alpha *= ONE_BY_SQRT3; + m_motor_state.v_beta *= ONE_BY_SQRT3; +#endif + // Park transform float vd_tmp = c * m_motor_state.v_alpha + s * m_motor_state.v_beta; float vq_tmp = c * m_motor_state.v_beta - s * m_motor_state.v_alpha; diff --git a/mcuconf.h b/mcuconf.h index 66d39c93..f356b620 100644 --- a/mcuconf.h +++ b/mcuconf.h @@ -93,8 +93,8 @@ #define STM32_I2SSRC STM32_I2SSRC_CKIN #define STM32_PLLI2SN_VALUE 192 #define STM32_PLLI2SR_VALUE 5 -#define STM32_PVD_ENABLE FALSE -#define STM32_PLS STM32_PLS_LEV0 +#define STM32_PVD_ENABLE TRUE +#define STM32_PLS STM32_PLS_LEV7 #define STM32_BKPRAM_ENABLE FALSE #endif diff --git a/stm32f4xx_conf.h b/stm32f4xx_conf.h index 24010bde..c554ee94 100644 --- a/stm32f4xx_conf.h +++ b/stm32f4xx_conf.h @@ -13,12 +13,6 @@ #include "stm32f4xx_syscfg.h" #include "stm32f4xx_tim.h" #include "stm32f4xx_wwdg.h" - -#ifdef USE_FULL_ASSERT -#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) -void assert_failed(uint8_t* file, uint32_t line); -#else -#define assert_param(expr) ((void)0) -#endif +#include "stm32f4xx_iwdg.h" #endif diff --git a/terminal.c b/terminal.c index 42e8c5dd..ddec0305 100644 --- a/terminal.c +++ b/terminal.c @@ -121,6 +121,9 @@ void terminal_process_string(char *str) { commands_printf("Current : %.1f", (double)fault_vec[i].current); commands_printf("Current filtered : %.1f", (double)fault_vec[i].current_filtered); commands_printf("Voltage : %.2f", (double)fault_vec[i].voltage); +#ifdef HW_VERSION_PALTA + commands_printf("Gate drv voltage : %.2f", (double)fault_vec[i].gate_driver_voltage); +#endif commands_printf("Duty : %.3f", (double)fault_vec[i].duty); commands_printf("RPM : %.1f", (double)fault_vec[i].rpm); commands_printf("Tacho : %d", fault_vec[i].tacho); @@ -178,6 +181,9 @@ void terminal_process_string(char *str) { commands_printf("Current 2 sample: %u\n", current2_samp); } else if (strcmp(argv[0], "volt") == 0) { commands_printf("Input voltage: %.2f\n", (double)GET_INPUT_VOLTAGE()); +#ifdef HW_VERSION_PALTA + commands_printf("Gate driver power supply output voltage: %.2f\n", (double)GET_GATE_DRIVER_SUPPLY_VOLTAGE()); +#endif } else if (strcmp(argv[0], "param_detect") == 0) { // Use COMM_MODE_DELAY and try to figure out the motor parameters. if (argc == 4) { diff --git a/timeout.c b/timeout.c index c85eb338..c7f9cf5d 100644 --- a/timeout.c +++ b/timeout.c @@ -19,23 +19,41 @@ #include "timeout.h" #include "mc_interface.h" +#include "stm32f4xx_conf.h" // Private variables static volatile systime_t timeout_msec; static volatile systime_t last_update_time; static volatile float timeout_brake_current; static volatile bool has_timeout; +static volatile uint32_t feed_counter[MAX_THREADS_MONITOR]; // Threads static THD_WORKING_AREA(timeout_thread_wa, 512); static THD_FUNCTION(timeout_thread, arg); +void timeout_init_IWDT(void); + void timeout_init(void) { timeout_msec = 1000; last_update_time = 0; timeout_brake_current = 0.0; has_timeout = false; + // WWDG configuration + RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); + // Timeout = t_PCLK1 (ms) * 4096 * 2^(WDGTB [1:0]) * (T[5:0] + 1) + // CLK1 = 42MHz + + // Window set between 6.24ms and 12.48ms. Mcu will reset if watchdog is fed outside the window + WWDG_SetPrescaler(WWDG_Prescaler_2); + WWDG_SetWindowValue(127); + WWDG_Enable(127); //0x7F + + timeout_init_IWDT(); + + chThdSleepMilliseconds(10); + chThdCreateStatic(timeout_thread_wa, sizeof(timeout_thread_wa), NORMALPRIO, timeout_thread, NULL); } @@ -60,6 +78,102 @@ float timeout_get_brake_current(void) { return timeout_brake_current; } +void timeout_feed_WDT(uint8_t index) { + ++feed_counter[index]; +} + +void timeout_init_IWDT(void) { + /* Enable write access to IWDG_PR and IWDG_RLR registers */ + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); + + /* IWDG counter clock: LSI/4 */ + IWDG_SetPrescaler(IWDG_Prescaler_4); + + /* Set counter reload value to obtain 12ms IWDG TimeOut. + * + * LSI timer per datasheet is 32KHz typical, but 17KHz min + * and 47KHz max over the complete range of operating conditions, + * so reload time must ensure watchdog will work correctly under + * all conditions. + * + * Timeout threads runs every 10ms. Take 20% margin so wdt should + * be fed every 12ms. The worst condition occurs when the wdt clock + * runs at the max freq (47KHz) due to oscillator tolerances. + * + * t_IWDG(ms) = t_LSI(ms) * 4 * 2^(IWDG_PR[2:0]) * (IWDG_RLR[11:0] + 1) + * t_LSI(ms) [MAX] = 0.021276ms + * 12ms = 0.0212765 * 4 * 1 * (140 + 1) + + Counter Reload Value = 140 + + When LSI clock runs the slowest, the IWDG will expire every 33.17ms + */ + IWDG_SetReload(140); + + IWDG_ReloadCounter(); + + /* Enable IWDG (the LSI oscillator will be enabled by hardware) */ + IWDG_Enable(); +} + +void timeout_configure_IWDT_slowest(void) { + while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0)) + { + // Continue to kick the dog + IWDG_ReloadCounter(); + } + // Unlock register + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); + // Update configuration + IWDG_SetReload(1400); + IWDG_SetPrescaler(IWDG_Prescaler_256); + // Wait for the new configuration to be taken into account + while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0)) + { + // Continue to kick the dog + IWDG_ReloadCounter(); + } +} + +void timeout_configure_IWDT(void) { + while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0)) + { + // Continue to kick the dog + IWDG_ReloadCounter(); + } + // Unlock register + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); + // Update configuration + IWDG_SetReload(140); + IWDG_SetPrescaler(IWDG_Prescaler_4); + // Wait for the new configuration to be taken into account + while(((IWDG->SR & IWDG_SR_RVU) != 0) || ((IWDG->SR & IWDG_SR_PVU) != 0)) + { + // Continue to kick the dog + IWDG_ReloadCounter(); + } +} + +bool timeout_had_IWDG_reset(void) { + // Check if the system has resumed from IWDG reset + if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET) { + /* IWDGRST flag set */ + /* Clear reset flags */ + RCC_ClearFlag(); + return true; + } + + // Check if the system has resumed from WWDG reset + if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET) { + /* IWDGRST flag set */ + /* Clear reset flags */ + RCC_ClearFlag(); + return true; + } + + return false; +} + static THD_FUNCTION(timeout_thread, arg) { (void)arg; @@ -74,6 +188,35 @@ static THD_FUNCTION(timeout_thread, arg) { has_timeout = false; } + bool threads_ok = true; + + // Monitored threads (foc, can, timer) must report at least one iteration, + // otherwise the watchdog won't be feed and MCU will reset. All threads should + // be monitored + if(feed_counter[THREAD_MCPWM] < MIN_THREAD_ITERATIONS) + threads_ok = false; +#if CAN_ENABLE + if(feed_counter[THREAD_CANBUS] < MIN_THREAD_ITERATIONS) + threads_ok = false; +#endif + if(feed_counter[THREAD_TIMER] < MIN_THREAD_ITERATIONS) + threads_ok = false; + + for( int i = 0; i < MAX_THREADS_MONITOR; i++) + feed_counter[i] = 0; + + if (threads_ok == true) { + // Feed WDT's + WWDG_SetCounter(127); // must reload in >6.24ms and <12.48ms + IWDG_ReloadCounter(); // must reload in <12ms + } + else + { + // not reloading the watchdog will produce a reset. + // This can be checked from the GUI logs as + // "FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET" + } + chThdSleepMilliseconds(10); } } diff --git a/timeout.h b/timeout.h index 4798e796..f794e4d5 100644 --- a/timeout.h +++ b/timeout.h @@ -24,12 +24,27 @@ #include "chtypes.h" #include "chsystypes.h" +#define MAX_THREADS_MONITOR 10 +#define MIN_THREAD_ITERATIONS 1 + +typedef enum { + THREAD_MCPWM = 0, + THREAD_CANBUS, + THREAD_TIMER, + THREAD_USB, + THREAD_APP +} WWDT_THREAD_TYPES; + // Functions void timeout_init(void); void timeout_configure(systime_t timeout, float brake_current); void timeout_reset(void); bool timeout_has_timeout(void); systime_t timeout_get_timeout_msec(void); +void timeout_configure_IWDT(void); +void timeout_configure_IWDT_slowest(void); +bool timeout_had_IWDG_reset(void); +void timeout_feed_WDT(uint8_t index); float timeout_get_brake_current(void); #endif /* TIMEOUT_H_ */ diff --git a/utils.h b/utils.h index f501a602..f6642437 100644 --- a/utils.h +++ b/utils.h @@ -83,5 +83,9 @@ uint32_t utils_crc32c(uint8_t *data, uint32_t len); #define ONE_BY_SQRT3 (0.57735026919) #define TWO_BY_SQRT3 (2.0f * 0.57735026919) #define SQRT3_BY_2 (0.86602540378) +#define COS_30_DEG (0.86602540378) +#define SIN_30_DEG (0.5) +#define COS_MINUS_30_DEG (0.86602540378) +#define SIN_MINUS_30_DEG (-0.5) #endif /* UTILS_H_ */ diff --git a/ws2811.c b/ws2811.c index 72475ee9..22b17c20 100644 --- a/ws2811.c +++ b/ws2811.c @@ -74,7 +74,7 @@ void ws2811_init(void) { } // Generate gamma correction table - for (int i = 0;i < 256;i++) { + for (i = 0;i < 256;i++) { gamma_table[i] = (int)roundf(powf((float)i / 255.0, 1.0 / 0.45) * 255.0); }