ATSAMD51 constantly receives wrong data over SERCOM/SPI

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using an ATSAMD51G18 where I have two SPI input channels that receive 24 bit frames. They act as slave completely and get the clock from the connected master. SCK and /SS are the same for both SPIs, the two data-lines make use of different sources but both are absolutely synchronously to SCK and /SS. The transmitted data come with an integrated error detection on software level (parity bit). Using this bit I noticed a constant error in received data of 0,21%.

 

That's how I initialise my two SPIs for reception of data:

 

   // SCK:  PA05
   // /SS:  PA06
   // DATA: PA07
   gpio_set_pin_function(CLKY, PINMUX_PA05D_SERCOM0_PAD1);
   gpio_set_pin_function(SYNCY, PINMUX_PA06D_SERCOM0_PAD2);
   gpio_set_pin_function(Y, PINMUX_PA07D_SERCOM0_PAD3);

   MCLK->APBAMASK.bit.SERCOM0_ = 1;
   GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK4 | GCLK_PCHCTRL_CHEN;

   SERCOM0->SPI.CTRLA.bit.ENABLE = 0;
   while(SERCOM0->SPI.SYNCBUSY.bit.ENABLE);
   SERCOM0->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(2) | SERCOM_SPI_CTRLA_DOPO(0) | SERCOM_SPI_CTRLA_DIPO(3) | SERCOM_SPI_CTRLA_CPHA;
   SERCOM0->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_RXEN /*| SERCOM_SPI_CTRLB_MSSEN | SERCOM_SPI_CTRLB_PLOADEN*/;
   SERCOM0->SPI.CTRLC.reg = SERCOM_SPI_CTRLC_DATA32B;
   SERCOM0->SPI.LENGTH.reg = SERCOM_SPI_LENGTH_LENEN | SERCOM_SPI_LENGTH_LEN(3);
   SERCOM0->SPI.CTRLA.bit.ENABLE = 1;
   while(SERCOM0->SPI.SYNCBUSY.bit.ENABLE);

   // SCK:  PA22
   // /SS:  PA20
   // DATA: PA21
   gpio_set_pin_function(CLKX, PINMUX_PA22D_SERCOM5_PAD1);
   gpio_set_pin_function(SYNCX, PINMUX_PA20C_SERCOM5_PAD2);
   gpio_set_pin_function(X, PINMUX_PA21C_SERCOM5_PAD3);

   MCLK->APBDMASK.bit.SERCOM5_ = 1;
   GCLK->PCHCTRL[SERCOM5_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK4 | GCLK_PCHCTRL_CHEN;

   SERCOM5->SPI.CTRLA.bit.ENABLE = 0;
   while(SERCOM5->SPI.SYNCBUSY.bit.ENABLE);
   SERCOM5->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(2) | SERCOM_SPI_CTRLA_DOPO(0) | SERCOM_SPI_CTRLA_DIPO(3) | SERCOM_SPI_CTRLA_CPHA;
   SERCOM5->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_RXEN /*| SERCOM_SPI_CTRLB_MSSEN | SERCOM_SPI_CTRLB_PLOADEN*/;
   SERCOM5->SPI.CTRLC.reg = SERCOM_SPI_CTRLC_DATA32B;
   SERCOM5->SPI.LENGTH.reg = SERCOM_SPI_LENGTH_LENEN | SERCOM_SPI_LENGTH_LEN(3);
   SERCOM5->SPI.CTRLA.bit.ENABLE = 1;
   while(SERCOM5->SPI.SYNCBUSY.bit.ENABLE);

 

And this is my receiving function:

 

if (SERCOM5->SPI.INTFLAG.bit.RXC) // checking one SPI port should be enough since both are running completely parallel
{
   uint32_t data1=SERCOM5->SPI.DATA.reg;
   uint32_t data2=SERCOM0->SPI.DATA.reg;
}

 

After that I'm doing the error-check with the contents of data1 and data2 and there can see wrong data arriving with a probability of 0,21%

 

Any idea what could be wrong in my code (probably in my initialisation or clock settings?)

 

Thanks!

 

Update: the wrong data arrive randomly on both channels, so I would think it has nothing to do with the fact that I'm checking RXC of one channel only.

 

Last Edited: Wed. Jul 15, 2020 - 11:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried some more with this and found following strange effect: In example above the SPI makes use of GCLK4 which is at 90 MHz. When I change this and use GCLK2 instead (which is at 30 MHz in my configuration), the error rate is even higher and I have more than 50% damaged frames!

 

So this seems there are some collisions between the external clock of the SPI master (SCLK is at about 2,4 MHz) which is sending the data, and the internal SERCOM-clock of the SPI slave which is receiving the data. But shouldn't the slave be a slave of the external clock completely? How is it possible the internal clock, the SERCOM-device is operated with, has some influence on this?

 

Thanks!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I made some progress: it has nothing to do with the SERCOM-clocks, I accidentially changed them in parallel to the real reason and therefore came to this wrong conclusion.

 

So the received data are corrupted whenever the ATSAMD starts while the SPI-master is already sending data. Means the synchronisation of the frames via /SS does not seem to work. That's what I tried:

 

  • first start the SPI-master and let it send data
  • next start my ATSAMD, very likely in the middle of a SPI-frame of the already running data transmission

-> FAIL, received data are damaged

 

  • first start my ATSAMD
  • next start the SPI-master and let it send data, here the ATSAMD receives the very first frame from the very beginning as it is already available

-> OK, the received data all are fine

 

  • start my ATSAMD
  • start the SPI-master and let it send data
  • reboot the SPI-master in the middle of an SPI-frame so that the last frame before reboot is incomplete

-> FAIL, received data are damaged

 

So it seems the ATSAMD receives crap whenever it does not see the full length of the 24 bit frame. Means the synchronisation to a frame via /SS does not seem to work properly. This also may explain why one have to set the expected frame length of three bytes via that weird

SERCOMx->SPI.LENGTH.reg = SERCOM_SPI_LENGTH_LENEN | SERCOM_SPI_LENGTH_LEN(3);

while the MCU should be able to count the frame length based on the received clocks during a /SS-cycle.

 

So...does anybody have an idea how to fix/workaround this problem? Syncing to a SPI frame automatically should be one of the base features of an SPI device...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Some more information: as the symptoms described above let one assume, /SS is not used and the SPI simply counts the bits via SCK, I made two more tests:

 

  • send data while /SS is at high permanently
  • send data while /SS is at low permanently

 

In both cases nothing could be received. So to sum it up: it seems, the SERCOM-SPI requires the /SS-framing for a data packet but ignores it for the received data when there is one packet in between where the size does not match. Means /SS low/high is used for receiving a frame but not for ensuring it is received correctly.

 

So as this seems to be a larger problem:

 

  • where/how can get one (even paid) support from Atmel/Microchip?
  • where can one report a hardware bug?

 

Thanks!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Typically both chips should be running before data is transmitted in any protocol.  Assuming that you mean both are in the bebugger and you are releasing them, try allowing the slave SPI to execute in debug.  Then the hardware will get the first packet.  Still this can cause buffer overrun.

 

The only way I see to prevent this is to have a GPIO out from slave to master, nRDY, with a pullup on the master input.  An unpowered chip will pull up and a not ready chip will output high (or open drain).

nRDY tells the master the slave is ready.

jeff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry but I do not agree with you: it is the purpose of the /SS signal to have a clear and non-ambiguous synchronisation between master and slave - to find where a frame starts and where it ends. And even when the slave starts receiving in the middle of a frame, only that very first frame should be damaged and all following ones should be correct. What we see here is that all frames are damaged when the first one has been incomplete.

 

And the problem is not a buffer overrun or something like that, the problem is, the received data are wrong.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Disagree or not.  My point is that if the system is not running, the physical state outside the chip is not represented inside the chip.  The first packer has an incorrect number of SCK, it may be possible - depends on the implementation - for it to stay out of sync until the shift register is reset.

jeff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jcandle wrote:
for it to stay out of sync until the shift register is reset.

 

That's what I said: for the FIRST frame it is OK to stay out of sync when the receiver started somewhere in the middle of an already running transmission. But for the NEXT frame everything should be fine - but it isn't, ALL following frames are damaged once the receiver was out of sync for the very first frame!