/* ***************************************************************************************
#   Project:    task3 - C: Timer & Interrupts
#   File:       task3.s
#
#   Language:   C
#
#   Hardware:   STefi Light v1.1
#   Processor:  STM32G431KBT6U
#
#   Author:     Manuel Lederhofer
#   Datum:      31.10.2014
#
#   Version:    6.1
#   History:
#       31.10.2014  ML  create file
#       27.09.2018  ML  edit comments, extend vector table
#       18.12.2018  ML  port from MKL05Z32VLC4 to STM32L476RG
#       27.02.2019  ML  move section of exception handlers to bottom of file,
#                           change ASM pseudo commands from .space to .org
#       25.09.2019  ML  minor changes for a better code and comment understanding
#       04.09.2020  HL  port from STM32L476RG to STM32F411xE
#       21.09.2020  ML  tidy up, comments and formatting
#       29.09.2021  ML  port from STM32F411xE to STM32F042K6T6
#       09.03.2022  ML  port from STM32F042K6T6 to STM32G431KBT6U
#       17.02.2025  TK  move ASM:Interrupts to task2, replace with C:Timer & Interrupts
#       24.06.2025  TK  remove "... put your code here ...", remove Systick

#
#   Status:     working
#
#   Description:
#       See the description and requirements of the requested application
#       in the lab exercise guide.
#
#   Notes:
#       - MCU speed at startup is 16 MHz
#
#   ToDo:
#       - Change the example code to match the description and requirements
#          of the requested application in the lab exercise guide.
#
#
#   Measurements:
#       Timers used         :
#       Current with WFI    :
#       Current without WFI :
#
 ************************************************************************************** */

/* ------------------------------------ INCLUDES -------------------------------------- */
#include "stm32g431xx.h"
#include "STefi-Light.h"

#define ROT_AN   (GPIOA->BSRR = (1UL<<16))
#define ROT_AUS  (GPIOA->BSRR = (1UL<<0))
#define GELB_AN  (GPIOA->BSRR = (1UL<<17))
#define GELB_AUS (GPIOA->BSRR = (1UL<<1))
#define GRÜN_AN  (GPIOA->BSRR = (1UL<<18))
#define GRÜN_AUS (GPIOA->BSRR = (1UL<<2))
#define BLAU_AN  (GPIOA->BSRR = (1UL<<19))
#define BLAU_AUS (GPIOA->BSRR = (1UL<<3))

/* ------------------------------------ DEFINES --------------------------------------- */
/* ------------------------------------ TYPE DEFINITIONS ------------------------------ */
/* ------------------------------------ GLOBAL VARIABLES ------------------------------ */
volatile uint32_t timer_ticks = 0;
volatile uint8_t ampel_aktiv = 0;
volatile uint32_t lbp = 0;
/* ------------------------------------ PRIVATE VARIABLES ----------------------------- */


/* ------------------------------------ PROTOTYPES ------------------------------------ */
static void GPIO_init(void);
void Timer_init(void);
void EXTI_init(void);

/* ------------------------------------ M A I N --------------------------------------- */
int main(void)
{
    /* --- initialization --- */
    __disable_irq();        // disable interrupts globally

    GPIO_init();
    Timer_init();
    EXTI_init();

    __enable_irq();         // enable interrupts globally

    lbp = 0;

    GRÜN_AN;
    ROT_AUS;
    GELB_AUS;
    BLAU_AUS;
    /* --- one time tasks --- */


    /* --- infinite processing loop --- */
    while (1){

        __WFI();

    }
    return 1;
}


/* ------------------------------------ GLOBAL FUNCTIONS ------------------------------ */
void EXTI_IRQHandler(void){
    if(EXTI->PR1 & EXTI_PR1_PIF0){
        EXTI->PR1 = EXTI_PR1_PIF0;

        if((timer_ticks - lbp)> 200){
            lbp = timer_ticks;

            if(ampel_aktiv == 0){
                timer_ticks = 0;
                ampel_aktiv=1;
            }
        }
    }
    TIM6_DAC_IRQHandler();
}


void TIM6_DAC_IRQHandler(void){
    if(TIM6->SR & (1<<0)){
        TIM6->SR &= ~(1U<<0);

        timer_ticks++;

        if(ampel_aktiv == 1){
            switch(timer_ticks){
            case 10000:
                GRÜN_AUS;
                GELB_AN;
                break;
            case 11000:
                GELB_AUS;
                ROT_AN;
                break;
            case 12000:
                break;
            case 27000:
                BLAU_AUS;
                GELB_AN;
                break;
            case 28000:
                ROT_AUS;
                GELB_AUS;
                GRÜN_AN;
                ampel_aktiv = 0;
                break;
            }
            if(timer_ticks >=12000 && timer_ticks < 27000){
                if(timer_ticks % 1000 == 0){
                    BLAU_AN;
                }
                else if(timer_ticks % 1000 == 500){
                    BLAU_AUS;
                }
            }
        }
    }
}
/* ------------------------------------ PRIVATE FUNCTIONS ----------------------------- */

/* ------------------------------------------------------------------------------------ *\
 * method:  static void GPIO_init(void)
 *
 * Initializes GPIOs on STefi Light for pins with peripherals attached.
 *
 * requires:    - nothing -
 * parameters:  - none -
 * returns:     - nothing -
\* ------------------------------------------------------------------------------------ */
static void GPIO_init(void)
{
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN;

    // LEDs PA0-PA3 Output (01)
    GPIOA->MODER &= ~(0xFF);
    GPIOA->MODER |= 0x55;

    // Initial alle aus (Low-Active: 1 = AUS)
    GPIOA->ODR |= 0x0F;

    // S0 (PB0) Input (00) mit Pull-Up (01)
    GPIOB->MODER &= ~(3 << 0);
    GPIOB->PUPDR |= (1 << 0);
}

void Timer_init(void) {
    RCC->APB1ENR1 |= RCC_APB1ENR1_TIM6EN;

    // 16MHz Systemtakt. 16MHz / 16 (PSC+1) = 1MHz.
    // Bei 1MHz sind 1000 Ticks (ARR+1) exakt 1 Millisekunde.
    TIM6->PSC = 15;
    TIM6->ARR = 999;
    TIM6->DIER |=(1<<0);
    NVIC_EnableIRQ(TIM6_DAC_IRQn);
    TIM6->CR1 |= (1<<0);
}

void EXTI_init(void) {
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
    SYSCFG->EXTICR[0] = (SYSCFG->EXTICR[0] & ~(0xF)) | 0x1;
    EXTI->IMR1 |= (1<<0);
    EXTI->FTSR1 |= (1<<0);
    NVIC_EnableIRQ(EXTI0_IRQn);
}


/* ------------------------------------------------------------------------------------ *\
 * method:  static void SysTick_init(void)
 *
 * At system startup SysTick runs with 1 MHz down to 0.
 *
 * Register names differ in datasheets.
 *  ST / CMSIS:         ARM:
 *  - SysTick->CALIB    - STK_CALIB
 *  - SysTick->CTRL     - STK_CSR
 *  - SysTick->LOAD     - STK_RVR
 *  - SysTick->VAL      - STK_CVR
 *
 * requires:    - nothing -
 * parameters:  - none -
 * returns:     - nothing -
 \* ------------------------------------------------------------------------------------ */



/* ************************************ E O F ***************************************** */
