/**
 * @file system_init_exit.c
 *
 * @brief This file contains definitions for system initialization and shutdown.
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed 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.
 */

#ifndef LINUX_TEMP_PORT
#include <stdio.h>
#include "system_init_exit.h"
#include "nvm.h"
#include "lwip.h"
#include "exo_osal.h"
#include "exo_common.h"
#include "exo_debug.h"
#include "cmsis_os.h"
#include "qspi.h"
#include "usb_netif.h"
#include "log_thread.h"
#include "version.h"
#include "ahw_ioal_driver_test.h"
#include "memory_test.h"
#include "eps_fw_update.h"
#include "max14830.h"
#include "max14830_task.h"
#include "drivers_test.h"
#include"obc_bringup_test.h"
#include "exo_gpio.h"
#include "err_handler.h"
#include "eps.h"
#include "logger.h"
#include "mux.h"

//STACK IMPLEMENTATION//
#ifdef ENABLE_STACK_USAGE_STATITICS_REPORT

TIM_HandleTypeDef htim13;
static void MX_TIM13_Init(void);

#define TIMER3_INITIALISATION MX_TIM13_Init

#else
#define TIMER3_INITIALISATION()
#endif
//#define TIMER_EN 1

extern uint32_t rbt_time;
static uint8_t erly_cth_tmr_cnt=0;
extern IWDG_HandleTypeDef hiwdg;
extern os_timer_handle_ptr early_wdt_catch_tmr;
extern volatile uint8_t disable_wdt;
extern QSPI_HandleTypeDef hqspi;
extern QSPI_InfoTypeDef QspiInfo;
static rst_reason rst_rsn_arr[MAX_RST_RSN_IDX];
uint16_t rst_count;
static uint8_t rst_rsn_idx;
static reboot_reason rbt_rsn_arr[MAX_RBT_RSN_ARR];
reset_cause_t reset_cause ;
uint8_t rbt_arr_idx=0;
extern volatile uint8_t system_error;
volatile uint8_t debug_cb_idx=0;
extern volatile uint8_t flight_mode;

extern volatile uint8_t system_error;
extern volatile uint8_t disable_commit;
volatile uint8_t disable_wdt=0;
s_exo_debug exo_dbg_cb;
uint8_t aShowTime[50] = {0};
os_timer_handle_ptr early_wdt_catch_tmr;
uint8_t kernel_init_done=0;
uint32_t start_time =0;
uint32_t total_time =0;
extern ioal_fmc_nor_hdle ioal_nor_flash;
extern os_sem_handle_ptr intr_semhandle;

size_t xPortGetFreeHeapSize_eram( void );

/**
 * @brief Global variable for flight mode
 */
volatile uint8_t flight_mode = 1;

/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
		.name = "defaultTask",
		.stack_size = 128 * 4,
		.priority = (osPriority_t)P_DEFAULT_PRIO,
};


DMA_HandleTypeDef hdma_i2c1_rx;
DMA_HandleTypeDef hdma_i2c1_tx;
DMA_HandleTypeDef hdma_i2c2_rx;
DMA_HandleTypeDef hdma_i2c2_tx;
DMA_HandleTypeDef hdma_i2c3_rx;
DMA_HandleTypeDef hdma_i2c3_tx;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi1_tx;
DMA_HandleTypeDef hdma_spi2_rx;
DMA_HandleTypeDef hdma_spi2_tx;
DMA_HandleTypeDef hdma_uart4_rx;
DMA_HandleTypeDef hdma_uart4_tx;
DMA_HandleTypeDef hdma_usart6_rx;
DMA_HandleTypeDef hdma_usart6_tx;

FMC_SDRAM_TimingTypeDef  SDRAM_Timing;
FMC_SDRAM_CommandTypeDef command;
SDRAM_HandleTypeDef hsdram1;
IWDG_HandleTypeDef hiwdg;
WWDG_HandleTypeDef hwwdg;

/**
 * @brief Define the watchdog enable or disable
 */
#ifdef WDT_ENABLE
volatile uint8_t WDT_ENB =1;
#else
volatile uint8_t WDT_ENB =0;
#ifdef COREBOARD
//#error "WDT Disabled"
#endif
#endif

/**
 * @brief Define the core board configuration
 */
#ifdef STM32F765xx
volatile uint8_t BOARD = 1;
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcpp"
//#warning  "#####################This is not compiled for CORE BOARD #######################"
#pragma GCC diagnostic pop
volatile uint8_t BOARD = 0;
#endif

/**
 * @Brief Enable or disable the UART print
 */
#ifndef PRINT_UART_4
#ifndef PRINT_UART_5
volatile uint8_t PRINT_ENB=1;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcpp"
//#warning  "################### Print was enabled #####################"
#pragma GCC diagnostic pop
#endif
#endif
#ifdef PRINT_UART_4
#ifndef PRINT_UART_5
volatile uint8_t PRINT_ENB=0;
#endif
#endif
#ifndef PRINT_UART_4
#ifdef PRINT_UART_5
volatile uint8_t PRINT_ENB=0;
#endif
#endif

/**
 * @brief Enable or disable Bootloader
 */
#ifdef BTLR_ON
volatile uint8_t BOOTLOADER =1;
#else
#ifdef COREBOARD
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcpp"
//#warning  "################### Bootloader was disabled#####################"
//#error   "################### Bootloader was disabled#####################"
#pragma GCC diagnostic pop
#endif
volatile uint8_t BOOTLOADER =0;
#endif

/**
 * @brief Configure the interface for ground station communication.
 */
