/**
 ******************************************************************************
 * @file           : main.c
 * @author         : Auto-generated by STM32CubeIDE
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */

#include "stm32l073xx.h"

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

void nastavUartHsi(void)
{
	// zapne hodinovy signal pro port A
	RCC->IOPENR |= RCC_IOPENR_IOPAEN;

	// vynuluje nastaveni rezimu PA2, PA3 (vstupni rezim)
	GPIOA->MODER &= ~(GPIO_MODER_MODE2 | GPIO_MODER_MODE3);

	// nastavi  PA2 a PA3 do alternativniho rezimu
	GPIOA->MODER |= (GPIO_MODER_MODE2_1 | GPIO_MODER_MODE3_1);

	// nastavi pinu PA2 a PA3 alternativni rezim 4 - UART
	GPIOA->AFR[0] |= ((4U << GPIO_AFRL_AFSEL2_Pos) | (4U << GPIO_AFRL_AFSEL3_Pos));

	// zapne hodinovy signal pro USART2
	RCC->APB1ENR |= RCC_APB1ENR_USART2EN;

	// 16 MHz / 1667 = 9598 Baud
	USART2->BRR = 1667U;

	// povoli USARTa prijem dat
	USART2->CR1 |= (USART_CR1_UE | USART_CR1_TE);

	// nastavi HSI jako zdroj hodinoveho signalu
	RCC->CCIPR |= RCC_CCIPR_USART2SEL_1;
}

void nastavI2c(uint8_t AdresaSlave)
{
	  // zapne hodinovy signal pro port C
	    RCC->IOPENR |= RCC_IOPENR_GPIOCEN;

		// vynuluje nastaveni pinu PC0 a PC1 (vstupni rezim)
		GPIOC->MODER &= ~(GPIO_MODER_MODE0 | GPIO_MODER_MODE1);

	    // nastavi piny PC0 a PC1 do alternativniho rezimu
	    GPIOC->MODER |= (GPIO_MODER_MODE0_1 | GPIO_MODER_MODE1_1);

		// nastavi alternativni rezim 7 pro piny PC0 a PC1
		GPIOC->AFR[0] |= ((7 << GPIO_AFRL_AFSEL0_Pos) | (7 << GPIO_AFRL_AFSEL1_Pos));

	    // nastavi piny PC0 a PC1 do rezimu open-drain
	    GPIOC->OTYPER |= (GPIO_OTYPER_OT_0 | GPIO_OTYPER_OT_1);

	    // nastavi HSI jako zdroj hodinoveho signalu
		RCC->CCIPR |= RCC_CCIPR_I2C3SEL_1;

	    // zapne hodinovy signal pro I2C3
		RCC->APB1ENR |= RCC_APB1ENR_I2C3EN;

	    // povoli a nastavi adresu Slave obvodu
		I2C3->OAR1 |= ((AdresaSlave << I2C_OAR1_OA1_Pos) | I2C_OAR1_OA1EN);

		// povoli linku 24 externiho preruseni
		EXTI->IMR |= EXTI_IMR_IM24;

		// povoli preruseni I2C3 ARM jadra
		NVIC->ISER[0] |= (1 << I2C3_IRQn);

		// zapne I2C3, povoli preruseni pri shode adresy probuzeni kontroleru
		I2C3->CR1 |= (I2C_CR1_PE | I2C_CR1_ADDRIE | I2C_CR1_WUPEN);
}


void I2C3_IRQHandler(void)
{
	// vynuluje priznak preruseni periferie
	I2C3->ICR |= I2C_ICR_ADDRCF;

	// vynuluje priznak preruseni linky ARM
	NVIC->ICPR[0] |= (1 << I2C3_IRQn);

	// precte prijaty bajt
	uint8_t data = I2C3->RXDR;

	// odesle znak
	USART2->TDR = 'x';
	while((USART2->ISR & USART_ISR_TC) != USART_ISR_TC);
}


int main(void)
{
	uint8_t AdresaSlave = 0xAA;

	nastavUartHsi();

	nastavI2c(AdresaSlave);

	// nastavi HSI jako zdroj hodinoveho signalu
	// po probuzeni (vychozi MSI)
	RCC->CFGR |= RCC_CFGR_STOPWUCK;

	// vrati se do odstaveneho rezimu po opusteni ISR
	SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;

	// nastavi odstaveny rezim pri operaci "wfi"
	SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

	// zapne odstaveny rezim probuzeny prerusenim
	asm("wfi");
}
