world leader in high performance signal processing
Trace: » ppi

Parallel Peripheral Interface (PPI)

The Parallel Peripheral Interface (PPI) is a half-duplex, bidirectional port accommodating up to 16 bits of data. It has a dedicated clock pin and three multiplexed frame sync pins. It is sometimes referred to as a “video port” as it most commonly used to drive video devices (like LCDs or CMOS sensors or video encoders/decoders). Really though, this can be used to drive any sort of high speed parallel device.

Blackfin Interface

The figure below provides a block diagram of the Blackfin PPI.

Linux Framework

No framework or API exists to help with controlling the PPI, so you will be spending a lot of time reading/writing directly to the PPI's MMR registers. Like any other driver, you will also need to use the portmux framework and request/free any peripheral pins you wish to utilize.

Time to grab a copy of the HRM for your particular Blackfin variant!

MMR Accessor Functions

All MMR reads and writes are done through so called “acessor helper functions”. These functions all have the form bfin_read_MMR() and bfin_write_MMR(value) where MMR is replaced with the actual register name.

For example, if you wish to read the PPI status register PPI_STATUS, then you should use the function bfin_read_PPI_STATUS().

Function Reference

Here are all the accessor functions laid out. Note that we include a helper bfin_clear_PPI_STATUS() function as different variants of the Blackfin processor require different handling of the PPI_STATUS register in order to clear it properly.

u16     bfin_read_PPI_CONTROL      (void)
void    bfin_write_PPI_CONTROL     (u16 val)
 
u16     bfin_read_PPI_STATUS       (void)
void    bfin_write_PPI_STATUS      (u16 val)
void    bfin_clear_PPI_STATUS      (void)
 
u16     bfin_read_PPI_DELAY        (void)
void    bfin_write_PPI_DELAY       (u16 val)
 
u16     bfin_read_PPI_COUNT        (void)
void    bfin_write_PPI_COUNT       (u16 val)
 
u16     bfin_read_PPI_FRAME        (void)
void    bfin_write_PPI_FRAME       (u16 val)

Troubleshooting

PPI Underrun/Overflow Errors

There are two potential causes:

PPI ERROR interrupt overtakes PPI-DMA-DONE interrupt due to higher priority:
  • Your driver in question performs a PPI out write operation.
  • And uses PPI DMA-DONE interrupts to signal completion of a work load.
  • And the PPI line sync PPI_FS1 re-asserts before the PPI is disabled, while there is a continuous PPI_CLK.

Workarounds:

  • Move IRQ_PPI_ERROR priority below IRQ_PPI (IRQ_DMAx)
  • Don't request IRQ_PPI_ERROR
The PPI FIFO is 16 bits wide and has 16 entries. In case the DMA can’t access L3 Memory fast enough, this fifo might overflow (OVR) or underrun (UNDR)

Workarounds:

  • Make sure you set the CDPRIO bit in the ASYNC Memory Configuration. (EBIU_AMGCTL: This allows the DMA to have higher priority than the Core for external memory accesses.)
  • Increase SCLK System Clock.
  • If external memory mapped peripherals like Ethernet Controllers are accesses while high speed PPI DMA is active into L3 Memory, External Async. Memmory access timings low. (EBIU_AMBCTL)
  • If possible use internal L1 data memory for DMA buffers.
  • If buffers dont fit in L1, you can try keep the data buffers in separate SDRAM data banks to reduce bank open/close latency. Linux does not inheritly support allocation in specific banks or on specific address ranges. It can be solved by direct addressing a specific bank, check the memory allocator page.
  • Fine-tune SDRAM initialization parameters. (Use faster SDRAM).
  • Always utilize the maximum DMA bus width, for 8-bit PPI transfers use the packing option.
  • Reduce PPI CLK.

Further reading

Code examples

Complete Table of Contents/Topics