/************************************
Software interface SDRAM.
*************************************
Mob. : +380662051255
Email: atom.tm@i.ua
Skype: alex.tm.ltd
************************************/

#include "System.hpp"

#pragma GCC push_options
#pragma GCC optimize("O0")

void SDRAM_Init(void);

void SDRAM_CamFile_Addr_START(uint32_t addr);
void SDRAM_CamFile_Addr_NEXT(uint32_t line);
void SDRAM_CamFile_Addr_END(void);

int  SDRAM_Write_1024b(uint32_t addr, uint8_t * pBuff);
int  SDRAM_Read_1024b(uint32_t addr, uint8_t * pBuff);


extern void SDCAM_GPIO_MEM_SET_mCpuWriteMem(void);
extern void SDCAM_GPIO_MEM_SET_mCpu(void);
extern void SDCAM_GPIO_MEM_SET_Cam(void);
extern void SDCAM_GPIO_MEM_SET_Default(void);


#define INTERRUPT_ENABLE()   __enable_irq()
#define INTERRUPT_DISABLE() __disable_irq()

#define   SDRAM_OK         ((uint8_t)0x00)
#define   SDRAM_ERROR      ((uint8_t)0x01)

#ifndef CPU_FREQ
#define CPU_FREQ ((uint32_t)48000000)
#endif

#define SDRAM_CLK_TACT_cycle_1ms() do{ \
	for(uint32_t ftmp=0;ftmp<((CPU_FREQ/1000)/48);ftmp++){ \
	SDRAM_CLK_HIGH();SDRAM_CLK_LOW();} \
}while(0)


#define SDRAM_IO_DATA_WRITE(data) do {\
	((GPIO_TypeDef*)IO_D0_GPIO_Port)->BSRR=((uint32_t)0xFF000000); \
	((GPIO_TypeDef*)IO_D0_GPIO_Port)->BSRR=(uint32_t)( ((uint32_t)0xFF&(data))<<8 ); \
} while (0)


#define SDRAM_IO_DATA_READ()((uint8_t)((uint16_t)IO_D0_GPIO_Port->IDR>>8))


#define SDRAM_IO_ADDR_PIN_SET(Port,Pin,Bit,Addr) ((uint32_t)(Addr)&(1<<(Bit)))? \
	((GPIO_TypeDef*)Port)->BSRR=((uint32_t)Pin): \
	((GPIO_TypeDef*)Port)->BSRR=((uint32_t)Pin<<16U)


#define SDRAM_GPIO_WRITE(Port,Pin,Val) (Val)? \
	((GPIO_TypeDef*)Port)->BSRR=((uint32_t)Pin): \
	((GPIO_TypeDef*)Port)->BSRR=((uint32_t)Pin<<16U)


#define SDRAM_IO_ADDR_A0_A9_RESET() do { \
	((GPIO_TypeDef*)GPIOB)->BSRR=(uint32_t)(O_M_A1_Pin|O_M_A2_Pin|O_M_A3_Pin)<<16U; \
	((GPIO_TypeDef*)GPIOA)->BSRR=(uint32_t)(O_M_A0_Pin|O_M_A4_Pin|O_M_A5_Pin|O_M_A6_Pin|O_M_A7_Pin| \
	O_M_A8_Pin|O_M_A9_Pin)<<16U; \
} while(0)


#define SDRAM_CLK_HIGH()((GPIO_TypeDef*)O_M_CLK_GPIO_Port)->BSRR =((uint32_t)O_M_CLK_Pin)
#define SDRAM_CLK_LOW() ((GPIO_TypeDef*)O_M_CLK_GPIO_Port)->BSRR =((uint32_t)O_M_CLK_Pin<<16U)

#define SDRAM_IO_CLK_ENABLE() ((GPIO_TypeDef*)O_CKE_GPIO_Port)->BSRR=((uint32_t)O_CKE_Pin)
#define SDRAM_IO_CLK_DISABLE()((GPIO_TypeDef*)O_CKE_GPIO_Port)->BSRR=((uint32_t)O_CKE_Pin<<16U)

#define SDCAM_O_C_OE_CPU() ((GPIO_TypeDef*)O_C_OE_GPIO_Port)->BSRR =((uint32_t)O_C_OE_Pin)
#define SDCAM_O_C_OE_CAM() ((GPIO_TypeDef*)O_C_OE_GPIO_Port)->BSRR =((uint32_t)O_C_OE_Pin<<16U)

#define SDRAM_CLK_TACT() do{SDRAM_CLK_HIGH();SDRAM_CLK_LOW();}while(0)


