why qspi with stm32l476 write wrong?

1

i've a homemade board with stm32l476 and w25q128jv qspi. I always use this QSPI with other stm32. I try this qspi and my software with stm32h7 and stm32f7 and all works fine, but i don't understand why with stm32l476 not work.

The pins that i use are:

GPIOE_10 --> QUADSPI_CLK

GPIOE_11 --> QUADSPI_NCS

GPIOE_12 --> QUADSPI_BK1_IO0

GPIOE_13 --> QUADSPI_BK1_IO1

GPIOE_14 --> QUADSPI_BK1_IO2

GPIOE_15 --> QUADSPI_BK1_IO3

I've a pull-up resistor for NCS to 3.3V and capacitor between 3.3V and GND.

When i write into it 256 byte of '0x23' at the posizion 0x90000000 and other 256 byte of '0xf3' at the position 0x90000100

it write this:

enter image description here

I use my software in this way:

  • init_qspi_pin();

  • init_qspi();

  • erase the qspi

  • qspi_write_array();

This is my software:

QSPI INIT:

 unsigned char init_qspi(){
unsigned long c1;
unsigned long pass_addr;
unsigned char passchar;
unsigned long passlong;
unsigned long passlong2;
//**  DEINIT  **
//DISABLE QSPI
QUADSPI->CR &= ~(QUADSPI_CR_EN);
//SPI FORCE RESET
RCC->AHB3RSTR |= RCC_AHB3RSTR_QSPIRST;  
//SPI FORCE RELEASE
RCC->AHB3RSTR &= ~(RCC_AHB3RSTR_QSPIRST);
//DISABLE QSPI MEMORY INTERFACE CLOCK
RCC->AHB3ENR &= ~(RCC_AHB3ENR_QSPIEN);

//**  INIT  **

//ENABLE QSPI MEMORY INTERFACE CLOCK
RCC->AHB3ENR |= RCC_AHB3ENR_QSPIEN;
while ((RCC->AHB3ENR & RCC_AHB3ENR_QSPIEN) == 0)
{
}
passlong = 1;

//SPI FORCE RESET
RCC->AHB3RSTR |= RCC_AHB3RSTR_QSPIRST;  
//SPI FORCE RELEASE
RCC->AHB3RSTR &= ~(RCC_AHB3RSTR_QSPIRST);

//ENABLE QSPI PINS CLOCK

init_QSPI_pin();

QUADSPI->CR = 0x00000000;

//SET QSPI FIFO THREESHOLD (4)
passlong = 4;
QUADSPI->CR |= ((passlong-1) << 8);

//WAIT QSPI BUSY FLAG RESET
while(QUADSPI->SR & QUADSPI_SR_BUSY){
}

//SET QSPI CLOCK PRESCALER = 1 (Fahb/2)
QUADSPI->CR |= (1 << 24);

//SET SAMPLE SHIFT (1/2 CYCLE)
QUADSPI->CR |= (1 << 4);

//SET FLASH SIZE (128 Mbit)
QUADSPI->DCR |= (0x17 << 16);

//SET CS HIGH TIME BETWEEN COMMANDS (2 clk cycles --> SET CSHT = CLK CYCLES - 1 = 1)
QUADSPI->DCR |= (1 << 8);

//SET THE LEVEL THAT CLK TAKES BETWEEN COMMANDS (WHEN CS IS HIGH).  
QUADSPI->DCR |= 0; //(LOW LEVEL)


//IMODE (INSTRUCTION MODE) = ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_IMODE_0;


QUADSPI->CCR &= ~(QUADSPI_CCR_ADSIZE);
QUADSPI->CCR |= QUADSPI_CCR_ADSIZE_1;

//ENABLE QSPI PERIPHERAL
QUADSPI->CR |= QUADSPI_CR_EN;


CMD_READ_QUAD_OUT       = 0x6B;
CMD_ERASE_4K_SECTOR     = 0x20;
CMD_QUAD_PAGE_PROGRAM   = 0x32;  

return 0;
}


MEMORYMAPPED:

void qspi_memory_mapped()
{

unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
volatile unsigned long *data_register;

data_register = &QUADSPI->DR;

//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);

//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;

//RESET TRANSFER FLAG
qspi_reset_flags();

//SET INSTRUCTION            
QUADSPI->CCR |= CMD_READ_QUAD_OUT;

//  DUMMY CLOCK CYCLES = 8
QUADSPI->CCR |= QUADSPI_CCR_DCYC;   


//FUNCTIONAL MODE (MEMORY MAPPED)
QUADSPI->CCR |= (QUADSPI_CCR_FMODE_1 | QUADSPI_CCR_FMODE_0);


//                  SET ADDRESS TO READ
QUADSPI->AR = 0x00000000;

}

