void DMA_Setup( DMA_CH_t * dmaChannel, const void * src, void * dest, int16_t blockSize, uint8_t repeatCount ) { DMA_Enable(); DMA_SetupBlock( dmaChannel, src, DMA_CH_SRCRELOAD_BLOCK_gc, DMA_CH_SRCDIR_INC_gc, dest, DMA_CH_DESTRELOAD_BURST_gc, DMA_CH_DESTDIR_INC_gc, blockSize, DMA_CH_BURSTLEN_2BYTE_gc, repeatCount, true ); // Timer Overflow will trigger DMA DMA_SetTriggerSource( dmaChannel, 0x40 ); DMA_EnableSingleShot( dmaChannel ); }
/* AsyncMemCopy * * Block size 0 = 64k. Enable the DMA channel to use first. * Then setup channel for copying data, increasing addresses, * no address pointer reload, with 8-byte bursts. * * \note This function is asynchronous and DOES NOT wait for * completion.This must be handled by the program * calling this function. * In this example, an interrupt. * */ void AsyncMemCopy( const void * src, void * dest, uint16_t blockSize, DMA_CH_t * dmaChannel ) { DMA_EnableChannel( dmaChannel ); DMA_SetupBlock( dmaChannel, src, DMA_CH_SRCRELOAD_NONE_gc, DMA_CH_SRCDIR_INC_gc, dest, DMA_CH_DESTRELOAD_NONE_gc, DMA_CH_DESTDIR_INC_gc, blockSize, DMA_CH_BURSTLEN_8BYTE_gc, 0, false ); DMA_StartTransfer( dmaChannel ); }
bool MemCopy( const void * src, void * dest, uint16_t blockSize, DMA_CH_t * dmaChannel ) { uint8_t flags = 0; DMA_EnableChannel( dmaChannel ); DMA_SetupBlock( dmaChannel, src, DMA_CH_SRCRELOAD_NONE_gc, DMA_CH_SRCDIR_INC_gc, dest, DMA_CH_DESTRELOAD_NONE_gc, DMA_CH_DESTDIR_INC_gc, blockSize, DMA_CH_BURSTLEN_8BYTE_gc, 0, false ); // no repeat DMA_StartTransfer( dmaChannel ); // Wait until the completion or error flag is set. The flags // must be cleared manually. do { flags = DMA_ReturnStatus_non_blocking( dmaChannel ); } while ( flags == 0 ); // Clear flags DMA.CH0.CTRLB |= ( flags ); // Check if error flag is set if ( ( flags & DMA_CH_ERRIF_bm ) != 0x00 ) { return true; } else { return false; } }
/*! \brief Example of a repeated block memory copy operation. * * Block size 0 = 64k. Enable the DMA channel to use first and the channel * will be disabled automatically. A parameter check to avoid illegal values. * Setup channel for copying data, increasing addresses, no address pointer * reload, with 8-byte bursts. * * \note This function wait until the transfer is complete and use a blocking * function which also makes this function blocking, hence the function * will dead-lock if the completion or error flag never get set. * * \retval true if success. * \retval false if failure. */ bool MultiBlockMemCopy( const void * src, void * dest, uint16_t blockSize, uint8_t repeatCount, volatile DMA_CH_t * dmaChannel ) { uint8_t flags; DMA_EnableChannel( dmaChannel ); DMA_SetupBlock( dmaChannel, src, DMA_CH_SRCRELOAD_NONE_gc, DMA_CH_SRCDIR_INC_gc, dest, DMA_CH_DESTRELOAD_NONE_gc, DMA_CH_DESTDIR_INC_gc, blockSize, DMA_CH_BURSTLEN_8BYTE_gc, repeatCount, true ); DMA_StartTransfer( dmaChannel ); /* Wait until the completion or error flag is set. The flags * must be cleared manually. */ do { flags = DMA_ReturnStatus_non_blocking( dmaChannel ); } while ( flags == 0); dmaChannel->CTRLB |= ( flags ); /* Check if error flag is set. */ if ( ( flags & DMA_CH_ERRIF_bm ) != 0x00 ) { return false; } else { return true; } }
int main(void) { facilitatePowersaving(); // Configure switches PORTCFG.MPCMASK = 0xff; // Configure several PINxCTRL registers at the same time SWITCHPORT.PIN0CTRL = (SWITCHPORT.PIN0CTRL & ~PORT_OPC_gm) | PORT_OPC_PULLUP_gc; //Enable pull-up to get a defined level on the switches SWITCHPORT.DIRCLR = 0xff; // Set port as input // Configure LEDs PORTCFG.MPCMASK = 0xff; // Configure several PINxCTRL registers at the same time LEDPORT.PIN0CTRL = PORT_INVEN_bm; // Invert input to turn the leds on when port output value is 1 LEDPORT.DIRSET = 0xff; // Set port as output LEDPORT.OUT = 0x00; // Set initial value // Set up ADCB0 on PB0 to read temp sensor. More of this can be achieved by using driver from appnote AVR1300 PORTQ.PIN2CTRL = (PORTQ.PIN2CTRL & ~PORT_OPC_gm) | PORT_OPC_PULLDOWN_gc; // This pin must be grounded to "enable" NTC-resistor PORTB.DIRCLR = PIN0; PORTB.PIN0CTRL = (PORTB.PIN0CTRL & ~PORT_OPC_gm); ADC_CalibrationValues_Load(&ADCB); // Load factory calibration data for ADC ADCB.CH0.CTRL = (ADCB.CH0.CTRL & ~ADC_CH_INPUTMODE_gm) | ADC_CH_INPUTMODE_SINGLEENDED_gc; // Single ended input ADCB.CH0.MUXCTRL = (ADCB.CH0.MUXCTRL & ~ADC_CH_MUXPOS_gm) | ADC_CH_MUXPOS_PIN0_gc; // Pin 0 is input ADCB.REFCTRL = (ADCB.REFCTRL & ~ADC_REFSEL_gm) | ADC_REFSEL_VCC_gc; // Internal AVCC/1.6 as reference ADCB.CTRLB |= ADC_FREERUN_bm; // Free running mode ADCB.PRESCALER = (ADCB.PRESCALER & ~ADC_PRESCALER_gm) | ADC_PRESCALER_DIV512_gc; // Divide clock by 1024. ADCB.CTRLB = (ADCB.CTRLB & ~ADC_RESOLUTION_gm) | ADC_RESOLUTION_8BIT_gc; // Set 8 bit resolution ADCB.CTRLA |= ADC_ENABLE_bm; // Enable ADC // Set up DMA CH0 to transfer from ADC to LEDS. We only read low byte. DMA_Enable(); DMA_SetupBlock( &DMA.CH0, (void const *) &(ADCB.CH0RES), DMA_CH_SRCRELOAD_NONE_gc, DMA_CH_SRCDIR_FIXED_gc, (void const *) &(LEDPORT.OUT), DMA_CH_DESTRELOAD_NONE_gc, DMA_CH_DESTDIR_FIXED_gc, 1, DMA_CH_BURSTLEN_1BYTE_gc, 0, true ); DMA_EnableSingleShot( &DMA.CH0 ); DMA_SetTriggerSource( &DMA.CH0, DMA_CH_TRIGSRC_ADCB_CH0_gc ); // ADC Channel 0 is trigger source. // Set up interrupt on button 0, or else we can't come back from IDLE SWITCHPORT.INTCTRL = (SWITCHPORT.INTCTRL & ~PORT_INT0LVL_gm) | PORT_INT0LVL_LO_gc; SWITCHPORT.INT0MASK = SWITCHMASK_ACTIVE; SWITCHPORT.PIN0CTRL = (SWITCHPORT.PIN0CTRL & ~PORT_ISC_gm) | PORT_ISC_FALLING_gc; // Enable low interrupt level in PMIC and enable global interrupts. PMIC.CTRL |= PMIC_LOLVLEN_bm; sei(); // Main loop. while (1) { if ((SWITCHPORT.IN & SWITCHMASK_ACTIVE) == 0x00) { // Button 0 pressed. Enter ACTIVE mode again. DMA_DisableChannel( &DMA.CH0 ); SLEEP.CTRL &= ~SLEEP_SEN_bm; // Disable sleep. sleep() is now ineffective. } else if ((SWITCHPORT.IN & SWITCHMASK_IDLE) == 0x00) { // Button 1 pressed. Enter Idle mode DMA_EnableChannel( &DMA.CH0 ); // Set and enable sleep. SLEEP.CTRL = (SLEEP.CTRL & ~SLEEP_SMODE_gm) | SLEEP_SMODE_IDLE_gc; SLEEP.CTRL |= SLEEP_SEN_bm; // Enable sleep. } else if (SLEEP.CTRL & SLEEP_SEN_bm) { // We are in wanting-to-sleep mode, but were awake. sleep(); } else { // Do active sampling and transfer of ADC data. LEDPORT.OUT = ADCB.CH0RES & 0xFF; } } }