#ifndef GSOBC_USB_EN
#ifdef COREBOARD
//#error    "################### GS via Ethernet was enabled, so PS based validaiton cannot be performed #####################"
#endif
volatile uint8_t GS_OBC_VIA_USB_DISABLE=1;
#else
volatile uint8_t GS_OBC_VIA_USB_DISABLE =0;
#endif

/**
 * @brief Configure the interface for payload communication.
 */
#ifndef PSOBC_ETH_EN
volatile uint8_t PS_OBC_VIA_ETH_DISABLE =1;
#else
#ifdef COREBOARD
//#error   "################### PS via Ethernet was enabled, #####################"
#endif
volatile uint8_t PS_OBC_VIA_ETH_DISABLE =0;
#endif

/**
 * @brief Configure the coreboard communication.
 */
#ifndef S_BAND_SIM_CB
volatile uint8_t CORE_BRD_S_BAND_SIM_DISABLE =1;
#else
#ifdef COREBOARD
//#error  "################### S_BAND Simulator was enabled #####################"
#endif
volatile uint8_t CORE_BRD_S_BAND_SIM_DISABLE =0;
#endif

/**
 * @brief Configure EPS default state.
 */
#ifdef EPS_HRM_ON_DFLT
volatile uint8_t EPS_HRM_ON_DEFLT =1;
#else
#ifdef COREBOARD
//#error  "################### HRM ON was disabled  #####################"
#endif
volatile uint8_t EPS_HRM_ON_DEFLT =0;
#endif
#if 0
/**
 * @brief Configure payload server default state.
 */
#ifndef EPS_PS_ON_DFLT
volatile uint8_t EPS_PS_ON_DEFLT_DISABLE =1;
#else
#ifdef COREBOARD
//#error  "################### PS ON was default enabled  #####################"
#endif
volatile uint8_t EPS_PS_ON_DEFLT_DISABLE =0;
#endif
#endif
/**
 * @brief Disable heat sink
 */
#ifdef HEAT_SINK_DISABLE
//#error  "################### HEAT SINK Auto ON/OFF was disabled   #####################"
#endif
/**
 * @brief This function is use to print the build macros.
 */
void build_macro_print();
/**
 * @brief This function is configure the system clock.
 */
void SystemClock_Config(void);

/**
 * @brief Function to initialize DMA controller.
 */
void MX_DMA_Init(void);

/**
 * @brief This function initialize the GPIO controller.
 */
static void MX_GPIO_Init(void);

/**
 * @brief This function initialize the Independent watchdog timer.
 */
#ifdef WDT_ENABLE

static void MX_IWDG_Init(void);
#endif
/**
 * @brief This function initialize the memory production unit.
 */
//Warning Clearance:static void MPU_Config(void);

/**
 * @brief This function is initialize the FMC.
 */
static void MX_FMC_Init(void);

/**
 * @brief This function initialize the SDRAM sequence.
 */
static void BSP_SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram1, FMC_SDRAM_CommandTypeDef *Command);

/**
 * @brief This function is initialize the FMC SDRAM.
 */
int8_t fmc_sdram_init();

/**
 * @brief This API initialize the error handler.
 */
void exo_err_hdlr_init(void);

/*
 * Initialize logger
 */
void log_init(void);

/*
 * Test Thread
 */
void test_task(void *argument);

void* gpio_j = GPIOJ;
void* gpio_a = GPIOA;
/**
 * @brief Application entry point.
 * @retval int
 */

static void c_print_disable_message(void);


#if defined(COREBOARD) || defined(STM32F769xx)

static void MPU_Config (void);


#if 0

/*
 * Enable MPU for SDRAM memory to avoid unaligned access issue
 */
static void MPU_Config (void)
{
  MPU_Region_InitTypeDef MPU_InitStruct;

  /* Disable the MPU */
  HAL_MPU_Disable();

  /* Configure the MPU attributes for SDRAM */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress = 0xC0000000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.SubRegionDisable = 0x00;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Enable the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}


#endif

static void MPU_Config(void)
{
	  MPU_Region_InitTypeDef MPU_InitStruct;

	  /* Disable the MPU */
	  HAL_MPU_Disable();
	  
	  /* Configure the MPU attributes for SDRAM */
	  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	  MPU_InitStruct.BaseAddress = 0xC0000000;
	  MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
	  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
	  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
	  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
	  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
	  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
	  MPU_InitStruct.SubRegionDisable = 0x00;
	  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

	  HAL_MPU_ConfigRegion(&MPU_InitStruct);

	  /* Configure the MPU as Normal Non Cacheable for Ethernet Buffers in the SRAM2 */
	  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	  MPU_InitStruct.BaseAddress = 0x20003E00;
	  MPU_InitStruct.Size = MPU_REGION_SIZE_512B;
	  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
	  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
	  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
	  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
	  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
	  MPU_InitStruct.SubRegionDisable = 0x00;
	  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

	  HAL_MPU_ConfigRegion(&MPU_InitStruct);

	  /* Configure the MPU as Device for Ethernet Descriptors in the SRAM2 */
	  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	  MPU_InitStruct.BaseAddress = 0x20003C00;
	  MPU_InitStruct.Size = MPU_REGION_SIZE_512B;
	  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
	  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
	  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
	  MPU_InitStruct.Number = MPU_REGION_NUMBER2;
	  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	  MPU_InitStruct.SubRegionDisable = 0x00;
	  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

	  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Enable the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

  /* Enable I-Cache */
 //   SCB_EnableICache();

  //SCB_InvalidateDCache();
  /* Enable D-Cache */
 // SCB_EnableDCache();
}
#endif

static void c_print_disable_message(void)
{
#ifndef ENABLE_CPRINT
	printf("\r\nDEBUG C PRINTS WERE DISABLED IN SOFTWARE !!!\n");
#endif

}

