This is an automated email from the ASF dual-hosted git repository.

raiden00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 25886c7b4793b1544c49b81ec266bf8f65877a05
Author: Daniel P. Carvalho <[email protected]>
AuthorDate: Wed Jun 26 16:18:07 2024 -0300

    b-g474e-dpow1: Added smps example.
---
 .../b-g474e-dpow1/configs/buckboost/defconfig      |   90 ++
 boards/arm/stm32/b-g474e-dpow1/include/board.h     |   59 +-
 boards/arm/stm32/b-g474e-dpow1/src/CMakeLists.txt  |    4 +
 boards/arm/stm32/b-g474e-dpow1/src/Make.defs       |    4 +
 boards/arm/stm32/b-g474e-dpow1/src/b-g474e-dpow1.h |   12 +
 boards/arm/stm32/b-g474e-dpow1/src/stm32_appinit.c |   10 +
 boards/arm/stm32/b-g474e-dpow1/src/stm32_smps.c    | 1262 ++++++++++++++++++++
 7 files changed, 1440 insertions(+), 1 deletion(-)

diff --git a/boards/arm/stm32/b-g474e-dpow1/configs/buckboost/defconfig 
b/boards/arm/stm32/b-g474e-dpow1/configs/buckboost/defconfig
new file mode 100644
index 0000000000..1c21cb0514
--- /dev/null
+++ b/boards/arm/stm32/b-g474e-dpow1/configs/buckboost/defconfig
@@ -0,0 +1,90 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_ARCH_LEDS is not set
+CONFIG_ADC=y
+CONFIG_ANALOG=y
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="b-g474e-dpow1"
+CONFIG_ARCH_BOARD_B_G474E_DPOW1=y
+CONFIG_ARCH_BUTTONS=y
+CONFIG_ARCH_CHIP="stm32"
+CONFIG_ARCH_CHIP_STM32=y
+CONFIG_ARCH_CHIP_STM32G474R=y
+CONFIG_ARCH_HIPRI_INTERRUPT=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_ENVIRON=y
+CONFIG_DISABLE_MQUEUE=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_DISABLE_PTHREAD=y
+CONFIG_DRIVERS_SMPS=y
+CONFIG_EXAMPLES_SMPS=y
+CONFIG_EXAMPLES_SMPS_DEVPATH="/dev/smps0"
+CONFIG_EXAMPLES_SMPS_IN_VOLTAGE_LIMIT=10000
+CONFIG_EXAMPLES_SMPS_OUT_CURRENT_LIMIT=100
+CONFIG_EXAMPLES_SMPS_OUT_POWER_LIMIT=100
+CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_DEFAULT=5000
+CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT=10000
+CONFIG_EXAMPLES_SMPS_TIME_DEFAULT=10
+CONFIG_FDCLONE_STDIO=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INIT_STACKSIZE=1024
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBDSP=y
+CONFIG_LIBM=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=256
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=512
+CONFIG_PTHREAD_STACK_DEFAULT=1024
+CONFIG_PTHREAD_STACK_MIN=1024
+CONFIG_RAM_SIZE=98304
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SMPS_HAVE_INPUT_VOLTAGE=y
+CONFIG_SMPS_HAVE_OUTPUT_VOLTAGE=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_STDIO_BUFFER_SIZE=128
+CONFIG_STM32_ADC1=y
+CONFIG_STM32_ADC1_INJECTED_CHAN=2
+CONFIG_STM32_ADC_CHANGE_SAMPLETIME=y
+CONFIG_STM32_ADC_LL_OPS=y
+CONFIG_STM32_ADC_NOIRQ=y
+CONFIG_STM32_CCMEXCLUDE=y
+CONFIG_STM32_HRTIM1=y
+CONFIG_STM32_HRTIM_ADC1_TRG2=y
+CONFIG_STM32_HRTIM_ADC=y
+CONFIG_STM32_HRTIM_DEADTIME=y
+CONFIG_STM32_HRTIM_DISABLE_CHARDRV=y
+CONFIG_STM32_HRTIM_PWM=y
+CONFIG_STM32_HRTIM_TIMC=y
+CONFIG_STM32_HRTIM_TIMC_DT=y
+CONFIG_STM32_HRTIM_TIMC_PWM=y
+CONFIG_STM32_HRTIM_TIMC_PWM_CH1=y
+CONFIG_STM32_HRTIM_TIMC_PWM_CH2=y
+CONFIG_STM32_HRTIM_TIMD=y
+CONFIG_STM32_HRTIM_TIMD_DT=y
+CONFIG_STM32_HRTIM_TIMD_PWM=y
+CONFIG_STM32_HRTIM_TIMD_PWM_CH1=y
+CONFIG_STM32_HRTIM_TIMD_PWM_CH2=y
+CONFIG_STM32_JTAG_SW_ENABLE=y
+CONFIG_STM32_PWR=y
+CONFIG_STM32_USART3=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=0
+CONFIG_USART3_SERIAL_CONSOLE=y
diff --git a/boards/arm/stm32/b-g474e-dpow1/include/board.h 
b/boards/arm/stm32/b-g474e-dpow1/include/board.h
index 4b4f25788a..d1219cdb45 100644
--- a/boards/arm/stm32/b-g474e-dpow1/include/board.h
+++ b/boards/arm/stm32/b-g474e-dpow1/include/board.h
@@ -185,6 +185,63 @@
 #define GPIO_USART3_TX     GPIO_USART3_TX_3 /* PC10 */
 #define GPIO_USART3_RX     GPIO_USART3_RX_3 /* PC11 */
 
