SAMC21: SPI receiving problem - Page 1
Forum section: electronics / general

author: Yipee
author_rank: Contributor
timestamp: March 08, 2021, 02:02:48 pm
content: Hello,I am trying to receive SPI communication. I am using SAMC21 Xplained Pro board. I selected this MCU because the project should use two CAN interfaces but I'm stuck at the beggining. Also I'm begginer at MCU's.I am able to receive data from Arduino Uno, but it requires delays between SS edges and between bytes. But when I connected it to real device it didn't worked. Then I tried to connect SERCOM1 as SPI slave and SERCOM5 as SPI master. I tested if I can receive data via SERCOM1 with the Arduino Uno (still with delays) and I connected oscilloscope to SERCOM5 to check if it is sending data. Both seems okay, but when I connect SERCOM5 to SERCOM1 the receiving does not work.My code base is from ASF examples for polled SPI:https://asf.microchip.com/docs/3.49.1/samc21/html/asfdoc_sam0_sercom_spi_slave_basic_use.htmlhttps://asf.microchip.com/docs/3.49.1/samc21/html/asfdoc_sam0_sercom_spi_master_basic_use.htmlMain loop:Code:while (1) {if(!port_pin_get_input_level(BUTTON_0_PIN)) {spi_select_slave(&spi_master_instance, &slave, true);spi_write_buffer_wait(&spi_master_instance, buffer, SPI_BUF_LENGTH);spi_select_slave(&spi_master_instance, &slave, false);port_pin_set_output_level(LED_0_PIN, LED0_ACTIVE);}if (spi_read_buffer_wait(&spi_slave_instance, buffer_rx, SPI_BUF_LENGTH, 0x00) == STATUS_OK) {uint8_t ok = true;for(uint8_t i = 0; i < SPI_BUF_LENGTH; i++) {ok &= buffer_rx == buffer;}port_pin_set_output_level(LED_0_PIN, LED0_INACTIVE);}}Slave mux settings:Code:#define CONF_SLAVE_SPI_MODULE SERCOM1#define CONF_SLAVE_MUX_SETTING SPI_SIGNAL_MUX_SETTING_O#define CONF_SLAVE_PINMUX_PAD0 PINMUX_PA16C_SERCOM1_PAD0#define CONF_SLAVE_PINMUX_PAD1 PINMUX_PA17C_SERCOM1_PAD1#define CONF_SLAVE_PINMUX_PAD2 PINMUX_PA18C_SERCOM1_PAD2#define CONF_SLAVE_PINMUX_PAD3 PINMUX_PA19C_SERCOM1_PAD3Master mux settings:Code:#define CONF_MASTER_SPI_MODULE SERCOM5#define CONF_MASTER_MUX_SETTING SPI_SIGNAL_MUX_SETTING_E#define CONF_MASTER_PINMUX_PAD0 PINMUX_PB02D_SERCOM5_PAD0#define CONF_MASTER_PINMUX_PAD1 PINMUX_PB03D_SERCOM5_PAD1#define CONF_MASTER_PINMUX_PAD2 PINMUX_PB00D_SERCOM5_PAD2#define CONF_MASTER_PINMUX_PAD3 PINMUX_PB01D_SERCOM5_PAD3Rest of code should be the same as examples.I also tried to modify ASF SPI slave callback example but I received only one interrupt and then nothing - the program never ran to handler again. But I tested it only against Arduino Uno where the communication was working with SPI polling.I don't need the master SPI, I use it now just for debug, if I can receive what I sent with no delays cheat, do you know what am I doing wrong?Is it possible to send and receive data using one MCU without interrupts?Now I am trying writing directly to registers, but I don't have it working yet.

author: ataradov
author_rank: Super Contributor
timestamp: March 08, 2021, 08:18:56 pm
content: I don't fully understand your description. Your want a SPI slave and it works if you insert pauses between the bytes? How fast is your clock and how long of a pause you need to insert?

author: oliviasmithh900
author_rank: Contributor
timestamp: March 08, 2021, 10:54:56 pm
content: Quote from: Yipee on March 08, 2021, 02:02:48 pmYeah you can send data continuously via SPI Protocol .... that's why SPI is for