void spi_uart_conv_int(void * arg)
{
	sem_give(intr_semhandle);
}



int main(void)
{



	if(0 == flight_mode)
	{
		disable_commit = 1;
		disable_wdt = 1;
		EPS_HRM_ON_DEFLT = 0;
	//	EPS_PS_ON_DEFLT_DISABLE = 0;
	}
	disable_wdt = 1;
    system_init();
    printf(" SYSTEM RESET CAUSE IS \"%s\"\n", reset_cause_get_name(reset_cause));
    printf("Exo firmware Major Version : %d\n",VER_u8DATA_SW_MAJOR);
    printf("Exo firmware Minor Version : %d\n",VER_u8DATA_SW_MINOR);
    app_main();
#ifdef TIMER_EN
	defaultTaskHandle = osThreadNew(test_task, NULL, &defaultTask_attributes);
#endif
	total_time = (HAL_GetTick()-start_time);
	printf("HAL init total time taken : %ld ms\n",total_time);
	total_time=0xFFFFFFFF;
	start_time = HAL_GetTick();
	kernel_init_done = 1;
	TIMER3_INITIALISATION();
	c_print_disable_message();

	//MX_TIM13_Init();

	osKernelStart();
}



void system_init()
{
	ps_brd_ssd_id ps_brd_id;
	ps_brd_id.ps_id = 2;
	ps_brd_id.ps_ssd_id =1;

	//int pr = 1;
	/*while(pr)
	{
     //   os_delay(10);
        if(pr == 0)
        {
        	break;
        }
	}*/

	reset_cause = reset_cause_get();
	cmalloc_track_init();
	MPU_Config();
	HAL_Init();
	SystemClock_Config();
	start_time = HAL_GetTick();
	MX_GPIO_Init();
	__enable_irq();
	MX_DMA_Init();
	osKernelInitialize();

#ifdef DBG_PRNT_EN
	log_thread_init(); // debug print enable
#endif

#ifdef COREBOARD
	 io_hal_fmc_nor_flash_init(&ioal_nor_flash,IOAL_INST_FMC_NOR1);
#endif

#if defined(COREBOARD) || defined(STM32F769xx)
	MX_FMC_Init();
	fmc_sdram_init();
    MPU_Config();
#endif
    hal_init();

    /*
     *  @brief This is functions is to enable the GEN2 boards
     */

#ifdef GEN2

    os_delay(1000);
	obc_gen2_gpio_init();
	back_plane_brd_select();
	os_delay(1000);
	power_board_init();
	io_board_init();
	io_board_select(1);
	common_mux_pin_select();
	edge_server_gpio_init();
	ps_brd_init();
	//paylaod_board_select(ps_brd_id);
	//edge_board_select(1);
	//max14830_start();
    //spi_to_uart_test();

#endif

#ifdef JANUS2
	obc_gpio_init();


#endif

#ifdef WDT_ENABLE
	if(disable_wdt==0)
	{
		MX_IWDG_Init();
		os_timer_create(&early_wdt_catch_tmr,"erly_wdt_ctch_tmr",PERIODIC,wdt_early_catch_tmr,NULL);
	}
#endif

	os_memcpy_fw_init();
	log_init(); // logger enable
	DEBUG_CPRINT((" SYSTEM RESET CAUSE IS \"%s\"\n", reset_cause_get_name(reset_cause)));
	build_macro_print();
	nvm_init();
	log_level_nvm_read();
	rtc_nvm_reload();
	preload_saved_rtc();
    save_rst_reason(reset_cause);
   // obc_gpio_exp_sequence();
#ifdef	JANUS2
	obc_gpio_exp_sequence();
#endif
	os_delay(750);   // ETH switch to ETH PHY LAN870A initialization delay
	MX_LWIP_Init();
	MX_USB_DEVICE_Init();
	ps_ethernet_enable();
#ifdef	MEM_DEBUG_ENB
	mem_debug_tracker_init();
#endif
	//err_init();
	bringup_sensors_init();
	exo_err_hdlr_init();
	bringup_force_test_run();
}

#ifdef TIMER_EN
/**
 * @brief This function for test task entry.
 */
void test_task(void *argument)
{
	for(;;)
	{
		ext_flash_mem_test();
#ifdef STM32F769xx
		HAL_GPIO_TogglePin(GPIOJ, GPIO_PIN_13);
#endif
	//	rtc_get_time();
		osDelay(1000);
	//	RTC_TimeShow(aShowTime);
	}
}
#endif
/**
 * @brief This function is use to print the build macros.
 */
void build_macro_print(void)
{
	DEBUG_CPRINT(("Flight Mode Enable stats %d",flight_mode));
	DEBUG_CPRINT(("WDT_ENB==%d\n",WDT_ENB));
	DEBUG_CPRINT(("BOARD==%d\n",BOARD));
//	DEBUG_CPRINT(("EPS_PS_ON_DEFLT_DISABLE==%d\n",EPS_PS_ON_DEFLT_DISABLE));
	DEBUG_CPRINT(("EPS_HRM_ON_DEFLT==%d\n",EPS_HRM_ON_DEFLT));
	DEBUG_CPRINT(("GS_OBC_VIA_USB_DISABLE==%d\n",GS_OBC_VIA_USB_DISABLE));
	DEBUG_CPRINT(("CORE_BRD_S_BAND_SIM_DISABLE==%d\n",CORE_BRD_S_BAND_SIM_DISABLE));
	DEBUG_CPRINT(("PRINT_ENB==%d\n",PRINT_ENB));
	DEBUG_CPRINT(("BOOTLOADER==%d\n",BOOTLOADER));
	DEBUG_CPRINT(("PS_OBC_VIA_ETH_DISABLE==%d\n",PS_OBC_VIA_ETH_DISABLE));
}
/**
 * @brief This function is initialize the FMC SDRAM.
 */

