Maker Pro
Maker Pro

16-bit SPI trying to read from 22-clock cycle ADC

B

Bill

Jan 1, 1970
0
Hi,

I'm trying to pull out data from the ADS8320 (a 16-bit ADC by Analog
Devices. See bottom of page 10 in
http://focus.ti.com/lit/ds/symlink/ads8320.pdf ) using the SPI in an
AT91SAM7S256. The problem is that the ADC needs 6 extra clock cycles
to sample the analog signal, before the 16 cycles that will output
each of the conversion result bits. So, a complete ADC cycle involves
a minimum of 22 clock cycles. Now, the SPI in the AT91SAM7 (and, as
far as I've seen, in all other MCUs), cannot generate more than 16
clock cycles within one CS activation.

How am I supposed to do this, in an elegant way? Of course I could bit
bang those lines, but I hate doing that, because it adds load to the
CPU, and doesn't take advantage of the SPI and DMA.

The AT91SAM7S256 allows holding the CS low until a new device is
addressed, so I could initiate two 11-bit readings in a row (in such a
way that the ADC would think it is a single CS assertion with 22 clock
cycles inside), and discard the bits with no information, but that's
still ugly to me. It would use the SPI, but not the DMA, and the two
readings would be different (the first one should hold CS low. The
second one should leave it high), which is kind of non-homogeneous.

Any more elegant ideas?

Thank you.
 
B

Bill

Jan 1, 1970
0
^^^^^^^^^^^^^^^^^^^^^

LOL

:) Sorry. TI. I'm using other Analog Devices ICs.
Generate transactions by SPI, but control the CS signal as GPIO.
I.e. assert the CS, read the required number of bits by SPI, deassert
the CS.

But still, bye bye DMA.


I'm very curious... what were the guys at TI (and at some other
companies) thinking when they designed this ADC with SPI interface?
Which SPI hardware were they thinking would be able to pull out data
in one transaction? Does anyone know of an MCU with SPI hardware able
to do this? Amazing.

Best,
 
M

Mel

Jan 1, 1970
0
Bill said:
I'm trying to pull out data from the ADS8320 (a 16-bit ADC by Analog
Devices. See bottom of page 10 in
http://focus.ti.com/lit/ds/symlink/ads8320.pdf ) using the SPI in an
AT91SAM7S256. [ ... ]
How am I supposed to do this, in an elegant way? Of course I could bit
bang those lines, but I hate doing that, because it adds load to the
CPU, and doesn't take advantage of the SPI and DMA.

You have Peripheral DMA Controller, use it. This is for a Microchip ADC,
but the three-byte transfer might resemble your problem. The method on the
ADC side was written up in the MCP3008 datasheet. Code fragment:


inline void poll_mcp3008 (int pad)
{
// Mode-register bits to select each of the MCP3008s, with MSTR bit
set
...
static const int modecsbits[4] = {0x000F0001 ^ (1 << (16+0))
, 0x000F0001 ^ (1 <<
(16+1))
, 0x000F0001 ^ (1 <<
(16+2))
, 0x000F0001 ^ (1 <<
(16+3))
};
// set SPI_MR(PCS) to select the pad
AT91C_BASE_SPI->SPI_MR = modecsbits[(pad >> 3) & 3];
// prime buffer with a start bit, 'single' bit, and channel number
pan_buf[0] = 1; // start bit
pan_buf[1] = 0x80 | ((pad & 7) << 4); // 'single' bit, channel
number,
2 pad bits and space for high 2 bits of value
pan_buf[2] = 0; // pad space where
low 8
bits of value will appear
// start a conversion
SPI_RwBuffer (AT91C_BASE_SPI, pan_buf, sizeof pan_buf);
}


And the SPI-RwBuffer added to the spi library routines (based on the other
SPI routines):


