Accessing multiple hardware SPI busses

Status
Not open for further replies.

tonton81

Well-known member
during testing, while reading canbus stream on SPI2, I tried to pull data from my port expanders on SPI1, however it was not picking up the data. Can 2 different hardware ports not be accessible (open) at the same time? I had to change most of my functions to global variables then bitshift the registers every cycle to their respective variables then compare/read those variables for the canbus stream parsing...
 
You should be able to use multiple SPI modules at the same time. There is very little information about your project for anyone to guess what might be going wrong for you. Maybe tell us a few more details, e.g. what Teensy you're using? a schematic maybe (or at least a description of what pins are wired to what)?

Sharing your code would be welcome also.
 
I am using a teensy 3.5, i'm reading a pin state on a mcp23s17 on SPI1 with a bit of canbus data on SPI2, and no it won't work, and no i dont have a schematic of why ONE PORT DOES NOT READ THE OTHER.
this is likely due to the core files not able to access more than 1 hardware (example, limitation of SPI transactions, which I use). And before you tell me it's my hardware, it's not, they both poll 24/7 individually, but I can;'t compare data in one SPI transaction with another port's SPI transaction.
 
I am using a teensy 3.5, i'm reading a pin state on a mcp23s17 on SPI1 with a bit of canbus data on SPI2, and no it won't work, and no i dont have a schematic of why ONE PORT DOES NOT READ THE OTHER.
this is likely due to the core files not able to access more than 1 hardware (example, limitation of SPI transactions, which I use). And before you tell me it's my hardware, it's not, they both poll 24/7 individually, but I can;'t compare data in one SPI transaction with another port's SPI transaction.

So please simplify your code demonstrating only your problem and post it here so we can have a look to it.
 
My guess is it is a code organization timing issue.

That is if your code is setup something like:
Code:
   SPI1.beginTransaction(...)
   SPI1.transfer(???) // start the reading of a register
... 
   value = SPI1.transfer(???) 
   SPI1.endtransaction(...)

    SPI2.beginTransaction(...)
    SPI2.transfer...
...
Then your code is setup to serialize access to the two SPI busses. That is your code is in lock step starting up talking on SPI1, waits for each byte or word to transfer, both send and receive and then finishes, before it starts looking at what is happening on SPI2 buss. Most SPI code is setup like this. Also most library code is setup like this.

But it is not the hardware constraint. Using the default SPI code you can do things like:
Code:
SPI1.beginTransaction(...)
SPI2.beginTransaction(...)
SPI1.transfer(x);
SPI2.transfer(x);

Again the code is still lockstepping the access to the SPI, but it is being done alternating every other byte....

Again this is not a hardware restriction, but more of an ease of use of libraries. The SPI buss (0) on the T3.5 has a read and write queue of 4 items, whereas the SPI1 and SPI2 busses have a queue of one item.

Again I don't believe there is any library code that currently separates the access out for the read queue versus the write queue. If you look at the SPI library for example for the SPI1.trasnfer(mybyte)
You see:
Code:
	inline static uint8_t transfer(uint8_t data) {
		SPI1_SR = SPI_SR_TCF;
		SPI1_PUSHR = data;
		while (!(SPI1_SR & SPI_SR_TCF)) ; // wait
		return SPI1_POPR;
	}
So it clears the TCF(Transfer complete flag) and then pushes your byte onto the queue and waits for the transfer to complete and then pops the returned value... So for example you could create a function that outputs on both queues...

But again only guessing as no real details given
 
you are correct, i only verify only 1 byte anyways, just throwing it out there for knowledge, i already drop the registers in their respective bitshifted globals now to compensate instead of using the reading method during another spi transaction
 
My guess is it is a code organization timing issue.

That is if your code is setup something like:
Code:
   SPI1.beginTransaction(...)
   SPI1.transfer(???) // start the reading of a register
... 
   value = SPI1.transfer(???) 
   SPI1.endtransaction(...)

    SPI2.beginTransaction(...)
    SPI2.transfer...
...
Then your code is setup to serialize access to the two SPI busses. That is your code is in lock step starting up talking on SPI1, waits for each byte or word to transfer, both send and receive and then finishes, before it starts looking at what is happening on SPI2 buss. Most SPI code is setup like this. Also most library code is setup like this.

But it is not the hardware constraint. Using the default SPI code you can do things like:
Code:
SPI1.beginTransaction(...)
SPI2.beginTransaction(...)
SPI1.transfer(x);
SPI2.transfer(x);

Again the code is still lockstepping the access to the SPI, but it is being done alternating every other byte....

Again this is not a hardware restriction, but more of an ease of use of libraries. The SPI buss (0) on the T3.5 has a read and write queue of 4 items, whereas the SPI1 and SPI2 busses have a queue of one item.

Again I don't believe there is any library code that currently separates the access out for the read queue versus the write queue. If you look at the SPI library for example for the SPI1.trasnfer(mybyte)
You see:
Code:
	inline static uint8_t transfer(uint8_t data) {
		SPI1_SR = SPI_SR_TCF;
		SPI1_PUSHR = data;
		while (!(SPI1_SR & SPI_SR_TCF)) ; // wait
		return SPI1_POPR;
	}
So it clears the TCF(Transfer complete flag) and then pushes your byte onto the queue and waits for the transfer to complete and then pops the returned value... So for example you could create a function that outputs on both queues...

But again only guessing as no real details given
Your answer is great. thank you.
 
i guess it depends on how the libraries access it (at the same time), for me, it was directly reading a mcp23s17 register (not using a library) during a canbus if statement triggered by a canid to cross match the register (ex. if canid byte > 400 && read mcp register to verify if a pin state was high or low) this was between SPI1 (8xmcp23s17) and SPI2 (3xmcp2515/mcp2551). regardless, i didnt spend too much time figuring it out, since moving functions to global vars and polling the registers every cycle and updating necessary variables took less time to recode, uses less reads to the mcp23s17s, and more efficient bitshifting the register into the proper variable for the comparator to look up during the canbus poll.
 
Status
Not open for further replies.
Back
Top