int8_t fmc_sdram_init()
{
	BSP_SDRAM_Initialization_Sequence(&hsdram1, &command);
	return 0;
}

#if defined(COREBOARD) || defined(STM32F765xx)
/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct = {0};
	RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

	/** Configure the main internal regulator output voltage
	 */
	__HAL_RCC_PWR_CLK_ENABLE();
	__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

	/** Initializes the RCC Oscillators according to the specified parameters
	 * in the RCC_OscInitTypeDef structure.
	 */
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
	RCC_OscInitStruct.HSEState = RCC_HSE_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.LSEState = RCC_LSE_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
	RCC_OscInitStruct.PLL.PLLM = 25;
	RCC_OscInitStruct.PLL.PLLN = 400;
	RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
	RCC_OscInitStruct.PLL.PLLQ = 5;
	RCC_OscInitStruct.PLL.PLLR = 2;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
		Error_Handler();
	}

	/** Activate the Over-Drive mode
	 */
	if (HAL_PWREx_EnableOverDrive() != HAL_OK)
	{
		Error_Handler();
	}

	/** Initializes the CPU, AHB and APB buses clocks
	 */
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
			|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK)
	{
		Error_Handler();
	}
	HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_PLLCLK, RCC_MCODIV_4);
}

#else

/**
 * @brief This function is configure the system clock.
 */
void SystemClock_Config(void)
{
	RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
	RCC_OscInitTypeDef RCC_OscInitStruct = {0};

	HAL_PWR_EnableBkUpAccess();
	__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);

	__HAL_RCC_PWR_CLK_ENABLE();
	__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

	HAL_StatusTypeDef ret = HAL_OK;
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
	RCC_OscInitStruct.HSEState = RCC_HSE_ON;
	RCC_OscInitStruct.LSEState = RCC_LSE_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
	RCC_OscInitStruct.PLL.PLLM = 25;
	RCC_OscInitStruct.PLL.PLLN = 400;
	RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
	RCC_OscInitStruct.PLL.PLLQ = 2;
	RCC_OscInitStruct.PLL.PLLR = 2;
	ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
	if(ret != HAL_OK)
	{
		while(1) { ; }
	}
	ret = HAL_PWREx_EnableOverDrive();
	if(ret != HAL_OK)
	{
		while(1) { ; }
	}
	RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
	ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6);
	if(ret != HAL_OK)
	{
		while(1) { ; }
	}
}
#endif


/**
 * @brief This function initialize the GPIO controller.
 */
static void MX_GPIO_Init(void)
{

		__HAL_RCC_GPIOE_CLK_ENABLE();
		__HAL_RCC_GPIOG_CLK_ENABLE();
		__HAL_RCC_GPIOD_CLK_ENABLE();
		__HAL_RCC_GPIOI_CLK_ENABLE();
		__HAL_RCC_GPIOF_CLK_ENABLE();
		__HAL_RCC_GPIOH_CLK_ENABLE();
		__HAL_RCC_GPIOC_CLK_ENABLE();
		__HAL_RCC_GPIOK_CLK_ENABLE();
		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		__HAL_RCC_GPIOJ_CLK_ENABLE();

	#ifdef STM32F769xx

		GPIO_InitTypeDef GPIO_InitStruct = {0};

		/*Configure GPIO pin 10 */
		GPIO_InitStruct.Pin = GPIO_PIN_10;
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

		/*Configure GPIO pin Output Level */
		HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_SET);


		/*Configure GPIO pin 14 */
		GPIO_InitStruct.Pin = GPIO_PIN_2;
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

		/*Configure GPIO pin Output Level */
		HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET);



		/*Configure GPIO pin Output Level */
		HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_13, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_5, GPIO_PIN_RESET);
#ifdef SPI_TO_UART_ENB
		/*Configure GPIO pin Output Level */
		  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);

		  /*Configure GPIO pin Output Level */
		  HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_3, GPIO_PIN_RESET);

		  /*Configure GPIO pin : GPIO_PIN_11 */
		  GPIO_InitStruct.Pin = GPIO_PIN_11;
		  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		  GPIO_InitStruct.Pull = GPIO_NOPULL;
		  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

		  /*Configure GPIO pin : GPIO_PIN_4 */
		  GPIO_InitStruct.Pin = GPIO_PIN_4;
		  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
		  GPIO_InitStruct.Pull = GPIO_NOPULL;
		  HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);

		/*Configure GPIO pin : GPIO_PIN_3 */
		GPIO_InitStruct.Pin = GPIO_PIN_3;
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);

		HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
		HAL_NVIC_EnableIRQ(EXTI4_IRQn);

#endif
		/*Configure GPIO pin : PJ13 */
		GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_5;
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);

		//configuring interrupt pin for EPS error flag
		GPIO_InitStruct.Pin = GPIO_PIN_8;
		GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

		/* EXTI interrupt init*/
		HAL_NVIC_SetPriority(EXTI9_5_IRQn,5 , 5);
		HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

#endif