#define SDRAM_IO_ADDRESS_SET(AddrLine,OffSet) do {\
	SDRAM_IO_ADDR_PIN_SET(O_M_A0_GPIO_Port, O_M_A0_Pin,  (0+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A1_GPIO_Port, O_M_A1_Pin,  (1+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A2_GPIO_Port, O_M_A2_Pin,  (2+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A3_GPIO_Port, O_M_A3_Pin,  (3+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A4_GPIO_Port, O_M_A4_Pin,  (4+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A5_GPIO_Port, O_M_A5_Pin,  (5+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A6_GPIO_Port, O_M_A6_Pin,  (6+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A7_GPIO_Port, O_M_A7_Pin,  (7+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A8_GPIO_Port, O_M_A8_Pin,  (8+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A9_GPIO_Port, O_M_A9_Pin,  (9+(OffSet)),(AddrLine));\
	SDRAM_IO_ADDR_PIN_SET(O_M_A10_GPIO_Port,O_M_A10_Pin,(10+(OffSet)),(AddrLine));\
} while (0)


#define SDRAM_COMMAND_LOAD_MODE_REGISTER(OpCode) do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,0); \
	SDRAM_IO_ADDRESS_SET(OpCode,0);\
} while (0)


#define SDRAM_COMMAND_REFRESH() do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,1); \
} while (0)


#define SDRAM_COMMAND_PRECHARGE_ALL() do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,0); \
	SDRAM_GPIO_WRITE(O_M_A10_GPIO_Port,O_M_A10_Pin,1); \
} while (0)


#define SDRAM_COMMAND_ACTIVE_START_ADDR(addr) do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,1); \
	SDRAM_IO_ADDRESS_SET(addr,10); \
} while (0)


#define SDRAM_COMMAND_ACTIVE_START_LINE(line) do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,1); \
	SDRAM_IO_ADDRESS_SET(line,0); \
} while (0)


#define SDRAM_COMMAND_BURST_TERMINATE() do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,0); \
} while (0)


#define SDRAM_COMMAND_NOP() do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,1); \
} while (0)


#define SDRAM_COMMAND_BURST_READ_Col0() do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,1); \
	SDRAM_IO_ADDR_A0_A9_RESET(); \
} while (0)


#define SDRAM_COMMAND_BURST_WRITE_Col0() do { \
	SDRAM_GPIO_WRITE(O_M_RAS_GPIO_Port,O_M_RAS_Pin,1); \
	SDRAM_GPIO_WRITE(O_M_CAS_GPIO_Port,O_M_CAS_Pin,0); \
	SDRAM_GPIO_WRITE(O_M_WE_GPIO_Port ,O_M_WE_Pin ,0); \
	SDRAM_IO_ADDR_A0_A9_RESET(); \
} while (0)


#define SDRAM_CMD_SELFREFRESH_MODE_EXIT() do{ \
	INTERRUPT_DISABLE(); \
	SDRAM_IO_CLK_ENABLE(); \
	SDRAM_COMMAND_NOP(); \
	SDRAM_CLK_TACT(); \
	SDRAM_CLK_TACT(); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_REFRESH(); \
	SDRAM_CLK_TACT(); \
	SDRAM_CLK_TACT(); \
}while(0)


#define SDRAM_CMD_SELFREFRESH_MODE_ENTER() do{ \
		SDRAM_IO_CLK_ENABLE(); \
		SDRAM_COMMAND_PRECHARGE_ALL(); \
		SDRAM_CLK_TACT(); \
		SDRAM_COMMAND_NOP(); \
		SDRAM_CLK_TACT(); \
		SDRAM_COMMAND_REFRESH(); \
		SDRAM_IO_CLK_DISABLE(); \
		SDRAM_CLK_TACT(); \
		SDRAM_COMMAND_NOP(); \
		SDRAM_CLK_TACT(); \
		INTERRUPT_ENABLE(); \
}while(0)


#define SDRAM_CMD_PRECHARGE_ALL() do{ \
	SDRAM_COMMAND_PRECHARGE_ALL(); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_NOP(); \
	SDRAM_CLK_TACT(); \
}while(0)


#define SDRAM_CMD_BURST_TERMINATE() do{ \
	SDRAM_COMMAND_BURST_TERMINATE(); \
	SDRAM_CLK_TACT(); \
}while(0)


#define SDRAM_CMD_BURST_ACTIVE_READ_ADDR(addr) do{ \
		SDRAM_COMMAND_ACTIVE_START_ADDR(addr); \
		SDRAM_CLK_TACT(); \
		SDRAM_COMMAND_NOP(); \
		SDRAM_CLK_TACT(); \
		SDRAM_COMMAND_BURST_READ_Col0(); \
		SDRAM_CLK_TACT(); \
		SDRAM_COMMAND_NOP(); \
		SDRAM_CLK_TACT(); \
		SDRAM_COMMAND_NOP(); \
		SDRAM_CLK_TACT(); \
}while(0)


