SPI and chip select pins


9 posts
by planeta9999 » Tue Jan 22, 2013 10:35 pm
Hello:

Im starting now with Raspberry pi, and I want develop several boards for it.
I have think about connect via a parallel port with 8 bits and some lines to activate latches, but also may be interesting work via SPI.

About SPI, seem that there are only available 2 chip select pins, so really do not offer many options. I may add for example a PIC microcontroller to comunicate with Raspberry via SPI, but also may connect with SPI chips for I/O functions that do not need any microcontroller, but to do it need some more chip select pins.

So the question is if its possible use additional GPIO pins for SPI Chip Select functions, besides the 2 official pins provided for it. For example with 3 chip select pins and a demultiplexer, will have 8 Chip Select lines.


Regards
Posts: 13
Joined: Wed Dec 26, 2012 10:39 pm
by Arjan » Wed Jan 23, 2013 4:24 pm
Hi,

You can use a 74HC138/9 for creating more /CS lines. See attachment for an example.

Sample code for selecting the three DAC's (MCP49x2) :
Code: Select all
         bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
         bcm2835_gpio_clr(HC139_A_GPIO_PIN);
         bcm2835_gpio_set(HC139_B_GPIO_PIN);
         bcm2835_gpio_set(LDAC_GPIO_PIN);
         bcm2835_spi_writenb(dac12_1[x], sizeof(dac12_1[x]));
         bcm2835_spi_writenb(dac12_2[x], sizeof(dac12_2[x]));
         bcm2835_gpio_clr(LDAC_GPIO_PIN);
         bcm2835_gpio_set(HC139_A_GPIO_PIN);
         bcm2835_gpio_clr(HC139_B_GPIO_PIN);
         bcm2835_spi_writenb(dac8_1[x], sizeof(dac8_1[x]));
         bcm2835_spi_writenb(dac8_2[x], sizeof(dac8_2[x]));
         bcm2835_gpio_clr(HC139_A_GPIO_PIN);
         bcm2835_gpio_clr(HC139_B_GPIO_PIN);
         bcm2835_spi_writenb(dac8_1[x], sizeof(dac8_1[x]));
         bcm2835_spi_writenb(dac8_2[x], sizeof(dac8_2[x]));
Attachments
74HC139.png
74HC139.png (7.56 KiB) Viewed 5312 times
Posts: 128
Joined: Sat Sep 08, 2012 1:59 pm
by planeta9999 » Wed Jan 23, 2013 5:38 pm
Arjan wrote:Hi,
You can use a 74HC138/9 for creating more /CS lines. See attachment for an example.


Ok, thanks Arjan.
I see your schematic and source code example, understand that always must select one of the two official chip select pins CE0 or CE1, and then you mix it with 2 more GPIO pins in a demultiplexer 74HC138/9 with 3 inputs and 8 ouputs, so understand will may get up to 16 CS lines to control 16 SPI devices (CE0 + 2 x GPIO and CE1 + 2 x GPIO).

Very interesting your solution.
But then always must use one of the two official CS pins, CE0 or CE1 ???
I mean that can not use for example GPIO24 or GPIO25 alone or another pin alone to work like CS pin for SPI. Raspberry SPI always require to use CE0 or CE1 like CS ???


Regards
Posts: 13
Joined: Wed Dec 26, 2012 10:39 pm
by NickieNay » Fri Feb 08, 2013 1:49 am
Hi Planet,

I have limited knowledge of SPI, but I don't see why one of the GPIO pins wouldn't work for extra chip select.

Pull low during transmission, drive high to end transmission.

I'm in the middle of interfacing Playstation 2 controllers with the R-Pi, and am thinking of doing this if I need more than two controllers.

~Nick
Posts: 1
Joined: Fri Feb 08, 2013 1:44 am
by Arjan » Fri Feb 08, 2013 8:54 am
Hi,

When you don't want to use the built in SPI controller, then you can basically use any GPIO pin for SPI. Doing this, you need to write the SPI logic in your own code : bit-banging. This code gives more extensive use of the CPU.

Better solution would be to extend the SPI /CS lines with a 138/139.
Then using Mike's library or using /dev/spidev. The latter is slow.

Arjan.
Posts: 128
Joined: Sat Sep 08, 2012 1:59 pm
by RichardBronosky » Mon Jul 08, 2013 6:48 pm
Arjan wrote:When you don't want to use the built in SPI controller, then you can basically use any GPIO pin for SPI. Doing this, you need to write the SPI logic in your own code : bit-banging. This code gives more extensive use of the CPU.

Better solution would be to extend the SPI /CS lines with a 138/139.
Then using Mike's library or using /dev/spidev. The latter is slow.


I hope that this bitbanging suggestion is not the only option. It seems to me that since CE0 and CE1 are GPIO8 and GPIO7 pins, any/most of the other free 12 GPIO pins should be usable. It would just require a tweak of the library. As long as you can pull those bits low and release them with the proper timing. http://elinux.org/RPi_SPI#Chip_Select suggests that to be <=3 clock cycles before and >=1 clock cycle after.

I have never done EE so I can only apply my software development knowledge to the problem.