#ifdef JANUS1

		GPIO_InitTypeDef GPIO_InitStruct = {0};
	/*Configure GPIO pin Output Level */
	HAL_GPIO_WritePin(GPIOK, GPIO_PIN_5, GPIO_PIN_SET);

	/*Configure GPIO pin : PK5 */
	GPIO_InitStruct.Pin = GPIO_PIN_5;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);

	/*Configure GPIO pin Output Level */
	HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_12, GPIO_PIN_RESET);

	/*Configure GPIO pin : PK5 */
	GPIO_InitStruct.Pin = GPIO_PIN_12;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);
	/*Configure GPIO pin : PA8 */
	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	//configuring interrupt pin for EPS error flag
	GPIO_InitStruct.Pin = GPIO_PIN_6;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

	/* EXTI interrupt init*/
	HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

	/* GPIO Ports Clock Enable */
	__HAL_RCC_GPIOK_CLK_ENABLE();

	/*Configure GPIO pin Output Level */
	HAL_GPIO_WritePin(GPIOK, GPIO_PIN_6, GPIO_PIN_RESET);

	/*Configure GPIO pin : PK6 */
	GPIO_InitStruct.Pin = GPIO_PIN_6;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);

	HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_10, GPIO_PIN_RESET);
	GPIO_InitStruct.Pin = GPIO_PIN_10;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_2|GPIO_PIN_0;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOK, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

	//    GPIO_InitStruct.Pin = GPIO_PIN_8;
	//    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
	//    GPIO_InitStruct.Pull = GPIO_NOPULL;
	//    HAL_GPIO_Init(GPIOJ, &GPIO_InitStruct);

	HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(EXTI0_IRQn);

	HAL_NVIC_SetPriority(EXTI2_IRQn, 5, 0);
	HAL_NVIC_EnableIRQ(EXTI2_IRQn);

	HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(EXTI3_IRQn);

	HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
#endif

#if defined(JANUS2) || defined(GEN2)

	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/*Configure GPIO pin : PA8 */
	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

#endif

}

//**********STACK_IMPLEMENTATION*******************************************************//
#ifdef ENABLE_STACK_USAGE_STATITICS_REPORT
static void MX_TIM13_Init(void)
{

  /* USER CODE BEGIN TIM13_Init 0 */
    __HAL_RCC_TIM13_CLK_ENABLE();

  /* USER CODE END TIM13_Init 0 */

  /* USER CODE BEGIN TIM13_Init 1 */

  /* USER CODE END TIM13_Init 1 */
  htim13.Instance = TIM13;
  htim13.Init.Prescaler = 3;
  htim13.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim13.Init.Period = 1599;
  htim13.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim13.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim13) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM13_Init 2 */
  /* Set priority for TIM8_UP_TIM13_IRQn IRQ */
      HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
      /* Enable IRQ for the TIM3 Timer*/
      HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
      /* Start TIM3 in interrupt mode */
      HAL_TIM_Base_Start_IT(&htim13);

  /* USER CODE END TIM13_Init 2 */

}
#endif
//**********************************************************************************//
/**
 * @brief Function to initialize DMA controller.
 */
void MX_DMA_Init(void)
{

	/* DMA controller clock enable */
	__HAL_RCC_DMA1_CLK_ENABLE();
	__HAL_RCC_DMA2_CLK_ENABLE();

	/* DMA interrupt init */
	/* DMA1_Stream0_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
	/* DMA1_Stream1_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
	/* DMA1_Stream2_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
	/* DMA1_Stream3_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
	/* DMA1_Stream4_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
	/* DMA1_Stream5_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
	/* DMA1_Stream6_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
	/* DMA1_Stream7_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
	/* DMA2_Stream0_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
	/* DMA2_Stream1_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
	/* DMA2_Stream5_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
	/* DMA2_Stream6_IRQn interrupt configuration */
	HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 5);
	HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);

}


#if defined(COREBOARD) || defined(STM32F769xx)
/**
 * @brief This function is initialize the FMC.
 */
static void MX_FMC_Init(void)
{
	FMC_SDRAM_TimingTypeDef SdramTiming = {0};

	hsdram1.Instance = FMC_SDRAM_DEVICE;
	/* hsdram1.Init */
	hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
#ifdef COREBOARD
	hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
	hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
#else
#ifdef STM32F769xx
	hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
	hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
#endif
#endif
	hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
	hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
	hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
	hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
	hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
	hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
	hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
	/* SdramTiming */
	SdramTiming.LoadToActiveDelay = 2;
	SdramTiming.ExitSelfRefreshDelay = 6;
	SdramTiming.SelfRefreshTime = 4;
	SdramTiming.RowCycleDelay = 6;
	SdramTiming.WriteRecoveryTime = 2;
	SdramTiming.RPDelay = 2;
	SdramTiming.RCDDelay = 2;

	if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
	{
		Error_Handler( );
	}
}
#endif

#ifdef WDT_ENABLE
/**
 * @brief This function initialize the Independent watchdog timer.
 */
void MX_IWDG_Init(void)
{
	hiwdg.Instance = IWDG;
	hiwdg.Init.Prescaler = IWDG_PRESCALER_256;
	hiwdg.Init.Window = 4095;
	hiwdg.Init.Reload = 3750;
	if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
	{
		Error_Handler();
	}
}
#endif


/**
 * @brief This function initialize the window watchdog timer.
 */
void MX_WWDG_Init(void)
{
	hwwdg.Instance = WWDG;
	hwwdg.Init.Prescaler = WWDG_PRESCALER_1;
	hwwdg.Init.Window = 64;
	hwwdg.Init.Counter = 64;
	hwwdg.Init.EWIMode = WWDG_EWI_DISABLE;
	if (HAL_WWDG_Init(&hwwdg) != HAL_OK)
	{
		Error_Handler();
	}
}
#if 0
/**
 * @brief This function initialize the memory production unit.
 */
