// Priorytety przerwan (zewnetrzengo i timera).
//
// Mikrokontroler wykonuje trzy "zadania":
//
// 1. Main - inkrementacja zmiennej main_var (co 0.5 s)
//
// 2. ISR przerwania zewnetrznego (EXTI) - wywolywana nacisnieciem USER Button (niebieski przycisk).
//    Na czas nacisniecia zablokowany jest powrot do main - sygnalizacja czerwona LED (G14).
//
// 3. ISR timera 7 - wywolywana jego przepelnieniem - zmiana stanu linii G13 (zielonej LED) na przeciwny
//    oraz inkrementacja zmiennej int_var.
//
// Zadanie glowne - ustawic priorytety przerwan tak, aby ISR timera 7 nie zostala zablokowana.
//
// Zadanie dodatkowe - uruchomic watchdoga - dobrac jego parametry i miejsce jego przeladowywania tak,
// aby przyblokowanie wykonywania jakiejkolwiek czesci programu na ok. dwie sekundy wywolywalo reset CPU.

#include <stdio.h>
#include "stm32f4xx.h"
#include "GLCD.h"

#define __FI       1
#if (__FI == 1)
  #define __FONT_WIDTH  16
  #define __FONT_HEIGHT 24
#else
  #define __FONT_WIDTH   6
  #define __FONT_HEIGHT  8
#endif

uint32_t main_var;
uint32_t int_var;

char tekst[20];

int main ()  {

// --- Inicjalizacja i konfiguracja wyswietlacza LCD ---

  GLCD_Initialize();
  GLCD_Clear(White);
  GLCD_SetBackColor(White);
  GLCD_SetTextColor(Black);

// --- Konfiguracja peryferiow ---

  RCC->AHB1ENR |= ((1<<6) | (1<<0));					// Wlacz "zegar" dla GPIO A i G.
  GPIOG->MODER |= (1<<(2*13)) | (1<<(2*14));	// Ustaw linie G13 i G14 jako wyjscia.

  GPIOG->PUPDR |= (1<<(2*2));									// Pull-up linii G2.

  RCC->APB1ENR |= (1<<5) |(1<<4);							// Wlacz "zegar" timerow TIM6 i TIM7.


// --- 1 ---
// Na podstawie dokumentacji i ustawien licznika TIM6:
// - skonfiguruj i wlacz timer TIM7,
// - wlacz generowanie przerwan z podana przez prowadzacego czestotliwoscia.
// Opis licznika - rozdzial 20. w Reference Manual.
// Rejestry licznika - podrozdzial 20.4.
// ---------

//	TIM7->PSC =								// Preskaler.
//	TIM7->ARR =								// Pojemnosc licznika - "n" stanow od zera do n-1 wlacznie.

//	TIM7->DIER =							// DMA/IRQ Enable Register - enable IRQ on update.
//	TIM7->CR1	=								// Wlacz timer.


	TIM6->PSC = 15999;				// Preskaler.
	TIM6->ARR = 999;					// pojemnnosc licznika - 1000 stanow (od zera do 999).
	TIM6->CR1 |=1;						// wlacz timer.

// --- 2b ---
// Skonfiguruj przyjowanie przerwan zewnetrznych
// z linii A0 (EXTI0, zbocze rosnace 0->1, niebieski przycisk).
// Opis - rozdzial 12.2 w Reference Manual.
// ---------

//	EXTI->IMR	=							// "odmaskuj"/wlacz linie EXTI0
//	EXTI->RTSR =						// ustaw reakcje na zbocze rosnace 0->1
//	EXTI->FTSR =					// ustaw reakcje na zbocze opadajace 1->0

// --- 3 ---
// Ustaw priorytety przerwan:
// timera TIM7 i zewnetrzengo EXTI0 tak, aby obsluga
// przerwania timera 7 nie byla nigdy blokowana.
// Opis w rozdziale 4.3.7. Programming Manual.
// Priorytet n-tego przerwania ustawia sie w rejestrze IP[n].
// ---------

//	NVIC->IP[] =
//	NVIC->IP[] =

// --- 2a ---
// Wlacz linie przerwan: zewnetrzne EXTI0 i timera TIM7
// w kontrolerze przerwan (NVIC).
// Tablica wektorow przerwan - Table 63. Reference Manual.
// Kazdy rejestr ISER[n] ma 32 bity.
// ISER[0] obsluguje przerwania od 0 do 31, ISER[1] - od 32 do 63 itd.

//	NVIC->ISER[] =
//	NVIC->ISER[] =

//==============================================
// --- Petla glowna ---

	for(;;){

		sprintf(tekst,"main = %u",main_var);
		GLCD_DisplayString(0, 0, __FI,tekst);

		main_var++;
			
		sprintf(tekst,"int  = %u",int_var);
		GLCD_DisplayString(2, 0, __FI,tekst);

// --- 4 ---
// Opcjonalnie dopisz:
// zablokuj dalsze wykonywanie petli dopoki linia G2 jest w stanie niskim.

//	Prosty delay - jakie wady ma takie rozwiazanie?
		TIM6->CNT=0; while(TIM6->CNT < 500);

	}
}

//==============================================
// Procedura obslugi przerwania (ISR) timera TIM7.

void TIM7_IRQHandler(void) { 	 

// Opis zachowania Update Interrupt Flag: 20.3.2 i 20.4.4 w Reference Manual.
	
	TIM7->SR &= ~1;						// Skasuj Update Interrupt Flag. 
	int_var++;
	GPIOG->ODR ^= (1<<13);		// Zmien stan zielonej LED.
	
}

//==============================================	
// Procedura obslugi przerwania (ISR) zewnetrzengo EXTI0

void EXTI0_IRQHandler(void) {

// Opis zachowania flag w Pending Request Register: 12.2.2 i 12.3.6 w Reference Manual.

	EXTI->PR |= 1;						//Skasuj Interrupt Pending Request.

	while(GPIOA->IDR & 1) GPIOG->BSRR = (1<<14);	// PRZYBLOKUJ i zaswiec czerwona LED dopoki niebieski jest nacisniety.
	
	GPIOG->BSRR = (1<<30);												// Wygas czerwona LED i powroc z ISR.
}
