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