View previous topic :: View next topic |
Author |
Message |
pedrohenrique
Joined: 20 Jun 2008 Posts: 4
|
Defining multiple SPI streams |
Posted: Fri Jun 20, 2008 1:38 pm |
|
|
Hi
I am trying to interface several slaves through the SPI bus. Each of the slaves requires a different mode (MODE 0 with 8 bits, MODE 1 with 16 bits and MODE 3 with 16 bits).
To do so I am defining 3 streams using the use spi statement, and communication using the spi_xfer command.
I have found that only the last use spi statement applies to all the code, and I can only interface the slave which the last statement matches (the others don't like the mode). If I change the order the same applies.
I would like to know if there is any way for me to define the streams in another fashion or if I can otherwise configure the bus prior to using it (while allowing me to still control the number of data bits)
Any help is greatly appreciated
Kind regards
Pedro Inácio |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jun 20, 2008 6:43 pm |
|
|
I did some testing for a few minutes here with vs. 4.074, and you are
correct. #use spi() with streams is not as flexible as we would wish.
It does not re-configure the hardware module when you use a different
stream.
It would be easier to use setup_spi() with spi_write() and spi_read(), etc.
Then you can call setup_spi() when you want to change the SPI mode or
the baud rate. |
|
|
pedrohenrique
Joined: 20 Jun 2008 Posts: 4
|
|
Posted: Sat Jun 21, 2008 2:38 am |
|
|
Dear PCM Programmer
Thank you for your input. I am glad to know that it is not an error on my part as I can try and take another approach. I will try to use those commands as you suggest and will let you know how it goes.
Kind regards
Pedro Inácio |
|
|
pedrohenrique
Joined: 20 Jun 2008 Posts: 4
|
|
Posted: Sat Jun 21, 2008 7:39 am |
|
|
Dear PCM Programmer
I followed your advice on the commands and was able to interface all the slave peripherals regardless of the order. I removed the use spi directives altogether.
Thank you very much for your help
Kind Regards
Pedro Inácio |
|
|
bboone
Joined: 04 Jun 2014 Posts: 3 Location: United States
|
|
Posted: Mon Oct 05, 2015 10:38 am |
|
|
is this still an issue in 5.024? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 05, 2015 12:09 pm |
|
|
What's your PIC ? I'll check it. |
|
|
bboone
Joined: 04 Jun 2014 Posts: 3 Location: United States
|
|
Posted: Mon Oct 05, 2015 12:48 pm |
|
|
pic18F87K90 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Oct 05, 2015 12:55 pm |
|
|
Software SPI, will give different speeds for defined streams. Different routines used for each transfer. For hardware, the port is configured once at the start of the code. The same applies with serial.
If only one stream is 'fast', you could set this up to use hardware, and the others to use software. Then just turn the SPI peripheral on/off when you want to use the software streams. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 05, 2015 12:57 pm |
|
|
Code: | #include <18F87K90.h>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
#use spi(SPI1, baud=1000000, mode=0, bits=8, stream=spi_stream_0)
#use spi(SPI1, baud=2000000, mode=1, bits=16, stream=spi_stream_1)
#use spi(SPI1, baud=5000000, mode=3, bits=16, stream=spi_stream_2)
//=======================================
void main()
{
int8 result_8;
int16 result_16;
result_8 = spi_xfer(spi_stream_0, 0x55);
result_16 = spi_xfer(spi_stream_1, 0x1234);
result_16 = spi_xfer(spi_stream_2, 0x5678);
while(TRUE);
} |
The .LST file below shows that the compiler is setting up the hardware
SPI module for the particular stream, each time it talks to that stream.
This is with compiler vs. 5.024.
Code: |
.................... result_8 = spi_xfer(spi_stream_0, 0x55);
000A4: BCF SSP1CON1.SSPEN
000A6: MOVLW 40
000A8: MOVWF SSP1STAT
000AA: MOVLW 20
000AC: MOVWF SSP1CON1
000AE: MOVLW 55
000B0: MOVWF ??65535
000B2: MOVLB 0
000B4: BRA 0004
000B6: MOVF @01,W
000B8: MOVFF 01,result_8
.................... result_16 = spi_xfer(spi_stream_1, 0x1234);
000BC: BCF SSP1CON1.SSPEN
000BE: MOVLW 00
000C0: MOVWF SSP1STAT
000C2: MOVLW 20
000C4: MOVWF SSP1CON1
000C6: MOVLW 12
000C8: MOVWF ??65535+1
000CA: MOVLW 34
000CC: MOVWF ??65535
000CE: BRA 0016
000D0: MOVF @01,W
000D2: MOVFF 02,result_16+1
000D6: MOVFF 01,result_16
.................... result_16 = spi_xfer(spi_stream_2, 0x5678);
000DA: BCF SSP1CON1.SSPEN
000DC: MOVLW 00
000DE: MOVWF SSP1STAT
000E0: MOVLW 30
000E2: MOVWF SSP1CON1
000E4: MOVLW 56
000E6: MOVWF ??65535+1
000E8: MOVLW 78
000EA: MOVWF ??65535
000EC: BRA 0036
000EE: MOVF @01,W
000F0: MOVFF 02,result_16+1
000F4: MOVFF 01,result_16
....................
.................... while(TRUE);
000F8: BRA 00F8
.................... } |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Oct 05, 2015 1:07 pm |
|
|
That is good, and new then. I looked at this a few versions ago, and it only initialised once.
So implies that it should work for the original poster, if he switches to a newer compiler. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Oct 06, 2015 7:37 am |
|
|
There is a piece here that might well cause problems....
Some of the different modes, will have the idle level on the lines change.
Now the code to setup the SPI, won't get called until you actually send a byte. Problem is that therefore, if your sequence is:
Deselect all chips
Select the one chip you want.
Output to the required port.
Since the chip is selected _before_ the byte is sent to the port, it'll see the wrong idle level at the start of the transaction. Problem.
If the idle levels do change, the only way to make it work would either be to program the peripheral yourself, or to use a 'dummy' byte. So:
Deselect all chips.
Send a dummy byte to the stream you are going to use. This then reprograms the peripheral and sets the correct idle levels.
Wait for this to send.
Now select the chip you want, and talk to this.
This way the chip is only selected after the lines have been taken over and set to the right levels.
This is only necessary if you are changing mode. |
|
|
Cenatronics
Joined: 27 Nov 2006 Posts: 13
|
|
Posted: Thu Jun 04, 2020 9:56 am |
|
|
Ttelmah wrote: | There is a piece here that might well cause problems....
Some of the different modes, will have the idle level on the lines change.
Now the code to setup the SPI, won't get called until you actually send a byte. Problem is that therefore, if your sequence is:
Deselect all chips
Select the one chip you want.
Output to the required port.
Since the chip is selected _before_ the byte is sent to the port, it'll see the wrong idle level at the start of the transaction. Problem.
If the idle levels do change, the only way to make it work would either be to program the peripheral yourself, or to use a 'dummy' byte. So:
Deselect all chips.
Send a dummy byte to the stream you are going to use. This then reprograms the peripheral and sets the correct idle levels.
Wait for this to send.
Now select the chip you want, and talk to this.
This way the chip is only selected after the lines have been taken over and set to the right levels.
This is only necessary if you are changing mode. |
Is this method also valid for the latest version (5.093)?
SNO |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Jun 05, 2020 12:48 am |
|
|
There is an undocumented 'other way'. On I2C, there is a command
i2c_init for exactly this. So you can setup the two streams, using
'NOINIT', and then simply 'INIT' the one you actually want to use.
I thought it worth just testing to see if SPI might do the same.
It works:
Code: |
#use spi(SPI1, mode=0, baud=100000, NOINIT, stream=SPI_MODE0)
#use spi(SPI1, mode=2, baud=100000, NOINIT, stream=SPI_MODE2)
//setup two spi streams without init.
spi_init(SPI_MODE0);
//Now select mode 0
output_low(CS1);
spi_xfer(address);
val=spi_xfer(0);
output_high(CS1);
//and talk to first chip
spi_init(SPI_MODE2);
//Now the mode 2 chip
output_low(CS2);
spi_xfer(secondaddress);
secondval=spi_xfer(0);
output_high(CS2);
//and talk to this
|
It is correctly setting the chip to the two different modes and using
these. |
|
|
Cenatronics
Joined: 27 Nov 2006 Posts: 13
|
|
Posted: Fri Jun 05, 2020 6:44 am |
|
|
Thanks for your comments.
SNO |
|
|
|