Hot!Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution

Page: 12 > Showing page 1 of 2
Author
vwheeler
Junior Member
  • Total Posts : 21
  • Reward points : 0
  • Joined: 2011/12/21 13:51:46
  • Location: 0
  • Status: offline
2015/05/29 16:23:54 (permalink)
5 (3)

Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution

There is another item in the forum about the PIC32MZ problem with SQI titled:
 
    "PIC32MZ Problem with SQI in PIO-Mode and working solution".
 
In it, the programmer finds that after he submits a Transmit and Read transaction that he winds up with extra bytes left over in the Transmit FIFO, and he writes a work-around to consume those bytes to leave the transaction "slate" clean for the next operation.
 
However, the CAUSE of his problem was that the current version of the PIC32 Family Reference Manual, Section 46. Serial Quad Interface (SQI) (DS60001244B), while it is 10X better than the original release (version 'A'), still has misleading statements AT EVERY TURN, and sadly, does not even come close to describing the actual behavior of the silicon.  Whether the silicon has bugs or not, I'm not venturing into that arena, but I did spend the last 48 hours (approximately 28 hours of work time) writing tests and documenting what I found so that I could reliably communicate with my external devices.  And I am doing so now.  The behavior is consistent, so I thought I would share part of the knowledge I gained in the last 48 hours.
 
The above documentation problem caused him to write code that inadvertently left unused and unwanted bytes in the Transmit FIFO.
 
The following is his original code with his work-around.
 
This is the code he used to set up the SQI module.
 
void HAL_SQI_Init(void)
{
 // Initialize the SQI1 Bus
    DEV_SendString(DEV_DEBUG, "> Initializing the sqi-bus...");

 //Configuring the clock
 PLIB_OSC_ReferenceOscBaseClockSelect(OSC_ID_0,OSC_REFERENCE_2,OSC_REF_BASECLOCK_SYSCLK); //RefClock2 = SysClk
 PLIB_OSC_ReferenceOscEnable(OSC_ID_0,OSC_REFERENCE_2);
 PLIB_OSC_ReferenceOutputEnable(OSC_ID_0,OSC_REFERENCE_2);

 // switch on that sqi beast
 SQI1CFG = SQI_ENABLE | (SQI_CS_OEN_0<<24) | (SQI_DATA_OEN_SINGLE<<20) | SQIxCFG_RESET | SQI_BURSTEN | CPOL_ACTIVE_LOW | CPHA_START | SQI_XFER_MODE_PIO;

 while ((SQI1CLKCON & SQIxCLKCON_CLK_IS_STABLE) == 0); // Wait for clock to be stable
 // Errata 34 - SQI Read Clock Speed: Clock speed for read operations does not meet the maximum specification
 // (SQ10) of 50 MHz. For read operations the maximum clock is 25 MHz.
 SQI1CLKCON = SQIxCLKCON_CLK_DIV_4 | SQIxCLKCON_CLKENABLE; // Enable SQI1 clock with divisor 4
 while ((SQI1CLKCON & SQIxCLKCON_CLK_IS_STABLE) == 0); // Wait for clock to be stable

    DEV_SendString(DEV_DEBUG, "done\r\n");
}

 
And the following is his commented code with the work-around near the bottom bracketed by the #ifdef USE_SQI_BUFFER_CLEAR_WORKAROUND:
 