unsigned char SPI_RwBuffer(AT91S_SPI *spi,
void *buffer,
unsigned int length)
{
// Check if the first bank is free
if (spi->SPI_RCR == 0) {
// set up to overlay the write buffer with incoming data ..
spi->SPI_RPR = (unsigned int) buffer;
spi->SPI_RCR = length;
spi->SPI_TPR = (unsigned int) buffer;
spi->SPI_TCR = length;
spi->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
return 1;
}
// Check if second bank is free
else if (spi->SPI_RNCR == 0) {

spi->SPI_RNPR = (unsigned int) buffer;
spi->SPI_RNCR = length;
spi->SPI_TNPR = (unsigned int) buffer;
spi->SPI_TNCR = length;
return 1;
}

// No free bank
return 0;
}


In this case the data from the MCP3008 overlays the buffer that contained
the tranmitted request. It doesn't have to be this way, but it was easy to
implement. SPI device interrupts when the full 3 bytes have been
transferred both ways.


Mel.
 
R

Rich Webb

Jan 1, 1970
0
:) Sorry. TI. I'm using other Analog Devices ICs.


But still, bye bye DMA.


I'm very curious... what were the guys at TI (and at some other
companies) thinking when they designed this ADC with SPI interface?
Which SPI hardware were they thinking would be able to pull out data
in one transaction? Does anyone know of an MCU with SPI hardware able
to do this? Amazing.

I haven't done a lot of (er, any) looking but one processor that I'm
using right now has a configuration register for its SPI peripheral to
do 8 to 16 bits per transfer, so two 11-bit transfers would be easy
enough to set up. NXP's LPC2119/2129. No DMA in this one, but (okay, I
did a little looking) the LPC24xx chips support configurable transfer
lengths and DMA on their SSP peripherals.
 
B

Bill

Jan 1, 1970
0
You have Peripheral DMA Controller, use it.

I would gladly use it, but I don't think it is possible. DMA is not
able neither to automatically change CSAAT (Chip Select Active After
Transfer) configuration between 8-bit transactions 2 and 3, nor to bit
bang CS to my needs.

Best,
 
B

Bill

Jan 1, 1970
0
I haven't done a lot of (er, any) looking but one processor that I'm
using right now has a configuration register for its SPI peripheral to
do 8 to 16 bits per transfer, so two 11-bit transfers would be easy
enough to set up. NXP's LPC2119/2129. No DMA in this one, but (okay, I
did a little looking) the LPC24xx chips support configurable transfer
lengths and DMA on their SSP peripherals.

No, no... the ADC cannot see CS going up and then again down between
two transfers, because that would reset the conversion process. That
means I have to bit bang CS or change CSAAT configuration (a bit that
determines whether CS remains low after each transfer) between the two
transfers. And, of course, no possible DMA.

So, in other words, your LPC2119 cannot do that in one transfer,
either, and I doubt that the DMA in the LPC24xx will be of any use, in
this problem.

Best,
 
B

Bill

Jan 1, 1970
0
If Englich is not yuor frist langwige, have someone else read if to you.

See Bottom of page 10 again !

don

I don't need English to be my first language to understand datasheets.

What do you exactly mean? Which piece of information did I miss?
 
M

Mel

Jan 1, 1970
0
Bill said:
I would gladly use it, but I don't think it is possible. DMA is not
able neither to automatically change CSAAT (Chip Select Active After
Transfer) configuration between 8-bit transactions 2 and 3, nor to bit
bang CS to my needs.

From what I'm seeing here, when the PDC is in charge, the SPI doesn't work
in 8-bit transactions. It works in a single transaction involving as many
8-bit bytes as the PDC demands. I see /CS go low, and while it's low 24
clock pulses come out in a single burst, then /CS goes high and life goes
on. (This is with the code I posted. Thank the deity for digital storage
scopes.)

Mel.
 
M

Martin Riddle

Jan 1, 1970
0
Bill said:
I don't need English to be my first language to understand datasheets.

What do you exactly mean? Which piece of information did I miss?

At the bottom of figure 3:

NOTE: Minimum 22 clock cycles required for 16-bit conversion. Shown are
24 clock cycles.
If CS remains LOW at the end of conversion, a new datastream with
LSB-first is shifted out again.



3, 8 bit transfers.

Cheers
 
B

