Been at this for more than one day, can't get it to work. Atmel SAMD51J19 chip. Just sits there and does nothing. Not sure where this is going wrong or at what part. When I debug it it runs without any errors and yet still doesn't appear to do anything. Not sure if it's I2C, DMAC, or what's casing it to not work. If someone can look it over and tell me if I went wrong somewhere I'd be very appreciative.
constexpr var32 sercom5_speed = 12000000; static const var8 i2cXfer[] = { // IODIRA = All Out 0x00, 0x00, // IODIRB = All Out 0x01, 0x00, // GPIOA = All Positive 0x12, 0xFF, // GPIOB = All Positive 0x13, 0xFF, }; constexpr var8 channels = 1; DmacDescriptor __attribute__((aligned(128))) dmaBase[channels]; DmacDescriptor __attribute__((aligned(128))) dmaWrtBk[channels]; // Enable all priority levels (Don't ignore any descriptor based on priority) DMAC->CTRL.reg = DMAC_CTRL_LVLEN0 | DMAC_CTRL_LVLEN1 | DMAC_CTRL_LVLEN2 | DMAC_CTRL_LVLEN3; // Allow to run in debug mode DMAC->DBGCTRL.bit.DBGRUN = true; // Setup priority system // A simple setup, all round-robin and priority 0-3 will have highest to lowest latency // awareness and elimination // For priority 0 // Round-Robin, Critical Latency Control DMAC->PRICTRL0.reg = DMAC_PRICTRL0_RRLVLEN0 | DMAC_PRICTRL0_QOS0_CRITICAL | // For priority 1 // Round-Robin, Medium Latency Control DMAC_PRICTRL0_RRLVLEN1 | DMAC_PRICTRL0_QOS1_SENSITIVE | // For priority 2 // Round-Robin, Some Latency Control DMAC_PRICTRL0_RRLVLEN2 | DMAC_PRICTRL0_QOS2_SHORTAGE | // For priority 3 // Round-Robin, No Latency Control DMAC_PRICTRL0_RRLVLEN3 | DMAC_PRICTRL0_QOS3_REGULAR; // Set memory addresses for base and write-back DMAC->BASEADDR.bit.BASEADDR = (var32)(dmaBase); DMAC->WRBADDR.bit.WRBADDR = (var32)(dmaWrtBk); // Enable DMAC->CTRL.bit.DMAENABLE = true; //////////////////////// /// DMAC Descriptor Setup //////////////////////// // Destination Address Increment Disabled DMA::dmaBase[0].BTCTRL.reg = DMAC_BTCTRL_STEPSIZE_X1 | // Address Increment Step Size = 1 byte DMAC_BTCTRL_STEPSEL_SRC | // Step size applies to source address DMAC_BTCTRL_SRCINC | // Increment Src Address by step size DMAC_BTCTRL_BEATSIZE_BYTE | // Beat Size = 1 Byte DMAC_BTCTRL_BLOCKACT_NOACT | // Disable channel at end of transaction DMAC_BTCTRL_EVOSEL_DISABLE | // Do nothing with event output DMAC_BTCTRL_VALID; // This channel is valid and ready for use // Number of blocks in a transfer var32 s = sizeof(i2cXfer); DMA::dmaBase[0].BTCNT.reg = sizeof(i2cXfer); DMA::dmaBase[0].SRCADDR.reg = (var32)i2cXfer + sizeof(i2cXfer); // (var32)i2cXfer; DMA::dmaBase[0].DSTADDR.reg = (var32)&SERCOM5->I2CM.DATA.reg; // ??? Maybe ??? SERCOM 5 DMA::dmaBase[0].DESCADDR.reg = 0x00000000; // Transaction has no more descriptors //////////////////////// /// DMAC Setup //////////////////////// // Create DMAC Entry for I2C DMAC->Channel[0].CHCTRLA.reg = DMAC_CHCTRLA_THRESHOLD_1BEAT | // Write after 1 beat DMAC_CHCTRLA_BURSTLEN_SINGLE | // Single Beat Burst DMAC_CHCTRLA_TRIGACT_BURST | // On each trigger write another 1-byte block DMAC_CHCTRLA_TRIGSRC(0x0F) | // Trigger when SERCOM5 TX Register becomes empty DMAC_CHCTRLA_RUNSTDBY; // Run in standby // No Action ??? DMAC->Channel[0].CHCTRLB.bit.CMD = DMAC_CHCTRLB_CMD_NOACT; // Lowest Priority DMAC->Channel[0].CHPRILVL.bit.PRILVL = 0; // Don't do anything with event inputs or outputs DMAC->Channel[0].CHEVCTRL.reg = 0; //////////////////////// /// I2C Setup on SERCOM 5 //////////////////////// // Setup SDA & SCL Pins // Continuous Sampling, Output Enable default to ground // Enable Input and Multiplex to D (Sercom) PORT->Group[1].CTRL.bit.SAMPLING |= (1 << 2) | (1 << 3); PORT->Group[1].DIRSET.bit.DIRSET = (1 << 2) | (1 << 3); PORT->Group[1].OUTCLR.bit.OUTCLR = (1 << 2) | (1 << 3); PORT->Group[1].PINCFG[2].bit.INEN = true; PORT->Group[1].PINCFG[2].bit.PMUXEN = true; PORT->Group[1].PINCFG[3].bit.INEN = true; PORT->Group[1].PINCFG[3].bit.PMUXEN = true; PORT->Group[1].PMUX[2 / 2].bit.PMUXE = 3; PORT->Group[1].PMUX[3 / 2].bit.PMUXO = 3; // Use Fast Mode (Fs) For 400KHz Timing // Slave SCL Low Extend Time-Out (DISABLED) // Master SCL Low Extend Time-Out (DISABLED) // SDA Hold Time (DISABLED) // Pin Usage (2 PINS) // Don't Reset // Keep Disabled SERCOM5->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_INACTOUT(3) | // Inactive Time-Out 20-21 SCL cycle time-out SERCOM_I2CM_CTRLA_SPEED(0) | // Fs (Up to 400KHz) SERCOM_I2CM_CTRLA_RUNSTDBY | // Run in Standby SERCOM_I2CM_CTRLA_MODE(5); // Master Mode // Acknowledge Action (Send ACK) // CMD (No Action) ??? Used for DMA ??? // Quick Command (DISABLED) SERCOM5->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; // Smart Mode // Data 8-bit SERCOM5->I2CM.CTRLC.reg = 0; // High Speed BAUD High & Low Disabled // Baud High and Low Set to 400KHz constexpr var32 i2c_speed = 400000; // 400KHz SERCOM5->I2CM.BAUD.reg = SERCOM_I2CM_BAUD_BAUD(sercom5_speed / i2c_speed); // Baud Rate = 400KHz [BAUD=30] // Address settings // Ten Bit Addressing Disabled SERCOM5->I2CM.ADDR.reg = SERCOM_I2CM_ADDR_LEN(1) | // 1 Byte Transactions??? SERCOM_I2CM_ADDR_LENEN | // Transaction Length Enable (For DMA) SERCOM_I2CM_ADDR_ADDR((0x20 << 1) | 0); // Address slave 0x20 in write mode (Bit 0 = 0) // Run in debug mode SERCOM5->I2CM.DBGCTRL.bit.DBGSTOP = false; // Enable SERCOM5->I2CM.CTRLA.bit.ENABLE = true; // Wait for bus to become ready and sync to end while(SERCOM5->I2CM.SYNCBUSY.reg); while(SERCOM5->I2CM.STATUS.bit.BUSSTATE != 1); //////////////////////// /// Activate DMAC //////////////////////// // Enable I2C DMAC DMAC->Channel[0].CHCTRLA.bit.ENABLE = true;