I would love to hear a follow up from anyone who does >2 SPI device interfacing. I need this for my next project.
-- Richard Bronosky
2x Raspberry Pi 512MB
User avatar
Posts: 58
Joined: Thu Feb 14, 2013 5:38 pm
Location: Atlanta, GA, USA
by Arjan » Mon Jul 08, 2013 7:52 pm
Hi,

I am not suggesting to use bit-banging ;)
Better solution would be to extend the SPI /CS lines with a 138/139.


See for an example interface : viewtopic.php?p=333992#p333992
And here for the SPI-DAC board (3 SPI devices) : viewtopic.php?p=366647#p366647
Posts: 128
Joined: Sat Sep 08, 2012 1:59 pm
by RichardBronosky » Tue Jul 09, 2013 3:45 pm
Arjan wrote:Hi,

I am not suggesting to use bit-banging ;)
Better solution would be to extend the SPI /CS lines with a 138/139.


See for an example interface : viewtopic.php?p=333992#p333992
And here for the SPI-DAC board (3 SPI devices) : viewtopic.php?p=366647#p366647


Those ILDA postings are way over my head. I can't extract the relevant info out of that.

So, at first I thought that your 74HC139 (4 port) was like an SPI shift register. I was going to complain that if you have to use CE1 to specify the chip that CE0 selects, aren't you going be subverting the SPI lib and basically be doing some bit banging anyway? However, I did some research before I posted (I know this is not common internet practice ;-) and read the logic tree on this datasheet: https://futurlec.com/74HC/74HC139.shtml (I really suck at reading EE datasheets and diagrams, but as a software developer, logic flow diagrams make perfect sense to me.)

From that it seems that you are suggesting this:
1. Connect the G (enable) pin to CE0.
2. Connect the A & B (select) pins to a pair of gpio pins.
3. Connect the Y pins (outputs 0-3) to the CS of each SPI devices.

Then the code should function like so:
1. Use code to activate the pair of gpio pins to choose the SPI device to use for this cycle.
2. Use the SPI library to read the device.
3. Profit.

Is that right?
-- Richard Bronosky
2x Raspberry Pi 512MB
User avatar
Posts: 58
Joined: Thu Feb 14, 2013 5:38 pm
Location: Atlanta, GA, USA
by Arjan » Wed Jul 24, 2013 10:09 am
Then the code should function like so:
1. Use code to activate the pair of gpio pins to choose the SPI device to use for this cycle.
2. Use the SPI library to read the device.
3. Profit.


That is correct.

I use the following for working with multiple DAC's
Code: Select all
#include <bcm2835.h>
#include <spi_dac.h>

.macro FUNC name
.text
.code 32
.global \name
\name:
.endm

.cpu arm1176jzf-s
.fpu vfp

FUNC spi_select_mcp4922
@ void spi_select_mcp4922(void)
ldr r0, =BCM2835_GPIO_BASE
mov r1, #(1 << HC139_A_GPIO_PIN)
str r1, [r0, #BCM2835_GPCLR0]
mov r1, #(1 << HC139_B_GPIO_PIN)
str r1, [r0, #BCM2835_GPSET0]
bx lr

FUNC spi_select_mcp4902_1
@ void spi_select_mcp4902_1(void)
ldr r0, =BCM2835_GPIO_BASE
mov r1, #(1 << HC139_A_GPIO_PIN)
str r1, [r0, #BCM2835_GPSET0]
mov r1, #(1 << HC139_B_GPIO_PIN)
str r1, [r0, #BCM2835_GPCLR0]
bx lr

FUNC spi_select_mcp4902_2
@ void spi_select_mcp4902_2(void)
ldr r0, =BCM2835_GPIO_BASE
mov r1, #(1 << HC139_A_GPIO_PIN)
str r1, [r0, #BCM2835_GPCLR0]
mov r1, #(1 << HC139_B_GPIO_PIN)
str r1, [r0, #BCM2835_GPCLR0]
bx lr
and
Code: Select all
#include <bcm2835.h>
#include <spi_dac.h>

void inline bcm2835_spi_mcp4922_a(uint16_t data) {
   spi_select_mcp4922();
   bcm2835_spi_write(data  | 0x3000 | (0<<15));
}

void inline bcm2835_spi_mcp4922_b(uint16_t data) {
   spi_select_mcp4922();
   bcm2835_spi_write(data | 0x3000 | (1<<15));
}

void inline bcm2835_spi_mcp4902_1a(uint16_t data) {
   spi_select_mcp4902_1();
   bcm2835_spi_write((data << 4) | 0x3000 | (0<<15));
}

void inline bcm2835_spi_mcp4902_1b(uint16_t data) {
   spi_select_mcp4902_1();
   bcm2835_spi_write((data << 4) | 0x3000 | (1<<15));
}

void inline bcm2835_spi_mcp4902_2a(uint16_t data) {
   spi_select_mcp4902_2();
   bcm2835_spi_write((data << 4) | 0x3000 | (0<<15));
}

void inline bcm2835_spi_mcp4902_2b(uint16_t data) {
   spi_select_mcp4902_2();
   bcm2835_spi_write((data << 4) | 0x3000 | (1<<15));
}


With Mike's library : http://www.airspayce.com/mikem/bcm2835/

See also https://github.com/vanvught/OpenILDA/tr ... rmware/lib

Regards, Arjan
Posts: 128
Joined: Sat Sep 08, 2012 1:59 pm