I'm working with an OMAP-L138 using the UPP peripherial in receive mode. A FPGA drives the UPP bus. The ARM is running linux I've observed two issues that seem to be related. After a reboot either the upp is perfectly fine and I receive data indefinitely or the upp fails. When it fails it either never generates interrupts (either EOL or EOW) or it generates interrupts but the data is continually misaligned (the data is offset by 9 16-bit words). A upp "failure" can be correctly predicted by reading the UPPCR->DB register bit after the peripheral has been initialized by the DSP and before the FPGA starts clocking the UPP signals. Below is a code snippet which initialized the UPP.
When the failure mode is mis-aligned data with interrupts I can re-init the UPP peripheral by calling initUppPeripheral() and recover. When the failure mode is "no interrupt" I can't seem to recover.
My first question is can the UPP's internal DMA become active even though there is no activity on the UPP signals? Is there a better way to reset the UPP peripheral so I can recover from this failure? Of course I would like to avoid the failure all together, so if there is a suggestion or clue as to what I may be doing wrong that would be very much appreciated.
void initUppPeripheral()
{
volatileint i;
/* reset the uPP */
CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_EN, DISABLE);
while(CSL_FEXT(uppRegs->UPPCR, UPP_UPPCR_DB)){};
CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_SWRST, RESET);
if (BIOS_getThreadType() == BIOS_ThreadType_Task)
{
Task_sleep(TICKS_PER_MSEC * 5); // test with a very long time
}
else
{
for(i = 0; i < 400; i++){}; //wait at least 200 clock cycles for reset.
}
CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_SWRST, RUNNING);
/*
* uPP Channel Control Register
* - Receive Mode
* - Single Channel Mode
* - Single Data Rate
* - 16-bit Interface
*/
uppRegs->UPCTL = CSL_FMKT(UPP_UPCTL_MODE, RECEIVE)
| CSL_FMKT(UPP_UPCTL_CHN, ONE)
| CSL_FMKT(UPP_UPCTL_SDRTXIL, DISABLE)
| CSL_FMKT(UPP_UPCTL_DDRDEMUX, DISABLE)
| CSL_FMKT(UPP_UPCTL_DRA, SINGLE)
| CSL_FMKT(UPP_UPCTL_IWA, 16BIT)
| CSL_FMKT(UPP_UPCTL_DPWA, FULL);
/*
* uPP Interface Configuration Register
* - StartA is active high
* - EnableA is active high
* - StartA signal is enabled for receive
* - EnableA signal is enabled for receive
* - ClockA is normal (i.e. signals align on rising edge of clock)
*
* Note: When initializing the uPP peripheral, the uPP interface
* configuration register (UPICR) must be programmed using a single,
* 32-bit write. Writing UPICR fields one-by-one can lead to
* unexpected results (reference SPRUGJ5B section 2.6.1)
*
* Note 2: The clock polarities are confusing; "signals
* align on the rising edge of clock" means other signals
* transition on the falling edge of the clock (i.e. start, data)
* and data is sampled on the rising edge.
*/
uppRegs->UPICR = CSL_FMKT(UPP_UPICR_STARTPOLA, NORMAL)
| CSL_FMKT(UPP_UPICR_ENAPOLA, NORMAL)
| CSL_FMKT(UPP_UPICR_STARTA, ENABLE)
| CSL_FMKT(UPP_UPICR_ENAA, ENABLE)
| CSL_FMKT(UPP_UPICR_CLKINVA, NORMAL);
/*
* uPP Threshold Configuration Register
* - Read threshold for I channel set to 64 bytes
*/
uppRegs->UPTCR = CSL_FMKT(UPP_UPTCR_RDSIZEI, 64B);
/*
* uPP Interrupt Enable Set Register
* - Enable Channel I (i.e. A) End-of-Line interrupt
* - Enable Channel I (i.e. A) End-of-Window interrupt
*/
uppRegs->UPIES = CSL_FMKT(UPP_UPIES_EOLI, SET)
| CSL_FMKT(UPP_UPIES_EOWI, SET);
CSL_FINST(uppRegs->UPDLB, UPP_UPDLB_BA, DISABLE);
CSL_FINST(uppRegs->UPDLB, UPP_UPDLB_AB, DISABLE);
/*
* uPP Peripheral Control Register
* - Set the EN bit to turn on the uPP peripheral
*/
CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_EN, ENABLE);
programUppDmaDescriptor();
}
/*************************************************************************/
inlinevoid programUppDmaDescriptor()
{
/*
* If no DMA transfer is Pending program another DMA descriptor.
*
* Program the DMA Descriptor:
* uPP DMA Channel I Descriptor 0 Register
* - starting address of the data buffer (i.e. 64-bit aligned window address)
* uPP DMA Channel I Descriptor 1 Register
* - Number of lines per window = UPP_NUMBER_OF_LINES
* - Number of bytes per line = UPP_LINE_LENGTH * 2 (BCNTH * 2)
* uPP DMA Channel I Descriptor 2 Register
* - offset between lines = UPP_LINE_OFFSET
* (must align on 64 bit boundary, lower 3 bits are zero)
*
* Note: Comments on E2E forum stating not to read-modify-write these register
*/
if (!CSL_FEXT(uppRegs->UPIS2, UPP_UPIS2_PEND))
{
m_dmaDescCounter++;
uppRegs->UPID0 = (uint32_t)&m_uppInputBuffer;
uppRegs->UPID1 = CSL_FMK(UPP_UPID1_LNCNT, UPP_NUMBER_OF_LINES)
| CSL_FMK(UPP_UPID1_BCNTH, UPP_LINE_LENGTH);
uppRegs->UPID2 = (UPP_LINE_OFFSET * sizeof(uint16_t));
}
}