I have a SPI connection between two AVRs, an XMEGA 128a1 and an AT90USB162. The AT90, running at 8MHz, is the master. The SPI runs at 4MHz. The reason for making the AT90 master is 1) I can run SPI at 4MHz, 2) I can use DMA for SPI on the XMEGA (slave only), and 3) easier for the slower AT90 to be master. I am sending packets of 32 bytes and am using SPI F.
DMA transfers are non-deterministic due to the fact that the CPU has priority. Thus, if the cpu spends a long time accessing the SRAM, the DMA must wait to become bus master. I only need the DMA to transfer 1 byte at a time, each triggered by SPI transfer complete.
As a slave, the XMEGA has a small amount of time to write to the SPI data register before the the AT90 begins shifting it out. If the DMA writes to the data register too late, the write collision flag should be set. My code detects this. Furthermore, if the write is delayed an integer multiple, the collision flag will not be set, but the bytes will be out of sync. My code detects this as well (using a timeout timer, as the DMA transfer complete interrupt will not fire in this case due to pending transfers). Either of these cases will trigger a packet re-transmission.
While this is an XMEGA, the AVR151 app note suggests that if a write into the SPI data register would cause a collision, the WCOL flag is set and the write aborted so as not to cause corruption. In my case, the DMA corrupts the data.
When a write collision occurs, the WRCOL flag seems to be set most of the time, but not all. Maybe this is because multiple collisions are occurring in each packet. I would expect the flag to be only set by hardware, and cleared only by reading the status register then the data register (or reset).
Does anyone have any experience with slave SPI and DMA on the XMEGA, that can shed some light on these problems? When I have time, I will prepare a minimal amount of code to reproduce the problem to send to Atmel, but I am not fond of doing this given there are two programs on two chips, so I thought I would ask here first.
While I'm posting, I should point out that the XMEGA loses the SPI interrupt when waking from sleep if both interrupt and DMA are used (ie: DMA write, interrupt read) (Atmel confirmed).
BTW, my code on the AT90 is purposely inefficient to space out the individual bytes for now (I am using global variables which require SRAM access, rather than autos that can be put into registers). It is only when I decrease the time between bytes (I can see this on my scope) that these problems occur.
EDIT: Problem #1 is not really a problem as long as WRCOL is set. I just didn't expect that behavior.