Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
New Contributor I
3,075 Views

Question about Write/Read SPI functions for Edison (Mraa)

Hi,

I am currently working with VC0706 SPI camera module and Edison arduino board.

For Camera-to-Edison connection, I am using pins 10-13 on the Arduino breakout board.

1) First questions is: Do I need to somehow manually set pins10-13 to SPI pins instead of default digital I/O on the arduino? (If so how can I do that?)

2) I was wondering if anyone has confirmed that the SPI functions in Mraa Intel iot-devkit library works properly.

I've tried to send some commands to my camera via both http://iotdk.intel.com/docs/master/mraa/spi_8h.html# a794395b9eae7ed095c63beb76e8e6930 mraa_spi_write_buf() and http://iotdk.intel.com/docs/master/mraa/spi_8h.html# a967d966b11c2e0452a2df681f1e4aee1 mraa_spi_transfer_buf() but I don't think the commands are being sent properly to my VC0706 Camera. Also, wirte/transfer functions are supposed to return Data received on the MISO line but I am skeptical as to if it actually returns the 'output' from my camera. (Because I receive 0x00 + 0x00 + 0x00 + 0x00 + 0x00 but according to the camera datasheet, return value should begin with 0x76)

Example of the command:

Command function :System reset

Command format :0x56+Serial number+0x26+0x00

Return format :0x76+Serial number+0x26+0x00+0x00 (But I would receive 0x00 + 0x00 + 0x00 + 0x00 + 0x00)

My code:

# include "mraa.h"

# include

# include

int

main(int argc, char **argv) {

mraa_init();

mraa_spi_context spi;

spi = mraa_spi_init(0);

unsigned int response = 0;

printf("Hello, SPI initialised\n");

//mraa_spi_mode_t MRAA_SPI_MODE0;

//mraa_spi_mode (spi, MRAA_SPI_MODE0);

// printf("Set to SPI mode:0\n");

int freq = 12000000; // set SPI frequency to 12 MHz

mraa_spi_frequency (spi, freq);

printf("SPI clock frequency set to %iHz\n", freq);

uint8_t data[] = {0x56, 0x00, 0x26, 0x00};

uint8_t *recv;

recv = mraa_spi_write_buf(spi, data, 4);

printf("Writing System_Reset 0x%X + 0x%X + 0x%X + 0x%X\n", data[0], data[1], data[2], data[3]);

usleep(100000);

if (recv == NULL)

printf("Errors encountered when writing to camera\n");

else

printf("RECEIVED 0x%X + 0x%X + 0x%X + 0x%X + 0x%X\n",recv[0], recv[1], recv[2], recv[3], recv[4]);

usleep(100000);

uint8_t *rxbuf;

mraa_spi_transfer_buf (spi, data, rxbuf, 4);

printf("Transfering System_Reset 0x%X + 0x%X + 0x%X + 0x%X\n", data[0], data[1], data[2], data[3]);

usleep(100000);

if (rxbuf == NULL)

printf("Errors encountered when transfering to camera\n");

else

printf("RECEIVED 0x%X + 0x%X + 0x%X + 0x%X + 0x%X\n",rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4]);

usleep(100000);

}

Thanks,

-Danny

0 Kudos
22 Replies
Highlighted
Employee
15 Views

Hi danny7yoo

Are you using the pins as :

MOSI: pin 11

MISO: pin 12

SCK: pin 13

What are you using in pin 10, "chip select" pin?

You are using https://github.com/intel-iot-devkit/mraa/blob/master/examples/spi_mcp4261.c this example as template so you should't have problems. Are you using a logic analyzer? If you do, are you writing as you should? Take a look at MISO signal and verify that you are writing what you want.

Regards;

CMata

Highlighted
New Contributor I
15 Views

Hi CMata,

Thanks for the reply. I do not have access to a logic analyzer as university is closed for the holiday.

One question regarding MISO. I thought the Edison is sending commands to the SPI device through MOSI and then receiving it back through MISO line? So shouldn't I be checking MOSI line to see if I'm sending the correct signal?

Thanks,

Danny

Highlighted
Employee
15 Views

Yes, sorry for that, you should check MOSI signal

0 Kudos
Highlighted
New Contributor I
15 Views

Writing System_Reset 0x56 + 0x0 + 0x26 + 0x0

RECEIVED 0x0 + 0x0 + 0x0 + 0x0 + 0x0

Transfering System_Reset 0x56 + 0x0 + 0x26 + 0x0

RECEIVED 0x85 + 0xC0 + 0x74 + 0x2A + 0x8B

 

I am getting this result which is no where close to what I am supposed to receive (0x76+0x00r+0x26+0x00+0x00 )

I am curious as to the difference between mraa_spi_write_buf, mraa_spi_transfer_buf

Highlighted
New Contributor I
15 Views

