00001 /* ---------------------------------------------------------------------------- 00002 * SAM Software Package License 00003 * ---------------------------------------------------------------------------- 00004 * Copyright (c) 2014, Atmel Corporation 00005 * 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * 00011 * - Redistributions of source code must retain the above copyright notice, 00012 * this list of conditions and the disclaimer below. 00013 * 00014 * Atmel's name may not be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR 00018 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 00020 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, 00021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00022 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 00023 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00024 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00025 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 00026 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00027 * ---------------------------------------------------------------------------- 00028 */ 00029 00030 /** 00031 * \page pwm PWM with DMA Example 00032 * 00033 * \section Purpose 00034 * 00035 * This example demonstrates a simple configuration of three PWM channels to 00036 * generate variable duty cycle signals. The update of the duty cycle values 00037 * is made automatically by the Peripheral DMA Controller . 00038 * This will cause LED on the evaluation kit to glow repeatedly. 00039 * 00040 * \section Requirements 00041 * 00042 * This package can be used with SAM V71 Xplained Ultra board. 00043 * 00044 * \section Description 00045 * 00046 * Three PWM channels (channel #0) are configured to generate 00047 * a 50Hz PWM signal. The update of the duty cycle values is made 00048 * automatically by the DMA. 00049 * 00050 * \section Usage 00051 * 00052 * -# Build the program and download it inside the SAM V71 Xplained Ultra board. 00053 * Please refer to the Getting Started with SAM V71 Microcontrollers.pdf 00054 * -# Optionally, on the computer, open and configure a terminal application 00055 * (e.g. HyperTerminal on Microsoft Windows) with these settings: 00056 * - 115200 baud rates 00057 * - 8 bits of data 00058 * - No parity 00059 * - 1 stop bit 00060 * - No flow control 00061 * -# Start the application. 00062 * -# Depending on the board being used, two LED will start glowing repeatedly. 00063 * -# Select one or more options to set the configuration of PWM channel. 00064 * 00065 * \section References 00066 * - pwm_pdc/main.c 00067 * - pwm.c 00068 * - pwm.h 00069 */ 00070 00071 /** 00072 * \file 00073 * 00074 * This file contains all the specific code for the pwm_pdc example. 00075 */ 00076 00077 /*---------------------------------------------------------------------------- 00078 * Headers 00079 *----------------------------------------------------------------------------*/ 00080 00081 #include "board.h" 00082 00083 #include <stdint.h> 00084 #include <stdio.h> 00085 00086 /*---------------------------------------------------------------------------- 00087 * Local definitions 00088 *----------------------------------------------------------------------------*/ 00089 00090 /** PWM frequency in Hz. */ 00091 #define PWM_FREQUENCY 50 00092 00093 /** Maximum duty cycle value. */ 00094 #define MAX_DUTY_CYCLE 100 00095 /** Minimum duty cycle value. */ 00096 #define MIN_DUTY_CYCLE 0 00097 00098 /** Duty cycle buffer length for three channels */ 00099 #define DUTY_BUFFER_LENGTH (MAX_DUTY_CYCLE - MIN_DUTY_CYCLE ) 00100 00101 /*---------------------------------------------------------------------------- 00102 * Local variables 00103 *----------------------------------------------------------------------------*/ 00104 00105 /** PIO pins to configure. */ 00106 00107 #define PIN_PWM_LED { PIO_PA23B_PWMC0_PWMH0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} 00108 #define CHANNEL_PWM_LED0 0 00109 // 00110 static const Pin pinPwm[] = { PIN_PWM_LED }; 00111 00112 /** duty cycle buffer*/ 00113 static uint16_t dwDutys[DUTY_BUFFER_LENGTH]; 00114 00115 /** Global DMA driver for all transfer */ 00116 static sXdmad dmad; 00117 00118 /** DMA channel for TX */ 00119 static uint32_t pwmDmaTxChannel; 00120 static LinkedListDescriporView1 dmaWriteLinkList[DUTY_BUFFER_LENGTH]; 00121 00122 /*---------------------------------------------------------------------------- 00123 * Local functions 00124 *----------------------------------------------------------------------------*/ 00125 00126 /** 00127 * Interrupt handler for the XDMAC. 00128 */ 00129 void XDMAC_Handler( void ) 00130 { 00131 XDMAD_Handler( &dmad ); 00132 } 00133 00134 /** 00135 * Interrupt handler for the PWMC. 00136 */ 00137 void PWM0_Handler( void ) 00138 { 00139 volatile uint32_t dummySt; 00140 /* WRDY: this flag is set to'1' when the PWM Controller is ready to receive 00141 new duty-cycle values and a new update period value. It is reset to '0' 00142 when the PWM_ISR2 is read.*/ 00143 dummySt = PWMC_GetStatus2(PWM0); 00144 } 00145 00146 /** 00147 * \brief xDMA driver configuration 00148 */ 00149 static void _ConfigureDma( void ) 00150 { 00151 sXdmad *pDmad = &dmad; 00152 /* Driver initialize */ 00153 XDMAD_Initialize( pDmad, 0 ); 00154 /* Allocate DMA channels for PWM */ 00155 pwmDmaTxChannel = XDMAD_AllocateChannel( pDmad, XDMAD_TRANSFER_MEMORY, ID_PWM0); 00156 if (pwmDmaTxChannel == XDMAD_ALLOC_FAILED ) { 00157 printf("xDMA channel allocation error\n\r"); 00158 while(1); 00159 } 00160 XDMAD_PrepareChannel(pDmad, pwmDmaTxChannel ); 00161 /* Configure interrupt for DMA transfer */ 00162 NVIC_ClearPendingIRQ(XDMAC_IRQn); 00163 NVIC_SetPriority( XDMAC_IRQn ,1); 00164 NVIC_EnableIRQ(XDMAC_IRQn); 00165 } 00166 00167 /** 00168 * \brief xDMA transfer PWM duty 00169 */ 00170 static void _PwmDmaTransfer(void) 00171 { 00172 sXdmadCfg xdmadCfg; 00173 uint32_t xdmaCndc; 00174 uint32_t i; 00175 for(i = 0; i < DUTY_BUFFER_LENGTH; i++) { 00176 dmaWriteLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1 00177 | XDMA_UBC_NDE_FETCH_EN 00178 | XDMA_UBC_NSEN_UPDATED 00179 | XDMAC_CUBC_UBLEN(1); 00180 dmaWriteLinkList[i].mbr_sa = (uint32_t)(&dwDutys[i]); 00181 dmaWriteLinkList[i].mbr_da = (uint32_t)(&(PWM0->PWM_DMAR)); 00182 if ( i == (DUTY_BUFFER_LENGTH - 1 )) { 00183 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[0]; 00184 } else { 00185 dmaWriteLinkList[i].mbr_nda = (uint32_t)&dmaWriteLinkList[i+1]; 00186 } 00187 } 00188 00189 xdmadCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN 00190 | XDMAC_CC_MBSIZE_SINGLE 00191 | XDMAC_CC_DSYNC_MEM2PER 00192 | XDMAC_CC_CSIZE_CHK_1 00193 | XDMAC_CC_DWIDTH_HALFWORD 00194 | XDMAC_CC_SIF_AHB_IF0 00195 | XDMAC_CC_DIF_AHB_IF1 00196 | XDMAC_CC_SAM_FIXED_AM 00197 | XDMAC_CC_DAM_FIXED_AM 00198 | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ID_PWM0, XDMAD_TRANSFER_TX )); 00199 xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1 00200 | XDMAC_CNDC_NDE_DSCR_FETCH_EN 00201 | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED 00202 | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED ; 00203 XDMAD_ConfigureTransfer( &dmad, pwmDmaTxChannel, &xdmadCfg, xdmaCndc, 00204 (uint32_t)&dmaWriteLinkList[0], XDMAC_CIE_LIE); 00205 SCB_CleanInvalidateDCache(); 00206 XDMAD_StartTransfer( &dmad, pwmDmaTxChannel); 00207 } 00208 00209 /*---------------------------------------------------------------------------- 00210 * Global functions 00211 *----------------------------------------------------------------------------*/ 00212 00213 /** 00214 * \brief Application entry point for PWM with PDC example. 00215 * 00216 * Outputs a PWM on LED1. 00217 * Channel #0 is configured as synchronous channels. 00218 * The update of the duty cycle values is made automatically by the Peripheral 00219 * DMA Controller. 00220 * 00221 * \return Unused (ANSI-C compatibility). 00222 */ 00223 int main(void) 00224 { 00225 uint32_t i; 00226 /* Disable watchdog */ 00227 WDT_Disable( WDT ) ; 00228 00229 /* Enable I and D cache */ 00230 SCB_EnableICache(); 00231 SCB_EnableDCache(); 00232 00233 /* Output example information */ 00234 printf("-- PWM with DMA Example %s --\n\r", SOFTPACK_VERSION); 00235 printf("-- %s\n\r", BOARD_NAME); 00236 printf( "-- Compiled: %s %s With %s--\n\r", __DATE__, __TIME__ , COMPILER_NAME) ; 00237 00238 /* PIO configuration */ 00239 PIO_Configure(pinPwm, PIO_LISTSIZE(pinPwm)); 00240 for (i= 0; i< DUTY_BUFFER_LENGTH; i++) dwDutys[i] = i/2; 00241 00242 /* Enable PWMC peripheral clock */ 00243 PMC_EnablePeripheral(ID_PWM0); 00244 00245 /* Configure interrupt for PWM transfer */ 00246 NVIC_DisableIRQ(PWM0_IRQn); 00247 NVIC_ClearPendingIRQ(PWM0_IRQn); 00248 NVIC_SetPriority(PWM0_IRQn, 0); 00249 00250 /* Configure DMA channel for PWM transfer */ 00251 _ConfigureDma(); 00252 00253 /* Set clock A to run at PWM_FREQUENCY * MAX_DUTY_CYCLE (clock B is not 00254 used) */ 00255 PWMC_ConfigureClocks(PWM0, PWM_FREQUENCY * MAX_DUTY_CYCLE , 0, BOARD_MCK); 00256 00257 /* Configure PWMC channel for LED0 (left-aligned, enable dead time 00258 generator) */ 00259 PWMC_ConfigureChannel( PWM0, 00260 0, /* channel */ 00261 PWM_CMR_CPRE_CLKA, /* prescaler, CLKA */ 00262 0, /* alignment */ 00263 0 /* polarity */ 00264 ); 00265 00266 PWMC_ConfigureSyncChannel(PWM0, 00267 /* Define the synchronous channels by the bits SYNCx */ 00268 (1 << CHANNEL_PWM_LED0), 00269 /* Select the manual write of duty-cycle values and the automatic 00270 update by setting the field UPDM */ 00271 PWM_SCM_UPDM_MODE2, 00272 0, 00273 0); 00274 00275 /* Configure channel 0 period */ 00276 PWMC_SetPeriod(PWM0, 0, DUTY_BUFFER_LENGTH); 00277 /* Configure channel 0 duty cycle */ 00278 PWMC_SetDutyCycle(PWM0, 0, MIN_DUTY_CYCLE); 00279 /* Define the update period by the field UPR in the PWM_SCUP register*/ 00280 PWMC_SetSyncChannelUpdatePeriod(PWM0, 8); 00281 /* Enable the synchronous channels by writing CHID0 in the PWM_ENA register */ 00282 PWMC_EnableChannel(PWM0, 0); 00283 /* Enable PWM interrupt */ 00284 PWMC_EnableIt(PWM0, 0, PWM_IER2_WRDY); 00285 NVIC_EnableIRQ(PWM0_IRQn); 00286 _PwmDmaTransfer(); 00287 while(1); 00288 }