void SQI_Read_FlashID (uint32_t *data)
{
#define FLASHCMD_NOP (0x00)
#define FLASHCMD_READ_JEDEC_ID (0x9F)
#define USE_SQI_BUFFER_CLEAR_WORKAROUND

 // Setup SQI FIFO Thresholds
 PLIB_SQI_ControlBufferThresholdSet(SQI_ID_0, 1);
 PLIB_SQI_TxBufferThresholdSet(SQI_ID_0,1);
 PLIB_SQI_RxBufferThresholdSet(SQI_ID_0,4);
 PLIB_SQI_TxBufferThresholdIntSet(SQI_ID_0,1);
 PLIB_SQI_RxBufferThresholdIntSet(SQI_ID_0,4);

 // Setup SQI transfer control words
 SQI1CON = SQIxCON_CS_0 | SQIxCON_SINGLE_LANE | SQIxCON_CMD_TRANSMIT | 1; // FLASHCMD_READ_JEDEC_ID
 //Write the command to the transfer buffer {FLASHCMD_READ_JEDEC_ID, NOP, NOP, NOP}
 SQI1TXDATA = FLASHCMD_READ_JEDEC_ID | FLASHCMD_NOP<<8 | FLASHCMD_NOP<<16 | FLASHCMD_NOP<<24;
 // Setup control word to read 4 bytes
 SQI1CON = SQIxCON_DASSERT | SQIxCON_CS_0 | SQIxCON_SINGLE_LANE | SQIxCON_CMD_RECEIVE | 4; // Receive 4 bytes
 while ((SQI1STAT1&0xff)==0); //wait for transmitting
 *data = PLIB_SQI_ReceiveData(SQI_ID_0);

 // Now there are still 3 Bytes in the transmit buffer!
 // We need to get rid of that 3 Bytes or it will mess up our next transmission!
 // Microchip did not implement such a transmit buffer clear function in hardware
 // and the soft reset does not do the job (see errata, tryed it with higher clock rates, but still does not work)
 // ==> soft sqi reset brings unexpected results
 //SQI1CFG = SQI1CFG | 1<<16;
 // ==> so we need a dirty workaround for it (that compensates the dirty work from microchip)
 // what we need to do is flush the next 3 bytes out through the sqi-bus without using the chip-Select.
 // starting the sqi bus transfer work through writing into the SQI1TXDATA register. so these are additional
 // 4 bytes that results in a total of 7 dummy bytes to flush out the sqi.
 // without using the chip select that nop-commands (=0) does not do any harmful thing on the sqi-bus
 //SQI1CFG = SQI1CFG & ~(3<<24); // Don't use Chip-Select ( i am not shure if that works)

 //in this case we use the other chip-select, where no device is connected to, so that transfer should not bother
 //our flash chip that is connected to chip select 0
#ifdef USE_SQI_BUFFER_CLEAR_WORKAROUND
 SQI1CON = SQIxCON_DASSERT | SQIxCON_CS_1 | SQIxCON_SINGLE_LANE | SQIxCON_CMD_TRANSMIT | 7; // NOP
 SQI1TXDATA = FLASHCMD_NOP;
 while ( (SQI1INTSTAT & 0x01) == 0); //wait for transfer to finish
#endif

 DEV_SendString(DEV_DEBUG, "> SQI_Read_FlashID: 0x");
 DEV_SendHEX(DEV_DEBUG, (unsigned char *)data, 4);
 DEV_SendString(DEV_DEBUG, "\r\n");
}

 
The problem is created by the following, and I insert my own comments so you can see what is ACTUALLY going on with the SQI module (contrary to what the author thought was going on):
 
 //Write the command to the transfer buffer {FLASHCMD_READ_JEDEC_ID, NOP, NOP, NOP}
 SQI1TXDATA = FLASHCMD_READ_JEDEC_ID | FLASHCMD_NOP<<8 | FLASHCMD_NOP<<16 | FLASHCMD_NOP<<24;
    /* This is the part where he gets into trouble. What this is is a 32-bit WRITE
     * into the Tx FIFO.  This causes the READ JEDEC ID command 0x9F to be
     * written into the Tx FIFO followed by 0x00, 0x00, 0x00. These are the
     * left-over bytes he runs into later that get in the way of the next transaction. */

 
The omitted part of the SQI documentation is that, while the SQI1TXDATA register "appears" to be a 32-bit register, it is sensitive to the WIDTH of the write.  If you write directly to the register, it will ALWAYS write 32 bits (4 bytes), no matter how much you don't want it to.  But you can write only 1 byte, or 2 bytes, by using a pointer.  The following code replacing the above line would remedy his problem and make the work-around unnecessary because it leaves the SQI module's FIFO's clean after the Transaction completes.  Which is to say (if the corresponding "detect" bits are enabled in the SQI1INTEN register):
 
SQI1INTSTATbits.TXEMPTYIF == 1
SQI1INTSTATbits.RXEMPTYIF == 1
and
SQI1INTSTATbits.CONEMPTYIF == 1
 
which is what you want after each "cycle of action" with the SQI module.  If you don't get this, then you're doing something wrong.  (Remember, this is about PIO mode.)
 
Here is the code that does the trick (replacing the line above):
 
 {
  UINT8 * lcpTxReg = (UINT8 *)&SQI1TXDATA;
  *lcpTxReg = FLASHCMD_READ_JEDEC_ID; // Start both transactions by writing 1 byte into the TX FIFO.
   // This 1 byte then gets consumed by the TX Transaction, leaving the FIFO empty afterwards.
 }

 
The attached image shows the scope results that it produces.
 
=-=-=-=
 
IMPORTANT:  The SQI1RXDATA register can be treated similarly (caution:  only read from this register AFTER the required number of bytes are in the RX FIFO -- doing otherwise causes problems).  You can read only 1 or 2 bytes from the RX FIFO by using a pointer of a type that has that number of bytes in it.  Example:  UINT16 * lui16pRxReg = (UINT16 *)&SQI1RXDATA;  Reading from this pointer will read 2 bytes, and remove 2 bytes from the RX FIFO.  Similarly with a pointer representing data that is 1 byte wide.
 
ALSO IMPORTANT:  Some PIC32MZ devices have other names for the SQI1RXDATA and SQI1TXDATA registers, replacing "DATA" with "BUF".  (You might have noticed this conflict in the example code in the current SQI document.)  How to find out what the TXDATA and RXDATA registers are called for a particular PIC32MZ processor is found in both the header file for that processor, as well as in the default linker script for that processor.  Search for "SQI1TX" and you will find it.
 