Hi CMata,

for pin10, I've connected it to SPI_SS pin from the VC0706 camera module.

I'm new to SPI but I know that SS needs to be set low in order to activate the slave(camera)? Is is done automatically on the Edison side?

-Danny

Highlighted
Valued Contributor III
15 Views

I will chime in a bit here as I have SPI working using MRAA (and Arduino) for use with the Adafruit TFT displays that use the ILI9341 display.

Some thoughts that come to mind, that I have run into and the like:

First the easy thing. The difference between write_buf and transfer_buf. (I added transfer_buf). write_buf calls transfer_buf. The difference is that write_buf calls malloc to allocate the read buffer, that is returned and as such your user application is responsible to free this buffer. Whereas transfer_buf, you pass in the buffer that you wish to use and if it is some fixed buffer you avoid having a lot of mallocs/frees going on Also if you are really only doing a write and don't need the return results, you can pass in NULL, and the kernel does not have to take the time to copy the data back to your buffer.

Also MRAA does initialize the SCLK, MISO, MOSI and CS to be in SPI mode when the spi_init is called.

Currently with user mode spi (through SPIDEV), the fastest speed that it appears to support is 6.5mhz. In addition for whatever reason there is a pretty big gap of time between bytes sent, so so lucky to maybe get about 3mhz. Hopefully this will change as the specs say that SPI can support up to 25mhz?

CS pin - By default MRAA now initializes the CS pin (Arduino pin 10) to be in SPI mode. This may be good or bad. The issue is, that there does not appear to be any control of it from the user side (SPIDEV). There are flags that are parts of the IOCTL control, that is supposed to allow you to choose if the CS pin should stay asserted or not between calls. Right now I believe that the CS goes low for each byte and then back high. It may have changed to do this by the wordsize mentioned in the IOCTL. Not sure.

This did not work for me in the ILI9341 driver, especially for read operations. As for example if you are in a read operation to get the state of several pixels, the chip will continue to output bytes of data to you as long as the CS stays asserted. So my code currently manually controls the CS pin. I do this by initializing the CS pin to gpio after the spi init call completes. This does all of the stuff needed to switch that pin back to GPIO mode (mode0) instead of being in SPI mode (mode1). Note: in my case I have a second GPIO pin that is used by the chip to know if the bytes are to be used as data or to be used as commands....

good luck

0 Kudos
Highlighted
New Contributor I
15 Views

Thanks Kurt for the detailed response.

I have a better understanding of SPI now. However, if transfer_buf and write_buf are essentially the same except the read buffer(memory), I don't understand why I would get a different reading.

e.g.

Writing System_Reset 0x56 + 0x0 + 0x26 + 0x0

RECEIVED 0x0 + 0x0 + 0x0 + 0x0 + 0x0

Transfering System_Reset 0x56 + 0x0 + 0x26 + 0x0

RECEIVED 0x85 + 0xC0 + 0x74 + 0x2A + 0x8B

I am not sure if I am even sending the intended command to MOSI properly, so i'll have to wait until Monday to get access to a logic analyzer at school.

 

Regarding CS pin(10), do you have a sample code as an example to show me how to get the CS pin to GPIO instead of SPI after initialization?

-Danny

0 Kudos
Highlighted
Valued Contributor III
15 Views

In your above program I am surprised that the Transfer is working and not faulting... That is: if you look at the code:

uint8_t *rxbuf;

mraa_spi_transfer_buf (spi, data, rxbuf, 4);

printf("Transfering System_Reset 0x%X + 0x%X + 0x%X + 0x%X\n", data[0], data[1], data[2], data[3]);

usleep(100000);

if (rxbuf == NULL)

printf("Errors encountered when transfering to camera\n");

else

printf("RECEIVED 0x%X + 0x%X + 0x%X + 0x%X + 0x%X\n",rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4]);

You see that you are passing rxbuf, to transfer which is simply a pointer so hopefully initialized to something valid or could easily fault, if 0, it would be passing NULL pointer and no data would be

returned.

in this case you should probably do uint8_t rxbuf[5];

to have an actual buffer available to read and write data to.

Forgot to look to see if on your write buffer case, if you free the memory back up or not. Not a main issue for short run test apps, but if part of a program that does lots of stuff can cause crashes at different times.

As for examples: I have the actual ILI9341 driver using it that is part of my Raspberry Pi project. This is a version of the code that builds directly under linux.

It is up on github.com under kurte/Raspberry_Pi. It is in the ILI9341... directory. Note: Soon I will be pushing up a similar version of this code as part of my Eclipse Workspace for doing work for my PhantomX Hexapod, also has some test apps and the like.

Kurt

0 Kudos
Highlighted
New Contributor I
15 Views

Hey Kurt,

