Code Monkey home page Code Monkey logo

Comments (5)

greiman avatar greiman commented on August 17, 2024

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.

cdd0042 avatar cdd0042 commented on August 17, 2024

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.

greiman avatar greiman commented on August 17, 2024

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.

raider-snake avatar raider-snake commented on August 17, 2024

@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 avatar greiman commented on August 17, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.