Adafruit_NeoPixel_ZeroDMA and I2C: Is this possible?
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Adafruit_NeoPixel_ZeroDMA and I2C: Is this possible?

by EricLarge on Thu Jan 24, 2019 3:36 pm

Hi all.

I realize I'm attempting to push my little Trinket M0 to its limits. I've currently got it doing 48Khz audio (amplitude-modulated sine wave) and running an animation on NeoPixels. Unfortunately, going the bit-bang route for the neopixels distorts the audio (despite turning interrupts off while the audio interrupt handler is running), so I had to switch to ZeroDMA. Since ZeroDMA is a very clever use of the SPI interface, this unfortunately causes it to grab not only the MOSI pin, but also the SPI SCK and MISO pins. Since the MISO pin is shared with the I2C SCK pin, I'm currently unable to use I2C on the device. I'd like to be able to connect it to my NeoTrellis keypad so I can control the audio and animation in real time.

Given that I2C and SPI share a pin, I would imagine this pin is on some sort of multiplexer. Is there any way to wrestle that pin away from SPI so I can use it for I2C? Yeah, I know I could use a Seesaw board to run the neopixels off of I2C, but they update a lot, and I'm concerned that it might create the same distortions as running neopixels without ZeroDMA. An odd keypress now and then shouldn't be as much of an issue with distortion, especially if I can also pry the SPI SCK line loose and use it for an interrupt.

Honestly, this little trinket has already exceeded my expectations as to what it can do, and now I consider it a challenge to see just how far I can push it. (Kinda sends me back to my Commodore 64 days.)

Thanks in advance for any help you can give me on this.


Update: Ooh! Found this! https://learn.adafruit.com/using-atsamd21-sercom-to-add-more-spi-i2c-serial-ports/overview. Missed it before. (rapidly digesting new information.) If I can just redirect some pins to pads that aren't being used...

Update 2: Okay, so from what I understand so far, each SERCOM pin has a standard and an alternate pin selection, pointing to specific pads. So only 2 choices per pin, right? Adafruit_NeoPixel_ZeroDMA looks like it's using SERCOM0, with the MISO pin set to PA09 (using its alt pin), however it has PA05 as its standard pin, which isn't connected to anything according to the schematic. The SPI SCK pin is using the standard pin to PA07, but the alternate pin is PA11, which is also not connected to anything. Am I on the right track here? Could I redirect MISO to PA05 and SCK to PA11 and get my pins back?

Update 3: Partial success. I modified this line in the Adafruit_NeoPixel_ZeroDMA library (original line commented for reference):

Code: Select all | TOGGLE FULL SIZE
#elif defined(ARDUINO_TRINKET_M0)
  //&sercom0, SERCOM0, SERCOM0_DMAC_ID_TX,    4,    2,   3, SPI_PAD_2_SCK_3, SERCOM_RX_PAD_1, PIO_SERCOM_ALT,
  &sercom0, SERCOM0, SERCOM0_DMAC_ID_TX,    4,    14,   6, SPI_PAD_2_SCK_3, SERCOM_RX_PAD_1, PIO_SERCOM_ALT,

I pointed SCK to pin 14 (PA11), and pin 3 is now working with GPIO. However pointing the MISO pin to pin 6 (PA05) didn't seem to work. I'm going to keep plugging away at this, but any suggestions would be most appreciated.

Update 4: Turns out all I had to do was call pinMode() AFTER using the .begin() method on the NeoPixel object. This reset the muxer to give those pins back to GPIO. It stands to reason that starting an I2C instance after starting the NeoPixel object should give the pins back to me. Long way 'round, and learned a lot, but glad I got my problem solved.

Update 5: Well, solved for getting GPIO working, but I realized that getting I2C working will probably involve more than wrestling the pin away from SERCOM0. If I2C also uses a SERCOM (which I imagine it would), then I'd still need to move the pins out of the way so I2C can grab them. I'm guessing that I2C runs on SERCOM2 (the only other one that uses those pins). Can anyone confirm that the trinket uses SERCOM2 for I2C?

Update 6: Yup. It's SERCOM2. Now I just need to work out how to work with the Neopixel DMA library so that it switches the pins on SERCOM0 without having to rewrite parts of the library (portability).

Update 7: Unfortunately, I think SERCOM2 might be fried. I can't even get an I2C example sketch to work by itself. Oscilloscope on pins 0 and 2 don't show any oscillation. Regular GPIO out those pins appears to work, but nothing when I try to send anything over I2C. I guess it's time to switch to a different chip, which would bring this experiment to a close, but I really enjoyed pushing it as far as I could. If anyone happens to know of a quirk that might be preventing I2C from working, I'll keep an eye on this post for replies.

Update 8: Nope. Not fried. I can get an SSD1306 display to work as long as it's the only thing connected. I think Neopixel and my audio interrupts are arguing over Timer 4. Tried switching over to ZeroDMA and then I think they were arguing over pins. I think the answer to my original question is a simple "no" at this point.

Posts: 15
Joined: Tue Apr 26, 2016 2:31 pm

Please be positive and constructive with your questions and comments.