Using wireless modules through SPI

Quang Phan
Hi,

I bought a board simliar to the Mini2440 called the TQ2440.  The two boards
are almost exact replicas.  I followed one of the threads on this forum to
get the SPI driver to work and successfully tested the SPI with the test
code.  Everything works, but now I want to write code for my wireless
module nrF24L01+ through SPI.  Since you cannot access pins directly
because Linux does not allow it, how exactly do I transmit and receive data
through my module?

Quang Phan
Oh, here is the link to my board: 
http://www.cutedigi.com/product_info.php?products_id=4238

Thanks in advance!

open-nandra
What do you mean can't access SPI pins directly? You need to write your own
wifi driver and hook it to SPI for mini2440 and use SPI api to send and
receive data.

good luck,

marek

Quang Phan
Thanks for the response. So I just need to write the driver and add it to
the kernel?

open-nandra
Sure it's the easiest part ;). Try to search maybe something already
existing. If you have spec & maybe some spare module I can help ;).

marek

Quang Phan
the module im using is the Nordic nrf24l01+. 

Here is the datasheet if you want more information:

http://www.nordicsemi.com/files/Product/data_sheet/nRF24L01P_Product_Spe...

Quang Phan
So I have found written driver for my module so I am gonna use that.  Do I
just need to copy the c file into the kernel "driver" folder and create a
Makefile and do "make zImage" to make new image file to include the driver?

open-nandra
Well no so easy ;). In board file you need to hook driver to SPI and also
add driver to kernel compilation (could be done out of kernel tree). If you
have link to source I could help you with integration.

marek

Quang Phan
I found this on an chinese blog. I've also noticed that the pins defined in
this source code is different than what I used, so I changed that
accordingly(eg. S3C2410_GPE11, 12 and 13 for me.

Here is the source code. The comments are in chinese but other than that,
it is very readable.  You can also use google translate. 
http://blog.163.com/jammy_lee/blog/static/101195478201016112945395/

Thanks again.

open-nandra
So it is working for you or? I would say this is not very clean way to
write kernel module because it manipulate with SPI pins directly. Anyway
you could use spidev module and write code in userspace instead in kernel
(check kernel documentation). Will look @driver but currently I'm little
busy maybe till end of next week ;). 

Marek

Quang Phan
I haven't tested it.  I wasn't sure how to put this in the kernel and so
forth.  But I will try your suggestion.

Quang Phan
Hey Marek,

You said that you could use spidev module in userspace code so I
experimented with the spidev_test.c given in the tutorial. Looping back the
MISO and MOSI works without the module.  When the module is connected to
the corresponding pins, I cannot receive the data I am trying to
transmitted.  My professor told me that since SPI transmit and receive data
by byteswapping, you need to byteswap twice. I modified the code to call
transfer() function twice in main(), but it still doesnt work. Am I on the
wrong track?

Thanks,
Quang

open-nandra
Well no you can't call transfer 2 times. SPI bus works in way you send data
and with every clock you also receive data (check connection and signals if
they seems to be correct).

Quang Phan
I notice when hooking SPI driver to board, the board file contains
static struct spi_board_info __initdata tq2440_spi0_board_info[] = {
  // SPI Port 0
  {
    .modalias  = "spidev",
    .max_speed_hz  = 8000000, //8 Mbps
    .bus_num  = 0,
    .chip_select  = 0,  
    .mode     = SPI_MODE_1,
  },
};

static void tq2440_spi0_cs(struct s3c2410_spi_info *spi, int cs, int pol)
{
    s3c2410_gpio_setpin(S3C2410_GPG2, pol);
}

static struct s3c2410_spi_info tq2440_spi0_platdata = {
    .num_cs = 1,
    .bus_num = 0,
    .set_cs = tq2440_spi0_cs,
};

Since I am using in the driver above the pins are defined directly to the
SPI, if i add this to board file, would it have the same parameters(eg.
.max_speed_hz, .bus_num = 0,.chip_select,....etc). Not quite sure how to
hook my new driver to board file.

Thanks in advance.

open-nandra
Use this:
http://open-nandra.com/2010/09/friendly-arm-2440-and-sca3000-accelerometer/

instead:
.modalias       = "sca3000_d01"
use :
.modalias       = "spidev"

Quang Phan
Hey open-nandra,

I loaded the driver I found on the kernel and open the device using "mknod
/dev/nrf24l01 c 241 0" since it is a character device driver.  I tried
running a test program that just is similar to the code below. But it does
not work.  Is the read() and write() function suppose to work for the SPI
port?  
I tried looping back MISO and MOSI pins on the SPI and send/receive with
write() and read() function and it does not work. It does work however when
I use the spidev_test.c from the Linux Documentation(uses ioctl() function
to transfer).  

unsigned char TxBuf[32] = {0x00};

int main(void)

{

    int fd = -1;

    int count = 1;
 

    //fd = open("/dev/nrf24l01", 0);

    fd = open("/dev/nrf24l01", O_RDWR);  
//打开nrf24l01为可读写文件

    if(fd < 0)

    {

        perror("Can't open /dev/nrf24l01 \n");

        exit(1);

    }

    printf("open /dev/nrf24l01 success \n");

    while(count <= 5)
    {

        write(fd, &TxBuf , sizeof(TxBuf));

        printf("Sending %d time \n", count);

        usleep(100*1000);
           
        count++;
    }

    close(fd);
}

open-nandra
Yes write and read methods are supported by spidev. In write you just send
data which would like to send via SPI. Anyway you need to do initialization
like in spidev example (missing in your code).

Quang Phan
Are you referring to this section of the spidev example?

struct spi_ioc_transfer tr = {
    .tx_buf = (unsigned long)tx,
    .rx_buf = (unsigned long)rx,
    .len = ARRAY_SIZE(tx),
    .delay_usecs = delay,
    .speed_hz = speed,
    .bits_per_word = bits,
  };

Since I am not using ioctl(), would I use this from the spi.h? I am not
really sure how to initialize this.

spi_write(struct spi_device *spi, const u8 *buf, size_t len)
{
  struct spi_transfer  t = {
      .tx_buf    = buf,
      .len    = len,
    };
  struct spi_message  m;

  spi_message_init(&m);
  spi_message_add_tail(&t, &m);
}

open-nandra
I think you can reuse all code from spidev_test. I refer to transfer
function in example. So first configure device then use transfer to
send/receive message.

marek

Edwar
i have same problem with you chan. i want to connect an IC transmitter
CC2550 with my mini2440. can that source code be used universally?