QSPI problems in 5282

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

QSPI problems in 5282

3,540 Views
SVC2
Contributor II
Hi,
 
Trying to program a SPI flash but it is not working, as I want to.
 
1) To check the completion of a transfer:

 When transfer is initiated (MCF_QSPI_QDLYR |=  MCF_QSPI_QDLYR_SPE; ).
 
  Is it recommended to check the SPI bit?
Code:
 while(1) {  vuint16 qdlyr=MCF_QSPI_QDLYR;  if( (qdlyr & MCF_QSPI_QDLYR_SPE >> 0xF)==0)   break; }

 
Or simply the SPIF bit: 
Code:
while (!(MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF))   ; //wait for queue to end

 
or both?
 
2)  I am always getting the response from the SPI Flash in QRR1 ( rcv[1] in code below). Any clue why?
 
Code:
void SPI_Flash_ReadStatusReg(void){ int i; spi_word_t rcv[16];  // QSPI Module  Command RAM Registers (QCR0-QCR15) #define SPI_CMD_CS_ASRT     0xC0E0 //chip select 0 Active Low   // Load Command: Set queue address (QAR) to COMMAND address [0x20 - 0x2F] MCF_QSPI_QAR = MCF_QSPI_QAR_CMD;  // Write the command words MCF_QSPI_QDR = (uint16)(SPI_CMD_CS_ASRT);   // Write Tx Data: Set queue address (QAR) to Transmit address [0x00 - 0x0F] MCF_QSPI_QAR = MCF_QSPI_QAR_TRANS;   // Load the data to transmit   MCF_QSPI_QDR = RDSR; //read status register (i,e. RDSR=0x05)  /* Determine the active level, the first and last index of the transmit queue */ MCF_QSPI_QWR = (0 | (MCF_QSPI_QWR & MCF_QSPI_QWR_CSIV)       | MCF_QSPI_QWR_NEWQP(0)       | MCF_QSPI_QWR_ENDQP(1));    /* begin transfer */ MCF_QSPI_QDLYR |= MCF_QSPI_QDLYR_SPE;  /* When transfer queue ends, QIR[SPIF] is set */ while (!(MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF))  ; //wait for queue to end /* Set RAM address pointer to received data */ MCF_QSPI_QAR = MCF_QSPI_QAR_RECV; /* read received data from the RAM */ for (i = 0; i < 16; ++i) {  rcv[i] = MCF_QSPI_QDR; } /* done */}

 
 
Thanks,
 
Simon
 
Labels (1)
0 Kudos
22 Replies

1,480 Views
RichTestardi
Senior Contributor II
Hi,
 
What exactly is the problem you are seeing?
 
If I understand correctly, the status from the read status register command *should* be in rcv[1].
 
rcv[0] should be ignored -- that is the data that was being shifted in while you were shifting out the read status register command -- it will be undefined.
 
If it helps, what I do after starting a transfer is:
 
        // start the transfer
        MCF_QSPI_QDLYR = MCF_QSPI_QDLYR_SPE;
 
        // wait for transfer complete
        assert(! (MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF));
        while (! (MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF)) {
        }
        MCF_QSPI_QIR = MCF_QSPI_QIR_SPIF;
 
        assert((MCF_QSPI_QWR & 0xf0) >> 4 == request-1);
        assert(! (MCF_QSPI_QDLYR & MCF_QSPI_QDLYR_SPE));

I use QSPI to talk to EzPort of another MCU, which is similar to, but not identical to, a generic SPI flash memory.
 
You can see all my code, including the qspi driver in qspi.[ch] and the flash access driver above it in clone.[ch] here:
 
 
Another guy is having some issues with QSPI/EzPort interaction here:
 
 
-- Rich
 
0 Kudos

1,480 Views
SVC2
Contributor II
Well, it is good to know that it is normal to have the response in rcv[1]. Thanks.
 
Attached are the signals: c1 (top) is Chip select, c2 (middle) is the clock and c3 (bottom) is the QSPI_Din (my forth channel on the scope is busted).
 
I am noticing 2 weird things:
1) When chip select is asserted, QSPI_Din is toggling.
2) Why is the clock being interrupted in the middle of the sequence?
Thanks,
SVC

 
0 Kudos

