int main( void ) { KEY_PORT.DIR = 0x00; // Set direction as input. LED_PORT.DIR = 0xFF; PORTCFG.MPCMASK = 0xFF; LED_PORT.PIN0CTRL |= (LED_PORT.PIN0CTRL ) | PORT_INVEN_bm; // Configure all keys to be active when pressed (inverted). PORTCFG.MPCMASK = 0xFF; KEY_PORT.PIN0CTRL |= (KEY_PORT.PIN0CTRL ) | PORT_INVEN_bm; // Enable overflow interrupt TCC0.INTCTRLA = ( TCC0.INTCTRLA & TC0_OVFINTLVL_gm ) | TC_OVFINTLVL_MED_gc; DMA_Setup(DMA_CHANNEL_0, SineWaveHighRes, (void *) &DACB.CH0DATA, SINE_WAVE_HIGH_RES * 2, DMA_REPEAT_FOREVER); DMA_Setup(DMA_CHANNEL_1, SineWaveLowRes, (void *) &DACB.CH1DATA, SINE_WAVE_LOW_RES * 2, DMA_REPEAT_FOREVER); DAC_DualChannel_Enable( &DACB, DAC_REFSEL_AVCC_gc, false, // Right adjusted DAC_CONINTVAL_4CLK_gc, DAC_REFRESH_32CLK_gc ); DMA_EnableChannel( DMA_CHANNEL_0 ); DMA_EnableChannel( DMA_CHANNEL_1 ); // Enable medium interrupt level in PMIC and enable global interrupts. PMIC.CTRL |= PMIC_MEDLVLEN_bm; sei(); while (1) { if(KEY_PORT.IN == 0x00) { // No Timer to trigger DMA: No Signal TCC0.CTRLA = ( TCC0.CTRLA & ~TC0_CLKSEL_gm ) | TC_CLKSEL_OFF_gc; } else { // Enable Timer C0, prescaler div1 means Main Clock (2MHz). TCC0.CTRLA = ( TCC0.CTRLA & ~TC0_CLKSEL_gm ) | TC_CLKSEL_DIV1_gc; if(KEY_PORT.IN & 0x01) { TCC0.PER = TIMER_C0_PERIOD; while(KEY_PORT.IN & 0x01) { LED_PORT.OUTSET = 0x01; } } LED_PORT.OUT = 0x00; } } }
//------------------------------------------------------------------------------ /// Starts buffer transfer on the given channel /// \param channel Particular channel number. /// \param size Total transfer size in byte. /// \param callback Optional callback function. /// \param polling Polling channel status enable. //------------------------------------------------------------------------------ unsigned char DMAD_BufferTransfer(unsigned char channel, unsigned int size, DmaCallback callback, unsigned char polling) { DmaTransfer *pTransfer = &(dmad.transfers[channel]); // Check that no transfer is pending on the channel if (pTransfer-> transferSize > 0 ) { TRACE_ERROR("DAM transfer is already pending\n\r"); return DMAD_ERROR_BUSY; } pTransfer->status = DMAD_ERROR_BUSY; pTransfer->transferSize = size; pTransfer->callback = callback; if(!polling){ DMA_EnableIt(DMA_BTC << channel); } // Enable the channel. DMA_EnableChannel(channel); if(polling){ while ((DMA_GetChannelStatus() & (DMA_ENA << channel)) == (DMA_ENA << channel)); pTransfer->callback(); DMA_DisableChannel(channel); } return 0; }
//------------------------------------------------------------------------------ /// Starts buffer transfer on the given channel /// \param channel Particular channel number. /// \param size Total transfer size in byte. /// \param callback Optional callback function. /// \param polling Polling channel status enable. //------------------------------------------------------------------------------ U8 DMAD_BufferTransfer(U8 channel, U32 size, DmaCallback callback, U8 polling) { DmaTransfer *pTransfer = &(dmad.transfers[channel]); if (pTransfer-> transferSize > 0 ) // Check that no transfer is pending on the channel { DEBUG_MSG("DAM transfer is already pending"); return DMAD_ERROR_BUSY; } pTransfer->status = DMAD_ERROR_BUSY; pTransfer->transferSize = size; pTransfer->callback = callback; if(!polling) { DMA_EnableIt(0x1 << channel); } DMA_EnableChannel(channel); // Enable the channel. if(polling) { while ((DMA_GetChannelStatus() & (0x1 << channel)) == (0x1 << channel)); if (pTransfer->callback) { pTransfer->callback(); } pTransfer->transferSize = 0; DMA_DisableChannel(channel); } return 0; }
void dma_init(uint32_t dmaNdx, uint32_t chnNdx){ assert(dmaNdx == 0); uint32_t bmOldChnEn; HAL_ENTER_CRITICAL(); bmOldChnEn = dma_idle.bmChnEn[dmaNdx]; dma_idle.bmChnEn[dmaNdx] = bmOldChnEn | 1 << chnNdx; if (0 == bmOldChnEn) DMA_Init(DMA0); HAL_NVIC_SetPriority(DMA0_IRQn, IRQ_PRI_DMA, IRQ_SUBPRI_DMA); HAL_LEAVE_CRITICAL(); DMA_EnableChannel(DMA0, chnNdx); }
/* 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 ); }
//------------------------------------------------------------------------------ /// Starts buffer transfer on the given dwChannel /// \param dwChannel Particular dwChannel number. /// \param size Total transfer size in byte. /// \param callback Optional callback function. /// \param polling Polling dwChannel status enable. //------------------------------------------------------------------------------ extern uint32_t DMAD_BufferTransfer( uint32_t dwChannel, uint32_t dwSize, DmaCallback callback, uint32_t dwPolling ) { DmaTransfer *pTransfer = &(dmad.transfers[dwChannel]) ; // Check that no transfer is pending on the dwChannel if ( pTransfer-> transferSize > 0 ) { TRACE_ERROR( "DAM transfer is already pending\n\r" ) ; return DMAD_ERROR_BUSY ; } pTransfer->status = DMAD_ERROR_BUSY ; pTransfer->transferSize = dwSize ; pTransfer->callback = callback ; if ( dwPolling == 0 ) { DMA_EnableIt( DMAC, DMA_BTC << dwChannel ) ; } // Enable the dwChannel. DMA_EnableChannel( DMAC, dwChannel ) ; if ( dwPolling != 0 ) { while ( (DMA_GetChannelStatus( DMAC ) & (DMAC_CHSR_ENA0 << dwChannel)) == (DMAC_CHSR_ENA0 << dwChannel)) ; if ( pTransfer->callback ) { pTransfer->callback() ; } pTransfer->transferSize = 0 ; DMA_DisableChannel( DMAC, dwChannel ) ; } return 0 ; }
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; } } }