Page 1 of 1

DMA and SPI documentation

Posted: Wed Aug 23, 2017 4:39 pm
by baantonia
Apart from the Broadcom Peripheral documentation, is there anywhere, documented use of DMA, especially with SPI? I'm trying to understand how I can communicate with a SPI device via DMA, initially using a mcp3002 which is on the Gertboard.

I have been able to copy memory contents from one place to another using DMA and have communicated with SPI chips in polled mode.

I know the addresses in the control blocks have to be relative to the VC processor but am stuck getting my head around the use of txfr_len, stride, ti flags and the SPI dlen and cs registers.

I've seen an example which uses the SPI GPIO pins but only for providing a timed loopback pulse, not for interfacing with an actual external SPI device.

Oh, and by the way, I'm doing this bare metal but programming in asm and C.

Re: DMA and SPI documentation

Posted: Wed Aug 23, 2017 5:16 pm
by piras77
I did this (in userland) with four CBs per record.

This works fine as long as the MISO/MOSI sequence fits into the SPI fifo:

1st CB to setup the SPI control register (1:1).
2nd CB to transfer MOSI (n:1).
3rd CB to read the Timer (1:1).
4th CB to transfer MISO (paced with PERMAP=7, 1:n).

Then I have several (thousands) records which are linked together. The last one points back to the first.

Timer values and MOSI form a ring buffer.

Only one DMA channel is required.

Note, MOSI starts with a configuration word that includes the size of the transfer in the upper 16 bits (the details should be in the BCM2835 document).

Re: DMA and SPI documentation

Posted: Wed Aug 23, 2017 5:34 pm
by baantonia
One of my issues is in understanding how individual bytes can be sent and received, as in polled mode, when writing to the FIFO 32bits are written, are the top 24 ignored? I'm trying to recreate the polled mode which sends and receives bytes for communicating with a mcp3002.

Interesting you say you've used a single channel.I'm assuming the information in brackets relate to number of 32bit memory addresses.

Re: DMA and SPI documentation

Posted: Wed Aug 23, 2017 5:53 pm
by piras77
With DMAEN it will be always 32-bit word transfer. So you have to pad. Still, since DMALEN is given in bytes, the last 0-3 bytes are going to be ignored.

And yes, 1:n a.s.o are 32-bit words.

I made some notes the time I wrote my code. Maybe there are some useful pointers. No guarantees, though. ;-)

Code: Select all

// Errata: FIFO register (p.155)
// If TA=0 and DMAEN=0: The first 32-bit write to this register will
// set the CS register (bit:0-7) and the DLEN register (bit:16-31). --
// This is similar to the DMA mode (§10.6.3.l). Hoewever, the DLEN
// register only affects the SCLK suspension at the end of each byte
// transfer (see errata for DLEN register). -- Subsequent writes to
// the FIFO register are considered as single-byte-writes (not words).
// Errata: CLK Register (p.156)
// It says "The divisor must be a power of 2." It should be: "The
// divisor must be a multiple of 2."
// Errata: DLEN register (p.156)
// It says "This field is only valid for DMA-mode (DMAEN set)".
// However, it also effects the non-DMA-mode: if DLEN=0 or DLEN=1,
// teh SCLK is suspended (i.e. stays low) for the duration of a
// single clock-cycle at the end of each byte-transfer. There is no
// such SCLK suspension if DLEN>1. 
// See
// * The base clock (APB CLK) seems to depend on the core clock which
//   varies on Pi-0 between 250 and 400 MHz. This distorts the SPI
//   clock! To prevent SPI clock changes, you have to fix the core-
//   clock to a certain speed, e.g. by core_freq=250 (/boot/config.txt).
// --------------------------------------------------------------------
// DMA Setup (see § 10.6.3 + errata)
// Two DMA channels are required [*1]:
// * channel (A) to write the tx-fifo,
// * channel (B) to  read the rx-fifo.
// The SPI side of the DMA channel must operate with 32-bit transfers
// (see source/destination field in the DMA TI register).
// [*1] It might be possible to operate the SPI with a single DMA
//      channel. That would require alternating control blocks (CB)
//      to read and write the SPI.
// Operation:
// (1) Enable DMA operation by setting SPI0.DMAEN. This will also 
//     enable pacing through DREQ lines for writing (DREQ signal number
//     #6) and reading (#7). [see §]
// (2) Write: Program a DMA control block (CB) for channel A. Besides
//     others:
//       CB.TI.DEST_INC = 0    # don't increment the destination address
//       CB.TI.DEST_WIDTH = 0  # use 32-bit word operations
//       CB.TI.DEST_DREQ = 1   # use paced write operations
//       CB.TI.PERMAP = 6      # pacing is done by DREQ signal # 6
//     The first 32-bit write sets SPI.CS register (bit:0-7),
//     SPI.CS:21-23 (bit:8-10) and SPI.DLEN register (bit:16-31). SPI.
//     DLEN should contain the number of bytes [not words] to transfer.
// (3) Read: Program a DMA control block for channel B. Besides others:
//       CB.TI.SRC_INC = 0     # don't increment the destination address
//       CB.TI.SRC_WIDTH = 0   # use 32-bit word operations
//       CB.TI.SRC_DREQ = 1    # use paced write operations
//       CB.TI.PERMAP = 7      # pacing is done by DREQ signal # 7
// (4) Choose two DMA channels, set CB, and enable ACTIVE.
// (5) Wait for the transfer end.
// --------------------------------------------------------------------
// DMA errata (new)
// * Cspol has no effect
// * The CE signal becomes shorter and shorter (from about 350ns at
//   about 4 MHz to finally 40ns at about div=500) and finally vanishes
//   * cs0 vanishes if not reversed, however keeps coming if is
//   * cs1 vanishes if reversed, however keep coming if not
// * If cs1 is activated, cs0 becomes also visible at low frequencies
//   with almost identical timings
// * Adcs has not the effect as described: it appears setting it does
//   make CE come about a clock-cycle earlier
// * Dmaen=1 appears to make read/writes from/to FIFO 32-bit wide
//   (wheter by DMA or CPU doesn't matter)
// * Writing to the FIFO if TA=0 appear to be always 32-bit writes. If
//   the word is immediately consumed (not enqueued) with the
//   characteristics described above. Thus, writes are consumed
//   immediately until one of them sets TA.
// * DMA operation with Dmaen=0 appears to be possible (with FIFO byte
//   access), however, reading the FIFO w/o pacing might be of very
//   little use.

Re: DMA and SPI documentation

Posted: Wed Aug 23, 2017 6:05 pm
by baantonia
Anything more useful than the Broadcom pdf would be great, thank you. The pdf provides vague instructions and very limited information on how each part interacts.

Re: DMA and SPI documentation

Posted: Wed Aug 23, 2017 7:03 pm
by baantonia
Thank you, your notes provide answers to a number of my questions.