/*
 * GD25Q16ETIGR.c
 *
 *  Created on: 7 сент. 2023 г.
 *      Author: seklyuts
 */
#include "f28x_project.h"
#include "spi_init.h"

#include "GD25Q16ETIGR.h"
#include "Arr.h"

//max adr 0x1FFFFF (2097152 bytes = 2048 Kbytes = 2 Mbyte)
#define WriteEnable                      0x06
#define WriteDisable                     0x04
#define ReadStatusRegister1              0x05         //(S7-S0)     (cont.)
#define ReadStatusRegister2              0x35         //(S15-S8)    (cont.)
#define WriteStatusRegister12            0x01         //S7-S0       S15-S8
#define VolatileSRwriteEnable            0x50
#define ReadData                         0x03         //A23-A16     A15-A8      A7-A0       (D7-D0)     (cont.)
#define FastRead                         0x0B         //A23-A16     A15-A8      A7-A0       dummy       (D7-D0)     (cont.)
#define ReadManufacturerDeviceID         0x90
#define PageProgram                      0x02         //A23-A16     A15-A8      A7-A0       D7-D0
#define SectorErase                      0x20         //A23-A16     A15-A8      A7-A0
#define ChipErase                        0xC7 //0x60

uint16_t sdata1 = ReadStatusRegister1;  // sent data
uint16_t GD25Q16ETIGR_buffer8bytes[8];

uint16_t SectorWasErraised[512];

uint16_t writeVerify = 1;


void delay(void)
{
    uint32_t i;
    for(i=0;i<100000;i++)
    {
        asm (" NOP");
    }
}



void GD25Q16ETIGR_checkRXFFST(void)
{
    volatile    uint16_t empty;
    while(SpiRegs.SPIFFRX.bit.RXFFST > 0)
    {
        empty = SpiRegs.SPIRXBUF;
    }
}


void GD25Q16ETIGR_clean_SectorWasErraised(void)
{
    uint16_t i;
    for(i=0; i<512; i++)
    {
        SectorWasErraised[i] = 0;
    }
}


void GD25Q16ETIGR_en(void)
{
    volatile    uint16_t empty;
//    GD25Q16ETIGR_checkRXFFST();
    transmitData(WriteEnable);
    while(SpiRegs.SPIFFRX.bit.RXFFST != 1)
    {

    }
    empty = SpiRegs.SPIRXBUF;
}

uint16_t GD25Q16ETIGR_ReadStatus(void)
{
    volatile    uint16_t empty;
//    GD25Q16ETIGR_checkRXFFST();
    transmitData(ReadStatusRegister1);
    transmitData(0xFF);
    while(SpiRegs.SPIFFRX.bit.RXFFST != 2)
    {

    }
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    return empty;
}

volatile uint32_t MaxRepeat = 0;

uint16_t GD25Q16ETIGR_WaitStatus(void)
{
    uint16_t repeat = 0, ErrRepeat = 0x4000;
    uint16_t Stat = 1;

    Stat = GD25Q16ETIGR_ReadStatus();
    while((Stat&0x1) != 0 )
    {
        Stat = GD25Q16ETIGR_ReadStatus();
        repeat++;
        if(repeat > ErrRepeat) return 1;
    }
    if(repeat > MaxRepeat) MaxRepeat = repeat;
    return 0;
}

uint16_t GD25Q16ETIGR_sector_erase(uint32_t Addr)
{
    volatile    uint16_t empty;

    uint16_t Err = 0;
    GD25Q16ETIGR_en();
    Err = GD25Q16ETIGR_WaitStatus();
    if(Err) return Err;

    GD25Q16ETIGR_en();

//    GD25Q16ETIGR_checkRXFFST();

    transmitData(SectorErase);
    transmitData(Addr>>16);
    transmitData(Addr>>8);
    transmitData(Addr);
    while(SpiRegs.SPIFFRX.bit.RXFFST != 4)
    {

    }
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    return 0;
}

uint16_t GD25Q16ETIGR_read_8_bytes(uint32_t Addr, uint16_t * read_data, uint16_t num_byte)//чтение до 8 байт
{
    volatile    uint16_t empty, i, j;

    uint16_t Err = 0;

    Err = GD25Q16ETIGR_WaitStatus();
    if(Err) return Err;

//    GD25Q16ETIGR_checkRXFFST();

    transmitData(ReadData);
    transmitData(Addr>>16);
    transmitData(Addr>>8);
    transmitData(Addr);
    for(i = 0; i<num_byte; i++) transmitData(0xFF);
    while(SpiRegs.SPIFFRX.bit.RXFFST != (num_byte+4))
    {

    }
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    for(j = 0; j<num_byte; j++)
    {
        read_data[j] = SpiRegs.SPIRXBUF;
    }
    return 0;
}