Bill

Jan 1, 1970
0
Freescale microcontrollers with queued SPI peripherals have no problems
doing long SPI transfers. Each individual transfer is from 8 to 16
clocks, but you can specify that the chip select will not be deasserted
after the first transfer,

The AT91SAM7S256 also allows that. The CSAAT (Chip Select Active After
Transfer) that I keep mentioning in my other posts is exactly that.
But that is of no use here. It does not allow me to use DMA. I still
need manual intervention from the CPU to change that CSAAT bit so that
it is 1 for the first transfer, and 0 for the second transfer (the CS
cannot be always 0, because the ADC would never trigger a new
conversion). The DMA won't do that for me. And won't bit bang CS for
me, either.

In other words. Yes, I can specify that the chip select will not be
deasserted after the first transfer. But how about after the second
transfer? I need that the chip select WILL BE deasserted after the
second transfer. And all that needs CPU intervention. The DMA cannot
automatically reconfigure a peripheral between transfers.

so that you can easily get 22 clock transfers.
There are many ColdFire's (and older 683xx devices) with a queued SPI,
and the latest PPC-based MPC5xxx devices have even more powerful SPI
peripherals connected to flexible DMA.

I don't know if that's what the guys at TI were thinking about, and I
doubt if it really helps you here, but there *are* microcontrollers
available that can handle all this in the background by DMA

There are tens of "MPC5xxx" devices. Could you specify one?
(/if/ you can understand the documentation...).

Doesn't that sound a bit unpolite? Of course I can. Why shouldn't I?


Best,
 
B

Bill

Jan 1, 1970
0
From what I'm seeing here, when the PDC is in charge, the SPI doesn't work
in 8-bit transactions. It works in a single transaction involving as many
8-bit bytes as the PDC demands. I see /CS go low, and while it's low 24
clock pulses come out in a single burst, then /CS goes high and life goes
on. (This is with the code I posted. Thank the deity for digital storage
scopes.)

No, no. It doesn't work that way. The PDC moves N units of
information, each unit being whichever length (from 8 to 16 bits) the
SPI has been configured to work with. You must be seeing a single
transfer there (in your 24 clock cycles).

Show me where, in the datasheet, the PDC forces the SPI to work in
transfers of 8 bits, or in a multiple of 8 bits. I couldn't find it.

Best,
 
B

Bill

Jan 1, 1970
0
anyhoo, have a look at the SSC instead and see if it doesn't fit your
needs better than the SPI.

This is interesting. I'm taking a look at the SSC. Never used it
before. Looks like it might be possible, but I'll wait to finish
reading.

Thanks!
 
B

Bill

Jan 1, 1970
0
At the bottom of figure 3:

NOTE: Minimum 22 clock cycles required for 16-bit conversion. Shown are
24 clock cycles.
If CS remains LOW at the end of conversion, a new datastream with
LSB-first is shifted out again.



3, 8 bit transfers.

Cheers

That has already been proposed by others, and won't work either,
without CPU intervention. Please read my other posts.
 
B

Bill

Jan 1, 1970
0
It appears strange. From my experience, normally TI would definitely
have some reasons for any such strange things.

To be more correct, for me, it is not TI's fault. It is the fault of
the designers of the SPI inside everyday MCUs. Knowing that there are
16/18/20/22/24-bit ADCs/DACs around, and that they need extra clock
cycles for the sampling phase, what are they waiting to implement SPIs
that can handle say 32 bits in a single transfer? I don't understand
it. It would be a few microdollars more of silicon.
In this scenario, bit banging appears reasonable. Well, that might
increase the CPU load.

Yes, I'm bit banging. The ADC could work up to 100 ksa/s. Thank god
I'm not going that high, because in that case the CPU could do nothing
else.
The best help would be from the TI support.

Yes, I'm curious to ask them.


Best,
 
B

Bill

Jan 1, 1970
0
You must be seeing a single transfer there (in your 24 clock cycles).

Disregard this sentence. It makes no sense. I was thinking about my
ADC. I don't know why you are seeing that. Maybe you have CSAAT set,
and you are switching between different devices?
 
