/**current_mode
  ******************************************************************************
  * @file    Project/main.c
  * @author  "Volodymyr M. Shylov" <shilow@ukr.net>
  * @version v.0.1
  * @date    24-11-2023
  * @brief   Main program body. VA-meter from DC/DC XL4005
   ******************************************************************************
  * @attention
  *
  * "THE BEER-WARE LICENSE" (Revision 42):
  * <shilow@ukr.net> wrote this file.  As long as you retain this notice you
  * can do whatever you want with this stuff. If we meet some day, and you think
  * this stuff is worth it, you can buy me a beer in return.   Shilov V.N.
  *
  ******************************************************************************
  */


/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
#include "board.h"
#include "led.h"
#include "delay.h"

/* Private define ------------------------------------------------------------*/
#define TIM4_PERIOD  (uint8_t)124

/* Private typedef -----------------------------------------------------------*/
typedef enum {
  voltage_mode,
  current_mode
} measure_mode_t;
/* Private constants ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint16_t ConversionBuffer[ADC_SMPLS];
__IO uint8_t BufferIndex = 0;
static uint16_t Voltage, Current;
static measure_mode_t MeasureMode = voltage_mode;

/* Private function prototypes -----------------------------------------------*/
static void boardInit(void);
static void showV(void);
static void showC(void);

void main(void)
{
  /* Board Configuration */
  boardInit();
  Delay(100);
  SWITCH_ON;

  /* Infinite loop */
  while (1) {
    wfi();
    if (BufferIndex >= ADC_SMPLS) {
      BufferIndex = 0;
      int8_t i;
      uint32_t tbuf = 0;
      for (i=0; i<ADC_SMPLS; i++) {
        tbuf += ConversionBuffer[i];  
      }

      if (MeasureMode == voltage_mode) {
        MeasureMode = current_mode;
        ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
        ADC1->CSR |= (uint8_t)(ADC_CHNLI);

        tbuf /= ADC_SMPLS;
        tbuf *= VOLTAGE_MUL;
        tbuf /= VOLT_MUL_MUL;
        Voltage = tbuf;
      } else {
        MeasureMode = voltage_mode;
        ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
        ADC1->CSR |= (uint8_t)(ADC_CHNLU);

        tbuf /= ADC_SMPLS;
        tbuf *= CURRENT_MUL;
        tbuf /= CURR_MUL_MUL;
        Current = tbuf;
      }

      /* arrived new data, show it */
      showV();
      showC();
    }
  }

}

/* Private functions ---------------------------------------------------------*/
static void showV(void) {
  uint16_t a = Voltage;
  LedDigits[0] = a / 1000;
  uint16_t b = a % 1000;
  LedDigits[1] = b / 100;
  uint8_t c = b % 100;
  LedDigits[2] = c / 10;
  LedDigits[3] = c % 10;
}

static void showC(void) {
  uint16_t a = Current;
  LedDigits[4] = a / 1000;
  uint16_t b = a % 1000;
  LedDigits[5] = b / 100;
  uint8_t c = b % 100;
  LedDigits[6] = c / 10;
  LedDigits[7] = c % 10;
}

