Jan 23, 2020
02:58 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 23, 2020
02:58 PM
I'm trying to use the QSPI with DMA, and as usual, the IfxQspi and IfxDMA libraries are extremely buggy.
I have fixed all the bugs I have found so far, and this is the current situation:
o QSPI triggers DMA to fill the TXFIFO and drain the RXFIFO
o DMA reads the transmit data and writes the receive data to the correct addresses
o DMA generates an end-of-transfer service request when TCOUNT = 0.
o Verified by checking DMA_CHCSR001.ICH = 1.
o The interrupt router is ignoring the request and does not generate an interrupt
o The service request is reaching the IR, because I can see SRC_DMACH1.SRR = 1
o The interrupt is winning arbitration, because INT_LWSR0.PN = 0x3d, and DMA1 is using interrupt 61
I'm trying to understand why the interrupt handler isn't being called even though the interrupt is winning arbitration?
What registers should I check?
Toshi
I have fixed all the bugs I have found so far, and this is the current situation:
o QSPI triggers DMA to fill the TXFIFO and drain the RXFIFO
o DMA reads the transmit data and writes the receive data to the correct addresses
o DMA generates an end-of-transfer service request when TCOUNT = 0.
o Verified by checking DMA_CHCSR001.ICH = 1.
o The interrupt router is ignoring the request and does not generate an interrupt
o The service request is reaching the IR, because I can see SRC_DMACH1.SRR = 1
o The interrupt is winning arbitration, because INT_LWSR0.PN = 0x3d, and DMA1 is using interrupt 61
I'm trying to understand why the interrupt handler isn't being called even though the interrupt is winning arbitration?
What registers should I check?
Toshi
- Tags:
- IFX
12 Replies
Jan 23, 2020
08:05 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 23, 2020
08:05 PM
It looks like CPU0 is failing to acknowledge the service request, because INT_LASR0.ID != INT_LWSR0.PN.
From what I understand, the only reason this should occur is because the ECC is wrong.
However, I don't think I have control over the generated ECC.
Toshi
From what I understand, the only reason this should occur is because the ECC is wrong.
However, I don't think I have control over the generated ECC.
Toshi
Jan 24, 2020
03:52 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 24, 2020
03:52 AM
Are interrupts enabled on the CPU? Check ICR.IE - interrupts are disabled by default.
Jan 24, 2020
01:55 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 24, 2020
01:55 PM
UC_wrangler wrote:
Are interrupts enabled on the CPU? Check ICR.IE - interrupts are disabled by default.
I just checked...ICR.IE is zero!
Don't know how it was reset, but now I have a lead!
Thanks for the help!
Toshi
Jan 24, 2020
06:32 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 24, 2020
06:32 PM
I found iLLD QSPI DMA transfers for length = 1 at 400 khz were broken.
I fixed it.
I found iLLD QSPI DMA transfers for length = 2 at 400 khz were broken.
I fixed that too.
Now I find iLLD QSPI DMA transfers for length = 6 at 400 khz are broken.
This iLLD QSPI driver redefines the word "broken" and takes it to the next level.
I fixed it.
I found iLLD QSPI DMA transfers for length = 2 at 400 khz were broken.
I fixed that too.
Now I find iLLD QSPI DMA transfers for length = 6 at 400 khz are broken.
This iLLD QSPI driver redefines the word "broken" and takes it to the next level.
Jan 24, 2020
07:16 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 24, 2020
07:16 PM
I don't know what mode you are using the QSPI in. Previously you stated you needed it to be variable based on the data received in the same frame. This requires you to use software to control the chip select.
If you simply need to have 8-bit data moves of variable lengths using two DMA channels. Here is a simple bare metal example.
You simply need to re-initialize the data pointers and the TREL to the size you want for another exchange.
If you simply need to have 8-bit data moves of variable lengths using two DMA channels. Here is a simple bare metal example.
You simply need to re-initialize the data pointers and the TREL to the size you want for another exchange.
void DMA_QSPI3_Init(uint16_t trel){
/* DMA Channel 005 used for QSPI3 Transmit */
DMA_SADR005.U = (uint32_t)&txData[0];
DMA_DADR005.U = (uint32_t)&QSPI3_DATAENTRY0.U;
Ifx_DMA_CH_CHCFGR chcfgr_5 = {
.B.TREL = trel, /*Transfer Reload Value */
.B.BLKM = dma_chcfgrxxx_blkm_OneTransferHasOneMove,
.B.RROAT = dma_chcfgrxxx_rroat_ResetAfterEachTransfer,
.B.CHMODE = dma_chcfgrxxx_chmode_SingleMode,
.B.CHDW = dma_chcfgrxxx_chdw_DataBitWidth_8,
.B.PATSEL = dma_chcfgrxxx_patsel_NoPatternCompareOperation,
.B.PRSEL = dma_chcfgrxxx_prsel_HardwareRequestSelected,
.B.DMAPRIO = dma_chcfgrxxx_dmaprio_LowPrioritySelected,
};
DMA_CHCFGR005.U = chcfgr_5.U;
Ifx_DMA_CH_ADICR adicr_5 = {
.B.SMF = dma_adicrxxx_smf_AddressOffsetIsCHDWx1,
.B.INCS = dma_adicrxxx_incs_AddressOffsetIsAdded,
.B.DMF = dma_adicrxxx_dmf_AddressOffsetIsCHDWx1,
.B.INCD = dma_adicrxxx_incd_AddressOffsetIsSubtracted,
.B.CBLS = dma_adicrxxx_cbls_SourceAddress31to0,
.B.CBLD = dma_adicrxxx_cbld_DestinationAddress31to0,
.B.SHCT = dma_adicrxxx_shct_MoveOperation,
.B.SCBE = dma_adicrxxx_scbe_SourceCircularBufferDisabled,
.B.DCBE = dma_adicrxxx_dcbe_DestinationCircularBufferEnabled,
.B.STAMP = dma_adicrxxx_stamp_NoAction,
.B.ETRL = dma_adicrxxx_etrl_NoInterruptOnLostEvent,
.B.WRPSE = dma_adicrxxx_wrpse_WrapSourceBufferInterruptTriggerDiabled,
.B.WRPDE = dma_adicrxxx_wrpde_WrapDestinationBufferInterruptTriggerDiabled,
.B.INTCT = dma_adicrxxx_intct_InterruptChangingTCOUNTandEqualsIRDV,
.B.IRDV = 0, /*Interrupt Raise Detect Value*/
};
DMA_ADICR005.U = adicr_5.U;
DMA_TSR005.B.ECH = 1;
/* DMA Channel 006: used for QSPI3 Receive */
DMA_SADR006.U = (uint32_t)&QSPI3_RXEXIT.U;
DMA_DADR006.U = (uint32_t)&rxData[0];
Ifx_DMA_CH_CHCFGR chcfgr_6 = {
.B.TREL = trel, /*Transfer Reload Value */
.B.BLKM = dma_chcfgrxxx_blkm_OneTransferHasOneMove,
.B.RROAT = dma_chcfgrxxx_rroat_ResetAfterEachTransfer,
.B.CHMODE = dma_chcfgrxxx_chmode_SingleMode,
.B.CHDW = dma_chcfgrxxx_chdw_DataBitWidth_8,
.B.PATSEL = dma_chcfgrxxx_patsel_NoPatternCompareOperation,
.B.PRSEL = dma_chcfgrxxx_prsel_HardwareRequestSelected,
.B.DMAPRIO = dma_chcfgrxxx_dmaprio_LowPrioritySelected,
};
DMA_CHCFGR006.U = chcfgr_6.U;
Ifx_DMA_CH_ADICR adicr_6 = {
.B.SMF = dma_adicrxxx_smf_AddressOffsetIsCHDWx1,
.B.INCS = dma_adicrxxx_incs_AddressOffsetIsSubtracted,
.B.DMF = dma_adicrxxx_dmf_AddressOffsetIsCHDWx1,
.B.INCD = dma_adicrxxx_incd_AddressOffsetIsAdded,
.B.CBLS = dma_adicrxxx_cbls_SourceAddress31to0,
.B.CBLD = dma_adicrxxx_cbld_DestinationAddress31to0,
.B.SHCT = dma_adicrxxx_shct_MoveOperation,
.B.SCBE = dma_adicrxxx_scbe_SourceCircularBufferEnabled,
.B.DCBE = dma_adicrxxx_dcbe_DestinationCircularBufferDisabled,
.B.STAMP = dma_adicrxxx_stamp_NoAction,
.B.ETRL = dma_adicrxxx_etrl_NoInterruptOnLostEvent,
.B.WRPSE = dma_adicrxxx_wrpse_WrapSourceBufferInterruptTriggerDiabled,
.B.WRPDE = dma_adicrxxx_wrpde_WrapDestinationBufferInterruptTriggerDiabled,
.B.INTCT =dma_adicrxxx_intct_InterruptChangingTCOUNTandEqualsIRDV,
.B.IRDV = 0, /*Interrupt Raise Detect Value*/
};
DMA_ADICR006.U = adicr_6.U;
DMA_TSR006.B.ECH = 1;
/* Setup interrupt from DMA Channel 5 and 6 when the Move Transaction has finished */
SRC_DMACH5.U = (CPU0_SERVICE << TOS) | (1 << SRE) | INTPRIO_DMA_CH5;
SRC_DMACH6.U = (CPU0_SERVICE << TOS) | (1 << SRE) | INTPRIO_DMA_CH6;
}
Jan 26, 2020
02:28 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 26, 2020
02:28 PM
cwunder wrote:
I don't know what mode you are using the QSPI in. Previously you stated you needed it to be variable based on the data received in the same frame. This requires you to use software to control the chip select.
If you simply need to have 8-bit data moves of variable lengths using two DMA channels. Here is a simple bare metal example.
You simply need to re-initialize the data pointers and the TREL to the size you want for another exchange.void DMA_QSPI3_Init(uint16_t trel){
/* DMA Channel 005 used for QSPI3 Transmit */
DMA_SADR005.U = (uint32_t)&txData[0];
DMA_DADR005.U = (uint32_t)&QSPI3_DATAENTRY0.U;
Ifx_DMA_CH_CHCFGR chcfgr_5 = {
.B.TREL = trel, /*Transfer Reload Value */
.B.BLKM = dma_chcfgrxxx_blkm_OneTransferHasOneMove,
.B.RROAT = dma_chcfgrxxx_rroat_ResetAfterEachTransfer,
.B.CHMODE = dma_chcfgrxxx_chmode_SingleMode,
.B.CHDW = dma_chcfgrxxx_chdw_DataBitWidth_8,
.B.PATSEL = dma_chcfgrxxx_patsel_NoPatternCompareOperation,
.B.PRSEL = dma_chcfgrxxx_prsel_HardwareRequestSelected,
.B.DMAPRIO = dma_chcfgrxxx_dmaprio_LowPrioritySelected,
};
DMA_CHCFGR005.U = chcfgr_5.U;
Ifx_DMA_CH_ADICR adicr_5 = {
.B.SMF = dma_adicrxxx_smf_AddressOffsetIsCHDWx1,
.B.INCS = dma_adicrxxx_incs_AddressOffsetIsAdded,
.B.DMF = dma_adicrxxx_dmf_AddressOffsetIsCHDWx1,
.B.INCD = dma_adicrxxx_incd_AddressOffsetIsSubtracted,
.B.CBLS = dma_adicrxxx_cbls_SourceAddress31to0,
.B.CBLD = dma_adicrxxx_cbld_DestinationAddress31to0,
.B.SHCT = dma_adicrxxx_shct_MoveOperation,
.B.SCBE = dma_adicrxxx_scbe_SourceCircularBufferDisabled,
.B.DCBE = dma_adicrxxx_dcbe_DestinationCircularBufferEnabled,
.B.STAMP = dma_adicrxxx_stamp_NoAction,
.B.ETRL = dma_adicrxxx_etrl_NoInterruptOnLostEvent,
.B.WRPSE = dma_adicrxxx_wrpse_WrapSourceBufferInterruptTriggerDiabled,
.B.WRPDE = dma_adicrxxx_wrpde_WrapDestinationBufferInterruptTriggerDiabled,
.B.INTCT = dma_adicrxxx_intct_InterruptChangingTCOUNTandEqualsIRDV,
.B.IRDV = 0, /*Interrupt Raise Detect Value*/
};
DMA_ADICR005.U = adicr_5.U;
DMA_TSR005.B.ECH = 1;
/* DMA Channel 006: used for QSPI3 Receive */
DMA_SADR006.U = (uint32_t)&QSPI3_RXEXIT.U;
DMA_DADR006.U = (uint32_t)&rxData[0];
Ifx_DMA_CH_CHCFGR chcfgr_6 = {
.B.TREL = trel, /*Transfer Reload Value */
.B.BLKM = dma_chcfgrxxx_blkm_OneTransferHasOneMove,
.B.RROAT = dma_chcfgrxxx_rroat_ResetAfterEachTransfer,
.B.CHMODE = dma_chcfgrxxx_chmode_SingleMode,
.B.CHDW = dma_chcfgrxxx_chdw_DataBitWidth_8,
.B.PATSEL = dma_chcfgrxxx_patsel_NoPatternCompareOperation,
.B.PRSEL = dma_chcfgrxxx_prsel_HardwareRequestSelected,
.B.DMAPRIO = dma_chcfgrxxx_dmaprio_LowPrioritySelected,
};
DMA_CHCFGR006.U = chcfgr_6.U;
Ifx_DMA_CH_ADICR adicr_6 = {
.B.SMF = dma_adicrxxx_smf_AddressOffsetIsCHDWx1,
.B.INCS = dma_adicrxxx_incs_AddressOffsetIsSubtracted,
.B.DMF = dma_adicrxxx_dmf_AddressOffsetIsCHDWx1,
.B.INCD = dma_adicrxxx_incd_AddressOffsetIsAdded,
.B.CBLS = dma_adicrxxx_cbls_SourceAddress31to0,
.B.CBLD = dma_adicrxxx_cbld_DestinationAddress31to0,
.B.SHCT = dma_adicrxxx_shct_MoveOperation,
.B.SCBE = dma_adicrxxx_scbe_SourceCircularBufferEnabled,
.B.DCBE = dma_adicrxxx_dcbe_DestinationCircularBufferDisabled,
.B.STAMP = dma_adicrxxx_stamp_NoAction,
.B.ETRL = dma_adicrxxx_etrl_NoInterruptOnLostEvent,
.B.WRPSE = dma_adicrxxx_wrpse_WrapSourceBufferInterruptTriggerDiabled,
.B.WRPDE = dma_adicrxxx_wrpde_WrapDestinationBufferInterruptTriggerDiabled,
.B.INTCT =dma_adicrxxx_intct_InterruptChangingTCOUNTandEqualsIRDV,
.B.IRDV = 0, /*Interrupt Raise Detect Value*/
};
DMA_ADICR006.U = adicr_6.U;
DMA_TSR006.B.ECH = 1;
/* Setup interrupt from DMA Channel 5 and 6 when the Move Transaction has finished */
SRC_DMACH5.U = (CPU0_SERVICE << TOS) | (1 << SRE) | INTPRIO_DMA_CH5;
SRC_DMACH6.U = (CPU0_SERVICE << TOS) | (1 << SRE) | INTPRIO_DMA_CH6;
}
I think it would be too much work to rewrite the whole QSPI module.
I'm planning on rewriting only IfxQspi_SpiMaster_write() since this is the worst code in the whole module, and the source of most of the problems.
Thanks for the help, though.
Toshi
Jan 27, 2020
03:32 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 27, 2020
03:32 PM
I've rewritten IfxQspi_SpiMaster_write() and running in to a problem.
The test code tries to send one byte via SPI DMA.
It loads the BACON into qspiSFR->BACONENTRY.U before triggering the DMA.
However, as soon as it loads the BACON, the SPI sends a byte, which I don't think it should do.
What am I missing?
Toshi
The test code tries to send one byte via SPI DMA.
It loads the BACON into qspiSFR->BACONENTRY.U before triggering the DMA.
However, as soon as it loads the BACON, the SPI sends a byte, which I don't think it should do.
What am I missing?
Toshi
Jan 27, 2020
04:09 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 27, 2020
04:09 PM
Ah, never mind.
The DMA is starting as soon as the BACON is pulled from the TXFIFO.
The DMA is starting as soon as the BACON is pulled from the TXFIFO.
Jan 29, 2020
11:54 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 29, 2020
11:54 AM
From what I can tell, there is an endianness incompatibility problem between the QSPI and DMA modules.
There is a QSPI feature ECON.BE that tries to "swap endianness" of the incoming data, but it appears to be broken.
Here's an example:
Given the byte stream 0x00 0x01 0x02 0x03 loaded via 32-bit DMA into the TXFIFO:
o ECON.BE = 0 (with BACON.BYTE = 0) will transmit:
32 bits: 0x03 0x02 0x01 0x00
24 bits: 0x02 0x01 0x00
16 bits: 0x01 0x00
8 bits: 0x00
o ECON.BE = 1 (with BACON.BYTE = 0) will transmit:
32 bits: 0x02 0x03 0x00 0x01
24 bits: 0x00 0x00 0x01
16 bits: 0x00 0x01
8 bits: 0x00
o ECON.BE = 2 (with BACON.BYTE = 0) will transmit:
32 bits: 0x00 0x01 0x02 0x03
24 bits: 0x01 0x02 0x00
16 bits: 0x00 0x00
8 bits: 0x00
None of the valid ECON.BE settings will send 24 bits as 0x00 0x01 0x02.
Anyone else notice this problem?
Toshi
There is a QSPI feature ECON.BE that tries to "swap endianness" of the incoming data, but it appears to be broken.
Here's an example:
Given the byte stream 0x00 0x01 0x02 0x03 loaded via 32-bit DMA into the TXFIFO:
o ECON.BE = 0 (with BACON.BYTE = 0) will transmit:
32 bits: 0x03 0x02 0x01 0x00
24 bits: 0x02 0x01 0x00
16 bits: 0x01 0x00
8 bits: 0x00
o ECON.BE = 1 (with BACON.BYTE = 0) will transmit:
32 bits: 0x02 0x03 0x00 0x01
24 bits: 0x00 0x00 0x01
16 bits: 0x00 0x01
8 bits: 0x00
o ECON.BE = 2 (with BACON.BYTE = 0) will transmit:
32 bits: 0x00 0x01 0x02 0x03
24 bits: 0x01 0x02 0x00
16 bits: 0x00 0x00
8 bits: 0x00
None of the valid ECON.BE settings will send 24 bits as 0x00 0x01 0x02.
Anyone else notice this problem?
Toshi
Jan 29, 2020
12:40 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 29, 2020
12:40 PM
Not surprising, from this note in the User Manual:
The endianness byte permutation should be used only for 16-bit and 32-bit data (and multiples of it), and not for other data lengths.
The endianness byte permutation should be used only for 16-bit and 32-bit data (and multiples of it), and not for other data lengths.
Jan 30, 2020
03:09 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 30, 2020
03:09 PM
UC_wrangler wrote:
Not surprising, from this note in the User Manual:
The endianness byte permutation should be used only for 16-bit and 32-bit data (and multiples of it), and not for other data lengths.
Ah, they documented the bug and made it a feature.
Toshi
Jan 11, 2022
01:52 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jan 11, 2022
01:52 AM
May i know how you tried to implement queue functionality in your code for multiple channels