Comments (5)
I can't help with Adafruit's SAMD51 DMA. I tried to use it in one of my apps and gave up.
I suggest you use the Adafruit port of SdFat and post issues with Adafruit.
I was going publish fast examples using Adafruit's DMA for SAMD but decided it was too flaky.
from sdfat.
Hey Greiman,
That makes sense. It has been tricky.
I started with the Adafruit Fork of SdFat, but I was trying to achieve high write speeds to keep up with my datalogging ADCs and I don't think the Adafruit Fork supports the SAMD51 DMA based SPI transfers.
I used this example to get my high write speeds. I was able to replicate it with the normal SdFat library: #434
I was just curious if you knew anything about which registers the begin() method uses so that I could identify any conflicts in my DMA datalogger. I can't find the root begin() anywhere.
from sdfat.
I was just curious if you knew anything about which registers the begin() method uses so that I could identify any conflicts in my DMA datalogger. I can't find the root begin() anywhere.
I don't remember details about the SAMD driver.
Looks like Adafruit's SdFat is far behind the current SdFat and has no option to use their DMA SPI driver.
from sdfat.
@greiman Is there anything in SdFat specifically when sd.begin(SD_CONFIG) is called that would enable the DMAC on a M4. Does SdFat have ZeroDMA as a dependency and if so where is that called in the library? I have done some testing with regard to the code above and found some interesting issue. I reconfigured the code write out the DMA controller and channel registers and added #define DEBUG_SD_BEGIN where I can easily configure if sd.begin is called or not. When sd.begin is not called (#define DEBUG_SD_BEGIN 0), the DMA runs normally and GPIO 10 and 11 (when on Grand Central board) pulse for 3us with a period of ~850 us indicating that the buffers are being filled and all of the DMA channels are sequencing properly (you can also see this in the registers that are printed). When sd.begin is called (#define DEBUG_SD_BEGIN 1), there is no pulsing on either GPIO. The registers indicate that something has changed the DMAC BASEADDR and WRB but none of the channel descriptor addresses. This causes CH2 (previously CH5) to throw a transfer error and suspend flag from the memory misalignment and halts the rest of the DMA sequence. Below is the code and serial monitor output which shows the error. (This error persists no matter if Spi_array_transfer 0 or 3 is used)
#include "SdFat.h"
#include "sdios.h"
#define error(s) sd.errorHalt(&Serial, F(s))
const uint8_t SD_CS_PIN = 83;
#define SPI_CLOCK SD_SCK_MHZ(50)
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
SdFat sd;
File file;
// Debug Parameters
#define DEBUG_R0_P0 0
#define DEBUG_R0_P1 0
#define DEBUG_R1_P0 0
#define DEBUG_R1_P1 0
#define DEBUG_SD_BEGIN 1
volatile boolean results0Part0Ready = false;
volatile boolean results0Part1Ready = false;
volatile boolean results1Part0Ready = false;
volatile boolean results1Part1Ready = false;
uint16_t adcResults0[2048]; // ADC results array 0
uint16_t adcResults1[2048]; // ADC results array 1
// ADC0 INPUTCTRL register MUXPOS settings
uint32_t inputCtrl0[] = { ADC_INPUTCTRL_MUXPOS_AIN0, // AIN0 = A0
ADC_INPUTCTRL_MUXPOS_AIN5, // AIN5 = A1
ADC_INPUTCTRL_MUXPOS_AIN3, // AIN3 = A3
ADC_INPUTCTRL_MUXPOS_AIN4 }; // AIN4 = A4
//uint16_t sintable[256]; // Sine table
typedef struct // DMAC descriptor structure
{
uint16_t btctrl;
uint16_t btcnt;
uint32_t srcaddr;
uint32_t dstaddr;
uint32_t descaddr;
} dmacdescriptor ;
volatile dmacdescriptor wrb[DMAC_CH_NUM] __attribute__ ((aligned (16))); // Write-back DMAC descriptors
dmacdescriptor descriptor_section[DMAC_CH_NUM] __attribute__ ((aligned (16))); // DMAC channel descriptors
dmacdescriptor descriptor __attribute__ ((aligned (16))); // Place holder descriptor
dmacdescriptor linked_descriptor[2] __attribute__ ((aligned (16))); // Linked descriptors
void setup() {
Serial.begin(115200); // Start the native USB port
while(!Serial); // Wait for the console to open
#if DEBUG_SD_BEGIN
// Initialize SD card before setting up DMA
if (!sd.begin(SD_CONFIG)) {
Serial.println("SD initialization failed!");
while (1); // Halt if SD card initialization fails
} else {
Serial.println("SD initialization succeeded!");
}
#endif
pinMode(10, OUTPUT); // Initialise the output on D10 for debug purposes
PORT->Group[PORTB].DIRSET.reg = PORT_PB23; // Initialise the output on D11 for debug purposes TODO: make it autoselect based on board
/DMAC->BASEADDR.reg = (uint32_t)descriptor_section; // Specify the location of the descriptors
/DMAC->WRBADDR.reg = (uint32_t)wrb; // Specify the location of the write back descriptors
// DMAC->BASEADDR.reg = 0x20002550; // Specify the location of the descriptors
// DMAC->WRBADDR.reg = 0x20002C70; // Specify the location of the write back descriptors
DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf); // Enable the DMAC peripheral
// ADC0
DMAC->Channel[2].CHPRILVL.reg = DMAC_CHPRILVL_PRILVL_LVL3; // Set DMAC channel 2 to priority level 3 (highest)
DMAC->Channel[2].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(ADC0_DMAC_ID_SEQ) | // Set DMAC to trigger on ADC0 DMAC sequence
DMAC_CHCTRLA_TRIGACT_BURST; // DMAC burst transfer
descriptor.descaddr = (uint32_t)&descriptor_section[2]; // Set up a circular descriptor
descriptor.srcaddr = (uint32_t)inputCtrl0 + sizeof(uint32_t) * 4; // Configure the DMAC to set the
descriptor.dstaddr = (uint32_t)&ADC0->DSEQDATA.reg; // Write the INPUT CTRL
descriptor.btcnt = 4; // Beat count is 2
descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_WORD | // Beat size is WORD (32-bits)
DMAC_BTCTRL_SRCINC | // Increment the source address
DMAC_BTCTRL_VALID; // Descriptor is valid
memcpy(&descriptor_section[2], &descriptor, sizeof(descriptor)); // Copy the descriptor to the descriptor section
DMAC->Channel[3].CHPRILVL.reg = DMAC_CHPRILVL_PRILVL_LVL3; // Set DMAC channel 3 to priority level 3 (highest)
DMAC->Channel[3].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(ADC0_DMAC_ID_RESRDY) | // Set DMAC to trigger when ADC0 result is ready
DMAC_CHCTRLA_TRIGACT_BURST; // DMAC burst transfer
descriptor.descaddr = (uint32_t)&linked_descriptor[0]; // Set up a circular descriptor
descriptor.srcaddr = (uint32_t)&ADC0->RESULT.reg; // Take the result from the ADC0 RESULT register
descriptor.dstaddr = (uint32_t)adcResults0 + sizeof(uint16_t) * 1024; // Place it in the adcResults0 array
descriptor.btcnt = 1024; // Beat count
descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD | // Beat size is HWORD (16-bits)
DMAC_BTCTRL_DSTINC | // Increment the destination address
DMAC_BTCTRL_VALID | // Descriptor is valid
DMAC_BTCTRL_BLOCKACT_SUSPEND; // Suspend DMAC channel 3 after block transfer
memcpy(&descriptor_section[3], &descriptor, sizeof(descriptor)); // Copy the descriptor to the descriptor section
descriptor.descaddr = (uint32_t)&descriptor_section[3]; // Set up a circular descriptor
descriptor.srcaddr = (uint32_t)&ADC0->RESULT.reg; // Take the result from the ADC0 RESULT register
descriptor.dstaddr = (uint32_t)&adcResults0[1024] + sizeof(uint16_t) * 1024; // Place it in the adcResults1 array
descriptor.btcnt = 1024; // Beat count
descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD | // Beat size is HWORD (16-bits)
DMAC_BTCTRL_DSTINC | // Increment the destination address
DMAC_BTCTRL_VALID | // Descriptor is valid
DMAC_BTCTRL_BLOCKACT_SUSPEND; // Suspend DMAC channel 3 after block transfer
memcpy(&linked_descriptor[0], &descriptor, sizeof(descriptor)); // Copy the descriptor to the descriptor section
NVIC_SetPriority(DMAC_3_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for DMAC Channel 3
NVIC_EnableIRQ(DMAC_3_IRQn); // Connect DMAC Channel 0 to Nested Vector Interrupt Controller (NVIC)
DMAC->Channel[3].CHINTENSET.reg = DMAC_CHINTENSET_SUSP; // Activate the suspend (SUSP) interrupt on DMAC channel 3
// ADC1
DMAC->Channel[4].CHPRILVL.reg = DMAC_CHPRILVL_PRILVL_LVL3; // Set DMAC channel 4 to priority level 3 (highest)
DMAC->Channel[4].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(ADC1_DMAC_ID_RESRDY) | // Set DMAC to trigger when ADC0 result is ready
DMAC_CHCTRLA_TRIGACT_BURST; // DMAC burst transfer
descriptor.descaddr = (uint32_t)&linked_descriptor[1]; // Set up a circular descriptor
descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg; // Take the result from the ADC0 RESULT register
descriptor.dstaddr = (uint32_t)adcResults1 + sizeof(uint16_t) * 1024; // Place it in the adcResults0 array
descriptor.btcnt = 1024; // Beat count
descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD | // Beat size is HWORD (16-bits)
DMAC_BTCTRL_DSTINC | // Increment the destination address
DMAC_BTCTRL_VALID | // Descriptor is valid
DMAC_BTCTRL_BLOCKACT_SUSPEND; // Suspend DMAC channel 4 after block transfer
memcpy(&descriptor_section[4], &descriptor, sizeof(descriptor)); // Copy the descriptor to the descriptor section
descriptor.descaddr = (uint32_t)&descriptor_section[4]; // Set up a circular descriptor
descriptor.srcaddr = (uint32_t)&ADC1->RESULT.reg; // Take the result from the ADC0 RESULT register
descriptor.dstaddr = (uint32_t)&adcResults1[1024] + sizeof(uint16_t) * 1024; // Place it in the adcResults1 array
descriptor.btcnt = 1024; // Beat count
descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD | // Beat size is HWORD (16-bits)
DMAC_BTCTRL_DSTINC | // Increment the destination address
DMAC_BTCTRL_VALID | // Descriptor is valid
DMAC_BTCTRL_BLOCKACT_SUSPEND; // Suspend DMAC channel 4 after block transfer
memcpy(&linked_descriptor[1], &descriptor, sizeof(descriptor)); // Copy the descriptor to the descriptor section
NVIC_SetPriority(DMAC_4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for DMAC Channel 4
NVIC_EnableIRQ(DMAC_4_IRQn); // Connect DMAC Channel 0 to Nested Vector Interrupt Controller (NVIC)
DMAC->Channel[4].CHINTENSET.reg = DMAC_CHINTENSET_SUSP; // Activate the suspend (SUSP) interrupt on DMAC channel 0
// ADC Register Settings
ADC1->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_AIN0_Val; // Set the analog input to A2
while(ADC1->SYNCBUSY.bit.INPUTCTRL); // Wait for synchronization
ADC1->SAMPCTRL.bit.SAMPLEN = 0x00; // Extend sampling time by SAMPCTRL ADC cycles (12 + 1 + 2)/750kHz = 20us = 50kHz
while(ADC1->SYNCBUSY.bit.SAMPCTRL); // Wait for synchronization
ADC1->DSEQCTRL.reg = ADC_DSEQCTRL_AUTOSTART | // Auto start a DMAC conversion upon ADC0 DMAC sequence completion
ADC_DSEQCTRL_INPUTCTRL; // Change the ADC0 INPUTCTRL register on DMAC sequence
ADC1->CTRLB.reg = ADC_CTRLB_RESSEL_8BIT;// | // Set ADC resolution to 8 bits
// ADC_CTRLB_FREERUN; // Set ADC to free run mode
while(ADC1->SYNCBUSY.bit.CTRLB); // Wait for synchronization
ADC1->CTRLA.bit.SLAVEEN = 1; // Set ADC1 to slave, ADC0 to master, both share CTRLA register
ADC0->INPUTCTRL.bit.MUXPOS = 0x0; // Set the analog input to A0
while(ADC0->SYNCBUSY.bit.INPUTCTRL); // Wait for synchronization
ADC0->SAMPCTRL.bit.SAMPLEN = 0x00; // Extend sampling time by SAMPCTRL ADC cycles (12 + 1 + 2)/750kHz = 20us = 50kHz
while(ADC0->SYNCBUSY.bit.SAMPCTRL); // Wait for synchronization
ADC0->DSEQCTRL.reg = ADC_DSEQCTRL_AUTOSTART | // Auto start a DMAC conversion upon ADC0 DMAC sequence completion
ADC_DSEQCTRL_INPUTCTRL; // Change the ADC0 INPUTCTRL register on DMAC sequence
ADC0->CTRLB.reg = ADC_CTRLB_RESSEL_8BIT;// | // Set ADC resolution to 8 bits
//ADC_CTRLB_FREERUN; // Set ADC to free run mode
while(ADC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
ADC0->CTRLA.reg = ADC_CTRLA_PRESCALER_DIV4; // Divide Clock ADC GCLK by 64 (48MHz/64 = 750kHz) (12 + 1)/750kHz = 17.3us sample time
ADC0->CTRLA.bit.ENABLE = 1; // Enable the ADC
while(ADC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
ADC0->SWTRIG.bit.START = 1; // Initiate a software trigger to start an ADC conversion
while(ADC0->SYNCBUSY.bit.SWTRIG); // Wait for synchronization
DMAC->Channel[2].CHCTRLA.bit.ENABLE = 1; // Enable DMAC channel 2
DMAC->Channel[3].CHCTRLA.bit.ENABLE = 1; // Enable DMAC channel 3
DMAC->Channel[4].CHCTRLA.bit.ENABLE = 1; // Enable DMAC channel 4
delay(1); // Wait a millisecond
// Set a timer to call debugPrintStatus every 10 seconds TODO configure this. Will use R1P0 for meantime
//Timer1.initialize(10000000); // 10 seconds
//Timer1.attachInterrupt(debugPrintStatus);
}
void loop()
{
debugPrintStatus();
if (results0Part0Ready) // Display the results in results0 array
{
Serial.println(F("Results0 Part0"));
#if DEBUG_R0_P0
Serial.print("DMA3 SUSP interrupt. CHCTRLA: ");
Serial.println(DMAC->Channel[3].CHCTRLA.reg, HEX);
Serial.print("DMA3 BTCNT: ");
Serial.println(descriptor_section[3].btcnt);
Serial.print("DMA3 DSTADDR: ");
Serial.println((uint32_t)descriptor_section[3].dstaddr, HEX);
Serial.print("DMA3 SRCADDR: ");
Serial.println((uint32_t)descriptor_section[3].srcaddr, HEX);
Serial.print("ADC0 Result: ");
Serial.println(ADC0->RESULT.reg);
#endif
Serial.println();
results0Part0Ready = false; // Clear the results0 ready flag
}
if (results0Part1Ready) // Display the results in results1 array
{
Serial.println(F("Results0 Part1"));
#if DEBUG_R0_P1
Serial.print("DMA3 SUSP interrupt. CHCTRLA: ");
Serial.println(DMAC->Channel[3].CHCTRLA.reg, HEX);
Serial.print("DMA3 BTCNT: ");
Serial.println(descriptor_section[3].btcnt);
Serial.print("DMA3 DSTADDR: ");
Serial.println((uint32_t)descriptor_section[3].dstaddr, HEX);
Serial.print("DMA3 SRCADDR: ");
Serial.println((uint32_t)descriptor_section[3].srcaddr, HEX);
Serial.print("ADC0 Result: ");
Serial.println(ADC0->RESULT.reg);
#endif
Serial.println();
results0Part1Ready = false; // Clear the results1 ready flag
}
if (results1Part0Ready) // Display the results in results0 array
{
Serial.println(F("Results1 Part0"));
#if DEBUG_R1_P0
Serial.print("DMA4 SUSP interrupt. CHCTRLA: ");
Serial.println(DMAC->Channel[4].CHCTRLA.reg, HEX);
Serial.print("DMA4 BTCNT: ");
Serial.println(descriptor_section[4].btcnt);
Serial.print("DMA4 DSTADDR: ");
Serial.println((uint32_t)descriptor_section[4].dstaddr, HEX);
Serial.print("DMA4 SRCADDR: ");
Serial.println((uint32_t)descriptor_section[4].srcaddr, HEX);
Serial.print("ADC1 Result: ");
Serial.println(ADC1->RESULT.reg);
#endif
Serial.println();
results1Part0Ready = false; // Clear the results0 ready flag
}
if (results1Part1Ready) // Display the results in results1 array
{
Serial.println(F("Results1 Part1"));
#if DEBUG_R1_P1
Serial.print("DMA4 SUSP interrupt. CHCTRLA: ");
Serial.println(DMAC->Channel[4].CHCTRLA.reg, HEX);
Serial.print("DMA4 BTCNT: ");
Serial.println(descriptor_section[4].btcnt);
Serial.print("DMA4 DSTADDR: ");
Serial.println((uint32_t)descriptor_section[4].dstaddr, HEX);
Serial.print("DMA4 SRCADDR: ");
Serial.println((uint32_t)descriptor_section[4].srcaddr, HEX);
Serial.print("ADC1 Result: ");
Serial.println(ADC1->RESULT.reg);
#endif
Serial.println();
results1Part1Ready = false; // Clear the results1 ready flag
}
}
void DMAC_3_Handler() // Interrupt handler for DMAC channel 3
{
static uint8_t count0 = 0; // Initialise the count
if (DMAC->Channel[3].CHINTFLAG.bit.SUSP) // Check if DMAC channel 3 has been suspended (SUSP)
{
DMAC->Channel[3].CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME; // Restart the DMAC on channel 3
DMAC->Channel[3].CHINTFLAG.bit.SUSP = 1; // Clear the suspend (SUSP)interrupt flag
if (count0) // Test if the count0 is 1
{
results0Part1Ready = true; // Set the results 0 part 1 ready flag
}
else
{
results0Part0Ready = true; // Set the results 0 part 0 ready flag
}
count0 = (count0 + 1) % 2; // Toggle the count0 between 0 and 1
digitalWrite(10, HIGH); // Toggle the output high then low on D10 for debug purposes
delayMicroseconds(3); // Short delay for visualization
digitalWrite(10, LOW);
}
}
void DMAC_4_Handler() // Interrupt handler for DMAC channel 4
{
static uint8_t count1 = 0; // Initialise the count
if (DMAC->Channel[4].CHINTFLAG.bit.SUSP) // Check if DMAC channel 4 has been suspended (SUSP)
{
DMAC->Channel[4].CHCTRLB.reg = DMAC_CHCTRLB_CMD_RESUME; // Restart the DMAC on channel 4
DMAC->Channel[4].CHINTFLAG.bit.SUSP = 1; // Clear the suspend (SUSP)interrupt flag
if (count1) // Test if the count1 is 1
{
results1Part1Ready = true; // Set the results 1 part 1 ready flag
}
else
{
results1Part0Ready = true; // Set the results 1 part 0 ready flag
}
count1 = (count1 + 1) % 2; // Toggle the count1 between 0 and 1
PORT->Group[PORTB].OUTSET.reg = PORT_PB23; // Toggle D10 HIGH // Toggle the output high then low on D11 for debug purposes
delayMicroseconds(3); // Short delay for visualization
PORT->Group[PORTB].OUTCLR.reg = PORT_PB23; // Toggle D10 LOW
}
}
void debugPrintStatus() {
// Print out DMAC channel status and flags
Serial.println(F("=== DMAC Channel Status ==="));
for (int i = 0; i < 5; i++) {
Serial.print(F("Channel ")); Serial.println(i);
Serial.print(F(" CHCTRLA: ")); Serial.println(DMAC->Channel[i].CHCTRLA.reg, HEX);
Serial.print(F(" CHCTRLB: ")); Serial.println(DMAC->Channel[i].CHCTRLB.reg, HEX);
Serial.print(F(" CHINTFLAG: ")); Serial.println(DMAC->Channel[i].CHINTFLAG.reg, HEX);
Serial.print(F(" CHINTENSET: ")); Serial.println(DMAC->Channel[i].CHINTENSET.reg, HEX);
Serial.print(F(" CHINTENCLR: ")); Serial.println(DMAC->Channel[i].CHINTENCLR.reg, HEX);
// Print descriptor information
Serial.print(F(" Descriptor Address: ")); Serial.println((uint32_t)&descriptor_section[i], HEX);
Serial.print(F(" BTCNT: ")); Serial.println(descriptor_section[i].btcnt);
Serial.print(F(" SRCADDR: ")); Serial.println((uint32_t)descriptor_section[i].srcaddr, HEX);
Serial.print(F(" DSTADDR: ")); Serial.println((uint32_t)descriptor_section[i].dstaddr, HEX);
Serial.print(F(" DESCADDR: ")); Serial.println((uint32_t)descriptor_section[i].descaddr, HEX);
}
// Print ADC status
Serial.println(F("=== ADC Status ==="));
Serial.print(F("ADC0 RESULT: ")); Serial.println(ADC0->RESULT.reg, HEX);
Serial.print(F("ADC0 INTFLAG: ")); Serial.println(ADC0->INTFLAG.reg, HEX);
Serial.print(F("ADC0 STATUS: ")); Serial.println(ADC0->STATUS.reg, HEX);
Serial.print(F("ADC1 RESULT: ")); Serial.println(ADC1->RESULT.reg, HEX);
Serial.print(F("ADC1 INTFLAG: ")); Serial.println(ADC1->INTFLAG.reg, HEX);
Serial.print(F("ADC1 STATUS: ")); Serial.println(ADC1->STATUS.reg, HEX);
// Print other important registers
Serial.println(F("=== Other Important Registers ==="));
Serial.print(F("DMAC BASEADDR: ")); Serial.println(DMAC->BASEADDR.reg, HEX);
Serial.print(F("DMAC WRBADDR: ")); Serial.println(DMAC->WRBADDR.reg, HEX);
Serial.print(F("DMAC CTRL: ")); Serial.println(DMAC->CTRL.reg, HEX);
} ```
```SD ENABLED
=== DMAC Channel Status ===
Channel 0
CHCTRLA: 200800
CHCTRLB: 0
CHINTFLAG: 0
CHINTENSET: 2
CHINTENCLR: 2
Descriptor Address: 20002550
BTCNT: 0
SRCADDR: 0
DSTADDR: 0
DESCADDR: 0
Channel 1
CHCTRLA: 200900
CHCTRLB: 0
CHINTFLAG: 0
CHINTENSET: 2
CHINTENCLR: 2
Descriptor Address: 20002560
BTCNT: 0
SRCADDR: 0
DSTADDR: 0
DESCADDR: 0
Channel 2
CHCTRLA: 204502
CHCTRLB: 0
CHINTFLAG: 5
CHINTENSET: 0
CHINTENCLR: 0
Descriptor Address: 20002570
BTCNT: 4
SRCADDR: 20000014
DSTADDR: 43001C34
DESCADDR: 20002570
Channel 3
CHCTRLA: 204402
CHCTRLB: 0
CHINTFLAG: 0
CHINTENSET: 4
CHINTENCLR: 4
Descriptor Address: 20002580
BTCNT: 1024
SRCADDR: 43001C40
DSTADDR: 20000D3E
DESCADDR: 200027A0
Channel 4
CHCTRLA: 204602
CHCTRLB: 0
CHINTFLAG: 0
CHINTENSET: 4
CHINTENCLR: 4
Descriptor Address: 20002590
BTCNT: 1024
SRCADDR: 43002040
DSTADDR: 20001D3E
DESCADDR: 200027B0
=== ADC Status ===
ADC0 RESULT: 3B
ADC0 INTFLAG: 0
ADC0 STATUS: 0
ADC1 RESULT: 2E
ADC1 INTFLAG: 0
ADC1 STATUS: 0
=== Other Important Registers ===
DMAC BASEADDR: 20000120 // Former BASEADDR was 20000550 which is 16 byte aligned with CH0
DMAC WRBADDR: 20000320
DMAC CTRL: F02
from sdfat.
@greiman Is there anything in SdFat specifically when sd.begin(SD_CONFIG) is called that would enable the DMAC on a M4.
SdFat does not know about DMA. It may cause DMA to be used if the SPI library is implemented with DMA.
SdFat only calls SPI.begin() with no arguments, SPI.beginTransaction(), SPI.transfer(), SPI.endTransaction() and possibly SPI.end() if sd.end() is called.
SdFat supports three SPI transfer signatures:
// Arduino standard library
uint8_t transfer(uint8_t data); // Rarely DMA
void transfer(void* buf, size_t count); // May be DMA
// Adafruit, Teensy, and other non Arduino boards.
void transfer(const void* txBuf, void* rxBuf, size_t count); // Often uses DMA.
Use of array transfers requires editing SdFatConfig here.
from sdfat.
Related Issues (20)
- Did not work at ESP32-CAM HOT 6
- MMC_ERASE HOT 2
- Wrapper to fs::FS to use SDfat in ESPAsyncWebserver HOT 6
- pico-sdk only rp2040 implementation HOT 11
- ESP32 S3 always fails to mount card HOT 10
- Unable to format flat Spiflash module with ESP8266 HOT 4
- Mount issues for a Windows-formatted card HOT 35
- SD NAND XTSD01G (surface mounted chip) not formating HOT 1
- Unable to share the same SPI bus with TFT_eSPI on ESP32 HOT 3
- Problems with multiple SD card HOT 3
- Long timeout calling begin() on Teensy 4.1 when no card present HOT 5
- SdFat 2.22 with USER_SPI1 pin + another USER_SPI2 in SPI_Mode3 HOT 2
- Arduino-Pico: huge slowdown with v2.2.2 (vs.2.1.1) HOT 5
- Problem with SdFat and TwoWire instance. HOT 3
- Issue after latest update. HOT 17
- exFat sd cards not working with Sdinfo.ino example, only FAT32 card HOT 7
- Allocating bin file with 0s HOT 2
- CS_Pin has to be driven high on ESP32 (to be low at the SDCARD) because of some logic inbetween HOT 3
- Initialization fails with ESP32 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sdfat.