When the mraa_spi_transfer_buf() is called, is the 'data' being sent through the MOSI line and then the return value from MISO is saved in the rxbuf?

 

I'm a little confused because it looks like the data is being sent through MISO instead.

D3 = pin 13 (CLK)

D2 = pin 12 (MOSI)

D1 = pin 11 (MISO)

D0 = pin 10 (Signal select)

 

Transfering System_Reset 0x56 + 0x0 + 0x26 + 0x0 (So this is MISO?)

RECEIVED 0x0 + 0x0 + 0x0 + 0x0 + 0x0 (So this is MOSI?)

 

 

Thanks,

Danny

 

 

 

0 Kudos
Highlighted
Valued Contributor III
15 Views

Hi, yes transfer works for me.

For example from some of my code to talk to the Adafruit display, I have code that copies lines of data from one part of the display to another part as part of a scroll operation. something like:

for (int y=(_y+CHAR_HEIGHT+1); y < (_y+_h-2); y++) { tft.readRect(_x+1, y, _w-2, 1, awColors); // try to read one row at a time... tft.writeRect(_x+1, y-CHAR_HEIGHT, _w-2, 1, awColors); // try to read one row at a time...

}

Where the tft.readRect is implemented:

oid Adafruit_ILI9341::readRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *pcolors)

{

uint16_t c = w * h;

spi_begin();

setAddr(x, y, x+w-1, y+h-1);

writecommand_cont(ILI9341_RAMRD); // read from RAM

DCHigh(); // make sure we are in data mode

uint8_t txdata[X86_BUFFSIZE * 3]; // how many to read at a time

memset(txdata, 0, X86_BUFFSIZE * 3);

uint8_t rxdata[X86_BUFFSIZE * 3]; // how many to read at a time

rxdata [0]= spiread(); // Read a DUMMY byte of GRAM

while (c){

uint16_t cRead = min (c, X86_BUFFSIZE);

mraa_spi_transfer_buf(SPI, txdata, rxdata, cRead * 3);

for (uint16_t i=0; i < cRead*3; i+=3) {

*pcolors++ = color565(rxdata[i], rxdata[i+1], rxdata[i+2]);

}

c -= cRead;

}

CSHigh();

spi_end();

}

This code could probably be cleaned up some, but shows how I am reading data back from the display. I init the TX buffer to be all zeros to send. Wish I could pass NULL pointer for TX buffer in spidev, when I don't care about send, but that faults...

0 Kudos
Highlighted
Employee
15 Views

Hi danny7yoo

Do you have any updates in this? Are you still having questions about this?

Regards;

CMata

0 Kudos
Highlighted
New Contributor I
15 Views

Hi CMata,

Sorry for the delayed reply.

I gave up on SPI camera for my project. I am looking to use a USB camera instead, using the UVC interface.

I gave up on SPI not because of the Edison but due to such poor documentation of SPI camera in general. The datasheet is so incomplete and poorly written for most SPI cameras out there.

Regards,

Danny

Highlighted
Novice
15 Views

Hi Kurt,

i wanted to use CS0 and CS1 as separate Chip-selects as you seem to do.

In my case, i initialized the CS as GPIO after spi_init, but it seems,that CS1 is connected to SPI.

How can i switch back to GPIO mode (sample code ?) ?

I can use CS0 as separate Chip-select, but not CS1. I guess CS0 is never switched to SPI-mode, CS1 always.

Regards,

Stefan Verse

0 Kudos
Highlighted
Valued Contributor III
15 Views

I am not sure how you have things set up. I only created one SPI object and use it for both logical devices. So I never did anything to let system know about CS1... So I simply manually set the IO state of which CS (likewise DC) pin to what I need before and after calls to SPI.transfer. So again I am not sure how you currently have yours set up.

Kurt

0 Kudos
Highlighted
Novice
15 Views

The setup is quite the same as yours,

i have an FPGA connected to spi and use it for communication with registers in the FPGA and also talk to a display.

This works with one spi object and using CS0 manually (framing many spi transfers).

Now i wanted to talk to another spi-object on the line using CS1 and found, that CS1 is activated during every spi-transfer on each byte. It seems that CS1 is connected to SPI always.

I tried to initialize the CS-GPIO after the SPI object, but CS1 stays connected to SPI.

Because i have an FPGA inbetween, i could switch to another GPIO line, but you mentioned you have a way to switch the CS-Line back to GPIO-Mode – so far i haven't found out how.

Stefan

0 Kudos
Highlighted
Novice
15 Views

As i can see the GPIO_init (mraa_setup_mux_mapped) should switch the CS pin to GPIO mode, but doesn't seem to work for me.

I'm wandering also, why CS1 is connected to SPI - is CS1 the arduino pin 10 ?

Stefan

0 Kudos
Highlighted
Valued Contributor III
15 Views