WRITE UNLOCK:

void qspi_write_unlock()
{
 unsigned long passlong=0;
QUADSPI->DLR = 0; 

//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;

//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;


//RESET TRANSFER FLAG
qspi_reset_flags();

//SET INSTRUCTION                TRIG!!
QUADSPI->CCR |= CMD_WRITE_ENABLE;

//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;

wait_transfer_complete();

//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);  



//RESET TRANSFER FLAG
qspi_reset_flags();

qspi_wait_device();
}

ENABLE QUAD BUS:

void qspi_enable_quad_bus(unsigned char enable)
{
 unsigned long passlong=0;
unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
unsigned long data_reg = 0x00000000;

qspi_write_unlock();

QUADSPI->DLR = 1; //SI SCRIVONO 2 BYTE

//DATA MODE = DATA ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;

//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;

//RESET TRANSFER FLAG
qspi_reset_flags();

//SET INSTRUCTION            
QUADSPI->CCR |= CMD_WRITE_REGISTER;

if (enable){
    config_reg = 0x02;
}

data_reg = config_reg;
data_reg <<= 8;
data_reg |= status_reg;

//                  SET DATA TO SEND     TRIG!!
QUADSPI->DR = data_reg;

//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;

wait_transfer_complete();

//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);  


//RESET TRANSFER FLAG
qspi_reset_flags();

qspi_wait_device();

 }

QSPI READ REGISTER:

unsigned char qspi_read_register(unsigned char read_reg_cmd)
{

unsigned long passlong;
unsigned long *p_ulong;

QUADSPI->DLR = 1; 

//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;

//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;

//SET INSTRUCTION
QUADSPI->CCR |= read_reg_cmd;

//FUNCTIONAL MODE (INDIRECT READ)            TRIG!!
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;

//wait_transfer_complete();
passlong = QUADSPI->DR;



//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);

//RESET TRANSFER FLAG
qspi_reset_flags();

return (unsigned char)passlong;
}

QSPI WAIT DEVICE:

void qspi_wait_device()
{

unsigned char passchar;

do
{
    //WAIT UNTILL THE FLAG "WRITE IN PROGRESS" NOT RESET
  passchar = qspi_read_register(CMD_READ_STATUS_REGISTER_1);

}
while(passchar & 0x01);
}

QSPI READ ARRAY FROM MEMORY:

unsigned char qspi_read_array(unsigned long start_address, unsigned char *p_data, unsigned long data_len)
{

unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
volatile unsigned long *data_register;

if (start_address + data_len > QSPI_TOTAL_SIZE)
    {
  return 1;  
}

data_register = &QUADSPI->DR;

QUADSPI->DLR = data_len - 1; 

//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);

//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;

//RESET TRANSFER FLAG
qspi_reset_flags();

//SET INSTRUCTION            
QUADSPI->CCR |= CMD_READ_QUAD_OUT;

//  DUMMY CLOCK CYCLES = 8
QUADSPI->CCR |= QUADSPI_CCR_DCYC;


//FUNCTIONAL MODE (READ)
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;


//                  SET ADDRESS TO READ     TRIG!!  
QUADSPI->AR = start_address;

while(data_len)
    {

    while(QUADSPI->SR & QUADSPI_SR_FTF)
            {

        if (data_len)
                    {
            *p_data = *(__IO uint8_t *)data_register;
            p_data++;
            data_len--;

            if (QUADSPI->SR & QUADSPI_SR_TEF)
                            {
                //TRANSFER ERROR
                return 1;
            }

        }
        else
        {
            break;
        }
    }
}

wait_transfer_complete();

//reset FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);  

QUADSPI->DLR = 0;


//RESET TRANSFER FLAG
qspi_reset_flags();
qspi_wait_device();

return 0;
}

QSPI ERASE:

void qspi_erase_sector(unsigned long sector_id)
{

unsigned char config_reg = 0x00;
unsigned char status_reg = 0x00;
unsigned long data = 0x00000000;
unsigned long passlong;

QUADSPI->DLR = 0;

//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;

//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;

//RESET TRANSFER FLAG
qspi_reset_flags();


//SET INSTRUCTION
switch(qspi_get_sector_size(sector_id))
{

    case (4*1024):
    {
        QUADSPI->CCR |= CMD_ERASE_4K_SECTOR;    
        break;
    }
    case (64*1024):
    {
        QUADSPI->CCR |= CMD_ERASE_64K_SECTOR;         
        break;
    }
    default:
      QUADSPI->CCR |= CMD_ERASE_4K_SECTOR;  
      break;
}


QUADSPI->AR = passlong;

wait_transfer_complete();

//reset FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);  

//RESET TRANSFER FLAG
qspi_reset_flags();

qspi_wait_device();
}

QSPI WRITE LOCK:

void qspi_write_lock()
{

QUADSPI->DLR = 0;

//DATA MODE = NO DATA
//QUADSPI->CCR |= 0;

//ADDRESS MODE = NO ADDRESS
//QUADSPI->CCR |= 0;

//RESET TRANSFER FLAG
qspi_reset_flags();

//SET INSTRUCTION                TRIG!!
QUADSPI->CCR |= CMD_WRITE_DISABLE;

//FUNCTIONAL MODE (write)
//QUADSPI->CCR |= 0;


wait_transfer_complete();

//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);  

//RESET TRANSFER FLAG
qspi_reset_flags();

qspi_wait_device();
 }

QSPI QUAD PAGE PROGRAM:

unsigned char qspi_quad_page_program(unsigned long start_address, unsigned char *p_data, unsigned long data_len){

unsigned long c1;
unsigned char passchar;
unsigned long data = 0x00000000;
volatile unsigned long *data_register;
unsigned char write_error;
unsigned long passlong;



if (data_len == 0){
    return 1;
}


data_register = &QUADSPI->DR;

QUADSPI->DLR = data_len - 1; //BYTES TO WRITE

//DATA MODE = DATA ON 4 LINES
QUADSPI->CCR |= (QUADSPI_CCR_DMODE_0 | QUADSPI_CCR_DMODE_1);

//ADDRESS MODE = ADDRESS ON A SINGLE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;


//RESET TRANSFER FLAG
qspi_reset_flags();

//SET INSTRUCTION            
QUADSPI->CCR |= CMD_QUAD_PAGE_PROGRAM;

//SET QSPI ADDRESS
QUADSPI->AR = start_address;

//FUNCTIONAL MODE (WRITE)
//QUADSPI->CCR |= 0;


qspi_buffer_len = data_len;
qspi_buffer = p_data;


while(qspi_buffer_len > 0){

    while(QUADSPI->SR & QUADSPI_SR_FTF){
        if (qspi_buffer_len){
            *(__IO uint8_t *)data_register = *qspi_buffer;
            qspi_buffer++;
            qspi_buffer_len--;

                if (QUADSPI->SR & QUADSPI_SR_TEF){
                    //TRANSFER ERROR
                return 1;
            }
        }
        else
        {
            break;
        }
    }
}




while (QUADSPI->SR & QUADSPI_SR_BUSY){
    c1++;
    c1--;
}


//RESET FMODE, DMODE, AMODE, INSTRUCTION E DUMMY CYCLES
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION | QUADSPI_CCR_DCYC);  

QUADSPI->DLR = 0;

qspi_reset_flags(); 

write_error = qspi_write_error_occurred();
if (write_error){
    return 1;

}

qspi_wait_device();

return 0;
}

QSPI ERROR:

unsigned char qspi_write_error_occurred()
{

unsigned char passchar;

passchar = qspi_read_register(CMD_READ_STATUS_REGISTER_1);

if(passchar & (0x01 << 6))
{

    return 1;
} 

return 0;
 }

QSPI WRITE ARRAY :

unsigned char qspi_write_array(unsigned long start_address, unsigned char *p_data, unsigned long data_len)
{

unsigned long c1, c2, c3;
//unsigned long page_start_addr;

unsigned char write_error;
unsigned long pages_to_write;
unsigned long remaining_bytes;
unsigned char passchar;
unsigned char *data_ptr;
unsigned long qspi_idx;


if (start_address + data_len > QSPI_TOTAL_SIZE){
  return 1;  
}


qspi_enable_quad_bus(1);

qspi_idx = start_address;
data_ptr = p_data;

pages_to_write = data_len / QSPI_PAGE_SIZE;

for(c1=0; c1 < pages_to_write; c1++)
{

    qspi_write_unlock();
    if(qspi_quad_page_program(qspi_idx, data_ptr, QSPI_PAGE_SIZE)){

        //ERROR
        return 1;
    }
    qspi_write_lock();


    qspi_idx += QSPI_PAGE_SIZE;
    data_ptr += QSPI_PAGE_SIZE;
}


remaining_bytes = data_len % QSPI_PAGE_SIZE;

if (remaining_bytes){

    qspi_write_unlock();
    if(qspi_quad_page_program(qspi_idx, data_ptr, remaining_bytes)){

        //ERROR
        return 1;
    }
    qspi_write_lock();        
}  


return 0;

}