1,480 Views
jayteemo
Contributor I


SVC2 wrote:
I am noticing 2 weird things:
1) When chip select is asserted, QSPI_Din is toggling.
2) Why is the clock being interrupted in the middle of the sequence?

1.)I'm not sure why that is occuring, but if it becomes a problem you can add a delay between the assertion of the CS and the beginning of the clock.  QDLYR[QCD], enabled in QCR[DSCK]

2.) It is doing 2 8-bit transfers... The first one receives command, the second sends the response data.  Check the QCR[DT] for the delay after the transfer enable... If DT = 1, you can shrink or grow the delay by changing the value of QDLYR[DTL].  If DT = 0, a standard delay period is used.  Time is needed to ensure the transfer RAM is loaded.



0 Kudos

1,480 Views
SVC2
Contributor II
I cannot check the DT since QCR0-QCR15 are write only but I am explicitly setting it to 0 so I presume the delay I see is normal.
 
What is the Default Reset value (i.e., DT=0)? I cannot find it in the document.
 
Thanks,
SVC
 
0 Kudos

1,480 Views
jayteemo
Contributor I
The reset values for QCR are undefined. 
Since you are explicitly setting DT=0 you are good.

Also, this should be applicable if you want to determine the time of the delay:
Standard delay after transfer =  17 /  fsys
when DT = 0.
0 Kudos

1,480 Views
SVC2
Contributor II

Hi,

 

I’m trying to control a SPI flash using the QSPI in 5282.

 

It works well when send/received data is less that queue size.

 

It is a nighmare when data is more than queue size (for example to read/write 256 data into flash).

 

I am trying to use it in wraparound mode, but I don't have a way to synchronize the device and the code running in the processor.

 

Code:
bool_t qspi_tx_cont(const uint16 cmd, 
       const uint16 *tx_buf, const uint16 tx_size, 
        Bsp_QSPI_err_t *err)
{
 const uint16 end_qp=(uint16) (tx_size > QSPI_QUEUE_LENGTH — QSPI_QUEUE_LENGTH : tx_size);
 uint32 count=0;
 uint16 i=0;
 
 // Fill the commands
 MCF_QSPI_QAR = MCF_QSPI_QAR_CMD; 
 for(i=0; i < QSPI_QUEUE_LENGTH; ++i)
  MCF_QSPI_QDR = cmd; //0xCE00;
 
 // Determine the active level, the first and last index of the transmit queue 
 MCF_QSPI_QWR = (unsigned short)(0 
                   | (MCF_QSPI_QWR & MCF_QSPI_QWR_CSIV)
     | MCF_QSPI_QWR_WREN   // Wrap enabled
     | MCF_QSPI_QWR_NEWQP(0)
     | MCF_QSPI_QWR_ENDQP(end_qp - 1)
     );

 // Clear the error flags 
 MCF_QSPI_QIR &= ~MCF_QSPI_QIR_WCEF;// Clear collision detected flag
 MCF_QSPI_QIR &= ~MCF_QSPI_QIR_ABRT;// Clear Abort flag

 // Fill Tx data
  MCF_QSPI_QAR = MCF_QSPI_QAR_TRANS;
        for(i=0; i < QSPI_QUEUE_LENGTH; ++i)
 {
  if(i < tx_size)
   MCF_QSPI_QDR = tx_buf[i];
  else
   MCF_QSPI_QDR = 0; // dummy 
 }

 // begin transfer in wrap around mode
 MCF_QSPI_QDLYR |= MCF_QSPI_QDLYR_SPE;
 
 
 // Send the rest
 while(i < tx_size)
 {
  
  // Fill Tx data
  MCF_QSPI_QAR = (uint16) (MCF_QSPI_QAR_TRANS + (i% QSPI_QUEUE_LENGTH));
  MCF_QSPI_QDR = tx_buf[i];

     // Next
  i++;
 }

 // Stop wrap around
 MCF_QSPI_QWR &= (~MCF_QSPI_QWR_WREN); 

 // Wait for transfer complete
 // When transfer queue ends, QIR[SPIF] is set
 count=0;
       while (! (MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF)) 
       {
     if(count++ > QSPI_TRANSFER_TIMEOUT)
     {
      if(err) *err = BSP_QSPI_TRANSFER_TIMEOUT;
      return FALSE;
     }
    }

 // SPE automatically clears when transfer is complete
 if(  MCF_QSPI_QDLYR & MCF_QSPI_QDLYR_SPE )
 {
  if(err) *err = BSP_QSPI_SPE_NOT_ASSERTED;
  return FALSE; 
 }
  
    
 // clear the SPIF flag 
 MCF_QSPI_QIR |= MCF_QSPI_QIR_SPIF;
 
 // check if a write collision error has occured 
 if(MCF_QSPI_QIR & MCF_QSPI_QIR_WCEF)
 {
  if(err) *err = BSP_QSPI_COLLISION;
  return FALSE;
 }
  
 // check for if an abort error has occured 
 else if(MCF_QSPI_QIR & MCF_QSPI_QIR_ABRT)
 {
  if(err) *err = BSP_QSPI_ABORTED;
  return FALSE;
 }
 

 // done
 return TRUE;
 
}
  


 