void MPU_Config(void)
{
	MPU_Region_InitTypeDef MPU_InitStruct = {0};
	/* Disables the MPU */
	HAL_MPU_Disable();
	/* Configure the MPU as Strongly ordered for not defined regions */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
	MPU_InitStruct.BaseAddress      = 0x00;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_4GB;
	MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsShareable      = MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	MPU_InitStruct.SubRegionDisable = 0x87;
	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;
	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// Internal RAM
	/** Initializes and configures the Region and the memory to be protected
	 */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
	MPU_InitStruct.BaseAddress      = 0x20000000;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	//  MPU_REGION_PRIV_RW_URO - Write only in previliged mode
	//  MPU_REGION_FULL_ACCESS -Full access
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
	// MPU_ACCESS_NOT_SHAREABLE
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	//MPU_ACCESS_CACHEABLE
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
	//MPU_ACCESS_NOT_BUFFERABLE
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// External RAM
	/** Initializes and configures the Region and the memory to be protected
	 */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER2;
	MPU_InitStruct.BaseAddress      = 0xC0000000;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_8MB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	//  MPU_REGION_PRIV_RW_URO - Write only in previliged mode
	//  MPU_REGION_FULL_ACCESS -Full access
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;
	// MPU_ACCESS_NOT_SHAREABLE
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	//MPU_ACCESS_CACHEABLE
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
	//MPU_ACCESS_NOT_BUFFERABLE
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// Internal Flash
	/** Initializes and configures the Region and the memory to be protected
	 */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER3;
	MPU_InitStruct.BaseAddress      = 0x08000000;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_2MB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	//  MPU_REGION_PRIV_RW_URO - Write only in previliged mode
	//  MPU_REGION_FULL_ACCESS -Full access
	MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_URO;

	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
	// MPU_ACCESS_NOT_SHAREABLE
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	//MPU_ACCESS_CACHEABLE
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
	//MPU_ACCESS_NOT_BUFFERABLE
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// FMC NOR Flash
	/** Initializes and configures the Region and the memory to be protected
	 */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER4;
	MPU_InitStruct.BaseAddress      = 0x06000000;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_16MB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	//  MPU_REGION_PRIV_RW_URO - Write only in previliged mode
	//  MPU_REGION_FULL_ACCESS -Full access
	MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_URO;

	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
	// MPU_ACCESS_NOT_SHAREABLE
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	//MPU_ACCESS_CACHEABLE
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
	//MPU_ACCESS_NOT_BUFFERABLE
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// QSPI NOR Flash
	/** Initializes and configures the Region and the memory to be protected
	 */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER5;
	MPU_InitStruct.BaseAddress      = 0x09000000;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_64MB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	//  MPU_REGION_PRIV_RW_URO - Write only in previliged mode
	//  MPU_REGION_FULL_ACCESS -Full access
	MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_URO;

	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;
	// MPU_ACCESS_NOT_SHAREABLE
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	//MPU_ACCESS_CACHEABLE
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
	//MPU_ACCESS_NOT_BUFFERABLE
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	// System memory
	/** Initializes and configures the Region and the memory to be protected
	 */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER6;
	MPU_InitStruct.BaseAddress      = 0x00000000;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_4MB;
	MPU_InitStruct.SubRegionDisable = 0x0;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	//  MPU_REGION_PRIV_RW_URO - Write only in previliged mode
	//  MPU_REGION_FULL_ACCESS -Full access
	MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_URO;

	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;
	// MPU_ACCESS_NOT_SHAREABLE
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	//MPU_ACCESS_CACHEABLE
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
	//MPU_ACCESS_NOT_BUFFERABLE
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);   //MPU_HFNMI_PRIVDEF_NONE

}
#endif
/**
 * @brief This function initialize the SDRAM sequence.
 */
static void BSP_SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram1, FMC_SDRAM_CommandTypeDef *Command)
{
	__IO uint32_t tmpmrd =0;
	/* Step 3:  Configure a clock configuration enable command */
	Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
	Command->AutoRefreshNumber = 1;
	Command->ModeRegisterDefinition = 0;

	/* Send the command */
	HAL_SDRAM_SendCommand(hsdram1, Command, SDRAM_TIMEOUT);

	/* Step 4: Insert 100 us minimum delay */
	/* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
	HAL_Delay(1);

	/* Step 5: Configure a PALL (precharge all) command */
	Command->CommandMode = FMC_SDRAM_CMD_PALL;
	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
	Command->AutoRefreshNumber = 1;
	Command->ModeRegisterDefinition = 0;

	/* Send the command */
	HAL_SDRAM_SendCommand(hsdram1, Command, SDRAM_TIMEOUT);

	/* Step 6 : Configure a Auto-Refresh command */
	Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
	Command->AutoRefreshNumber = 8;
	Command->ModeRegisterDefinition = 0;

	/* Send the command */
	HAL_SDRAM_SendCommand(hsdram1, Command, SDRAM_TIMEOUT);

	/* Step 7: Program the external memory mode register */
	tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |
			SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
			SDRAM_MODEREG_CAS_LATENCY_2           |
			SDRAM_MODEREG_OPERATING_MODE_STANDARD |
			SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

	Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
	Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
	Command->AutoRefreshNumber = 1;
	Command->ModeRegisterDefinition = tmpmrd;

	/* Send the command */
	HAL_SDRAM_SendCommand(hsdram1, Command, SDRAM_TIMEOUT);

	/* Step 8: Set the refresh rate counter */
	/* (15.62 us x Freq) - 20 */
	/* Set the device refresh counter */
	hsdram1->Instance->SDRTR |= ((uint32_t)((1292)<< 1));

}