ALSO IMPORTANT:  The Errata sheet gives incorrect guidance about the CMDTHR register field values.  Particularly the RXCMDTHR field ABSOLUTELY DICTATES how many bytes are received in a Receive Transaction, overriding the number of bytes presented in the Receive Transaction itself.  Only if these 2 numbers are equal (for each Receive Transaction) do you get intuitive behavior.  If the number of bytes in the traction is smaller, this is not harmful except that it still reads RXCMDTHR bytes, and leaves you with extra bytes in the Receive FIFO to clean out before the next transaction.  However, if the number of bytes in the transaction is larger, then the Chip-Select line will not be de-asserted, and the bytes over and above the RXCMDTHR number will never be received.  The Receive Transaction is aborted at this point.  To get intuitive behavior, set both values with identical number of bytes for each Receive Transaction.  (Also, it appears that a Receive Transaction will be discarded under any conflicting circumstances, including if the Receive FIFO is not completely empty when it is time to start the Receive Transaction.  Yes, I said "EMPTY".  The PIC32MZ2048ECM144 revision A5 silicon I am testing with here DISCARDS a Receive Transaction if the Receive FIFO is not empty.  These and many other important details are contained in edited PDF document described below.)
 
ALSO IMPORTANT:  There are probably around 20 other important and misleading (or omitted) things in the SQI document that I have documented for my own use.  I am guessing, based on what I have found, that a lot of customers that would LIKE to use SQI are running away from it because of the disparity between the SQI documentation and the silicon behavior.  I'm looking for an appropriate avenue to share this data in detail.  I wanted to attach the EDITED PDF file I have so far (which is going to change every day for the next week or so), but this website blocked me telling me the maximum file size for an attachment is 200 KB, and the file is around 600 KB (400 KB zipped).  So, I have made it available at a web address:
 
 
[[Well, it won't let me add a web link to it either.... Hmmm....  How do I share this....]]
Let's try this:
You put the HTTP:// in front of it, and remove spaces from the address in your browser.
crystal-clear-research.com/pic32mz_sqi_clarifications / PIC32_FRM_Section_46_Serial_Quad_Interface_%28SQI%29__60001244B__extensively_edited.pdf
 
IMPORTANT:  You will actually need to download this document and read it with ADOBE READER to see the extensive documentation I added (almost every highlight has a pop-up note behind it that does not show at all under most PDF viewers in browsers), and the "Sticky Notes" under browsers make it difficult to read.
 
You will find HIGHLIGHTS with attached pop-up notes, and "Sticky Notes" with inside this document.  I probably added another 5-6 pages worth of documentation, and it is all about PIO mode and how to make it work right and the behavior to predict.  None of it pertains (as far as I know) to DMA or XIP modes.  I will update it periodically as I make new discoveries.  I sure hope the PIC32MZ branch of Microchip gets their stuff together on this peripheral....
 
Please let me know if this was helpful to your project(s).
 
Kind regards,
V.Wheeler
 
post edited by vwheeler - 2015/05/29 21:41:33

Attached Image(s)

#1

20 Replies Related Threads

    ThomasRhoon
    Starting Member
    • Total Posts : 53
    • Reward points : 0
    • Joined: 2014/01/22 14:42:08
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/03 05:29:06 (permalink)
    0
    Amazing!!
     
    I am also spending days and hours trying to investigate issues with SQI used in DMA mode and it just doesn't behave like the average documentation in the datasheet and reference manual and alot of things are unclear...beside the examples and the harmony documentation of the SQI functions which is even more buggy.
     
    So lets dive into your lecture.
    Thanks so far!
     
     
    #2
    ThomasRhoon
    Starting Member
    • Total Posts : 53
    • Reward points : 0
    • Joined: 2014/01/22 14:42:08
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/03 05:40:31 (permalink)
    0
    I assume the same issues with a uncomplete and wrong documentation for the DMA usage of it. Lets see if i can project some of the issues also into the DMA module.
    #3
    ThomasRhoon
    Starting Member
    • Total Posts : 53
    • Reward points : 0
    • Joined: 2014/01/22 14:42:08
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/07 11:20:35 (permalink)
    0
    Ok even worse, i just found out that i always tried to get something running using the REV A reference manual of the SQI peripheral.
     
    So how do you get to the Revision B of it because if i browse on the microchip website -> 32bit MCU -> Documentation -> Reference Manual -> 46 SQI.. That leads to Revision A
    #4
    andersm
    Super Member
    • Total Posts : 2476
    • Reward points : 0
    • Joined: 2012/10/07 14:57:44
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/07 11:59:03 (permalink)
    0
    ThomasRhoonSo how do you get to the Revision B of it because if i browse on the microchip website -> 32bit MCU -> Documentation -> Reference Manual -> 46 SQI.. That leads to Revision A

    Design Support -> Reference Manuals -> search for SQI and pick the newer file.
    #5
    ThomasRhoon
    Starting Member
    • Total Posts : 53
    • Reward points : 0
    • Joined: 2014/01/22 14:42:08
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/08 05:14:50 (permalink)
    0
    Oh great!
     
    They should mark their website as 'not-up-to-date'. I guess how many developers spent hours (and so alot of money) on these kind of things... :-(
     
    Back to the topic, lets see if we can add some info for the DMA mode!
    #6
    vwheeler
    Junior Member
    • Total Posts : 21
    • Reward points : 0
    • Joined: 2011/12/21 13:51:46
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/10 15:58:51 (permalink)
    0
    Hi, Thomas!
     
    Thanks for the encouragement.  I'm going to have to dig into SQI DMA usage soon as well soon, so I look forward to hearing how your adventure goes.  I did see a comment in one other forum thread where someone stated that DMA mode worked according to documentation, and indeed, the DMA mode does seem quite a bit more thoroughly documented than PIO mode (I believe I wrote 3-4 pages worth myself for PIO mode, which you have to get through to set your external chips up for DMA mode).
     
    Did you happen to get a copy of the "edited" PDF that I put up at that web link?  ("Edited" = sticky notes and pop-up notes added wherever the PIO Mode or register data was inaccurate or incomplete or mis-named -- literally dozens of such notes.)
     
    I would concur:  most of the Microchip documentation I have seen in the last 5 years has been both clear and accurate.  I can only imaging why the SQI isn't, but either way, I sure hope they bring it up to the standards of the rest of the documentation soon.
     
    Kind regards,
    Vic
     
    #7
    vwheeler
    Junior Member
    • Total Posts : 21
    • Reward points : 0
    • Joined: 2011/12/21 13:51:46
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/10 16:02:32 (permalink)
    0
    I was one of those developers that lost days over revision "A" documentation, and already sent a documentation fix request to them about it.  I found "B" after being in COMPLETE DISBELIEF and dismay over how much was omitted from revision "A", and I went to search for an update believing it was not possible for them to ship silicon with documentation in that state (sorry if my opinion is harsh).  Revision "B" I found about 10X better, and that's what I built on.  I added my all my pop-up notes to revision "B" at the web link in the original post.
     
     
    #8
    ThomasRhoon
    Starting Member
    • Total Posts : 53
    • Reward points : 0
    • Joined: 2014/01/22 14:42:08
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/11 07:11:22 (permalink)
    0
    I read your (sticky note) PDF very well of course; there i also found out that the manual got another revision and was more detailed than the one i had.

    Your comments helped alot to understand whats going on.

    In general the DMA example in revision B works ( with some minor changings, since it includes typo's, so i assume that code is not directly tested ).

    Here are some things i found out for DMA transfers:

    - it is not clear at all if and how the SQI DMA is connected to the regular DMA. So i started of course to search for SQI stuff in the regular DMA module and it's just not in there and works different. So no chaining of SQI with other DMA events directly. One would have to use the interrupts for that. All SQI DMA settings have to be set in the SQI module. So the only relation to those DMA modules seem to be somewhere hidden inside.

    - In the case you want the ISR to be fired you would have to enable the SQI interrupt of course
    IPC42bits.SQI1IP = 5;        //Priority 5
    IPC42bits.SQI1IS = 2;        //Subpriority 2

    IFS5bits.SQI1IF = 0;        //clear Interrupt flag first
    IEC5bits.SQI1IE = 1;        //enable 'real'  sqi interrupt so it can get to the ISR
        
    And turn on the needed 'signal' bits of course:
    For example:
    SQI1INTSENbits.PKTCOMPISE = 1;        //packet complete
    SQI1INTSENbits.BDDONEISE = 1;        //buffer descriptor done
        
    Those should be set as well in the buffer descriptor itself to work ( BD_CTRLbits.BDDONEINTIEN )
        
    So when the interrupt hits caused by a finished buffer descriptor, bit SQI1INTSTATbits.BDDONEIF is being set as well as  IFS5bits.SQI1IF
    The only way i could find to clear SQI1INTSTATbits.BDDONEIF and then IFS5bits.SQI1IF again was to disable SQI1INTSENbits.BDDONEISE first which clears also SQI1INTSTATbits.BDDONEIF and then enable it again if needed. Then IFS5bits.SQI1IF can be cleared. Also neither turning off the DMA or starting a new 'burst' seem to clear the interrupt flags.
        
    In case you don't know, this is the interrupt vector: void __attribute__((vector(_SQI1_VECTOR), interrupt(IPL5AUTO), nomips16)) SQIHandler(void)
        
    - BD_CTRLbits.DIR   defines if you want to receive or transmit.
    0 = Data is transferred from a memory location specified by the Host to an internal buffer
    Means that it is a transmission
        
    1 = Data is transferred from an internal buffer to memory location specified by the Host
    Means that you want to receive
        
    I didn't find that too clear, while in the rest of the document the words transmit and receive are used.

    - BD_CTRLbits.BD_BUFLEN claims the following: "This field contains the length of the transfer buffer and is updated as the transfer progresses"
    I don't see it changing at all (and why should it, because it would manipulate your set up BD), it stays at the defined value. Does it probably mean that it can be updated while the transfer is 'busy' ?

    - SQI1BDCONbits.START
    Starts the DMA, fetching the buffer descriptor. I see different variations in the example about it is being set and cleared. In general: You need to clear it manually, probably the best right after you set it to avoid any extra latency in the ISR when clearing and setting it there again in case you want to start a new DMA transfer. After starting it, it just runs, regardless of the flag staying set of being cleared.

    - DMA timings (and maybe also for PIO Mode) are not as i expected them. That means, i expected with a burst (several bytes for 1 'transmission') all bytes would be back to back clocked out and the clock would be stable with the same pulse/pause ratio pushing the bytes out (at least inside the given specifications of 25 Mhz read and even more for write transactions). Imagine you want to send out 10 bytes in a row with the speed of 20Mhz. The clock should be toggling in 50ns/2 speed. What i see on the scope in quad mode is that after sending 1 byte ( 2 clocks, perfect pulse/pause of 50ns/2 ) it pauses for a while until it gets to the next byte. So it seem to be very busy getting the next byte into the transmit buffer which causes the timeout (or does someone got an idea how to speed that up?? ) I attached an image for that showing only the clock supposed to run in 20mhz where you see that behaviour while sending a bunch of bytes in quad lane mode using DMA.
    Unfournately thats not acceptable with my desired application :-(
        
    -SQI1BDSTAT
    I am not seeing that buffer being changed in a transfer at all ( i am transmitting only at the moment) but i think it is supposed to change with transactions, while SQI1BDTXDSTAT is changing as expected. (Manual: DMA status can be monitored through the SQI1INTSTAT,SQI1BDSTAT, SQI1BDTXDSTAT and SQI1BDRXDSTAT registers)

    Further i don't understand whats the difference between the 'Buffer Descritor Done' and the 'Packet Complete' flags. What is the difference? When i set both, both flags will fire once the buffer descriptor is done. If i only set one ( in the BD, then that one fires ). I guess you could use them when you are chaining BD's. So in each BD you set the BD Interrupt enable and in the last BD you set the packet enable. But i guess you could do that also the other way around, so they might just be 2 different sources with the same behaviour.

    Thats my investigation so far.

    Attached Image(s)

    #9
    tj256
    Senior Member
    • Total Posts : 103
    • Reward points : 0
    • Joined: 2014/10/12 21:06:01
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/18 08:11:46 (permalink)
    0
    Thanks so much for the help here. I don't know what is going on at Microchip, but with a licensed core all they have to do is make peripherals. For some reason even that escapes them. 
     
    I notice that the DMA engine doesn't clear the bits or set status in the descriptors like the Ethernet subsystem does (same kind of DMA there). So I think somehow at least for A3 the DMA engine is unable to write back into memory.
     
    I also notice that I have to turn/pulse the single descriptor on then off:
      
      SQI1BDCON = 0x00000005;
      SQI1BDCON = 0;
     
    If I leave the bit set on my system, TX sits there going forever. This goes along with my theory that it can never mark the descriptor as 'sent' so it just keeps sending it.
     
    I have DMA/TX working, but this is just getting crazy. What is going on at this company? I only see broken things from them now. 
     
    The overall experience with microchip is going down fast.
     
    post edited by tj256 - 2015/06/18 11:24:53
    #10
    tj256
    Senior Member
    • Total Posts : 103
    • Reward points : 0
    • Joined: 2014/10/12 21:06:01
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/18 11:21:40 (permalink)
    0
    How about a working TX/RX function that uses DMA? I am now reading/writing SQI data! Microchip needs to get on the ball and give us a "hack.pdf" that shows basically what I'm attaching.
     
    I only use ONE descriptor so I get interrupts when I transition from TX to RX and at packet boundries (256 bytes). But it's better than PIO mode (32 bytes)
     
    Someone earlier asked about the standard DMA module. I tried to use it at first, thinking how dumb it is to not take advantage of generic things. But it didn't work. As near as I can tell, the reason is simply that the standard DMA works only on the Peripheral bus, while the Ethernet (has it's own DMA) and SQI (also has it's own DMA) are on the higher speed bus. Now if you ask me, this is not the way to do it. Why am I going to want to force my users to spend time coding up all these DMA variants? Seems dumb. But these days, dumb is the way things are.
     
    The function I wrote last night at 2am while listening to drum and bass (see code below) is this:
     
    void FLASH_TXRX( char *pData,int nTotalBytes, int nBytesThisPacket, SQI_MODE mode, bool bTX, bool bDeAssert )


    pData - Pointer to your buffer
    nTotalBytes - Total bytes to TX or RX
    nBytesThisPacket- If set, sends this many bytes then flips TX/RX mode for the rest of the buffer
    bTX  - If set Transmits.
    bDeAssert - If set, deasserts CS at the end of transmission.
     
    I finally have communication with my FLASH chip. Why is Microchip making our lives so hard? 
     
    The silicon I have is A3 so will I break when I upgrade?  Hummm.  The good news is that I run at the full 50 mhz and it works just fine. So the lesson here is to ignore everything the datasheets tell you when you start having issues.
     
    Now for the bad part: I have "gaps" in between bytes like others have noticed. The effective transfer rate at 50 mhz clock is only 26 mbits. But you get *4 so we're over 100 mbits. The SPI is only 26 so we still win with all this pain.  The buffer thresholds seem to play a role in this issue.
     
    WARNING: I can't run in mode 3. If I run in it, I am "off" by one byte in the RX buffer. For example, if I try to get the JDEC ID , the last byte is FF. The second time around I get the last byte from the first two followed by the first two bytes. So Mode 3 is a nonstarter for me. 
     
    Another gotcha seems to happen if I point the buffer at an unaligned memory location. It starts to "mix up" the bytes in a repeatable yet annoying pattern.
     
    Now how is it legal to continue advertising speeds of 300 mbits when microchip knows this is false?
     

     
    // Straight up code to talk to the SQI.
    // NOTE: If this were Harmony, it would be 500 files and run 10x slower. (And not work)
     
    typedef enum
    {
    SQI_MODE_SINGLE, // 00 = Single Lane mode
    SQI_MODE_DUAL, // 01 = Dual Lane mode
    SQI_MODE_QUAD, // 10 = Quad Lane mode
    } SQI_MODE;
     
    #include "flash.h"
     
    #include "dma.h"

    static int g_nSQIBytesLeft = 0;

    #define FLASH_DMA_CHANNEL 0
    #define FLASH_DMA_PRIO 0
    #define FLASH_MAX_PACKET 255

    // *****************************************************************************
    // *****************************************************************************
    // Section: SQI DMA DESCRIPTORS
    // *****************************************************************************
    // *****************************************************************************

    typedef union
    {
        struct
        {
         unsigned BUFLEN : 8;
         unsigned : 8;
         unsigned BDDONEINTIEN : 1;
         unsigned PKTINTEN : 1;
         unsigned LASTPKT : 1;
         unsigned LASTBD : 1;
         unsigned DIR : 1;
         unsigned : 1;
         unsigned MODE : 2;
         unsigned : 1;
         unsigned LSBF : 1;
         unsigned : 2;
         unsigned SQICS : 2;
         unsigned DEASSERT : 1;
         unsigned DESCEN : 1;
        };
        unsigned int w;
    } BD_CTRL;


    typedef struct
    {
     BD_CTRL BDCtrl; // Buffer Descriptor Control Word
     U32 BDStat; // Buffer Descriptor Status Word - reserved
     U32 *BDAddr; // Buffer Address
     struct sqiDMADesc *pNext; // Next Buffer Descriptor Address Pointer
    } SQI_DESC;

    // Single global descriptor
    SQI_DESC g_SQIDesc;
    bool g_bDeAssert;
    bool g_bBusy;
    bool g_bSQIFlip;

    void FLASH_GlobalInitIO()
    {
     // Set up descriptor linked list (constant fields)
     SQI_DESC *pDesc = PATOKVA1(&g_SQIDesc);
     memzero( pDesc, sizeof(SQI_DESC));
     g_bDeAssert = false;
     g_bBusy = false;

     // Set clock to high speed per the errata or reset won't work.
     SQI1CLKCONbits.CLKDIV = 0; // 00000000 = Base clock TBC is divided by 2
     SQI1CLKCONbits.EN = 1;
     while( !SQI1CLKCONbits.STABLE ); // This should be quick.

     // Errata: Clear bogus ints that are enabled.
     SQI1INTSEN = SQI1INTSTAT = 0;

     // Configure SQI1CFG
     SQI1CFGbits.RESET = 1; // Reset the SQI
     SQI1CFGbits.CSEN = 3; // 11 = Chip Select 0 and Chip Select 1 are used
     SQI1CFGbits.DATAEN = 2; // 10 = SQID3-SQID0 outputs are enabled
     SQI1CFGbits.BURSTEN = 1; // They say to do this. Stupid internal thing.
     //SQI1CFGbits.SERMODE = 0; // Clock phase and polarity are controlled by the CPHA and CPOL bit settings
     SQI1CFGbits.WP = 0; // this bit is used to drive the SQID2 signal in single/dual mode
     SQI1CFGbits.HOLD = 0; // this bit is used to drive the SQID3 signal in single/dual mode
     SQI1CFGbits.RXLATCH = 0; // RX Data sent to receive buffer when CMDINIT<1:0> (SQI1CON<17:16>) is set to TX
     SQI1CFGbits.LSBF = 0; // MSB is sent or received first
     SQI1CFGbits.MODE = 2; // DMA mode is selected

     // "MODE 0" (Mode 3 seems to lag by 1 bit in the RX buffer)
     SQI1CFGbits.CPHA = 0; // SQICLK starts toggling at the start of the first data bit
     SQI1CFGbits.CPOL = 0; // Active-low SQICLK (SQICLK high is the Idle state)

     // Configure SQI1CON
     SQI1CONbits.DASSERT = 1; // Chip Select is deasserted after transmission or reception of the specified number of bytes
     SQI1CONbits.DEVSEL = 1; // Select Device 1
     // SQI1CONbits.LANEMODE = 2; // Quad Lane mode
     SQI1CONbits.LANEMODE = 0; // 00 = Single Lane mode

     // Configure SQI1CMDTHR. -- ERRATA SAYS * OF 4!
     SQI1INTTHRbits.TXINTTHR = 0x04;
     SQI1INTTHRbits.RXINTTHR = 0x18;

     // Interrupt flags
     SQI1BDPOLLCON = 0;
     IPC42bits.SQI1IP = 2;
     IPC42bits.SQI1IS = 1;

     SQI1INTSEN = 0;
     SQI1INTSENbits.BDDONEISE = 1; //buffer descriptor done
     SQI1INTEN = 0;
     SQI1INTENbits.BDDONEIE = 1;

     SQI1BDBASEADDR = (U32) KVATOPA(&g_SQIDesc); // descriptor address

     SQI1CFGbits.SQIEN = 1; // This must be done AFTER setup or it just doesn't work.
    }

    void FLASH_GlobalInit()
    {
     FLASH_GlobalInitIO();

    // Do a reset on our flash chip:
    int i;
    char rst_qio[] = {0xFF};
    char res_en[] = { 0x66, 0x99 };
    char jdec_id[] = { 0x9F };
    char eqio[] = { 0x38 };
    char quad_jid[] = { 0xAF };
    char ALIGNED(4) rxbuffer[16];   // Buffer MUST be aligned! Or bytes are swizzled by Microchip to spite you.
     
    // Reset - Enable sequence. CS must drop in between.
    FLASH_TXRX( &rst_qio[0], NULL, 1, 0, SQI_MODE_QUAD, true, true ); // FF
    FLASH_TXRX( &res_en[0], NULL, 1, 0, SQI_MODE_SINGLE, true, true ); // 66
    FLASH_TXRX( &res_en[1], NULL, 1, 0, SQI_MODE_SINGLE, true, true ); // 99

    FLASH_TXRX( jdec_id, rxbuffer, 4, 1, SQI_MODE_SINGLE, true, true ); // JDEC-ID Read



    void FLASH_TXRX( char *pData,int nTotalBytes, int nBytesThisPacket, SQI_MODE mode, bool bTX, bool bDeAssert )
    {
     int i;

     FLASH_Wait();

     g_bSQIFlip = (nBytesThisPacket>0);
     if(!nBytesThisPacket)
      nBytesThisPacket = MIN(FLASH_MAX_PACKET,nTotalBytes);
     g_nSQIBytesLeft = nTotalBytes - nBytesThisPacket;
     g_bDeAssert = bDeAssert;
     g_bBusy = true;


     if(bTX)
      SYSTEM_DataLineFlushBuffer( pData, nTotalBytes); // Cache coherency

     SQI_DESC *pDesc = PATOKVA1(&g_SQIDesc);
     pDesc->BDCtrl.DEASSERT = g_bDeAssert && (g_nSQIBytesLeft == 0);
     pDesc->BDCtrl.SQICS = 1;
     pDesc->BDCtrl.DESCEN = 1;
     pDesc->BDCtrl.DIR = bTX?0:1; // TX = 0 , RX= 1
     pDesc->BDCtrl.BUFLEN = nBytesThisPacket;
     pDesc->BDAddr = KVATOPA(pData);
     pDesc->BDStat = 0;
     pDesc->BDCtrl.MODE = mode;
     pDesc->BDCtrl.LASTPKT = 1;
     pDesc->BDCtrl.LASTBD = 1;
     pDesc->BDCtrl.BDDONEINTIEN = 1;

     //
     IFS5bits.SQI1IF = 0; // clear Interrupt flag first
     IEC5bits.SQI1IE = 1; // enable 'real' sqi interrupt

     // Enable and start DMA process.
     // Pulse the dma start. Can't leave it on or it runs continuous.

     DISABLE_INTS
     SQI1BDCON = 0x00000005;
     SQI1BDCON = 0;
     RESTORE_INTS
    }

    void FLASH_Wait()
    {
     while(g_bBusy);
    }

    // Do next 256 byte "packet"
    void _FLASHInterruptHandler(void)
    {
     //SQI1CONbits.DASSERT=0;
     SQI1INTSENbits.BDDONEISE = 0;
     SQI1INTENbits.BDDONEIE = 0;
     SQI1INTSENbits.BDDONEISE = 1; // Clear SQI1INTSTATbits.BDDONEIF. Can't do it directly.
     SQI1INTENbits.BDDONEIE = 1;
     IFS5bits.SQI1IF = 0;

     SQI_DESC *pDesc = PATOKVA1(&g_SQIDesc);
     if(pDesc->BDCtrl.DIR)
      SYSTEM_DataLineInvalidateBuffer( PATOKVA0(pDesc->BDAddr), pDesc->BDCtrl.BUFLEN); // Cache coherency


     if( g_nSQIBytesLeft )
     {
      int nBytesThisPacket = MIN(FLASH_MAX_PACKET,g_nSQIBytesLeft);
      g_nSQIBytesLeft -= nBytesThisPacket;
      pDesc->BDCtrl.DEASSERT = g_bDeAssert && (g_nSQIBytesLeft == 0);
      U32 *pNewAddr = (U32*) PTR_ADD(pDesc->BDAddr,pDesc->BDCtrl.BUFLEN);
      pDesc->BDAddr = pNewAddr;
      pDesc->BDCtrl.BUFLEN = nBytesThisPacket;
      if(g_bSQIFlip) pDesc->BDCtrl.DIR ^= 1;
      DISABLE_INTS
      SQI1BDCON = 0x00000005;
      SQI1BDCON = 0;
      RESTORE_INTS
     }
     g_bBusy = (g_nSQIBytesLeft > 0);

    }


    post edited by tj256 - 2015/06/18 16:08:20
    #11
    ThomasRhoon
    Starting Member
    • Total Posts : 53
    • Reward points : 0
    • Joined: 2014/01/22 14:42:08
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/19 03:36:19 (permalink)
    0
    Revision A5 is also not updating the buffer descriptor. I guess it makes little difference then. I thought SQI with A3 was broken anyway??
     
    The gaps are a no-go for me so i dropped using SQI for my application for now cause i don't expect the helping 'finetune'-bit to solve the GAP problem. Spent too much time on it anyway and the project must go on.
     
    #12
    tj256
    Senior Member
    • Total Posts : 103
    • Reward points : 0
    • Joined: 2014/10/12 21:06:01
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/19 04:43:25 (permalink)
    4 (2)
    According to the newer errata A3 can work with their proposed workarounds, but even those seem to be inadequate. The big question for me is this: Why does the errata not mention the inability of the hardware to update the descriptors? you would notice this if you tried to use the system at all. Which brings me back to the question "What is going on at Microchip?"
     
    I'm 90% working now-- I hear you on "too much time". This has been an exercise in frustration for sure. It seems there are still issues with the RX buffer collecting junk on occasion, with no real reason apparent. 
     
    I may wind up aborting this effort, but my design requires a high bandwidth serial stream. This is worrying.
    post edited by tj256 - 2015/06/19 04:51:23
    #13
    vwheeler
    Junior Member
    • Total Posts : 21
    • Reward points : 0
    • Joined: 2011/12/21 13:51:46
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/19 14:22:04 (permalink)
    0
    Hi, Thomas!
     
    This is excellent info!  Thank you!  Especially turning off the IF bits -- I bet that was hard to find!
     
    Kind regards,
    Vic
    #14
    tj256
    Senior Member
    • Total Posts : 103
    • Reward points : 0
    • Joined: 2014/10/12 21:06:01
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/06/21 09:10:29 (permalink)
    0
    Let us know if you get DMA with SQI working. I spent a good deal of time on it and have concluded that even with workarounds it is unreliable. There may be a magical set of things to do to get some basic functionality but thus far I can't seem to get reliable RX. 
     
    I know Harmony has some samples, however these are very specific use cases. While these work, I try to do my own basic read/write operations I start to run into trouble.
    #15
    WhyLee
    New Member
    • Total Posts : 11
    • Reward points : 0
    • Joined: 2014/05/12 07:52:09
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/07/06 07:50:27 (permalink)
    0
    Thanks for the hint that also with int8_t or int16_t pointer can be written into the registers. when i have time i'll change my old 4-byte-aligned code.
    now for me it is working stable (rev. a5) and code is fast enough. when i want to speed up the spi-bus to the speed that was originally intended the transfer crashed anyway. so i do not necessarily to switch to dma-mode if i can not speed up the bus transfer speed. microchip is also not willing to fix that.
    maybe in the new 'EF' version of the chip that could be fixed. but we didn't get samples of the new chip that sould be out there since may 2015 (at least for a few costumers).
    #16
    jgvicke
    Super Member
    • Total Posts : 458
    • Reward points : 0
    • Joined: 2010/09/28 20:18:24
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/08/28 21:19:43 (permalink)
    0
    I am trying to get SQI up and running on the new EF starter kit. The demo of the code works, but of course their function reference a static location in memory for their read write buffers, and my attempt at converting to take a pointer to a buffer location is not working.
     
    Does anyone have a library working that they could share? Any help would be appreciated!
     
    Thanks,
    John Vickers

    PIC32 Helpful Tools I have made:
    https://rebrand.ly/PIC32MZ144PinMapping
    https://rebrand.ly/PIC32MX100PinMapping

    Feel free to email me if you have any suggestions for any of these tools.
    #17
    Joeyg
    New Member
    • Total Posts : 12
    • Reward points : 0
    • Joined: 2010/11/28 17:05:21
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/09/03 19:03:33 (permalink)
    0
    Which  PIC32MZ?
     
    PIC32MZxxxECxxx  die rev  A5   or  PIC32MZxxxEFxxx die rev A1
     
    Regards
    Joe
    #18
    jgvicke
    Super Member
    • Total Posts : 458
    • Reward points : 0
    • Joined: 2010/09/28 20:18:24
    • Location: 0
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2015/09/03 20:02:41 (permalink)
    0
    I actually got some code working. I am still tweaking it to do what I want, but it is functional. This post was incredibly helpful:
     
    http://www.microchip.com/forums/m871110.aspx
     
    I am working on the PIC32MZ2048EFM144 chips.
     
    John Vickers

    PIC32 Helpful Tools I have made:
    https://rebrand.ly/PIC32MZ144PinMapping
    https://rebrand.ly/PIC32MX100PinMapping

    Feel free to email me if you have any suggestions for any of these tools.
    #19
    adam.glowacki
    New Member
    • Total Posts : 11
    • Reward points : 0
    • Joined: 2016/08/02 06:31:45
    • Location: Poland
    • Status: offline
    Re: Answer to PIC32MZ Problem with SQI in PIO-Mode and working solution 2018/11/08 06:19:05 (permalink)
    0
    Great thread. But let me add a small hint for those who would like to work in PIO mode. When you define a pointer to the SQI1TXDATA or SQI1RXDATA, make sure to declare them 'volatile' (NOT as in the original post). I forgot about it when defining a 8bit pointer to SQI1RXDATA. And I spent a whole day trying out to figure out why 5 bytes disappear from FIFO while my application apparently reads only 4 ;-) I know, it seems obvious. Nonetheless, I totally forgot. So I would suggest to edit the original post so that less experienced people (like me) would not run into trouble :-)

    #20
    Page: 12 > Showing page 1 of 2
    Jump to:
    © 2018 APG vNext Commercial Version 4.5