-/* Pin Multiplexing Disambiguation ******************************************/
+/* Board configuration for SMPS example:
+ *   PB12 - HRTIM1_CHC1
+ *   PB13 - HRTIM1_CHC2
+ *   PB14 - HRTIM1_CHD1
+ *   PB15 - HRTIM1_CHD2
+ *   VIN  - ADC Channel 2 (PA1)
+ *   VOUT - ADC Channel 4 (PA3)
+ */
+
+#if defined(CONFIG_EXAMPLES_SMPS)
+
+/* HRTIM configuration ******************************************************/
+
+/* Timer C configuration - Buck operations */
+
+#define HRTIM_TIMC_PRESCALER HRTIM_PRESCALER_1
+#define HRTIM_TIMC_MODE      HRTIM_MODE_CONT
+#define HRTIM_TIMC_UPDATE    0
+#define HRTIM_TIMC_RESET     0
+
+#define HRTIM_TIMC_CH1_SET   HRTIM_OUT_SET_NONE
+#define HRTIM_TIMC_CH1_RST   HRTIM_OUT_RST_NONE
+#define HRTIM_TIMC_CH2_SET   HRTIM_OUT_SET_NONE
+#define HRTIM_TIMC_CH2_RST   HRTIM_OUT_RST_NONE
+
+#define HRTIM_TIMC_DT_FSLOCK HRTIM_DT_LOCK
+#define HRTIM_TIMC_DT_RSLOCK HRTIM_DT_LOCK
+#define HRTIM_TIMC_DT_FVLOCK HRTIM_DT_RW
+#define HRTIM_TIMC_DT_RVLOCK HRTIM_DT_RW
+#define HRTIM_TIMC_DT_FSIGN  HRTIM_DT_SIGN_POSITIVE
+#define HRTIM_TIMC_DT_RSIGN  HRTIM_DT_SIGN_POSITIVE
+#define HRTIM_TIMC_DT_PRESCALER HRTIM_DEADTIME_PRESCALER_1
+
+/* Timer D configuration - Boost operations */
+
+#define HRTIM_TIMD_PRESCALER HRTIM_PRESCALER_1
+#define HRTIM_TIMD_MODE      HRTIM_MODE_CONT
+#define HRTIM_TIMD_UPDATE    0
+#define HRTIM_TIMD_RESET     0
+
+#define HRTIM_TIMD_CH1_SET   HRTIM_OUT_SET_NONE
+#define HRTIM_TIMD_CH1_RST   HRTIM_OUT_RST_NONE
+#define HRTIM_TIMD_CH2_SET   HRTIM_OUT_SET_NONE
+#define HRTIM_TIMD_CH2_RST   HRTIM_OUT_RST_NONE
+
+#define HRTIM_TIMD_DT_FSLOCK HRTIM_DT_LOCK
+#define HRTIM_TIMD_DT_RSLOCK HRTIM_DT_LOCK
+#define HRTIM_TIMD_DT_FVLOCK HRTIM_DT_RW
+#define HRTIM_TIMD_DT_RVLOCK HRTIM_DT_RW
+#define HRTIM_TIMD_DT_FSIGN  HRTIM_DT_SIGN_POSITIVE
+#define HRTIM_TIMD_DT_RSIGN  HRTIM_DT_SIGN_POSITIVE
+#define HRTIM_TIMD_DT_PRESCALER HRTIM_DEADTIME_PRESCALER_1
+
+#define HRTIM_ADC_TRG2       HRTIM_ADCTRG24_CC4
+
+/* DMA channels *************************************************************/
+
+#endif /* CONFIG_EXAMPLES_SMPS */
 
 #endif /* __BOARDS_ARM_STM32_B_G474E_DPOW1_INCLUDE_BOARD_H */
diff --git a/boards/arm/stm32/b-g474e-dpow1/src/CMakeLists.txt 
b/boards/arm/stm32/b-g474e-dpow1/src/CMakeLists.txt
index d0c35a88d0..ced983e42c 100644
--- a/boards/arm/stm32/b-g474e-dpow1/src/CMakeLists.txt
+++ b/boards/arm/stm32/b-g474e-dpow1/src/CMakeLists.txt
@@ -30,6 +30,10 @@ if(CONFIG_BOARDCTL)
   list(APPEND SRCS stm32_appinit.c)
 endif()
 
+if(CONFIG_DRIVERS_SMPS)
+  list(APPEND SRCS stm32_smps.c)
+endif()
+
 target_sources(board PRIVATE ${SRCS})
 
 set_property(GLOBAL PROPERTY LD_SCRIPT "${NUTTX_BOARD_DIR}/scripts/ld.script")
diff --git a/boards/arm/stm32/b-g474e-dpow1/src/Make.defs 
b/boards/arm/stm32/b-g474e-dpow1/src/Make.defs
index fbc74033c1..8c7dc5159f 100644
--- a/boards/arm/stm32/b-g474e-dpow1/src/Make.defs
+++ b/boards/arm/stm32/b-g474e-dpow1/src/Make.defs
@@ -33,6 +33,10 @@ ifeq ($(CONFIG_BOARDCTL),y)
 CSRCS += stm32_appinit.c
 endif
 
+ifeq ($(CONFIG_DRIVERS_SMPS),y)
+CSRCS += stm32_smps.c
+endif
+
 DEPPATH += --dep-path board
 VPATH += :board
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board
diff --git a/boards/arm/stm32/b-g474e-dpow1/src/b-g474e-dpow1.h 
b/boards/arm/stm32/b-g474e-dpow1/src/b-g474e-dpow1.h
index 2871324a5f..9cee308419 100644
--- a/boards/arm/stm32/b-g474e-dpow1/src/b-g474e-dpow1.h
+++ b/boards/arm/stm32/b-g474e-dpow1/src/b-g474e-dpow1.h
@@ -74,4 +74,16 @@
  * Public Function Prototypes
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: stm32_smps_setup
+ *
+ * Description:
+ *  Initialize SMPS peripheral for the board.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_DRIVERS_SMPS
+int stm32_smps_setup(void);
+#endif
+
 #endif /* __BOARDS_ARM_STM32_B_G474E_DPOW1_SRC_B_G474E_DPOW1_H */