/**
 * @brief  Period elapsed callback in non blocking mode
 * @note   This function is called  when TIM1 interrupt took place, inside
 * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
 * a global variable "uwTick" used as application time base.
 * @param  htim : TIM handle
 * @retval None
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == TIM1) {
		HAL_IncTick();
	}
}

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
	/* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	EXO_ASSERT(UNKNOWN_ERROR);
	__disable_irq();
	while (1)
	{
	}
}

/**
 * @brief API to get the reset reason name from the given reset cause
 */
reset_cause_t reset_cause_get(void)
{
	reset_cause_t reset_cause;

	if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST))
	{
		reset_cause = RESET_CAUSE_LOW_POWER_RESET;
	}
	else if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST))
	{
		reset_cause = RESET_CAUSE_WINDOW_WATCHDOG_RESET;
	}
	else if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST))
	{
		reset_cause = RESET_CAUSE_INDEPENDENT_WATCHDOG_RESET;
	}
	else if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST))
	{
		// This reset is induced by calling the ARM CMSIS
		// `NVIC_SystemReset()` function!
		reset_cause = RESET_CAUSE_SOFTWARE_RESET;
	}
	else if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST))
	{
		reset_cause = RESET_CAUSE_POWER_ON_POWER_DOWN_RESET;
	}
	else if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST))
	{
		reset_cause = RESET_CAUSE_EXTERNAL_RESET_PIN_RESET;
	}
	// Needs to come *after* checking the `RCC_FLAG_PORRST` flag in order to
	// ensure first that the reset cause is NOT a POR/PDR reset. See note
	// below.
	else if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST))
	{
		reset_cause = RESET_CAUSE_BROWNOUT_RESET;
	}
	else
	{
		reset_cause = RESET_CAUSE_UNKNOWN;
	}

	// Clear all the reset flags or else they will remain set during future
	// resets until system power is fully removed.
	__HAL_RCC_CLEAR_RESET_FLAGS();

	return reset_cause;
}

/**
 * @brief API to get the reset reason name from the given reset cause
 */
const char * reset_cause_get_name(reset_cause_t reset_cause)
{
	const char * reset_cause_name = "TBD";
	switch (reset_cause)
	{
	case RESET_CAUSE_UNKNOWN:
		reset_cause_name = "UNKNOWN";
		break;
	case RESET_CAUSE_LOW_POWER_RESET:
		reset_cause_name = "LOW_POWER_RESET";
		break;
	case RESET_CAUSE_WINDOW_WATCHDOG_RESET:
		reset_cause_name = "WINDOW_WATCHDOG_RESET";
		break;
	case RESET_CAUSE_INDEPENDENT_WATCHDOG_RESET:
		reset_cause_name = "INDEPENDENT_WATCHDOG_RESET";
		break;
	case RESET_CAUSE_SOFTWARE_RESET:
		reset_cause_name = "SOFTWARE_RESET";
		break;
	case RESET_CAUSE_POWER_ON_POWER_DOWN_RESET:
		reset_cause_name = "POWER-ON_RESET (POR) / POWER-DOWN_RESET (PDR)";
		break;
	case RESET_CAUSE_EXTERNAL_RESET_PIN_RESET:
		reset_cause_name = "EXTERNAL_RESET_PIN_RESET";
		break;
	case RESET_CAUSE_BROWNOUT_RESET:
		reset_cause_name = "BROWNOUT_RESET (BOR)";
		break;
	}

	return reset_cause_name;
}

void get_mcu_reset_reason_info(reset_info* rst_inf)
{
	uint8_t mem_size = sizeof(rst_reason)*MAX_RST_RSN_IDX;
    os_memcpy(rst_inf,&rst_rsn_arr,mem_size);
    os_memcpy(((uint8_t*)rst_inf)+mem_size,&rst_count,2);
    os_memcpy(((uint8_t*)rst_inf)+mem_size+2,&rst_rsn_idx,1);
}


/**
 *
 *
 *
 * @brief API to save the reset reason in NVM.
 */
void save_rst_reason(uint32_t rst_rsn)
{

	rst_reason rsn;
	rsn.reset_reason=rst_rsn;
	rsn.get_time = (time_t)get_crnt_time_date_in_epoch();
	nvm_parameter_read(NVM_DATA,NVM_RST_RSN_IDX,(uint8_t*)&rst_rsn_idx);
	nvm_parameter_read(NVM_DATA,NVM_RST_CNT,(uint8_t*)&rst_count);
	nvm_parameter_read(NVM_DATA,NVM_RST_RSN_BUFF,(uint8_t*)&rst_rsn_arr);
	nvm_parameter_read(NVM_DATA,NVM_MIN_RBT_TIME,(uint8_t*)&rbt_time);

	if(rst_rsn_idx < MAX_RST_RSN_IDX)
	{
		rst_rsn_arr[rst_rsn_idx]=rsn;
		rst_rsn_idx++;
	}
	else
	{
		rst_rsn_idx=0;
		rst_rsn_arr[rst_rsn_idx]=rsn;
	}
	if(rst_count<60000)
	{
		rst_count++;
	}
	else
	{
		rst_count=1;
	}
	nvm_parameter_write(NVM_DATA,NVM_RST_RSN_IDX,(uint8_t*)&rst_rsn_idx);
	nvm_parameter_write(NVM_DATA,NVM_RST_CNT,(uint8_t*)&rst_count);
	nvm_parameter_write(NVM_DATA,NVM_RST_RSN_BUFF,(uint8_t*)&rst_rsn_arr);
    nvm_commit();
}

/**
 * @brief API to shutdown the system
 */