uint16_t GD25Q16ETIGR_verify_8_bytes(uint32_t Addr, uint16_t * verify_data, uint16_t num_byte)//чтение и проверка до 8 байт
{
    volatile    uint16_t empty, i, j;

    uint16_t Err = 0;

    Err = GD25Q16ETIGR_WaitStatus();
    if(Err) return Err;

//    GD25Q16ETIGR_checkRXFFST();

    transmitData(ReadData);
    transmitData(Addr>>16);
    transmitData(Addr>>8);
    transmitData(Addr);
    for(i = 0; i<num_byte; i++) transmitData(0xFF);
    while(SpiRegs.SPIFFRX.bit.RXFFST != (num_byte+4))
    {

    }
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    for(j = 0; j<num_byte; j++)
    {
        if(verify_data[j] != SpiRegs.SPIRXBUF) Err++;
    }

//    GD25Q16ETIGR_checkRXFFST();

    return Err;
}







uint16_t GD25Q16ETIGR_write_8_bytes(uint32_t Addr, uint16_t * write_data, uint16_t num_byte)//запись до 8 байт
{
    volatile    uint16_t empty, i, j;

    uint16_t Err = 0;
    GD25Q16ETIGR_en();
    Err = GD25Q16ETIGR_WaitStatus();
    if(Err) return Err;

    GD25Q16ETIGR_en();

//    GD25Q16ETIGR_checkRXFFST();

    transmitData(PageProgram);
    transmitData(Addr>>16);
    transmitData(Addr>>8);
    transmitData(Addr);
    for(i = 0; i<num_byte; i++) transmitData(write_data[i]);
    while(SpiRegs.SPIFFRX.bit.RXFFST != (num_byte+4))
    {

    }
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    empty = SpiRegs.SPIRXBUF;
    for(j = 0; j<num_byte; j++)
    {
        empty = SpiRegs.SPIRXBUF;
    }
    return 0;
}


uint32_t ErrAdr[8];// адреса неисправных байтов, которые не удалось записать даже повторно.
uint32_t CounterOfFixedError = 0;
uint32_t CounterOfTotalError = 0;

uint16_t GD25Q16ETIGR_write_veryfy_8_bytes(uint32_t Addr, uint16_t * write_data, uint16_t num_byte)//запись и проверка до 8 байт
{
    uint16_t addr_write_data[8];
    uint16_t addr_read_data[8];
    uint16_t i, Err = 0, DoneOK = 0;

    for(i = 0; i<num_byte; i++)
    {
        addr_write_data[i] = write_data[i];
    }

    Err = GD25Q16ETIGR_write_8_bytes(Addr, addr_write_data, num_byte);
    if(Err) return Err;
    Err = GD25Q16ETIGR_read_8_bytes(Addr, addr_read_data, num_byte);
    if(Err) return Err;

    for(i = 0; i<num_byte; i++)
    {
            if(addr_write_data[i] == addr_read_data[i])
            {
                DoneOK++;
            }
            else
            {
                Err = GD25Q16ETIGR_write_8_bytes(Addr+i, addr_write_data+i, 1);
                if(Err) return Err;
                Err = GD25Q16ETIGR_read_8_bytes(Addr, addr_read_data, num_byte);
                if(Err) return Err;
                if(addr_write_data[i] == addr_read_data[i])
                {
                    DoneOK++;
                    CounterOfFixedError++;
                }
                else
                {
                    ErrAdr[Err] = Addr+i;
                    CounterOfTotalError++;
                }
            }
    }
    return 0;
}



uint16_t GD25Q16ETIGR_read_data(uint32_t Addr, uint16_t quant8, uint16_t * read_data)
{
    uint32_t i=0;
    uint16_t addr_read_data[8];
    uint16_t Err = 0;

    if(quant8 > 8)
    {
        for(i = 0; i < (quant8-8); i += 8)
        {//в этом цикле только полные посылки по 8 байт
            Err = GD25Q16ETIGR_read_8_bytes(Addr+i, addr_read_data, 8);
            if(Err) return Err;
            copy8_to_16(addr_read_data, read_data, 4);
            read_data+=4;
        }
    }
    if(i < quant8)
    {//тут м.б. от 1 до 8 байт
        Err = GD25Q16ETIGR_read_8_bytes(Addr+i, addr_read_data, (quant8 - i));
        if(Err) return Err;
        if((quant8 - i) & 1) {addr_read_data[quant8] = 0; quant8++; }//если байт нечётное число, то дополняем до чётного нулём
        copy8_to_16(addr_read_data, read_data, (quant8 - i)/2);
    }
    return 0;
}