K

krw

Jan 1, 1970
0
Hi,

I'm trying to pull out data from the ADS8320 (a 16-bit ADC by Analog
Devices. See bottom of page 10 in
http://focus.ti.com/lit/ds/symlink/ads8320.pdf ) using the SPI in an
AT91SAM7S256. The problem is that the ADC needs 6 extra clock cycles
to sample the analog signal, before the 16 cycles that will output
each of the conversion result bits. So, a complete ADC cycle involves
a minimum of 22 clock cycles. Now, the SPI in the AT91SAM7 (and, as
far as I've seen, in all other MCUs), cannot generate more than 16
clock cycles within one CS activation.

Seems like a pretty poor implementation of the SPI master. I've
generally rolled my own, but at least the later TI DSPs allow SPI word
lengths of 1 to 32 bits.
How am I supposed to do this, in an elegant way? Of course I could bit
bang those lines, but I hate doing that, because it adds load to the
CPU, and doesn't take advantage of the SPI and DMA.

Bit bang the sample clock then use SPI to transfer data? Use an FPGA
to do your I/O?
The AT91SAM7S256 allows holding the CS low until a new device is
addressed, so I could initiate two 11-bit readings in a row (in such a
way that the ADC would think it is a single CS assertion with 22 clock
cycles inside), and discard the bits with no information, but that's
still ugly to me. It would use the SPI, but not the DMA, and the two
readings would be different (the first one should hold CS low. The
second one should leave it high), which is kind of non-homogeneous.

Any more elegant ideas?

You have a sows ear and you want a silk purse? ;-)
 
D

David Brown

Jan 1, 1970
0
Bill said:
The AT91SAM7S256 also allows that. The CSAAT (Chip Select Active After
Transfer) that I keep mentioning in my other posts is exactly that.
But that is of no use here. It does not allow me to use DMA. I still
need manual intervention from the CPU to change that CSAAT bit so that
it is 1 for the first transfer, and 0 for the second transfer (the CS
cannot be always 0, because the ADC would never trigger a new
conversion). The DMA won't do that for me. And won't bit bang CS for
me, either.

I'm not familiar with the AT91SAM devices (I'm not very familiar with
ARMs in general - it's nearly twenty years sine I used one), so this may
or may not give you some ideas...

First, is the CSAAT bit in a register adjacent to the SPI transfer
register(s) ? If so, it's possible that your DMA could be set up to
transfer a new value to that control register at the same time as
sending another 16-bit word to the SPI transmit register. (On the
Freescale devices, the equivalent to CSAAT is in a command byte that is
collected from the queue along with the data to send.)

Secondly, if you have several DMA channels and they are flexible enough,
it might be possible to configure a chain of DMA events. For example,
the SPI transfer complete could trigger a DMA transfer. Instead of
writing the next SPI transmit value, this could "manually" trigger two
new DMA channels. The first of these is set up to set the CSAAT bit,
and the second to write the next SPI transfer.
In other words. Yes, I can specify that the chip select will not be
deasserted after the first transfer. But how about after the second
transfer? I need that the chip select WILL BE deasserted after the
second transfer. And all that needs CPU intervention. The DMA cannot
automatically reconfigure a peripheral between transfers.



There are tens of "MPC5xxx" devices. Could you specify one?

There are indeed a fair number of them, and (AFAIK) they all have
powerful SPI peripherals and lots of flexible DMA channels. So without
anything else to go on (performance, flash, external bus, timers, etc.),
it would be a random guess as to which would be suitable for you (though
MPC55xx or MPC56xx narrows it down a little). I've used an MPC5554, if
that helps at all. If you are considering changing architecture, then
you should also look at the ColdFires (specially the v2 cores) - they
are easier to work with.
Doesn't that sound a bit unpolite? Of course I can. Why shouldn't I?