void system_shutdown(void)
{
	DEBUG_CPRINT(("System Shutdown...........\n"));
	exo_wdt_refresh();
	nvm_commit();
#ifdef WDT_ENABLE
	if(disable_wdt==0)
	{
		HAL_NVIC_SystemReset();
	}
	else
	{
		while(1);
	}
#else
	while(1);
#endif
}

/**
 * @brief API to refresh watchdog timer
 */
void exo_wdt_refresh()
{
#ifdef WDT_ENABLE
	if(disable_wdt==0)
	{
		HAL_IWDG_Refresh(&hiwdg);
		erly_cth_tmr_cnt=0;
		os_timer_start(early_wdt_catch_tmr,EARLY_WDT_CATCH_TIME);
	}
#endif
}

/**
 * @brief Watchdog early catch timer handler
 */
void wdt_early_catch_tmr(void* args)
{
	erly_cth_tmr_cnt++;
	if(erly_cth_tmr_cnt>2)
	{
		EXO_ASSERT(EARLY_WDT_TIMER_ASSERT);
	}
}

/**
 * @brief API request to reboot.
 */
uint8_t reboot_request(uint32_t reboot_src)
{
	uint8_t ret_val=0;
	uint64_t crnt_tm=0;
	uint64_t recent_rbt_tm=0;
	nvm_parameter_read(NVM_DATA,NVM_REBOOT_RSN_BUFF,(uint8_t*)rbt_rsn_arr);
	nvm_parameter_read(NVM_DATA,NVM_REBOOT_RSN_IDX,(uint8_t*)&rbt_arr_idx);
	crnt_tm = get_crnt_time_date_in_epoch();
	if(rst_rsn_idx>0)
	{
		recent_rbt_tm=rst_rsn_arr[rst_rsn_idx-1].get_time;
	}
	if((crnt_tm - recent_rbt_tm) > rbt_time*60)
	{
		rbt_rsn_arr[rbt_arr_idx].rbt_src=reboot_src;
		rbt_rsn_arr[rbt_arr_idx].rbt_tm=(time_t)crnt_tm;

		if(rbt_arr_idx < (MAX_RBT_RSN_ARR-1))
		{rbt_arr_idx++;}
		else
		{rbt_arr_idx=0;}

		nvm_parameter_write(NVM_DATA,NVM_REBOOT_RSN_BUFF,(uint8_t*)rbt_rsn_arr);
		nvm_parameter_write(NVM_DATA,NVM_REBOOT_RSN_IDX,(uint8_t*)&rbt_arr_idx);
		ret_val=0;
		system_shutdown();
	}
	else
	{
		ret_val=1;

	}
	return ret_val;
}

/**
 * @brief API to save the debug information.
 */
void exo_err_hdlr_save_dgb_cb(uint8_t err_no)
{
	// Update sw debug control block
	//    exo_dbg_cb.sw_dbg.last_thread_id_exec =
	exo_dbg_cb.sw_dbg.reset_cause          = err_no;
	exo_dbg_cb.sw_dbg.shutdown_rtc_time    = get_crnt_time_date_in_epoch();
	exo_dbg_cb.sw_dbg.iram_avail_heap_size =  xPortGetFreeHeapSize();
	exo_dbg_cb.sw_dbg.sram_avail_heap_size = xPortGetFreeHeapSize_eram();

	// update sys structure including err number
	// nvm write debug context s_exo_debug with asscated index number,
	// save gloable variable idex to nvm
	nvm_parameter_write(NVM_DATA,DBG_CB_IDX ,(uint8_t*)&debug_cb_idx);

	nvm_parameter_write(NVM_DATA,DBG_CB_0 + debug_cb_idx ,(uint8_t*)&exo_dbg_cb);

}

/**
 * @brief Function for error handler.
 */
void exo_err_hdlr(uint8_t err_no)
{

#if (PERIODIC_LOG_ENB != PERIODIC_LOGGER_OFF) 
        logger_periodic_timeout_cb(NULL);
#endif
	taskDISABLE_INTERRUPTS();
	/** Set the Error Flag to handle os_delay with sw_os_delay() */
	system_error=1;

#ifdef WDT_ENABLE
	HAL_IWDG_Refresh(&hiwdg);
#endif

	print_mem_leak();

#ifdef WDT_ENABLE
	HAL_IWDG_Refresh(&hiwdg);
#endif

	exo_err_hdlr_save_dgb_cb(err_no);

#ifdef WDT_ENABLE
	HAL_IWDG_Refresh(&hiwdg);
#endif

	os_delay(1000);

	// call shutdown api
#ifdef WDT_ENABLE
	system_shutdown();
#endif
	/**Call never returns here*/
	while(1);
}

/**
 * @brief This API initialize the error handler.
 */
void exo_err_hdlr_init(void)
{
	if(MAX_DBG_SIZE < sizeof(s_exo_debug))
	{
		EXO_ASSERT(ERR_HDLR_MAX_SIZE_EXCEED);
	}

	exo_dbg_cb.sw_dbg.boot_rtc_time = get_crnt_time_date_in_epoch();

	// Read NVM current IDX, save it in global variable,
	nvm_parameter_read(NVM_DATA,DBG_CB_IDX,(uint8_t*)&debug_cb_idx);

	if(debug_cb_idx > (MAX_DBG_IDX))
	{
		debug_cb_idx = 0;
	}

	// Increament and save it global variable
	debug_cb_idx = (debug_cb_idx + 1) % MAX_DBG_IDX;

}

#ifdef  USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
	/* USER CODE BEGIN 6 */
	/* User can add his own implementation to report the file name and line number,
ex: DEBUG_CPRINT(Wrong parameters value: file %s on line %d\r\n", file, line)) */
	/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
#endif
