AnsweredAssumed Answered

i.MX6 SPI slave occasionally missing RX bursts

Question asked by christian_s on Oct 10, 2015
Latest reply on Oct 20, 2015 by alejandrolozano

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

Outcomes