-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cpu/msp430fxyz: improved SPI driver speed #5886
Conversation
|
||
return length; | ||
} | ||
|
||
int spi_transfer_byte(spi_t dev, char out, char *in) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you'll have to remove this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ups...
c1a982e
to
b381fd5
Compare
fixed and squashed the occurrence of the old transfer_byte() function |
Theoretically I agree with you about this adoption. Practically it appears that the cc2420 on the z1 node does not work with this PR. As a test I took to "old" SPI implementation and added a |
But could you hook up your scope and check out the output signal/timings with this PR, to make sure the driver is not broken in general but that the male functioning has something to do with timings?! |
I don't have a Z1 here available right now, so I can't really test anything here. But by looking at the code again, the only thing that has changed should be, that we leave out a function call for each byte transferred, though we should have tighter inter-byte timings. Looking at the CC2420 datasheet, an SPI clock up to 20MHz should be fine (and we are currently at 5MHz, right?), so seems that the radio should actually work fine under the new conditions. Wonder what we are doing wrong here. |
The SPI driver itself works like this, I checked it. However, the cc2420 driver (@4Mhz) has some problems here and there. There are some SPI accesses which are not successful when using |
I still have some trouble to understand, why the cc2420 driver has problems with the new code. When calling the transfer_bytes function with
Not sure... We need to figure out, why exactly the cc2420 is not behaving correctly. And if we open up new problems, it IMHO points more in the direction of bad driver implementation than to a broken SPI driver. And if so, we should face the problems with other drivers and fix them by the root instead of building upon a non-optimal SPI driver below to obfuscate those problems. But first step first, we need to understand whats going wrong here.
State now, I am absolutely against it - feels to me like building a quick-fix workaround into a main RIOT API: not good... |
I am against the idea of creating two separate API calls for the same functionality. It should be possible to rewrite the loops for efficiency to take different code paths depending on whether the input is NULL or not and depending on the desired bus clock vs. the core clock to try to speed up the transfer. |
+1 -----Original Message----- I am against the idea of creating two separate API calls for the same functionality. It should be possible to rewrite the loops for efficiency to take different code paths depending on whether the input is NULL or not and depending on the desired bus clock vs. the core clock to try to speed up the transfer. You are receiving this because you commented. |
@gebart that's what this PR does, isn't it? I still need to get this PR running with the cc2420 radio. |
for (unsigned i = 0; i < length; i++) { | ||
while (!(SPI_IF & SPI_IE_TX_BIT)) {} | ||
SPI_DEV->TXBUF = (uint8_t)out[i]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the following lines here:
while(SPI_DEV->STAT & 1){};
SPI_DEV->RXBUF;
The first line waits for any ongoing transmission by reading the UCBUSY bit in the status register (compare datasheet sec. 16.4.5). The second line simply reads the receive buffer which will clear the UCxRXIFG
bit. In master mode that bit indicates that data has been received. I tell you, without this read operation, things can get messy :/ ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@haukepetersen you wrote the msp_430-regs file. Maybe you want to add a macro for the UCBUSY bit in the status register?
done. @PeterKietzmann: could you do me one more favor? Could you connect your logic analyzer and post the output for I would be interested in how much performance difference we encounter between the two code paths in the current form. But as said, I don't have a |
@haukepetersen my logic analyser currently strikes, that's why I used an oscilloscope on the clock line. Case a) has an inter-byte-delay of ~360 ns (yes nano seconds) whereas b) has about 4,8 us. Is that enough for you? |
thanks! An inter-byte difference of 4us, wow! So I guess this short-path makes sense here. Will play around with this on some other platforms as well... Thx again and post your progress on the |
In the periph_conf.h of different msp430 based boards, |
while (!(SPI_IF & SPI_IE_TX_BIT)) {} | ||
SPI_DEV->TXBUF = (uint8_t)out[i]; | ||
while (SPI_DEV->STAT & USCI_SPI_STAT_UCBUSY) {} | ||
SPI_DEV->RXBUF; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both lines should go below the closing brace in line 227 (just be called once, after the transmission of multiple bytes). However, we will need to adapt this passage for the older msp430 revisions so we can do it then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What we need here (below the closing brace in line 227) is:
#ifndef SPI_USE_USCI
while (!(SPI_IF & SPI_IE_TX_BIT) || !(SPI_IF & SPI_IE_RX_BIT)) {}
SPI_DEV->RXBUF;
#else
while (SPI_DEV->STAT & USCI_SPI_STAT_UCBUSY) {}
SPI_DEV->RXBUF;
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not just use while (!(SPI_IF & SPI_IE_TX_BIT) || !(SPI_IF & SPI_IE_RX_BIT)) {}
for both variants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No this (and simply waiting for !(SPI_IF & SPI_IE_RX_BIT)
) does not work on z1 nodes with msp430xf2xx. I can't fully explain it but I've tested it several times.
} | ||
return 1; | ||
else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@haukepetersen I'd like to improve "simple" receiving as well
else if (!out) {
for (unsigned i = 0; i < length; i++) {
SPI_DEV->TXBUF = 0;
while (!(SPI_IF & SPI_IE_RX_BIT)) {}
in[i] = (char)SPI_DEV->RXBUF;
}
}
88e0ff0
to
df4b80c
Compare
|
fast receive is ok |
else { | ||
char tmp; | ||
for (unsigned i = 0; i < length; i++) { | ||
tmp = (out) ? out[i] : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the !out
case handled above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep. will adapt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I confused this PRs. Can't adapt this one but #5921 later. However, your comment makes sense and test succeeded.
in[i] = (char)SPI_DEV->RXBUF; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It leads to the same assembly, but I'd prefer a little more C-like code:
unsigned n = length;
while(n--) {
SPI_DEV->TXBUF = *out++;
}
- makes the for loops less verbose
- saves the compiler from doing all the dereferences (
in[i] = x
...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, I actually tend to like the newby-array-notation better. I think it is easier to read for non-professional-pointer-magicians (or am I the only one?), and the effects on the compiler are neglectable...
df4b80c
to
5d939ca
Compare
fixed @kaspar030 I won't fix the array-style notation in the loop. |
5d939ca
to
864ebed
Compare
also was so free to squash... |
I prefer the "old" notations as well, in terms of readability. However, I won't have NACKed Kaspars proposal. Will check this PR in the afternoon |
SPI_DEV->TXBUF = (uint8_t)out[i]; | ||
} | ||
while (!(SPI_IF & SPI_IE_RX_BIT)) {} | ||
SPI_DEV->RXBUF; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need the following here, even though it's not the prettiest solution. I've read the manual several times and tested different configurations on (and between) z1 and telosb motes so I'm pretty convinced this is the right thing to do:
#ifndef SPI_USE_USCI
while (!(SPI_IF & SPI_IE_TX_BIT) || !(SPI_IF & SPI_IE_RX_BIT)) {}
SPI_DEV->RXBUF;
#else
while (SPI_DEV->STAT & 1) {}
SPI_DEV->RXBUF;
#endif
IIRC you already introduced a macro for checking bit no 1 (BUSY
bit) in the status register for devices with SPI_USE_USCI
but this was lost I guess.
ACK once addressed. If we consider this PR for the release can we probably include #5921 as well?! |
864ebed
to
0e65637
Compare
fixed and squashed right in. |
while (!(SPI_IF & SPI_IE_TX_BIT)) {} | ||
SPI_DEV->TXBUF = (uint8_t)out[i]; | ||
} | ||
while (!(SPI_IF & SPI_IE_RX_BIT)) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @haukepetersen I was to imprecise in my previous comment. This line can go out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
0e65637
to
470fe20
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK and go
From the discussion in #4780 we heard, that the SPI driver speed for the MSP430 platform performs poorly when writing a burst of data (e.g. when transferring network packets to the radio). This PR should improve the situation quite a bit.
Changes:
transfer_byte()
(convenience) function to the periph_common module while making thetransfer_bytes()
function local to the driver. This will significantly reduce the number of function calls while transferring data...@PeterKietzmann would you mind to test this and benchmark this against your existing numbers? Thx