According to the docs at https://learn.adafruit.com/introducing- ... m4/pinouts
#5 - GPIO #5. This is a special OUTPUT-only pin that can PWM. It is level-shifted up to Vhi voltage, so its perfect for driving NeoPixels that want a ~5V logic level input. You can use this with our NeoPixel DMA control library to automatically write NeoPixel data without needing any processor time.
But then the product page says:
1 x Special Vhigh output pin gives you the higher voltage from VBAT or VUSB, for driving NeoPixels, servos, and other 5V-logic devices. Digital 5 level-shifted output for high-voltage logic level output.
Can drive NeoPixels or DotStars on any pins, with enough memory to drive 60,000+ pixels. DMA-NeoPixel support on the VHigh pin so you can drive pixels without having to spend any processor time on it.
the vhigh pin is not that #5 pin on the ItsyBitsy. So which pin allows for NeoPixel DMA library?
I currently have an application that has the NeoPxel wired to digital pin 5. This works with the regular neopixel library. When i replace it with the ZeroDMA version it sets the color once and hangs in the show() method.
#include <Adafruit_NeoPixel_ZeroDMA.h>
Adafruit_NeoPixel_ZeroDMA leds = Adafruit_NeoPixel_ZeroDMA(NUM_LEDS, NEO_PIXEL_PORT, NEO_GRB);
I would like to use this version so that I can reduce the interrupt issues with the NeoPixel version.
ItsyBitsy M4 and NeoPixel ZeroDMA on pin 5
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- DilvishEhldar
- Posts: 17
- Joined: Sun Aug 12, 2018 2:58 pm
- DilvishEhldar
- Posts: 17
- Joined: Sun Aug 12, 2018 2:58 pm
Re: ItsyBitsy M4 and NeoPixel ZeroDMA on pin 5
Still looking for information on this. Perhaps an wiring/code example of ZeroDMA being used on an ItsyBitsy M4 would also suffice.
- MartinL2
- Posts: 60
- Joined: Sun Mar 10, 2019 2:17 pm
Re: ItsyBitsy M4 and NeoPixel ZeroDMA on pin 5
Hi DilvishEhldar,
Just specify the number of NeoPixels:
Initialise in the setup() portion of your sketch:
Specify the NeoPixel number and GRB colour with an intensity from 0 to 255:
When the NeoPixels have all been configured, pull the trigger on the DMAC to send the data:
The code is a little less efficient on memory than the Adafruit library, using 24 bytes per pixel, however the timing exactly matches NeoPixel specification using an 800kHz binary coded PWM signal with 32% and 64% duty-cycle pulse widths.
Here's a code example using the TC3 timer and the DMA on digtial pin D5 for the Itsy Bitsy M4:Perhaps an wiring/code example of ZeroDMA being used on an ItsyBitsy M4 would also suffice.
Code: Select all
// Drive NeoPixels on Itsy Bitsy M4 digital pin 5 with the DMAC and TC3
#define NEOPIXEL_NO 8
#define DMAC_CHANNEL 11
struct __packed
{
struct __packed
{
uint8_t green[8];
uint8_t red[8];
uint8_t blue[8];
} neoPixelGRB[NEOPIXEL_NO];
uint8_t resetCode = 0;
} neoPixelData;
typedef struct // DMAC descriptor structure
{
uint16_t BANNED;
uint16_t BANNED;
uint32_t srcaddr;
uint32_t dstaddr;
uint32_t descaddr;
} dmacdescriptor ;
volatile dmacdescriptor wrb[DMAC_CH_NUM] __attribute__ ((aligned (16))); // DMAC write back descriptor array
dmacdescriptor descriptor_section[DMAC_CH_NUM] __attribute__ ((aligned (16))); // DMAC channel descriptor array
dmacdescriptor descriptor __attribute__ ((aligned (16))); // DMAC place holder descriptor
void setup()
{
neoPixelBegin(); // Initialise timer TC3 and DMAC
}
void loop() // Test code...
{
for (uint8_t i = 0; i < NEOPIXEL_NO; i++)
{
neoPixelWrite(i, 0, 32, 0); // Configure memory to set up 8 NeoPixels to display red at 1/8th intensity
}
neoPixelDisplay(); // Send data to the NeoPixels
delay(1000); // Wait 1 second
for (uint8_t i = 0; i < NEOPIXEL_NO; i++)
{
neoPixelWrite(i, 32, 0, 0); // Configure memory to set up 8 NeoPixels to display green at 1/8th intensity
}
neoPixelDisplay(); // Send data to the NeoPixels
delay(1000); // Wait 1 second
}
void neoPixelBegin() // Initialise timer TC3 and the DMAC
{
GCLK->PCHCTRL[26].reg = GCLK_PCHCTRL_BANNED | // Enable perhipheral channel
GCLK_PCHCTRL_GEN_GCLK2; // Connect 100MHz generic clock 2 to TC2 and TC3
// Enable the pin multiplxer for digital pin 5
PORT->Group[g_APinDescription[5].ulPort].PINCFG[g_APinDescription[5].ulPin].bit.PMUXEN = 1;
// Switch the pin mulitplexer to peripheral E for digital pin 5
PORT->Group[g_APinDescription[5].ulPort].PMUX[g_APinDescription[5].ulPin >> 1].reg |= PORT_PMUX_PMUXO(4);
TC3->COUNT8.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | // Set prescaler to 1, 100MHz/1 = 100MHz
TC_CTRLA_MODE_COUNT8; // Set the counter to 8-bit mode
TC3->COUNT8.WAVE.reg = TC_WAVE_WAVEGEN_NPWM; // Set timer to output Normal PWM mode (NPWM)
TC3->COUNT8.PER.reg = 124; // Set the timer period PER for a PWM frequency of 800kHz
while (TC3->COUNT8.SYNCBUSY.bit.PER); // Wait for synchronization
TC3->COUNT8.CC[1].reg = 0; // Set the duty-cycle to 0% or 0V
while (TC3->COUNT8.SYNCBUSY.bit.CC1); // Wait for synchronization
DMAC->BASEADDR.reg = (uint32_t)descriptor_section; // Set the base address descriptor
DMAC->WRBADDR.reg = (uint32_t)wrb; // Set the write back address
DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf); // Enable the DMAC peripheral and all priority levels
// Set-up DMAC to trigger on TC3 overflow
DMAC->Channel[DMAC_CHANNEL].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(TC3_DMAC_ID_OVF) | DMAC_CHCTRLA_TRIGACT_BURST;
descriptor.descaddr = 0; // Indicate that this is the only descriptor (no linked list)
descriptor.srcaddr = (uint32_t)&neoPixelData + sizeof(neoPixelData); // Set the source as the head of the neoPixelData structure
descriptor.dstaddr = (uint32_t)&TC3->COUNT8.CCBUF[1].reg; // Set the destination as the TC3 buffered counter compare register
descriptor.BANNED = sizeof(neoPixelData); // Send neoPixelData structure in bytes
descriptor.BANNED = DMAC_BANNED_BEATSIZE_BYTE | DMAC_BANNED_SRCINC | DMAC_BANNED_VALID; // Send data as bytes, increment the source memory
memcpy(&descriptor_section[DMAC_CHANNEL], &descriptor, sizeof(descriptor)); // Copy the descriptor to the descriptor for the DMAC channel
TC3->COUNT8.CTRLA.bit.ENABLE = 1; // Enable TC3
while (TC3->COUNT8.SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void neoPixelWrite(uint16_t neoPixelNumber, uint8_t green, uint8_t red, uint8_t blue)
{
uint32_t colour = green << 16 | red << 8 | blue; // Combine the green, red and blue colour data
uint8_t* pNeoPixelData = (uint8_t*)&neoPixelData.neoPixelGRB[neoPixelNumber]; // Select the appropriate NeoPixel in memory with a byte pointer
for (uint32_t bitMask = 0x00800000; bitMask > 0; bitMask >>= 1) // Iterate through each colour bit
{
*pNeoPixelData++ = (colour & bitMask) ? 79 : 39; // Load the memory with GRB colour duty cycle pulse widths for each bit
}
}
void neoPixelDisplay()
{
DMAC->Channel[DMAC_CHANNEL].CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; // Trigger a DMAC transfer of the data to the NeoPixels
}
Code: Select all
#define NEOPIXEL_NO 8
Code: Select all
neoPixelBegin(); // Initialise timer TC3 and DMAC
Code: Select all
neoPixelWrite(i, 0, 32, 0); // Configure memory to set up 8 NeoPixels to display red at 1/8th intensity
Code: Select all
neoPixelDisplay(); // Send data to the NeoPixels
- DilvishEhldar
- Posts: 17
- Joined: Sun Aug 12, 2018 2:58 pm
Re: ItsyBitsy M4 and NeoPixel ZeroDMA on pin 5
This is really great! I will try this right away. It looks very promising!
Thank you SO much for taking the time to respond.
Thank you SO much for taking the time to respond.
- DilvishEhldar
- Posts: 17
- Joined: Sun Aug 12, 2018 2:58 pm
Re: ItsyBitsy M4 and NeoPixel ZeroDMA on pin 5
Thank you again for taking the time to share an example. It worked perfectly. Unfortunately it does not work when I combine it with other libraries and code. In fact I found that the AdaFruit_NeoPixel_ZeroDMA also works when I created an isolated test case. The issue for my project seems to be incompatibility between the the AdaFruit branch of the Teensy Audio library. Even though that uses the AdaFruit_ZeroDMA library, there is some major incompatibility that I have not tracked down. Perhaps it is with timers. Perhaps it is a bug in the ZeroDMA library when multiple channels are allocated.
- MartinL2
- Posts: 60
- Joined: Sun Mar 10, 2019 2:17 pm
Re: ItsyBitsy M4 and NeoPixel ZeroDMA on pin 5
Are you able to check what's being output on D5 with an oscilloscope?
Usually the DMA works pretty well with multiple channels. Although, when I've used it to simultaneously generate 16 high speed, binary coded PWM pulses on 8 outputs, it was necessary to add two 0's to both the beginning and end of the transmitted data structure (for the 8 DMA channels), in order to allow all the PWM outputs to be clocked out successfully. Otherwise it would sometimes miss a pulse, either at the beginning or end of the sequence.
If it's a timer compatibility issue, then timers TCC1 and TCC2 are also available on D5.
Usually the DMA works pretty well with multiple channels. Although, when I've used it to simultaneously generate 16 high speed, binary coded PWM pulses on 8 outputs, it was necessary to add two 0's to both the beginning and end of the transmitted data structure (for the 8 DMA channels), in order to allow all the PWM outputs to be clocked out successfully. Otherwise it would sometimes miss a pulse, either at the beginning or end of the sequence.
If it's a timer compatibility issue, then timers TCC1 and TCC2 are also available on D5.
Please be positive and constructive with your questions and comments.