static void boardInit(void) {
  /* Насколько я понял, для частот выше 16МГц нужно вводить задержку при работе с FLASH:
    - Before using the HSE clock make sure that the "Flash_Wait_States" is set to 1.
    - To do so :
     - with STVD (menu: Debug Instrument -> MCU configuration -> Options)
     - with EWSTM8 (menu: ST-LINK -> Option bytes ->Flash_Wait_States: 1)
  */

  /* Initialization of the clock to 16MHz */
  CLK->CKDIVR = 0x00;

  /* Disable clock of unused peripherial */
  CLK->PCKENR1 = (uint8_t)(~(CLK_PCKENR1_UART1 | CLK_PCKENR1_SPI));
  CLK->PCKENR2 = (uint8_t)(~(CLK_PCKENR2_CAN | CLK_PCKENR2_AWU)); // | CLK_PCKENR2_ADC

  /* SWIM clock */
  CLK->SWIMCCR = 0x00;

  /* SWITCH pin to Push-Pull, High, Fast */
  SWITCH_PORT->ODR |= (uint8_t)(SWITCH_PIN);
  SWITCH_PORT->DDR |= (uint8_t)(SWITCH_PIN);
  SWITCH_PORT->CR1 |= (uint8_t)(SWITCH_PIN);
  SWITCH_PORT->CR2 |= (uint8_t)(SWITCH_PIN);
  SWITCH_OFF;

  /* Configure GPIO used for LED to Push-Pull, High, Fast*/
  GPIOA->ODR |= (uint8_t)LED_SEG_CG;
  GPIOA->DDR |= (uint8_t)LED_SEG_CG;
  GPIOA->CR1 |= (uint8_t)LED_SEG_CG;
  GPIOA->CR2 |= (uint8_t)LED_SEG_CG;

  GPIOB->ODR |= (uint8_t)LED_SEG_DH;
  GPIOB->DDR |= (uint8_t)LED_SEG_DH;
  GPIOB->CR1 |= (uint8_t)LED_SEG_DH;
  GPIOB->CR2 |= (uint8_t)LED_SEG_DH;

  GPIOC->ODR |= (uint8_t)LED_SEG_BE;
  GPIOC->DDR |= (uint8_t)LED_SEG_BE;
  GPIOC->CR1 |= (uint8_t)LED_SEG_BE;
  GPIOC->CR2 |= (uint8_t)LED_SEG_BE;

  GPIOD->ODR |= (uint8_t)LED_SEG_AF;
  GPIOD->DDR |= (uint8_t)LED_SEG_AF;
  GPIOD->CR1 |= (uint8_t)LED_SEG_AF;
  GPIOD->CR2 |= (uint8_t)LED_SEG_AF;

  /* `SPI` pins to Push-Pull, High, Fast */
  SPI_PORT->ODR |= (uint8_t)(SPI_SCK|SPI_DATA);
  SPI_PORT->DDR |= (uint8_t)(SPI_SCK|SPI_DATA);
  SPI_PORT->CR1 |= (uint8_t)(SPI_SCK|SPI_DATA);
  SPI_PORT->CR2 |= (uint8_t)(SPI_SCK|SPI_DATA);

  /* I2C GPIO SDA SCL - HiZ, Open drain, Fast */
  //GPIOB->DDR |= (GPIO_PIN_4 | GPIO_PIN_5);
  //GPIOB->ODR |= (GPIO_PIN_4 | GPIO_PIN_5);
  //GPIOB->CR2 |= (GPIO_PIN_4 | GPIO_PIN_5);

  /** Configure ADC1 peripheral */
  /* Configure the data alignment */
  ADC1->CR2 |= (uint8_t)(ADC1_CR2_ALIGN);
  /* Set the single conversion mode */
  ADC1->CR1 &= (uint8_t)(~ADC1_CR1_CONT);
  /* Clear the ADC1 channels */
  ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
  /* Select the ADC1 channel */
  ADC1->CSR |= (uint8_t)(ADC_CHNLU);
  /* Clear the SPSEL bits */
  ADC1->CR1 &= (uint8_t)(~ADC1_CR1_SPSEL);
  /* Select the prescaler division factor according to ADC1_PrescalerSelection values */
  ADC1->CR1 |= (uint8_t)(ADC1_PRESSEL_FCPU_D8);
  /* Enable the external Trigger */
  ADC1->CR2 |= (uint8_t)(ADC1_CR2_EXTTRIG);
  /* Set the 'Internal TIM1 TRGO event' as external trigger */
  ADC1->CR2 &= (uint8_t)~(ADC1_CR2_EXTSEL);
  /* disables the ADC1 Schmitt Trigger on a selected channel(s) */
  ADC1->TDRL |= (uint8_t)((1 << ADC_SCHTU) | (1 << ADC_SCHTI));
  /* Enable the ADC1 EOC interrupt */
  ADC1->CSR |= (uint8_t)ADC1_IT_EOCIE;
  /* Enable the ADC1 peripheral */
  ADC1->CR1 |= ADC1_CR1_ADON;

  /** Configure TIM1 peripheral. Time Base configuration:
  Timer period - 3,125 ms
  TIM1_Period = 50
  TIM1_Prescaler = 1000
  TIM1_CounterMode = TIM1_COUNTERMODE_UP
  TIM1_RepetitionCounter = 0
  */
  /* Set the Autoreload value */
  TIM1->ARRH = (uint8_t)(49 >> 8);
  TIM1->ARRL = (uint8_t)(49);
  /* Set the Prescaler value */
  TIM1->PSCRH = (uint8_t)(499 >> 8);
  TIM1->PSCRL = (uint8_t)(499);
  /* Select the Counter Mode */
  TIM1->CR1 = 0x0;
  /* Set the Repetition Counter value */
  TIM1->RCR = 0;
  /* Trigrer configuration */
  TIM1->CR2 = (uint8_t)TIM1_TRGOSOURCE_UPDATE;
  /* Update Interrupt Enable */
  //TIM1->IER |= (uint8_t)TIM1_IT_UPDATE;
  /* Enable TIM1 */
  TIM1->CR1 |= TIM1_CR1_CEN;

  /**
  TIM4 configuration:
   - TIM4CLK is set to 16 MHz, the TIM4 Prescaler is equal to 128 so the TIM1 counter
     clock used is 16 MHz / 128 = 125 000 Hz
   - With 125 000 Hz we can generate time base:
     max time base is 2.048 ms if TIM4_PERIOD = 255 --> (255 + 1) / 125000 = 2.048 ms
     min time base is 0.016 ms if TIM4_PERIOD = 1   --> (  1 + 1) / 125000 = 0.016 ms
   - In this example we need to generate a time base equal to 1 ms
     so TIM4_PERIOD = (0.001 * 125000 - 1) = 124
   */

  /* Time base configuration. Set the Prescaler value */
  TIM4->PSCR = (uint8_t)(TIM4_PRESCALER_128);
  /* Set the Autoreload value */
  TIM4->ARR = (uint8_t)(TIM4_PERIOD);
  /* Clear TIM4 update flag */
  TIM4->SR1 = (uint8_t)(~TIM4_FLAG_UPDATE);
  /* Enable update interrupt */
  TIM4->IER |= (uint8_t)TIM4_IT_UPDATE;

  /* enable interrupts */
  enableInterrupts();

  /* Enable TIM4 */
  TIM4->CR1 |= (uint8_t)TIM4_CR1_CEN;
}

/************************ (C) COPYRIGHT Shilov V.N. *****END OF FILE****/
