i.MX6 SPI slave occasionally missing RX bursts

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

i.MX6 SPI slave occasionally missing RX bursts

1,110件の閲覧回数
christian_s
Contributor II

On our custom i.MX6Q based board we use the SPI controller as slave.

Since we are running under Linux, we had to write a custom SPI slave driver.

This driver is very lean. It's basically just bare metal register configuration and IRQ handling - no unneccessary overhead.

The driver seems to work pretty good, because the master can communicate with our board and we can answer.

However occasionally the SPI controller seems to be missing SPI bursts from the master.

My test environment:

  • Raspberry Pi 2 as SPI master sending an 8 bit value that is incremented by 1 each iteration
  • 8 bits per word
  • SPI mode 0
  • very slow SPI clock: 7629Hz
  • 100ms delay between each burst
  • Slave just sends back the data it received

Even though the IRQ load on the i.MX6 is extremely low, about 0.5% of all SPI bursts are not recognized/lost by the i.MX6 SPI controller.

Things get worse as we increase the clock speed.

I read about the silicon SPI bug on the i.MX6, but as far I understood this only applies to burst lengths of (32 * n) + 1.

Does anyone have an idea what might be going wrong?

My relevant source code:

SPI Master main loop:

uint8_t i = 0;

while ( 1 ) {

    tx_buffer = i++;

    rc = ioctl(fd, SPI_IOC_MESSAGE(1), &transfer);

    if ( rc < 0 ) {

        printf("Error transmitting SPI frame\n");

        exit(255);

    }

    fprintf(f, "Sent: 0x%.2X - Received: 0x%.2X\n", tx_buffer, rx_buffer);

    usleep(100 * 1000);

}

Slave Kernel configuration code:

reg = 0x70f4e1; // 7629Hz 8bpw

writel(reg, slave->io_base + OFFSET_CONREG);

reg = 0;

writel(reg, slave->io_base + OFFSET_CONFIGREG);

reg = 0;

reg |= MX51_ECSPI_INT_RREN;

writel(reg, slave->io_base + OFFSET_INTREG);

Slave ISR code:

static irqreturn_t spi_slave_isr(int irq, void *dev_id) {

    struct spi_slave_data* slave = dev_id;

    unsigned value;

    unsigned rxcnt;

    value = readl(slave->io_base + OFFSET_TESTREG);

    rxcnt = (value & MASK_RX_FIFO_COUNT) >> SHIFT_RX_FIFO_COUNT;

    for ( ; rxcnt; --rxcnt ) {

        value = readl(slave->io_base + OFFSET_RXDATA);

        writel((uint32_t)value, slave->io_base + OFFSET_TXDATA); // just resend what we just received

        printk(KERN_INFO "rx: 0x%.2X\n", value); // not a problem here because we have 100ms delay

    }

    return IRQ_HANDLED;

}

Erroneous console output on the slave:

rx: 0x91

rx: 0x92

rx: 0x93

rx: 0x94

rx: 0x95

rx: 0x96

rx: 0x98

rx: 0x99

rx: 0x9A

rx: 0x9B

Note that 0x97 is missing

Corresponding output on the master:

Sent: 0x92 - Received: 0x91

Sent: 0x93 - Received: 0x92

Sent: 0x94 - Received: 0x93

Sent: 0x95 - Received: 0x94

Sent: 0x96 - Received: 0x95

Sent: 0x97 - Received: 0x95

Sent: 0x98 - Received: 0x56

Sent: 0x99 - Received: 0x98

Sent: 0x9A - Received: 0x99

Sent: 0x9B - Received: 0x9A

Sent: 0x9C - Received: 0x9B

Thanks for any help in advance.

Chris

ラベル(2)
0 件の賞賛
1 返信

588件の閲覧回数
alejandrolozan1
NXP Employee
NXP Employee

Hi,

I have not tried to implement a driver for the ECSPI  module as slave in Linux. But you may find useful the below document:

i.MX6 ESPI slave mode support patch based on rel_imx_3.0.35_4.1.0

The driver is non-dtb compatible, so you will have to perform a few changes. I believe it´s worth taking a look at it.

Best Regards,

Alejandro

0 件の賞賛