-
Notifications
You must be signed in to change notification settings - Fork 13.3k
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
add bitbang spi function - enhancement #33
Comments
I'm slowly starting to figure out the xtensa lx106 instruction set, and have the shiftOut up from 3.81mbps to 6.15mbps. Here's the updated code: The -mno-serialize-volatile, IMHO, should be safe as long no code does a read of an address immediately after a store to the same address (something tha seems to be rather pointless to me). |
I would prefer inline assembley here instead of using -mno-serialize-volatile globally. Then we could let users create instances of |
I haven't figured out lx106 assembler well enough yet.
|
Looking at the SPI code it, it seems you started with the 1.6 Arduino core
|
Oh right, I wanted to start with something simple and then forgot to add transactions back. Needs to be fixed. HSPI does have beginTransaction, by the way, it's just declared in the SPIImpl interface. |
I don't understand why every method of SPIimpl is pure virtual. I think at least end() and setDataMode() should have a default empty implementation, and probably more of the methods. |
I just wanna say thanks for looking into this issue, and I hope it becomes a thing! It would really help on some of the more pin-restricted variants of the ESP8266 breakout boards, considering all the pins that all need to be present to use hardware SPI. Though I do wonder about how this would work if a piece of code is expecting and tries to use the hardware SPI port.....I suppose it wouldn't be too hard to patch the begin(); to something like begin(pin1, pin2, pin3, pin4); in a given library as needed. (not a lot of them are written to support passing of an SPI object, hardware or software) If you guys have a more clever solution, I'd be interested to know! |
here is some AVR code that I have written a while back. It will be fairly easy to add transactions and convert it to ESP. Is this what you are looking for? SSPI::SSPI(uint8_t mosi, uint8_t miso, uint8_t sck, uint8_t ss){
_mode = SSPI_MODE0;
_bit_order = SSPI_MSB_FIRST;
_bitcount = 8;
_ss_inverted = false;
_mosi_pin = portInputRegister(digitalPinToPort(mosi));
_mosi_ddr = portModeRegister(digitalPinToPort(mosi));
_mosi_port = portOutputRegister(digitalPinToPort(mosi));
_mosi_mask = digitalPinToBitMask(mosi);
_miso_pin = portInputRegister(digitalPinToPort(miso));
_miso_ddr = portModeRegister(digitalPinToPort(miso));
_miso_port = portOutputRegister(digitalPinToPort(miso));
_miso_mask = digitalPinToBitMask(miso);
_sck_pin = portInputRegister(digitalPinToPort(sck));
_sck_ddr = portModeRegister(digitalPinToPort(sck));
_sck_port = portOutputRegister(digitalPinToPort(sck));
_sck_mask = digitalPinToBitMask(sck);
_ss_pin = portInputRegister(digitalPinToPort(ss));
_ss_ddr = portModeRegister(digitalPinToPort(ss));
_ss_port = portOutputRegister(digitalPinToPort(ss));
_ss_mask = digitalPinToBitMask(ss);
*_mosi_ddr |= _mosi_mask;//output
*_miso_ddr &= ~_miso_mask;//input
*_sck_ddr |= _sck_mask;//output
*_ss_ddr |= _ss_mask;//output
*_mosi_port &= ~_mosi_mask;//low
*_sck_port &= ~_sck_mask;//low
*_ss_port |= _ss_mask;//high
}
uint32_t SSPI::transmit(uint32_t data, uint8_t bitcount, bool wait){
uint8_t index = 0;
uint8_t i = bitcount;
uint32_t value = 0;
//for each bit
while(i--){
if (_bit_order == SSPI_MSB_FIRST){
index = i;
} else {
index = ((bitcount - 1) - i);
}
//mode 0 and 3 slave reads on leading edge so we need to set the bit before clocking in
if((_mode & 1) == 0){
if ((data & (1 << index)) != 0){
*_mosi_port |= _mosi_mask;//high
} else {
*_mosi_port &= ~_mosi_mask;//low
}
}
//clock leading edge
if((_mode & 2) == 0){
*_sck_port |= _sck_mask;//high
} else {
*_sck_port &= ~_sck_mask;//low
}
//modes 0 and 3 read the bit here while 2 and 4 set it to be read on trailing clock edge
if((_mode & 1) == 0){
value |= (((*_miso_pin & _miso_mask) != 0) << index);
} else {
if ((data & (1 << index)) != 0){
*_mosi_port |= _mosi_mask;//high
} else {
*_mosi_port &= ~_mosi_mask;//low
}
}
//trailing edge
if((_mode & 2) == 0){
*_sck_port &= ~_sck_mask;//low
} else {
*_sck_port |= _sck_mask;//high
}
//modes 2 and 4 read the bit here
if((_mode & 1) != 0) if((*_miso_pin & _miso_mask) != 0) value |= (1 << index);
}
//if requested, wait for the slave to release the miso line
while(wait && ((*_miso_pin & _miso_mask) != 0));
return value;
}
//setters
void SSPI::setSsInverted(bool inverted){
if(_ss_inverted != inverted) *_ss_port ^= _ss_mask; //toggle on change
_ss_inverted = inverted;
}
void SSPI::setMode(uint8_t mode){
uint8_t m = (mode & 0x03);
if((m & 2) != (_mode & 2)) *_sck_port ^= _sck_mask; //toggle on CPOL change
_mode = m;
}
void SSPI::setBitOrder(uint8_t bitOrder){
_bit_order = (bitOrder & 1);
}
void SSPI::setBitCount(uint8_t bitCount){
_bitcount = ((bitCount - 1) & 0x1F) + 1;//32 max
}
void SSPI::select(){
_ss_inverted?*_ss_port|=_ss_mask:*_ss_port&=~_ss_mask;
}
void SSPI::deselect(){
_ss_inverted?*_ss_port&=~_ss_mask:*_ss_port|=_ss_mask;
} |
There were a couple of possibly useful files in my recent duplicate post. Here they are, moved over, just for reference: https://github.com/greiman/DigitalIO/blob/master/DigitalIO/src/SoftSPI.h I'm tempted to try replacing the 'fast' digital I/O functions with regular ones and just giving it a shot to see what happens. |
Also possibly useful: |
4 mbps all good but that is just one type of SPI. If you want to support more modes, time will go up. |
@igrr, I can wrap the above code to a more ESP8266 approach if you want me to |
That might help a bunch, considering there are ready-made soft SPI libraries out there written in AVR assembly. It may be as simple as swapping the reading and writing code to acheive a workable result. (one of the repos I linked above depends on "fast" digitalRead() and digitalWrite() functions but is otherwise fairly independent of hardware) Edit: I don't suppose you know of a decent primer on eps8266 assembly? |
I don't know such an exp8266 assembly primer :-/ However, there are a couple of general inline assembly how-to on the net. And last but not least: Do not hesitate to ask me, I will always try to help! |
@nerdralph @Matthew-Bradley @me-no-dev |
I've come to think we're overthinking this problem. For most applications, a fast spi interface isn't really needed. A lot of the devices that get attached to an spi buss are pretty low-speed, like RFID card readers and temperature sensors. This is especially true if you're the master device and have control of the clock. I remember seeing a software spi implementation for the AVR that relied upon functions like digitalwritefast(). I'm thinking that if you went and replaced all such functions with the regular versions, it would be perfectly adequate, even given the ESP's really slow GPIO pins. (compared to an AVR) |
There are power considerations. Slower SPI speed = longer wake timee for
batter powered devices.
…On Oct 20, 2017 10:10 PM, "Matt" ***@***.***> wrote:
I've come to think we're overthinking this problem. For most applications,
a fast spi interface isn't really needed. A lot of the devices that get
attached to an spi buss are pretty low-speed, like RFID card readers and
temperature sensors. This is especially true if you're the master device
and have control of the clock.
I remember seeing a software spi implementation for the AVR that relied
upon functions like digitalwritefast(). I'm thinking that if you went and
replaced all such functions with the regular versions, it would be
perfectly adequate, even given the ESP's really slow GPIO pins. (compared
to an AVR)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#33 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AFTc-uWIOMN9mpjRXDlZTTifjcV5q6pJks5suUSLgaJpZM4D42Kx>
.
|
What ever happend with this? |
I was measured 4.81mbps for the following code:
void shiftOutFast(byte data)
{
byte i = 8;
do{
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << CLOCK);
if(data & 0x80)
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << DATA);
else
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << DATA);
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << CLOCK);
data <<= 1;
}while(--i);
return;
}
http://nerdralph.blogspot.ca/2015/04/a-4mbps-shiftout-for-esp8266arduino.html
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
The text was updated successfully, but these errors were encountered: