/**
  ******************************************************************************
  * @file    main.c
  * @author  STMicroelectronics - MCD Application Team
  * @version V1.0.0
  * @date    19-January-2018
  * @brief   Displaying variable voltage on a bar of LEDs Application example.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software 
  * distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"                // file needed only for registers mask 
#include "parameter.h"
/**
  * @addtogroup ADC2_Example1
  * @{
  */

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

#define ALL_LEDs ((u8)0x0F)       // LEDs mask 

/* Private macro -------------------------------------------------------------*/

#define switch_all_LEDs_on    { GPIOB->ODR|= ALL_LEDs; }  //LEDs control : all on
#define switch_all_LEDs_off   { GPIOB->ODR&=~ALL_LEDs; }    //LEDs control : all off

/* Private variables ---------------------------------------------------------*/
  u8  temp_AD_H;             // temporary registers for reading ADC result (MSB)
  u8  temp_AD_L;             // temporary registers for reading ADC result (LSB)
  u8  ADInit;                // flag for ADC initialized
  u8  ADSampRdy;             // flag for filed of samples ready
  u8  AD_samp;               // counter of stored samples
  u16 AD_sample[NUMB_SAMP];  // store samples field 
  u16 AD_avg_value;          // average of ADC result
  
  u8 peak_memo;              // variables for peak level detector
  u8 peak_filt;              // variables for peak level detector*/

/* Private function prototypes -----------------------------------------------*/
/**
  * @brief Count average of samples stored in the u16 field
  * @par Parameters:
  *  *p: pointer to the beginning of the field
  * smp: number of samples in the field
  * @retval Average u16 value
  */
u16 u16_average(u16 *p, u8 smp) { 
  u8 i;
  u16 sum;
  
  for(i=0, sum= 0; i < smp; ++i)
    sum+= *p++;   
  return sum / smp;
}
/* -------------------------------------------------------------------------- */
/**
  * @brief Prepare data for four LED bar of signal and peak indicator
  * @par Parameters:
  * val: Level of the mesured signal [0-4]
  * @retval 4 bits (low nibble) of the composite bar graph information
  */
u8 signal_and_peak_level(u8 val) {
  u8 signal;
  u8 peak;
  
  switch(val) {
    case 0: peak= 0; signal=  0; break; //set peak and signal levels
    case 1: peak= 1; signal=  1; break;
    case 2: peak= 2; signal=  3; break;
    case 3: peak= 4; signal=  7; break;
    case 4: peak= 8; signal= 15; break;
    default: peak= signal= 15;
  };
  if(peak_filt == 0) {                  // slow fall of peak level indicator 
    if(peak_memo) {
      peak_memo>>= 1;
      peak_filt= PEAK_FILTER;
    };
  }
  else
    --peak_filt;
  if(peak >= peak_memo) {              // check the highest level value
    peak_memo= peak;                   // and copy it to peak indicator
    peak_filt= PEAK_FILTER;            // with fall speed refresh
  };
  return (signal | peak_memo);         // return bar graph information
}

/* Public functions ----------------------------------------------------------*/
/**
  * @brief Validation firmware main entry point.
  * @par Parameters:
  * None
  * @retval void None
  */  
void main(void) {
  u8 leds;
//                *** GPIO INIT ***
  GPIOB->ODR&=~ALL_LEDs;        // LEDs - as push-pull outputs, all off
  GPIOB->DDR|= ALL_LEDs;        // 
  GPIOB->CR1|= ALL_LEDs;
  
  GPIOC->DDR|= 0x02;            // PC.1 as push-pull outputs
  GPIOC->CR1|= 0x02;
    
  GPIOE->CR1&=~0x40;            // PE.6 as a floating input
  GPIOE->DDR&=~0x40;
  
//                *** ADC INITIALIZATION ***
  TIM1->ARRH= (u8)(AUTORELOAD >> 8);              // set autoreload register for trigger period
  TIM1->ARRL= (u8)(AUTORELOAD);                   // 
  TIM1->CCR1H= (u8)((AUTORELOAD-AD_STAB) >> 8);   // set compare register for trigger period
  TIM1->CCR1L= (u8)(AUTORELOAD-AD_STAB);
  TIM1->CR1|= TIM1_CR1_ARPE;                      // auto reload register is buferred
  
  TIM1->CR2= (4<<4) & TIM1_CR2_MMS;               // CC1REF is used as TRGO
  TIM1->CCMR1= (6<<4) & TIM1_CCMR_OCM;            // CC1REF in PWM 1 mode
  TIM1->IER|= TIM1_IER_CC1IE;                     // CC1 interrupt enable
  TIM1->CCER1|= TIM1_CCER1_CC1P;                  // CC1 negative polarity
  TIM1->CCER1|= TIM1_CCER1_CC1E;                  // CC1 output enable
  TIM1->BKR|= TIM1_BKR_MOE;                       
  
  TIM1->SMCR|=  TIM1_SMCR_MSM;                    // synchronization of TRGO with ADC
  
  TIM1->CR1|= TIM1_CR1_CEN;                       // timer 1 enable
    
  ADC2->CSR= ADC2_CSR_EOCIE | (9 & ADC2_CSR_CH);  // ADC EOC interrupt enable, channel 9
  ADC2->CR1= 4<<4 & ADC2_CR1_SPSEL;               // master clock/8, single conversion
  ADC2->CR2= ADC2_CR2_EXTTRIG;                    // external trigger on timer 1 TRGO, left alignment
  ADC2->TDRH= 2;                                  // disable Schmitt trigger on AD input 9
  ADC2->TDRL= 0;                                  //

  // init ADC variables
  AD_samp= 0;                                     // number of stored samples 0
  ADInit= TRUE;                                   // ADC initialized 
  ADSampRdy= FALSE;                               // No sample 
  
  ADC2->CR1|= ADC2_CR1_ADON;                      // ADC on

  enableInterrupts();                             // enable all interrupts 
  
//                *** MAIN LOOP *** 
  while (1) {
    if (ADSampRdy == TRUE) {                             // field of ADC samples is ready?
      AD_avg_value= u16_average(&AD_sample[0], AD_samp); // average of samples
      
      AD_samp= 0;                                        // reinitalize ADC variables
      ADSampRdy= FALSE;
            
      leds= signal_and_peak_level((u8)((AD_avg_value + 128) / 256)); // setting LED status
      
      GPIOB->ODR&= leds | (~ALL_LEDs);  // LEDs settings in according to LED status
      GPIOB->ODR|= leds;
    };
  };
}
/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