Sorry, I didn't mean it to sound impolite to /you/. It's just that the
documentation for these devices is complicated and often unclear. The
"SPI" peripherals on the MPC55xx support serial multiplexing of internal
timer channels as well as SPI (which supports multiple queues amongst
other features), and it's no small job figuring out what is really
needed to get the SPI running as desired. Similarly with DMA. There is
also a lack of appnotes for this sort of setup, so you have to be
prepared for a fair amount of work figuring things out. Once you
understand it all, however, you can do all sorts of wonderful things
with the MPC's peripherals.
 
S

Stef

Jan 1, 1970
0
In comp.arch.embedded,
Bill said:
Hi,

I'm trying to pull out data from the ADS8320 (a 16-bit ADC by Analog
Devices. See bottom of page 10 in
http://focus.ti.com/lit/ds/symlink/ads8320.pdf ) using the SPI in an
AT91SAM7S256. The problem is that the ADC needs 6 extra clock cycles
to sample the analog signal, before the 16 cycles that will output
each of the conversion result bits. So, a complete ADC cycle involves
a minimum of 22 clock cycles. Now, the SPI in the AT91SAM7 (and, as
far as I've seen, in all other MCUs), cannot generate more than 16
clock cycles within one CS activation.

How am I supposed to do this, in an elegant way? Of course I could bit
bang those lines, but I hate doing that, because it adds load to the
CPU, and doesn't take advantage of the SPI and DMA.

The AT91SAM7S256 allows holding the CS low until a new device is
addressed, so I could initiate two 11-bit readings in a row (in such a
way that the ADC would think it is a single CS assertion with 22 clock
cycles inside), and discard the bits with no information, but that's
still ugly to me. It would use the SPI, but not the DMA, and the two
readings would be different (the first one should hold CS low. The
second one should leave it high), which is kind of non-homogeneous.

Ofcourse you can do this with 2 11-bit transfers (or 3 8-bit as mentioned
by others) and still use the PDC (DMA). If you couldn't, how would you
for example read EEPROMS?

Just set CSAAT=0 "The Peripheral Chip Select Line rises as soon as the
last transfer is achieved", fill your TX buffer and point PDC to it.
Then write the PDC counter and the CS will go low before the first
transfer and only rise after the PDC has completed last transfer.

You ofcourse have to make sure all other settings match your hardware,
check that every bit in every register is set as required, understand
the function of each bit.

This is the way I always use SPI on the SAM7. I do use variable
peripheral select and no CS decoding, but I don't think these options
affect the CS deassertion behaviour.
 
B

Bill

Jan 1, 1970
0
Well, I was wrong in at least one thing: I thought that, with CSAAT=0,
CS would be deasserted (high) between consecutive "word transfers"
within one "block transfer", but it is not. I had clear from the
beginning (from diagrams and text) that there was a way to keep CS=0
between word transfers, but I thought that it implied CSAAT=1, and it
is not true. CS is 0 between consecutive word transfers (of the same
block transfer) regardless of the value of CSAAT.

So, yes, I can leave CSAAT=0 permanently, there is no CPU intervention
needed (other than at the beginning and at the end of each block
transfer), and I can use DMA, with two 11-bit word transfers per block
transfer.


This is good, but I think that it could be better. Difficult to
explain, but I'll try:

Imagine my external ADC (with SPI interface) is sampling the analog
input at 100 ksa/s (the TI ADS8320 that I mentioned allows that). So,
10 us between samples. Not much. Each sample needs 22-clock cycles
inside each assertion of CS=0, so each sample needs one DMA block
transfer (with for instance two 11-bit word transfers inside). Each
DMA block transfer needs CPU intervention. So, I need CPU intervention
every 10 us. That's a short time. Only 480 cycles of my 48 MHz SAM7.
Since (that I know) a DMA block transfer cannot be triggered directly
by a timer overflow or underflow, an interrupt service routine
(triggered by a 10 us timer underflow) must be executed every so
often, so that the CPU can manually trigger the DMA block transfer and
collect the data. Adding up the overhead of the interrupt context
switching and the instructons needed to move data from and to the
block buffers, to re-trigger the block transfer, and all this in C++,
I think that all that may consume a "significant" portion of those 480
cycles. And the CPU is supposed to do something with that data, and
some other things. I see that hog as a killer, or at least as a pitty.

If the SPI in the MCU allowed 22-bit (word) transfers, and the DMA
allowed triggering the next word transfer (inside a block transfer)
when a certain timer underflows, then the DMA blocks wouldn't need to
be so small. Each analog sample could travel in one single SPI word
transfer, and one DMA block could be planned to carry for instance
1000 word transfers. That would be one DMA block every 10 ms. The
buffer (FIFO) memory would be larger, but the CPU intervention needed
would be much lower. There would be the same number of useful cycles,
but much fewer wasted cycles. There wouldn't need to exist an
interrupt service routine executed every 10 us, which is a killer.
That would be a good SPI and a good DMA, in my opinion, and the extra
cost in silicon is negligible, compared to the added benefit. Why
don't most MCUs allow that? Even cheap MCUs could include that. An MCU
with the price of a SAM7 should include that, in my opinion.

Best,
 
S

Stef

Jan 1, 1970
0
In comp.arch.embedded,
Bill said:
This is good, but I think that it could be better. Difficult to
explain, but I'll try:

Imagine my external ADC (with SPI interface) is sampling the analog
input at 100 ksa/s (the TI ADS8320 that I mentioned allows that). So,
10 us between samples. Not much. Each sample needs 22-clock cycles
inside each assertion of CS=0, so each sample needs one DMA block
transfer (with for instance two 11-bit word transfers inside). Each
DMA block transfer needs CPU intervention. So, I need CPU intervention
every 10 us. That's a short time. Only 480 cycles of my 48 MHz SAM7.
Since (that I know) a DMA block transfer cannot be triggered directly
by a timer overflow or underflow, an interrupt service routine
(triggered by a 10 us timer underflow) must be executed every so
often, so that the CPU can manually trigger the DMA block transfer and
collect the data. Adding up the overhead of the interrupt context
switching and the instructons needed to move data from and to the
block buffers, to re-trigger the block transfer, and all this in C++,
I think that all that may consume a "significant" portion of those 480
cycles. And the CPU is supposed to do something with that data, and
some other things. I see that hog as a killer, or at least as a pitty.

If the SPI in the MCU allowed 22-bit (word) transfers, and the DMA
allowed triggering the next word transfer (inside a block transfer)
when a certain timer underflows, then the DMA blocks wouldn't need to
be so small. Each analog sample could travel in one single SPI word
transfer, and one DMA block could be planned to carry for instance
1000 word transfers. That would be one DMA block every 10 ms. The
buffer (FIFO) memory would be larger, but the CPU intervention needed
would be much lower. There would be the same number of useful cycles,
but much fewer wasted cycles. There wouldn't need to exist an
interrupt service routine executed every 10 us, which is a killer.
That would be a good SPI and a good DMA, in my opinion, and the extra
cost in silicon is negligible, compared to the added benefit. Why
don't most MCUs allow that? Even cheap MCUs could include that. An MCU
with the price of a SAM7 should include that, in my opinion.


Processing bigger blocks does save some interrupt overhead, but you
still need to handle all the data so the advantage may not be that big.
And 480 cycles is still a decent amount to do some work. ;-)

But with a bit of creativity, you can get bigger blocks from your DMA.
If you use "variable peripheral select" you can create a buffer with
your ADC transfers and dummy transfers to another chipselect in between
to get the required CS switching pattern. If you then set up the SPI
clock correctly, you can let the PDC perform the 100kHz interval
transfers up to 64k 'bytes' (including the dummies).

Another option is to use the SSC (as mentioned by others), this can
transfer up to 32 bits per transfer. Transfers can be started on an
external event on RF pin. If you tie a TC output to the RF input, you
can use the TC waveform mode to initiate the transfers.

But I agree, being able to program some interval timer (maybe TC) and
use that directly to initiate transfers to peripherals would be nice
to have. But as long as it's not there, see what is and try to get the
most out of that. And if you are not tied to the SAM7, check if there
are other CPU's that have features that suit your wishes.
 
Top