I did the same thing on a AT32UC3C0512 (yet, I was the master which probably made it a bit easier).
The idea is probably the following (if you're using the ASF framework, it should work in slave mode as well):
- Call spi_get(SPI)
- Loop until spi_is_rx_ready(SPI) or until you run into a timeout
- Call spi_get(SPI) for the next byte (or 10 byte or whatever you set the spi_rx register size to be)
- Do this a few times until you received all bytes
Here's some code as a starting point, hope it helps a little:
volatile avr32_spi_t *spi = device->spi;
unsigned int timeout = SPI_TIMEOUT;
timeout = SPI_TIMEOUT;
while (!spi_is_rx_ready(spi)) {
if (!timeout--) {
tmc260_deselect_device(device);
return ERR_TIMEOUT;
}
}
// Store the received data
rx_msb = spi_get(spi);
I'm not quite sure what has to be done to reset the flag which is set once a byte was received. I would assume simply reading the rx register should do the trick.
It should also be possible to port this code to using interrupts (call the ISR whenever a byte was received/RX register is full).
From the AT32UC3C0512 datasheet:
The SPI waits for NSS to go active before receiving the serial clock from an external master.
When NSS falls, the clock is validated on the serializer, which processes the number of bits
defined by the Bits Per Transfer field of the Chip Select Register 0 (CSR0.BITS). These bits are
processed following a phase and a polarity defined respectively by the CSR0.NCPHA and
CSR0.CPOL bits. Note that the BITS, CPOL, and NCPHA bits of the other Chip Select Registers
have no effect when the SPI is configured in Slave Mode.
The bits are shifted out on the MISO line and sampled on the MOSI line.
When all the bits are processed, the received data is transferred in the Receive Data Register
and the SR.RDRF bit rises. If the RDR register has not been read before new data is received,
the SR.OVRES bit is set. Data is loaded in RDR even if this flag is set. The user has to read the
SR register to clear the SR.OVRES bit.
As far as I understand, a flag will be set after 8 to 10 databits. For a first try, you will need to read the data and see if the flag gets raised a second time, even if CS doesn't get asserted a second time.
An alternative solution
You can also use an interrupt on the SCK line (depending on the mode on the rising or falling edge) and sample the data "manually". Once you discover a condition where SCK rises (or falls) and CS is high, you are outside the "normal" datatransfer and you start a new reception.
I did something like this before (around 2006), I need to speed up the programming of SPI flash devices in our production and we want to do parallel SPI operation for all the 8 flash device. So thinking out of the box, what I did is:
- create a fixture which can slot in 8 devices
- the CS pin, CLK, MOSI are all connected in common to all device. So all flash devices, receive the commands from these pins at the same time.
- For reading, I used a full port (PORTB0 to PORTB7) to connect to the individual MISO of the flash devices.
This was a success. It used SPI bitbanging and involves bit-shifting to form the data read from the port. But still very fast than accessing or reading an SPI device one at a time.
But I see that you are using PIC32MZ2048 and only 2 SPI device, maybe you can try exploring the QSI (Quad Serial Interface) if it can achieve your needs without resorting to bitbanging.
Best Answer
Yes. According to the "PIC32MZ Embedded Connectivity (EC) Family" datasheet, page 1, it has "Six 4-wire SPI modules". Those peripheral interfaces will be independent.
It also has DMA, so those ports can be read with minimal CPU overhead.
How many SPI interfaces are actually available depends on the package, and which pins are available.