author: Yipee
author_rank: Contributor
timestamp: March 09, 2021, 09:53:26 am
content: Quote from: ataradov on March 08, 2021, 08:18:56 pmIt requires 10µs long pause after SS LOW and before SS HIGH and 6µs between bytes. I haven't checked it by oscilloscope, but these are minimal values set to Arduino's functionDelayMicroseconds. When I set lower values then it shifts order of bytes or could not read it at all.I had set clock divider to three, so the frequency of SAMC21 should be 16MHz. With the pauses I could receive data up to baud 16Mbits, but without them it did not receive anything even if the baud was set to 100kbits.Now I also noticed that when I set buffer length 2 or less then the loop from SERCOM5 to SERCOM1 works at full speed without delays. I even tested baud 24Mbits (with clock set to 48Mhz) and it works. Unfortunatelly I need to receive three bytes long value.Quote from: oliviasmithh900 on March 08, 2021, 10:54:56 pmThanks, but I meant the question if MCU can receive data on SPI1 which were sent from SPI5 by the same MCU without callbacks (using pooling only). I know I asked wrong question, my fault. But I already know the answer: it is possible. I thought it whole time, just my code was convincing me opposite.Which register should I "kill" to receive at least 3 bytes long value as fast as possible?

author: Yipee
author_rank: Contributor
timestamp: March 09, 2021, 03:50:14 pm
content: I noticed that when the buffer size is bigger than two bytes then I am stil able to receive first two bytes. The RX buffer loads first two bytes with received data but the rest of the buffer is filled by zeroes.But I think I solved the problem with callback version. When I calledspi_read_buffer_jobagain after receiving data, then it seems working fast. I thought that I tried this million times but maybe I had there another bug...Thank you for your support. Now I'm just curious why only two bytes are fast when using the pooling. Do you have an idea?

author: ataradov
author_rank: Super Contributor
timestamp: March 09, 2021, 05:14:59 pm
content: Quote from: Yipee on March 09, 2021, 09:53:26 amThe drivers in ASF are highly inefficient. They should be able to receive at 100 kBits/s though. But if you want high performance, you would have to write high performance code. And you need to run at the fastest possible clock.How fast you can receive 1 or 2 bytes is irrelevant, since this is done by the hardware. After that software needs to receive the buffered data.So I'd say what you are observing is normal and if you want things to be fast, you need to write fast drivers. And for that you need to dispose of the ASF. You can leave the clock initialization stuff and all that, but you will have to write the SPI driver yourself.

author: Yipee
author_rank: Contributor
timestamp: March 11, 2021, 07:33:41 am
content: Quote from: ataradov on March 09, 2021, 05:14:59 pmThank you for the answer. It is a wishlist item to write the drivers by myself but for now the ASF solution is good enough.

author: Yipee
author_rank: Contributor
timestamp: March 17, 2021, 11:18:44 am
content: I am here again. The loop from SPI5 to SPI1 works like charm, but I tried to connect Arduino again (Arduino -> SPI1, SPI5 not connected). It reads few values then it stops reading. By "few values" I mean something between 0 and 200000. When Moon is in good conjunction with Mars then it can receive even more values.To the problem: when it stops receiving, all SPI interrupt flags are set except error flag. The error flag can be set too, but it is not a rule. I have callback for SPI_CALLBACK_BUFFER_RECEIVED, but it is not called an more - transfer_complete_spi_slave is false. When I call spi_abort_job and then register it again with spi_read_buffer_job, then an overflow error is raised.What is the correct way to handle this situation? I tried a lot of things (even init the spi again), but when it stops reading I couldn't get it working again. I know, the best solution would be to write own spi driver, but there is no time for it now.

author: Yipee
author_rank: Contributor
timestamp: March 17, 2021, 03:39:28 pm
content: Quote from: Yipee on March 17, 2021, 11:18:44 amI solved it by using DMA.I don't know if the problem appears again, but it seems a lot better now.