diff --git a/boards/arm/stm32/b-g474e-dpow1/src/stm32_appinit.c 
b/boards/arm/stm32/b-g474e-dpow1/src/stm32_appinit.c
index 224060a955..6badc2865c 100644
--- a/boards/arm/stm32/b-g474e-dpow1/src/stm32_appinit.c
+++ b/boards/arm/stm32/b-g474e-dpow1/src/stm32_appinit.c
@@ -86,6 +86,16 @@ int board_app_initialize(uintptr_t arg)
     }
 #endif
 
+#ifdef CONFIG_DRIVERS_SMPS
+  /* Initialize smps and register the smps driver */
+
+  ret = stm32_smps_setup();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: stm32_smps_setup failed: %d\n", ret);
+    }
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/stm32/b-g474e-dpow1/src/stm32_smps.c 
b/boards/arm/stm32/b-g474e-dpow1/src/stm32_smps.c
new file mode 100644
index 0000000000..9cf7c5f527
--- /dev/null
+++ b/boards/arm/stm32/b-g474e-dpow1/src/stm32_smps.c
@@ -0,0 +1,1262 @@
+/****************************************************************************
+ * boards/arm/stm32/b-g474e-dpow1/src/stm32_smps.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/boardctl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <debug.h>
+#include <dsp.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/analog/adc.h>
+#include <nuttx/analog/ioctl.h>
+#include <nuttx/power/smps.h>
+
+#include <arch/armv7-m/nvicpri.h>
+
+#include "arm_internal.h"
+#include "ram_vectors.h"
+
+#include "stm32_hrtim.h"
+#include "stm32_adc.h"
+
+#include <arch/board/board.h>
+
+#if defined(CONFIG_EXAMPLES_SMPS) && defined(CONFIG_DRIVERS_SMPS)
+
+#ifndef CONFIG_LIBDSP
+#  error CONFIG_LIBDSP is required
+#endif
+
+#ifndef CONFIG_ARCH_HIPRI_INTERRUPT
+#  error CONFIG_ARCH_HIPRI_INTERRUPT is required
+#endif
+
+#ifndef CONFIG_ARCH_RAMVECTORS
+#  error CONFIG_ARCH_RAMVECTORS is required
+#endif
+
+#ifndef CONFIG_ARCH_IRQPRIO
+#  error CONFIG_ARCH_IRQPRIO is required
+#endif
+
+#ifndef CONFIG_ARCH_FPU
+#  warning Set CONFIG_ARCH_FPU for hardware FPU support
+#endif
+
+#if !defined(CONFIG_STM32_HRTIM1) || !defined(CONFIG_STM32_HRTIM)
+#  error "SMPS example requires HRTIM1 support"
+#endif
+
+#if !defined(CONFIG_STM32_ADC1) || !defined(CONFIG_ADC)
+#  error "SMPS example requires ADC1 support"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* ADC1 channels used in this example */
+
+#define ADC1_NCHANNELS 2
+
+/* ADC1 injected channels numeration */
+
+#define V_IN_ADC_INJ_CHANNEL  0
+#define V_OUT_ADC_INJ_CHANNEL 1
+
+/* Voltage reference for ADC */
+
+#define ADC_REF_VOLTAGE ((float)3.3)
+
+/* ADC resolution */
+
+#define ADC_VAL_MAX     4095
+
+/* Input voltage conversion ratio - 6.8k/(6.8k + 27k) */
+
+#define V_IN_RATIO (float)((float)(6800+27000)/(float)6800)
+
+/* Output voltage conversion ratio - 3.3k/(3.3k + 13.3k) */
+
+#define V_OUT_RATIO (float)((float)(3300+13300)/(float)3300)
+
+/* Some absolute limits */
+
+#define SMPS_ABSOLUTE_OUT_CURRENT_LIMIT_mA 250
+#define SMPS_ABSOLUTE_OUT_VOLTAGE_LIMIT_mV 15000
+#define SMPS_ABSOLUTE_IN_VOLTAGE_LIMIT_mV  15000
+
+#if CONFIG_EXAMPLES_SMPS_OUT_CURRENT_LIMIT > SMPS_ABSOLUTE_OUT_CURRENT_LIMIT_mA
+#  error "Output current limit great than absolute limit!"
+#endif
+#if CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT > SMPS_ABSOLUTE_OUT_VOLTAGE_LIMIT_mV
+#  error "Output voltage limit greater than absolute limit!"
+#endif
+#if CONFIG_EXAMPLES_SMPS_IN_VOLTAGE_LIMIT > SMPS_ABSOLUTE_IN_VOLTAGE_LIMIT_mV
+#  error "Input voltage limit greater than absolute limit!"
+#endif
+
+/* Maximum output voltage for boost converter in float */
+
+#define BOOST_VOLT_MAX ((float)CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT/1000.0)
+
+/* At this time only PID controller implemented */
+
+#define SMPS_CONTROLLER_PID   1
+
+/* Converter's finite accuracy */
+
+#define SMPS_VOLTAGE_ACCURACY ((float)0.01)
+
+/* Buck-boost mode threshold */
+
+#define SMPS_BUCKBOOST_RANGE  ((float)0.5)
+
+/* PID controller configuration */
+
+#define PID_KP                ((float)1.0)
+#define PID_KI                ((float)0.1)
+#define PID_KD                ((float)0.0)
+
+/* Converter frequencies:
+ *   - TIMC_PWM_FREQ - buck converter 250kHz
+ *   - TIMD_PWM_FREQ - boost converter 250kHz
+ */
+
+#define TIMC_PWM_FREQ 250000
+#define TIMD_PWM_FREQ 250000
+
+/* Deadtime configuration */
+
+#define DT_RISING 0x0B0
+#define DT_FALLING 0x0B0
+
+/* Helper macros */
+
+#define HRTIM_ALL_OUTPUTS_ENABLE(hrtim, state)                        \
+  HRTIM_OUTPUTS_ENABLE(hrtim, HRTIM_OUT_TIMC_CH1|HRTIM_OUT_TIMC_CH2|  \
+                       HRTIM_OUT_TIMD_CH1|HRTIM_OUT_TIMD_CH2, state);
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Current converter mode */
+
+enum converter_mode_e
+{
+  CONVERTER_MODE_INIT,      /* Initial mode */
+  CONVERTER_MODE_BUCK,      /* Buck mode operations  (V_in > V_out) */
+  CONVERTER_MODE_BOOST,     /* Boost mode operations (V_in < V_out) */
+  CONVERTER_MODE_BUCKBOOST, /* Buck-boost operations (V_in near V_out) */
+};
+
+/* SMPS lower drivers structure */
+
+struct smps_lower_dev_s
+{
+  struct hrtim_dev_s     *hrtim; /* PWM generation */
+  struct stm32_adc_dev_s *adc;   /* input and output voltage sense */
+  struct comp_dev_s      *comp;  /* not used in this demo - only as reference 
*/
+  struct dac_dev_s       *dac;   /* not used in this demo - only as reference 
*/
+  struct opamp_dev_s     *opamp; /* not used in this demo - only as reference 
*/
+};
+
+/* Private data for smps */
+
+struct smps_priv_s
+{
+  uint8_t               conv_mode;   /* Converter mode */
+  uint16_t              v_in_raw;    /* Voltage input RAW value */
+  uint16_t              v_out_raw;   /* Voltage output RAW value */
+  float                 v_in;        /* Voltage input real value in V */
+  float                 v_out;       /* Voltage output real value in V  */
+  bool                  running;     /* Running flag */
+  pid_controller_f32_t  pid;         /* PID controller */
+  float                *c_limit_tab; /* Current limit tab */
+};
+
+/****************************************************************************
+ * Private Function Protototypes
+ ****************************************************************************/
+
+static int smps_setup(struct smps_dev_s *dev);
+static int smps_shutdown(struct smps_dev_s *dev);
+static int smps_start(struct smps_dev_s *dev);
+static int smps_stop(struct smps_dev_s *dev);
+static int smps_params_set(struct smps_dev_s *dev,
+                           struct smps_params_s *param);
+static int smps_mode_set(struct smps_dev_s *dev, uint8_t mode);
+static int smps_limits_set(struct smps_dev_s *dev,
+                           struct smps_limits_s *limits);
+static int smps_state_get(struct smps_dev_s *dev,
+                          struct smps_state_s *state);
+static int smps_fault_set(struct smps_dev_s *dev, uint8_t fault);
+static int smps_fault_get(struct smps_dev_s *dev,
+                          uint8_t *fault);
+static int smps_fault_clean(struct smps_dev_s *dev,
+                            uint8_t fault);
+static int smps_ioctl(struct smps_dev_s *dev, int cmd,
+                      unsigned long arg);
+
+static void smps_conv_mode_set(struct smps_priv_s *priv,
+                               struct smps_lower_dev_s *lower,
+                               uint8_t mode);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct smps_lower_dev_s g_smps_lower;
+struct smps_priv_s g_smps_priv;
+struct smps_s g_smps;
+
+struct smps_ops_s g_smps_ops =
+{
+  .setup       = smps_setup,
+  .shutdown    = smps_shutdown,
+  .start       = smps_start,
+  .stop        = smps_stop,
+  .params_set  = smps_params_set,
+  .mode_set    = smps_mode_set,
+  .limits_set  = smps_limits_set,
+  .fault_set   = smps_fault_set,
+  .state_get   = smps_state_get,
+  .fault_get   = smps_fault_get,
+  .fault_clean = smps_fault_clean,
+  .ioctl       = smps_ioctl
+};
+
+struct smps_dev_s g_smps_dev =
+{
+  .ops   = &g_smps_ops,
+  .priv  = &g_smps,
+  .lower = NULL
+};
+
+/* ADC configuration:
+ *    - Input voltage (V_IN) - ADC1 Channel 2 (PA1)
+ *    - Output voltage (V_OUT) - ADC1 Channel 4 (PA3)
+ *
+ * ADC channels configured in injected mode.
+ *
+ * Transistors configuration in buck mode:
+ *    - T6 -  ON
+ *    - T2 -  OFF
+ *    - T5 and T1 - buck operation
+ * Transistors configuration in boost mode:
+ *    - T5 - ON
+ *    - T1 - OFF
+ *    - T6 and T2 - boost operation
+ * Transistors configuration in buck-boost mode:
+ *    - T5 and T1 - buck operation
+ *    - T6 and T2 - boost operation
+ *
+ * HRTIM outputs configuration:
+ *    - T5   -> PB12 -> HRTIM_CHC1
+ *    - T6   -> PB14 -> HRTIM_CHD1
+ *    - T1   -> PB13 -> HRTIM_CHC2
+ *    - T2   -> PB15 -> HRTIM_CHD2
+ */
+
+/* ADC channel list */
+
+static const uint8_t g_adc1chan[ADC1_NCHANNELS] =
+{
+  2,
+  4
+};
+
+/* Configurations of pins used by ADC channel */
+
+static const uint32_t g_adc1pins[ADC1_NCHANNELS] =
+{
+  GPIO_ADC1_IN2,                /* PA1 - V_IN */
+  GPIO_ADC1_IN4,                /* PA3 - V_OUT */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: smps_setup
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_setup(struct smps_dev_s *dev)
+{
+  struct smps_lower_dev_s *lower = dev->lower;
+  struct smps_s           *smps  = (struct smps_s *)dev->priv;
+  struct hrtim_dev_s      *hrtim = NULL;
+  struct stm32_adc_dev_s  *adc   = NULL;
+  struct smps_priv_s      *priv;
+  struct adc_channel_s     channels[ADC1_NCHANNELS];
+  struct adc_sample_time_s stime;
+  int ret = OK;
+  int i   = 0;
+
+  /* Initialize smps structure */
+
+  smps->opmode       = SMPS_OPMODE_INIT;
+  smps->state.state  = SMPS_STATE_INIT;
+  smps->priv         = &g_smps_priv;
+
+  /* Check lower half drivers */
+
+  hrtim = lower->hrtim;
+  if (hrtim == NULL)
+    {
+      pwrerr("ERROR:  Failed to get hrtim ");
+      ret = ERROR;
+      goto errout;
+    }
+
+  adc = lower->adc;
+  if (adc == NULL)
+    {
+      pwrerr("ERROR:  Failed to get ADC lower level interface");
+      ret = ERROR;
+      goto errout;
+    }
+
+  /* Update ADC sample time */
+
+  for (i = 0; i < ADC1_NCHANNELS; i += 1)
+    {
+      channels[i].sample_time = ADC_SMPR_92p5;
+      channels[i].channel     = g_adc1chan[i];
+    }
+
+  memset(&stime, 0, sizeof(struct adc_sample_time_s));
+
+  stime.channels_nbr = ADC1_NCHANNELS;
+  stime.channel      = channels;
+
+  STM32_ADC_SAMPLETIME_SET(adc, &stime);
+  STM32_ADC_SAMPLETIME_WRITE(adc);
+
+  /* TODO: create current limit table */
+
+  UNUSED(priv);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: smps_shutdown
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_shutdown(struct smps_dev_s *dev)
+{
+  struct smps_s      *smps = (struct smps_s *)dev->priv;
+  struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv;
+
+  /* Stop smps if running */
+
+  if (priv->running == true)
+    {
+      smps_stop(dev);
+    }
+
+  /* Reset smps structure */
+
+  memset(smps, 0, sizeof(struct smps_s));
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: smps_start
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_start(struct smps_dev_s *dev)
+{
+  struct smps_lower_dev_s *lower = dev->lower;
+  struct smps_s           *smps  = (struct smps_s *)dev->priv;
+  struct smps_priv_s      *priv  = (struct smps_priv_s *)smps->priv;
+  struct hrtim_dev_s      *hrtim = lower->hrtim;
+  struct stm32_adc_dev_s  *adc   = lower->adc;
+  volatile uint64_t per = 0;
+  uint64_t fclk = 0;
+  int ret = OK;
+
+  /* Disable HRTIM outputs */
+
+  HRTIM_ALL_OUTPUTS_ENABLE(hrtim, false);
+
+  /* Reset SMPS private structure */
+
+  memset(priv, 0, sizeof(struct smps_priv_s));
+
+#ifdef SMPS_CONTROLLER_PID
+  /* Initialize PID controller */
+
+  pid_controller_init(&priv->pid, PID_KP, PID_KI, PID_KD);
+
+  /* Set PID controller saturation */
+
+  pid_saturation_set(&priv->pid, 0.0, BOOST_VOLT_MAX);
+
+  /* Reset PI integral if saturated */
+
+  pi_ireset_enable(&priv->pid, true);
+#endif
+
+  /* Get TIMC period value for given frequency */
+
+  fclk = HRTIM_FCLK_GET(hrtim, HRTIM_TIMER_TIMC);
+  per = fclk / TIMC_PWM_FREQ;
+  if (per > HRTIM_PER_MAX)
+    {
+      pwrerr("ERROR:  Can not achieve timc pwm "
+             "freq=%" PRIu32 " if fclk=%" PRIu64 "\n",
+             (uint32_t)TIMC_PWM_FREQ, (uint64_t)fclk);
+      ret = -EINVAL;
+      goto errout;
+    }
+
+  /* Set TIMC period value */
+
+  HRTIM_PER_SET(hrtim, HRTIM_TIMER_TIMC, (uint16_t)per);
+
+  /* Get TIMD period value for given frequency */
+
+  fclk = HRTIM_FCLK_GET(hrtim, HRTIM_TIMER_TIMD);
+  per = fclk / TIMD_PWM_FREQ;
+  if (per > HRTIM_PER_MAX)
+    {
+      pwrerr("ERROR:  Can not achieve timd pwm "
+             "freq=%" PRIu32 " if fclk=%" PRIu64 "\n",
+             (uint32_t)TIMD_PWM_FREQ, (uint64_t)fclk);
+      ret = -EINVAL;
+      goto errout;
+    }
+
+  /* Set TIMD period value */
+
+  HRTIM_PER_SET(hrtim, HRTIM_TIMER_TIMD, (uint16_t)per);
+
+  /* ADC trigger on TIMC CMP4 */
+
+  HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMC, HRTIM_CMP4, 10000);
+
+  /* Configure TIMER C and TIMER D deadtime mode
+   *
+   * NOTE: In deadtime mode we have to configure output 1 only
+   * (SETx1, RSTx1), output 2 configuration is not significant.
+   */
+
+  HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMC, HRTIM_DT_EDGE_RISING,
+                        DT_RISING);
+  HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMC, HRTIM_DT_EDGE_FALLING,
+                        DT_FALLING);
+  HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMD, HRTIM_DT_EDGE_RISING,
+                        DT_RISING);
+  HRTIM_DEADTIME_UPDATE(hrtim, HRTIM_TIMER_TIMD, HRTIM_DT_EDGE_FALLING,
+                        DT_FALLING);
+
+  /* Set T5 and T2 to a low state.
+   * Deadtime mode force T1 and T6 to a high state.
+   */
+
+  HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMC_CH1, HRTIM_OUT_SET_NONE);
+  HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMC_CH1, HRTIM_OUT_RST_PER);
+
+  HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMD_CH1, HRTIM_OUT_SET_NONE);
+  HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMD_CH1, HRTIM_OUT_RST_PER);
+
+  /* Set running flag */
+
+  priv->running = true;
+
+  HRTIM_ALL_OUTPUTS_ENABLE(hrtim, true);
+
+  /* Enable ADC JEOS interrupts */
+
+  STM32_ADC_INT_ENABLE(adc, ADC_INT_JEOS);
+
+  /* Enable ADC12 interrupts */
+
+  up_enable_irq(STM32_IRQ_ADC12);
+
+  /* Start injected conversion */
+
+  STM32_ADC_INJ_STARTCONV(adc, true);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: smps_stop
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_stop(struct smps_dev_s *dev)
+{
+  struct smps_lower_dev_s *lower = dev->lower;
+  struct smps_s           *smps  = (struct smps_s *)dev->priv;
+  struct smps_priv_s      *priv  = (struct smps_priv_s *)smps->priv;
+  struct hrtim_dev_s      *hrtim = lower->hrtim;
+  struct stm32_adc_dev_s  *adc   = lower->adc;
+
+  /* Disable HRTIM outputs */
+
+  HRTIM_ALL_OUTPUTS_ENABLE(hrtim, false);
+
+  /* Stop injected conversion */
+
+  STM32_ADC_INJ_STARTCONV(adc, false);
+
+  /* Disable ADC JEOS interrupts */
+
+  STM32_ADC_INT_DISABLE(adc, ADC_INT_JEOS);
+
+  /* Disable ADC12 interrupts */
+
+  up_disable_irq(STM32_IRQ_ADC12);
+
+  /* Reset running flag */
+
+  priv->running = false;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: smps_params_set
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_params_set(struct smps_dev_s *dev,
+                           struct smps_params_s *param)
+{
+  struct smps_s *smps = (struct smps_s *)dev->priv;
+  int ret = OK;
+
+  /* Only output voltage */
+
+  smps->param.v_out = param->v_out;
+
+  /* REVISIT: use current and power parameters ? */
+
+  if (param->i_out > 0)
+    {
+      pwrwarn("WARNING: Output current parameters not used in this demo\n");
+    }
+
+  if (param->p_out > 0)
+    {
+      pwrwarn("WARNING: Output power parameters not used in this demo\n");
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: smps_mode_set
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_mode_set(struct smps_dev_s *dev, uint8_t mode)
+{
+  struct smps_s *smps = (struct smps_s *)dev->priv;
+  int ret = OK;
+
+  /* Only constant voltage mode supported */
+
+  if (mode == SMPS_OPMODE_CV)
+    {
+      smps->opmode = mode;
+    }
+  else
+    {
+      pwrerr("ERROR:  Unsupported SMPS mode %d!\n", mode);
+      ret = ERROR;
+      goto errout;
+    }
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: smps_limits_set
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_limits_set(struct smps_dev_s *dev,
+                           struct smps_limits_s *limits)
+{
+  struct smps_s *smps = (struct smps_s *)dev->priv;
+  int ret = OK;
+
+  /* Some assertions */
+
+  if (limits->v_out <= 0)
+    {
+      pwrerr("ERROR:  Output voltage limit must be set!\n");
+      ret = ERROR;
+      goto errout;
+    }
+
+  if (limits->v_in <= 0)
+    {
+      pwrerr("ERROR:  Input voltage limit must be set!\n");
+      ret = ERROR;
+      goto errout;
+    }
+
+  if (limits->i_out <= 0)
+    {
+      pwrerr("ERROR:  Output current limit must be set!\n");
+      ret = ERROR;
+      goto errout;
+    }
+
+  if (limits->v_out * 1000 > CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT)
+    {
+      limits->v_out = (float)CONFIG_EXAMPLES_SMPS_OUT_VOLTAGE_LIMIT / 1000.0;
+      pwrwarn("WARNING: "
+              "SMPS output voltage limiit > SMPS absolute output voltage "
+              "limit. Set output voltage limit to %.2f.\n",
+              limits->v_out);
+    }
+
+  if (limits->v_in * 1000 > CONFIG_EXAMPLES_SMPS_IN_VOLTAGE_LIMIT)
+    {
+      limits->v_in = (float)CONFIG_EXAMPLES_SMPS_IN_VOLTAGE_LIMIT / 1000.0;
+      pwrwarn("WARNING: "
+              "SMPS input voltage limiit > SMPS absolute input voltage "
+              "limit. Set input voltage limit to %.2f.\n",
+              limits->v_in);
+    }
+
+  if (limits->i_out * 1000 > CONFIG_EXAMPLES_SMPS_OUT_CURRENT_LIMIT)
+    {
+      limits->i_out = (float)CONFIG_EXAMPLES_SMPS_OUT_CURRENT_LIMIT / 1000.0;
+      pwrwarn("WARNING: "
+              "SMPS output current limiit > SMPS absolute output current "
+              "limit. Set output current limit to %.2f.\n",
+              limits->i_out);
+    }
+
+  /* Set output voltage limit */
+
+  smps->limits.v_out = limits->v_out;
+
+  /* Set input voltage limit */
+
+  smps->limits.v_in = limits->v_in;
+
+  /* Set current limit */
+
+  smps->limits.i_out = limits->i_out;
+
+  /* Lock limits */
+
+  smps->limits.lock = true;
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: smps_state_get
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_state_get(struct smps_dev_s *dev,
+                          struct smps_state_s *state)
+{
+  struct smps_s *smps = (struct smps_s *)dev->priv;
+
+  /* Copy localy stored feedbacks data to status structure */
+
+  smps->state.fb.v_in  = g_smps_priv.v_in;
+  smps->state.fb.v_out = g_smps_priv.v_out;
+
+  /* Return state structure to caller */
+
+  memcpy(state, &smps->state, sizeof(struct smps_state_s));
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: smps_fault_set
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_fault_set(struct smps_dev_s *dev, uint8_t fault)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: smps_fault_get
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_fault_get(struct smps_dev_s *dev, uint8_t *fault)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: smps_fault_clean
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_fault_clean(struct smps_dev_s *dev, uint8_t fault)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: smps_state_get
+ *
+ * Description:
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int smps_ioctl(struct smps_dev_s *dev, int cmd, unsigned long arg)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: smps_controller
+ *
+ * Description:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static float smps_controller(struct smps_priv_s *priv, float err)
+{
+  float out = 0.0;
+
+#ifdef SMPS_CONTROLLER_PID
+  out = pid_controller(&priv->pid, err);
+#else
+#  error "At this time only PID controller implemented"
+#endif
+
+  return out;
+}
+
+/****************************************************************************
+ * Name: smps_duty_set
+ *
+ * Description:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void smps_duty_set(struct smps_priv_s *priv,
+                          struct smps_lower_dev_s *lower,
+                          float out)
+{
+  struct hrtim_dev_s *hrtim = lower->hrtim;
+  uint8_t mode = priv->conv_mode;
+  uint16_t cmp = 0;
+  float duty = 0.0;
+  uint16_t per = 0;
+
+  switch (mode)
+    {
+      case CONVERTER_MODE_INIT:
+        {
+          /* Do nothing */
+
+          break;
+        }
+
+      case CONVERTER_MODE_BUCK:
+        {
+          if (out >= priv->v_in) out = priv->v_in;
+          if (out < 0.0) out = 0.0;
+
+          duty = out / priv->v_in;
+
+#warning TODO: current limit in buck mode
+
+          per = HRTIM_PER_GET(hrtim, HRTIM_TIMER_TIMC);
+
+          cmp = (uint16_t)(per * duty);
+
+          if (cmp > per - 30) cmp = per - 30;
+
+          /* Set T5 duty cycle. T1 is complementary to T5 */
+
+          HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMC, HRTIM_CMP1, cmp);
+
+          break;
+        }
+
+      case CONVERTER_MODE_BOOST:
+        {
+          per = HRTIM_PER_GET(hrtim, HRTIM_TIMER_TIMC);
+
+          if (out < priv->v_in) out = priv->v_in;
+          if (out >= BOOST_VOLT_MAX) out = BOOST_VOLT_MAX;
+
+          duty = 1.0 - priv->v_in / out;
+
+#warning TODO: current limit in boost mode
+
+          cmp = (uint16_t)(per * duty);
+
+          /* Set T2 duty cycle. T6 is complementary to T2 */
+
+          HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMD, HRTIM_CMP1, cmp);
+
+          break;
+        }
+
+      case CONVERTER_MODE_BUCKBOOST:
+        {
+          /* Buck converter is set to fixed duty cycle (80%).
+           * Now we need set boost converter
+           */
+
+          per = HRTIM_PER_GET(hrtim, HRTIM_TIMER_TIMC);
+
+          if (out < priv->v_in) out = priv->v_in;
+          if (out >= BOOST_VOLT_MAX) out = BOOST_VOLT_MAX;
+
+          duty = 1.0 - priv->v_in / out;
+
+#warning TODO: current limit in buck boost mode
+
+          cmp = (uint16_t)(per * duty);
+
+          /* Set T2 duty cycle. T6 is complementary to T2 */
+
+          HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMD, HRTIM_CMP1, cmp);
+
+          break;
+        }
+
+      default:
+        {
+          pwrerr("ERROR:  Unknown converter mode %d!\n", mode);
+          break;
+        }
+        }
+}
+
+/****************************************************************************
+ * Name: smps_conv_mode_set
+ *
+ * Description:
+ *   Change converter mode (buck/boost/buck-boost).
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void smps_conv_mode_set(struct smps_priv_s *priv,
+                               struct smps_lower_dev_s *lower,
+                               uint8_t mode)
+{
+  struct hrtim_dev_s *hrtim = lower->hrtim;
+
+  /* Disable all outputs */
+
+  HRTIM_ALL_OUTPUTS_ENABLE(hrtim, false);
+
+  switch (mode)
+    {
+      case CONVERTER_MODE_INIT:
+        {
+          break;
+        }
+
+      case CONVERTER_MODE_BUCK:
+        {
+          /* Set T2 low (T6 high) on the next PER */
+
+          HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMD_CH1,
+                               HRTIM_OUT_SET_NONE);
+          HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMD_CH1,
+                               HRTIM_OUT_RST_PER);
+
+          /* Set T5 to a high state on PER and reset on CMP1.
+           * T1 is complementary to T5.
+           */
+
+          HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMC_CH1,
+                               HRTIM_OUT_SET_PER);
+          HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMC_CH1,
+                               HRTIM_OUT_RST_CMP1);
+
+          break;
+        }
+
+      case CONVERTER_MODE_BOOST:
+        {
+          /* Set T4 high (T11 low) on the next PER */
+
+          HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMC_CH1,
+                               HRTIM_OUT_SET_PER);
+          HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMC_CH1,
+                               HRTIM_OUT_RST_NONE);
+
+          /* Set T12 to a high state on PER and reset on CMP1.
+           * T5 is complementary to T12.
+           */
+
+          HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMD_CH1,
+                               HRTIM_OUT_SET_PER);
+          HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMD_CH1,
+                               HRTIM_OUT_RST_CMP1);
+
+          break;
+        }
+
+      case CONVERTER_MODE_BUCKBOOST:
+        {
+          /* Set T4 to a high state on PER and reset on CMP1.
+           * T11 is complementary to T4.
+           */
+
+          HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMC_CH1,
+                               HRTIM_OUT_SET_PER);
+          HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMC_CH1,
+                               HRTIM_OUT_RST_CMP1);
+
+          /* Set T12 to a high state on PER and reset on CMP1.
+           * T5 is complementary to T12.
+           */
+
+          HRTIM_OUTPUT_SET_SET(hrtim, HRTIM_OUT_TIMD_CH1,
+                               HRTIM_OUT_SET_PER);
+          HRTIM_OUTPUT_RST_SET(hrtim, HRTIM_OUT_TIMD_CH1,
+                               HRTIM_OUT_RST_CMP1);
+
+          /* Set fixed duty cycle (80%) on buck converter (T4 and T11) */
+
+          HRTIM_CMP_SET(hrtim, HRTIM_TIMER_TIMC, HRTIM_CMP1,
+                        0.8 * ((uint16_t)HRTIM_PER_GET(hrtim,
+                                                       HRTIM_TIMER_TIMC)));
+
+          break;
+        }
+
+      default:
+        {
+          pwrerr("ERROR:  Unknown converter mode %d!\n", mode);
+          break;
+        }
+    }
+
+  /* Set mode in private data */
+
+  priv->conv_mode = mode;
+
+  /* Enable outputs */
+
+  HRTIM_ALL_OUTPUTS_ENABLE(hrtim, true);
+}
+
+/****************************************************************************
+ * Name: adc12_handler
+ ****************************************************************************/
+
+static void adc12_handler(void)
+{
+  struct smps_dev_s       *dev   = &g_smps_dev;
+  struct smps_s           *smps  = (struct smps_s *)dev->priv;
+  struct smps_priv_s      *priv  = (struct smps_priv_s *)smps->priv;
+  struct smps_lower_dev_s *lower = dev->lower;
+  struct stm32_adc_dev_s  *adc   = lower->adc;
+  uint32_t pending;
+  float ref = ADC_REF_VOLTAGE;
+  float bit = ADC_VAL_MAX;
+  float err;
+  float out;
+  uint8_t mode;
+
+  pending = STM32_ADC_INT_GET(adc);
+
+  if (pending & ADC_INT_JEOC && priv->running == true)
+    {
+      /* Get raw ADC values */
+
+      priv->v_out_raw = STM32_ADC_INJDATA_GET(adc, V_OUT_ADC_INJ_CHANNEL);
+      priv->v_in_raw  = STM32_ADC_INJDATA_GET(adc, V_IN_ADC_INJ_CHANNEL);
+
+      /* Convert raw values to real values */
+
+      priv->v_out = (priv->v_out_raw * ref / bit) * V_OUT_RATIO;
+      priv->v_in  = (priv->v_in_raw * ref / bit) * V_IN_RATIO;
+
+      /* According to measured voltages we set converter
+       * in appropriate mode
+       */
+
+      if (smps->param.v_out > (priv->v_in + SMPS_BUCKBOOST_RANGE))
+        {
+          /* Desired output voltage greater than input voltage - set
+           * boost converter
+           */
+
+          mode = CONVERTER_MODE_BOOST;
+        }
+
+      else if (smps->param.v_out < (priv->v_in - SMPS_BUCKBOOST_RANGE))
+        {
+          /* Desired output voltage lower than input voltage - set
+           * buck converter
+           */
+
+          mode = CONVERTER_MODE_BUCK;
+        }
+
+      else
+        {
+          /* Desired output voltage close to input voltage - set
+           * buck-boost converter
+           */
+
+          mode = CONVERTER_MODE_BUCKBOOST;
+        }
+
+      /* Configure converter to the new mode if needed */
+
+      if (priv->conv_mode != mode)
+        {
+          smps_conv_mode_set(priv, lower, mode);
+        }
+
+      /* Get regulator error */
+
+      err = smps->param.v_out - priv->v_out;
+
+      if (err >= SMPS_VOLTAGE_ACCURACY || err <= (-SMPS_VOLTAGE_ACCURACY))
+        {
+          /* PID controller */
+
+          out = smps_controller(priv, err);
+
+          /* Update duty cycle */
+
+          smps_duty_set(priv, lower, out);
+        }
+    }
+
+  /* Clear pending */
+
+  STM32_ADC_INT_ACK(adc, pending);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_smps_setup
+ *
+ * Description:
+ *   Initialize SMPS driver.
+ *
+ *   This function should be call by board_app_initialize().
+ *
+ * Returned Value:
+ *   0 on success, a negated errno value on failure
+ *
+ ****************************************************************************/
+
+int stm32_smps_setup(void)
+{
+  struct smps_lower_dev_s *lower = &g_smps_lower;
+  struct smps_dev_s *smps        = &g_smps_dev;
+  struct hrtim_dev_s *hrtim      = NULL;
+  struct adc_dev_s *adc          = NULL;
+  static bool initialized        = false;
+  int ret                        = OK;
+  int i;
+
+  /* Initialize only once */
+
+  if (!initialized)
+    {
+      /* Get the HRTIM interface */
+
+      hrtim = stm32_hrtiminitialize();
+      if (hrtim == NULL)
+        {
+          pwrerr("ERROR:  Failed to get HRTIM1 interface\n");
+          return -ENODEV;
+        }
+
+      /* Configure the pins as analog inputs for the selected channels */
+
+      for (i = 0; i < ADC1_NCHANNELS; i++)
+        {
+          stm32_configgpio(g_adc1pins[i]);
+        }
+
+      /* Get the ADC interface */
+
+      adc = stm32_adcinitialize(1, g_adc1chan, ADC1_NCHANNELS);
+      if (adc == NULL)
+        {
+          pwrerr("ERROR:  Failed to get ADC %d interface\n", 1);
+          return -ENODEV;
+        }
+
+      /* Initialize SMPS lower driver interfaces */
+
+      lower->hrtim = hrtim;
+      lower->adc   = adc->ad_priv;
+      lower->comp  = NULL;
+      lower->dac   = NULL;
+      lower->opamp = NULL;
+
+      /* Attach ADC12 ram vector */
+
+      ret = arm_ramvec_attach(STM32_IRQ_ADC12, adc12_handler);
+      if (ret < 0)
+        {
+          pwrerr("ERROR:  arm_ramvec_attach failed: %d\n", ret);
+          ret = EXIT_FAILURE;
+          goto errout;
+        }
+
+      /* Set the priority of the ADC12 interrupt vector */
+
+      ret = up_prioritize_irq(STM32_IRQ_ADC12, NVIC_SYSH_HIGH_PRIORITY);
+      if (ret < 0)
+        {
+          pwrerr("ERROR:  up_prioritize_irq failed: %d\n", ret);
+          ret = EXIT_FAILURE;
+          goto errout;
+        }
+
+      /* Setup ADC hardware */
+
+      adc->ad_ops->ao_setup(adc);
+
+      /* We do not need register character drivers for SMPS lower
+       * peripherals. All control should be done via SMPS character
+       * driver.
+       */
+
+      ret = smps_register(CONFIG_EXAMPLES_SMPS_DEVPATH, smps, (void *)lower);
+      if (ret < 0)
+        {
+          pwrerr("ERROR:  smps_register failed: %d\n", ret);
+          return ret;
+        }
+
+      initialized = true;
+    }
+
+errout:
+  return ret;
+}
+
+#endif /* CONFIG_EXAMPLE_SMPS && CONFIG_DRIVERS_SMPS*/


Reply via email to