I am seeing data corruption when using the imx6ull qspi peripheral. I have put prints in after filling the TX FIFO and the prints show the data going into the FIFO is correct but it comes out of the chip onto the qspi bus wrong. Here is an example, the bold data is incorrect (this is a baremetal project):
FC 4F 02 00 FD 4F 02 00 FE 4F 02 00 FF 4F 02 00
00 50 02 00 01 50 02 00 02 50 02 00 03 50 02 00
04 50 02 00 05 50 02 00 06 50 02 00 07 50 02 00
08 50 02 00 09 50 02 00 0A 50 02 00 0B 50 02 00
0C 50 02 00 0D 50 02 00 0E 50 02 00 0F 50 02 00
10 50 02 00 11 50 02 00 12 50 02 00 13 50 02 00
14 50 02 00 15 50 02 00 16 50 02 00 17 50 02 00
18 50 02 00 19 50 02 00 1A 50 02 00 1B 50 02 00
1C 50 02 00 1D 50 02 00 1E 50 02 00 1F 50 02 00
20 50 02 00 21 50 02 00 22 50 02 00 23 50 02 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
40 50 02 00 41 50 02 00 42 50 02 00 43 50 02 00
44 50 02 00 45 50 02 00 46 50 02 00 47 50 02 00
48 50 02 00 49 50 02 00 4A 50 02 00 4B 50 02 00
4C 50 02 00 4D 50 02 00 4E 50 02 00 4F 50 02 00
50 50 02 00 51 50 02 00 52 50 02 00 53 50 02 00
54 50 02 00 55 50 02 00 56 50 02 00 57 50 02 00
58 50 02 00 59 50 02 00 5A 50 02 00 5B 50 02 00
5C 50 02 00 5D 50 02 00 5E 50 02 00 5F 50 02 00
It should have been this:
24 50 02 00 25 50 02 00 26 50 02 00 27 50 02 00
28 50 02 00 29 50 02 00 2A 50 02 00 2B 50 02 00
2C 50 02 00 2D 50 02 00 2E 50 02 00 2F 50 02 00
30 50 02 00 31 50 02 00 32 50 02 00 33 50 02 00
34 50 02 00 35 50 02 00 36 50 02 00 37 50 02 00
38 50 02 00 39 50 02 00 3A 50 02 00 3B 50 02 00
3C 50 02 00 3D 50 02 00 3E 50 02 00 3F 50 02 00
Here is my code to write to the qspi peripheral:
void QSPI_Write(QuadSPI_Type *base, uint32_t *buffer, size_t size)
{
uint32_t i = 0;
for (i = 0; i < size / 4U; i++)
{
/* Check if the buffer is full */
while (QuadSPI->SR & QuadSPI_SR_TXFULL_MASK)
{
}
base->TBDR = *buffer;
buffer++;
}
}
void programQspiFlash(uint32_t addr, uint32_t *src_addr)
{
while (QuadSPI->SR & QuadSPI_SR_BUSY_MASK)
{
}
// clear FIFO
QuadSPI->MCR |= QuadSPI_MCR_CLR_TXF_MASK;
// Set IP Command Address
QuadSPI->SFAR = addr;
// cmd write enable
while (QuadSPI->SR & QuadSPI_SR_BUSY_MASK & QuadSPI_SR_BUSY_MASK)
{
}
while (QuadSPI->SR & QuadSPI_SR_BUSY_MASK & (QuadSPI_SR_BUSY_MASK | QuadSPI_SR_IP_ACC_MASK))
{
}
QuadSPI->SPTRCLR = QuadSPI_SPTRCLR_IPPTRC_MASK;
// Write the seqid bit
QuadSPI->IPCR = ((QuadSPI->IPCR & (~QuadSPI_IPCR_SEQID_MASK)) | QuadSPI_IPCR_SEQID(1));
// end cmd write enable
while (QuadSPI->SR & QuadSPI_SR_BUSY_MASK)
{
}
QuadSPI->SPTRCLR = QuadSPI_SPTRCLR_IPPTRC_MASK;
// First write some data into TXFIFO to prevent from under run
QSPI_Write(QuadSPI, src_addr, 128);
src_addr += 32;
// Start the program
QuadSPI->IPCR = ((QuadSPI->IPCR & (~QuadSPI_IPCR_IDATSZ_MASK)) | QuadSPI_IPCR_IDATSZ(FLASH_PAGE_SIZE));
while (QuadSPI->SR & (QuadSPI_SR_BUSY_MASK | QuadSPI_SR_IP_ACC_MASK))
{
}
QuadSPI->SPTRCLR = QuadSPI_SPTRCLR_IPPTRC_MASK;
// Write the seqid bit
QuadSPI->IPCR = ((QuadSPI->IPCR & (~QuadSPI_IPCR_SEQID_MASK)) | QuadSPI_IPCR_SEQID(4U));
QSPI_Write(QuadSPI, src_addr, 128);
src_addr += 32;
// Wait until flash finished program
uint32_t val = 0;
do
{
while (QuadSPI->SR & QuadSPI_SR_BUSY_MASK)
{
}
// Clear FIFO
QuadSPI->MCR |= QuadSPI_MCR_CLR_RXF_MASK;
// Clear command sequence.
QuadSPI->SPTRCLR = QuadSPI_SPTRCLR_IPPTRC_MASK;
// Write the seqid bit
QuadSPI->IPCR = ((QuadSPI->IPCR & (~QuadSPI_IPCR_SEQID_MASK)) | QuadSPI_IPCR_SEQID(3U));
while (QuadSPI->SR & QuadSPI_SR_BUSY_MASK)
{
}
val = *(volatile uint32_t *)(FSL_FEATURE_QSPI_ARDB_BASE);
// Clear ARDB area
QuadSPI->FR = QuadSPI_FR_RBDF_MASK;
} while (val & 0x1);
while (QuadSPI->SR & (QuadSPI_SR_BUSY_MASK | QuadSPI_SR_IP_ACC_MASK))
{
}
// Do a software reset of the qspi peripheral
// Reset AHB domain and buffer domian
QuadSPI->MCR |= (QuadSPI_MCR_SWRSTHD_MASK | QuadSPI_MCR_SWRSTSD_MASK);
// Wait for the reset to finish
int i = 0;
for (i = 0; i < 100; i++)
{
__ASM("nop");
}
// Disable QSPI module
QuadSPI->MCR |= QuadSPI_MCR_MDIS_MASK;
// Clear the reset flags
QuadSPI->MCR &= ~(QuadSPI_MCR_SWRSTHD_MASK | QuadSPI_MCR_SWRSTSD_MASK);
// Enable QSPI module
QuadSPI->MCR &= ~QuadSPI_MCR_MDIS_MASK;
}
I am at a loss to explain the data corruption, has anyone seen this before or have any ideas to the issue?
Solved! Go to Solution.
If I disable all interrupts before programming the flash I never see any corruption. Is it recommended to disable interrupts before programming qspi with the imx6ull? I haven't found anything in the reference manual to that effect but somehow interrupts are causing corruption in my application.
If I disable all interrupts before programming the flash I never see any corruption. Is it recommended to disable interrupts before programming qspi with the imx6ull? I haven't found anything in the reference manual to that effect but somehow interrupts are causing corruption in my application.
inrerrupts may affect timings, as processor spends some time processing them.
In general qspi with interrupts working fine in nxp linux bsps on
linux-imx - i.MX Linux kernel
Linux Documentation
i.MX Software | NXP
Best regards
igor
Hi Kevin
data corruption can be caused by timings and signal noise, one can check them
with oscilloscope, use that qspi datasheet timings and sect.4.12.10 QUAD SPI (QSPI) Timing
Parameters i.MX6ULL Datasheet
https://www.nxp.com/docs/en/data-sheet/IMX6ULLCEC.pdf
Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------