This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

using spidev with speeds greater than 4000000

Other Parts Discussed in Thread: AM3517

Hi,

I am using the AM3517 processor along with the TI v05.07 SDK that has Linux kernel version: 2.6.37. I wrote a usespace program to use spidev to transmit a block of data from the AM3517 chip to an Atmel uC. I want to use the spidev for speeds greater than 400000. However after explicitly setting the speed to 500000, I get the following when I run my code.

[ 286.275329] spidev spi1.0: setup: speed 3000000, sample leading edge, clk
normal
[ 286.283203] spidev spi1.0: setup mode 0, 8 bits/w, 5000000 Hz max --> 0
[ 286.290344] spidev spi1.0: spi mode 00
[ 286.296508] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.304382] spidev spi1.0: setup mode 0, 8 bits/w, 5000000 Hz max --> 0
[ 286.311340] spidev spi1.0: 8 bits per word
[ 286.316223] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.325378] spidev spi1.0: setup mode 0, 8 bits/w, 5000000 Hz max --> 0
[ 286.332427] spidev spi1.0: 5000000 Hz (max)
[ 286.338348] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.346191] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.355499] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.363372] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.372680] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.380554] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.389434] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.397277] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.406372] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.414276] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.424591] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal
[ 286.432434] spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal

My code is below- 

***********************Spi.c********************************

#include "Spi.h"
#include <iostream>

using namespace std;

int Spi::spiOpen(std::string devspi){
int statusVal = -1;
this->spifd = open(devspi.c_str(), O_RDWR);
if(this->spifd < 0){
perror("could not open SPI device");
exit(1);
}

statusVal = ioctl (this->spifd, SPI_IOC_WR_MODE, &(this->mode));
if(statusVal < 0){
perror("Could not set SPIMode (WR)...ioctl fail");
exit(1);
}

statusVal = ioctl (this->spifd, SPI_IOC_RD_MODE, &(this->mode));
if(statusVal < 0) {
perror("Could not set SPIMode (RD)...ioctl fail");
exit(1);
}

statusVal = ioctl (this->spifd, SPI_IOC_WR_BITS_PER_WORD, &(this->bitsPerWord));
if(statusVal < 0) {
perror("Could not set SPI bitsPerWord (WR)...ioctl fail");
exit(1);
}

statusVal = ioctl (this->spifd, SPI_IOC_RD_BITS_PER_WORD, &(this->bitsPerWord));
if(statusVal < 0) {
perror("Could not set SPI bitsPerWord(RD)...ioctl fail");
exit(1);
}

statusVal = ioctl (this->spifd, SPI_IOC_WR_MAX_SPEED_HZ, &(this->speed));
if(statusVal < 0) {
perror("Could not set SPI speed (WR)...ioctl fail");
exit(1);
}

statusVal = ioctl (this->spifd, SPI_IOC_RD_MAX_SPEED_HZ, &(this->speed));
if(statusVal < 0) {
perror("Could not set SPI speed (RD)...ioctl fail");
exit(1);
}
return statusVal;
}


int Spi::spiClose(){
int statusVal = -1;
statusVal = close(this->spifd);
if(statusVal < 0) {
perror("Could not close SPI device");
exit(1);
}
return statusVal;
}

int Spi::spiWriteRead( unsigned char *data, int length){

struct spi_ioc_transfer spi[length];
int i = 0;
int retVal = -1;

// one spi transfer for each byte

for (i = 0 ; i < length ; i++){

spi[i].tx_buf = (unsigned long)(data + i); // transmit from "data"
spi[i].rx_buf = (unsigned long)(data + i) ; // receive into "data"
spi[i].len = sizeof(*(data + i)) ;
spi[i].delay_usecs = 0 ;
spi[i].speed_hz = this->speed ;
spi[i].bits_per_word = this->bitsPerWord ;
spi[i].cs_change = 0;
}

retVal = ioctl (this->spifd, SPI_IOC_MESSAGE(length), &spi) ;

if(retVal < 0){
perror("Problem transmitting spi data..ioctl");
exit(1);
}

return retVal;

}

Spi::Spi(){
this->mode = SPI_MODE_0 ;
this->bitsPerWord = 8;
this->speed = 48000000;
this->spifd = -1;

this->spiOpen(std::string("/dev/spidev1.0"));

}


Spi::Spi(std::string devspi, unsigned char spiMode, unsigned int spiSpeed, unsigned char spibitsPerWord){
this->mode = spiMode ;
this->bitsPerWord = spibitsPerWord;
this->speed = spiSpeed;
this->spifd = -1;

this->spiOpen(devspi);

}
Spi::~Spi(){
this->spiClose();
}