#define SDRAM_CMD_BURST_ACTIVE_WRITE_ADDR(addr) do{ \
	SDRAM_COMMAND_ACTIVE_START_ADDR(addr); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_NOP(); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_BURST_WRITE_Col0(); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_NOP(); \
	SDRAM_CLK_TACT(); \
}while(0)


#define SDRAM_CMD_BURST_ACTIVE_WRITE_LINE(line) do{ \
	SDRAM_COMMAND_ACTIVE_START_LINE(line); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_NOP(); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_BURST_WRITE_Col0(); \
	SDRAM_CLK_TACT(); \
	SDRAM_COMMAND_NOP(); \
	SDRAM_CLK_TACT(); \
}while(0)



void SDRAM_Init(void)
{
    INTERRUPT_DISABLE();
    SDRAM_GPIO_WRITE(O_M_CS_GPIO_Port, O_M_CS_Pin , 0); 

	SDCAM_GPIO_MEM_SET_mCpu();

	SDRAM_CLK_TACT_cycle_1ms();

	SDRAM_COMMAND_NOP();
	SDRAM_IO_ADDRESS_SET(0,0);
	SDRAM_IO_CLK_ENABLE();
	SDRAM_CLK_TACT_cycle_1ms();

	SDRAM_COMMAND_LOAD_MODE_REGISTER((uint16_t)0x0027);
	SDRAM_CLK_TACT();

	SDRAM_COMMAND_NOP();
	SDRAM_IO_ADDRESS_SET(0,0);
	SDRAM_CLK_TACT_cycle_1ms();

	SDRAM_CMD_SELFREFRESH_MODE_ENTER();

	SDRAM_CLK_TACT_cycle_1ms();

	SDCAM_GPIO_MEM_SET_Default();
}


void SDRAM_CamFile_Addr_START(uint32_t addr)
{
	SDCAM_GPIO_MEM_SET_mCpu();
	SDRAM_CMD_SELFREFRESH_MODE_EXIT();
	SDRAM_CMD_BURST_ACTIVE_WRITE_ADDR(addr);
	SDCAM_O_C_OE_CAM();
}


void SDRAM_CamFile_Addr_NEXT(uint32_t line)
{
	SDCAM_O_C_OE_CPU(); 
	SDRAM_COMMAND_NOP(); 
	SDRAM_CLK_TACT();
	SDRAM_CLK_TACT();
	SDRAM_CMD_BURST_TERMINATE();
	SDRAM_CMD_PRECHARGE_ALL();
	SDRAM_COMMAND_ACTIVE_START_LINE(line); 
	SDRAM_CLK_TACT(); 
	SDRAM_COMMAND_NOP(); 
	SDRAM_CLK_TACT(); 
	SDRAM_COMMAND_BURST_WRITE_Col0(); 
	SDRAM_CLK_TACT(); 
	SDRAM_COMMAND_NOP(); 
	SDCAM_O_C_OE_CAM();
}


void SDRAM_CamFile_Addr_END(void)
{
	SDCAM_GPIO_MEM_SET_mCpu();
	SDRAM_CMD_BURST_TERMINATE();
	SDRAM_CMD_SELFREFRESH_MODE_ENTER();
	SDCAM_GPIO_MEM_SET_Default();
}

int SDRAM_Write_1024b(uint32_t addr, uint8_t * pBuff)
{
	SDCAM_GPIO_MEM_SET_mCpuWriteMem();
	SDRAM_CMD_SELFREFRESH_MODE_EXIT();
	SDRAM_CMD_BURST_ACTIVE_WRITE_ADDR(addr);

	SDRAM_CLK_LOW();
	for(register int ftmp=0;ftmp<1024;ftmp++){
		SDRAM_IO_DATA_WRITE(pBuff[ftmp]);
		SDRAM_CLK_HIGH();
		SDRAM_CLK_LOW();
	}

	SDRAM_CMD_BURST_TERMINATE();
	SDRAM_CMD_SELFREFRESH_MODE_ENTER();
	SDCAM_GPIO_MEM_SET_Default();

	return SDRAM_OK;
}


int SDRAM_Read_1024b(uint32_t addr, uint8_t * pBuff)
{
	SDCAM_GPIO_MEM_SET_mCpu();
	SDRAM_CMD_SELFREFRESH_MODE_EXIT();
	SDRAM_CMD_BURST_ACTIVE_READ_ADDR(addr);
	
	for(register int ftmp=0;ftmp<1024;ftmp++){
		SDRAM_CLK_HIGH();
		pBuff[ftmp] = SDRAM_IO_DATA_READ();
		SDRAM_CLK_LOW();
	}

	SDRAM_CMD_BURST_TERMINATE();
	SDRAM_CMD_SELFREFRESH_MODE_ENTER();
	SDCAM_GPIO_MEM_SET_Default();

	return SDRAM_OK;
}


#pragma GCC pop_options