Any hints?

 

Thanks,

S.

 

0 Kudos

1,480 Views
RichTestardi
Senior Contributor II
Hi,
 
Is there a reason you need wraparound mode?  (Like you don't know how much data to expect when the transfer begins?)
 
You don't need to use wraparound mode just to send more data than fits in the queue, and in fact I don't do so yet support arbitrary transfer lengths in the driver linked to above (and I use it to talk to essentially a QSPI flash device -- a CF with EzPort -- you can see all  the flash command processing in clone.c and the transport driver in qspi.c).
 
The only trick when processing more than one queue of data is the chip select management.  If you use a GPIO pin, this is trivial; if you use one of the QSPI chip selects, you have to be just a bit more careful (see my qspi.c).
 
If you really want to use wraparound mode, I believe you have to synchronize with QIR[SPIF] before "reloading" the queue.
 
-- Rich
 
0 Kudos

1,480 Views
SVC2
Contributor II
 
I tried your code and, as you mentioned, since I am using the QSPI chip Select, it does not work.
 
I can see on my scope the chip select toggling at each iteration of the loop.
 
S.
 
0 Kudos

1,480 Views
RichTestardi
Senior Contributor II
Uggh!!!  I forgot there was a bug in that zip archive setting the command data that I have since fixed.  Sorry, I'll try to get the zip updated this week.
 
In the meantime, try this:
 
Code:
// perform both output and input qspi i/ovoidqspi_transfer(byte *buffer, int length){#if MCF52221 || MCF52233 || MCF52259    int i;    int x;    int request;    x = splx(7);        // while there is data remaining...    while (length) {        // process up to 16 bytes at a time        request = MIN(length, 16);        // for all bytes...        for (i = 0; i < request; i++) {            // set up the command            MCF_QSPI_QAR = MCF_QSPI_QAR_CMD+i;            MCF_QSPI_QDR = MCF_QSPI_QDR_CONT|(csiv?0:MCF_QSPI_QDR_QSPI_CS0);            // copy tx data to qspi ram            MCF_QSPI_QAR = MCF_QSPI_QAR_TRANS+i;            MCF_QSPI_QDR = buffer[i];        }        // set the queue pointers        assert(request);        MCF_QSPI_QWR = (csiv?0:MCF_QSPI_QWR_CSIV)|MCF_QSPI_QWR_ENDQP(request-1)|MCF_QSPI_QWR_NEWQP(0);        // start the transfer        MCF_QSPI_QDLYR = MCF_QSPI_QDLYR_SPE;        // wait for transfer complete        assert(! (MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF));        while (! (MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF)) {        }        MCF_QSPI_QIR = MCF_QSPI_QIR_SPIF;        assert((MCF_QSPI_QWR & 0xf0) >> 4 == request-1);        assert(! (MCF_QSPI_QDLYR & MCF_QSPI_QDLYR_SPE));        // for all bytes...        for (i = 0; i < request; i++) {            // copy rx data from qspi ram            MCF_QSPI_QAR = MCF_QSPI_QAR_RECV+i;            buffer[i] = MCF_QSPI_QDR;        }        buffer += request;        length -= request;    }    // transfer complete    MCF_QSPI_QWR = csiv?MCF_QSPI_QWR_CSIV:0;        splx(x);#elif MCF51JM128    // cs active    if (csiv) {        PTED &= ~PTEDD_PTEDD7_MASK;    } else {        PTED |= PTEDD_PTEDD7_MASK;    }        while (length) {        // N.B. spi needs us to read the status register even for release code!        ASSERT(SPI1S & SPI1S_SPTEF_MASK);        ASSERT(! (SPI1S & SPI1S_SPRF_MASK));                SPI1DL = *buffer;                while (! (SPI1S & SPI1S_SPTEF_MASK)) {            // NULL        }                while (! (SPI1S & SPI1S_SPRF_MASK)) {            // NULL        }                *buffer = SPI1DL;                buffer++;        length--;    }    // cs inactive    if (csiv) {        PTED |= PTEDD_PTEDD7_MASK;    } else {        PTED &= ~PTEDD_PTEDD7_MASK;    }#endif}

 
(I edited this because My "?" characters got munged in the paste.)


Message Edited by Rich T on 2009-02-17 09:54 AM
0 Kudos

1,480 Views
blackjack
Contributor I

Hi Rich,

             Where do i can get your zip code. Right now iam trying to work on M52233 MCU but could not get the result.

0 Kudos

1,480 Views
RichTestardi
Senior Contributor II

It's all at the bottom of this page: http://www.cpustick.com/downloads.htm

 

-- Rich

 

0 Kudos

1,480 Views
SVC2
Contributor II
I tried with the following modifications. Again, the chip select is toggling:
 
 
Code:
// perform both output and input qspi i/ovoid qspi_transfer(uint16 *buffer, int length){    int i;    int x;    int request;  //  x = splx(7);        // while there is data remaining...    while (length) {        // process up to 16 bytes at a time        request = QSPI_MIN(length, 16);        // for all bytes...        for (i = 0; i < request; i++) {            // set up the command            MCF_QSPI_QAR = MCF_QSPI_QAR_CMD+i;            MCF_QSPI_QDR = 0xCE00;            // copy tx data to qspi ram            MCF_QSPI_QAR = MCF_QSPI_QAR_TRANS+i;            MCF_QSPI_QDR = buffer[i];        }        // set the queue pointers                assert(request);        MCF_QSPI_QWR = (MCF_QSPI_QWR_CSIV|                        MCF_QSPI_QWR_ENDQP(request-1)|                        MCF_QSPI_QWR_NEWQP(0));                // start the transfer        MCF_QSPI_QDLYR = MCF_QSPI_QDLYR_SPE;        // wait for transfer complete        assert(! (MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF));        while (! (MCF_QSPI_QIR & MCF_QSPI_QIR_SPIF)) {        }        MCF_QSPI_QIR = MCF_QSPI_QIR_SPIF;        assert((MCF_QSPI_QWR & 0xf0) >> 4 == request-1);        assert(! (MCF_QSPI_QDLYR & MCF_QSPI_QDLYR_SPE));        // for all bytes...        for (i = 0; i < request; i++) {            // copy rx data from qspi ram            MCF_QSPI_QAR = MCF_QSPI_QAR_RECV+i;            buffer[i] = MCF_QSPI_QDR;        }        buffer += request;        length -= request;    }    // transfer complete    MCF_QSPI_QWR = csiv—MCF_QSPI_QWR_CSIV:0;    //    splx(x);}

 
0 Kudos

1,480 Views
SVC2
Contributor II
Actually, my fault, your code works fine!
 
Thank you very much, I really appreciate your help.
 
S.
 
0 Kudos

1,480 Views
RichTestardi
Senior Contributor II
Well, it didn't work fine the first time! :smileyhappy:
 
Thanks for catching that; I updated the zip file out on the web.
 
-- Rich
 
0 Kudos

1,480 Views
SVC2
Contributor II

Should there be any delay after I initialize the QSPI registers and start using it?

 

When I trace step through the code, it works. Nevertheless, when I run it, it does not work.

 

Thanks,
Simon

 

0 Kudos

1,480 Views
RichTestardi
Senior Contributor II

The only delay I have been aware of is after I reset the target chip, it some time before it will properly respond to flash commands.  I do not believe the local qspi needs any time.

 

Wow, it looks like we have a new web interface here, and spell check!

0 Kudos

1,480 Views
SVC2
Contributor II

Hi,

 

Now I am adding more devices in different chip selects. I notice that when the code

 

  MCF_QSPI_QWR = (unsigned short) (
                       ((cs_active_lvl == SPI_CS_ACTIVE_LO) ? 0: MCF_QSPI_QWR_CSIV) |
                        MCF_QSPI_QWR_ENDQP(request-1) |
                        MCF_QSPI_QWR_NEWQP(0));

is executed, ALL 4 chips selects are getting asserted (driven Low).

 

Is there a way to assert solely the desired CS?

 

Note that the command I enter is:

 

MCF_QSPI_QAR = (uint16)(MCF_QSPI_QAR_CMD+i);MCF_QSPI_QDR = (uint16)(MCF_QSPI_QDR_CONT  |                    MCF_QSPI_QDR_BITSE |                           active_level);

 

 

where

 

 

active_level= cs_active_lvl == SPI_CS_ACTIVE_LO ? ((~chip_select)&0xF00) : chip_select;// chip_select variable is set as //        MCF_QSPI_QDR_QSPI_CS3 or MCF_QSPI_QDR_QSPI_CS2,..//// Note:// MCF_QSPI_QDR_QSPI_CS3= 0x800 => ~0x800 & 0xF00 = 0x700// MCF_QSPI_QDR_QSPI_CS2= 0x400 => ~0x400 & 0xF00 = 0xB00// MCF_QSPI_QDR_QSPI_CS1= 0x200 => ~0x200 & 0xF00 = 0xD00// MCF_QSPI_QDR_QSPI_CS0= 0x100 => ~0x100 & 0xF00 = 0xE00//

 

 

 

Thanks,

Simon

 

0 Kudos

1,480 Views
RichTestardi
Senior Contributor II

The QWR controls the "inactive" level of the CS -- i.e., the level of all 4 lines while you are not driving a transfer.  During the transfer, you control the "active" chip selects individually with the 4 bits in the command register.

 

Typically, you'll want the "inactive" level to be 1, so you should set bit 12 of QWR to 1.  Then you will want to set the appropriate CS line low in the command register -- typically only one of bits 8 thru 11 of QCRx will be 0 at a time unless you are using an external decoder.

 

> Is there a way to assert solely the desired CS?

 

Yes, by setting just that desired CS to 0 (assuming active low) in QCRx, and all of the other CS to 1.

0 Kudos

1,480 Views
SVC2
Contributor II

Rich,

 

In the example you sent me, you have:

 


while(length)

// process up to 16 bytes at a time

request = MIN(length, 16);

 

// for all bytes...

for (i = 0; i < request; i++)

{

// set up the command

MCF_QSPI_QAR = MCF_QSPI_QAR_CMD+i;

MCF_QSPI_QDR = MCF_QSPI_QDR_CONT;

 

// copy tx data to qspi ram

MCF_QSPI_QAR = MCF_QSPI_QAR_TRANS+i;

MCF_QSPI_QDR = buffer[i];

}

 

// set the queue pointers

assert(request);

MCF_QSPI_QWR = (csiv?0:MCF_QSPI_QWR_CSIV)   |

                          MCF_QSPI_QWR_ENDQP(request-1) |

                          MCF_QSPI_QWR_NEWQP(0);

 

//...


With csiv set to 1, QWR is being set to 0, thus ALL 4 chip selects going Low.

 

Simon

 

 

0 Kudos

1,480 Views
RichTestardi
Senior Contributor II

That's correct -- thats the *inactive* value that is used when you want no chips selected, so all lines should be the same.  You probably want that to be "1".

 

Then, when you have chips selected, you need to put the proper bitmask in here in the command registers:

 

        // for all bytes...
        for (i = 0; i < request; i++) {
            // set up the command
            MCF_QSPI_QAR = MCF_QSPI_QAR_CMD+i;
            MCF_QSPI_QDR = MCF_QSPI_QDR_CONT|(csiv?0:MCF_QSPI_QDR_QSPI_CS0);

            // copy tx data to qspi ram
            MCF_QSPI_QAR = MCF_QSPI_QAR_TRANS+i;
            MCF_QSPI_QDR = buffer[i];
        }

 

You want to change the CS0 term to be the appropriate bitmask.

 

 

0 Kudos