text: /** \copyright
   * Copyright (c) 2012, Stuart W Baker
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are  permitted provided that the following conditions are met:
   *
   *  - Redistributions of source code must retain the above copyright notice,
   *    this list of conditions and the following disclaimer.
   *
   *  - Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   *
   * \file HwInit.cxx
   * This file represents the hardware initialization for the TI Tiva MCU.
   *
   * @author Stuart W. Baker
   * @date 5 January 2013
   */
  
  #include <new>
  #include <cstdint>
  
  #include "stm32f3xx_hal_conf.h"
  
  #include "os/OS.hxx"
  #include "Stm32Uart.hxx"
  #include "Stm32Can.hxx"
  #include "Stm32EEPROMEmulation.hxx"
  
  #include "hardware.hxx"
  
  /** override stdin */
  const char *STDIN_DEVICE = "/dev/ser0";
  
  /** override stdout */
  const char *STDOUT_DEVICE = "/dev/ser0";
  
  /** override stderr */
  const char *STDERR_DEVICE = "/dev/ser0";
  
  /** UART 0 serial driver instance */
  
  // this driver causes us to crash in default_interrupt_handler. Check that the
  // appropriate weak definition / implementation is used.
  
  //static Stm32Uart uart0("/dev/ser0", USART1, USART1_IRQn);
  
  /** CAN 0 CAN driver instance */
  static Stm32Can can0("/dev/can0");
  
  /** EEPROM emulation driver. The file size might be made bigger. */
  static Stm32EEPROMEmulation eeprom0("/dev/eeprom", 512);
  const size_t EEPROMEmulation::SECTOR_SIZE = 2048;
  
  extern "C" {
  
  /** Blink LED */
  uint32_t blinker_pattern = 0;
  static uint32_t rest_pattern = 0;
  
  void hw_set_to_safe(void)
  {
  }
  
  void resetblink(uint32_t pattern)
  {
      blinker_pattern = pattern;
      
      if (pattern)
      {
          HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_SET);
      }
      else
      {
          HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_RESET);
      }
      /* make a timer event trigger immediately */
  }
  
  void setblink(uint32_t pattern)
  {
      resetblink(pattern);
  }
  
  void tim7_interrupt_handler(void)
  {
      //
      // Clear the timer interrupt.
      //
      TIM7->SR = ~TIM_IT_UPDATE;
  
      // Set output LED.
      BLINKER_RAW_Pin::set(rest_pattern & 1);
  
      // Shift and maybe reset pattern.
      rest_pattern >>= 1;
      if (!rest_pattern)
      {
          rest_pattern = blinker_pattern;
      }
  }
  
  void diewith(uint32_t pattern)
  {
      //vPortClearInterruptMask(0x20);
      asm("cpsie i\n");
  
      resetblink(pattern);
      while (1)
          ;
  }
  
  /** CPU clock speed. */
  const unsigned long cm3_cpu_clock_hz = 72000000;
  uint32_t SystemCoreClock;
  const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
  const uint8_t APBPrescTable[8]  = {0, 0, 0, 0, 1, 2, 3, 4};
  
  
  /**
    * @brief  System Clock Configuration
    *         The system Clock is configured as follow : 
    *            System Clock source            = PLL (HSE)
    *            SYSCLK(Hz)                     = 72000000
    *            HCLK(Hz)                       = 72000000
    *            AHB Prescaler                  = 1
    *            APB1 Prescaler                 = 2
    *            APB2 Prescaler                 = 1
    *            HSE Frequency(Hz)              = 8000000
    *            HSE PREDIV                     = 1
    *            PLLMUL                         = 9
    *            Flash Latency(WS)              = 2
    * @param  None
    * @retval None
    */
  static void clock_setup(void)
  {
      HAL_RCC_DeInit();
      
      RCC_ClkInitTypeDef RCC_ClkInitStruct;
      RCC_OscInitTypeDef RCC_OscInitStruct;
  
      /* Enable HSE Oscillator and activate PLL with HSE as source */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
      RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
      RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
      RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  
      HAL_RCC_OscConfig(&RCC_OscInitStruct); 
      	
      /* Select PLL as system clock source and configure the HCLK, PCLK1 and
       * PCLK2 clocks dividers
       */
      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_DIV2;  
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  
      HASSERT(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) == HAL_OK);
  
      SystemCoreClock = cm3_cpu_clock_hz;
  }
  
  /** Initialize the processor hardware.
   */
  void hw_preinit(void)
  {
      /* Globally disables interrupts until the FreeRTOS scheduler is up. */
      asm("cpsid i\n");
  
      /* these FLASH settings enable opertion at 72 MHz */
      __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
      __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_2);
  
      /* setup the system clock */
      clock_setup();
  
      /* enable peripheral clocks */
      __HAL_RCC_GPIOA_CLK_ENABLE();
      __HAL_RCC_GPIOB_CLK_ENABLE();
      __HAL_RCC_GPIOE_CLK_ENABLE();
      __HAL_RCC_USART1_CLK_ENABLE();
      __HAL_RCC_CAN1_CLK_ENABLE();
      __HAL_RCC_TIM7_CLK_ENABLE();
  
      GpioInit::hw_init();
  
      /* setup pinmux */
      GPIO_InitTypeDef gpio_init;
      memset(&gpio_init, 0, sizeof(gpio_init));
      /* USART1 pinmux on PA9 and PA10 */
      gpio_init.Mode      = GPIO_MODE_AF_PP;
      gpio_init.Pull      = GPIO_PULLUP;
      gpio_init.Speed     = GPIO_SPEED_FREQ_HIGH;
      gpio_init.Alternate = GPIO_AF7_USART1;
      gpio_init.Pin       = GPIO_PIN_9;
      HAL_GPIO_Init(GPIOA, &gpio_init);
      gpio_init.Pin       = GPIO_PIN_10;
      HAL_GPIO_Init(GPIOA, &gpio_init);
  
      /* CAN pinmux on PB8 and PB9 */
      gpio_init.Mode      = GPIO_MODE_AF_PP;
      gpio_init.Pull      = GPIO_PULLUP;
      gpio_init.Speed     = GPIO_SPEED_FREQ_HIGH;
      gpio_init.Alternate = GPIO_AF9_CAN;
      gpio_init.Pin       = GPIO_PIN_8;
      HAL_GPIO_Init(GPIOB, &gpio_init);
      gpio_init.Pin       = GPIO_PIN_9;
      HAL_GPIO_Init(GPIOB, &gpio_init);
  
      /* Initializes the blinker timer. */
      TIM_HandleTypeDef TimHandle;
      memset(&TimHandle, 0, sizeof(TimHandle));
      TimHandle.Instance = TIM7;
      TimHandle.Init.Period = configCPU_CLOCK_HZ / 10000 / 8;
      TimHandle.Init.Prescaler = 10000;
      TimHandle.Init.ClockDivision = 0;
      TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
      TimHandle.Init.RepetitionCounter = 0;
      if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
      {
          /* Initialization Error */
          HASSERT(0);
      }
      if (HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
      {
          /* Starting Error */
          HASSERT(0);
      }
      NVIC_SetPriority(TIM7_IRQn, 0);
      NVIC_EnableIRQ(TIM7_IRQn);
  }
  
  }
  