Sorry not sure what is all going on in your system. Would need to see more what is connected to what and how your code is initialized...

CS0 on Arduino board is on pin 10, For my Adafruit shield, this is the TFT cs. This is the one where I initialize SPI and then initialize GPIO on this pin, which changes pin 10 back to GPIO mode (mode 0) and as such the changes by SPI subsystem do not make it out to the IO pin. On this shield pin 9 is the DC pin and pin 8 is the CS associated with the touch screen. Note: if you call SPI initialize again after setting pin 10 to GPIO mode it may very well change it back to SPI mode (mode1). So you need to check to see the order of when things are done.

0 Kudos
Highlighted
Novice
15 Views

The CS signals are initialized after the spi. Above is a plot of the signals - i recorded the first three spi transfers - two with cs0 and one with cs1 - both set manually.

As you can see in line cs1 - it is always activated with each byte, but never manually framing 3 spi_bytes.

Here is my initialisation-code with all three transfers (two times SPI_WRITE and one for cs1 afterwards).

Maybe you can see something.

Stefan

# include "mraa.h"

mraa_spi_context spi;

mraa_gpio_context gpio_cs0;

mraa_gpio_context gpio_cs1;

mraa_i2c_context i2c0;

mraa_uart_context uart;

uint8_t display_mode;

uint16_t SPI_write(uint8_t reg, uint8_t dh, uint8_t dl)

{

uint8_t buf[3];

buf[0]=reg;

buf[1]=dh;

buf[2]=dl;

mraa_gpio_write(gpio_cs0, 0);

mraa_spi_transfer_buf(spi,&buf[0],&buf[0],3);

mraa_gpio_write(gpio_cs0, 1);

return(((buf[1]<<8) | buf[2]));

}

void UTFT::_hw_special_init()

{

display_mode = 0;

mraa_init();

mraa_set_priority(99);

mraa_gpio_context gpio_done = mraa_gpio_init(48); //15

mraa_gpio_context gpio_init = mraa_gpio_init(36);//14

mraa_gpio_context gpio_prog = mraa_gpio_init(15); //165

mraa_gpio_dir(gpio_init, MRAA_GPIO_IN);

mraa_gpio_dir(gpio_done, MRAA_GPIO_IN);

mraa_gpio_dir(gpio_prog, MRAA_GPIO_IN);

spi = mraa_spi_init(0);

gpio_cs0 = mraa_gpio_init(23);

gpio_cs1 = mraa_gpio_init(14);

mraa_gpio_mode(gpio_cs0, MRAA_GPIO_STRONG);

mraa_gpio_mode(gpio_cs1, MRAA_GPIO_STRONG);

mraa_gpio_dir(gpio_cs0, MRAA_GPIO_OUT);

mraa_gpio_dir(gpio_cs1, MRAA_GPIO_OUT);

mraa_gpio_write(gpio_cs0, 1);

mraa_gpio_write(gpio_cs1, 1);

SPI_write(0x01,0x00,0x01);

uint8_t dip_sw;

dip_sw=SPI_write(0x87,0x00,0x00);

flip_x = (dip_sw>>0) & 0x01;

flip_y = (dip_sw>>1) & 0x01;

uint8_t buf[3];

buf[0]=0x85;

buf[1]=0;

buf[2]=0;

mraa_gpio_write(gpio_cs1, 0);

mraa_spi_transfer_buf(spi,&buf[0],&buf[0],3);

mraa_gpio_write(gpio_cs1, 1);

i2c0 = mraa_i2c_init(1);

mraa_i2c_address(i2c0,0x55);

mraa_i2c_write_byte(i2c0,0xA9);

uart = mraa_uart_init(0);

system("/bin/stty < /dev/ttyMFD1 115200");

int fd = open("/dev/ttyMFD1",O_RDWR);

write(fd,"X",1);

}

0 Kudos
Highlighted
Valued Contributor III
15 Views

Yep - If you look at the MRAA sources, for when SPI is init, it will call this function:

mraa_result_t

mraa_intel_edison_spi_init_pre(int bus)

{

if (miniboard == 1) {

mraa_intel_edison_pinmode_change(111, 1);

mraa_intel_edison_pinmode_change(115, 1);

mraa_intel_edison_pinmode_change(114, 1);

mraa_intel_edison_pinmode_change(109, 1);

return MRAA_SUCCESS;

}

As you can see in this code it is setting physical pins (111, 115, 104, 109) to Mode 1, which is SPI mode. If you look at 111, you see that it is MRAA pin 9(J17-10) This is also SPI-5-CS1. So this is CS1... on the MINI board (Note on Arduino this is the CS pin used for SPI...).

If you dont't want this, you can either create a GPIO pin for this pin, or simply all like the above, but mode 0.

mraa_intel_edison_pinmode_change(111, 0);

0 Kudos