SERCOM SPI not working on SAME54 - ASF4

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

Hello,

I'm unable to successfully use the SPI Synchronous Master driver from Atmel START to read data. I'm using a SAM E54 Xplained Pro board, and trying to communitcate with an FTDI display controller.

I have the CPU clocked at 48MHz, and the SPI core and slow clocks also set to 48MHz. Most of the other SPI settings are left to the default; the baud rate in Atmel START is set to 50,000, and the receive buffer is enabled.

This is basically how I've been trying to initialize and use SPI:

struct io_descriptor *spi_io = NULL;

int main(void)
{
    // Initializes MCU and drivers, including SPI pins and clock
    atmel_start_init();

    spi_m_sync_enable(&SPI_0);
    spi_m_sync_get_io_descriptor(&SPI_0, &spi_io);

    ...

    // For writes:
    unsigned char w = 13;
    io_write(spi_io, &w, 1);

    // For reads:
    unsigned char r = 0;
    io_read(spi_io, &r, 1);
}

The display controller has four ID registers that return known values when read (I send the register's address over SPI, then the register's value is received in the next byte). However, reading any of these registers returns the same value (a 4).

What I've tried:

  • Connecting the SAM board's MISO pin to ground or Vcc. Reading in bytes will return zero's or 0xFF's as expected.
  • Changing the baud rate in config/hpl_sercom_config.h. This either makes the reads return zero or has no effect.
  • Changing the SPI clock speed (to 12MHz or 400kHz). This either makes the reads return zero or has no effect.
  • Using different pins for SPI. No change.

I don't have access to a logic analyzer to closer inspect the signals. I'm suspecting that my clock or baud settings are wrong, as I'm not sure what code changes I could make.

I was able to write a bit-banged SPI transfer function that works successfully, but it's far too slow. If seeing that code would help solve my issue, let me know.

Can anyone help me figure this out, or provide any suggestions?

 

This topic has a solution.
Last Edited: Mon. Feb 4, 2019 - 11:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

FTDI display controller ok but which is it? You might have a problem with the slave select pin, I think you would need to control it manually to have the slave selected for both the write and the read part of reading a register. 

/Lars

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

The controller's an FT81x. I'm pretty certain the slave select pin isn't the issue; I've ported a library for the FT81x to the SAM board, called Gameduino, and it works without issue using the bit-banged SPI code.

Since it works fine like that, I think the issue lies somewhere in configuring Atmel START's SPI driver, which I have little experience with.

Last Edited: Sun. Jan 20, 2019 - 03:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You will have to show the SPI configuration (i.e., the config done in START) and the actual (failing) code for reading and writing registers in the FT81x.

/Lars

 

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

I have the SPI configured in START as follows:

  • Driver: HAL:Driver:SPI_Master_Sync
  • Instance: SERCOM6
  • MISO: PC07, MOSI: PC04, SCK: PC05
  • Core and Slow clock set to a 48MHz source (CPU is also at 48MHz)
  • Receive buffer enabled
  • 8-bit character size
  • Baud rate of 50,000
  • No advanced configuration: dummy byte 0x1FF, MSB first, SCK low when idle, Sample input on leading edge

Code:

// While loop from Gameduino library, attempting to read identifying
// value 0x08 from register 0xC0000
while ((__rd16(0xC0000UL) & 0xFF) != 0x08)
    ;


// __rd16 implementation from Gameduino, modified for SAM E54
// spi_write_byte does an io_write(spi_io, (uint8_t *)&byte, 1)
// spi_read_bytes does an io_read(spi_io, (uint8_t *)bytes, count)
static unsigned int __rd16(uint32_t addr)
{
    uint32_t r = 0;
    
    gpio_set_pin_level(SPI_CS_N, false);
    spi_write_byte((addr >> 16) & 0xFF);
    spi_write_byte((addr >> 8) & 0xFF);
    spi_write_byte(addr & 0xFF);
    spi_write_byte(0);
    spi_read_bytes(&r, sizeof(uint32_t));
    gpio_set_pin_level(SPI_CS_N, true);
    return r;
}

I'd like to reiterate that the Gameduino library worked flawlessly with the bit-banged SPI code. SPI writes and reads were done with this code:

// Where MOSI and SCK are outputs, and MISO is an
// input with no pull-up or pull-down
uint8_t spi_xfer_byte(uint8_t send)
{
    uint8_t recv = 0;
    
    gpio_set_pin_level(SCK, false);
    for (int i = 0; i < 8; i++) {
        gpio_set_pin_level(MOSI, (send & (1 << (7 - i))));
        gpio_set_pin_level(SCK, true);
        if (gpio_get_pin_level(MISO))
            recv |= (1 << (7 - i));
        gpio_set_pin_level(SCK, false);
    }
    
    return recv;
}

Maybe my START configuration doesn't match with how the bit-banged code works?

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

Has anyone done Master SPI reading/writing on the SAME54 or similar?

The above bit-banged code communicates with the FT81x without issue, so the problem is most likely in configuring SERCOM SPI.

I've switched to the Lite:SPI:SPI_Master driver in START:

  • Using SERCOM5 now. MISO PB17, MOSI PB00, SCK PB01.
  • 1MHz core clock, 32.768 kHz slow clock.
  • Baud rate of 9600.
  • Everything else left to START's defaults.

I call SPI_0_enable() (from the lite driver), then do calls to SPI_0_exchange_data(). Reading or writing to the FT81x produces no results.

 

Is my clock for SPI too fast or slow? My 1MHz source comes from the Digital Frequency Locked Loop (DFLL48M); could that create issues?

Can anyone provide any help or info for getting SERCOM SPI to work?

 

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

DFLL48M is supposed to generate 48MHz nothing else. Or do you divide it 48 times to get 1 MHz? If you attach a project I could check if the SERCOM outputs anything (but I would have to adapt it to SAMD51).

/Lars

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 

I no longer have the issue I've been describing, though how the issue was solved is still unclear to me. I did divide DFLL48M to 1 MHz.

I got access to an oscilloscope with a logic probe, and watched the SPI transaction between the SAME54 and the display controller. The chip select signal (controlled by gpio_set_pin_level calls) would not stay low throughout the transaction; it would flicker high and low as each byte was clocked out.

So I used a different pin for chip select, though that didn't work. My issue finally resolved after switching around between SERCOMs and pin configurations. I would like to note that (according to my memory, but pretty certain) Atmel START let me use pins for functions the data sheet said were not allowed, e.g. using a PAD[0] or PAD[2] pin for SCK when SCK can only be PAD[1]. I skipped START and wrote my own code for pin configuration, which ended up working.

 

Hope this helps anyone with a similar issue.