QSPI GET MODEL:

unsigned short qspi_get_model()
{

unsigned long device_id;
unsigned long device_info;

device_id = qspi_read_device_id();
device_id = qspi_read_device_id();
device_info = qspi_read_device_info();

if((device_id   == 0x000017EF)&&
   (device_info == 0x001870EF)){

    return QSPI_MODEL__W25Q128JV;
}
else if((device_id   == 0x00001701)&&
        (device_info == 0x00182001)){

    return QSPI_MODEL__S25FL128S;
}
    else if((device_info == 0x0018BA20)){

    return QSPI_MODEL__MIA;
    }

return 0x0000;


}

QSPI INFO :

unsigned long qspi_read_device_info()
{

unsigned long passlong;
unsigned long *p_ulong;


QUADSPI->DLR = 2; 

//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;

//ADDRESS MODE = NO ADDRESS
QUADSPI->CCR &= ~(QUADSPI_CCR_ADMODE);

//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_DEV_INFO;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;

//FLASH ADDRESS
QUADSPI->AR = 0x00000000;

wait_transfer_complete();

passlong = QUADSPI->DR;

//RESET TRANSFER FLAG
qspi_reset_flags(); 

//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);

//RESET TRANSFER FLAG
qspi_reset_flags();

return passlong;
}

QSPI READ INFO:

unsigned long qspi_read_device_id()
{

unsigned long passlong;
unsigned long *p_ulong;

QUADSPI->DLR = 1;

//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;

//ADDRESS MODE = ADDRESS ON ONE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;

//SET INSTRUCTION
QUADSPI->CCR |= CMD_READ_DEVICE_ID;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;

//RESET TRANSFER FLAG
qspi_reset_flags();
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;

wait_transfer_complete();

passlong = QUADSPI->DR;

//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);

//RESET TRANSFER FLAG
qspi_reset_flags();

return passlong;
}

QSPI READ INFO:

unsigned long qspi_read_info(unsigned char instruction,unsigned char nByteToRead)
{

unsigned long passlong;
unsigned long *p_ulong;

QUADSPI->DLR = nByteToRead - 1;

//DATA MODE = DATA ON 1 LINE
QUADSPI->CCR |= QUADSPI_CCR_DMODE_0;

//ADDRESS MODE = ADDRESS ON ONE LINE
QUADSPI->CCR |= QUADSPI_CCR_ADMODE_0;

//SET INSTRUCTION
QUADSPI->CCR |= instruction;
//FUNCTIONAL MODE
QUADSPI->CCR |= QUADSPI_CCR_FMODE_0;

//RESET TRANSFER FLAG
qspi_reset_flags();
//FLASH ADDRESS
QUADSPI->AR = 0x00000000;

wait_transfer_complete();

passlong = QUADSPI->DR;

//RESET FMODE, DMODE, AMODE E INSTRUCTION
QUADSPI->CCR &= ~(QUADSPI_CCR_FMODE | QUADSPI_CCR_DMODE | QUADSPI_CCR_ADMODE | QUADSPI_CCR_INSTRUCTION);

//RESET TRANSFER FLAG
qspi_reset_flags();

return passlong;
}

QSPI RESET FLAG

void qspi_reset_flags()
{
unsigned char c1;
while (QUADSPI->SR & QUADSPI_SR_BUSY)
{
}
 END:   
QUADSPI->FCR = 0xFFFFFFFF;
 }

QSPI WAIT TRASFERT COMPLETE:

void wait_transfer_complete()
{
while ((QUADSPI->SR & QUADSPI_SR_TCF) == 0)
{
}
 }

Someone can help me?

c
asked on Stack Overflow Jun 18, 2019 by Tremotino • edited Jun 18, 2019 by Siong Thye Goh

1 Answer

0

Memory-mapped mode: Only read operations are allowed to the external Flash memory in this mode.

answered on Stack Overflow Dec 5, 2019 by user12482889

User contributions licensed under CC BY-SA 3.0