{"id":476,"date":"2012-10-17T12:28:52","date_gmt":"2012-10-17T12:28:52","guid":{"rendered":"https:\/\/raspberry-projects.com\/pi\/?p=476"},"modified":"2019-08-01T19:46:09","modified_gmt":"2019-08-01T19:46:09","slug":"using-the-spi-interface","status":"publish","type":"post","link":"https:\/\/raspberry-projects.com\/pi\/programming-in-c\/spi\/using-the-spi-interface","title":{"rendered":"Using The SPI Interface"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\">Resources<\/h4>\n\n\n\n<p><a href=\"https:\/\/www.raspberrypi.org\/documentation\/hardware\/raspberrypi\/spi\/README.md\">https:\/\/www.raspberrypi.org\/documentation\/hardware\/raspberrypi\/spi\/README.md<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/www.kernel.org\/doc\/Documentation\/spi\/spidev\">https:\/\/www.kernel.org\/doc\/Documentation\/spi\/spidev<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Enabling The SPI&nbsp;Port <\/h4>\n\n\n\n<p>The SPI&nbsp;port needs to be enabled in Rasbian before it can be used. See&nbsp;<a href=\"https:\/\/raspberry-projects.com\/pi\/pi-operating-systems\/raspbian\/io-pins-raspbian\/spi-pins\">here<\/a>. <\/p>\n\n\n\n<p>Leave the IO pins used unconfigured (do not set them as inputs or outptus). <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Using The SPI Port With The BCM2835 library by Mike McCauley <\/h4>\n\n\n\n<p>This uses the same library as used for the IO pins &#8211; see <a href=\"https:\/\/raspberry-projects.com\/pi\/programming-in-c\/c-libraries\/bcm2835-by-mike-mccauley\">here<\/a>. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\/\/Setup SPI pins\n\tbcm2835_spi_begin();\n\t\n\t\/\/Set CS pins polarity to low\n\tbcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, 0);\n\tbcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS1, 0);\n\t\n\t\/\/Set SPI clock speed\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_65536 = 0,       \/\/\/&lt; 65536 = 262.144us = 3.814697260kHz (total H+L clock period) \n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_32768 = 32768,   \/\/\/&lt; 32768 = 131.072us = 7.629394531kHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_16384 = 16384,   \/\/\/&lt; 16384 = 65.536us = 15.25878906kHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_8192  = 8192,    \/\/\/&lt; 8192 = 32.768us = 30\/51757813kHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_4096  = 4096,    \/\/\/&lt; 4096 = 16.384us = 61.03515625kHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_2048  = 2048,    \/\/\/&lt; 2048 = 8.192us = 122.0703125kHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_1024  = 1024,    \/\/\/&lt; 1024 = 4.096us = 244.140625kHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_512   = 512,     \/\/\/&lt; 512 = 2.048us = 488.28125kHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_256   = 256,     \/\/\/&lt; 256 = 1.024us = 976.5625MHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_128   = 128,     \/\/\/&lt; 128 = 512ns = = 1.953125MHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_64    = 64,      \/\/\/&lt; 64 = 256ns = 3.90625MHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_32    = 32,      \/\/\/&lt; 32 = 128ns = 7.8125MHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_16    = 16,      \/\/\/&lt; 16 = 64ns = 15.625MHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_8     = 8,       \/\/\/&lt; 8 = 32ns = 31.25MHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_4     = 4,       \/\/\/&lt; 4 = 16ns = 62.5MHz\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_2     = 2,       \/\/\/&lt; 2 = 8ns = 125MHz, fastest you can get\n\t\/\/\tBCM2835_SPI_CLOCK_DIVIDER_1     = 1,       \/\/\/&lt; 1 = 262.144us = 3.814697260kHz, same as 0\/65536\n\tbcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_128);\n\n\t\/\/Set SPI data mode\n\t\/\/\tBCM2835_SPI_MODE0 = 0,  \/\/ CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge\n\t\/\/\tBCM2835_SPI_MODE1 = 1,  \/\/ CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge, output data (change) on rising edge\n\t\/\/\tBCM2835_SPI_MODE2 = 2,  \/\/ CPOL = 1, CPHA = 0, Clock idle high, data is clocked in on falling edge, output data (change) on rising edge\n\t\/\/\tBCM2835_SPI_MODE3 = 3,  \/\/ CPOL = 1, CPHA = 1, Clock idle high, data is clocked in on rising, edge output data (change) on falling edge\n\tbcm2835_spi_setDataMode(BCM2835_SPI_MODE0);\t\t\/\/(SPI_MODE_# | SPI_CS_HIGH)=Chip Select active high, (SPI_MODE_# | SPI_NO_CS)=1 device per bus no Chip Select\n\n\t\/\/Set with CS pin to use for next transfers\n\tbcm2835_spi_chipSelect(BCM2835_SPI_CS0);\n\n\t\/\/Transfer 1 byte\n\t\/\/uint8_t data;\n\t\/\/data = bcm2835_spi_transfer((uint8_t)0x55);\n\t\n\t\/\/Transfer many bytes\n\tchar data_buffer[10];\n\tint Count;\n\tfor (Count = 0; Count &lt; 10; Count++)\n\t\tdata_buffer[Count] = 0x80 + Count;\n\tbcm2835_spi_transfern(&amp;data_buffer[0], 10);\t\t\t\/\/data_buffer used for tx and rx\n\t\n\t\/\/Return SPI pins to default inputs state\n\t\/\/bcm2835_spi_end();<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Using The SPI Port Without the BCM2835 Library <\/h4>\n\n\n\n<p>This working example is based on the excellent example <a href=\"http:\/\/hertaville.com\/2013\/07\/24\/interfacing-an-spi-adc-mcp3008-chip-to-the-raspberry-pi-using-c\/\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;fcntl.h>\t\t\t\t\/\/Needed for SPI port\n#include &lt;sys\/ioctl.h>\t\t\t\/\/Needed for SPI port\n#include &lt;linux\/spi\/spidev.h>\t\/\/Needed for SPI port\n#include &lt;unistd.h>\t\t\t\/\/Needed for SPI port\n#include &lt;stdio.h>\n#include &lt;stdlib.h>\n#include &lt;string>\n#include &lt;iostream>\n#include &lt;unistd.h>\n#include &lt;cstring>\n\nint spi_cs0_fd;\t\t\t\t\/\/file descriptor for the SPI device\nint spi_cs1_fd;\t\t\t\t\/\/file descriptor for the SPI device\nunsigned char spi_mode;\nunsigned char spi_bitsPerWord;\nunsigned int spi_speed;\n\n\n\n\n\/\/***********************************\n\/\/***********************************\n\/\/********** SPI OPEN PORT **********\n\/\/***********************************\n\/\/***********************************\n\/\/spi_device\t0=CS0, 1=CS1\nint SpiOpenPort (int spi_device)\n{\n\tint status_value = -1;\n    int *spi_cs_fd;\n\n\n    \/\/----- SET SPI MODE -----\n    \/\/SPI_MODE_0 (0,0) \tCPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge\n    \/\/SPI_MODE_1 (0,1) \tCPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge, output data (change) on rising edge\n    \/\/SPI_MODE_2 (1,0) \tCPOL = 1, CPHA = 0, Clock idle high, data is clocked in on falling edge, output data (change) on rising edge\n    \/\/SPI_MODE_3 (1,1) \tCPOL = 1, CPHA = 1, Clock idle high, data is clocked in on rising, edge output data (change) on falling edge\n    spi_mode = SPI_MODE_0;\n    \n    \/\/----- SET BITS PER WORD -----\n    spi_bitsPerWord = 8;\n    \n    \/\/----- SET SPI BUS SPEED -----\n    spi_speed = 1000000;\t\t\/\/1000000 = 1MHz (1uS per bit) \n\n\n    if (spi_device)\n    \tspi_cs_fd = &amp;spi_cs1_fd;\n    else\n    \tspi_cs_fd = &amp;spi_cs0_fd;\n\n\n    if (spi_device)\n    \t*spi_cs_fd = open(\"\/dev\/spidev0.1\", O_RDWR);\n    else\n    \t*spi_cs_fd = open(\"\/dev\/spidev0.0\", O_RDWR);\n\n    if (*spi_cs_fd &lt; 0)\n    {\n        perror(\"Error - Could not open SPI device\");\n        exit(1);\n    }\n\n    status_value = ioctl(*spi_cs_fd, SPI_IOC_WR_MODE, &amp;spi_mode);\n    if(status_value &lt; 0)\n    {\n        perror(\"Could not set SPIMode (WR)...ioctl fail\");\n        exit(1);\n    }\n\n    status_value = ioctl(*spi_cs_fd, SPI_IOC_RD_MODE, &amp;spi_mode);\n    if(status_value &lt; 0)\n    {\n      perror(\"Could not set SPIMode (RD)...ioctl fail\");\n      exit(1);\n    }\n\n    status_value = ioctl(*spi_cs_fd, SPI_IOC_WR_BITS_PER_WORD, &amp;spi_bitsPerWord);\n    if(status_value &lt; 0)\n    {\n      perror(\"Could not set SPI bitsPerWord (WR)...ioctl fail\");\n      exit(1);\n    }\n\n    status_value = ioctl(*spi_cs_fd, SPI_IOC_RD_BITS_PER_WORD, &amp;spi_bitsPerWord);\n    if(status_value &lt; 0)\n    {\n      perror(\"Could not set SPI bitsPerWord(RD)...ioctl fail\");\n      exit(1);\n    }\n\n    status_value = ioctl(*spi_cs_fd, SPI_IOC_WR_MAX_SPEED_HZ, &amp;spi_speed);\n    if(status_value &lt; 0)\n    {\n      perror(\"Could not set SPI speed (WR)...ioctl fail\");\n      exit(1);\n    }\n\n    status_value = ioctl(*spi_cs_fd, SPI_IOC_RD_MAX_SPEED_HZ, &amp;spi_speed);\n    if(status_value &lt; 0)\n    {\n      perror(\"Could not set SPI speed (RD)...ioctl fail\");\n      exit(1);\n    }\n    return(status_value);\n}\n\n\n\n\/\/************************************\n\/\/************************************\n\/\/********** SPI CLOSE PORT **********\n\/\/************************************\n\/\/************************************\nint SpiClosePort (int spi_device)\n{\n\tint status_value = -1;\n    int *spi_cs_fd;\n\n    if (spi_device)\n    \tspi_cs_fd = &amp;spi_cs1_fd;\n    else\n    \tspi_cs_fd = &amp;spi_cs0_fd;\n\n\n    status_value = close(*spi_cs_fd);\n    if(status_value &lt; 0)\n    {\n    \tperror(\"Error - Could not close SPI device\");\n    \texit(1);\n    }\n    return(status_value);\n}\n\n\n\n\/\/*******************************************\n\/\/*******************************************\n\/\/********** SPI WRITE &amp; READ DATA **********\n\/\/*******************************************\n\/\/*******************************************\n\/\/SpiDevice\t\t0 or 1\n\/\/TxData and RxData can be the same buffer (read of each byte occurs before write)\n\/\/Length\t\tMax 511 (a C SPI limitation it seems)\n\/\/LeaveCsLow\t1=Do not return CS high at end of transfer (you will be making a further call to transfer more data), 0=Set CS high when done\nint SpiWriteAndRead (int SpiDevice, unsigned char *TxData, unsigned char *RxData, int Length, int LeaveCsLow)\n{\n\tstruct spi_ioc_transfer spi;\n\tint i = 0;\n\tint retVal = -1;\n\tint spi_cs_fd;\n\n\tif (SpiDevice)\n\t\tspi_cs_fd = spi_cs1_fd;\n\telse\n\t\tspi_cs_fd = spi_cs0_fd;\n\n\tspi.tx_buf = (unsigned long)TxData;\t\t\/\/transmit from \"data\"\n\tspi.rx_buf = (unsigned long)RxData;\t\t\/\/receive into \"data\"\n\tspi.len = Length;\n\tspi.delay_usecs = 0;\n\tspi.speed_hz = spi_speed;\n\tspi.bits_per_word = spi_bitsPerWord;\n\tspi.cs_change = LeaveCsLow;\t\t\t\t\t\t\/\/0=Set CS high after a transfer, 1=leave CS set low\n\n\tretVal = ioctl(spi_cs_fd, SPI_IOC_MESSAGE(1), &amp;spi);\n\n\tif(retVal &lt; 0)\n\t{\n\t\tperror(\"Error - Problem transmitting spi data..ioctl\");\n\t\texit(1);\n\t}\n\n\treturn retVal;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Useful Resources <\/h4>\n\n\n\n<p><a href=\"http:\/\/hertaville.com\/2013\/07\/24\/interfacing-an-spi-adc-mcp3008-chip-to-the-raspberry-pi-using-c\/\">http:\/\/hertaville.com\/2013\/07\/24\/interfacing-an-spi-adc-mcp3008-chip-to-the-raspberry-pi-using-c\/<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Issues <\/h4>\n\n\n\n<p>&#8220;Error &#8211; Problem transmitting spi data..ioctl: Invalid argument <\/p>\n\n\n\n<p>Due to changes in the underlying library the spi_ioc_transfer struct&nbsp;now&nbsp;needs to be initialised to NULL, and a hacky fix is to add this&nbsp;to the beginning of the for loop (this has been done in the code example above) <\/p>\n\n\n\n<p>memset(&amp;spi[i], 0, sizeof (spi[i])); <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Resources https:\/\/www.raspberrypi.org\/documentation\/hardware\/raspberrypi\/spi\/README.md https:\/\/www.kernel.org\/doc\/Documentation\/spi\/spidev Enabling The SPI&nbsp;Port The SPI&nbsp;port needs to be enabled in Rasbian before it can be used. See&nbsp;here. Leave the IO pins used unconfigured (do not set them as inputs or outptus). Using The SPI Port With The BCM2835 library by Mike McCauley This uses the same library as used for the IO [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-476","post","type-post","status-publish","format-standard","hentry","category-spi"],"_links":{"self":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/476","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/comments?post=476"}],"version-history":[{"count":27,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/476\/revisions"}],"predecessor-version":[{"id":3111,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/posts\/476\/revisions\/3111"}],"wp:attachment":[{"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/media?parent=476"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/categories?post=476"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/raspberry-projects.com\/pi\/wp-json\/wp\/v2\/tags?post=476"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}