uint16_t GD25Q16ETIGR_verify_data(uint32_t Addr, uint16_t quant8, uint16_t * verify_data)
{
    uint32_t i=0;
    uint16_t addr_vfy_data[8];
    uint16_t quant16;

    if(quant8 > 8)
    {
        for(i = 0; i < (quant8-8); i += 8)
        {//в этом цикле только полные посылки по 8 байт
            copy16_to_8(verify_data, addr_vfy_data, 4);
            if(GD25Q16ETIGR_verify_8_bytes(Addr+i, addr_vfy_data, 8)) return 1;
            verify_data+=4;
        }
    }
    if(i < quant8)
    {//тут м.б. от 1 до 8 байт
        quant16 = quant16bitWords(quant8-i);
        copy16_to_8(verify_data, addr_vfy_data, quant16);
        if(GD25Q16ETIGR_verify_8_bytes(Addr+i, addr_vfy_data, (quant8 - i))) return 1;
    }
    return 0;
}

uint16_t GD25Q16ETIGR_write_1_page(uint32_t Addr, uint16_t quant8, uint16_t * write_data) // запись внутри одной страницы
{
    uint32_t i=0;
    uint16_t addr_write_data[8];
    uint16_t quant16;
    uint16_t Err = 0;

    if(quant8 > 8)
    {
        for(i = 0; i < (quant8-8); i += 8)
        { //в этом цикле только полные посылки по 8 байт
            copy16_to_8(write_data, addr_write_data, 4);
            if(!writeVerify) Err = GD25Q16ETIGR_write_8_bytes(Addr+i, addr_write_data, 8);
            else Err = GD25Q16ETIGR_write_veryfy_8_bytes(Addr+i, addr_write_data, 8);
            if(Err) return Err;
            write_data += 4;
        }
    }
    if(i < quant8)
    {//тут м.б. от 1 до 8 байт
        quant16 = quant16bitWords(quant8-i);
        copy16_to_8(write_data, addr_write_data, quant16);
        if(!writeVerify) Err = GD25Q16ETIGR_write_8_bytes(Addr+i, addr_write_data, (quant8 - i));
        else Err = GD25Q16ETIGR_write_veryfy_8_bytes(Addr+i, addr_write_data, (quant8 - i));
        if(Err) return Err;
    }
    return 0;
}

uint16_t GD25Q16ETIGR_write_data(uint32_t Addr_8bit, uint16_t quant_8bit, uint16_t * write_data)
{
    uint16_t * addr_write_data = write_data;
    uint16_t page_quant_8bit = 0;
    uint16_t FlashSektorStart = 0;
    uint16_t FlashSektorEnd = 0;
    uint16_t i=0;
    uint16_t Err = 0;

    FlashSektorStart = (Addr_8bit)>>12; //сектор с которого начинается запись
    FlashSektorEnd = (Addr_8bit + quant_8bit - 1)>>12; //сектор в котором конец записи

    for(i = FlashSektorStart; i <= FlashSektorEnd; i++)
    {
        if(!SectorWasErraised[i]) {SectorWasErraised[i] = 1; Err = GD25Q16ETIGR_sector_erase((uint32_t)i*0x1000); if(Err) return Err;}
    }

    while( (Addr_8bit&0xFF)+(quant_8bit) > GD25Q16E_PAGE)           //если данные выходят за границу текущей страницы
    {
        page_quant_8bit = GD25Q16E_PAGE - (Addr_8bit&0xFF);       //вычисляем кол-во байт данных до конца текущей страницы
        Err = GD25Q16ETIGR_write_1_page(Addr_8bit,  page_quant_8bit, addr_write_data); //записываем эти данные на текущую страницу
        if(Err) return Err;
        Addr_8bit += page_quant_8bit;                                             //перелистываем страницу внешней памяти
        addr_write_data += page_quant_8bit/2;                                  //шагаем на следующие незаписанные данные в буфере (они у нас 16-битными словами)
        quant_8bit -= page_quant_8bit;                                            //уменьшаем кол-во данных на величину которую уже записали
    }
    if(quant_8bit > 0)
    {
        Err = GD25Q16ETIGR_write_1_page(Addr_8bit,  quant_8bit, addr_write_data); //если данные для записи остались, то записываем их
        if(Err) return Err;
    }
    return 0;
}




uint16_t GD25Q16ETIGR_ReadManufacturerDeviceID(void)
{
    volatile    uint16_t empty, i, j;

//    GD25Q16ETIGR_checkRXFFST();

    transmitData(ReadManufacturerDeviceID);

    for(i = 0; i<5; i++) transmitData(0xFF);
    while(SpiRegs.SPIFFRX.bit.RXFFST != (6))
    {

    }
    for(j = 0; j<6; j++)
    {
        empty = SpiRegs.SPIRXBUF;
    }
    return empty;
}