************************main.cpp*******************

#include "Spi.h"

using namespace std;

int main(void)
{
Spi spi("/dev/spidev1.0", SPI_MODE_0, 5000000, 8);
//Spi spi;
int i = 6;
unsigned char data[1];
int rx_data=0;
while(i > 0)
{
data[0] = 1;
//data[1] = 'A';
//data[2] = 0;

spi.spiWriteRead(data, sizeof(data) );
rx_data = (int)data[0];
cout<<"the received data is:"<<rx_data<<endl;

i--;
}
return 0;
}

Any help on solving this?

  • Moving this to the Linux forum.

  • Did you check what is the setting for this structure field:  .max_speed_hz ?

    This should be located somewhere in a structure of this type:

    static struct spi_board_info beagle_spi_board_info[] = {
        {
            .modalias    = "spidev",
            .max_speed_hz    = 10000000, //10 Mbps
            .bus_num    = 3,
            .chip_select    = 0,   
            .mode = SPI_MODE_1,   
            },
    };

  • i went to arch/arm/mach-omap2 and found this in the boad-am3517evm.c

    * Board initialization
    */
    static struct omap_board_config_kernel am3517_evm_config[] __initdata = {
    };

    /* SPI */
    static struct spi_board_info tcw_spi_board_info[] = {
    {
    .modalias = "spidev",
    .max_speed_hz = 48000000, //48 Mbps
    .bus_num = 1,
    .chip_select = 0,
    .mode = SPI_MODE_3,
    },
    {
    .modalias = "spidev",
    .max_speed_hz = 48000000, //48 Mbps
    .bus_num = 2,
    .chip_select = 0,
    .mode = SPI_MODE_3,
    },

    };

    static struct omap_dmtimer_bl_platform_data omap_dm_timer_bl_pdata = {
    .gpio_onoff = GPIO_BACKL

    Do you reckon this is the right place to look for? How do i know which file is being used used for configuring the board during kernel configuration?

  • Some inconsistencies. You state a desired speed of 500000. Your fragment uses 5000000 in the Spi construction, eg

      Spi spi("/dev/spidev1.0", SPI_MODE_0, 5000000, 8);

    Extra zero. This print line:

      spidev spi1.0: setup mode 0, 8 bits/w, 5000000 Hz max --> 0

    suggests that the core driver (drivers/spi/spi.c) did get the 5000000 request. This line

      spidev spi1.0: setup: speed 3000000, sample leading edge, clk normal

    implies that the HW specific driver (drivers/spi/omap2_mcspi.c) applied the nearest speed under the desired frequency of 5000000. That would be 3000000 = 48000000/(2^div) where div is 4. The next speed would be 6000000 for a div of 3 and that would be greater than the desired speed of 5000000.

  • The 5k was a typing error. I am looking to achieve a baud rate greater than 4M and hence tried 5M as a test. 

    I always thought that explicitly specifying the speed such as spi[i].speed_hz = this->speed  would override the default speed. If I am to set a speed of say 6M as you mentioned above with div =3, how would i do it?

    Would writing something like this suffice?

    spi[i].speed_hz = 6000000;

    Also , a few questions from your above comment.

    1) You said that the core driver (drivers/spi/spi.c ) received my request for 5M baud rate and it passed this to omap2_mcspi.c?

    2) Does omap2_mcspi.c get called automatically by spi.c?

    3) Does that also mean that spi.c will call omap2_mcspi.c and DMA is automatically invoked when the size of my transfer exceeds a defined threshold(say when I'm looking to transfer 300 bytes of data as one block in one write cycle)?

    Thanks alot for your help!

  • I've never used this platform or spidev. I can make some guesses based upon examination of your code and kernel code. As far as I can tell in your code, the contructor initializes the speed member that is used later, ie.

      Spi spi("/dev/spidev1.0", SPI_MODE_0, 6000000, 8);

    You should see different values printed out.

    From inspection, you can see this calling path:
    drivers/spi/spidev.c:spidev_ioctl()
    drivers/spi/spi.c:spi_setup()
    drivers/spi/omap2_mcspi.c:omap2_mcspi_setup() via  pointer spi->master->setup()

    The bitbang module may be also be in there as it is the pseudo "superclass".

    As for DMA, review drivers/spi/omap2_mcspi.c. It appears to define 160 bytes as the threshold between PIO and DMA.

    #define DMA_MIN_BYTES                   160

    That's all I got. Best to just experiment to see what you get.