MCUdude / MegaCoreX

An Arduino hardware package for ATmega4809, ATmega4808, ATmega3209, ATmega3208, ATmega1609, ATmega1608, ATmega809 and ATmega808
GNU Lesser General Public License v2.1
239 stars 47 forks source link

SPI Pinswap 2 not available #199

Open CarbonV opened 2 months ago

CarbonV commented 2 months ago

I have spotted at https://github.com/MCUdude/MegaCoreX/blob/master/megaavr/variants/48pin-standard/pins_arduino.h on line 119 it is noted that it is noted that Pinswap 2 is not available. What would be the reason for this, is there any way there can be worked around this?

As you can probably guess I have a custom PCB where I connected the pinswap 2 SPI pins as I originally based my board on the Nano Every design.

Thanks in advance!

MCUdude commented 2 months ago

I haven't worked on this core for a long time, so I honestly don't remember why I wrote that it was unavailable. But when looking at the SPI.h/cpp source code, it appears that SPI swap 2 is available. I suggest you give it a try 🙂

CarbonV commented 2 months ago

I did, and it seems to not be working. But as I have no debugger it might be something else I missed, I'll keep digging.

SpenceKonde commented 2 months ago

Somehow that sounds vaguely familiar, but I see no references to it anywhere.... I see nothing about it in errata, nor do I remember seeing that one go by.

Do you have a 'scope? if so I would write the code to use one mux option, test it ( expecting it to work, thus giving a screenshot of a working transaction) then swap the wires and the code to use mux 2, and see what was different... Depending on the results you see with the scope, and how simple you can get code that reproduces it (the ideal test case is something that can be demonstrated with only the board, jumpers, and a 'scope). And if you do that and get two different scope traces when the code is otherwise identical, I think that would be very informative (if disheartening). I see no reason it wouldn't work short of a silicon bug, or a bug in user code, which is why am giving the advise about a demonstration test case 2 paragraphs down.

That note about pinswap option 2 is present WAAAY back. I see it in history at times when you can check the SPI.h at the time, and see that pins/swap wasn't even in yet - so at the time that note was added, you couldn't use options 1 or 2 :-P

How are you swapping pins? Using pins() or swap()? Make sure you're getting true back from SPI.pins() or SPI.swap() if you get false back, that means it didn't like the arguments, and it has set the pinset to the default. (while SPI.swap(2) doesn't have a ton of space for a mistake to hide in your code; pins() with 4 arguments, which must be passed in the correct order, is easier to make a simple copying error, especially with 4 pins that lack a memorable order.

MCUdude's pinswap code looks like that logic was copied from an earlyish version of my cores (or the other way around, but unless I just had a bad dream about writing that.... My cores no longer look at the supplied SS pin, nor require the fourth argument; it's got a default value and is marked ((unused)), on the grounds that there's no rationale to asking a user to supply the number of a pin that is not required by the library for any functionality and while running the SPI peripheral via SPI.h, is no different from any other pin. Unlike classic AVR, SS is totally irrelevant to what the SPI.h library does:

  1. Library always sets SSD to disable the SS functionality autoswitching from master mode to slave. Therefore, there is no need to keep SS set output, a requirement that provided poor developer experience on classic AVRs.
  2. Library does not support slave mode, nor has any AVR library called SPI.h supported slave mode. Since the SS pin is only used in slave mode and to trigger a transition to slave mode, and the library doesn't support the first one and disables the second one, the SS pin is not relevant to SPI.h.

On that basis, I dropped any requirement for specifying the SS pin by making it __attribute((unused)) and giving it a default value, commented out the tests of the SS pin, and documented it's optionality. I feel like there may also be a case or two on the DD where there's no SS pin for a pinset, which may have forced that, though I probably had done that earlier. whatever

I did do back of the envelope calculations for the usability of SPI slave mode and uh, there is a reason SPI.h doesn't attempt to implement it. The problems are myriad, but they all come down to speed; this is why I never went any further working on this; it was clear it wouldn't be a good fit.I2C and Serial are better fits to communication between AVRs. :

  1. Typical speeds that SPI is used at are very high compared to what Arduinoland is used to - you see specs of 40, 60, 80 MHz commonly spec'ed. Arduino as slave can going absolutely balls to the wall can achieve bursts of F_CPU/4.
  2. Assuming you willingly send 0's the first byte, at full speed you have just 32 clock cycles to enter the SPI interrupt, (3 to get to the vector table 3 to get to the ISR, minimum of 9 in the prologue (that's just to clear out a pointer register and do the required things). Oh wait no. you can't just send one dummy byte, because until you see first byte you probably don't know what you're supposed to send. But if you only discover that when the byte is received, the next byte is coming in at that point and you needed to write the byte to send before that.
  3. There is no way for a slave to tell the master to slooooow down like I2C (where it can stretch the clock if it needs more time to compose it's response
CarbonV commented 2 months ago

Thanks for your reply @SpenceKonde, I don't have a scope on hand but I could use one from the office if the need arises. I can already confirm that SPI.swap(2) does return true which makes me think the problem is user code. I am using the RFM69 library which uses SPI to communicate with a HopeRF RFM69, I think that library overwrites my SPI code and uses the default pins for SPI. My arduino coding is not up to par to figure out how to figure that out too be honest so I'll have to do some research and digging.

Thanks again for the suggestions I'll let you know if I go the scope route.

CarbonV commented 2 months ago

I can confirm that pinswap 2 on SPI works. I assume the comment about unavailability can be removed.